/usr/include/d/stdx-allocator/stdx/allocator/building_blocks/segregator.d is in libstdx-allocator-dev 2.77.1.1-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 | ///
module stdx.allocator.building_blocks.segregator;
import stdx.allocator.common;
/**
Dispatches allocations (and deallocations) between two allocators ($(D
SmallAllocator) and $(D LargeAllocator)) depending on the size allocated, as
follows. All allocations smaller than or equal to $(D threshold) will be
dispatched to $(D SmallAllocator). The others will go to $(D LargeAllocator).
If both allocators are $(D shared), the $(D Segregator) will also offer $(D
shared) methods.
*/
struct Segregator(size_t threshold, SmallAllocator, LargeAllocator)
{
import std.algorithm.comparison : min;
import std.traits : hasMember;
import stdx.allocator.internal : Ternary;
static if (stateSize!SmallAllocator) private SmallAllocator _small;
else private alias _small = SmallAllocator.instance;
static if (stateSize!LargeAllocator) private LargeAllocator _large;
else private alias _large = LargeAllocator.instance;
version (StdDdoc)
{
/**
The alignment offered is the minimum of the two allocators' alignment.
*/
enum uint alignment;
/**
This method is defined only if at least one of the allocators defines
it. The good allocation size is obtained from $(D SmallAllocator) if $(D
s <= threshold), or $(D LargeAllocator) otherwise. (If one of the
allocators does not define $(D goodAllocSize), the default
implementation in this module applies.)
*/
static size_t goodAllocSize(size_t s);
/**
The memory is obtained from $(D SmallAllocator) if $(D s <= threshold),
or $(D LargeAllocator) otherwise.
*/
void[] allocate(size_t);
/**
This method is defined if both allocators define it, and forwards to
$(D SmallAllocator) or $(D LargeAllocator) appropriately.
*/
void[] alignedAllocate(size_t, uint);
/**
This method is defined only if at least one of the allocators defines
it. If $(D SmallAllocator) defines $(D expand) and $(D b.length +
delta <= threshold), the call is forwarded to $(D SmallAllocator). If $(D
LargeAllocator) defines $(D expand) and $(D b.length > threshold), the
call is forwarded to $(D LargeAllocator). Otherwise, the call returns
$(D false).
*/
bool expand(ref void[] b, size_t delta);
/**
This method is defined only if at least one of the allocators defines
it. If $(D SmallAllocator) defines $(D reallocate) and $(D b.length <=
threshold && s <= threshold), the call is forwarded to $(D
SmallAllocator). If $(D LargeAllocator) defines $(D expand) and $(D
b.length > threshold && s > threshold), the call is forwarded to $(D
LargeAllocator). Otherwise, the call returns $(D false).
*/
bool reallocate(ref void[] b, size_t s);
/**
This method is defined only if at least one of the allocators defines
it, and work similarly to $(D reallocate).
*/
bool alignedReallocate(ref void[] b, size_t s);
/**
This method is defined only if both allocators define it. The call is
forwarded to $(D SmallAllocator) if $(D b.length <= threshold), or $(D
LargeAllocator) otherwise.
*/
Ternary owns(void[] b);
/**
This function is defined only if both allocators define it, and forwards
appropriately depending on $(D b.length).
*/
bool deallocate(void[] b);
/**
This function is defined only if both allocators define it, and calls
$(D deallocateAll) for them in turn.
*/
bool deallocateAll();
/**
This function is defined only if both allocators define it, and returns
the conjunction of $(D empty) calls for the two.
*/
Ternary empty();
}
/**
Composite allocators involving nested instantiations of $(D Segregator) make
it difficult to access individual sub-allocators stored within. $(D
allocatorForSize) simplifies the task by supplying the allocator nested
inside a $(D Segregator) that is responsible for a specific size $(D s).
Example:
----
alias A = Segregator!(300,
Segregator!(200, A1, A2),
A3);
A a;
static assert(typeof(a.allocatorForSize!10) == A1);
static assert(typeof(a.allocatorForSize!250) == A2);
static assert(typeof(a.allocatorForSize!301) == A3);
----
*/
ref auto allocatorForSize(size_t s)()
{
static if (s <= threshold)
static if (is(SmallAllocator == Segregator!(Args), Args...))
return _small.allocatorForSize!s;
else return _small;
else
static if (is(LargeAllocator == Segregator!(Args), Args...))
return _large.allocatorForSize!s;
else return _large;
}
enum uint alignment = min(SmallAllocator.alignment,
LargeAllocator.alignment);
private template Impl()
{
size_t goodAllocSize(size_t s)
{
return s <= threshold
? _small.goodAllocSize(s)
: _large.goodAllocSize(s);
}
void[] allocate(size_t s)
{
return s <= threshold ? _small.allocate(s) : _large.allocate(s);
}
static if (hasMember!(SmallAllocator, "alignedAllocate")
&& hasMember!(LargeAllocator, "alignedAllocate"))
void[] alignedAllocate(size_t s, uint a)
{
return s <= threshold
? _small.alignedAllocate(s, a)
: _large.alignedAllocate(s, a);
}
static if (hasMember!(SmallAllocator, "expand")
|| hasMember!(LargeAllocator, "expand"))
bool expand(ref void[] b, size_t delta)
{
if (!delta) return true;
if (b.length + delta <= threshold)
{
// Old and new allocations handled by _small
static if (hasMember!(SmallAllocator, "expand"))
return _small.expand(b, delta);
else
return false;
}
if (b.length > threshold)
{
// Old and new allocations handled by _large
static if (hasMember!(LargeAllocator, "expand"))
return _large.expand(b, delta);
else
return false;
}
// Oops, cross-allocator transgression
return false;
}
static if (hasMember!(SmallAllocator, "reallocate")
|| hasMember!(LargeAllocator, "reallocate"))
bool reallocate(ref void[] b, size_t s)
{
static if (hasMember!(SmallAllocator, "reallocate"))
if (b.length <= threshold && s <= threshold)
{
// Old and new allocations handled by _small
return _small.reallocate(b, s);
}
static if (hasMember!(LargeAllocator, "reallocate"))
if (b.length > threshold && s > threshold)
{
// Old and new allocations handled by _large
return _large.reallocate(b, s);
}
// Cross-allocator transgression
return .reallocate(this, b, s);
}
static if (hasMember!(SmallAllocator, "alignedReallocate")
|| hasMember!(LargeAllocator, "alignedReallocate"))
bool reallocate(ref void[] b, size_t s)
{
static if (hasMember!(SmallAllocator, "alignedReallocate"))
if (b.length <= threshold && s <= threshold)
{
// Old and new allocations handled by _small
return _small.alignedReallocate(b, s);
}
static if (hasMember!(LargeAllocator, "alignedReallocate"))
if (b.length > threshold && s > threshold)
{
// Old and new allocations handled by _large
return _large.alignedReallocate(b, s);
}
// Cross-allocator transgression
return .alignedReallocate(this, b, s);
}
static if (hasMember!(SmallAllocator, "owns")
&& hasMember!(LargeAllocator, "owns"))
Ternary owns(void[] b)
{
return Ternary(b.length <= threshold
? _small.owns(b) : _large.owns(b));
}
static if (hasMember!(SmallAllocator, "deallocate")
&& hasMember!(LargeAllocator, "deallocate"))
bool deallocate(void[] data)
{
return data.length <= threshold
? _small.deallocate(data)
: _large.deallocate(data);
}
static if (hasMember!(SmallAllocator, "deallocateAll")
&& hasMember!(LargeAllocator, "deallocateAll"))
bool deallocateAll()
{
// Use & insted of && to evaluate both
return _small.deallocateAll() & _large.deallocateAll();
}
static if (hasMember!(SmallAllocator, "empty")
&& hasMember!(LargeAllocator, "empty"))
Ternary empty()
{
return _small.empty && _large.empty;
}
static if (hasMember!(SmallAllocator, "resolveInternalPointer")
&& hasMember!(LargeAllocator, "resolveInternalPointer"))
Ternary resolveInternalPointer(const void* p, ref void[] result)
{
Ternary r = _small.resolveInternalPointer(p, result);
return r == Ternary.no ? _large.resolveInternalPointer(p, result) : r;
}
}
private enum sharedMethods =
!stateSize!SmallAllocator
&& !stateSize!LargeAllocator
&& is(typeof(SmallAllocator.instance) == shared)
&& is(typeof(LargeAllocator.instance) == shared);
static if (sharedMethods)
{
static shared Segregator instance;
shared { mixin Impl!(); }
}
else
{
static if (!stateSize!SmallAllocator && !stateSize!LargeAllocator)
static __gshared Segregator instance;
mixin Impl!();
}
}
///
@system unittest
{
import stdx.allocator.building_blocks.free_list : FreeList;
import stdx.allocator.gc_allocator : GCAllocator;
import stdx.allocator.mallocator : Mallocator;
alias A =
Segregator!(
1024 * 4,
Segregator!(
128, FreeList!(Mallocator, 0, 128),
GCAllocator),
Segregator!(
1024 * 1024, Mallocator,
GCAllocator)
);
A a;
auto b = a.allocate(200);
assert(b.length == 200);
a.deallocate(b);
}
/**
A $(D Segregator) with more than three arguments expands to a composition of
elemental $(D Segregator)s, as illustrated by the following example:
----
alias A =
Segregator!(
n1, A1,
n2, A2,
n3, A3,
A4
);
----
With this definition, allocation requests for $(D n1) bytes or less are directed
to $(D A1); requests between $(D n1 + 1) and $(D n2) bytes (inclusive) are
directed to $(D A2); requests between $(D n2 + 1) and $(D n3) bytes (inclusive)
are directed to $(D A3); and requests for more than $(D n3) bytes are directed
to $(D A4). If some particular range should not be handled, $(D NullAllocator)
may be used appropriately.
*/
template Segregator(Args...)
if (Args.length > 3)
{
// Binary search
private enum cutPoint = ((Args.length - 2) / 4) * 2;
static if (cutPoint >= 2)
{
alias Segregator = .Segregator!(
Args[cutPoint],
.Segregator!(Args[0 .. cutPoint], Args[cutPoint + 1]),
.Segregator!(Args[cutPoint + 2 .. $])
);
}
else
{
// Favor small sizes
alias Segregator = .Segregator!(
Args[0],
Args[1],
.Segregator!(Args[2 .. $])
);
}
}
///
@system unittest
{
import stdx.allocator.building_blocks.free_list : FreeList;
import stdx.allocator.gc_allocator : GCAllocator;
import stdx.allocator.mallocator : Mallocator;
alias A =
Segregator!(
128, FreeList!(Mallocator, 0, 128),
1024 * 4, GCAllocator,
1024 * 1024, Mallocator,
GCAllocator
);
A a;
auto b = a.allocate(201);
assert(b.length == 201);
a.deallocate(b);
}
|