PageRenderTime 236ms CodeModel.GetById 40ms app.highlight 180ms 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

Large files files are truncated, but you can click here to view the full 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 su

Large files files are truncated, but you can click here to view the full file