PageRenderTime 346ms CodeModel.GetById 18ms app.highlight 305ms RepoModel.GetById 1ms app.codeStats 1ms

/std/array.d

http://github.com/jcd/phobos
D | 3150 lines | 2166 code | 323 blank | 661 comment | 397 complexity | 9c21ab7ef269da24c40f6560b3dd75ee MD5 | raw file
   1// Written in the D programming language.
   2/**
   3Functions and types that manipulate built-in arrays.
   4
   5Copyright: Copyright Andrei Alexandrescu 2008- and Jonathan M Davis 2011-.
   6
   7License:   $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
   8
   9Authors:   $(WEB erdani.org, Andrei Alexandrescu) and Jonathan M Davis
  10
  11Source: $(PHOBOSSRC std/_array.d)
  12*/
  13module std.array;
  14
  15import core.memory, core.bitop;
  16import std.algorithm, std.ascii, std.conv, std.exception, std.functional,
  17       std.range, std.string, std.traits, std.typecons, std.typetuple,
  18       std.uni, std.utf;
  19import std.c.string : memcpy;
  20version(unittest) import core.exception, std.stdio;
  21
  22/**
  23Returns a newly-allocated dynamic array consisting of a copy of the
  24input range, static array, dynamic array, or class or struct with an
  25$(D opApply) function $(D r).  Note that narrow strings are handled as
  26a special case in an overload.
  27 */
  28ForeachType!Range[] array(Range)(Range r)
  29if (isIterable!Range && !isNarrowString!Range && !isInfinite!Range)
  30{
  31    alias ForeachType!Range E;
  32    static if (hasLength!Range)
  33    {
  34        if(r.length == 0) return null;
  35
  36        static auto trustedAllocateArray(size_t n) @trusted nothrow
  37        {
  38            return uninitializedArray!(Unqual!E[])(n);
  39        }
  40        auto result = trustedAllocateArray(r.length);
  41
  42        size_t i;
  43        static auto trustedGetAddr(T)(ref T t) @trusted nothrow pure
  44        {
  45            return &t;
  46        }
  47        foreach (e; r)
  48        {
  49            emplace(trustedGetAddr(result[i]), e);
  50            ++i;
  51        }
  52        return cast(E[])result;
  53    }
  54    else
  55    {
  56        auto a = appender!(E[])();
  57        foreach (e; r)
  58        {
  59            a.put(e);
  60        }
  61        return a.data;
  62    }
  63}
  64
  65///
  66@safe pure nothrow unittest
  67{
  68    auto a = array([1, 2, 3, 4, 5][]);
  69    assert(a == [ 1, 2, 3, 4, 5 ]);
  70}
  71
  72@safe pure nothrow unittest
  73{
  74    struct Foo
  75    {
  76        int a;
  77    }
  78    auto a = array([Foo(1), Foo(2), Foo(3), Foo(4), Foo(5)][]);
  79    assert(equal(a, [Foo(1), Foo(2), Foo(3), Foo(4), Foo(5)]));
  80}
  81
  82@system unittest
  83{
  84    struct Foo
  85    {
  86        int a;
  87        auto opAssign(Foo foo)
  88        {
  89            assert(0);
  90        }
  91        auto opEquals(Foo foo)
  92        {
  93            return a == foo.a;
  94        }
  95    }
  96    auto a = array([Foo(1), Foo(2), Foo(3), Foo(4), Foo(5)][]);
  97    assert(equal(a, [Foo(1), Foo(2), Foo(3), Foo(4), Foo(5)]));
  98}
  99
 100/**
 101Convert a narrow string to an array type that fully supports random access.
 102This is handled as a special case and always returns a $(D dchar[]),
 103$(D const(dchar)[]), or $(D immutable(dchar)[]) depending on the constness of
 104the input.
 105*/
 106ElementType!String[] array(String)(String str) if (isNarrowString!String)
 107{
 108    return to!(typeof(return))(str);
 109}
 110
 111unittest
 112{
 113    static struct TestArray { int x; string toString() { return .to!string(x); } }
 114
 115    static struct OpAssign
 116    {
 117        uint num;
 118        this(uint num) { this.num = num; }
 119
 120        // Templating opAssign to make sure the bugs with opAssign being
 121        // templated are fixed.
 122        void opAssign(T)(T rhs) { this.num = rhs.num; }
 123    }
 124
 125    static struct OpApply
 126    {
 127        int opApply(int delegate(ref int) dg)
 128        {
 129            int res;
 130            foreach(i; 0..10)
 131            {
 132                res = dg(i);
 133                if(res) break;
 134            }
 135
 136            return res;
 137        }
 138    }
 139
 140    auto a = array([1, 2, 3, 4, 5][]);
 141    //writeln(a);
 142    assert(a == [ 1, 2, 3, 4, 5 ]);
 143
 144    auto b = array([TestArray(1), TestArray(2)][]);
 145    //writeln(b);
 146
 147    class C
 148    {
 149        int x;
 150        this(int y) { x = y; }
 151        override string toString() const { return .to!string(x); }
 152    }
 153    auto c = array([new C(1), new C(2)][]);
 154    //writeln(c);
 155
 156    auto d = array([1.0, 2.2, 3][]);
 157    assert(is(typeof(d) == double[]));
 158    //writeln(d);
 159
 160    auto e = [OpAssign(1), OpAssign(2)];
 161    auto f = array(e);
 162    assert(e == f);
 163
 164    assert(array(OpApply.init) == [0,1,2,3,4,5,6,7,8,9]);
 165    assert(array("ABC") == "ABC"d);
 166    assert(array("ABC".dup) == "ABC"d.dup);
 167}
 168
 169//Bug# 8233
 170unittest
 171{
 172    assert(array("hello world"d) == "hello world"d);
 173    immutable a = [1, 2, 3, 4, 5];
 174    assert(array(a) == a);
 175    const b = a;
 176    assert(array(b) == a);
 177
 178    //To verify that the opAssign branch doesn't get screwed up by using Unqual.
 179    //EDIT: array no longer calls opAssign.
 180    struct S
 181    {
 182        ref S opAssign(S)(const ref S rhs)
 183        {
 184            assert(0);
 185        }
 186
 187        int i;
 188    }
 189
 190    foreach(T; TypeTuple!(S, const S, immutable S))
 191    {
 192        auto arr = [T(1), T(2), T(3), T(4)];
 193        assert(array(arr) == arr);
 194    }
 195}
 196
 197unittest
 198{
 199    //9824
 200    static struct S
 201    {
 202        @disable void opAssign(S);
 203        int i;
 204    }
 205    auto arr = [S(0), S(1), S(2)];
 206    arr.array();
 207}
 208
 209// Bugzilla 10220
 210unittest
 211{
 212    import std.algorithm : equal;
 213    import std.range : repeat;
 214
 215    static struct S
 216    {
 217        int val;
 218
 219        @disable this();
 220        this(int v) { val = v; }
 221    }
 222    assertCTFEable!(
 223    {
 224        auto r = S(1).repeat(2).array();
 225        assert(equal(r, [S(1), S(1)]));
 226    });
 227}
 228
 229unittest
 230{
 231    //Turn down infinity:
 232    static assert(!is(typeof(
 233        repeat(1).array()
 234    )));
 235}
 236
 237/**
 238Returns a newly allocated associative array out of elements of the input range,
 239which must be a range of tuples (Key, Value).
 240 */
 241
 242auto assocArray(Range)(Range r)
 243    if (isInputRange!Range && isTuple!(ElementType!Range) &&
 244        ElementType!Range.length == 2)
 245{
 246    alias ElementType!Range.Types[0] KeyType;
 247    alias ElementType!Range.Types[1] ValueType;
 248    ValueType[KeyType] aa;
 249    foreach (t; r)
 250        aa[t[0]] = t[1];
 251    return aa;
 252}
 253
 254///
 255/*@safe*/ pure /*nothrow*/ unittest
 256{
 257    auto a = assocArray(zip([0, 1, 2], ["a", "b", "c"]));
 258    assert(is(typeof(a) == string[int]));
 259    assert(a == [0:"a", 1:"b", 2:"c"]);
 260
 261    auto b = assocArray([ tuple("foo", "bar"), tuple("baz", "quux") ]);
 262    assert(is(typeof(b) == string[string]));
 263    assert(b == ["foo":"bar", "baz":"quux"]);
 264}
 265
 266/// @@@11053@@@ - Cannot be version(unittest) - recursive instantiation error
 267unittest
 268{
 269    static assert(!__traits(compiles, [ tuple("foo", "bar", "baz") ].assocArray()));
 270    static assert(!__traits(compiles, [ tuple("foo") ].assocArray()));
 271    static assert( __traits(compiles, [ tuple("foo", "bar") ].assocArray()));
 272}
 273
 274private template blockAttribute(T)
 275{
 276    static if (hasIndirections!(T) || is(T == void))
 277    {
 278        enum blockAttribute = 0;
 279    }
 280    else
 281    {
 282        enum blockAttribute = GC.BlkAttr.NO_SCAN;
 283    }
 284}
 285version(unittest)
 286{
 287    static assert(!(blockAttribute!void & GC.BlkAttr.NO_SCAN));
 288}
 289
 290// Returns the number of dimensions in an array T.
 291private template nDimensions(T)
 292{
 293    static if(isArray!T)
 294    {
 295        enum nDimensions = 1 + nDimensions!(typeof(T.init[0]));
 296    }
 297    else
 298    {
 299        enum nDimensions = 0;
 300    }
 301}
 302
 303version(unittest)
 304{
 305    static assert(nDimensions!(uint[]) == 1);
 306    static assert(nDimensions!(float[][]) == 2);
 307}
 308
 309/**
 310Returns a new array of type $(D T) allocated on the garbage collected heap
 311without initializing its elements.  This can be a useful optimization if every
 312element will be immediately initialized.  $(D T) may be a multidimensional
 313array.  In this case sizes may be specified for any number of dimensions from 1
 314to the number in $(D T).
 315*/
 316auto uninitializedArray(T, I...)(I sizes)
 317if(allSatisfy!(isIntegral, I))
 318{
 319    return arrayAllocImpl!(false, T, I)(sizes);
 320}
 321
 322///
 323unittest
 324{
 325    double[] arr = uninitializedArray!(double[])(100);
 326    assert(arr.length == 100);
 327
 328    double[][] matrix = uninitializedArray!(double[][])(42, 31);
 329    assert(matrix.length == 42);
 330    assert(matrix[0].length == 31);
 331}
 332
 333/**
 334Returns a new array of type $(D T) allocated on the garbage collected heap.
 335Initialization is guaranteed only for pointers, references and slices,
 336for preservation of memory safety.
 337*/
 338auto minimallyInitializedArray(T, I...)(I sizes) @trusted
 339if(allSatisfy!(isIntegral, I))
 340{
 341    return arrayAllocImpl!(true, T, I)(sizes);
 342}
 343
 344@safe unittest
 345{
 346    double[] arr = minimallyInitializedArray!(double[])(100);
 347    assert(arr.length == 100);
 348
 349    double[][] matrix = minimallyInitializedArray!(double[][])(42);
 350    assert(matrix.length == 42);
 351    foreach(elem; matrix)
 352    {
 353        assert(elem.ptr is null);
 354    }
 355}
 356
 357private auto arrayAllocImpl(bool minimallyInitialized, T, I...)(I sizes)
 358if(allSatisfy!(isIntegral, I))
 359{
 360    static assert(sizes.length >= 1,
 361        "Cannot allocate an array without the size of at least the first " ~
 362        " dimension.");
 363    static assert(sizes.length <= nDimensions!T,
 364        to!string(sizes.length) ~ " dimensions specified for a " ~
 365        to!string(nDimensions!T) ~ " dimensional array.");
 366
 367    alias typeof(T.init[0]) E;
 368
 369    auto ptr = (__ctfe) ?
 370        {
 371            static if(__traits(compiles, new E[1]))
 372            {
 373                return (new E[sizes[0]]).ptr;
 374            }
 375            else
 376            {
 377                E[] arr;
 378                foreach (i; 0 .. sizes[0])
 379                    arr ~= E.init;
 380                return arr.ptr;
 381            }
 382        }() :
 383        cast(E*) GC.malloc(sizes[0] * E.sizeof, blockAttribute!(E));
 384    auto ret = ptr[0..sizes[0]];
 385
 386    static if(sizes.length > 1)
 387    {
 388        foreach(ref elem; ret)
 389        {
 390            elem = uninitializedArray!(E)(sizes[1..$]);
 391        }
 392    }
 393    else static if(minimallyInitialized && hasIndirections!E)
 394    {
 395        ret[] = E.init;
 396    }
 397
 398    return ret;
 399}
 400
 401/**
 402Implements the range interface primitive $(D empty) for built-in
 403arrays. Due to the fact that nonmember functions can be called with
 404the first argument using the dot notation, $(D array.empty) is
 405equivalent to $(D empty(array)).
 406 */
 407
 408@property bool empty(T)(in T[] a) @safe pure nothrow
 409{
 410    return !a.length;
 411}
 412
 413///
 414@safe pure nothrow unittest
 415{
 416    auto a = [ 1, 2, 3 ];
 417    assert(!a.empty);
 418    assert(a[3 .. $].empty);
 419}
 420
 421/**
 422Implements the range interface primitive $(D save) for built-in
 423arrays. Due to the fact that nonmember functions can be called with
 424the first argument using the dot notation, $(D array.save) is
 425equivalent to $(D save(array)). The function does not duplicate the
 426content of the array, it simply returns its argument.
 427 */
 428
 429@property T[] save(T)(T[] a) @safe pure nothrow
 430{
 431    return a;
 432}
 433
 434///
 435@safe pure nothrow unittest
 436{
 437    auto a = [ 1, 2, 3 ];
 438    auto b = a.save;
 439    assert(b is a);
 440}
 441/**
 442Implements the range interface primitive $(D popFront) for built-in
 443arrays. Due to the fact that nonmember functions can be called with
 444the first argument using the dot notation, $(D array.popFront) is
 445equivalent to $(D popFront(array)). For $(GLOSSARY narrow strings),
 446$(D popFront) automaticaly advances to the next $(GLOSSARY code
 447point).
 448*/
 449
 450void popFront(T)(ref T[] a) @safe pure nothrow
 451if (!isNarrowString!(T[]) && !is(T[] == void[]))
 452{
 453    assert(a.length, "Attempting to popFront() past the end of an array of " ~ T.stringof);
 454    a = a[1 .. $];
 455}
 456
 457///
 458@safe pure nothrow unittest
 459{
 460    auto a = [ 1, 2, 3 ];
 461    a.popFront();
 462    assert(a == [ 2, 3 ]);
 463}
 464
 465version(unittest)
 466{
 467    static assert(!is(typeof({          int[4] a; popFront(a); })));
 468    static assert(!is(typeof({ immutable int[] a; popFront(a); })));
 469    static assert(!is(typeof({          void[] a; popFront(a); })));
 470}
 471
 472// Specialization for narrow strings. The necessity of
 473void popFront(C)(ref C[] str) @trusted pure nothrow
 474if (isNarrowString!(C[]))
 475{
 476    assert(str.length, "Attempting to popFront() past the end of an array of " ~ C.stringof);
 477
 478    static if(is(Unqual!C == char))
 479    {
 480        immutable c = str[0];
 481        if(c < 0x80)
 482        {
 483            //ptr is used to avoid unnnecessary bounds checking.
 484            str = str.ptr[1 .. str.length];
 485        }
 486        else
 487        {
 488             import core.bitop;
 489             auto msbs = 7 - bsr(~c);
 490             if((msbs < 2) | (msbs > 6))
 491             {
 492                 //Invalid UTF-8
 493                 msbs = 1;
 494             }
 495             str = str[msbs .. $];
 496        }
 497    }
 498    else static if(is(Unqual!C == wchar))
 499    {
 500        immutable u = str[0];
 501        str = str[1 + (u >= 0xD800 && u <= 0xDBFF) .. $];
 502    }
 503    else static assert(0, "Bad template constraint.");
 504}
 505
 506@safe pure unittest
 507{
 508    foreach(S; TypeTuple!(string, wstring, dstring))
 509    {
 510        S s = "\xC2\xA9hello";
 511        s.popFront();
 512        assert(s == "hello");
 513
 514        S str = "hello\U00010143\u0100\U00010143";
 515        foreach(dchar c; ['h', 'e', 'l', 'l', 'o', '\U00010143', '\u0100', '\U00010143'])
 516        {
 517            assert(str.front == c);
 518            str.popFront();
 519        }
 520        assert(str.empty);
 521
 522        static assert(!is(typeof({          immutable S a; popFront(a); })));
 523        static assert(!is(typeof({ typeof(S.init[0])[4] a; popFront(a); })));
 524    }
 525
 526    C[] _eatString(C)(C[] str)
 527    {
 528        while(!str.empty)
 529            str.popFront();
 530
 531        return str;
 532    }
 533    enum checkCTFE = _eatString("ウェブサイト@La_Verité.com");
 534    static assert(checkCTFE.empty);
 535    enum checkCTFEW = _eatString("ウェブサイト@La_Verité.com"w);
 536    static assert(checkCTFEW.empty);
 537}
 538
 539/**
 540Implements the range interface primitive $(D popBack) for built-in
 541arrays. Due to the fact that nonmember functions can be called with
 542the first argument using the dot notation, $(D array.popBack) is
 543equivalent to $(D popBack(array)). For $(GLOSSARY narrow strings), $(D
 544popFront) automaticaly eliminates the last $(GLOSSARY code point).
 545*/
 546
 547void popBack(T)(ref T[] a) @safe pure nothrow
 548if (!isNarrowString!(T[]) && !is(T[] == void[]))
 549{
 550    assert(a.length);
 551    a = a[0 .. $ - 1];
 552}
 553
 554///
 555@safe pure nothrow unittest
 556{
 557    auto a = [ 1, 2, 3 ];
 558    a.popBack();
 559    assert(a == [ 1, 2 ]);
 560}
 561
 562version(unittest)
 563{
 564    static assert(!is(typeof({ immutable int[] a; popBack(a); })));
 565    static assert(!is(typeof({          int[4] a; popBack(a); })));
 566    static assert(!is(typeof({          void[] a; popBack(a); })));
 567}
 568
 569// Specialization for arrays of char
 570void popBack(T)(ref T[] a) @safe pure
 571if (isNarrowString!(T[]))
 572{
 573    assert(a.length, "Attempting to popBack() past the front of an array of " ~ T.stringof);
 574    a = a[0 .. $ - std.utf.strideBack(a, $)];
 575}
 576
 577@safe pure unittest
 578{
 579    foreach(S; TypeTuple!(string, wstring, dstring))
 580    {
 581        S s = "hello\xE2\x89\xA0";
 582        s.popBack();
 583        assert(s == "hello");
 584        S s3 = "\xE2\x89\xA0";
 585        auto c = s3.back;
 586        assert(c == cast(dchar)'\u2260');
 587        s3.popBack();
 588        assert(s3 == "");
 589
 590        S str = "\U00010143\u0100\U00010143hello";
 591        foreach(dchar ch; ['o', 'l', 'l', 'e', 'h', '\U00010143', '\u0100', '\U00010143'])
 592        {
 593            assert(str.back == ch);
 594            str.popBack();
 595        }
 596        assert(str.empty);
 597
 598        static assert(!is(typeof({          immutable S a; popBack(a); })));
 599        static assert(!is(typeof({ typeof(S.init[0])[4] a; popBack(a); })));
 600    }
 601}
 602
 603/**
 604Implements the range interface primitive $(D front) for built-in
 605arrays. Due to the fact that nonmember functions can be called with
 606the first argument using the dot notation, $(D array.front) is
 607equivalent to $(D front(array)). For $(GLOSSARY narrow strings), $(D
 608front) automaticaly returns the first $(GLOSSARY code point) as a $(D
 609dchar).
 610*/
 611@property ref T front(T)(T[] a) @safe pure nothrow
 612if (!isNarrowString!(T[]) && !is(T[] == void[]))
 613{
 614    assert(a.length, "Attempting to fetch the front of an empty array of " ~ T.stringof);
 615    return a[0];
 616}
 617
 618///
 619@safe pure nothrow unittest
 620{
 621    int[] a = [ 1, 2, 3 ];
 622    assert(a.front == 1);
 623}
 624
 625@safe pure nothrow unittest
 626{
 627    auto a = [ 1, 2 ];
 628    a.front = 4;
 629    assert(a.front == 4);
 630    assert(a == [ 4, 2 ]);
 631
 632    immutable b = [ 1, 2 ];
 633    assert(b.front == 1);
 634
 635    int[2] c = [ 1, 2 ];
 636    assert(c.front == 1);
 637}
 638
 639@property dchar front(T)(T[] a) @safe pure if (isNarrowString!(T[]))
 640{
 641    assert(a.length, "Attempting to fetch the front of an empty array of " ~ T.stringof);
 642    size_t i = 0;
 643    return decode(a, i);
 644}
 645
 646/**
 647Implements the range interface primitive $(D back) for built-in
 648arrays. Due to the fact that nonmember functions can be called with
 649the first argument using the dot notation, $(D array.back) is
 650equivalent to $(D back(array)). For $(GLOSSARY narrow strings), $(D
 651back) automaticaly returns the last $(GLOSSARY code point) as a $(D
 652dchar).
 653*/
 654@property ref T back(T)(T[] a) @safe pure nothrow if (!isNarrowString!(T[]))
 655{
 656    assert(a.length, "Attempting to fetch the back of an empty array of " ~ T.stringof);
 657    return a[$ - 1];
 658}
 659
 660///
 661@safe pure nothrow unittest
 662{
 663    int[] a = [ 1, 2, 3 ];
 664    assert(a.back == 3);
 665    a.back += 4;
 666    assert(a.back == 7);
 667}
 668
 669@safe pure nothrow unittest
 670{
 671    immutable b = [ 1, 2, 3 ];
 672    assert(b.back == 3);
 673
 674    int[3] c = [ 1, 2, 3 ];
 675    assert(c.back == 3);
 676}
 677
 678// Specialization for strings
 679@property dchar back(T)(T[] a) @safe pure if (isNarrowString!(T[]))
 680{
 681    assert(a.length, "Attempting to fetch the back of an empty array of " ~ T.stringof);
 682    size_t i = a.length - std.utf.strideBack(a, a.length);
 683    return decode(a, i);
 684}
 685
 686// overlap
 687/*
 688NOTE: Undocumented for now, overlap does not yet work with ctfe.
 689Returns the overlapping portion, if any, of two arrays. Unlike $(D
 690equal), $(D overlap) only compares the pointers in the ranges, not the
 691values referred by them. If $(D r1) and $(D r2) have an overlapping
 692slice, returns that slice. Otherwise, returns the null slice.
 693*/
 694inout(T)[] overlap(T)(inout(T)[] r1, inout(T)[] r2) @trusted pure nothrow
 695{
 696    alias inout(T) U;
 697    static U* max(U* a, U* b) nothrow { return a > b ? a : b; }
 698    static U* min(U* a, U* b) nothrow { return a < b ? a : b; }
 699
 700    auto b = max(r1.ptr, r2.ptr);
 701    auto e = min(r1.ptr + r1.length, r2.ptr + r2.length);
 702    return b < e ? b[0 .. e - b] : null;
 703}
 704
 705///
 706@safe pure /*nothrow*/ unittest
 707{
 708    int[] a = [ 10, 11, 12, 13, 14 ];
 709    int[] b = a[1 .. 3];
 710    assert(overlap(a, b) == [ 11, 12 ]);
 711    b = b.dup;
 712    // overlap disappears even though the content is the same
 713    assert(overlap(a, b).empty);
 714}
 715
 716/*@safe nothrow*/ unittest
 717{
 718    static void test(L, R)(L l, R r)
 719    {
 720        scope(failure) writeln("Types: L %s  R %s", L.stringof, R.stringof);
 721
 722        assert(overlap(l, r) == [ 100, 12 ]);
 723
 724        assert(overlap(l, l[0 .. 2]) is l[0 .. 2]);
 725        assert(overlap(l, l[3 .. 5]) is l[3 .. 5]);
 726        assert(overlap(l[0 .. 2], l) is l[0 .. 2]);
 727        assert(overlap(l[3 .. 5], l) is l[3 .. 5]);
 728    }
 729
 730    int[] a = [ 10, 11, 12, 13, 14 ];
 731    int[] b = a[1 .. 3];
 732    a[1] = 100;
 733
 734    immutable int[] c = a.idup;
 735    immutable int[] d = c[1 .. 3];
 736
 737    test(a, b);
 738    assert(overlap(a, b.dup).empty);
 739    test(c, d);
 740    assert(overlap(c, d.idup).empty);
 741}
 742
 743@safe pure nothrow unittest // bugzilla 9836
 744{
 745	// range primitives for array should work with alias this types
 746    struct Wrapper
 747    {
 748        int[] data;
 749        alias data this;
 750
 751        @property Wrapper save() { return this; }
 752    }
 753    auto w = Wrapper([1,2,3,4]);
 754    std.array.popFront(w); // should work
 755
 756    static assert(isInputRange!Wrapper);
 757    static assert(isForwardRange!Wrapper);
 758    static assert(isBidirectionalRange!Wrapper);
 759    static assert(isRandomAccessRange!Wrapper);
 760}
 761
 762/+
 763Commented out until the insert which has been deprecated has been removed.
 764I'd love to just remove it in favor of insertInPlace, but then code would then
 765use this version of insert and silently break. So, it's here so that it can
 766be used once insert has not only been deprecated but removed, but until then,
 767it's commented out.
 768
 769/++
 770    Creates a new array which is a copy of $(D array) with $(D stuff) (which
 771    must be an input range or a single item) inserted at position $(D pos).
 772
 773    Examples:
 774    --------------------
 775    int[] a = [ 1, 2, 3, 4 ];
 776    auto b = a.insert(2, [ 1, 2 ]);
 777    assert(a == [ 1, 2, 3, 4 ]);
 778    assert(b == [ 1, 2, 1, 2, 3, 4 ]);
 779    --------------------
 780 +/
 781T[] insert(T, Range)(T[] array, size_t pos, Range stuff)
 782    if(isInputRange!Range &&
 783       (is(ElementType!Range : T) ||
 784        isSomeString!(T[]) && is(ElementType!Range : dchar)))
 785{
 786    static if(hasLength!Range && is(ElementEncodingType!Range : T))
 787    {
 788        auto retval = new Unqual!(T)[](array.length + stuff.length);
 789        retval[0 .. pos] = array[0 .. pos];
 790        copy(stuff, retval[pos .. pos + stuff.length]);
 791        retval[pos + stuff.length .. $] = array[pos .. $];
 792        return cast(T[])retval;
 793    }
 794    else
 795    {
 796        auto app = appender!(T[])();
 797        app.put(array[0 .. pos]);
 798        app.put(stuff);
 799        app.put(array[pos .. $]);
 800        return app.data;
 801    }
 802}
 803
 804/++ Ditto +/
 805T[] insert(T)(T[] array, size_t pos, T stuff)
 806{
 807    auto retval = new T[](array.length + 1);
 808    retval[0 .. pos] = array[0 .. pos];
 809    retval[pos] = stuff;
 810    retval[pos + 1 .. $] = array[pos .. $];
 811    return retval;
 812}
 813
 814//Verify Example.
 815unittest
 816{
 817    int[] a = [ 1, 2, 3, 4 ];
 818    auto b = a.insert(2, [ 1, 2 ]);
 819    assert(a == [ 1, 2, 3, 4 ]);
 820    assert(b == [ 1, 2, 1, 2, 3, 4 ]);
 821}
 822
 823unittest
 824{
 825    auto a = [1, 2, 3, 4];
 826    assert(a.insert(0, [6, 7]) == [6, 7, 1, 2, 3, 4]);
 827    assert(a.insert(2, [6, 7]) == [1, 2, 6, 7, 3, 4]);
 828    assert(a.insert(a.length, [6, 7]) == [1, 2, 3, 4, 6, 7]);
 829
 830    assert(a.insert(0, filter!"true"([6, 7])) == [6, 7, 1, 2, 3, 4]);
 831    assert(a.insert(2, filter!"true"([6, 7])) == [1, 2, 6, 7, 3, 4]);
 832    assert(a.insert(a.length, filter!"true"([6, 7])) == [1, 2, 3, 4, 6, 7]);
 833
 834    assert(a.insert(0, 22) == [22, 1, 2, 3, 4]);
 835    assert(a.insert(2, 22) == [1, 2, 22, 3, 4]);
 836    assert(a.insert(a.length, 22) == [1, 2, 3, 4, 22]);
 837    assert(a == [1, 2, 3, 4]);
 838
 839    auto testStr(T, U)(string file = __FILE__, size_t line = __LINE__)
 840    {
 841
 842        auto l = to!T("hello");
 843        auto r = to!U(" world");
 844
 845        enforce(insert(l, 0, r) == " worldhello",
 846                new AssertError("testStr failure 1", file, line));
 847        enforce(insert(l, 3, r) == "hel worldlo",
 848                new AssertError("testStr failure 2", file, line));
 849        enforce(insert(l, l.length, r) == "hello world",
 850                new AssertError("testStr failure 3", file, line));
 851        enforce(insert(l, 0, filter!"true"(r)) == " worldhello",
 852                new AssertError("testStr failure 4", file, line));
 853        enforce(insert(l, 3, filter!"true"(r)) == "hel worldlo",
 854                new AssertError("testStr failure 5", file, line));
 855        enforce(insert(l, l.length, filter!"true"(r)) == "hello world",
 856                new AssertError("testStr failure 6", file, line));
 857    }
 858
 859    testStr!(string, string)();
 860    testStr!(string, wstring)();
 861    testStr!(string, dstring)();
 862    testStr!(wstring, string)();
 863    testStr!(wstring, wstring)();
 864    testStr!(wstring, dstring)();
 865    testStr!(dstring, string)();
 866    testStr!(dstring, wstring)();
 867    testStr!(dstring, dstring)();
 868}
 869+/
 870
 871private void copyBackwards(T)(T[] src, T[] dest)
 872{
 873    import core.stdc.string;
 874    assert(src.length == dest.length);
 875
 876    void trustedMemmove(void* d, const void* s, size_t len) @trusted
 877    {
 878        memmove(d, s, len);
 879    }
 880
 881    if (!__ctfe)
 882        trustedMemmove(dest.ptr, src.ptr, src.length * T.sizeof);
 883    else
 884    {
 885        immutable len = src.length;
 886        for (size_t i = len; i-- > 0;)
 887        {
 888            dest[i] = src[i];
 889        }
 890    }
 891}
 892
 893/++
 894    Inserts $(D stuff) (which must be an input range or any number of
 895    implicitly convertible items) in $(D array) at position $(D pos).
 896
 897    Example:
 898    ---
 899    int[] a = [ 1, 2, 3, 4 ];
 900    a.insertInPlace(2, [ 1, 2 ]);
 901    assert(a == [ 1, 2, 1, 2, 3, 4 ]);
 902    a.insertInPlace(3, 10u, 11);
 903    assert(a == [ 1, 2, 1, 10, 11, 2, 3, 4]);
 904    ---
 905 +/
 906void insertInPlace(T, U...)(ref T[] array, size_t pos, U stuff)
 907    if(!isSomeString!(T[])
 908        && allSatisfy!(isInputRangeOrConvertible!T, U) && U.length > 0)
 909{
 910    static if(allSatisfy!(isInputRangeWithLengthOrConvertible!T, U))
 911    {
 912        import core.stdc.string;
 913        void assign(E)(ref T dest, ref E src)
 914        {
 915            static if (is(typeof(dest.opAssign(src))) ||
 916                       !is(typeof(dest = src)))
 917            {
 918                // this should be in-place construction
 919                emplace(&dest, src);
 920            }
 921            else
 922            {
 923                dest = src;
 924            }
 925        }
 926        auto trustedAllocateArray(size_t n) @trusted nothrow
 927        {
 928            return uninitializedArray!(T[])(n);
 929        }
 930        void trustedMemcopy(T[] dest, T[] src) @trusted
 931        {
 932            assert(src.length == dest.length);
 933            if (!__ctfe)
 934                memcpy(dest.ptr, src.ptr, src.length * T.sizeof);
 935            else
 936            {
 937                dest[] = src[];
 938            }
 939        }
 940
 941        immutable oldLen = array.length;
 942        size_t to_insert = 0;
 943        foreach (i, E; U)
 944        {
 945            static if (is(E : T)) //a single convertible value, not a range
 946                to_insert += 1;
 947            else
 948                to_insert += stuff[i].length;
 949        }
 950        auto tmp = trustedAllocateArray(to_insert);
 951        auto j = 0;
 952        foreach (i, E; U)
 953        {
 954            static if (is(E : T)) //ditto
 955            {
 956                assign(tmp[j++], stuff[i]);
 957            }
 958            else
 959            {
 960                foreach (v; stuff[i])
 961                {
 962                    assign(tmp[j++], v);
 963                }
 964            }
 965        }
 966        array.length += to_insert;
 967        copyBackwards(array[pos..oldLen], array[pos+to_insert..$]);
 968        trustedMemcopy(array[pos..pos+to_insert], tmp);
 969    }
 970    else
 971    {
 972        // stuff has some InputRanges in it that don't have length
 973        // assume that stuff to be inserted is typically shorter
 974        // then the array that can be arbitrary big
 975        // TODO: needs a better implementation as there is no need to build an _array_
 976        // a singly-linked list of memory blocks (rope, etc.) will do
 977        auto app = appender!(T[])();
 978        foreach (i, E; U)
 979            app.put(stuff[i]);
 980        insertInPlace(array, pos, app.data);
 981    }
 982}
 983
 984/++ Ditto +/
 985void insertInPlace(T, U...)(ref T[] array, size_t pos, U stuff)
 986    if(isSomeString!(T[]) && allSatisfy!(isCharOrStringOrDcharRange, U))
 987{
 988    static if(is(Unqual!T == T)
 989        && allSatisfy!(isInputRangeWithLengthOrConvertible!dchar, U))
 990    {
 991        // mutable, can do in place
 992        //helper function: re-encode dchar to Ts and store at *ptr
 993        static T* putDChar(T* ptr, dchar ch)
 994        {
 995            static if(is(T == dchar))
 996            {
 997                *ptr++ = ch;
 998                return ptr;
 999            }
1000            else
1001            {
1002                T[dchar.sizeof/T.sizeof] buf;
1003                size_t len = encode(buf, ch);
1004                final switch(len)
1005                {
1006                    static if(T.sizeof == char.sizeof)
1007                    {
1008                case 4:
1009                        ptr[3] = buf[3];
1010                        goto case;
1011                case 3:
1012                        ptr[2] = buf[2];
1013                        goto case;
1014                    }
1015                case 2:
1016                    ptr[1] = buf[1];
1017                    goto case;
1018                case 1:
1019                    ptr[0] = buf[0];
1020                }
1021                ptr += len;
1022                return ptr;
1023            }
1024        }
1025        immutable oldLen = array.length;
1026        size_t to_insert = 0;
1027        //count up the number of *codeunits* to insert
1028        foreach (i, E; U)
1029            to_insert += codeLength!T(stuff[i]);
1030        array.length += to_insert;
1031        copyBackwards(array[pos..oldLen], array[pos+to_insert..$]);
1032        auto ptr = array.ptr + pos;
1033        foreach (i, E; U)
1034        {
1035            static if(is(E : dchar))
1036            {
1037                ptr = putDChar(ptr, stuff[i]);
1038            }
1039            else
1040            {
1041                foreach (dchar ch; stuff[i])
1042                    ptr = putDChar(ptr, ch);
1043            }
1044        }
1045        assert(ptr == array.ptr + pos + to_insert, text(ptr - array.ptr, " vs ", pos + to_insert ));
1046    }
1047    else
1048    {
1049        // immutable/const, just construct a new array
1050        auto app = appender!(T[])();
1051        app.put(array[0..pos]);
1052        foreach (i, E; U)
1053            app.put(stuff[i]);
1054        app.put(array[pos..$]);
1055        array = app.data;
1056    }
1057}
1058
1059//constraint helpers
1060private template isInputRangeWithLengthOrConvertible(E)
1061{
1062    template isInputRangeWithLengthOrConvertible(R)
1063    {
1064        //hasLength not defined for char[], wchar[] and dchar[]
1065        enum isInputRangeWithLengthOrConvertible =
1066            (isInputRange!R && is(typeof(R.init.length))
1067                && is(ElementType!R : E))  || is(R : E);
1068    }
1069}
1070
1071//ditto
1072private template isCharOrStringOrDcharRange(T)
1073{
1074    enum isCharOrStringOrDcharRange = isSomeString!T || isSomeChar!T ||
1075        (isInputRange!T && is(ElementType!T : dchar));
1076}
1077
1078//ditto
1079private template isInputRangeOrConvertible(E)
1080{
1081    template isInputRangeOrConvertible(R)
1082    {
1083        enum isInputRangeOrConvertible =
1084            (isInputRange!R && is(ElementType!R : E))  || is(R : E);
1085    }
1086}
1087
1088
1089//Verify Example.
1090@safe unittest
1091{
1092    int[] a = [ 1, 2, 3, 4 ];
1093    a.insertInPlace(2, [ 1, 2 ]);
1094    assert(a == [ 1, 2, 1, 2, 3, 4 ]);
1095    a.insertInPlace(3, 10u, 11);
1096    assert(a == [ 1, 2, 1, 10, 11, 2, 3, 4]);
1097}
1098
1099unittest
1100{
1101    bool test(T, U, V)(T orig, size_t pos, U toInsert, V result,
1102               string file = __FILE__, size_t line = __LINE__)
1103    {
1104        {
1105            static if(is(T == typeof(T.init.dup)))
1106                auto a = orig.dup;
1107            else
1108                auto a = orig.idup;
1109
1110            a.insertInPlace(pos, toInsert);
1111            if(!std.algorithm.equal(a, result))
1112                return false;
1113        }
1114
1115        static if(isInputRange!U)
1116        {
1117            orig.insertInPlace(pos, filter!"true"(toInsert));
1118            return std.algorithm.equal(orig, result);
1119        }
1120        else
1121            return true;
1122    }
1123
1124
1125    assert(test([1, 2, 3, 4], 0, [6, 7], [6, 7, 1, 2, 3, 4]));
1126    assert(test([1, 2, 3, 4], 2, [8, 9], [1, 2, 8, 9, 3, 4]));
1127    assert(test([1, 2, 3, 4], 4, [10, 11], [1, 2, 3, 4, 10, 11]));
1128
1129    assert(test([1, 2, 3, 4], 0, 22, [22, 1, 2, 3, 4]));
1130    assert(test([1, 2, 3, 4], 2, 23, [1, 2, 23, 3, 4]));
1131    assert(test([1, 2, 3, 4], 4, 24, [1, 2, 3, 4, 24]));
1132
1133    auto testStr(T, U)(string file = __FILE__, size_t line = __LINE__)
1134    {
1135
1136        auto l = to!T("hello");
1137        auto r = to!U(" વિશ્વ");
1138
1139        enforce(test(l, 0, r, " વિશ્વhello"),
1140                new AssertError("testStr failure 1", file, line));
1141        enforce(test(l, 3, r, "hel વિશ્વlo"),
1142                new AssertError("testStr failure 2", file, line));
1143        enforce(test(l, l.length, r, "hello વિશ્વ"),
1144                new AssertError("testStr failure 3", file, line));
1145    }
1146
1147    foreach (T; TypeTuple!(char, wchar, dchar,
1148        immutable(char), immutable(wchar), immutable(dchar)))
1149    {
1150        foreach (U; TypeTuple!(char, wchar, dchar,
1151            immutable(char), immutable(wchar), immutable(dchar)))
1152        {
1153            testStr!(T[], U[])();
1154        }
1155
1156    }
1157
1158    // variadic version
1159    bool testVar(T, U...)(T orig, size_t pos, U args)
1160    {
1161        static if(is(T == typeof(T.init.dup)))
1162            auto a = orig.dup;
1163        else
1164            auto a = orig.idup;
1165        auto result = args[$-1];
1166
1167        a.insertInPlace(pos, args[0..$-1]);
1168        if (!std.algorithm.equal(a, result))
1169            return false;
1170        return true;
1171    }
1172    assert(testVar([1, 2, 3, 4], 0, 6, 7u, [6, 7, 1, 2, 3, 4]));
1173    assert(testVar([1L, 2, 3, 4], 2, 8, 9L, [1, 2, 8, 9, 3, 4]));
1174    assert(testVar([1L, 2, 3, 4], 4, 10L, 11, [1, 2, 3, 4, 10, 11]));
1175    assert(testVar([1L, 2, 3, 4], 4, [10, 11], 40L, 42L,
1176                    [1, 2, 3, 4, 10, 11, 40, 42]));
1177    assert(testVar([1L, 2, 3, 4], 4, 10, 11, [40L, 42],
1178                    [1, 2, 3, 4, 10, 11, 40, 42]));
1179    assert(testVar("t".idup, 1, 'e', 's', 't', "test"));
1180    assert(testVar("!!"w.idup, 1, "\u00e9ll\u00f4", 'x', "TTT"w, 'y',
1181                    "!\u00e9ll\u00f4xTTTy!"));
1182    assert(testVar("flipflop"d.idup, 4, '_',
1183                    "xyz"w, '\U00010143', '_', "abc"d, "__",
1184                    "flip_xyz\U00010143_abc__flop"));
1185}
1186
1187unittest
1188{
1189    // insertInPlace interop with postblit
1190    struct Int
1191    {
1192        int* payload;
1193        this(int k)
1194        {
1195            payload = new int;
1196            *payload = k;
1197        }
1198        this(this)
1199        {
1200            int* np = new int;
1201            *np = *payload;
1202            payload = np;
1203        }
1204        ~this()
1205        {
1206            if (payload)
1207                *payload = 0; //'destroy' it
1208        }
1209        @property int getPayload(){ return *payload; }
1210        alias getPayload this;
1211    }
1212
1213    Int[] arr = [Int(1), Int(4), Int(5)];
1214    assert(arr[0] == 1);
1215    insertInPlace(arr, 1, Int(2), Int(3));
1216    assert(equal(arr, [1, 2, 3, 4, 5]));  //check it works with postblit
1217}
1218
1219@safe unittest
1220{
1221    assertCTFEable!(
1222    {
1223        int[] a = [1, 2];
1224        a.insertInPlace(2, 3);
1225        a.insertInPlace(0, -1, 0);
1226        return a == [-1, 0, 1, 2, 3];
1227    });
1228}
1229
1230unittest // bugzilla 6874
1231{
1232    // allocate some space
1233    byte[] a;
1234    a.length = 1;
1235
1236    // fill it
1237    a.length = a.capacity;
1238
1239    // write beyond
1240    byte[] b = a[$ .. $];
1241    b.insertInPlace(0, a);
1242
1243    // make sure that reallocation has happened
1244    assert(GC.addrOf(&b[0]) == GC.addrOf(&b[$-1]));
1245}
1246
1247
1248/++
1249    Returns whether the $(D front)s of $(D lhs) and $(D rhs) both refer to the
1250    same place in memory, making one of the arrays a slice of the other which
1251    starts at index $(D 0).
1252  +/
1253@safe
1254pure nothrow bool sameHead(T)(in T[] lhs, in T[] rhs)
1255{
1256    return lhs.ptr == rhs.ptr;
1257}
1258
1259
1260/++
1261    Returns whether the $(D back)s of $(D lhs) and $(D rhs) both refer to the
1262    same place in memory, making one of the arrays a slice of the other which
1263    end at index $(D $).
1264  +/
1265@trusted
1266pure nothrow bool sameTail(T)(in T[] lhs, in T[] rhs)
1267{
1268    return lhs.ptr + lhs.length == rhs.ptr + rhs.length;
1269}
1270
1271@safe pure nothrow unittest
1272{
1273    foreach(T; TypeTuple!(int[], const(int)[], immutable(int)[], const int[], immutable int[]))
1274    {
1275        T a = [1, 2, 3, 4, 5];
1276        T b = a;
1277        T c = a[1 .. $];
1278        T d = a[0 .. 1];
1279        T e = null;
1280
1281        assert(sameHead(a, a));
1282        assert(sameHead(a, b));
1283        assert(!sameHead(a, c));
1284        assert(sameHead(a, d));
1285        assert(!sameHead(a, e));
1286
1287        assert(sameTail(a, a));
1288        assert(sameTail(a, b));
1289        assert(sameTail(a, c));
1290        assert(!sameTail(a, d));
1291        assert(!sameTail(a, e));
1292
1293        //verifies R-value compatibilty
1294        assert(a.sameHead(a[0 .. 0]));
1295        assert(a.sameTail(a[$ .. $]));
1296    }
1297}
1298
1299/********************************************
1300Returns an array that consists of $(D s) (which must be an input
1301range) repeated $(D n) times. This function allocates, fills, and
1302returns a new array. For a lazy version, refer to $(XREF range, repeat).
1303 */
1304ElementEncodingType!S[] replicate(S)(S s, size_t n) if (isDynamicArray!S)
1305{
1306    alias ElementEncodingType!S[] RetType;
1307
1308    // Optimization for return join(std.range.repeat(s, n));
1309    if (n == 0)
1310        return RetType.init;
1311    if (n == 1)
1312        return cast(RetType) s;
1313    auto r = new Unqual!(typeof(s[0]))[n * s.length];
1314    if (s.length == 1)
1315        r[] = s[0];
1316    else
1317    {
1318        immutable len = s.length, nlen = n * len;
1319        for (size_t i = 0; i < nlen; i += len)
1320        {
1321            r[i .. i + len] = s[];
1322        }
1323    }
1324    return cast(RetType) r;
1325}
1326
1327ElementType!S[] replicate(S)(S s, size_t n)
1328if (isInputRange!S && !isDynamicArray!S)
1329{
1330    return join(std.range.repeat(s, n));
1331}
1332
1333unittest
1334{
1335    debug(std_array) printf("array.replicate.unittest\n");
1336
1337    foreach (S; TypeTuple!(string, wstring, dstring, char[], wchar[], dchar[]))
1338    {
1339        S s;
1340        immutable S t = "abc";
1341
1342        assert(replicate(to!S("1234"), 0) is null);
1343        assert(replicate(to!S("1234"), 0) is null);
1344        assert(replicate(to!S("1234"), 1) == "1234");
1345        assert(replicate(to!S("1234"), 2) == "12341234");
1346        assert(replicate(to!S("1"), 4) == "1111");
1347        assert(replicate(t, 3) == "abcabcabc");
1348        assert(replicate(cast(S) null, 4) is null);
1349    }
1350}
1351
1352/++
1353Eagerly split the string $(D s) into an array of words, using whitespace as
1354delimiter. Runs of whitespace are merged together (no empty words are produced).
1355
1356$(D @safe), $(D pure) and $(D CTFE)-able.
1357+/
1358S[] split(S)(S s) @safe pure
1359if (isSomeString!S)
1360{
1361    size_t istart;
1362    bool inword = false;
1363    S[] result;
1364
1365    foreach (i, dchar c ; s)
1366    {
1367        if (std.uni.isWhite(c))
1368        {
1369            if (inword)
1370            {
1371                result ~= s[istart .. i];
1372                inword = false;
1373            }
1374        }
1375        else
1376        {
1377            if (!inword)
1378            {
1379                istart = i;
1380                inword = true;
1381            }
1382        }
1383    }
1384    if (inword)
1385        result ~= s[istart .. $];
1386    return result;
1387}
1388
1389unittest
1390{
1391    static auto makeEntry(S)(string l, string[] r)
1392    {return tuple(l.to!S(), r.to!(S[])());}
1393
1394    foreach (S; TypeTuple!(string, wstring, dstring,))
1395    {
1396        auto entries =
1397        [
1398            makeEntry!S("", []),
1399            makeEntry!S(" ", []),
1400            makeEntry!S("hello", ["hello"]),
1401            makeEntry!S(" hello ", ["hello"]),
1402            makeEntry!S("  h  e  l  l  o ", ["h", "e", "l", "l", "o"]),
1403            makeEntry!S("peter\t\npaul\rjerry", ["peter", "paul", "jerry"]),
1404            makeEntry!S(" \t\npeter paul\tjerry \n", ["peter", "paul", "jerry"]),
1405            makeEntry!S("\u2000日\u202F本\u205F語\u3000", ["日", "本", "語"]),
1406            makeEntry!S("  哈・郎博尔德}    ___一个", ["哈・郎博尔德}", "___一个"])
1407        ];
1408        foreach (entry; entries)
1409            assert(entry[0].split() == entry[1], format("got: %s, expected: %s.", entry[0].split(), entry[1]));
1410    }
1411
1412    //Just to test that an immutable is split-able
1413    immutable string s = " \t\npeter paul\tjerry \n";
1414    assert(split(s) == ["peter", "paul", "jerry"]);
1415}
1416
1417unittest //safety, purity, ctfe ...
1418{
1419    void dg() @safe pure {
1420        assert(split("hello world"c) == ["hello"c, "world"c]);
1421        assert(split("hello world"w) == ["hello"w, "world"w]);
1422        assert(split("hello world"d) == ["hello"d, "world"d]);
1423    }
1424    dg();
1425    assertCTFEable!dg;
1426}
1427
1428/++
1429Alias for $(XREF algorithm, splitter).
1430 +/
1431alias splitter = std.algorithm.splitter;
1432
1433/++
1434Eagerly splits $(D s) into an array, using $(D delim) as the delimiter.
1435
1436See also: $(XREF algorithm, splitter) for the lazy version of this operator.
1437 +/
1438auto split(R, E)(R r, E delim)
1439if (isForwardRange!R && is(typeof(ElementType!R.init == E.init)))
1440{
1441    auto spl = std.algorithm.splitter(r, delim);
1442    alias S = typeof(spl.front.init); // "Slice_t"
1443    auto app = appender!(S[])();
1444    foreach (e; spl)
1445        app.put(e);
1446    return app.data;
1447}
1448auto split(R1, R2)(R1 r, R2 delim)
1449if (isForwardRange!R1 && isForwardRange!R2 && is(typeof(ElementType!R1.init == ElementType!R2.init)))
1450{
1451    auto spl = std.algorithm.splitter(r, delim);
1452    alias S = typeof(spl.front.init); // "Slice_t"
1453    auto app = appender!(S[])();
1454    foreach (e; spl)
1455        app.put(e);
1456    return app.data;
1457}
1458///ditto
1459auto split(alias isTerminator, R)(R r)
1460if (isForwardRange!R && is(typeof(unaryFun!isTerminator(r.front))))
1461{
1462    auto spl = std.algorithm.splitter!isTerminator(r);
1463    alias S = typeof(spl.front.init); // "Slice_t"
1464    auto app = appender!(S[])();
1465    foreach (e; spl)
1466        app.put(e);
1467    return app.data;
1468}
1469
1470unittest
1471{
1472    debug(std_array) printf("array.split\n");
1473    foreach (S; TypeTuple!(string, wstring, dstring,
1474                    immutable(string), immutable(wstring), immutable(dstring),
1475                    char[], wchar[], dchar[],
1476                    const(char)[], const(wchar)[], const(dchar)[],
1477                    const(char[]), immutable(char[])))
1478    {
1479        S s = to!S(",peter,paul,jerry,");
1480
1481        auto words = split(s, ",");
1482        assert(words.length == 5, text(words.length));
1483        assert(cmp(words[0], "") == 0);
1484        assert(cmp(words[1], "peter") == 0);
1485        assert(cmp(words[2], "paul") == 0);
1486        assert(cmp(words[3], "jerry") == 0);
1487        assert(cmp(words[4], "") == 0);
1488
1489        auto s1 = s[0 .. s.length - 1];   // lop off trailing ','
1490        words = split(s1, ",");
1491        assert(words.length == 4);
1492        assert(cmp(words[3], "jerry") == 0);
1493
1494        auto s2 = s1[1 .. s1.length];   // lop off leading ','
1495        words = split(s2, ",");
1496        assert(words.length == 3);
1497        assert(cmp(words[0], "peter") == 0);
1498
1499        auto s3 = to!S(",,peter,,paul,,jerry,,");
1500
1501        words = split(s3, ",,");
1502        assert(words.length == 5);
1503        assert(cmp(words[0], "") == 0);
1504        assert(cmp(words[1], "peter") == 0);
1505        assert(cmp(words[2], "paul") == 0);
1506        assert(cmp(words[3], "jerry") == 0);
1507        assert(cmp(words[4], "") == 0);
1508
1509        auto s4 = s3[0 .. s3.length - 2];    // lop off trailing ',,'
1510        words = split(s4, ",,");
1511        assert(words.length == 4);
1512        assert(cmp(words[3], "jerry") == 0);
1513
1514        auto s5 = s4[2 .. s4.length];    // lop off leading ',,'
1515        words = split(s5, ",,");
1516        assert(words.length == 3);
1517        assert(cmp(words[0], "peter") == 0);
1518    }
1519}
1520
1521
1522/++
1523   Concatenates all of the ranges in $(D ror) together into one array using
1524   $(D sep) as the separator if present.
1525  +/
1526ElementEncodingType!(ElementType!RoR)[] join(RoR, R)(RoR ror, R sep)
1527    if(isInputRange!RoR &&
1528       isInputRange!(ElementType!RoR) &&
1529       isInputRange!R &&
1530       is(Unqual!(ElementType!(ElementType!RoR)) == Unqual!(ElementType!R)))
1531{
1532    alias ElementType!RoR RoRElem;
1533    alias typeof(return) RetType;
1534
1535    if (ror.empty)
1536        return RetType.init;
1537
1538    // Constraint only requires input range for sep.
1539    // This converts sep to an array (forward range) if it isn't one,
1540    // and makes sure it has the same string encoding for string types.
1541    static if (isSomeString!RetType &&
1542               !is(Unqual!(ElementEncodingType!RetType) == Unqual!(ElementEncodingType!R)))
1543        auto sepArr = to!RetType(sep);
1544    else static if (!isArray!R)
1545        auto sepArr = array(sep);
1546    else
1547        alias sep sepArr;
1548
1549    auto result = appender!RetType();
1550    static if(isForwardRange!RoR &&
1551              (isNarrowString!RetType || hasLength!RoRElem))
1552    {
1553        // Reserve appender length if it can be computed.
1554        size_t resultLen = 0;
1555        immutable sepArrLength = sepArr.length;
1556        for (auto temp = ror.save; !temp.empty; temp.popFront())
1557            resultLen += temp.front.length + sepArrLength;
1558        resultLen -= sepArrLength;
1559        result.reserve(resultLen);
1560        version(unittest) scope(exit) assert(result.data.length == resultLen);
1561    }
1562    put(result, ror.front);
1563    ror.popFront();
1564    for (; !ror.empty; ror.popFront())
1565    {
1566        put(result, sepArr);
1567        put(result, ror.front);
1568    }
1569    return result.data;
1570}
1571
1572/// Ditto
1573ElementEncodingType!(ElementType!RoR)[] join(RoR)(RoR ror)
1574    if(isInputRange!RoR &&
1575       isInputRange!(ElementType!RoR))
1576{
1577    alias typeof(return) RetType;
1578
1579    if (ror.empty)
1580        return RetType.init;
1581
1582    alias ElementType!RoR R;
1583    auto result = appender!RetType();
1584    static if(isForwardRange!RoR && (hasLength!R || isNarrowString!R))
1585    {
1586        // Reserve appender length if it can be computed.
1587        immutable resultLen = reduce!("a + b.length")(cast(size_t) 0, ror.save);
1588        result.reserve(resultLen);
1589        version(unittest) scope(exit) assert(result.data.length == resultLen);
1590    }
1591    for (; !ror.empty; ror.popFront())
1592        put(result, ror.front);
1593    return result.data;
1594}
1595
1596///
1597@safe pure nothrow unittest
1598{
1599    assert(join(["hello", "silly", "world"], " ") == "hello silly world");
1600    assert(join(["hello", "silly", "world"]) == "hellosillyworld");
1601
1602    assert(join([[1, 2, 3], [4, 5]], [72, 73]) == [1, 2, 3, 72, 73, 4, 5]);
1603    assert(join([[1, 2, 3], [4, 5]]) == [1, 2, 3, 4, 5]);
1604}
1605
1606unittest
1607{
1608    debug(std_array) printf("array.join.unittest\n");
1609
1610    foreach(R; TypeTuple!(string, wstring, dstring))
1611    {
1612        R word1 = "日本語";
1613        R word2 = "paul";
1614        R word3 = "jerry";
1615        R[] words = [word1, word2, word3];
1616
1617        auto filteredWord1    = filter!"true"(word1);
1618        auto filteredLenWord1 = takeExactly(filteredWord1, word1.walkLength());
1619        auto filteredWord2    = filter!"true"(word2);
1620        auto filteredLenWord2 = takeExactly(filteredWord2, word2.walkLength());
1621        auto filteredWord3    = filter!"true"(word3);
1622        auto filteredLenWord3 = takeExactly(filteredWord3, word3.walkLength());
1623        auto filteredWordsArr = [filteredWord1, filteredWord2, filteredWord3];
1624        auto filteredLenWordsArr = [filteredLenWord1, filteredLenWord2, filteredLenWord3];
1625        auto filteredWords    = filter!"true"(filteredWordsArr);
1626
1627        foreach(S; TypeTuple!(string, wstring, dstring))
1628        {
1629            assert(join(filteredWords, to!S(", ")) == "日本語, paul, jerry");
1630            assert(join(filteredWordsArr, to!S(", ")) == "日本語, paul, jerry");
1631            assert(join(filteredLenWordsArr, to!S(", ")) == "日本語, paul, jerry");
1632            assert(join(filter!"true"(words), to!S(", ")) == "日本語, paul, jerry");
1633            assert(join(words, to!S(", ")) == "日本語, paul, jerry");
1634
1635            assert(join(filteredWords, to!S("")) == "日本語pauljerry");
1636            assert(join(filteredWordsArr, to!S("")) == "日本語pauljerry");
1637            assert(join(filteredLenWordsArr, to!S("")) == "日本語pauljerry");
1638            assert(join(filter!"true"(words), to!S("")) == "日本語pauljerry");
1639            assert(join(words, to!S("")) == "日本語pauljerry");
1640
1641            assert(join(filter!"true"([word1]), to!S(", ")) == "日本語");
1642            assert(join([filteredWord1], to!S(", ")) == "日本語");
1643            assert(join([filteredLenWord1], to!S(", ")) == "日本語");
1644            assert(join(filter!"true"([filteredWord1]), to!S(", ")) == "日本語");
1645            assert(join([word1], to!S(", ")) == "日本語");
1646
1647            assert(join(filteredWords, to!S(word1)) == "日本語日本語paul日本語jerry");
1648            assert(join(filteredWordsArr, to!S(word1)) == "日本語日本語paul日本語jerry");
1649            assert(join(filteredLenWordsArr, to!S(word1)) == "日本語日本語paul日本語jerry");
1650            assert(join(filter!"true"(words), to!S(word1)) == "日本語日本語paul日本語jerry");
1651            assert(join(words, to!S(word1)) == "日本語日本語paul日本語jerry");
1652
1653            auto filterComma = filter!"true"(to!S(", "));
1654            assert(join(filteredWords, filterComma) == "日本語, paul, jerry");
1655            assert(join(filteredWordsArr, filterComma) == "日本語, paul, jerry");
1656            assert(join(filteredLenWordsArr, filterComma) == "日本語, paul, jerry");
1657            assert(join(filter!"true"(words), filterComma) == "日本語, paul, jerry");
1658            assert(join(words, filterComma) == "日本語, paul, jerry");
1659        }
1660
1661        assert(join(filteredWords) == "日本語pauljerry");
1662        assert(join(filteredWordsArr) == "日本語pauljerry");
1663        assert(join(filteredLenWordsArr) == "日本語pauljerry");
1664        assert(join(filter!"true"(words)) == "日本語pauljerry");
1665        assert(join(words) == "日本語pauljerry");
1666
1667        assert(join(filteredWords, filter!"true"(", ")) == "日本語, paul, jerry");
1668        assert(join(filteredWordsArr, filter!"true"(", ")) == "日本語, paul, jerry");
1669        assert(join(filteredLenWordsArr, filter!"true"(", ")) == "日本語, paul, jerry");
1670        assert(join(filter!"true"(words), filter!"true"(", ")) == "日本語, paul, jerry");
1671        assert(join(words, filter!"true"(", ")) == "日本語, paul, jerry");
1672
1673        assert(join(filter!"true"(cast(typeof(filteredWordsArr))[]), ", ").empty);
1674        assert(join(cast(typeof(filteredWordsArr))[], ", ").empty);
1675        assert(join(cast(typeof(filteredLenWordsArr))[], ", ").empty);
1676        assert(join(filter!"true"(cast(R[])[]), ", ").empty);
1677        assert(join(cast(R[])[], ", ").empty);
1678
1679        assert(join(filter!"true"(cast(typeof(filteredWordsArr))[])).empty);
1680        assert(join(cast(typeof(filteredWordsArr))[]).empty);
1681        assert(join(cast(typeof(filteredLenWordsArr))[]).empty);
1682
1683        assert(join(filter!"true"(cast(R[])[])).empty);
1684        assert(join(cast(R[])[]).empty);
1685    }
1686
1687    assert(join([[1, 2], [41, 42]], [5, 6]) == [1, 2, 5, 6, 41, 42]);
1688    assert(join([[1, 2], [41, 42]], cast(int[])[]) == [1, 2, 41, 42]);
1689    assert(join([[1, 2]], [5, 6]) == [1, 2]);
1690    assert(join(cast(int[][])[], [5, 6]).empty);
1691
1692    assert(join([[1, 2], [41, 42]]) == [1, 2, 41, 42]);
1693    assert(join(cast(int[][])[]).empty);
1694
1695    alias filter!"true" f;
1696    assert(join([[1, 2], [41, 42]],          [5, 6]) == [1, 2, 5, 6, 41, 42]);
1697    assert(join(f([[1, 2], [41, 42]]),       [5, 6]) == [1, 2, 5, 6, 41, 42]);
1698    assert(join([f([1, 2]), f([41, 42])],    [5, 6]) == [1, 2, 5, 6, 41, 42]);
1699    assert(join(f([f([1, 2]), f([41, 42])]), [5, 6]) == [1, 2, 5, 6, 41, 42]);
1700    assert(join([[1, 2], [41, 42]],          f([5, 6])) == [1, 2, 5, 6, 41, 42]);
1701    assert(join(f([[1, 2], [41, 42]]),       f([5, 6])) == [1, 2, 5, 6, 41, 42]);
1702    assert(join([f([1, 2]), f([41, 42])],    f([5, 6])) == [1, 2, 5, 6, 41, 42]);
1703    assert(join(f([f([1, 2]), f([41, 42])]), f([5, 6])) == [1, 2, 5, 6, 41, 42]);
1704}
1705
1706
1707/++
1708    Replace occurrences of $(D from) with $(D to) in $(D subject). Returns a new
1709    array without changing the contents of $(D subject), or the original array
1710    if no match is found.
1711 +/
1712E[] replace(E, R1, R2)(E[] subject, R1 from, R2 to)
1713if (isDynamicArray!(E[]) && isForwardRange!R1 && isForwardRange!R2
1714        && (hasLength!R2 || isSomeString!R2))
1715{
1716    if (from.empty) return subject;
1717
1718    auto balance = std.algorithm.find(subject, from.save);
1719    if (balance.empty)
1720        return subject;
1721
1722    auto app = appender!(E[])();
1723    app.put(subject[0 .. subject.length - balance.length]);
1724    app.put(to.save);
1725    replaceInto(app, balance[from.length .. $], from, to);
1726
1727    return app.data;
1728}
1729
1730/++
1731    Same as above, but outputs the result via OutputRange $(D sink).
1732    If no match is found the original array is transfered to $(D sink) as is.
1733+/
1734void replaceInto(E, Sink, R1, R2)(Sink sink, E[] subject, R1 from, R2 to)
1735if (isOutputRange!(Sink, E) && isDynamicArray!(E[])
1736    && isForwardRange!R1 && isForwardRange!R2
1737    && (hasLength!R2 || isSomeString!R2))
1738{
1739    if (from.empty)
1740    {
1741        sink.put(subject);
1742        return;
1743    }
1744    for (;;)
1745    {
1746        auto balance = std.algorithm.find(subject, from.save);
1747        if (balance.empty)
1748        {
1749            sink.put(subject);
1750            break;
1751        }
1752        sink.put(subject[0 .. subject.length - balance.length]);
1753        sink.put(to.save);
1754        subject = balance[from.length .. $];
1755    }
1756}
1757
1758unittest
1759{
1760    debug(std_array) printf("array.replace.unittest\n");
1761
1762    foreach (S; TypeTuple!(string, wstring, dstring, char[], wchar[], dchar[]))
1763    {
1764        auto s = to!S("This is a foo foo list");
1765        auto from = to!S("foo");
1766        auto into = to!S("silly");
1767        S r;
1768        int i;
1769
1770        r = replace(s, from, into);
1771        i = cmp(r, "This is a silly silly list");
1772        assert(i == 0);
1773
1774        r = replace(s, to!S(""), into);
1775        i = cmp(r, "This is a foo foo list");
1776        assert(i == 0);
1777
1778        assert(replace(r, to!S("won't find this"), to!S("whatever")) is r);
1779    }
1780
1781    immutable s = "This is a foo foo list";
1782    assert(replace(s, "foo", "silly") == "This is a silly silly list");
1783}
1784
1785unittest
1786{
1787    struct CheckOutput(C)
1788    {
1789        C[] desired;
1790        this(C[] arr){ desired = arr; }
1791        void put(C[] part){ assert(skipOver(desired, part)); }
1792    }
1793    foreach (S; TypeTuple!(string, wstring, dstring, char[], wchar[], dchar[]))
1794    {
1795        alias ElementEncodingType!S Char;
1796        S s = to!S("yet another dummy text, yet another ...");
1797        S from = to!S("yet another");
1798        S into = to!S("some");
1799        replaceInto(CheckOutput!(Char)(to!S("some dummy text, some ..."))
1800                    , s, from, into);
1801    }
1802}
1803
1804/+
1805Commented out until the replace which has been deprecated has been removed.
1806I'd love to just remove it in favor of replaceInPlace, but then code would then
1807use this version of replaceInPlace and silently break. So, it's here so that it
1808can be used once replace has not only been deprecated but removed, but
1809until then, it's commented out.
1810
1811/++
1812    Replaces elements from $(D array) with indices ranging from $(D from)
1813    (inclusive) to $(D to) (exclusive) with the range $(D stuff). Returns a new
1814    array without changing the contents of $(D subject).
1815
1816    Examples:
1817    --------------------
1818    auto a = [ 1, 2, 3, 4 ];
1819    auto b = a.replace(1, 3, [ 9, 9, 9 ]);
1820    assert(a == [ 1, 2, 3, 4 ]);
1821    assert(b == [ 1, 9, 9, 9, 4 ]);
1822    --------------------
1823 +/
1824T[] replace(T, Range)(T[] subject, size_t from, size_t to, Range stuff)
1825    if(isInputRange!Range &&
1826       (is(ElementType!Range : T) ||
1827        isSomeString!(T[]) && is(ElementType!Range : dchar)))
1828{
1829    static if(hasLength!Range && is(ElementEncodingType!Range : T))
1830    {
1831        assert(from <= to);
1832        immutable sliceLen = to - from;
1833        auto retval = new Unqual!(T)[](subject.length - sliceLen + stuff.length);
1834        retval[0 .. from] = subject[0 .. from];
1835
1836        if(!stuff.empty)
1837            copy(stuff, retval[from .. from + stuff.length]);
1838
1839        retval[from + stuff.length .. $] = subject[to .. $];
1840        return cast(T[])retval;
1841    }
1842    else
1843    {
1844        auto app = appender!(T[])();
1845        app.put(subject[0 .. from]);
1846        app.put(stuff);
1847        app.put(subject[to .. $]);
1848        return app.data;
1849    }
1850}
1851
1852//Verify Examples.
1853unittest
1854{
1855    auto a = [ 1, 2, 3, 4 ];
1856    auto b = a.replace(1, 3, [ 9, 9, 9 ]);
1857    assert(a == [ 1, 2, 3, 4 ]);
1858    assert(b == [ 1, 9, 9, 9, 4 ]);
1859}
1860
1861unittest
1862{
1863    auto a = [ 1, 2, 3, 4 ];
1864    assert(replace(a, 0, 0, [5, 6, 7]) == [5, 6, 7, 1, 2, 3, 4]);
1865    assert(replace(a, 0, 2, cast(int[])[]) == [3, 4]);
1866    assert(replace(a, 0, 4, [5, 6, 7]) == [5, 6, 7]);
1867    assert(replace(a, 0, 2, [5, 6, 7]) == [5, 6, 7, 3, 4]);
1868    assert(replace(a, 2, 4, [5, 6, 7]) == [1, 2, 5, 6, 7]);
1869
1870    assert(replace(a, 0, 0, filter!"true"([5, 6, 7])) == [5, 6, 7, 1, 2, 3, 4]);
1871    assert(replace(a, 0, 2, filter!"true"(cast(int[])[])) == [3, 4]);
1872    assert(replace(a, 0, 4, filter!"true"([5, 6, 7])) == [5, 6, 7]);
1873    assert(replace(a, 0, 2, filter!"true"([5, 6, 7])) == [5, 6, 7, 3, 4]);
1874    assert(replace(a, 2, 4, filter!"true"([5, 6, 7])) == [1, 2, 5, 6, 7]);
1875    assert(a == [ 1, 2, 3, 4 ]);
1876
1877    auto testStr(T, U)(string file = __FILE__, size_t line = __LINE__)
1878    {
1879
1880        auto l = to!T("hello");
1881        auto r = to!U(" world");
1882
1883        enforce(replace(l, 0, 0, r) == " worldhello",
1884                new AssertError("testStr failure 1", file, line));
1885        enforce(replace(l, 0, 3, r) == " worldlo",
1886                new AssertError("testStr failure 2", file, line));
1887        enforce(replace(l, 3, l.length, r) == "hel world",
1888                new AssertError("testStr failure 3", file, line));
1889        enforce(replace(l, 0, l.length, r) == " world",
1890                new AssertError("testStr failure 4", file, line));
1891        enforce(replace(l, l.length, l.length, r) == "hello world",
1892                new AssertError("testStr failure 5", file, line));
1893    }
1894
1895    testStr!(string, string)();
1896    testStr!(string, wstring)();
1897    testStr!(string, dstring)();
1898    testStr!(wstring, string)();
1899    testStr!(wstring, wstring)();
1900    testStr!(wstring, dstring)();
1901    testStr!(dstring, string)();
1902    testStr!(dstring, wstring)();
1903    testStr!(dstring, dstring)();
1904}
1905+/
1906
1907/++
1908    Replaces elements from $(D array) with indices ranging from $(D from)
1909    (inclusive) to $(D to) (exclusive) with the range $(D stuff). Expands or
1910    shrinks the array as needed.
1911
1912    Example:
1913    ---
1914    int[] a = [ 1, 2, 3, 4 ];
1915    a.replaceInPlace(1, 3, [ 9, 9, 9 ]);
1916    assert(a == [ 1, 9, 9, 9, 4 ]);
1917    ---
1918 +/
1919void replaceInPlace(T, Range)(ref T[] array, size_t from, size_t to, Range stuff)
1920    if(isDynamicArray!Range &&
1921       is(ElementEncodingType!Range : T) &&
1922       !is(T == const T) &&
1923       !is(T == immutable T))
1924{
1925    if (overlap(array, stuff).length)
1926    {
1927        // use slower/conservative method
1928        array = array[0 .. from] ~ stuff ~ array[to .. $];
1929    }
1930    else if (stuff.length <= to - from)
1931    {
1932        // replacement reduces length
1933        immutable stuffEnd = from + stuff.length;
1934        array[from .. stuffEnd] = stuff[];
1935        array = remove(array, tuple(stuffEnd, to));
1936    }
1937    else
1938    {
1939        // replacement increases length
1940        // @@@TODO@@@: optimize this
1941        immutable replaceLen = to - from;
1942        array[from .. to] = stuff[0 .. replaceLen];
1943        insertInPlace(array, to, stuff[replaceLen .. $]);
1944    }
1945}
1946
1947void replaceInPlace(T, Range)(ref T[] array, size_t from, size_t to, Range stuff)
1948    if(isInputRange!Range &&
1949       ((!isDynamicArray!Range && is(ElementType!Range : T)) ||
1950        (isDynamicArray!Range && is(ElementType!Range : T) &&
1951             (is(T == const T) || is(T == immutable T))) ||
1952        isSomeString!(T[]) && is(ElementType!Range : dchar)))
1953{
1954    auto app = appender!(T[])();
1955    app.put(array[0 .. from]);
1956    app.put(stuff);
1957    app.put(array[to .. $]);
1958    array = app.data;
1959
1960    //This simplified version can be used once the old replace has been removed
1961    //and the new one uncommented out.
1962    //array = replace(array, from, to stuff);
1963}
1964
1965//Verify Examples.
1966unittest
1967{
1968    int[] a = [1, 4, 5];
1969    replaceInPlace(a, 1u, 2u, [2, 3, 4]);
1970    assert(a == [1, 2, 3, 4, 5]);
1971    replaceInPlace(a, 1u, 2u, cast(int[])[]);
1972    assert(a == [1, 3, 4, 5]);
1973    replaceInPlace(a, 1u, 3u, a[2 .. 4]);
1974    assert(a == [1, 4, 5, 5]);
1975}
1976
1977unittest
1978{
1979    bool test(T, U, V)(T orig, size_t from, size_t to, U toReplace, V result,
1980               string file = __FILE__, size_t line = __LINE__)
1981    {
1982        {
1983            static if(is(T == typeof(T.init.dup)))
1984                auto a = orig.dup;
1985            else
1986                auto a = orig.idup;
1987
1988            a.replaceInPlace(from, to, toReplace);
1989            if(!std.algorithm.equal(a, result))
1990                return false;
1991        }
1992
1993        static if(isInputRange!U)
1994        {
1995            orig.replaceInPlace(from, to, filter!"true"(toReplace));
1996            return std.algorithm.equal(orig, result);
1997        }
1998        else
1999            return true;
2000    }
2001
2002    assert(test([1, 2, 3, 4], 0, 0, [5, 6, 7], [5, 6, 7, 1, 2, 3, 4]));
2003    assert(test([1, 2, 3, 4], 0, 2, cast(int[])[], [3, 4]));
2004    assert(test([1, 2, 3, 4], 0, 4, [5, 6, 7], [5, 6, 7]));
2005    assert(test([1, 2, 3, 4], 0, 2, [5, 6, 7], [5, 6, 7, 3, 4]));
2006    assert(test([1, 2, 3, 4], 2, 4, [5, 6, 7], [1, 2, 5, 6, 7]));
2007
2008    assert(test([1, 2, 3, 4], 0, 0, filter!"true"([5, 6, 7]), [5, 6, 7, 1, 2, 3, 4]));
2009    assert(test([1, 2, 3, 4], 0, 2, filter!"true"(cast(int[])[]), [3, 4]));
2010    assert(test([1, 2, 3, 4], 0, 4, filter!"true"([5, 6, 7]), [5, 6, 7]));
2011    assert(test([1, 2, 3, 4], 0, 2, filter!"true"([5, 6, 7]), [5, 6, 7, 3, 4]));
2012    assert(test([1, 2, 3, 4], 2, 4, filter!"true"([5, 6, 7]), [1, 2, 5, 6, 7]));
2013
2014    auto testStr(T, U)(string file = __FILE__, size_t line = __LINE__)
2015    {
2016
2017        auto l = to!T("hello");
2018        auto r = to!U(" world");
2019
2020        enforce(test(l, 0, 0, r, " worldhello"),
2021                new AssertError("testStr failure 1", file, line));
2022        enforce(test(l, 0, 3, r, " worldlo"),
2023                new AssertError("testStr failure 2", file, line));
2024        enforce(test(l, 3, l.length, r, "hel world"),
2025                new AssertError("testStr failure 3", file, line));
2026        enforce(test(l, 0, l.length, r, " world"),
2027                new AssertError("testStr failure 4", file, line));
2028        enforce(test(l, l.length, l.length, r, "hello world"),
2029                new AssertError("testStr failure 5", file, line));
2030    }
2031
2032    testStr!(string, string)();
2033    testStr!(string, wstring)();
2034    testStr!(string, dstring)();
2035    testStr!(wstring, string)();
2036    testStr!(wstring, wstring)();
2037    testStr!(wstring, dstring)();
2038    testStr!(dstring, string)();
2039    testStr!(dstring, wstring)();
2040    testStr!(dstring, dstring)();
2041}
2042
2043/++
2044    Replaces the first occurrence of $(D from) with $(D to) in $(D a). Returns a
2045    new array without changing the contents of $(D subject), or the original
2046    array if no match is found.
2047 +/
2048E[] replaceFirst(E, R1, R2)(E[] subject, R1 from, R2 to)
2049if (isDynamicArray!(E[]) &&
2050    isForwardRange!R1 && is(typeof(appender!(E[])().put(from[0 .. 1]))) &&
2051    isForwardRange!R2 && is(typeof(appender!(E[])().put(to[0 .. 1]))))
2052{
2053    if (from.empty) return subject;
2054    auto balance = std.algorithm.find(subject, from.save);
2055    if (balance.empty) return subject;
2056    auto app = appender!(E[])();
2057    app.put(subject[0 .. subject.length - balance.length]);
2058    app.put(to.save);
2059    app.put(balance[from.length .. $]);
2060
2061    return app.data;
2062}
2063
2064unittest
2065{
2066    debug(std_array) printf("array.replaceFirst.unittest\n");
2067
2068    foreach(S; TypeTuple!(string, wstring, dstring, char[], wchar[], dchar[],
2069                          const(char[]), immutable(char[])))
2070    {
2071        alias Unqual!S T;
2072
2073        auto s = to!S("This is a foo foo list");
2074        auto from = to!T("foo");
2075        auto into = to!T("silly");
2076
2077        S r1 = replaceFirst(s, from, into);
2078        assert(cmp(r1, "This is a silly foo list") == 0);
2079
2080        S r2 = replaceFirst(r1, from, into);
2081        assert(cmp(r2, "This is a silly silly list") == 0);
2082
2083        S r3 = replaceFirst(s, to!T(""), into);
2084        assert(cmp(r3, "This is a foo foo list") == 0);
2085
2086        assert(replaceFirst(r3, to!T("won't find"), to!T("whatever")) is r3);
2087    }
2088}
2089
2090//Bug# 8187
2091unittest
2092{
2093    auto res = ["a", "a"];
2094    assert(replace(res, "a", "b") == ["b", "b"]);
2095    assert(replaceFirst(res, "a", "b") == ["b", "a"]);
2096}
2097
2098/++
2099    Returns an array that is $(D s) with $(D slice) replaced by
2100    $(D replacement[]).
2101 +/
2102inout(T)[] replaceSlice(T)(inout(T)[] s, in T[] slice, in T[] replacement)
2103in
2104{
2105    // Verify that slice[] really is a slice of s[]
2106    assert(overlap(s, slice) is slice);
2107}
2108body
2109{
2110    auto result = new T[s.length - slice.length + replacement.length];
2111    immutable so = slice.ptr - s.ptr;
2112    result[0 .. so] = s[0 .. so];
2113    result[so .. so + replacement.length] = replacement[];
2114    result[so + replacement.length .. result.length] =
2115        s[so + slice.length .. s.length];
2116
2117    return cast(inout(T)[]) result;
2118}
2119
2120unittest
2121{
2122    debug(std_array) printf("array.replaceSlice.unittest\n");
2123
2124    string s = "hello";
2125    string slice = s[2 .. 4];
2126
2127    auto r = replaceSlice(s, slice, "bar");
2128    int i;
2129    i = cmp(r, "hebaro");
2130    assert(i == 0);
2131}
2132
2133/**
2134Implements an output range that appends data to an array. This is
2135recommended over $(D a ~= data) when appending many elements because it is more
2136efficient.
2137
2138Example:
2139----
2140auto app = appender!string();
2141string b = "abcdefg";
2142foreach (char c; b) app.put(c);
2143assert(app.data == "abcdefg");
2144
2145int[] a = [ 1, 2 ];
2146auto app2 = appender(a);
2147app2.put(3);
2148app2.put([ 4, 5, 6 ]);
2149assert(app2.data == [ 1, 2, 3, 4, 5, 6 ]);
2150----
2151 */
2152struct Appender(A : T[], T)
2153{
2154    private struct Data
2155    {
2156        size_t capacity;
2157        Unqual!T[] arr;
2158    }
2159
2160    private Data* _data;
2161
2162    /**
2163     * Construct an appender with a given array.  Note that this does not copy the
2164     * data.  If the array has a larger capacity as determined by arr.capacity,
2165     * it will be used by the appender.  After initializing an appender on an array,
2166     * appending to the original array will reallocate.
2167     */
2168    this(Unqual!T[] arr) @safe pure nothrow
2169    {
2170        // initialize to a given array.
2171        _data = new Data;
2172        _data.arr = arr;
2173
2174        if (__ctfe)
2175            return;
2176
2177        // We want to use up as much of the block the array is in as possible.
2178        // if we consume all the block that we can, then array appending is
2179        // safe WRT built-in append, and we can use the entire block.
2180        auto cap = ()@trusted{ return arr.capacity; }();
2181        if (cap > arr.length)
2182            arr = ()@trusted{ return arr.ptr[0 .. cap]; }();
2183        // we assume no reallocation occurred
2184        assert(arr.ptr is _data.arr.ptr);
2185        _data.capacity = arr.length;
2186    }
2187
2188    /**
2189     * Reserve at least newCapacity elements for appending.  Note that more elements
2190     * may be reserved than requested.  If newCapacity <= capacity, then nothing is
2191     * done.
2192     */
2193    void reserve(size_t newCapacity) @safe pure nothrow
2194    {
2195        if (_data)
2196        {
2197            if (newCapacity > _data.capacity)
2198                ensureAddable(newCapacity - _data.arr.length);
2199        }
2200        else
2201        {
2202            ensureAddable(newCapacity);
2203        }
2204    }
2205
2206    /**
2207     * Returns the capacity of the array (the maximum number of elements the
2208     * managed array can accommodate before triggering a reallocation).  If any
2209     * appending will reallocate, $(D capacity) returns $(D 0).
2210     */
2211    @property size_t capacity() const @safe pure nothrow
2212    {
2213        return _data ? _data.capacity : 0;
2214    }
2215
2216    /**
2217     * Returns the managed array.
2218     */
2219    @property inout(T)[] data() inout @trusted pure nothrow
2220    {
2221        /* @trusted operation:
2222         * casting Unqual!T[] to inout(T)[]
2223         */
2224        return cast(typeof(return))(_data ? _data.arr : null);
2225    }
2226
2227    // ensure we can add nelems elements, resizing as necessary
2228    private void ensureAddable(size_t nelems) @safe pure nothrow
2229    {
2230        if (!_data)
2231            _data = new Data;
2232        immutable len = _data.arr.length;
2233        immutable reqlen = len + nelems;
2234
2235        if (()@trusted{ return _data.capacity; }() >= reqlen)
2236            return;
2237
2238        // need to increase capacity
2239        if (__ctfe)
2240        {
2241            static if (__traits(compiles, new Unqual!T[1]))
2242            {
2243                _data.arr.length = reqlen;
2244            }
2245            else
2246            {
2247                // avoid restriction of @disable this()
2248                ()@trusted{ _data.arr = _data.arr[0 .. _data.capacity]; }();
2249                foreach (i; _data.capacity .. reqlen)
2250                    _data.arr ~= Unqual!T.init;
2251            }
2252            _data.arr = _data.arr[0 .. len];
2253            _data.capacity = reqlen;
2254        }
2255        else
2256        {
2257            // Time to reallocate.
2258            // We need to almost duplicate what's in druntime, except we
2259            // have better access to the capacity field.
2260            auto newlen = appenderNewCapacity!(T.sizeof)(_data.capacity, reqlen);
2261            // first, try extending the current block
2262            auto u = ()@trusted{ return
2263                GC.extend(_data.arr.ptr, nelems * T.sizeof, (newlen - len) * T.sizeof);
2264            }();
2265            if (u)
2266            {
2267                // extend worked, update the capacity
2268                _data.capacity = u / T.sizeof;
2269            }
2270            else
2271            {
2272                // didn't work, must reallocate
2273                auto bi = ()@trusted{ return
2274                    GC.qalloc(newlen * T.sizeof, (typeid(T[]).next.flags & 1) ? 0 : GC.BlkAttr.NO_SCAN);
2275                }();
2276                _data.capacity = bi.size / T.sizeof;
2277                if (len)
2278                    ()@trusted{ memcpy(bi.base, _data.arr.ptr, len * T.sizeof); }();
2279                _data.arr = ()@trusted{ return (cast(Unqual!T*)bi.base)[0 .. len]; }();
2280                // leave the old data, for safety reasons
2281            }
2282        }
2283    }
2284
2285    private template canPutItem(U)
2286    {
2287        enum bool canPutItem =
2288            isImplicitlyConvertible!(U, T) ||
2289            isSomeChar!T && isSomeChar!U;
2290    }
2291    private template canPutConstRange(Range)
2292    {
2293        enum bool canPutConstRange =
2294            isInputRange!(Unqual!Range) &&
2295            !isInputRange!Range;
2296    }
2297    private template canPutRange(Range)
2298    {
2299        enum bool canPutRange =
2300            isInputRange!Range &&
2301            is(typeof(Appender.init.put(Range.init.front)));
2302    }
2303
2304    /**
2305     * Appends one item to the managed array.
2306     */
2307    void put(U)(U item) if (canPutItem!U)
2308    {
2309        static if (isSomeChar!T && isSomeChar!U && T.sizeof < U.sizeof)
2310        {
2311            /* may throwable operation:
2312             * - std.utf.encode
2313             */
2314            // must do some transcoding around here
2315            Unqual!T[T.sizeof == 1 ? 4 : 2] encoded;
2316            auto len = std.utf.encode(encoded, item);
2317            put(encoded[0 .. len]);
2318        }
2319        else
2320        {
2321            ensureAddable(1);
2322            immutable len = _data.arr.length;
2323
2324            auto bigDataFun() @trusted nothrow { return _data.arr.ptr[0 .. len + 1];}
2325            auto bigData = bigDataFun();
2326
2327            static if (is(Unqual!T == T))
2328                alias uitem = item;
2329            else
2330                auto ref uitem() @trusted nothrow @property { return cast(Unqual!T)item;}
2331
2332            //The idea is to only call emplace if we must.
2333            static if ( is(typeof(bigData[0].opAssign(uitem))) ||
2334                       !is(typeof(bigData[0] = uitem)))
2335            {
2336                //pragma(msg, T.stringof); pragma(msg, U.stringof);
2337                emplace(&bigData[len], uitem);
2338            }
2339            else
2340            {
2341                //pragma(msg, T.stringof); pragma(msg, U.stringof);
2342                bigData[len] = uitem;
2343            }
2344
2345            //We do this at the end, in case of exceptions
2346            _data.arr = bigData;
2347        }
2348    }
2349
2350    // Const fixing hack.
2351    void put(Range)(Range items) if (canPutConstRange!Range)
2352    {
2353        alias put!(Unqual!Range) p;
2354        p(items);
2355    }
2356
2357    /**
2358     * Appends an entire range to the managed array.
2359     */
2360    void put(Range)(Range items) if (canPutRange!Range)
2361    {
2362        // note, we disable this branch for appending one type of char to
2363        // another because we can't trust the length portion.
2364        static if (!(isSomeChar!T && isSomeChar!(ElementType!Range) &&
2365                     !is(immutable Range == immutable T[])) &&
2366                    is(typeof(items.length) == size_t))
2367        {
2368            // optimization -- if this type is something other than a string,
2369            // and we are adding exactly one element, call the version for one
2370            // element.
2371            static if (!isSomeChar!T)
2372            {
2373                if (items.length == 1)
2374                {
2375                    put(items.front);
2376                    return;
2377                }
2378            }
2379
2380            // make sure we have enough space, then add the items
2381            ensureAddable(items.length);
2382            immutable len = _data.arr.length;
2383            immutable newlen = len + items.length;
2384
2385            auto bigDataFun() @trusted nothrow { return _data.arr.ptr[0 .. newlen];}
2386            auto bigData = bigDataFun();
2387
2388            enum mustEmplace =  is(typeof(bigData[0].opAssign(cast(Unqual!T)items.front))) ||
2389                               !is(typeof(bigData[0] = cast(Unqual!T)items.front));
2390
2391            static if (is(typeof(_data.arr[] = items[])) && !mustEmplace)
2392            {
2393                //pragma(msg, T.stringof); pragma(msg, Range.stringof);
2394                bigData[len .. newlen] = items[];
2395            }
2396            else static if (is(Unqual!T == ElementType!Range))
2397            {
2398                foreach (ref it ; bigData[len .. newlen])
2399                {
2400                    static if (mustEmplace)
2401                        emplace(&it, items.front);
2402                    else
2403                        it = items.front;
2404                    items.popFront();
2405                }
2406            }
2407            else
2408            {
2409                static auto ref getUItem(U)(U item) @trusted {return cast(Unqual!T)item;}
2410                foreach (ref it ; bigData[len .. newlen])
2411                {
2412                    static if (mustEmplace)
2413                        emplace(&it, getUItem(items.front));
2414                    else
2415                        it = getUItem(items.front);
2416                    items.popFront();
2417                }
2418            }
2419
2420            //We do this at the end, in case of exceptions
2421            _data.arr = bigData;
2422        }
2423        else
2424        {
2425            //pragma(msg, Range.stringof);
2426            // Generic input range
2427            for (; !items.empty; items.popFront())
2428            {
2429                put(items.front);
2430            }
2431        }
2432    }
2433
2434    /**
2435     * Appends one item to the managed array.
2436     */
2437    void opOpAssign(string op : "~", U)(U item) if (canPutItem!U)
2438    {
2439        put(item);
2440    }
2441
2442    // Const fixing hack.
2443    void opOpAssign(string op : "~", Range)(Range items) if (canPutConstRange!Range)
2444    {
2445        put(items);
2446    }
2447
2448    /**
2449     * Appends an entire range to the managed array.
2450     */
2451    void opOpAssign(string op : "~", Range)(Range items) if (canPutRange!Range)
2452    {
2453        put(items);
2454    }
2455
2456    // only allow overwriting data on non-immutable and non-const data
2457    static if (isMutable!T)
2458    {
2459        /**
2460         * Clears the managed array.  This allows the elements of the array to be reused
2461         * for appending.
2462         *
2463         * Note that clear is disabled for immutable or const element types, due to the
2464         * possibility that $(D Appender) might overwrite immutable data.
2465         */
2466        void clear() @safe pure nothrow
2467        {
2468            if (_data)
2469            {
2470                _data.arr = ()@trusted{ return _data.arr.ptr[0 .. 0]; }();
2471            }
2472        }
2473
2474        /**
2475         * Shrinks the managed array to the given length.
2476         *
2477         * Throws: $(D Exception) if newlength is greater than the current array length.
2478         */
2479        void shrinkTo(size_t newlength) @safe pure
2480        {
2481            if (_data)
2482            {
2483                enforce(newlength <= _data.arr.length);
2484                _data.arr = ()@trusted{ return _data.arr.ptr[0 .. newlength]; }();
2485            }
2486            else
2487                enforce(newlength == 0);
2488        }
2489    }
2490}
2491
2492//Calculates an efficient growth scheme based on the old capacity
2493//of data, and the minimum requested capacity.
2494//arg curLen: The current length
2495//arg reqLen: The length as requested by the user
2496//ret sugLen: A suggested growth.
2497private size_t appenderNewCapacity(size_t TSizeOf)(size_t curLen, size_t reqLen) @safe pure nothrow
2498{
2499    if(curLen == 0)
2500        return max(reqLen,8);
2501    ulong mult = 100 + (1000UL) / (bsr(curLen * TSizeOf) + 1);
2502    // limit to doubling the length, we don't want to grow too much
2503    if(mult > 200)
2504        mult = 200;
2505    auto sugLen = cast(size_t)((curLen * mult + 99) / 100);
2506    return max(reqLen, sugLen);
2507}
2508
2509/**
2510 * An appender that can update an array in-place.  It forwards all calls to an
2511 * underlying appender implementation.  Any calls made to the appender also update
2512 * the pointer to the original array passed in.
2513 */
2514struct RefAppender(A : T[], T)
2515{
2516    private
2517    {
2518        Appender!(A, T) impl;
2519        T[] *arr;
2520    }
2521
2522    /**
2523     * Construct a ref appender with a given array reference.  This does not copy the
2524     * data.  If the array has a larger capacity as determined by arr.capacity, it
2525     * will be used by the appender.  $(D RefAppender) assumes that arr is a non-null
2526     * value.
2527     *
2528     * Note, do not use builtin appending (i.e. ~=) on the original array passed in
2529     * until you are done with the appender, because calls to the appender override
2530     * those appends.
2531     */
2532    this(T[] *arr)
2533    {
2534        impl = Appender!(A, T)(*arr);
2535        this.arr = arr;
2536    }
2537
2538    auto opDispatch(string fn, Args...)(Args args) if (is(typeof(mixin("impl." ~ fn ~ "(args)"))))
2539    {
2540        // we do it this way because we can't cache a void return
2541        scope(exit) *this.arr = impl.data;
2542        mixin("return impl." ~ fn ~ "(args);");
2543    }
2544
2545    private alias Appender!(A, T) AppenderType;
2546
2547    /**
2548     * Appends one item to the managed array.
2549     */
2550    void opOpAssign(string op : "~", U)(U item) if (AppenderType.canPutItem!U)
2551    {
2552        scope(exit) *this.arr = impl.data;
2553        impl.put(item);
2554    }
2555
2556    // Const fixing hack.
2557    void opOpAssign(string op : "~", Range)(Range items) if (AppenderType.canPutConstRange!Range)
2558    {
2559        scope(exit) *this.arr = impl.data;
2560        impl.put(items);
2561    }
2562
2563    /**
2564     * Appends an entire range to the managed array.
2565     */
2566    void opOpAssign(string op : "~", Range)(Range items) if (AppenderType.canPutRange!Range)
2567    {
2568        scope(exit) *this.arr = impl.data;
2569        impl.put(items);
2570    }
2571
2572    /**
2573     * Returns the capacity of the array (the maximum number of elements the
2574     * managed array can accommodate before triggering a reallocation).  If any
2575     * appending will reallocate, $(D capacity) returns $(D 0).
2576     */
2577    @property size_t capacity() const
2578    {
2579        return impl.capacity;
2580    }
2581
2582    /**
2583     * Returns the managed array.
2584     */
2585    @property inout(T)[] data() inout
2586    {
2587        return impl.data;
2588    }
2589}
2590
2591/++
2592    Convenience function that returns an $(D Appender!A) object initialized
2593    with $(D array).
2594 +/
2595Appender!(E[]) appender(A : E[], E)()
2596{
2597    return Appender!(E[])(null);
2598}
2599/// ditto
2600Appender!(E[]) appender(A : E[], E)(A array)
2601{
2602    static if (isMutable!E)
2603    {
2604        return Appender!(E[])(array);
2605    }
2606    else
2607    {
2608        /* @system operation:
2609         * - casting array to Unqual!E[] (remove qualifiers)
2610         */
2611        return Appender!(E[])(cast(Unqual!E[])array);
2612    }
2613}
2614
2615@safe pure nothrow unittest
2616{
2617    {
2618        auto app = appender!(char[])();
2619        string b = "abcdefg";
2620        foreach (char c; b) app.put(c);
2621        assert(app.data == "abcdefg");
2622    }
2623    {
2624        auto app = appender!(char[])();
2625        string b = "abcdefg";
2626        foreach (char c; b) app ~= c;
2627        assert(app.data == "abcdefg");
2628    }
2629    {
2630        int[] a = [ 1, 2 ];
2631        auto app2 = appender(a);
2632        assert(app2.data == [ 1, 2 ]);
2633        app2.put(3);
2634        app2.put([ 4, 5, 6 ][]);
2635        assert(app2.data == [ 1, 2, 3, 4, 5, 6 ]);
2636        app2.put([ 7 ]);
2637        assert(app2.data == [ 1, 2, 3, 4, 5, 6, 7 ]);
2638    }
2639
2640    int[] a = [ 1, 2 ];
2641    auto app2 = appender(a);
2642    assert(app2.data == [ 1, 2 ]);
2643    app2 ~= 3;
2644    app2 ~= [ 4, 5, 6 ][];
2645    assert(app2.data == [ 1, 2, 3, 4, 5, 6 ]);
2646    app2 ~= [ 7 ];
2647    assert(app2.data == [ 1, 2, 3, 4, 5, 6, 7 ]);
2648
2649    app2.reserve(5);
2650    assert(app2.capacity >= 5);
2651
2652    try // shrinkTo may throw
2653    {
2654        app2.shrinkTo(3);
2655    }
2656    catch (Exception) assert(0);
2657    assert(app2.data == [ 1, 2, 3 ]);
2658    assertThrown(app2.shrinkTo(5));
2659
2660    const app3 = app2;
2661    assert(app3.capacity >= 3);
2662    assert(app3.data == [1, 2, 3]);
2663
2664    auto app4 = appender([]);
2665    try // shrinkTo may throw
2666    {
2667        app4.shrinkTo(0);
2668    }
2669    catch (Exception) assert(0);
2670
2671    // Issue 5663 & 9725 tests
2672    foreach (S; TypeTuple!(char[], const(char)[], string))
2673    {
2674        {
2675            Appender!S app5663i;
2676            assertNotThrown(app5663i.put("\xE3"));
2677            assert(app5663i.data == "\xE3");
2678
2679            Appender!S app5663c;
2680            assertNotThrown(app5663c.put(cast(const(char)[])"\xE3"));
2681            assert(app5663c.data == "\xE3");
2682
2683            Appender!S app5663m;
2684            assertNotThrown(app5663m.put("\xE3".dup));
2685            assert(app5663m.data == "\xE3");
2686        }
2687        // ditto for ~=
2688        {
2689            Appender!S app5663i;
2690            assertNotThrown(app5663i ~= "\xE3");
2691            assert(app5663i.data == "\xE3");
2692
2693            Appender!S app5663c;
2694            assertNotThrown(app5663c ~= cast(const(char)[])"\xE3");
2695            assert(app5663c.data == "\xE3");
2696
2697            Appender!S app5663m;
2698            assertNotThrown(app5663m ~= "\xE3".dup);
2699            assert(app5663m.data == "\xE3");
2700        }
2701    }
2702
2703    static struct S10122
2704    {
2705        int val;
2706
2707        @disable this();
2708        this(int v) @safe pure nothrow { val = v; }
2709    }
2710    assertCTFEable!(
2711    {
2712        auto w = appender!(S10122[])();
2713        w.put(S10122(1));
2714        assert(w.data.length == 1 && w.data[0].val == 1);
2715    });
2716}
2717
2718@safe pure nothrow unittest
2719{
2720    {
2721        auto w = appender!string();
2722        w.reserve(4);
2723        w.capacity;
2724        w.data;
2725        try
2726        {
2727            wchar wc = 'a';
2728            dchar dc = 'a';
2729            w.put(wc);    // decoding may throw
2730            w.put(dc);    // decoding may throw
2731        }
2732        catch (Exception) assert(0);
2733    }
2734    {
2735        auto w = appender!(int[])();
2736        w.reserve(4);
2737        w.capacity;
2738        w.data;
2739        w.put(10);
2740        w.put([10]);
2741        w.clear();
2742        try
2743        {
2744            w.shrinkTo(0);
2745        }
2746        catch (Exception) assert(0);
2747
2748        struct N
2749        {
2750            int payload;
2751            alias payload this;
2752        }
2753        w.put(N(1));
2754        w.put([N(2)]);
2755
2756        struct S(T)
2757        {
2758            @property bool empty() { return true; }
2759            @property T front() { return T.init; }
2760            void popFront() {}
2761        }
2762        S!int r;
2763        w.put(r);
2764    }
2765}
2766
2767unittest
2768{
2769    //10690
2770    [tuple(1)].filter!(t => true).array; // No error
2771    [tuple("A")].filter!(t => true).array; // error
2772}
2773
2774unittest
2775{
2776    //Coverage for put(Range)
2777    struct S1
2778    {
2779    }
2780    struct S2
2781    {
2782        void opAssign(S2){}
2783    }
2784    auto a1 = Appender!(S1[])();
2785    auto a2 = Appender!(S2[])();
2786    auto au1 = Appender!(const(S1)[])();
2787    auto au2 = Appender!(const(S2)[])();
2788    a1.put(S1().repeat().take(10));
2789    a2.put(S2().repeat().take(10));
2790    auto sc1 = const(S1)();
2791    auto sc2 = const(S2)();
2792    au1.put(sc1.repeat().take(10));
2793    au2.put(sc2.repeat().take(10));
2794}
2795
2796unittest
2797{
2798    struct S
2799    {
2800        int* p;
2801    }
2802
2803    auto a0 = Appender!(S[])();
2804    auto a1 = Appender!(const(S)[])();
2805    auto a2 = Appender!(immutable(S)[])();
2806    auto s0 = S(null);
2807    auto s1 = const(S)(null);
2808    auto s2 = immutable(S)(null);
2809    a1.put(s0);
2810    a1.put(s1);
2811    a1.put(s2);
2812    a1.put([s0]);
2813    a1.put([s1]);
2814    a1.put([s2]);
2815    a0.put(s0);
2816    static assert(!is(typeof(a0.put(a1))));
2817    static assert(!is(typeof(a0.put(a2))));
2818    a0.put([s0]);
2819    static assert(!is(typeof(a0.put([a1]))));
2820    static assert(!is(typeof(a0.put([a2]))));
2821    static assert(!is(typeof(a2.put(a0))));
2822    static assert(!is(typeof(a2.put(a1))));
2823    a2.put(s2);
2824    static assert(!is(typeof(a2.put([a0]))));
2825    static assert(!is(typeof(a2.put([a1]))));
2826    a2.put([s2]);
2827}
2828
2829unittest
2830{ //9528
2831    const(E)[] fastCopy(E)(E[] src) {
2832            auto app = appender!(const(E)[])();
2833            foreach (i, e; src)
2834                    app.put(e);
2835            return app.data;
2836    }
2837
2838    class C {}
2839    struct S { const(C) c; }
2840    S[] s = [ S(new C) ];
2841
2842    auto t = fastCopy(s); // Does not compile
2843}
2844
2845unittest
2846{ //10753
2847    struct Foo {
2848       immutable dchar d;
2849    }
2850    struct Bar {
2851       immutable int x;
2852    }
2853   "12".map!Foo.array;
2854   [1, 2].map!Bar.array;
2855}
2856
2857/++
2858    Convenience function that returns a $(D RefAppender!A) object initialized
2859    with $(D array).  Don't use null for the $(D array) pointer, use the other
2860    version of $(D appender) instead.
2861 +/
2862RefAppender!(E[]) appender(A : E[]*, E)(A array)
2863{
2864    return RefAppender!(E[])(array);
2865}
2866
2867unittest
2868{
2869    {
2870        auto arr = new char[0];
2871        auto app = appender(&arr);
2872        string b = "abcdefg";
2873        foreach (char c; b) app.put(c);
2874        assert(app.data == "abcdefg");
2875        assert(arr == "abcdefg");
2876    }
2877    {
2878        auto arr = new char[0];
2879        auto app = appender(&arr);
2880        string b = "abcdefg";
2881        foreach (char c; b) app ~= c;
2882        assert(app.data == "abcdefg");
2883        assert(arr == "abcdefg");
2884    }
2885    {
2886        int[] a = [ 1, 2 ];
2887        auto app2 = appender(&a);
2888        assert(app2.data == [ 1, 2 ]);
2889        assert(a == [ 1, 2 ]);
2890        app2.put(3);
2891        app2.put([ 4, 5, 6 ][]);
2892        assert(app2.data == [ 1, 2, 3, 4, 5, 6 ]);
2893        assert(a == [ 1, 2, 3, 4, 5, 6 ]);
2894    }
2895
2896    int[] a = [ 1, 2 ];
2897    auto app2 = appender(&a);
2898    assert(app2.data == [ 1, 2 ]);
2899    assert(a == [ 1, 2 ]);
2900    app2 ~= 3;
2901    app2 ~= [ 4, 5, 6 ][];
2902    assert(app2.data == [ 1, 2, 3, 4, 5, 6 ]);
2903    assert(a == [ 1, 2, 3, 4, 5, 6 ]);
2904
2905    app2.reserve(5);
2906    assert(app2.capacity >= 5);
2907
2908    try // shrinkTo may throw
2909    {
2910        app2.shrinkTo(3);
2911    }
2912    catch (Exception) assert(0);
2913    assert(app2.data == [ 1, 2, 3 ]);
2914    assertThrown(app2.shrinkTo(5));
2915
2916    const app3 = app2;
2917    assert(app3.capacity >= 3);
2918    assert(app3.data == [1, 2, 3]);
2919}
2920
2921unittest
2922{
2923    Appender!(int[]) app;
2924    short[] range = [1, 2, 3];
2925    app.put(range);
2926    assert(app.data == [1, 2, 3]);
2927}
2928
2929/*
2930A simple slice type only holding pointers to the beginning and the end
2931of an array. Experimental duplication of the built-in slice - do not
2932use yet.
2933 */
2934struct SimpleSlice(T)
2935{
2936    private T * _b, _e;
2937
2938    this(U...)(U values)
2939    {
2940        _b = cast(T*) core.memory.GC.malloc(U.length * T.sizeof);
2941        _e = _b + U.length;
2942        foreach (i, Unused; U) _b[i] = values[i];
2943    }
2944
2945    void opAssign(R)(R anotherSlice)
2946    {
2947        static if (is(typeof(*_b = anotherSlice)))
2948        {
2949            // assign all elements to a value
2950            foreach (p; _b .. _e)
2951            {
2952                *p = anotherSlice;
2953            }
2954        }
2955        else
2956        {
2957            // assign another slice to this
2958            enforce(anotherSlice.length == length);
2959            auto p = _b;
2960            foreach (p; _b .. _e)
2961            {
2962                *p = anotherSlice.front;
2963                anotherSlice.popFront();
2964            }
2965        }
2966    }
2967
2968/**
2969   Range primitives.
2970 */
2971    bool empty() const
2972    {
2973        assert(_b <= _e);
2974        return _b == _e;
2975    }
2976
2977/// Ditto
2978    ref T front()
2979    {
2980        assert(!empty);
2981        return *_b;
2982    }
2983
2984/// Ditto
2985    void popFront()
2986    {
2987        assert(!empty);
2988        ++_b;
2989    }
2990
2991/// Ditto
2992    ref T back()
2993    {
2994        assert(!empty);
2995        return _e[-1];
2996    }
2997
2998/// Ditto
2999    void popBack()
3000    {
3001        assert(!empty);
3002        --_e;
3003    }
3004
3005/// Ditto
3006    T opIndex(size_t n)
3007    {
3008        assert(n < length);
3009        return _b[n];
3010    }
3011
3012/// Ditto
3013    const(T) opIndex(size_t n) const
3014    {
3015        assert(n < length);
3016        return _b[n];
3017    }
3018
3019/// Ditto
3020    void opIndexAssign(T value, size_t n)
3021    {
3022        assert(n < length);
3023        _b[n] = value;
3024    }
3025
3026/// Ditto
3027    SimpleSliceLvalue!T opSlice()
3028    {
3029        typeof(return) result = void;
3030        result._b = _b;
3031        result._e = _e;
3032        return result;
3033    }
3034
3035/// Ditto
3036    SimpleSliceLvalue!T opSlice(size_t x, size_t y)
3037    {
3038        enforce(x <= y && y <= length);
3039        typeof(return) result = { _b + x, _b + y };
3040        return result;
3041    }
3042
3043    @property
3044    {
3045        /// Returns the length of the slice.
3046        size_t length() const
3047        {
3048            return _e - _b;
3049        }
3050
3051        /**
3052        Sets the length of the slice. Newly added elements will be filled with
3053        $(D T.init).
3054         */
3055        void length(size_t newLength)
3056        {
3057            immutable oldLength = length;
3058            _b = cast(T*) core.memory.GC.realloc(_b, newLength * T.sizeof);
3059            _e = _b + newLength;
3060            this[oldLength .. $] = T.init;
3061        }
3062    }
3063
3064/// Concatenation.
3065    SimpleSlice opCat(R)(R another)
3066    {
3067        immutable newLen = length + another.length;
3068        typeof(return) result = void;
3069        result._b = cast(T*)
3070            core.memory.GC.malloc(newLen * T.sizeof);
3071        result._e = result._b + newLen;
3072        result[0 .. this.length] = this;
3073        result[this.length .. result.length] = another;
3074        return result;
3075    }
3076
3077/// Concatenation with rebinding.
3078    void opCatAssign(R)(R another)
3079    {
3080        auto newThis = this ~ another;
3081        move(newThis, this);
3082    }
3083}
3084
3085// Support for mass assignment
3086struct SimpleSliceLvalue(T)
3087{
3088    private SimpleSlice!T _s;
3089    alias _s this;
3090
3091    void opAssign(R)(R anotherSlice)
3092    {
3093        static if (is(typeof(*_b = anotherSlice)))
3094        {
3095            // assign all elements to a value
3096            foreach (p; _b .. _e)
3097            {
3098                *p = anotherSlice;
3099            }
3100        }
3101        else
3102        {
3103            // assign another slice to this
3104            enforce(anotherSlice.length == length);
3105            auto p = _b;
3106            foreach (p; _b .. _e)
3107            {
3108                *p = anotherSlice.front;
3109                anotherSlice.popFront();
3110            }
3111        }
3112    }
3113}
3114
3115unittest
3116{
3117    // SimpleSlice!(int) s;
3118
3119    // s = SimpleSlice!(int)(4, 5, 6);
3120    // assert(equal(s, [4, 5, 6][]));
3121    // assert(s.length == 3);
3122    // assert(s[0] == 4);
3123    // assert(s[1] == 5);
3124    // assert(s[2] == 6);
3125
3126    // assert(s[] == s);
3127    // assert(s[0 .. s.length] == s);
3128    // assert(equal(s[0 .. s.length - 1], [4, 5][]));
3129
3130    // auto s1 = s ~ s[0 .. 1];
3131    // assert(equal(s1, [4, 5, 6, 4][]));
3132
3133    // assert(s1[3] == 4);
3134    // s1[3] = 42;
3135    // assert(s1[3] == 42);
3136
3137    // const s2 = s;
3138    // assert(s2.length == 3);
3139    // assert(!s2.empty);
3140    // assert(s2[0] == s[0]);
3141
3142    // s[0 .. 2] = 10;
3143    // assert(equal(s, [10, 10, 6][]));
3144
3145    // s ~= [ 5, 9 ][];
3146    // assert(equal(s, [10, 10, 6, 5, 9][]));
3147
3148    // s.length = 7;
3149    // assert(equal(s, [10, 10, 6, 5, 9, 0, 0][]));
3150}