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