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