std.experimental.allocator.typed
This module defines TypedAllocator
, a statically-typed allocator that aggregates multiple untyped allocators and uses them depending on the static properties of the types allocated. For example, distinct allocators may be used for thread-local vs. thread-shared data, or for fixed-size data (struct
, class
objects) vs. resizable data (arrays).
- enum AllocFlag: uint;
-
Allocation-related flags dictated by type characteristics.
TypedAllocator
deduces these flags from the type being allocated and uses the appropriate allocator accordingly.- fixedSize
-
Fixed-size allocation (unlikely to get reallocated later). Examples:
int
,double
, anystruct
orclass
type. By default it is assumed that the allocation is variable-size, i.e. susceptible to later reallocation (for example all array types). This flag is advisory, i.e. in-place resizing may be attempted forfixedSize
allocations and may succeed. The flag is just a hint to the compiler it may use allocation strategies that work well with objects of fixed size. - hasNoIndirections
-
The type being allocated embeds no pointers. Examples:
int
,int[]
,Tuple!(int, float)
. The implicit conservative assumption is that the type has members with indirections so it needs to be scanned if garbage collected. Example of types with pointers:int*[]
,Tuple!(int, string)
. -
By default it is conservatively assumed that allocated memory may be
cast
toshared
, passed across threads, and deallocated in a different thread than the one that allocated it. If that's not the case, there are two options. First,immutableShared
means the memory is allocated forimmutable
data and will be deallocated in the same thread it was allocated in. Second,threadLocal
means the memory is not to be shared across threads at all. The two flags cannot be simultaneously present.
- struct TypedAllocator(PrimaryAllocator, Policies...);
-
TypedAllocator
acts like a chassis on which several specialized allocators can be assembled. To let the system make a choice about a particular kind of allocation, useDefault
for the respective parameters.There is a hierarchy of allocation kinds. When an allocator is implemented for a given combination of flags, it is used. Otherwise, the next down the list is chosen.
AllocFlag
combinationDescription
`AllocFlag.threadLocal | AllocFlag.hasNoIndirections | AllocFlag.fixedSize` This is the most specific allocation policy: the memory being allocated is thread local, has no indirections at all, and will not be reallocated. Examples of types fitting this description: int
,double
,Tuple!(int, long)
, but notTuple!(int, string)
, which contains an indirection.
`AllocFlag.threadLocal | AllocFlag.hasNoIndirections` As above, but may be reallocated later. Examples of types fitting this description are int[]
,double[]
,Tuple!(int, long)[]
, but notTuple!(int, string)[]
, which contains an indirection.
`AllocFlag.threadLocal` As above, but may embed indirections. Examples of types fitting this description are int*[]
,Object[]
,Tuple!(int, string)[]
.
`AllocFlag.immutableShared | AllocFlag.hasNoIndirections | AllocFlag.fixedSize` The type being allocated is immutable
and has no pointers. The thread that allocated it must also deallocate it. Example:immutable(int)
.
`AllocFlag.immutableShared | AllocFlag.hasNoIndirections` As above, but the type may be appended to in the future. Example: string
.
`AllocFlag.immutableShared` As above, but the type may embed references. Example: immutable(Object)[]
.
`AllocFlag.hasNoIndirections | AllocFlag.fixedSize` The type being allocated may be shared across threads, embeds no indirections, and has fixed size.
`AllocFlag.hasNoIndirections` The type being allocated may be shared across threads, may embed indirections, and has variable size.
`AllocFlag.fixedSize` The type being allocated may be shared across threads, may embed indirections, and has fixed size.
`0` The most conservative/general allocation: memory may be shared, deallocated in a different thread, may or may not be resized, and may embed references. - Parameters:
PrimaryAllocator The default allocator. Policies Zero or more pairs consisting of an AllocFlag
and an allocator type.
- Examples:
-
import std.experimental.allocator.gc_allocator : GCAllocator; import std.experimental.allocator.mallocator : Mallocator; import std.experimental.allocator.mmap_allocator : MmapAllocator; alias MyAllocator = TypedAllocator!(GCAllocator, AllocFlag.fixedSize | AllocFlag.threadLocal, Mallocator, AllocFlag.fixedSize | AllocFlag.threadLocal | AllocFlag.hasNoIndirections, MmapAllocator, ); MyAllocator a; auto b = &a.allocatorFor!0(); static assert(is(typeof(*b) == shared const(GCAllocator))); enum f1 = AllocFlag.fixedSize | AllocFlag.threadLocal; auto c = &a.allocatorFor!f1(); static assert(is(typeof(*c) == Mallocator)); enum f2 = AllocFlag.fixedSize | AllocFlag.threadLocal; static assert(is(typeof(a.allocatorFor!f2()) == Mallocator)); // Partial match enum f3 = AllocFlag.threadLocal; static assert(is(typeof(a.allocatorFor!f3()) == Mallocator)); int* p = a.make!int; scope(exit) a.dispose(p); int[] arr = a.makeArray!int(42); scope(exit) a.dispose(arr); assert(a.expandArray(arr, 3)); assert(a.shrinkArray(arr, 4));
- ref auto allocatorFor(uint flags)();
ref auto allocatorFor(T)(); -
Given
flags
as a combination ofAllocFlag
values, or a typeT
, returns the allocator that's a closest fit in capabilities. - uint type2flags(T)();
-
Given a type
T
, returns its allocation-related flags as a combination ofAllocFlag
values. - auto make(T, A...)(auto ref A args);
-
Dynamically allocates (using the appropriate allocator chosen with
allocatorFor!T
) 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 usingmake!(T[])
creates a pointer to an (empty) array ofT
s, not an array. To allocate and initialize an array, usemakeArray!T
described below.)- Parameters:
T Type of the object being created. 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.
- T[] makeArray(T)(size_t length);
T[] makeArray(T)(size_t length, auto ref T init);
T[] makeArray(T, R)(R range)
Constraints: if (isInputRange!R); -
Create an array of
T
withlength
elements. 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 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 the used allocator's primitives do. The overloads that involve copy initialization deallocate memory and propagate the exception if the copy operation throws.
- bool expandArray(T)(ref T[] array, size_t delta);
bool expandArray(T)(T[] array, size_t delta, auto ref T init);
bool expandArray(T, R)(ref T[] array, R range)
Constraints: if (isInputRange!R); -
Grows
array
by appendingdelta
more elements. The needed memory is allocated using the same allocator that was used for the array type. 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 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 the used allocator's primitives do. The overloads that involve copy initialization deallocate memory and propagate the exception if the copy operation throws.
- bool shrinkArray(T)(ref T[] arr, size_t delta);
-
Shrinks an array by
delta
elements usingallocatorFor!(T[])
.If
arr.length < delta
, does nothing and returnsfalse
. Otherwise, destroys the lastarr.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 T[] arr
a reference to the array being shrunk size_t delta
number of elements to remove (upon success the new length of arr
isarr.length - delta
)
- Returns:
-
true
upon success,false
if memory could not be reallocated. In the latter casearr[$ - delta .. $]
is left with default-initialized elements.
- Throws:
- The first two overloads throw only if the used allocator's primitives do. The overloads that involve copy initialization deallocate memory and propagate the exception if the copy operation throws.
- void dispose(T)(T* p);
void dispose(T)(T p)
Constraints: if (is(T == class) || is(T == interface));
void dispose(T)(T[] array); -
Destroys and then deallocates (using
allocatorFor!T
) 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.
© 1999–2021 The D Language Foundation
Licensed under the Boost License 1.0.
https://dlang.org/phobos/std_experimental_allocator_typed.html