std.experimental.allocator
High-level interface for allocators. Implements bundled allocation/creation and destruction/deallocation of data including struct
s and class
es, and also array primitives related to allocation. This module is the entry point for both making use of allocators and for their documentation.
Category | Functions |
---|---|
Make | make makeArray makeMultidimensionalArray |
Dispose | dispose disposeMultidimensionalArray |
Modify | expandArray shrinkArray |
Global | processAllocator theAllocator |
Class interface | allocatorObject CAllocatorImpl IAllocator |
- Synopsis
// Allocate an int, initialize it with 42 int* p = theAllocator.make!int(42); assert(*p == 42); // Destroy and deallocate it theAllocator.dispose(p); // Allocate using the global process allocator p = processAllocator.make!int(100); assert(*p == 100); // Destroy and deallocate processAllocator.dispose(p); // Create an array of 50 doubles initialized to -1.0 double[] arr = theAllocator.makeArray!double(50, -1.0); // Append two zeros to it theAllocator.expandArray(arr, 2, 0.0); // On second thought, take that back theAllocator.shrinkArray(arr, 2); // Destroy and deallocate theAllocator.dispose(arr);
Layered Structure
D's allocators have a layered structure in both implementation and documentation:- A high-level, dynamically-typed layer (described further down in this module). It consists of an interface called
IAllocator
, which concrete allocators need to implement. The interface primitives themselves are oblivious to the type of the objects being allocated; they only deal invoid[]
, by necessity of the interface being dynamic (as opposed to type-parameterized). Each thread has a current allocator it uses by default, which is a thread-local variabletheAllocator
of typeIAllocator
. The process has a global allocator calledprocessAllocator
, also of typeIAllocator
. When a new thread is created,processAllocator
is copied intotheAllocator
. An application can change the objects to which these references point. By default, at application startup,processAllocator
refers to an object that uses D's garbage collected heap. This layer also include high-level functions such asmake
anddispose
that comfortably allocate/create and respectively destroy/deallocate objects. This layer is all needed for most casual uses of allocation primitives. - A mid-level, statically-typed layer for assembling several allocators into one. It uses properties of the type of the objects being created to route allocation requests to possibly specialized allocators. This layer is relatively thin and implemented and documented in the
std.experimental.allocator.typed
module. It allows an interested user to e.g. use different allocators for arrays versus fixed-sized objects, to the end of better overall performance. - A low-level collection of highly generic heap building blocks
— Lego-like pieces that can be used to assemble application-specific allocators. The real allocation smarts are occurring at this level. This layer is of interest to advanced applications that want to configure their own allocators. A good illustration of typical uses of these building blocks is modulestd.experimental.allocator.showcase
which defines a collection of frequently- used preassembled allocator objects. The implementation and documentation entry point isstd.experimental.allocator.building_blocks
. By design, the primitives of the static interface have the same signatures as theIAllocator
primitives but are for the most part optional and driven by static introspection. The parameterized classCAllocatorImpl
offers an immediate and useful means to package a static low-level allocator into an implementation ofIAllocator
. - Core allocator objects that interface with D's garbage collected heap (
std.experimental.allocator.gc_allocator
), the Cmalloc
family (std.experimental.allocator.mallocator
), and the OS (std.experimental.allocator.mmap_allocator
). Most custom allocators would ultimately obtain memory from one of these core allocators.
Idiomatic Use of std.experimental.allocator
As of this time, std.experimental.allocator
is not integrated with D's built-in operators that allocate memory, such as new
, array literals, or array concatenation operators. That means std.experimental.allocator
is opt-inmake
, dispose
, and the array-specific functions makeArray
, expandArray
, and shrinkArray
. These use by default D's garbage collected heap, but open the application to better configuration options. These primitives work either with theAllocator
but also with any allocator obtained by combining heap building blocks. For example: void fun(size_t n) { // Use the current allocator int[] a1 = theAllocator.makeArray!int(n); scope(exit) theAllocator.dispose(a1); ... }To experiment with alternative allocators, set
theAllocator
for the current thread. For example, consider an application that allocates many 8-byte objects. These are not well supported by the default allocator, so a free list allocator would be recommended. To install one in main
, the application would use: void main() { import std.experimental.allocator.building_blocks.free_list : FreeList; theAllocator = allocatorObject(FreeList!8()); ... }
Saving the IAllocator
Reference For Later Use
As with any global resource, setting theAllocator
and processAllocator
should not be done often and casually. In particular, allocating memory with one allocator and deallocating with another causes undefined behavior. Typically, these variables are set during application initialization phase and last through the application. To avoid this, long-lived objects that need to perform allocations, reallocations, and deallocations relatively often may want to store a reference to the allocator object they use throughout their lifetime. Then, instead of using theAllocator
for internal allocation-related tasks, they'd use the internally held reference. For example, consider a user-defined hash table: struct HashTable { private IAllocator allocator; this(size_t buckets, IAllocator allocator = theAllocator) { this.allocator = allocator; ... } // Getter and setter IAllocator allocator() { return allocator; } void allocator(IAllocator a) { assert(empty); allocator = a; } }Following initialization, the
HashTable
object would consistently use its allocator
object for acquiring memory. Furthermore, setting HashTable.allocator
to point to a different allocator should be legal but only if the object is empty; otherwise, the object wouldn't be able to deallocate its existing state. Using Allocators without IAllocator
Allocators assembled from the heap building blocks don't need to go through IAllocator
to be usable. They have the same primitives as IAllocator
and they work with make
, makeArray
, dispose
etc. So it suffice to create allocator objects wherever fit and use them appropriately: void fun(size_t n) { // Use a stack-installed allocator for up to 64KB StackFront!65536 myAllocator; int[] a2 = myAllocator.makeArray!int(n); scope(exit) myAllocator.dispose(a2); ... }In this case,
myAllocator
does not obey the IAllocator
interface, but implements its primitives so it can work with makeArray
by means of duck typing. One important thing to note about this setup is that statically-typed assembled allocators are almost always faster than allocators that go through IAllocator
. An important rule of thumb is: "assemble allocator first, adapt to IAllocator
after". A good allocator implements intricate logic by means of template assembly, and gets wrapped with IAllocator
(usually by means of allocatorObject
) only once, at client level. - License:
- Boost License 1.0.
- Authors:
- Andrei Alexandrescu
- Source
- std/experimental/allocator
- interface IAllocator;
-
Dynamic allocator interface. Code that defines allocators ultimately implements this interface. This should be used wherever a uniform type is required for encapsulating various allocator implementations.
Composition of allocators is not recommended at this level due to inflexibility of dynamic interfaces and inefficiencies caused by cascaded multiple calls. Instead, compose allocators using the static interface defined in
std.experimental.allocator.building_blocks
, then adapt the composed allocator toIAllocator
(possibly by usingCAllocatorImpl
below).
Methods returningTernary
returnTernary.yes
upon success,Ternary.no
upon failure, andTernary.unknown
if the primitive is not implemented by the allocator instance.- abstract nothrow @property uint alignment();
-
Returns the alignment offered.
- abstract nothrow size_t goodAllocSize(size_t s);
-
Returns the good allocation size that guarantees zero internal fragmentation.
- abstract nothrow void[] allocate(size_t, TypeInfo ti = null);
-
Allocates
n
bytes of memory. - abstract nothrow void[] alignedAllocate(size_t n, uint a);
-
Allocates
n
bytes of memory with specified alignmenta
. Implementations that do not support this primitive should always returnnull
. - abstract nothrow void[] allocateAll();
-
Allocates and returns all memory available to this allocator. Implementations that do not support this primitive should always return
null
. - abstract nothrow bool expand(ref void[], size_t);
-
Expands a memory block in place and returns
true
if successful. Implementations that don't support this primitive should always returnfalse
. - abstract nothrow bool reallocate(ref void[], size_t);
-
Reallocates a memory block.
- abstract nothrow bool alignedReallocate(ref void[] b, size_t size, uint alignment);
-
Reallocates a memory block with specified alignment.
- abstract nothrow Ternary owns(void[] b);
-
Returns
Ternary.yes
if the allocator ownsb
,Ternary.no
if the allocator doesn't ownb
, andTernary.unknown
if ownership cannot be determined. Implementations that don't support this primitive should always returnTernary.unknown
. - abstract nothrow Ternary resolveInternalPointer(const void* p, ref void[] result);
-
Resolves an internal pointer to the full block allocated. Implementations that don't support this primitive should always return
Ternary.unknown
. - abstract nothrow bool deallocate(void[] b);
-
Deallocates a memory block. Implementations that don't support this primitive should always return
false
. A simple way to check that an allocator supports deallocation is to calldeallocate(null)
. - abstract nothrow bool deallocateAll();
-
Deallocates all memory. Implementations that don't support this primitive should always return
false
. - abstract nothrow Ternary empty();
-
Returns
Ternary.yes
if no memory is currently allocated from this allocator,Ternary.no
if some allocations are currently active, orTernary.unknown
if not supported. - abstract pure nothrow @nogc @safe void incRef();
-
Increases the reference count of the concrete class that implements this interface.
For stateless allocators, this does nothing.
- abstract pure nothrow @nogc @safe bool decRef();
-
Decreases the reference count of the concrete class that implements this interface. When the reference count is
0
, the object self-destructs.- Returns:
-
true
if the reference count is greater than0
andfalse
when it hits0
. For stateless allocators, it always returnstrue
.
- struct RCIAllocator;
-
A reference counted struct that wraps the dynamic allocator interface. This should be used wherever a uniform type is required for encapsulating various allocator implementations.
Code that defines allocators ultimately implements the
IAllocator
interface, possibly by usingCAllocatorImpl
below, and then build aRCIAllocator
out of this.
Composition of allocators is not recommended at this level due to inflexibility of dynamic interfaces and inefficiencies caused by cascaded multiple calls. Instead, compose allocators using the static interface defined instd.experimental.allocator.building_blocks
, then adapt the composed allocator toRCIAllocator
(possibly by usingallocatorObject
below). -
Dynamic shared allocator interface. Code that defines allocators shareable across threads ultimately implements this interface. This should be used wherever a uniform type is required for encapsulating various allocator implementations.
Composition of allocators is not recommended at this level due to inflexibility of dynamic interfaces and inefficiencies caused by cascaded multiple calls. Instead, compose allocators using the static interface defined in
std.experimental.allocator.building_blocks
, then adapt the composed allocator toISharedAllocator
(possibly by usingCSharedAllocatorImpl
below).
Methods returningTernary
returnTernary.yes
upon success,Ternary.no
upon failure, andTernary.unknown
if the primitive is not implemented by the allocator instance.-
Returns the alignment offered.
-
Returns the good allocation size that guarantees zero internal fragmentation.
-
Allocates
n
bytes of memory. -
Allocates
n
bytes of memory with specified alignmenta
. Implementations that do not support this primitive should always returnnull
. -
Allocates and returns all memory available to this allocator. Implementations that do not support this primitive should always return
null
. -
Expands a memory block in place and returns
true
if successful. Implementations that don't support this primitive should always returnfalse
. -
Reallocates a memory block.
-
Reallocates a memory block with specified alignment.
-
Returns
Ternary.yes
if the allocator ownsb
,Ternary.no
if the allocator doesn't ownb
, andTernary.unknown
if ownership cannot be determined. Implementations that don't support this primitive should always returnTernary.unknown
. -
Resolves an internal pointer to the full block allocated. Implementations that don't support this primitive should always return
Ternary.unknown
. -
Deallocates a memory block. Implementations that don't support this primitive should always return
false
. A simple way to check that an allocator supports deallocation is to calldeallocate(null)
. -
Deallocates all memory. Implementations that don't support this primitive should always return
false
. -
Returns
Ternary.yes
if no memory is currently allocated from this allocator,Ternary.no
if some allocations are currently active, orTernary.unknown
if not supported. -
Increases the reference count of the concrete class that implements this interface.
For stateless allocators, this does nothing.
-
Decreases the reference count of the concrete class that implements this interface. When the reference count is
0
, the object self-destructs.For stateless allocators, this does nothing.
- Returns:
-
true
if the reference count is greater than0
andfalse
when it hits0
. For stateless allocators, it always returnstrue
.
-
-
A reference counted struct that wraps the dynamic shared allocator interface. This should be used wherever a uniform type is required for encapsulating various allocator implementations.
Code that defines allocators shareable across threads ultimately implements the
ISharedAllocator
interface, possibly by usingCSharedAllocatorImpl
below, and then build aRCISharedAllocator
out of this.
Composition of allocators is not recommended at this level due to inflexibility of dynamic interfaces and inefficiencies caused by cascaded multiple calls. Instead, compose allocators using the static interface defined instd.experimental.allocator.building_blocks
, then adapt the composed allocator toRCISharedAllocator
(possibly by usingsharedAllocatorObject
below). - nothrow @nogc @property ref @safe RCIAllocator theAllocator();
nothrow @nogc @property @system void theAllocator(RCIAllocator a); -
Gets/sets the allocator for the current thread. This is the default allocator that should be used for allocating thread-local memory. For allocating memory to be shared across threads, use
processAllocator
(below). By default,theAllocator
ultimately fetches memory fromprocessAllocator
, which in turn uses the garbage collected heap.- Examples:
-
// Install a new allocator that is faster for 128-byte allocations. import std.experimental.allocator.building_blocks.free_list : FreeList; import std.experimental.allocator.gc_allocator : GCAllocator; auto oldAllocator = theAllocator; scope(exit) theAllocator = oldAllocator; theAllocator = allocatorObject(FreeList!(GCAllocator, 128)()); // Use the now changed allocator to allocate an array const ubyte[] arr = theAllocator.makeArray!ubyte(128); assert(arr.ptr); //...
- nothrow @nogc @property ref @trusted RCISharedAllocator processAllocator();
nothrow @nogc @property @system void processAllocator(ref RCISharedAllocator a); -
Gets/sets the allocator for the current process. This allocator must be used for allocating memory shared across threads. Objects created using this allocator can be cast to
shared
. - auto make(T, Allocator, A...)(auto ref Allocator alloc, auto ref A args);
-
Dynamically allocates (using
alloc
) and then creates in the memory allocated an object of typeT
, usingargs
(if any) for its initialization. Initialization occurs in the memory allocated and is otherwise semantically the same asT(args)
. (Note that usingalloc.make!(T[])
creates a pointer to an (empty) array ofT
s, not an array. To use an allocator to allocate and initialize an array, usealloc.makeArray!T
described below.)- Parameters:
T Type of the object being created. Allocator alloc
The allocator used for getting the needed memory. It may be an object implementing the static interface for allocators, or an IAllocator
reference.A args
Optional arguments used for initializing the created object. If not present, the object is default constructed.
- Returns:
- If
T
is a class type, returns a reference to the createdT
object. Otherwise, returns aT*
pointing to the created object. In all cases, returnsnull
if allocation failed.
- Throws:
- If
T
's constructor throws, deallocates the allocated memory and propagates the exception.
- Examples:
-
// Dynamically allocate one integer const int* p1 = theAllocator.make!int; // It's implicitly initialized with its .init value writeln(*p1); // 0 // Dynamically allocate one double, initialize to 42.5 const double* p2 = theAllocator.make!double(42.5); writeln(*p2); // 42.5 // Dynamically allocate a struct static struct Point { int x, y, z; } // Use the generated constructor taking field values in order const Point* p = theAllocator.make!Point(1, 2); assert(p.x == 1 && p.y == 2 && p.z == 0); // Dynamically allocate a class object static class Customer { uint id = uint.max; this() {} this(uint id) { this.id = id; } // ... } Customer cust = theAllocator.make!Customer; assert(cust.id == uint.max); // default initialized cust = theAllocator.make!Customer(42); writeln(cust.id); // 42 // explicit passing of outer pointer static class Outer { int x = 3; class Inner { auto getX() { return x; } } } auto outer = theAllocator.make!Outer(); auto inner = theAllocator.make!(Outer.Inner)(outer); writeln(outer.x); // inner.getX
- T[] makeArray(T, Allocator)(auto ref Allocator alloc, size_t length);
T[] makeArray(T, Allocator)(auto ref Allocator alloc, size_t length, T init);
Unqual!(ElementEncodingType!R)[] makeArray(Allocator, R)(auto ref Allocator alloc, R range)
Constraints: if (isInputRange!R && !isInfinite!R);
T[] makeArray(T, Allocator, R)(auto ref Allocator alloc, R range)
Constraints: if (isInputRange!R && !isInfinite!R); -
Create an array of
T
withlength
elements usingalloc
. The array is either default-initialized, filled with copies ofinit
, or initialized with values fetched fromrange
.- Parameters:
T element type of the array being created Allocator alloc
the allocator used for getting memory size_t length
length of the newly created array T init
element used for filling the array R range
range used for initializing the array elements
- Returns:
- The newly-created array, or
null
if eitherlength
was0
or allocation failed.
- Throws:
- The first two overloads throw only if
alloc
's primitives do. The overloads that involve copy initialization deallocate memory and propagate the exception if the copy operation throws.
- Examples:
-
import std.algorithm.comparison : equal; static void test(T)() { T[] a = theAllocator.makeArray!T(2); assert(a.equal([0, 0])); a = theAllocator.makeArray!T(3, 42); assert(a.equal([42, 42, 42])); import std.range : only; a = theAllocator.makeArray!T(only(42, 43, 44)); assert(a.equal([42, 43, 44])); } test!int(); test!(shared int)(); test!(const int)(); test!(immutable int)();
- bool expandArray(T, Allocator)(auto ref Allocator alloc, ref T[] array, size_t delta);
bool expandArray(T, Allocator)(auto ref Allocator alloc, ref T[] array, size_t delta, auto ref T init);
bool expandArray(T, Allocator, R)(auto ref Allocator alloc, ref T[] array, R range)
Constraints: if (isInputRange!R); -
Grows
array
by appendingdelta
more elements. The needed memory is allocated usingalloc
. The extra elements added are either default- initialized, filled with copies ofinit
, or initialized with values fetched fromrange
.- Parameters:
T element type of the array being created Allocator alloc
the allocator used for getting memory T[] array
a reference to the array being grown size_t delta
number of elements to add (upon success the new length of array
isarray.length + delta
)T init
element used for filling the array R range
range used for initializing the array elements
- Returns:
-
true
upon success,false
if memory could not be allocated. In the latter casearray
is left unaffected.
- Throws:
- The first two overloads throw only if
alloc
's primitives do. The overloads that involve copy initialization deallocate memory and propagate the exception if the copy operation throws.
- Examples:
-
auto arr = theAllocator.makeArray!int([1, 2, 3]); assert(theAllocator.expandArray(arr, 2)); writeln(arr); // [1, 2, 3, 0, 0] import std.range : only; assert(theAllocator.expandArray(arr, only(4, 5))); writeln(arr); // [1, 2, 3, 0, 0, 4, 5]
- bool shrinkArray(T, Allocator)(auto ref Allocator alloc, ref T[] array, size_t delta);
-
Shrinks an array by
delta
elements.If
array.length < delta
, does nothing and returnsfalse
. Otherwise, destroys the lastarray.length - delta
elements in the array and then reallocates the array's buffer. If reallocation fails, fills the array with default-initialized data.- Parameters:
T element type of the array being created Allocator alloc
the allocator used for getting memory T[] array
a reference to the array being shrunk size_t delta
number of elements to remove (upon success the new length of array
isarray.length - delta
)
- Returns:
-
true
upon success,false
if memory could not be reallocated. In the latter case, the slicearray[$ - delta .. $]
is left with default-initialized elements.
- Throws:
- The first two overloads throw only if
alloc
's primitives do. The overloads that involve copy initialization deallocate memory and propagate the exception if the copy operation throws.
- Examples:
-
int[] a = theAllocator.makeArray!int(100, 42); writeln(a.length); // 100 assert(theAllocator.shrinkArray(a, 98)); writeln(a.length); // 2 writeln(a); // [42, 42]
- void dispose(A, T)(auto ref A alloc, auto ref T* p);
void dispose(A, T)(auto ref A alloc, auto ref T p)
Constraints: if (is(T == class) || is(T == interface));
void dispose(A, T)(auto ref A alloc, auto ref T[] array); -
Destroys and then deallocates (using
alloc
) the object pointed to by a pointer, the class object referred to by aclass
orinterface
reference, or an entire array. It is assumed the respective entities had been allocated with the same allocator. - auto makeMultidimensionalArray(T, Allocator, size_t N)(auto ref Allocator alloc, size_t[N] lengths...);
-
Allocates a multidimensional array of elements of type T.
- Parameters:
N number of dimensions T element type of an element of the multidimensional arrat Allocator alloc
the allocator used for getting memory size_t[N] lengths
static array containing the size of each dimension
- Returns:
- An N-dimensional array with individual elements of type T.
- Examples:
-
import std.experimental.allocator.mallocator : Mallocator; auto mArray = Mallocator.instance.makeMultidimensionalArray!int(2, 3, 6); // deallocate when exiting scope scope(exit) { Mallocator.instance.disposeMultidimensionalArray(mArray); } writeln(mArray.length); // 2 foreach (lvl2Array; mArray) { writeln(lvl2Array.length); // 3 foreach (lvl3Array; lvl2Array) writeln(lvl3Array.length); // 6 }
- void disposeMultidimensionalArray(T, Allocator)(auto ref Allocator alloc, auto ref T[] array);
-
Destroys and then deallocates a multidimensional array, assuming it was created with makeMultidimensionalArray and the same allocator was used.
- Parameters:
T element type of an element of the multidimensional array Allocator alloc
the allocator used for getting memory T[] array
the multidimensional array that is to be deallocated
- Examples:
-
struct TestAllocator { import std.experimental.allocator.common : platformAlignment; import std.experimental.allocator.mallocator : Mallocator; alias allocator = Mallocator.instance; private static struct ByteRange { void* ptr; size_t length; } private ByteRange[] _allocations; enum uint alignment = platformAlignment; void[] allocate(size_t numBytes) { auto ret = allocator.allocate(numBytes); _allocations ~= ByteRange(ret.ptr, ret.length); return ret; } bool deallocate(void[] bytes) { import std.algorithm.mutation : remove; import std.algorithm.searching : canFind; bool pred(ByteRange other) { return other.ptr == bytes.ptr && other.length == bytes.length; } assert(_allocations.canFind!pred); _allocations = _allocations.remove!pred; return allocator.deallocate(bytes); } ~this() { assert(!_allocations.length); } } TestAllocator allocator; auto mArray = allocator.makeMultidimensionalArray!int(2, 3, 5, 6, 7, 2); allocator.disposeMultidimensionalArray(mArray);
- RCIAllocator allocatorObject(A)(auto ref A a)
Constraints: if (!isPointer!A);
RCIAllocator allocatorObject(A)(A* pa); -
Returns a dynamically-typed
CAllocator
built around a given statically- typed allocatora
of typeA
. Passing a pointer to the allocator creates a dynamic allocator around the allocator pointed to by the pointer, without attempting to copy or move it. Passing the allocator by value or reference behaves as follows.- If
A
has no state, the resulting object is allocated in static shared storage. - If
A
has state, the result willstd.algorithm.mutation.move
the supplied allocatorA a
within. The result itself is allocated in its own statically-typed allocator.
- Examples:
-
import std.experimental.allocator.mallocator : Mallocator; RCIAllocator a = allocatorObject(Mallocator.instance); auto b = a.allocate(100); writeln(b.length); // 100 assert(a.deallocate(b)); // The in-situ region must be used by pointer import std.experimental.allocator.building_blocks.region : InSituRegion; auto r = InSituRegion!1024(); a = allocatorObject(&r); b = a.allocate(200); writeln(b.length); // 200 // In-situ regions can deallocate the last allocation assert(a.deallocate(b));
- If
-
Returns a dynamically-typed
CSharedAllocator
built around a given statically- typed allocatora
of typeA
. Passing a pointer to the allocator creates a dynamic allocator around the allocator pointed to by the pointer, without attempting to copy or move it. Passing the allocator by value or reference behaves as follows.- If
A
has no state, the resulting object is allocated in static shared storage. - If
A
has state and is copyable, the result willstd.algorithm.mutation.move
the supplied allocatorA a
within. The result itself is allocated in its own statically-typed allocator. - If
A
has state and is not copyable, the result will move the passed-in argument into the result. The result itself is allocated in its own statically-typed allocator.
- If
- class CAllocatorImpl(Allocator, Flag!"indirect" indirect = No.indirect): IAllocator;
-
Implementation of
IAllocator
usingAllocator
. This adapts a statically-built allocator type toIAllocator
that is directly usable by non-templated code.Usually
CAllocatorImpl
is used indirectly by callingtheAllocator
.- pure @nogc ref @safe Allocator impl();
-
The implementation is available as a public member.
- pure @nogc @safe this(Allocator* pa);
-
The implementation is available as a public member.
- @property uint alignment();
-
Returns
impl.alignment
. - size_t goodAllocSize(size_t s);
-
Returns
impl.goodAllocSize(s)
. - void[] allocate(size_t s, TypeInfo ti = null);
-
Returns
impl.allocate(s)
. - void[] alignedAllocate(size_t s, uint a);
-
If
impl.alignedAllocate
exists, calls it and returns the result. Otherwise, always returnsnull
. - Ternary owns(void[] b);
-
If
Allocator
implementsowns
, forwards to it. Otherwise, returnsTernary.unknown
. - bool expand(ref void[] b, size_t s);
-
Returns
impl.expand(b, s)
if defined,false
otherwise. - bool reallocate(ref void[] b, size_t s);
-
Returns
impl.reallocate(b, s)
. - bool alignedReallocate(ref void[] b, size_t s, uint a);
-
Forwards to
impl.alignedReallocate
if defined,false
otherwise. - bool deallocate(void[] b);
-
If
impl.deallocate
is not defined, returnsfalse
. Otherwise it forwards the call. - bool deallocateAll();
-
Calls
impl.deallocateAll()
and returns the result if defined, otherwise returnsfalse
. - Ternary empty();
-
Forwards to
impl.empty()
if defined, otherwise returnsTernary.unknown
. - void[] allocateAll();
-
Returns
impl.allocateAll()
if present,null
otherwise.
-
Implementation of
ISharedAllocator
usingAllocator
. This adapts a statically-built, shareable across threads, allocator type toISharedAllocator
that is directly usable by non-templated code.Usually
CSharedAllocatorImpl
is used indirectly by callingprocessAllocator
.-
The implementation is available as a public member.
-
The implementation is available as a public member.
-
Returns
impl.alignment
. -
Returns
impl.goodAllocSize(s)
. -
Returns
impl.allocate(s)
. -
If
impl.alignedAllocate
exists, calls it and returns the result. Otherwise, always returnsnull
. -
If
Allocator
implementsowns
, forwards to it. Otherwise, returnsTernary.unknown
. -
Returns
impl.expand(b, s)
if defined,false
otherwise. -
Returns
impl.reallocate(b, s)
. -
Forwards to
impl.alignedReallocate
if defined,false
otherwise. -
If
impl.deallocate
is not defined, returnsfalse
. Otherwise it forwards the call. -
Calls
impl.deallocateAll()
and returns the result if defined, otherwise returnsfalse
. -
Forwards to
impl.empty()
if defined, otherwise returnsTernary.unknown
. -
Returns
impl.allocateAll()
if present,null
otherwise.
-
© 1999–2021 The D Language Foundation
Licensed under the Boost License 1.0.
https://dlang.org/phobos/std_experimental_allocator.html