xref: /netbsd-src/external/gpl3/gcc.old/dist/libphobos/src/std/experimental/allocator/package.d (revision 627f7eb200a4419d89b531d55fccd2ee3ffdcde0)
1 // Written in the D programming language.
2 /**
3 
4 High-level interface for allocators. Implements bundled allocation/creation
5 and destruction/deallocation of data including `struct`s and `class`es,
6 and also array primitives related to allocation. This module is the entry point
7 for both making use of allocators and for their documentation.
8 
9 $(SCRIPT inhibitQuickIndex = 1;)
10 $(BOOKTABLE,
11 $(TR $(TH Category) $(TH Functions))
12 $(TR $(TD Make) $(TD
13     $(LREF make)
14     $(LREF makeArray)
15     $(LREF makeMultidimensionalArray)
16 ))
17 $(TR $(TD Dispose) $(TD
18     $(LREF dispose)
19     $(LREF disposeMultidimensionalArray)
20 ))
21 $(TR $(TD Modify) $(TD
22     $(LREF expandArray)
23     $(LREF shrinkArray)
24 ))
25 $(TR $(TD Global) $(TD
26     $(LREF processAllocator)
27     $(LREF theAllocator)
28 ))
29 $(TR $(TD Class interface) $(TD
30     $(LREF allocatorObject)
31     $(LREF CAllocatorImpl)
32     $(LREF IAllocator)
33 ))
34 )
35 
36 Synopsis:
37 ---
38 // Allocate an int, initialize it with 42
39 int* p = theAllocator.make!int(42);
40 assert(*p == 42);
41 // Destroy and deallocate it
42 theAllocator.dispose(p);
43 
44 // Allocate using the global process allocator
45 p = processAllocator.make!int(100);
46 assert(*p == 100);
47 // Destroy and deallocate
48 processAllocator.dispose(p);
49 
50 // Create an array of 50 doubles initialized to -1.0
51 double[] arr = theAllocator.makeArray!double(50, -1.0);
52 // Append two zeros to it
53 theAllocator.expandArray(arr, 2, 0.0);
54 // On second thought, take that back
55 theAllocator.shrinkArray(arr, 2);
56 // Destroy and deallocate
57 theAllocator.dispose(arr);
58 ---
59 
60 $(H2 Layered Structure)
61 
62 D's allocators have a layered structure in both implementation and documentation:
63 
64 $(OL
65 $(LI A high-level, dynamically-typed layer (described further down in this
66 module). It consists of an interface called $(LREF IAllocator), which concret;
67 allocators need to implement. The interface primitives themselves are oblivious
68 to the type of the objects being allocated; they only deal in `void[]`, by
69 necessity of the interface being dynamic (as opposed to type-parameterized).
70 Each thread has a current allocator it uses by default, which is a thread-local
71 variable $(LREF theAllocator) of type $(LREF IAllocator). The process has a
72 global _allocator called $(LREF processAllocator), also of type $(LREF
73 IAllocator). When a new thread is created, $(LREF processAllocator) is copied
74 into $(LREF theAllocator). An application can change the objects to which these
75 references point. By default, at application startup, $(LREF processAllocator)
76 refers to an object that uses D's garbage collected heap. This layer also
77 include high-level functions such as $(LREF make) and $(LREF dispose) that
78 comfortably allocate/create and respectively destroy/deallocate objects. This
79 layer is all needed for most casual uses of allocation primitives.)
80 
81 $(LI A mid-level, statically-typed layer for assembling several allocators into
82 one. It uses properties of the type of the objects being created to route
83 allocation requests to possibly specialized allocators. This layer is relatively
84 thin and implemented and documented in the $(MREF
85 std,experimental,_allocator,typed) module. It allows an interested user to e.g.
86 use different allocators for arrays versus fixed-sized objects, to the end of
87 better overall performance.)
88 
89 $(LI A low-level collection of highly generic $(I heap building blocks)$(MDASH)
90 Lego-like pieces that can be used to assemble application-specific allocators.
91 The real allocation smarts are occurring at this level. This layer is of
92 interest to advanced applications that want to configure their own allocators.
93 A good illustration of typical uses of these building blocks is module $(MREF
94 std,experimental,_allocator,showcase) which defines a collection of frequently-
95 used preassembled allocator objects. The implementation and documentation entry
96 point is $(MREF std,experimental,_allocator,building_blocks). By design, the
97 primitives of the static interface have the same signatures as the $(LREF
98 IAllocator) primitives but are for the most part optional and driven by static
99 introspection. The parameterized class $(LREF CAllocatorImpl) offers an
100 immediate and useful means to package a static low-level _allocator into an
101 implementation of $(LREF IAllocator).)
102 
103 $(LI Core _allocator objects that interface with D's garbage collected heap
104 ($(MREF std,experimental,_allocator,gc_allocator)), the C `malloc` family
105 ($(MREF std,experimental,_allocator,mallocator)), and the OS ($(MREF
106 std,experimental,_allocator,mmap_allocator)). Most custom allocators would
107 ultimately obtain memory from one of these core allocators.)
108 )
109 
110 $(H2 Idiomatic Use of $(D std.experimental._allocator))
111 
112 As of this time, $(D std.experimental._allocator) is not integrated with D's
113 built-in operators that allocate memory, such as `new`, array literals, or
114 array concatenation operators. That means $(D std.experimental._allocator) is
115 opt-in$(MDASH)applications need to make explicit use of it.
116 
117 For casual creation and disposal of dynamically-allocated objects, use $(LREF
118 make), $(LREF dispose), and the array-specific functions $(LREF makeArray),
119 $(LREF expandArray), and $(LREF shrinkArray). These use by default D's garbage
120 collected heap, but open the application to better configuration options. These
121 primitives work either with `theAllocator` but also with any allocator obtained
122 by combining heap building blocks. For example:
123 
124 ----
125 void fun(size_t n)
126 {
127     // Use the current allocator
128     int[] a1 = theAllocator.makeArray!int(n);
129     scope(exit) theAllocator.dispose(a1);
130     ...
131 }
132 ----
133 
134 To experiment with alternative allocators, set $(LREF theAllocator) for the
135 current thread. For example, consider an application that allocates many 8-byte
136 objects. These are not well supported by the default _allocator, so a
137 $(MREF_ALTTEXT free list _allocator,
138 std,experimental,_allocator,building_blocks,free_list) would be recommended.
139 To install one in `main`, the application would use:
140 
141 ----
142 void main()
143 {
144     import std.experimental.allocator.building_blocks.free_list
145         : FreeList;
146     theAllocator = allocatorObject(FreeList!8());
147     ...
148 }
149 ----
150 
151 $(H3 Saving the `IAllocator` Reference For Later Use)
152 
153 As with any global resource, setting `theAllocator` and `processAllocator`
154 should not be done often and casually. In particular, allocating memory with
155 one allocator and deallocating with another causes undefined behavior.
156 Typically, these variables are set during application initialization phase and
157 last through the application.
158 
159 To avoid this, long-lived objects that need to perform allocations,
160 reallocations, and deallocations relatively often may want to store a reference
161 to the _allocator object they use throughout their lifetime. Then, instead of
162 using `theAllocator` for internal allocation-related tasks, they'd use the
163 internally held reference. For example, consider a user-defined hash table:
164 
165 ----
166 struct HashTable
167 {
168     private IAllocator _allocator;
169     this(size_t buckets, IAllocator allocator = theAllocator) {
170         this._allocator = allocator;
171         ...
172     }
173     // Getter and setter
174     IAllocator allocator() { return _allocator; }
175     void allocator(IAllocator a) { assert(empty); _allocator = a; }
176 }
177 ----
178 
179 Following initialization, the `HashTable` object would consistently use its
180 $(D _allocator) object for acquiring memory. Furthermore, setting
181 $(D HashTable._allocator) to point to a different _allocator should be legal but
182 only if the object is empty; otherwise, the object wouldn't be able to
183 deallocate its existing state.
184 
185 $(H3 Using Allocators without `IAllocator`)
186 
187 Allocators assembled from the heap building blocks don't need to go through
188 `IAllocator` to be usable. They have the same primitives as `IAllocator` and
189 they work with $(LREF make), $(LREF makeArray), $(LREF dispose) etc. So it
190 suffice to create allocator objects wherever fit and use them appropriately:
191 
192 ----
193 void fun(size_t n)
194 {
195     // Use a stack-installed allocator for up to 64KB
196     StackFront!65536 myAllocator;
197     int[] a2 = myAllocator.makeArray!int(n);
198     scope(exit) myAllocator.dispose(a2);
199     ...
200 }
201 ----
202 
203 In this case, `myAllocator` does not obey the `IAllocator` interface, but
204 implements its primitives so it can work with `makeArray` by means of duck
205 typing.
206 
207 One important thing to note about this setup is that statically-typed assembled
208 allocators are almost always faster than allocators that go through
209 `IAllocator`. An important rule of thumb is: "assemble allocator first, adapt
210 to `IAllocator` after". A good allocator implements intricate logic by means of
211 template assembly, and gets wrapped with `IAllocator` (usually by means of
212 $(LREF allocatorObject)) only once, at client level.
213 
214 Copyright: Andrei Alexandrescu 2013-.
215 
216 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
217 
218 Authors: $(HTTP erdani.com, Andrei Alexandrescu)
219 
220 Source: $(PHOBOSSRC std/experimental/_allocator)
221 
222 */
223 
224 module std.experimental.allocator;
225 
226 public import std.experimental.allocator.common,
227     std.experimental.allocator.typed;
228 
229 // Example in the synopsis above
230 @system unittest
231 {
232     import std.algorithm.comparison : min, max;
233     import std.experimental.allocator.building_blocks.allocator_list
234         : AllocatorList;
235     import std.experimental.allocator.building_blocks.bitmapped_block
236         : BitmappedBlock;
237     import std.experimental.allocator.building_blocks.bucketizer : Bucketizer;
238     import std.experimental.allocator.building_blocks.free_list : FreeList;
239     import std.experimental.allocator.building_blocks.segregator : Segregator;
240     import std.experimental.allocator.gc_allocator : GCAllocator;
241 
242     alias FList = FreeList!(GCAllocator, 0, unbounded);
243     alias A = Segregator!(
244         8, FreeList!(GCAllocator, 0, 8),
245         128, Bucketizer!(FList, 1, 128, 16),
246         256, Bucketizer!(FList, 129, 256, 32),
247         512, Bucketizer!(FList, 257, 512, 64),
248         1024, Bucketizer!(FList, 513, 1024, 128),
249         2048, Bucketizer!(FList, 1025, 2048, 256),
250         3584, Bucketizer!(FList, 2049, 3584, 512),
251         4072 * 1024, AllocatorList!(
252             (n) => BitmappedBlock!(4096)(
253                     cast(ubyte[])(GCAllocator.instance.allocate(
254                         max(n, 4072 * 1024))))),
255         GCAllocator
256     );
257     A tuMalloc;
258     auto b = tuMalloc.allocate(500);
259     assert(b.length == 500);
260     auto c = tuMalloc.allocate(113);
261     assert(c.length == 113);
262     assert(tuMalloc.expand(c, 14));
263     tuMalloc.deallocate(b);
264     tuMalloc.deallocate(c);
265 }
266 
267 import std.range.primitives;
268 import std.traits;
269 import std.typecons;
270 
271 /**
272 Dynamic allocator interface. Code that defines allocators ultimately implements
273 this interface. This should be used wherever a uniform type is required for
274 encapsulating various allocator implementations.
275 
276 Composition of allocators is not recommended at this level due to
277 inflexibility of dynamic interfaces and inefficiencies caused by cascaded
278 multiple calls. Instead, compose allocators using the static interface defined
279 in $(A std_experimental_allocator_building_blocks.html,
280 `std.experimental.allocator.building_blocks`), then adapt the composed
281 allocator to `IAllocator` (possibly by using $(LREF CAllocatorImpl) below).
282 
283 Methods returning $(D Ternary) return $(D Ternary.yes) upon success,
284 $(D Ternary.no) upon failure, and $(D Ternary.unknown) if the primitive is not
285 implemented by the allocator instance.
286 */
287 interface IAllocator
288 {
289     /**
290     Returns the alignment offered.
291     */
292     @property uint alignment();
293 
294     /**
295     Returns the good allocation size that guarantees zero internal
296     fragmentation.
297     */
298     size_t goodAllocSize(size_t s);
299 
300     /**
301     Allocates `n` bytes of memory.
302     */
303     void[] allocate(size_t, TypeInfo ti = null);
304 
305     /**
306     Allocates `n` bytes of memory with specified alignment `a`. Implementations
307     that do not support this primitive should always return `null`.
308     */
309     void[] alignedAllocate(size_t n, uint a);
310 
311     /**
312     Allocates and returns all memory available to this allocator.
313     Implementations that do not support this primitive should always return
314     `null`.
315     */
316     void[] allocateAll();
317 
318     /**
319     Expands a memory block in place and returns `true` if successful.
320     Implementations that don't support this primitive should always return
321     `false`.
322     */
323     bool expand(ref void[], size_t);
324 
325     /// Reallocates a memory block.
326     bool reallocate(ref void[], size_t);
327 
328     /// Reallocates a memory block with specified alignment.
329     bool alignedReallocate(ref void[] b, size_t size, uint alignment);
330 
331     /**
332     Returns $(D Ternary.yes) if the allocator owns $(D b), $(D Ternary.no) if
333     the allocator doesn't own $(D b), and $(D Ternary.unknown) if ownership
334     cannot be determined. Implementations that don't support this primitive
335     should always return `Ternary.unknown`.
336     */
337     Ternary owns(void[] b);
338 
339     /**
340     Resolves an internal pointer to the full block allocated. Implementations
341     that don't support this primitive should always return `Ternary.unknown`.
342     */
343     Ternary resolveInternalPointer(const void* p, ref void[] result);
344 
345     /**
346     Deallocates a memory block. Implementations that don't support this
347     primitive should always return `false`. A simple way to check that an
348     allocator supports deallocation is to call $(D deallocate(null)).
349     */
350     bool deallocate(void[] b);
351 
352     /**
353     Deallocates all memory. Implementations that don't support this primitive
354     should always return `false`.
355     */
356     bool deallocateAll();
357 
358     /**
359     Returns $(D Ternary.yes) if no memory is currently allocated from this
360     allocator, $(D Ternary.no) if some allocations are currently active, or
361     $(D Ternary.unknown) if not supported.
362     */
363     Ternary empty();
364 }
365 
366 /**
367 Dynamic shared allocator interface. Code that defines allocators shareable
368 across threads ultimately implements this interface. This should be used
369 wherever a uniform type is required for encapsulating various allocator
370 implementations.
371 
372 Composition of allocators is not recommended at this level due to
373 inflexibility of dynamic interfaces and inefficiencies caused by cascaded
374 multiple calls. Instead, compose allocators using the static interface defined
375 in $(A std_experimental_allocator_building_blocks.html,
376 `std.experimental.allocator.building_blocks`), then adapt the composed
377 allocator to `ISharedAllocator` (possibly by using $(LREF CSharedAllocatorImpl) below).
378 
379 Methods returning $(D Ternary) return $(D Ternary.yes) upon success,
380 $(D Ternary.no) upon failure, and $(D Ternary.unknown) if the primitive is not
381 implemented by the allocator instance.
382 */
383 interface ISharedAllocator
384 {
385     /**
386     Returns the alignment offered.
387     */
388     @property uint alignment() shared;
389 
390     /**
391     Returns the good allocation size that guarantees zero internal
392     fragmentation.
393     */
394     size_t goodAllocSize(size_t s) shared;
395 
396     /**
397     Allocates `n` bytes of memory.
398     */
399     void[] allocate(size_t, TypeInfo ti = null) shared;
400 
401     /**
402     Allocates `n` bytes of memory with specified alignment `a`. Implementations
403     that do not support this primitive should always return `null`.
404     */
405     void[] alignedAllocate(size_t n, uint a) shared;
406 
407     /**
408     Allocates and returns all memory available to this allocator.
409     Implementations that do not support this primitive should always return
410     `null`.
411     */
412     void[] allocateAll() shared;
413 
414     /**
415     Expands a memory block in place and returns `true` if successful.
416     Implementations that don't support this primitive should always return
417     `false`.
418     */
419     bool expand(ref void[], size_t) shared;
420 
421     /// Reallocates a memory block.
422     bool reallocate(ref void[], size_t) shared;
423 
424     /// Reallocates a memory block with specified alignment.
425     bool alignedReallocate(ref void[] b, size_t size, uint alignment) shared;
426 
427     /**
428     Returns $(D Ternary.yes) if the allocator owns $(D b), $(D Ternary.no) if
429     the allocator doesn't own $(D b), and $(D Ternary.unknown) if ownership
430     cannot be determined. Implementations that don't support this primitive
431     should always return `Ternary.unknown`.
432     */
433     Ternary owns(void[] b) shared;
434 
435     /**
436     Resolves an internal pointer to the full block allocated. Implementations
437     that don't support this primitive should always return `Ternary.unknown`.
438     */
439     Ternary resolveInternalPointer(const void* p, ref void[] result) shared;
440 
441     /**
442     Deallocates a memory block. Implementations that don't support this
443     primitive should always return `false`. A simple way to check that an
444     allocator supports deallocation is to call $(D deallocate(null)).
445     */
446     bool deallocate(void[] b) shared;
447 
448     /**
449     Deallocates all memory. Implementations that don't support this primitive
450     should always return `false`.
451     */
452     bool deallocateAll() shared;
453 
454     /**
455     Returns $(D Ternary.yes) if no memory is currently allocated from this
456     allocator, $(D Ternary.no) if some allocations are currently active, or
457     $(D Ternary.unknown) if not supported.
458     */
459     Ternary empty() shared;
460 }
461 
462 private shared ISharedAllocator _processAllocator;
463 private IAllocator _threadAllocator;
464 
setupThreadAllocator()465 private IAllocator setupThreadAllocator() nothrow @nogc @safe
466 {
467     /*
468     Forwards the `_threadAllocator` calls to the `processAllocator`
469     */
470     static class ThreadAllocator : IAllocator
471     {
472         override @property uint alignment()
473         {
474             return processAllocator.alignment();
475         }
476 
477         override size_t goodAllocSize(size_t s)
478         {
479             return processAllocator.goodAllocSize(s);
480         }
481 
482         override void[] allocate(size_t n, TypeInfo ti = null)
483         {
484             return processAllocator.allocate(n, ti);
485         }
486 
487         override void[] alignedAllocate(size_t n, uint a)
488         {
489             return processAllocator.alignedAllocate(n, a);
490         }
491 
492         override void[] allocateAll()
493         {
494             return processAllocator.allocateAll();
495         }
496 
497         override bool expand(ref void[] b, size_t size)
498         {
499             return processAllocator.expand(b, size);
500         }
501 
502         override bool reallocate(ref void[] b, size_t size)
503         {
504             return processAllocator.reallocate(b, size);
505         }
506 
507         override bool alignedReallocate(ref void[] b, size_t size, uint alignment)
508         {
509             return processAllocator.alignedReallocate(b, size, alignment);
510         }
511 
512         override Ternary owns(void[] b)
513         {
514             return processAllocator.owns(b);
515         }
516 
517         override Ternary resolveInternalPointer(const void* p, ref void[] result)
518         {
519             return processAllocator.resolveInternalPointer(p, result);
520         }
521 
522         override bool deallocate(void[] b)
523         {
524             return processAllocator.deallocate(b);
525         }
526 
527         override bool deallocateAll()
528         {
529             return processAllocator.deallocateAll();
530         }
531 
532         override Ternary empty()
533         {
534             return processAllocator.empty();
535         }
536     }
537 
538     assert(!_threadAllocator);
539     import std.conv : emplace;
540     static ulong[stateSize!(ThreadAllocator).divideRoundUp(ulong.sizeof)] _threadAllocatorState;
541     _threadAllocator = () @trusted { return emplace!(ThreadAllocator)(_threadAllocatorState[]); } ();
542     return _threadAllocator;
543 }
544 
545 /**
546 Gets/sets the allocator for the current thread. This is the default allocator
547 that should be used for allocating thread-local memory. For allocating memory
548 to be shared across threads, use $(D processAllocator) (below). By default,
549 $(D theAllocator) ultimately fetches memory from $(D processAllocator), which
550 in turn uses the garbage collected heap.
551 */
theAllocator()552 nothrow @safe @nogc @property IAllocator theAllocator()
553 {
554     auto p = _threadAllocator;
555     return p !is null ? p : setupThreadAllocator();
556 }
557 
558 /// Ditto
theAllocator(IAllocator a)559 nothrow @safe @nogc @property void theAllocator(IAllocator a)
560 {
561     assert(a);
562     _threadAllocator = a;
563 }
564 
565 ///
566 @system unittest
567 {
568     // Install a new allocator that is faster for 128-byte allocations.
569     import std.experimental.allocator.building_blocks.free_list : FreeList;
570     import std.experimental.allocator.gc_allocator : GCAllocator;
571     auto oldAllocator = theAllocator;
572     scope(exit) theAllocator = oldAllocator;
573     theAllocator = allocatorObject(FreeList!(GCAllocator, 128)());
574     // Use the now changed allocator to allocate an array
575     const ubyte[] arr = theAllocator.makeArray!ubyte(128);
576     assert(arr.ptr);
577     //...
578 }
579 
580 /**
581 Gets/sets the allocator for the current process. This allocator must be used
582 for allocating memory shared across threads. Objects created using this
583 allocator can be cast to $(D shared).
584 */
shared(ISharedAllocator)585 @property shared(ISharedAllocator) processAllocator()
586 {
587     import std.experimental.allocator.gc_allocator : GCAllocator;
588     import std.concurrency : initOnce;
589     return initOnce!_processAllocator(
590         sharedAllocatorObject(GCAllocator.instance));
591 }
592 
593 /// Ditto
processAllocator(shared ISharedAllocator a)594 @property void processAllocator(shared ISharedAllocator a)
595 {
596     assert(a);
597     _processAllocator = a;
598 }
599 
600 @system unittest
601 {
602     import core.exception : AssertError;
603     import std.exception : assertThrown;
604     import std.experimental.allocator.building_blocks.free_list : SharedFreeList;
605     import std.experimental.allocator.mallocator : Mallocator;
606 
607     assert(processAllocator);
608     assert(theAllocator);
609 
610     testAllocatorObject(processAllocator);
611     testAllocatorObject(theAllocator);
612 
613     shared SharedFreeList!(Mallocator, chooseAtRuntime, chooseAtRuntime) sharedFL;
614     shared ISharedAllocator sharedFLObj = sharedAllocatorObject(sharedFL);
615     assert(sharedFLObj);
616     testAllocatorObject(sharedFLObj);
617 
618     // Test processAllocator setter
619     shared ISharedAllocator oldProcessAllocator = processAllocator;
620     processAllocator = sharedFLObj;
621     assert(processAllocator is sharedFLObj);
622 
623     testAllocatorObject(processAllocator);
624     testAllocatorObject(theAllocator);
625     assertThrown!AssertError(processAllocator = null);
626 
627     // Restore initial processAllocator state
628     processAllocator = oldProcessAllocator;
629     assert(processAllocator is oldProcessAllocator);
630 
631     shared ISharedAllocator indirectShFLObj = sharedAllocatorObject(&sharedFL);
632     testAllocatorObject(indirectShFLObj);
633 
634     IAllocator indirectMallocator = allocatorObject(&Mallocator.instance);
635     testAllocatorObject(indirectMallocator);
636 }
637 
638 /**
639 Dynamically allocates (using $(D alloc)) and then creates in the memory
640 allocated an object of type $(D T), using $(D args) (if any) for its
641 initialization. Initialization occurs in the memory allocated and is otherwise
642 semantically the same as $(D T(args)).
643 (Note that using $(D alloc.make!(T[])) creates a pointer to an (empty) array
644 of $(D T)s, not an array. To use an allocator to allocate and initialize an
645 array, use $(D alloc.makeArray!T) described below.)
646 
647 Params:
648 T = Type of the object being created.
649 alloc = The allocator used for getting the needed memory. It may be an object
650 implementing the static interface for allocators, or an $(D IAllocator)
651 reference.
652 args = Optional arguments used for initializing the created object. If not
653 present, the object is default constructed.
654 
655 Returns: If $(D T) is a class type, returns a reference to the created $(D T)
656 object. Otherwise, returns a $(D T*) pointing to the created object. In all
657 cases, returns $(D null) if allocation failed.
658 
659 Throws: If $(D T)'s constructor throws, deallocates the allocated memory and
660 propagates the exception.
661 */
make(T,Allocator,A...)662 auto make(T, Allocator, A...)(auto ref Allocator alloc, auto ref A args)
663 {
664     import std.algorithm.comparison : max;
665     import std.conv : emplace, emplaceRef;
666     auto m = alloc.allocate(max(stateSize!T, 1));
667     if (!m.ptr) return null;
668 
669     // make can only be @safe if emplace or emplaceRef is `pure`
670     auto construct()
671     {
672         static if (is(T == class)) return emplace!T(m, args);
673         else
674         {
675             // Assume cast is safe as allocation succeeded for `stateSize!T`
676             auto p = () @trusted { return cast(T*) m.ptr; }();
677             emplaceRef(*p, args);
678             return p;
679         }
680     }
681 
682     scope(failure)
683     {
684         static if (is(typeof(() pure { return construct(); })))
685         {
686             // Assume deallocation is safe because:
687             // 1) in case of failure, `m` is the only reference to this memory
688             // 2) `m` is known to originate from `alloc`
689             () @trusted { alloc.deallocate(m); }();
690         }
691         else
692         {
693             alloc.deallocate(m);
694         }
695     }
696 
697     return construct();
698 }
699 
700 ///
701 @system unittest
702 {
703     // Dynamically allocate one integer
704     const int* p1 = theAllocator.make!int;
705     // It's implicitly initialized with its .init value
706     assert(*p1 == 0);
707     // Dynamically allocate one double, initialize to 42.5
708     const double* p2 = theAllocator.make!double(42.5);
709     assert(*p2 == 42.5);
710 
711     // Dynamically allocate a struct
712     static struct Point
713     {
714         int x, y, z;
715     }
716     // Use the generated constructor taking field values in order
717     const Point* p = theAllocator.make!Point(1, 2);
718     assert(p.x == 1 && p.y == 2 && p.z == 0);
719 
720     // Dynamically allocate a class object
721     static class Customer
722     {
723         uint id = uint.max;
this()724         this() {}
this(uint id)725         this(uint id) { this.id = id; }
726         // ...
727     }
728     Customer cust = theAllocator.make!Customer;
729     assert(cust.id == uint.max); // default initialized
730     cust = theAllocator.make!Customer(42);
731     assert(cust.id == 42);
732 
733     // explicit passing of outer pointer
734     static class Outer
735     {
736         int x = 3;
737         class Inner
738         {
getX()739             auto getX() { return x; }
740         }
741     }
742     auto outer = theAllocator.make!Outer();
743     auto inner = theAllocator.make!(Outer.Inner)(outer);
744     assert(outer.x == inner.getX);
745 }
746 
747 @system unittest // bugzilla 15639 & 15772
748 {
749     abstract class Foo {}
750     class Bar: Foo {}
751     static assert(!is(typeof(theAllocator.make!Foo)));
752     static assert( is(typeof(theAllocator.make!Bar)));
753 }
754 
755 @system unittest
756 {
test(Allocator)757     void test(Allocator)(auto ref Allocator alloc)
758     {
759         const int* a = alloc.make!int(10);
760         assert(*a == 10);
761 
762         struct A
763         {
764             int x;
765             string y;
766             double z;
767         }
768 
769         A* b = alloc.make!A(42);
770         assert(b.x == 42);
771         assert(b.y is null);
772         import std.math : isNaN;
773         assert(b.z.isNaN);
774 
775         b = alloc.make!A(43, "44", 45);
776         assert(b.x == 43);
777         assert(b.y == "44");
778         assert(b.z == 45);
779 
780         static class B
781         {
782             int x;
783             string y;
784             double z;
785             this(int _x, string _y = null, double _z = double.init)
786             {
787                 x = _x;
788                 y = _y;
789                 z = _z;
790             }
791         }
792 
793         B c = alloc.make!B(42);
794         assert(c.x == 42);
795         assert(c.y is null);
796         assert(c.z.isNaN);
797 
798         c = alloc.make!B(43, "44", 45);
799         assert(c.x == 43);
800         assert(c.y == "44");
801         assert(c.z == 45);
802 
803         const parray = alloc.make!(int[]);
804         assert((*parray).empty);
805     }
806 
807     import std.experimental.allocator.gc_allocator : GCAllocator;
808     test(GCAllocator.instance);
809     test(theAllocator);
810 }
811 
812 // Attribute propagation
813 nothrow @safe @nogc unittest
814 {
815     import std.experimental.allocator.mallocator : Mallocator;
816     alias alloc = Mallocator.instance;
817 
test(T,Args...)818     void test(T, Args...)(auto ref Args args)
819     {
820         auto k = alloc.make!T(args);
821         () @trusted { alloc.dispose(k); }();
822     }
823 
824     test!int;
825     test!(int*);
826     test!int(0);
827     test!(int*)(null);
828 }
829 
830 // should be pure with the GCAllocator
831 /*pure nothrow*/ @safe unittest
832 {
833     import std.experimental.allocator.gc_allocator : GCAllocator;
834 
835     alias alloc = GCAllocator.instance;
836 
test(T,Args...)837     void test(T, Args...)(auto ref Args args)
838     {
839         auto k = alloc.make!T(args);
840         (a) @trusted { a.dispose(k); }(alloc);
841     }
842 
843     test!int();
844     test!(int*);
845     test!int(0);
846     test!(int*)(null);
847 }
848 
849 // Verify that making an object by calling an impure constructor is not @safe
850 nothrow @safe @nogc unittest
851 {
852     import std.experimental.allocator.mallocator : Mallocator;
thisPure853     static struct Pure { this(int) pure nothrow @nogc @safe {} }
854 
855     cast(void) Mallocator.instance.make!Pure(0);
856 
857     static int g = 0;
thisImpure858     static struct Impure { this(int) nothrow @nogc @safe {
859         g++;
860     } }
861     static assert(!__traits(compiles, cast(void) Mallocator.instance.make!Impure(0)));
862 }
863 
864 // test failure with a pure, failing struct
865 @safe unittest
866 {
867     import std.exception : assertThrown, enforce;
868 
869     // this struct can't be initialized
870     struct InvalidStruct
871     {
thisInvalidStruct872         this(int b)
873         {
874             enforce(1 == 2);
875         }
876     }
877     import std.experimental.allocator.mallocator : Mallocator;
878     assertThrown(make!InvalidStruct(Mallocator.instance, 42));
879 }
880 
881 // test failure with an impure, failing struct
882 @system unittest
883 {
884     import std.exception : assertThrown, enforce;
885     static int g;
886     struct InvalidImpureStruct
887     {
thisInvalidImpureStruct888         this(int b)
889         {
890             g++;
891             enforce(1 == 2);
892         }
893     }
894     import std.experimental.allocator.mallocator : Mallocator;
895     assertThrown(make!InvalidImpureStruct(Mallocator.instance, 42));
896 }
897 
fillWithMemcpy(T)898 private void fillWithMemcpy(T)(void[] array, auto ref T filler) nothrow
899 {
900     import core.stdc.string : memcpy;
901     import std.algorithm.comparison : min;
902     if (!array.length) return;
903     memcpy(array.ptr, &filler, T.sizeof);
904     // Fill the array from the initialized portion of itself exponentially.
905     for (size_t offset = T.sizeof; offset < array.length; )
906     {
907         size_t extent = min(offset, array.length - offset);
908         memcpy(array.ptr + offset, array.ptr, extent);
909         offset += extent;
910     }
911 }
912 
913 @system unittest
914 {
915     int[] a;
916     fillWithMemcpy(a, 42);
917     assert(a.length == 0);
918     a = [ 1, 2, 3, 4, 5 ];
919     fillWithMemcpy(a, 42);
920     assert(a == [ 42, 42, 42, 42, 42]);
921 }
922 
uninitializedFillDefault(T)923 private T[] uninitializedFillDefault(T)(T[] array) nothrow
924 {
925     T t = T.init;
926     fillWithMemcpy(array, t);
927     return array;
928 }
929 
930 pure nothrow @nogc
931 @system unittest
932 {
933     static struct S { int x = 42; @disable this(this); }
934 
935     int[5] expected = [42, 42, 42, 42, 42];
936     S[5] arr = void;
937     uninitializedFillDefault(arr);
938     assert((cast(int*) arr.ptr)[0 .. arr.length] == expected);
939 }
940 
941 @system unittest
942 {
943     int[] a = [1, 2, 4];
944     uninitializedFillDefault(a);
945     assert(a == [0, 0, 0]);
946 }
947 
948 /**
949 Create an array of $(D T) with $(D length) elements using $(D alloc). The array is either default-initialized, filled with copies of $(D init), or initialized with values fetched from `range`.
950 
951 Params:
952 T = element type of the array being created
953 alloc = the allocator used for getting memory
954 length = length of the newly created array
955 init = element used for filling the array
956 range = range used for initializing the array elements
957 
958 Returns:
959 The newly-created array, or $(D null) if either $(D length) was $(D 0) or
960 allocation failed.
961 
962 Throws:
963 The first two overloads throw only if `alloc`'s primitives do. The
964 overloads that involve copy initialization deallocate memory and propagate the
965 exception if the copy operation throws.
966 */
makeArray(T,Allocator)967 T[] makeArray(T, Allocator)(auto ref Allocator alloc, size_t length)
968 {
969     if (!length) return null;
970     auto m = alloc.allocate(T.sizeof * length);
971     if (!m.ptr) return null;
972     alias U = Unqual!T;
973     return () @trusted { return cast(T[]) uninitializedFillDefault(cast(U[]) m); }();
974 }
975 
976 @system unittest
977 {
test1(A)978     void test1(A)(auto ref A alloc)
979     {
980         int[] a = alloc.makeArray!int(0);
981         assert(a.length == 0 && a.ptr is null);
982         a = alloc.makeArray!int(5);
983         assert(a.length == 5);
984         static immutable cheatsheet = [0, 0, 0, 0, 0];
985         assert(a == cheatsheet);
986     }
987 
test2(A)988     void test2(A)(auto ref A alloc)
989     {
990         static struct S { int x = 42; @disable this(this); }
991         S[] arr = alloc.makeArray!S(5);
992         assert(arr.length == 5);
993         int[] arrInt = () @trusted { return (cast(int*) arr.ptr)[0 .. 5]; }();
994         static immutable res = [42, 42, 42, 42, 42];
995         assert(arrInt == res);
996     }
997 
998     import std.experimental.allocator.gc_allocator : GCAllocator;
999     import std.experimental.allocator.mallocator : Mallocator;
1000     (alloc) /*pure nothrow*/ @safe { test1(alloc); test2(alloc);} (GCAllocator.instance);
1001     (alloc) nothrow @safe @nogc { test1(alloc); test2(alloc);} (Mallocator.instance);
1002     test2(theAllocator);
1003 }
1004 
1005 @system unittest
1006 {
1007     import std.algorithm.comparison : equal;
1008     auto a = theAllocator.makeArray!(shared int)(5);
1009     static assert(is(typeof(a) == shared(int)[]));
1010     assert(a.length == 5);
1011     assert(a.equal([0, 0, 0, 0, 0]));
1012 
1013     auto b = theAllocator.makeArray!(const int)(5);
1014     static assert(is(typeof(b) == const(int)[]));
1015     assert(b.length == 5);
1016     assert(b.equal([0, 0, 0, 0, 0]));
1017 
1018     auto c = theAllocator.makeArray!(immutable int)(5);
1019     static assert(is(typeof(c) == immutable(int)[]));
1020     assert(c.length == 5);
1021     assert(c.equal([0, 0, 0, 0, 0]));
1022 }
1023 
1024 private enum hasPurePostblit(T) = !hasElaborateCopyConstructor!T ||
1025     is(typeof(() pure { T.init.__xpostblit(); }));
1026 
1027 private enum hasPureDtor(T) = !hasElaborateDestructor!T ||
1028     is(typeof(() pure { T.init.__xdtor(); }));
1029 
1030 // `true` when postblit and destructor of T cannot escape references to itself
1031 private enum canSafelyDeallocPostRewind(T) = hasPurePostblit!T && hasPureDtor!T;
1032 
1033 /// Ditto
makeArray(T,Allocator)1034 T[] makeArray(T, Allocator)(auto ref Allocator alloc, size_t length,
1035     auto ref T init)
1036 {
1037     if (!length) return null;
1038     auto m = alloc.allocate(T.sizeof * length);
1039     if (!m.ptr) return null;
1040     auto result = () @trusted { return cast(T[]) m; } ();
1041     import std.traits : hasElaborateCopyConstructor;
1042     static if (hasElaborateCopyConstructor!T)
1043     {
1044         scope(failure)
1045         {
1046             static if (canSafelyDeallocPostRewind!T)
1047                 () @trusted { alloc.deallocate(m); } ();
1048             else
1049                 alloc.deallocate(m);
1050         }
1051 
1052         size_t i = 0;
1053         static if (hasElaborateDestructor!T)
1054         {
1055             scope (failure)
1056             {
1057                 foreach (j; 0 .. i)
1058                 {
1059                     destroy(result[j]);
1060                 }
1061             }
1062         }
1063         import std.conv : emplace;
1064         for (; i < length; ++i)
1065         {
1066             emplace!T(&result[i], init);
1067         }
1068     }
1069     else
1070     {
1071         alias U = Unqual!T;
1072         () @trusted { fillWithMemcpy(cast(U[]) result, *(cast(U*) &init)); }();
1073     }
1074     return result;
1075 }
1076 
1077 ///
1078 @system unittest
1079 {
1080     import std.algorithm.comparison : equal;
test(T)1081     static void test(T)()
1082     {
1083         T[] a = theAllocator.makeArray!T(2);
1084         assert(a.equal([0, 0]));
1085         a = theAllocator.makeArray!T(3, 42);
1086         assert(a.equal([42, 42, 42]));
1087         import std.range : only;
1088         a = theAllocator.makeArray!T(only(42, 43, 44));
1089         assert(a.equal([42, 43, 44]));
1090     }
1091     test!int();
1092     test!(shared int)();
1093     test!(const int)();
1094     test!(immutable int)();
1095 }
1096 
1097 @system unittest
1098 {
test(A)1099     void test(A)(auto ref A alloc)
1100     {
1101         long[] a = alloc.makeArray!long(0, 42);
1102         assert(a.length == 0 && a.ptr is null);
1103         a = alloc.makeArray!long(5, 42);
1104         assert(a.length == 5);
1105         assert(a == [ 42, 42, 42, 42, 42 ]);
1106     }
1107     import std.experimental.allocator.gc_allocator : GCAllocator;
1108     (alloc) /*pure nothrow*/ @safe { test(alloc); } (GCAllocator.instance);
1109     test(theAllocator);
1110 }
1111 
1112 // test failure with a pure, failing struct
1113 @safe unittest
1114 {
1115     import std.exception : assertThrown, enforce;
1116 
1117     struct NoCopy
1118     {
1119         @disable this();
1120 
thisNoCopy1121         this(int b){}
1122 
1123         // can't be copied
thisNoCopy1124         this(this)
1125         {
1126             enforce(1 == 2);
1127         }
1128     }
1129     import std.experimental.allocator.mallocator : Mallocator;
1130     assertThrown(makeArray!NoCopy(Mallocator.instance, 10, NoCopy(42)));
1131 }
1132 
1133 // test failure with an impure, failing struct
1134 @system unittest
1135 {
1136     import std.exception : assertThrown, enforce;
1137 
1138     static int i = 0;
1139     struct Singleton
1140     {
1141         @disable this();
1142 
thisSingleton1143         this(int b){}
1144 
1145         // can't be copied
thisSingleton1146         this(this)
1147         {
1148             enforce(i++ == 0);
1149         }
1150 
~thisSingleton1151         ~this()
1152         {
1153             i--;
1154         }
1155     }
1156     import std.experimental.allocator.mallocator : Mallocator;
1157     assertThrown(makeArray!Singleton(Mallocator.instance, 10, Singleton(42)));
1158 }
1159 
1160 /// Ditto
1161 Unqual!(ElementEncodingType!R)[] makeArray(Allocator, R)(auto ref Allocator alloc, R range)
1162 if (isInputRange!R && !isInfinite!R)
1163 {
1164     alias T = Unqual!(ElementEncodingType!R);
1165     return makeArray!(T, Allocator, R)(alloc, range);
1166 }
1167 
1168 /// Ditto
1169 T[] makeArray(T, Allocator, R)(auto ref Allocator alloc, R range)
1170 if (isInputRange!R && !isInfinite!R)
1171 {
1172     static if (isForwardRange!R || hasLength!R)
1173     {
1174         static if (hasLength!R || isNarrowString!R)
1175             immutable length = range.length;
1176         else
1177             immutable length = range.save.walkLength;
1178 
1179         if (!length) return null;
1180         auto m = alloc.allocate(T.sizeof * length);
1181         if (!m.ptr) return null;
1182         auto result = () @trusted { return cast(T[]) m; } ();
1183 
1184         size_t i = 0;
scope(failure)1185         scope (failure)
1186         {
1187             foreach (j; 0 .. i)
1188             {
1189                 auto p = () @trusted { return cast(Unqual!T*) &result[j]; }();
1190                 destroy(p);
1191             }
1192 
1193             static if (canSafelyDeallocPostRewind!T)
1194                 () @trusted { alloc.deallocate(m); } ();
1195             else
1196                 alloc.deallocate(m);
1197         }
1198 
1199         import std.conv : emplaceRef;
1200         static if (isNarrowString!R || isRandomAccessRange!R)
1201         {
1202             foreach (j; 0 .. range.length)
1203             {
1204                 emplaceRef!T(result[i++], range[j]);
1205             }
1206         }
1207         else
1208         {
1209             for (; !range.empty; range.popFront, ++i)
1210             {
1211                 emplaceRef!T(result[i], range.front);
1212             }
1213         }
1214 
1215         return result;
1216     }
1217     else
1218     {
1219         // Estimated size
1220         size_t estimated = 8;
1221         auto m = alloc.allocate(T.sizeof * estimated);
1222         if (!m.ptr) return null;
1223         auto result = () @trusted { return cast(T[]) m; } ();
1224 
1225         size_t initialized = 0;
bailout()1226         void bailout()
1227         {
1228             foreach (i; 0 .. initialized + 1)
1229             {
1230                 destroy(result[i]);
1231             }
1232 
1233             static if (canSafelyDeallocPostRewind!T)
1234                 () @trusted { alloc.deallocate(m); } ();
1235             else
1236                 alloc.deallocate(m);
1237         }
1238         scope (failure) bailout;
1239 
1240         for (; !range.empty; range.popFront, ++initialized)
1241         {
1242             if (initialized == estimated)
1243             {
1244                 // Need to reallocate
1245                 static if (hasPurePostblit!T)
1246                     auto success = () @trusted { return alloc.reallocate(m, T.sizeof * (estimated *= 2)); } ();
1247                 else
1248                     auto success = alloc.reallocate(m, T.sizeof * (estimated *= 2));
1249                 if (!success)
1250                 {
1251                     bailout;
1252                     return null;
1253                 }
1254                 result = () @trusted { return cast(T[]) m; } ();
1255             }
1256             import std.conv : emplaceRef;
1257             emplaceRef(result[initialized], range.front);
1258         }
1259 
1260         if (initialized < estimated)
1261         {
1262             // Try to shrink memory, no harm if not possible
1263             static if (hasPurePostblit!T)
1264                 auto success = () @trusted { return alloc.reallocate(m, T.sizeof * initialized); } ();
1265             else
1266                 auto success = alloc.reallocate(m, T.sizeof * initialized);
1267             if (success)
1268                 result = () @trusted { return cast(T[]) m; } ();
1269         }
1270 
1271         return result[0 .. initialized];
1272     }
1273 }
1274 
1275 @system unittest
1276 {
test(A)1277     void test(A)(auto ref A alloc)
1278     {
1279         long[] a = alloc.makeArray!long((int[]).init);
1280         assert(a.length == 0 && a.ptr is null);
1281         a = alloc.makeArray!long([5, 42]);
1282         assert(a.length == 2);
1283         assert(a == [ 5, 42]);
1284 
1285         // we can also infer the type
1286         auto b = alloc.makeArray([4.0, 2.0]);
1287         static assert(is(typeof(b) == double[]));
1288         assert(b == [4.0, 2.0]);
1289     }
1290     import std.experimental.allocator.gc_allocator : GCAllocator;
1291     (alloc) pure nothrow @safe { test(alloc); } (GCAllocator.instance);
1292     test(theAllocator);
1293 }
1294 
1295 // infer types for strings
1296 @system unittest
1297 {
test(A)1298     void test(A)(auto ref A alloc)
1299     {
1300         auto c = alloc.makeArray("fooπ��");
1301         static assert(is(typeof(c) == char[]));
1302         assert(c == "fooπ��");
1303 
1304         auto d = alloc.makeArray("fooπ��"d);
1305         static assert(is(typeof(d) == dchar[]));
1306         assert(d == "fooπ��");
1307 
1308         auto w = alloc.makeArray("fooπ��"w);
1309         static assert(is(typeof(w) == wchar[]));
1310         assert(w == "fooπ��");
1311     }
1312 
1313     import std.experimental.allocator.gc_allocator : GCAllocator;
1314     (alloc) pure nothrow @safe { test(alloc); } (GCAllocator.instance);
1315     test(theAllocator);
1316 }
1317 
1318 /*pure*/ nothrow @safe unittest
1319 {
1320     import std.algorithm.comparison : equal;
1321     import std.experimental.allocator.gc_allocator : GCAllocator;
1322     import std.internal.test.dummyrange;
1323     import std.range : iota;
foreach(DummyType;AllDummyRanges)1324     foreach (DummyType; AllDummyRanges)
1325     {
1326         (alloc) pure nothrow @safe
1327         {
1328             DummyType d;
1329             auto arr = alloc.makeArray(d);
1330             assert(arr.length == 10);
1331             assert(arr.equal(iota(1, 11)));
1332         } (GCAllocator.instance);
1333     }
1334 }
1335 
1336 // test failure with a pure, failing struct
1337 @safe unittest
1338 {
1339     import std.exception : assertThrown, enforce;
1340 
1341     struct NoCopy
1342     {
1343         int b;
1344 
1345         @disable this();
1346 
thisNoCopy1347         this(int b)
1348         {
1349             this.b = b;
1350         }
1351 
1352         // can't be copied
thisNoCopy1353         this(this)
1354         {
1355             enforce(b < 3, "there can only be three elements");
1356         }
1357     }
1358     import std.experimental.allocator.mallocator : Mallocator;
1359     auto arr = [NoCopy(1), NoCopy(2), NoCopy(3)];
1360     assertThrown(makeArray!NoCopy(Mallocator.instance, arr));
1361 
1362     struct NoCopyRange
1363     {
1364         static j = 0;
emptyNoCopyRange1365         bool empty()
1366         {
1367             return j > 5;
1368         }
1369 
frontNoCopyRange1370         auto front()
1371         {
1372             return NoCopy(j);
1373         }
1374 
popFrontNoCopyRange1375         void popFront()
1376         {
1377             j++;
1378         }
1379     }
1380     assertThrown(makeArray!NoCopy(Mallocator.instance, NoCopyRange()));
1381 }
1382 
1383 // test failure with an impure, failing struct
1384 @system unittest
1385 {
1386     import std.exception : assertThrown, enforce;
1387 
1388     static i = 0;
1389     static maxElements = 2;
1390     struct NoCopy
1391     {
1392         int val;
1393         @disable this();
1394 
thisNoCopy1395         this(int b){
1396             this.val = i++;
1397         }
1398 
1399         // can't be copied
thisNoCopy1400         this(this)
1401         {
1402             enforce(i++ < maxElements, "there can only be four elements");
1403         }
1404     }
1405 
1406     import std.experimental.allocator.mallocator : Mallocator;
1407     auto arr = [NoCopy(1), NoCopy(2)];
1408     assertThrown(makeArray!NoCopy(Mallocator.instance, arr));
1409 
1410     // allow more copies and thus force reallocation
1411     i = 0;
1412     maxElements = 30;
1413     static j = 0;
1414 
1415     struct NoCopyRange
1416     {
emptyNoCopyRange1417         bool empty()
1418         {
1419             return j > 100;
1420         }
1421 
frontNoCopyRange1422         auto front()
1423         {
1424             return NoCopy(1);
1425         }
1426 
popFrontNoCopyRange1427         void popFront()
1428         {
1429             j++;
1430         }
1431     }
1432     assertThrown(makeArray!NoCopy(Mallocator.instance, NoCopyRange()));
1433 
1434     maxElements = 300;
1435     auto arr2 = makeArray!NoCopy(Mallocator.instance, NoCopyRange());
1436 
1437     import std.algorithm.comparison : equal;
1438     import std.algorithm.iteration : map;
1439     import std.range : iota;
1440     assert(arr2.map!`a.val`.equal(iota(32, 204, 2)));
1441 }
1442 
version(unittest)1443 version (unittest)
1444 {
1445     private struct ForcedInputRange
1446     {
1447         int[]* array;
1448         pure nothrow @safe @nogc:
1449         bool empty() { return !array || (*array).empty; }
1450         ref int front() { return (*array)[0]; }
1451         void popFront() { *array = (*array)[1 .. $]; }
1452     }
1453 }
1454 
1455 @system unittest
1456 {
1457     import std.array : array;
1458     import std.range : iota;
1459     int[] arr = iota(10).array;
1460 
1461     void test(A)(auto ref A alloc)
1462     {
1463         ForcedInputRange r;
1464         long[] a = alloc.makeArray!long(r);
1465         assert(a.length == 0 && a.ptr is null);
1466         auto arr2 = arr;
1467         r.array = () @trusted { return &arr2; } ();
1468         a = alloc.makeArray!long(r);
1469         assert(a.length == 10);
1470         assert(a == iota(10).array);
1471     }
1472     import std.experimental.allocator.gc_allocator : GCAllocator;
1473     (alloc) pure nothrow @safe { test(alloc); } (GCAllocator.instance);
1474     test(theAllocator);
1475 }
1476 
1477 /**
1478 Grows $(D array) by appending $(D delta) more elements. The needed memory is
1479 allocated using $(D alloc). The extra elements added are either default-
1480 initialized, filled with copies of $(D init), or initialized with values
1481 fetched from `range`.
1482 
1483 Params:
1484 T = element type of the array being created
1485 alloc = the allocator used for getting memory
1486 array = a reference to the array being grown
1487 delta = number of elements to add (upon success the new length of $(D array) is
1488 $(D array.length + delta))
1489 init = element used for filling the array
1490 range = range used for initializing the array elements
1491 
1492 Returns:
1493 $(D true) upon success, $(D false) if memory could not be allocated. In the
1494 latter case $(D array) is left unaffected.
1495 
1496 Throws:
1497 The first two overloads throw only if `alloc`'s primitives do. The
1498 overloads that involve copy initialization deallocate memory and propagate the
1499 exception if the copy operation throws.
1500 */
1501 bool expandArray(T, Allocator)(auto ref Allocator alloc, ref T[] array,
1502         size_t delta)
1503 {
1504     if (!delta) return true;
1505     if (array is null) return false;
1506     immutable oldLength = array.length;
1507     void[] buf = array;
1508     if (!alloc.reallocate(buf, buf.length + T.sizeof * delta)) return false;
1509     array = cast(T[]) buf;
1510     array[oldLength .. $].uninitializedFillDefault;
1511     return true;
1512 }
1513 
1514 @system unittest
1515 {
1516     void test(A)(auto ref A alloc)
1517     {
1518         auto arr = alloc.makeArray!int([1, 2, 3]);
1519         assert(alloc.expandArray(arr, 3));
1520         assert(arr == [1, 2, 3, 0, 0, 0]);
1521     }
1522     import std.experimental.allocator.gc_allocator : GCAllocator;
1523     test(GCAllocator.instance);
1524     test(theAllocator);
1525 }
1526 
1527 /// Ditto
1528 bool expandArray(T, Allocator)(auto ref Allocator alloc, ref T[] array,
1529     size_t delta, auto ref T init)
1530 {
1531     if (!delta) return true;
1532     if (array is null) return false;
1533     void[] buf = array;
1534     if (!alloc.reallocate(buf, buf.length + T.sizeof * delta)) return false;
1535     immutable oldLength = array.length;
1536     array = cast(T[]) buf;
1537     scope(failure) array[oldLength .. $].uninitializedFillDefault;
1538     import std.algorithm.mutation : uninitializedFill;
1539     array[oldLength .. $].uninitializedFill(init);
1540     return true;
1541 }
1542 
1543 @system unittest
1544 {
1545     void test(A)(auto ref A alloc)
1546     {
1547         auto arr = alloc.makeArray!int([1, 2, 3]);
1548         assert(alloc.expandArray(arr, 3, 1));
1549         assert(arr == [1, 2, 3, 1, 1, 1]);
1550     }
1551     import std.experimental.allocator.gc_allocator : GCAllocator;
1552     test(GCAllocator.instance);
1553     test(theAllocator);
1554 }
1555 
1556 /// Ditto
1557 bool expandArray(T, Allocator, R)(auto ref Allocator alloc, ref T[] array,
1558         R range)
1559 if (isInputRange!R)
1560 {
1561     if (array is null) return false;
1562     static if (isForwardRange!R)
1563     {
1564         immutable delta = walkLength(range.save);
1565         if (!delta) return true;
1566         immutable oldLength = array.length;
1567 
1568         // Reallocate support memory
1569         void[] buf = array;
1570         if (!alloc.reallocate(buf, buf.length + T.sizeof * delta))
1571         {
1572             return false;
1573         }
1574         array = cast(T[]) buf;
1575         // At this point we're committed to the new length.
1576 
1577         auto toFill = array[oldLength .. $];
1578         scope (failure)
1579         {
1580             // Fill the remainder with default-constructed data
1581             toFill.uninitializedFillDefault;
1582         }
1583 
1584         for (; !range.empty; range.popFront, toFill.popFront)
1585         {
1586             assert(!toFill.empty);
1587             import std.conv : emplace;
1588             emplace!T(&toFill.front, range.front);
1589         }
1590         assert(toFill.empty);
1591     }
1592     else
1593     {
1594         scope(failure)
1595         {
1596             // The last element didn't make it, fill with default
1597             array[$ - 1 .. $].uninitializedFillDefault;
1598         }
1599         void[] buf = array;
1600         for (; !range.empty; range.popFront)
1601         {
1602             if (!alloc.reallocate(buf, buf.length + T.sizeof))
1603             {
1604                 array = cast(T[]) buf;
1605                 return false;
1606             }
1607             import std.conv : emplace;
1608             emplace!T(buf[$ - T.sizeof .. $], range.front);
1609         }
1610 
1611         array = cast(T[]) buf;
1612     }
1613     return true;
1614 }
1615 
1616 ///
1617 @system unittest
1618 {
1619     auto arr = theAllocator.makeArray!int([1, 2, 3]);
1620     assert(theAllocator.expandArray(arr, 2));
1621     assert(arr == [1, 2, 3, 0, 0]);
1622     import std.range : only;
1623     assert(theAllocator.expandArray(arr, only(4, 5)));
1624     assert(arr == [1, 2, 3, 0, 0, 4, 5]);
1625 }
1626 
1627 @system unittest
1628 {
1629     auto arr = theAllocator.makeArray!int([1, 2, 3]);
1630     ForcedInputRange r;
1631     int[] b = [ 1, 2, 3, 4 ];
1632     auto temp = b;
1633     r.array = &temp;
1634     assert(theAllocator.expandArray(arr, r));
1635     assert(arr == [1, 2, 3, 1, 2, 3, 4]);
1636 }
1637 
1638 /**
1639 Shrinks an array by $(D delta) elements.
1640 
1641 If $(D array.length < delta), does nothing and returns `false`. Otherwise,
1642 destroys the last $(D array.length - delta) elements in the array and then
1643 reallocates the array's buffer. If reallocation fails, fills the array with
1644 default-initialized data.
1645 
1646 Params:
1647 T = element type of the array being created
1648 alloc = the allocator used for getting memory
1649 array = a reference to the array being shrunk
1650 delta = number of elements to remove (upon success the new length of $(D array) is $(D array.length - delta))
1651 
1652 Returns:
1653 `true` upon success, `false` if memory could not be reallocated. In the latter
1654 case, the slice $(D array[$ - delta .. $]) is left with default-initialized
1655 elements.
1656 
1657 Throws:
1658 The first two overloads throw only if `alloc`'s primitives do. The
1659 overloads that involve copy initialization deallocate memory and propagate the
1660 exception if the copy operation throws.
1661 */
1662 bool shrinkArray(T, Allocator)(auto ref Allocator alloc,
1663         ref T[] array, size_t delta)
1664 {
1665     if (delta > array.length) return false;
1666 
1667     // Destroy elements. If a destructor throws, fill the already destroyed
1668     // stuff with the default initializer.
1669     {
1670         size_t destroyed;
1671         scope(failure)
1672         {
1673             array[$ - delta .. $][0 .. destroyed].uninitializedFillDefault;
1674         }
1675         foreach (ref e; array[$ - delta .. $])
1676         {
1677             e.destroy;
1678             ++destroyed;
1679         }
1680     }
1681 
1682     if (delta == array.length)
1683     {
1684         alloc.deallocate(array);
1685         array = null;
1686         return true;
1687     }
1688 
1689     void[] buf = array;
1690     if (!alloc.reallocate(buf, buf.length - T.sizeof * delta))
1691     {
1692         // urgh, at least fill back with default
1693         array[$ - delta .. $].uninitializedFillDefault;
1694         return false;
1695     }
1696     array = cast(T[]) buf;
1697     return true;
1698 }
1699 
1700 ///
1701 @system unittest
1702 {
1703     int[] a = theAllocator.makeArray!int(100, 42);
1704     assert(a.length == 100);
1705     assert(theAllocator.shrinkArray(a, 98));
1706     assert(a.length == 2);
1707     assert(a == [42, 42]);
1708 }
1709 
1710 @system unittest
1711 {
1712     void test(A)(auto ref A alloc)
1713     {
1714         long[] a = alloc.makeArray!long((int[]).init);
1715         assert(a.length == 0 && a.ptr is null);
1716         a = alloc.makeArray!long(100, 42);
1717         assert(alloc.shrinkArray(a, 98));
1718         assert(a.length == 2);
1719         assert(a == [ 42, 42]);
1720     }
1721     import std.experimental.allocator.gc_allocator : GCAllocator;
1722     test(GCAllocator.instance);
1723     test(theAllocator);
1724 }
1725 
1726 /**
1727 
1728 Destroys and then deallocates (using $(D alloc)) the object pointed to by a
1729 pointer, the class object referred to by a $(D class) or $(D interface)
1730 reference, or an entire array. It is assumed the respective entities had been
1731 allocated with the same allocator.
1732 
1733 */
1734 void dispose(A, T)(auto ref A alloc, T* p)
1735 {
1736     static if (hasElaborateDestructor!T)
1737     {
1738         destroy(*p);
1739     }
1740     alloc.deallocate((cast(void*) p)[0 .. T.sizeof]);
1741 }
1742 
1743 /// Ditto
1744 void dispose(A, T)(auto ref A alloc, T p)
1745 if (is(T == class) || is(T == interface))
1746 {
1747     if (!p) return;
1748     static if (is(T == interface))
1749     {
1750         version (Windows)
1751         {
1752             import core.sys.windows.unknwn : IUnknown;
1753             static assert(!is(T: IUnknown), "COM interfaces can't be destroyed in "
1754                 ~ __PRETTY_FUNCTION__);
1755         }
1756         auto ob = cast(Object) p;
1757     }
1758     else
1759         alias ob = p;
1760     auto support = (cast(void*) ob)[0 .. typeid(ob).initializer.length];
1761     destroy(p);
1762     alloc.deallocate(support);
1763 }
1764 
1765 /// Ditto
1766 void dispose(A, T)(auto ref A alloc, T[] array)
1767 {
1768     static if (hasElaborateDestructor!(typeof(array[0])))
1769     {
1770         foreach (ref e; array)
1771         {
1772             destroy(e);
1773         }
1774     }
1775     alloc.deallocate(array);
1776 }
1777 
1778 @system unittest
1779 {
1780     static int x;
1781     static interface I
1782     {
1783         void method();
1784     }
1785     static class A : I
1786     {
1787         int y;
1788         override void method() { x = 21; }
1789         ~this() { x = 42; }
1790     }
1791     static class B : A
1792     {
1793     }
1794     auto a = theAllocator.make!A;
1795     a.method();
1796     assert(x == 21);
1797     theAllocator.dispose(a);
1798     assert(x == 42);
1799 
1800     B b = theAllocator.make!B;
1801     b.method();
1802     assert(x == 21);
1803     theAllocator.dispose(b);
1804     assert(x == 42);
1805 
1806     I i = theAllocator.make!B;
1807     i.method();
1808     assert(x == 21);
1809     theAllocator.dispose(i);
1810     assert(x == 42);
1811 
1812     int[] arr = theAllocator.makeArray!int(43);
1813     theAllocator.dispose(arr);
1814 }
1815 
1816 @system unittest //bugzilla 15721
1817 {
1818     import std.experimental.allocator.mallocator : Mallocator;
1819 
1820     interface Foo {}
1821     class Bar: Foo {}
1822 
1823     Bar bar;
1824     Foo foo;
1825     bar = Mallocator.instance.make!Bar;
1826     foo = cast(Foo) bar;
1827     Mallocator.instance.dispose(foo);
1828 }
1829 
1830 /**
1831 Allocates a multidimensional array of elements of type T.
1832 
1833 Params:
1834 N = number of dimensions
1835 T = element type of an element of the multidimensional arrat
1836 alloc = the allocator used for getting memory
1837 lengths = static array containing the size of each dimension
1838 
1839 Returns:
1840 An N-dimensional array with individual elements of type T.
1841 */
1842 auto makeMultidimensionalArray(T, Allocator, size_t N)(auto ref Allocator alloc, size_t[N] lengths...)
1843 {
1844     static if (N == 1)
1845     {
1846         return makeArray!T(alloc, lengths[0]);
1847     }
1848     else
1849     {
1850         alias E = typeof(makeMultidimensionalArray!(T, Allocator, N - 1)(alloc, lengths[1 .. $]));
1851         auto ret = makeArray!E(alloc, lengths[0]);
1852         foreach (ref e; ret)
1853             e = makeMultidimensionalArray!(T, Allocator, N - 1)(alloc, lengths[1 .. $]);
1854         return ret;
1855     }
1856 }
1857 
1858 ///
1859 @system unittest
1860 {
1861     import std.experimental.allocator.mallocator : Mallocator;
1862 
1863     auto mArray = Mallocator.instance.makeMultidimensionalArray!int(2, 3, 6);
1864 
1865     // deallocate when exiting scope
1866     scope(exit)
1867     {
1868         Mallocator.instance.disposeMultidimensionalArray(mArray);
1869     }
1870 
1871     assert(mArray.length == 2);
1872     foreach (lvl2Array; mArray)
1873     {
1874         assert(lvl2Array.length == 3);
1875         foreach (lvl3Array; lvl2Array)
1876             assert(lvl3Array.length == 6);
1877     }
1878 }
1879 
1880 /**
1881 Destroys and then deallocates a multidimensional array, assuming it was
1882 created with makeMultidimensionalArray and the same allocator was used.
1883 
1884 Params:
1885 T = element type of an element of the multidimensional array
1886 alloc = the allocator used for getting memory
1887 array = the multidimensional array that is to be deallocated
1888 */
1889 void disposeMultidimensionalArray(T, Allocator)(auto ref Allocator alloc, T[] array)
1890 {
1891     static if (isArray!T)
1892     {
1893         foreach (ref e; array)
1894             disposeMultidimensionalArray(alloc, e);
1895     }
1896 
1897     dispose(alloc, array);
1898 }
1899 
1900 ///
1901 @system unittest
1902 {
1903     struct TestAllocator
1904     {
1905         import std.experimental.allocator.common : platformAlignment;
1906         import std.experimental.allocator.mallocator : Mallocator;
1907 
1908         alias allocator = Mallocator.instance;
1909 
1910         private static struct ByteRange
1911         {
1912             void* ptr;
1913             size_t length;
1914         }
1915 
1916         private ByteRange[] _allocations;
1917 
1918         enum uint alignment = platformAlignment;
1919 
1920         void[] allocate(size_t numBytes)
1921         {
1922              auto ret = allocator.allocate(numBytes);
1923              _allocations ~= ByteRange(ret.ptr, ret.length);
1924              return ret;
1925         }
1926 
1927         bool deallocate(void[] bytes)
1928         {
1929             import std.algorithm.mutation : remove;
1930             import std.algorithm.searching : canFind;
1931 
1932             bool pred(ByteRange other)
1933             { return other.ptr == bytes.ptr && other.length == bytes.length; }
1934 
1935             assert(_allocations.canFind!pred);
1936 
1937              _allocations = _allocations.remove!pred;
1938              return allocator.deallocate(bytes);
1939         }
1940 
1941         ~this()
1942         {
1943             assert(!_allocations.length);
1944         }
1945     }
1946 
1947     TestAllocator allocator;
1948 
1949     auto mArray = allocator.makeMultidimensionalArray!int(2, 3, 5, 6, 7, 2);
1950 
1951     allocator.disposeMultidimensionalArray(mArray);
1952 }
1953 
1954 /**
1955 
1956 Returns a dynamically-typed $(D CAllocator) built around a given statically-
1957 typed allocator $(D a) of type $(D A). Passing a pointer to the allocator
1958 creates a dynamic allocator around the allocator pointed to by the pointer,
1959 without attempting to copy or move it. Passing the allocator by value or
1960 reference behaves as follows.
1961 
1962 $(UL
1963 $(LI If $(D A) has no state, the resulting object is allocated in static
1964 shared storage.)
1965 $(LI If $(D A) has state and is copyable, the result will store a copy of it
1966 within. The result itself is allocated in its own statically-typed allocator.)
1967 $(LI If $(D A) has state and is not copyable, the result will move the
1968 passed-in argument into the result. The result itself is allocated in its own
1969 statically-typed allocator.)
1970 )
1971 
1972 */
1973 CAllocatorImpl!A allocatorObject(A)(auto ref A a)
1974 if (!isPointer!A)
1975 {
1976     import std.conv : emplace;
1977     static if (stateSize!A == 0)
1978     {
1979         enum s = stateSize!(CAllocatorImpl!A).divideRoundUp(ulong.sizeof);
1980         static __gshared ulong[s] state;
1981         static __gshared CAllocatorImpl!A result;
1982         if (!result)
1983         {
1984             // Don't care about a few races
1985             result = emplace!(CAllocatorImpl!A)(state[]);
1986         }
1987         assert(result);
1988         return result;
1989     }
1990     else static if (is(typeof({ A b = a; A c = b; }))) // copyable
1991     {
1992         auto state = a.allocate(stateSize!(CAllocatorImpl!A));
1993         import std.traits : hasMember;
1994         static if (hasMember!(A, "deallocate"))
1995         {
1996             scope(failure) a.deallocate(state);
1997         }
1998         return cast(CAllocatorImpl!A) emplace!(CAllocatorImpl!A)(state);
1999     }
2000     else // the allocator object is not copyable
2001     {
2002         // This is sensitive... create on the stack and then move
2003         enum s = stateSize!(CAllocatorImpl!A).divideRoundUp(ulong.sizeof);
2004         ulong[s] state;
2005         import std.algorithm.mutation : move;
2006         emplace!(CAllocatorImpl!A)(state[], move(a));
2007         auto dynState = a.allocate(stateSize!(CAllocatorImpl!A));
2008         // Bitblast the object in its final destination
2009         dynState[] = state[];
2010         return cast(CAllocatorImpl!A) dynState.ptr;
2011     }
2012 }
2013 
2014 /// Ditto
2015 CAllocatorImpl!(A, Yes.indirect) allocatorObject(A)(A* pa)
2016 {
2017     assert(pa);
2018     import std.conv : emplace;
2019     auto state = pa.allocate(stateSize!(CAllocatorImpl!(A, Yes.indirect)));
2020     import std.traits : hasMember;
2021     static if (hasMember!(A, "deallocate"))
2022     {
2023         scope(failure) pa.deallocate(state);
2024     }
2025     return emplace!(CAllocatorImpl!(A, Yes.indirect))
2026         (state, pa);
2027 }
2028 
2029 ///
2030 @system unittest
2031 {
2032     import std.experimental.allocator.mallocator : Mallocator;
2033     IAllocator a = allocatorObject(Mallocator.instance);
2034     auto b = a.allocate(100);
2035     assert(b.length == 100);
2036     assert(a.deallocate(b));
2037 
2038     // The in-situ region must be used by pointer
2039     import std.experimental.allocator.building_blocks.region : InSituRegion;
2040     auto r = InSituRegion!1024();
2041     a = allocatorObject(&r);
2042     b = a.allocate(200);
2043     assert(b.length == 200);
2044     // In-situ regions can deallocate the last allocation
2045     assert(a.deallocate(b));
2046 }
2047 
2048 /**
2049 
2050 Returns a dynamically-typed $(D CSharedAllocator) built around a given statically-
2051 typed allocator $(D a) of type $(D A). Passing a pointer to the allocator
2052 creates a dynamic allocator around the allocator pointed to by the pointer,
2053 without attempting to copy or move it. Passing the allocator by value or
2054 reference behaves as follows.
2055 
2056 $(UL
2057 $(LI If $(D A) has no state, the resulting object is allocated in static
2058 shared storage.)
2059 $(LI If $(D A) has state and is copyable, the result will store a copy of it
2060 within. The result itself is allocated in its own statically-typed allocator.)
2061 $(LI If $(D A) has state and is not copyable, the result will move the
2062 passed-in argument into the result. The result itself is allocated in its own
2063 statically-typed allocator.)
2064 )
2065 
2066 */
2067 shared(CSharedAllocatorImpl!A) sharedAllocatorObject(A)(auto ref A a)
2068 if (!isPointer!A)
2069 {
2070     import std.conv : emplace;
2071     static if (stateSize!A == 0)
2072     {
2073         enum s = stateSize!(CSharedAllocatorImpl!A).divideRoundUp(ulong.sizeof);
2074         static __gshared ulong[s] state;
2075         static shared CSharedAllocatorImpl!A result;
2076         if (!result)
2077         {
2078             // Don't care about a few races
2079             result = cast(shared
2080                     CSharedAllocatorImpl!A)(emplace!(CSharedAllocatorImpl!A)(state[]));
2081         }
2082         assert(result);
2083         return result;
2084     }
2085     else static if (is(typeof({ shared A b = a; shared A c = b; }))) // copyable
2086     {
2087         auto state = a.allocate(stateSize!(CSharedAllocatorImpl!A));
2088         import std.traits : hasMember;
2089         static if (hasMember!(A, "deallocate"))
2090         {
2091             scope(failure) a.deallocate(state);
2092         }
2093         return emplace!(shared CSharedAllocatorImpl!A)(state);
2094     }
2095     else // the allocator object is not copyable
2096     {
2097         assert(0, "Not yet implemented");
2098     }
2099 }
2100 
2101 /// Ditto
2102 shared(CSharedAllocatorImpl!(A, Yes.indirect)) sharedAllocatorObject(A)(A* pa)
2103 {
2104     assert(pa);
2105     import std.conv : emplace;
2106     auto state = pa.allocate(stateSize!(CSharedAllocatorImpl!(A, Yes.indirect)));
2107     import std.traits : hasMember;
2108     static if (hasMember!(A, "deallocate"))
2109     {
2110         scope(failure) pa.deallocate(state);
2111     }
2112     return emplace!(shared CSharedAllocatorImpl!(A, Yes.indirect))(state, pa);
2113 }
2114 
2115 
2116 /**
2117 
2118 Implementation of `IAllocator` using `Allocator`. This adapts a
2119 statically-built allocator type to `IAllocator` that is directly usable by
2120 non-templated code.
2121 
2122 Usually `CAllocatorImpl` is used indirectly by calling $(LREF theAllocator).
2123 */
2124 class CAllocatorImpl(Allocator, Flag!"indirect" indirect = No.indirect)
2125     : IAllocator
2126 {
2127     import std.traits : hasMember;
2128 
2129     /**
2130     The implementation is available as a public member.
2131     */
2132     static if (indirect)
2133     {
2134         private Allocator* pimpl;
2135         ref Allocator impl()
2136         {
2137             return *pimpl;
2138         }
2139         this(Allocator* pa)
2140         {
2141             pimpl = pa;
2142         }
2143     }
2144     else
2145     {
2146         static if (stateSize!Allocator) Allocator impl;
2147         else alias impl = Allocator.instance;
2148     }
2149 
2150     /// Returns `impl.alignment`.
2151     override @property uint alignment()
2152     {
2153         return impl.alignment;
2154     }
2155 
2156     /**
2157     Returns `impl.goodAllocSize(s)`.
2158     */
2159     override size_t goodAllocSize(size_t s)
2160     {
2161         return impl.goodAllocSize(s);
2162     }
2163 
2164     /**
2165     Returns `impl.allocate(s)`.
2166     */
2167     override void[] allocate(size_t s, TypeInfo ti = null)
2168     {
2169         return impl.allocate(s);
2170     }
2171 
2172     /**
2173     If `impl.alignedAllocate` exists, calls it and returns the result.
2174     Otherwise, always returns `null`.
2175     */
2176     override void[] alignedAllocate(size_t s, uint a)
2177     {
2178         static if (hasMember!(Allocator, "alignedAllocate"))
2179             return impl.alignedAllocate(s, a);
2180         else
2181             return null;
2182     }
2183 
2184     /**
2185     If `Allocator` implements `owns`, forwards to it. Otherwise, returns
2186     `Ternary.unknown`.
2187     */
2188     override Ternary owns(void[] b)
2189     {
2190         static if (hasMember!(Allocator, "owns")) return impl.owns(b);
2191         else return Ternary.unknown;
2192     }
2193 
2194     /// Returns $(D impl.expand(b, s)) if defined, `false` otherwise.
2195     override bool expand(ref void[] b, size_t s)
2196     {
2197         static if (hasMember!(Allocator, "expand"))
2198             return impl.expand(b, s);
2199         else
2200             return s == 0;
2201     }
2202 
2203     /// Returns $(D impl.reallocate(b, s)).
2204     override bool reallocate(ref void[] b, size_t s)
2205     {
2206         return impl.reallocate(b, s);
2207     }
2208 
2209     /// Forwards to `impl.alignedReallocate` if defined, `false` otherwise.
2210     bool alignedReallocate(ref void[] b, size_t s, uint a)
2211     {
2212         static if (!hasMember!(Allocator, "alignedAllocate"))
2213         {
2214             return false;
2215         }
2216         else
2217         {
2218             return impl.alignedReallocate(b, s, a);
2219         }
2220     }
2221 
2222     // Undocumented for now
2223     Ternary resolveInternalPointer(const void* p, ref void[] result)
2224     {
2225         static if (hasMember!(Allocator, "resolveInternalPointer"))
2226         {
2227             return impl.resolveInternalPointer(p, result);
2228         }
2229         else
2230         {
2231             return Ternary.unknown;
2232         }
2233     }
2234 
2235     /**
2236     If `impl.deallocate` is not defined, returns `false`. Otherwise it forwards
2237     the call.
2238     */
2239     override bool deallocate(void[] b)
2240     {
2241         static if (hasMember!(Allocator, "deallocate"))
2242         {
2243             return impl.deallocate(b);
2244         }
2245         else
2246         {
2247             return false;
2248         }
2249     }
2250 
2251     /**
2252     Calls `impl.deallocateAll()` and returns the result if defined,
2253     otherwise returns `false`.
2254     */
2255     override bool deallocateAll()
2256     {
2257         static if (hasMember!(Allocator, "deallocateAll"))
2258         {
2259             return impl.deallocateAll();
2260         }
2261         else
2262         {
2263             return false;
2264         }
2265     }
2266 
2267     /**
2268     Forwards to `impl.empty()` if defined, otherwise returns `Ternary.unknown`.
2269     */
2270     override Ternary empty()
2271     {
2272         static if (hasMember!(Allocator, "empty"))
2273         {
2274             return Ternary(impl.empty);
2275         }
2276         else
2277         {
2278             return Ternary.unknown;
2279         }
2280     }
2281 
2282     /**
2283     Returns `impl.allocateAll()` if present, `null` otherwise.
2284     */
2285     override void[] allocateAll()
2286     {
2287         static if (hasMember!(Allocator, "allocateAll"))
2288         {
2289             return impl.allocateAll();
2290         }
2291         else
2292         {
2293             return null;
2294         }
2295     }
2296 }
2297 
2298 /**
2299 
2300 Implementation of `ISharedAllocator` using `Allocator`. This adapts a
2301 statically-built, shareable across threads, allocator type to `ISharedAllocator`
2302 that is directly usable by non-templated code.
2303 
2304 Usually `CSharedAllocatorImpl` is used indirectly by calling
2305 $(LREF processAllocator).
2306 */
2307 class CSharedAllocatorImpl(Allocator, Flag!"indirect" indirect = No.indirect)
2308     : ISharedAllocator
2309 {
2310     import std.traits : hasMember;
2311 
2312     /**
2313     The implementation is available as a public member.
2314     */
2315     static if (indirect)
2316     {
2317         private shared Allocator* pimpl;
2318         ref Allocator impl() shared
2319         {
2320             return *pimpl;
2321         }
2322         this(Allocator* pa) shared
2323         {
2324             pimpl = pa;
2325         }
2326     }
2327     else
2328     {
2329         static if (stateSize!Allocator) shared Allocator impl;
2330         else alias impl = Allocator.instance;
2331     }
2332 
2333     /// Returns `impl.alignment`.
2334     override @property uint alignment() shared
2335     {
2336         return impl.alignment;
2337     }
2338 
2339     /**
2340     Returns `impl.goodAllocSize(s)`.
2341     */
2342     override size_t goodAllocSize(size_t s) shared
2343     {
2344         return impl.goodAllocSize(s);
2345     }
2346 
2347     /**
2348     Returns `impl.allocate(s)`.
2349     */
2350     override void[] allocate(size_t s, TypeInfo ti = null) shared
2351     {
2352         return impl.allocate(s);
2353     }
2354 
2355     /**
2356     If `impl.alignedAllocate` exists, calls it and returns the result.
2357     Otherwise, always returns `null`.
2358     */
2359     override void[] alignedAllocate(size_t s, uint a) shared
2360     {
2361         static if (hasMember!(Allocator, "alignedAllocate"))
2362             return impl.alignedAllocate(s, a);
2363         else
2364             return null;
2365     }
2366 
2367     /**
2368     If `Allocator` implements `owns`, forwards to it. Otherwise, returns
2369     `Ternary.unknown`.
2370     */
2371     override Ternary owns(void[] b) shared
2372     {
2373         static if (hasMember!(Allocator, "owns")) return impl.owns(b);
2374         else return Ternary.unknown;
2375     }
2376 
2377     /// Returns $(D impl.expand(b, s)) if defined, `false` otherwise.
2378     override bool expand(ref void[] b, size_t s) shared
2379     {
2380         static if (hasMember!(Allocator, "expand"))
2381             return impl.expand(b, s);
2382         else
2383             return s == 0;
2384     }
2385 
2386     /// Returns $(D impl.reallocate(b, s)).
2387     override bool reallocate(ref void[] b, size_t s) shared
2388     {
2389         return impl.reallocate(b, s);
2390     }
2391 
2392     /// Forwards to `impl.alignedReallocate` if defined, `false` otherwise.
2393     bool alignedReallocate(ref void[] b, size_t s, uint a) shared
2394     {
2395         static if (!hasMember!(Allocator, "alignedAllocate"))
2396         {
2397             return false;
2398         }
2399         else
2400         {
2401             return impl.alignedReallocate(b, s, a);
2402         }
2403     }
2404 
2405     // Undocumented for now
2406     Ternary resolveInternalPointer(const void* p, ref void[] result) shared
2407     {
2408         static if (hasMember!(Allocator, "resolveInternalPointer"))
2409         {
2410             return impl.resolveInternalPointer(p, result);
2411         }
2412         else
2413         {
2414             return Ternary.unknown;
2415         }
2416     }
2417 
2418     /**
2419     If `impl.deallocate` is not defined, returns `false`. Otherwise it forwards
2420     the call.
2421     */
2422     override bool deallocate(void[] b) shared
2423     {
2424         static if (hasMember!(Allocator, "deallocate"))
2425         {
2426             return impl.deallocate(b);
2427         }
2428         else
2429         {
2430             return false;
2431         }
2432     }
2433 
2434     /**
2435     Calls `impl.deallocateAll()` and returns the result if defined,
2436     otherwise returns `false`.
2437     */
2438     override bool deallocateAll() shared
2439     {
2440         static if (hasMember!(Allocator, "deallocateAll"))
2441         {
2442             return impl.deallocateAll();
2443         }
2444         else
2445         {
2446             return false;
2447         }
2448     }
2449 
2450     /**
2451     Forwards to `impl.empty()` if defined, otherwise returns `Ternary.unknown`.
2452     */
2453     override Ternary empty() shared
2454     {
2455         static if (hasMember!(Allocator, "empty"))
2456         {
2457             return Ternary(impl.empty);
2458         }
2459         else
2460         {
2461             return Ternary.unknown;
2462         }
2463     }
2464 
2465     /**
2466     Returns `impl.allocateAll()` if present, `null` otherwise.
2467     */
2468     override void[] allocateAll() shared
2469     {
2470         static if (hasMember!(Allocator, "allocateAll"))
2471         {
2472             return impl.allocateAll();
2473         }
2474         else
2475         {
2476             return null;
2477         }
2478     }
2479 }
2480 
2481 
2482 // Example in intro above
2483 @system unittest
2484 {
2485     // Allocate an int, initialize it with 42
2486     int* p = theAllocator.make!int(42);
2487     assert(*p == 42);
2488 
2489     // Destroy and deallocate it
2490     theAllocator.dispose(p);
2491 
2492     // Allocate using the global process allocator
2493     p = processAllocator.make!int(100);
2494     assert(*p == 100);
2495 
2496     // Destroy and deallocate
2497     processAllocator.dispose(p);
2498 
2499     // Create an array of 50 doubles initialized to -1.0
2500     double[] arr = theAllocator.makeArray!double(50, -1.0);
2501 
2502     // Check internal pointer
2503     void[] result;
2504     assert(theAllocator.resolveInternalPointer(null, result) == Ternary.no);
2505     Ternary r = theAllocator.resolveInternalPointer(arr.ptr, result);
2506     assert(result.ptr is arr.ptr && result.length >= arr.length);
2507 
2508     // Append two zeros to it
2509     theAllocator.expandArray(arr, 2, 0.0);
2510     // On second thought, take that back
2511     theAllocator.shrinkArray(arr, 2);
2512     // Destroy and deallocate
2513     theAllocator.dispose(arr);
2514 }
2515 
2516 __EOF__
2517 
2518 /**
2519 
2520 Stores an allocator object in thread-local storage (i.e. non-$(D shared) D
2521 global). $(D ThreadLocal!A) is a subtype of $(D A) so it appears to implement
2522 $(D A)'s allocator primitives.
2523 
2524 $(D A) must hold state, otherwise $(D ThreadLocal!A) refuses instantiation. This
2525 means e.g. $(D ThreadLocal!Mallocator) does not work because $(D Mallocator)'s
2526 state is not stored as members of $(D Mallocator), but instead is hidden in the
2527 C library implementation.
2528 
2529 */
2530 struct ThreadLocal(A)
2531 {
2532     static assert(stateSize!A,
2533         typeof(A).stringof
2534         ~ " does not have state so it cannot be used with ThreadLocal");
2535 
2536     /**
2537     The allocator instance.
2538     */
2539     static A instance;
2540 
2541     /**
2542     `ThreadLocal!A` is a subtype of `A` so it appears to implement `A`'s
2543     allocator primitives.
2544     */
2545     alias instance this;
2546 
2547     /**
2548     `ThreadLocal` disables all constructors. The intended usage is
2549     `ThreadLocal!A.instance`.
2550     */
2551     @disable this();
2552     /// Ditto
2553     @disable this(this);
2554 }
2555 
2556 ///
2557 unittest
2558 {
2559     static assert(!is(ThreadLocal!Mallocator));
2560     static assert(!is(ThreadLocal!GCAllocator));
2561     alias ThreadLocal!(FreeList!(GCAllocator, 0, 8)) Allocator;
2562     auto b = Allocator.instance.allocate(5);
2563     static assert(hasMember!(Allocator, "allocate"));
2564 }
2565 
2566 /*
2567 (Not public.)
2568 
2569 A binary search tree that uses no allocation of its own. Instead, it relies on
2570 user code to allocate nodes externally. Then $(D EmbeddedTree)'s primitives wire
2571 the nodes appropriately.
2572 
2573 Warning: currently $(D EmbeddedTree) is not using rebalancing, so it may
2574 degenerate. A red-black tree implementation storing the color with one of the
2575 pointers is planned for the future.
2576 */
2577 private struct EmbeddedTree(T, alias less)
2578 {
2579     static struct Node
2580     {
2581         T payload;
2582         Node* left, right;
2583     }
2584 
2585     private Node* root;
2586 
2587     private Node* insert(Node* n, ref Node* backref)
2588     {
2589         backref = n;
2590         n.left = n.right = null;
2591         return n;
2592     }
2593 
2594     Node* find(Node* data)
2595     {
2596         for (auto n = root; n; )
2597         {
2598             if (less(data, n))
2599             {
2600                 n = n.left;
2601             }
2602             else if (less(n, data))
2603             {
2604                 n = n.right;
2605             }
2606             else
2607             {
2608                 return n;
2609             }
2610         }
2611         return null;
2612     }
2613 
2614     Node* insert(Node* data)
2615     {
2616         if (!root)
2617         {
2618             root = data;
2619             data.left = data.right = null;
2620             return root;
2621         }
2622         auto n = root;
2623         for (;;)
2624         {
2625             if (less(data, n))
2626             {
2627                 if (!n.left)
2628                 {
2629                     // Found insertion point
2630                     return insert(data, n.left);
2631                 }
2632                 n = n.left;
2633             }
2634             else if (less(n, data))
2635             {
2636                 if (!n.right)
2637                 {
2638                     // Found insertion point
2639                     return insert(data, n.right);
2640                 }
2641                 n = n.right;
2642             }
2643             else
2644             {
2645                 // Found
2646                 return n;
2647             }
2648             if (!n) return null;
2649         }
2650     }
2651 
2652     Node* remove(Node* data)
2653     {
2654         auto n = root;
2655         Node* parent = null;
2656         for (;;)
2657         {
2658             if (!n) return null;
2659             if (less(data, n))
2660             {
2661                 parent = n;
2662                 n = n.left;
2663             }
2664             else if (less(n, data))
2665             {
2666                 parent = n;
2667                 n = n.right;
2668             }
2669             else
2670             {
2671                 // Found
2672                 remove(n, parent);
2673                 return n;
2674             }
2675         }
2676     }
2677 
2678     private void remove(Node* n, Node* parent)
2679     {
2680         assert(n);
2681         assert(!parent || parent.left == n || parent.right == n);
2682         Node** referrer = parent
2683             ? (parent.left == n ? &parent.left : &parent.right)
2684             : &root;
2685         if (!n.left)
2686         {
2687             *referrer = n.right;
2688         }
2689         else if (!n.right)
2690         {
2691             *referrer = n.left;
2692         }
2693         else
2694         {
2695             // Find the leftmost child in the right subtree
2696             auto leftmost = n.right;
2697             Node** leftmostReferrer = &n.right;
2698             while (leftmost.left)
2699             {
2700                 leftmostReferrer = &leftmost.left;
2701                 leftmost = leftmost.left;
2702             }
2703             // Unlink leftmost from there
2704             *leftmostReferrer = leftmost.right;
2705             // Link leftmost in lieu of n
2706             leftmost.left = n.left;
2707             leftmost.right = n.right;
2708             *referrer = leftmost;
2709         }
2710     }
2711 
2712     Ternary empty() const
2713     {
2714         return Ternary(!root);
2715     }
2716 
2717     void dump()
2718     {
2719         writeln(typeid(this), " @ ", cast(void*) &this);
2720         dump(root, 3);
2721     }
2722 
2723     void dump(Node* r, uint indent)
2724     {
2725         write(repeat(' ', indent).array);
2726         if (!r)
2727         {
2728             writeln("(null)");
2729             return;
2730         }
2731         writeln(r.payload, " @ ", cast(void*) r);
2732         dump(r.left, indent + 3);
2733         dump(r.right, indent + 3);
2734     }
2735 
2736     void assertSane()
2737     {
2738         static bool isBST(Node* r, Node* lb, Node* ub)
2739         {
2740             if (!r) return true;
2741             if (lb && !less(lb, r)) return false;
2742             if (ub && !less(r, ub)) return false;
2743             return isBST(r.left, lb, r) &&
2744                 isBST(r.right, r, ub);
2745         }
2746         if (isBST(root, null, null)) return;
2747         dump;
2748         assert(0);
2749     }
2750 }
2751 
2752 unittest
2753 {
2754     alias a = GCAllocator.instance;
2755     alias Tree = EmbeddedTree!(int, (a, b) => a.payload < b.payload);
2756     Tree t;
2757     assert(t.empty);
2758     int[] vals = [ 6, 3, 9, 1, 0, 2, 8, 11 ];
2759     foreach (v; vals)
2760     {
2761         auto n = new Tree.Node(v, null, null);
2762         assert(t.insert(n));
2763         assert(n);
2764         t.assertSane;
2765     }
2766     assert(!t.empty);
2767     foreach (v; vals)
2768     {
2769         Tree.Node n = { v };
2770         assert(t.remove(&n));
2771         t.assertSane;
2772     }
2773     assert(t.empty);
2774 }
2775 
2776 /*
2777 
2778 $(D InternalPointersTree) adds a primitive on top of another allocator: calling
2779 $(D resolveInternalPointer(p)) returns the block within which the internal
2780 pointer $(D p) lies. Pointers right after the end of allocated blocks are also
2781 considered internal.
2782 
2783 The implementation stores three additional words with each allocation (one for
2784 the block size and two for search management).
2785 
2786 */
2787 private struct InternalPointersTree(Allocator)
2788 {
2789     alias Tree = EmbeddedTree!(size_t,
2790         (a, b) => cast(void*) a + a.payload < cast(void*) b);
2791     alias Parent = AffixAllocator!(Allocator, Tree.Node);
2792 
2793     // Own state
2794     private Tree blockMap;
2795 
2796     alias alignment = Parent.alignment;
2797 
2798     /**
2799     The implementation is available as a public member.
2800     */
2801     static if (stateSize!Parent) Parent parent;
2802     else alias parent = Parent.instance;
2803 
2804     /// Allocator API.
2805     void[] allocate(size_t bytes)
2806     {
2807         auto r = parent.allocate(bytes);
2808         if (!r.ptr) return r;
2809         Tree.Node* n = &parent.prefix(r);
2810         n.payload = bytes;
2811         blockMap.insert(n) || assert(0);
2812         return r;
2813     }
2814 
2815     /// Ditto
2816     bool deallocate(void[] b)
2817     {
2818         if (!b.ptr) return;
2819         Tree.Node* n = &parent.prefix(b);
2820         blockMap.remove(n) || assert(false);
2821         parent.deallocate(b);
2822         return true;
2823     }
2824 
2825     /// Ditto
2826     static if (hasMember!(Allocator, "reallocate"))
2827     bool reallocate(ref void[] b, size_t s)
2828     {
2829         auto n = &parent.prefix(b);
2830         assert(n.payload == b.length);
2831         blockMap.remove(n) || assert(0);
2832         if (!parent.reallocate(b, s))
2833         {
2834             // Failed, must reinsert the same node in the tree
2835             assert(n.payload == b.length);
2836             blockMap.insert(n) || assert(0);
2837             return false;
2838         }
2839         // Insert the new node
2840         n = &parent.prefix(b);
2841         n.payload = s;
2842         blockMap.insert(n) || assert(0);
2843         return true;
2844     }
2845 
2846     /// Ditto
2847     Ternary owns(void[] b)
2848     {
2849         void[] result;
2850         return resolveInternalPointer(b.ptr, result);
2851     }
2852 
2853     /// Ditto
2854     Ternary empty()
2855     {
2856         return Ternary(blockMap.empty);
2857     }
2858 
2859     /** Returns the block inside which $(D p) resides, or $(D null) if the
2860     pointer does not belong.
2861     */
2862     Ternary resolveInternalPointer(const void* p, ref void[] result)
2863     {
2864         // Must define a custom find
2865         Tree.Node* find()
2866         {
2867             for (auto n = blockMap.root; n; )
2868             {
2869                 if (p < n)
2870                 {
2871                     n = n.left;
2872                 }
2873                 else if (p > (cast(void*) (n + 1)) + n.payload)
2874                 {
2875                     n = n.right;
2876                 }
2877                 else
2878                 {
2879                     return n;
2880                 }
2881             }
2882             return null;
2883         }
2884 
2885         auto n = find();
2886         if (!n) return Ternary.no;
2887         result = (cast(void*) (n + 1))[0 .. n.payload];
2888         return Ternary.yes;
2889     }
2890 }
2891 
2892 unittest
2893 {
2894     InternalPointersTree!(Mallocator) a;
2895     int[] vals = [ 6, 3, 9, 1, 2, 8, 11 ];
2896     void[][] allox;
2897     foreach (v; vals)
2898     {
2899         allox ~= a.allocate(v);
2900     }
2901     a.blockMap.assertSane;
2902 
2903     foreach (b; allox)
2904     {
2905         void[] p;
2906         Ternary r = a.resolveInternalPointer(b.ptr, p);
2907         assert(p.ptr is b.ptr && p.length >= b.length);
2908         r = a.resolveInternalPointer(b.ptr + b.length, p);
2909         assert(p.ptr is b.ptr && p.length >= b.length);
2910         r = a.resolveInternalPointer(b.ptr + b.length / 2, p);
2911         assert(p.ptr is b.ptr && p.length >= b.length);
2912         auto bogus = new void[b.length];
2913         assert(a.resolveInternalPointer(bogus.ptr, p) == Ternary.no);
2914     }
2915 
2916     foreach (b; allox.randomCover)
2917     {
2918         a.deallocate(b);
2919     }
2920 
2921     assert(a.empty);
2922 }
2923 
2924 //version (std_allocator_benchmark)
2925 unittest
2926 {
2927     static void testSpeed(A)()
2928     {
2929         static if (stateSize!A) A a;
2930         else alias a = A.instance;
2931 
2932         void[][128] bufs;
2933 
2934         import std.random;
2935         foreach (i; 0 .. 100_000)
2936         {
2937             auto j = uniform(0, bufs.length);
2938             switch (uniform(0, 2))
2939             {
2940             case 0:
2941                 a.deallocate(bufs[j]);
2942                 bufs[j] = a.allocate(uniform(0, 4096));
2943                 break;
2944             case 1:
2945                 a.deallocate(bufs[j]);
2946                 bufs[j] = null;
2947                 break;
2948             default:
2949                 assert(0);
2950             }
2951         }
2952     }
2953 
2954     alias FList = FreeList!(GCAllocator, 0, unbounded);
2955     alias A = Segregator!(
2956         8, FreeList!(GCAllocator, 0, 8),
2957         128, Bucketizer!(FList, 1, 128, 16),
2958         256, Bucketizer!(FList, 129, 256, 32),
2959         512, Bucketizer!(FList, 257, 512, 64),
2960         1024, Bucketizer!(FList, 513, 1024, 128),
2961         2048, Bucketizer!(FList, 1025, 2048, 256),
2962         3584, Bucketizer!(FList, 2049, 3584, 512),
2963         4072 * 1024, AllocatorList!(
2964             (size_t n) => BitmappedBlock!(4096)(GCAllocator.instance.allocate(
2965                 max(n, 4072 * 1024)))),
2966         GCAllocator
2967     );
2968 
2969     import std.datetime, std.experimental.allocator.null_allocator;
2970     if (false) writeln(benchmark!(
2971         testSpeed!NullAllocator,
2972         testSpeed!Mallocator,
2973         testSpeed!GCAllocator,
2974         testSpeed!(ThreadLocal!A),
2975         testSpeed!(A),
2976     )(20)[].map!(t => t.to!("seconds", double)));
2977 }
2978 
2979 unittest
2980 {
2981     auto a = allocatorObject(Mallocator.instance);
2982     auto b = a.allocate(100);
2983     assert(b.length == 100);
2984 
2985     FreeList!(GCAllocator, 0, 8) fl;
2986     auto sa = allocatorObject(fl);
2987     b = a.allocate(101);
2988     assert(b.length == 101);
2989 
2990     FallbackAllocator!(InSituRegion!(10240, 64), GCAllocator) fb;
2991     // Doesn't work yet...
2992     //a = allocatorObject(fb);
2993     //b = a.allocate(102);
2994     //assert(b.length == 102);
2995 }
2996 
2997 ///
2998 unittest
2999 {
3000     /// Define an allocator bound to the built-in GC.
3001     IAllocator alloc = allocatorObject(GCAllocator.instance);
3002     auto b = alloc.allocate(42);
3003     assert(b.length == 42);
3004     assert(alloc.deallocate(b) == Ternary.yes);
3005 
3006     // Define an elaborate allocator and bind it to the class API.
3007     // Note that the same variable "alloc" is used.
3008     alias FList = FreeList!(GCAllocator, 0, unbounded);
3009     alias A = ThreadLocal!(
3010         Segregator!(
3011             8, FreeList!(GCAllocator, 0, 8),
3012             128, Bucketizer!(FList, 1, 128, 16),
3013             256, Bucketizer!(FList, 129, 256, 32),
3014             512, Bucketizer!(FList, 257, 512, 64),
3015             1024, Bucketizer!(FList, 513, 1024, 128),
3016             2048, Bucketizer!(FList, 1025, 2048, 256),
3017             3584, Bucketizer!(FList, 2049, 3584, 512),
3018             4072 * 1024, AllocatorList!(
3019                 (n) => BitmappedBlock!(4096)(GCAllocator.instance.allocate(
3020                     max(n, 4072 * 1024)))),
3021             GCAllocator
3022         )
3023     );
3024 
3025     auto alloc2 = allocatorObject(A.instance);
3026     b = alloc.allocate(101);
3027     assert(alloc.deallocate(b) == Ternary.yes);
3028 }
3029