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