PageRenderTime 687ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 1ms

/std/array.d

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