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