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 concrete
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 `std.experimental.allocator`)
111 
112 As of this time, `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 `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 `allocator` object for acquiring memory. Furthermore, setting
181 `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 // Fix https://issues.dlang.org/show_bug.cgi?id=17806
230 // this should always be the first unittest in this module in order to ensure
231 // that we use the `processAllocator` setter before the getter
232 @system unittest
233 {
234     import std.experimental.allocator.mallocator : Mallocator;
235     import std.experimental.allocator.gc_allocator : GCAllocator;
236     auto newAlloc = sharedAllocatorObject(Mallocator.instance);
237     processAllocator = newAlloc;
238     assert(processAllocator is newAlloc);
239     processAllocator = sharedAllocatorObject(GCAllocator.instance);
240 }
241 
242 // Example in the synopsis above
243 @system unittest
244 {
245     import std.algorithm.comparison : min, max;
246     import std.experimental.allocator.building_blocks.allocator_list
247         : AllocatorList;
248     import std.experimental.allocator.building_blocks.bitmapped_block
249         : BitmappedBlock;
250     import std.experimental.allocator.building_blocks.bucketizer : Bucketizer;
251     import std.experimental.allocator.building_blocks.free_list : FreeList;
252     import std.experimental.allocator.building_blocks.segregator : Segregator;
253     import std.experimental.allocator.gc_allocator : GCAllocator;
254 
255     alias FList = FreeList!(GCAllocator, 0, unbounded);
256     alias A = Segregator!(
257         8, FreeList!(GCAllocator, 0, 8),
258         128, Bucketizer!(FList, 1, 128, 16),
259         256, Bucketizer!(FList, 129, 256, 32),
260         512, Bucketizer!(FList, 257, 512, 64),
261         1024, Bucketizer!(FList, 513, 1024, 128),
262         2048, Bucketizer!(FList, 1025, 2048, 256),
263         3584, Bucketizer!(FList, 2049, 3584, 512),
264         4072 * 1024, AllocatorList!(
265             (n) => BitmappedBlock!(4096)(
266                     cast(ubyte[])(GCAllocator.instance.allocate(
267                         max(n, 4072 * 1024))))),
268         GCAllocator
269     );
270     A tuMalloc;
271     auto b = tuMalloc.allocate(500);
272     assert(b.length == 500);
273     auto c = tuMalloc.allocate(113);
274     assert(c.length == 113);
275     assert(tuMalloc.expand(c, 14));
276     tuMalloc.deallocate(b);
277     tuMalloc.deallocate(c);
278 }
279 
280 import std.range.primitives;
281 import std.traits;
282 import std.typecons;
283 
284 /**
285 Dynamic allocator interface. Code that defines allocators ultimately implements
286 this interface. This should be used wherever a uniform type is required for
287 encapsulating various allocator implementations.
288 
289 Composition of allocators is not recommended at this level due to
290 inflexibility of dynamic interfaces and inefficiencies caused by cascaded
291 multiple calls. Instead, compose allocators using the static interface defined
292 in $(MREF std,experimental,allocator,building_blocks),
293 then adapt the composed
294 allocator to `IAllocator` (possibly by using $(LREF CAllocatorImpl) below).
295 
296 Methods returning `Ternary` return `Ternary.yes` upon success,
297 `Ternary.no` upon failure, and `Ternary.unknown` if the primitive is not
298 implemented by the allocator instance.
299 */
300 interface IAllocator
301 {
302 nothrow:
303     /**
304     Returns the alignment offered.
305     */
306     @property uint alignment();
307 
308     /**
309     Returns the good allocation size that guarantees zero internal
310     fragmentation.
311     */
312     size_t goodAllocSize(size_t s);
313 
314     /**
315     Allocates `n` bytes of memory.
316     */
317     void[] allocate(size_t, TypeInfo ti = null);
318 
319     /**
320     Allocates `n` bytes of memory with specified alignment `a`. Implementations
321     that do not support this primitive should always return `null`.
322     */
323     void[] alignedAllocate(size_t n, uint a);
324 
325     /**
326     Allocates and returns all memory available to this allocator.
327     Implementations that do not support this primitive should always return
328     `null`.
329     */
330     void[] allocateAll();
331 
332     /**
333     Expands a memory block in place and returns `true` if successful.
334     Implementations that don't support this primitive should always return
335     `false`.
336     */
337     bool expand(ref void[], size_t);
338 
339     /// Reallocates a memory block.
340     bool reallocate(ref void[], size_t);
341 
342     /// Reallocates a memory block with specified alignment.
343     bool alignedReallocate(ref void[] b, size_t size, uint alignment);
344 
345     /**
346     Returns `Ternary.yes` if the allocator owns `b`, `Ternary.no` if
347     the allocator doesn't own `b`, and `Ternary.unknown` if ownership
348     cannot be determined. Implementations that don't support this primitive
349     should always return `Ternary.unknown`.
350     */
351     Ternary owns(void[] b);
352 
353     /**
354     Resolves an internal pointer to the full block allocated. Implementations
355     that don't support this primitive should always return `Ternary.unknown`.
356     */
357     Ternary resolveInternalPointer(const void* p, ref void[] result);
358 
359     /**
360     Deallocates a memory block. Implementations that don't support this
361     primitive should always return `false`. A simple way to check that an
362     allocator supports deallocation is to call `deallocate(null)`.
363     */
364     bool deallocate(void[] b);
365 
366     /**
367     Deallocates all memory. Implementations that don't support this primitive
368     should always return `false`.
369     */
370     bool deallocateAll();
371 
372     /**
373     Returns `Ternary.yes` if no memory is currently allocated from this
374     allocator, `Ternary.no` if some allocations are currently active, or
375     `Ternary.unknown` if not supported.
376     */
377     Ternary empty();
378 
379     /**
380     Increases the reference count of the concrete class that implements this
381     interface.
382 
383     For stateless allocators, this does nothing.
384     */
385     @safe @nogc pure
386     void incRef();
387 
388     /**
389     Decreases the reference count of the concrete class that implements this
390     interface.
391     When the reference count is `0`, the object self-destructs.
392 
393     Returns: `true` if the reference count is greater than `0` and `false` when
394     it hits `0`. For stateless allocators, it always returns `true`.
395     */
396     @safe @nogc pure
397     bool decRef();
398 }
399 
400 /**
401 A reference counted struct that wraps the dynamic allocator interface.
402 This should be used wherever a uniform type is required for encapsulating
403 various allocator implementations.
404 
405 Code that defines allocators ultimately implements the $(LREF IAllocator)
406 interface, possibly by using $(LREF CAllocatorImpl) below, and then build a
407 `RCIAllocator` out of this.
408 
409 Composition of allocators is not recommended at this level due to
410 inflexibility of dynamic interfaces and inefficiencies caused by cascaded
411 multiple calls. Instead, compose allocators using the static interface defined
412 in $(A std_experimental_allocator_building_blocks.html,
413 `std.experimental.allocator.building_blocks`), then adapt the composed
414 allocator to `RCIAllocator` (possibly by using $(LREF allocatorObject) below).
415 */
416 struct RCIAllocator
417 {
418     private IAllocator _alloc;
419 
420 nothrow:
421     private @nogc pure @safe
thisRCIAllocator422     this(this _)(IAllocator alloc)
423     {
424         assert(alloc);
425         _alloc = alloc;
426     }
427 
428     @nogc pure @safe
thisRCIAllocator429     this(this)
430     {
431         if (_alloc !is null)
432         {
433             _alloc.incRef();
434         }
435     }
436 
437     @nogc pure @safe
~thisRCIAllocator438     ~this()
439     {
440         if (_alloc !is null)
441         {
442             bool isLast = !_alloc.decRef();
443             if (isLast) _alloc = null;
444         }
445     }
446 
447     @nogc pure @safe
opAssignRCIAllocator448     auto ref opAssign()(typeof(this) rhs)
449     {
450         if (_alloc is rhs._alloc)
451         {
452             return this;
453         }
454         // incRef was allready called by rhs posblit, so we're just moving
455         // calling dtor is the equivalent of decRef
456         __dtor();
457         _alloc = rhs._alloc;
458         // move
459         rhs._alloc = null;
460         return this;
461     }
462 
463     @nogc pure @safe
isNullRCIAllocator464     bool isNull(this _)()
465     {
466         return _alloc is null;
467     }
468 
alignmentRCIAllocator469     @property uint alignment()
470     {
471         assert(_alloc);
472         return _alloc.alignment();
473     }
474 
goodAllocSizeRCIAllocator475     size_t goodAllocSize(size_t s)
476     {
477         assert(_alloc);
478         return _alloc.goodAllocSize(s);
479     }
480 
481     void[] allocate(size_t n, TypeInfo ti = null)
482     {
483         assert(_alloc);
484         return _alloc.allocate(n, ti);
485     }
486 
alignedAllocateRCIAllocator487     void[] alignedAllocate(size_t n, uint a)
488     {
489         assert(_alloc);
490         return _alloc.alignedAllocate(n, a);
491     }
492 
allocateAllRCIAllocator493     void[] allocateAll()
494     {
495         assert(_alloc);
496         return _alloc.allocateAll();
497     }
498 
expandRCIAllocator499     bool expand(ref void[] b, size_t size)
500     {
501         assert(_alloc);
502         return _alloc.expand(b, size);
503     }
504 
reallocateRCIAllocator505     bool reallocate(ref void[] b, size_t size)
506     {
507         assert(_alloc);
508         return _alloc.reallocate(b, size);
509     }
510 
alignedReallocateRCIAllocator511     bool alignedReallocate(ref void[] b, size_t size, uint alignment)
512     {
513         assert(_alloc);
514         return _alloc.alignedReallocate(b, size, alignment);
515     }
516 
ownsRCIAllocator517     Ternary owns(void[] b)
518     {
519         assert(_alloc);
520         return _alloc.owns(b);
521     }
522 
resolveInternalPointerRCIAllocator523     Ternary resolveInternalPointer(const void* p, ref void[] result)
524     {
525         assert(_alloc);
526         return _alloc.resolveInternalPointer(p, result);
527     }
528 
deallocateRCIAllocator529     bool deallocate(void[] b)
530     {
531         assert(_alloc);
532         return _alloc.deallocate(b);
533     }
534 
deallocateAllRCIAllocator535     bool deallocateAll()
536     {
537         assert(_alloc);
538         return _alloc.deallocateAll();
539     }
540 
emptyRCIAllocator541     Ternary empty()
542     {
543         assert(_alloc);
544         return _alloc.empty();
545     }
546 }
547 
548 @system unittest
549 {
550     import std.experimental.allocator.building_blocks.region : Region;
551     import std.conv : emplace;
552 
553     auto reg = Region!()(new ubyte[1024]);
554     auto state = reg.allocate(stateSize!(CAllocatorImpl!(Region!(), Yes.indirect)));
555     auto regObj = emplace!(CAllocatorImpl!(Region!(), Yes.indirect))(state, &reg);
556 
557     auto rcalloc = RCIAllocator(regObj);
558     auto b = rcalloc.allocate(10);
559     assert(b.length == 10);
560 
561     // The reference counting is zero based
562     assert((cast(CAllocatorImpl!(Region!(), Yes.indirect))(rcalloc._alloc)).rc == 1);
563     {
564         auto rca2 = rcalloc;
565         assert((cast(CAllocatorImpl!(Region!(), Yes.indirect))(rcalloc._alloc)).rc == 2);
566     }
567     assert((cast(CAllocatorImpl!(Region!(), Yes.indirect))(rcalloc._alloc)).rc == 1);
568 }
569 
570 @system unittest
571 {
572     import std.conv;
573     import std.experimental.allocator.mallocator;
574     import std.experimental.allocator.building_blocks.stats_collector;
575 
576     alias SCAlloc = StatsCollector!(Mallocator, Options.bytesUsed);
577     SCAlloc statsCollectorAlloc;
578 
579     ulong bytesUsed = statsCollectorAlloc.bytesUsed;
580     assert(bytesUsed == 0);
581 
582     {
583         auto _allocator = allocatorObject(&statsCollectorAlloc);
584         bytesUsed = statsCollectorAlloc.bytesUsed;
585         assert(bytesUsed == stateSize!(CAllocatorImpl!(SCAlloc, Yes.indirect)));
586     }
587 
588     bytesUsed = statsCollectorAlloc.bytesUsed;
589     assert(bytesUsed == 0, "RCIAllocator leaks memory; leaked "
590             ~ to!string(bytesUsed) ~ " bytes");
591 }
592 
593 @system unittest
594 {
595     import std.conv;
596     import std.experimental.allocator.mallocator;
597     import std.experimental.allocator.building_blocks.stats_collector;
598 
599     alias SCAlloc = StatsCollector!(Mallocator, Options.bytesUsed);
600     SCAlloc statsCollectorAlloc;
601 
602     ulong bytesUsed = statsCollectorAlloc.bytesUsed;
603     assert(bytesUsed == 0);
604 
605     {
606         auto _allocator = allocatorObject(statsCollectorAlloc);
607 
608         // Ensure that the allocator was passed through in CAllocatorImpl
609         // This allocator was used to allocate the chunk that holds the
610         // CAllocatorImpl object; which is it's own wrapper
611         bytesUsed = (cast(CAllocatorImpl!(SCAlloc))(_allocator._alloc)).impl.bytesUsed;
612         assert(bytesUsed == stateSize!(CAllocatorImpl!(SCAlloc)),
613                "RCIAllocator leaks memory; leaked " ~ to!string(bytesUsed) ~ " bytes");
614         _allocator.allocate(1);
615         bytesUsed = (cast(CAllocatorImpl!(SCAlloc))(_allocator._alloc)).impl.bytesUsed;
616         assert(bytesUsed == stateSize!(CAllocatorImpl!(SCAlloc)) + 1,
617                "RCIAllocator leaks memory; leaked " ~ to!string(bytesUsed) ~ " bytes");
618     }
619 
620     bytesUsed = statsCollectorAlloc.bytesUsed;
621     assert(bytesUsed == stateSize!(CAllocatorImpl!(SCAlloc)),
622             "RCIAllocator leaks memory; leaked "
623             ~ to!string(bytesUsed) ~ " bytes");
624 }
625 
626 /**
627 Dynamic shared allocator interface. Code that defines allocators shareable
628 across threads ultimately implements this interface. This should be used
629 wherever a uniform type is required for encapsulating various allocator
630 implementations.
631 
632 Composition of allocators is not recommended at this level due to
633 inflexibility of dynamic interfaces and inefficiencies caused by cascaded
634 multiple calls. Instead, compose allocators using the static interface defined
635 in $(MREF std,experimental,allocator,building_blocks),
636 then adapt the composed
637 allocator to `ISharedAllocator` (possibly by using $(LREF CSharedAllocatorImpl) below).
638 
639 Methods returning `Ternary` return `Ternary.yes` upon success,
640 `Ternary.no` upon failure, and `Ternary.unknown` if the primitive is not
641 implemented by the allocator instance.
642 */
643 interface ISharedAllocator
644 {
645 nothrow:
646     /**
647     Returns the alignment offered.
648     */
649     @property uint alignment() shared;
650 
651     /**
652     Returns the good allocation size that guarantees zero internal
653     fragmentation.
654     */
655     size_t goodAllocSize(size_t s) shared;
656 
657     /**
658     Allocates `n` bytes of memory.
659     */
660     void[] allocate(size_t, TypeInfo ti = null) shared;
661 
662     /**
663     Allocates `n` bytes of memory with specified alignment `a`. Implementations
664     that do not support this primitive should always return `null`.
665     */
666     void[] alignedAllocate(size_t n, uint a) shared;
667 
668     /**
669     Allocates and returns all memory available to this allocator.
670     Implementations that do not support this primitive should always return
671     `null`.
672     */
673     void[] allocateAll() shared;
674 
675     /**
676     Expands a memory block in place and returns `true` if successful.
677     Implementations that don't support this primitive should always return
678     `false`.
679     */
680     bool expand(ref void[], size_t) shared;
681 
682     /// Reallocates a memory block.
683     bool reallocate(ref void[], size_t) shared;
684 
685     /// Reallocates a memory block with specified alignment.
686     bool alignedReallocate(ref void[] b, size_t size, uint alignment) shared;
687 
688     /**
689     Returns `Ternary.yes` if the allocator owns `b`, `Ternary.no` if
690     the allocator doesn't own `b`, and `Ternary.unknown` if ownership
691     cannot be determined. Implementations that don't support this primitive
692     should always return `Ternary.unknown`.
693     */
694     Ternary owns(void[] b) shared;
695 
696     /**
697     Resolves an internal pointer to the full block allocated. Implementations
698     that don't support this primitive should always return `Ternary.unknown`.
699     */
700     Ternary resolveInternalPointer(const void* p, ref void[] result) shared;
701 
702     /**
703     Deallocates a memory block. Implementations that don't support this
704     primitive should always return `false`. A simple way to check that an
705     allocator supports deallocation is to call `deallocate(null)`.
706     */
707     bool deallocate(void[] b) shared;
708 
709     /**
710     Deallocates all memory. Implementations that don't support this primitive
711     should always return `false`.
712     */
713     bool deallocateAll() shared;
714 
715     /**
716     Returns `Ternary.yes` if no memory is currently allocated from this
717     allocator, `Ternary.no` if some allocations are currently active, or
718     `Ternary.unknown` if not supported.
719     */
720     Ternary empty() shared;
721 
722     /**
723     Increases the reference count of the concrete class that implements this
724     interface.
725 
726     For stateless allocators, this does nothing.
727     */
728     @safe @nogc pure
729     void incRef() shared;
730 
731     /**
732     Decreases the reference count of the concrete class that implements this
733     interface.
734     When the reference count is `0`, the object self-destructs.
735 
736     For stateless allocators, this does nothing.
737 
738     Returns: `true` if the reference count is greater than `0` and `false` when
739     it hits `0`. For stateless allocators, it always returns `true`.
740     */
741     @safe @nogc pure
742     bool decRef() shared;
743 }
744 
745 /**
746 A reference counted struct that wraps the dynamic shared allocator interface.
747 This should be used wherever a uniform type is required for encapsulating
748 various allocator implementations.
749 
750 Code that defines allocators shareable across threads ultimately implements the
751 $(LREF ISharedAllocator) interface, possibly by using
752 $(LREF CSharedAllocatorImpl) below, and then build a `RCISharedAllocator` out
753 of this.
754 
755 Composition of allocators is not recommended at this level due to
756 inflexibility of dynamic interfaces and inefficiencies caused by cascaded
757 multiple calls. Instead, compose allocators using the static interface defined
758 in $(A std_experimental_allocator_building_blocks.html,
759 `std.experimental.allocator.building_blocks`), then adapt the composed allocator
760 to `RCISharedAllocator` (possibly by using $(LREF sharedAllocatorObject) below).
761 */
762 shared struct RCISharedAllocator
763 {
764     private ISharedAllocator _alloc;
765 
766 nothrow:
767     private @nogc pure @safe
thisRCISharedAllocator768     this(shared ISharedAllocator alloc)
769     {
770         assert(alloc);
771         _alloc = alloc;
772     }
773 
774     @nogc pure @safe
thisRCISharedAllocator775     this(this)
776     {
777         if (_alloc !is null)
778         {
779             _alloc.incRef();
780         }
781     }
782 
783     @nogc pure @safe
~thisRCISharedAllocator784     ~this()
785     {
786         if (_alloc !is null)
787         {
788             bool isLast = !_alloc.decRef();
789             if (isLast) _alloc = null;
790         }
791     }
792 
793     @nogc pure @safe
opAssignRCISharedAllocator794     auto ref opAssign()(RCISharedAllocator rhs)
795     {
796         if (_alloc is rhs._alloc)
797         {
798             return this;
799         }
800         // incRef was allready called by rhs posblit, so we're just moving
801         if (_alloc !is null)
802         {
803             _alloc.decRef();
804         }
805         _alloc = rhs._alloc;
806         // move
807         rhs._alloc = null;
808         return this;
809     }
810 
811     @nogc pure @safe
isNullRCISharedAllocator812     bool isNull(this _)()
813     {
814         return _alloc is null;
815     }
816 
alignmentRCISharedAllocator817     @property uint alignment()
818     {
819         assert(_alloc);
820         return _alloc.alignment();
821     }
822 
goodAllocSizeRCISharedAllocator823     size_t goodAllocSize(size_t s)
824     {
825         assert(_alloc);
826         return _alloc.goodAllocSize(s);
827     }
828 
829     void[] allocate(size_t n, TypeInfo ti = null)
830     {
831         assert(_alloc);
832         return _alloc.allocate(n, ti);
833     }
834 
alignedAllocateRCISharedAllocator835     void[] alignedAllocate(size_t n, uint a)
836     {
837         assert(_alloc);
838         return _alloc.alignedAllocate(n, a);
839     }
840 
allocateAllRCISharedAllocator841     void[] allocateAll()
842     {
843         assert(_alloc);
844         return _alloc.allocateAll();
845     }
846 
expandRCISharedAllocator847     bool expand(ref void[] b, size_t size)
848     {
849         assert(_alloc);
850         return _alloc.expand(b, size);
851     }
852 
reallocateRCISharedAllocator853     bool reallocate(ref void[] b, size_t size)
854     {
855         assert(_alloc);
856         return _alloc.reallocate(b, size);
857     }
858 
alignedReallocateRCISharedAllocator859     bool alignedReallocate(ref void[] b, size_t size, uint alignment)
860     {
861         assert(_alloc);
862         return _alloc.alignedReallocate(b, size, alignment);
863     }
864 
ownsRCISharedAllocator865     Ternary owns(void[] b)
866     {
867         assert(_alloc);
868         return _alloc.owns(b);
869     }
870 
resolveInternalPointerRCISharedAllocator871     Ternary resolveInternalPointer(const void* p, ref void[] result)
872     {
873         assert(_alloc);
874         return _alloc.resolveInternalPointer(p, result);
875     }
876 
deallocateRCISharedAllocator877     bool deallocate(void[] b)
878     {
879         assert(_alloc);
880         return _alloc.deallocate(b);
881     }
882 
deallocateAllRCISharedAllocator883     bool deallocateAll()
884     {
885         assert(_alloc);
886         return _alloc.deallocateAll();
887     }
888 
emptyRCISharedAllocator889     Ternary empty()
890     {
891         assert(_alloc);
892         return _alloc.empty();
893     }
894 }
895 
896 private RCISharedAllocator _processAllocator;
897 private RCIAllocator _threadAllocator;
898 
899 @nogc nothrow @safe
setupThreadAllocator()900 private ref RCIAllocator setupThreadAllocator()
901 {
902     /*
903     Forwards the `_threadAllocator` calls to the `processAllocator`
904     */
905     static class ThreadAllocator : IAllocator
906     {
907     nothrow:
908         private RCISharedAllocator _allocator;
909 
910         @nogc @safe
911         this(ref RCISharedAllocator procAlloc)
912         {
913             _allocator = procAlloc;
914         }
915 
916         override @property uint alignment()
917         {
918             return _allocator.alignment();
919         }
920 
921         override size_t goodAllocSize(size_t s)
922         {
923             return _allocator.goodAllocSize(s);
924         }
925 
926         override void[] allocate(size_t n, TypeInfo ti = null)
927         {
928             return _allocator.allocate(n, ti);
929         }
930 
931         override void[] alignedAllocate(size_t n, uint a)
932         {
933             return _allocator.alignedAllocate(n, a);
934         }
935 
936         override void[] allocateAll()
937         {
938             return _allocator.allocateAll();
939         }
940 
941         override bool expand(ref void[] b, size_t size)
942         {
943             return _allocator.expand(b, size);
944         }
945 
946         override bool reallocate(ref void[] b, size_t size)
947         {
948             return _allocator.reallocate(b, size);
949         }
950 
951         override bool alignedReallocate(ref void[] b, size_t size, uint alignment)
952         {
953             return _allocator.alignedReallocate(b, size, alignment);
954         }
955 
956         override Ternary owns(void[] b)
957         {
958             return _allocator.owns(b);
959         }
960 
961         override Ternary resolveInternalPointer(const void* p, ref void[] result)
962         {
963             return _allocator.resolveInternalPointer(p, result);
964         }
965 
966         override bool deallocate(void[] b)
967         {
968             return _allocator.deallocate(b);
969         }
970 
971         override bool deallocateAll()
972         {
973             return _allocator.deallocateAll();
974         }
975 
976         override Ternary empty()
977         {
978             return _allocator.empty();
979         }
980 
981         @nogc pure @safe
982         override void incRef()
983         {
984             _allocator._alloc.incRef();
985         }
986 
987         @nogc pure @safe
988         override bool decRef()
989         {
990             return _allocator._alloc.decRef();
991         }
992     }
993 
994     assert(_threadAllocator.isNull);
995     import core.lifetime : emplace;
996     static ulong[stateSize!(ThreadAllocator).divideRoundUp(ulong.sizeof)] _threadAllocatorState;
997     () @trusted {
998         _threadAllocator = RCIAllocator(emplace!(ThreadAllocator)(_threadAllocatorState[], processAllocator()));
999     }();
1000     return _threadAllocator;
1001 }
1002 
1003 // Fix threadAllocator bug: the threadAllocator should hold an internal reference
1004 // to the processAllocator that it's using
1005 @system unittest
1006 {
1007     import std.experimental.allocator.mallocator : Mallocator;
1008 
1009     auto a = sharedAllocatorObject(Mallocator.instance);
1010     auto buf = theAllocator.allocate(42);
1011     processAllocator = a;
1012     theAllocator.deallocate(buf);
1013 }
1014 
1015 /**
1016 Gets/sets the allocator for the current thread. This is the default allocator
1017 that should be used for allocating thread-local memory. For allocating memory
1018 to be shared across threads, use `processAllocator` (below). By default,
1019 `theAllocator` ultimately fetches memory from `processAllocator`, which
1020 in turn uses the garbage collected heap.
1021 */
1022 @nogc nothrow @safe
theAllocator()1023 @property ref RCIAllocator theAllocator()
1024 {
1025     alias p = _threadAllocator;
1026     return !p.isNull() ? p : setupThreadAllocator();
1027 }
1028 
1029 /// Ditto
1030 nothrow @system @nogc
theAllocator(RCIAllocator a)1031 @property void theAllocator(RCIAllocator a)
1032 {
1033     assert(!a.isNull);
1034     _threadAllocator = a;
1035 }
1036 
1037 ///
1038 @system unittest
1039 {
1040     // Install a new allocator that is faster for 128-byte allocations.
1041     import std.experimental.allocator.building_blocks.free_list : FreeList;
1042     import std.experimental.allocator.gc_allocator : GCAllocator;
1043     auto oldAllocator = theAllocator;
1044     scope(exit) theAllocator = oldAllocator;
1045     theAllocator = allocatorObject(FreeList!(GCAllocator, 128)());
1046     // Use the now changed allocator to allocate an array
1047     const ubyte[] arr = theAllocator.makeArray!ubyte(128);
1048     assert(arr.ptr);
1049     //...
1050 }
1051 
1052 /**
1053 Gets/sets the allocator for the current process. This allocator must be used
1054 for allocating memory shared across threads. Objects created using this
1055 allocator can be cast to `shared`.
1056 */
1057 @nogc nothrow @trusted
processAllocator()1058 @property ref RCISharedAllocator processAllocator()
1059 {
1060     import std.experimental.allocator.gc_allocator : GCAllocator;
1061     import std.concurrency : initOnce;
1062 
1063     static RCISharedAllocator* forceAttributes()
1064     {
1065         return &initOnce!_processAllocator(
1066                 sharedAllocatorObject(GCAllocator.instance));
1067     }
1068 
1069     return *(cast(RCISharedAllocator* function() @nogc nothrow)(&forceAttributes))();
1070 }
1071 
1072 /// Ditto
1073 @nogc nothrow @system
processAllocator(ref RCISharedAllocator a)1074 @property void processAllocator(ref RCISharedAllocator a)
1075 {
1076     assert(!a.isNull);
1077     processAllocator() = a;
1078 }
1079 
1080 @system unittest
1081 {
1082     import core.exception : AssertError;
1083     import std.exception : assertThrown;
1084     import std.experimental.allocator.building_blocks.free_list : SharedFreeList;
1085     import std.experimental.allocator.mallocator : Mallocator;
1086 
1087     assert(!processAllocator.isNull);
1088     assert(!theAllocator.isNull);
1089 
1090     testAllocatorObject(processAllocator);
1091     testAllocatorObject(theAllocator);
1092 
1093     shared SharedFreeList!(Mallocator, chooseAtRuntime, chooseAtRuntime) sharedFL;
1094     RCISharedAllocator sharedFLObj = sharedAllocatorObject(sharedFL);
1095     alias SharedAllocT = CSharedAllocatorImpl!(
1096             shared SharedFreeList!(
1097                 Mallocator, chooseAtRuntime, chooseAtRuntime));
1098 
1099     assert((cast(SharedAllocT)(sharedFLObj._alloc)).rc == 1);
1100     assert(!sharedFLObj.isNull);
1101     testAllocatorObject(sharedFLObj);
1102 
1103     // Test processAllocator setter
1104     RCISharedAllocator oldProcessAllocator = processAllocator;
1105     processAllocator = sharedFLObj;
1106     assert((cast(SharedAllocT)(sharedFLObj._alloc)).rc == 2);
1107     assert(processAllocator._alloc is sharedFLObj._alloc);
1108 
1109     testAllocatorObject(processAllocator);
1110     testAllocatorObject(theAllocator);
1111     assertThrown!AssertError(processAllocator = RCISharedAllocator(null));
1112 
1113     // Restore initial processAllocator state
1114     processAllocator = oldProcessAllocator;
1115     assert((cast(SharedAllocT)(sharedFLObj._alloc)).rc == 1);
1116     assert(processAllocator is oldProcessAllocator);
1117 
1118     RCISharedAllocator indirectShFLObj = sharedAllocatorObject(&sharedFL);
1119     testAllocatorObject(indirectShFLObj);
1120     alias IndirectSharedAllocT = CSharedAllocatorImpl!(
1121             shared SharedFreeList!(
1122                 Mallocator, chooseAtRuntime, chooseAtRuntime)
1123             , Yes.indirect);
1124 
1125     assert((cast(IndirectSharedAllocT)(indirectShFLObj._alloc)).rc == 1);
1126 
1127     RCIAllocator indirectMallocator = allocatorObject(&Mallocator.instance);
1128     testAllocatorObject(indirectMallocator);
1129 }
1130 
1131 /**
1132 Dynamically allocates (using `alloc`) and then creates in the memory
1133 allocated an object of type `T`, using `args` (if any) for its
1134 initialization. Initialization occurs in the memory allocated and is otherwise
1135 semantically the same as `T(args)`.
1136 (Note that using `alloc.make!(T[])` creates a pointer to an (empty) array
1137 of `T`s, not an array. To use an allocator to allocate and initialize an
1138 array, use `alloc.makeArray!T` described below.)
1139 
1140 Params:
1141 T = Type of the object being created.
1142 alloc = The allocator used for getting the needed memory. It may be an object
1143 implementing the static interface for allocators, or an `IAllocator`
1144 reference.
1145 args = Optional arguments used for initializing the created object. If not
1146 present, the object is default constructed.
1147 
1148 Returns: If `T` is a class type, returns a reference to the created `T`
1149 object. Otherwise, returns a `T*` pointing to the created object. In all
1150 cases, returns `null` if allocation failed.
1151 
1152 Throws: If `T`'s constructor throws, deallocates the allocated memory and
1153 propagates the exception.
1154 */
make(T,Allocator,A...)1155 auto make(T, Allocator, A...)(auto ref Allocator alloc, auto ref A args)
1156 {
1157     import std.algorithm.comparison : max;
1158     static if (!is(T == class) && !is(T == interface) && A.length == 0
1159         && __traits(compiles, {T t;}) && __traits(isZeroInit, T)
1160         && is(typeof(alloc.allocateZeroed(size_t.max))))
1161     {
1162         auto m = alloc.allocateZeroed(max(T.sizeof, 1));
1163         return (() @trusted => cast(T*) m.ptr)();
1164     }
1165     else
1166     {
1167         import core.internal.lifetime : emplaceRef;
1168         import core.lifetime : emplace;
1169 
1170         auto m = alloc.allocate(max(stateSize!T, 1));
1171         if (!m.ptr) return null;
1172 
1173         // make can only be @safe if emplace or emplaceRef is `pure`
1174         auto construct()
1175         {
1176             static if (is(T == class)) return emplace!T(m, args);
1177             else
1178             {
1179                 // Assume cast is safe as allocation succeeded for `stateSize!T`
1180                 auto p = () @trusted { return cast(T*) m.ptr; }();
1181                 emplaceRef!T(*p, args);
1182                 return p;
1183             }
1184         }
1185 
1186         scope(failure)
1187         {
1188             static if (is(typeof(() pure { return construct(); })))
1189             {
1190                 // Assume deallocation is safe because:
1191                 // 1) in case of failure, `m` is the only reference to this memory
1192                 // 2) `m` is known to originate from `alloc`
1193                 () @trusted { alloc.deallocate(m); }();
1194             }
1195             else
1196             {
1197                 alloc.deallocate(m);
1198             }
1199         }
1200 
1201         return construct();
1202     }
1203 }
1204 
1205 ///
1206 @system unittest
1207 {
1208     // Dynamically allocate one integer
1209     const int* p1 = theAllocator.make!int;
1210     // It's implicitly initialized with its .init value
1211     assert(*p1 == 0);
1212     // Dynamically allocate one double, initialize to 42.5
1213     const double* p2 = theAllocator.make!double(42.5);
1214     assert(*p2 == 42.5);
1215 
1216     // Dynamically allocate a struct
1217     static struct Point
1218     {
1219         int x, y, z;
1220     }
1221     // Use the generated constructor taking field values in order
1222     const Point* p = theAllocator.make!Point(1, 2);
1223     assert(p.x == 1 && p.y == 2 && p.z == 0);
1224 
1225     // Dynamically allocate a class object
1226     static class Customer
1227     {
1228         uint id = uint.max;
this()1229         this() {}
this(uint id)1230         this(uint id) { this.id = id; }
1231         // ...
1232     }
1233     Customer cust = theAllocator.make!Customer;
1234     assert(cust.id == uint.max); // default initialized
1235     cust = theAllocator.make!Customer(42);
1236     assert(cust.id == 42);
1237 
1238     // explicit passing of outer pointer
1239     static class Outer
1240     {
1241         int x = 3;
1242         class Inner
1243         {
getX()1244             auto getX() { return x; }
1245         }
1246     }
1247     auto outer = theAllocator.make!Outer();
1248     auto inner = theAllocator.make!(Outer.Inner)(outer);
1249     assert(outer.x == inner.getX);
1250 }
1251 
1252 // https://issues.dlang.org/show_bug.cgi?id=15639
1253 // https://issues.dlang.org/show_bug.cgi?id=15772
1254 @system unittest
1255 {
1256     abstract class Foo {}
1257     class Bar: Foo {}
1258     static assert(!is(typeof(theAllocator.make!Foo)));
1259     static assert( is(typeof(theAllocator.make!Bar)));
1260 }
1261 
1262 @system unittest
1263 {
test(Allocator)1264     void test(Allocator)(auto ref Allocator alloc)
1265     {
1266         const int* a = alloc.make!int(10);
1267         assert(*a == 10);
1268 
1269         struct A
1270         {
1271             int x;
1272             string y;
1273             double z;
1274         }
1275 
1276         A* b = alloc.make!A(42);
1277         assert(b.x == 42);
1278         assert(b.y is null);
1279         import std.math.traits : isNaN;
1280         assert(b.z.isNaN);
1281 
1282         b = alloc.make!A(43, "44", 45);
1283         assert(b.x == 43);
1284         assert(b.y == "44");
1285         assert(b.z == 45);
1286 
1287         static class B
1288         {
1289             int x;
1290             string y;
1291             double z;
1292             this(int _x, string _y = null, double _z = double.init)
1293             {
1294                 x = _x;
1295                 y = _y;
1296                 z = _z;
1297             }
1298         }
1299 
1300         B c = alloc.make!B(42);
1301         assert(c.x == 42);
1302         assert(c.y is null);
1303         assert(c.z.isNaN);
1304 
1305         c = alloc.make!B(43, "44", 45);
1306         assert(c.x == 43);
1307         assert(c.y == "44");
1308         assert(c.z == 45);
1309 
1310         const parray = alloc.make!(int[]);
1311         assert((*parray).empty);
1312     }
1313 
1314     import std.experimental.allocator.gc_allocator : GCAllocator;
1315     test(GCAllocator.instance);
1316     test(theAllocator);
1317 }
1318 
1319 // Attribute propagation
1320 nothrow @safe @nogc unittest
1321 {
1322     import std.experimental.allocator.mallocator : Mallocator;
1323     alias alloc = Mallocator.instance;
1324 
test(T,Args...)1325     void test(T, Args...)(auto ref Args args)
1326     {
1327         auto k = alloc.make!T(args);
1328         () @trusted { alloc.dispose(k); }();
1329     }
1330 
1331     test!int;
1332     test!(int*);
1333     test!int(0);
1334     test!(int*)(null);
1335 }
1336 
1337 // should be pure with the GCAllocator
1338 /*pure nothrow*/ @safe unittest
1339 {
1340     import std.experimental.allocator.gc_allocator : GCAllocator;
1341 
1342     alias alloc = GCAllocator.instance;
1343 
test(T,Args...)1344     void test(T, Args...)(auto ref Args args)
1345     {
1346         auto k = alloc.make!T(args);
1347         (a) @trusted { a.dispose(k); }(alloc);
1348     }
1349 
1350     test!int();
1351     test!(int*);
1352     test!int(0);
1353     test!(int*)(null);
1354 }
1355 
1356 // Verify that making an object by calling an impure constructor is not @safe
1357 nothrow @safe @nogc unittest
1358 {
1359     import std.experimental.allocator.mallocator : Mallocator;
thisPure1360     static struct Pure { this(int) pure nothrow @nogc @safe {} }
1361 
1362     cast(void) Mallocator.instance.make!Pure(0);
1363 
1364     static int g = 0;
thisImpure1365     static struct Impure { this(int) nothrow @nogc @safe {
1366         g++;
1367     } }
1368     static assert(!__traits(compiles, cast(void) Mallocator.instance.make!Impure(0)));
1369 }
1370 
1371 // test failure with a pure, failing struct
1372 @safe unittest
1373 {
1374     import std.exception : assertThrown, enforce;
1375 
1376     // this struct can't be initialized
1377     struct InvalidStruct
1378     {
thisInvalidStruct1379         this(int b)
1380         {
1381             enforce(1 == 2);
1382         }
1383     }
1384     import std.experimental.allocator.mallocator : Mallocator;
1385     assertThrown(make!InvalidStruct(Mallocator.instance, 42));
1386 }
1387 
1388 // test failure with an impure, failing struct
1389 @system unittest
1390 {
1391     import std.exception : assertThrown, enforce;
1392     static int g;
1393     struct InvalidImpureStruct
1394     {
thisInvalidImpureStruct1395         this(int b)
1396         {
1397             g++;
1398             enforce(1 == 2);
1399         }
1400     }
1401     import std.experimental.allocator.mallocator : Mallocator;
1402     assertThrown(make!InvalidImpureStruct(Mallocator.instance, 42));
1403 }
1404 
1405 // Don't allow zero-ctor-args `make` for structs with `@disable this();`
1406 @system unittest
1407 {
1408     struct NoDefaultCtor
1409     {
1410         int i;
1411         @disable this();
1412     }
1413     import std.experimental.allocator.mallocator : Mallocator;
1414     static assert(!__traits(compiles, make!NoDefaultCtor(Mallocator.instance)),
1415         "Don't allow zero-ctor-args `make` for structs with `@disable this();`");
1416 }
1417 
1418 // https://issues.dlang.org/show_bug.cgi?id=18937
1419 @safe unittest
1420 {
1421     static struct S
1422     {
1423         ubyte[16 * 1024] data;
1424     }
1425 
1426     static struct SomeAllocator
1427     {
allocate(size_t)1428         ubyte[] allocate(size_t) { return []; }
deallocate(void[])1429         void deallocate(void[]) {}
1430     }
1431 
1432     auto x = SomeAllocator().make!S();
1433 }
1434 
1435 private void fillWithMemcpy(T)(scope void[] array, auto ref T filler) nothrow
1436 if (T.sizeof == 1)
1437 {
1438     import core.stdc.string : memset;
1439     import std.traits : CopyConstness;
1440     if (!array.length) return;
1441     memset(array.ptr, *cast(CopyConstness!(T*, ubyte*)) &filler, array.length);
1442 }
1443 
1444 private void fillWithMemcpy(T)(scope void[] array, auto ref T filler) nothrow
1445 if (T.sizeof != 1)
1446 {
1447     import core.stdc.string : memcpy;
1448     import std.algorithm.comparison : min;
1449     if (!array.length) return;
1450     memcpy(array.ptr, &filler, T.sizeof);
1451     // Fill the array from the initialized portion of itself exponentially.
1452     for (size_t offset = T.sizeof; offset < array.length; )
1453     {
1454         size_t extent = min(offset, array.length - offset);
1455         memcpy(array.ptr + offset, array.ptr, extent);
1456         offset += extent;
1457     }
1458 }
1459 
1460 @system unittest
1461 {
1462     // Test T.sizeof == 1 path of fillWithMemcpy.
1463     ubyte[] a;
1464     fillWithMemcpy(a, ubyte(42));
1465     assert(a.length == 0);
1466     a = [ 1, 2, 3, 4, 5 ];
1467     fillWithMemcpy(a, ubyte(42));
1468     assert(a == [ 42, 42, 42, 42, 42]);
1469 }
1470 
1471 @system unittest
1472 {
1473     int[] a;
1474     fillWithMemcpy(a, 42);
1475     assert(a.length == 0);
1476     a = [ 1, 2, 3, 4, 5 ];
1477     fillWithMemcpy(a, 42);
1478     assert(a == [ 42, 42, 42, 42, 42]);
1479 }
1480 
1481 //Make shared object
1482 @system unittest
1483 {
1484     import core.atomic : atomicLoad;
1485     auto psi = theAllocator.make!(shared(int))(10);
1486     assert(10 == (*psi).atomicLoad());
1487 }
1488 
uninitializedFillDefault(T)1489 private T[] uninitializedFillDefault(T)(T[] array) nothrow
1490 {
1491     static if (__traits(isZeroInit, T))
1492     {
1493         import core.stdc.string : memset;
1494         if (array !is null)
1495             memset(array.ptr, 0, T.sizeof * array.length);
1496         return array;
1497     }
1498     else static if (is(immutable T == immutable char) || is(immutable T == immutable wchar))
1499     {
1500         import core.stdc.string : memset;
1501         if (array !is null)
1502             memset(array.ptr, 0xff, T.sizeof * array.length);
1503         return array;
1504     }
1505     else
1506     {
1507         T t = T.init;
1508         fillWithMemcpy(array, t);
1509         return array;
1510     }
1511 }
1512 
1513 pure nothrow @nogc
1514 @system unittest
1515 {
1516     static struct S { int x = 42; @disable this(this); }
1517 
1518     int[5] expected = [42, 42, 42, 42, 42];
1519     S[5] arr = void;
1520     uninitializedFillDefault(arr);
1521     assert((cast(int*) arr.ptr)[0 .. arr.length] == expected);
1522 }
1523 
1524 @system unittest
1525 {
1526     int[] a = [1, 2, 4];
1527     uninitializedFillDefault(a);
1528     assert(a == [0, 0, 0]);
1529 
1530     char[] b = [1, 2, 4];
1531     uninitializedFillDefault(b);
1532     assert(b == [0xff, 0xff, 0xff]);
1533 
1534     wchar[] c = [1, 2, 4];
1535     uninitializedFillDefault(c);
1536     assert(c == [0xffff, 0xffff, 0xffff]);
1537 }
1538 
1539 @system unittest
1540 {
1541     static struct P { float x = 0; float y = 0; }
1542 
1543     static assert(__traits(isZeroInit, P));
1544     P[] a = [P(10, 11), P(20, 21), P(40, 41)];
1545     uninitializedFillDefault(a);
1546     assert(a == [P.init, P.init, P.init]);
1547 }
1548 
1549 /**
1550 Create an array of `T` with `length` elements using `alloc`. The array is either default-initialized, filled with copies of `init`, or initialized with values fetched from `range`.
1551 
1552 Params:
1553 T = element type of the array being created
1554 alloc = the allocator used for getting memory
1555 length = length of the newly created array
1556 init = element used for filling the array
1557 range = range used for initializing the array elements
1558 
1559 Returns:
1560 The newly-created array, or `null` if either `length` was `0` or
1561 allocation failed.
1562 
1563 Throws:
1564 The first two overloads throw only if `alloc`'s primitives do. The
1565 overloads that involve copy initialization deallocate memory and propagate the
1566 exception if the copy operation throws.
1567 */
makeArray(T,Allocator)1568 T[] makeArray(T, Allocator)(auto ref Allocator alloc, size_t length)
1569 {
1570     if (!length) return null;
1571     static if (T.sizeof <= 1)
1572     {
1573         const nAlloc = length * T.sizeof;
1574     }
1575     else
1576     {
1577         import core.checkedint : mulu;
1578         bool overflow;
1579         const nAlloc = mulu(length, T.sizeof, overflow);
1580         if (overflow) return null;
1581     }
1582 
1583     static if (__traits(isZeroInit, T) && hasMember!(Allocator, "allocateZeroed"))
1584     {
1585         auto m = alloc.allocateZeroed(nAlloc);
1586         return (() @trusted => cast(T[]) m)();
1587     }
1588     else
1589     {
1590         auto m = alloc.allocate(nAlloc);
1591         if (!m.ptr) return null;
1592         alias U = Unqual!T;
1593         return () @trusted { return cast(T[]) uninitializedFillDefault(cast(U[]) m); }();
1594     }
1595 }
1596 
1597 @system unittest
1598 {
test1(A)1599     void test1(A)(auto ref A alloc)
1600     {
1601         int[] a = alloc.makeArray!int(0);
1602         assert(a.length == 0 && a.ptr is null);
1603         a = alloc.makeArray!int(5);
1604         assert(a.length == 5);
1605         static immutable cheatsheet = [0, 0, 0, 0, 0];
1606         assert(a == cheatsheet);
1607     }
1608 
test2(A)1609     void test2(A)(auto ref A alloc)
1610     {
1611         static struct S { int x = 42; @disable this(this); }
1612         S[] arr = alloc.makeArray!S(5);
1613         assert(arr.length == 5);
1614         int[] arrInt = () @trusted { return (cast(int*) arr.ptr)[0 .. 5]; }();
1615         static immutable res = [42, 42, 42, 42, 42];
1616         assert(arrInt == res);
1617     }
1618 
1619     import std.experimental.allocator.gc_allocator : GCAllocator;
1620     import std.experimental.allocator.mallocator : Mallocator;
1621     (alloc) /*pure nothrow*/ @safe { test1(alloc); test2(alloc);} (GCAllocator.instance);
1622     (alloc) nothrow @safe @nogc { test1(alloc); test2(alloc);} (Mallocator.instance);
1623     test2(theAllocator);
1624 }
1625 
1626 @system unittest
1627 {
1628     import std.algorithm.comparison : equal;
1629     auto a = theAllocator.makeArray!(shared int)(5);
1630     static assert(is(typeof(a) == shared(int)[]));
1631     assert(a.length == 5);
1632     assert(a.equal([0, 0, 0, 0, 0]));
1633 
1634     auto b = theAllocator.makeArray!(const int)(5);
1635     static assert(is(typeof(b) == const(int)[]));
1636     assert(b.length == 5);
1637     assert(b.equal([0, 0, 0, 0, 0]));
1638 
1639     auto c = theAllocator.makeArray!(immutable int)(5);
1640     static assert(is(typeof(c) == immutable(int)[]));
1641     assert(c.length == 5);
1642     assert(c.equal([0, 0, 0, 0, 0]));
1643 }
1644 
1645 // https://issues.dlang.org/show_bug.cgi?id=19085 - makeArray with void
1646 @system unittest
1647 {
1648     auto b = theAllocator.makeArray!void(5);
1649     scope(exit) theAllocator.dispose(b);
1650     auto c = cast(ubyte[]) b;
1651     assert(c.length == 5);
1652     assert(c == [0, 0, 0, 0, 0]); // default initialization
1653 }
1654 
1655 private enum hasPurePostblit(T) = !hasElaborateCopyConstructor!T ||
1656     is(typeof(() pure { T.init.__xpostblit(); }));
1657 
1658 private enum hasPureDtor(T) = !hasElaborateDestructor!T ||
1659     is(typeof(() pure { T.init.__xdtor(); }));
1660 
1661 // `true` when postblit and destructor of T cannot escape references to itself
1662 private enum canSafelyDeallocPostRewind(T) = hasPurePostblit!T && hasPureDtor!T;
1663 
1664 /// Ditto
makeArray(T,Allocator)1665 T[] makeArray(T, Allocator)(auto ref Allocator alloc, size_t length, T init)
1666 {
1667     if (!length) return null;
1668     auto m = alloc.allocate(T.sizeof * length);
1669     if (!m.ptr) return null;
1670     auto result = () @trusted { return cast(T[]) m; } ();
1671     import std.traits : hasElaborateCopyConstructor;
1672     static if (hasElaborateCopyConstructor!T)
1673     {
1674         scope(failure)
1675         {
1676             static if (canSafelyDeallocPostRewind!T)
1677                 () @trusted { alloc.deallocate(m); } ();
1678             else
1679                 alloc.deallocate(m);
1680         }
1681 
1682         size_t i = 0;
1683         static if (hasElaborateDestructor!T)
1684         {
1685             scope (failure)
1686             {
1687                 foreach (j; 0 .. i)
1688                 {
1689                     destroy(result[j]);
1690                 }
1691             }
1692         }
1693         import core.lifetime : emplace;
1694         for (; i < length; ++i)
1695         {
1696             emplace!T(&result[i], init);
1697         }
1698     }
1699     else
1700     {
1701         alias U = Unqual!T;
1702         () @trusted { fillWithMemcpy(cast(U[]) result, *(cast(U*) &init)); }();
1703     }
1704     return result;
1705 }
1706 
1707 ///
1708 @system unittest
1709 {
1710     import std.algorithm.comparison : equal;
test(T)1711     static void test(T)()
1712     {
1713         T[] a = theAllocator.makeArray!T(2);
1714         assert(a.equal([0, 0]));
1715         a = theAllocator.makeArray!T(3, 42);
1716         assert(a.equal([42, 42, 42]));
1717         import std.range : only;
1718         a = theAllocator.makeArray!T(only(42, 43, 44));
1719         assert(a.equal([42, 43, 44]));
1720     }
1721     test!int();
1722     test!(shared int)();
1723     test!(const int)();
1724     test!(immutable int)();
1725 }
1726 
1727 @system unittest
1728 {
test(T)1729     void test(T)(in T initialValue)
1730     {
1731         auto t = theAllocator.makeArray!T(100, initialValue);
1732         //auto t = theAllocator.makeArray(100, initialValue); // works well with the old code
1733     }
1734 
1735     const int init = 3;
1736     test(init);
1737 }
1738 
1739 @system unittest
1740 {
test(A)1741     void test(A)(auto ref A alloc)
1742     {
1743         long[] a = alloc.makeArray!long(0, 42);
1744         assert(a.length == 0 && a.ptr is null);
1745         a = alloc.makeArray!long(5, 42);
1746         assert(a.length == 5);
1747         assert(a == [ 42, 42, 42, 42, 42 ]);
1748     }
1749     import std.experimental.allocator.gc_allocator : GCAllocator;
1750     (alloc) /*pure nothrow*/ @safe { test(alloc); } (GCAllocator.instance);
1751     test(theAllocator);
1752 }
1753 
1754 // test failure with a pure, failing struct
1755 @safe unittest
1756 {
1757     import std.exception : assertThrown, enforce;
1758 
1759     struct NoCopy
1760     {
1761         @disable this();
1762 
thisNoCopy1763         this(int b){}
1764 
1765         // can't be copied
thisNoCopy1766         this(this)
1767         {
1768             enforce(1 == 2);
1769         }
1770     }
1771     import std.experimental.allocator.mallocator : Mallocator;
1772     assertThrown(makeArray!NoCopy(Mallocator.instance, 10, NoCopy(42)));
1773 }
1774 
1775 // test failure with an impure, failing struct
1776 @system unittest
1777 {
1778     import std.exception : assertThrown, enforce;
1779 
1780     static int i = 0;
1781     struct Singleton
1782     {
1783         @disable this();
1784 
thisSingleton1785         this(int b){}
1786 
1787         // can't be copied
thisSingleton1788         this(this)
1789         {
1790             enforce(i++ == 0);
1791         }
1792 
~thisSingleton1793         ~this()
1794         {
1795             i--;
1796         }
1797     }
1798     import std.experimental.allocator.mallocator : Mallocator;
1799     assertThrown(makeArray!Singleton(Mallocator.instance, 10, Singleton(42)));
1800 }
1801 
1802 /// Ditto
1803 Unqual!(ElementEncodingType!R)[] makeArray(Allocator, R)(auto ref Allocator alloc, R range)
1804 if (isInputRange!R && !isInfinite!R)
1805 {
1806     alias T = Unqual!(ElementEncodingType!R);
1807     return makeArray!(T, Allocator, R)(alloc, range);
1808 }
1809 
1810 /// Ditto
1811 T[] makeArray(T, Allocator, R)(auto ref Allocator alloc, R range)
1812 if (isInputRange!R && !isInfinite!R)
1813 {
1814     static if (isForwardRange!R || hasLength!R)
1815     {
1816         static if (hasLength!R || isNarrowString!R)
1817             immutable length = range.length;
1818         else
1819             immutable length = range.save.walkLength;
1820 
1821         if (!length) return null;
1822         auto m = alloc.allocate(T.sizeof * length);
1823         if (!m.ptr) return null;
1824         auto result = () @trusted { return cast(T[]) m; } ();
1825 
1826         size_t i = 0;
scope(failure)1827         scope (failure)
1828         {
1829             foreach (j; 0 .. i)
1830             {
1831                 auto p = () @trusted { return cast(Unqual!T*) &result[j]; }();
1832                 destroy(p);
1833             }
1834 
1835             static if (canSafelyDeallocPostRewind!T)
1836                 () @trusted { alloc.deallocate(m); } ();
1837             else
1838                 alloc.deallocate(m);
1839         }
1840 
1841         import core.internal.lifetime : emplaceRef;
1842         static if (isNarrowString!R || isRandomAccessRange!R)
1843         {
1844             foreach (j; 0 .. range.length)
1845             {
1846                 emplaceRef!T(result[i++], range[j]);
1847             }
1848         }
1849         else
1850         {
1851             for (; !range.empty; range.popFront, ++i)
1852             {
1853                 emplaceRef!T(result[i], range.front);
1854             }
1855         }
1856 
1857         return result;
1858     }
1859     else
1860     {
1861         // Estimated size
1862         size_t estimated = 8;
1863         auto m = alloc.allocate(T.sizeof * estimated);
1864         if (!m.ptr) return null;
1865         auto result = () @trusted { return cast(T[]) m; } ();
1866 
1867         size_t initialized = 0;
bailout()1868         void bailout()
1869         {
1870             foreach (i; 0 .. initialized + 1)
1871             {
1872                 destroy(result[i]);
1873             }
1874 
1875             static if (canSafelyDeallocPostRewind!T)
1876                 () @trusted { alloc.deallocate(m); } ();
1877             else
1878                 alloc.deallocate(m);
1879         }
1880         scope (failure) bailout;
1881 
1882         for (; !range.empty; range.popFront, ++initialized)
1883         {
1884             if (initialized == estimated)
1885             {
1886                 // Need to reallocate
1887                 static if (hasPurePostblit!T)
1888                     auto success = () @trusted { return alloc.reallocate(m, T.sizeof * (estimated *= 2)); } ();
1889                 else
1890                     auto success = alloc.reallocate(m, T.sizeof * (estimated *= 2));
1891                 if (!success)
1892                 {
1893                     bailout;
1894                     return null;
1895                 }
1896                 result = () @trusted { return cast(T[]) m; } ();
1897             }
1898             import core.internal.lifetime : emplaceRef;
1899             emplaceRef(result[initialized], range.front);
1900         }
1901 
1902         if (initialized < estimated)
1903         {
1904             // Try to shrink memory, no harm if not possible
1905             static if (hasPurePostblit!T)
1906                 auto success = () @trusted { return alloc.reallocate(m, T.sizeof * initialized); } ();
1907             else
1908                 auto success = alloc.reallocate(m, T.sizeof * initialized);
1909             if (success)
1910                 result = () @trusted { return cast(T[]) m; } ();
1911         }
1912 
1913         return result[0 .. initialized];
1914     }
1915 }
1916 
1917 @system unittest
1918 {
test(A)1919     void test(A)(auto ref A alloc)
1920     {
1921         long[] a = alloc.makeArray!long((int[]).init);
1922         assert(a.length == 0 && a.ptr is null);
1923         a = alloc.makeArray!long([5, 42]);
1924         assert(a.length == 2);
1925         assert(a == [ 5, 42]);
1926 
1927         // we can also infer the type
1928         auto b = alloc.makeArray([4.0, 2.0]);
1929         static assert(is(typeof(b) == double[]));
1930         assert(b == [4.0, 2.0]);
1931     }
1932     import std.experimental.allocator.gc_allocator : GCAllocator;
1933     (alloc) pure nothrow @safe { test(alloc); } (GCAllocator.instance);
1934     test(theAllocator);
1935 }
1936 
1937 // infer types for strings
1938 @system unittest
1939 {
test(A)1940     void test(A)(auto ref A alloc)
1941     {
1942         auto c = alloc.makeArray("fooπ��");
1943         static assert(is(typeof(c) == char[]));
1944         assert(c == "fooπ��");
1945 
1946         auto d = alloc.makeArray("fooπ��"d);
1947         static assert(is(typeof(d) == dchar[]));
1948         assert(d == "fooπ��");
1949 
1950         auto w = alloc.makeArray("fooπ��"w);
1951         static assert(is(typeof(w) == wchar[]));
1952         assert(w == "fooπ��");
1953     }
1954 
1955     import std.experimental.allocator.gc_allocator : GCAllocator;
1956     (alloc) pure nothrow @safe { test(alloc); } (GCAllocator.instance);
1957     test(theAllocator);
1958 }
1959 
1960 /*pure*/ nothrow @safe unittest
1961 {
1962     import std.algorithm.comparison : equal;
1963     import std.experimental.allocator.gc_allocator : GCAllocator;
1964     import std.internal.test.dummyrange;
1965     import std.range : iota;
foreach(DummyType;AllDummyRanges)1966     foreach (DummyType; AllDummyRanges)
1967     {
1968         (alloc) pure nothrow @safe
1969         {
1970             DummyType d;
1971             auto arr = alloc.makeArray(d);
1972             assert(arr.length == 10);
1973             assert(arr.equal(iota(1, 11)));
1974         } (GCAllocator.instance);
1975     }
1976 }
1977 
1978 // test failure with a pure, failing struct
1979 @safe unittest
1980 {
1981     import std.exception : assertThrown, enforce;
1982 
1983     struct NoCopy
1984     {
1985         int b;
1986 
1987         @disable this();
1988 
thisNoCopy1989         this(int b)
1990         {
1991             this.b = b;
1992         }
1993 
1994         // can't be copied
thisNoCopy1995         this(this)
1996         {
1997             enforce(b < 3, "there can only be three elements");
1998         }
1999     }
2000     import std.experimental.allocator.mallocator : Mallocator;
2001     auto arr = [NoCopy(1), NoCopy(2), NoCopy(3)];
2002     assertThrown(makeArray!NoCopy(Mallocator.instance, arr));
2003 
2004     struct NoCopyRange
2005     {
2006         static j = 0;
emptyNoCopyRange2007         bool empty()
2008         {
2009             return j > 5;
2010         }
2011 
frontNoCopyRange2012         auto front()
2013         {
2014             return NoCopy(j);
2015         }
2016 
popFrontNoCopyRange2017         void popFront()
2018         {
2019             j++;
2020         }
2021     }
2022     makeArray!NoCopy(Mallocator.instance, NoCopyRange()); // rvalue elements are forwarded/moved
2023 }
2024 
2025 // test failure with an impure, failing struct
2026 @system unittest
2027 {
2028     import std.exception : assertThrown, enforce;
2029 
2030     static i = 0;
2031     static maxElements = 2;
2032     struct NoCopy
2033     {
2034         int val;
2035         @disable this();
2036 
thisNoCopy2037         this(int b){
2038             this.val = i++;
2039         }
2040 
2041         // can't be copied
thisNoCopy2042         this(this)
2043         {
2044             enforce(i++ < maxElements, "there can only be four elements");
2045         }
2046     }
2047 
2048     import std.experimental.allocator.mallocator : Mallocator;
2049     auto arr = [NoCopy(1), NoCopy(2)];
2050     assertThrown(makeArray!NoCopy(Mallocator.instance, arr));
2051 
2052     i = 0;
2053     maxElements = 0; // disallow any postblit
2054     static j = 0;
2055 
2056     struct NoCopyRange
2057     {
emptyNoCopyRange2058         bool empty()
2059         {
2060             return j > 100;
2061         }
2062 
frontNoCopyRange2063         auto front()
2064         {
2065             return NoCopy(1);
2066         }
2067 
popFrontNoCopyRange2068         void popFront()
2069         {
2070             j++;
2071         }
2072     }
2073 
2074     auto arr2 = makeArray!NoCopy(Mallocator.instance, NoCopyRange());
2075     assert(i == j && i == 101); // all 101 rvalue elements forwarded/moved
2076 }
2077 
version(StdUnittest)2078 version (StdUnittest)
2079 {
2080     private struct ForcedInputRange(T)
2081     {
2082         T[]* array;
2083         pure nothrow @safe @nogc:
2084         bool empty() { return !array || (*array).empty; }
2085         ref T front() { return (*array)[0]; }
2086         void popFront() { *array = (*array)[1 .. $]; }
2087     }
2088 }
2089 
2090 @system unittest
2091 {
2092     import std.array : array;
2093     import std.range : iota;
2094     int[] arr = iota(10).array;
2095 
test(A)2096     void test(A)(auto ref A alloc)
2097     {
2098         ForcedInputRange!int r;
2099         long[] a = alloc.makeArray!long(r);
2100         assert(a.length == 0 && a.ptr is null);
2101         auto arr2 = arr;
2102         r.array = () @trusted { return &arr2; } ();
2103         a = alloc.makeArray!long(r);
2104         assert(a.length == 10);
2105         assert(a == iota(10).array);
2106     }
2107     import std.experimental.allocator.gc_allocator : GCAllocator;
2108     (alloc) pure nothrow @safe { test(alloc); } (GCAllocator.instance);
2109     test(theAllocator);
2110 }
2111 
2112 /**
2113 Grows `array` by appending `delta` more elements. The needed memory is
2114 allocated using `alloc`. The extra elements added are either default-
2115 initialized, filled with copies of `init`, or initialized with values
2116 fetched from `range`.
2117 
2118 Params:
2119 T = element type of the array being created
2120 alloc = the allocator used for getting memory
2121 array = a reference to the array being grown
2122 delta = number of elements to add (upon success the new length of `array` is
2123 $(D array.length + delta))
2124 init = element used for filling the array
2125 range = range used for initializing the array elements
2126 
2127 Returns:
2128 `true` upon success, `false` if memory could not be allocated. In the
2129 latter case `array` is left unaffected.
2130 
2131 Throws:
2132 The first two overloads throw only if `alloc`'s primitives do. The
2133 overloads that involve copy initialization deallocate memory and propagate the
2134 exception if the copy operation throws.
2135 */
expandArray(T,Allocator)2136 bool expandArray(T, Allocator)(auto ref Allocator alloc, ref T[] array,
2137         size_t delta)
2138 {
2139     if (!delta) return true;
2140     if (array is null) return false;
2141     immutable oldLength = array.length;
2142     void[] buf = array;
2143     if (!alloc.reallocate(buf, buf.length + T.sizeof * delta)) return false;
2144     array = cast(T[]) buf;
2145     array[oldLength .. $].uninitializedFillDefault;
2146     return true;
2147 }
2148 
2149 @system unittest
2150 {
test(A)2151     void test(A)(auto ref A alloc)
2152     {
2153         auto arr = alloc.makeArray!int([1, 2, 3]);
2154         assert(alloc.expandArray(arr, 3));
2155         assert(arr == [1, 2, 3, 0, 0, 0]);
2156     }
2157     import std.experimental.allocator.gc_allocator : GCAllocator;
2158     test(GCAllocator.instance);
2159     test(theAllocator);
2160 }
2161 
2162 /// Ditto
expandArray(T,Allocator)2163 bool expandArray(T, Allocator)(auto ref Allocator alloc, ref T[] array,
2164     size_t delta, auto ref T init)
2165 {
2166     if (!delta) return true;
2167     if (array is null) return false;
2168     void[] buf = array;
2169     if (!alloc.reallocate(buf, buf.length + T.sizeof * delta)) return false;
2170     immutable oldLength = array.length;
2171     array = cast(T[]) buf;
2172     scope(failure) array[oldLength .. $].uninitializedFillDefault;
2173     import std.algorithm.mutation : uninitializedFill;
2174     array[oldLength .. $].uninitializedFill(init);
2175     return true;
2176 }
2177 
2178 @system unittest
2179 {
test(A)2180     void test(A)(auto ref A alloc)
2181     {
2182         auto arr = alloc.makeArray!int([1, 2, 3]);
2183         assert(alloc.expandArray(arr, 3, 1));
2184         assert(arr == [1, 2, 3, 1, 1, 1]);
2185     }
2186     import std.experimental.allocator.gc_allocator : GCAllocator;
2187     test(GCAllocator.instance);
2188     test(theAllocator);
2189 }
2190 
2191 /// Ditto
2192 bool expandArray(T, Allocator, R)(auto ref Allocator alloc, ref T[] array,
2193         R range)
2194 if (isInputRange!R)
2195 {
2196     if (array is null) return false;
2197     static if (isForwardRange!R)
2198     {
2199         immutable delta = walkLength(range.save);
2200         if (!delta) return true;
2201         immutable oldLength = array.length;
2202 
2203         // Reallocate support memory
2204         void[] buf = array;
2205         if (!alloc.reallocate(buf, buf.length + T.sizeof * delta))
2206         {
2207             return false;
2208         }
2209         array = cast(T[]) buf;
2210         // At this point we're committed to the new length.
2211 
2212         auto toFill = array[oldLength .. $];
scope(failure)2213         scope (failure)
2214         {
2215             // Fill the remainder with default-constructed data
2216             toFill.uninitializedFillDefault;
2217         }
2218 
2219         for (; !range.empty; range.popFront, toFill = toFill[1 .. $])
2220         {
2221             assert(toFill.length > 0);
2222             import core.lifetime : emplace;
2223             emplace!T(&toFill[0], range.front);
2224         }
2225         assert(toFill.length == 0);
2226     }
2227     else
2228     {
scope(failure)2229         scope(failure)
2230         {
2231             // The last element didn't make it, fill with default
2232             array[$ - 1 .. $].uninitializedFillDefault;
2233         }
2234         void[] buf = array;
2235         for (; !range.empty; range.popFront)
2236         {
2237             if (!alloc.reallocate(buf, buf.length + T.sizeof))
2238             {
2239                 array = cast(T[]) buf;
2240                 return false;
2241             }
2242             import core.lifetime : emplace;
2243             emplace!T(buf[$ - T.sizeof .. $], range.front);
2244         }
2245 
2246         array = cast(T[]) buf;
2247     }
2248     return true;
2249 }
2250 
2251 ///
2252 @system unittest
2253 {
2254     auto arr = theAllocator.makeArray!int([1, 2, 3]);
2255     assert(theAllocator.expandArray(arr, 2));
2256     assert(arr == [1, 2, 3, 0, 0]);
2257     import std.range : only;
2258     assert(theAllocator.expandArray(arr, only(4, 5)));
2259     assert(arr == [1, 2, 3, 0, 0, 4, 5]);
2260 }
2261 
2262 @system unittest
2263 {
2264     auto arr = theAllocator.makeArray!int([1, 2, 3]);
2265     ForcedInputRange!int r;
2266     int[] b = [ 1, 2, 3, 4 ];
2267     auto temp = b;
2268     r.array = &temp;
2269     assert(theAllocator.expandArray(arr, r));
2270     assert(arr == [1, 2, 3, 1, 2, 3, 4]);
2271 }
2272 
2273 // Regression test for https://issues.dlang.org/show_bug.cgi?id=20929
2274 @system unittest
2275 {
test(Char,Allocator)2276     static void test(Char, Allocator)(auto ref Allocator alloc)
2277     {
2278         auto arr = alloc.makeArray!Char(1, Char('f'));
2279 
2280         import std.utf : byUTF;
2281         auto forwardRange = "oo".byUTF!Char();
2282         static assert(isForwardRange!(typeof(forwardRange)));
2283         // Test the forward-range code-path.
2284         assert(alloc.expandArray(arr, forwardRange));
2285 
2286         assert(arr == "foo");
2287 
2288         immutable(Char)[] temp = "bar";
2289         auto inputRange = ForcedInputRange!(immutable(Char))(&temp);
2290         // Test the input-range code-path.
2291         assert(alloc.expandArray(arr, inputRange));
2292 
2293         assert(arr == "foobar");
2294     }
2295 
2296     import std.experimental.allocator.gc_allocator : GCAllocator;
2297     test!char(GCAllocator.instance);
2298     test!wchar(GCAllocator.instance);
2299     test!char(theAllocator);
2300     test!wchar(theAllocator);
2301 }
2302 
2303 /**
2304 Shrinks an array by `delta` elements.
2305 
2306 If $(D array.length < delta), does nothing and returns `false`. Otherwise,
2307 destroys the last $(D array.length - delta) elements in the array and then
2308 reallocates the array's buffer. If reallocation fails, fills the array with
2309 default-initialized data.
2310 
2311 Params:
2312 T = element type of the array being created
2313 alloc = the allocator used for getting memory
2314 array = a reference to the array being shrunk
2315 delta = number of elements to remove (upon success the new length of `array` is $(D array.length - delta))
2316 
2317 Returns:
2318 `true` upon success, `false` if memory could not be reallocated. In the latter
2319 case, the slice $(D array[$ - delta .. $]) is left with default-initialized
2320 elements.
2321 
2322 Throws:
2323 The first two overloads throw only if `alloc`'s primitives do. The
2324 overloads that involve copy initialization deallocate memory and propagate the
2325 exception if the copy operation throws.
2326 */
shrinkArray(T,Allocator)2327 bool shrinkArray(T, Allocator)(auto ref Allocator alloc,
2328         ref T[] array, size_t delta)
2329 {
2330     if (delta > array.length) return false;
2331 
2332     // Destroy elements. If a destructor throws, fill the already destroyed
2333     // stuff with the default initializer.
2334     {
2335         size_t destroyed;
2336         scope(failure)
2337         {
2338             array[$ - delta .. $][0 .. destroyed].uninitializedFillDefault;
2339         }
2340         foreach (ref e; array[$ - delta .. $])
2341         {
2342             e.destroy;
2343             ++destroyed;
2344         }
2345     }
2346 
2347     if (delta == array.length)
2348     {
2349         alloc.deallocate(array);
2350         array = null;
2351         return true;
2352     }
2353 
2354     void[] buf = array;
2355     if (!alloc.reallocate(buf, buf.length - T.sizeof * delta))
2356     {
2357         // urgh, at least fill back with default
2358         array[$ - delta .. $].uninitializedFillDefault;
2359         return false;
2360     }
2361     array = cast(T[]) buf;
2362     return true;
2363 }
2364 
2365 ///
2366 @system unittest
2367 {
2368     int[] a = theAllocator.makeArray!int(100, 42);
2369     assert(a.length == 100);
2370     assert(theAllocator.shrinkArray(a, 98));
2371     assert(a.length == 2);
2372     assert(a == [42, 42]);
2373 }
2374 
2375 @system unittest
2376 {
test(A)2377     void test(A)(auto ref A alloc)
2378     {
2379         long[] a = alloc.makeArray!long((int[]).init);
2380         assert(a.length == 0 && a.ptr is null);
2381         a = alloc.makeArray!long(100, 42);
2382         assert(alloc.shrinkArray(a, 98));
2383         assert(a.length == 2);
2384         assert(a == [ 42, 42]);
2385     }
2386     import std.experimental.allocator.gc_allocator : GCAllocator;
2387     test(GCAllocator.instance);
2388     test(theAllocator);
2389 }
2390 
2391 /**
2392 
2393 Destroys and then deallocates (using `alloc`) the object pointed to by a
2394 pointer, the class object referred to by a `class` or `interface`
2395 reference, or an entire array. It is assumed the respective entities had been
2396 allocated with the same allocator.
2397 
2398 */
dispose(A,T)2399 void dispose(A, T)(auto ref A alloc, auto ref T* p)
2400 {
2401     static if (hasElaborateDestructor!T)
2402     {
2403         destroy(*p);
2404     }
2405     alloc.deallocate((cast(void*) p)[0 .. T.sizeof]);
2406     static if (__traits(isRef, p))
2407         p = null;
2408 }
2409 
2410 /// Ditto
2411 void dispose(A, T)(auto ref A alloc, auto ref T p)
2412 if (is(T == class) || is(T == interface))
2413 {
2414     if (!p) return;
2415     static if (is(T == interface))
2416     {
version(Windows)2417         version (Windows)
2418         {
2419             import core.sys.windows.unknwn : IUnknown;
2420             static assert(!is(T: IUnknown), "COM interfaces can't be destroyed in "
2421                 ~ __PRETTY_FUNCTION__);
2422         }
2423         auto ob = cast(Object) p;
2424     }
2425     else
2426         alias ob = p;
2427     auto support = (cast(void*) ob)[0 .. typeid(ob).initializer.length];
2428     destroy(p);
2429     alloc.deallocate(support);
2430     static if (__traits(isRef, p))
2431         p = null;
2432 }
2433 
2434 /// Ditto
dispose(A,T)2435 void dispose(A, T)(auto ref A alloc, auto ref T[] array)
2436 {
2437     static if (hasElaborateDestructor!(typeof(array[0])))
2438     {
2439         foreach (ref e; array)
2440         {
2441             destroy(e);
2442         }
2443     }
2444     alloc.deallocate(array);
2445     static if (__traits(isRef, array))
2446         array = null;
2447 }
2448 
2449 @system unittest
2450 {
2451     static int x;
2452     static interface I
2453     {
2454         void method();
2455     }
2456     static class A : I
2457     {
2458         int y;
method()2459         override void method() { x = 21; }
~this()2460         ~this() { x = 42; }
2461     }
2462     static class B : A
2463     {
2464     }
2465     auto a = theAllocator.make!A;
2466     a.method();
2467     assert(x == 21);
2468     theAllocator.dispose(a);
2469     assert(x == 42);
2470 
2471     B b = theAllocator.make!B;
2472     b.method();
2473     assert(x == 21);
2474     theAllocator.dispose(b);
2475     assert(x == 42);
2476 
2477     I i = theAllocator.make!B;
2478     i.method();
2479     assert(x == 21);
2480     theAllocator.dispose(i);
2481     assert(x == 42);
2482 
2483     int[] arr = theAllocator.makeArray!int(43);
2484     theAllocator.dispose(arr);
2485 }
2486 
2487 // https://issues.dlang.org/show_bug.cgi?id=16512
2488 @system unittest
2489 {
2490     import std.experimental.allocator.mallocator : Mallocator;
2491 
2492     int* i = Mallocator.instance.make!int(0);
2493     Mallocator.instance.dispose(i);
2494     assert(i is null);
2495 
2496     Object o = Mallocator.instance.make!Object();
2497     Mallocator.instance.dispose(o);
2498     assert(o is null);
2499 
2500     uint* u = Mallocator.instance.make!uint(0);
2501     Mallocator.instance.dispose((){return u;}());
2502     assert(u !is null);
2503 
2504     uint[] ua = Mallocator.instance.makeArray!uint([0,1,2]);
2505     Mallocator.instance.dispose(ua);
2506     assert(ua is null);
2507 }
2508 
2509 // https://issues.dlang.org/show_bug.cgi?id=15721
2510 @system unittest
2511 {
2512     import std.experimental.allocator.mallocator : Mallocator;
2513 
2514     interface Foo {}
2515     class Bar: Foo {}
2516 
2517     Bar bar;
2518     Foo foo;
2519     bar = Mallocator.instance.make!Bar;
2520     foo = cast(Foo) bar;
2521     Mallocator.instance.dispose(foo);
2522 }
2523 
2524 /**
2525 Allocates a multidimensional array of elements of type T.
2526 
2527 Params:
2528 N = number of dimensions
2529 T = element type of an element of the multidimensional arrat
2530 alloc = the allocator used for getting memory
2531 lengths = static array containing the size of each dimension
2532 
2533 Returns:
2534 An N-dimensional array with individual elements of type T.
2535 */
makeMultidimensionalArray(T,Allocator,size_t N)2536 auto makeMultidimensionalArray(T, Allocator, size_t N)(auto ref Allocator alloc, size_t[N] lengths...)
2537 {
2538     static if (N == 1)
2539     {
2540         return makeArray!T(alloc, lengths[0]);
2541     }
2542     else
2543     {
2544         alias E = typeof(makeMultidimensionalArray!(T, Allocator, N - 1)(alloc, lengths[1 .. $]));
2545         auto ret = makeArray!E(alloc, lengths[0]);
2546         foreach (ref e; ret)
2547             e = makeMultidimensionalArray!(T, Allocator, N - 1)(alloc, lengths[1 .. $]);
2548         return ret;
2549     }
2550 }
2551 
2552 ///
2553 @system unittest
2554 {
2555     import std.experimental.allocator.mallocator : Mallocator;
2556 
2557     auto mArray = Mallocator.instance.makeMultidimensionalArray!int(2, 3, 6);
2558 
2559     // deallocate when exiting scope
scope(exit)2560     scope(exit)
2561     {
2562         Mallocator.instance.disposeMultidimensionalArray(mArray);
2563     }
2564 
2565     assert(mArray.length == 2);
foreach(lvl2Array;mArray)2566     foreach (lvl2Array; mArray)
2567     {
2568         assert(lvl2Array.length == 3);
2569         foreach (lvl3Array; lvl2Array)
2570             assert(lvl3Array.length == 6);
2571     }
2572 }
2573 
2574 /**
2575 Destroys and then deallocates a multidimensional array, assuming it was
2576 created with makeMultidimensionalArray and the same allocator was used.
2577 
2578 Params:
2579 T = element type of an element of the multidimensional array
2580 alloc = the allocator used for getting memory
2581 array = the multidimensional array that is to be deallocated
2582 */
disposeMultidimensionalArray(T,Allocator)2583 void disposeMultidimensionalArray(T, Allocator)(auto ref Allocator alloc, auto ref T[] array)
2584 {
2585     static if (isArray!T)
2586     {
2587         foreach (ref e; array)
2588             disposeMultidimensionalArray(alloc, e);
2589     }
2590 
2591     dispose(alloc, array);
2592     static if (__traits(isRef, array))
2593         array = null;
2594 }
2595 
2596 ///
2597 @system unittest
2598 {
2599     struct TestAllocator
2600     {
2601         import std.experimental.allocator.common : platformAlignment;
2602         import std.experimental.allocator.mallocator : Mallocator;
2603 
2604         alias allocator = Mallocator.instance;
2605 
2606         private static struct ByteRange
2607         {
2608             void* ptr;
2609             size_t length;
2610         }
2611 
2612         private ByteRange[] _allocations;
2613 
2614         enum uint alignment = platformAlignment;
2615 
allocateTestAllocator2616         void[] allocate(size_t numBytes)
2617         {
2618              auto ret = allocator.allocate(numBytes);
2619              _allocations ~= ByteRange(ret.ptr, ret.length);
2620              return ret;
2621         }
2622 
deallocateTestAllocator2623         bool deallocate(void[] bytes)
2624         {
2625             import std.algorithm.mutation : remove;
2626             import std.algorithm.searching : canFind;
2627 
2628             bool pred(ByteRange other)
2629             { return other.ptr == bytes.ptr && other.length == bytes.length; }
2630 
2631             assert(_allocations.canFind!pred);
2632 
2633              _allocations = _allocations.remove!pred;
2634              return allocator.deallocate(bytes);
2635         }
2636 
~thisTestAllocator2637         ~this()
2638         {
2639             assert(!_allocations.length);
2640         }
2641     }
2642 
2643     TestAllocator allocator;
2644 
2645     auto mArray = allocator.makeMultidimensionalArray!int(2, 3, 5, 6, 7, 2);
2646 
2647     allocator.disposeMultidimensionalArray(mArray);
2648 }
2649 
2650 /**
2651 
2652 Returns a dynamically-typed `CAllocator` built around a given statically-
2653 typed allocator `a` of type `A`. Passing a pointer to the allocator
2654 creates a dynamic allocator around the allocator pointed to by the pointer,
2655 without attempting to copy or move it. Passing the allocator by value or
2656 reference behaves as follows.
2657 
2658 $(UL
2659 $(LI If `A` has no state, the resulting object is allocated in static
2660 shared storage.)
2661 $(LI If `A` has state, the result will $(REF move, std,algorithm,mutation)
2662 the supplied allocator $(D A a) within. The result itself is allocated in its
2663 own statically-typed allocator.)
2664 )
2665 
2666 */
2667 RCIAllocator allocatorObject(A)(auto ref A a)
2668 if (!isPointer!A)
2669 {
2670     import core.lifetime : emplace;
2671     static if (stateSize!A == 0)
2672     {
2673         enum s = stateSize!(CAllocatorImpl!A).divideRoundUp(ulong.sizeof);
2674         __gshared ulong[s] state;
2675         __gshared RCIAllocator result;
2676         if (result.isNull)
2677         {
2678             // Don't care about a few races
2679             result = RCIAllocator(emplace!(CAllocatorImpl!A)(state[]));
2680         }
2681         assert(!result.isNull);
2682         return result;
2683     }
2684     else
2685     {
2686         auto state = a.allocate(stateSize!(CAllocatorImpl!A));
2687         import std.algorithm.mutation : move;
2688         import std.traits : hasMember;
2689         static if (hasMember!(A, "deallocate"))
2690         {
2691             scope(failure) a.deallocate(state);
2692         }
2693         auto tmp = cast(CAllocatorImpl!A) emplace!(CAllocatorImpl!A)(state);
2694         move(a, tmp.impl);
2695         return RCIAllocator(tmp);
2696     }
2697 }
2698 
2699 /// Ditto
allocatorObject(A)2700 RCIAllocator allocatorObject(A)(A* pa)
2701 {
2702     assert(pa);
2703     import core.lifetime : emplace;
2704     auto state = pa.allocate(stateSize!(CAllocatorImpl!(A, Yes.indirect)));
2705     import std.traits : hasMember;
2706     static if (hasMember!(A, "deallocate"))
2707     {
2708         scope(failure) pa.deallocate(state);
2709     }
2710     return RCIAllocator(emplace!(CAllocatorImpl!(A, Yes.indirect))
2711                             (state, pa));
2712 }
2713 
2714 ///
2715 @system unittest
2716 {
2717     import std.experimental.allocator.mallocator : Mallocator;
2718 
2719     RCIAllocator a = allocatorObject(Mallocator.instance);
2720     auto b = a.allocate(100);
2721     assert(b.length == 100);
2722     assert(a.deallocate(b));
2723 
2724     // The in-situ region must be used by pointer
2725     import std.experimental.allocator.building_blocks.region : InSituRegion;
2726     auto r = InSituRegion!1024();
2727     a = allocatorObject(&r);
2728     b = a.allocate(200);
2729     assert(b.length == 200);
2730     // In-situ regions can deallocate the last allocation
2731     assert(a.deallocate(b));
2732 }
2733 
2734 @system unittest
2735 {
2736     import std.conv;
2737     import std.experimental.allocator.mallocator;
2738     import std.experimental.allocator.building_blocks.stats_collector;
2739 
2740     alias SCAlloc = StatsCollector!(Mallocator, Options.bytesUsed);
2741     SCAlloc statsCollectorAlloc;
2742     assert(statsCollectorAlloc.bytesUsed == 0);
2743 
2744     auto _allocator = allocatorObject(statsCollectorAlloc);
2745     // Ensure that the allocator was passed through in CAllocatorImpl
2746     // This allocator was used to allocate the chunk that holds the
2747     // CAllocatorImpl object; which is it's own wrapper
2748     assert((cast(CAllocatorImpl!(SCAlloc))(_allocator._alloc)).impl.bytesUsed
2749             == stateSize!(CAllocatorImpl!(SCAlloc)));
2750     _allocator.allocate(1);
2751     assert((cast(CAllocatorImpl!(SCAlloc))(_allocator._alloc)).impl.bytesUsed
2752             == stateSize!(CAllocatorImpl!(SCAlloc)) + 1);
2753 }
2754 
2755 /**
2756 
2757 Returns a dynamically-typed `CSharedAllocator` built around a given statically-
2758 typed allocator `a` of type `A`. Passing a pointer to the allocator
2759 creates a dynamic allocator around the allocator pointed to by the pointer,
2760 without attempting to copy or move it. Passing the allocator by value or
2761 reference behaves as follows.
2762 
2763 $(UL
2764 $(LI If `A` has no state, the resulting object is allocated in static
2765 shared storage.)
2766 $(LI If `A` has state and is copyable, the result will
2767 $(REF move, std,algorithm,mutation) the supplied allocator $(D A a) within.
2768 The result itself is allocated in its own statically-typed allocator.)
2769 $(LI If `A` has state and is not copyable, the result will move the
2770 passed-in argument into the result. The result itself is allocated in its own
2771 statically-typed allocator.)
2772 )
2773 
2774 */
2775 //nothrow @safe
2776 //nothrow @nogc @safe
2777 nothrow
2778 RCISharedAllocator sharedAllocatorObject(A)(auto ref A a)
2779 if (!isPointer!A)
2780 {
2781     import core.lifetime : emplace;
2782     static if (stateSize!A == 0)
2783     {
2784         enum s = stateSize!(CSharedAllocatorImpl!A).divideRoundUp(ulong.sizeof);
2785         static shared ulong[s] state;
2786         static RCISharedAllocator result;
2787         if (result.isNull)
2788         {
2789             // Don't care about a few races
2790             result = RCISharedAllocator(
2791                     (cast(shared CSharedAllocatorImpl!A)(
2792                         emplace!(CSharedAllocatorImpl!A)(
2793                             (() @trusted => cast(ulong[]) state[])()))));
2794         }
2795         assert(!result.isNull);
2796         return result;
2797     }
2798     else static if (is(typeof({ shared A b = a; shared A c = b; }))) // copyable
2799     {
2800         auto state = a.allocate(stateSize!(CSharedAllocatorImpl!A));
2801         import std.algorithm.mutation : move;
2802         import std.traits : hasMember;
2803         static if (hasMember!(A, "deallocate"))
2804         {
2805             scope(failure) a.deallocate(state);
2806         }
2807         auto tmp = emplace!(shared CSharedAllocatorImpl!A)(state);
2808         move(a, tmp.impl);
2809         return RCISharedAllocator(tmp);
2810     }
2811     else // the allocator object is not copyable
2812     {
2813         assert(0, "Not yet implemented");
2814     }
2815 }
2816 
2817 /// Ditto
sharedAllocatorObject(A)2818 RCISharedAllocator sharedAllocatorObject(A)(A* pa)
2819 {
2820     assert(pa);
2821     import core.lifetime : emplace;
2822     auto state = pa.allocate(stateSize!(CSharedAllocatorImpl!(A, Yes.indirect)));
2823     import std.traits : hasMember;
2824     static if (hasMember!(A, "deallocate"))
2825     {
2826         scope(failure) pa.deallocate(state);
2827     }
2828     return RCISharedAllocator(emplace!(shared CSharedAllocatorImpl!(A, Yes.indirect))(state, pa));
2829 }
2830 
2831 
2832 /**
2833 
2834 Implementation of `IAllocator` using `Allocator`. This adapts a
2835 statically-built allocator type to `IAllocator` that is directly usable by
2836 non-templated code.
2837 
2838 Usually `CAllocatorImpl` is used indirectly by calling $(LREF theAllocator).
2839 */
2840 class CAllocatorImpl(Allocator, Flag!"indirect" indirect = No.indirect)
2841     : IAllocator
2842 {
2843     import std.traits : hasMember;
2844 
2845     static if (stateSize!Allocator) private size_t rc = 1;
2846 
2847     /**
2848     The implementation is available as a public member.
2849     */
2850     static if (indirect)
2851     {
2852     nothrow:
2853         private Allocator* pimpl;
2854 
2855         @nogc pure @safe
impl()2856         ref Allocator impl()
2857         {
2858             return *pimpl;
2859         }
2860 
2861         @nogc pure @safe
this(Allocator * pa)2862         this(Allocator* pa)
2863         {
2864             pimpl = pa;
2865         }
2866     }
2867     else
2868     {
2869         static if (stateSize!Allocator) Allocator impl;
2870         else alias impl = Allocator.instance;
2871     }
2872 
2873 nothrow:
2874     /// Returns `impl.alignment`.
alignment()2875     override @property uint alignment()
2876     {
2877         return impl.alignment;
2878     }
2879 
2880     /**
2881     Returns `impl.goodAllocSize(s)`.
2882     */
goodAllocSize(size_t s)2883     override size_t goodAllocSize(size_t s)
2884     {
2885         return impl.goodAllocSize(s);
2886     }
2887 
2888     /**
2889     Returns `impl.allocate(s)`.
2890     */
2891     override void[] allocate(size_t s, TypeInfo ti = null)
2892     {
2893         return impl.allocate(s);
2894     }
2895 
2896     /**
2897     If `impl.alignedAllocate` exists, calls it and returns the result.
2898     Otherwise, always returns `null`.
2899     */
alignedAllocate(size_t s,uint a)2900     override void[] alignedAllocate(size_t s, uint a)
2901     {
2902         static if (hasMember!(Allocator, "alignedAllocate"))
2903             return impl.alignedAllocate(s, a);
2904         else
2905             return null;
2906     }
2907 
2908     /**
2909     If `Allocator` implements `owns`, forwards to it. Otherwise, returns
2910     `Ternary.unknown`.
2911     */
owns(void[]b)2912     override Ternary owns(void[] b)
2913     {
2914         static if (hasMember!(Allocator, "owns")) return impl.owns(b);
2915         else return Ternary.unknown;
2916     }
2917 
2918     /// Returns $(D impl.expand(b, s)) if defined, `false` otherwise.
expand(ref void[]b,size_t s)2919     override bool expand(ref void[] b, size_t s)
2920     {
2921         static if (hasMember!(Allocator, "expand"))
2922             return impl.expand(b, s);
2923         else
2924             return s == 0;
2925     }
2926 
2927     /// Returns $(D impl.reallocate(b, s)).
reallocate(ref void[]b,size_t s)2928     override bool reallocate(ref void[] b, size_t s)
2929     {
2930         return impl.reallocate(b, s);
2931     }
2932 
2933     /// Forwards to `impl.alignedReallocate` if defined, `false` otherwise.
alignedReallocate(ref void[]b,size_t s,uint a)2934     bool alignedReallocate(ref void[] b, size_t s, uint a)
2935     {
2936         static if (!hasMember!(Allocator, "alignedAllocate"))
2937         {
2938             return false;
2939         }
2940         else
2941         {
2942             return impl.alignedReallocate(b, s, a);
2943         }
2944     }
2945 
2946     // Undocumented for now
resolveInternalPointer(const void * p,ref void[]result)2947     Ternary resolveInternalPointer(const void* p, ref void[] result)
2948     {
2949         static if (hasMember!(Allocator, "resolveInternalPointer"))
2950         {
2951             return impl.resolveInternalPointer(p, result);
2952         }
2953         else
2954         {
2955             return Ternary.unknown;
2956         }
2957     }
2958 
2959     /**
2960     If `impl.deallocate` is not defined, returns `false`. Otherwise it forwards
2961     the call.
2962     */
deallocate(void[]b)2963     override bool deallocate(void[] b)
2964     {
2965         static if (hasMember!(Allocator, "deallocate"))
2966         {
2967             return impl.deallocate(b);
2968         }
2969         else
2970         {
2971             return false;
2972         }
2973     }
2974 
2975     /**
2976     Calls `impl.deallocateAll()` and returns the result if defined,
2977     otherwise returns `false`.
2978     */
deallocateAll()2979     override bool deallocateAll()
2980     {
2981         static if (hasMember!(Allocator, "deallocateAll"))
2982         {
2983             return impl.deallocateAll();
2984         }
2985         else
2986         {
2987             return false;
2988         }
2989     }
2990 
2991     /**
2992     Forwards to `impl.empty()` if defined, otherwise returns `Ternary.unknown`.
2993     */
empty()2994     override Ternary empty()
2995     {
2996         static if (hasMember!(Allocator, "empty"))
2997         {
2998             return Ternary(impl.empty);
2999         }
3000         else
3001         {
3002             return Ternary.unknown;
3003         }
3004     }
3005 
3006     /**
3007     Returns `impl.allocateAll()` if present, `null` otherwise.
3008     */
allocateAll()3009     override void[] allocateAll()
3010     {
3011         static if (hasMember!(Allocator, "allocateAll"))
3012         {
3013             return impl.allocateAll();
3014         }
3015         else
3016         {
3017             return null;
3018         }
3019     }
3020 
3021     @nogc nothrow pure @safe
incRef()3022     override void incRef()
3023     {
3024         static if (stateSize!Allocator) ++rc;
3025     }
3026 
3027     @nogc nothrow pure @trusted
decRef()3028     override bool decRef()
3029     {
3030         static if (stateSize!Allocator)
3031         {
3032             import core.stdc.string : memcpy;
3033 
3034             if (rc == 1)
3035             {
3036                 static if (indirect)
3037                 {
3038                     Allocator* tmp = pimpl;
3039                 }
3040                 else
3041                 {
3042                     Allocator tmp;
3043                     memcpy(&tmp, &this.impl, Allocator.sizeof);
3044                 }
3045                 void[] support = (cast(void*) this)[0 .. stateSize!(typeof(this))];
3046                 tmp.deallocate(support);
3047                 return false;
3048             }
3049 
3050             --rc;
3051             return true;
3052         }
3053         else
3054         {
3055             return true;
3056         }
3057     }
3058 }
3059 
3060 /**
3061 
3062 Implementation of `ISharedAllocator` using `Allocator`. This adapts a
3063 statically-built, shareable across threads, allocator type to `ISharedAllocator`
3064 that is directly usable by non-templated code.
3065 
3066 Usually `CSharedAllocatorImpl` is used indirectly by calling
3067 $(LREF processAllocator).
3068 */
3069 class CSharedAllocatorImpl(Allocator, Flag!"indirect" indirect = No.indirect)
3070     : ISharedAllocator
3071 {
3072     import std.traits : hasMember;
3073     import core.atomic : atomicOp, atomicLoad;
3074 
3075     static if (stateSize!Allocator) shared size_t rc = 1;
3076 
3077     /**
3078     The implementation is available as a public member.
3079     */
3080     static if (indirect)
3081     {
3082     nothrow:
3083         private shared Allocator* pimpl;
3084 
3085         @nogc pure @safe
impl()3086         ref Allocator impl() shared
3087         {
3088             return *pimpl;
3089         }
3090 
3091         @nogc pure @safe
this(Allocator * pa)3092         this(Allocator* pa) shared
3093         {
3094             pimpl = pa;
3095         }
3096     }
3097     else
3098     {
3099         static if (stateSize!Allocator) shared Allocator impl;
3100         else alias impl = Allocator.instance;
3101     }
3102 
3103 nothrow:
3104     /// Returns `impl.alignment`.
alignment()3105     override @property uint alignment() shared
3106     {
3107         return impl.alignment;
3108     }
3109 
3110     /**
3111     Returns `impl.goodAllocSize(s)`.
3112     */
goodAllocSize(size_t s)3113     override size_t goodAllocSize(size_t s) shared
3114     {
3115         return impl.goodAllocSize(s);
3116     }
3117 
3118     /**
3119     Returns `impl.allocate(s)`.
3120     */
3121     override void[] allocate(size_t s, TypeInfo ti = null) shared
3122     {
3123         return impl.allocate(s);
3124     }
3125 
3126     /**
3127     If `impl.alignedAllocate` exists, calls it and returns the result.
3128     Otherwise, always returns `null`.
3129     */
alignedAllocate(size_t s,uint a)3130     override void[] alignedAllocate(size_t s, uint a) shared
3131     {
3132         static if (hasMember!(Allocator, "alignedAllocate"))
3133             return impl.alignedAllocate(s, a);
3134         else
3135             return null;
3136     }
3137 
3138     /**
3139     If `Allocator` implements `owns`, forwards to it. Otherwise, returns
3140     `Ternary.unknown`.
3141     */
owns(void[]b)3142     override Ternary owns(void[] b) shared
3143     {
3144         static if (hasMember!(Allocator, "owns")) return impl.owns(b);
3145         else return Ternary.unknown;
3146     }
3147 
3148     /// Returns $(D impl.expand(b, s)) if defined, `false` otherwise.
expand(ref void[]b,size_t s)3149     override bool expand(ref void[] b, size_t s) shared
3150     {
3151         static if (hasMember!(Allocator, "expand"))
3152             return impl.expand(b, s);
3153         else
3154             return s == 0;
3155     }
3156 
3157     /// Returns $(D impl.reallocate(b, s)).
reallocate(ref void[]b,size_t s)3158     override bool reallocate(ref void[] b, size_t s) shared
3159     {
3160         return impl.reallocate(b, s);
3161     }
3162 
3163     /// Forwards to `impl.alignedReallocate` if defined, `false` otherwise.
alignedReallocate(ref void[]b,size_t s,uint a)3164     bool alignedReallocate(ref void[] b, size_t s, uint a) shared
3165     {
3166         static if (!hasMember!(Allocator, "alignedAllocate"))
3167         {
3168             return false;
3169         }
3170         else
3171         {
3172             return impl.alignedReallocate(b, s, a);
3173         }
3174     }
3175 
3176     // Undocumented for now
resolveInternalPointer(const void * p,ref void[]result)3177     Ternary resolveInternalPointer(const void* p, ref void[] result) shared
3178     {
3179         static if (hasMember!(Allocator, "resolveInternalPointer"))
3180         {
3181             return impl.resolveInternalPointer(p, result);
3182         }
3183         else
3184         {
3185             return Ternary.unknown;
3186         }
3187     }
3188 
3189     /**
3190     If `impl.deallocate` is not defined, returns `false`. Otherwise it forwards
3191     the call.
3192     */
deallocate(void[]b)3193     override bool deallocate(void[] b) shared
3194     {
3195         static if (hasMember!(Allocator, "deallocate"))
3196         {
3197             return impl.deallocate(b);
3198         }
3199         else
3200         {
3201             return false;
3202         }
3203     }
3204 
3205     /**
3206     Calls `impl.deallocateAll()` and returns the result if defined,
3207     otherwise returns `false`.
3208     */
deallocateAll()3209     override bool deallocateAll() shared
3210     {
3211         static if (hasMember!(Allocator, "deallocateAll"))
3212         {
3213             return impl.deallocateAll();
3214         }
3215         else
3216         {
3217             return false;
3218         }
3219     }
3220 
3221     /**
3222     Forwards to `impl.empty()` if defined, otherwise returns `Ternary.unknown`.
3223     */
empty()3224     override Ternary empty() shared
3225     {
3226         static if (hasMember!(Allocator, "empty"))
3227         {
3228             return Ternary(impl.empty);
3229         }
3230         else
3231         {
3232             return Ternary.unknown;
3233         }
3234     }
3235 
3236     /**
3237     Returns `impl.allocateAll()` if present, `null` otherwise.
3238     */
allocateAll()3239     override void[] allocateAll() shared
3240     {
3241         static if (hasMember!(Allocator, "allocateAll"))
3242         {
3243             return impl.allocateAll();
3244         }
3245         else
3246         {
3247             return null;
3248         }
3249     }
3250 
3251     @nogc nothrow pure @safe
incRef()3252     override void incRef() shared
3253     {
3254         static if (stateSize!Allocator) atomicOp!"+="(rc, 1);
3255     }
3256 
3257     @nogc nothrow pure @trusted
decRef()3258     override bool decRef() shared
3259     {
3260         static if (stateSize!Allocator)
3261         {
3262             import core.stdc.string : memcpy;
3263 
3264             // rc starts as 1 to avoid comparing with size_t(0) - 1
3265             if (atomicOp!"-="(rc, 1) == 0)
3266             {
3267                 static if (indirect)
3268                 {
3269                     Allocator* tmp = pimpl;
3270                 }
3271                 else
3272                 {
3273                     Allocator tmp;
3274                     memcpy(cast(void*) &tmp, cast(void*) &this.impl, Allocator.sizeof);
3275                     Allocator empty;
3276                     memcpy(cast(void*) &this.impl, cast(void*) &empty, Allocator.sizeof);
3277                 }
3278                 void[] support = (cast(void*) this)[0 .. stateSize!(typeof(this))];
3279                 (cast(bool delegate(void[]) @nogc nothrow pure)(&tmp.deallocate))(support);
3280                 return false;
3281             }
3282             return true;
3283         }
3284         else
3285         {
3286             return true;
3287         }
3288     }
3289 }
3290 
3291 
3292 // Example in intro above
3293 @system unittest
3294 {
3295     // Allocate an int, initialize it with 42
3296     int* p = theAllocator.make!int(42);
3297     assert(*p == 42);
3298 
3299     // Destroy and deallocate it
3300     theAllocator.dispose(p);
3301 
3302     // Allocate using the global process allocator
3303     p = processAllocator.make!int(100);
3304     assert(*p == 100);
3305 
3306     // Destroy and deallocate
3307     processAllocator.dispose(p);
3308 
3309     // Create an array of 50 doubles initialized to -1.0
3310     double[] arr = theAllocator.makeArray!double(50, -1.0);
3311 
3312     // Check internal pointer
3313     void[] result;
3314     assert(theAllocator.resolveInternalPointer(null, result) == Ternary.no);
3315     Ternary r = theAllocator.resolveInternalPointer(arr.ptr, result);
3316     assert(result.ptr is arr.ptr && result.length >= arr.length);
3317 
3318     // Append two zeros to it
3319     theAllocator.expandArray(arr, 2, 0.0);
3320     // On second thought, take that back
3321     theAllocator.shrinkArray(arr, 2);
3322     // Destroy and deallocate
3323     theAllocator.dispose(arr);
3324 }
3325 
3326 /**
3327 
3328 Stores an allocator object in thread-local storage (i.e. non-`shared` D
3329 global). `ThreadLocal!A` is a subtype of `A` so it appears to implement
3330 `A`'s allocator primitives.
3331 
3332 `A` must hold state, otherwise `ThreadLocal!A` refuses instantiation. This
3333 means e.g. `ThreadLocal!Mallocator` does not work because `Mallocator`'s
3334 state is not stored as members of `Mallocator`, but instead is hidden in the
3335 C library implementation.
3336 
3337 */
ThreadLocal(A)3338 struct ThreadLocal(A)
3339 {
3340     static assert(stateSize!A,
3341         typeof(A).stringof
3342         ~ " does not have state so it cannot be used with ThreadLocal");
3343 
3344     /**
3345     The allocator instance.
3346     */
3347     static A instance;
3348 
3349     /**
3350     `ThreadLocal!A` is a subtype of `A` so it appears to implement `A`'s
3351     allocator primitives.
3352     */
3353     alias instance this;
3354 
3355     /**
3356     `ThreadLocal` disables all constructors. The intended usage is
3357     `ThreadLocal!A.instance`.
3358     */
3359     @disable this();
3360     /// Ditto
3361     @disable this(this);
3362 }
3363 
3364 ///
3365 @system
3366 unittest
3367 {
3368     import std.experimental.allocator.building_blocks.free_list : FreeList;
3369     import std.experimental.allocator.gc_allocator : GCAllocator;
3370     import std.experimental.allocator.mallocator : Mallocator;
3371 
3372     static assert(!is(ThreadLocal!Mallocator));
3373     static assert(!is(ThreadLocal!GCAllocator));
3374     alias Allocator = ThreadLocal!(FreeList!(GCAllocator, 0, 8));
3375     auto b = Allocator.instance.allocate(5);
3376     static assert(__traits(hasMember, Allocator, "allocate"));
3377 }
3378 
3379 /*
3380 (Not public.)
3381 
3382 A binary search tree that uses no allocation of its own. Instead, it relies on
3383 user code to allocate nodes externally. Then `EmbeddedTree`'s primitives wire
3384 the nodes appropriately.
3385 
3386 Warning: currently `EmbeddedTree` is not using rebalancing, so it may
3387 degenerate. A red-black tree implementation storing the color with one of the
3388 pointers is planned for the future.
3389 */
EmbeddedTree(T,alias less)3390 private struct EmbeddedTree(T, alias less)
3391 {
3392     static struct Node
3393     {
3394         T payload;
3395         Node* left, right;
3396     }
3397 
3398     private Node* root;
3399 
3400     private Node* insert(Node* n, ref Node* backref)
3401     {
3402         backref = n;
3403         n.left = n.right = null;
3404         return n;
3405     }
3406 
3407     Node* find(Node* data)
3408     {
3409         for (auto n = root; n; )
3410         {
3411             if (less(data, n))
3412             {
3413                 n = n.left;
3414             }
3415             else if (less(n, data))
3416             {
3417                 n = n.right;
3418             }
3419             else
3420             {
3421                 return n;
3422             }
3423         }
3424         return null;
3425     }
3426 
3427     Node* insert(Node* data)
3428     {
3429         if (!root)
3430         {
3431             root = data;
3432             data.left = data.right = null;
3433             return root;
3434         }
3435         auto n = root;
3436         for (;;)
3437         {
3438             if (less(data, n))
3439             {
3440                 if (!n.left)
3441                 {
3442                     // Found insertion point
3443                     return insert(data, n.left);
3444                 }
3445                 n = n.left;
3446             }
3447             else if (less(n, data))
3448             {
3449                 if (!n.right)
3450                 {
3451                     // Found insertion point
3452                     return insert(data, n.right);
3453                 }
3454                 n = n.right;
3455             }
3456             else
3457             {
3458                 // Found
3459                 return n;
3460             }
3461             if (!n) return null;
3462         }
3463     }
3464 
3465     Node* remove(Node* data)
3466     {
3467         auto n = root;
3468         Node* parent = null;
3469         for (;;)
3470         {
3471             if (!n) return null;
3472             if (less(data, n))
3473             {
3474                 parent = n;
3475                 n = n.left;
3476             }
3477             else if (less(n, data))
3478             {
3479                 parent = n;
3480                 n = n.right;
3481             }
3482             else
3483             {
3484                 // Found
3485                 remove(n, parent);
3486                 return n;
3487             }
3488         }
3489     }
3490 
3491     private void remove(Node* n, Node* parent)
3492     {
3493         assert(n);
3494         assert(!parent || parent.left == n || parent.right == n);
3495         Node** referrer = parent
3496             ? (parent.left == n ? &parent.left : &parent.right)
3497             : &root;
3498         if (!n.left)
3499         {
3500             *referrer = n.right;
3501         }
3502         else if (!n.right)
3503         {
3504             *referrer = n.left;
3505         }
3506         else
3507         {
3508             // Find the leftmost child in the right subtree
3509             auto leftmost = n.right;
3510             Node** leftmostReferrer = &n.right;
3511             while (leftmost.left)
3512             {
3513                 leftmostReferrer = &leftmost.left;
3514                 leftmost = leftmost.left;
3515             }
3516             // Unlink leftmost from there
3517             *leftmostReferrer = leftmost.right;
3518             // Link leftmost in lieu of n
3519             leftmost.left = n.left;
3520             leftmost.right = n.right;
3521             *referrer = leftmost;
3522         }
3523     }
3524 
3525     Ternary empty() const
3526     {
3527         return Ternary(!root);
3528     }
3529 
3530     void dump()
3531     {
3532         import std.stdio : writeln;
3533         writeln(typeid(this), " @ ", cast(void*) &this);
3534         dump(root, 3);
3535     }
3536 
3537     void dump(Node* r, uint indent)
3538     {
3539         import std.stdio : write, writeln;
3540         import std.range : repeat;
3541         import std.array : array;
3542 
3543         write(repeat(' ', indent).array);
3544         if (!r)
3545         {
3546             writeln("(null)");
3547             return;
3548         }
3549         writeln(r.payload, " @ ", cast(void*) r);
3550         dump(r.left, indent + 3);
3551         dump(r.right, indent + 3);
3552     }
3553 
3554     void assertSane()
3555     {
3556         static bool isBST(Node* r, Node* lb, Node* ub)
3557         {
3558             if (!r) return true;
3559             if (lb && !less(lb, r)) return false;
3560             if (ub && !less(r, ub)) return false;
3561             return isBST(r.left, lb, r) &&
3562                 isBST(r.right, r, ub);
3563         }
3564         if (isBST(root, null, null)) return;
3565         dump;
3566         assert(0);
3567     }
3568 }
3569 
3570 @system
3571 unittest
3572 {
3573     import std.experimental.allocator.gc_allocator : GCAllocator;
3574 
3575     alias a = GCAllocator.instance;
3576     alias Tree = EmbeddedTree!(int, (a, b) => a.payload < b.payload);
3577     Tree t;
3578     assert(t.empty == Ternary.yes);
3579     int[] vals = [ 6, 3, 9, 1, 0, 2, 8, 11 ];
foreach(v;vals)3580     foreach (v; vals)
3581     {
3582         auto n = new Tree.Node(v, null, null);
3583         assert(t.insert(n));
3584         assert(n);
3585         t.assertSane;
3586     }
3587     assert(t.empty != Ternary.yes);
foreach(v;vals)3588     foreach (v; vals)
3589     {
3590         Tree.Node n = { v };
3591         assert(t.remove(&n));
3592         t.assertSane;
3593     }
3594     assert(t.empty == Ternary.yes);
3595 }
3596 
3597 /*
3598 
3599 `InternalPointersTree` adds a primitive on top of another allocator: calling
3600 `resolveInternalPointer(p)` returns the block within which the internal
3601 pointer `p` lies. Pointers right after the end of allocated blocks are also
3602 considered internal.
3603 
3604 The implementation stores three additional words with each allocation (one for
3605 the block size and two for search management).
3606 
3607 */
InternalPointersTree(Allocator)3608 private struct InternalPointersTree(Allocator)
3609 {
3610     import std.experimental.allocator.building_blocks.affix_allocator : AffixAllocator;
3611 
3612     alias Tree = EmbeddedTree!(size_t,
3613         (a, b) => cast(void*) a + a.payload < cast(void*) b);
3614     alias Parent = AffixAllocator!(Allocator, Tree.Node);
3615 
3616     // Own state
3617     private Tree blockMap;
3618 
3619     alias alignment = Parent.alignment;
3620 
3621     /**
3622     The implementation is available as a public member.
3623     */
3624     static if (stateSize!Parent) Parent parent;
3625     else alias parent = Parent.instance;
3626 
3627     /// Allocator API.
3628     void[] allocate(size_t bytes)
3629     {
3630         auto r = parent.allocate(bytes);
3631         if (!r.ptr) return r;
3632         Tree.Node* n = &parent.prefix(r);
3633         n.payload = bytes;
3634         blockMap.insert(n) || assert(0);
3635         return r;
3636     }
3637 
3638     /// Ditto
3639     bool deallocate(void[] b)
3640     {
3641         if (!b.ptr) return true;
3642         Tree.Node* n = &parent.prefix(b);
3643         blockMap.remove(n) || assert(false);
3644         parent.deallocate(b);
3645         return true;
3646     }
3647 
3648     /// Ditto
3649     static if (hasMember!(Allocator, "reallocate"))
3650     bool reallocate(ref void[] b, size_t s)
3651     {
3652         auto n = &parent.prefix(b);
3653         assert(n.payload == b.length);
3654         blockMap.remove(n) || assert(0);
3655         if (!parent.reallocate(b, s))
3656         {
3657             // Failed, must reinsert the same node in the tree
3658             assert(n.payload == b.length);
3659             blockMap.insert(n) || assert(0);
3660             return false;
3661         }
3662         // Insert the new node
3663         n = &parent.prefix(b);
3664         n.payload = s;
3665         blockMap.insert(n) || assert(0);
3666         return true;
3667     }
3668 
3669     /// Ditto
3670     Ternary owns(void[] b)
3671     {
3672         void[] result;
3673         return resolveInternalPointer(b.ptr, result);
3674     }
3675 
3676     /// Ditto
3677     Ternary empty()
3678     {
3679         return Ternary(blockMap.empty);
3680     }
3681 
3682     /** Returns the block inside which `p` resides, or `null` if the
3683     pointer does not belong.
3684     */
3685     pure nothrow @safe @nogc
3686     Ternary resolveInternalPointer(const void* p, ref void[] result)
3687     {
3688         // Must define a custom find
3689         Tree.Node* find()
3690         {
3691             for (auto n = blockMap.root; n; )
3692             {
3693                 if (p < n)
3694                 {
3695                     n = n.left;
3696                 }
3697                 else if ((() @trusted => p > (cast(void*) (n + 1)) + n.payload)())
3698                 {
3699                     n = n.right;
3700                 }
3701                 else
3702                 {
3703                     return n;
3704                 }
3705             }
3706             return null;
3707         }
3708 
3709         auto n = find();
3710         if (!n) return Ternary.no;
3711         result = (() @trusted => (cast(void*) (n + 1))[0 .. n.payload])();
3712         return Ternary.yes;
3713     }
3714 }
3715 
3716 @system
3717 unittest
3718 {
3719     import std.experimental.allocator.mallocator : Mallocator;
3720     import std.random : randomCover;
3721 
3722     InternalPointersTree!(Mallocator) a;
3723     int[] vals = [ 6, 3, 9, 1, 2, 8, 11 ];
3724     void[][] allox;
foreach(v;vals)3725     foreach (v; vals)
3726     {
3727         allox ~= a.allocate(v);
3728     }
3729     a.blockMap.assertSane;
3730 
foreach(b;allox)3731     foreach (b; allox)
3732     {
3733         () pure nothrow @safe {
3734             void[] p;
3735             Ternary r = (() @nogc => a.resolveInternalPointer(&b[0], p))();
3736             assert(&p[0] == &b[0] && p.length >= b.length);
3737             r = a.resolveInternalPointer((() @trusted => &b[0] + b.length)(), p);
3738 
3739             /* This line randomly fails on MacOS 12.x x64
3740              * https://issues.dlang.org/show_bug.cgi?id=22660
3741              * Commenting it out until someone can fix it.
3742              */
3743             //assert(&p[0] == &b[0] && p.length >= b.length);
3744 
3745             r = a.resolveInternalPointer((() @trusted => &b[0] + b.length / 2)(), p);
3746             assert(&p[0] == &b[0] && p.length >= b.length);
3747             auto bogus = new void[b.length];
3748             assert(a.resolveInternalPointer(&bogus[0], p) == Ternary.no);
3749         }();
3750     }
3751 
3752     foreach (b; allox.randomCover)
3753     {
3754         () nothrow @nogc { a.deallocate(b); }();
3755     }
3756 
3757     assert(a.empty == Ternary.yes);
3758 }
3759 
3760 //version (std_allocator_benchmark)
3761 @system
3762 unittest
3763 {
3764     import std.experimental.allocator.building_blocks.null_allocator : NullAllocator;
3765     import std.experimental.allocator.building_blocks.allocator_list : AllocatorList;
3766     import std.experimental.allocator.building_blocks.bitmapped_block : BitmappedBlock;
3767     import std.experimental.allocator.building_blocks.segregator : Segregator;
3768     import std.experimental.allocator.building_blocks.bucketizer : Bucketizer;
3769     import std.experimental.allocator.building_blocks.free_list : FreeList;
3770     import std.experimental.allocator.gc_allocator : GCAllocator;
3771     import std.experimental.allocator.mallocator : Mallocator;
3772 
testSpeed(A)3773     static void testSpeed(A)()
3774     {
3775         static if (stateSize!A) A a;
3776         else alias a = A.instance;
3777 
3778         void[][128] bufs;
3779 
3780         import std.random;
3781         foreach (i; 0 .. 100_000)
3782         {
3783             auto j = uniform(0, bufs.length);
3784             switch (uniform(0, 2))
3785             {
3786             case 0:
3787                 () nothrow @nogc { a.deallocate(bufs[j]); }();
3788                 bufs[j] = a.allocate(uniform(0, 4096));
3789                 break;
3790             case 1:
3791                 () nothrow @nogc { a.deallocate(bufs[j]); }();
3792                 bufs[j] = null;
3793                 break;
3794             default:
3795                 assert(0);
3796             }
3797         }
3798     }
3799 
3800     import std.algorithm.comparison : max;
3801 
3802     alias FList = FreeList!(GCAllocator, 0, unbounded);
3803     alias A = Segregator!(
3804         8, FreeList!(GCAllocator, 0, 8),
3805         128, Bucketizer!(FList, 1, 128, 16),
3806         256, Bucketizer!(FList, 129, 256, 32),
3807         512, Bucketizer!(FList, 257, 512, 64),
3808         1024, Bucketizer!(FList, 513, 1024, 128),
3809         2048, Bucketizer!(FList, 1025, 2048, 256),
3810         3584, Bucketizer!(FList, 2049, 3584, 512),
3811         4072 * 1024, AllocatorList!(
3812             (size_t n) => BitmappedBlock!(4096)(cast(ubyte[]) GCAllocator.instance.allocate(
3813                 max(n, 4072 * 1024)))),
3814         GCAllocator
3815     );
3816 
3817     import std.stdio;
3818     import std.conv : to;
3819     import std.datetime.stopwatch;
3820     import std.algorithm.iteration : map;
3821 
3822     if (false) writeln(benchmark!(
3823         testSpeed!NullAllocator,
3824         testSpeed!Mallocator,
3825         testSpeed!GCAllocator,
3826         testSpeed!(ThreadLocal!A),
3827         testSpeed!(A),
3828     )(20)[].map!(t => t.to!Duration));
3829 }
3830 
3831 @system
3832 unittest
3833 {
3834     import std.experimental.allocator.building_blocks.free_list : FreeList;
3835     import std.experimental.allocator.building_blocks.region : InSituRegion;
3836     import std.experimental.allocator.building_blocks.fallback_allocator : FallbackAllocator;
3837     import std.experimental.allocator.gc_allocator : GCAllocator;
3838     import std.experimental.allocator.mallocator : Mallocator;
3839 
3840     auto a = allocatorObject(Mallocator.instance);
3841     auto b = a.allocate(100);
3842     assert(b.length == 100);
3843 
3844     FreeList!(GCAllocator, 0, 8) fl;
3845     auto sa = allocatorObject(fl);
3846     b = a.allocate(101);
3847     assert(b.length == 101);
3848 
3849     FallbackAllocator!(InSituRegion!(10240, 64), GCAllocator) fb;
3850     // Doesn't work yet...
3851     //a = allocatorObject(fb);
3852     //b = a.allocate(102);
3853     //assert(b.length == 102);
3854 }
3855 
3856 ///
3857 @system
3858 unittest
3859 {
3860     import std.experimental.allocator.building_blocks.allocator_list : AllocatorList;
3861     import std.experimental.allocator.building_blocks.bitmapped_block : BitmappedBlock;
3862     import std.experimental.allocator.building_blocks.segregator : Segregator;
3863     import std.experimental.allocator.building_blocks.bucketizer : Bucketizer;
3864     import std.experimental.allocator.building_blocks.free_list : FreeList;
3865     import std.experimental.allocator.gc_allocator : GCAllocator;
3866 
3867     /// Define an allocator bound to the built-in GC.
3868     auto alloc = allocatorObject(GCAllocator.instance);
3869     auto b = alloc.allocate(42);
3870     assert(b.length == 42);
3871     assert(alloc.deallocate(b));
3872 
3873     import std.algorithm.comparison : max;
3874     // Define an elaborate allocator and bind it to the class API.
3875     alias FList = FreeList!(GCAllocator, 0, unbounded);
3876     alias A = ThreadLocal!(
3877         Segregator!(
3878             8, FreeList!(GCAllocator, 0, 8),
3879             128, Bucketizer!(FList, 1, 128, 16),
3880             256, Bucketizer!(FList, 129, 256, 32),
3881             512, Bucketizer!(FList, 257, 512, 64),
3882             1024, Bucketizer!(FList, 513, 1024, 128),
3883             2048, Bucketizer!(FList, 1025, 2048, 256),
3884             3584, Bucketizer!(FList, 2049, 3584, 512),
3885             4072 * 1024, AllocatorList!(
3886                 (n) => BitmappedBlock!(4096)(cast(ubyte[]) GCAllocator.instance.allocate(
3887                     max(n, 4072 * 1024)))),
3888             GCAllocator
3889         )
3890     );
3891 
3892     auto alloc2 = allocatorObject(A.instance);
3893     b = alloc2.allocate(101);
3894     assert(alloc2.deallocate(b));
3895 }
3896