Daily bump.
[gcc.git] / libphobos / src / std / array.d
blobfea70258ebf094ab1877ec7a17c758a1cfc3b55f
1 // Written in the D programming language.
2 /**
3 Functions and types that manipulate built-in arrays and associative arrays.
5 This module provides all kinds of functions to create, manipulate or convert arrays:
7 $(SCRIPT inhibitQuickIndex = 1;)
8 $(DIVC quickindex,
9 $(BOOKTABLE ,
10 $(TR $(TH Function Name) $(TH Description)
12 $(TR $(TD $(LREF array))
13 $(TD Returns a copy of the input in a newly allocated dynamic array.
15 $(TR $(TD $(LREF appender))
16 $(TD Returns a new $(LREF Appender) or $(LREF RefAppender) initialized with a given array.
18 $(TR $(TD $(LREF assocArray))
19 $(TD Returns a newly allocated associative array from a range of key/value tuples.
21 $(TR $(TD $(LREF byPair))
22 $(TD Construct a range iterating over an associative array by key/value tuples.
24 $(TR $(TD $(LREF insertInPlace))
25 $(TD Inserts into an existing array at a given position.
27 $(TR $(TD $(LREF join))
28 $(TD Concatenates a range of ranges into one array.
30 $(TR $(TD $(LREF minimallyInitializedArray))
31 $(TD Returns a new array of type `T`.
33 $(TR $(TD $(LREF replace))
34 $(TD Returns a new array with all occurrences of a certain subrange replaced.
36 $(TR $(TD $(LREF replaceFirst))
37 $(TD Returns a new array with the first occurrence of a certain subrange replaced.
39 $(TR $(TD $(LREF replaceInPlace))
40 $(TD Replaces all occurrences of a certain subrange and puts the result into a given array.
42 $(TR $(TD $(LREF replaceInto))
43 $(TD Replaces all occurrences of a certain subrange and puts the result into an output range.
45 $(TR $(TD $(LREF replaceLast))
46 $(TD Returns a new array with the last occurrence of a certain subrange replaced.
48 $(TR $(TD $(LREF replaceSlice))
49 $(TD Returns a new array with a given slice replaced.
51 $(TR $(TD $(LREF replicate))
52 $(TD Creates a new array out of several copies of an input array or range.
54 $(TR $(TD $(LREF sameHead))
55 $(TD Checks if the initial segments of two arrays refer to the same
56 place in memory.
58 $(TR $(TD $(LREF sameTail))
59 $(TD Checks if the final segments of two arrays refer to the same place
60 in memory.
62 $(TR $(TD $(LREF split))
63 $(TD Eagerly split a range or string into an array.
65 $(TR $(TD $(LREF staticArray))
66 $(TD Creates a new static array from given data.
68 $(TR $(TD $(LREF uninitializedArray))
69 $(TD Returns a new array of type `T` without initializing its elements.
73 Copyright: Copyright Andrei Alexandrescu 2008- and Jonathan M Davis 2011-.
75 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
77 Authors: $(HTTP erdani.org, Andrei Alexandrescu) and
78 $(HTTP jmdavisprog.com, Jonathan M Davis)
80 Source: $(PHOBOSSRC std/array.d)
82 module std.array;
84 import std.functional;
85 import std.meta;
86 import std.traits;
88 import std.range.primitives;
89 public import std.range.primitives : save, empty, popFront, popBack, front, back;
91 /**
92 * Allocates an array and initializes it with copies of the elements
93 * of range `r`.
95 * Narrow strings are handled as follows:
96 * - If autodecoding is turned on (default), then they are handled as a separate overload.
97 * - If autodecoding is turned off, then this is equivalent to duplicating the array.
99 * Params:
100 * r = range (or aggregate with `opApply` function) whose elements are copied into the allocated array
101 * Returns:
102 * allocated and initialized array
104 ForeachType!Range[] array(Range)(Range r)
105 if (isIterable!Range && !isAutodecodableString!Range && !isInfinite!Range)
107 if (__ctfe)
109 // Compile-time version to avoid memcpy calls.
110 // Also used to infer attributes of array().
111 typeof(return) result;
112 foreach (e; r)
113 result ~= e;
114 return result;
117 alias E = ForeachType!Range;
118 static if (hasLength!Range)
120 const length = r.length;
121 if (length == 0)
122 return null;
124 import core.internal.lifetime : emplaceRef;
126 auto result = (() @trusted => uninitializedArray!(Unqual!E[])(length))();
128 // Every element of the uninitialized array must be initialized
129 size_t cnt; //Number of elements that have been initialized
132 foreach (e; r)
134 emplaceRef!E(result[cnt], e);
135 ++cnt;
137 } catch (Exception e)
139 //https://issues.dlang.org/show_bug.cgi?id=22185
140 //Make any uninitialized elements safely destructible.
141 foreach (ref elem; result[cnt..$])
143 import core.internal.lifetime : emplaceInitializer;
144 emplaceInitializer(elem);
146 throw e;
149 https://issues.dlang.org/show_bug.cgi?id=22673
151 We preallocated an array, we should ensure that enough range elements
152 were gathered such that every slot in the array is filled. If not, the GC
153 will collect the allocated array, leading to the `length - cnt` left over elements
154 being collected too - despite their contents having no guarantee of destructibility.
156 assert(length == cnt,
157 "Range .length property was not equal to the length yielded by the range before becoming empty");
158 return (() @trusted => cast(E[]) result)();
160 else
162 auto a = appender!(E[])();
163 foreach (e; r)
165 a.put(e);
167 return a.data;
171 /// ditto
172 ForeachType!(typeof((*Range).init))[] array(Range)(Range r)
173 if (is(Range == U*, U) && isIterable!U && !isAutodecodableString!Range && !isInfinite!Range)
175 return array(*r);
179 @safe pure nothrow unittest
181 auto a = array([1, 2, 3, 4, 5][]);
182 assert(a == [ 1, 2, 3, 4, 5 ]);
185 @safe pure nothrow unittest
187 import std.algorithm.comparison : equal;
188 struct Foo
190 int a;
192 auto a = array([Foo(1), Foo(2), Foo(3), Foo(4), Foo(5)][]);
193 assert(equal(a, [Foo(1), Foo(2), Foo(3), Foo(4), Foo(5)]));
196 @safe pure nothrow unittest
198 struct MyRange
200 enum front = 123;
201 enum empty = true;
202 void popFront() {}
205 auto arr = (new MyRange).array;
206 assert(arr.empty);
209 @safe pure nothrow unittest
211 immutable int[] a = [1, 2, 3, 4];
212 auto b = (&a).array;
213 assert(b == a);
216 @safe pure nothrow unittest
218 import std.algorithm.comparison : equal;
219 struct Foo
221 int a;
222 noreturn opAssign(Foo)
224 assert(0);
226 auto opEquals(Foo foo)
228 return a == foo.a;
231 auto a = array([Foo(1), Foo(2), Foo(3), Foo(4), Foo(5)][]);
232 assert(equal(a, [Foo(1), Foo(2), Foo(3), Foo(4), Foo(5)]));
235 // https://issues.dlang.org/show_bug.cgi?id=12315
236 @safe pure nothrow unittest
238 static struct Bug12315 { immutable int i; }
239 enum bug12315 = [Bug12315(123456789)].array();
240 static assert(bug12315[0].i == 123456789);
243 @safe pure nothrow unittest
245 import std.range;
246 static struct S{int* p;}
247 auto a = array(immutable(S).init.repeat(5));
248 assert(a.length == 5);
251 // https://issues.dlang.org/show_bug.cgi?id=18995
252 @system unittest
254 import core.memory : __delete;
255 int nAlive = 0;
256 struct S
258 bool alive;
259 this(int) { alive = true; ++nAlive; }
260 this(this) { nAlive += alive; }
261 ~this() { nAlive -= alive; alive = false; }
264 import std.algorithm.iteration : map;
265 import std.range : iota;
267 auto arr = iota(3).map!(a => S(a)).array;
268 assert(nAlive == 3);
270 // No good way to ensure the GC frees this, just call the lifetime function
271 // directly.
272 __delete(arr);
274 assert(nAlive == 0);
277 @safe pure nothrow @nogc unittest
279 //Turn down infinity:
280 static assert(!is(typeof(
281 repeat(1).array()
282 )));
285 // https://issues.dlang.org/show_bug.cgi?id=20937
286 @safe pure nothrow unittest
288 struct S {int* x;}
289 struct R
291 immutable(S) front;
292 bool empty;
293 @safe pure nothrow void popFront(){empty = true;}
295 R().array;
298 // Test that `array(scope InputRange r)` returns a non-scope array
299 // https://issues.dlang.org/show_bug.cgi?id=23300
300 @safe pure nothrow unittest
302 @safe int[] fun()
304 import std.algorithm.iteration : map;
305 int[3] arr = [1, 2, 3];
306 scope r = arr[].map!(x => x + 3);
307 return r.array;
312 Convert a narrow autodecoding string to an array type that fully supports
313 random access. This is handled as a special case and always returns an array
314 of `dchar`
316 NOTE: This function is never used when autodecoding is turned off.
318 Params:
319 str = `isNarrowString` to be converted to an array of `dchar`
320 Returns:
321 a `dchar[]`, `const(dchar)[]`, or `immutable(dchar)[]` depending on the constness of
322 the input.
324 CopyTypeQualifiers!(ElementType!String,dchar)[] array(String)(scope String str)
325 if (isAutodecodableString!String)
327 import std.utf : toUTF32;
328 auto temp = str.toUTF32;
329 /* Unsafe cast. Allowed because toUTF32 makes a new array
330 and copies all the elements.
332 return () @trusted { return cast(CopyTypeQualifiers!(ElementType!String, dchar)[]) temp; } ();
336 @safe pure nothrow unittest
338 import std.range.primitives : isRandomAccessRange;
339 import std.traits : isAutodecodableString;
341 // note that if autodecoding is turned off, `array` will not transcode these.
342 static if (isAutodecodableString!string)
343 assert("Hello D".array == "Hello D"d);
344 else
345 assert("Hello D".array == "Hello D");
347 static if (isAutodecodableString!wstring)
348 assert("Hello D"w.array == "Hello D"d);
349 else
350 assert("Hello D"w.array == "Hello D"w);
352 static assert(isRandomAccessRange!dstring == true);
355 @safe unittest
357 import std.conv : to;
359 static struct TestArray { int x; string toString() @safe { return to!string(x); } }
361 static struct OpAssign
363 uint num;
364 this(uint num) { this.num = num; }
366 // Templating opAssign to make sure the bugs with opAssign being
367 // templated are fixed.
368 void opAssign(T)(T rhs) { this.num = rhs.num; }
371 static struct OpApply
373 int opApply(scope int delegate(ref int) @safe dg)
375 int res;
376 foreach (i; 0 .. 10)
378 res = dg(i);
379 if (res) break;
382 return res;
386 auto a = array([1, 2, 3, 4, 5][]);
387 assert(a == [ 1, 2, 3, 4, 5 ]);
389 auto b = array([TestArray(1), TestArray(2)][]);
390 assert(b == [TestArray(1), TestArray(2)]);
392 class C
394 int x;
395 this(int y) { x = y; }
396 override string toString() const @safe { return to!string(x); }
398 auto c = array([new C(1), new C(2)][]);
399 assert(c[0].x == 1);
400 assert(c[1].x == 2);
402 auto d = array([1.0, 2.2, 3][]);
403 assert(is(typeof(d) == double[]));
404 assert(d == [1.0, 2.2, 3]);
406 auto e = [OpAssign(1), OpAssign(2)];
407 auto f = array(e);
408 assert(e == f);
410 assert(array(OpApply.init) == [0,1,2,3,4,5,6,7,8,9]);
411 static if (isAutodecodableString!string)
413 assert(array("ABC") == "ABC"d);
414 assert(array("ABC".dup) == "ABC"d.dup);
418 // https://issues.dlang.org/show_bug.cgi?id=8233
419 @safe pure nothrow unittest
421 assert(array("hello world"d) == "hello world"d);
422 immutable a = [1, 2, 3, 4, 5];
423 assert(array(a) == a);
424 const b = a;
425 assert(array(b) == a);
427 //To verify that the opAssign branch doesn't get screwed up by using Unqual.
428 //EDIT: array no longer calls opAssign.
429 struct S
431 ref S opAssign(S)(const ref S rhs)
433 assert(0);
436 int i;
439 static foreach (T; AliasSeq!(S, const S, immutable S))
441 auto arr = [T(1), T(2), T(3), T(4)];
442 assert(array(arr) == arr);
446 // https://issues.dlang.org/show_bug.cgi?id=9824
447 @safe pure nothrow unittest
449 static struct S
451 @disable void opAssign(S);
452 int i;
454 auto arr = [S(0), S(1), S(2)];
455 arr.array();
458 // https://issues.dlang.org/show_bug.cgi?id=10220
459 @safe pure nothrow unittest
461 import std.algorithm.comparison : equal;
462 import std.exception;
463 import std.range : repeat;
465 static struct S
467 int val;
469 @disable this();
470 this(int v) { val = v; }
472 assertCTFEable!(
474 auto r = S(1).repeat(2).array();
475 assert(equal(r, [S(1), S(1)]));
478 //https://issues.dlang.org/show_bug.cgi?id=22673
479 @system unittest
481 struct LyingRange
483 enum size_t length = 100;
484 enum theRealLength = 50;
485 size_t idx = 0;
486 bool empty()
488 return idx <= theRealLength;
490 void popFront()
492 ++idx;
494 size_t front()
496 return idx;
499 static assert(hasLength!LyingRange);
500 LyingRange rng;
501 import std.exception : assertThrown;
502 assertThrown!Error(array(rng));
504 //https://issues.dlang.org/show_bug.cgi?id=22185
505 @system unittest
507 import std.stdio;
508 static struct ThrowingCopy
510 int x = 420;
511 this(ref return scope ThrowingCopy rhs)
513 rhs.x = 420;
515 throw new Exception("This throws");
517 ~this()
520 Any time this destructor runs, it should be running on "valid"
521 data. This is is mimicked by having a .init other than 0 (the value the memory
522 practically will be from the GC).
524 if (x != 420)
526 //This will only trigger during GC finalization so avoid writefln for now.
527 printf("Destructor failure in ThrowingCopy(%d) @ %p", x, &this);
528 assert(x == 420, "unittest destructor failed");
532 static struct LyingThrowingRange
534 enum size_t length = 100;
535 enum size_t evilRealLength = 50;
536 size_t idx;
537 ThrowingCopy front()
539 return ThrowingCopy(12);
541 bool empty()
543 return idx == evilRealLength;
545 void popFront()
547 ++idx;
550 static assert(hasLength!LyingThrowingRange);
551 import std.exception : assertThrown;
553 assertThrown(array(LyingThrowingRange()));
555 import core.memory : GC;
557 Force a collection early. Doesn't always actually finalize the bad objects
558 but trying to collect soon after the allocation is thrown away means any potential failures
559 will happen earlier.
561 GC.collect();
565 Returns a newly allocated associative array from a range of key/value tuples
566 or from a range of keys and a range of values.
568 Params:
569 r = An $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
570 of tuples of keys and values.
571 keys = An $(REF_ALTTEXT input range, isInputRange, std,range,primitives) of keys
572 values = An $(REF_ALTTEXT input range, isInputRange, std,range,primitives) of values
574 Returns:
576 A newly allocated associative array out of elements of the input
577 range, which must be a range of tuples (Key, Value) or
578 a range of keys and a range of values. If given two ranges of unequal
579 lengths after the elements of the shorter are exhausted the remaining
580 elements of the longer will not be considered.
581 Returns a null associative array reference when given an empty range.
582 Duplicates: Associative arrays have unique keys. If r contains duplicate keys,
583 then the result will contain the value of the last pair for that key in r.
585 See_Also: $(REF Tuple, std,typecons), $(REF zip, std,range)
588 auto assocArray(Range)(Range r)
589 if (isInputRange!Range)
591 import std.typecons : isTuple;
593 alias E = ElementType!Range;
594 static assert(isTuple!E, "assocArray: argument must be a range of tuples,"
595 ~" but was a range of "~E.stringof);
596 static assert(E.length == 2, "assocArray: tuple dimension must be 2");
597 alias KeyType = E.Types[0];
598 alias ValueType = E.Types[1];
599 static assert(isMutable!ValueType, "assocArray: value type must be mutable");
601 ValueType[KeyType] aa;
602 foreach (ref t; r)
603 aa[t[0]] = t[1];
604 return aa;
607 /// ditto
608 auto assocArray(Keys, Values)(Keys keys, Values values)
609 if (isInputRange!Values && isInputRange!Keys)
611 static if (isDynamicArray!Keys && isDynamicArray!Values
612 && !isNarrowString!Keys && !isNarrowString!Values)
614 void* aa;
616 // aaLiteral is nothrow when the destructors don't throw
617 static if (is(typeof(() nothrow
619 import std.range : ElementType;
620 import std.traits : hasElaborateDestructor;
621 alias KeyElement = ElementType!Keys;
622 static if (hasElaborateDestructor!KeyElement)
623 KeyElement.init.__xdtor();
625 alias ValueElement = ElementType!Values;
626 static if (hasElaborateDestructor!ValueElement)
627 ValueElement.init.__xdtor();
628 })))
630 scope(failure) assert(false, "aaLiteral must not throw");
632 if (values.length > keys.length)
633 values = values[0 .. keys.length];
634 else if (keys.length > values.length)
635 keys = keys[0 .. values.length];
636 aa = aaLiteral(keys, values);
638 alias Key = typeof(keys[0]);
639 alias Value = typeof(values[0]);
640 return (() @trusted => cast(Value[Key]) aa)();
642 else
644 // zip is not always able to infer nothrow
645 alias Key = ElementType!Keys;
646 alias Value = ElementType!Values;
647 static assert(isMutable!Value, "assocArray: value type must be mutable");
648 Value[Key] aa;
649 foreach (key; keys)
651 if (values.empty) break;
653 // aa[key] is incorrectly not @safe if the destructor throws
654 // https://issues.dlang.org/show_bug.cgi?id=18592
655 static if (is(typeof(() @safe
657 import std.range : ElementType;
658 import std.traits : hasElaborateDestructor;
659 alias KeyElement = ElementType!Keys;
660 static if (hasElaborateDestructor!KeyElement)
661 KeyElement.init.__xdtor();
663 alias ValueElement = ElementType!Values;
664 static if (hasElaborateDestructor!ValueElement)
665 ValueElement.init.__xdtor();
667 aa[key] = values.front;
668 })))
670 () @trusted {
671 aa[key] = values.front;
672 }();
674 else
676 aa[key] = values.front;
678 values.popFront();
680 return aa;
685 @safe pure /*nothrow*/ unittest
687 import std.range : repeat, zip;
688 import std.typecons : tuple;
689 import std.range.primitives : autodecodeStrings;
690 auto a = assocArray(zip([0, 1, 2], ["a", "b", "c"])); // aka zipMap
691 static assert(is(typeof(a) == string[int]));
692 assert(a == [0:"a", 1:"b", 2:"c"]);
694 auto b = assocArray([ tuple("foo", "bar"), tuple("baz", "quux") ]);
695 static assert(is(typeof(b) == string[string]));
696 assert(b == ["foo":"bar", "baz":"quux"]);
698 static if (autodecodeStrings)
699 alias achar = dchar;
700 else
701 alias achar = immutable(char);
702 auto c = assocArray("ABCD", true.repeat);
703 static assert(is(typeof(c) == bool[achar]));
704 bool[achar] expected = ['D':true, 'A':true, 'B':true, 'C':true];
705 assert(c == expected);
708 // Cannot be version (StdUnittest) - recursive instantiation error
709 // https://issues.dlang.org/show_bug.cgi?id=11053
710 @safe pure nothrow unittest
712 import std.typecons;
713 static assert(!__traits(compiles, [ 1, 2, 3 ].assocArray()));
714 static assert(!__traits(compiles, [ tuple("foo", "bar", "baz") ].assocArray()));
715 static assert(!__traits(compiles, [ tuple("foo") ].assocArray()));
716 assert([ tuple("foo", "bar") ].assocArray() == ["foo": "bar"]);
719 // https://issues.dlang.org/show_bug.cgi?id=13909
720 @safe pure nothrow unittest
722 import std.typecons;
723 auto a = [tuple!(const string, string)("foo", "bar")];
724 auto b = [tuple!(string, const string)("foo", "bar")];
725 assert(a == b);
726 assert(assocArray(a) == [cast(const(string)) "foo": "bar"]);
727 static assert(!__traits(compiles, assocArray(b)));
730 // https://issues.dlang.org/show_bug.cgi?id=5502
731 @safe pure nothrow unittest
733 auto a = assocArray([0, 1, 2], ["a", "b", "c"]);
734 static assert(is(typeof(a) == string[int]));
735 assert(a == [0:"a", 1:"b", 2:"c"]);
737 auto b = assocArray([0, 1, 2], [3L, 4, 5]);
738 static assert(is(typeof(b) == long[int]));
739 assert(b == [0: 3L, 1: 4, 2: 5]);
742 // https://issues.dlang.org/show_bug.cgi?id=5502
743 @safe pure unittest
745 import std.algorithm.iteration : filter, map;
746 import std.range : enumerate;
747 import std.range.primitives : autodecodeStrings;
749 auto r = "abcde".enumerate.filter!(a => a.index == 2);
750 auto a = assocArray(r.map!(a => a.value), r.map!(a => a.index));
751 static if (autodecodeStrings)
752 alias achar = dchar;
753 else
754 alias achar = immutable(char);
755 static assert(is(typeof(a) == size_t[achar]));
756 assert(a == [achar('c'): size_t(2)]);
759 @safe nothrow pure unittest
761 import std.range : iota;
762 auto b = assocArray(3.iota, 3.iota(6));
763 static assert(is(typeof(b) == int[int]));
764 assert(b == [0: 3, 1: 4, 2: 5]);
766 b = assocArray([0, 1, 2], [3, 4, 5]);
767 assert(b == [0: 3, 1: 4, 2: 5]);
770 @safe unittest
772 struct ThrowingElement
774 int i;
775 static bool b;
776 ~this(){
777 if (b)
778 throw new Exception("");
781 static assert(!__traits(compiles, () nothrow { assocArray([ThrowingElement()], [0]);}));
782 assert(assocArray([ThrowingElement()], [0]) == [ThrowingElement(): 0]);
784 static assert(!__traits(compiles, () nothrow { assocArray([0], [ThrowingElement()]);}));
785 assert(assocArray([0], [ThrowingElement()]) == [0: ThrowingElement()]);
787 import std.range : iota;
788 static assert(!__traits(compiles, () nothrow { assocArray(1.iota, [ThrowingElement()]);}));
789 assert(assocArray(1.iota, [ThrowingElement()]) == [0: ThrowingElement()]);
792 @system unittest
794 import std.range : iota;
795 struct UnsafeElement
797 int i;
798 static bool b;
799 ~this(){
800 int[] arr;
801 void* p = arr.ptr + 1; // unsafe
804 static assert(!__traits(compiles, () @safe { assocArray(1.iota, [UnsafeElement()]);}));
805 assert(assocArray(1.iota, [UnsafeElement()]) == [0: UnsafeElement()]);
808 @safe unittest
810 struct ValueRange
812 string front() const @system;
813 @safe:
814 void popFront() {}
815 bool empty() const { return false; }
817 int[] keys;
818 ValueRange values;
819 static assert(!__traits(compiles, assocArray(keys, values)));
823 Construct a range iterating over an associative array by key/value tuples.
825 Params:
826 aa = The associative array to iterate over.
828 Returns: A $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives)
829 of Tuple's of key and value pairs from the given associative array. The members
830 of each pair can be accessed by name (`.key` and `.value`). or by integer
831 index (0 and 1 respectively).
833 auto byPair(AA)(AA aa)
834 if (isAssociativeArray!AA)
836 import std.algorithm.iteration : map;
837 import std.typecons : tuple;
839 return aa.byKeyValue
840 .map!(pair => tuple!("key", "value")(pair.key, pair.value));
844 @safe pure nothrow unittest
846 import std.algorithm.sorting : sort;
847 import std.typecons : tuple, Tuple;
849 auto aa = ["a": 1, "b": 2, "c": 3];
850 Tuple!(string, int)[] pairs;
852 // Iteration over key/value pairs.
853 foreach (pair; aa.byPair)
855 if (pair.key == "b")
856 pairs ~= tuple("B", pair.value);
857 else
858 pairs ~= pair;
861 // Iteration order is implementation-dependent, so we should sort it to get
862 // a fixed order.
863 pairs.sort();
864 assert(pairs == [
865 tuple("B", 2),
866 tuple("a", 1),
867 tuple("c", 3)
871 @safe pure nothrow unittest
873 import std.typecons : tuple, Tuple;
874 import std.meta : AliasSeq;
876 auto aa = ["a":2];
877 auto pairs = aa.byPair();
879 alias PT = typeof(pairs.front);
880 static assert(is(PT : Tuple!(string,int)));
881 static assert(PT.fieldNames == AliasSeq!("key", "value"));
882 static assert(isForwardRange!(typeof(pairs)));
884 assert(!pairs.empty);
885 assert(pairs.front == tuple("a", 2));
887 auto savedPairs = pairs.save;
889 pairs.popFront();
890 assert(pairs.empty);
891 assert(!savedPairs.empty);
892 assert(savedPairs.front == tuple("a", 2));
895 // https://issues.dlang.org/show_bug.cgi?id=17711
896 @safe pure nothrow unittest
898 const(int[string]) aa = [ "abc": 123 ];
900 // Ensure that byKeyValue is usable with a const AA.
901 auto kv = aa.byKeyValue;
902 assert(!kv.empty);
903 assert(kv.front.key == "abc" && kv.front.value == 123);
904 kv.popFront();
905 assert(kv.empty);
907 // Ensure byPair is instantiable with const AA.
908 auto r = aa.byPair;
909 static assert(isInputRange!(typeof(r)));
910 assert(!r.empty && r.front[0] == "abc" && r.front[1] == 123);
911 r.popFront();
912 assert(r.empty);
915 private template blockAttribute(T)
917 import core.memory;
918 static if (hasIndirections!(T) || is(T == void))
920 enum blockAttribute = 0;
922 else
924 enum blockAttribute = GC.BlkAttr.NO_SCAN;
928 @safe unittest
930 import core.memory : UGC = GC;
931 static assert(!(blockAttribute!void & UGC.BlkAttr.NO_SCAN));
934 // Returns the number of dimensions in an array T.
935 private template nDimensions(T)
937 static if (isArray!T)
939 enum nDimensions = 1 + nDimensions!(typeof(T.init[0]));
941 else
943 enum nDimensions = 0;
947 @safe unittest
949 static assert(nDimensions!(uint[]) == 1);
950 static assert(nDimensions!(float[][]) == 2);
954 Returns a new array of type `T` allocated on the garbage collected heap
955 without initializing its elements. This can be a useful optimization if every
956 element will be immediately initialized. `T` may be a multidimensional
957 array. In this case sizes may be specified for any number of dimensions from 0
958 to the number in `T`.
960 uninitializedArray is `nothrow` and weakly `pure`.
962 uninitializedArray is `@system` if the uninitialized element type has pointers.
964 Params:
965 T = The type of the resulting array elements
966 sizes = The length dimension(s) of the resulting array
967 Returns:
968 An array of `T` with `I.length` dimensions.
970 auto uninitializedArray(T, I...)(I sizes) nothrow @system
971 if (isDynamicArray!T && allSatisfy!(isIntegral, I) && hasIndirections!(ElementEncodingType!T))
973 enum isSize_t(E) = is (E : size_t);
974 alias toSize_t(E) = size_t;
976 static assert(allSatisfy!(isSize_t, I),
977 "Argument types in "~I.stringof~" are not all convertible to size_t: "
978 ~Filter!(templateNot!(isSize_t), I).stringof);
980 //Eagerlly transform non-size_t into size_t to avoid template bloat
981 alias ST = staticMap!(toSize_t, I);
983 return arrayAllocImpl!(false, T, ST)(sizes);
986 /// ditto
987 auto uninitializedArray(T, I...)(I sizes) nothrow @trusted
988 if (isDynamicArray!T && allSatisfy!(isIntegral, I) && !hasIndirections!(ElementEncodingType!T))
990 enum isSize_t(E) = is (E : size_t);
991 alias toSize_t(E) = size_t;
993 static assert(allSatisfy!(isSize_t, I),
994 "Argument types in "~I.stringof~" are not all convertible to size_t: "
995 ~Filter!(templateNot!(isSize_t), I).stringof);
997 //Eagerlly transform non-size_t into size_t to avoid template bloat
998 alias ST = staticMap!(toSize_t, I);
1000 return arrayAllocImpl!(false, T, ST)(sizes);
1003 @system nothrow pure unittest
1005 double[] arr = uninitializedArray!(double[])(100);
1006 assert(arr.length == 100);
1008 double[][] matrix = uninitializedArray!(double[][])(42, 31);
1009 assert(matrix.length == 42);
1010 assert(matrix[0].length == 31);
1012 char*[] ptrs = uninitializedArray!(char*[])(100);
1013 assert(ptrs.length == 100);
1017 Returns a new array of type `T` allocated on the garbage collected heap.
1019 Partial initialization is done for types with indirections, for preservation
1020 of memory safety. Note that elements will only be initialized to 0, but not
1021 necessarily the element type's `.init`.
1023 minimallyInitializedArray is `nothrow` and weakly `pure`.
1025 Params:
1026 T = The type of the array elements
1027 sizes = The length dimension(s) of the resulting array
1028 Returns:
1029 An array of `T` with `I.length` dimensions.
1031 auto minimallyInitializedArray(T, I...)(I sizes) nothrow @trusted
1032 if (isDynamicArray!T && allSatisfy!(isIntegral, I))
1034 enum isSize_t(E) = is (E : size_t);
1035 alias toSize_t(E) = size_t;
1037 static assert(allSatisfy!(isSize_t, I),
1038 "Argument types in "~I.stringof~" are not all convertible to size_t: "
1039 ~Filter!(templateNot!(isSize_t), I).stringof);
1040 //Eagerlly transform non-size_t into size_t to avoid template bloat
1041 alias ST = staticMap!(toSize_t, I);
1043 return arrayAllocImpl!(true, T, ST)(sizes);
1047 @safe pure nothrow unittest
1049 import std.algorithm.comparison : equal;
1050 import std.range : repeat;
1052 auto arr = minimallyInitializedArray!(int[])(42);
1053 assert(arr.length == 42);
1055 // Elements aren't necessarily initialized to 0, so don't do this:
1056 // assert(arr.equal(0.repeat(42)));
1057 // If that is needed, initialize the array normally instead:
1058 auto arr2 = new int[42];
1059 assert(arr2.equal(0.repeat(42)));
1062 @safe pure nothrow unittest
1064 cast(void) minimallyInitializedArray!(int[][][][][])();
1065 double[] arr = minimallyInitializedArray!(double[])(100);
1066 assert(arr.length == 100);
1068 double[][] matrix = minimallyInitializedArray!(double[][])(42);
1069 assert(matrix.length == 42);
1070 foreach (elem; matrix)
1072 assert(elem.ptr is null);
1076 // from rt/lifetime.d
1077 private extern(C) void[] _d_newarrayU(const TypeInfo ti, size_t length) pure nothrow;
1079 // from rt/tracegc.d
1080 version (D_ProfileGC)
1081 private extern (C) void[] _d_newarrayUTrace(string file, size_t line,
1082 string funcname, const scope TypeInfo ti, size_t length) pure nothrow;
1084 private auto arrayAllocImpl(bool minimallyInitialized, T, I...)(I sizes) nothrow
1086 static assert(I.length <= nDimensions!T,
1087 I.length.stringof~"dimensions specified for a "~nDimensions!T.stringof~" dimensional array.");
1089 alias E = ElementEncodingType!T;
1091 E[] ret;
1093 static if (I.length != 0)
1095 static assert(is(I[0] == size_t), "I[0] must be of type size_t not "
1096 ~ I[0].stringof);
1097 alias size = sizes[0];
1100 static if (I.length == 1)
1102 if (__ctfe)
1104 static if (__traits(compiles, new E[](size)))
1105 ret = new E[](size);
1106 else static if (__traits(compiles, ret ~= E.init))
1110 //Issue: if E has an impure postblit, then all of arrayAllocImpl
1111 //Will be impure, even during non CTFE.
1112 foreach (i; 0 .. size)
1113 ret ~= E.init;
1115 catch (Exception e)
1116 assert(0, e.msg);
1118 else
1119 assert(0, "No postblit nor default init on " ~ E.stringof ~
1120 ": At least one is required for CTFE.");
1122 else
1124 import core.stdc.string : memset;
1127 NOTES:
1128 _d_newarrayU is part of druntime, and creates an uninitialized
1129 block, just like GC.malloc. However, it also sets the appropriate
1130 bits, and sets up the block as an appendable array of type E[],
1131 which will inform the GC how to destroy the items in the block
1132 when it gets collected.
1134 _d_newarrayU returns a void[], but with the length set according
1135 to E.sizeof.
1137 version (D_ProfileGC)
1139 // FIXME: file, line, function should be propagated from the
1140 // caller, not here.
1141 *(cast(void[]*)&ret) = _d_newarrayUTrace(__FILE__, __LINE__,
1142 __FUNCTION__, typeid(E[]), size);
1144 else
1145 *(cast(void[]*)&ret) = _d_newarrayU(typeid(E[]), size);
1146 static if (minimallyInitialized && hasIndirections!E)
1147 // _d_newarrayU would have asserted if the multiplication below
1148 // had overflowed, so we don't have to check it again.
1149 memset(ret.ptr, 0, E.sizeof * ret.length);
1152 else static if (I.length > 1)
1154 ret = arrayAllocImpl!(false, E[])(size);
1155 foreach (ref elem; ret)
1156 elem = arrayAllocImpl!(minimallyInitialized, E)(sizes[1..$]);
1159 return ret;
1162 @safe nothrow pure unittest
1164 auto s1 = uninitializedArray!(int[])();
1165 auto s2 = minimallyInitializedArray!(int[])();
1166 assert(s1.length == 0);
1167 assert(s2.length == 0);
1170 // https://issues.dlang.org/show_bug.cgi?id=9803
1171 @safe nothrow pure unittest
1173 auto a = minimallyInitializedArray!(int*[])(1);
1174 assert(a[0] == null);
1175 auto b = minimallyInitializedArray!(int[][])(1);
1176 assert(b[0].empty);
1177 auto c = minimallyInitializedArray!(int*[][])(1, 1);
1178 assert(c[0][0] == null);
1181 // https://issues.dlang.org/show_bug.cgi?id=10637
1182 @safe pure nothrow unittest
1184 static struct S
1186 static struct I{int i; alias i this;}
1187 int* p;
1188 this() @disable;
1189 this(int i)
1191 p = &(new I(i)).i;
1193 this(this)
1195 p = &(new I(*p)).i;
1197 ~this()
1199 // note, this assert is invalid -- a struct should always be able
1200 // to run its dtor on the .init value, I'm leaving it here
1201 // commented out because the original test case had it. I'm not
1202 // sure what it's trying to prove.
1204 // What happens now that minimallyInitializedArray adds the
1205 // destructor run to the GC, is that this assert would fire in the
1206 // GC, which triggers an invalid memory operation.
1207 //assert(p != null);
1210 auto a = minimallyInitializedArray!(S[])(1);
1211 assert(a[0].p == null);
1212 enum b = minimallyInitializedArray!(S[])(1);
1213 assert(b[0].p == null);
1216 @safe pure nothrow unittest
1218 static struct S1
1220 this() @disable;
1221 this(this) @disable;
1223 auto a1 = minimallyInitializedArray!(S1[][])(2, 2);
1224 assert(a1);
1225 static struct S2
1227 this() @disable;
1228 //this(this) @disable;
1230 auto a2 = minimallyInitializedArray!(S2[][])(2, 2);
1231 assert(a2);
1232 enum b2 = minimallyInitializedArray!(S2[][])(2, 2);
1233 assert(b2 !is null);
1234 static struct S3
1236 //this() @disable;
1237 this(this) @disable;
1239 auto a3 = minimallyInitializedArray!(S3[][])(2, 2);
1240 assert(a3);
1241 enum b3 = minimallyInitializedArray!(S3[][])(2, 2);
1242 assert(b3 !is null);
1246 Returns the overlapping portion, if any, of two arrays. Unlike `equal`,
1247 `overlap` only compares the pointers and lengths in the
1248 ranges, not the values referred by them. If `r1` and `r2` have an
1249 overlapping slice, returns that slice. Otherwise, returns the null
1250 slice.
1252 Params:
1253 a = The first array to compare
1254 b = The second array to compare
1255 Returns:
1256 The overlapping portion of the two arrays.
1258 CommonType!(T[], U[]) overlap(T, U)(T[] a, U[] b) @trusted
1259 if (is(typeof(a.ptr < b.ptr) == bool))
1261 import std.algorithm.comparison : min;
1263 auto end = min(a.ptr + a.length, b.ptr + b.length);
1264 // CTFE requires pairing pointer comparisons, which forces a
1265 // slightly inefficient implementation.
1266 if (a.ptr <= b.ptr && b.ptr < a.ptr + a.length)
1268 return b.ptr[0 .. end - b.ptr];
1271 if (b.ptr <= a.ptr && a.ptr < b.ptr + b.length)
1273 return a.ptr[0 .. end - a.ptr];
1276 return null;
1280 @safe pure nothrow unittest
1282 int[] a = [ 10, 11, 12, 13, 14 ];
1283 int[] b = a[1 .. 3];
1284 assert(overlap(a, b) == [ 11, 12 ]);
1285 b = b.dup;
1286 // overlap disappears even though the content is the same
1287 assert(overlap(a, b).empty);
1289 static test()() @nogc
1291 auto a = "It's three o'clock"d;
1292 auto b = a[5 .. 10];
1293 return b.overlap(a);
1296 //works at compile-time
1297 static assert(test == "three"d);
1301 @safe pure nothrow unittest
1303 import std.meta : AliasSeq;
1305 // can be used as an alternative implementation of overlap that returns
1306 // `true` or `false` instead of a slice of the overlap
1307 bool isSliceOf(T)(const scope T[] part, const scope T[] whole)
1309 return part.overlap(whole) is part;
1312 auto x = [1, 2, 3, 4, 5];
1314 assert(isSliceOf(x[3..$], x));
1315 assert(isSliceOf(x[], x));
1316 assert(!isSliceOf(x, x[3..$]));
1317 assert(!isSliceOf([7, 8], x));
1318 assert(isSliceOf(null, x));
1320 // null is a slice of itself
1321 assert(isSliceOf(null, null));
1323 foreach (T; AliasSeq!(int[], const(int)[], immutable(int)[], const int[], immutable int[]))
1325 T a = [1, 2, 3, 4, 5];
1326 T b = a;
1327 T c = a[1 .. $];
1328 T d = a[0 .. 1];
1329 T e = null;
1331 assert(isSliceOf(a, a));
1332 assert(isSliceOf(b, a));
1333 assert(isSliceOf(a, b));
1335 assert(isSliceOf(c, a));
1336 assert(isSliceOf(c, b));
1337 assert(!isSliceOf(a, c));
1338 assert(!isSliceOf(b, c));
1340 assert(isSliceOf(d, a));
1341 assert(isSliceOf(d, b));
1342 assert(!isSliceOf(a, d));
1343 assert(!isSliceOf(b, d));
1345 assert(isSliceOf(e, a));
1346 assert(isSliceOf(e, b));
1347 assert(isSliceOf(e, c));
1348 assert(isSliceOf(e, d));
1350 //verifies R-value compatibilty
1351 assert(!isSliceOf(a[$ .. $], a));
1352 assert(isSliceOf(a[0 .. 0], a));
1353 assert(isSliceOf(a, a[0.. $]));
1354 assert(isSliceOf(a[0 .. $], a));
1358 @safe pure nothrow unittest
1360 static void test(L, R)(L l, R r)
1362 assert(overlap(l, r) == [ 100, 12 ]);
1364 assert(overlap(l, l[0 .. 2]) is l[0 .. 2]);
1365 assert(overlap(l, l[3 .. 5]) is l[3 .. 5]);
1366 assert(overlap(l[0 .. 2], l) is l[0 .. 2]);
1367 assert(overlap(l[3 .. 5], l) is l[3 .. 5]);
1370 int[] a = [ 10, 11, 12, 13, 14 ];
1371 int[] b = a[1 .. 3];
1372 a[1] = 100;
1374 immutable int[] c = a.idup;
1375 immutable int[] d = c[1 .. 3];
1377 test(a, b);
1378 assert(overlap(a, b.dup).empty);
1379 test(c, d);
1380 assert(overlap(c, d.dup.idup).empty);
1383 // https://issues.dlang.org/show_bug.cgi?id=9836
1384 @safe pure nothrow unittest
1386 // range primitives for array should work with alias this types
1387 struct Wrapper
1389 int[] data;
1390 alias data this;
1392 @property Wrapper save() { return this; }
1394 auto w = Wrapper([1,2,3,4]);
1395 std.array.popFront(w); // should work
1397 static assert(isInputRange!Wrapper);
1398 static assert(isForwardRange!Wrapper);
1399 static assert(isBidirectionalRange!Wrapper);
1400 static assert(isRandomAccessRange!Wrapper);
1403 private void copyBackwards(T)(T[] src, T[] dest)
1405 import core.stdc.string : memmove;
1406 import std.format : format;
1408 assert(src.length == dest.length, format!
1409 "src.length %s must equal dest.length %s"(src.length, dest.length));
1411 if (!__ctfe || hasElaborateCopyConstructor!T)
1413 /* insertInPlace relies on dest being uninitialized, so no postblits allowed,
1414 * as this is a MOVE that overwrites the destination, not a COPY.
1415 * BUG: insertInPlace will not work with ctfe and postblits
1417 memmove(dest.ptr, src.ptr, src.length * T.sizeof);
1419 else
1421 immutable len = src.length;
1422 for (size_t i = len; i-- > 0;)
1424 dest[i] = src[i];
1430 Inserts `stuff` (which must be an input range or any number of
1431 implicitly convertible items) in `array` at position `pos`.
1433 Params:
1434 array = The array that `stuff` will be inserted into.
1435 pos = The position in `array` to insert the `stuff`.
1436 stuff = An $(REF_ALTTEXT input range, isInputRange, std,range,primitives),
1437 or any number of implicitly convertible items to insert into `array`.
1439 void insertInPlace(T, U...)(ref T[] array, size_t pos, U stuff)
1440 if (!isSomeString!(T[])
1441 && allSatisfy!(isInputRangeOrConvertible!T, U) && U.length > 0)
1443 static if (allSatisfy!(isInputRangeWithLengthOrConvertible!T, U))
1445 import core.internal.lifetime : emplaceRef;
1447 immutable oldLen = array.length;
1449 size_t to_insert = 0;
1450 foreach (i, E; U)
1452 static if (is(E : T)) //a single convertible value, not a range
1453 to_insert += 1;
1454 else
1455 to_insert += stuff[i].length;
1457 if (to_insert)
1459 array.length += to_insert;
1461 // Takes arguments array, pos, stuff
1462 // Spread apart array[] at pos by moving elements
1463 (() @trusted { copyBackwards(array[pos .. oldLen], array[pos+to_insert..$]); })();
1465 // Initialize array[pos .. pos+to_insert] with stuff[]
1466 auto j = 0;
1467 foreach (i, E; U)
1469 static if (is(E : T))
1471 emplaceRef!T(array[pos + j++], stuff[i]);
1473 else
1475 foreach (v; stuff[i])
1477 emplaceRef!T(array[pos + j++], v);
1483 else
1485 // stuff has some InputRanges in it that don't have length
1486 // assume that stuff to be inserted is typically shorter
1487 // then the array that can be arbitrary big
1488 // TODO: needs a better implementation as there is no need to build an _array_
1489 // a singly-linked list of memory blocks (rope, etc.) will do
1490 auto app = appender!(T[])();
1491 foreach (i, E; U)
1492 app.put(stuff[i]);
1493 insertInPlace(array, pos, app.data);
1497 /// Ditto
1498 void insertInPlace(T, U...)(ref T[] array, size_t pos, U stuff)
1499 if (isSomeString!(T[]) && allSatisfy!(isCharOrStringOrDcharRange, U))
1501 static if (is(Unqual!T == T)
1502 && allSatisfy!(isInputRangeWithLengthOrConvertible!dchar, U))
1504 import std.utf : codeLength, byDchar;
1505 // mutable, can do in place
1506 //helper function: re-encode dchar to Ts and store at *ptr
1507 static T* putDChar(T* ptr, dchar ch)
1509 static if (is(T == dchar))
1511 *ptr++ = ch;
1512 return ptr;
1514 else
1516 import std.utf : encode;
1517 T[dchar.sizeof/T.sizeof] buf;
1518 immutable len = encode(buf, ch);
1519 final switch (len)
1521 static if (T.sizeof == char.sizeof)
1523 case 4:
1524 ptr[3] = buf[3];
1525 goto case;
1526 case 3:
1527 ptr[2] = buf[2];
1528 goto case;
1530 case 2:
1531 ptr[1] = buf[1];
1532 goto case;
1533 case 1:
1534 ptr[0] = buf[0];
1536 ptr += len;
1537 return ptr;
1540 size_t to_insert = 0;
1541 //count up the number of *codeunits* to insert
1542 foreach (i, E; U)
1543 to_insert += codeLength!T(stuff[i]);
1544 array.length += to_insert;
1546 @trusted static void moveToRight(T[] arr, size_t gap)
1548 static assert(!hasElaborateCopyConstructor!T,
1549 "T must not have an elaborate copy constructor");
1550 import core.stdc.string : memmove;
1551 if (__ctfe)
1553 for (size_t i = arr.length - gap; i; --i)
1554 arr[gap + i - 1] = arr[i - 1];
1556 else
1557 memmove(arr.ptr + gap, arr.ptr, (arr.length - gap) * T.sizeof);
1559 moveToRight(array[pos .. $], to_insert);
1560 auto ptr = array.ptr + pos;
1561 foreach (i, E; U)
1563 static if (is(E : dchar))
1565 ptr = putDChar(ptr, stuff[i]);
1567 else
1569 foreach (ch; stuff[i].byDchar)
1570 ptr = putDChar(ptr, ch);
1573 assert(ptr == array.ptr + pos + to_insert, "(ptr == array.ptr + pos + to_insert) is false");
1575 else
1577 // immutable/const, just construct a new array
1578 auto app = appender!(T[])();
1579 app.put(array[0 .. pos]);
1580 foreach (i, E; U)
1581 app.put(stuff[i]);
1582 app.put(array[pos..$]);
1583 array = app.data;
1588 @safe pure unittest
1590 int[] a = [ 1, 2, 3, 4 ];
1591 a.insertInPlace(2, [ 1, 2 ]);
1592 assert(a == [ 1, 2, 1, 2, 3, 4 ]);
1593 a.insertInPlace(3, 10u, 11);
1594 assert(a == [ 1, 2, 1, 10, 11, 2, 3, 4]);
1596 union U
1598 float a = 3.0;
1599 int b;
1602 U u1 = { b : 3 };
1603 U u2 = { b : 4 };
1604 U u3 = { b : 5 };
1605 U[] unionArr = [u2, u3];
1606 unionArr.insertInPlace(2, [u1]);
1607 assert(unionArr == [u2, u3, u1]);
1608 unionArr.insertInPlace(0, [u3, u2]);
1609 assert(unionArr == [u3, u2, u2, u3, u1]);
1611 static class C
1613 int a;
1614 float b;
1616 this(int a, float b) { this.a = a; this.b = b; }
1619 C c1 = new C(42, 1.0);
1620 C c2 = new C(0, 0.0);
1621 C c3 = new C(int.max, float.init);
1623 C[] classArr = [c1, c2, c3];
1624 insertInPlace(classArr, 3, [c2, c3]);
1625 C[5] classArr1 = classArr;
1626 assert(classArr1 == [c1, c2, c3, c2, c3]);
1627 insertInPlace(classArr, 0, c3, c1);
1628 C[7] classArr2 = classArr;
1629 assert(classArr2 == [c3, c1, c1, c2, c3, c2, c3]);
1632 //constraint helpers
1633 private template isInputRangeWithLengthOrConvertible(E)
1635 template isInputRangeWithLengthOrConvertible(R)
1637 //hasLength not defined for char[], wchar[] and dchar[]
1638 enum isInputRangeWithLengthOrConvertible =
1639 (isInputRange!R && is(typeof(R.init.length))
1640 && is(ElementType!R : E)) || is(R : E);
1644 //ditto
1645 private template isCharOrStringOrDcharRange(T)
1647 enum isCharOrStringOrDcharRange = isSomeString!T || isSomeChar!T ||
1648 (isInputRange!T && is(ElementType!T : dchar));
1651 //ditto
1652 private template isInputRangeOrConvertible(E)
1654 template isInputRangeOrConvertible(R)
1656 enum isInputRangeOrConvertible =
1657 (isInputRange!R && is(ElementType!R : E)) || is(R : E);
1661 @system unittest
1663 // @system due to insertInPlace
1664 import core.exception;
1665 import std.algorithm.comparison : equal;
1666 import std.algorithm.iteration : filter;
1667 import std.conv : to;
1668 import std.exception;
1671 bool test(T, U, V)(T orig, size_t pos, U toInsert, V result)
1674 static if (is(T == typeof(T.init.dup)))
1675 auto a = orig.dup;
1676 else
1677 auto a = orig.idup;
1679 a.insertInPlace(pos, toInsert);
1680 if (!equal(a, result))
1681 return false;
1684 static if (isInputRange!U)
1686 orig.insertInPlace(pos, filter!"true"(toInsert));
1687 return equal(orig, result);
1689 else
1690 return true;
1694 assert(test([1, 2, 3, 4], 0, [6, 7], [6, 7, 1, 2, 3, 4]));
1695 assert(test([1, 2, 3, 4], 2, [8, 9], [1, 2, 8, 9, 3, 4]));
1696 assert(test([1, 2, 3, 4], 4, [10, 11], [1, 2, 3, 4, 10, 11]));
1698 assert(test([1, 2, 3, 4], 0, 22, [22, 1, 2, 3, 4]));
1699 assert(test([1, 2, 3, 4], 2, 23, [1, 2, 23, 3, 4]));
1700 assert(test([1, 2, 3, 4], 4, 24, [1, 2, 3, 4, 24]));
1702 void testStr(T, U)(string file = __FILE__, size_t line = __LINE__)
1705 auto l = to!T("hello");
1706 auto r = to!U(" વિશ્વ");
1708 enforce(test(l, 0, r, " વિશ્વhello"),
1709 new AssertError("testStr failure 1", file, line));
1710 enforce(test(l, 3, r, "hel વિશ્વlo"),
1711 new AssertError("testStr failure 2", file, line));
1712 enforce(test(l, l.length, r, "hello વિશ્વ"),
1713 new AssertError("testStr failure 3", file, line));
1716 static foreach (T; AliasSeq!(char, wchar, dchar,
1717 immutable(char), immutable(wchar), immutable(dchar)))
1719 static foreach (U; AliasSeq!(char, wchar, dchar,
1720 immutable(char), immutable(wchar), immutable(dchar)))
1722 testStr!(T[], U[])();
1727 // variadic version
1728 bool testVar(T, U...)(T orig, size_t pos, U args)
1730 static if (is(T == typeof(T.init.dup)))
1731 auto a = orig.dup;
1732 else
1733 auto a = orig.idup;
1734 auto result = args[$-1];
1736 a.insertInPlace(pos, args[0..$-1]);
1737 if (!equal(a, result))
1738 return false;
1739 return true;
1741 assert(testVar([1, 2, 3, 4], 0, 6, 7u, [6, 7, 1, 2, 3, 4]));
1742 assert(testVar([1L, 2, 3, 4], 2, 8, 9L, [1, 2, 8, 9, 3, 4]));
1743 assert(testVar([1L, 2, 3, 4], 4, 10L, 11, [1, 2, 3, 4, 10, 11]));
1744 assert(testVar([1L, 2, 3, 4], 4, [10, 11], 40L, 42L,
1745 [1, 2, 3, 4, 10, 11, 40, 42]));
1746 assert(testVar([1L, 2, 3, 4], 4, 10, 11, [40L, 42],
1747 [1, 2, 3, 4, 10, 11, 40, 42]));
1748 assert(testVar("t".idup, 1, 'e', 's', 't', "test"));
1749 assert(testVar("!!"w.idup, 1, "\u00e9ll\u00f4", 'x', "TTT"w, 'y',
1750 "!\u00e9ll\u00f4xTTTy!"));
1751 assert(testVar("flipflop"d.idup, 4, '_',
1752 "xyz"w, '\U00010143', '_', "abc"d, "__",
1753 "flip_xyz\U00010143_abc__flop"));
1756 @system unittest
1758 import std.algorithm.comparison : equal;
1759 // insertInPlace interop with postblit
1760 static struct Int
1762 int* payload;
1763 this(int k)
1765 payload = new int;
1766 *payload = k;
1768 this(this)
1770 int* np = new int;
1771 *np = *payload;
1772 payload = np;
1774 ~this()
1776 if (payload)
1777 *payload = 0; //'destroy' it
1779 @property int getPayload(){ return *payload; }
1780 alias getPayload this;
1783 Int[] arr = [Int(1), Int(4), Int(5)];
1784 assert(arr[0] == 1);
1785 insertInPlace(arr, 1, Int(2), Int(3));
1786 assert(equal(arr, [1, 2, 3, 4, 5])); //check it works with postblit
1789 @safe unittest
1791 import std.exception;
1792 assertCTFEable!(
1794 int[] a = [1, 2];
1795 a.insertInPlace(2, 3);
1796 a.insertInPlace(0, -1, 0);
1797 return a == [-1, 0, 1, 2, 3];
1801 // https://issues.dlang.org/show_bug.cgi?id=6874
1802 @system unittest
1804 import core.memory;
1805 // allocate some space
1806 byte[] a;
1807 a.length = 1;
1809 // fill it
1810 a.length = a.capacity;
1812 // write beyond
1813 byte[] b = a[$ .. $];
1814 b.insertInPlace(0, a);
1816 // make sure that reallocation has happened
1817 assert(GC.addrOf(&b[0]) == GC.addrOf(&b[$-1]));
1822 Returns whether the `front`s of `lhs` and `rhs` both refer to the
1823 same place in memory, making one of the arrays a slice of the other which
1824 starts at index `0`.
1826 Params:
1827 lhs = the first array to compare
1828 rhs = the second array to compare
1829 Returns:
1830 `true` if $(D lhs.ptr == rhs.ptr), `false` otherwise.
1832 @safe
1833 pure nothrow @nogc bool sameHead(T)(in T[] lhs, in T[] rhs)
1835 return lhs.ptr == rhs.ptr;
1839 @safe pure nothrow unittest
1841 auto a = [1, 2, 3, 4, 5];
1842 auto b = a[0 .. 2];
1844 assert(a.sameHead(b));
1849 Returns whether the `back`s of `lhs` and `rhs` both refer to the
1850 same place in memory, making one of the arrays a slice of the other which
1851 end at index `$`.
1853 Params:
1854 lhs = the first array to compare
1855 rhs = the second array to compare
1856 Returns:
1857 `true` if both arrays are the same length and $(D lhs.ptr == rhs.ptr),
1858 `false` otherwise.
1860 @trusted
1861 pure nothrow @nogc bool sameTail(T)(in T[] lhs, in T[] rhs)
1863 return lhs.ptr + lhs.length == rhs.ptr + rhs.length;
1867 @safe pure nothrow unittest
1869 auto a = [1, 2, 3, 4, 5];
1870 auto b = a[3..$];
1872 assert(a.sameTail(b));
1875 @safe pure nothrow unittest
1877 static foreach (T; AliasSeq!(int[], const(int)[], immutable(int)[], const int[], immutable int[]))
1879 T a = [1, 2, 3, 4, 5];
1880 T b = a;
1881 T c = a[1 .. $];
1882 T d = a[0 .. 1];
1883 T e = null;
1885 assert(sameHead(a, a));
1886 assert(sameHead(a, b));
1887 assert(!sameHead(a, c));
1888 assert(sameHead(a, d));
1889 assert(!sameHead(a, e));
1891 assert(sameTail(a, a));
1892 assert(sameTail(a, b));
1893 assert(sameTail(a, c));
1894 assert(!sameTail(a, d));
1895 assert(!sameTail(a, e));
1897 //verifies R-value compatibilty
1898 assert(a.sameHead(a[0 .. 0]));
1899 assert(a.sameTail(a[$ .. $]));
1904 Params:
1905 s = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
1906 or a dynamic array
1907 n = number of times to repeat `s`
1909 Returns:
1910 An array that consists of `s` repeated `n` times. This function allocates, fills, and
1911 returns a new array.
1913 See_Also:
1914 For a lazy version, refer to $(REF repeat, std,range).
1916 ElementEncodingType!S[] replicate(S)(S s, size_t n)
1917 if (isDynamicArray!S)
1919 alias RetType = ElementEncodingType!S[];
1921 // Optimization for return join(std.range.repeat(s, n));
1922 if (n == 0)
1923 return RetType.init;
1924 if (n == 1)
1925 return cast(RetType) s;
1926 auto r = new Unqual!(typeof(s[0]))[n * s.length];
1927 if (s.length == 1)
1928 r[] = s[0];
1929 else
1931 immutable len = s.length, nlen = n * len;
1932 for (size_t i = 0; i < nlen; i += len)
1934 r[i .. i + len] = s[];
1937 return r;
1940 /// ditto
1941 ElementType!S[] replicate(S)(S s, size_t n)
1942 if (isInputRange!S && !isDynamicArray!S)
1944 import std.range : repeat;
1945 return join(std.range.repeat(s, n));
1950 @safe unittest
1952 auto a = "abc";
1953 auto s = replicate(a, 3);
1955 assert(s == "abcabcabc");
1957 auto b = [1, 2, 3];
1958 auto c = replicate(b, 3);
1960 assert(c == [1, 2, 3, 1, 2, 3, 1, 2, 3]);
1962 auto d = replicate(b, 0);
1964 assert(d == []);
1967 @safe unittest
1969 import std.conv : to;
1971 static foreach (S; AliasSeq!(string, wstring, dstring, char[], wchar[], dchar[]))
1973 immutable S t = "abc";
1975 assert(replicate(to!S("1234"), 0) is null);
1976 assert(replicate(to!S("1234"), 0) is null);
1977 assert(replicate(to!S("1234"), 1) == "1234");
1978 assert(replicate(to!S("1234"), 2) == "12341234");
1979 assert(replicate(to!S("1"), 4) == "1111");
1980 assert(replicate(t, 3) == "abcabcabc");
1981 assert(replicate(cast(S) null, 4) is null);
1986 Eagerly splits `range` into an array, using `sep` as the delimiter.
1988 When no delimiter is provided, strings are split into an array of words,
1989 using whitespace as delimiter.
1990 Runs of whitespace are merged together (no empty words are produced).
1992 The `range` must be a $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives).
1993 The separator can be a value of the same type as the elements in `range`
1994 or it can be another forward `range`.
1996 Params:
1997 s = the string to split by word if no separator is given
1998 range = the range to split
1999 sep = a value of the same type as the elements of `range` or another
2000 isTerminator = a predicate that splits the range when it returns `true`.
2002 Returns:
2003 An array containing the divided parts of `range` (or the words of `s`).
2005 See_Also:
2006 $(REF splitter, std,algorithm,iteration) for a lazy version without allocating memory.
2008 $(REF splitter, std,regex) for a version that splits using a regular
2009 expression defined separator.
2011 S[] split(S)(S s) @safe pure
2012 if (isSomeString!S)
2014 size_t istart;
2015 bool inword = false;
2016 auto result = appender!(S[]);
2018 foreach (i, dchar c ; s)
2020 import std.uni : isWhite;
2021 if (isWhite(c))
2023 if (inword)
2025 put(result, s[istart .. i]);
2026 inword = false;
2029 else
2031 if (!inword)
2033 istart = i;
2034 inword = true;
2038 if (inword)
2039 put(result, s[istart .. $]);
2040 return result.data;
2044 @safe unittest
2046 import std.uni : isWhite;
2047 assert("Learning,D,is,fun".split(",") == ["Learning", "D", "is", "fun"]);
2048 assert("Learning D is fun".split!isWhite == ["Learning", "D", "is", "fun"]);
2049 assert("Learning D is fun".split(" D ") == ["Learning", "is fun"]);
2053 @safe unittest
2055 string str = "Hello World!";
2056 assert(str.split == ["Hello", "World!"]);
2058 string str2 = "Hello\t\tWorld\t!";
2059 assert(str2.split == ["Hello", "World", "!"]);
2062 @safe unittest
2064 import std.conv : to;
2065 import std.format : format;
2066 import std.typecons;
2068 static auto makeEntry(S)(string l, string[] r)
2069 {return tuple(l.to!S(), r.to!(S[])());}
2071 static foreach (S; AliasSeq!(string, wstring, dstring,))
2073 auto entries =
2075 makeEntry!S("", []),
2076 makeEntry!S(" ", []),
2077 makeEntry!S("hello", ["hello"]),
2078 makeEntry!S(" hello ", ["hello"]),
2079 makeEntry!S(" h e l l o ", ["h", "e", "l", "l", "o"]),
2080 makeEntry!S("peter\t\npaul\rjerry", ["peter", "paul", "jerry"]),
2081 makeEntry!S(" \t\npeter paul\tjerry \n", ["peter", "paul", "jerry"]),
2082 makeEntry!S("\u2000\u202F\u205F\u3000", ["日", "本", "語"]),
2083 makeEntry!S("  哈・郎博尔德}    ___一个", ["哈・郎博尔德}", "___一个"])
2085 foreach (entry; entries)
2086 assert(entry[0].split() == entry[1], format("got: %s, expected: %s.", entry[0].split(), entry[1]));
2089 //Just to test that an immutable is split-able
2090 immutable string s = " \t\npeter paul\tjerry \n";
2091 assert(split(s) == ["peter", "paul", "jerry"]);
2094 @safe unittest //purity, ctfe ...
2096 import std.exception;
2097 void dg() @safe pure {
2098 assert(split("hello world"c) == ["hello"c, "world"c]);
2099 assert(split("hello world"w) == ["hello"w, "world"w]);
2100 assert(split("hello world"d) == ["hello"d, "world"d]);
2102 dg();
2103 assertCTFEable!dg;
2107 @safe unittest
2109 assert(split("hello world") == ["hello","world"]);
2110 assert(split("192.168.0.1", ".") == ["192", "168", "0", "1"]);
2112 auto a = split([1, 2, 3, 4, 5, 1, 2, 3, 4, 5], [2, 3]);
2113 assert(a == [[1], [4, 5, 1], [4, 5]]);
2116 ///ditto
2117 auto split(Range, Separator)(Range range, Separator sep)
2118 if (isForwardRange!Range && (
2119 is(typeof(ElementType!Range.init == Separator.init)) ||
2120 is(typeof(ElementType!Range.init == ElementType!Separator.init)) && isForwardRange!Separator
2123 import std.algorithm.iteration : splitter;
2124 return range.splitter(sep).array;
2126 ///ditto
2127 auto split(alias isTerminator, Range)(Range range)
2128 if (isForwardRange!Range && is(typeof(unaryFun!isTerminator(range.front))))
2130 import std.algorithm.iteration : splitter;
2131 return range.splitter!isTerminator.array;
2134 @safe unittest
2136 import std.algorithm.comparison : cmp;
2137 import std.conv;
2139 static foreach (S; AliasSeq!(string, wstring, dstring,
2140 immutable(string), immutable(wstring), immutable(dstring),
2141 char[], wchar[], dchar[],
2142 const(char)[], const(wchar)[], const(dchar)[],
2143 const(char[]), immutable(char[])))
2145 S s = to!S(",peter,paul,jerry,");
2147 auto words = split(s, ",");
2148 assert(words.length == 5, text(words.length));
2149 assert(cmp(words[0], "") == 0);
2150 assert(cmp(words[1], "peter") == 0);
2151 assert(cmp(words[2], "paul") == 0);
2152 assert(cmp(words[3], "jerry") == 0);
2153 assert(cmp(words[4], "") == 0);
2155 auto s1 = s[0 .. s.length - 1]; // lop off trailing ','
2156 words = split(s1, ",");
2157 assert(words.length == 4);
2158 assert(cmp(words[3], "jerry") == 0);
2160 auto s2 = s1[1 .. s1.length]; // lop off leading ','
2161 words = split(s2, ",");
2162 assert(words.length == 3);
2163 assert(cmp(words[0], "peter") == 0);
2165 auto s3 = to!S(",,peter,,paul,,jerry,,");
2167 words = split(s3, ",,");
2168 assert(words.length == 5);
2169 assert(cmp(words[0], "") == 0);
2170 assert(cmp(words[1], "peter") == 0);
2171 assert(cmp(words[2], "paul") == 0);
2172 assert(cmp(words[3], "jerry") == 0);
2173 assert(cmp(words[4], "") == 0);
2175 auto s4 = s3[0 .. s3.length - 2]; // lop off trailing ',,'
2176 words = split(s4, ",,");
2177 assert(words.length == 4);
2178 assert(cmp(words[3], "jerry") == 0);
2180 auto s5 = s4[2 .. s4.length]; // lop off leading ',,'
2181 words = split(s5, ",,");
2182 assert(words.length == 3);
2183 assert(cmp(words[0], "peter") == 0);
2188 Conservative heuristic to determine if a range can be iterated cheaply.
2189 Used by `join` in decision to do an extra iteration of the range to
2190 compute the resultant length. If iteration is not cheap then precomputing
2191 length could be more expensive than using `Appender`.
2193 For now, we only assume arrays are cheap to iterate.
2195 private enum bool hasCheapIteration(R) = isArray!R;
2198 Eagerly concatenates all of the ranges in `ror` together (with the GC)
2199 into one array using `sep` as the separator if present.
2201 Params:
2202 ror = An $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
2203 of input ranges
2204 sep = An input range, or a single element, to join the ranges on
2206 Returns:
2207 An array of elements
2209 See_Also:
2210 For a lazy version, see $(REF joiner, std,algorithm,iteration)
2212 ElementEncodingType!(ElementType!RoR)[] join(RoR, R)(RoR ror, R sep)
2213 if (isInputRange!RoR &&
2214 isInputRange!(Unqual!(ElementType!RoR)) &&
2215 isInputRange!R &&
2216 (is(immutable ElementType!(ElementType!RoR) == immutable ElementType!R) ||
2217 (isSomeChar!(ElementType!(ElementType!RoR)) && isSomeChar!(ElementType!R))
2220 alias RetType = typeof(return);
2221 alias RetTypeElement = Unqual!(ElementEncodingType!RetType);
2222 alias RoRElem = ElementType!RoR;
2224 if (ror.empty)
2225 return RetType.init;
2227 // Constraint only requires input range for sep.
2228 // This converts sep to an array (forward range) if it isn't one,
2229 // and makes sure it has the same string encoding for string types.
2230 static if (isSomeString!RetType &&
2231 !is(immutable ElementEncodingType!RetType == immutable ElementEncodingType!R))
2233 import std.conv : to;
2234 auto sepArr = to!RetType(sep);
2236 else static if (!isArray!R)
2237 auto sepArr = array(sep);
2238 else
2239 alias sepArr = sep;
2241 static if (hasCheapIteration!RoR && (hasLength!RoRElem || isNarrowString!RoRElem))
2243 import core.internal.lifetime : emplaceRef;
2244 size_t length; // length of result array
2245 size_t rorLength; // length of range ror
2246 foreach (r; ror.save)
2248 length += r.length;
2249 ++rorLength;
2251 if (!rorLength)
2252 return null;
2253 length += (rorLength - 1) * sepArr.length;
2255 auto result = (() @trusted => uninitializedArray!(RetTypeElement[])(length))();
2256 size_t len;
2257 foreach (e; ror.front)
2258 emplaceRef(result[len++], e);
2259 ror.popFront();
2260 foreach (r; ror)
2262 foreach (e; sepArr)
2263 emplaceRef(result[len++], e);
2264 foreach (e; r)
2265 emplaceRef(result[len++], e);
2267 assert(len == result.length);
2268 return (() @trusted => cast(RetType) result)();
2270 else
2272 auto result = appender!RetType();
2273 put(result, ror.front);
2274 ror.popFront();
2275 for (; !ror.empty; ror.popFront())
2277 put(result, sepArr);
2278 put(result, ror.front);
2280 return result.data;
2284 // https://issues.dlang.org/show_bug.cgi?id=14230
2285 @safe unittest
2287 string[] ary = ["","aa","bb","cc"]; // leaded by _empty_ element
2288 assert(ary.join(" @") == " @aa @bb @cc"); // OK in 2.067b1 and olders
2291 // https://issues.dlang.org/show_bug.cgi?id=21337
2292 @system unittest
2294 import std.algorithm.iteration : map;
2296 static class Once
2298 bool empty;
2300 void popFront()
2302 empty = true;
2305 int front()
2307 return 0;
2311 assert([1, 2].map!"[a]".join(new Once) == [1, 0, 2]);
2314 /// Ditto
2315 ElementEncodingType!(ElementType!RoR)[] join(RoR, E)(RoR ror, scope E sep)
2316 if (isInputRange!RoR &&
2317 isInputRange!(Unqual!(ElementType!RoR)) &&
2318 ((is(E : ElementType!(ElementType!RoR))) ||
2319 (!autodecodeStrings && isSomeChar!(ElementType!(ElementType!RoR)) &&
2320 isSomeChar!E)))
2322 alias RetType = typeof(return);
2323 alias RetTypeElement = Unqual!(ElementEncodingType!RetType);
2324 alias RoRElem = ElementType!RoR;
2326 if (ror.empty)
2327 return RetType.init;
2329 static if (hasCheapIteration!RoR && (hasLength!RoRElem || isNarrowString!RoRElem))
2331 static if (isSomeChar!E && isSomeChar!RetTypeElement && E.sizeof > RetTypeElement.sizeof)
2333 import std.utf : encode;
2334 RetTypeElement[4 / RetTypeElement.sizeof] encodeSpace;
2335 immutable size_t sepArrLength = encode(encodeSpace, sep);
2336 return join(ror, encodeSpace[0 .. sepArrLength]);
2338 else
2340 import core.internal.lifetime : emplaceRef;
2341 import std.format : format;
2342 size_t length;
2343 size_t rorLength;
2344 foreach (r; ror.save)
2346 length += r.length;
2347 ++rorLength;
2349 if (!rorLength)
2350 return null;
2351 length += rorLength - 1;
2352 auto result = uninitializedArray!(RetTypeElement[])(length);
2355 size_t len;
2356 foreach (e; ror.front)
2357 emplaceRef(result[len++], e);
2358 ror.popFront();
2359 foreach (r; ror)
2361 emplaceRef(result[len++], sep);
2362 foreach (e; r)
2363 emplaceRef(result[len++], e);
2365 assert(len == result.length, format!
2366 "len %s must equal result.lenght %s"(len, result.length));
2367 return (() @trusted => cast(RetType) result)();
2370 else
2372 auto result = appender!RetType();
2373 put(result, ror.front);
2374 ror.popFront();
2375 for (; !ror.empty; ror.popFront())
2377 put(result, sep);
2378 put(result, ror.front);
2380 return result.data;
2384 // https://issues.dlang.org/show_bug.cgi?id=14230
2385 @safe unittest
2387 string[] ary = ["","aa","bb","cc"];
2388 assert(ary.join('@') == "@aa@bb@cc");
2391 /// Ditto
2392 ElementEncodingType!(ElementType!RoR)[] join(RoR)(RoR ror)
2393 if (isInputRange!RoR &&
2394 isInputRange!(Unqual!(ElementType!RoR)))
2396 alias RetType = typeof(return);
2397 alias ConstRetTypeElement = ElementEncodingType!RetType;
2398 static if (isAssignable!(Unqual!ConstRetTypeElement, ConstRetTypeElement))
2400 alias RetTypeElement = Unqual!ConstRetTypeElement;
2402 else
2404 alias RetTypeElement = ConstRetTypeElement;
2406 alias RoRElem = ElementType!RoR;
2408 if (ror.empty)
2409 return RetType.init;
2411 static if (hasCheapIteration!RoR && (hasLength!RoRElem || isNarrowString!RoRElem))
2413 import core.internal.lifetime : emplaceRef;
2414 size_t length;
2415 foreach (r; ror.save)
2416 length += r.length;
2418 auto result = (() @trusted => uninitializedArray!(RetTypeElement[])(length))();
2419 size_t len;
2420 foreach (r; ror)
2421 foreach (e; r)
2422 emplaceRef!RetTypeElement(result[len++], e);
2423 assert(len == result.length,
2424 "emplaced an unexpected number of elements");
2425 return (() @trusted => cast(RetType) result)();
2427 else
2429 auto result = appender!RetType();
2430 for (; !ror.empty; ror.popFront())
2431 put(result, ror.front);
2432 return result.data;
2437 @safe pure nothrow unittest
2439 assert(join(["hello", "silly", "world"], " ") == "hello silly world");
2440 assert(join(["hello", "silly", "world"]) == "hellosillyworld");
2442 assert(join([[1, 2, 3], [4, 5]], [72, 73]) == [1, 2, 3, 72, 73, 4, 5]);
2443 assert(join([[1, 2, 3], [4, 5]]) == [1, 2, 3, 4, 5]);
2445 const string[] arr = ["apple", "banana"];
2446 assert(arr.join(",") == "apple,banana");
2447 assert(arr.join() == "applebanana");
2450 @safe pure unittest
2452 import std.conv : to;
2453 import std.range.primitives : autodecodeStrings;
2455 static foreach (T; AliasSeq!(string,wstring,dstring))
2457 auto arr2 = "Здравствуй Мир Unicode".to!(T);
2458 auto arr = ["Здравствуй", "Мир", "Unicode"].to!(T[]);
2459 assert(join(arr) == "ЗдравствуйМирUnicode");
2460 static foreach (S; AliasSeq!(char,wchar,dchar))
2462 auto jarr = arr.join(to!S(' '));
2463 static assert(is(typeof(jarr) == T));
2464 assert(jarr == arr2);
2466 static foreach (S; AliasSeq!(string,wstring,dstring))
2468 auto jarr = arr.join(to!S(" "));
2469 static assert(is(typeof(jarr) == T));
2470 assert(jarr == arr2);
2474 static foreach (T; AliasSeq!(string,wstring,dstring))
2476 auto arr2 = "Здравствуй\u047CМир\u047CUnicode".to!(T);
2477 auto arr = ["Здравствуй", "Мир", "Unicode"].to!(T[]);
2478 static foreach (S; AliasSeq!(wchar,dchar))
2480 auto jarr = arr.join(to!S('\u047C'));
2481 static assert(is(typeof(jarr) == T));
2482 assert(jarr == arr2);
2486 const string[] arr = ["apple", "banana"];
2487 assert(arr.join(',') == "apple,banana");
2490 @safe unittest
2492 class A { }
2494 const A[][] array;
2495 auto result = array.join; // can't remove constness, so don't try
2497 static assert(is(typeof(result) == const(A)[]));
2500 @safe unittest
2502 import std.algorithm;
2503 import std.conv : to;
2504 import std.range;
2506 static foreach (R; AliasSeq!(string, wstring, dstring))
2508 R word1 = "日本語";
2509 R word2 = "paul";
2510 R word3 = "jerry";
2511 R[] words = [word1, word2, word3];
2513 auto filteredWord1 = filter!"true"(word1);
2514 auto filteredLenWord1 = takeExactly(filteredWord1, word1.walkLength());
2515 auto filteredWord2 = filter!"true"(word2);
2516 auto filteredLenWord2 = takeExactly(filteredWord2, word2.walkLength());
2517 auto filteredWord3 = filter!"true"(word3);
2518 auto filteredLenWord3 = takeExactly(filteredWord3, word3.walkLength());
2519 auto filteredWordsArr = [filteredWord1, filteredWord2, filteredWord3];
2520 auto filteredLenWordsArr = [filteredLenWord1, filteredLenWord2, filteredLenWord3];
2521 auto filteredWords = filter!"true"(filteredWordsArr);
2523 static foreach (S; AliasSeq!(string, wstring, dstring))
2525 assert(join(filteredWords, to!S(", ")) == "日本語, paul, jerry");
2526 assert(join(filteredWords, to!(ElementType!S)(',')) == "日本語,paul,jerry");
2527 assert(join(filteredWordsArr, to!(ElementType!(S))(',')) == "日本語,paul,jerry");
2528 assert(join(filteredWordsArr, to!S(", ")) == "日本語, paul, jerry");
2529 assert(join(filteredWordsArr, to!(ElementType!(S))(',')) == "日本語,paul,jerry");
2530 assert(join(filteredLenWordsArr, to!S(", ")) == "日本語, paul, jerry");
2531 assert(join(filter!"true"(words), to!S(", ")) == "日本語, paul, jerry");
2532 assert(join(words, to!S(", ")) == "日本語, paul, jerry");
2534 assert(join(filteredWords, to!S("")) == "日本語pauljerry");
2535 assert(join(filteredWordsArr, to!S("")) == "日本語pauljerry");
2536 assert(join(filteredLenWordsArr, to!S("")) == "日本語pauljerry");
2537 assert(join(filter!"true"(words), to!S("")) == "日本語pauljerry");
2538 assert(join(words, to!S("")) == "日本語pauljerry");
2540 assert(join(filter!"true"([word1]), to!S(", ")) == "日本語");
2541 assert(join([filteredWord1], to!S(", ")) == "日本語");
2542 assert(join([filteredLenWord1], to!S(", ")) == "日本語");
2543 assert(join(filter!"true"([filteredWord1]), to!S(", ")) == "日本語");
2544 assert(join([word1], to!S(", ")) == "日本語");
2546 assert(join(filteredWords, to!S(word1)) == "日本語日本語paul日本語jerry");
2547 assert(join(filteredWordsArr, to!S(word1)) == "日本語日本語paul日本語jerry");
2548 assert(join(filteredLenWordsArr, to!S(word1)) == "日本語日本語paul日本語jerry");
2549 assert(join(filter!"true"(words), to!S(word1)) == "日本語日本語paul日本語jerry");
2550 assert(join(words, to!S(word1)) == "日本語日本語paul日本語jerry");
2552 auto filterComma = filter!"true"(to!S(", "));
2553 assert(join(filteredWords, filterComma) == "日本語, paul, jerry");
2554 assert(join(filteredWordsArr, filterComma) == "日本語, paul, jerry");
2555 assert(join(filteredLenWordsArr, filterComma) == "日本語, paul, jerry");
2556 assert(join(filter!"true"(words), filterComma) == "日本語, paul, jerry");
2557 assert(join(words, filterComma) == "日本語, paul, jerry");
2560 assert(join(filteredWords) == "日本語pauljerry");
2561 assert(join(filteredWordsArr) == "日本語pauljerry");
2562 assert(join(filteredLenWordsArr) == "日本語pauljerry");
2563 assert(join(filter!"true"(words)) == "日本語pauljerry");
2564 assert(join(words) == "日本語pauljerry");
2566 assert(join(filteredWords, filter!"true"(", ")) == "日本語, paul, jerry");
2567 assert(join(filteredWordsArr, filter!"true"(", ")) == "日本語, paul, jerry");
2568 assert(join(filteredLenWordsArr, filter!"true"(", ")) == "日本語, paul, jerry");
2569 assert(join(filter!"true"(words), filter!"true"(", ")) == "日本語, paul, jerry");
2570 assert(join(words, filter!"true"(", ")) == "日本語, paul, jerry");
2572 assert(join(filter!"true"(cast(typeof(filteredWordsArr))[]), ", ").empty);
2573 assert(join(cast(typeof(filteredWordsArr))[], ", ").empty);
2574 assert(join(cast(typeof(filteredLenWordsArr))[], ", ").empty);
2575 assert(join(filter!"true"(cast(R[])[]), ", ").empty);
2576 assert(join(cast(R[])[], ", ").empty);
2578 assert(join(filter!"true"(cast(typeof(filteredWordsArr))[])).empty);
2579 assert(join(cast(typeof(filteredWordsArr))[]).empty);
2580 assert(join(cast(typeof(filteredLenWordsArr))[]).empty);
2582 assert(join(filter!"true"(cast(R[])[])).empty);
2583 assert(join(cast(R[])[]).empty);
2586 assert(join([[1, 2], [41, 42]], [5, 6]) == [1, 2, 5, 6, 41, 42]);
2587 assert(join([[1, 2], [41, 42]], cast(int[])[]) == [1, 2, 41, 42]);
2588 assert(join([[1, 2]], [5, 6]) == [1, 2]);
2589 assert(join(cast(int[][])[], [5, 6]).empty);
2591 assert(join([[1, 2], [41, 42]]) == [1, 2, 41, 42]);
2592 assert(join(cast(int[][])[]).empty);
2594 alias f = filter!"true";
2595 assert(join([[1, 2], [41, 42]], [5, 6]) == [1, 2, 5, 6, 41, 42]);
2596 assert(join(f([[1, 2], [41, 42]]), [5, 6]) == [1, 2, 5, 6, 41, 42]);
2597 assert(join([f([1, 2]), f([41, 42])], [5, 6]) == [1, 2, 5, 6, 41, 42]);
2598 assert(join(f([f([1, 2]), f([41, 42])]), [5, 6]) == [1, 2, 5, 6, 41, 42]);
2599 assert(join([[1, 2], [41, 42]], f([5, 6])) == [1, 2, 5, 6, 41, 42]);
2600 assert(join(f([[1, 2], [41, 42]]), f([5, 6])) == [1, 2, 5, 6, 41, 42]);
2601 assert(join([f([1, 2]), f([41, 42])], f([5, 6])) == [1, 2, 5, 6, 41, 42]);
2602 assert(join(f([f([1, 2]), f([41, 42])]), f([5, 6])) == [1, 2, 5, 6, 41, 42]);
2605 // https://issues.dlang.org/show_bug.cgi?id=10683
2606 @safe unittest
2608 import std.range : join;
2609 import std.typecons : tuple;
2610 assert([[tuple(1)]].join == [tuple(1)]);
2611 assert([[tuple("x")]].join == [tuple("x")]);
2614 // https://issues.dlang.org/show_bug.cgi?id=13877
2615 @safe unittest
2617 // Test that the range is iterated only once.
2618 import std.algorithm.iteration : map;
2619 int c = 0;
2620 auto j1 = [1, 2, 3].map!(_ => [c++]).join;
2621 assert(c == 3);
2622 assert(j1 == [0, 1, 2]);
2624 c = 0;
2625 auto j2 = [1, 2, 3].map!(_ => [c++]).join(9);
2626 assert(c == 3);
2627 assert(j2 == [0, 9, 1, 9, 2]);
2629 c = 0;
2630 auto j3 = [1, 2, 3].map!(_ => [c++]).join([9]);
2631 assert(c == 3);
2632 assert(j3 == [0, 9, 1, 9, 2]);
2637 Replace occurrences of `from` with `to` in `subject` in a new array.
2639 Params:
2640 subject = the array to scan
2641 from = the item to replace
2642 to = the item to replace all instances of `from` with
2644 Returns:
2645 A new array without changing the contents of `subject`, or the original
2646 array if no match is found.
2648 See_Also:
2649 $(REF substitute, std,algorithm,iteration) for a lazy replace.
2651 E[] replace(E, R1, R2)(E[] subject, R1 from, R2 to)
2652 if ((isForwardRange!R1 && isForwardRange!R2 && (hasLength!R2 || isSomeString!R2)) ||
2653 is(Unqual!E : Unqual!R1))
2655 size_t changed = 0;
2656 return replace(subject, from, to, changed);
2660 @safe unittest
2662 assert("Hello Wörld".replace("o Wö", "o Wo") == "Hello World");
2663 assert("Hello Wörld".replace("l", "h") == "Hehho Wörhd");
2666 @safe unittest
2668 assert([1, 2, 3, 4, 2].replace([2], [5]) == [1, 5, 3, 4, 5]);
2669 assert([3, 3, 3].replace([3], [0]) == [0, 0, 0]);
2670 assert([3, 3, 4, 3].replace([3, 3], [1, 1, 1]) == [1, 1, 1, 4, 3]);
2673 // https://issues.dlang.org/show_bug.cgi?id=18215
2674 @safe unittest
2676 auto arr = ["aaa.dd", "b"];
2677 arr = arr.replace("aaa.dd", ".");
2678 assert(arr == [".", "b"]);
2680 arr = ["_", "_", "aaa.dd", "b", "c", "aaa.dd", "e"];
2681 arr = arr.replace("aaa.dd", ".");
2682 assert(arr == ["_", "_", ".", "b", "c", ".", "e"]);
2685 // https://issues.dlang.org/show_bug.cgi?id=18215
2686 @safe unittest
2688 assert([[0], [1, 2], [0], [3]].replace([0], [4]) == [[4], [1, 2], [4], [3]]);
2689 assert([[0], [1, 2], [0], [3], [1, 2]]
2690 .replace([1, 2], [0]) == [[0], [0], [0], [3], [0]]);
2691 assert([[0], [1, 2], [0], [3], [1, 2], [0], [1, 2]]
2692 .replace([[0], [1, 2]], [[4]]) == [[4], [0], [3], [1, 2], [4]]);
2695 // https://issues.dlang.org/show_bug.cgi?id=10930
2696 @safe unittest
2698 assert([0, 1, 2].replace(1, 4) == [0, 4, 2]);
2699 assert("äbö".replace('ä', 'a') == "abö");
2702 // empty array
2703 @safe unittest
2705 int[] arr;
2706 assert(replace(arr, 1, 2) == []);
2710 Replace occurrences of `from` with `to` in `subject` in a new array.
2711 `changed` counts how many replacements took place.
2713 Params:
2714 subject = the array to scan
2715 from = the item to replace
2716 to = the item to replace all instances of `from` with
2717 changed = the number of replacements
2719 Returns:
2720 A new array without changing the contents of `subject`, or the original
2721 array if no match is found.
2723 E[] replace(E, R1, R2)(E[] subject, R1 from, R2 to, ref size_t changed)
2724 if ((isForwardRange!R1 && isForwardRange!R2 && (hasLength!R2 || isSomeString!R2)) ||
2725 is(Unqual!E : Unqual!R1))
2727 import std.algorithm.searching : find;
2728 import std.range : dropOne;
2730 static if (isInputRange!R1)
2732 if (from.empty) return subject;
2733 alias rSave = a => a.save;
2735 else
2737 alias rSave = a => a;
2740 auto balance = find(subject, rSave(from));
2741 if (balance.empty)
2742 return subject;
2744 auto app = appender!(E[])();
2745 app.put(subject[0 .. subject.length - balance.length]);
2746 app.put(rSave(to));
2747 ++changed;
2748 // replacing an element in an array is different to a range replacement
2749 static if (is(Unqual!E : Unqual!R1))
2750 replaceInto(app, balance.dropOne, from, to, changed);
2751 else
2752 replaceInto(app, balance[from.length .. $], from, to, changed);
2754 return app.data;
2758 @safe unittest
2760 size_t changed = 0;
2761 assert("Hello Wörld".replace("o Wö", "o Wo", changed) == "Hello World");
2762 assert(changed == 1);
2764 changed = 0;
2765 assert("Hello Wörld".replace("l", "h", changed) == "Hehho Wörhd");
2766 import std.stdio : writeln;
2767 writeln(changed);
2768 assert(changed == 3);
2772 Replace occurrences of `from` with `to` in `subject` and output the result into
2773 `sink`.
2775 Params:
2776 sink = an $(REF_ALTTEXT output range, isOutputRange, std,range,primitives)
2777 subject = the array to scan
2778 from = the item to replace
2779 to = the item to replace all instances of `from` with
2781 See_Also:
2782 $(REF substitute, std,algorithm,iteration) for a lazy replace.
2784 void replaceInto(E, Sink, R1, R2)(Sink sink, E[] subject, R1 from, R2 to)
2785 if (isOutputRange!(Sink, E) &&
2786 ((isForwardRange!R1 && isForwardRange!R2 && (hasLength!R2 || isSomeString!R2)) ||
2787 is(Unqual!E : Unqual!R1)))
2789 size_t changed = 0;
2790 replaceInto(sink, subject, from, to, changed);
2794 @safe unittest
2796 auto arr = [1, 2, 3, 4, 5];
2797 auto from = [2, 3];
2798 auto to = [4, 6];
2799 auto sink = appender!(int[])();
2801 replaceInto(sink, arr, from, to);
2803 assert(sink.data == [1, 4, 6, 4, 5]);
2806 // empty array
2807 @safe unittest
2809 auto sink = appender!(int[])();
2810 int[] arr;
2811 replaceInto(sink, arr, 1, 2);
2812 assert(sink.data == []);
2815 @safe unittest
2817 import std.algorithm.comparison : cmp;
2818 import std.conv : to;
2820 static foreach (S; AliasSeq!(string, wstring, dstring, char[], wchar[], dchar[]))
2822 static foreach (T; AliasSeq!(string, wstring, dstring, char[], wchar[], dchar[]))
2824 auto s = to!S("This is a foo foo list");
2825 auto from = to!T("foo");
2826 auto into = to!S("silly");
2827 S r;
2828 int i;
2830 r = replace(s, from, into);
2831 i = cmp(r, "This is a silly silly list");
2832 assert(i == 0);
2834 r = replace(s, to!S(""), into);
2835 i = cmp(r, "This is a foo foo list");
2836 assert(i == 0);
2838 assert(replace(r, to!S("won't find this"), to!S("whatever")) is r);
2842 immutable s = "This is a foo foo list";
2843 assert(replace(s, "foo", "silly") == "This is a silly silly list");
2846 @safe unittest
2848 import std.algorithm.searching : skipOver;
2849 import std.conv : to;
2851 struct CheckOutput(C)
2853 C[] desired;
2854 this(C[] arr){ desired = arr; }
2855 void put(C[] part){ assert(skipOver(desired, part)); }
2857 static foreach (S; AliasSeq!(string, wstring, dstring, char[], wchar[], dchar[]))
2859 alias Char = ElementEncodingType!S;
2860 S s = to!S("yet another dummy text, yet another ...");
2861 S from = to!S("yet another");
2862 S into = to!S("some");
2863 replaceInto(CheckOutput!(Char)(to!S("some dummy text, some ..."))
2864 , s, from, into);
2868 // https://issues.dlang.org/show_bug.cgi?id=10930
2869 @safe unittest
2871 auto sink = appender!(int[])();
2872 replaceInto(sink, [0, 1, 2], 1, 5);
2873 assert(sink.data == [0, 5, 2]);
2875 auto sink2 = appender!(dchar[])();
2876 replaceInto(sink2, "äbö", 'ä', 'a');
2877 assert(sink2.data == "abö");
2881 Replace occurrences of `from` with `to` in `subject` and output the result into
2882 `sink`. `changed` counts how many replacements took place.
2884 Params:
2885 sink = an $(REF_ALTTEXT output range, isOutputRange, std,range,primitives)
2886 subject = the array to scan
2887 from = the item to replace
2888 to = the item to replace all instances of `from` with
2889 changed = the number of replacements
2891 void replaceInto(E, Sink, R1, R2)(Sink sink, E[] subject, R1 from, R2 to, ref size_t changed)
2892 if (isOutputRange!(Sink, E) &&
2893 ((isForwardRange!R1 && isForwardRange!R2 && (hasLength!R2 || isSomeString!R2)) ||
2894 is(Unqual!E : Unqual!R1)))
2896 import std.algorithm.searching : find;
2897 import std.range : dropOne;
2899 static if (isInputRange!R1)
2901 if (from.empty)
2903 sink.put(subject);
2904 return;
2906 alias rSave = a => a.save;
2908 else
2910 alias rSave = a => a;
2912 for (;;)
2914 auto balance = find(subject, rSave(from));
2915 if (balance.empty)
2917 sink.put(subject);
2918 break;
2920 sink.put(subject[0 .. subject.length - balance.length]);
2921 sink.put(rSave(to));
2922 ++changed;
2923 // replacing an element in an array is different to a range replacement
2924 static if (is(Unqual!E : Unqual!R1))
2925 subject = balance.dropOne;
2926 else
2927 subject = balance[from.length .. $];
2932 @safe unittest
2934 auto arr = [1, 2, 3, 4, 5];
2935 auto from = [2, 3];
2936 auto to = [4, 6];
2937 auto sink = appender!(int[])();
2939 size_t changed = 0;
2940 replaceInto(sink, arr, from, to, changed);
2942 assert(sink.data == [1, 4, 6, 4, 5]);
2943 assert(changed == 1);
2947 Replaces elements from `array` with indices ranging from `from`
2948 (inclusive) to `to` (exclusive) with the range `stuff`.
2950 Params:
2951 subject = the array to scan
2952 from = the starting index
2953 to = the ending index
2954 stuff = the items to replace in-between `from` and `to`
2956 Returns:
2957 A new array without changing the contents of `subject`.
2959 See_Also:
2960 $(REF substitute, std,algorithm,iteration) for a lazy replace.
2962 T[] replace(T, Range)(T[] subject, size_t from, size_t to, Range stuff)
2963 if (isInputRange!Range &&
2964 (is(ElementType!Range : T) ||
2965 isSomeString!(T[]) && is(ElementType!Range : dchar)))
2967 static if (hasLength!Range && is(ElementEncodingType!Range : T))
2969 import std.algorithm.mutation : copy;
2970 assert(from <= to, "from must be before or equal to to");
2971 immutable sliceLen = to - from;
2972 auto retval = new Unqual!(T)[](subject.length - sliceLen + stuff.length);
2973 retval[0 .. from] = subject[0 .. from];
2975 if (!stuff.empty)
2976 copy(stuff, retval[from .. from + stuff.length]);
2978 retval[from + stuff.length .. $] = subject[to .. $];
2979 static if (is(T == const) || is(T == immutable))
2981 return () @trusted { return cast(T[]) retval; } ();
2983 else
2985 return cast(T[]) retval;
2988 else
2990 auto app = appender!(T[])();
2991 app.put(subject[0 .. from]);
2992 app.put(stuff);
2993 app.put(subject[to .. $]);
2994 return app.data;
2999 @safe unittest
3001 auto a = [ 1, 2, 3, 4 ];
3002 auto b = a.replace(1, 3, [ 9, 9, 9 ]);
3003 assert(a == [ 1, 2, 3, 4 ]);
3004 assert(b == [ 1, 9, 9, 9, 4 ]);
3007 @system unittest
3009 import core.exception;
3010 import std.algorithm.iteration : filter;
3011 import std.conv : to;
3012 import std.exception;
3015 auto a = [ 1, 2, 3, 4 ];
3016 assert(replace(a, 0, 0, [5, 6, 7]) == [5, 6, 7, 1, 2, 3, 4]);
3017 assert(replace(a, 0, 2, cast(int[])[]) == [3, 4]);
3018 assert(replace(a, 0, 4, [5, 6, 7]) == [5, 6, 7]);
3019 assert(replace(a, 0, 2, [5, 6, 7]) == [5, 6, 7, 3, 4]);
3020 assert(replace(a, 2, 4, [5, 6, 7]) == [1, 2, 5, 6, 7]);
3022 assert(replace(a, 0, 0, filter!"true"([5, 6, 7])) == [5, 6, 7, 1, 2, 3, 4]);
3023 assert(replace(a, 0, 2, filter!"true"(cast(int[])[])) == [3, 4]);
3024 assert(replace(a, 0, 4, filter!"true"([5, 6, 7])) == [5, 6, 7]);
3025 assert(replace(a, 0, 2, filter!"true"([5, 6, 7])) == [5, 6, 7, 3, 4]);
3026 assert(replace(a, 2, 4, filter!"true"([5, 6, 7])) == [1, 2, 5, 6, 7]);
3027 assert(a == [ 1, 2, 3, 4 ]);
3029 void testStr(T, U)(string file = __FILE__, size_t line = __LINE__)
3032 auto l = to!T("hello");
3033 auto r = to!U(" world");
3035 enforce(replace(l, 0, 0, r) == " worldhello",
3036 new AssertError("testStr failure 1", file, line));
3037 enforce(replace(l, 0, 3, r) == " worldlo",
3038 new AssertError("testStr failure 2", file, line));
3039 enforce(replace(l, 3, l.length, r) == "hel world",
3040 new AssertError("testStr failure 3", file, line));
3041 enforce(replace(l, 0, l.length, r) == " world",
3042 new AssertError("testStr failure 4", file, line));
3043 enforce(replace(l, l.length, l.length, r) == "hello world",
3044 new AssertError("testStr failure 5", file, line));
3047 testStr!(string, string)();
3048 testStr!(string, wstring)();
3049 testStr!(string, dstring)();
3050 testStr!(wstring, string)();
3051 testStr!(wstring, wstring)();
3052 testStr!(wstring, dstring)();
3053 testStr!(dstring, string)();
3054 testStr!(dstring, wstring)();
3055 testStr!(dstring, dstring)();
3057 enum s = "0123456789";
3058 enum w = "⁰¹²³⁴⁵⁶⁷⁸⁹"w;
3059 enum d = "⁰¹²³⁴⁵⁶⁷⁸⁹"d;
3061 assert(replace(s, 0, 0, "***") == "***0123456789");
3062 assert(replace(s, 10, 10, "***") == "0123456789***");
3063 assert(replace(s, 3, 8, "1012") == "012101289");
3064 assert(replace(s, 0, 5, "43210") == "4321056789");
3065 assert(replace(s, 5, 10, "43210") == "0123443210");
3067 assert(replace(w, 0, 0, "***"w) == "***⁰¹²³⁴⁵⁶⁷⁸⁹"w);
3068 assert(replace(w, 10, 10, "***"w) == "⁰¹²³⁴⁵⁶⁷⁸⁹***"w);
3069 assert(replace(w, 3, 8, "¹⁰¹²"w) == "⁰¹²¹⁰¹²⁸⁹"w);
3070 assert(replace(w, 0, 5, "⁴³²¹⁰"w) == "⁴³²¹⁰⁵⁶⁷⁸⁹"w);
3071 assert(replace(w, 5, 10, "⁴³²¹⁰"w) == "⁰¹²³⁴⁴³²¹⁰"w);
3073 assert(replace(d, 0, 0, "***"d) == "***⁰¹²³⁴⁵⁶⁷⁸⁹"d);
3074 assert(replace(d, 10, 10, "***"d) == "⁰¹²³⁴⁵⁶⁷⁸⁹***"d);
3075 assert(replace(d, 3, 8, "¹⁰¹²"d) == "⁰¹²¹⁰¹²⁸⁹"d);
3076 assert(replace(d, 0, 5, "⁴³²¹⁰"d) == "⁴³²¹⁰⁵⁶⁷⁸⁹"d);
3077 assert(replace(d, 5, 10, "⁴³²¹⁰"d) == "⁰¹²³⁴⁴³²¹⁰"d);
3080 // https://issues.dlang.org/show_bug.cgi?id=18166
3081 @safe pure unittest
3083 auto str = replace("aaaaa"d, 1, 4, "***"d);
3084 assert(str == "a***a");
3088 Replaces elements from `array` with indices ranging from `from`
3089 (inclusive) to `to` (exclusive) with the range `stuff`. Expands or
3090 shrinks the array as needed.
3092 Params:
3093 array = the array to scan
3094 from = the starting index
3095 to = the ending index
3096 stuff = the items to replace in-between `from` and `to`
3098 void replaceInPlace(T, Range)(ref T[] array, size_t from, size_t to, Range stuff)
3099 if (is(typeof(replace(array, from, to, stuff))))
3101 static if (isDynamicArray!Range &&
3102 is(Unqual!(ElementEncodingType!Range) == T) &&
3103 !isNarrowString!(T[]))
3105 // optimized for homogeneous arrays that can be overwritten.
3106 import std.algorithm.mutation : remove;
3107 import std.typecons : tuple;
3109 if (overlap(array, stuff).length)
3111 // use slower/conservative method
3112 array = array[0 .. from] ~ stuff ~ array[to .. $];
3114 else if (stuff.length <= to - from)
3116 // replacement reduces length
3117 immutable stuffEnd = from + stuff.length;
3118 array[from .. stuffEnd] = stuff[];
3119 if (stuffEnd < to)
3120 array = remove(array, tuple(stuffEnd, to));
3122 else
3124 // replacement increases length
3125 // @@@TODO@@@: optimize this
3126 immutable replaceLen = to - from;
3127 array[from .. to] = stuff[0 .. replaceLen];
3128 insertInPlace(array, to, stuff[replaceLen .. $]);
3131 else
3133 // default implementation, just do what replace does.
3134 array = replace(array, from, to, stuff);
3139 @safe unittest
3141 int[] a = [1, 4, 5];
3142 replaceInPlace(a, 1u, 2u, [2, 3, 4]);
3143 assert(a == [1, 2, 3, 4, 5]);
3144 replaceInPlace(a, 1u, 2u, cast(int[])[]);
3145 assert(a == [1, 3, 4, 5]);
3146 replaceInPlace(a, 1u, 3u, a[2 .. 4]);
3147 assert(a == [1, 4, 5, 5]);
3150 // https://issues.dlang.org/show_bug.cgi?id=12889
3151 @safe unittest
3153 int[1][] arr = [[0], [1], [2], [3], [4], [5], [6]];
3154 int[1][] stuff = [[0], [1]];
3155 replaceInPlace(arr, 4, 6, stuff);
3156 assert(arr == [[0], [1], [2], [3], [0], [1], [6]]);
3159 @system unittest
3161 // https://issues.dlang.org/show_bug.cgi?id=14925
3162 char[] a = "mon texte 1".dup;
3163 char[] b = "abc".dup;
3164 replaceInPlace(a, 4, 9, b);
3165 assert(a == "mon abc 1");
3167 // ensure we can replace in place with different encodings
3168 string unicoded = "\U00010437";
3169 string unicodedLong = "\U00010437aaaaa";
3170 string base = "abcXXXxyz";
3171 string result = "abc\U00010437xyz";
3172 string resultLong = "abc\U00010437aaaaaxyz";
3173 size_t repstart = 3;
3174 size_t repend = 3 + 3;
3176 void testStringReplaceInPlace(T, U)()
3178 import std.algorithm.comparison : equal;
3179 import std.conv;
3180 auto a = unicoded.to!(U[]);
3181 auto b = unicodedLong.to!(U[]);
3183 auto test = base.to!(T[]);
3185 test.replaceInPlace(repstart, repend, a);
3186 assert(equal(test, result), "Failed for types " ~ T.stringof ~ " and " ~ U.stringof);
3188 test = base.to!(T[]);
3190 test.replaceInPlace(repstart, repend, b);
3191 assert(equal(test, resultLong), "Failed for types " ~ T.stringof ~ " and " ~ U.stringof);
3194 import std.meta : AliasSeq;
3195 alias allChars = AliasSeq!(char, immutable(char), const(char),
3196 wchar, immutable(wchar), const(wchar),
3197 dchar, immutable(dchar), const(dchar));
3198 foreach (T; allChars)
3199 foreach (U; allChars)
3200 testStringReplaceInPlace!(T, U)();
3202 void testInout(inout(int)[] a)
3204 // will be transferred to the 'replace' function
3205 replaceInPlace(a, 1, 2, [1,2,3]);
3209 @safe unittest
3211 // the constraint for the first overload used to match this, which wouldn't compile.
3212 import std.algorithm.comparison : equal;
3213 long[] a = [1L, 2, 3];
3214 int[] b = [4, 5, 6];
3215 a.replaceInPlace(1, 2, b);
3216 assert(equal(a, [1L, 4, 5, 6, 3]));
3219 @system unittest
3221 import core.exception;
3222 import std.algorithm.comparison : equal;
3223 import std.algorithm.iteration : filter;
3224 import std.conv : to;
3225 import std.exception;
3228 bool test(T, U, V)(T orig, size_t from, size_t to, U toReplace, V result)
3231 static if (is(T == typeof(T.init.dup)))
3232 auto a = orig.dup;
3233 else
3234 auto a = orig.idup;
3236 a.replaceInPlace(from, to, toReplace);
3237 if (!equal(a, result))
3238 return false;
3241 static if (isInputRange!U)
3243 orig.replaceInPlace(from, to, filter!"true"(toReplace));
3244 return equal(orig, result);
3246 else
3247 return true;
3250 assert(test([1, 2, 3, 4], 0, 0, [5, 6, 7], [5, 6, 7, 1, 2, 3, 4]));
3251 assert(test([1, 2, 3, 4], 0, 2, cast(int[])[], [3, 4]));
3252 assert(test([1, 2, 3, 4], 0, 4, [5, 6, 7], [5, 6, 7]));
3253 assert(test([1, 2, 3, 4], 0, 2, [5, 6, 7], [5, 6, 7, 3, 4]));
3254 assert(test([1, 2, 3, 4], 2, 4, [5, 6, 7], [1, 2, 5, 6, 7]));
3256 assert(test([1, 2, 3, 4], 0, 0, filter!"true"([5, 6, 7]), [5, 6, 7, 1, 2, 3, 4]));
3257 assert(test([1, 2, 3, 4], 0, 2, filter!"true"(cast(int[])[]), [3, 4]));
3258 assert(test([1, 2, 3, 4], 0, 4, filter!"true"([5, 6, 7]), [5, 6, 7]));
3259 assert(test([1, 2, 3, 4], 0, 2, filter!"true"([5, 6, 7]), [5, 6, 7, 3, 4]));
3260 assert(test([1, 2, 3, 4], 2, 4, filter!"true"([5, 6, 7]), [1, 2, 5, 6, 7]));
3262 void testStr(T, U)(string file = __FILE__, size_t line = __LINE__)
3265 auto l = to!T("hello");
3266 auto r = to!U(" world");
3268 enforce(test(l, 0, 0, r, " worldhello"),
3269 new AssertError("testStr failure 1", file, line));
3270 enforce(test(l, 0, 3, r, " worldlo"),
3271 new AssertError("testStr failure 2", file, line));
3272 enforce(test(l, 3, l.length, r, "hel world"),
3273 new AssertError("testStr failure 3", file, line));
3274 enforce(test(l, 0, l.length, r, " world"),
3275 new AssertError("testStr failure 4", file, line));
3276 enforce(test(l, l.length, l.length, r, "hello world"),
3277 new AssertError("testStr failure 5", file, line));
3280 testStr!(string, string)();
3281 testStr!(string, wstring)();
3282 testStr!(string, dstring)();
3283 testStr!(wstring, string)();
3284 testStr!(wstring, wstring)();
3285 testStr!(wstring, dstring)();
3286 testStr!(dstring, string)();
3287 testStr!(dstring, wstring)();
3288 testStr!(dstring, dstring)();
3292 Replaces the first occurrence of `from` with `to` in `subject`.
3294 Params:
3295 subject = the array to scan
3296 from = the item to replace
3297 to = the item to replace `from` with
3299 Returns:
3300 A new array without changing the contents of `subject`, or the original
3301 array if no match is found.
3303 E[] replaceFirst(E, R1, R2)(E[] subject, R1 from, R2 to)
3304 if (isDynamicArray!(E[]) &&
3305 isForwardRange!R1 && is(typeof(appender!(E[])().put(from[0 .. 1]))) &&
3306 isForwardRange!R2 && is(typeof(appender!(E[])().put(to[0 .. 1]))))
3308 if (from.empty) return subject;
3309 static if (isSomeString!(E[]))
3311 import std.string : indexOf;
3312 immutable idx = subject.indexOf(from);
3314 else
3316 import std.algorithm.searching : countUntil;
3317 immutable idx = subject.countUntil(from);
3319 if (idx == -1)
3320 return subject;
3322 auto app = appender!(E[])();
3323 app.put(subject[0 .. idx]);
3324 app.put(to);
3326 static if (isSomeString!(E[]) && isSomeString!R1)
3328 import std.utf : codeLength;
3329 immutable fromLength = codeLength!(Unqual!E, R1)(from);
3331 else
3332 immutable fromLength = from.length;
3334 app.put(subject[idx + fromLength .. $]);
3336 return app.data;
3340 @safe unittest
3342 auto a = [1, 2, 2, 3, 4, 5];
3343 auto b = a.replaceFirst([2], [1337]);
3344 assert(b == [1, 1337, 2, 3, 4, 5]);
3346 auto s = "This is a foo foo list";
3347 auto r = s.replaceFirst("foo", "silly");
3348 assert(r == "This is a silly foo list");
3351 @safe unittest
3353 import std.algorithm.comparison : cmp;
3354 import std.conv : to;
3356 static foreach (S; AliasSeq!(string, wstring, dstring, char[], wchar[], dchar[],
3357 const(char[]), immutable(char[])))
3359 static foreach (T; AliasSeq!(string, wstring, dstring, char[], wchar[], dchar[],
3360 const(char[]), immutable(char[])))
3362 auto s = to!S("This is a foo foo list");
3363 auto s2 = to!S("Thüs is a ßöö foo list");
3364 auto from = to!T("foo");
3365 auto from2 = to!T("ßöö");
3366 auto into = to!T("silly");
3367 auto into2 = to!T("sälly");
3369 S r1 = replaceFirst(s, from, into);
3370 assert(cmp(r1, "This is a silly foo list") == 0);
3372 S r11 = replaceFirst(s2, from2, into2);
3373 assert(cmp(r11, "Thüs is a sälly foo list") == 0,
3374 to!string(r11) ~ " : " ~ S.stringof ~ " " ~ T.stringof);
3376 S r2 = replaceFirst(r1, from, into);
3377 assert(cmp(r2, "This is a silly silly list") == 0);
3379 S r3 = replaceFirst(s, to!T(""), into);
3380 assert(cmp(r3, "This is a foo foo list") == 0);
3382 assert(replaceFirst(r3, to!T("won't find"), to!T("whatever")) is r3);
3387 // https://issues.dlang.org/show_bug.cgi?id=8187
3388 @safe unittest
3390 auto res = ["a", "a"];
3391 assert(replace(res, "a", "b") == ["b", "b"]);
3392 assert(replaceFirst(res, "a", "b") == ["b", "a"]);
3396 Replaces the last occurrence of `from` with `to` in `subject`.
3398 Params:
3399 subject = the array to scan
3400 from = the item to replace
3401 to = the item to replace `from` with
3403 Returns:
3404 A new array without changing the contents of `subject`, or the original
3405 array if no match is found.
3407 E[] replaceLast(E, R1, R2)(E[] subject, R1 from , R2 to)
3408 if (isDynamicArray!(E[]) &&
3409 isForwardRange!R1 && is(typeof(appender!(E[])().put(from[0 .. 1]))) &&
3410 isForwardRange!R2 && is(typeof(appender!(E[])().put(to[0 .. 1]))))
3412 import std.range : retro;
3413 if (from.empty) return subject;
3414 static if (isSomeString!(E[]))
3416 import std.string : lastIndexOf;
3417 auto idx = subject.lastIndexOf(from);
3419 else
3421 import std.algorithm.searching : countUntil;
3422 auto idx = retro(subject).countUntil(retro(from));
3425 if (idx == -1)
3426 return subject;
3428 static if (isSomeString!(E[]) && isSomeString!R1)
3430 import std.utf : codeLength;
3431 auto fromLength = codeLength!(Unqual!E, R1)(from);
3433 else
3434 auto fromLength = from.length;
3436 auto app = appender!(E[])();
3437 static if (isSomeString!(E[]))
3438 app.put(subject[0 .. idx]);
3439 else
3440 app.put(subject[0 .. $ - idx - fromLength]);
3442 app.put(to);
3444 static if (isSomeString!(E[]))
3445 app.put(subject[idx+fromLength .. $]);
3446 else
3447 app.put(subject[$ - idx .. $]);
3449 return app.data;
3453 @safe unittest
3455 auto a = [1, 2, 2, 3, 4, 5];
3456 auto b = a.replaceLast([2], [1337]);
3457 assert(b == [1, 2, 1337, 3, 4, 5]);
3459 auto s = "This is a foo foo list";
3460 auto r = s.replaceLast("foo", "silly");
3461 assert(r == "This is a foo silly list", r);
3464 @safe unittest
3466 import std.algorithm.comparison : cmp;
3467 import std.conv : to;
3469 static foreach (S; AliasSeq!(string, wstring, dstring, char[], wchar[], dchar[],
3470 const(char[]), immutable(char[])))
3472 static foreach (T; AliasSeq!(string, wstring, dstring, char[], wchar[], dchar[],
3473 const(char[]), immutable(char[])))
3475 auto s = to!S("This is a foo foo list");
3476 auto s2 = to!S("Thüs is a ßöö ßöö list");
3477 auto from = to!T("foo");
3478 auto from2 = to!T("ßöö");
3479 auto into = to!T("silly");
3480 auto into2 = to!T("sälly");
3482 S r1 = replaceLast(s, from, into);
3483 assert(cmp(r1, "This is a foo silly list") == 0, to!string(r1));
3485 S r11 = replaceLast(s2, from2, into2);
3486 assert(cmp(r11, "Thüs is a ßöö sälly list") == 0,
3487 to!string(r11) ~ " : " ~ S.stringof ~ " " ~ T.stringof);
3489 S r2 = replaceLast(r1, from, into);
3490 assert(cmp(r2, "This is a silly silly list") == 0);
3492 S r3 = replaceLast(s, to!T(""), into);
3493 assert(cmp(r3, "This is a foo foo list") == 0);
3495 assert(replaceLast(r3, to!T("won't find"), to!T("whatever")) is r3);
3501 Creates a new array such that the items in `slice` are replaced with the
3502 items in `replacement`. `slice` and `replacement` do not need to be the
3503 same length. The result will grow or shrink based on the items given.
3505 Params:
3506 s = the base of the new array
3507 slice = the slice of `s` to be replaced
3508 replacement = the items to replace `slice` with
3510 Returns:
3511 A new array that is `s` with `slice` replaced by
3512 `replacement[]`.
3514 See_Also:
3515 $(REF substitute, std,algorithm,iteration) for a lazy replace.
3517 inout(T)[] replaceSlice(T)(inout(T)[] s, in T[] slice, in T[] replacement)
3520 // Verify that slice[] really is a slice of s[]
3521 assert(overlap(s, slice) is slice, "slice[] is not a subslice of s[]");
3525 auto result = new T[s.length - slice.length + replacement.length];
3526 immutable so = &slice[0] - &s[0];
3527 result[0 .. so] = s[0 .. so];
3528 result[so .. so + replacement.length] = replacement[];
3529 result[so + replacement.length .. result.length] =
3530 s[so + slice.length .. s.length];
3532 return () @trusted inout {
3533 return cast(inout(T)[]) result;
3534 }();
3538 @safe unittest
3540 auto a = [1, 2, 3, 4, 5];
3541 auto b = replaceSlice(a, a[1 .. 4], [0, 0, 0]);
3543 assert(b == [1, 0, 0, 0, 5]);
3546 @safe unittest
3548 import std.algorithm.comparison : cmp;
3550 string s = "hello";
3551 string slice = s[2 .. 4];
3553 auto r = replaceSlice(s, slice, "bar");
3554 int i;
3555 i = cmp(r, "hebaro");
3556 assert(i == 0);
3560 Implements an output range that appends data to an array. This is
3561 recommended over $(D array ~= data) when appending many elements because it is more
3562 efficient. `Appender` maintains its own array metadata locally, so it can avoid
3563 the $(DDSUBLINK spec/arrays, capacity-reserve, performance hit of looking up slice `capacity`)
3564 for each append.
3566 Params:
3567 A = the array type to simulate.
3569 See_Also: $(LREF appender)
3571 struct Appender(A)
3572 if (isDynamicArray!A)
3574 import core.memory : GC;
3576 private alias T = ElementEncodingType!A;
3578 private struct Data
3580 size_t capacity;
3581 Unqual!T[] arr;
3582 bool tryExtendBlock = false;
3585 private Data* _data;
3588 * Constructs an `Appender` with a given array. Note that this does not copy the
3589 * data. If the array has a larger capacity as determined by `arr.capacity`,
3590 * it will be used by the appender. After initializing an appender on an array,
3591 * appending to the original array will reallocate.
3593 this(A arr) @trusted
3595 // initialize to a given array.
3596 _data = new Data;
3597 _data.arr = cast(Unqual!T[]) arr; //trusted
3599 if (__ctfe)
3600 return;
3602 // We want to use up as much of the block the array is in as possible.
3603 // if we consume all the block that we can, then array appending is
3604 // safe WRT built-in append, and we can use the entire block.
3605 // We only do this for mutable types that can be extended.
3606 static if (isMutable!T && is(typeof(arr.length = size_t.max)))
3608 immutable cap = arr.capacity; //trusted
3609 // Replace with "GC.setAttr( Not Appendable )" once pure (and fixed)
3610 if (cap > arr.length)
3611 arr.length = cap;
3613 _data.capacity = arr.length;
3617 * Reserve at least newCapacity elements for appending. Note that more elements
3618 * may be reserved than requested. If `newCapacity <= capacity`, then nothing is
3619 * done.
3621 * Params:
3622 * newCapacity = the capacity the `Appender` should have
3624 void reserve(size_t newCapacity)
3626 if (_data)
3628 if (newCapacity > _data.capacity)
3629 ensureAddable(newCapacity - _data.arr.length);
3631 else
3633 ensureAddable(newCapacity);
3638 * Returns: the capacity of the array (the maximum number of elements the
3639 * managed array can accommodate before triggering a reallocation). If any
3640 * appending will reallocate, `0` will be returned.
3642 @property size_t capacity() const
3644 return _data ? _data.capacity : 0;
3647 /// Returns: The number of elements appended.
3648 @property size_t length() const => _data ? _data.arr.length : 0;
3651 * Use opSlice() from now on.
3652 * Returns: The managed array.
3654 @property inout(T)[] data() inout
3656 return this[];
3660 * Returns: The managed array.
3662 @property inout(T)[] opSlice() inout @trusted
3664 /* @trusted operation:
3665 * casting Unqual!T[] to inout(T)[]
3667 return cast(typeof(return))(_data ? _data.arr : null);
3670 // ensure we can add nelems elements, resizing as necessary
3671 private void ensureAddable(size_t nelems)
3673 if (!_data)
3674 _data = new Data;
3675 immutable len = _data.arr.length;
3676 immutable reqlen = len + nelems;
3678 if (_data.capacity >= reqlen)
3679 return;
3681 // need to increase capacity
3682 if (__ctfe)
3684 static if (__traits(compiles, new Unqual!T[1]))
3686 _data.arr.length = reqlen;
3688 else
3690 // avoid restriction of @disable this()
3691 _data.arr = _data.arr[0 .. _data.capacity];
3692 foreach (i; _data.capacity .. reqlen)
3693 _data.arr ~= Unqual!T.init;
3695 _data.arr = _data.arr[0 .. len];
3696 _data.capacity = reqlen;
3698 else
3700 import core.stdc.string : memcpy, memset;
3701 // Time to reallocate.
3702 // We need to almost duplicate what's in druntime, except we
3703 // have better access to the capacity field.
3704 auto newlen = appenderNewCapacity!(T.sizeof)(_data.capacity, reqlen);
3705 // first, try extending the current block
3706 if (_data.tryExtendBlock)
3708 immutable u = (() @trusted => GC.extend(_data.arr.ptr, nelems * T.sizeof, (newlen - len) * T.sizeof))();
3709 if (u)
3711 // extend worked, update the capacity
3712 // if the type has indirections, we need to zero any new
3713 // data that we requested, as the existing data may point
3714 // at large unused blocks.
3715 static if (hasIndirections!T)
3717 immutable addedSize = u - (_data.capacity * T.sizeof);
3718 () @trusted { memset(_data.arr.ptr + _data.capacity, 0, addedSize); }();
3721 _data.capacity = u / T.sizeof;
3722 return;
3727 // didn't work, must reallocate
3728 import core.checkedint : mulu;
3729 bool overflow;
3730 const nbytes = mulu(newlen, T.sizeof, overflow);
3731 if (overflow) assert(false, "the reallocation would exceed the "
3732 ~ "available pointer range");
3734 auto bi = (() @trusted => GC.qalloc(nbytes, blockAttribute!T))();
3735 _data.capacity = bi.size / T.sizeof;
3736 if (len)
3737 () @trusted { memcpy(bi.base, _data.arr.ptr, len * T.sizeof); }();
3739 _data.arr = (() @trusted => (cast(Unqual!T*) bi.base)[0 .. len])();
3741 // we requested new bytes that are not in the existing
3742 // data. If T has pointers, then this new data could point at stale
3743 // objects from the last time this block was allocated. Zero that
3744 // new data out, it may point at large unused blocks!
3745 static if (hasIndirections!T)
3746 () @trusted {
3747 memset(bi.base + (len * T.sizeof), 0, (newlen - len) * T.sizeof);
3748 }();
3750 _data.tryExtendBlock = true;
3751 // leave the old data, for safety reasons
3755 private template canPutItem(U)
3757 enum bool canPutItem =
3758 is(Unqual!U : Unqual!T) ||
3759 isSomeChar!T && isSomeChar!U;
3761 private template canPutConstRange(Range)
3763 enum bool canPutConstRange =
3764 isInputRange!(Unqual!Range) &&
3765 !isInputRange!Range &&
3766 is(typeof(Appender.init.put(Range.init.front)));
3768 private template canPutRange(Range)
3770 enum bool canPutRange =
3771 isInputRange!Range &&
3772 is(typeof(Appender.init.put(Range.init.front)));
3776 * Appends `item` to the managed array. Performs encoding for
3777 * `char` types if `A` is a differently typed `char` array.
3779 * Params:
3780 * item = the single item to append
3782 void put(U)(U item)
3783 if (canPutItem!U)
3785 static if (isSomeChar!T && isSomeChar!U && T.sizeof < U.sizeof)
3787 /* may throwable operation:
3788 * - std.utf.encode
3790 // must do some transcoding around here
3791 import std.utf : encode;
3792 Unqual!T[T.sizeof == 1 ? 4 : 2] encoded;
3793 auto len = encode(encoded, item);
3794 put(encoded[0 .. len]);
3796 else
3798 import core.lifetime : emplace;
3800 ensureAddable(1);
3801 immutable len = _data.arr.length;
3803 auto bigData = (() @trusted => _data.arr.ptr[0 .. len + 1])();
3804 auto itemUnqual = (() @trusted => & cast() item)();
3805 emplace(&bigData[len], *itemUnqual);
3806 //We do this at the end, in case of exceptions
3807 _data.arr = bigData;
3811 // Const fixing hack.
3812 void put(Range)(Range items)
3813 if (canPutConstRange!Range)
3815 alias p = put!(Unqual!Range);
3816 p(items);
3820 * Appends an entire range to the managed array. Performs encoding for
3821 * `char` elements if `A` is a differently typed `char` array.
3823 * Params:
3824 * items = the range of items to append
3826 void put(Range)(Range items)
3827 if (canPutRange!Range)
3829 // note, we disable this branch for appending one type of char to
3830 // another because we can't trust the length portion.
3831 static if (!(isSomeChar!T && isSomeChar!(ElementType!Range) &&
3832 !is(immutable Range == immutable T[])) &&
3833 is(typeof(items.length) == size_t))
3835 // optimization -- if this type is something other than a string,
3836 // and we are adding exactly one element, call the version for one
3837 // element.
3838 static if (!isSomeChar!T)
3840 if (items.length == 1)
3842 put(items.front);
3843 return;
3847 // make sure we have enough space, then add the items
3848 auto bigDataFun(size_t extra)
3850 ensureAddable(extra);
3851 return (() @trusted => _data.arr.ptr[0 .. _data.arr.length + extra])();
3853 auto bigData = bigDataFun(items.length);
3855 immutable len = _data.arr.length;
3856 immutable newlen = bigData.length;
3858 alias UT = Unqual!T;
3860 static if (is(typeof(_data.arr[] = items[])) &&
3861 !hasElaborateAssign!UT && isAssignable!(UT, ElementEncodingType!Range))
3863 bigData[len .. newlen] = items[];
3865 else
3867 import core.internal.lifetime : emplaceRef;
3868 foreach (ref it ; bigData[len .. newlen])
3870 emplaceRef!T(it, items.front);
3871 items.popFront();
3875 //We do this at the end, in case of exceptions
3876 _data.arr = bigData;
3878 else static if (isSomeChar!T && isSomeChar!(ElementType!Range) &&
3879 !is(immutable T == immutable ElementType!Range))
3881 // need to decode and encode
3882 import std.utf : decodeFront;
3883 while (!items.empty)
3885 auto c = items.decodeFront;
3886 put(c);
3889 else
3891 //pragma(msg, Range.stringof);
3892 // Generic input range
3893 for (; !items.empty; items.popFront())
3895 put(items.front);
3901 * Appends to the managed array.
3903 * See_Also: $(LREF Appender.put)
3905 alias opOpAssign(string op : "~") = put;
3907 // only allow overwriting data on non-immutable and non-const data
3908 static if (isMutable!T)
3911 * Clears the managed array. This allows the elements of the array to be reused
3912 * for appending.
3914 * Note: clear is disabled for immutable or const element types, due to the
3915 * possibility that `Appender` might overwrite immutable data.
3917 void clear() @trusted pure nothrow
3919 if (_data)
3921 _data.arr = _data.arr.ptr[0 .. 0];
3926 * Shrinks the managed array to the given length.
3928 * Throws: `Exception` if newlength is greater than the current array length.
3929 * Note: shrinkTo is disabled for immutable or const element types.
3931 void shrinkTo(size_t newlength) @trusted pure
3933 import std.exception : enforce;
3934 if (_data)
3936 enforce(newlength <= _data.arr.length, "Attempting to shrink Appender with newlength > length");
3937 _data.arr = _data.arr.ptr[0 .. newlength];
3939 else
3940 enforce(newlength == 0, "Attempting to shrink empty Appender with non-zero newlength");
3945 * Gives a string in the form of `Appender!(A)(data)`.
3947 * Params:
3948 * w = A `char` accepting
3949 * $(REF_ALTTEXT output range, isOutputRange, std, range, primitives).
3950 * fmt = A $(REF FormatSpec, std, format) which controls how the array
3951 * is formatted.
3952 * Returns:
3953 * A `string` if `writer` is not set; `void` otherwise.
3955 string toString()() const
3957 import std.format.spec : singleSpec;
3959 auto app = appender!string();
3960 auto spec = singleSpec("%s");
3961 immutable len = _data ? _data.arr.length : 0;
3962 // different reserve lengths because each element in a
3963 // non-string-like array uses two extra characters for `, `.
3964 static if (isSomeString!A)
3966 app.reserve(len + 25);
3968 else
3970 // Multiplying by three is a very conservative estimate of
3971 // length, as it assumes each element is only one char
3972 app.reserve((len * 3) + 25);
3974 toString(app, spec);
3975 return app.data;
3978 import std.format.spec : FormatSpec;
3980 /// ditto
3981 template toString(Writer)
3982 if (isOutputRange!(Writer, char))
3984 void toString(ref Writer w, scope const ref FormatSpec!char fmt) const
3986 import std.format.write : formatValue;
3987 import std.range.primitives : put;
3988 put(w, Unqual!(typeof(this)).stringof);
3989 put(w, '(');
3990 formatValue(w, data, fmt);
3991 put(w, ')');
3997 @safe pure nothrow unittest
3999 auto app = appender!string();
4000 string b = "abcdefg";
4001 foreach (char c; b)
4002 app.put(c);
4003 assert(app[] == "abcdefg");
4005 int[] a = [ 1, 2 ];
4006 auto app2 = appender(a);
4007 app2.put(3);
4008 assert(app2.length == 3);
4009 app2.put([ 4, 5, 6 ]);
4010 assert(app2[] == [ 1, 2, 3, 4, 5, 6 ]);
4013 @safe pure unittest
4015 import std.format : format;
4016 import std.format.spec : singleSpec;
4018 auto app = appender!(int[])();
4019 app.put(1);
4020 app.put(2);
4021 app.put(3);
4022 assert("%s".format(app) == "Appender!(int[])(%s)".format([1,2,3]));
4024 auto app2 = appender!string();
4025 auto spec = singleSpec("%s");
4026 app.toString(app2, spec);
4027 assert(app2[] == "Appender!(int[])([1, 2, 3])");
4029 auto app3 = appender!string();
4030 spec = singleSpec("%(%04d, %)");
4031 app.toString(app3, spec);
4032 assert(app3[] == "Appender!(int[])(0001, 0002, 0003)");
4035 // https://issues.dlang.org/show_bug.cgi?id=17251
4036 @safe pure nothrow unittest
4038 static struct R
4040 int front() const { return 0; }
4041 bool empty() const { return true; }
4042 void popFront() {}
4045 auto app = appender!(R[]);
4046 const(R)[1] r;
4047 app.put(r[0]);
4048 app.put(r[]);
4051 // https://issues.dlang.org/show_bug.cgi?id=13300
4052 @safe pure nothrow unittest
4054 static test(bool isPurePostblit)()
4056 static if (!isPurePostblit)
4057 static int i;
4059 struct Simple
4061 @disable this(); // Without this, it works.
4062 static if (!isPurePostblit)
4063 this(this) { i++; }
4064 else
4065 pure this(this) { }
4067 private:
4068 this(int tmp) { }
4071 struct Range
4073 @property Simple front() { return Simple(0); }
4074 void popFront() { count++; }
4075 @property empty() { return count < 3; }
4076 size_t count;
4079 Range r;
4080 auto a = r.array();
4083 static assert(__traits(compiles, () pure { test!true(); }));
4084 static assert(!__traits(compiles, () pure { test!false(); }));
4087 // https://issues.dlang.org/show_bug.cgi?id=19572
4088 @safe pure nothrow unittest
4090 static struct Struct
4092 int value;
4094 int fun() const { return 23; }
4096 alias fun this;
4099 Appender!(Struct[]) appender;
4101 appender.put(const(Struct)(42));
4103 auto result = appender[][0];
4105 assert(result.value != 23);
4108 @safe pure unittest
4110 import std.conv : to;
4111 import std.utf : byCodeUnit;
4112 auto str = "ウェブサイト";
4113 auto wstr = appender!wstring();
4114 put(wstr, str.byCodeUnit);
4115 assert(wstr.data == str.to!wstring);
4118 // https://issues.dlang.org/show_bug.cgi?id=21256
4119 @safe pure unittest
4121 Appender!string app1;
4122 app1.toString();
4124 Appender!(int[]) app2;
4125 app2.toString();
4128 // https://issues.dlang.org/show_bug.cgi?id=24856
4129 @system unittest
4131 import core.memory : GC;
4132 import std.stdio : writeln;
4133 import std.algorithm.searching : canFind;
4134 GC.disable();
4135 scope(exit) GC.enable();
4136 void*[] freeme;
4137 // generate some poison blocks to allocate from.
4138 auto poison = cast(void*) 0xdeadbeef;
4139 foreach (i; 0 .. 10)
4141 auto blk = new void*[7];
4142 blk[] = poison;
4143 freeme ~= blk.ptr;
4146 foreach (p; freeme)
4147 GC.free(p);
4149 int tests = 0;
4150 foreach (i; 0 .. 10)
4152 Appender!(void*[]) app;
4153 app.put(null);
4154 // if not a realloc of one of the deadbeef pointers, continue
4155 if (!freeme.canFind(app.data.ptr))
4156 continue;
4157 ++tests;
4158 assert(!app.data.ptr[0 .. app.capacity].canFind(poison), "Appender not zeroing data!");
4160 // just notify in the log whether this test actually could be done.
4161 if (tests == 0)
4162 writeln("WARNING: test of Appender zeroing did not occur");
4165 //Calculates an efficient growth scheme based on the old capacity
4166 //of data, and the minimum requested capacity.
4167 //arg curLen: The current length
4168 //arg reqLen: The length as requested by the user
4169 //ret sugLen: A suggested growth.
4170 private size_t appenderNewCapacity(size_t TSizeOf)(size_t curLen, size_t reqLen)
4172 import core.bitop : bsr;
4173 import std.algorithm.comparison : max;
4174 if (curLen == 0)
4175 return max(reqLen,8);
4176 ulong mult = 100 + (1000UL) / (bsr(curLen * TSizeOf) + 1);
4177 // limit to doubling the length, we don't want to grow too much
4178 if (mult > 200)
4179 mult = 200;
4180 auto sugLen = cast(size_t)((curLen * mult + 99) / 100);
4181 return max(reqLen, sugLen);
4185 * A version of $(LREF Appender) that can update an array in-place.
4186 * It forwards all calls to an underlying appender implementation.
4187 * Any calls made to the appender also update the pointer to the
4188 * original array passed in.
4190 * Tip: Use the `arrayPtr` overload of $(LREF appender) for construction with type-inference.
4192 * Params:
4193 * A = The array type to simulate
4195 struct RefAppender(A)
4196 if (isDynamicArray!A)
4198 private alias T = ElementEncodingType!A;
4200 private
4202 Appender!A impl;
4203 A* arr;
4207 * Constructs a `RefAppender` with a given array reference. This does not copy the
4208 * data. If the array has a larger capacity as determined by `arr.capacity`, it
4209 * will be used by the appender.
4211 * Note: Do not use built-in appending (i.e. `~=`) on the original array
4212 * until you are done with the appender, because subsequent calls to the appender
4213 * will reallocate the array data without those appends.
4215 * Params:
4216 * arr = Pointer to an array. Must not be _null.
4218 this(A* arr)
4220 impl = Appender!A(*arr);
4221 this.arr = arr;
4224 /** Wraps remaining `Appender` methods such as $(LREF put).
4225 * Params:
4226 * fn = Method name to call.
4227 * args = Arguments to pass to the method.
4229 void opDispatch(string fn, Args...)(Args args)
4230 if (__traits(compiles, (Appender!A a) => mixin("a." ~ fn ~ "(args)")))
4232 // we do it this way because we can't cache a void return
4233 scope(exit) *this.arr = impl[];
4234 mixin("return impl." ~ fn ~ "(args);");
4238 * Appends `rhs` to the managed array.
4239 * Params:
4240 * rhs = Element or range.
4242 void opOpAssign(string op : "~", U)(U rhs)
4243 if (__traits(compiles, (Appender!A a){ a.put(rhs); }))
4245 scope(exit) *this.arr = impl[];
4246 impl.put(rhs);
4250 * Returns the capacity of the array (the maximum number of elements the
4251 * managed array can accommodate before triggering a reallocation). If any
4252 * appending will reallocate, `capacity` returns `0`.
4254 @property size_t capacity() const
4256 return impl.capacity;
4259 /// Returns: The number of elements appended.
4260 @property size_t length() const => impl.length;
4262 /* Use opSlice() instead.
4263 * Returns: the managed array.
4265 @property inout(T)[] data() inout
4267 return impl[];
4271 * Returns: the managed array.
4273 @property inout(ElementEncodingType!A)[] opSlice() inout
4275 return impl[];
4280 @safe pure nothrow
4281 unittest
4283 int[] a = [1, 2];
4284 auto app2 = appender(&a);
4285 assert(app2[] == [1, 2]);
4286 assert(a == [1, 2]);
4287 app2 ~= 3;
4288 assert(app2.length == 3);
4289 app2 ~= [4, 5, 6];
4290 assert(app2[] == [1, 2, 3, 4, 5, 6]);
4291 assert(a == [1, 2, 3, 4, 5, 6]);
4293 app2.reserve(5);
4294 assert(app2.capacity >= 5);
4298 Convenience function that returns an $(LREF Appender) instance,
4299 optionally initialized with `array`.
4301 Appender!A appender(A)()
4302 if (isDynamicArray!A)
4304 return Appender!A(null);
4306 /// ditto
4307 Appender!(E[]) appender(A : E[], E)(auto ref A array)
4309 static assert(!isStaticArray!A || __traits(isRef, array),
4310 "Cannot create Appender from an rvalue static array");
4312 return Appender!(E[])(array);
4315 @safe pure nothrow unittest
4317 auto app = appender!(char[])();
4318 string b = "abcdefg";
4319 foreach (char c; b) app.put(c);
4320 assert(app[] == "abcdefg");
4323 @safe pure nothrow unittest
4325 auto app = appender!(char[])();
4326 string b = "abcdefg";
4327 foreach (char c; b) app ~= c;
4328 assert(app[] == "abcdefg");
4331 @safe pure nothrow unittest
4333 int[] a = [ 1, 2 ];
4334 auto app2 = appender(a);
4335 assert(app2[] == [ 1, 2 ]);
4336 app2.put(3);
4337 app2.put([ 4, 5, 6 ][]);
4338 assert(app2[] == [ 1, 2, 3, 4, 5, 6 ]);
4339 app2.put([ 7 ]);
4340 assert(app2[] == [ 1, 2, 3, 4, 5, 6, 7 ]);
4343 @safe pure nothrow unittest
4345 auto app4 = appender([]);
4346 try // shrinkTo may throw
4348 app4.shrinkTo(0);
4350 catch (Exception) assert(0);
4353 // https://issues.dlang.org/show_bug.cgi?id=5663
4354 // https://issues.dlang.org/show_bug.cgi?id=9725
4355 @safe pure nothrow unittest
4357 import std.exception : assertNotThrown;
4359 static foreach (S; AliasSeq!(char[], const(char)[], string))
4362 Appender!S app5663i;
4363 assertNotThrown(app5663i.put("\xE3"));
4364 assert(app5663i[] == "\xE3");
4366 Appender!S app5663c;
4367 assertNotThrown(app5663c.put(cast(const(char)[])"\xE3"));
4368 assert(app5663c[] == "\xE3");
4370 Appender!S app5663m;
4371 assertNotThrown(app5663m.put("\xE3".dup));
4372 assert(app5663m[] == "\xE3");
4374 // ditto for ~=
4376 Appender!S app5663i;
4377 assertNotThrown(app5663i ~= "\xE3");
4378 assert(app5663i[] == "\xE3");
4380 Appender!S app5663c;
4381 assertNotThrown(app5663c ~= cast(const(char)[])"\xE3");
4382 assert(app5663c[] == "\xE3");
4384 Appender!S app5663m;
4385 assertNotThrown(app5663m ~= "\xE3".dup);
4386 assert(app5663m[] == "\xE3");
4391 // https://issues.dlang.org/show_bug.cgi?id=10122
4392 @safe pure nothrow unittest
4394 import std.exception : assertCTFEable;
4396 static struct S10122
4398 int val;
4400 @disable this();
4401 this(int v) @safe pure nothrow { val = v; }
4403 assertCTFEable!(
4405 auto w = appender!(S10122[])();
4406 w.put(S10122(1));
4407 assert(w[].length == 1 && w[][0].val == 1);
4411 @safe pure nothrow unittest
4413 import std.exception : assertThrown;
4415 int[] a = [ 1, 2 ];
4416 auto app2 = appender(a);
4417 assert(app2[] == [ 1, 2 ]);
4418 app2 ~= 3;
4419 app2 ~= [ 4, 5, 6 ][];
4420 assert(app2[] == [ 1, 2, 3, 4, 5, 6 ]);
4421 app2 ~= [ 7 ];
4422 assert(app2[] == [ 1, 2, 3, 4, 5, 6, 7 ]);
4424 app2.reserve(5);
4425 assert(app2.capacity >= 5);
4427 try // shrinkTo may throw
4429 app2.shrinkTo(3);
4431 catch (Exception) assert(0);
4432 assert(app2[] == [ 1, 2, 3 ]);
4433 assertThrown(app2.shrinkTo(5));
4435 const app3 = app2;
4436 assert(app3.capacity >= 3);
4437 assert(app3[] == [1, 2, 3]);
4441 @safe pure nothrow
4442 unittest
4444 auto w = appender!string;
4445 // pre-allocate space for at least 10 elements (this avoids costly reallocations)
4446 w.reserve(10);
4447 assert(w.capacity >= 10);
4449 w.put('a'); // single elements
4450 w.put("bc"); // multiple elements
4452 // use the append syntax
4453 w ~= 'd';
4454 w ~= "ef";
4456 assert(w[] == "abcdef");
4459 @safe pure nothrow unittest
4461 auto w = appender!string();
4462 w.reserve(4);
4463 cast(void) w.capacity;
4464 cast(void) w[];
4467 wchar wc = 'a';
4468 dchar dc = 'a';
4469 w.put(wc); // decoding may throw
4470 w.put(dc); // decoding may throw
4472 catch (Exception) assert(0);
4475 @safe pure nothrow unittest
4477 auto w = appender!(int[])();
4478 w.reserve(4);
4479 cast(void) w.capacity;
4480 cast(void) w[];
4481 w.put(10);
4482 w.put([10]);
4483 w.clear();
4486 w.shrinkTo(0);
4488 catch (Exception) assert(0);
4490 struct N
4492 int payload;
4493 alias payload this;
4495 w.put(N(1));
4496 w.put([N(2)]);
4498 struct S(T)
4500 @property bool empty() { return true; }
4501 @property T front() { return T.init; }
4502 void popFront() {}
4504 S!int r;
4505 w.put(r);
4508 // https://issues.dlang.org/show_bug.cgi?id=10690
4509 @safe pure nothrow unittest
4511 import std.algorithm.iteration : filter;
4512 import std.typecons : tuple;
4513 [tuple(1)].filter!(t => true).array; // No error
4514 [tuple("A")].filter!(t => true).array; // error
4517 @safe pure nothrow unittest
4519 import std.range;
4520 //Coverage for put(Range)
4521 struct S1
4524 struct S2
4526 void opAssign(S2){}
4528 auto a1 = Appender!(S1[])();
4529 auto a2 = Appender!(S2[])();
4530 auto au1 = Appender!(const(S1)[])();
4531 a1.put(S1().repeat().take(10));
4532 a2.put(S2().repeat().take(10));
4533 auto sc1 = const(S1)();
4534 au1.put(sc1.repeat().take(10));
4537 @system pure unittest
4539 import std.range;
4540 struct S2
4542 void opAssign(S2){}
4544 auto au2 = Appender!(const(S2)[])();
4545 auto sc2 = const(S2)();
4546 au2.put(sc2.repeat().take(10));
4549 @system pure nothrow unittest
4551 struct S
4553 int* p;
4556 auto a0 = Appender!(S[])();
4557 auto a1 = Appender!(const(S)[])();
4558 auto a2 = Appender!(immutable(S)[])();
4559 auto s0 = S(null);
4560 auto s1 = const(S)(null);
4561 auto s2 = immutable(S)(null);
4562 a1.put(s0);
4563 a1.put(s1);
4564 a1.put(s2);
4565 a1.put([s0]);
4566 a1.put([s1]);
4567 a1.put([s2]);
4568 a0.put(s0);
4569 static assert(!is(typeof(a0.put(a1))));
4570 static assert(!is(typeof(a0.put(a2))));
4571 a0.put([s0]);
4572 static assert(!is(typeof(a0.put([a1]))));
4573 static assert(!is(typeof(a0.put([a2]))));
4574 static assert(!is(typeof(a2.put(a0))));
4575 static assert(!is(typeof(a2.put(a1))));
4576 a2.put(s2);
4577 static assert(!is(typeof(a2.put([a0]))));
4578 static assert(!is(typeof(a2.put([a1]))));
4579 a2.put([s2]);
4582 // https://issues.dlang.org/show_bug.cgi?id=9528
4583 @safe pure nothrow unittest
4585 const(E)[] fastCopy(E)(E[] src) {
4586 auto app = appender!(const(E)[])();
4587 foreach (i, e; src)
4588 app.put(e);
4589 return app[];
4592 static class C {}
4593 static struct S { const(C) c; }
4594 S[] s = [ S(new C) ];
4596 auto t = fastCopy(s); // Does not compile
4597 assert(t.length == 1);
4600 // https://issues.dlang.org/show_bug.cgi?id=10753
4601 @safe pure unittest
4603 import std.algorithm.iteration : map;
4604 struct Foo {
4605 immutable dchar d;
4607 struct Bar {
4608 immutable int x;
4610 "12".map!Foo.array;
4611 [1, 2].map!Bar.array;
4614 @safe pure nothrow unittest
4616 import std.algorithm.comparison : equal;
4618 //New appender signature tests
4619 alias mutARR = int[];
4620 alias conARR = const(int)[];
4621 alias immARR = immutable(int)[];
4623 mutARR mut;
4624 conARR con;
4625 immARR imm;
4627 auto app1 = Appender!mutARR(mut); //Always worked. Should work. Should not create a warning.
4628 app1.put(7);
4629 assert(equal(app1[], [7]));
4630 static assert(!is(typeof(Appender!mutARR(con)))); //Never worked. Should not work.
4631 static assert(!is(typeof(Appender!mutARR(imm)))); //Never worked. Should not work.
4633 auto app2 = Appender!conARR(mut); //Always worked. Should work. Should not create a warning.
4634 app2.put(7);
4635 assert(equal(app2[], [7]));
4636 auto app3 = Appender!conARR(con); //Didn't work. Now works. Should not create a warning.
4637 app3.put(7);
4638 assert(equal(app3[], [7]));
4639 auto app4 = Appender!conARR(imm); //Didn't work. Now works. Should not create a warning.
4640 app4.put(7);
4641 assert(equal(app4[], [7]));
4643 //{auto app = Appender!immARR(mut);} //Worked. Will cease to work. Creates warning.
4644 //static assert(!is(typeof(Appender!immARR(mut)))); //Worked. Will cease to work. Uncomment me after full deprecation.
4645 static assert(!is(typeof(Appender!immARR(con)))); //Never worked. Should not work.
4646 auto app5 = Appender!immARR(imm); //Didn't work. Now works. Should not create a warning.
4647 app5.put(7);
4648 assert(equal(app5[], [7]));
4650 //Deprecated. Please uncomment and make sure this doesn't work:
4651 //char[] cc;
4652 //static assert(!is(typeof(Appender!string(cc))));
4654 //This should always work:
4655 auto app6 = appender!string(null);
4656 assert(app6[] == null);
4657 auto app7 = appender!(const(char)[])(null);
4658 assert(app7[] == null);
4659 auto app8 = appender!(char[])(null);
4660 assert(app8[] == null);
4663 @safe pure nothrow unittest //Test large allocations (for GC.extend)
4665 import std.algorithm.comparison : equal;
4666 import std.range;
4667 Appender!(char[]) app;
4668 app.reserve(1); //cover reserve on non-initialized
4669 foreach (_; 0 .. 100_000)
4670 app.put('a');
4671 assert(equal(app[], 'a'.repeat(100_000)));
4674 @safe pure nothrow unittest
4676 auto reference = new ubyte[](2048 + 1); //a number big enough to have a full page (EG: the GC extends)
4677 auto arr = reference.dup;
4678 auto app = appender(arr[0 .. 0]);
4679 app.reserve(1); //This should not trigger a call to extend
4680 app.put(ubyte(1)); //Don't clobber arr
4681 assert(reference[] == arr[]);
4684 @safe pure nothrow unittest // clear method is supported only for mutable element types
4686 Appender!string app;
4687 app.put("foo");
4688 static assert(!__traits(compiles, app.clear()));
4689 assert(app[] == "foo");
4692 @safe pure nothrow unittest
4694 static struct D//dynamic
4696 int[] i;
4697 alias i this;
4699 static struct S//static
4701 int[5] i;
4702 alias i this;
4704 static assert(!is(Appender!(char[5])));
4705 static assert(!is(Appender!D));
4706 static assert(!is(Appender!S));
4708 enum int[5] a = [];
4709 int[5] b;
4710 D d;
4711 S s;
4712 int[5] foo(){return a;}
4714 static assert(!is(typeof(appender(a))));
4715 static assert( is(typeof(appender(b))));
4716 static assert( is(typeof(appender(d))));
4717 static assert( is(typeof(appender(s))));
4718 static assert(!is(typeof(appender(foo()))));
4721 @system unittest
4723 // https://issues.dlang.org/show_bug.cgi?id=13077
4724 static class A {}
4726 // reduced case
4727 auto w = appender!(shared(A)[])();
4728 w.put(new shared A());
4730 // original case
4731 import std.range;
4732 InputRange!(shared A) foo()
4734 return [new shared A].inputRangeObject;
4736 auto res = foo.array;
4737 assert(res.length == 1);
4741 Convenience function that returns a $(LREF RefAppender) instance initialized
4742 with `arrayPtr`. Don't use null for the array pointer, use the other
4743 version of `appender` instead.
4745 RefAppender!(E[]) appender(P : E[]*, E)(P arrayPtr)
4747 return RefAppender!(E[])(arrayPtr);
4751 @safe pure nothrow
4752 unittest
4754 int[] a = [1, 2];
4755 auto app2 = appender(&a);
4756 assert(app2[] == [1, 2]);
4757 assert(a == [1, 2]);
4758 app2 ~= 3;
4759 app2 ~= [4, 5, 6];
4760 assert(app2[] == [1, 2, 3, 4, 5, 6]);
4761 assert(a == [1, 2, 3, 4, 5, 6]);
4763 app2.reserve(5);
4764 assert(app2.capacity >= 5);
4767 @safe pure nothrow unittest
4769 auto arr = new char[0];
4770 auto app = appender(&arr);
4771 string b = "abcdefg";
4772 foreach (char c; b) app.put(c);
4773 assert(app[] == "abcdefg");
4774 assert(arr == "abcdefg");
4777 @safe pure nothrow unittest
4779 auto arr = new char[0];
4780 auto app = appender(&arr);
4781 string b = "abcdefg";
4782 foreach (char c; b) app ~= c;
4783 assert(app[] == "abcdefg");
4784 assert(arr == "abcdefg");
4787 @safe pure nothrow unittest
4789 int[] a = [ 1, 2 ];
4790 auto app2 = appender(&a);
4791 assert(app2[] == [ 1, 2 ]);
4792 assert(a == [ 1, 2 ]);
4793 app2.put(3);
4794 app2.put([ 4, 5, 6 ][]);
4795 assert(app2[] == [ 1, 2, 3, 4, 5, 6 ]);
4796 assert(a == [ 1, 2, 3, 4, 5, 6 ]);
4799 @safe pure nothrow unittest
4801 import std.exception : assertThrown;
4803 int[] a = [ 1, 2 ];
4804 auto app2 = appender(&a);
4805 assert(app2[] == [ 1, 2 ]);
4806 assert(a == [ 1, 2 ]);
4807 app2 ~= 3;
4808 app2 ~= [ 4, 5, 6 ][];
4809 assert(app2[] == [ 1, 2, 3, 4, 5, 6 ]);
4810 assert(a == [ 1, 2, 3, 4, 5, 6 ]);
4812 app2.reserve(5);
4813 assert(app2.capacity >= 5);
4815 try // shrinkTo may throw
4817 app2.shrinkTo(3);
4819 catch (Exception) assert(0);
4820 assert(app2[] == [ 1, 2, 3 ]);
4821 assertThrown(app2.shrinkTo(5));
4823 const app3 = app2;
4824 assert(app3.capacity >= 3);
4825 assert(app3[] == [1, 2, 3]);
4828 // https://issues.dlang.org/show_bug.cgi?id=14605
4829 @safe pure nothrow unittest
4831 static assert(isOutputRange!(Appender!(int[]), int));
4832 static assert(isOutputRange!(RefAppender!(int[]), int));
4835 @safe pure nothrow unittest
4837 Appender!(int[]) app;
4838 short[] range = [1, 2, 3];
4839 app.put(range);
4840 assert(app[] == [1, 2, 3]);
4843 @safe pure nothrow unittest
4845 string s = "hello".idup;
4846 char[] a = "hello".dup;
4847 auto appS = appender(s);
4848 auto appA = appender(a);
4849 put(appS, 'w');
4850 put(appA, 'w');
4851 s ~= 'a'; //Clobbers here?
4852 a ~= 'a'; //Clobbers here?
4853 assert(appS[] == "hellow");
4854 assert(appA[] == "hellow");
4858 Constructs a static array from a dynamic array whose length is known at compile-time.
4859 The element type can be inferred or specified explicitly:
4861 * $(D [1, 2].staticArray) returns `int[2]`
4862 * $(D [1, 2].staticArray!float) returns `float[2]`
4864 Note: `staticArray` returns by value, so expressions involving large arrays may be inefficient.
4866 Params:
4867 a = The input array.
4869 Returns: A static array constructed from `a`.
4871 pragma(inline, true) T[n] staticArray(T, size_t n)(auto ref T[n] a)
4873 return a;
4876 /// static array from array literal
4877 nothrow pure @safe @nogc unittest
4879 auto a = [0, 1].staticArray;
4880 static assert(is(typeof(a) == int[2]));
4881 assert(a == [0, 1]);
4884 /// ditto
4885 pragma(inline, true) U[n] staticArray(U, T, size_t n)(auto ref T[n] a)
4886 if (!is(T == U) && is(T : U))
4888 return a[].staticArray!(U[n]);
4891 /// static array from array with implicit casting of elements
4892 nothrow pure @safe @nogc unittest
4894 auto b = [0, 1].staticArray!long;
4895 static assert(is(typeof(b) == long[2]));
4896 assert(b == [0, 1]);
4899 nothrow pure @safe @nogc unittest
4901 int val = 3;
4902 static immutable gold = [1, 2, 3];
4903 [1, 2, val].staticArray.checkStaticArray!int([1, 2, 3]);
4905 @nogc void checkNogc()
4907 [1, 2, val].staticArray.checkStaticArray!int(gold);
4910 checkNogc();
4912 [1, 2, val].staticArray!double.checkStaticArray!double(gold);
4913 [1, 2, 3].staticArray!int.checkStaticArray!int(gold);
4915 [1, 2, 3].staticArray!(const(int)).checkStaticArray!(const(int))(gold);
4916 [1, 2, 3].staticArray!(const(double)).checkStaticArray!(const(double))(gold);
4918 const(int)[3] a2 = [1, 2, 3].staticArray;
4921 [cast(byte) 1, cast(byte) 129].staticArray.checkStaticArray!byte([1, -127]);
4925 Constructs a static array from a range.
4926 When `a.length` is not known at compile time, the number of elements must be
4927 given as a template argument (e.g. `myrange.staticArray!2`).
4928 Size and type can be combined, if the source range elements are implicitly
4929 convertible to the requested element type (eg: `2.iota.staticArray!(long[2])`).
4931 When the range `a` is known at compile time, it can be given as a
4932 template argument to avoid having to specify the number of elements
4933 (e.g.: `staticArray!(2.iota)` or `staticArray!(double, 2.iota)`).
4935 Params:
4936 a = The input range. If there are less elements than the specified length of the static array,
4937 the rest of it is default-initialized. If there are more than specified, the first elements
4938 up to the specified length are used.
4939 rangeLength = Output for the number of elements used from `a`. Optional.
4941 auto staticArray(size_t n, T)(scope T a)
4942 if (isInputRange!T)
4944 alias U = ElementType!T;
4945 return staticArray!(U[n], U, n)(a);
4948 /// ditto
4949 auto staticArray(size_t n, T)(scope T a, out size_t rangeLength)
4950 if (isInputRange!T)
4952 alias U = ElementType!T;
4953 return staticArray!(U[n], U, n)(a, rangeLength);
4956 /// ditto
4957 auto staticArray(Un : U[n], U, size_t n, T)(scope T a)
4958 if (isInputRange!T && is(ElementType!T : U))
4960 size_t extraStackSpace;
4961 return staticArray!(Un, U, n)(a, extraStackSpace);
4964 /// ditto
4965 auto staticArray(Un : U[n], U, size_t n, T)(scope T a, out size_t rangeLength)
4966 if (isInputRange!T && is(ElementType!T : U))
4968 import std.algorithm.mutation : uninitializedFill;
4969 import std.range : take;
4970 import core.internal.lifetime : emplaceRef;
4972 if (__ctfe)
4974 size_t i;
4975 // Compile-time version to avoid unchecked memory access.
4976 Unqual!U[n] ret;
4977 for (auto iter = a.take(n); !iter.empty; iter.popFront())
4979 ret[i] = iter.front;
4980 i++;
4983 rangeLength = i;
4984 return (() @trusted => cast(U[n]) ret)();
4987 auto ret = (() @trusted
4989 Unqual!U[n] theArray = void;
4990 return theArray;
4991 }());
4993 size_t i;
4994 if (true)
4996 // ret was void-initialized so let's initialize the unfilled part manually.
4997 // also prevents destructors to be called on uninitialized memory if
4998 // an exception is thrown
4999 scope (exit) ret[i .. $].uninitializedFill(U.init);
5001 for (auto iter = a.take(n); !iter.empty; iter.popFront())
5003 emplaceRef!U(ret[i++], iter.front);
5007 rangeLength = i;
5008 return (() @trusted => cast(U[n]) ret)();
5011 /// static array from range + size
5012 nothrow pure @safe @nogc unittest
5014 import std.range : iota;
5016 auto input = 3.iota;
5017 auto a = input.staticArray!2;
5018 static assert(is(typeof(a) == int[2]));
5019 assert(a == [0, 1]);
5020 auto b = input.staticArray!(long[4]);
5021 static assert(is(typeof(b) == long[4]));
5022 assert(b == [0, 1, 2, 0]);
5025 // Tests that code compiles when there is an elaborate destructor and exceptions
5026 // are thrown. Unfortunately can't test that memory is initialized
5027 // before having a destructor called on it.
5028 @safe nothrow unittest
5030 // exists only to allow doing something in the destructor. Not tested
5031 // at the end because value appears to depend on implementation of the.
5032 // function.
5033 static int preventersDestroyed = 0;
5035 static struct CopyPreventer
5037 bool on = false;
5038 this(this)
5040 if (on) throw new Exception("Thou shalt not copy past me!");
5043 ~this()
5045 preventersDestroyed++;
5048 auto normalArray =
5050 CopyPreventer(false),
5051 CopyPreventer(false),
5052 CopyPreventer(true),
5053 CopyPreventer(false),
5054 CopyPreventer(true),
5059 auto staticArray = normalArray.staticArray!5;
5060 assert(false);
5062 catch (Exception e){}
5066 nothrow pure @safe @nogc unittest
5068 auto a = [1, 2].staticArray;
5069 assert(is(typeof(a) == int[2]) && a == [1, 2]);
5071 import std.range : iota;
5073 2.iota.staticArray!2.checkStaticArray!int([0, 1]);
5074 2.iota.staticArray!(double[2]).checkStaticArray!double([0, 1]);
5075 2.iota.staticArray!(long[2]).checkStaticArray!long([0, 1]);
5078 nothrow pure @safe @nogc unittest
5080 import std.range : iota;
5081 size_t copiedAmount;
5082 2.iota.staticArray!1(copiedAmount);
5083 assert(copiedAmount == 1);
5084 2.iota.staticArray!3(copiedAmount);
5085 assert(copiedAmount == 2);
5088 /// ditto
5089 auto staticArray(alias a)()
5090 if (isInputRange!(typeof(a)))
5092 return .staticArray!(size_t(a.length))(a);
5095 /// ditto
5096 auto staticArray(U, alias a)()
5097 if (isInputRange!(typeof(a)))
5099 return .staticArray!(U[size_t(a.length)])(a);
5102 /// static array from CT range
5103 nothrow pure @safe @nogc unittest
5105 import std.range : iota;
5107 enum a = staticArray!(2.iota);
5108 static assert(is(typeof(a) == int[2]));
5109 assert(a == [0, 1]);
5111 enum b = staticArray!(long, 2.iota);
5112 static assert(is(typeof(b) == long[2]));
5113 assert(b == [0, 1]);
5116 nothrow pure @safe @nogc unittest
5118 import std.range : iota;
5120 enum a = staticArray!(2.iota);
5121 staticArray!(2.iota).checkStaticArray!int([0, 1]);
5122 staticArray!(double, 2.iota).checkStaticArray!double([0, 1]);
5123 staticArray!(long, 2.iota).checkStaticArray!long([0, 1]);
5126 version (StdUnittest) private void checkStaticArray(T, T1, T2)(T1 a, T2 b) nothrow @safe pure @nogc
5128 static assert(is(T1 == T[T1.length]));
5129 assert(a == b, "a must be equal to b");