1 /*
2  * Hunt - A refined core library for D programming language.
3  *
4  * Copyright (C) 2018-2019 HuntLabs
5  *
6  * Website: https://www.huntlabs.net/
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11 
12 module hunt.collection.Array;
13 
14 import core.exception : RangeError;
15 import std.range.primitives;
16 import std.traits;
17 
18 public import std.container.util;
19 
20 ///
21 pure @system unittest
22 {
23     auto arr = Array!int(0, 2, 3);
24     assert(arr[0] == 0);
25     assert(arr.front == 0);
26     assert(arr.back == 3);
27 
28     // reserve space
29     arr.reserve(1000);
30     assert(arr.length == 3);
31     assert(arr.capacity >= 1000);
32 
33     // insertion
34     arr.insertBefore(arr[1..$], 1);
35     assert(arr.front == 0);
36     assert(arr.length == 4);
37 
38     arr.insertBack(4);
39     assert(arr.back == 4);
40     assert(arr.length == 5);
41 
42     // set elements
43     arr[1] *= 42;
44     assert(arr[1] == 42);
45 }
46 
47 ///
48 pure @system unittest
49 {
50     import std.algorithm.comparison : equal;
51     auto arr = Array!int(1, 2, 3);
52 
53     // concat
54     auto b = Array!int(11, 12, 13);
55     arr ~= b;
56     assert(arr.length == 6);
57 
58     // slicing
59     assert(arr[1 .. 3].equal([2, 3]));
60 
61     // remove
62     arr.linearRemove(arr[1 .. 3]);
63     assert(arr[0 .. 2].equal([1, 11]));
64 }
65 
66 /// `Array!bool` packs together values efficiently by allocating one bit per element
67 pure @system unittest
68 {
69     Array!bool arr;
70     arr.insert([true, true, false, true, false]);
71     assert(arr.length == 5);
72 }
73 
74 private struct RangeT(A)
75 {
76     /* Workaround for https://issues.dlang.org/show_bug.cgi?id=13629
77        See also: http://forum.dlang.org/post/vbmwhzvawhnkoxrhbnyb@forum.dlang.org
78     */
79     private A[1] _outer_;
80     private @property ref inout(A) _outer() inout { return _outer_[0]; }
81 
82     private size_t _a, _b;
83 
84     /* E is different from T when A is more restrictively qualified than T:
85        immutable(Array!int) => T == int, E = immutable(int) */
86     alias E = typeof(_outer_[0]._data._payload[0]);
87 
88     private this(ref A data, size_t a, size_t b)
89     {
90         _outer_ = data;
91         _a = a;
92         _b = b;
93     }
94 
95     @property RangeT save()
96     {
97         return this;
98     }
99 
100     @property bool empty() @safe pure nothrow const
101     {
102         return _a >= _b;
103     }
104 
105     @property size_t length() @safe pure nothrow const
106     {
107         return _b - _a;
108     }
109     alias opDollar = length;
110 
111     @property ref inout(E) front() inout
112     {
113         assert(!empty, "Attempting to access the front of an empty Array");
114         return _outer[_a];
115     }
116     @property ref inout(E) back() inout
117     {
118         assert(!empty, "Attempting to access the back of an empty Array");
119         return _outer[_b - 1];
120     }
121 
122     void popFront() @safe @nogc pure nothrow
123     {
124         assert(!empty, "Attempting to popFront an empty Array");
125         ++_a;
126     }
127 
128     void popBack() @safe @nogc pure nothrow
129     {
130         assert(!empty, "Attempting to popBack an empty Array");
131         --_b;
132     }
133 
134     static if (isMutable!A)
135     {
136         import std.algorithm.mutation : move;
137 
138         E moveFront()
139         {
140             assert(!empty, "Attempting to moveFront an empty Array");
141             assert(_a < _outer.length,
142                 "Attempting to moveFront using an out of bounds low index on an Array");
143             return move(_outer._data._payload[_a]);
144         }
145 
146         E moveBack()
147         {
148             assert(!empty, "Attempting to moveBack an empty Array");
149             assert(_a <= _outer.length,
150                 "Attempting to moveBack using an out of bounds high index on an Array");
151             return move(_outer._data._payload[_b - 1]);
152         }
153 
154         E moveAt(size_t i)
155         {
156             assert(_a + i < _b,
157                 "Attempting to moveAt using an out of bounds index on an Array");
158             assert(_a + i < _outer.length,
159                 "Cannot move past the end of the array");
160             return move(_outer._data._payload[_a + i]);
161         }
162     }
163 
164     ref inout(E) opIndex(size_t i) inout
165     {
166         assert(_a + i < _b,
167             "Attempting to fetch using an out of bounds index on an Array");
168         return _outer[_a + i];
169     }
170 
171     RangeT opSlice()
172     {
173         return typeof(return)(_outer, _a, _b);
174     }
175 
176     RangeT opSlice(size_t i, size_t j)
177     {
178         assert(i <= j && _a + j <= _b,
179             "Attempting to slice using an out of bounds indices on an Array");
180         return typeof(return)(_outer, _a + i, _a + j);
181     }
182 
183     RangeT!(const(A)) opSlice() const
184     {
185         return typeof(return)(_outer, _a, _b);
186     }
187 
188     RangeT!(const(A)) opSlice(size_t i, size_t j) const
189     {
190         assert(i <= j && _a + j <= _b,
191             "Attempting to slice using an out of bounds indices on an Array");
192         return typeof(return)(_outer, _a + i, _a + j);
193     }
194 
195     static if (isMutable!A)
196     {
197         void opSliceAssign(E value)
198         {
199             assert(_b <= _outer.length,
200                 "Attempting to assign using an out of bounds indices on an Array");
201             _outer[_a .. _b] = value;
202         }
203 
204         void opSliceAssign(E value, size_t i, size_t j)
205         {
206             assert(_a + j <= _b,
207                 "Attempting to slice assign using an out of bounds indices on an Array");
208             _outer[_a + i .. _a + j] = value;
209         }
210 
211         void opSliceUnary(string op)()
212         if (op == "++" || op == "--")
213         {
214             assert(_b <= _outer.length,
215                 "Attempting to slice using an out of bounds indices on an Array");
216             mixin(op~"_outer[_a .. _b];");
217         }
218 
219         void opSliceUnary(string op)(size_t i, size_t j)
220         if (op == "++" || op == "--")
221         {
222             assert(_a + j <= _b,
223                 "Attempting to slice using an out of bounds indices on an Array");
224             mixin(op~"_outer[_a + i .. _a + j];");
225         }
226 
227         void opSliceOpAssign(string op)(E value)
228         {
229             assert(_b <= _outer.length,
230                 "Attempting to slice using an out of bounds indices on an Array");
231             mixin("_outer[_a .. _b] "~op~"= value;");
232         }
233 
234         void opSliceOpAssign(string op)(E value, size_t i, size_t j)
235         {
236             assert(_a + j <= _b,
237                 "Attempting to slice using an out of bounds indices on an Array");
238             mixin("_outer[_a + i .. _a + j] "~op~"= value;");
239         }
240     }
241 }
242 
243 /**
244  * _Array type with deterministic control of memory. The memory allocated
245  * for the array is reclaimed as soon as possible; there is no reliance
246  * on the garbage collector. `Array` uses `malloc`, `realloc` and `free`
247  * for managing its own memory.
248  *
249  * This means that pointers to elements of an `Array` will become
250  * dangling as soon as the element is removed from the `Array`. On the other hand
251  * the memory allocated by an `Array` will be scanned by the GC and
252  * GC managed objects referenced from an `Array` will be kept alive.
253  *
254  * Note:
255  *
256  * When using `Array` with range-based functions like those in `std.algorithm`,
257  * `Array` must be sliced to get a range (for example, use `array[].map!`
258  * instead of `array.map!`). The container itself is not a range.
259  */
260 struct Array(T)
261 if (!is(immutable T == immutable bool))
262 {
263     import core.memory : free = pureFree;
264     // import std.internal.memory : enforceMalloc, enforceRealloc;
265     import core.stdc.string : memcpy, memmove, memset;
266 
267     import core.memory : GC;
268 
269     import std.exception : enforce;
270     import std.typecons : RefCounted, RefCountedAutoInitialize;
271 
272     // This structure is not copyable.
273     private struct Payload
274     {
275         size_t _capacity;
276         T[] _payload;
277 
278         this(T[] p) { _capacity = p.length; _payload = p; }
279 
280         // Destructor releases array memory
281         ~this()
282         {
283             // Warning: destroy would destroy also class instances.
284             // The hasElaborateDestructor protects us here.
285             static if (hasElaborateDestructor!T)
286                 foreach (ref e; _payload)
287                     .destroy(e);
288 
289             static if (hasIndirections!T)
290                 GC.removeRange(_payload.ptr);
291 
292             free(_payload.ptr);
293         }
294 
295         this(this) @disable;
296 
297         void opAssign(Payload rhs) @disable;
298 
299         @property size_t length() const
300         {
301             return _payload.length;
302         }
303 
304         @property void length(size_t newLength)
305         {
306             import std.algorithm.mutation : initializeAll;
307 
308             if (length >= newLength)
309             {
310                 // shorten
311                 static if (hasElaborateDestructor!T)
312                     foreach (ref e; _payload.ptr[newLength .. _payload.length])
313                         .destroy(e);
314 
315                 _payload = _payload.ptr[0 .. newLength];
316                 return;
317             }
318             immutable startEmplace = length;
319             if (_capacity < newLength)
320             {
321                 // enlarge
322                 static if (T.sizeof == 1)
323                 {
324                     const nbytes = newLength;
325                 }
326                 else
327                 {
328                     import core.checkedint : mulu;
329 
330                     bool overflow;
331                     const nbytes = mulu(newLength, T.sizeof, overflow);
332                     if (overflow)
333                         assert(false, "Overflow");
334                 }
335 
336                 static if (hasIndirections!T)
337                 {
338                     auto newPayloadPtr = cast(T*) enforceMalloc(nbytes);
339                     auto newPayload = newPayloadPtr[0 .. newLength];
340                     memcpy(newPayload.ptr, _payload.ptr, startEmplace * T.sizeof);
341                     memset(newPayload.ptr + startEmplace, 0,
342                             (newLength - startEmplace) * T.sizeof);
343                     GC.addRange(newPayload.ptr, nbytes);
344                     GC.removeRange(_payload.ptr);
345                     free(_payload.ptr);
346                     _payload = newPayload;
347                 }
348                 else
349                 {
350                     _payload = (cast(T*) enforceRealloc(_payload.ptr,
351                             nbytes))[0 .. newLength];
352                 }
353                 _capacity = newLength;
354             }
355             else
356             {
357                 _payload = _payload.ptr[0 .. newLength];
358             }
359             initializeAll(_payload.ptr[startEmplace .. newLength]);
360         }
361 
362         @property size_t capacity() const
363         {
364             return _capacity;
365         }
366 
367         void reserve(size_t elements)
368         {
369             if (elements <= capacity) return;
370             static if (T.sizeof == 1)
371             {
372                 const sz = elements;
373             }
374             else
375             {
376                 import core.checkedint : mulu;
377                 bool overflow;
378                 const sz = mulu(elements, T.sizeof, overflow);
379                 if (overflow)
380                     assert(false, "Overflow");
381             }
382             static if (hasIndirections!T)
383             {
384                 /* Because of the transactional nature of this
385                  * relative to the garbage collector, ensure no
386                  * threading bugs by using malloc/copy/free rather
387                  * than realloc.
388                  */
389                 immutable oldLength = length;
390 
391                 auto newPayloadPtr = cast(T*) enforceMalloc(sz);
392                 auto newPayload = newPayloadPtr[0 .. oldLength];
393 
394                 // copy old data over to new array
395                 memcpy(newPayload.ptr, _payload.ptr, T.sizeof * oldLength);
396                 // Zero out unused capacity to prevent gc from seeing false pointers
397                 memset(newPayload.ptr + oldLength,
398                         0,
399                         (elements - oldLength) * T.sizeof);
400                 GC.addRange(newPayload.ptr, sz);
401                 GC.removeRange(_payload.ptr);
402                 free(_payload.ptr);
403                 _payload = newPayload;
404             }
405             else
406             {
407                 // These can't have pointers, so no need to zero unused region
408                 auto newPayloadPtr = cast(T*) enforceRealloc(_payload.ptr, sz);
409                 auto newPayload = newPayloadPtr[0 .. length];
410                 _payload = newPayload;
411             }
412             _capacity = elements;
413         }
414 
415         // Insert one item
416         size_t insertBack(Elem)(Elem elem)
417         if (isImplicitlyConvertible!(Elem, T))
418         {
419             import std.conv : emplace;
420             if (_capacity == length)
421             {
422                 reserve(1 + capacity * 3 / 2);
423             }
424             assert(capacity > length && _payload.ptr,
425                 "Failed to reserve memory");
426             emplace(_payload.ptr + _payload.length, elem);
427             _payload = _payload.ptr[0 .. _payload.length + 1];
428             return 1;
429         }
430 
431         // Insert a range of items
432         size_t insertBack(Range)(Range r)
433         if (isInputRange!Range && isImplicitlyConvertible!(ElementType!Range, T))
434         {
435             static if (hasLength!Range)
436             {
437                 immutable oldLength = length;
438                 reserve(oldLength + r.length);
439             }
440             size_t result;
441             foreach (item; r)
442             {
443                 insertBack(item);
444                 ++result;
445             }
446             static if (hasLength!Range)
447             {
448                 assert(length == oldLength + r.length,
449                     "Failed to insertBack range");
450             }
451             return result;
452         }
453     }
454     private alias Data = RefCounted!(Payload, RefCountedAutoInitialize.no);
455     private Data _data;
456 
457     /**
458      * Constructor taking a number of items.
459      */
460     this(U)(U[] values...)
461     if (isImplicitlyConvertible!(U, T))
462     {
463         import std.conv : emplace;
464 
465         static if (T.sizeof == 1)
466         {
467             const nbytes = values.length;
468         }
469         else
470         {
471             import core.checkedint : mulu;
472             bool overflow;
473             const nbytes = mulu(values.length, T.sizeof, overflow);
474             if (overflow)
475                 assert(false, "Overflow");
476         }
477         auto p = cast(T*) enforceMalloc(nbytes);
478         static if (hasIndirections!T)
479         {
480             if (p)
481                 GC.addRange(p, T.sizeof * values.length);
482         }
483 
484         foreach (i, e; values)
485         {
486             emplace(p + i, e);
487         }
488         _data = Data(p[0 .. values.length]);
489     }
490 
491     /**
492      * Constructor taking an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
493      */
494     this(Range)(Range r)
495     if (isInputRange!Range && isImplicitlyConvertible!(ElementType!Range, T) && !is(Range == T[]))
496     {
497         insertBack(r);
498     }
499 
500     /**
501      * Comparison for equality.
502      */
503     bool opEquals(Array rhs)
504     {
505         return opEquals(rhs);
506     }
507 
508     /// ditto
509     bool opEquals(ref Array rhs)
510     {
511         if (empty) return rhs.empty;
512         if (rhs.empty) return false;
513         return _data._payload == rhs._data._payload;
514     }
515 
516     /**
517      *  Defines the array's primary range, which is a random-access range.
518      *
519      *  `ConstRange` is a variant with `const` elements.
520      *  `ImmutableRange` is a variant with `immutable` elements.
521      */
522     alias Range = RangeT!Array;
523 
524     /// ditto
525     alias ConstRange = RangeT!(const Array);
526 
527     /// ditto
528     alias ImmutableRange = RangeT!(immutable Array);
529 
530     /**
531      * Duplicates the array. The elements themselves are not transitively
532      * duplicated.
533      *
534      * Complexity: $(BIGOH length).
535      */
536     @property Array dup()
537     {
538         if (!_data.refCountedStore.isInitialized) return this;
539         return Array(_data._payload);
540     }
541 
542     /**
543      * Returns: `true` if and only if the array has no elements.
544      *
545      * Complexity: $(BIGOH 1)
546      */
547     @property bool empty() const
548     {
549         return !_data.refCountedStore.isInitialized || _data._payload.empty;
550     }
551 
552     /**
553      * Returns: The number of elements in the array.
554      *
555      * Complexity: $(BIGOH 1).
556      */
557     @property size_t length() const
558     {
559         return _data.refCountedStore.isInitialized ? _data._payload.length : 0;
560     }
561 
562     /// ditto
563     size_t opDollar() const
564     {
565         return length;
566     }
567 
568     /**
569      * Returns: The maximum number of elements the array can store without
570      * reallocating memory and invalidating iterators upon insertion.
571      *
572      * Complexity: $(BIGOH 1)
573      */
574     @property size_t capacity()
575     {
576         return _data.refCountedStore.isInitialized ? _data._capacity : 0;
577     }
578 
579     /**
580      * Ensures sufficient capacity to accommodate `e` _elements.
581      * If `e < capacity`, this method does nothing.
582      *
583      * Postcondition: `capacity >= e`
584      *
585      * Note: If the capacity is increased, one should assume that all
586      * iterators to the elements are invalidated.
587      *
588      * Complexity: at most $(BIGOH length) if `e > capacity`, otherwise $(BIGOH 1).
589      */
590     void reserve(size_t elements)
591     {
592         if (!_data.refCountedStore.isInitialized)
593         {
594             if (!elements) return;
595             static if (T.sizeof == 1)
596             {
597                 const sz = elements;
598             }
599             else
600             {
601                 import core.checkedint : mulu;
602                 bool overflow;
603                 const sz = mulu(elements, T.sizeof, overflow);
604                 if (overflow)
605                     assert(false, "Overflow");
606             }
607             auto p = enforceMalloc(sz);
608             static if (hasIndirections!T)
609             {
610                 GC.addRange(p, sz);
611             }
612             _data = Data(cast(T[]) p[0 .. 0]);
613             _data._capacity = elements;
614         }
615         else
616         {
617             _data.reserve(elements);
618         }
619     }
620 
621     /**
622      * Returns: A range that iterates over elements of the array in
623      * forward order.
624      *
625      * Complexity: $(BIGOH 1)
626      */
627     Range opSlice()
628     {
629         return typeof(return)(this, 0, length);
630     }
631 
632     ConstRange opSlice() const
633     {
634         return typeof(return)(this, 0, length);
635     }
636 
637     ImmutableRange opSlice() immutable
638     {
639         return typeof(return)(this, 0, length);
640     }
641 
642     /**
643      * Returns: A range that iterates over elements of the array from
644      * index `i` up to (excluding) index `j`.
645      *
646      * Precondition: `i <= j && j <= length`
647      *
648      * Complexity: $(BIGOH 1)
649      */
650     Range opSlice(size_t i, size_t j)
651     {
652         assert(i <= j && j <= length, "Invalid slice bounds");
653         return typeof(return)(this, i, j);
654     }
655 
656     ConstRange opSlice(size_t i, size_t j) const
657     {
658         assert(i <= j && j <= length, "Invalid slice bounds");
659         return typeof(return)(this, i, j);
660     }
661 
662     ImmutableRange opSlice(size_t i, size_t j) immutable
663     {
664         assert(i <= j && j <= length, "Invalid slice bounds");
665         return typeof(return)(this, i, j);
666     }
667 
668     /**
669      * Returns: The first element of the array.
670      *
671      * Precondition: `empty == false`
672      *
673      * Complexity: $(BIGOH 1)
674      */
675     @property ref inout(T) front() inout
676     {
677         assert(_data.refCountedStore.isInitialized,
678             "Cannot get front of empty range");
679         return _data._payload[0];
680     }
681 
682     /**
683      * Returns: The last element of the array.
684      *
685      * Precondition: `empty == false`
686      *
687      * Complexity: $(BIGOH 1)
688      */
689     @property ref inout(T) back() inout
690     {
691         assert(_data.refCountedStore.isInitialized,
692             "Cannot get back of empty range");
693         return _data._payload[$ - 1];
694     }
695 
696     /**
697      * Returns: The element or a reference to the element at the specified index.
698      *
699      * Precondition: `i < length`
700      *
701      * Complexity: $(BIGOH 1)
702      */
703     ref inout(T) opIndex(size_t i) inout
704     {
705         assert(_data.refCountedStore.isInitialized,
706             "Cannot index empty range");
707         return _data._payload[i];
708     }
709 
710     /**
711      * Slicing operators executing the specified operation on the entire slice.
712      *
713      * Precondition: `i < j && j < length`
714      *
715      * Complexity: $(BIGOH slice.length)
716      */
717     void opSliceAssign(T value)
718     {
719         if (!_data.refCountedStore.isInitialized) return;
720         _data._payload[] = value;
721     }
722 
723     /// ditto
724     void opSliceAssign(T value, size_t i, size_t j)
725     {
726         auto slice = _data.refCountedStore.isInitialized ?
727             _data._payload :
728             T[].init;
729         slice[i .. j] = value;
730     }
731 
732     /// ditto
733     void opSliceUnary(string op)()
734     if (op == "++" || op == "--")
735     {
736         if (!_data.refCountedStore.isInitialized) return;
737         mixin(op~"_data._payload[];");
738     }
739 
740     /// ditto
741     void opSliceUnary(string op)(size_t i, size_t j)
742     if (op == "++" || op == "--")
743     {
744         auto slice = _data.refCountedStore.isInitialized ? _data._payload : T[].init;
745         mixin(op~"slice[i .. j];");
746     }
747 
748     /// ditto
749     void opSliceOpAssign(string op)(T value)
750     {
751         if (!_data.refCountedStore.isInitialized) return;
752         mixin("_data._payload[] "~op~"= value;");
753     }
754 
755     /// ditto
756     void opSliceOpAssign(string op)(T value, size_t i, size_t j)
757     {
758         auto slice = _data.refCountedStore.isInitialized ? _data._payload : T[].init;
759         mixin("slice[i .. j] "~op~"= value;");
760     }
761 
762     private enum hasSliceWithLength(T) = is(typeof({ T t = T.init; t[].length; }));
763 
764     /**
765      * Returns: A new array which is a concatenation of `this` and its argument.
766      *
767      * Complexity:
768      * $(BIGOH length + m), where `m` is the number of elements in `stuff`.
769      */
770     Array opBinary(string op, Stuff)(Stuff stuff)
771     if (op == "~")
772     {
773         Array result;
774 
775         static if (hasLength!Stuff || isNarrowString!Stuff)
776             result.reserve(length + stuff.length);
777         else static if (hasSliceWithLength!Stuff)
778             result.reserve(length + stuff[].length);
779         else static if (isImplicitlyConvertible!(Stuff, T))
780             result.reserve(length + 1);
781 
782         result.insertBack(this[]);
783         result ~= stuff;
784         return result;
785     }
786 
787     /**
788      * Forwards to `insertBack`.
789      */
790     void opOpAssign(string op, Stuff)(auto ref Stuff stuff)
791     if (op == "~")
792     {
793         static if (is(typeof(stuff[])) && isImplicitlyConvertible!(typeof(stuff[0]), T))
794         {
795             insertBack(stuff[]);
796         }
797         else
798         {
799             insertBack(stuff);
800         }
801     }
802 
803     /**
804      * Removes all the elements from the array and releases allocated memory.
805      *
806      * Postcondition: `empty == true && capacity == 0`
807      *
808      * Complexity: $(BIGOH length)
809      */
810     void clear()
811     {
812         _data = Data.init;
813     }
814 
815     /**
816      * Sets the number of elements in the array to `newLength`. If `newLength`
817      * is greater than `length`, the new elements are added to the end of the
818      * array and initialized with `T.init`.
819      *
820      * Complexity:
821      * Guaranteed $(BIGOH abs(length - newLength)) if `capacity >= newLength`.
822      * If `capacity < newLength` the worst case is $(BIGOH newLength).
823      *
824      * Postcondition: `length == newLength`
825      */
826     @property void length(size_t newLength)
827     {
828         _data.refCountedStore.ensureInitialized();
829         _data.length = newLength;
830     }
831 
832     /**
833      * Removes the last element from the array and returns it.
834      * Both stable and non-stable versions behave the same and guarantee
835      * that ranges iterating over the array are never invalidated.
836      *
837      * Precondition: `empty == false`
838      *
839      * Returns: The element removed.
840      *
841      * Complexity: $(BIGOH 1).
842      *
843      * Throws: `Exception` if the array is empty.
844      */
845     T removeAny()
846     {
847         auto result = back;
848         removeBack();
849         return result;
850     }
851 
852     /// ditto
853     alias stableRemoveAny = removeAny;
854 
855     /**
856      * Inserts the specified elements at the back of the array. `stuff` can be
857      * a value convertible to `T` or a range of objects convertible to `T`.
858      *
859      * Returns: The number of elements inserted.
860      *
861      * Complexity:
862      * $(BIGOH length + m) if reallocation takes place, otherwise $(BIGOH m),
863      * where `m` is the number of elements in `stuff`.
864      */
865     size_t insertBack(Stuff)(Stuff stuff)
866     if (isImplicitlyConvertible!(Stuff, T) ||
867             isInputRange!Stuff && isImplicitlyConvertible!(ElementType!Stuff, T))
868     {
869         _data.refCountedStore.ensureInitialized();
870         return _data.insertBack(stuff);
871     }
872 
873     /// ditto
874     alias insert = insertBack;
875 
876     /**
877      * Removes the value from the back of the array. Both stable and non-stable
878      * versions behave the same and guarantee that ranges iterating over the
879      * array are never invalidated.
880      *
881      * Precondition: `empty == false`
882      *
883      * Complexity: $(BIGOH 1).
884      *
885      * Throws: `Exception` if the array is empty.
886      */
887     void removeBack()
888     {
889         enforce(!empty);
890         static if (hasElaborateDestructor!T)
891             .destroy(_data._payload[$ - 1]);
892 
893         _data._payload = _data._payload[0 .. $ - 1];
894     }
895 
896     /// ditto
897     alias stableRemoveBack = removeBack;
898 
899     /**
900      * Removes `howMany` values from the back of the array.
901      * Unlike the unparameterized versions above, these functions
902      * do not throw if they could not remove `howMany` elements. Instead,
903      * if `howMany > n`, all elements are removed. The returned value is
904      * the effective number of elements removed. Both stable and non-stable
905      * versions behave the same and guarantee that ranges iterating over
906      * the array are never invalidated.
907      *
908      * Returns: The number of elements removed.
909      *
910      * Complexity: $(BIGOH howMany).
911      */
912     size_t removeBack(size_t howMany)
913     {
914         if (howMany > length) howMany = length;
915         static if (hasElaborateDestructor!T)
916             foreach (ref e; _data._payload[$ - howMany .. $])
917                 .destroy(e);
918 
919         _data._payload = _data._payload[0 .. $ - howMany];
920         return howMany;
921     }
922 
923     /// ditto
924     alias stableRemoveBack = removeBack;
925 
926     /**
927      * Inserts `stuff` before, after, or instead range `r`, which must
928      * be a valid range previously extracted from this array. `stuff`
929      * can be a value convertible to `T` or a range of objects convertible
930      * to `T`. Both stable and non-stable version behave the same and
931      * guarantee that ranges iterating over the array are never invalidated.
932      *
933      * Returns: The number of values inserted.
934      *
935      * Complexity: $(BIGOH length + m), where `m` is the length of `stuff`.
936      *
937      * Throws: `Exception` if `r` is not a range extracted from this array.
938      */
939     size_t insertBefore(Stuff)(Range r, Stuff stuff)
940     if (isImplicitlyConvertible!(Stuff, T))
941     {
942         import std.conv : emplace;
943         enforce(r._outer._data is _data && r._a <= length);
944         reserve(length + 1);
945         assert(_data.refCountedStore.isInitialized,
946             "Failed to allocate capacity to insertBefore");
947         // Move elements over by one slot
948         memmove(_data._payload.ptr + r._a + 1,
949                 _data._payload.ptr + r._a,
950                 T.sizeof * (length - r._a));
951         emplace(_data._payload.ptr + r._a, stuff);
952         _data._payload = _data._payload.ptr[0 .. _data._payload.length + 1];
953         return 1;
954     }
955 
956     /// ditto
957     size_t insertBefore(Stuff)(Range r, Stuff stuff)
958     if (isInputRange!Stuff && isImplicitlyConvertible!(ElementType!Stuff, T))
959     {
960         import std.conv : emplace;
961         enforce(r._outer._data is _data && r._a <= length);
962         static if (isForwardRange!Stuff)
963         {
964             // Can find the length in advance
965             auto extra = walkLength(stuff);
966             if (!extra) return 0;
967             reserve(length + extra);
968             assert(_data.refCountedStore.isInitialized,
969                 "Failed to allocate capacity to insertBefore");
970             // Move elements over by extra slots
971             memmove(_data._payload.ptr + r._a + extra,
972                     _data._payload.ptr + r._a,
973                     T.sizeof * (length - r._a));
974             foreach (p; _data._payload.ptr + r._a ..
975                     _data._payload.ptr + r._a + extra)
976             {
977                 emplace(p, stuff.front);
978                 stuff.popFront();
979             }
980             _data._payload =
981                 _data._payload.ptr[0 .. _data._payload.length + extra];
982             return extra;
983         }
984         else
985         {
986             import std.algorithm.mutation : bringToFront;
987             enforce(_data);
988             immutable offset = r._a;
989             enforce(offset <= length);
990             auto result = insertBack(stuff);
991             bringToFront(this[offset .. length - result],
992                     this[length - result .. length]);
993             return result;
994         }
995     }
996 
997     /// ditto
998     alias stableInsertBefore = insertBefore;
999 
1000     /// ditto
1001     size_t insertAfter(Stuff)(Range r, Stuff stuff)
1002     {
1003         import std.algorithm.mutation : bringToFront;
1004         enforce(r._outer._data is _data);
1005         // TODO: optimize
1006         immutable offset = r._b;
1007         enforce(offset <= length);
1008         auto result = insertBack(stuff);
1009         bringToFront(this[offset .. length - result],
1010                 this[length - result .. length]);
1011         return result;
1012     }
1013 
1014     /// ditto
1015     size_t replace(Stuff)(Range r, Stuff stuff)
1016     if (isInputRange!Stuff && isImplicitlyConvertible!(ElementType!Stuff, T))
1017     {
1018         enforce(r._outer._data is _data);
1019         size_t result;
1020         for (; !stuff.empty; stuff.popFront())
1021         {
1022             if (r.empty)
1023             {
1024                 // insert the rest
1025                 return result + insertBefore(r, stuff);
1026             }
1027             r.front = stuff.front;
1028             r.popFront();
1029             ++result;
1030         }
1031         // Remove remaining stuff in r
1032         linearRemove(r);
1033         return result;
1034     }
1035 
1036     /// ditto
1037     size_t replace(Stuff)(Range r, Stuff stuff)
1038     if (isImplicitlyConvertible!(Stuff, T))
1039     {
1040         enforce(r._outer._data is _data);
1041         if (r.empty)
1042         {
1043             insertBefore(r, stuff);
1044         }
1045         else
1046         {
1047             r.front = stuff;
1048             r.popFront();
1049             linearRemove(r);
1050         }
1051         return 1;
1052     }
1053 
1054     /**
1055      * Removes all elements belonging to `r`, which must be a range
1056      * obtained originally from this array.
1057      *
1058      * Returns: A range spanning the remaining elements in the array that
1059      * initially were right after `r`.
1060      *
1061      * Complexity: $(BIGOH length)
1062      *
1063      * Throws: `Exception` if `r` is not a valid range extracted from this array.
1064      */
1065     Range linearRemove(Range r)
1066     {
1067         import std.algorithm.mutation : copy;
1068 
1069         enforce(r._outer._data is _data);
1070         enforce(_data.refCountedStore.isInitialized);
1071         enforce(r._a <= r._b && r._b <= length);
1072         immutable offset1 = r._a;
1073         immutable offset2 = r._b;
1074         immutable tailLength = length - offset2;
1075         // Use copy here, not a[] = b[] because the ranges may overlap
1076         copy(this[offset2 .. length], this[offset1 .. offset1 + tailLength]);
1077         length = offset1 + tailLength;
1078         return this[length - tailLength .. length];
1079     }
1080 }
1081 
1082 @system unittest
1083 {
1084     Array!int a;
1085     assert(a.empty);
1086 }
1087 
1088 @system unittest
1089 {
1090     Array!int a;
1091     a.length = 10;
1092     assert(a.length == 10);
1093     assert(a.capacity >= a.length);
1094 }
1095 
1096 @system unittest
1097 {
1098     struct Dumb { int x = 5; }
1099     Array!Dumb a;
1100     a.length = 10;
1101     assert(a.length == 10);
1102     assert(a.capacity >= a.length);
1103     immutable cap = a.capacity;
1104     foreach (ref e; a)
1105         e.x = 10;
1106     a.length = 5;
1107     assert(a.length == 5);
1108     // do not realloc if length decreases
1109     assert(a.capacity == cap);
1110     foreach (ref e; a)
1111         assert(e.x == 10);
1112 
1113     a.length = 8;
1114     assert(a.length == 8);
1115     // do not realloc if capacity sufficient
1116     assert(a.capacity == cap);
1117     assert(Dumb.init.x == 5);
1118     foreach (i; 0 .. 5)
1119         assert(a[i].x == 10);
1120     foreach (i; 5 .. a.length)
1121         assert(a[i].x == Dumb.init.x);
1122 
1123     // realloc required, check if values properly copied
1124     a[] = Dumb(1);
1125     a.length = 20;
1126     assert(a.capacity >= 20);
1127     foreach (i; 0 .. 8)
1128         assert(a[i].x == 1);
1129     foreach (i; 8 .. a.length)
1130         assert(a[i].x == Dumb.init.x);
1131 
1132     // check if overlapping elements properly initialized
1133     a.length = 1;
1134     a.length = 20;
1135     assert(a[0].x == 1);
1136     foreach (e; a[1 .. $])
1137         assert(e.x == Dumb.init.x);
1138 }
1139 
1140 @system unittest
1141 {
1142     Array!int a = Array!int(1, 2, 3);
1143     //a._data._refCountedDebug = true;
1144     auto b = a.dup;
1145     assert(b == Array!int(1, 2, 3));
1146     b.front = 42;
1147     assert(b == Array!int(42, 2, 3));
1148     assert(a == Array!int(1, 2, 3));
1149 }
1150 
1151 @system unittest
1152 {
1153     auto a = Array!int(1, 2, 3);
1154     assert(a.length == 3);
1155 }
1156 
1157 @system unittest
1158 {
1159     const Array!int a = [1, 2];
1160 
1161     assert(a[0] == 1);
1162     assert(a.front == 1);
1163     assert(a.back == 2);
1164 
1165     static assert(!__traits(compiles, { a[0] = 1; }));
1166     static assert(!__traits(compiles, { a.front = 1; }));
1167     static assert(!__traits(compiles, { a.back = 1; }));
1168 
1169     auto r = a[];
1170     size_t i;
1171     foreach (e; r)
1172     {
1173         assert(e == i + 1);
1174         i++;
1175     }
1176 }
1177 
1178 @safe unittest
1179 {
1180     // https://issues.dlang.org/show_bug.cgi?id=13621
1181     import std.container : Array, BinaryHeap;
1182     alias Heap = BinaryHeap!(Array!int);
1183 }
1184 
1185 @system unittest
1186 {
1187     // https://issues.dlang.org/show_bug.cgi?id=18800
1188     static struct S { void* p; }
1189     Array!S a;
1190     a.length = 10;
1191 }
1192 
1193 @system unittest
1194 {
1195     Array!int a;
1196     a.reserve(1000);
1197     assert(a.length == 0);
1198     assert(a.empty);
1199     assert(a.capacity >= 1000);
1200     auto p = a._data._payload.ptr;
1201     foreach (i; 0 .. 1000)
1202     {
1203         a.insertBack(i);
1204     }
1205     assert(p == a._data._payload.ptr);
1206 }
1207 
1208 @system unittest
1209 {
1210     auto a = Array!int(1, 2, 3);
1211     a[1] *= 42;
1212     assert(a[1] == 84);
1213 }
1214 
1215 @system unittest
1216 {
1217     auto a = Array!int(1, 2, 3);
1218     auto b = Array!int(11, 12, 13);
1219     auto c = a ~ b;
1220     assert(c == Array!int(1, 2, 3, 11, 12, 13));
1221     assert(a ~ b[] == Array!int(1, 2, 3, 11, 12, 13));
1222     assert(a ~ [4,5] == Array!int(1,2,3,4,5));
1223 }
1224 
1225 @system unittest
1226 {
1227     auto a = Array!int(1, 2, 3);
1228     auto b = Array!int(11, 12, 13);
1229     a ~= b;
1230     assert(a == Array!int(1, 2, 3, 11, 12, 13));
1231 }
1232 
1233 @system unittest
1234 {
1235     auto a = Array!int(1, 2, 3, 4);
1236     assert(a.removeAny() == 4);
1237     assert(a == Array!int(1, 2, 3));
1238 }
1239 
1240 @system unittest
1241 {
1242     auto a = Array!int(1, 2, 3, 4, 5);
1243     auto r = a[2 .. a.length];
1244     assert(a.insertBefore(r, 42) == 1);
1245     assert(a == Array!int(1, 2, 42, 3, 4, 5));
1246     r = a[2 .. 2];
1247     assert(a.insertBefore(r, [8, 9]) == 2);
1248     assert(a == Array!int(1, 2, 8, 9, 42, 3, 4, 5));
1249 }
1250 
1251 @system unittest
1252 {
1253     auto a = Array!int(0, 1, 2, 3, 4, 5, 6, 7, 8);
1254     a.linearRemove(a[4 .. 6]);
1255     assert(a == Array!int(0, 1, 2, 3, 6, 7, 8));
1256 }
1257 
1258 // Give the Range object some testing.
1259 @system unittest
1260 {
1261     import std.algorithm.comparison : equal;
1262     import std.range : retro;
1263     auto a = Array!int(0, 1, 2, 3, 4, 5, 6)[];
1264     auto b = Array!int(6, 5, 4, 3, 2, 1, 0)[];
1265     alias A = typeof(a);
1266 
1267     static assert(isRandomAccessRange!A);
1268     static assert(hasSlicing!A);
1269     static assert(hasAssignableElements!A);
1270     static assert(hasMobileElements!A);
1271 
1272     assert(equal(retro(b), a));
1273     assert(a.length == 7);
1274     assert(equal(a[1 .. 4], [1, 2, 3]));
1275 }
1276 
1277 // https://issues.dlang.org/show_bug.cgi?id=5920
1278 @system unittest
1279 {
1280     struct structBug5920
1281     {
1282         int order;
1283         uint* pDestructionMask;
1284         ~this()
1285         {
1286             if (pDestructionMask)
1287                 *pDestructionMask += 1 << order;
1288         }
1289     }
1290 
1291     alias S = structBug5920;
1292     uint dMask;
1293 
1294     auto arr = Array!S(cast(S[])[]);
1295     foreach (i; 0 .. 8)
1296         arr.insertBack(S(i, &dMask));
1297     // don't check dMask now as S may be copied multiple times (it's ok?)
1298     {
1299         assert(arr.length == 8);
1300         dMask = 0;
1301         arr.length = 6;
1302         assert(arr.length == 6);    // make sure shrinking calls the d'tor
1303         assert(dMask == 0b1100_0000);
1304         arr.removeBack();
1305         assert(arr.length == 5);    // make sure removeBack() calls the d'tor
1306         assert(dMask == 0b1110_0000);
1307         arr.removeBack(3);
1308         assert(arr.length == 2);    // ditto
1309         assert(dMask == 0b1111_1100);
1310         arr.clear();
1311         assert(arr.length == 0);    // make sure clear() calls the d'tor
1312         assert(dMask == 0b1111_1111);
1313     }
1314     assert(dMask == 0b1111_1111);   // make sure the d'tor is called once only.
1315 }
1316 
1317 // Test for https://issues.dlang.org/show_bug.cgi?id=5792
1318 // (mainly just to check if this piece of code is compilable)
1319 @system unittest
1320 {
1321     auto a = Array!(int[])([[1,2],[3,4]]);
1322     a.reserve(4);
1323     assert(a.capacity >= 4);
1324     assert(a.length == 2);
1325     assert(a[0] == [1,2]);
1326     assert(a[1] == [3,4]);
1327     a.reserve(16);
1328     assert(a.capacity >= 16);
1329     assert(a.length == 2);
1330     assert(a[0] == [1,2]);
1331     assert(a[1] == [3,4]);
1332 }
1333 
1334 // test replace!Stuff with range Stuff
1335 @system unittest
1336 {
1337     import std.algorithm.comparison : equal;
1338     auto a = Array!int([1, 42, 5]);
1339     a.replace(a[1 .. 2], [2, 3, 4]);
1340     assert(equal(a[], [1, 2, 3, 4, 5]));
1341 }
1342 
1343 // test insertBefore and replace with empty Arrays
1344 @system unittest
1345 {
1346     import std.algorithm.comparison : equal;
1347     auto a = Array!int();
1348     a.insertBefore(a[], 1);
1349     assert(equal(a[], [1]));
1350 }
1351 @system unittest
1352 {
1353     import std.algorithm.comparison : equal;
1354     auto a = Array!int();
1355     a.insertBefore(a[], [1, 2]);
1356     assert(equal(a[], [1, 2]));
1357 }
1358 @system unittest
1359 {
1360     import std.algorithm.comparison : equal;
1361     auto a = Array!int();
1362     a.replace(a[], [1, 2]);
1363     assert(equal(a[], [1, 2]));
1364 }
1365 @system unittest
1366 {
1367     import std.algorithm.comparison : equal;
1368     auto a = Array!int();
1369     a.replace(a[], 1);
1370     assert(equal(a[], [1]));
1371 }
1372 // make sure that Array instances refuse ranges that don't belong to them
1373 @system unittest
1374 {
1375     import std.exception : assertThrown;
1376 
1377     Array!int a = [1, 2, 3];
1378     auto r = a.dup[];
1379     assertThrown(a.insertBefore(r, 42));
1380     assertThrown(a.insertBefore(r, [42]));
1381     assertThrown(a.insertAfter(r, 42));
1382     assertThrown(a.replace(r, 42));
1383     assertThrown(a.replace(r, [42]));
1384     assertThrown(a.linearRemove(r));
1385 }
1386 @system unittest
1387 {
1388     auto a = Array!int([1, 1]);
1389     a[1]  = 0; //Check Array.opIndexAssign
1390     assert(a[1] == 0);
1391     a[1] += 1; //Check Array.opIndexOpAssign
1392     assert(a[1] == 1);
1393 
1394     //Check Array.opIndexUnary
1395     ++a[0];
1396     //a[0]++ //op++ doesn't return, so this shouldn't work, even with 5044 fixed
1397     assert(a[0] == 2);
1398     assert(+a[0] == +2);
1399     assert(-a[0] == -2);
1400     assert(~a[0] == ~2);
1401 
1402     auto r = a[];
1403     r[1]  = 0; //Check Array.Range.opIndexAssign
1404     assert(r[1] == 0);
1405     r[1] += 1; //Check Array.Range.opIndexOpAssign
1406     assert(r[1] == 1);
1407 
1408     //Check Array.Range.opIndexUnary
1409     ++r[0];
1410     //r[0]++ //op++ doesn't return, so this shouldn't work, even with 5044 fixed
1411     assert(r[0] == 3);
1412     assert(+r[0] == +3);
1413     assert(-r[0] == -3);
1414     assert(~r[0] == ~3);
1415 }
1416 
1417 @system unittest
1418 {
1419     import std.algorithm.comparison : equal;
1420 
1421     //Test "array-wide" operations
1422     auto a = Array!int([0, 1, 2]); //Array
1423     a[] += 5;
1424     assert(a[].equal([5, 6, 7]));
1425     ++a[];
1426     assert(a[].equal([6, 7, 8]));
1427     a[1 .. 3] *= 5;
1428     assert(a[].equal([6, 35, 40]));
1429     a[0 .. 2] = 0;
1430     assert(a[].equal([0, 0, 40]));
1431 
1432     //Test empty array
1433     auto a2 = Array!int.init;
1434     ++a2[];
1435     ++a2[0 .. 0];
1436     a2[] = 0;
1437     a2[0 .. 0] = 0;
1438     a2[] += 0;
1439     a2[0 .. 0] += 0;
1440 
1441     //Test "range-wide" operations
1442     auto r = Array!int([0, 1, 2])[]; //Array.Range
1443     r[] += 5;
1444     assert(r.equal([5, 6, 7]));
1445     ++r[];
1446     assert(r.equal([6, 7, 8]));
1447     r[1 .. 3] *= 5;
1448     assert(r.equal([6, 35, 40]));
1449     r[0 .. 2] = 0;
1450     assert(r.equal([0, 0, 40]));
1451 
1452     //Test empty Range
1453     auto r2 = Array!int.init[];
1454     ++r2[];
1455     ++r2[0 .. 0];
1456     r2[] = 0;
1457     r2[0 .. 0] = 0;
1458     r2[] += 0;
1459     r2[0 .. 0] += 0;
1460 }
1461 
1462 // Test issue 11194
1463 @system unittest
1464 {
1465     static struct S {
1466         int i = 1337;
1467         void* p;
1468         this(this) { assert(i == 1337); }
1469         ~this() { assert(i == 1337); }
1470     }
1471     Array!S arr;
1472     S s;
1473     arr ~= s;
1474     arr ~= s;
1475 }
1476 
1477 // https://issues.dlang.org/show_bug.cgi?id=11459
1478 @safe unittest
1479 {
1480     static struct S
1481     {
1482         bool b;
1483         alias b this;
1484     }
1485     alias A = Array!S;
1486     alias B = Array!(shared bool);
1487 }
1488 
1489 // https://issues.dlang.org/show_bug.cgi?id=11884
1490 @system unittest
1491 {
1492     import std.algorithm.iteration : filter;
1493     auto a = Array!int([1, 2, 2].filter!"true"());
1494 }
1495 
1496 // https://issues.dlang.org/show_bug.cgi?id=8282
1497 @safe unittest
1498 {
1499     auto arr = new Array!int;
1500 }
1501 
1502 // https://issues.dlang.org/show_bug.cgi?id=6998
1503 @system unittest
1504 {
1505     static int i = 0;
1506     class C
1507     {
1508         int dummy = 1;
1509         this(){++i;}
1510         ~this(){--i;}
1511     }
1512 
1513     assert(i == 0);
1514     auto c = new C();
1515     assert(i == 1);
1516 
1517     //scope
1518     {
1519         auto arr = Array!C(c);
1520         assert(i == 1);
1521     }
1522     //Array should not have destroyed the class instance
1523     assert(i == 1);
1524 
1525     //Just to make sure the GC doesn't collect before the above test.
1526     assert(c.dummy == 1);
1527 }
1528 
1529 //https://issues.dlang.org/show_bug.cgi?id=6998 (2)
1530 @system unittest
1531 {
1532     static class C {int i;}
1533     auto c = new C;
1534     c.i = 42;
1535     Array!C a;
1536     a ~= c;
1537     a.clear;
1538     assert(c.i == 42); //fails
1539 }
1540 
1541 @safe unittest
1542 {
1543     static assert(is(Array!int.Range));
1544     static assert(is(Array!int.ConstRange));
1545 }
1546 
1547 @system unittest // const/immutable Array and Ranges
1548 {
1549     static void test(A, R, E, S)()
1550     {
1551         A a;
1552         R r = a[];
1553         assert(r.empty);
1554         assert(r.length == 0);
1555         static assert(is(typeof(r.front) == E));
1556         static assert(is(typeof(r.back) == E));
1557         static assert(is(typeof(r[0]) == E));
1558         static assert(is(typeof(r[]) == S));
1559         static assert(is(typeof(r[0 .. 0]) == S));
1560     }
1561 
1562     alias A = Array!int;
1563 
1564     test!(A, A.Range, int, A.Range);
1565     test!(A, const A.Range, const int, A.ConstRange);
1566 
1567     test!(const A, A.ConstRange, const int, A.ConstRange);
1568     test!(const A, const A.ConstRange, const int, A.ConstRange);
1569 
1570     test!(immutable A, A.ImmutableRange, immutable int, A.ImmutableRange);
1571     test!(immutable A, const A.ImmutableRange, immutable int, A.ImmutableRange);
1572     test!(immutable A, immutable A.ImmutableRange, immutable int,
1573         A.ImmutableRange);
1574 }
1575 
1576 // ensure @nogc
1577 @nogc @system unittest
1578 {
1579     Array!int ai;
1580     ai ~= 1;
1581     assert(ai.front == 1);
1582 
1583     ai.reserve(10);
1584     assert(ai.capacity == 10);
1585 
1586     static immutable arr = [1, 2, 3];
1587     ai.insertBack(arr);
1588 }
1589 
1590 /**
1591  * typeof may give wrong result in case of classes defining `opCall` operator
1592  * https://issues.dlang.org/show_bug.cgi?id=20589
1593  *
1594  * destructor std.container.array.Array!(MyClass).Array.~this is @system
1595  * so the unittest is @system too
1596  */
1597 @system unittest
1598 {
1599     class MyClass
1600     {
1601         T opCall(T)(T p)
1602         {
1603             return p;
1604         }
1605     }
1606 
1607     Array!MyClass arr;
1608 }
1609 
1610 
1611 ////////////////////////////////////////////////////////////////////////////////
1612 // Array!bool
1613 ////////////////////////////////////////////////////////////////////////////////
1614 
1615 /**
1616  * _Array specialized for `bool`. Packs together values efficiently by
1617  * allocating one bit per element.
1618  */
1619 struct Array(T)
1620 if (is(immutable T == immutable bool))
1621 {
1622     import std.exception : enforce;
1623     import std.typecons : RefCounted, RefCountedAutoInitialize;
1624 
1625     static immutable uint bitsPerWord = size_t.sizeof * 8;
1626     private static struct Data
1627     {
1628         Array!size_t.Payload _backend;
1629         size_t _length;
1630     }
1631     private RefCounted!(Data, RefCountedAutoInitialize.no) _store;
1632 
1633     private @property ref size_t[] data()
1634     {
1635         assert(_store.refCountedStore.isInitialized,
1636             "Cannot get data of uninitialized Array");
1637         return _store._backend._payload;
1638     }
1639 
1640     /**
1641      * Defines the array's primary range.
1642      */
1643     struct Range
1644     {
1645         private Array _outer;
1646         private size_t _a, _b;
1647         /// Range primitives
1648         @property Range save()
1649         {
1650             version (bug4437)
1651             {
1652                 return this;
1653             }
1654             else
1655             {
1656                 auto copy = this;
1657                 return copy;
1658             }
1659         }
1660         /// Ditto
1661         @property bool empty()
1662         {
1663             return _a >= _b || _outer.length < _b;
1664         }
1665         /// Ditto
1666         @property T front()
1667         {
1668             enforce(!empty, "Attempting to access the front of an empty Array");
1669             return _outer[_a];
1670         }
1671         /// Ditto
1672         @property void front(bool value)
1673         {
1674             enforce(!empty, "Attempting to set the front of an empty Array");
1675             _outer[_a] = value;
1676         }
1677         /// Ditto
1678         T moveFront()
1679         {
1680             enforce(!empty, "Attempting to move the front of an empty Array");
1681             return _outer.moveAt(_a);
1682         }
1683         /// Ditto
1684         void popFront()
1685         {
1686             enforce(!empty, "Attempting to popFront an empty Array");
1687             ++_a;
1688         }
1689         /// Ditto
1690         @property T back()
1691         {
1692             enforce(!empty, "Attempting to access the back of an empty Array");
1693             return _outer[_b - 1];
1694         }
1695         /// Ditto
1696         @property void back(bool value)
1697         {
1698             enforce(!empty, "Attempting to set the back of an empty Array");
1699             _outer[_b - 1] = value;
1700         }
1701         /// Ditto
1702         T moveBack()
1703         {
1704             enforce(!empty, "Attempting to move the back of an empty Array");
1705             return _outer.moveAt(_b - 1);
1706         }
1707         /// Ditto
1708         void popBack()
1709         {
1710             enforce(!empty, "Attempting to popBack an empty Array");
1711             --_b;
1712         }
1713         /// Ditto
1714         T opIndex(size_t i)
1715         {
1716             return _outer[_a + i];
1717         }
1718         /// Ditto
1719         void opIndexAssign(T value, size_t i)
1720         {
1721             _outer[_a + i] = value;
1722         }
1723         /// Ditto
1724         T moveAt(size_t i)
1725         {
1726             return _outer.moveAt(_a + i);
1727         }
1728         /// Ditto
1729         @property size_t length() const
1730         {
1731             assert(_a <= _b, "Invalid bounds");
1732             return _b - _a;
1733         }
1734         alias opDollar = length;
1735         /// ditto
1736         Range opSlice(size_t low, size_t high)
1737         {
1738             // Note: indexes start at 0, which is equivalent to _a
1739             assert(
1740                 low <= high && high <= (_b - _a),
1741                 "Using out of bounds indexes on an Array"
1742             );
1743             return Range(_outer, _a + low, _a + high);
1744         }
1745     }
1746 
1747     /**
1748      * Property returning `true` if and only if the array has
1749      * no elements.
1750      *
1751      * Complexity: $(BIGOH 1)
1752      */
1753     @property bool empty()
1754     {
1755         return !length;
1756     }
1757 
1758     /**
1759      * Returns: A duplicate of the array.
1760      *
1761      * Complexity: $(BIGOH length).
1762      */
1763     @property Array dup()
1764     {
1765         Array result;
1766         result.insertBack(this[]);
1767         return result;
1768     }
1769 
1770     /**
1771      * Returns the number of elements in the array.
1772      *
1773      * Complexity: $(BIGOH 1).
1774      */
1775     @property size_t length() const
1776     {
1777         return _store.refCountedStore.isInitialized ? _store._length : 0;
1778     }
1779     size_t opDollar() const
1780     {
1781         return length;
1782     }
1783 
1784     /**
1785      * Returns: The maximum number of elements the array can store without
1786      * reallocating memory and invalidating iterators upon insertion.
1787      *
1788      * Complexity: $(BIGOH 1).
1789      */
1790     @property size_t capacity()
1791     {
1792         return _store.refCountedStore.isInitialized
1793             ? cast(size_t) bitsPerWord * _store._backend.capacity
1794             : 0;
1795     }
1796 
1797     /**
1798      * Ensures sufficient capacity to accommodate `e` _elements.
1799      * If `e < capacity`, this method does nothing.
1800      *
1801      * Postcondition: `capacity >= e`
1802      *
1803      * Note: If the capacity is increased, one should assume that all
1804      * iterators to the elements are invalidated.
1805      *
1806      * Complexity: at most $(BIGOH length) if `e > capacity`, otherwise $(BIGOH 1).
1807      */
1808     void reserve(size_t e)
1809     {
1810         import std.conv : to;
1811         _store.refCountedStore.ensureInitialized();
1812         _store._backend.reserve(to!size_t((e + bitsPerWord - 1) / bitsPerWord));
1813     }
1814 
1815     /**
1816      * Returns: A range that iterates over all elements of the array in forward order.
1817      *
1818      * Complexity: $(BIGOH 1)
1819      */
1820     Range opSlice()
1821     {
1822         return Range(this, 0, length);
1823     }
1824 
1825 
1826     /**
1827      * Returns: A range that iterates the array between two specified positions.
1828      *
1829      * Complexity: $(BIGOH 1)
1830      */
1831     Range opSlice(size_t a, size_t b)
1832     {
1833         enforce(a <= b && b <= length);
1834         return Range(this, a, b);
1835     }
1836 
1837     /**
1838      * Returns: The first element of the array.
1839      *
1840      * Precondition: `empty == false`
1841      *
1842      * Complexity: $(BIGOH 1)
1843      *
1844      * Throws: `Exception` if the array is empty.
1845      */
1846     @property bool front()
1847     {
1848         enforce(!empty);
1849         return data.ptr[0] & 1;
1850     }
1851 
1852     /// Ditto
1853     @property void front(bool value)
1854     {
1855         enforce(!empty);
1856         if (value) data.ptr[0] |= 1;
1857         else data.ptr[0] &= ~cast(size_t) 1;
1858     }
1859 
1860     /**
1861      * Returns: The last element of the array.
1862      *
1863      * Precondition: `empty == false`
1864      *
1865      * Complexity: $(BIGOH 1)
1866      *
1867      * Throws: `Exception` if the array is empty.
1868      */
1869     @property bool back()
1870     {
1871         enforce(!empty);
1872         return cast(bool)(data.back & (cast(size_t) 1 << ((_store._length - 1) % bitsPerWord)));
1873     }
1874 
1875     /// Ditto
1876     @property void back(bool value)
1877     {
1878         enforce(!empty);
1879         if (value)
1880         {
1881             data.back |= (cast(size_t) 1 << ((_store._length - 1) % bitsPerWord));
1882         }
1883         else
1884         {
1885             data.back &=
1886                 ~(cast(size_t) 1 << ((_store._length - 1) % bitsPerWord));
1887         }
1888     }
1889 
1890     /**
1891      * Indexing operators yielding or modifyng the value at the specified index.
1892      *
1893      * Precondition: `i < length`
1894      *
1895      * Complexity: $(BIGOH 1)
1896      */
1897     bool opIndex(size_t i)
1898     {
1899         auto div = cast(size_t) (i / bitsPerWord);
1900         auto rem = i % bitsPerWord;
1901         enforce(div < data.length);
1902         return cast(bool)(data.ptr[div] & (cast(size_t) 1 << rem));
1903     }
1904 
1905     /// ditto
1906     void opIndexAssign(bool value, size_t i)
1907     {
1908         auto div = cast(size_t) (i / bitsPerWord);
1909         auto rem = i % bitsPerWord;
1910         enforce(div < data.length);
1911         if (value) data.ptr[div] |= (cast(size_t) 1 << rem);
1912         else data.ptr[div] &= ~(cast(size_t) 1 << rem);
1913     }
1914 
1915     /// ditto
1916     void opIndexOpAssign(string op)(bool value, size_t i)
1917     {
1918         auto div = cast(size_t) (i / bitsPerWord);
1919         auto rem = i % bitsPerWord;
1920         enforce(div < data.length);
1921         auto oldValue = cast(bool) (data.ptr[div] & (cast(size_t) 1 << rem));
1922         // Do the deed
1923         auto newValue = mixin("oldValue "~op~" value");
1924         // Write back the value
1925         if (newValue != oldValue)
1926         {
1927             if (newValue) data.ptr[div] |= (cast(size_t) 1 << rem);
1928             else data.ptr[div] &= ~(cast(size_t) 1 << rem);
1929         }
1930     }
1931 
1932     /// Ditto
1933     T moveAt(size_t i)
1934     {
1935         return this[i];
1936     }
1937 
1938     /**
1939      * Returns: A new array which is a concatenation of `this` and its argument.
1940      *
1941      * Complexity:
1942      * $(BIGOH length + m), where `m` is the number of elements in `stuff`.
1943      */
1944     Array!bool opBinary(string op, Stuff)(Stuff rhs)
1945     if (op == "~")
1946     {
1947         Array!bool result;
1948 
1949         static if (hasLength!Stuff)
1950             result.reserve(length + rhs.length);
1951         else static if (is(typeof(rhs[])) && hasLength!(typeof(rhs[])))
1952             result.reserve(length + rhs[].length);
1953         else static if (isImplicitlyConvertible!(Stuff, bool))
1954             result.reserve(length + 1);
1955 
1956         result.insertBack(this[]);
1957         result ~= rhs;
1958         return result;
1959     }
1960 
1961     /**
1962      * Forwards to `insertBack`.
1963      */
1964     Array!bool opOpAssign(string op, Stuff)(Stuff stuff)
1965     if (op == "~")
1966     {
1967         static if (is(typeof(stuff[]))) insertBack(stuff[]);
1968         else insertBack(stuff);
1969         return this;
1970     }
1971 
1972     /**
1973      * Removes all the elements from the array and releases allocated memory.
1974      *
1975      * Postcondition: `empty == true && capacity == 0`
1976      *
1977      * Complexity: $(BIGOH length)
1978      */
1979     void clear()
1980     {
1981         this = Array();
1982     }
1983 
1984     /**
1985      * Sets the number of elements in the array to `newLength`. If `newLength`
1986      * is greater than `length`, the new elements are added to the end of the
1987      * array and initialized with `false`.
1988      *
1989      * Complexity:
1990      * Guaranteed $(BIGOH abs(length - newLength)) if `capacity >= newLength`.
1991      * If `capacity < newLength` the worst case is $(BIGOH newLength).
1992      *
1993      * Postcondition: `length == newLength`
1994      */
1995     @property void length(size_t newLength)
1996     {
1997         import std.conv : to;
1998         _store.refCountedStore.ensureInitialized();
1999         auto newDataLength =
2000             to!size_t((newLength + bitsPerWord - 1) / bitsPerWord);
2001         _store._backend.length = newDataLength;
2002         _store._length = newLength;
2003     }
2004 
2005     /**
2006      * Removes the last element from the array and returns it.
2007      * Both stable and non-stable versions behave the same and guarantee
2008      * that ranges iterating over the array are never invalidated.
2009      *
2010      * Precondition: `empty == false`
2011      *
2012      * Returns: The element removed.
2013      *
2014      * Complexity: $(BIGOH 1).
2015      *
2016      * Throws: `Exception` if the array is empty.
2017      */
2018     T removeAny()
2019     {
2020         auto result = back;
2021         removeBack();
2022         return result;
2023     }
2024 
2025     /// ditto
2026     alias stableRemoveAny = removeAny;
2027 
2028     /**
2029      * Inserts the specified elements at the back of the array. `stuff` can be
2030      * a value convertible to `bool` or a range of objects convertible to `bool`.
2031      *
2032      * Returns: The number of elements inserted.
2033      *
2034      * Complexity:
2035      * $(BIGOH length + m) if reallocation takes place, otherwise $(BIGOH m),
2036      * where `m` is the number of elements in `stuff`.
2037      */
2038     size_t insertBack(Stuff)(Stuff stuff)
2039     if (is(Stuff : bool))
2040     {
2041         _store.refCountedStore.ensureInitialized();
2042         auto rem = _store._length % bitsPerWord;
2043         if (rem)
2044         {
2045             // Fits within the current array
2046             if (stuff)
2047             {
2048                 data[$ - 1] |= (cast(size_t) 1 << rem);
2049             }
2050             else
2051             {
2052                 data[$ - 1] &= ~(cast(size_t) 1 << rem);
2053             }
2054         }
2055         else
2056         {
2057             // Need to add more data
2058             _store._backend.insertBack(stuff);
2059         }
2060         ++_store._length;
2061         return 1;
2062     }
2063 
2064     /// ditto
2065     size_t insertBack(Stuff)(Stuff stuff)
2066     if (isInputRange!Stuff && is(ElementType!Stuff : bool))
2067     {
2068         static if (!hasLength!Stuff) size_t result;
2069         for (; !stuff.empty; stuff.popFront())
2070         {
2071             insertBack(stuff.front);
2072             static if (!hasLength!Stuff) ++result;
2073         }
2074         static if (!hasLength!Stuff) return result;
2075         else return stuff.length;
2076     }
2077 
2078     /// ditto
2079     alias stableInsertBack = insertBack;
2080 
2081     /// ditto
2082     alias insert = insertBack;
2083 
2084     /// ditto
2085     alias stableInsert = insertBack;
2086 
2087     /// ditto
2088     alias linearInsert = insertBack;
2089 
2090     /// ditto
2091     alias stableLinearInsert = insertBack;
2092 
2093     /**
2094      * Removes the value from the back of the array. Both stable and non-stable
2095      * versions behave the same and guarantee that ranges iterating over the
2096      * array are never invalidated.
2097      *
2098      * Precondition: `empty == false`
2099      *
2100      * Complexity: $(BIGOH 1).
2101      *
2102      * Throws: `Exception` if the array is empty.
2103      */
2104     void removeBack()
2105     {
2106         enforce(_store._length);
2107         if (_store._length % bitsPerWord)
2108         {
2109             // Cool, just decrease the length
2110             --_store._length;
2111         }
2112         else
2113         {
2114             // Reduce the allocated space
2115             --_store._length;
2116             _store._backend.length = _store._backend.length - 1;
2117         }
2118     }
2119 
2120     /// ditto
2121     alias stableRemoveBack = removeBack;
2122 
2123     /**
2124      * Removes `howMany` values from the back of the array. Unlike the
2125      * unparameterized versions above, these functions do not throw if
2126      * they could not remove `howMany` elements. Instead, if `howMany > n`,
2127      * all elements are removed. The returned value is the effective number
2128      * of elements removed. Both stable and non-stable versions behave the same
2129      * and guarantee that ranges iterating over the array are never invalidated.
2130      *
2131      * Returns: The number of elements removed.
2132      *
2133      * Complexity: $(BIGOH howMany).
2134      */
2135     size_t removeBack(size_t howMany)
2136     {
2137         if (howMany >= length)
2138         {
2139             howMany = length;
2140             clear();
2141         }
2142         else
2143         {
2144             length = length - howMany;
2145         }
2146         return howMany;
2147     }
2148 
2149     /// ditto
2150     alias stableRemoveBack = removeBack;
2151 
2152     /**
2153      * Inserts `stuff` before, after, or instead range `r`, which must
2154      * be a valid range previously extracted from this array. `stuff`
2155      * can be a value convertible to `bool` or a range of objects convertible
2156      * to `bool`. Both stable and non-stable version behave the same and
2157      * guarantee that ranges iterating over the array are never invalidated.
2158      *
2159      * Returns: The number of values inserted.
2160      *
2161      * Complexity: $(BIGOH length + m), where `m` is the length of `stuff`.
2162      */
2163     size_t insertBefore(Stuff)(Range r, Stuff stuff)
2164     {
2165         import std.algorithm.mutation : bringToFront;
2166         // TODO: make this faster, it moves one bit at a time
2167         immutable inserted = stableInsertBack(stuff);
2168         immutable tailLength = length - inserted;
2169         bringToFront(
2170             this[r._a .. tailLength],
2171             this[tailLength .. length]);
2172         return inserted;
2173     }
2174 
2175     /// ditto
2176     alias stableInsertBefore = insertBefore;
2177 
2178     /// ditto
2179     size_t insertAfter(Stuff)(Range r, Stuff stuff)
2180     {
2181         import std.algorithm.mutation : bringToFront;
2182         // TODO: make this faster, it moves one bit at a time
2183         immutable inserted = stableInsertBack(stuff);
2184         immutable tailLength = length - inserted;
2185         bringToFront(
2186             this[r._b .. tailLength],
2187             this[tailLength .. length]);
2188         return inserted;
2189     }
2190 
2191     /// ditto
2192     alias stableInsertAfter = insertAfter;
2193 
2194     /// ditto
2195     size_t replace(Stuff)(Range r, Stuff stuff)
2196     if (is(Stuff : bool))
2197     {
2198         if (!r.empty)
2199         {
2200             // There is room
2201             r.front = stuff;
2202             r.popFront();
2203             linearRemove(r);
2204         }
2205         else
2206         {
2207             // No room, must insert
2208             insertBefore(r, stuff);
2209         }
2210         return 1;
2211     }
2212 
2213     /// ditto
2214     alias stableReplace = replace;
2215 
2216     /**
2217      * Removes all elements belonging to `r`, which must be a range
2218      * obtained originally from this array.
2219      *
2220      * Returns: A range spanning the remaining elements in the array that
2221      * initially were right after `r`.
2222      *
2223      * Complexity: $(BIGOH length)
2224      */
2225     Range linearRemove(Range r)
2226     {
2227         import std.algorithm.mutation : copy;
2228         copy(this[r._b .. length], this[r._a .. length]);
2229         length = length - r.length;
2230         return this[r._a .. length];
2231     }
2232 }
2233 
2234 @system unittest
2235 {
2236     Array!bool a;
2237     assert(a.empty);
2238 }
2239 
2240 @system unittest
2241 {
2242     Array!bool arr;
2243     arr.insert([false, false, false, false]);
2244     assert(arr.front == false);
2245     assert(arr.back == false);
2246     assert(arr[1] == false);
2247     auto slice = arr[];
2248     slice = arr[0 .. $];
2249     slice = slice[1 .. $];
2250     slice.front = true;
2251     slice.back = true;
2252     slice[1] = true;
2253     slice = slice[0 .. $]; // https://issues.dlang.org/show_bug.cgi?id=19171
2254     assert(slice.front == true);
2255     assert(slice.back == true);
2256     assert(slice[1] == true);
2257     assert(slice.moveFront == true);
2258     assert(slice.moveBack == true);
2259     assert(slice.moveAt(1) == true);
2260 }
2261 
2262 // uncomparable values are valid values for an array
2263 // https://issues.dlang.org/show_bug.cgi?id=16331
2264 @system unittest
2265 {
2266     double[] values = [double.nan, double.nan];
2267     auto arr = Array!double(values);
2268 }
2269 
2270 @nogc @system unittest
2271 {
2272     auto a = Array!int(0, 1, 2);
2273     int[3] b = [3, 4, 5];
2274     short[3] ci = [0, 1, 0];
2275     auto c = Array!short(ci);
2276     assert(Array!int(0, 1, 2, 0, 1, 2) == a ~ a);
2277     assert(Array!int(0, 1, 2, 3, 4, 5) == a ~ b);
2278     assert(Array!int(0, 1, 2, 3) == a ~ 3);
2279     assert(Array!int(0, 1, 2, 0, 1, 0) == a ~ c);
2280 }
2281 
2282 @nogc @system unittest
2283 {
2284     auto a = Array!char('a', 'b');
2285     assert(Array!char("abc") == a ~ 'c');
2286     import std.utf : byCodeUnit;
2287     assert(Array!char("abcd") == a ~ "cd".byCodeUnit);
2288 }
2289 
2290 @nogc @system unittest
2291 {
2292     auto a = Array!dchar("ąćę"d);
2293     assert(Array!dchar("ąćęϢϖ"d) == a ~ "Ϣϖ"d);
2294     wchar x = 'Ϣ';
2295     assert(Array!dchar("ąćęϢz"d) == a ~ x ~ 'z');
2296 }
2297 
2298 @system unittest
2299 {
2300     Array!bool a;
2301     assert(a.empty);
2302     a.insertBack(false);
2303     assert(!a.empty);
2304 }
2305 
2306 @system unittest
2307 {
2308     Array!bool a;
2309     assert(a.empty);
2310     auto b = a.dup;
2311     assert(b.empty);
2312     a.insertBack(true);
2313     assert(b.empty);
2314 }
2315 
2316 @system unittest
2317 {
2318     import std.conv : to;
2319     Array!bool a;
2320     assert(a.length == 0);
2321     a.insert(true);
2322     assert(a.length == 1, to!string(a.length));
2323 }
2324 
2325 @system unittest
2326 {
2327     import std.conv : to;
2328     Array!bool a;
2329     assert(a.capacity == 0);
2330     foreach (i; 0 .. 100)
2331     {
2332         a.insert(true);
2333         assert(a.capacity >= a.length, to!string(a.capacity));
2334     }
2335 }
2336 
2337 @system unittest
2338 {
2339     Array!bool a;
2340     assert(a.capacity == 0);
2341     a.reserve(15657);
2342     assert(a.capacity >= 15657);
2343     a.reserve(100);
2344     assert(a.capacity >= 15657);
2345 }
2346 
2347 @system unittest
2348 {
2349     Array!bool a;
2350     a.insertBack([true, false, true, true]);
2351     assert(a[0 .. 2].length == 2);
2352 }
2353 
2354 @system unittest
2355 {
2356     Array!bool a;
2357     a.insertBack([true, false, true, true]);
2358     assert(a[].length == 4);
2359 }
2360 
2361 @system unittest
2362 {
2363     Array!bool a;
2364     a.insertBack([true, false, true, true]);
2365     assert(a.front);
2366     a.front = false;
2367     assert(!a.front);
2368 }
2369 
2370 @system unittest
2371 {
2372     Array!bool a;
2373     a.insertBack([true, false, true, true]);
2374     assert(a[].length == 4);
2375 }
2376 
2377 @system unittest
2378 {
2379     Array!bool a;
2380     a.insertBack([true, false, true, true]);
2381     assert(a.back);
2382     a.back = false;
2383     assert(!a.back);
2384 }
2385 
2386 @system unittest
2387 {
2388     Array!bool a;
2389     a.insertBack([true, false, true, true]);
2390     assert(a[0] && !a[1]);
2391     a[0] &= a[1];
2392     assert(!a[0]);
2393 }
2394 
2395 @system unittest
2396 {
2397     import std.algorithm.comparison : equal;
2398     Array!bool a;
2399     a.insertBack([true, false, true, true]);
2400     Array!bool b;
2401     b.insertBack([true, true, false, true]);
2402     assert(equal((a ~ b)[],
2403                     [true, false, true, true, true, true, false, true]));
2404     assert((a ~ [true, false])[].equal([true, false, true, true, true, false]));
2405     Array!bool c;
2406     c.insertBack(true);
2407     assert((c ~ false)[].equal([true, false]));
2408 }
2409 @system unittest
2410 {
2411     import std.algorithm.comparison : equal;
2412     Array!bool a;
2413     a.insertBack([true, false, true, true]);
2414     Array!bool b;
2415     a.insertBack([false, true, false, true, true]);
2416     a ~= b;
2417     assert(equal(
2418                 a[],
2419                 [true, false, true, true, false, true, false, true, true]));
2420 }
2421 
2422 @system unittest
2423 {
2424     Array!bool a;
2425     a.insertBack([true, false, true, true]);
2426     a.clear();
2427     assert(a.capacity == 0);
2428 }
2429 
2430 @system unittest
2431 {
2432     Array!bool a;
2433     a.length = 1057;
2434     assert(a.length == 1057);
2435     assert(a.capacity >= a.length);
2436     foreach (e; a)
2437     {
2438         assert(!e);
2439     }
2440     immutable cap = a.capacity;
2441     a.length = 100;
2442     assert(a.length == 100);
2443     // do not realloc if length decreases
2444     assert(a.capacity == cap);
2445 }
2446 
2447 @system unittest
2448 {
2449     Array!bool a;
2450     a.length = 1057;
2451     assert(!a.removeAny());
2452     assert(a.length == 1056);
2453     foreach (e; a)
2454     {
2455         assert(!e);
2456     }
2457 }
2458 
2459 @system unittest
2460 {
2461     Array!bool a;
2462     for (int i = 0; i < 100; ++i)
2463         a.insertBack(true);
2464     foreach (e; a)
2465         assert(e);
2466 }
2467 
2468 @system unittest
2469 {
2470     Array!bool a;
2471     a.length = 1057;
2472     assert(a.removeBack(1000) == 1000);
2473     assert(a.length == 57);
2474     foreach (e; a)
2475     {
2476         assert(!e);
2477     }
2478 }
2479 
2480 @system unittest
2481 {
2482     import std.conv : to;
2483     Array!bool a;
2484     version (bugxxxx)
2485     {
2486         a._store.refCountedDebug = true;
2487     }
2488     a.insertBefore(a[], true);
2489     assert(a.length == 1, to!string(a.length));
2490     a.insertBefore(a[], false);
2491     assert(a.length == 2, to!string(a.length));
2492     a.insertBefore(a[1 .. $], true);
2493     import std.algorithm.comparison : equal;
2494     assert(a[].equal([false, true, true]));
2495 }
2496 
2497 @system unittest
2498 {
2499     import std.conv : to;
2500     Array!bool a;
2501     a.length = 10;
2502     a.insertAfter(a[0 .. 5], true);
2503     assert(a.length == 11, to!string(a.length));
2504     assert(a[5]);
2505 }
2506 @system unittest
2507 {
2508     alias V3 = int[3];
2509     V3 v = [1, 2, 3];
2510     Array!V3 arr;
2511     arr ~= v;
2512     assert(arr[0] == [1, 2, 3]);
2513 }
2514 @system unittest
2515 {
2516     alias V3 = int[3];
2517     V3[2] v = [[1, 2, 3], [4, 5, 6]];
2518     Array!V3 arr;
2519     arr ~= v;
2520     assert(arr[0] == [1, 2, 3]);
2521     assert(arr[1] == [4, 5, 6]);
2522 }
2523 
2524 // Change of length reallocates without calling GC.
2525 // https://issues.dlang.org/show_bug.cgi?id=13642
2526 @system unittest
2527 {
2528     import core.memory;
2529     class ABC { void func() { int x = 5; } }
2530 
2531     Array!ABC arr;
2532     // Length only allocates if capacity is too low.
2533     arr.reserve(4);
2534     assert(arr.capacity == 4);
2535 
2536     void func() @nogc
2537     {
2538         arr.length = 5;
2539     }
2540     func();
2541 
2542     foreach (ref b; arr) b = new ABC;
2543     GC.collect();
2544     arr[1].func();
2545 }
2546 
2547 
2548 
2549 version (D_Exceptions)
2550 {
2551     import core.exception : onOutOfMemoryError;
2552     private enum allocationFailed = `onOutOfMemoryError();`;
2553 }
2554 else
2555 {
2556     private enum allocationFailed = `assert(0, "Memory allocation failed");`;
2557 }
2558 
2559 // (below comments are non-DDOC, but are written in similar style)
2560 
2561 /+
2562 Mnemonic for `enforce!OutOfMemoryError(malloc(size))` that (unlike malloc)
2563 can be considered pure because it causes the program to abort if the result
2564 of the allocation is null, with the consequence that errno will not be
2565 visibly changed by calling this function. Note that `malloc` can also
2566 return `null` in non-failure situations if given an argument of 0. Hence,
2567 it is a programmer error to use this function if the requested allocation
2568 size is logically permitted to be zero. `enforceCalloc` and `enforceRealloc`
2569 work analogously.
2570 
2571 All these functions are usable in `betterC`.
2572 +/
2573 void* enforceMalloc()(size_t size) @nogc nothrow pure @safe
2574 {
2575     auto result = fakePureMalloc(size);
2576     if (!result) mixin(allocationFailed);
2577     return result;
2578 }
2579 
2580 // ditto
2581 void* enforceCalloc()(size_t nmemb, size_t size) @nogc nothrow pure @safe
2582 {
2583     auto result = fakePureCalloc(nmemb, size);
2584     if (!result) mixin(allocationFailed);
2585     return result;
2586 }
2587 
2588 // ditto
2589 void* enforceRealloc()(void* ptr, size_t size) @nogc nothrow pure @system
2590 {
2591     auto result = fakePureRealloc(ptr, size);
2592     if (!result) mixin(allocationFailed);
2593     return result;
2594 }
2595 
2596 // Purified for local use only.
2597 extern (C) @nogc nothrow pure private
2598 {
2599     pragma(mangle, "malloc") void* fakePureMalloc(size_t) @safe;
2600     pragma(mangle, "calloc") void* fakePureCalloc(size_t nmemb, size_t size) @safe;
2601     pragma(mangle, "realloc") void* fakePureRealloc(void* ptr, size_t size) @system;
2602 }