// Written in the D programming language./** High-level interface for allocators. Implements bundled allocation/creationand destruction/deallocation of data including `struct`s and `class`es,and also array primitives related to allocation. This module is the entry pointfor both making use of allocators and for their documentation. $(SCRIPT inhibitQuickIndex = 1;)$(BOOKTABLE,$(TR $(TH Category) $(TH Functions))$(TR $(TD Make) $(TD $(LREF make) $(LREF makeArray) $(LREF makeMultidimensionalArray)))$(TR $(TD Dispose) $(TD $(LREF dispose) $(LREF disposeMultidimensionalArray)))$(TR $(TD Modify) $(TD $(LREF expandArray) $(LREF shrinkArray)))$(TR $(TD Global) $(TD $(LREF processAllocator) $(LREF theAllocator)))$(TR $(TD Class interface) $(TD $(LREF CAllocatorImpl) $(LREF CSharedAllocatorImpl) $(LREF IAllocator) $(LREF ISharedAllocator)))$(TR $(TD Structs) $(TD $(LREF allocatorObject) $(LREF RCIAllocator) $(LREF RCISharedAllocator) $(LREF sharedAllocatorObject) $(LREF ThreadLocal)))) Synopsis:$(RUNNABLE_EXAMPLE---// Allocate an int, initialize it with 42int* p = theAllocator.make!int(42);assert(*p == 42);// Destroy and deallocate ittheAllocator.dispose(p); // Allocate using the global process allocatorp = processAllocator.make!int(100);assert(*p == 100);// Destroy and deallocateprocessAllocator.dispose(p);---)$(RUNNABLE_EXAMPLE---// Create an array of 50 doubles initialized to -1.0double[] arr = theAllocator.makeArray!double(50, -1.0);// Append two zeros to ittheAllocator.expandArray(arr, 2, 0.0);// On second thought, take that backtheAllocator.shrinkArray(arr, 2);// Destroy and deallocatetheAllocator.dispose(arr);---) $(H2 Layered Structure) D's allocators have a layered structure in both implementation and documentation: $(OL$(LI A high-level, dynamically-typed layer (described further down in thismodule). It consists of an interface called $(LREF IAllocator), which concreteallocators need to implement. The interface primitives themselves are obliviousto the type of the objects being allocated; they only deal in `void[]`, bynecessity of the interface being dynamic (as opposed to type-parameterized).Each thread has a current allocator it uses by default, which is a thread-localvariable $(LREF theAllocator) of type $(LREF IAllocator). The process has aglobal allocator called $(LREF processAllocator), also of type $(LREFIAllocator). When a new thread is created, $(LREF processAllocator) is copiedinto $(LREF theAllocator). An application can change the objects to which thesereferences point. By default, at application startup, $(LREF processAllocator)refers to an object that uses D's garbage collected heap. This layer alsoinclude high-level functions such as $(LREF make) and $(LREF dispose) thatcomfortably allocate/create and respectively destroy/deallocate objects. Thislayer is all needed for most casual uses of allocation primitives.) $(LI A mid-level, statically-typed layer for assembling several allocators intoone. It uses properties of the type of the objects being created to routeallocation requests to possibly specialized allocators. This layer is relativelythin and implemented and documented in the $(MREFstd,experimental,allocator,typed) module. It allows an interested user to e.g.use different allocators for arrays versus fixed-sized objects, to the end ofbetter overall performance.) $(LI A low-level collection of highly generic $(I heap building blocks)$(MDASH)Lego-like pieces that can be used to assemble application-specific allocators.The real allocation smarts are occurring at this level. This layer is ofinterest to advanced applications that want to configure their own allocators.A good illustration of typical uses of these building blocks is module $(MREFstd,experimental,allocator,showcase) which defines a collection of frequently-used preassembled allocator objects. The implementation and documentation entrypoint is $(MREF std,experimental,allocator,building_blocks). By design, theprimitives of the static interface have the same signatures as the $(LREFIAllocator) primitives but are for the most part optional and driven by staticintrospection. The parameterized class $(LREF CAllocatorImpl) offers animmediate and useful means to package a static low-level allocator into animplementation of $(LREF IAllocator).) $(LI Core allocator objects that interface with D's garbage collected heap($(MREF std,experimental,allocator,gc_allocator)), the C `malloc` family($(MREF std,experimental,allocator,mallocator)), and the OS ($(MREFstd,experimental,allocator,mmap_allocator)). Most custom allocators wouldultimately obtain memory from one of these core allocators.)) $(H2 Idiomatic Use of `std.experimental.allocator`) As of this time, `std.experimental.allocator` is not integrated with D'sbuilt-in operators that allocate memory, such as `new`, array literals, orarray concatenation operators. That means `std.experimental.allocator` isopt-in$(MDASH)applications need to make explicit use of it. For casual creation and disposal of dynamically-allocated objects, use $(LREFmake), $(LREF dispose), and the array-specific functions $(LREF makeArray),$(LREF expandArray), and $(LREF shrinkArray). These use by default D's garbagecollected heap, but open the application to better configuration options. Theseprimitives work either with `theAllocator` but also with any allocator obtainedby 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 $(LREF theAllocator) for thecurrent thread. For example, consider an application that allocates many 8-byteobjects. These are not well supported by the default allocator, so a$(MREF_ALTTEXT free list allocator,std,experimental,allocator,building_blocks,free_list) 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()); ...}---- $(H3 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 withone allocator and deallocating with another causes undefined behavior.Typically, these variables are set during application initialization phase andlast through the application. To avoid this, long-lived objects that need to perform allocations,reallocations, and deallocations relatively often may want to store a referenceto the allocator object they use throughout their lifetime. Then, instead ofusing `theAllocator` for internal allocation-related tasks, they'd use theinternally 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 butonly if the object is empty; otherwise, the object wouldn't be able todeallocate its existing state. $(H3 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` andthey work with $(LREF make), $(LREF makeArray), $(LREF dispose) etc. So itsuffice 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, butimplements its primitives so it can work with `makeArray` by means of ducktyping. One important thing to note about this setup is that statically-typed assembledallocators are almost always faster than allocators that go through`IAllocator`. An important rule of thumb is: "assemble allocator first, adaptto `IAllocator` after". A good allocator implements intricate logic by means oftemplate assembly, and gets wrapped with `IAllocator` (usually by means of$(LREF allocatorObject)) only once, at client level. Copyright: Andrei Alexandrescu 2013-. License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(HTTP erdani.com, Andrei Alexandrescu) Source: $(PHOBOSSRC std/experimental/allocator) */ module std.experimental.allocator; public import std.experimental.allocator.common, std.experimental.allocator.typed; // Fix https://issues.dlang.org/show_bug.cgi?id=17806// this should always be the first unittest in this module in order to ensure// that we use the `processAllocator` setter before the getter@system unittest{ import std.experimental.allocator.mallocator : Mallocator; import std.experimental.allocator.gc_allocator : GCAllocator; auto newAlloc = sharedAllocatorObject(Mallocator.instance); processAllocator = newAlloc; assert(processAllocator is newAlloc); processAllocator = sharedAllocatorObject(GCAllocator.instance);} // Example in the synopsis above@system unittest{ import std.algorithm.comparison : min, max; import std.experimental.allocator.building_blocks.allocator_list : AllocatorList; import std.experimental.allocator.building_blocks.bitmapped_block : BitmappedBlock; import std.experimental.allocator.building_blocks.bucketizer : Bucketizer; import std.experimental.allocator.building_blocks.free_list : FreeList; import std.experimental.allocator.building_blocks.segregator : Segregator; import std.experimental.allocator.gc_allocator : GCAllocator; alias FList = FreeList!(GCAllocator, 0, unbounded); alias A = Segregator!( 8, FreeList!(GCAllocator, 0, 8), 128, Bucketizer!(FList, 1, 128, 16), 256, Bucketizer!(FList, 129, 256, 32), 512, Bucketizer!(FList, 257, 512, 64), 1024, Bucketizer!(FList, 513, 1024, 128), 2048, Bucketizer!(FList, 1025, 2048, 256), 3584, Bucketizer!(FList, 2049, 3584, 512), 4072 * 1024, AllocatorList!( (n) => BitmappedBlock!(4096)( cast(ubyte[])(GCAllocator.instance.allocate( max(n, 4072 * 1024))))), GCAllocator ); A tuMalloc; auto b = tuMalloc.allocate(500); assert(b.length == 500); auto c = tuMalloc.allocate(113); assert(c.length == 113); assert(tuMalloc.expand(c, 14)); tuMalloc.deallocate(b); tuMalloc.deallocate(c);} import std.range.primitives;import std.traits;import std.typecons; /**Dynamic allocator interface. Code that defines allocators ultimately implementsthis interface. This should be used wherever a uniform type is required forencapsulating various allocator implementations. Composition of allocators is not recommended at this level due toinflexibility of dynamic interfaces and inefficiencies caused by cascadedmultiple calls. Instead, compose allocators using the static interface definedin $(MREF std,experimental,allocator,building_blocks),then adapt the composedallocator to `IAllocator` (possibly by using $(LREF CAllocatorImpl) below). Methods returning `Ternary` return `Ternary.yes` upon success,`Ternary.no` upon failure, and `Ternary.unknown` if the primitive is notimplemented by the allocator instance.*/interface IAllocator{nothrow: /** Returns the alignment offered. */ @property uint alignment(); /** Returns the good allocation size that guarantees zero internal fragmentation. */ size_t goodAllocSize(size_t s); /** Allocates `n` bytes of memory. */ void[] allocate(size_t, TypeInfo ti = null); /** Allocates `n` bytes of memory with specified alignment `a`. Implementations that do not support this primitive should always return `null`. */ void[] alignedAllocate(size_t n, uint a); /** Allocates and returns all memory available to this allocator. Implementations that do not support this primitive should always return `null`. */ void[] allocateAll(); /** Expands a memory block in place and returns `true` if successful. Implementations that don't support this primitive should always return `false`. */ bool expand(ref void[], size_t); /// Reallocates a memory block. bool reallocate(ref void[], size_t); /// Reallocates a memory block with specified alignment. bool alignedReallocate(ref void[] b, size_t size, uint alignment); /** Returns `Ternary.yes` if the allocator owns `b`, `Ternary.no` if the allocator doesn't own `b`, and `Ternary.unknown` if ownership cannot be determined. Implementations that don't support this primitive should always return `Ternary.unknown`. */ Ternary owns(void[] b); /** Resolves an internal pointer to the full block allocated. Implementations that don't support this primitive should always return `Ternary.unknown`. */ Ternary resolveInternalPointer(const void* p, ref void[] result); /** 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 call `deallocate(null)`. */ bool deallocate(void[] b); /** Deallocates all memory. Implementations that don't support this primitive should always return `false`. */ bool deallocateAll(); /** Returns `Ternary.yes` if no memory is currently allocated from this allocator, `Ternary.no` if some allocations are currently active, or `Ternary.unknown` if not supported. */ Ternary empty(); /** Increases the reference count of the concrete class that implements this interface. For stateless allocators, this does nothing. */ @safe @nogc pure void incRef(); /** 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 than `0` and `false` when it hits `0`. For stateless allocators, it always returns `true`. */ @safe @nogc pure bool decRef();} /**A reference counted struct that wraps the dynamic allocator interface.This should be used wherever a uniform type is required for encapsulatingvarious allocator implementations. Code that defines allocators ultimately implements the $(LREF IAllocator)interface, possibly by using $(LREF CAllocatorImpl) below, and then build a`RCIAllocator` out of this. Composition of allocators is not recommended at this level due toinflexibility of dynamic interfaces and inefficiencies caused by cascadedmultiple calls. Instead, compose allocators using the static interface definedin $(A std_experimental_allocator_building_blocks.html,`std.experimental.allocator.building_blocks`), then adapt the composedallocator to `RCIAllocator` (possibly by using $(LREF allocatorObject) below).*/struct RCIAllocator{ private IAllocator _alloc; nothrow: private @nogc pure @safe this(this _)(IAllocator alloc) { assert(alloc); _alloc = alloc; } @nogc pure @safe this(this) { if (_alloc !is null) { _alloc.incRef(); } } @nogc pure @safe ~this() { if (_alloc !is null) { bool isLast = !_alloc.decRef(); if (isLast) _alloc = null; } } @nogc pure @safe auto ref opAssign()(typeof(this) rhs) { if (_alloc is rhs._alloc) { return this; } // incRef was allready called by rhs posblit, so we're just moving // calling dtor is the equivalent of decRef __dtor(); _alloc = rhs._alloc; // move rhs._alloc = null; return this; } @nogc pure @safe bool isNull(this _)() { return _alloc is null; } @property uint alignment() { assert(_alloc); return _alloc.alignment(); } size_t goodAllocSize(size_t s) { assert(_alloc); return _alloc.goodAllocSize(s); } void[] allocate(size_t n, TypeInfo ti = null) { assert(_alloc); return _alloc.allocate(n, ti); } void[] alignedAllocate(size_t n, uint a)Lines 1–500 of 3908. Load more
// Written in the D programming language. /** 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. $(SCRIPT inhibitQuickIndex = 1;) $(BOOKTABLE, $(TR $(TH Category) $(TH Functions)) $(TR $(TD Make) $(TD $(LREF make) $(LREF makeArray) $(LREF makeMultidimensionalArray) )) $(TR $(TD Dispose) $(TD $(LREF dispose) $(LREF disposeMultidimensionalArray) )) $(TR $(TD Modify) $(TD $(LREF expandArray) $(LREF shrinkArray) )) $(TR $(TD Global) $(TD $(LREF processAllocator) $(LREF theAllocator) )) $(TR $(TD Class interface) $(TD $(LREF CAllocatorImpl) $(LREF CSharedAllocatorImpl) $(LREF IAllocator) $(LREF ISharedAllocator) )) $(TR $(TD Structs) $(TD $(LREF allocatorObject) $(LREF RCIAllocator) $(LREF RCISharedAllocator) $(LREF sharedAllocatorObject) $(LREF ThreadLocal) )) ) Synopsis: $(RUNNABLE_EXAMPLE --- // 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); --- ) $(RUNNABLE_EXAMPLE --- // 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); --- ) $(H2 Layered Structure) D's allocators have a layered structure in both implementation and documentation: $(OL $(LI A high-level, dynamically-typed layer (described further down in this module). It consists of an interface called $(LREF IAllocator), which concrete allocators need to implement. The interface primitives themselves are oblivious to the type of the objects being allocated; they only deal in `void[]`, 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 variable $(LREF theAllocator) of type $(LREF IAllocator). The process has a global allocator called $(LREF processAllocator), also of type $(LREF IAllocator). When a new thread is created, $(LREF processAllocator) is copied into $(LREF theAllocator). An application can change the objects to which these references point. By default, at application startup, $(LREF processAllocator) refers to an object that uses D's garbage collected heap. This layer also include high-level functions such as $(LREF make) and $(LREF dispose) that comfortably allocate/create and respectively destroy/deallocate objects. This layer is all needed for most casual uses of allocation primitives.) $(LI 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 $(MREF 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.) $(LI A low-level collection of highly generic $(I heap building blocks)$(MDASH) 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 module $(MREF std,experimental,allocator,showcase) which defines a collection of frequently- used preassembled allocator objects. The implementation and documentation entry point is $(MREF std,experimental,allocator,building_blocks). By design, the primitives of the static interface have the same signatures as the $(LREF IAllocator) primitives but are for the most part optional and driven by static introspection. The parameterized class $(LREF CAllocatorImpl) offers an immediate and useful means to package a static low-level allocator into an implementation of $(LREF IAllocator).) $(LI Core allocator objects that interface with D's garbage collected heap ($(MREF std,experimental,allocator,gc_allocator)), the C `malloc` family ($(MREF std,experimental,allocator,mallocator)), and the OS ($(MREF std,experimental,allocator,mmap_allocator)). Most custom allocators would ultimately obtain memory from one of these core allocators.) ) $(H2 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-in$(MDASH)applications need to make explicit use of it. For casual creation and disposal of dynamically-allocated objects, use $(LREF make), $(LREF dispose), and the array-specific functions $(LREF makeArray), $(LREF expandArray), and $(LREF 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 $(LREF 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 $(MREF_ALTTEXT free list allocator, std,experimental,allocator,building_blocks,free_list) 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()); ... } ---- $(H3 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. $(H3 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 $(LREF make), $(LREF makeArray), $(LREF 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 $(LREF allocatorObject)) only once, at client level. Copyright: Andrei Alexandrescu 2013-. License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(HTTP erdani.com, Andrei Alexandrescu) Source: $(PHOBOSSRC std/experimental/allocator) */ module std.experimental.allocator; public import std.experimental.allocator.common, std.experimental.allocator.typed; // Fix https://issues.dlang.org/show_bug.cgi?id=17806 // this should always be the first unittest in this module in order to ensure // that we use the `processAllocator` setter before the getter @system unittest { import std.experimental.allocator.mallocator : Mallocator; import std.experimental.allocator.gc_allocator : GCAllocator; auto newAlloc = sharedAllocatorObject(Mallocator.instance); processAllocator = newAlloc; assert(processAllocator is newAlloc); processAllocator = sharedAllocatorObject(GCAllocator.instance); } // Example in the synopsis above @system unittest { import std.algorithm.comparison : min, max; import std.experimental.allocator.building_blocks.allocator_list : AllocatorList; import std.experimental.allocator.building_blocks.bitmapped_block : BitmappedBlock; import std.experimental.allocator.building_blocks.bucketizer : Bucketizer; import std.experimental.allocator.building_blocks.free_list : FreeList; import std.experimental.allocator.building_blocks.segregator : Segregator; import std.experimental.allocator.gc_allocator : GCAllocator; alias FList = FreeList!(GCAllocator, 0, unbounded); alias A = Segregator!( 8, FreeList!(GCAllocator, 0, 8), 128, Bucketizer!(FList, 1, 128, 16), 256, Bucketizer!(FList, 129, 256, 32), 512, Bucketizer!(FList, 257, 512, 64), 1024, Bucketizer!(FList, 513, 1024, 128), 2048, Bucketizer!(FList, 1025, 2048, 256), 3584, Bucketizer!(FList, 2049, 3584, 512), 4072 * 1024, AllocatorList!( (n) => BitmappedBlock!(4096)( cast(ubyte[])(GCAllocator.instance.allocate( max(n, 4072 * 1024))))), GCAllocator ); A tuMalloc; auto b = tuMalloc.allocate(500); assert(b.length == 500); auto c = tuMalloc.allocate(113); assert(c.length == 113); assert(tuMalloc.expand(c, 14)); tuMalloc.deallocate(b); tuMalloc.deallocate(c); } import std.range.primitives; import std.traits; import std.typecons; /** 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 $(MREF std,experimental,allocator,building_blocks), then adapt the composed allocator to `IAllocator` (possibly by using $(LREF CAllocatorImpl) below). Methods returning `Ternary` return `Ternary.yes` upon success, `Ternary.no` upon failure, and `Ternary.unknown` if the primitive is not implemented by the allocator instance. */ interface IAllocator { nothrow: /** Returns the alignment offered. */ @property uint alignment(); /** Returns the good allocation size that guarantees zero internal fragmentation. */ size_t goodAllocSize(size_t s); /** Allocates `n` bytes of memory. */ void[] allocate(size_t, TypeInfo ti = null); /** Allocates `n` bytes of memory with specified alignment `a`. Implementations that do not support this primitive should always return `null`. */ void[] alignedAllocate(size_t n, uint a); /** Allocates and returns all memory available to this allocator. Implementations that do not support this primitive should always return `null`. */ void[] allocateAll(); /** Expands a memory block in place and returns `true` if successful. Implementations that don't support this primitive should always return `false`. */ bool expand(ref void[], size_t); /// Reallocates a memory block. bool reallocate(ref void[], size_t); /// Reallocates a memory block with specified alignment. bool alignedReallocate(ref void[] b, size_t size, uint alignment); /** Returns `Ternary.yes` if the allocator owns `b`, `Ternary.no` if the allocator doesn't own `b`, and `Ternary.unknown` if ownership cannot be determined. Implementations that don't support this primitive should always return `Ternary.unknown`. */ Ternary owns(void[] b); /** Resolves an internal pointer to the full block allocated. Implementations that don't support this primitive should always return `Ternary.unknown`. */ Ternary resolveInternalPointer(const void* p, ref void[] result); /** 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 call `deallocate(null)`. */ bool deallocate(void[] b); /** Deallocates all memory. Implementations that don't support this primitive should always return `false`. */ bool deallocateAll(); /** Returns `Ternary.yes` if no memory is currently allocated from this allocator, `Ternary.no` if some allocations are currently active, or `Ternary.unknown` if not supported. */ Ternary empty(); /** Increases the reference count of the concrete class that implements this interface. For stateless allocators, this does nothing. */ @safe @nogc pure void incRef(); /** 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 than `0` and `false` when it hits `0`. For stateless allocators, it always returns `true`. */ @safe @nogc pure bool decRef(); } /** 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 $(LREF IAllocator) interface, possibly by using $(LREF CAllocatorImpl) below, and then build a `RCIAllocator` 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 in $(A std_experimental_allocator_building_blocks.html, `std.experimental.allocator.building_blocks`), then adapt the composed allocator to `RCIAllocator` (possibly by using $(LREF allocatorObject) below). */ struct RCIAllocator { private IAllocator _alloc; nothrow: private @nogc pure @safe this(this _)(IAllocator alloc) { assert(alloc); _alloc = alloc; } @nogc pure @safe this(this) { if (_alloc !is null) { _alloc.incRef(); } } @nogc pure @safe ~this() { if (_alloc !is null) { bool isLast = !_alloc.decRef(); if (isLast) _alloc = null; } } @nogc pure @safe auto ref opAssign()(typeof(this) rhs) { if (_alloc is rhs._alloc) { return this; } // incRef was allready called by rhs posblit, so we're just moving // calling dtor is the equivalent of decRef __dtor(); _alloc = rhs._alloc; // move rhs._alloc = null; return this; } @nogc pure @safe bool isNull(this _)() { return _alloc is null; } @property uint alignment() { assert(_alloc); return _alloc.alignment(); } size_t goodAllocSize(size_t s) { assert(_alloc); return _alloc.goodAllocSize(s); } void[] allocate(size_t n, TypeInfo ti = null) { assert(_alloc); return _alloc.allocate(n, ti); } void[] alignedAllocate(size_t n, uint a)