Allocator that adds some extra data before (of type Prefix
) and/or after (of type Suffix
) any allocation made with its parent allocator. This is useful for uses where additional allocation-related information is needed, such as mutexes, reference counts, or walls for debugging memory corruption errors.
If Prefix
is not void
, Allocator
must guarantee an alignment at least as large as Prefix.alignof
.
Suffixes are slower to get at because of alignment rounding, so prefixes should be preferred. However, small prefixes blunt the alignment so if a large alignment with a small affix is needed, suffixes should be chosen.
The following methods are defined if Allocator
defines them, and forward to it: deallocateAll
, empty
, owns
.
import std.experimental.allocator.mallocator : Mallocator; // One word before and after each allocation. alias A = AffixAllocator!(Mallocator, size_t, size_t); auto b = A.instance.allocate(11); A.instance.prefix(b) = 0xCAFE_BABE; A.instance.suffix(b) = 0xDEAD_BEEF; assert(A.instance.prefix(b) == 0xCAFE_BABE && A.instance.suffix(b) == 0xDEAD_BEEF);
If Prefix
is void
, the alignment is that of the parent. Otherwise, the alignment is the same as the Prefix
's alignment.
If the parent allocator Allocator
is stateful, an instance of it is stored as a member. Otherwise, AffixAllocator
uses Allocator.instance
. In either case, the name _parent
is uniformly used for accessing the parent allocator.
If the parent allocator Allocator
is stateful, an instance of it is stored as a member. Otherwise, AffixAllocator
uses Allocator.instance
. In either case, the name _parent
is uniformly used for accessing the parent allocator.
Standard allocator methods. Each is defined if and only if the parent allocator defines the homonym method (except for goodAllocSize
, which may use the global default). Also, the methods will be shared
if the parent allocator defines them as such.
The instance
singleton is defined if and only if the parent allocator has no state and defines its own it
object.
Affix access functions offering references to the affixes of a block b
previously allocated with this allocator. b
may not be null. They are defined if and only if the corresponding affix is not void
.
The qualifiers of the affix are not always the same as the qualifiers of the argument. This is because the affixes are not part of the data itself, but instead are just associated with the data and known to the allocator. The table below documents the type of preffix(b)
and affix(b)
depending on the type of b
.
Argument Type | Return | Comments |
---|---|---|
shared(U)[] | ref shared Affix | Data is shared across threads and the affix follows suit. |
immutable(U)[] | ref shared Affix | Although the data is immutable, the allocator "knows" the underlying memory is mutable, so immutable is elided for the affix which is independent from the data itself. However, the result is shared because immutable is implicitly shareable so multiple threads may access and manipulate the affix for the same data. |
const(shared(U))[] | ref shared Affix | The data is always shareable across threads. Even if the data is const , the affix is modifiable by the same reasoning as for immutable . |
const(U)[] | ref const Affix | The input may have originated from U[] or immutable(U)[] , so it may be actually shared or not. Returning an unqualified affix may result in race conditions, whereas returning a shared affix may result in inadvertent sharing of mutable thread-local data across multiple threads. So the returned type is conservatively ref const . |
U[] | ref Affix | Unqualified data has unqualified affixes. |
b !is null
and b
must have been allocated with this allocator.
© 1999–2019 The D Language Foundation
Licensed under the Boost License 1.0.
https://dlang.org/phobos/std_experimental_allocator_building_blocks_affix_allocator.html