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