This allocator sits on top of ParentAllocator
and quantizes allocation sizes, usually from arbitrary positive numbers to a small set of round numbers (e.g. powers of two, page sizes etc). This technique is commonly used to:
Quantizer
. These advantages are present even if ParentAllocator
does not support reallocation at all.FreeList
and FreeTree
. Rounding allocation requests up makes for smaller free lists/trees at the cost of slack memory (internal fragmentation).allocateAll
, owns
, deallocateAll
, empty
. roundingFunction
must satisfy three constraints. These are not enforced (save for the use of assert
) for the sake of efficiency. roundingFunction(n) >= n
for all n
of type size_t
;roundingFunction
must be monotonically increasing, i.e. roundingFunction(n1) <= roundingFunction(n2)
for all n1 < n2
;roundingFunction
must be nothrow
, @safe
, @nogc
and pure
, i.e. always return the same value for a given n
.import std.experimental.allocator.building_blocks.free_tree : FreeTree; import std.experimental.allocator.gc_allocator : GCAllocator; size_t roundUpToMultipleOf(size_t s, uint base) { auto rem = s % base; return rem ? s + base - rem : s; } // Quantize small allocations to a multiple of cache line, large ones to a // multiple of page size alias MyAlloc = Quantizer!( FreeTree!GCAllocator, n => roundUpToMultipleOf(n, n <= 16_384 ? 64 : 4096)); MyAlloc alloc; const buf = alloc.allocate(256); assert(buf.ptr);
The parent allocator. Depending on whether ParentAllocator
holds state or not, this is a member variable or an alias for ParentAllocator.instance
.
Returns roundingFunction(n)
.
Alignment is identical to that of the parent.
Gets a larger buffer buf
by calling parent.allocate(goodAllocSize(n))
. If buf
is null
, returns null
. Otherwise, returns buf[0 .. n]
.
Defined only if parent.alignedAllocate
exists and works similarly to allocate
by forwarding to parent.alignedAllocate(goodAllocSize(n), a)
.
First checks whether there's enough slack memory preallocated for b
by evaluating b.length + delta <= goodAllocSize(b.length)
. If that's the case, expands b
in place. Otherwise, attempts to use parent.expand
appropriately if present.
Expands or shrinks allocated block to an allocated size of goodAllocSize(s)
. Expansion occurs in place under the conditions required by expand
. Shrinking occurs in place if goodAllocSize(b.length) == goodAllocSize(s)
.
Defined only if ParentAllocator.alignedAllocate
exists. Expansion occurs in place under the conditions required by expand
. Shrinking occurs in place if goodAllocSize(b.length) == goodAllocSize(s)
.
Defined if ParentAllocator.deallocate
exists and forwards to parent.deallocate(b.ptr[0 .. goodAllocSize(b.length)])
.
© 1999–2019 The D Language Foundation
Licensed under the Boost License 1.0.
https://dlang.org/phobos/std_experimental_allocator_building_blocks_quantizer.html