1 // Written in the D programming language.
2 /**
3 Functions and types that manipulate built-in arrays and associative arrays.
4 
5 This module provides all kinds of functions to create, manipulate or convert arrays:
6 
7 $(SCRIPT inhibitQuickIndex = 1;)
8 $(DIVC quickindex,
9 $(BOOKTABLE ,
10 $(TR $(TH Function Name) $(TH Description)
11 )
12     $(TR $(TD $(LREF array))
13         $(TD Returns a copy of the input in a newly allocated dynamic array.
14     ))
15     $(TR $(TD $(LREF appender))
16         $(TD Returns a new $(LREF Appender) or $(LREF RefAppender) initialized with a given array.
17     ))
18     $(TR $(TD $(LREF assocArray))
19         $(TD Returns a newly allocated associative array from a range of key/value tuples.
20     ))
21     $(TR $(TD $(LREF byPair))
22         $(TD Construct a range iterating over an associative array by key/value tuples.
23     ))
24     $(TR $(TD $(LREF insertInPlace))
25         $(TD Inserts into an existing array at a given position.
26     ))
27     $(TR $(TD $(LREF join))
28         $(TD Concatenates a range of ranges into one array.
29     ))
30     $(TR $(TD $(LREF minimallyInitializedArray))
31         $(TD Returns a new array of type `T`.
32     ))
33     $(TR $(TD $(LREF replace))
34         $(TD Returns a new array with all occurrences of a certain subrange replaced.
35     ))
36     $(TR $(TD $(LREF replaceFirst))
37         $(TD Returns a new array with the first occurrence of a certain subrange replaced.
38     ))
39     $(TR $(TD $(LREF replaceInPlace))
40         $(TD Replaces all occurrences of a certain subrange and puts the result into a given array.
41     ))
42     $(TR $(TD $(LREF replaceInto))
43         $(TD Replaces all occurrences of a certain subrange and puts the result into an output range.
44     ))
45     $(TR $(TD $(LREF replaceLast))
46         $(TD Returns a new array with the last occurrence of a certain subrange replaced.
47     ))
48     $(TR $(TD $(LREF replaceSlice))
49         $(TD Returns a new array with a given slice replaced.
50     ))
51     $(TR $(TD $(LREF replicate))
52         $(TD Creates a new array out of several copies of an input array or range.
53     ))
54     $(TR $(TD $(LREF sameHead))
55         $(TD Checks if the initial segments of two arrays refer to the same
56         place in memory.
57     ))
58     $(TR $(TD $(LREF sameTail))
59         $(TD Checks if the final segments of two arrays refer to the same place
60         in memory.
61     ))
62     $(TR $(TD $(LREF split))
63         $(TD Eagerly split a range or string into an array.
64     ))
65     $(TR $(TD $(LREF staticArray))
66         $(TD Creates a new static array from given data.
67     ))
68     $(TR $(TD $(LREF uninitializedArray))
69         $(TD Returns a new array of type `T` without initializing its elements.
70     ))
71 ))
72 
73 Copyright: Copyright Andrei Alexandrescu 2008- and Jonathan M Davis 2011-.
74 
75 License:   $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
76 
77 Authors:   $(HTTP erdani.org, Andrei Alexandrescu) and
78            $(HTTP jmdavisprog.com, Jonathan M Davis)
79 
80 Source: $(PHOBOSSRC std/array.d)
81 */
82 module std.array;
83 
84 import std.functional;
85 import std.meta;
86 import std.traits;
87 
88 import std.range.primitives;
89 public import std.range.primitives : save, empty, popFront, popBack, front, back;
90 
91 /**
92  * Allocates an array and initializes it with copies of the elements
93  * of range `r`.
94  *
95  * Narrow strings are handled as follows:
96  * - If autodecoding is turned on (default), then they are handled as a separate overload.
97  * - If autodecoding is turned off, then this is equivalent to duplicating the array.
98  *
99  * Params:
100  *      r = range (or aggregate with `opApply` function) whose elements are copied into the allocated array
101  * Returns:
102  *      allocated and initialized array
103  */
104 ForeachType!Range[] array(Range)(Range r)
105 if (isIterable!Range && !isAutodecodableString!Range && !isInfinite!Range)
106 {
107     if (__ctfe)
108     {
109         // Compile-time version to avoid memcpy calls.
110         // Also used to infer attributes of array().
111         typeof(return) result;
112         foreach (e; r)
113             result ~= e;
114         return result;
115     }
116 
117     alias E = ForeachType!Range;
118     static if (hasLength!Range)
119     {
120         auto length = r.length;
121         if (length == 0)
122             return null;
123 
124         import std.conv : emplaceRef;
125 
126         auto result = (() @trusted => uninitializedArray!(Unqual!E[])(length))();
127 
128         // Every element of the uninitialized array must be initialized
129         size_t i;
130         foreach (e; r)
131         {
132             emplaceRef!E(result[i], e);
133             ++i;
134         }
135         return (() @trusted => cast(E[]) result)();
136     }
137     else
138     {
139         auto a = appender!(E[])();
140         foreach (e; r)
141         {
142             a.put(e);
143         }
144         return a.data;
145     }
146 }
147 
148 /// ditto
149 ForeachType!(PointerTarget!Range)[] array(Range)(Range r)
150 if (isPointer!Range && isIterable!(PointerTarget!Range) && !isAutodecodableString!Range && !isInfinite!Range)
151 {
152     return array(*r);
153 }
154 
155 ///
156 @safe pure nothrow unittest
157 {
158     auto a = array([1, 2, 3, 4, 5][]);
159     assert(a == [ 1, 2, 3, 4, 5 ]);
160 }
161 
162 @safe pure nothrow unittest
163 {
164     import std.algorithm.comparison : equal;
165     struct Foo
166     {
167         int a;
168     }
169     auto a = array([Foo(1), Foo(2), Foo(3), Foo(4), Foo(5)][]);
170     assert(equal(a, [Foo(1), Foo(2), Foo(3), Foo(4), Foo(5)]));
171 }
172 
173 @safe pure nothrow unittest
174 {
175     struct MyRange
176     {
177         enum front = 123;
178         enum empty = true;
179         void popFront() {}
180     }
181 
182     auto arr = (new MyRange).array;
183     assert(arr.empty);
184 }
185 
186 @system pure nothrow unittest
187 {
188     immutable int[] a = [1, 2, 3, 4];
189     auto b = (&a).array;
190     assert(b == a);
191 }
192 
193 @safe unittest
194 {
195     import std.algorithm.comparison : equal;
196     struct Foo
197     {
198         int a;
199         void opAssign(Foo)
200         {
201             assert(0);
202         }
203         auto opEquals(Foo foo)
204         {
205             return a == foo.a;
206         }
207     }
208     auto a = array([Foo(1), Foo(2), Foo(3), Foo(4), Foo(5)][]);
209     assert(equal(a, [Foo(1), Foo(2), Foo(3), Foo(4), Foo(5)]));
210 }
211 
212 // https://issues.dlang.org/show_bug.cgi?id=12315
213 @safe unittest
214 {
215     static struct Bug12315 { immutable int i; }
216     enum bug12315 = [Bug12315(123456789)].array();
217     static assert(bug12315[0].i == 123456789);
218 }
219 
220 @safe unittest
221 {
222     import std.range;
223     static struct S{int* p;}
224     auto a = array(immutable(S).init.repeat(5));
225     assert(a.length == 5);
226 }
227 
228 version (StdUnittest)
229     private extern(C) void _d_delarray_t(void[] *p, TypeInfo_Struct ti);
230 
231 // https://issues.dlang.org/show_bug.cgi?id=18995
232 @system unittest
233 {
234     int nAlive = 0;
235     struct S
236     {
237         bool alive;
238         this(int) { alive = true; ++nAlive; }
239         this(this) { nAlive += alive; }
240         ~this() { nAlive -= alive; alive = false; }
241     }
242 
243     import std.algorithm.iteration : map;
244     import std.range : iota;
245 
246     auto arr = iota(3).map!(a => S(a)).array;
247     assert(nAlive == 3);
248 
249     // No good way to ensure the GC frees this, just call the lifetime function
250     // directly. If delete wasn't deprecated, this is what delete would do.
251     _d_delarray_t(cast(void[]*)&arr, typeid(S));
252 
253     assert(nAlive == 0);
254 }
255 
256 /**
257 Convert a narrow autodecoding string to an array type that fully supports
258 random access.  This is handled as a special case and always returns an array
259 of `dchar`
260 
261 NOTE: This function is never used when autodecoding is turned off.
262 
263 Params:
264     str = `isNarrowString` to be converted to an array of `dchar`
265 Returns:
266     a `dchar[]`, `const(dchar)[]`, or `immutable(dchar)[]` depending on the constness of
267     the input.
268 */
269 CopyTypeQualifiers!(ElementType!String,dchar)[] array(String)(scope String str)
270 if (isAutodecodableString!String)
271 {
272     import std.utf : toUTF32;
273     auto temp = str.toUTF32;
274     /* Unsafe cast. Allowed because toUTF32 makes a new array
275        and copies all the elements.
276      */
277     return () @trusted { return cast(CopyTypeQualifiers!(ElementType!String, dchar)[]) temp; } ();
278 }
279 
280 ///
281 @safe unittest
282 {
283     import std.range.primitives : isRandomAccessRange;
284     import std.traits : isAutodecodableString;
285 
286     // note that if autodecoding is turned off, `array` will not transcode these.
287     static if (isAutodecodableString!string)
288         assert("Hello D".array == "Hello D"d);
289     else
290         assert("Hello D".array == "Hello D");
291 
292     static if (isAutodecodableString!wstring)
293         assert("Hello D"w.array == "Hello D"d);
294     else
295         assert("Hello D"w.array == "Hello D"w);
296 
297     static assert(isRandomAccessRange!dstring == true);
298 }
299 
300 @safe unittest
301 {
302     import std.conv : to;
303 
304     static struct TestArray { int x; string toString() @safe { return to!string(x); } }
305 
306     static struct OpAssign
307     {
308         uint num;
309         this(uint num) { this.num = num; }
310 
311         // Templating opAssign to make sure the bugs with opAssign being
312         // templated are fixed.
313         void opAssign(T)(T rhs) { this.num = rhs.num; }
314     }
315 
316     static struct OpApply
317     {
318         int opApply(scope int delegate(ref int) @safe dg)
319         {
320             int res;
321             foreach (i; 0 .. 10)
322             {
323                 res = dg(i);
324                 if (res) break;
325             }
326 
327             return res;
328         }
329     }
330 
331     auto a = array([1, 2, 3, 4, 5][]);
332     assert(a == [ 1, 2, 3, 4, 5 ]);
333 
334     auto b = array([TestArray(1), TestArray(2)][]);
335     assert(b == [TestArray(1), TestArray(2)]);
336 
337     class C
338     {
339         int x;
340         this(int y) { x = y; }
341         override string toString() const @safe { return to!string(x); }
342     }
343     auto c = array([new C(1), new C(2)][]);
344     assert(c[0].x == 1);
345     assert(c[1].x == 2);
346 
347     auto d = array([1.0, 2.2, 3][]);
348     assert(is(typeof(d) == double[]));
349     assert(d == [1.0, 2.2, 3]);
350 
351     auto e = [OpAssign(1), OpAssign(2)];
352     auto f = array(e);
353     assert(e == f);
354 
355     assert(array(OpApply.init) == [0,1,2,3,4,5,6,7,8,9]);
356     static if (isAutodecodableString!string)
357     {
358         assert(array("ABC") == "ABC"d);
359         assert(array("ABC".dup) == "ABC"d.dup);
360     }
361 }
362 
363 // https://issues.dlang.org/show_bug.cgi?id=8233
364 @safe unittest
365 {
366     assert(array("hello world"d) == "hello world"d);
367     immutable a = [1, 2, 3, 4, 5];
368     assert(array(a) == a);
369     const b = a;
370     assert(array(b) == a);
371 
372     //To verify that the opAssign branch doesn't get screwed up by using Unqual.
373     //EDIT: array no longer calls opAssign.
374     struct S
375     {
376         ref S opAssign(S)(const ref S rhs)
377         {
378             assert(0);
379         }
380 
381         int i;
382     }
383 
384     static foreach (T; AliasSeq!(S, const S, immutable S))
385     {{
386         auto arr = [T(1), T(2), T(3), T(4)];
387         assert(array(arr) == arr);
388     }}
389 }
390 
391 // https://issues.dlang.org/show_bug.cgi?id=9824
392 @safe unittest
393 {
394     static struct S
395     {
396         @disable void opAssign(S);
397         int i;
398     }
399     auto arr = [S(0), S(1), S(2)];
400     arr.array();
401 }
402 
403 // https://issues.dlang.org/show_bug.cgi?id=10220
404 @safe unittest
405 {
406     import std.algorithm.comparison : equal;
407     import std.exception;
408     import std.range : repeat;
409 
410     static struct S
411     {
412         int val;
413 
414         @disable this();
415         this(int v) { val = v; }
416     }
417     assertCTFEable!(
418     {
419         auto r = S(1).repeat(2).array();
420         assert(equal(r, [S(1), S(1)]));
421     });
422 }
423 
424 @safe unittest
425 {
426     //Turn down infinity:
427     static assert(!is(typeof(
428         repeat(1).array()
429     )));
430 }
431 
432 /**
433 Returns a newly allocated associative array from a range of key/value tuples
434 or from a range of keys and a range of values.
435 
436 Params:
437     r = An $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
438     of tuples of keys and values.
439     keys = An $(REF_ALTTEXT input range, isInputRange, std,range,primitives) of keys
440     values = An $(REF_ALTTEXT input range, isInputRange, std,range,primitives) of values
441 
442 Returns:
443 
444     A newly allocated associative array out of elements of the input
445     range, which must be a range of tuples (Key, Value) or
446     a range of keys and a range of values. If given two ranges of unequal
447     lengths after the elements of the shorter are exhausted the remaining
448     elements of the longer will not be considered.
449     Returns a null associative array reference when given an empty range.
450     Duplicates: Associative arrays have unique keys. If r contains duplicate keys,
451     then the result will contain the value of the last pair for that key in r.
452 
453 See_Also: $(REF Tuple, std,typecons), $(REF zip, std,range)
454  */
455 
456 auto assocArray(Range)(Range r)
457 if (isInputRange!Range)
458 {
459     import std.typecons : isTuple;
460 
461     alias E = ElementType!Range;
462     static assert(isTuple!E, "assocArray: argument must be a range of tuples,"
463         ~" but was a range of "~E.stringof);
464     static assert(E.length == 2, "assocArray: tuple dimension must be 2");
465     alias KeyType = E.Types[0];
466     alias ValueType = E.Types[1];
467     static assert(isMutable!ValueType, "assocArray: value type must be mutable");
468 
469     ValueType[KeyType] aa;
470     foreach (t; r)
471         aa[t[0]] = t[1];
472     return aa;
473 }
474 
475 /// ditto
476 auto assocArray(Keys, Values)(Keys keys, Values values)
477 if (isInputRange!Values && isInputRange!Keys)
478 {
479     static if (isDynamicArray!Keys && isDynamicArray!Values
480         && !isNarrowString!Keys && !isNarrowString!Values)
481     {
482         void* aa;
483         {
484             // aaLiteral is nothrow when the destructors don't throw
485             static if (is(typeof(() nothrow
486             {
487                 import std.range : ElementType;
488                 import std.traits : hasElaborateDestructor;
489                 alias KeyElement = ElementType!Keys;
490                 static if (hasElaborateDestructor!KeyElement)
491                     KeyElement.init.__xdtor();
492 
493                 alias ValueElement = ElementType!Values;
494                 static if (hasElaborateDestructor!ValueElement)
495                     ValueElement.init.__xdtor();
496             })))
497             {
498                 scope(failure) assert(false, "aaLiteral must not throw");
499             }
500             if (values.length > keys.length)
501                 values = values[0 .. keys.length];
502             else if (keys.length > values.length)
503                 keys = keys[0 .. values.length];
504             aa = aaLiteral(keys, values);
505         }
506         alias Key = typeof(keys[0]);
507         alias Value = typeof(values[0]);
508         return (() @trusted => cast(Value[Key]) aa)();
509     }
510     else
511     {
512         // zip is not always able to infer nothrow
513         alias Key = ElementType!Keys;
514         alias Value = ElementType!Values;
515         static assert(isMutable!Value, "assocArray: value type must be mutable");
516         Value[Key] aa;
517         foreach (key; keys)
518         {
519             if (values.empty) break;
520 
521             // aa[key] is incorrectly not @safe if the destructor throws
522             // https://issues.dlang.org/show_bug.cgi?id=18592
523             static if (is(typeof(() @safe
524             {
525                 import std.range : ElementType;
526                 import std.traits : hasElaborateDestructor;
527                 alias KeyElement = ElementType!Keys;
528                 static if (hasElaborateDestructor!KeyElement)
529                     KeyElement.init.__xdtor();
530 
531                 alias ValueElement = ElementType!Values;
532                 static if (hasElaborateDestructor!ValueElement)
533                     ValueElement.init.__xdtor();
534             })))
535             {
536                 () @trusted {
537                     aa[key] = values.front;
538                 }();
539             }
540             else
541             {
542                 aa[key] = values.front;
543             }
544             values.popFront();
545         }
546         return aa;
547     }
548 }
549 
550 ///
551 @safe pure /*nothrow*/ unittest
552 {
553     import std.range : repeat, zip;
554     import std.typecons : tuple;
555     import std.range.primitives : autodecodeStrings;
556     auto a = assocArray(zip([0, 1, 2], ["a", "b", "c"])); // aka zipMap
557     static assert(is(typeof(a) == string[int]));
558     assert(a == [0:"a", 1:"b", 2:"c"]);
559 
560     auto b = assocArray([ tuple("foo", "bar"), tuple("baz", "quux") ]);
561     static assert(is(typeof(b) == string[string]));
562     assert(b == ["foo":"bar", "baz":"quux"]);
563 
564     static if (autodecodeStrings)
565         alias achar = dchar;
566     else
567         alias achar = immutable(char);
568     auto c = assocArray("ABCD", true.repeat);
569     static assert(is(typeof(c) == bool[achar]));
570     bool[achar] expected = ['D':true, 'A':true, 'B':true, 'C':true];
571     assert(c == expected);
572 }
573 
574 // Cannot be version (StdUnittest) - recursive instantiation error
575 // https://issues.dlang.org/show_bug.cgi?id=11053
576 @safe unittest
577 {
578     import std.typecons;
579     static assert(!__traits(compiles, [ 1, 2, 3 ].assocArray()));
580     static assert(!__traits(compiles, [ tuple("foo", "bar", "baz") ].assocArray()));
581     static assert(!__traits(compiles, [ tuple("foo") ].assocArray()));
582     assert([ tuple("foo", "bar") ].assocArray() == ["foo": "bar"]);
583 }
584 
585 // https://issues.dlang.org/show_bug.cgi?id=13909
586 @safe unittest
587 {
588     import std.typecons;
589     auto a = [tuple!(const string, string)("foo", "bar")];
590     auto b = [tuple!(string, const string)("foo", "bar")];
591     assert(a == b);
592     assert(assocArray(a) == [cast(const(string)) "foo": "bar"]);
593     static assert(!__traits(compiles, assocArray(b)));
594 }
595 
596 // https://issues.dlang.org/show_bug.cgi?id=5502
597 @safe unittest
598 {
599     auto a = assocArray([0, 1, 2], ["a", "b", "c"]);
600     static assert(is(typeof(a) == string[int]));
601     assert(a == [0:"a", 1:"b", 2:"c"]);
602 
603     auto b = assocArray([0, 1, 2], [3L, 4, 5]);
604     static assert(is(typeof(b) == long[int]));
605     assert(b == [0: 3L, 1: 4, 2: 5]);
606 }
607 
608 // https://issues.dlang.org/show_bug.cgi?id=5502
609 @safe unittest
610 {
611     import std.algorithm.iteration : filter, map;
612     import std.range : enumerate;
613     import std.range.primitives : autodecodeStrings;
614 
615     auto r = "abcde".enumerate.filter!(a => a.index == 2);
616     auto a = assocArray(r.map!(a => a.value), r.map!(a => a.index));
617     static if (autodecodeStrings)
618         alias achar = dchar;
619     else
620         alias achar = immutable(char);
621     static assert(is(typeof(a) == size_t[achar]));
622     assert(a == [achar('c'): size_t(2)]);
623 }
624 
625 @safe nothrow pure unittest
626 {
627     import std.range : iota;
628     auto b = assocArray(3.iota, 3.iota(6));
629     static assert(is(typeof(b) == int[int]));
630     assert(b == [0: 3, 1: 4, 2: 5]);
631 
632     b = assocArray([0, 1, 2], [3, 4, 5]);
633     assert(b == [0: 3, 1: 4, 2: 5]);
634 }
635 
636 @safe unittest
637 {
638     struct ThrowingElement
639     {
640         int i;
641         static bool b;
642         ~this(){
643             if (b)
644                 throw new Exception("");
645         }
646     }
647     static assert(!__traits(compiles, () nothrow { assocArray([ThrowingElement()], [0]);}));
648     assert(assocArray([ThrowingElement()], [0]) == [ThrowingElement(): 0]);
649 
650     static assert(!__traits(compiles, () nothrow { assocArray([0], [ThrowingElement()]);}));
651     assert(assocArray([0], [ThrowingElement()]) == [0: ThrowingElement()]);
652 
653     import std.range : iota;
654     static assert(!__traits(compiles, () nothrow { assocArray(1.iota, [ThrowingElement()]);}));
655     assert(assocArray(1.iota, [ThrowingElement()]) == [0: ThrowingElement()]);
656 }
657 
658 @system unittest
659 {
660     import std.range : iota;
661     struct UnsafeElement
662     {
663         int i;
664         static bool b;
665         ~this(){
666             int[] arr;
667             void* p = arr.ptr + 1; // unsafe
668         }
669     }
670     static assert(!__traits(compiles, () @safe { assocArray(1.iota, [UnsafeElement()]);}));
671     assert(assocArray(1.iota, [UnsafeElement()]) == [0: UnsafeElement()]);
672 }
673 
674 /**
675 Construct a range iterating over an associative array by key/value tuples.
676 
677 Params:
678     aa = The associative array to iterate over.
679 
680 Returns: A $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives)
681 of Tuple's of key and value pairs from the given associative array. The members
682 of each pair can be accessed by name (`.key` and `.value`). or by integer
683 index (0 and 1 respectively).
684 */
685 auto byPair(AA)(AA aa)
686 if (isAssociativeArray!AA)
687 {
688     import std.algorithm.iteration : map;
689     import std.typecons : tuple;
690 
691     return aa.byKeyValue
692         .map!(pair => tuple!("key", "value")(pair.key, pair.value));
693 }
694 
695 ///
696 @safe unittest
697 {
698     import std.algorithm.sorting : sort;
699     import std.typecons : tuple, Tuple;
700 
701     auto aa = ["a": 1, "b": 2, "c": 3];
702     Tuple!(string, int)[] pairs;
703 
704     // Iteration over key/value pairs.
705     foreach (pair; aa.byPair)
706     {
707         if (pair.key == "b")
708             pairs ~= tuple("B", pair.value);
709         else
710             pairs ~= pair;
711     }
712 
713     // Iteration order is implementation-dependent, so we should sort it to get
714     // a fixed order.
715     pairs.sort();
716     assert(pairs == [
717         tuple("B", 2),
718         tuple("a", 1),
719         tuple("c", 3)
720     ]);
721 }
722 
723 @safe unittest
724 {
725     import std.typecons : tuple, Tuple;
726     import std.meta : AliasSeq;
727 
728     auto aa = ["a":2];
729     auto pairs = aa.byPair();
730 
731     alias PT = typeof(pairs.front);
732     static assert(is(PT : Tuple!(string,int)));
733     static assert(PT.fieldNames == AliasSeq!("key", "value"));
734     static assert(isForwardRange!(typeof(pairs)));
735 
736     assert(!pairs.empty);
737     assert(pairs.front == tuple("a", 2));
738 
739     auto savedPairs = pairs.save;
740 
741     pairs.popFront();
742     assert(pairs.empty);
743     assert(!savedPairs.empty);
744     assert(savedPairs.front == tuple("a", 2));
745 }
746 
747 // https://issues.dlang.org/show_bug.cgi?id=17711
748 @safe unittest
749 {
750     const(int[string]) aa = [ "abc": 123 ];
751 
752     // Ensure that byKeyValue is usable with a const AA.
753     auto kv = aa.byKeyValue;
754     assert(!kv.empty);
755     assert(kv.front.key == "abc" && kv.front.value == 123);
756     kv.popFront();
757     assert(kv.empty);
758 
759     // Ensure byPair is instantiable with const AA.
760     auto r = aa.byPair;
761     static assert(isInputRange!(typeof(r)));
762     assert(!r.empty && r.front[0] == "abc" && r.front[1] == 123);
763     r.popFront();
764     assert(r.empty);
765 }
766 
767 private template blockAttribute(T)
768 {
769     import core.memory;
770     static if (hasIndirections!(T) || is(T == void))
771     {
772         enum blockAttribute = 0;
773     }
774     else
775     {
776         enum blockAttribute = GC.BlkAttr.NO_SCAN;
777     }
778 }
779 
780 @safe unittest
781 {
782     import core.memory : UGC = GC;
783     static assert(!(blockAttribute!void & UGC.BlkAttr.NO_SCAN));
784 }
785 
786 // Returns the number of dimensions in an array T.
787 private template nDimensions(T)
788 {
789     static if (isArray!T)
790     {
791         enum nDimensions = 1 + nDimensions!(typeof(T.init[0]));
792     }
793     else
794     {
795         enum nDimensions = 0;
796     }
797 }
798 
799 @safe unittest
800 {
801     static assert(nDimensions!(uint[]) == 1);
802     static assert(nDimensions!(float[][]) == 2);
803 }
804 
805 /++
806 Returns a new array of type `T` allocated on the garbage collected heap
807 without initializing its elements. This can be a useful optimization if every
808 element will be immediately initialized. `T` may be a multidimensional
809 array. In this case sizes may be specified for any number of dimensions from 0
810 to the number in `T`.
811 
812 uninitializedArray is `nothrow` and weakly `pure`.
813 
814 uninitializedArray is `@system` if the uninitialized element type has pointers.
815 
816 Params:
817     T = The type of the resulting array elements
818     sizes = The length dimension(s) of the resulting array
819 Returns:
820     An array of `T` with `I.length` dimensions.
821 +/
822 auto uninitializedArray(T, I...)(I sizes) nothrow @system
823 if (isDynamicArray!T && allSatisfy!(isIntegral, I) && hasIndirections!(ElementEncodingType!T))
824 {
825     enum isSize_t(E) = is (E : size_t);
826     alias toSize_t(E) = size_t;
827 
828     static assert(allSatisfy!(isSize_t, I),
829         "Argument types in "~I.stringof~" are not all convertible to size_t: "
830         ~Filter!(templateNot!(isSize_t), I).stringof);
831 
832     //Eagerlly transform non-size_t into size_t to avoid template bloat
833     alias ST = staticMap!(toSize_t, I);
834 
835     return arrayAllocImpl!(false, T, ST)(sizes);
836 }
837 
838 /// ditto
839 auto uninitializedArray(T, I...)(I sizes) nothrow @trusted
840 if (isDynamicArray!T && allSatisfy!(isIntegral, I) && !hasIndirections!(ElementEncodingType!T))
841 {
842     enum isSize_t(E) = is (E : size_t);
843     alias toSize_t(E) = size_t;
844 
845     static assert(allSatisfy!(isSize_t, I),
846         "Argument types in "~I.stringof~" are not all convertible to size_t: "
847         ~Filter!(templateNot!(isSize_t), I).stringof);
848 
849     //Eagerlly transform non-size_t into size_t to avoid template bloat
850     alias ST = staticMap!(toSize_t, I);
851 
852     return arrayAllocImpl!(false, T, ST)(sizes);
853 }
854 ///
855 @system nothrow pure unittest
856 {
857     double[] arr = uninitializedArray!(double[])(100);
858     assert(arr.length == 100);
859 
860     double[][] matrix = uninitializedArray!(double[][])(42, 31);
861     assert(matrix.length == 42);
862     assert(matrix[0].length == 31);
863 
864     char*[] ptrs = uninitializedArray!(char*[])(100);
865     assert(ptrs.length == 100);
866 }
867 
868 /++
869 Returns a new array of type `T` allocated on the garbage collected heap.
870 
871 Partial initialization is done for types with indirections, for preservation
872 of memory safety. Note that elements will only be initialized to 0, but not
873 necessarily the element type's `.init`.
874 
875 minimallyInitializedArray is `nothrow` and weakly `pure`.
876 
877 Params:
878     T = The type of the array elements
879     sizes = The length dimension(s) of the resulting array
880 Returns:
881     An array of `T` with `I.length` dimensions.
882 +/
883 auto minimallyInitializedArray(T, I...)(I sizes) nothrow @trusted
884 if (isDynamicArray!T && allSatisfy!(isIntegral, I))
885 {
886     enum isSize_t(E) = is (E : size_t);
887     alias toSize_t(E) = size_t;
888 
889     static assert(allSatisfy!(isSize_t, I),
890         "Argument types in "~I.stringof~" are not all convertible to size_t: "
891         ~Filter!(templateNot!(isSize_t), I).stringof);
892     //Eagerlly transform non-size_t into size_t to avoid template bloat
893     alias ST = staticMap!(toSize_t, I);
894 
895     return arrayAllocImpl!(true, T, ST)(sizes);
896 }
897 
898 ///
899 @safe pure nothrow unittest
900 {
901     import std.algorithm.comparison : equal;
902     import std.range : repeat;
903 
904     auto arr = minimallyInitializedArray!(int[])(42);
905     assert(arr.length == 42);
906 
907     // Elements aren't necessarily initialized to 0, so don't do this:
908     // assert(arr.equal(0.repeat(42)));
909     // If that is needed, initialize the array normally instead:
910     auto arr2 = new int[42];
911     assert(arr2.equal(0.repeat(42)));
912 }
913 
914 @safe pure nothrow unittest
915 {
916     cast(void) minimallyInitializedArray!(int[][][][][])();
917     double[] arr = minimallyInitializedArray!(double[])(100);
918     assert(arr.length == 100);
919 
920     double[][] matrix = minimallyInitializedArray!(double[][])(42);
921     assert(matrix.length == 42);
922     foreach (elem; matrix)
923     {
924         assert(elem.ptr is null);
925     }
926 }
927 
928 // from rt/lifetime.d
929 private extern(C) void[] _d_newarrayU(const TypeInfo ti, size_t length) pure nothrow;
930 
931 private auto arrayAllocImpl(bool minimallyInitialized, T, I...)(I sizes) nothrow
932 {
933     static assert(I.length <= nDimensions!T,
934         I.length.stringof~"dimensions specified for a "~nDimensions!T.stringof~" dimensional array.");
935 
936     alias E = ElementEncodingType!T;
937 
938     E[] ret;
939 
940     static if (I.length != 0)
941     {
942         static assert(is(I[0] == size_t), "I[0] must be of type size_t not "
943                 ~ I[0].stringof);
944         alias size = sizes[0];
945     }
946 
947     static if (I.length == 1)
948     {
949         if (__ctfe)
950         {
951             static if (__traits(compiles, new E[](size)))
952                 ret = new E[](size);
953             else static if (__traits(compiles, ret ~= E.init))
954             {
955                 try
956                 {
957                     //Issue: if E has an impure postblit, then all of arrayAllocImpl
958                     //Will be impure, even during non CTFE.
959                     foreach (i; 0 .. size)
960                         ret ~= E.init;
961                 }
962                 catch (Exception e)
963                     assert(0, e.msg);
964             }
965             else
966                 assert(0, "No postblit nor default init on " ~ E.stringof ~
967                     ": At least one is required for CTFE.");
968         }
969         else
970         {
971             import core.stdc..string : memset;
972 
973             /+
974               NOTES:
975               _d_newarrayU is part of druntime, and creates an uninitialized
976               block, just like GC.malloc. However, it also sets the appropriate
977               bits, and sets up the block as an appendable array of type E[],
978               which will inform the GC how to destroy the items in the block
979               when it gets collected.
980 
981               _d_newarrayU returns a void[], but with the length set according
982               to E.sizeof.
983             +/
984             *(cast(void[]*)&ret) = _d_newarrayU(typeid(E[]), size);
985             static if (minimallyInitialized && hasIndirections!E)
986                 // _d_newarrayU would have asserted if the multiplication below
987                 // had overflowed, so we don't have to check it again.
988                 memset(ret.ptr, 0, E.sizeof * ret.length);
989         }
990     }
991     else static if (I.length > 1)
992     {
993         ret = arrayAllocImpl!(false, E[])(size);
994         foreach (ref elem; ret)
995             elem = arrayAllocImpl!(minimallyInitialized, E)(sizes[1..$]);
996     }
997 
998     return ret;
999 }
1000 
1001 @safe nothrow pure unittest
1002 {
1003     auto s1 = uninitializedArray!(int[])();
1004     auto s2 = minimallyInitializedArray!(int[])();
1005     assert(s1.length == 0);
1006     assert(s2.length == 0);
1007 }
1008 
1009 // https://issues.dlang.org/show_bug.cgi?id=9803
1010 @safe nothrow pure unittest
1011 {
1012     auto a = minimallyInitializedArray!(int*[])(1);
1013     assert(a[0] == null);
1014     auto b = minimallyInitializedArray!(int[][])(1);
1015     assert(b[0].empty);
1016     auto c = minimallyInitializedArray!(int*[][])(1, 1);
1017     assert(c[0][0] == null);
1018 }
1019 
1020 // https://issues.dlang.org/show_bug.cgi?id=10637
1021 @safe unittest
1022 {
1023     static struct S
1024     {
1025         static struct I{int i; alias i this;}
1026         int* p;
1027         this() @disable;
1028         this(int i)
1029         {
1030             p = &(new I(i)).i;
1031         }
1032         this(this)
1033         {
1034             p = &(new I(*p)).i;
1035         }
1036         ~this()
1037         {
1038             // note, this assert is invalid -- a struct should always be able
1039             // to run its dtor on the .init value, I'm leaving it here
1040             // commented out because the original test case had it. I'm not
1041             // sure what it's trying to prove.
1042             //
1043             // What happens now that minimallyInitializedArray adds the
1044             // destructor run to the GC, is that this assert would fire in the
1045             // GC, which triggers an invalid memory operation.
1046             //assert(p != null);
1047         }
1048     }
1049     auto a = minimallyInitializedArray!(S[])(1);
1050     assert(a[0].p == null);
1051     enum b = minimallyInitializedArray!(S[])(1);
1052     assert(b[0].p == null);
1053 }
1054 
1055 @safe nothrow unittest
1056 {
1057     static struct S1
1058     {
1059         this() @disable;
1060         this(this) @disable;
1061     }
1062     auto a1 = minimallyInitializedArray!(S1[][])(2, 2);
1063     assert(a1);
1064     static struct S2
1065     {
1066         this() @disable;
1067         //this(this) @disable;
1068     }
1069     auto a2 = minimallyInitializedArray!(S2[][])(2, 2);
1070     assert(a2);
1071     enum b2 = minimallyInitializedArray!(S2[][])(2, 2);
1072     assert(b2);
1073     static struct S3
1074     {
1075         //this() @disable;
1076         this(this) @disable;
1077     }
1078     auto a3 = minimallyInitializedArray!(S3[][])(2, 2);
1079     assert(a3);
1080     enum b3 = minimallyInitializedArray!(S3[][])(2, 2);
1081     assert(b3);
1082 }
1083 
1084 /++
1085 Returns the overlapping portion, if any, of two arrays. Unlike `equal`,
1086 `overlap` only compares the pointers and lengths in the
1087 ranges, not the values referred by them. If `r1` and `r2` have an
1088 overlapping slice, returns that slice. Otherwise, returns the null
1089 slice.
1090 
1091 Params:
1092     a = The first array to compare
1093     b = The second array to compare
1094 Returns:
1095     The overlapping portion of the two arrays.
1096 +/
1097 CommonType!(T[], U[]) overlap(T, U)(T[] a, U[] b) @trusted
1098 if (is(typeof(a.ptr < b.ptr) == bool))
1099 {
1100     import std.algorithm.comparison : min;
1101 
1102     auto end = min(a.ptr + a.length, b.ptr + b.length);
1103     // CTFE requires pairing pointer comparisons, which forces a
1104     // slightly inefficient implementation.
1105     if (a.ptr <= b.ptr && b.ptr < a.ptr + a.length)
1106     {
1107         return b.ptr[0 .. end - b.ptr];
1108     }
1109 
1110     if (b.ptr <= a.ptr && a.ptr < b.ptr + b.length)
1111     {
1112         return a.ptr[0 .. end - a.ptr];
1113     }
1114 
1115     return null;
1116 }
1117 
1118 ///
1119 @safe pure nothrow unittest
1120 {
1121     int[] a = [ 10, 11, 12, 13, 14 ];
1122     int[] b = a[1 .. 3];
1123     assert(overlap(a, b) == [ 11, 12 ]);
1124     b = b.dup;
1125     // overlap disappears even though the content is the same
1126     assert(overlap(a, b).empty);
1127 
1128     static test()() @nogc
1129     {
1130         auto a = "It's three o'clock"d;
1131         auto b = a[5 .. 10];
1132         return b.overlap(a);
1133     }
1134 
1135     //works at compile-time
1136     static assert(test == "three"d);
1137 }
1138 
1139 @safe nothrow unittest
1140 {
1141     static void test(L, R)(L l, R r)
1142     {
1143         assert(overlap(l, r) == [ 100, 12 ]);
1144 
1145         assert(overlap(l, l[0 .. 2]) is l[0 .. 2]);
1146         assert(overlap(l, l[3 .. 5]) is l[3 .. 5]);
1147         assert(overlap(l[0 .. 2], l) is l[0 .. 2]);
1148         assert(overlap(l[3 .. 5], l) is l[3 .. 5]);
1149     }
1150 
1151     int[] a = [ 10, 11, 12, 13, 14 ];
1152     int[] b = a[1 .. 3];
1153     a[1] = 100;
1154 
1155     immutable int[] c = a.idup;
1156     immutable int[] d = c[1 .. 3];
1157 
1158     test(a, b);
1159     assert(overlap(a, b.dup).empty);
1160     test(c, d);
1161     assert(overlap(c, d.idup).empty);
1162 }
1163 
1164  // https://issues.dlang.org/show_bug.cgi?id=9836
1165 @safe pure nothrow unittest
1166 {
1167     // range primitives for array should work with alias this types
1168     struct Wrapper
1169     {
1170         int[] data;
1171         alias data this;
1172 
1173         @property Wrapper save() { return this; }
1174     }
1175     auto w = Wrapper([1,2,3,4]);
1176     std.array.popFront(w); // should work
1177 
1178     static assert(isInputRange!Wrapper);
1179     static assert(isForwardRange!Wrapper);
1180     static assert(isBidirectionalRange!Wrapper);
1181     static assert(isRandomAccessRange!Wrapper);
1182 }
1183 
1184 private void copyBackwards(T)(T[] src, T[] dest)
1185 {
1186     import core.stdc..string : memmove;
1187     import std.format : format;
1188 
1189     assert(src.length == dest.length, format!
1190             "src.length %s must equal dest.length %s"(src.length, dest.length));
1191 
1192     if (!__ctfe || hasElaborateCopyConstructor!T)
1193     {
1194         /* insertInPlace relies on dest being uninitialized, so no postblits allowed,
1195          * as this is a MOVE that overwrites the destination, not a COPY.
1196          * BUG: insertInPlace will not work with ctfe and postblits
1197          */
1198         memmove(dest.ptr, src.ptr, src.length * T.sizeof);
1199     }
1200     else
1201     {
1202         immutable len = src.length;
1203         for (size_t i = len; i-- > 0;)
1204         {
1205             dest[i] = src[i];
1206         }
1207     }
1208 }
1209 
1210 /++
1211     Inserts `stuff` (which must be an input range or any number of
1212     implicitly convertible items) in `array` at position `pos`.
1213 
1214     Params:
1215         array = The array that `stuff` will be inserted into.
1216         pos   = The position in `array` to insert the `stuff`.
1217         stuff = An $(REF_ALTTEXT input range, isInputRange, std,range,primitives),
1218         or any number of implicitly convertible items to insert into `array`.
1219  +/
1220 void insertInPlace(T, U...)(ref T[] array, size_t pos, U stuff)
1221 if (!isSomeString!(T[])
1222     && allSatisfy!(isInputRangeOrConvertible!T, U) && U.length > 0)
1223 {
1224     static if (allSatisfy!(isInputRangeWithLengthOrConvertible!T, U))
1225     {
1226         import std.conv : emplaceRef;
1227 
1228         immutable oldLen = array.length;
1229 
1230         size_t to_insert = 0;
1231         foreach (i, E; U)
1232         {
1233             static if (is(E : T)) //a single convertible value, not a range
1234                 to_insert += 1;
1235             else
1236                 to_insert += stuff[i].length;
1237         }
1238         if (to_insert)
1239         {
1240             array.length += to_insert;
1241 
1242             // Takes arguments array, pos, stuff
1243             // Spread apart array[] at pos by moving elements
1244             (() @trusted { copyBackwards(array[pos .. oldLen], array[pos+to_insert..$]); })();
1245 
1246             // Initialize array[pos .. pos+to_insert] with stuff[]
1247             auto j = 0;
1248             foreach (i, E; U)
1249             {
1250                 static if (is(E : T))
1251                 {
1252                     emplaceRef!T(array[pos + j++], stuff[i]);
1253                 }
1254                 else
1255                 {
1256                     foreach (v; stuff[i])
1257                     {
1258                         emplaceRef!T(array[pos + j++], v);
1259                     }
1260                 }
1261             }
1262         }
1263     }
1264     else
1265     {
1266         // stuff has some InputRanges in it that don't have length
1267         // assume that stuff to be inserted is typically shorter
1268         // then the array that can be arbitrary big
1269         // TODO: needs a better implementation as there is no need to build an _array_
1270         // a singly-linked list of memory blocks (rope, etc.) will do
1271         auto app = appender!(T[])();
1272         foreach (i, E; U)
1273             app.put(stuff[i]);
1274         insertInPlace(array, pos, app.data);
1275     }
1276 }
1277 
1278 /// Ditto
1279 void insertInPlace(T, U...)(ref T[] array, size_t pos, U stuff)
1280 if (isSomeString!(T[]) && allSatisfy!(isCharOrStringOrDcharRange, U))
1281 {
1282     static if (is(Unqual!T == T)
1283         && allSatisfy!(isInputRangeWithLengthOrConvertible!dchar, U))
1284     {
1285         import std.utf : codeLength, byDchar;
1286         // mutable, can do in place
1287         //helper function: re-encode dchar to Ts and store at *ptr
1288         static T* putDChar(T* ptr, dchar ch)
1289         {
1290             static if (is(T == dchar))
1291             {
1292                 *ptr++ = ch;
1293                 return ptr;
1294             }
1295             else
1296             {
1297                 import std.utf : encode;
1298                 T[dchar.sizeof/T.sizeof] buf;
1299                 immutable len = encode(buf, ch);
1300                 final switch (len)
1301                 {
1302                     static if (T.sizeof == char.sizeof)
1303                     {
1304                 case 4:
1305                         ptr[3] = buf[3];
1306                         goto case;
1307                 case 3:
1308                         ptr[2] = buf[2];
1309                         goto case;
1310                     }
1311                 case 2:
1312                     ptr[1] = buf[1];
1313                     goto case;
1314                 case 1:
1315                     ptr[0] = buf[0];
1316                 }
1317                 ptr += len;
1318                 return ptr;
1319             }
1320         }
1321         size_t to_insert = 0;
1322         //count up the number of *codeunits* to insert
1323         foreach (i, E; U)
1324             to_insert += codeLength!T(stuff[i]);
1325         array.length += to_insert;
1326 
1327         @trusted static void moveToRight(T[] arr, size_t gap)
1328         {
1329             static assert(!hasElaborateCopyConstructor!T,
1330                     "T must not have an elaborate copy constructor");
1331             import core.stdc..string : memmove;
1332             if (__ctfe)
1333             {
1334                 for (size_t i = arr.length - gap; i; --i)
1335                     arr[gap + i - 1] = arr[i - 1];
1336             }
1337             else
1338                 memmove(arr.ptr + gap, arr.ptr, (arr.length - gap) * T.sizeof);
1339         }
1340         moveToRight(array[pos .. $], to_insert);
1341         auto ptr = array.ptr + pos;
1342         foreach (i, E; U)
1343         {
1344             static if (is(E : dchar))
1345             {
1346                 ptr = putDChar(ptr, stuff[i]);
1347             }
1348             else
1349             {
1350                 foreach (ch; stuff[i].byDchar)
1351                     ptr = putDChar(ptr, ch);
1352             }
1353         }
1354         assert(ptr == array.ptr + pos + to_insert, "(ptr == array.ptr + pos + to_insert) is false");
1355     }
1356     else
1357     {
1358         // immutable/const, just construct a new array
1359         auto app = appender!(T[])();
1360         app.put(array[0 .. pos]);
1361         foreach (i, E; U)
1362             app.put(stuff[i]);
1363         app.put(array[pos..$]);
1364         array = app.data;
1365     }
1366 }
1367 
1368 ///
1369 @safe pure unittest
1370 {
1371     int[] a = [ 1, 2, 3, 4 ];
1372     a.insertInPlace(2, [ 1, 2 ]);
1373     assert(a == [ 1, 2, 1, 2, 3, 4 ]);
1374     a.insertInPlace(3, 10u, 11);
1375     assert(a == [ 1, 2, 1, 10, 11, 2, 3, 4]);
1376 }
1377 
1378 //constraint helpers
1379 private template isInputRangeWithLengthOrConvertible(E)
1380 {
1381     template isInputRangeWithLengthOrConvertible(R)
1382     {
1383         //hasLength not defined for char[], wchar[] and dchar[]
1384         enum isInputRangeWithLengthOrConvertible =
1385             (isInputRange!R && is(typeof(R.init.length))
1386                 && is(ElementType!R : E))  || is(R : E);
1387     }
1388 }
1389 
1390 //ditto
1391 private template isCharOrStringOrDcharRange(T)
1392 {
1393     enum isCharOrStringOrDcharRange = isSomeString!T || isSomeChar!T ||
1394         (isInputRange!T && is(ElementType!T : dchar));
1395 }
1396 
1397 //ditto
1398 private template isInputRangeOrConvertible(E)
1399 {
1400     template isInputRangeOrConvertible(R)
1401     {
1402         enum isInputRangeOrConvertible =
1403             (isInputRange!R && is(ElementType!R : E))  || is(R : E);
1404     }
1405 }
1406 
1407 @system unittest
1408 {
1409     // @system due to insertInPlace
1410     import core.exception;
1411     import std.algorithm.comparison : equal;
1412     import std.algorithm.iteration : filter;
1413     import std.conv : to;
1414     import std.exception;
1415 
1416 
1417     bool test(T, U, V)(T orig, size_t pos, U toInsert, V result)
1418     {
1419         {
1420             static if (is(T == typeof(T.init.dup)))
1421                 auto a = orig.dup;
1422             else
1423                 auto a = orig.idup;
1424 
1425             a.insertInPlace(pos, toInsert);
1426             if (!equal(a, result))
1427                 return false;
1428         }
1429 
1430         static if (isInputRange!U)
1431         {
1432             orig.insertInPlace(pos, filter!"true"(toInsert));
1433             return equal(orig, result);
1434         }
1435         else
1436             return true;
1437     }
1438 
1439 
1440     assert(test([1, 2, 3, 4], 0, [6, 7], [6, 7, 1, 2, 3, 4]));
1441     assert(test([1, 2, 3, 4], 2, [8, 9], [1, 2, 8, 9, 3, 4]));
1442     assert(test([1, 2, 3, 4], 4, [10, 11], [1, 2, 3, 4, 10, 11]));
1443 
1444     assert(test([1, 2, 3, 4], 0, 22, [22, 1, 2, 3, 4]));
1445     assert(test([1, 2, 3, 4], 2, 23, [1, 2, 23, 3, 4]));
1446     assert(test([1, 2, 3, 4], 4, 24, [1, 2, 3, 4, 24]));
1447 
1448     void testStr(T, U)(string file = __FILE__, size_t line = __LINE__)
1449     {
1450 
1451         auto l = to!T("hello");
1452         auto r = to!U(" વિશ્વ");
1453 
1454         enforce(test(l, 0, r, " વિશ્વhello"),
1455                 new AssertError("testStr failure 1", file, line));
1456         enforce(test(l, 3, r, "hel વિશ્વlo"),
1457                 new AssertError("testStr failure 2", file, line));
1458         enforce(test(l, l.length, r, "hello વિશ્વ"),
1459                 new AssertError("testStr failure 3", file, line));
1460     }
1461 
1462     static foreach (T; AliasSeq!(char, wchar, dchar,
1463         immutable(char), immutable(wchar), immutable(dchar)))
1464     {
1465         static foreach (U; AliasSeq!(char, wchar, dchar,
1466             immutable(char), immutable(wchar), immutable(dchar)))
1467         {
1468             testStr!(T[], U[])();
1469         }
1470 
1471     }
1472 
1473     // variadic version
1474     bool testVar(T, U...)(T orig, size_t pos, U args)
1475     {
1476         static if (is(T == typeof(T.init.dup)))
1477             auto a = orig.dup;
1478         else
1479             auto a = orig.idup;
1480         auto result = args[$-1];
1481 
1482         a.insertInPlace(pos, args[0..$-1]);
1483         if (!equal(a, result))
1484             return false;
1485         return true;
1486     }
1487     assert(testVar([1, 2, 3, 4], 0, 6, 7u, [6, 7, 1, 2, 3, 4]));
1488     assert(testVar([1L, 2, 3, 4], 2, 8, 9L, [1, 2, 8, 9, 3, 4]));
1489     assert(testVar([1L, 2, 3, 4], 4, 10L, 11, [1, 2, 3, 4, 10, 11]));
1490     assert(testVar([1L, 2, 3, 4], 4, [10, 11], 40L, 42L,
1491                     [1, 2, 3, 4, 10, 11, 40, 42]));
1492     assert(testVar([1L, 2, 3, 4], 4, 10, 11, [40L, 42],
1493                     [1, 2, 3, 4, 10, 11, 40, 42]));
1494     assert(testVar("t".idup, 1, 'e', 's', 't', "test"));
1495     assert(testVar("!!"w.idup, 1, "\u00e9ll\u00f4", 'x', "TTT"w, 'y',
1496                     "!\u00e9ll\u00f4xTTTy!"));
1497     assert(testVar("flipflop"d.idup, 4, '_',
1498                     "xyz"w, '\U00010143', '_', "abc"d, "__",
1499                     "flip_xyz\U00010143_abc__flop"));
1500 }
1501 
1502 @system unittest
1503 {
1504     import std.algorithm.comparison : equal;
1505     // insertInPlace interop with postblit
1506     static struct Int
1507     {
1508         int* payload;
1509         this(int k)
1510         {
1511             payload = new int;
1512             *payload = k;
1513         }
1514         this(this)
1515         {
1516             int* np = new int;
1517             *np = *payload;
1518             payload = np;
1519         }
1520         ~this()
1521         {
1522             if (payload)
1523                 *payload = 0; //'destroy' it
1524         }
1525         @property int getPayload(){ return *payload; }
1526         alias getPayload this;
1527     }
1528 
1529     Int[] arr = [Int(1), Int(4), Int(5)];
1530     assert(arr[0] == 1);
1531     insertInPlace(arr, 1, Int(2), Int(3));
1532     assert(equal(arr, [1, 2, 3, 4, 5]));  //check it works with postblit
1533 }
1534 
1535 @safe unittest
1536 {
1537     import std.exception;
1538     assertCTFEable!(
1539     {
1540         int[] a = [1, 2];
1541         a.insertInPlace(2, 3);
1542         a.insertInPlace(0, -1, 0);
1543         return a == [-1, 0, 1, 2, 3];
1544     });
1545 }
1546 
1547 // https://issues.dlang.org/show_bug.cgi?id=6874
1548 @system unittest
1549 {
1550     import core.memory;
1551     // allocate some space
1552     byte[] a;
1553     a.length = 1;
1554 
1555     // fill it
1556     a.length = a.capacity;
1557 
1558     // write beyond
1559     byte[] b = a[$ .. $];
1560     b.insertInPlace(0, a);
1561 
1562     // make sure that reallocation has happened
1563     assert(GC.addrOf(&b[0]) == GC.addrOf(&b[$-1]));
1564 }
1565 
1566 
1567 /++
1568     Returns whether the `front`s of `lhs` and `rhs` both refer to the
1569     same place in memory, making one of the arrays a slice of the other which
1570     starts at index `0`.
1571 
1572     Params:
1573         lhs = the first array to compare
1574         rhs = the second array to compare
1575     Returns:
1576         `true` if $(D lhs.ptr == rhs.ptr), `false` otherwise.
1577   +/
1578 @safe
1579 pure nothrow bool sameHead(T)(in T[] lhs, in T[] rhs)
1580 {
1581     return lhs.ptr == rhs.ptr;
1582 }
1583 
1584 ///
1585 @safe pure nothrow unittest
1586 {
1587     auto a = [1, 2, 3, 4, 5];
1588     auto b = a[0 .. 2];
1589 
1590     assert(a.sameHead(b));
1591 }
1592 
1593 
1594 /++
1595     Returns whether the `back`s of `lhs` and `rhs` both refer to the
1596     same place in memory, making one of the arrays a slice of the other which
1597     end at index `$`.
1598 
1599     Params:
1600         lhs = the first array to compare
1601         rhs = the second array to compare
1602     Returns:
1603         `true` if both arrays are the same length and $(D lhs.ptr == rhs.ptr),
1604         `false` otherwise.
1605   +/
1606 @trusted
1607 pure nothrow bool sameTail(T)(in T[] lhs, in T[] rhs)
1608 {
1609     return lhs.ptr + lhs.length == rhs.ptr + rhs.length;
1610 }
1611 
1612 ///
1613 @safe pure nothrow unittest
1614 {
1615     auto a = [1, 2, 3, 4, 5];
1616     auto b = a[3..$];
1617 
1618     assert(a.sameTail(b));
1619 }
1620 
1621 @safe pure nothrow unittest
1622 {
1623     static foreach (T; AliasSeq!(int[], const(int)[], immutable(int)[], const int[], immutable int[]))
1624     {{
1625         T a = [1, 2, 3, 4, 5];
1626         T b = a;
1627         T c = a[1 .. $];
1628         T d = a[0 .. 1];
1629         T e = null;
1630 
1631         assert(sameHead(a, a));
1632         assert(sameHead(a, b));
1633         assert(!sameHead(a, c));
1634         assert(sameHead(a, d));
1635         assert(!sameHead(a, e));
1636 
1637         assert(sameTail(a, a));
1638         assert(sameTail(a, b));
1639         assert(sameTail(a, c));
1640         assert(!sameTail(a, d));
1641         assert(!sameTail(a, e));
1642 
1643         //verifies R-value compatibilty
1644         assert(a.sameHead(a[0 .. 0]));
1645         assert(a.sameTail(a[$ .. $]));
1646     }}
1647 }
1648 
1649 /**
1650 Params:
1651     s = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
1652     or a dynamic array
1653     n = number of times to repeat `s`
1654 
1655 Returns:
1656     An array that consists of `s` repeated `n` times. This function allocates, fills, and
1657     returns a new array.
1658 
1659 See_Also:
1660     For a lazy version, refer to $(REF repeat, std,range).
1661  */
1662 ElementEncodingType!S[] replicate(S)(S s, size_t n)
1663 if (isDynamicArray!S)
1664 {
1665     alias RetType = ElementEncodingType!S[];
1666 
1667     // Optimization for return join(std.range.repeat(s, n));
1668     if (n == 0)
1669         return RetType.init;
1670     if (n == 1)
1671         return cast(RetType) s;
1672     auto r = new Unqual!(typeof(s[0]))[n * s.length];
1673     if (s.length == 1)
1674         r[] = s[0];
1675     else
1676     {
1677         immutable len = s.length, nlen = n * len;
1678         for (size_t i = 0; i < nlen; i += len)
1679         {
1680             r[i .. i + len] = s[];
1681         }
1682     }
1683     return r;
1684 }
1685 
1686 /// ditto
1687 ElementType!S[] replicate(S)(S s, size_t n)
1688 if (isInputRange!S && !isDynamicArray!S)
1689 {
1690     import std.range : repeat;
1691     return join(std.range.repeat(s, n));
1692 }
1693 
1694 
1695 ///
1696 @safe unittest
1697 {
1698     auto a = "abc";
1699     auto s = replicate(a, 3);
1700 
1701     assert(s == "abcabcabc");
1702 
1703     auto b = [1, 2, 3];
1704     auto c = replicate(b, 3);
1705 
1706     assert(c == [1, 2, 3, 1, 2, 3, 1, 2, 3]);
1707 
1708     auto d = replicate(b, 0);
1709 
1710     assert(d == []);
1711 }
1712 
1713 @safe unittest
1714 {
1715     import std.conv : to;
1716 
1717     static foreach (S; AliasSeq!(string, wstring, dstring, char[], wchar[], dchar[]))
1718     {{
1719         immutable S t = "abc";
1720 
1721         assert(replicate(to!S("1234"), 0) is null);
1722         assert(replicate(to!S("1234"), 0) is null);
1723         assert(replicate(to!S("1234"), 1) == "1234");
1724         assert(replicate(to!S("1234"), 2) == "12341234");
1725         assert(replicate(to!S("1"), 4) == "1111");
1726         assert(replicate(t, 3) == "abcabcabc");
1727         assert(replicate(cast(S) null, 4) is null);
1728     }}
1729 }
1730 
1731 /++
1732 Eagerly splits `range` into an array, using `sep` as the delimiter.
1733 
1734 When no delimiter is provided, strings are split into an array of words,
1735 using whitespace as delimiter.
1736 Runs of whitespace are merged together (no empty words are produced).
1737 
1738 The `range` must be a $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives).
1739 The separator can be a value of the same type as the elements in `range`
1740 or it can be another forward `range`.
1741 
1742 Params:
1743     s = the string to split by word if no separator is given
1744     range = the range to split
1745     sep = a value of the same type as the elements of `range` or another
1746     isTerminator = a predicate that splits the range when it returns `true`.
1747 
1748 Returns:
1749     An array containing the divided parts of `range` (or the words of `s`).
1750 
1751 See_Also:
1752 $(REF splitter, std,algorithm,iteration) for a lazy version without allocating memory.
1753 
1754 $(REF splitter, std,regex) for a version that splits using a regular
1755 expression defined separator.
1756 +/
1757 S[] split(S)(S s) @safe pure
1758 if (isSomeString!S)
1759 {
1760     size_t istart;
1761     bool inword = false;
1762     auto result = appender!(S[]);
1763 
1764     foreach (i, dchar c ; s)
1765     {
1766         import std.uni : isWhite;
1767         if (isWhite(c))
1768         {
1769             if (inword)
1770             {
1771                 put(result, s[istart .. i]);
1772                 inword = false;
1773             }
1774         }
1775         else
1776         {
1777             if (!inword)
1778             {
1779                 istart = i;
1780                 inword = true;
1781             }
1782         }
1783     }
1784     if (inword)
1785         put(result, s[istart .. $]);
1786     return result.data;
1787 }
1788 
1789 ///
1790 @safe unittest
1791 {
1792     import std.uni : isWhite;
1793     assert("Learning,D,is,fun".split(",") == ["Learning", "D", "is", "fun"]);
1794     assert("Learning D is fun".split!isWhite == ["Learning", "D", "is", "fun"]);
1795     assert("Learning D is fun".split(" D ") == ["Learning", "is fun"]);
1796 }
1797 
1798 ///
1799 @safe unittest
1800 {
1801     string str = "Hello World!";
1802     assert(str.split == ["Hello", "World!"]);
1803 
1804     string str2 = "Hello\t\tWorld\t!";
1805     assert(str2.split == ["Hello", "World", "!"]);
1806 }
1807 
1808 @safe unittest
1809 {
1810     import std.conv : to;
1811     import std.format;
1812     import std.typecons;
1813 
1814     static auto makeEntry(S)(string l, string[] r)
1815     {return tuple(l.to!S(), r.to!(S[])());}
1816 
1817     static foreach (S; AliasSeq!(string, wstring, dstring,))
1818     {{
1819         auto entries =
1820         [
1821             makeEntry!S("", []),
1822             makeEntry!S(" ", []),
1823             makeEntry!S("hello", ["hello"]),
1824             makeEntry!S(" hello ", ["hello"]),
1825             makeEntry!S("  h  e  l  l  o ", ["h", "e", "l", "l", "o"]),
1826             makeEntry!S("peter\t\npaul\rjerry", ["peter", "paul", "jerry"]),
1827             makeEntry!S(" \t\npeter paul\tjerry \n", ["peter", "paul", "jerry"]),
1828             makeEntry!S("\u2000日\u202F本\u205F語\u3000", ["日", "本", "語"]),
1829             makeEntry!S("  哈・郎博尔德}    ___一个", ["哈・郎博尔德}", "___一个"])
1830         ];
1831         foreach (entry; entries)
1832             assert(entry[0].split() == entry[1], format("got: %s, expected: %s.", entry[0].split(), entry[1]));
1833     }}
1834 
1835     //Just to test that an immutable is split-able
1836     immutable string s = " \t\npeter paul\tjerry \n";
1837     assert(split(s) == ["peter", "paul", "jerry"]);
1838 }
1839 
1840 @safe unittest //purity, ctfe ...
1841 {
1842     import std.exception;
1843     void dg() @safe pure {
1844         assert(split("hello world"c) == ["hello"c, "world"c]);
1845         assert(split("hello world"w) == ["hello"w, "world"w]);
1846         assert(split("hello world"d) == ["hello"d, "world"d]);
1847     }
1848     dg();
1849     assertCTFEable!dg;
1850 }
1851 
1852 ///
1853 @safe unittest
1854 {
1855     assert(split("hello world") == ["hello","world"]);
1856     assert(split("192.168.0.1", ".") == ["192", "168", "0", "1"]);
1857 
1858     auto a = split([1, 2, 3, 4, 5, 1, 2, 3, 4, 5], [2, 3]);
1859     assert(a == [[1], [4, 5, 1], [4, 5]]);
1860 }
1861 
1862 ///ditto
1863 auto split(Range, Separator)(Range range, Separator sep)
1864 if (isForwardRange!Range && (
1865     is(typeof(ElementType!Range.init == Separator.init)) ||
1866     is(typeof(ElementType!Range.init == ElementType!Separator.init)) && isForwardRange!Separator
1867     ))
1868 {
1869     import std.algorithm.iteration : splitter;
1870     return range.splitter(sep).array;
1871 }
1872 ///ditto
1873 auto split(alias isTerminator, Range)(Range range)
1874 if (isForwardRange!Range && is(typeof(unaryFun!isTerminator(range.front))))
1875 {
1876     import std.algorithm.iteration : splitter;
1877     return range.splitter!isTerminator.array;
1878 }
1879 
1880 @safe unittest
1881 {
1882     import std.algorithm.comparison : cmp;
1883     import std.conv;
1884 
1885     static foreach (S; AliasSeq!(string, wstring, dstring,
1886                     immutable(string), immutable(wstring), immutable(dstring),
1887                     char[], wchar[], dchar[],
1888                     const(char)[], const(wchar)[], const(dchar)[],
1889                     const(char[]), immutable(char[])))
1890     {{
1891         S s = to!S(",peter,paul,jerry,");
1892 
1893         auto words = split(s, ",");
1894         assert(words.length == 5, text(words.length));
1895         assert(cmp(words[0], "") == 0);
1896         assert(cmp(words[1], "peter") == 0);
1897         assert(cmp(words[2], "paul") == 0);
1898         assert(cmp(words[3], "jerry") == 0);
1899         assert(cmp(words[4], "") == 0);
1900 
1901         auto s1 = s[0 .. s.length - 1];   // lop off trailing ','
1902         words = split(s1, ",");
1903         assert(words.length == 4);
1904         assert(cmp(words[3], "jerry") == 0);
1905 
1906         auto s2 = s1[1 .. s1.length];   // lop off leading ','
1907         words = split(s2, ",");
1908         assert(words.length == 3);
1909         assert(cmp(words[0], "peter") == 0);
1910 
1911         auto s3 = to!S(",,peter,,paul,,jerry,,");
1912 
1913         words = split(s3, ",,");
1914         assert(words.length == 5);
1915         assert(cmp(words[0], "") == 0);
1916         assert(cmp(words[1], "peter") == 0);
1917         assert(cmp(words[2], "paul") == 0);
1918         assert(cmp(words[3], "jerry") == 0);
1919         assert(cmp(words[4], "") == 0);
1920 
1921         auto s4 = s3[0 .. s3.length - 2];    // lop off trailing ',,'
1922         words = split(s4, ",,");
1923         assert(words.length == 4);
1924         assert(cmp(words[3], "jerry") == 0);
1925 
1926         auto s5 = s4[2 .. s4.length];    // lop off leading ',,'
1927         words = split(s5, ",,");
1928         assert(words.length == 3);
1929         assert(cmp(words[0], "peter") == 0);
1930     }}
1931 }
1932 
1933 /+
1934    Conservative heuristic to determine if a range can be iterated cheaply.
1935    Used by `join` in decision to do an extra iteration of the range to
1936    compute the resultant length. If iteration is not cheap then precomputing
1937    length could be more expensive than using `Appender`.
1938 
1939    For now, we only assume arrays are cheap to iterate.
1940  +/
1941 private enum bool hasCheapIteration(R) = isArray!R;
1942 
1943 /++
1944    Eagerly concatenates all of the ranges in `ror` together (with the GC)
1945    into one array using `sep` as the separator if present.
1946 
1947    Params:
1948         ror = An $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
1949         of input ranges
1950         sep = An input range, or a single element, to join the ranges on
1951 
1952    Returns:
1953         An array of elements
1954 
1955    See_Also:
1956         For a lazy version, see $(REF joiner, std,algorithm,iteration)
1957   +/
1958 ElementEncodingType!(ElementType!RoR)[] join(RoR, R)(RoR ror, scope R sep)
1959 if (isInputRange!RoR &&
1960     isInputRange!(Unqual!(ElementType!RoR)) &&
1961     isInputRange!R &&
1962     (is(immutable ElementType!(ElementType!RoR) == immutable ElementType!R) ||
1963      (isSomeChar!(ElementType!(ElementType!RoR)) && isSomeChar!(ElementType!R))
1964     ))
1965 {
1966     alias RetType = typeof(return);
1967     alias RetTypeElement = Unqual!(ElementEncodingType!RetType);
1968     alias RoRElem = ElementType!RoR;
1969 
1970     if (ror.empty)
1971         return RetType.init;
1972 
1973     // Constraint only requires input range for sep.
1974     // This converts sep to an array (forward range) if it isn't one,
1975     // and makes sure it has the same string encoding for string types.
1976     static if (isSomeString!RetType &&
1977                !is(immutable ElementEncodingType!RetType == immutable ElementEncodingType!R))
1978     {
1979         import std.conv : to;
1980         auto sepArr = to!RetType(sep);
1981     }
1982     else static if (!isArray!R)
1983         auto sepArr = array(sep);
1984     else
1985         alias sepArr = sep;
1986 
1987     static if (hasCheapIteration!RoR && (hasLength!RoRElem || isNarrowString!RoRElem))
1988     {
1989         import std.conv : emplaceRef;
1990         size_t length;          // length of result array
1991         size_t rorLength;       // length of range ror
1992         foreach (r; ror.save)
1993         {
1994             length += r.length;
1995             ++rorLength;
1996         }
1997         if (!rorLength)
1998             return null;
1999         length += (rorLength - 1) * sepArr.length;
2000 
2001         auto result = (() @trusted => uninitializedArray!(RetTypeElement[])(length))();
2002         size_t len;
2003         foreach (e; ror.front)
2004             emplaceRef(result[len++], e);
2005         ror.popFront();
2006         foreach (r; ror)
2007         {
2008             foreach (e; sepArr)
2009                 emplaceRef(result[len++], e);
2010             foreach (e; r)
2011                 emplaceRef(result[len++], e);
2012         }
2013         assert(len == result.length);
2014         return (() @trusted => cast(RetType) result)();
2015     }
2016     else
2017     {
2018         auto result = appender!RetType();
2019         put(result, ror.front);
2020         ror.popFront();
2021         for (; !ror.empty; ror.popFront())
2022         {
2023             put(result, sep);
2024             put(result, ror.front);
2025         }
2026         return result.data;
2027     }
2028 }
2029 
2030 // https://issues.dlang.org/show_bug.cgi?id=14230
2031 @safe unittest
2032 {
2033    string[] ary = ["","aa","bb","cc"]; // leaded by _empty_ element
2034    assert(ary.join(" @") == " @aa @bb @cc"); // OK in 2.067b1 and olders
2035 }
2036 
2037 /// Ditto
2038 ElementEncodingType!(ElementType!RoR)[] join(RoR, E)(RoR ror, scope E sep)
2039 if (isInputRange!RoR &&
2040     isInputRange!(Unqual!(ElementType!RoR)) &&
2041     ((is(E : ElementType!(ElementType!RoR))) ||
2042      (!autodecodeStrings && isSomeChar!(ElementType!(ElementType!RoR)) &&
2043       isSomeChar!E)))
2044 {
2045     alias RetType = typeof(return);
2046     alias RetTypeElement = Unqual!(ElementEncodingType!RetType);
2047     alias RoRElem = ElementType!RoR;
2048 
2049     if (ror.empty)
2050         return RetType.init;
2051 
2052     static if (hasCheapIteration!RoR && (hasLength!RoRElem || isNarrowString!RoRElem))
2053     {
2054         static if (isSomeChar!E && isSomeChar!RetTypeElement && E.sizeof > RetTypeElement.sizeof)
2055         {
2056             import std.utf : encode;
2057             RetTypeElement[4 / RetTypeElement.sizeof] encodeSpace;
2058             immutable size_t sepArrLength = encode(encodeSpace, sep);
2059             return join(ror, encodeSpace[0 .. sepArrLength]);
2060         }
2061         else
2062         {
2063             import std.conv : emplaceRef;
2064             import std.format : format;
2065             size_t length;
2066             size_t rorLength;
2067             foreach (r; ror.save)
2068             {
2069                 length += r.length;
2070                 ++rorLength;
2071             }
2072             if (!rorLength)
2073                 return null;
2074             length += rorLength - 1;
2075             auto result = uninitializedArray!(RetTypeElement[])(length);
2076 
2077 
2078             size_t len;
2079             foreach (e; ror.front)
2080                 emplaceRef(result[len++], e);
2081             ror.popFront();
2082             foreach (r; ror)
2083             {
2084                 emplaceRef(result[len++], sep);
2085                 foreach (e; r)
2086                     emplaceRef(result[len++], e);
2087             }
2088             assert(len == result.length, format!
2089                     "len %s must equal result.lenght %s"(len, result.length));
2090             return (() @trusted => cast(RetType) result)();
2091         }
2092     }
2093     else
2094     {
2095         auto result = appender!RetType();
2096         put(result, ror.front);
2097         ror.popFront();
2098         for (; !ror.empty; ror.popFront())
2099         {
2100             put(result, sep);
2101             put(result, ror.front);
2102         }
2103         return result.data;
2104     }
2105 }
2106 
2107 // https://issues.dlang.org/show_bug.cgi?id=10895
2108 @safe unittest
2109 {
2110     class A
2111     {
2112         string name;
2113         alias name this;
2114         this(string name) { this.name = name; }
2115     }
2116     auto a = [new A(`foo`)];
2117     assert(a[0].length == 3);
2118     auto temp = join(a, " ");
2119     assert(a[0].length == 3);
2120     assert(temp.length == 3);
2121 }
2122 
2123 // https://issues.dlang.org/show_bug.cgi?id=14230
2124 @safe unittest
2125 {
2126    string[] ary = ["","aa","bb","cc"];
2127    assert(ary.join('@') == "@aa@bb@cc");
2128 }
2129 
2130 /// Ditto
2131 ElementEncodingType!(ElementType!RoR)[] join(RoR)(RoR ror)
2132 if (isInputRange!RoR &&
2133     isInputRange!(Unqual!(ElementType!RoR)))
2134 {
2135     alias RetType = typeof(return);
2136     alias ConstRetTypeElement = ElementEncodingType!RetType;
2137     static if (isAssignable!(Unqual!ConstRetTypeElement, ConstRetTypeElement))
2138     {
2139         alias RetTypeElement = Unqual!ConstRetTypeElement;
2140     }
2141     else
2142     {
2143         alias RetTypeElement = ConstRetTypeElement;
2144     }
2145     alias RoRElem = ElementType!RoR;
2146 
2147     if (ror.empty)
2148         return RetType.init;
2149 
2150     static if (hasCheapIteration!RoR && (hasLength!RoRElem || isNarrowString!RoRElem))
2151     {
2152         import std.conv : emplaceRef;
2153         size_t length;
2154         foreach (r; ror.save)
2155             length += r.length;
2156 
2157         auto result = (() @trusted => uninitializedArray!(RetTypeElement[])(length))();
2158         size_t len;
2159         foreach (r; ror)
2160             foreach (e; r)
2161                 emplaceRef!RetTypeElement(result[len++], e);
2162         assert(len == result.length,
2163                 "emplaced an unexpected number of elements");
2164         return (() @trusted => cast(RetType) result)();
2165     }
2166     else
2167     {
2168         auto result = appender!RetType();
2169         for (; !ror.empty; ror.popFront())
2170             put(result, ror.front);
2171         return result.data;
2172     }
2173 }
2174 
2175 ///
2176 @safe pure nothrow unittest
2177 {
2178     assert(join(["hello", "silly", "world"], " ") == "hello silly world");
2179     assert(join(["hello", "silly", "world"]) == "hellosillyworld");
2180 
2181     assert(join([[1, 2, 3], [4, 5]], [72, 73]) == [1, 2, 3, 72, 73, 4, 5]);
2182     assert(join([[1, 2, 3], [4, 5]]) == [1, 2, 3, 4, 5]);
2183 
2184     const string[] arr = ["apple", "banana"];
2185     assert(arr.join(",") == "apple,banana");
2186     assert(arr.join() == "applebanana");
2187 }
2188 
2189 @safe pure unittest
2190 {
2191     import std.conv : to;
2192     import std.range.primitives : autodecodeStrings;
2193 
2194     static foreach (T; AliasSeq!(string,wstring,dstring))
2195     {{
2196         auto arr2 = "Здравствуй Мир Unicode".to!(T);
2197         auto arr = ["Здравствуй", "Мир", "Unicode"].to!(T[]);
2198         assert(join(arr) == "ЗдравствуйМирUnicode");
2199         static foreach (S; AliasSeq!(char,wchar,dchar))
2200         {{
2201             auto jarr = arr.join(to!S(' '));
2202             static assert(is(typeof(jarr) == T));
2203             assert(jarr == arr2);
2204         }}
2205         static foreach (S; AliasSeq!(string,wstring,dstring))
2206         {{
2207             auto jarr = arr.join(to!S(" "));
2208             static assert(is(typeof(jarr) == T));
2209             assert(jarr == arr2);
2210         }}
2211     }}
2212 
2213     static foreach (T; AliasSeq!(string,wstring,dstring))
2214     {{
2215         auto arr2 = "Здравствуй\u047CМир\u047CUnicode".to!(T);
2216         auto arr = ["Здравствуй", "Мир", "Unicode"].to!(T[]);
2217         static foreach (S; AliasSeq!(wchar,dchar))
2218         {{
2219             auto jarr = arr.join(to!S('\u047C'));
2220             static assert(is(typeof(jarr) == T));
2221             assert(jarr == arr2);
2222         }}
2223     }}
2224 
2225     const string[] arr = ["apple", "banana"];
2226     assert(arr.join(',') == "apple,banana");
2227 }
2228 
2229 @safe unittest
2230 {
2231     class A { }
2232 
2233     const A[][] array;
2234     auto result = array.join; // can't remove constness, so don't try
2235 
2236     static assert(is(typeof(result) == const(A)[]));
2237 }
2238 
2239 @safe unittest
2240 {
2241     import std.algorithm;
2242     import std.conv : to;
2243     import std.range;
2244 
2245     static foreach (R; AliasSeq!(string, wstring, dstring))
2246     {{
2247         R word1 = "日本語";
2248         R word2 = "paul";
2249         R word3 = "jerry";
2250         R[] words = [word1, word2, word3];
2251 
2252         auto filteredWord1    = filter!"true"(word1);
2253         auto filteredLenWord1 = takeExactly(filteredWord1, word1.walkLength());
2254         auto filteredWord2    = filter!"true"(word2);
2255         auto filteredLenWord2 = takeExactly(filteredWord2, word2.walkLength());
2256         auto filteredWord3    = filter!"true"(word3);
2257         auto filteredLenWord3 = takeExactly(filteredWord3, word3.walkLength());
2258         auto filteredWordsArr = [filteredWord1, filteredWord2, filteredWord3];
2259         auto filteredLenWordsArr = [filteredLenWord1, filteredLenWord2, filteredLenWord3];
2260         auto filteredWords    = filter!"true"(filteredWordsArr);
2261 
2262         static foreach (S; AliasSeq!(string, wstring, dstring))
2263         {{
2264             assert(join(filteredWords, to!S(", ")) == "日本語, paul, jerry");
2265             assert(join(filteredWords, to!(ElementType!S)(',')) == "日本語,paul,jerry");
2266             assert(join(filteredWordsArr, to!(ElementType!(S))(',')) == "日本語,paul,jerry");
2267             assert(join(filteredWordsArr, to!S(", ")) == "日本語, paul, jerry");
2268             assert(join(filteredWordsArr, to!(ElementType!(S))(',')) == "日本語,paul,jerry");
2269             assert(join(filteredLenWordsArr, to!S(", ")) == "日本語, paul, jerry");
2270             assert(join(filter!"true"(words), to!S(", ")) == "日本語, paul, jerry");
2271             assert(join(words, to!S(", ")) == "日本語, paul, jerry");
2272 
2273             assert(join(filteredWords, to!S("")) == "日本語pauljerry");
2274             assert(join(filteredWordsArr, to!S("")) == "日本語pauljerry");
2275             assert(join(filteredLenWordsArr, to!S("")) == "日本語pauljerry");
2276             assert(join(filter!"true"(words), to!S("")) == "日本語pauljerry");
2277             assert(join(words, to!S("")) == "日本語pauljerry");
2278 
2279             assert(join(filter!"true"([word1]), to!S(", ")) == "日本語");
2280             assert(join([filteredWord1], to!S(", ")) == "日本語");
2281             assert(join([filteredLenWord1], to!S(", ")) == "日本語");
2282             assert(join(filter!"true"([filteredWord1]), to!S(", ")) == "日本語");
2283             assert(join([word1], to!S(", ")) == "日本語");
2284 
2285             assert(join(filteredWords, to!S(word1)) == "日本語日本語paul日本語jerry");
2286             assert(join(filteredWordsArr, to!S(word1)) == "日本語日本語paul日本語jerry");
2287             assert(join(filteredLenWordsArr, to!S(word1)) == "日本語日本語paul日本語jerry");
2288             assert(join(filter!"true"(words), to!S(word1)) == "日本語日本語paul日本語jerry");
2289             assert(join(words, to!S(word1)) == "日本語日本語paul日本語jerry");
2290 
2291             auto filterComma = filter!"true"(to!S(", "));
2292             assert(join(filteredWords, filterComma) == "日本語, paul, jerry");
2293             assert(join(filteredWordsArr, filterComma) == "日本語, paul, jerry");
2294             assert(join(filteredLenWordsArr, filterComma) == "日本語, paul, jerry");
2295             assert(join(filter!"true"(words), filterComma) == "日本語, paul, jerry");
2296             assert(join(words, filterComma) == "日本語, paul, jerry");
2297         }}
2298 
2299         assert(join(filteredWords) == "日本語pauljerry");
2300         assert(join(filteredWordsArr) == "日本語pauljerry");
2301         assert(join(filteredLenWordsArr) == "日本語pauljerry");
2302         assert(join(filter!"true"(words)) == "日本語pauljerry");
2303         assert(join(words) == "日本語pauljerry");
2304 
2305         assert(join(filteredWords, filter!"true"(", ")) == "日本語, paul, jerry");
2306         assert(join(filteredWordsArr, filter!"true"(", ")) == "日本語, paul, jerry");
2307         assert(join(filteredLenWordsArr, filter!"true"(", ")) == "日本語, paul, jerry");
2308         assert(join(filter!"true"(words), filter!"true"(", ")) == "日本語, paul, jerry");
2309         assert(join(words, filter!"true"(", ")) == "日本語, paul, jerry");
2310 
2311         assert(join(filter!"true"(cast(typeof(filteredWordsArr))[]), ", ").empty);
2312         assert(join(cast(typeof(filteredWordsArr))[], ", ").empty);
2313         assert(join(cast(typeof(filteredLenWordsArr))[], ", ").empty);
2314         assert(join(filter!"true"(cast(R[])[]), ", ").empty);
2315         assert(join(cast(R[])[], ", ").empty);
2316 
2317         assert(join(filter!"true"(cast(typeof(filteredWordsArr))[])).empty);
2318         assert(join(cast(typeof(filteredWordsArr))[]).empty);
2319         assert(join(cast(typeof(filteredLenWordsArr))[]).empty);
2320 
2321         assert(join(filter!"true"(cast(R[])[])).empty);
2322         assert(join(cast(R[])[]).empty);
2323     }}
2324 
2325     assert(join([[1, 2], [41, 42]], [5, 6]) == [1, 2, 5, 6, 41, 42]);
2326     assert(join([[1, 2], [41, 42]], cast(int[])[]) == [1, 2, 41, 42]);
2327     assert(join([[1, 2]], [5, 6]) == [1, 2]);
2328     assert(join(cast(int[][])[], [5, 6]).empty);
2329 
2330     assert(join([[1, 2], [41, 42]]) == [1, 2, 41, 42]);
2331     assert(join(cast(int[][])[]).empty);
2332 
2333     alias f = filter!"true";
2334     assert(join([[1, 2], [41, 42]],          [5, 6]) == [1, 2, 5, 6, 41, 42]);
2335     assert(join(f([[1, 2], [41, 42]]),       [5, 6]) == [1, 2, 5, 6, 41, 42]);
2336     assert(join([f([1, 2]), f([41, 42])],    [5, 6]) == [1, 2, 5, 6, 41, 42]);
2337     assert(join(f([f([1, 2]), f([41, 42])]), [5, 6]) == [1, 2, 5, 6, 41, 42]);
2338     assert(join([[1, 2], [41, 42]],          f([5, 6])) == [1, 2, 5, 6, 41, 42]);
2339     assert(join(f([[1, 2], [41, 42]]),       f([5, 6])) == [1, 2, 5, 6, 41, 42]);
2340     assert(join([f([1, 2]), f([41, 42])],    f([5, 6])) == [1, 2, 5, 6, 41, 42]);
2341     assert(join(f([f([1, 2]), f([41, 42])]), f([5, 6])) == [1, 2, 5, 6, 41, 42]);
2342 }
2343 
2344 // https://issues.dlang.org/show_bug.cgi?id=10683
2345 @safe unittest
2346 {
2347     import std.range : join;
2348     import std.typecons : tuple;
2349     assert([[tuple(1)]].join == [tuple(1)]);
2350     assert([[tuple("x")]].join == [tuple("x")]);
2351 }
2352 
2353 // https://issues.dlang.org/show_bug.cgi?id=13877
2354 @safe unittest
2355 {
2356     // Test that the range is iterated only once.
2357     import std.algorithm.iteration : map;
2358     int c = 0;
2359     auto j1 = [1, 2, 3].map!(_ => [c++]).join;
2360     assert(c == 3);
2361     assert(j1 == [0, 1, 2]);
2362 
2363     c = 0;
2364     auto j2 = [1, 2, 3].map!(_ => [c++]).join(9);
2365     assert(c == 3);
2366     assert(j2 == [0, 9, 1, 9, 2]);
2367 
2368     c = 0;
2369     auto j3 = [1, 2, 3].map!(_ => [c++]).join([9]);
2370     assert(c == 3);
2371     assert(j3 == [0, 9, 1, 9, 2]);
2372 }
2373 
2374 
2375 /++
2376     Replace occurrences of `from` with `to` in `subject` in a new array.
2377 
2378     Params:
2379         subject = the array to scan
2380         from = the item to replace
2381         to = the item to replace all instances of `from` with
2382 
2383     Returns:
2384         A new array without changing the contents of `subject`, or the original
2385         array if no match is found.
2386 
2387     See_Also:
2388         $(REF substitute, std,algorithm,iteration) for a lazy replace.
2389  +/
2390 E[] replace(E, R1, R2)(E[] subject, R1 from, R2 to)
2391 if ((isForwardRange!R1 && isForwardRange!R2 && (hasLength!R2 || isSomeString!R2)) ||
2392     is(Unqual!E : Unqual!R1))
2393 {
2394     import std.algorithm.searching : find;
2395     import std.range : dropOne;
2396 
2397     static if (isInputRange!R1)
2398     {
2399         if (from.empty) return subject;
2400         alias rSave = a => a.save;
2401     }
2402     else
2403     {
2404         alias rSave = a => a;
2405     }
2406 
2407     auto balance = find(subject, rSave(from));
2408     if (balance.empty)
2409         return subject;
2410 
2411     auto app = appender!(E[])();
2412     app.put(subject[0 .. subject.length - balance.length]);
2413     app.put(rSave(to));
2414     // replacing an element in an array is different to a range replacement
2415     static if (is(Unqual!E : Unqual!R1))
2416         replaceInto(app, balance.dropOne, from, to);
2417     else
2418         replaceInto(app, balance[from.length .. $], from, to);
2419 
2420     return app.data;
2421 }
2422 
2423 ///
2424 @safe unittest
2425 {
2426     assert("Hello Wörld".replace("o Wö", "o Wo") == "Hello World");
2427     assert("Hello Wörld".replace("l", "h") == "Hehho Wörhd");
2428 }
2429 
2430 @safe unittest
2431 {
2432     assert([1, 2, 3, 4, 2].replace([2], [5]) == [1, 5, 3, 4, 5]);
2433     assert([3, 3, 3].replace([3], [0]) == [0, 0, 0]);
2434     assert([3, 3, 4, 3].replace([3, 3], [1, 1, 1]) == [1, 1, 1, 4, 3]);
2435 }
2436 
2437 // https://issues.dlang.org/show_bug.cgi?id=18215
2438 @safe unittest
2439 {
2440     auto arr = ["aaa.dd", "b"];
2441     arr = arr.replace("aaa.dd", ".");
2442     assert(arr == [".", "b"]);
2443 
2444     arr = ["_", "_", "aaa.dd", "b", "c", "aaa.dd", "e"];
2445     arr = arr.replace("aaa.dd", ".");
2446     assert(arr == ["_", "_", ".", "b", "c", ".", "e"]);
2447 }
2448 
2449 // https://issues.dlang.org/show_bug.cgi?id=18215
2450 @safe unittest
2451 {
2452     assert([[0], [1, 2], [0], [3]].replace([0], [4]) == [[4], [1, 2], [4], [3]]);
2453     assert([[0], [1, 2], [0], [3], [1, 2]]
2454             .replace([1, 2], [0]) == [[0], [0], [0], [3], [0]]);
2455     assert([[0], [1, 2], [0], [3], [1, 2], [0], [1, 2]]
2456             .replace([[0], [1, 2]], [[4]]) == [[4], [0], [3], [1, 2], [4]]);
2457 }
2458 
2459 // https://issues.dlang.org/show_bug.cgi?id=10930
2460 @safe unittest
2461 {
2462     assert([0, 1, 2].replace(1, 4) == [0, 4, 2]);
2463     assert("äbö".replace('ä', 'a') == "abö");
2464 }
2465 
2466 // empty array
2467 @safe unittest
2468 {
2469     int[] arr;
2470     assert(replace(arr, 1, 2) == []);
2471 }
2472 
2473 /++
2474     Replace occurrences of `from` with `to` in `subject` and output the result into
2475     `sink`.
2476 
2477     Params:
2478         sink = an $(REF_ALTTEXT output range, isOutputRange, std,range,primitives)
2479         subject = the array to scan
2480         from = the item to replace
2481         to = the item to replace all instances of `from` with
2482 
2483     See_Also:
2484         $(REF substitute, std,algorithm,iteration) for a lazy replace.
2485  +/
2486 void replaceInto(E, Sink, R1, R2)(Sink sink, E[] subject, R1 from, R2 to)
2487 if (isOutputRange!(Sink, E) &&
2488     ((isForwardRange!R1 && isForwardRange!R2 && (hasLength!R2 || isSomeString!R2)) ||
2489     is(Unqual!E : Unqual!R1)))
2490 {
2491     import std.algorithm.searching : find;
2492     import std.range : dropOne;
2493 
2494     static if (isInputRange!R1)
2495     {
2496         if (from.empty)
2497         {
2498             sink.put(subject);
2499             return;
2500         }
2501         alias rSave = a => a.save;
2502     }
2503     else
2504     {
2505         alias rSave = a => a;
2506     }
2507     for (;;)
2508     {
2509         auto balance = find(subject, rSave(from));
2510         if (balance.empty)
2511         {
2512             sink.put(subject);
2513             break;
2514         }
2515         sink.put(subject[0 .. subject.length - balance.length]);
2516         sink.put(rSave(to));
2517         // replacing an element in an array is different to a range replacement
2518         static if (is(Unqual!E : Unqual!R1))
2519             subject = balance.dropOne;
2520         else
2521             subject = balance[from.length .. $];
2522     }
2523 }
2524 
2525 ///
2526 @safe unittest
2527 {
2528     auto arr = [1, 2, 3, 4, 5];
2529     auto from = [2, 3];
2530     auto to = [4, 6];
2531     auto sink = appender!(int[])();
2532 
2533     replaceInto(sink, arr, from, to);
2534 
2535     assert(sink.data == [1, 4, 6, 4, 5]);
2536 }
2537 
2538 // empty array
2539 @safe unittest
2540 {
2541     auto sink = appender!(int[])();
2542     int[] arr;
2543     replaceInto(sink, arr, 1, 2);
2544     assert(sink.data == []);
2545 }
2546 
2547 @safe unittest
2548 {
2549     import std.algorithm.comparison : cmp;
2550     import std.conv : to;
2551 
2552     static foreach (S; AliasSeq!(string, wstring, dstring, char[], wchar[], dchar[]))
2553     {
2554         static foreach (T; AliasSeq!(string, wstring, dstring, char[], wchar[], dchar[]))
2555         {{
2556             auto s = to!S("This is a foo foo list");
2557             auto from = to!T("foo");
2558             auto into = to!S("silly");
2559             S r;
2560             int i;
2561 
2562             r = replace(s, from, into);
2563             i = cmp(r, "This is a silly silly list");
2564             assert(i == 0);
2565 
2566             r = replace(s, to!S(""), into);
2567             i = cmp(r, "This is a foo foo list");
2568             assert(i == 0);
2569 
2570             assert(replace(r, to!S("won't find this"), to!S("whatever")) is r);
2571         }}
2572     }
2573 
2574     immutable s = "This is a foo foo list";
2575     assert(replace(s, "foo", "silly") == "This is a silly silly list");
2576 }
2577 
2578 @safe unittest
2579 {
2580     import std.algorithm.searching : skipOver;
2581     import std.conv : to;
2582 
2583     struct CheckOutput(C)
2584     {
2585         C[] desired;
2586         this(C[] arr){ desired = arr; }
2587         void put(C[] part){ assert(skipOver(desired, part)); }
2588     }
2589     static foreach (S; AliasSeq!(string, wstring, dstring, char[], wchar[], dchar[]))
2590     {{
2591         alias Char = ElementEncodingType!S;
2592         S s = to!S("yet another dummy text, yet another ...");
2593         S from = to!S("yet another");
2594         S into = to!S("some");
2595         replaceInto(CheckOutput!(Char)(to!S("some dummy text, some ..."))
2596                     , s, from, into);
2597     }}
2598 }
2599 
2600 // https://issues.dlang.org/show_bug.cgi?id=10930
2601 @safe unittest
2602 {
2603     auto sink = appender!(int[])();
2604     replaceInto(sink, [0, 1, 2], 1, 5);
2605     assert(sink.data == [0, 5, 2]);
2606 
2607     auto sink2 = appender!(dchar[])();
2608     replaceInto(sink2, "äbö", 'ä', 'a');
2609     assert(sink2.data == "abö");
2610 }
2611 
2612 /++
2613     Replaces elements from `array` with indices ranging from `from`
2614     (inclusive) to `to` (exclusive) with the range `stuff`.
2615 
2616     Params:
2617         subject = the array to scan
2618         from = the starting index
2619         to = the ending index
2620         stuff = the items to replace in-between `from` and `to`
2621 
2622     Returns:
2623         A new array without changing the contents of `subject`.
2624 
2625     See_Also:
2626         $(REF substitute, std,algorithm,iteration) for a lazy replace.
2627  +/
2628 T[] replace(T, Range)(T[] subject, size_t from, size_t to, Range stuff)
2629 if (isInputRange!Range &&
2630     (is(ElementType!Range : T) ||
2631     isSomeString!(T[]) && is(ElementType!Range : dchar)))
2632 {
2633     static if (hasLength!Range && is(ElementEncodingType!Range : T))
2634     {
2635         import std.algorithm.mutation : copy;
2636         assert(from <= to, "from must be before or equal to to");
2637         immutable sliceLen = to - from;
2638         auto retval = new Unqual!(T)[](subject.length - sliceLen + stuff.length);
2639         retval[0 .. from] = subject[0 .. from];
2640 
2641         if (!stuff.empty)
2642             copy(stuff, retval[from .. from + stuff.length]);
2643 
2644         retval[from + stuff.length .. $] = subject[to .. $];
2645         static if (is(T == const) || is(T == immutable))
2646         {
2647             return () @trusted { return cast(T[]) retval; } ();
2648         }
2649         else
2650         {
2651             return cast(T[]) retval;
2652         }
2653     }
2654     else
2655     {
2656         auto app = appender!(T[])();
2657         app.put(subject[0 .. from]);
2658         app.put(stuff);
2659         app.put(subject[to .. $]);
2660         return app.data;
2661     }
2662 }
2663 
2664 ///
2665 @safe unittest
2666 {
2667     auto a = [ 1, 2, 3, 4 ];
2668     auto b = a.replace(1, 3, [ 9, 9, 9 ]);
2669     assert(a == [ 1, 2, 3, 4 ]);
2670     assert(b == [ 1, 9, 9, 9, 4 ]);
2671 }
2672 
2673 @system unittest
2674 {
2675     import core.exception;
2676     import std.algorithm.iteration : filter;
2677     import std.conv : to;
2678     import std.exception;
2679 
2680 
2681     auto a = [ 1, 2, 3, 4 ];
2682     assert(replace(a, 0, 0, [5, 6, 7]) == [5, 6, 7, 1, 2, 3, 4]);
2683     assert(replace(a, 0, 2, cast(int[])[]) == [3, 4]);
2684     assert(replace(a, 0, 4, [5, 6, 7]) == [5, 6, 7]);
2685     assert(replace(a, 0, 2, [5, 6, 7]) == [5, 6, 7, 3, 4]);
2686     assert(replace(a, 2, 4, [5, 6, 7]) == [1, 2, 5, 6, 7]);
2687 
2688     assert(replace(a, 0, 0, filter!"true"([5, 6, 7])) == [5, 6, 7, 1, 2, 3, 4]);
2689     assert(replace(a, 0, 2, filter!"true"(cast(int[])[])) == [3, 4]);
2690     assert(replace(a, 0, 4, filter!"true"([5, 6, 7])) == [5, 6, 7]);
2691     assert(replace(a, 0, 2, filter!"true"([5, 6, 7])) == [5, 6, 7, 3, 4]);
2692     assert(replace(a, 2, 4, filter!"true"([5, 6, 7])) == [1, 2, 5, 6, 7]);
2693     assert(a == [ 1, 2, 3, 4 ]);
2694 
2695     void testStr(T, U)(string file = __FILE__, size_t line = __LINE__)
2696     {
2697 
2698         auto l = to!T("hello");
2699         auto r = to!U(" world");
2700 
2701         enforce(replace(l, 0, 0, r) == " worldhello",
2702                 new AssertError("testStr failure 1", file, line));
2703         enforce(replace(l, 0, 3, r) == " worldlo",
2704                 new AssertError("testStr failure 2", file, line));
2705         enforce(replace(l, 3, l.length, r) == "hel world",
2706                 new AssertError("testStr failure 3", file, line));
2707         enforce(replace(l, 0, l.length, r) == " world",
2708                 new AssertError("testStr failure 4", file, line));
2709         enforce(replace(l, l.length, l.length, r) == "hello world",
2710                 new AssertError("testStr failure 5", file, line));
2711     }
2712 
2713     testStr!(string, string)();
2714     testStr!(string, wstring)();
2715     testStr!(string, dstring)();
2716     testStr!(wstring, string)();
2717     testStr!(wstring, wstring)();
2718     testStr!(wstring, dstring)();
2719     testStr!(dstring, string)();
2720     testStr!(dstring, wstring)();
2721     testStr!(dstring, dstring)();
2722 
2723     enum s = "0123456789";
2724     enum w = "⁰¹²³⁴⁵⁶⁷⁸⁹"w;
2725     enum d = "⁰¹²³⁴⁵⁶⁷⁸⁹"d;
2726 
2727     assert(replace(s, 0, 0, "***") == "***0123456789");
2728     assert(replace(s, 10, 10, "***") == "0123456789***");
2729     assert(replace(s, 3, 8, "1012") == "012101289");
2730     assert(replace(s, 0, 5, "43210") == "4321056789");
2731     assert(replace(s, 5, 10, "43210") == "0123443210");
2732 
2733     assert(replace(w, 0, 0, "***"w) == "***⁰¹²³⁴⁵⁶⁷⁸⁹"w);
2734     assert(replace(w, 10, 10, "***"w) == "⁰¹²³⁴⁵⁶⁷⁸⁹***"w);
2735     assert(replace(w, 3, 8, "¹⁰¹²"w) == "⁰¹²¹⁰¹²⁸⁹"w);
2736     assert(replace(w, 0, 5, "⁴³²¹⁰"w) == "⁴³²¹⁰⁵⁶⁷⁸⁹"w);
2737     assert(replace(w, 5, 10, "⁴³²¹⁰"w) == "⁰¹²³⁴⁴³²¹⁰"w);
2738 
2739     assert(replace(d, 0, 0, "***"d) == "***⁰¹²³⁴⁵⁶⁷⁸⁹"d);
2740     assert(replace(d, 10, 10, "***"d) == "⁰¹²³⁴⁵⁶⁷⁸⁹***"d);
2741     assert(replace(d, 3, 8, "¹⁰¹²"d) == "⁰¹²¹⁰¹²⁸⁹"d);
2742     assert(replace(d, 0, 5, "⁴³²¹⁰"d) == "⁴³²¹⁰⁵⁶⁷⁸⁹"d);
2743     assert(replace(d, 5, 10, "⁴³²¹⁰"d) == "⁰¹²³⁴⁴³²¹⁰"d);
2744 }
2745 
2746 // https://issues.dlang.org/show_bug.cgi?id=18166
2747 @safe pure unittest
2748 {
2749     auto str = replace("aaaaa"d, 1, 4, "***"d);
2750     assert(str == "a***a");
2751 }
2752 
2753 /++
2754     Replaces elements from `array` with indices ranging from `from`
2755     (inclusive) to `to` (exclusive) with the range `stuff`. Expands or
2756     shrinks the array as needed.
2757 
2758     Params:
2759         array = the array to scan
2760         from = the starting index
2761         to = the ending index
2762         stuff = the items to replace in-between `from` and `to`
2763  +/
2764 void replaceInPlace(T, Range)(ref T[] array, size_t from, size_t to, Range stuff)
2765 if (is(typeof(replace(array, from, to, stuff))))
2766 {
2767     static if (isDynamicArray!Range &&
2768               is(Unqual!(ElementEncodingType!Range) == T) &&
2769               !isNarrowString!(T[]))
2770     {
2771         // optimized for homogeneous arrays that can be overwritten.
2772         import std.algorithm.mutation : remove;
2773         import std.typecons : tuple;
2774 
2775         if (overlap(array, stuff).length)
2776         {
2777             // use slower/conservative method
2778             array = array[0 .. from] ~ stuff ~ array[to .. $];
2779         }
2780         else if (stuff.length <= to - from)
2781         {
2782             // replacement reduces length
2783             immutable stuffEnd = from + stuff.length;
2784             array[from .. stuffEnd] = stuff[];
2785             if (stuffEnd < to)
2786                 array = remove(array, tuple(stuffEnd, to));
2787         }
2788         else
2789         {
2790             // replacement increases length
2791             // @@@TODO@@@: optimize this
2792             immutable replaceLen = to - from;
2793             array[from .. to] = stuff[0 .. replaceLen];
2794             insertInPlace(array, to, stuff[replaceLen .. $]);
2795         }
2796     }
2797     else
2798     {
2799         // default implementation, just do what replace does.
2800         array = replace(array, from, to, stuff);
2801     }
2802 }
2803 
2804 ///
2805 @safe unittest
2806 {
2807     int[] a = [1, 4, 5];
2808     replaceInPlace(a, 1u, 2u, [2, 3, 4]);
2809     assert(a == [1, 2, 3, 4, 5]);
2810     replaceInPlace(a, 1u, 2u, cast(int[])[]);
2811     assert(a == [1, 3, 4, 5]);
2812     replaceInPlace(a, 1u, 3u, a[2 .. 4]);
2813     assert(a == [1, 4, 5, 5]);
2814 }
2815 
2816 // https://issues.dlang.org/show_bug.cgi?id=12889
2817 @safe unittest
2818 {
2819     int[1][] arr = [[0], [1], [2], [3], [4], [5], [6]];
2820     int[1][] stuff = [[0], [1]];
2821     replaceInPlace(arr, 4, 6, stuff);
2822     assert(arr == [[0], [1], [2], [3], [0], [1], [6]]);
2823 }
2824 
2825 @system unittest
2826 {
2827     // https://issues.dlang.org/show_bug.cgi?id=14925
2828     char[] a = "mon texte 1".dup;
2829     char[] b = "abc".dup;
2830     replaceInPlace(a, 4, 9, b);
2831     assert(a == "mon abc 1");
2832 
2833     // ensure we can replace in place with different encodings
2834     string unicoded = "\U00010437";
2835     string unicodedLong = "\U00010437aaaaa";
2836     string base = "abcXXXxyz";
2837     string result = "abc\U00010437xyz";
2838     string resultLong = "abc\U00010437aaaaaxyz";
2839     size_t repstart = 3;
2840     size_t repend = 3 + 3;
2841 
2842     void testStringReplaceInPlace(T, U)()
2843     {
2844         import std.algorithm.comparison : equal;
2845         import std.conv;
2846         auto a = unicoded.to!(U[]);
2847         auto b = unicodedLong.to!(U[]);
2848 
2849         auto test = base.to!(T[]);
2850 
2851         test.replaceInPlace(repstart, repend, a);
2852         assert(equal(test, result), "Failed for types " ~ T.stringof ~ " and " ~ U.stringof);
2853 
2854         test = base.to!(T[]);
2855 
2856         test.replaceInPlace(repstart, repend, b);
2857         assert(equal(test, resultLong), "Failed for types " ~ T.stringof ~ " and " ~ U.stringof);
2858     }
2859 
2860     import std.meta : AliasSeq;
2861     alias allChars = AliasSeq!(char, immutable(char), const(char),
2862                          wchar, immutable(wchar), const(wchar),
2863                          dchar, immutable(dchar), const(dchar));
2864     foreach (T; allChars)
2865         foreach (U; allChars)
2866             testStringReplaceInPlace!(T, U)();
2867 
2868     void testInout(inout(int)[] a)
2869     {
2870         // will be transferred to the 'replace' function
2871         replaceInPlace(a, 1, 2, [1,2,3]);
2872     }
2873 }
2874 
2875 @safe unittest
2876 {
2877     // the constraint for the first overload used to match this, which wouldn't compile.
2878     import std.algorithm.comparison : equal;
2879     long[] a = [1L, 2, 3];
2880     int[] b = [4, 5, 6];
2881     a.replaceInPlace(1, 2, b);
2882     assert(equal(a, [1L, 4, 5, 6, 3]));
2883 }
2884 
2885 @system unittest
2886 {
2887     import core.exception;
2888     import std.algorithm.comparison : equal;
2889     import std.algorithm.iteration : filter;
2890     import std.conv : to;
2891     import std.exception;
2892 
2893 
2894     bool test(T, U, V)(T orig, size_t from, size_t to, U toReplace, V result)
2895     {
2896         {
2897             static if (is(T == typeof(T.init.dup)))
2898                 auto a = orig.dup;
2899             else
2900                 auto a = orig.idup;
2901 
2902             a.replaceInPlace(from, to, toReplace);
2903             if (!equal(a, result))
2904                 return false;
2905         }
2906 
2907         static if (isInputRange!U)
2908         {
2909             orig.replaceInPlace(from, to, filter!"true"(toReplace));
2910             return equal(orig, result);
2911         }
2912         else
2913             return true;
2914     }
2915 
2916     assert(test([1, 2, 3, 4], 0, 0, [5, 6, 7], [5, 6, 7, 1, 2, 3, 4]));
2917     assert(test([1, 2, 3, 4], 0, 2, cast(int[])[], [3, 4]));
2918     assert(test([1, 2, 3, 4], 0, 4, [5, 6, 7], [5, 6, 7]));
2919     assert(test([1, 2, 3, 4], 0, 2, [5, 6, 7], [5, 6, 7, 3, 4]));
2920     assert(test([1, 2, 3, 4], 2, 4, [5, 6, 7], [1, 2, 5, 6, 7]));
2921 
2922     assert(test([1, 2, 3, 4], 0, 0, filter!"true"([5, 6, 7]), [5, 6, 7, 1, 2, 3, 4]));
2923     assert(test([1, 2, 3, 4], 0, 2, filter!"true"(cast(int[])[]), [3, 4]));
2924     assert(test([1, 2, 3, 4], 0, 4, filter!"true"([5, 6, 7]), [5, 6, 7]));
2925     assert(test([1, 2, 3, 4], 0, 2, filter!"true"([5, 6, 7]), [5, 6, 7, 3, 4]));
2926     assert(test([1, 2, 3, 4], 2, 4, filter!"true"([5, 6, 7]), [1, 2, 5, 6, 7]));
2927 
2928     void testStr(T, U)(string file = __FILE__, size_t line = __LINE__)
2929     {
2930 
2931         auto l = to!T("hello");
2932         auto r = to!U(" world");
2933 
2934         enforce(test(l, 0, 0, r, " worldhello"),
2935                 new AssertError("testStr failure 1", file, line));
2936         enforce(test(l, 0, 3, r, " worldlo"),
2937                 new AssertError("testStr failure 2", file, line));
2938         enforce(test(l, 3, l.length, r, "hel world"),
2939                 new AssertError("testStr failure 3", file, line));
2940         enforce(test(l, 0, l.length, r, " world"),
2941                 new AssertError("testStr failure 4", file, line));
2942         enforce(test(l, l.length, l.length, r, "hello world"),
2943                 new AssertError("testStr failure 5", file, line));
2944     }
2945 
2946     testStr!(string, string)();
2947     testStr!(string, wstring)();
2948     testStr!(string, dstring)();
2949     testStr!(wstring, string)();
2950     testStr!(wstring, wstring)();
2951     testStr!(wstring, dstring)();
2952     testStr!(dstring, string)();
2953     testStr!(dstring, wstring)();
2954     testStr!(dstring, dstring)();
2955 }
2956 
2957 /++
2958     Replaces the first occurrence of `from` with `to` in `subject`.
2959 
2960     Params:
2961         subject = the array to scan
2962         from = the item to replace
2963         to = the item to replace `from` with
2964 
2965     Returns:
2966         A new array without changing the contents of `subject`, or the original
2967         array if no match is found.
2968  +/
2969 E[] replaceFirst(E, R1, R2)(E[] subject, R1 from, R2 to)
2970 if (isDynamicArray!(E[]) &&
2971     isForwardRange!R1 && is(typeof(appender!(E[])().put(from[0 .. 1]))) &&
2972     isForwardRange!R2 && is(typeof(appender!(E[])().put(to[0 .. 1]))))
2973 {
2974     if (from.empty) return subject;
2975     static if (isSomeString!(E[]))
2976     {
2977         import std..string : indexOf;
2978         immutable idx = subject.indexOf(from);
2979     }
2980     else
2981     {
2982         import std.algorithm.searching : countUntil;
2983         immutable idx = subject.countUntil(from);
2984     }
2985     if (idx == -1)
2986         return subject;
2987 
2988     auto app = appender!(E[])();
2989     app.put(subject[0 .. idx]);
2990     app.put(to);
2991 
2992     static if (isSomeString!(E[]) && isSomeString!R1)
2993     {
2994         import std.utf : codeLength;
2995         immutable fromLength = codeLength!(Unqual!E, R1)(from);
2996     }
2997     else
2998         immutable fromLength = from.length;
2999 
3000     app.put(subject[idx + fromLength .. $]);
3001 
3002     return app.data;
3003 }
3004 
3005 ///
3006 @safe unittest
3007 {
3008     auto a = [1, 2, 2, 3, 4, 5];
3009     auto b = a.replaceFirst([2], [1337]);
3010     assert(b == [1, 1337, 2, 3, 4, 5]);
3011 
3012     auto s = "This is a foo foo list";
3013     auto r = s.replaceFirst("foo", "silly");
3014     assert(r == "This is a silly foo list");
3015 }
3016 
3017 @safe unittest
3018 {
3019     import std.algorithm.comparison : cmp;
3020     import std.conv : to;
3021 
3022     static foreach (S; AliasSeq!(string, wstring, dstring, char[], wchar[], dchar[],
3023                           const(char[]), immutable(char[])))
3024     {
3025         static foreach (T; AliasSeq!(string, wstring, dstring, char[], wchar[], dchar[],
3026                               const(char[]), immutable(char[])))
3027         {{
3028             auto s = to!S("This is a foo foo list");
3029             auto s2 = to!S("Thüs is a ßöö foo list");
3030             auto from = to!T("foo");
3031             auto from2 = to!T("ßöö");
3032             auto into = to!T("silly");
3033             auto into2 = to!T("sälly");
3034 
3035             S r1 = replaceFirst(s, from, into);
3036             assert(cmp(r1, "This is a silly foo list") == 0);
3037 
3038             S r11 = replaceFirst(s2, from2, into2);
3039             assert(cmp(r11, "Thüs is a sälly foo list") == 0,
3040                 to!string(r11) ~ " : " ~ S.stringof ~ " " ~ T.stringof);
3041 
3042             S r2 = replaceFirst(r1, from, into);
3043             assert(cmp(r2, "This is a silly silly list") == 0);
3044 
3045             S r3 = replaceFirst(s, to!T(""), into);
3046             assert(cmp(r3, "This is a foo foo list") == 0);
3047 
3048             assert(replaceFirst(r3, to!T("won't find"), to!T("whatever")) is r3);
3049         }}
3050     }
3051 }
3052 
3053 // https://issues.dlang.org/show_bug.cgi?id=8187
3054 @safe unittest
3055 {
3056     auto res = ["a", "a"];
3057     assert(replace(res, "a", "b") == ["b", "b"]);
3058     assert(replaceFirst(res, "a", "b") == ["b", "a"]);
3059 }
3060 
3061 /++
3062     Replaces the last occurrence of `from` with `to` in `subject`.
3063 
3064     Params:
3065         subject = the array to scan
3066         from = the item to replace
3067         to = the item to replace `from` with
3068 
3069     Returns:
3070         A new array without changing the contents of `subject`, or the original
3071         array if no match is found.
3072  +/
3073 E[] replaceLast(E, R1, R2)(E[] subject, R1 from , R2 to)
3074 if (isDynamicArray!(E[]) &&
3075     isForwardRange!R1 && is(typeof(appender!(E[])().put(from[0 .. 1]))) &&
3076     isForwardRange!R2 && is(typeof(appender!(E[])().put(to[0 .. 1]))))
3077 {
3078     import std.range : retro;
3079     if (from.empty) return subject;
3080     static if (isSomeString!(E[]))
3081     {
3082         import std..string : lastIndexOf;
3083         auto idx = subject.lastIndexOf(from);
3084     }
3085     else
3086     {
3087         import std.algorithm.searching : countUntil;
3088         auto idx = retro(subject).countUntil(retro(from));
3089     }
3090 
3091     if (idx == -1)
3092         return subject;
3093 
3094     static if (isSomeString!(E[]) && isSomeString!R1)
3095     {
3096         import std.utf : codeLength;
3097         auto fromLength = codeLength!(Unqual!E, R1)(from);
3098     }
3099     else
3100         auto fromLength = from.length;
3101 
3102     auto app = appender!(E[])();
3103     static if (isSomeString!(E[]))
3104         app.put(subject[0 .. idx]);
3105     else
3106         app.put(subject[0 .. $ - idx - fromLength]);
3107 
3108     app.put(to);
3109 
3110     static if (isSomeString!(E[]))
3111         app.put(subject[idx+fromLength .. $]);
3112     else
3113         app.put(subject[$ - idx .. $]);
3114 
3115     return app.data;
3116 }
3117 
3118 ///
3119 @safe unittest
3120 {
3121     auto a = [1, 2, 2, 3, 4, 5];
3122     auto b = a.replaceLast([2], [1337]);
3123     assert(b == [1, 2, 1337, 3, 4, 5]);
3124 
3125     auto s = "This is a foo foo list";
3126     auto r = s.replaceLast("foo", "silly");
3127     assert(r == "This is a foo silly list", r);
3128 }
3129 
3130 @safe unittest
3131 {
3132     import std.algorithm.comparison : cmp;
3133     import std.conv : to;
3134 
3135     static foreach (S; AliasSeq!(string, wstring, dstring, char[], wchar[], dchar[],
3136                           const(char[]), immutable(char[])))
3137     {
3138         static foreach (T; AliasSeq!(string, wstring, dstring, char[], wchar[], dchar[],
3139                               const(char[]), immutable(char[])))
3140         {{
3141             auto s = to!S("This is a foo foo list");
3142             auto s2 = to!S("Thüs is a ßöö ßöö list");
3143             auto from = to!T("foo");
3144             auto from2 = to!T("ßöö");
3145             auto into = to!T("silly");
3146             auto into2 = to!T("sälly");
3147 
3148             S r1 = replaceLast(s, from, into);
3149             assert(cmp(r1, "This is a foo silly list") == 0, to!string(r1));
3150 
3151             S r11 = replaceLast(s2, from2, into2);
3152             assert(cmp(r11, "Thüs is a ßöö sälly list") == 0,
3153                 to!string(r11) ~ " : " ~ S.stringof ~ " " ~ T.stringof);
3154 
3155             S r2 = replaceLast(r1, from, into);
3156             assert(cmp(r2, "This is a silly silly list") == 0);
3157 
3158             S r3 = replaceLast(s, to!T(""), into);
3159             assert(cmp(r3, "This is a foo foo list") == 0);
3160 
3161             assert(replaceLast(r3, to!T("won't find"), to!T("whatever")) is r3);
3162         }}
3163     }
3164 }
3165 
3166 /++
3167     Creates a new array such that the items in `slice` are replaced with the
3168     items in `replacement`. `slice` and `replacement` do not need to be the
3169     same length. The result will grow or shrink based on the items given.
3170 
3171     Params:
3172         s = the base of the new array
3173         slice = the slice of `s` to be replaced
3174         replacement = the items to replace `slice` with
3175 
3176     Returns:
3177         A new array that is `s` with `slice` replaced by
3178         `replacement[]`.
3179 
3180     See_Also:
3181         $(REF substitute, std,algorithm,iteration) for a lazy replace.
3182  +/
3183 inout(T)[] replaceSlice(T)(inout(T)[] s, in T[] slice, in T[] replacement)
3184 in
3185 {
3186     // Verify that slice[] really is a slice of s[]
3187     assert(overlap(s, slice) is slice, "slice[] is not a subslice of s[]");
3188 }
3189 do
3190 {
3191     auto result = new T[s.length - slice.length + replacement.length];
3192     immutable so = &slice[0] - &s[0];
3193     result[0 .. so] = s[0 .. so];
3194     result[so .. so + replacement.length] = replacement[];
3195     result[so + replacement.length .. result.length] =
3196         s[so + slice.length .. s.length];
3197 
3198     return () @trusted inout {
3199         return cast(inout(T)[]) result;
3200     }();
3201 }
3202 
3203 ///
3204 @safe unittest
3205 {
3206     auto a = [1, 2, 3, 4, 5];
3207     auto b = replaceSlice(a, a[1 .. 4], [0, 0, 0]);
3208 
3209     assert(b == [1, 0, 0, 0, 5]);
3210 }
3211 
3212 @safe unittest
3213 {
3214     import std.algorithm.comparison : cmp;
3215 
3216     string s = "hello";
3217     string slice = s[2 .. 4];
3218 
3219     auto r = replaceSlice(s, slice, "bar");
3220     int i;
3221     i = cmp(r, "hebaro");
3222     assert(i == 0);
3223 }
3224 
3225 /**
3226 Implements an output range that appends data to an array. This is
3227 recommended over $(D array ~= data) when appending many elements because it is more
3228 efficient. `Appender` maintains its own array metadata locally, so it can avoid
3229 global locking for each append where $(LREF capacity) is non-zero.
3230 
3231 Params:
3232     A = the array type to simulate.
3233 
3234 See_Also: $(LREF appender)
3235  */
3236 struct Appender(A)
3237 if (isDynamicArray!A)
3238 {
3239     import core.memory : GC;
3240 
3241     private alias T = ElementEncodingType!A;
3242 
3243     private struct Data
3244     {
3245         size_t capacity;
3246         Unqual!T[] arr;
3247         bool canExtend = false;
3248     }
3249 
3250     private Data* _data;
3251 
3252     /**
3253      * Constructs an `Appender` with a given array.  Note that this does not copy the
3254      * data.  If the array has a larger capacity as determined by `arr.capacity`,
3255      * it will be used by the appender.  After initializing an appender on an array,
3256      * appending to the original array will reallocate.
3257      */
3258     this(A arr) @trusted pure nothrow
3259     {
3260         // initialize to a given array.
3261         _data = new Data;
3262         _data.arr = cast(Unqual!T[]) arr; //trusted
3263 
3264         if (__ctfe)
3265             return;
3266 
3267         // We want to use up as much of the block the array is in as possible.
3268         // if we consume all the block that we can, then array appending is
3269         // safe WRT built-in append, and we can use the entire block.
3270         // We only do this for mutable types that can be extended.
3271         static if (isMutable!T && is(typeof(arr.length = size_t.max)))
3272         {
3273             immutable cap = arr.capacity; //trusted
3274             // Replace with "GC.setAttr( Not Appendable )" once pure (and fixed)
3275             if (cap > arr.length)
3276                 arr.length = cap;
3277         }
3278         _data.capacity = arr.length;
3279     }
3280 
3281     /**
3282      * Reserve at least newCapacity elements for appending.  Note that more elements
3283      * may be reserved than requested. If `newCapacity <= capacity`, then nothing is
3284      * done.
3285      *
3286      * Params:
3287      *     newCapacity = the capacity the `Appender` should have
3288      */
3289     void reserve(size_t newCapacity)
3290     {
3291         if (_data)
3292         {
3293             if (newCapacity > _data.capacity)
3294                 ensureAddable(newCapacity - _data.arr.length);
3295         }
3296         else
3297         {
3298             ensureAddable(newCapacity);
3299         }
3300     }
3301 
3302     /**
3303      * Returns: the capacity of the array (the maximum number of elements the
3304      * managed array can accommodate before triggering a reallocation). If any
3305      * appending will reallocate, `0` will be returned.
3306      */
3307     @property size_t capacity() const @safe pure nothrow
3308     {
3309         return _data ? _data.capacity : 0;
3310     }
3311 
3312     /**
3313      * Use opSlice() from now on.
3314      * Returns: The managed array.
3315      */
3316     @property inout(ElementEncodingType!A)[] data() inout @trusted pure nothrow
3317     {
3318         return this[];
3319     }
3320 
3321     /**
3322      * Returns: The managed array.
3323      */
3324     @property inout(ElementEncodingType!A)[] opSlice() inout @trusted pure nothrow
3325     {
3326         /* @trusted operation:
3327          * casting Unqual!T[] to inout(T)[]
3328          */
3329         return cast(typeof(return))(_data ? _data.arr : null);
3330     }
3331 
3332     // ensure we can add nelems elements, resizing as necessary
3333     private void ensureAddable(size_t nelems)
3334     {
3335         if (!_data)
3336             _data = new Data;
3337         immutable len = _data.arr.length;
3338         immutable reqlen = len + nelems;
3339 
3340         if (_data.capacity >= reqlen)
3341             return;
3342 
3343         // need to increase capacity
3344         if (__ctfe)
3345         {
3346             static if (__traits(compiles, new Unqual!T[1]))
3347             {
3348                 _data.arr.length = reqlen;
3349             }
3350             else
3351             {
3352                 // avoid restriction of @disable this()
3353                 _data.arr = _data.arr[0 .. _data.capacity];
3354                 foreach (i; _data.capacity .. reqlen)
3355                     _data.arr ~= Unqual!T.init;
3356             }
3357             _data.arr = _data.arr[0 .. len];
3358             _data.capacity = reqlen;
3359         }
3360         else
3361         {
3362             // Time to reallocate.
3363             // We need to almost duplicate what's in druntime, except we
3364             // have better access to the capacity field.
3365             auto newlen = appenderNewCapacity!(T.sizeof)(_data.capacity, reqlen);
3366             // first, try extending the current block
3367             if (_data.canExtend)
3368             {
3369                 immutable u = (() @trusted => GC.extend(_data.arr.ptr, nelems * T.sizeof, (newlen - len) * T.sizeof))();
3370                 if (u)
3371                 {
3372                     // extend worked, update the capacity
3373                     _data.capacity = u / T.sizeof;
3374                     return;
3375                 }
3376             }
3377 
3378 
3379             // didn't work, must reallocate
3380             import core.checkedint : mulu;
3381             bool overflow;
3382             const nbytes = mulu(newlen, T.sizeof, overflow);
3383             if (overflow) assert(false, "the reallocation would exceed the "
3384                     ~ "available pointer range");
3385 
3386             auto bi = (() @trusted => GC.qalloc(nbytes, blockAttribute!T))();
3387             _data.capacity = bi.size / T.sizeof;
3388             import core.stdc..string : memcpy;
3389             if (len)
3390                 () @trusted { memcpy(bi.base, _data.arr.ptr, len * T.sizeof); }();
3391             _data.arr = (() @trusted => (cast(Unqual!T*) bi.base)[0 .. len])();
3392             _data.canExtend = true;
3393             // leave the old data, for safety reasons
3394         }
3395     }
3396 
3397     private template canPutItem(U)
3398     {
3399         enum bool canPutItem =
3400             isImplicitlyConvertible!(Unqual!U, Unqual!T) ||
3401             isSomeChar!T && isSomeChar!U;
3402     }
3403     private template canPutConstRange(Range)
3404     {
3405         enum bool canPutConstRange =
3406             isInputRange!(Unqual!Range) &&
3407             !isInputRange!Range &&
3408             is(typeof(Appender.init.put(Range.init.front)));
3409     }
3410     private template canPutRange(Range)
3411     {
3412         enum bool canPutRange =
3413             isInputRange!Range &&
3414             is(typeof(Appender.init.put(Range.init.front)));
3415     }
3416 
3417     /**
3418      * Appends `item` to the managed array. Performs encoding for
3419      * `char` types if `A` is a differently typed `char` array.
3420      *
3421      * Params:
3422      *     item = the single item to append
3423      */
3424     void put(U)(U item) if (canPutItem!U)
3425     {
3426         static if (isSomeChar!T && isSomeChar!U && T.sizeof < U.sizeof)
3427         {
3428             /* may throwable operation:
3429              * - std.utf.encode
3430              */
3431             // must do some transcoding around here
3432             import std.utf : encode;
3433             Unqual!T[T.sizeof == 1 ? 4 : 2] encoded;
3434             auto len = encode(encoded, item);
3435             put(encoded[0 .. len]);
3436         }
3437         else
3438         {
3439             import std.conv : emplaceRef;
3440 
3441             ensureAddable(1);
3442             immutable len = _data.arr.length;
3443 
3444             auto bigData = (() @trusted => _data.arr.ptr[0 .. len + 1])();
3445             emplaceRef!(Unqual!T)(bigData[len], cast() item);
3446             //We do this at the end, in case of exceptions
3447             _data.arr = bigData;
3448         }
3449     }
3450 
3451     // Const fixing hack.
3452     void put(Range)(Range items) if (canPutConstRange!Range)
3453     {
3454         alias p = put!(Unqual!Range);
3455         p(items);
3456     }
3457 
3458     /**
3459      * Appends an entire range to the managed array. Performs encoding for
3460      * `char` elements if `A` is a differently typed `char` array.
3461      *
3462      * Params:
3463      *     items = the range of items to append
3464      */
3465     void put(Range)(Range items) if (canPutRange!Range)
3466     {
3467         // note, we disable this branch for appending one type of char to
3468         // another because we can't trust the length portion.
3469         static if (!(isSomeChar!T && isSomeChar!(ElementType!Range) &&
3470                      !is(immutable Range == immutable T[])) &&
3471                     is(typeof(items.length) == size_t))
3472         {
3473             // optimization -- if this type is something other than a string,
3474             // and we are adding exactly one element, call the version for one
3475             // element.
3476             static if (!isSomeChar!T)
3477             {
3478                 if (items.length == 1)
3479                 {
3480                     put(items.front);
3481                     return;
3482                 }
3483             }
3484 
3485             // make sure we have enough space, then add the items
3486             auto bigDataFun(size_t extra)
3487             {
3488                 ensureAddable(extra);
3489                 return (() @trusted => _data.arr.ptr[0 .. _data.arr.length + extra])();
3490             }
3491             auto bigData = bigDataFun(items.length);
3492 
3493             immutable len = _data.arr.length;
3494             immutable newlen = bigData.length;
3495 
3496             alias UT = Unqual!T;
3497 
3498             static if (is(typeof(_data.arr[] = items[])) &&
3499                 !hasElaborateAssign!UT && isAssignable!(UT, ElementEncodingType!Range))
3500             {
3501                 bigData[len .. newlen] = items[];
3502             }
3503             else
3504             {
3505                 import std.conv : emplaceRef;
3506                 foreach (ref it ; bigData[len .. newlen])
3507                 {
3508                     emplaceRef!T(it, items.front);
3509                     items.popFront();
3510                 }
3511             }
3512 
3513             //We do this at the end, in case of exceptions
3514             _data.arr = bigData;
3515         }
3516         else static if (isSomeChar!T && isSomeChar!(ElementType!Range) &&
3517                         !is(immutable T == immutable ElementType!Range))
3518         {
3519             // need to decode and encode
3520             import std.utf : decodeFront;
3521             while (!items.empty)
3522             {
3523                 auto c = items.decodeFront;
3524                 put(c);
3525             }
3526         }
3527         else
3528         {
3529             //pragma(msg, Range.stringof);
3530             // Generic input range
3531             for (; !items.empty; items.popFront())
3532             {
3533                 put(items.front);
3534             }
3535         }
3536     }
3537 
3538     /**
3539      * Appends to the managed array.
3540      *
3541      * See_Also: $(LREF Appender.put)
3542      */
3543     alias opOpAssign(string op : "~") = put;
3544 
3545     // only allow overwriting data on non-immutable and non-const data
3546     static if (isMutable!T)
3547     {
3548         /**
3549          * Clears the managed array.  This allows the elements of the array to be reused
3550          * for appending.
3551          *
3552          * Note: clear is disabled for immutable or const element types, due to the
3553          * possibility that `Appender` might overwrite immutable data.
3554          */
3555         void clear() @trusted pure nothrow
3556         {
3557             if (_data)
3558             {
3559                 _data.arr = _data.arr.ptr[0 .. 0];
3560             }
3561         }
3562 
3563         /**
3564          * Shrinks the managed array to the given length.
3565          *
3566          * Throws: `Exception` if newlength is greater than the current array length.
3567          * Note: shrinkTo is disabled for immutable or const element types.
3568          */
3569         void shrinkTo(size_t newlength) @trusted pure
3570         {
3571             import std.exception : enforce;
3572             if (_data)
3573             {
3574                 enforce(newlength <= _data.arr.length, "Attempting to shrink Appender with newlength > length");
3575                 _data.arr = _data.arr.ptr[0 .. newlength];
3576             }
3577             else
3578                 enforce(newlength == 0, "Attempting to shrink empty Appender with non-zero newlength");
3579         }
3580     }
3581 
3582     /**
3583      * Gives a string in the form of `Appender!(A)(data)`.
3584      *
3585      * Params:
3586      *     w = A `char` accepting
3587      *     $(REF_ALTTEXT output range, isOutputRange, std, range, primitives).
3588      *     fmt = A $(REF FormatSpec, std, format) which controls how the array
3589      *     is formatted.
3590      * Returns:
3591      *     A `string` if `writer` is not set; `void` otherwise.
3592      */
3593     string toString()() const
3594     {
3595         import std.format : singleSpec;
3596 
3597         auto app = appender!string();
3598         auto spec = singleSpec("%s");
3599         // different reserve lengths because each element in a
3600         // non-string-like array uses two extra characters for `, `.
3601         static if (isSomeString!A)
3602         {
3603             app.reserve(_data.arr.length + 25);
3604         }
3605         else
3606         {
3607             // Multiplying by three is a very conservative estimate of
3608             // length, as it assumes each element is only one char
3609             app.reserve((_data.arr.length * 3) + 25);
3610         }
3611         toString(app, spec);
3612         return app.data;
3613     }
3614 
3615     /// ditto
3616     template toString(Writer)
3617     if (isOutputRange!(Writer, char))
3618     {
3619         import std.format : FormatSpec;
3620 
3621         void toString(ref Writer w, scope const ref std.format.FormatSpec!char fmt) const
3622         {
3623             import std.format : formatValue;
3624             import std.range.primitives : put;
3625             put(w, Unqual!(typeof(this)).stringof);
3626             put(w, '(');
3627             formatValue(w, data, fmt);
3628             put(w, ')');
3629         }
3630     }
3631 }
3632 
3633 ///
3634 @safe unittest
3635 {
3636     auto app = appender!string();
3637     string b = "abcdefg";
3638     foreach (char c; b)
3639         app.put(c);
3640     assert(app[] == "abcdefg");
3641 
3642     int[] a = [ 1, 2 ];
3643     auto app2 = appender(a);
3644     app2.put(3);
3645     app2.put([ 4, 5, 6 ]);
3646     assert(app2[] == [ 1, 2, 3, 4, 5, 6 ]);
3647 }
3648 
3649 @safe pure unittest
3650 {
3651     import std.format : format, singleSpec;
3652 
3653     auto app = appender!(int[])();
3654     app.put(1);
3655     app.put(2);
3656     app.put(3);
3657     assert("%s".format(app) == "Appender!(int[])(%s)".format([1,2,3]));
3658 
3659     auto app2 = appender!string();
3660     auto spec = singleSpec("%s");
3661     app.toString(app2, spec);
3662     assert(app2[] == "Appender!(int[])([1, 2, 3])");
3663 
3664     auto app3 = appender!string();
3665     spec = singleSpec("%(%04d, %)");
3666     app.toString(app3, spec);
3667     assert(app3[] == "Appender!(int[])(0001, 0002, 0003)");
3668 }
3669 
3670 // https://issues.dlang.org/show_bug.cgi?id=17251
3671 @safe unittest
3672 {
3673     static struct R
3674     {
3675         int front() const { return 0; }
3676         bool empty() const { return true; }
3677         void popFront() {}
3678     }
3679 
3680     auto app = appender!(R[]);
3681     const(R)[1] r;
3682     app.put(r[0]);
3683     app.put(r[]);
3684 }
3685 
3686 // https://issues.dlang.org/show_bug.cgi?id=13300
3687 @safe unittest
3688 {
3689     static test(bool isPurePostblit)()
3690     {
3691         static if (!isPurePostblit)
3692             static int i;
3693 
3694         struct Simple
3695         {
3696             @disable this(); // Without this, it works.
3697             static if (!isPurePostblit)
3698                 this(this) { i++; }
3699             else
3700                 pure this(this) { }
3701 
3702             private:
3703             this(int tmp) { }
3704         }
3705 
3706         struct Range
3707         {
3708             @property Simple front() { return Simple(0); }
3709             void popFront() { count++; }
3710             @property empty() { return count < 3; }
3711             size_t count;
3712         }
3713 
3714         Range r;
3715         auto a = r.array();
3716     }
3717 
3718     static assert(__traits(compiles, () pure { test!true(); }));
3719     static assert(!__traits(compiles, () pure { test!false(); }));
3720 }
3721 
3722 // https://issues.dlang.org/show_bug.cgi?id=19572
3723 @system unittest
3724 {
3725     static struct Struct
3726     {
3727         int value;
3728 
3729         int fun() const { return 23; }
3730 
3731         alias fun this;
3732     }
3733 
3734     Appender!(Struct[]) appender;
3735 
3736     appender.put(const(Struct)(42));
3737 
3738     auto result = appender[][0];
3739 
3740     assert(result.value != 23);
3741 }
3742 
3743 @safe unittest
3744 {
3745     import std.conv : to;
3746     import std.utf : byCodeUnit;
3747     auto str = "ウェブサイト";
3748     auto wstr = appender!wstring();
3749     put(wstr, str.byCodeUnit);
3750     assert(wstr.data == str.to!wstring);
3751 }
3752 
3753 //Calculates an efficient growth scheme based on the old capacity
3754 //of data, and the minimum requested capacity.
3755 //arg curLen: The current length
3756 //arg reqLen: The length as requested by the user
3757 //ret sugLen: A suggested growth.
3758 private size_t appenderNewCapacity(size_t TSizeOf)(size_t curLen, size_t reqLen) @safe pure nothrow
3759 {
3760     import core.bitop : bsr;
3761     import std.algorithm.comparison : max;
3762     if (curLen == 0)
3763         return max(reqLen,8);
3764     ulong mult = 100 + (1000UL) / (bsr(curLen * TSizeOf) + 1);
3765     // limit to doubling the length, we don't want to grow too much
3766     if (mult > 200)
3767         mult = 200;
3768     auto sugLen = cast(size_t)((curLen * mult + 99) / 100);
3769     return max(reqLen, sugLen);
3770 }
3771 
3772 /**
3773  * A version of $(LREF Appender) that can update an array in-place.
3774  * It forwards all calls to an underlying appender implementation.
3775  * Any calls made to the appender also update the pointer to the
3776  * original array passed in.
3777  *
3778  * Tip: Use the `arrayPtr` overload of $(LREF appender) for construction with type-inference.
3779  *
3780  * Params:
3781  *     A = The array type to simulate
3782  */
3783 struct RefAppender(A)
3784 if (isDynamicArray!A)
3785 {
3786     private
3787     {
3788         Appender!A impl;
3789         A* arr;
3790     }
3791 
3792     /**
3793      * Constructs a `RefAppender` with a given array reference.  This does not copy the
3794      * data.  If the array has a larger capacity as determined by `arr.capacity`, it
3795      * will be used by the appender.
3796      *
3797      * Note: Do not use built-in appending (i.e. `~=`) on the original array
3798      * until you are done with the appender, because subsequent calls to the appender
3799      * will reallocate the array data without those appends.
3800      *
3801      * Params:
3802      * arr = Pointer to an array. Must not be _null.
3803      */
3804     this(A* arr)
3805     {
3806         impl = Appender!A(*arr);
3807         this.arr = arr;
3808     }
3809 
3810     /** Wraps remaining `Appender` methods such as $(LREF put).
3811      * Params:
3812      * fn = Method name to call.
3813      * args = Arguments to pass to the method.
3814      */
3815     void opDispatch(string fn, Args...)(Args args)
3816     if (__traits(compiles, (Appender!A a) => mixin("a." ~ fn ~ "(args)")))
3817     {
3818         // we do it this way because we can't cache a void return
3819         scope(exit) *this.arr = impl[];
3820         mixin("return impl." ~ fn ~ "(args);");
3821     }
3822 
3823     /**
3824      * Appends `rhs` to the managed array.
3825      * Params:
3826      * rhs = Element or range.
3827      */
3828     void opOpAssign(string op : "~", U)(U rhs)
3829     if (__traits(compiles, (Appender!A a){ a.put(rhs); }))
3830     {
3831         scope(exit) *this.arr = impl[];
3832         impl.put(rhs);
3833     }
3834 
3835     /**
3836      * Returns the capacity of the array (the maximum number of elements the
3837      * managed array can accommodate before triggering a reallocation).  If any
3838      * appending will reallocate, `capacity` returns `0`.
3839      */
3840     @property size_t capacity() const
3841     {
3842         return impl.capacity;
3843     }
3844 
3845     /* Use opSlice() instead.
3846      * Returns: the managed array.
3847      */
3848     @property inout(ElementEncodingType!A)[] data() inout
3849     {
3850         return impl[];
3851     }
3852 
3853     /**
3854      * Returns: the managed array.
3855      */
3856     @property inout(ElementEncodingType!A)[] opSlice() inout
3857     {
3858         return impl[];
3859     }
3860 }
3861 
3862 ///
3863 @system pure nothrow
3864 unittest
3865 {
3866     int[] a = [1, 2];
3867     auto app2 = appender(&a);
3868     assert(app2[] == [1, 2]);
3869     assert(a == [1, 2]);
3870     app2 ~= 3;
3871     app2 ~= [4, 5, 6];
3872     assert(app2[] == [1, 2, 3, 4, 5, 6]);
3873     assert(a == [1, 2, 3, 4, 5, 6]);
3874 
3875     app2.reserve(5);
3876     assert(app2.capacity >= 5);
3877 }
3878 
3879 /++
3880     Convenience function that returns an $(LREF Appender) instance,
3881     optionally initialized with `array`.
3882  +/
3883 Appender!A appender(A)()
3884 if (isDynamicArray!A)
3885 {
3886     return Appender!A(null);
3887 }
3888 /// ditto
3889 Appender!(E[]) appender(A : E[], E)(auto ref A array)
3890 {
3891     static assert(!isStaticArray!A || __traits(isRef, array),
3892         "Cannot create Appender from an rvalue static array");
3893 
3894     return Appender!(E[])(array);
3895 }
3896 
3897 @safe pure nothrow unittest
3898 {
3899     import std.exception;
3900     {
3901         auto app = appender!(char[])();
3902         string b = "abcdefg";
3903         foreach (char c; b) app.put(c);
3904         assert(app[] == "abcdefg");
3905     }
3906     {
3907         auto app = appender!(char[])();
3908         string b = "abcdefg";
3909         foreach (char c; b) app ~= c;
3910         assert(app[] == "abcdefg");
3911     }
3912     {
3913         int[] a = [ 1, 2 ];
3914         auto app2 = appender(a);
3915         assert(app2[] == [ 1, 2 ]);
3916         app2.put(3);
3917         app2.put([ 4, 5, 6 ][]);
3918         assert(app2[] == [ 1, 2, 3, 4, 5, 6 ]);
3919         app2.put([ 7 ]);
3920         assert(app2[] == [ 1, 2, 3, 4, 5, 6, 7 ]);
3921     }
3922 
3923     int[] a = [ 1, 2 ];
3924     auto app2 = appender(a);
3925     assert(app2[] == [ 1, 2 ]);
3926     app2 ~= 3;
3927     app2 ~= [ 4, 5, 6 ][];
3928     assert(app2[] == [ 1, 2, 3, 4, 5, 6 ]);
3929     app2 ~= [ 7 ];
3930     assert(app2[] == [ 1, 2, 3, 4, 5, 6, 7 ]);
3931 
3932     app2.reserve(5);
3933     assert(app2.capacity >= 5);
3934 
3935     try // shrinkTo may throw
3936     {
3937         app2.shrinkTo(3);
3938     }
3939     catch (Exception) assert(0);
3940     assert(app2[] == [ 1, 2, 3 ]);
3941     assertThrown(app2.shrinkTo(5));
3942 
3943     const app3 = app2;
3944     assert(app3.capacity >= 3);
3945     assert(app3[] == [1, 2, 3]);
3946 
3947     auto app4 = appender([]);
3948     try // shrinkTo may throw
3949     {
3950         app4.shrinkTo(0);
3951     }
3952     catch (Exception) assert(0);
3953 
3954     // https://issues.dlang.org/show_bug.cgi?id=5663
3955     // https://issues.dlang.org/show_bug.cgi?id=9725
3956     static foreach (S; AliasSeq!(char[], const(char)[], string))
3957     {
3958         {
3959             Appender!S app5663i;
3960             assertNotThrown(app5663i.put("\xE3"));
3961             assert(app5663i[] == "\xE3");
3962 
3963             Appender!S app5663c;
3964             assertNotThrown(app5663c.put(cast(const(char)[])"\xE3"));
3965             assert(app5663c[] == "\xE3");
3966 
3967             Appender!S app5663m;
3968             assertNotThrown(app5663m.put("\xE3".dup));
3969             assert(app5663m[] == "\xE3");
3970         }
3971         // ditto for ~=
3972         {
3973             Appender!S app5663i;
3974             assertNotThrown(app5663i ~= "\xE3");
3975             assert(app5663i[] == "\xE3");
3976 
3977             Appender!S app5663c;
3978             assertNotThrown(app5663c ~= cast(const(char)[])"\xE3");
3979             assert(app5663c[] == "\xE3");
3980 
3981             Appender!S app5663m;
3982             assertNotThrown(app5663m ~= "\xE3".dup);
3983             assert(app5663m[] == "\xE3");
3984         }
3985     }
3986 
3987     static struct S10122
3988     {
3989         int val;
3990 
3991         @disable this();
3992         this(int v) @safe pure nothrow { val = v; }
3993     }
3994     assertCTFEable!(
3995     {
3996         auto w = appender!(S10122[])();
3997         w.put(S10122(1));
3998         assert(w[].length == 1 && w[][0].val == 1);
3999     });
4000 }
4001 
4002 ///
4003 @safe pure nothrow
4004 unittest
4005 {
4006     auto w = appender!string;
4007     // pre-allocate space for at least 10 elements (this avoids costly reallocations)
4008     w.reserve(10);
4009     assert(w.capacity >= 10);
4010 
4011     w.put('a'); // single elements
4012     w.put("bc"); // multiple elements
4013 
4014     // use the append syntax
4015     w ~= 'd';
4016     w ~= "ef";
4017 
4018     assert(w[] == "abcdef");
4019 }
4020 
4021 @safe pure nothrow unittest
4022 {
4023     {
4024         auto w = appender!string();
4025         w.reserve(4);
4026         cast(void) w.capacity;
4027         cast(void) w[];
4028         try
4029         {
4030             wchar wc = 'a';
4031             dchar dc = 'a';
4032             w.put(wc);    // decoding may throw
4033             w.put(dc);    // decoding may throw
4034         }
4035         catch (Exception) assert(0);
4036     }
4037     {
4038         auto w = appender!(int[])();
4039         w.reserve(4);
4040         cast(void) w.capacity;
4041         cast(void) w[];
4042         w.put(10);
4043         w.put([10]);
4044         w.clear();
4045         try
4046         {
4047             w.shrinkTo(0);
4048         }
4049         catch (Exception) assert(0);
4050 
4051         struct N
4052         {
4053             int payload;
4054             alias payload this;
4055         }
4056         w.put(N(1));
4057         w.put([N(2)]);
4058 
4059         struct S(T)
4060         {
4061             @property bool empty() { return true; }
4062             @property T front() { return T.init; }
4063             void popFront() {}
4064         }
4065         S!int r;
4066         w.put(r);
4067     }
4068 }
4069 
4070 // https://issues.dlang.org/show_bug.cgi?id=10690
4071 @safe unittest
4072 {
4073     import std.algorithm;
4074     import std.typecons;
4075     [tuple(1)].filter!(t => true).array; // No error
4076     [tuple("A")].filter!(t => true).array; // error
4077 }
4078 
4079 @safe unittest
4080 {
4081     import std.range;
4082     //Coverage for put(Range)
4083     struct S1
4084     {
4085     }
4086     struct S2
4087     {
4088         void opAssign(S2){}
4089     }
4090     auto a1 = Appender!(S1[])();
4091     auto a2 = Appender!(S2[])();
4092     auto au1 = Appender!(const(S1)[])();
4093     a1.put(S1().repeat().take(10));
4094     a2.put(S2().repeat().take(10));
4095     auto sc1 = const(S1)();
4096     au1.put(sc1.repeat().take(10));
4097 }
4098 
4099 @system unittest
4100 {
4101     import std.range;
4102     struct S2
4103     {
4104         void opAssign(S2){}
4105     }
4106     auto au2 = Appender!(const(S2)[])();
4107     auto sc2 = const(S2)();
4108     au2.put(sc2.repeat().take(10));
4109 }
4110 
4111 @system unittest
4112 {
4113     struct S
4114     {
4115         int* p;
4116     }
4117 
4118     auto a0 = Appender!(S[])();
4119     auto a1 = Appender!(const(S)[])();
4120     auto a2 = Appender!(immutable(S)[])();
4121     auto s0 = S(null);
4122     auto s1 = const(S)(null);
4123     auto s2 = immutable(S)(null);
4124     a1.put(s0);
4125     a1.put(s1);
4126     a1.put(s2);
4127     a1.put([s0]);
4128     a1.put([s1]);
4129     a1.put([s2]);
4130     a0.put(s0);
4131     static assert(!is(typeof(a0.put(a1))));
4132     static assert(!is(typeof(a0.put(a2))));
4133     a0.put([s0]);
4134     static assert(!is(typeof(a0.put([a1]))));
4135     static assert(!is(typeof(a0.put([a2]))));
4136     static assert(!is(typeof(a2.put(a0))));
4137     static assert(!is(typeof(a2.put(a1))));
4138     a2.put(s2);
4139     static assert(!is(typeof(a2.put([a0]))));
4140     static assert(!is(typeof(a2.put([a1]))));
4141     a2.put([s2]);
4142 }
4143 
4144 // https://issues.dlang.org/show_bug.cgi?id=9528
4145 @safe unittest
4146 {
4147     const(E)[] fastCopy(E)(E[] src) {
4148             auto app = appender!(const(E)[])();
4149             foreach (i, e; src)
4150                     app.put(e);
4151             return app[];
4152     }
4153 
4154     class C {}
4155     struct S { const(C) c; }
4156     S[] s = [ S(new C) ];
4157 
4158     auto t = fastCopy(s); // Does not compile
4159     assert(t.length == 1);
4160 }
4161 
4162 // https://issues.dlang.org/show_bug.cgi?id=10753
4163 @safe unittest
4164 {
4165     import std.algorithm.iteration : map;
4166     struct Foo {
4167        immutable dchar d;
4168     }
4169     struct Bar {
4170        immutable int x;
4171     }
4172     "12".map!Foo.array;
4173     [1, 2].map!Bar.array;
4174 }
4175 
4176 @safe unittest
4177 {
4178     import std.algorithm.comparison : equal;
4179 
4180     //New appender signature tests
4181     alias mutARR = int[];
4182     alias conARR = const(int)[];
4183     alias immARR = immutable(int)[];
4184 
4185     mutARR mut;
4186     conARR con;
4187     immARR imm;
4188 
4189     auto app1 = Appender!mutARR(mut);                //Always worked. Should work. Should not create a warning.
4190     app1.put(7);
4191     assert(equal(app1[], [7]));
4192     static assert(!is(typeof(Appender!mutARR(con)))); //Never worked.  Should not work.
4193     static assert(!is(typeof(Appender!mutARR(imm)))); //Never worked.  Should not work.
4194 
4195     auto app2 = Appender!conARR(mut); //Always worked. Should work. Should not create a warning.
4196     app2.put(7);
4197     assert(equal(app2[], [7]));
4198     auto app3 = Appender!conARR(con); //Didn't work.   Now works.   Should not create a warning.
4199     app3.put(7);
4200     assert(equal(app3[], [7]));
4201     auto app4 = Appender!conARR(imm); //Didn't work.   Now works.   Should not create a warning.
4202     app4.put(7);
4203     assert(equal(app4[], [7]));
4204 
4205     //{auto app = Appender!immARR(mut);}                //Worked. Will cease to work. Creates warning.
4206     //static assert(!is(typeof(Appender!immARR(mut)))); //Worked. Will cease to work. Uncomment me after full deprecation.
4207     static assert(!is(typeof(Appender!immARR(con))));   //Never worked. Should not work.
4208     auto app5 = Appender!immARR(imm);                  //Didn't work.  Now works. Should not create a warning.
4209     app5.put(7);
4210     assert(equal(app5[], [7]));
4211 
4212     //Deprecated. Please uncomment and make sure this doesn't work:
4213     //char[] cc;
4214     //static assert(!is(typeof(Appender!string(cc))));
4215 
4216     //This should always work:
4217     auto app6 = appender!string(null);
4218     assert(app6[] == null);
4219     auto app7 = appender!(const(char)[])(null);
4220     assert(app7[] == null);
4221     auto app8 = appender!(char[])(null);
4222     assert(app8[] == null);
4223 }
4224 
4225 @safe unittest //Test large allocations (for GC.extend)
4226 {
4227     import std.algorithm.comparison : equal;
4228     import std.range;
4229     Appender!(char[]) app;
4230     app.reserve(1); //cover reserve on non-initialized
4231     foreach (_; 0 .. 100_000)
4232         app.put('a');
4233     assert(equal(app[], 'a'.repeat(100_000)));
4234 }
4235 
4236 @safe unittest
4237 {
4238     auto reference = new ubyte[](2048 + 1); //a number big enough to have a full page (EG: the GC extends)
4239     auto arr = reference.dup;
4240     auto app = appender(arr[0 .. 0]);
4241     app.reserve(1); //This should not trigger a call to extend
4242     app.put(ubyte(1)); //Don't clobber arr
4243     assert(reference[] == arr[]);
4244 }
4245 
4246 @safe unittest // clear method is supported only for mutable element types
4247 {
4248     Appender!string app;
4249     app.put("foo");
4250     static assert(!__traits(compiles, app.clear()));
4251     assert(app[] == "foo");
4252 }
4253 
4254 @safe unittest
4255 {
4256     static struct D//dynamic
4257     {
4258         int[] i;
4259         alias i this;
4260     }
4261     static struct S//static
4262     {
4263         int[5] i;
4264         alias i this;
4265     }
4266     static assert(!is(Appender!(char[5])));
4267     static assert(!is(Appender!D));
4268     static assert(!is(Appender!S));
4269 
4270     enum int[5] a = [];
4271     int[5] b;
4272     D d;
4273     S s;
4274     int[5] foo(){return a;}
4275 
4276     static assert(!is(typeof(appender(a))));
4277     static assert( is(typeof(appender(b))));
4278     static assert( is(typeof(appender(d))));
4279     static assert( is(typeof(appender(s))));
4280     static assert(!is(typeof(appender(foo()))));
4281 }
4282 
4283 @system unittest
4284 {
4285     // https://issues.dlang.org/show_bug.cgi?id=13077
4286     static class A {}
4287 
4288     // reduced case
4289     auto w = appender!(shared(A)[])();
4290     w.put(new shared A());
4291 
4292     // original case
4293     import std.range;
4294     InputRange!(shared A) foo()
4295     {
4296         return [new shared A].inputRangeObject;
4297     }
4298     auto res = foo.array;
4299     assert(res.length == 1);
4300 }
4301 
4302 /++
4303     Convenience function that returns a $(LREF RefAppender) instance initialized
4304     with `arrayPtr`. Don't use null for the array pointer, use the other
4305     version of `appender` instead.
4306  +/
4307 RefAppender!(E[]) appender(P : E[]*, E)(P arrayPtr)
4308 {
4309     return RefAppender!(E[])(arrayPtr);
4310 }
4311 
4312 ///
4313 @system pure nothrow
4314 unittest
4315 {
4316     int[] a = [1, 2];
4317     auto app2 = appender(&a);
4318     assert(app2[] == [1, 2]);
4319     assert(a == [1, 2]);
4320     app2 ~= 3;
4321     app2 ~= [4, 5, 6];
4322     assert(app2[] == [1, 2, 3, 4, 5, 6]);
4323     assert(a == [1, 2, 3, 4, 5, 6]);
4324 
4325     app2.reserve(5);
4326     assert(app2.capacity >= 5);
4327 }
4328 
4329 @system unittest
4330 {
4331     import std.exception;
4332     {
4333         auto arr = new char[0];
4334         auto app = appender(&arr);
4335         string b = "abcdefg";
4336         foreach (char c; b) app.put(c);
4337         assert(app[] == "abcdefg");
4338         assert(arr == "abcdefg");
4339     }
4340     {
4341         auto arr = new char[0];
4342         auto app = appender(&arr);
4343         string b = "abcdefg";
4344         foreach (char c; b) app ~= c;
4345         assert(app[] == "abcdefg");
4346         assert(arr == "abcdefg");
4347     }
4348     {
4349         int[] a = [ 1, 2 ];
4350         auto app2 = appender(&a);
4351         assert(app2[] == [ 1, 2 ]);
4352         assert(a == [ 1, 2 ]);
4353         app2.put(3);
4354         app2.put([ 4, 5, 6 ][]);
4355         assert(app2[] == [ 1, 2, 3, 4, 5, 6 ]);
4356         assert(a == [ 1, 2, 3, 4, 5, 6 ]);
4357     }
4358 
4359     int[] a = [ 1, 2 ];
4360     auto app2 = appender(&a);
4361     assert(app2[] == [ 1, 2 ]);
4362     assert(a == [ 1, 2 ]);
4363     app2 ~= 3;
4364     app2 ~= [ 4, 5, 6 ][];
4365     assert(app2[] == [ 1, 2, 3, 4, 5, 6 ]);
4366     assert(a == [ 1, 2, 3, 4, 5, 6 ]);
4367 
4368     app2.reserve(5);
4369     assert(app2.capacity >= 5);
4370 
4371     try // shrinkTo may throw
4372     {
4373         app2.shrinkTo(3);
4374     }
4375     catch (Exception) assert(0);
4376     assert(app2[] == [ 1, 2, 3 ]);
4377     assertThrown(app2.shrinkTo(5));
4378 
4379     const app3 = app2;
4380     assert(app3.capacity >= 3);
4381     assert(app3[] == [1, 2, 3]);
4382 }
4383 
4384 // https://issues.dlang.org/show_bug.cgi?id=14605
4385 @safe unittest
4386 {
4387     static assert(isOutputRange!(Appender!(int[]), int));
4388     static assert(isOutputRange!(RefAppender!(int[]), int));
4389 }
4390 
4391 @safe unittest
4392 {
4393     Appender!(int[]) app;
4394     short[] range = [1, 2, 3];
4395     app.put(range);
4396     assert(app[] == [1, 2, 3]);
4397 }
4398 
4399 @safe unittest
4400 {
4401     string s = "hello".idup;
4402     char[] a = "hello".dup;
4403     auto appS = appender(s);
4404     auto appA = appender(a);
4405     put(appS, 'w');
4406     put(appA, 'w');
4407     s ~= 'a'; //Clobbers here?
4408     a ~= 'a'; //Clobbers here?
4409     assert(appS[] == "hellow");
4410     assert(appA[] == "hellow");
4411 }
4412 
4413 /++
4414 Constructs a static array from `a`.
4415 The type of elements can be specified implicitly so that $(D [1, 2].staticArray) results in `int[2]`,
4416 or explicitly, e.g. $(D [1, 2].staticArray!float) returns `float[2]`.
4417 When `a` is a range whose length is not known at compile time, the number of elements must be
4418 given as template argument (e.g. `myrange.staticArray!2`).
4419 Size and type can be combined, if the source range elements are implicitly
4420 convertible to the requested element type (eg: `2.iota.staticArray!(long[2])`).
4421 When the range `a` is known at compile time, it can also be specified as a
4422 template argument to avoid having to specify the number of elements
4423 (e.g.: `staticArray!(2.iota)` or `staticArray!(double, 2.iota)`).
4424 
4425 Note: `staticArray` returns by value, so expressions involving large arrays may be inefficient.
4426 
4427 Params:
4428     a = The input elements. If there are less elements than the specified length of the static array,
4429     the rest of it is default-initialized. If there are more than specified, the first elements
4430     up to the specified length are used.
4431     rangeLength = outputs the number of elements used from `a` to it. Optional.
4432 
4433 Returns: A static array constructed from `a`.
4434 +/
4435 pragma(inline, true) T[n] staticArray(T, size_t n)(auto ref T[n] a)
4436 {
4437     return a;
4438 }
4439 
4440 /// static array from array literal
4441 nothrow pure @safe unittest
4442 {
4443     auto a = [0, 1].staticArray;
4444     static assert(is(typeof(a) == int[2]));
4445     assert(a == [0, 1]);
4446 }
4447 
4448 pragma(inline, true) U[n] staticArray(U, T, size_t n)(auto ref T[n] a)
4449 if (!is(T == U) && is(T : U))
4450 {
4451     return a[].staticArray!(U[n]);
4452 }
4453 
4454 /// static array from array with implicit casting of elements
4455 nothrow pure @safe unittest
4456 {
4457     auto b = [0, 1].staticArray!long;
4458     static assert(is(typeof(b) == long[2]));
4459     assert(b == [0, 1]);
4460 }
4461 
4462 nothrow pure @safe unittest
4463 {
4464     int val = 3;
4465     static immutable gold = [1, 2, 3];
4466     [1, 2, val].staticArray.checkStaticArray!int([1, 2, 3]);
4467 
4468     @nogc void checkNogc()
4469     {
4470         [1, 2, val].staticArray.checkStaticArray!int(gold);
4471     }
4472 
4473     checkNogc();
4474 
4475     [1, 2, val].staticArray!double.checkStaticArray!double(gold);
4476     [1, 2, 3].staticArray!int.checkStaticArray!int(gold);
4477 
4478     [1, 2, 3].staticArray!(const(int)).checkStaticArray!(const(int))(gold);
4479     [1, 2, 3].staticArray!(const(double)).checkStaticArray!(const(double))(gold);
4480     {
4481         const(int)[3] a2 = [1, 2, 3].staticArray;
4482     }
4483 
4484     [cast(byte) 1, cast(byte) 129].staticArray.checkStaticArray!byte([1, -127]);
4485 }
4486 
4487 /// ditto
4488 auto staticArray(size_t n, T)(scope T a)
4489 if (isInputRange!T)
4490 {
4491     alias U = ElementType!T;
4492     return staticArray!(U[n], U, n)(a);
4493 }
4494 
4495 /// ditto
4496 auto staticArray(size_t n, T)(scope T a, out size_t rangeLength)
4497 if (isInputRange!T)
4498 {
4499     alias U = ElementType!T;
4500     return staticArray!(U[n], U, n)(a, rangeLength);
4501 }
4502 
4503 /// ditto
4504 auto staticArray(Un : U[n], U, size_t n, T)(scope T a)
4505 if (isInputRange!T && is(ElementType!T : U))
4506 {
4507     size_t extraStackSpace;
4508     return staticArray!(Un, U, n)(a, extraStackSpace);
4509 }
4510 
4511 /// ditto
4512 auto staticArray(Un : U[n], U, size_t n, T)(scope T a, out size_t rangeLength)
4513 if (isInputRange!T && is(ElementType!T : U))
4514 {
4515     import std.algorithm.mutation : uninitializedFill;
4516     import std.range : take;
4517     import std.conv : emplaceRef;
4518 
4519     if (__ctfe)
4520     {
4521         size_t i;
4522         // Compile-time version to avoid unchecked memory access.
4523         Unqual!U[n] ret;
4524         for (auto iter = a.take(n); !iter.empty; iter.popFront())
4525         {
4526             ret[i] = iter.front;
4527             i++;
4528         }
4529 
4530         rangeLength = i;
4531         return (() @trusted => cast(U[n]) ret)();
4532     }
4533 
4534     auto ret = (() @trusted
4535     {
4536         Unqual!U[n] theArray = void;
4537         return theArray;
4538     }());
4539 
4540     size_t i;
4541     if (true)
4542     {
4543         // ret was void-initialized so let's initialize the unfilled part manually.
4544         // also prevents destructors to be called on uninitialized memory if
4545         // an exception is thrown
4546         scope (exit) ret[i .. $].uninitializedFill(U.init);
4547 
4548         for (auto iter = a.take(n); !iter.empty; iter.popFront())
4549         {
4550             emplaceRef!U(ret[i++], iter.front);
4551         }
4552     }
4553 
4554     rangeLength = i;
4555     return (() @trusted => cast(U[n]) ret)();
4556 }
4557 
4558 /// static array from range + size
4559 nothrow pure @safe unittest
4560 {
4561     import std.range : iota;
4562 
4563     auto input = 3.iota;
4564     auto a = input.staticArray!2;
4565     static assert(is(typeof(a) == int[2]));
4566     assert(a == [0, 1]);
4567     auto b = input.staticArray!(long[4]);
4568     static assert(is(typeof(b) == long[4]));
4569     assert(b == [0, 1, 2, 0]);
4570 }
4571 
4572 // Tests that code compiles when there is an elaborate destructor and exceptions
4573 // are thrown. Unfortunately can't test that memory is initialized
4574 // before having a destructor called on it.
4575 // @system required because of https://issues.dlang.org/show_bug.cgi?id=18872.
4576 @system nothrow unittest
4577 {
4578     // exists only to allow doing something in the destructor. Not tested
4579     // at the end because value appears to depend on implementation of the.
4580     // function.
4581     static int preventersDestroyed = 0;
4582 
4583     static struct CopyPreventer
4584     {
4585         bool on = false;
4586         this(this)
4587         {
4588             if (on) throw new Exception("Thou shalt not copy past me!");
4589         }
4590 
4591         ~this()
4592         {
4593             preventersDestroyed++;
4594         }
4595     }
4596     auto normalArray =
4597     [
4598         CopyPreventer(false),
4599         CopyPreventer(false),
4600         CopyPreventer(true),
4601         CopyPreventer(false),
4602         CopyPreventer(true),
4603     ];
4604 
4605     try
4606     {
4607         auto staticArray = normalArray.staticArray!5;
4608         assert(false);
4609     }
4610     catch (Exception e){}
4611 }
4612 
4613 
4614 nothrow pure @safe unittest
4615 {
4616     auto a = [1, 2].staticArray;
4617     assert(is(typeof(a) == int[2]) && a == [1, 2]);
4618 
4619     import std.range : iota;
4620 
4621     2.iota.staticArray!2.checkStaticArray!int([0, 1]);
4622     2.iota.staticArray!(double[2]).checkStaticArray!double([0, 1]);
4623     2.iota.staticArray!(long[2]).checkStaticArray!long([0, 1]);
4624 }
4625 
4626 nothrow pure @system unittest
4627 {
4628     import std.range : iota;
4629     size_t copiedAmount;
4630     2.iota.staticArray!1(copiedAmount);
4631     assert(copiedAmount == 1);
4632     2.iota.staticArray!3(copiedAmount);
4633     assert(copiedAmount == 2);
4634 }
4635 
4636 /// ditto
4637 auto staticArray(alias a)()
4638 if (isInputRange!(typeof(a)))
4639 {
4640     return .staticArray!(size_t(a.length))(a);
4641 }
4642 
4643 /// ditto
4644 auto staticArray(U, alias a)()
4645 if (isInputRange!(typeof(a)))
4646 {
4647     return .staticArray!(U[size_t(a.length)])(a);
4648 }
4649 
4650 /// static array from CT range
4651 nothrow pure @safe unittest
4652 {
4653     import std.range : iota;
4654 
4655     enum a = staticArray!(2.iota);
4656     static assert(is(typeof(a) == int[2]));
4657     assert(a == [0, 1]);
4658 
4659     enum b = staticArray!(long, 2.iota);
4660     static assert(is(typeof(b) == long[2]));
4661     assert(b == [0, 1]);
4662 }
4663 
4664 nothrow pure @safe unittest
4665 {
4666     import std.range : iota;
4667 
4668     enum a = staticArray!(2.iota);
4669     staticArray!(2.iota).checkStaticArray!int([0, 1]);
4670     staticArray!(double, 2.iota).checkStaticArray!double([0, 1]);
4671     staticArray!(long, 2.iota).checkStaticArray!long([0, 1]);
4672 }
4673 
4674 version (StdUnittest) private void checkStaticArray(T, T1, T2)(T1 a, T2 b) nothrow @safe pure @nogc
4675 {
4676     static assert(is(T1 == T[T1.length]));
4677     assert(a == b, "a must be equal to b");
4678 }
Suggestion Box / Bug Report