xref: /netbsd-src/external/gpl3/gcc/dist/libphobos/src/std/container/array.d (revision 0a3071956a3a9fdebdbf7f338cf2d439b45fc728)
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 
RangeT(A)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(cast(void*) _payload.ptr);
416 
417             free(cast(void*) _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(cast(void*) newPayload.ptr, cast(void*) _payload.ptr, T.sizeof * oldLength);
493                 // Zero out unused capacity to prevent gc from seeing false pointers
494                 memset( cast(void*) (newPayload.ptr + oldLength),
495                         0,
496                         (elements - oldLength) * T.sizeof);
497                 GC.addRange(cast(void*) newPayload.ptr, sz);
498                 GC.removeRange(cast(void*) _payload.ptr);
499                 free(cast(void*) _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     // fix https://issues.dlang.org/show_bug.cgi?23140
615     private alias Unshared(T) = T;
616     private alias Unshared(T: shared U, U) = U;
617 
618     /// ditto
619     bool opEquals(ref const Array rhs) const
620     {
621         if (empty) return rhs.empty;
622         if (rhs.empty) return false;
623 
624         return cast(Unshared!(T)[]) _data._payload ==  cast(Unshared!(T)[]) rhs._data._payload;
625     }
626 
627     /**
628      *  Defines the array's primary range, which is a random-access range.
629      *
630      *  `ConstRange` is a variant with `const` elements.
631      *  `ImmutableRange` is a variant with `immutable` elements.
632      */
633     alias Range = RangeT!Array;
634 
635     /// ditto
636     alias ConstRange = RangeT!(const Array);
637 
638     /// ditto
639     alias ImmutableRange = RangeT!(immutable Array);
640 
641     /**
642      * Duplicates the array. The elements themselves are not transitively
643      * duplicated.
644      *
645      * Complexity: $(BIGOH length).
646      */
647     @property Array dup()
648     {
649         if (!_data.refCountedStore.isInitialized) return this;
650         return Array(_data._payload);
651     }
652 
653     /**
654      * Returns: `true` if and only if the array has no elements.
655      *
656      * Complexity: $(BIGOH 1)
657      */
658     @property bool empty() const
659     {
660         return !_data.refCountedStore.isInitialized || _data._payload.empty;
661     }
662 
663     /**
664      * Returns: The number of elements in the array.
665      *
666      * Complexity: $(BIGOH 1).
667      */
668     @property size_t length() const
669     {
670         return _data.refCountedStore.isInitialized ? _data._payload.length : 0;
671     }
672 
673     /// ditto
674     size_t opDollar() const
675     {
676         return length;
677     }
678 
679     /**
680      * Returns: The maximum number of elements the array can store without
681      * reallocating memory and invalidating iterators upon insertion.
682      *
683      * Complexity: $(BIGOH 1)
684      */
685     @property size_t capacity()
686     {
687         return _data.refCountedStore.isInitialized ? _data._capacity : 0;
688     }
689 
690     /**
691      * Returns: the internal representation of the array.
692      *
693      * Complexity: $(BIGOH 1).
694      */
695 
696     inout(T)[] data() inout @system
697     {
698         return _data.refCountedStore.isInitialized ? _data._payload : [];
699     }
700 
701     /**
702      * Ensures sufficient capacity to accommodate `e` _elements.
703      * If `e < capacity`, this method does nothing.
704      *
705      * Postcondition: `capacity >= e`
706      *
707      * Note: If the capacity is increased, one should assume that all
708      * iterators to the elements are invalidated.
709      *
710      * Complexity: at most $(BIGOH length) if `e > capacity`, otherwise $(BIGOH 1).
711      */
712     void reserve(size_t elements)
713     {
714         if (elements > capacity)
715         {
716             _data.refCountedStore.ensureInitialized();
717             _data.reserve(elements);
718             assert(capacity == elements); // Might need changing to ">=" if implementation of Payload.reserve is changed.
719         }
720     }
721 
722     /**
723      * Returns: A range that iterates over elements of the array in
724      * forward order.
725      *
726      * Complexity: $(BIGOH 1)
727      */
728     Range opSlice()
729     {
730         return typeof(return)(this, 0, length);
731     }
732 
733     ConstRange opSlice() const
734     {
735         return typeof(return)(this, 0, length);
736     }
737 
738     ImmutableRange opSlice() immutable
739     {
740         return typeof(return)(this, 0, length);
741     }
742 
743     /**
744      * Returns: A range that iterates over elements of the array from
745      * index `i` up to (excluding) index `j`.
746      *
747      * Precondition: `i <= j && j <= length`
748      *
749      * Complexity: $(BIGOH 1)
750      */
751     Range opSlice(size_t i, size_t j)
752     {
753         assert(i <= j && j <= length, "Invalid slice bounds");
754         return typeof(return)(this, i, j);
755     }
756 
757     ConstRange opSlice(size_t i, size_t j) const
758     {
759         assert(i <= j && j <= length, "Invalid slice bounds");
760         return typeof(return)(this, i, j);
761     }
762 
763     ImmutableRange opSlice(size_t i, size_t j) immutable
764     {
765         assert(i <= j && j <= length, "Invalid slice bounds");
766         return typeof(return)(this, i, j);
767     }
768 
769     /**
770      * Returns: The first element of the array.
771      *
772      * Precondition: `empty == false`
773      *
774      * Complexity: $(BIGOH 1)
775      */
776     @property ref inout(T) front() inout
777     {
778         assert(_data.refCountedStore.isInitialized,
779             "Cannot get front of empty range");
780         return _data._payload[0];
781     }
782 
783     /**
784      * Returns: The last element of the array.
785      *
786      * Precondition: `empty == false`
787      *
788      * Complexity: $(BIGOH 1)
789      */
790     @property ref inout(T) back() inout
791     {
792         assert(_data.refCountedStore.isInitialized,
793             "Cannot get back of empty range");
794         return _data._payload[$ - 1];
795     }
796 
797     /**
798      * Returns: The element or a reference to the element at the specified index.
799      *
800      * Precondition: `i < length`
801      *
802      * Complexity: $(BIGOH 1)
803      */
804     ref inout(T) opIndex(size_t i) inout
805     {
806         assert(_data.refCountedStore.isInitialized,
807             "Cannot index empty range");
808         return _data._payload[i];
809     }
810 
811     /**
812      * Slicing operators executing the specified operation on the entire slice.
813      *
814      * Precondition: `i < j && j < length`
815      *
816      * Complexity: $(BIGOH slice.length)
817      */
818     void opSliceAssign(T value)
819     {
820         if (!_data.refCountedStore.isInitialized) return;
821         _data._payload[] = value;
822     }
823 
824     /// ditto
825     void opSliceAssign(T value, size_t i, size_t j)
826     {
827         auto slice = _data.refCountedStore.isInitialized ?
828             _data._payload :
829             T[].init;
830         slice[i .. j] = value;
831     }
832 
833     /// ditto
834     void opSliceUnary(string op)()
835     if (op == "++" || op == "--")
836     {
837         if (!_data.refCountedStore.isInitialized) return;
838         mixin(op~"_data._payload[];");
839     }
840 
841     /// ditto
842     void opSliceUnary(string op)(size_t i, size_t j)
843     if (op == "++" || op == "--")
844     {
845         auto slice = _data.refCountedStore.isInitialized ? _data._payload : T[].init;
846         mixin(op~"slice[i .. j];");
847     }
848 
849     /// ditto
850     void opSliceOpAssign(string op)(T value)
851     {
852         if (!_data.refCountedStore.isInitialized) return;
853         mixin("_data._payload[] "~op~"= value;");
854     }
855 
856     /// ditto
857     void opSliceOpAssign(string op)(T value, size_t i, size_t j)
858     {
859         auto slice = _data.refCountedStore.isInitialized ? _data._payload : T[].init;
860         mixin("slice[i .. j] "~op~"= value;");
861     }
862 
863     private enum hasSliceWithLength(T) = is(typeof({ T t = T.init; t[].length; }));
864 
865     /**
866      * Returns: A new array which is a concatenation of `this` and its argument.
867      *
868      * Complexity:
869      * $(BIGOH length + m), where `m` is the number of elements in `stuff`.
870      */
871     Array opBinary(string op, Stuff)(Stuff stuff)
872     if (op == "~")
873     {
874         Array result;
875 
876         static if (hasLength!Stuff || isNarrowString!Stuff)
877             result.reserve(length + stuff.length);
878         else static if (hasSliceWithLength!Stuff)
879             result.reserve(length + stuff[].length);
880         else static if (isImplicitlyConvertible!(Stuff, T))
881             result.reserve(length + 1);
882 
883         result.insertBack(this[]);
884         result ~= stuff;
885         return result;
886     }
887 
888     /**
889      * Forwards to `insertBack`.
890      */
891     void opOpAssign(string op, Stuff)(auto ref Stuff stuff)
892     if (op == "~")
893     {
894         static if (is(typeof(stuff[])) && isImplicitlyConvertible!(typeof(stuff[0]), T))
895         {
896             insertBack(stuff[]);
897         }
898         else
899         {
900             insertBack(stuff);
901         }
902     }
903 
904     /**
905      * Removes all the elements from the array and releases allocated memory.
906      *
907      * Postcondition: `empty == true && capacity == 0`
908      *
909      * Complexity: $(BIGOH length)
910      */
911     void clear()
912     {
913         _data = Data.init;
914     }
915 
916     /**
917      * Sets the number of elements in the array to `newLength`. If `newLength`
918      * is greater than `length`, the new elements are added to the end of the
919      * array and initialized with `T.init`. If `T` is a `struct` whose default
920      * constructor is annotated with `@disable`, `newLength` must be lower than
921      * or equal to `length`.
922      *
923      * Complexity:
924      * Guaranteed $(BIGOH abs(length - newLength)) if `capacity >= newLength`.
925      * If `capacity < newLength` the worst case is $(BIGOH newLength).
926      *
927      * Precondition: `__traits(compiles, { static T _; }) || newLength <= length`
928      *
929      * Postcondition: `length == newLength`
930      */
931     @property void length(size_t newLength)
932     {
933         _data.refCountedStore.ensureInitialized();
934         _data.length = newLength;
935     }
936 
937     /**
938      * Removes the last element from the array and returns it.
939      * Both stable and non-stable versions behave the same and guarantee
940      * that ranges iterating over the array are never invalidated.
941      *
942      * Precondition: `empty == false`
943      *
944      * Returns: The element removed.
945      *
946      * Complexity: $(BIGOH 1).
947      *
948      * Throws: `Exception` if the array is empty.
949      */
950     T removeAny()
951     {
952         auto result = back;
953         removeBack();
954         return result;
955     }
956 
957     /// ditto
958     alias stableRemoveAny = removeAny;
959 
960     /**
961      * Inserts the specified elements at the back of the array. `stuff` can be
962      * a value convertible to `T` or a range of objects convertible to `T`.
963      *
964      * Returns: The number of elements inserted.
965      *
966      * Complexity:
967      * $(BIGOH length + m) if reallocation takes place, otherwise $(BIGOH m),
968      * where `m` is the number of elements in `stuff`.
969      */
970     size_t insertBack(Stuff)(Stuff stuff)
971     if (isImplicitlyConvertible!(Stuff, T) ||
972             isInputRange!Stuff && isImplicitlyConvertible!(ElementType!Stuff, T))
973     {
974         _data.refCountedStore.ensureInitialized();
975         return _data.insertBack(stuff);
976     }
977 
978     /// ditto
979     alias insert = insertBack;
980 
981     /**
982      * Removes the value from the back of the array. Both stable and non-stable
983      * versions behave the same and guarantee that ranges iterating over the
984      * array are never invalidated.
985      *
986      * Precondition: `empty == false`
987      *
988      * Complexity: $(BIGOH 1).
989      *
990      * Throws: `Exception` if the array is empty.
991      */
992     void removeBack()
993     {
994         enforce(!empty);
995         static if (hasElaborateDestructor!T)
996             .destroy(_data._payload[$ - 1]);
997 
998         _data._payload = _data._payload[0 .. $ - 1];
999     }
1000 
1001     /// ditto
1002     alias stableRemoveBack = removeBack;
1003 
1004     /**
1005      * Removes `howMany` values from the back of the array.
1006      * Unlike the unparameterized versions above, these functions
1007      * do not throw if they could not remove `howMany` elements. Instead,
1008      * if `howMany > n`, all elements are removed. The returned value is
1009      * the effective number of elements removed. Both stable and non-stable
1010      * versions behave the same and guarantee that ranges iterating over
1011      * the array are never invalidated.
1012      *
1013      * Returns: The number of elements removed.
1014      *
1015      * Complexity: $(BIGOH howMany).
1016      */
1017     size_t removeBack(size_t howMany)
1018     {
1019         if (howMany > length) howMany = length;
1020         static if (hasElaborateDestructor!T)
1021             foreach (ref e; _data._payload[$ - howMany .. $])
1022                 .destroy(e);
1023 
1024         _data._payload = _data._payload[0 .. $ - howMany];
1025         return howMany;
1026     }
1027 
1028     /// ditto
1029     alias stableRemoveBack = removeBack;
1030 
1031     /**
1032      * Inserts `stuff` before, after, or instead range `r`, which must
1033      * be a valid range previously extracted from this array. `stuff`
1034      * can be a value convertible to `T` or a range of objects convertible
1035      * to `T`. Both stable and non-stable version behave the same and
1036      * guarantee that ranges iterating over the array are never invalidated.
1037      *
1038      * Returns: The number of values inserted.
1039      *
1040      * Complexity: $(BIGOH length + m), where `m` is the length of `stuff`.
1041      *
1042      * Throws: `Exception` if `r` is not a range extracted from this array.
1043      */
1044     size_t insertBefore(Stuff)(Range r, Stuff stuff)
1045     if (isImplicitlyConvertible!(Stuff, T))
1046     {
1047         import core.lifetime : emplace;
1048         enforce(r._outer._data is _data && r._a <= length);
1049         reserve(length + 1);
1050         assert(_data.refCountedStore.isInitialized,
1051             "Failed to allocate capacity to insertBefore");
1052         // Move elements over by one slot
1053         memmove(_data._payload.ptr + r._a + 1,
1054                 _data._payload.ptr + r._a,
1055                 T.sizeof * (length - r._a));
1056         emplace(_data._payload.ptr + r._a, stuff);
1057         _data._payload = _data._payload.ptr[0 .. _data._payload.length + 1];
1058         return 1;
1059     }
1060 
1061     /// ditto
1062     size_t insertBefore(Stuff)(Range r, Stuff stuff)
1063     if (isInputRange!Stuff && isImplicitlyConvertible!(ElementType!Stuff, T))
1064     {
1065         import core.lifetime : emplace;
1066         enforce(r._outer._data is _data && r._a <= length);
1067         static if (isForwardRange!Stuff)
1068         {
1069             // Can find the length in advance
1070             auto extra = walkLength(stuff);
1071             if (!extra) return 0;
1072             reserve(length + extra);
1073             assert(_data.refCountedStore.isInitialized,
1074                 "Failed to allocate capacity to insertBefore");
1075             // Move elements over by extra slots
1076             memmove(_data._payload.ptr + r._a + extra,
1077                     _data._payload.ptr + r._a,
1078                     T.sizeof * (length - r._a));
1079             foreach (p; _data._payload.ptr + r._a ..
1080                     _data._payload.ptr + r._a + extra)
1081             {
1082                 emplace(p, stuff.front);
1083                 stuff.popFront();
1084             }
1085             _data._payload =
1086                 _data._payload.ptr[0 .. _data._payload.length + extra];
1087             return extra;
1088         }
1089         else
1090         {
1091             import std.algorithm.mutation : bringToFront;
1092             enforce(_data);
1093             immutable offset = r._a;
1094             enforce(offset <= length);
1095             auto result = insertBack(stuff);
1096             bringToFront(this[offset .. length - result],
1097                     this[length - result .. length]);
1098             return result;
1099         }
1100     }
1101 
1102     /// ditto
1103     alias stableInsertBefore = insertBefore;
1104 
1105     /// ditto
1106     size_t insertAfter(Stuff)(Range r, Stuff stuff)
1107     if (isImplicitlyConvertible!(Stuff, T) ||
1108             isInputRange!Stuff && isImplicitlyConvertible!(ElementType!Stuff, T))
1109     {
1110         import std.algorithm.mutation : bringToFront;
1111         enforce(r._outer._data is _data);
1112         // TODO: optimize
1113         immutable offset = r._b;
1114         enforce(offset <= length);
1115         auto result = insertBack(stuff);
1116         bringToFront(this[offset .. length - result],
1117                 this[length - result .. length]);
1118         return result;
1119     }
1120 
1121     /// ditto
1122     size_t replace(Stuff)(Range r, Stuff stuff)
1123     if (isInputRange!Stuff && isImplicitlyConvertible!(ElementType!Stuff, T))
1124     {
1125         enforce(r._outer._data is _data);
1126         size_t result;
1127         for (; !stuff.empty; stuff.popFront())
1128         {
1129             if (r.empty)
1130             {
1131                 // insert the rest
1132                 return result + insertBefore(r, stuff);
1133             }
1134             r.front = stuff.front;
1135             r.popFront();
1136             ++result;
1137         }
1138         // Remove remaining stuff in r
1139         linearRemove(r);
1140         return result;
1141     }
1142 
1143     /// ditto
1144     size_t replace(Stuff)(Range r, Stuff stuff)
1145     if (isImplicitlyConvertible!(Stuff, T))
1146     {
1147         enforce(r._outer._data is _data);
1148         if (r.empty)
1149         {
1150             insertBefore(r, stuff);
1151         }
1152         else
1153         {
1154             r.front = stuff;
1155             r.popFront();
1156             linearRemove(r);
1157         }
1158         return 1;
1159     }
1160 
1161     /**
1162      * Removes all elements belonging to `r`, which must be a range
1163      * obtained originally from this array.
1164      *
1165      * Returns: A range spanning the remaining elements in the array that
1166      * initially were right after `r`.
1167      *
1168      * Complexity: $(BIGOH length)
1169      *
1170      * Throws: `Exception` if `r` is not a valid range extracted from this array.
1171      */
1172     Range linearRemove(Range r)
1173     {
1174         import std.algorithm.mutation : copy;
1175 
1176         enforce(r._outer._data is _data);
1177         enforce(_data.refCountedStore.isInitialized);
1178         enforce(r._a <= r._b && r._b <= length);
1179         immutable offset1 = r._a;
1180         immutable offset2 = r._b;
1181         immutable tailLength = length - offset2;
1182         // Use copy here, not a[] = b[] because the ranges may overlap
1183         copy(this[offset2 .. length], this[offset1 .. offset1 + tailLength]);
1184         length = offset1 + tailLength;
1185         return this[length - tailLength .. length];
1186     }
1187 }
1188 
1189 @system unittest
1190 {
1191     Array!int a;
1192     assert(a.empty);
1193 }
1194 
1195 @system unittest
1196 {
1197     Array!int a;
1198     a.length = 10;
1199     assert(a.length == 10);
1200     assert(a.capacity >= a.length);
1201 }
1202 
1203 @system unittest
1204 {
1205     struct Dumb { int x = 5; }
1206     Array!Dumb a;
1207     a.length = 10;
1208     assert(a.length == 10);
1209     assert(a.capacity >= a.length);
1210     immutable cap = a.capacity;
1211     foreach (ref e; a)
1212         e.x = 10;
1213     a.length = 5;
1214     assert(a.length == 5);
1215     // do not realloc if length decreases
1216     assert(a.capacity == cap);
1217     foreach (ref e; a)
1218         assert(e.x == 10);
1219 
1220     a.length = 8;
1221     assert(a.length == 8);
1222     // do not realloc if capacity sufficient
1223     assert(a.capacity == cap);
1224     assert(Dumb.init.x == 5);
1225     foreach (i; 0 .. 5)
1226         assert(a[i].x == 10);
1227     foreach (i; 5 .. a.length)
1228         assert(a[i].x == Dumb.init.x);
1229 
1230     // realloc required, check if values properly copied
1231     a[] = Dumb(1);
1232     a.length = 20;
1233     assert(a.capacity >= 20);
1234     foreach (i; 0 .. 8)
1235         assert(a[i].x == 1);
1236     foreach (i; 8 .. a.length)
1237         assert(a[i].x == Dumb.init.x);
1238 
1239     // check if overlapping elements properly initialized
1240     a.length = 1;
1241     a.length = 20;
1242     assert(a[0].x == 1);
1243     foreach (e; a[1 .. $])
1244         assert(e.x == Dumb.init.x);
1245 }
1246 
1247 @system unittest
1248 {
1249     Array!int a = Array!int(1, 2, 3);
1250     //a._data._refCountedDebug = true;
1251     auto b = a.dup;
1252     assert(b == Array!int(1, 2, 3));
1253     b.front = 42;
1254     assert(b == Array!int(42, 2, 3));
1255     assert(a == Array!int(1, 2, 3));
1256 }
1257 
1258 @system unittest
1259 {
1260     auto a = Array!int(1, 2, 3);
1261     assert(a.length == 3);
1262 }
1263 
1264 @system unittest
1265 {
1266     const Array!int a = [1, 2];
1267 
1268     assert(a[0] == 1);
1269     assert(a.front == 1);
1270     assert(a.back == 2);
1271 
1272     static assert(!__traits(compiles, { a[0] = 1; }));
1273     static assert(!__traits(compiles, { a.front = 1; }));
1274     static assert(!__traits(compiles, { a.back = 1; }));
1275 
1276     auto r = a[];
1277     size_t i;
1278     foreach (e; r)
1279     {
1280         assert(e == i + 1);
1281         i++;
1282     }
1283 }
1284 
1285 @safe unittest
1286 {
1287     // https://issues.dlang.org/show_bug.cgi?id=13621
1288     import std.container : Array, BinaryHeap;
1289     alias Heap = BinaryHeap!(Array!int);
1290 }
1291 
1292 @system unittest
1293 {
1294     // https://issues.dlang.org/show_bug.cgi?id=18800
1295     static struct S { void* p; }
1296     Array!S a;
1297     a.length = 10;
1298 }
1299 
1300 @system unittest
1301 {
1302     Array!int a;
1303     a.reserve(1000);
1304     assert(a.length == 0);
1305     assert(a.empty);
1306     assert(a.capacity >= 1000);
1307     auto p = a._data._payload.ptr;
1308     foreach (i; 0 .. 1000)
1309     {
1310         a.insertBack(i);
1311     }
1312     assert(p == a._data._payload.ptr);
1313 }
1314 
1315 @system unittest
1316 {
1317     auto a = Array!int(1, 2, 3);
1318     a[1] *= 42;
1319     assert(a[1] == 84);
1320 }
1321 
1322 @system unittest
1323 {
1324     auto a = Array!int(1, 2, 3);
1325     auto b = Array!int(11, 12, 13);
1326     auto c = a ~ b;
1327     assert(c == Array!int(1, 2, 3, 11, 12, 13));
1328     assert(a ~ b[] == Array!int(1, 2, 3, 11, 12, 13));
1329     assert(a ~ [4,5] == Array!int(1,2,3,4,5));
1330 }
1331 
1332 @system unittest
1333 {
1334     auto a = Array!int(1, 2, 3);
1335     auto b = Array!int(11, 12, 13);
1336     a ~= b;
1337     assert(a == Array!int(1, 2, 3, 11, 12, 13));
1338 }
1339 
1340 @system unittest
1341 {
1342     auto a = Array!int(1, 2, 3, 4);
1343     assert(a.removeAny() == 4);
1344     assert(a == Array!int(1, 2, 3));
1345 }
1346 
1347 @system unittest
1348 {
1349     auto a = Array!int(1, 2, 3, 4, 5);
1350     auto r = a[2 .. a.length];
1351     assert(a.insertBefore(r, 42) == 1);
1352     assert(a == Array!int(1, 2, 42, 3, 4, 5));
1353     r = a[2 .. 2];
1354     assert(a.insertBefore(r, [8, 9]) == 2);
1355     assert(a == Array!int(1, 2, 8, 9, 42, 3, 4, 5));
1356 }
1357 
1358 @system unittest
1359 {
1360     auto a = Array!int(0, 1, 2, 3, 4, 5, 6, 7, 8);
1361     a.linearRemove(a[4 .. 6]);
1362     assert(a == Array!int(0, 1, 2, 3, 6, 7, 8));
1363 }
1364 
1365 // Give the Range object some testing.
1366 @system unittest
1367 {
1368     import std.algorithm.comparison : equal;
1369     import std.range : retro;
1370     auto a = Array!int(0, 1, 2, 3, 4, 5, 6)[];
1371     auto b = Array!int(6, 5, 4, 3, 2, 1, 0)[];
1372     alias A = typeof(a);
1373 
1374     static assert(isRandomAccessRange!A);
1375     static assert(hasSlicing!A);
1376     static assert(hasAssignableElements!A);
1377     static assert(hasMobileElements!A);
1378 
1379     assert(equal(retro(b), a));
1380     assert(a.length == 7);
1381     assert(equal(a[1 .. 4], [1, 2, 3]));
1382 }
1383 
1384 // https://issues.dlang.org/show_bug.cgi?id=5920
1385 @system unittest
1386 {
1387     struct structBug5920
1388     {
1389         int order;
1390         uint* pDestructionMask;
1391         ~this()
1392         {
1393             if (pDestructionMask)
1394                 *pDestructionMask += 1 << order;
1395         }
1396     }
1397 
1398     alias S = structBug5920;
1399     uint dMask;
1400 
1401     auto arr = Array!S(cast(S[])[]);
1402     foreach (i; 0 .. 8)
1403         arr.insertBack(S(i, &dMask));
1404     // don't check dMask now as S may be copied multiple times (it's ok?)
1405     {
1406         assert(arr.length == 8);
1407         dMask = 0;
1408         arr.length = 6;
1409         assert(arr.length == 6);    // make sure shrinking calls the d'tor
1410         assert(dMask == 0b1100_0000);
1411         arr.removeBack();
1412         assert(arr.length == 5);    // make sure removeBack() calls the d'tor
1413         assert(dMask == 0b1110_0000);
1414         arr.removeBack(3);
1415         assert(arr.length == 2);    // ditto
1416         assert(dMask == 0b1111_1100);
1417         arr.clear();
1418         assert(arr.length == 0);    // make sure clear() calls the d'tor
1419         assert(dMask == 0b1111_1111);
1420     }
1421     assert(dMask == 0b1111_1111);   // make sure the d'tor is called once only.
1422 }
1423 
1424 // Test for https://issues.dlang.org/show_bug.cgi?id=5792
1425 // (mainly just to check if this piece of code is compilable)
1426 @system unittest
1427 {
1428     auto a = Array!(int[])([[1,2],[3,4]]);
1429     a.reserve(4);
1430     assert(a.capacity >= 4);
1431     assert(a.length == 2);
1432     assert(a[0] == [1,2]);
1433     assert(a[1] == [3,4]);
1434     a.reserve(16);
1435     assert(a.capacity >= 16);
1436     assert(a.length == 2);
1437     assert(a[0] == [1,2]);
1438     assert(a[1] == [3,4]);
1439 }
1440 
1441 // test replace!Stuff with range Stuff
1442 @system unittest
1443 {
1444     import std.algorithm.comparison : equal;
1445     auto a = Array!int([1, 42, 5]);
1446     a.replace(a[1 .. 2], [2, 3, 4]);
1447     assert(equal(a[], [1, 2, 3, 4, 5]));
1448 }
1449 
1450 // test insertBefore and replace with empty Arrays
1451 @system unittest
1452 {
1453     import std.algorithm.comparison : equal;
1454     auto a = Array!int();
1455     a.insertBefore(a[], 1);
1456     assert(equal(a[], [1]));
1457 }
1458 @system unittest
1459 {
1460     import std.algorithm.comparison : equal;
1461     auto a = Array!int();
1462     a.insertBefore(a[], [1, 2]);
1463     assert(equal(a[], [1, 2]));
1464 }
1465 @system unittest
1466 {
1467     import std.algorithm.comparison : equal;
1468     auto a = Array!int();
1469     a.replace(a[], [1, 2]);
1470     assert(equal(a[], [1, 2]));
1471 }
1472 @system unittest
1473 {
1474     import std.algorithm.comparison : equal;
1475     auto a = Array!int();
1476     a.replace(a[], 1);
1477     assert(equal(a[], [1]));
1478 }
1479 // make sure that Array instances refuse ranges that don't belong to them
1480 @system unittest
1481 {
1482     import std.exception : assertThrown;
1483 
1484     Array!int a = [1, 2, 3];
1485     auto r = a.dup[];
1486     assertThrown(a.insertBefore(r, 42));
1487     assertThrown(a.insertBefore(r, [42]));
1488     assertThrown(a.insertAfter(r, 42));
1489     assertThrown(a.replace(r, 42));
1490     assertThrown(a.replace(r, [42]));
1491     assertThrown(a.linearRemove(r));
1492 }
1493 @system unittest
1494 {
1495     auto a = Array!int([1, 1]);
1496     a[1]  = 0; //Check Array.opIndexAssign
1497     assert(a[1] == 0);
1498     a[1] += 1; //Check Array.opIndexOpAssign
1499     assert(a[1] == 1);
1500 
1501     //Check Array.opIndexUnary
1502     ++a[0];
1503     //a[0]++ //op++ doesn't return, so this shouldn't work, even with 5044 fixed
1504     assert(a[0] == 2);
1505     assert(+a[0] == +2);
1506     assert(-a[0] == -2);
1507     assert(~a[0] == ~2);
1508 
1509     auto r = a[];
1510     r[1]  = 0; //Check Array.Range.opIndexAssign
1511     assert(r[1] == 0);
1512     r[1] += 1; //Check Array.Range.opIndexOpAssign
1513     assert(r[1] == 1);
1514 
1515     //Check Array.Range.opIndexUnary
1516     ++r[0];
1517     //r[0]++ //op++ doesn't return, so this shouldn't work, even with 5044 fixed
1518     assert(r[0] == 3);
1519     assert(+r[0] == +3);
1520     assert(-r[0] == -3);
1521     assert(~r[0] == ~3);
1522 }
1523 
1524 @system unittest
1525 {
1526     import std.algorithm.comparison : equal;
1527 
1528     //Test "array-wide" operations
1529     auto a = Array!int([0, 1, 2]); //Array
1530     a[] += 5;
1531     assert(a[].equal([5, 6, 7]));
1532     ++a[];
1533     assert(a[].equal([6, 7, 8]));
1534     a[1 .. 3] *= 5;
1535     assert(a[].equal([6, 35, 40]));
1536     a[0 .. 2] = 0;
1537     assert(a[].equal([0, 0, 40]));
1538 
1539     //Test empty array
1540     auto a2 = Array!int.init;
1541     ++a2[];
1542     ++a2[0 .. 0];
1543     a2[] = 0;
1544     a2[0 .. 0] = 0;
1545     a2[] += 0;
1546     a2[0 .. 0] += 0;
1547 
1548     //Test "range-wide" operations
1549     auto r = Array!int([0, 1, 2])[]; //Array.Range
1550     r[] += 5;
1551     assert(r.equal([5, 6, 7]));
1552     ++r[];
1553     assert(r.equal([6, 7, 8]));
1554     r[1 .. 3] *= 5;
1555     assert(r.equal([6, 35, 40]));
1556     r[0 .. 2] = 0;
1557     assert(r.equal([0, 0, 40]));
1558 
1559     //Test empty Range
1560     auto r2 = Array!int.init[];
1561     ++r2[];
1562     ++r2[0 .. 0];
1563     r2[] = 0;
1564     r2[0 .. 0] = 0;
1565     r2[] += 0;
1566     r2[0 .. 0] += 0;
1567 }
1568 
1569 // Test issue 11194
1570 @system unittest
1571 {
1572     static struct S {
1573         int i = 1337;
1574         void* p;
1575         this(this) { assert(i == 1337); }
1576         ~this() { assert(i == 1337); }
1577     }
1578     Array!S arr;
1579     S s;
1580     arr ~= s;
1581     arr ~= s;
1582 }
1583 
1584 // https://issues.dlang.org/show_bug.cgi?id=11459
1585 @safe unittest
1586 {
1587     static struct S
1588     {
1589         bool b;
1590         alias b this;
1591     }
1592     alias A = Array!S;
1593     alias B = Array!(shared bool);
1594 }
1595 
1596 // https://issues.dlang.org/show_bug.cgi?id=11884
1597 @system unittest
1598 {
1599     import std.algorithm.iteration : filter;
1600     auto a = Array!int([1, 2, 2].filter!"true"());
1601 }
1602 
1603 // https://issues.dlang.org/show_bug.cgi?id=8282
1604 @safe unittest
1605 {
1606     auto arr = new Array!int;
1607 }
1608 
1609 // https://issues.dlang.org/show_bug.cgi?id=6998
1610 @system unittest
1611 {
1612     static int i = 0;
1613     class C
1614     {
1615         int dummy = 1;
1616         this(){++i;}
1617         ~this(){--i;}
1618     }
1619 
1620     assert(i == 0);
1621     auto c = new C();
1622     assert(i == 1);
1623 
1624     //scope
1625     {
1626         auto arr = Array!C(c);
1627         assert(i == 1);
1628     }
1629     //Array should not have destroyed the class instance
1630     assert(i == 1);
1631 
1632     //Just to make sure the GC doesn't collect before the above test.
1633     assert(c.dummy == 1);
1634 }
1635 
1636 //https://issues.dlang.org/show_bug.cgi?id=6998 (2)
1637 @system unittest
1638 {
1639     static class C {int i;}
1640     auto c = new C;
1641     c.i = 42;
1642     Array!C a;
1643     a ~= c;
1644     a.clear;
1645     assert(c.i == 42); //fails
1646 }
1647 
1648 @safe unittest
1649 {
1650     static assert(is(Array!int.Range));
1651     static assert(is(Array!int.ConstRange));
1652 }
1653 
1654 @system unittest // const/immutable Array and Ranges
1655 {
1656     static void test(A, R, E, S)()
1657     {
1658         A a;
1659         R r = a[];
1660         assert(r.empty);
1661         assert(r.length == 0);
1662         static assert(is(typeof(r.front) == E));
1663         static assert(is(typeof(r.back) == E));
1664         static assert(is(typeof(r[0]) == E));
1665         static assert(is(typeof(r[]) == S));
1666         static assert(is(typeof(r[0 .. 0]) == S));
1667     }
1668 
1669     alias A = Array!int;
1670 
1671     test!(A, A.Range, int, A.Range);
1672     test!(A, const A.Range, const int, A.ConstRange);
1673 
1674     test!(const A, A.ConstRange, const int, A.ConstRange);
1675     test!(const A, const A.ConstRange, const int, A.ConstRange);
1676 
1677     test!(immutable A, A.ImmutableRange, immutable int, A.ImmutableRange);
1678     test!(immutable A, const A.ImmutableRange, immutable int, A.ImmutableRange);
1679     test!(immutable A, immutable A.ImmutableRange, immutable int,
1680         A.ImmutableRange);
1681 }
1682 
1683 // ensure @nogc
1684 @nogc @system unittest
1685 {
1686     Array!int ai;
1687     ai ~= 1;
1688     assert(ai.front == 1);
1689 
1690     ai.reserve(10);
1691     assert(ai.capacity == 10);
1692 
1693     static immutable arr = [1, 2, 3];
1694     ai.insertBack(arr);
1695 }
1696 
1697 /*
1698  * typeof may give wrong result in case of classes defining `opCall` operator
1699  * https://issues.dlang.org/show_bug.cgi?id=20589
1700  *
1701  * destructor std.container.array.Array!(MyClass).Array.~this is @system
1702  * so the unittest is @system too
1703  */
1704 @system unittest
1705 {
1706     class MyClass
1707     {
1708         T opCall(T)(T p)
1709         {
1710             return p;
1711         }
1712     }
1713 
1714     Array!MyClass arr;
1715 }
1716 
1717 @system unittest
1718 {
1719     import std.algorithm.comparison : equal;
1720     auto a = Array!int([1,2,3,4,5]);
1721     assert(a.length == 5);
1722 
1723     assert(a.insertAfter(a[0 .. 5], [7, 8]) == 2);
1724     assert(equal(a[], [1,2,3,4,5,7,8]));
1725 
1726     assert(a.insertAfter(a[0 .. 5], 6) == 1);
1727     assert(equal(a[], [1,2,3,4,5,6,7,8]));
1728 }
1729 
1730 // https://issues.dlang.org/show_bug.cgi?id=22105
1731 @system unittest
1732 {
1733     import core.exception : AssertError;
1734     import std.exception : assertThrown, assertNotThrown;
1735 
1736     struct NoDefaultCtor
1737     {
1738         int i;
1739         @disable this();
1740         this(int j) { i = j; }
1741     }
1742 
1743     auto array = Array!NoDefaultCtor([NoDefaultCtor(1), NoDefaultCtor(2)]);
1744     assertNotThrown!AssertError(array.length = 1);
1745     assertThrown!AssertError(array.length = 5);
1746 }
1747 
1748 // https://issues.dlang.org/show_bug.cgi?id=23140
1749 @system unittest
1750 {
1751     shared class C
1752     {
1753     }
1754 
1755     Array!C ac;
1756     ac = Array!C([new C]);
1757 }
1758 ////////////////////////////////////////////////////////////////////////////////
1759 // Array!bool
1760 ////////////////////////////////////////////////////////////////////////////////
1761 
1762 /**
1763  * _Array specialized for `bool`. Packs together values efficiently by
1764  * allocating one bit per element.
1765  */
1766 struct Array(T)
1767 if (is(immutable T == immutable bool))
1768 {
1769     import std.exception : enforce;
1770     import std.typecons : RefCounted, RefCountedAutoInitialize;
1771 
1772     static immutable uint bitsPerWord = size_t.sizeof * 8;
1773     private static struct Data
1774     {
1775         Array!size_t.Payload _backend;
1776         size_t _length;
1777     }
1778     private RefCounted!(Data, RefCountedAutoInitialize.no) _store;
1779 
1780     private @property ref size_t[] data()
1781     {
1782         assert(_store.refCountedStore.isInitialized,
1783             "Cannot get data of uninitialized Array");
1784         return _store._backend._payload;
1785     }
1786 
1787     /**
1788      * Defines the array's primary range.
1789      */
1790     struct Range
1791     {
1792         private Array _outer;
1793         private size_t _a, _b;
1794         /// Range primitives
1795         @property Range save()
1796         {
1797             version (bug4437)
1798             {
1799                 return this;
1800             }
1801             else
1802             {
1803                 auto copy = this;
1804                 return copy;
1805             }
1806         }
1807         /// Ditto
1808         @property bool empty()
1809         {
1810             return _a >= _b || _outer.length < _b;
1811         }
1812         /// Ditto
1813         @property T front()
1814         {
1815             enforce(!empty, "Attempting to access the front of an empty Array");
1816             return _outer[_a];
1817         }
1818         /// Ditto
1819         @property void front(bool value)
1820         {
1821             enforce(!empty, "Attempting to set the front of an empty Array");
1822             _outer[_a] = value;
1823         }
1824         /// Ditto
1825         T moveFront()
1826         {
1827             enforce(!empty, "Attempting to move the front of an empty Array");
1828             return _outer.moveAt(_a);
1829         }
1830         /// Ditto
1831         void popFront()
1832         {
1833             enforce(!empty, "Attempting to popFront an empty Array");
1834             ++_a;
1835         }
1836         /// Ditto
1837         @property T back()
1838         {
1839             enforce(!empty, "Attempting to access the back of an empty Array");
1840             return _outer[_b - 1];
1841         }
1842         /// Ditto
1843         @property void back(bool value)
1844         {
1845             enforce(!empty, "Attempting to set the back of an empty Array");
1846             _outer[_b - 1] = value;
1847         }
1848         /// Ditto
1849         T moveBack()
1850         {
1851             enforce(!empty, "Attempting to move the back of an empty Array");
1852             return _outer.moveAt(_b - 1);
1853         }
1854         /// Ditto
1855         void popBack()
1856         {
1857             enforce(!empty, "Attempting to popBack an empty Array");
1858             --_b;
1859         }
1860         /// Ditto
1861         T opIndex(size_t i)
1862         {
1863             return _outer[_a + i];
1864         }
1865         /// Ditto
1866         void opIndexAssign(T value, size_t i)
1867         {
1868             _outer[_a + i] = value;
1869         }
1870         /// Ditto
1871         T moveAt(size_t i)
1872         {
1873             return _outer.moveAt(_a + i);
1874         }
1875         /// Ditto
1876         @property size_t length() const
1877         {
1878             assert(_a <= _b, "Invalid bounds");
1879             return _b - _a;
1880         }
1881         alias opDollar = length;
1882         /// ditto
1883         Range opSlice(size_t low, size_t high)
1884         {
1885             // Note: indexes start at 0, which is equivalent to _a
1886             assert(
1887                 low <= high && high <= (_b - _a),
1888                 "Using out of bounds indexes on an Array"
1889             );
1890             return Range(_outer, _a + low, _a + high);
1891         }
1892     }
1893 
1894     /**
1895      * Constructor taking a number of items.
1896      */
1897     this(U)(U[] values...)
1898     if (isImplicitlyConvertible!(U, T))
1899     {
1900         reserve(values.length);
1901         foreach (i, v; values)
1902         {
1903             auto rem = i % bitsPerWord;
1904             if (rem)
1905             {
1906                 // Fits within the current array
1907                 if (v)
1908                 {
1909                     data[$ - 1] |= (cast(size_t) 1 << rem);
1910                 }
1911                 else
1912                 {
1913                     data[$ - 1] &= ~(cast(size_t) 1 << rem);
1914                 }
1915             }
1916             else
1917             {
1918                 // Need to add more data
1919                 _store._backend.insertBack(v);
1920             }
1921         }
1922         _store._length = values.length;
1923     }
1924 
1925     /**
1926      * Constructor taking an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
1927      */
1928     this(Range)(Range r)
1929     if (isInputRange!Range && isImplicitlyConvertible!(ElementType!Range, T) && !is(Range == T[]))
1930     {
1931         insertBack(r);
1932     }
1933 
1934     /**
1935      * Property returning `true` if and only if the array has
1936      * no elements.
1937      *
1938      * Complexity: $(BIGOH 1)
1939      */
1940     @property bool empty()
1941     {
1942         return !length;
1943     }
1944 
1945     /**
1946      * Returns: A duplicate of the array.
1947      *
1948      * Complexity: $(BIGOH length).
1949      */
1950     @property Array dup()
1951     {
1952         Array result;
1953         result.insertBack(this[]);
1954         return result;
1955     }
1956 
1957     /**
1958      * Returns the number of elements in the array.
1959      *
1960      * Complexity: $(BIGOH 1).
1961      */
1962     @property size_t length() const
1963     {
1964         return _store.refCountedStore.isInitialized ? _store._length : 0;
1965     }
1966     alias opDollar = length;
1967 
1968     /**
1969      * Returns: The maximum number of elements the array can store without
1970      * reallocating memory and invalidating iterators upon insertion.
1971      *
1972      * Complexity: $(BIGOH 1).
1973      */
1974     @property size_t capacity()
1975     {
1976         return _store.refCountedStore.isInitialized
1977             ? cast(size_t) bitsPerWord * _store._backend.capacity
1978             : 0;
1979     }
1980 
1981     /**
1982      * Ensures sufficient capacity to accommodate `e` _elements.
1983      * If `e < capacity`, this method does nothing.
1984      *
1985      * Postcondition: `capacity >= e`
1986      *
1987      * Note: If the capacity is increased, one should assume that all
1988      * iterators to the elements are invalidated.
1989      *
1990      * Complexity: at most $(BIGOH length) if `e > capacity`, otherwise $(BIGOH 1).
1991      */
1992     void reserve(size_t e)
1993     {
1994         import std.conv : to;
1995         _store.refCountedStore.ensureInitialized();
1996         _store._backend.reserve(to!size_t((e + bitsPerWord - 1) / bitsPerWord));
1997     }
1998 
1999     /**
2000      * Returns: A range that iterates over all elements of the array in forward order.
2001      *
2002      * Complexity: $(BIGOH 1)
2003      */
2004     Range opSlice()
2005     {
2006         return Range(this, 0, length);
2007     }
2008 
2009 
2010     /**
2011      * Returns: A range that iterates the array between two specified positions.
2012      *
2013      * Complexity: $(BIGOH 1)
2014      */
2015     Range opSlice(size_t a, size_t b)
2016     {
2017         enforce(a <= b && b <= length);
2018         return Range(this, a, b);
2019     }
2020 
2021     /**
2022      * Returns: The first element of the array.
2023      *
2024      * Precondition: `empty == false`
2025      *
2026      * Complexity: $(BIGOH 1)
2027      *
2028      * Throws: `Exception` if the array is empty.
2029      */
2030     @property bool front()
2031     {
2032         enforce(!empty);
2033         return data.ptr[0] & 1;
2034     }
2035 
2036     /// Ditto
2037     @property void front(bool value)
2038     {
2039         enforce(!empty);
2040         if (value) data.ptr[0] |= 1;
2041         else data.ptr[0] &= ~cast(size_t) 1;
2042     }
2043 
2044     /**
2045      * Returns: The last element of the array.
2046      *
2047      * Precondition: `empty == false`
2048      *
2049      * Complexity: $(BIGOH 1)
2050      *
2051      * Throws: `Exception` if the array is empty.
2052      */
2053     @property bool back()
2054     {
2055         enforce(!empty);
2056         return cast(bool)(data.back & (cast(size_t) 1 << ((_store._length - 1) % bitsPerWord)));
2057     }
2058 
2059     /// Ditto
2060     @property void back(bool value)
2061     {
2062         enforce(!empty);
2063         if (value)
2064         {
2065             data.back |= (cast(size_t) 1 << ((_store._length - 1) % bitsPerWord));
2066         }
2067         else
2068         {
2069             data.back &=
2070                 ~(cast(size_t) 1 << ((_store._length - 1) % bitsPerWord));
2071         }
2072     }
2073 
2074     /**
2075      * Indexing operators yielding or modifyng the value at the specified index.
2076      *
2077      * Precondition: `i < length`
2078      *
2079      * Complexity: $(BIGOH 1)
2080      */
2081     bool opIndex(size_t i)
2082     {
2083         auto div = cast(size_t) (i / bitsPerWord);
2084         auto rem = i % bitsPerWord;
2085         enforce(div < data.length);
2086         return cast(bool)(data.ptr[div] & (cast(size_t) 1 << rem));
2087     }
2088 
2089     /// ditto
2090     void opIndexAssign(bool value, size_t i)
2091     {
2092         auto div = cast(size_t) (i / bitsPerWord);
2093         auto rem = i % bitsPerWord;
2094         enforce(div < data.length);
2095         if (value) data.ptr[div] |= (cast(size_t) 1 << rem);
2096         else data.ptr[div] &= ~(cast(size_t) 1 << rem);
2097     }
2098 
2099     /// ditto
2100     void opIndexOpAssign(string op)(bool value, size_t i)
2101     {
2102         auto div = cast(size_t) (i / bitsPerWord);
2103         auto rem = i % bitsPerWord;
2104         enforce(div < data.length);
2105         auto oldValue = cast(bool) (data.ptr[div] & (cast(size_t) 1 << rem));
2106         // Do the deed
2107         auto newValue = mixin("oldValue "~op~" value");
2108         // Write back the value
2109         if (newValue != oldValue)
2110         {
2111             if (newValue) data.ptr[div] |= (cast(size_t) 1 << rem);
2112             else data.ptr[div] &= ~(cast(size_t) 1 << rem);
2113         }
2114     }
2115 
2116     /// Ditto
2117     T moveAt(size_t i)
2118     {
2119         return this[i];
2120     }
2121 
2122     /**
2123      * Returns: A new array which is a concatenation of `this` and its argument.
2124      *
2125      * Complexity:
2126      * $(BIGOH length + m), where `m` is the number of elements in `stuff`.
2127      */
2128     Array!bool opBinary(string op, Stuff)(Stuff rhs)
2129     if (op == "~")
2130     {
2131         Array!bool result;
2132 
2133         static if (hasLength!Stuff)
2134             result.reserve(length + rhs.length);
2135         else static if (is(typeof(rhs[])) && hasLength!(typeof(rhs[])))
2136             result.reserve(length + rhs[].length);
2137         else static if (isImplicitlyConvertible!(Stuff, bool))
2138             result.reserve(length + 1);
2139 
2140         result.insertBack(this[]);
2141         result ~= rhs;
2142         return result;
2143     }
2144 
2145     /**
2146      * Forwards to `insertBack`.
2147      */
2148     Array!bool opOpAssign(string op, Stuff)(Stuff stuff)
2149     if (op == "~")
2150     {
2151         static if (is(typeof(stuff[]))) insertBack(stuff[]);
2152         else insertBack(stuff);
2153         return this;
2154     }
2155 
2156     /**
2157      * Removes all the elements from the array and releases allocated memory.
2158      *
2159      * Postcondition: `empty == true && capacity == 0`
2160      *
2161      * Complexity: $(BIGOH length)
2162      */
2163     void clear()
2164     {
2165         this = Array();
2166     }
2167 
2168     /**
2169      * Sets the number of elements in the array to `newLength`. If `newLength`
2170      * is greater than `length`, the new elements are added to the end of the
2171      * array and initialized with `false`.
2172      *
2173      * Complexity:
2174      * Guaranteed $(BIGOH abs(length - newLength)) if `capacity >= newLength`.
2175      * If `capacity < newLength` the worst case is $(BIGOH newLength).
2176      *
2177      * Postcondition: `length == newLength`
2178      */
2179     @property void length(size_t newLength)
2180     {
2181         import std.conv : to;
2182         _store.refCountedStore.ensureInitialized();
2183         auto newDataLength =
2184             to!size_t((newLength + bitsPerWord - 1) / bitsPerWord);
2185         _store._backend.length = newDataLength;
2186         _store._length = newLength;
2187     }
2188 
2189     /**
2190      * Removes the last element from the array and returns it.
2191      * Both stable and non-stable versions behave the same and guarantee
2192      * that ranges iterating over the array are never invalidated.
2193      *
2194      * Precondition: `empty == false`
2195      *
2196      * Returns: The element removed.
2197      *
2198      * Complexity: $(BIGOH 1).
2199      *
2200      * Throws: `Exception` if the array is empty.
2201      */
2202     T removeAny()
2203     {
2204         auto result = back;
2205         removeBack();
2206         return result;
2207     }
2208 
2209     /// ditto
2210     alias stableRemoveAny = removeAny;
2211 
2212     /**
2213      * Inserts the specified elements at the back of the array. `stuff` can be
2214      * a value convertible to `bool` or a range of objects convertible to `bool`.
2215      *
2216      * Returns: The number of elements inserted.
2217      *
2218      * Complexity:
2219      * $(BIGOH length + m) if reallocation takes place, otherwise $(BIGOH m),
2220      * where `m` is the number of elements in `stuff`.
2221      */
2222     size_t insertBack(Stuff)(Stuff stuff)
2223     if (is(Stuff : bool))
2224     {
2225         _store.refCountedStore.ensureInitialized();
2226         auto rem = _store._length % bitsPerWord;
2227         if (rem)
2228         {
2229             // Fits within the current array
2230             if (stuff)
2231             {
2232                 data[$ - 1] |= (cast(size_t) 1 << rem);
2233             }
2234             else
2235             {
2236                 data[$ - 1] &= ~(cast(size_t) 1 << rem);
2237             }
2238         }
2239         else
2240         {
2241             // Need to add more data
2242             _store._backend.insertBack(stuff);
2243         }
2244         ++_store._length;
2245         return 1;
2246     }
2247 
2248     /// ditto
2249     size_t insertBack(Stuff)(Stuff stuff)
2250     if (isInputRange!Stuff && is(ElementType!Stuff : bool))
2251     {
2252         size_t result;
2253         static if (hasLength!Stuff)
2254             result = stuff.length;
2255 
2256         for (; !stuff.empty; stuff.popFront())
2257         {
2258             insertBack(stuff.front);
2259             static if (!hasLength!Stuff) ++result;
2260         }
2261 
2262         return result;
2263     }
2264 
2265     /// ditto
2266     alias stableInsertBack = insertBack;
2267 
2268     /// ditto
2269     alias insert = insertBack;
2270 
2271     /// ditto
2272     alias stableInsert = insertBack;
2273 
2274     /// ditto
2275     alias linearInsert = insertBack;
2276 
2277     /// ditto
2278     alias stableLinearInsert = insertBack;
2279 
2280     /**
2281      * Removes the value from the back of the array. Both stable and non-stable
2282      * versions behave the same and guarantee that ranges iterating over the
2283      * array are never invalidated.
2284      *
2285      * Precondition: `empty == false`
2286      *
2287      * Complexity: $(BIGOH 1).
2288      *
2289      * Throws: `Exception` if the array is empty.
2290      */
2291     void removeBack()
2292     {
2293         enforce(_store._length);
2294         if (_store._length % bitsPerWord)
2295         {
2296             // Cool, just decrease the length
2297             --_store._length;
2298         }
2299         else
2300         {
2301             // Reduce the allocated space
2302             --_store._length;
2303             _store._backend.length = _store._backend.length - 1;
2304         }
2305     }
2306 
2307     /// ditto
2308     alias stableRemoveBack = removeBack;
2309 
2310     /**
2311      * Removes `howMany` values from the back of the array. Unlike the
2312      * unparameterized versions above, these functions do not throw if
2313      * they could not remove `howMany` elements. Instead, if `howMany > n`,
2314      * all elements are removed. The returned value is the effective number
2315      * of elements removed. Both stable and non-stable versions behave the same
2316      * and guarantee that ranges iterating over the array are never invalidated.
2317      *
2318      * Returns: The number of elements removed.
2319      *
2320      * Complexity: $(BIGOH howMany).
2321      */
2322     size_t removeBack(size_t howMany)
2323     {
2324         if (howMany >= length)
2325         {
2326             howMany = length;
2327             clear();
2328         }
2329         else
2330         {
2331             length = length - howMany;
2332         }
2333         return howMany;
2334     }
2335 
2336     /// ditto
2337     alias stableRemoveBack = removeBack;
2338 
2339     /**
2340      * Inserts `stuff` before, after, or instead range `r`, which must
2341      * be a valid range previously extracted from this array. `stuff`
2342      * can be a value convertible to `bool` or a range of objects convertible
2343      * to `bool`. Both stable and non-stable version behave the same and
2344      * guarantee that ranges iterating over the array are never invalidated.
2345      *
2346      * Returns: The number of values inserted.
2347      *
2348      * Complexity: $(BIGOH length + m), where `m` is the length of `stuff`.
2349      */
2350     size_t insertBefore(Stuff)(Range r, Stuff stuff)
2351     {
2352         import std.algorithm.mutation : bringToFront;
2353         // TODO: make this faster, it moves one bit at a time
2354         immutable inserted = stableInsertBack(stuff);
2355         immutable tailLength = length - inserted;
2356         bringToFront(
2357             this[r._a .. tailLength],
2358             this[tailLength .. length]);
2359         return inserted;
2360     }
2361 
2362     /// ditto
2363     alias stableInsertBefore = insertBefore;
2364 
2365     /// ditto
2366     size_t insertAfter(Stuff)(Range r, Stuff stuff)
2367     if (isImplicitlyConvertible!(Stuff, T) ||
2368             isInputRange!Stuff && isImplicitlyConvertible!(ElementType!Stuff, T))
2369     {
2370         import std.algorithm.mutation : bringToFront;
2371         // TODO: make this faster, it moves one bit at a time
2372         immutable inserted = stableInsertBack(stuff);
2373         immutable tailLength = length - inserted;
2374         bringToFront(
2375             this[r._b .. tailLength],
2376             this[tailLength .. length]);
2377         return inserted;
2378     }
2379 
2380     /// ditto
2381     alias stableInsertAfter = insertAfter;
2382 
2383     /// ditto
2384     size_t replace(Stuff)(Range r, Stuff stuff)
2385     if (is(Stuff : bool))
2386     {
2387         if (!r.empty)
2388         {
2389             // There is room
2390             r.front = stuff;
2391             r.popFront();
2392             linearRemove(r);
2393         }
2394         else
2395         {
2396             // No room, must insert
2397             insertBefore(r, stuff);
2398         }
2399         return 1;
2400     }
2401 
2402     /// ditto
2403     alias stableReplace = replace;
2404 
2405     /**
2406      * Removes all elements belonging to `r`, which must be a range
2407      * obtained originally from this array.
2408      *
2409      * Returns: A range spanning the remaining elements in the array that
2410      * initially were right after `r`.
2411      *
2412      * Complexity: $(BIGOH length)
2413      */
2414     Range linearRemove(Range r)
2415     {
2416         import std.algorithm.mutation : copy;
2417         copy(this[r._b .. length], this[r._a .. length]);
2418         length = length - r.length;
2419         return this[r._a .. length];
2420     }
2421 }
2422 
2423 @system unittest
2424 {
2425     import std.algorithm.comparison : equal;
2426 
2427     auto a = Array!bool([true, true, false, false, true, false]);
2428     assert(equal(a[], [true, true, false, false, true, false]));
2429 }
2430 
2431 // using Ranges
2432 @system unittest
2433 {
2434     import std.algorithm.comparison : equal;
2435     import std.range : retro;
2436     bool[] arr = [true, true, false, false, true, false];
2437 
2438     auto a = Array!bool(retro(arr));
2439     assert(equal(a[], retro(arr)));
2440 }
2441 
2442 @system unittest
2443 {
2444     Array!bool a;
2445     assert(a.empty);
2446 }
2447 
2448 @system unittest
2449 {
2450     auto arr = Array!bool([false, false, false, false]);
2451     assert(arr.front == false);
2452     assert(arr.back == false);
2453     assert(arr[1] == false);
2454     auto slice = arr[];
2455     slice = arr[0 .. $];
2456     slice = slice[1 .. $];
2457     slice.front = true;
2458     slice.back = true;
2459     slice[1] = true;
2460     slice = slice[0 .. $]; // https://issues.dlang.org/show_bug.cgi?id=19171
2461     assert(slice.front == true);
2462     assert(slice.back == true);
2463     assert(slice[1] == true);
2464     assert(slice.moveFront == true);
2465     assert(slice.moveBack == true);
2466     assert(slice.moveAt(1) == true);
2467 }
2468 
2469 // uncomparable values are valid values for an array
2470 // https://issues.dlang.org/show_bug.cgi?id=16331
2471 @system unittest
2472 {
2473     double[] values = [double.nan, double.nan];
2474     auto arr = Array!double(values);
2475 }
2476 
2477 @nogc @system unittest
2478 {
2479     auto a = Array!int(0, 1, 2);
2480     int[3] b = [3, 4, 5];
2481     short[3] ci = [0, 1, 0];
2482     auto c = Array!short(ci);
2483     assert(Array!int(0, 1, 2, 0, 1, 2) == a ~ a);
2484     assert(Array!int(0, 1, 2, 3, 4, 5) == a ~ b);
2485     assert(Array!int(0, 1, 2, 3) == a ~ 3);
2486     assert(Array!int(0, 1, 2, 0, 1, 0) == a ~ c);
2487 }
2488 
2489 @nogc @system unittest
2490 {
2491     auto a = Array!char('a', 'b');
2492     assert(Array!char("abc") == a ~ 'c');
2493     import std.utf : byCodeUnit;
2494     assert(Array!char("abcd") == a ~ "cd".byCodeUnit);
2495 }
2496 
2497 @nogc @system unittest
2498 {
2499     auto a = Array!dchar("ąćę"d);
2500     assert(Array!dchar("ąćęϢϖ"d) == a ~ "Ϣϖ"d);
2501     wchar x = 'Ϣ';
2502     assert(Array!dchar("ąćęϢz"d) == a ~ x ~ 'z');
2503 }
2504 
2505 @system unittest
2506 {
2507     Array!bool a;
2508     assert(a.empty);
2509     a.insertBack(false);
2510     assert(!a.empty);
2511 }
2512 
2513 @system unittest
2514 {
2515     Array!bool a;
2516     assert(a.empty);
2517     auto b = a.dup;
2518     assert(b.empty);
2519     a.insertBack(true);
2520     assert(b.empty);
2521 }
2522 
2523 @system unittest
2524 {
2525     import std.conv : to;
2526     Array!bool a;
2527     assert(a.length == 0);
2528     a.insert(true);
2529     assert(a.length == 1, to!string(a.length));
2530 }
2531 
2532 @system unittest
2533 {
2534     import std.conv : to;
2535     Array!bool a;
2536     assert(a.capacity == 0);
2537     foreach (i; 0 .. 100)
2538     {
2539         a.insert(true);
2540         assert(a.capacity >= a.length, to!string(a.capacity));
2541     }
2542 }
2543 
2544 @system unittest
2545 {
2546     Array!bool a;
2547     assert(a.capacity == 0);
2548     a.reserve(15657);
2549     assert(a.capacity >= 15657);
2550     a.reserve(100);
2551     assert(a.capacity >= 15657);
2552 }
2553 
2554 @system unittest
2555 {
2556     auto a = Array!bool([true, false, true, true]);
2557     assert(a[0 .. 2].length == 2);
2558 }
2559 
2560 @system unittest
2561 {
2562     auto a = Array!bool([true, false, true, true]);
2563     assert(a[].length == 4);
2564 }
2565 
2566 @system unittest
2567 {
2568     auto a = Array!bool([true, false, true, true]);
2569     assert(a.front);
2570     a.front = false;
2571     assert(!a.front);
2572 }
2573 
2574 @system unittest
2575 {
2576     auto a = Array!bool([true, false, true, true]);
2577     assert(a[].length == 4);
2578 }
2579 
2580 @system unittest
2581 {
2582     auto a = Array!bool([true, false, true, true]);
2583     assert(a.back);
2584     a.back = false;
2585     assert(!a.back);
2586 }
2587 
2588 @system unittest
2589 {
2590     auto a = Array!bool([true, false, true, true]);
2591     assert(a[0] && !a[1]);
2592     a[0] &= a[1];
2593     assert(!a[0]);
2594 }
2595 
2596 @system unittest
2597 {
2598     import std.algorithm.comparison : equal;
2599     auto a = Array!bool([true, false, true, true]);
2600     auto b = Array!bool([true, true, false, true]);
2601     assert(equal((a ~ b)[],
2602                     [true, false, true, true, true, true, false, true]));
2603     assert((a ~ [true, false])[].equal([true, false, true, true, true, false]));
2604     Array!bool c;
2605     c.insertBack(true);
2606     assert((c ~ false)[].equal([true, false]));
2607 }
2608 @system unittest
2609 {
2610     import std.algorithm.comparison : equal;
2611     auto a = Array!bool([true, false, true, true]);
2612     auto b = Array!bool([false, true, false, true, true]);
2613     a ~= b;
2614     assert(equal(
2615                 a[],
2616                 [true, false, true, true, false, true, false, true, true]));
2617 }
2618 
2619 @system unittest
2620 {
2621     auto a = Array!bool([true, false, true, true]);
2622     a.clear();
2623     assert(a.capacity == 0);
2624 }
2625 
2626 @system unittest
2627 {
2628     Array!bool a;
2629     a.length = 1057;
2630     assert(a.length == 1057);
2631     assert(a.capacity >= a.length);
2632     foreach (e; a)
2633     {
2634         assert(!e);
2635     }
2636     immutable cap = a.capacity;
2637     a.length = 100;
2638     assert(a.length == 100);
2639     // do not realloc if length decreases
2640     assert(a.capacity == cap);
2641 }
2642 
2643 @system unittest
2644 {
2645     Array!bool a;
2646     a.length = 1057;
2647     assert(!a.removeAny());
2648     assert(a.length == 1056);
2649     foreach (e; a)
2650     {
2651         assert(!e);
2652     }
2653 }
2654 
2655 @system unittest
2656 {
2657     Array!bool a;
2658     for (int i = 0; i < 100; ++i)
2659         a.insertBack(true);
2660     foreach (e; a)
2661         assert(e);
2662 }
2663 
2664 @system unittest
2665 {
2666     Array!bool a;
2667     a.length = 1057;
2668     assert(a.removeBack(1000) == 1000);
2669     assert(a.length == 57);
2670     foreach (e; a)
2671     {
2672         assert(!e);
2673     }
2674 }
2675 
2676 @system unittest
2677 {
2678     import std.conv : to;
2679     Array!bool a;
2680     version (bugxxxx)
2681     {
2682         a._store.refCountedDebug = true;
2683     }
2684     a.insertBefore(a[], true);
2685     assert(a.length == 1, to!string(a.length));
2686     a.insertBefore(a[], false);
2687     assert(a.length == 2, to!string(a.length));
2688     a.insertBefore(a[1 .. $], true);
2689     import std.algorithm.comparison : equal;
2690     assert(a[].equal([false, true, true]));
2691 }
2692 
2693 // https://issues.dlang.org/show_bug.cgi?id=21555
2694 @system unittest
2695 {
2696     import std.algorithm.comparison : equal;
2697     Array!bool arr;
2698     size_t len = arr.insertBack([false, true]);
2699     assert(len == 2);
2700 }
2701 
2702 // https://issues.dlang.org/show_bug.cgi?id=21556
2703 @system unittest
2704 {
2705     import std.algorithm.comparison : equal;
2706     Array!bool a;
2707     a.insertBack([true, true, false, false, true]);
2708     assert(a.length == 5);
2709 
2710     assert(a.insertAfter(a[0 .. 5], [false, false]) == 2);
2711     assert(equal(a[], [true, true, false, false, true, false, false]));
2712 
2713     assert(a.insertAfter(a[0 .. 5], true) == 1);
2714     assert(equal(a[], [true, true, false, false, true, true, false, false]));
2715 }
2716 
2717 @system unittest
2718 {
2719     import std.conv : to;
2720     Array!bool a;
2721     a.length = 10;
2722     a.insertAfter(a[0 .. 5], true);
2723     assert(a.length == 11, to!string(a.length));
2724     assert(a[5]);
2725 }
2726 @system unittest
2727 {
2728     alias V3 = int[3];
2729     V3 v = [1, 2, 3];
2730     Array!V3 arr;
2731     arr ~= v;
2732     assert(arr[0] == [1, 2, 3]);
2733 }
2734 @system unittest
2735 {
2736     alias V3 = int[3];
2737     V3[2] v = [[1, 2, 3], [4, 5, 6]];
2738     Array!V3 arr;
2739     arr ~= v;
2740     assert(arr[0] == [1, 2, 3]);
2741     assert(arr[1] == [4, 5, 6]);
2742 }
2743 
2744 // Change of length reallocates without calling GC.
2745 // https://issues.dlang.org/show_bug.cgi?id=13642
2746 @system unittest
2747 {
2748     import core.memory;
2749     class ABC { void func() { int x = 5; } }
2750 
2751     Array!ABC arr;
2752     // Length only allocates if capacity is too low.
2753     arr.reserve(4);
2754     assert(arr.capacity == 4);
2755 
2756     void func() @nogc
2757     {
2758         arr.length = 5;
2759     }
2760     func();
2761 
2762     foreach (ref b; arr) b = new ABC;
2763     GC.collect();
2764     arr[1].func();
2765 }
2766 
2767 @system unittest
2768 {
2769 
2770     Array!int arr = [1, 2, 4, 5];
2771     int[] data = arr.data();
2772 
2773     const Array!int arr2 = [8, 9];
2774     assert(arr2.data() == [8, 9]);
2775 
2776     data[0] = 0;
2777     assert(arr[0] == 0);
2778 
2779     arr.length = 0;
2780     assert(arr.data == []);
2781 
2782     Array!int empty;
2783     assert(empty.data == []);
2784 }
2785