1 // Written in the D programming language.
2 /**
3 This is a submodule of $(MREF std, algorithm).
4 It contains generic mutation algorithms.
5
6 $(SCRIPT inhibitQuickIndex = 1;)
7 $(BOOKTABLE Cheat Sheet,
8 $(TR $(TH Function Name) $(TH Description))
9 $(T2 bringToFront,
10 If `a = [1, 2, 3]` and `b = [4, 5, 6, 7]`,
11 `bringToFront(a, b)` leaves `a = [4, 5, 6]` and
12 `b = [7, 1, 2, 3]`.)
13 $(T2 copy,
14 Copies a range to another. If
15 `a = [1, 2, 3]` and `b = new int[5]`, then `copy(a, b)`
16 leaves `b = [1, 2, 3, 0, 0]` and returns `b[3 .. $]`.)
17 $(T2 fill,
18 Fills a range with a pattern,
19 e.g., if `a = new int[3]`, then `fill(a, 4)`
20 leaves `a = [4, 4, 4]` and `fill(a, [3, 4])` leaves
21 `a = [3, 4, 3]`.)
22 $(T2 initializeAll,
23 If `a = [1.2, 3.4]`, then `initializeAll(a)` leaves
24 `a = [double.init, double.init]`.)
25 $(T2 move,
26 `move(a, b)` moves `a` into `b`. `move(a)` reads `a`
27 destructively when necessary.)
28 $(T2 moveEmplace,
29 Similar to `move` but assumes `target` is uninitialized.)
30 $(T2 moveAll,
31 Moves all elements from one range to another.)
32 $(T2 moveEmplaceAll,
33 Similar to `moveAll` but assumes all elements in `target` are uninitialized.)
34 $(T2 moveSome,
35 Moves as many elements as possible from one range to another.)
36 $(T2 moveEmplaceSome,
37 Similar to `moveSome` but assumes all elements in `target` are uninitialized.)
38 $(T2 remove,
39 Removes elements from a range in-place, and returns the shortened
40 range.)
41 $(T2 reverse,
42 If `a = [1, 2, 3]`, `reverse(a)` changes it to `[3, 2, 1]`.)
43 $(T2 strip,
44 Strips all leading and trailing elements equal to a value, or that
45 satisfy a predicate.
46 If `a = [1, 1, 0, 1, 1]`, then `strip(a, 1)` and
47 `strip!(e => e == 1)(a)` returns `[0]`.)
48 $(T2 stripLeft,
49 Strips all leading elements equal to a value, or that satisfy a
50 predicate. If `a = [1, 1, 0, 1, 1]`, then `stripLeft(a, 1)` and
51 `stripLeft!(e => e == 1)(a)` returns `[0, 1, 1]`.)
52 $(T2 stripRight,
53 Strips all trailing elements equal to a value, or that satisfy a
54 predicate.
55 If `a = [1, 1, 0, 1, 1]`, then `stripRight(a, 1)` and
56 `stripRight!(e => e == 1)(a)` returns `[1, 1, 0]`.)
57 $(T2 swap,
58 Swaps two values.)
59 $(T2 swapAt,
60 Swaps two values by indices.)
61 $(T2 swapRanges,
62 Swaps all elements of two ranges.)
63 $(T2 uninitializedFill,
64 Fills a range (assumed uninitialized) with a value.)
65 )
66
67 Copyright: Andrei Alexandrescu 2008-.
68
69 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
70
71 Authors: $(HTTP erdani.com, Andrei Alexandrescu)
72
73 Source: $(PHOBOSSRC std/algorithm/mutation.d)
74
75 Macros:
76 T2=$(TR $(TDNW $(LREF $1)) $(TD $+))
77 */
78 module std.algorithm.mutation;
79
80 import std.range.primitives;
81 import std.traits : isArray, isAssignable, isBlitAssignable, isNarrowString,
82 Unqual, isSomeChar, isMutable;
83 import std.meta : allSatisfy;
84 import std.typecons : tuple, Tuple;
85
86 // bringToFront
87 /**
88 `bringToFront` takes two ranges `front` and `back`, which may
89 be of different types. Considering the concatenation of `front` and
90 `back` one unified range, `bringToFront` rotates that unified
91 range such that all elements in `back` are brought to the beginning
92 of the unified range. The relative ordering of elements in `front`
93 and `back`, respectively, remains unchanged.
94
95 The `bringToFront` function treats strings at the code unit
96 level and it is not concerned with Unicode character integrity.
97 `bringToFront` is designed as a function for moving elements
98 in ranges, not as a string function.
99
100 Performs $(BIGOH max(front.length, back.length)) evaluations of $(D
101 swap).
102
103 The `bringToFront` function can rotate elements in one buffer left or right, swap
104 buffers of equal length, and even move elements across disjoint
105 buffers of different types and different lengths.
106
107 Preconditions:
108
109 Either `front` and `back` are disjoint, or `back` is
110 reachable from `front` and `front` is not reachable from $(D
111 back).
112
113 Params:
114 front = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
115 back = a $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives)
116
117 Returns:
118 The number of elements brought to the front, i.e., the length of `back`.
119
120 See_Also:
121 $(LINK2 http://en.cppreference.com/w/cpp/algorithm/rotate, STL's `rotate`)
122 */
123 size_t bringToFront(InputRange, ForwardRange)(InputRange front, ForwardRange back)
124 if (isInputRange!InputRange && isForwardRange!ForwardRange)
125 {
126 import std.string : representation;
127
128 static if (isNarrowString!InputRange)
129 {
130 auto frontW = representation(front);
131 }
132 else
133 {
134 alias frontW = front;
135 }
136 static if (isNarrowString!ForwardRange)
137 {
138 auto backW = representation(back);
139 }
140 else
141 {
142 alias backW = back;
143 }
144
145 return bringToFrontImpl(frontW, backW);
146 }
147
148 /**
149 The simplest use of `bringToFront` is for rotating elements in a
150 buffer. For example:
151 */
152 @safe unittest
153 {
154 auto arr = [4, 5, 6, 7, 1, 2, 3];
155 auto p = bringToFront(arr[0 .. 4], arr[4 .. $]);
156 assert(p == arr.length - 4);
157 assert(arr == [ 1, 2, 3, 4, 5, 6, 7 ]);
158 }
159
160 /**
161 The `front` range may actually "step over" the `back`
162 range. This is very useful with forward ranges that cannot compute
163 comfortably right-bounded subranges like `arr[0 .. 4]` above. In
164 the example below, `r2` is a right subrange of `r1`.
165 */
166 @safe unittest
167 {
168 import std.algorithm.comparison : equal;
169 import std.container : SList;
170 import std.range.primitives : popFrontN;
171
172 auto list = SList!(int)(4, 5, 6, 7, 1, 2, 3);
173 auto r1 = list[];
174 auto r2 = list[]; popFrontN(r2, 4);
175 assert(equal(r2, [ 1, 2, 3 ]));
176 bringToFront(r1, r2);
177 assert(equal(list[], [ 1, 2, 3, 4, 5, 6, 7 ]));
178 }
179
180 /**
181 Elements can be swapped across ranges of different types:
182 */
183 @safe unittest
184 {
185 import std.algorithm.comparison : equal;
186 import std.container : SList;
187
188 auto list = SList!(int)(4, 5, 6, 7);
189 auto vec = [ 1, 2, 3 ];
190 bringToFront(list[], vec);
191 assert(equal(list[], [ 1, 2, 3, 4 ]));
192 assert(equal(vec, [ 5, 6, 7 ]));
193 }
194
195 /**
196 Unicode integrity is not preserved:
197 */
198 @safe unittest
199 {
200 import std.string : representation;
201 auto ar = representation("a".dup);
202 auto br = representation("ç".dup);
203
204 bringToFront(ar, br);
205
206 auto a = cast(char[]) ar;
207 auto b = cast(char[]) br;
208
209 // Illegal UTF-8
210 assert(a == "\303");
211 // Illegal UTF-8
212 assert(b == "\247a");
213 }
214
215 private size_t bringToFrontImpl(InputRange, ForwardRange)(InputRange front, ForwardRange back)
216 if (isInputRange!InputRange && isForwardRange!ForwardRange)
217 {
218 import std.array : sameHead;
219 import std.range : take, Take;
220 enum bool sameHeadExists = is(typeof(front.sameHead(back)));
221 size_t result;
222
223 for (bool semidone; !front.empty && !back.empty; )
224 {
225 static if (sameHeadExists)
226 {
227 if (front.sameHead(back)) break; // shortcut
228 }
229 // Swap elements until front and/or back ends.
230 auto back0 = back.save;
231 size_t nswaps;
232 do
233 {
234 static if (sameHeadExists)
235 {
236 // Detect the stepping-over condition.
237 if (front.sameHead(back0)) back0 = back.save;
238 }
239 swapFront(front, back);
240 ++nswaps;
241 front.popFront();
242 back.popFront();
243 }
244 while (!front.empty && !back.empty);
245
246 if (!semidone) result += nswaps;
247
248 // Now deal with the remaining elements.
249 if (back.empty)
250 {
251 if (front.empty) break;
252 // Right side was shorter, which means that we've brought
253 // all the back elements to the front.
254 semidone = true;
255 // Next pass: bringToFront(front, back0) to adjust the rest.
256 back = back0;
257 }
258 else
259 {
260 assert(front.empty, "Expected front to be empty");
261 // Left side was shorter. Let's step into the back.
262 static if (is(InputRange == Take!ForwardRange))
263 {
264 front = take(back0, nswaps);
265 }
266 else
267 {
268 immutable subresult = bringToFront(take(back0, nswaps),
269 back);
270 if (!semidone) result += subresult;
271 break; // done
272 }
273 }
274 }
275 return result;
276 }
277
278 @safe unittest
279 {
280 import std.algorithm.comparison : equal;
281 import std.conv : text;
282 import std.random : Random = Xorshift, uniform;
283
284 // a more elaborate test
285 {
286 auto rnd = Random(123_456_789);
287 int[] a = new int[uniform(100, 200, rnd)];
288 int[] b = new int[uniform(100, 200, rnd)];
289 foreach (ref e; a) e = uniform(-100, 100, rnd);
290 foreach (ref e; b) e = uniform(-100, 100, rnd);
291 int[] c = a ~ b;
292 // writeln("a= ", a);
293 // writeln("b= ", b);
294 auto n = bringToFront(c[0 .. a.length], c[a.length .. $]);
295 //writeln("c= ", c);
296 assert(n == b.length);
297 assert(c == b ~ a, text(c, "\n", a, "\n", b));
298 }
299 // different types, moveFront, no sameHead
300 {
R(T)301 static struct R(T)
302 {
303 T[] data;
304 size_t i;
305 @property
306 {
307 R save() { return this; }
308 bool empty() { return i >= data.length; }
309 T front() { return data[i]; }
310 T front(real e) { return data[i] = cast(T) e; }
311 }
312 void popFront() { ++i; }
313 }
314 auto a = R!int([1, 2, 3, 4, 5]);
315 auto b = R!real([6, 7, 8, 9]);
316 auto n = bringToFront(a, b);
317 assert(n == 4);
318 assert(a.data == [6, 7, 8, 9, 1]);
319 assert(b.data == [2, 3, 4, 5]);
320 }
321 // front steps over back
322 {
323 int[] arr, r1, r2;
324
325 // back is shorter
326 arr = [4, 5, 6, 7, 1, 2, 3];
327 r1 = arr;
328 r2 = arr[4 .. $];
329 bringToFront(r1, r2) == 3 || assert(0);
330 assert(equal(arr, [1, 2, 3, 4, 5, 6, 7]));
331
332 // front is shorter
333 arr = [5, 6, 7, 1, 2, 3, 4];
334 r1 = arr;
335 r2 = arr[3 .. $];
336 bringToFront(r1, r2) == 4 || assert(0);
337 assert(equal(arr, [1, 2, 3, 4, 5, 6, 7]));
338 }
339
340 // https://issues.dlang.org/show_bug.cgi?id=16959
341 auto arr = ['4', '5', '6', '7', '1', '2', '3'];
342 auto p = bringToFront(arr[0 .. 4], arr[4 .. $]);
343
344 assert(p == arr.length - 4);
345 assert(arr == ['1', '2', '3', '4', '5', '6', '7']);
346 }
347
348 // Tests if types are arrays and support slice assign.
349 private enum bool areCopyCompatibleArrays(T1, T2) =
350 isArray!T1 && isArray!T2 && is(typeof(T2.init[] = T1.init[]));
351
352 // copy
353 /**
354 Copies the content of `source` into `target` and returns the
355 remaining (unfilled) part of `target`.
356
357 Preconditions: `target` shall have enough room to accommodate
358 the entirety of `source`.
359
360 Params:
361 source = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
362 target = an output range
363
364 Returns:
365 The unfilled part of target
366 */
367 TargetRange copy(SourceRange, TargetRange)(SourceRange source, TargetRange target)
368 if (isInputRange!SourceRange && isOutputRange!(TargetRange, ElementType!SourceRange))
369 {
370 static if (areCopyCompatibleArrays!(SourceRange, TargetRange))
371 {
372 const tlen = target.length;
373 const slen = source.length;
374 assert(tlen >= slen,
375 "Cannot copy a source range into a smaller target range.");
376
377 immutable overlaps = () @trusted {
378 return source.ptr < target.ptr + tlen &&
379 target.ptr < source.ptr + slen; }();
380
381 if (overlaps)
382 {
383 if (source.ptr < target.ptr)
384 {
385 foreach_reverse (idx; 0 .. slen)
386 target[idx] = source[idx];
387 }
388 else
389 {
390 foreach (idx; 0 .. slen)
391 target[idx] = source[idx];
392 }
393 return target[slen .. tlen];
394 }
395 else
396 {
397 // Array specialization. This uses optimized memory copying
398 // routines under the hood and is about 10-20x faster than the
399 // generic implementation.
400 target[0 .. slen] = source[];
401 return target[slen .. $];
402 }
403 }
404 else
405 {
406 // Specialize for 2 random access ranges.
407 // Typically 2 random access ranges are faster iterated by common
408 // index than by x.popFront(), y.popFront() pair
409 static if (isRandomAccessRange!SourceRange &&
410 hasLength!SourceRange &&
411 hasSlicing!TargetRange &&
412 isRandomAccessRange!TargetRange &&
413 hasLength!TargetRange)
414 {
415 auto len = source.length;
416 foreach (idx; 0 .. len)
417 target[idx] = source[idx];
418 return target[len .. target.length];
419 }
420 else
421 {
422 foreach (element; source)
423 put(target, element);
424 return target;
425 }
426 }
427 }
428
429 ///
430 @safe unittest
431 {
432 int[] a = [ 1, 5 ];
433 int[] b = [ 9, 8 ];
434 int[] buf = new int[](a.length + b.length + 10);
435 auto rem = a.copy(buf); // copy a into buf
436 rem = b.copy(rem); // copy b into remainder of buf
437 assert(buf[0 .. a.length + b.length] == [1, 5, 9, 8]);
438 assert(rem.length == 10); // unused slots in buf
439 }
440
441 /**
442 As long as the target range elements support assignment from source
443 range elements, different types of ranges are accepted:
444 */
445 @safe unittest
446 {
447 float[] src = [ 1.0f, 5 ];
448 double[] dest = new double[src.length];
449 src.copy(dest);
450 }
451
452 /**
453 To _copy at most `n` elements from a range, you may want to use
454 $(REF take, std,range):
455 */
456 @safe unittest
457 {
458 import std.range;
459 int[] src = [ 1, 5, 8, 9, 10 ];
460 auto dest = new int[](3);
461 src.take(dest.length).copy(dest);
462 assert(dest == [ 1, 5, 8 ]);
463 }
464
465 /**
466 To _copy just those elements from a range that satisfy a predicate,
467 use $(LREF filter):
468 */
469 @safe unittest
470 {
471 import std.algorithm.iteration : filter;
472 int[] src = [ 1, 5, 8, 9, 10, 1, 2, 0 ];
473 auto dest = new int[src.length];
474 auto rem = src
475 .filter!(a => (a & 1) == 1)
476 .copy(dest);
477 assert(dest[0 .. $ - rem.length] == [ 1, 5, 9, 1 ]);
478 }
479
480 /**
481 $(REF retro, std,range) can be used to achieve behavior similar to
482 $(LINK2 http://en.cppreference.com/w/cpp/algorithm/copy_backward, STL's `copy_backward`'):
483 */
484 @safe unittest
485 {
486 import std.algorithm, std.range;
487 int[] src = [1, 2, 4];
488 int[] dest = [0, 0, 0, 0, 0];
489 src.retro.copy(dest.retro);
490 assert(dest == [0, 0, 1, 2, 4]);
491 }
492
493 // Test CTFE copy.
494 @safe unittest
495 {
496 enum c = copy([1,2,3], [4,5,6,7]);
497 assert(c == [7]);
498 }
499
500
501 @safe unittest
502 {
503 import std.algorithm.iteration : filter;
504
505 {
506 int[] a = [ 1, 5 ];
507 int[] b = [ 9, 8 ];
508 auto e = copy(filter!("a > 1")(a), b);
509 assert(b[0] == 5 && e.length == 1);
510 }
511
512 {
513 int[] a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
514 copy(a[5 .. 10], a[4 .. 9]);
515 assert(a[4 .. 9] == [6, 7, 8, 9, 10]);
516 }
517
518 // https://issues.dlang.org/show_bug.cgi?id=21724
519 {
520 int[] a = [1, 2, 3, 4];
521 copy(a[0 .. 2], a[1 .. 3]);
522 assert(a == [1, 1, 2, 4]);
523 }
524
525 // https://issues.dlang.org/show_bug.cgi?id=7898
526 {
527 enum v =
528 {
529 import std.algorithm;
530 int[] arr1 = [10, 20, 30, 40, 50];
531 int[] arr2 = arr1.dup;
532 copy(arr1, arr2);
533 return 35;
534 }();
535 assert(v == 35);
536 }
537 }
538
539 // https://issues.dlang.org/show_bug.cgi?id=13650
540 @safe unittest
541 {
542 import std.meta : AliasSeq;
543 static foreach (Char; AliasSeq!(char, wchar, dchar))
544 {{
545 Char[3] a1 = "123";
546 Char[6] a2 = "456789";
547 assert(copy(a1[], a2[]) is a2[3..$]);
548 assert(a1[] == "123");
549 assert(a2[] == "123789");
550 }}
551 }
552
553 // https://issues.dlang.org/show_bug.cgi?id=18804
554 @safe unittest
555 {
556 static struct NullSink
557 {
putNullSink558 void put(E)(E) {}
559 }
560 int line = 0;
561 struct R
562 {
563 int front;
emptyR564 @property bool empty() { return line == 1; }
popFrontR565 void popFront() { line = 1; }
566 }
567 R r;
568 copy(r, NullSink());
569 assert(line == 1);
570 }
571
572 /**
573 Assigns `value` to each element of input range `range`.
574
575 Alternatively, instead of using a single `value` to fill the `range`,
576 a `filter` $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives)
577 can be provided. The length of `filler` and `range` do not need to match, but
578 `filler` must not be empty.
579
580 Params:
581 range = An
582 $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
583 that exposes references to its elements and has assignable
584 elements
585 value = Assigned to each element of range
586 filler = A
587 $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives)
588 representing the _fill pattern.
589
590 Throws: If `filler` is empty.
591
592 See_Also:
593 $(LREF uninitializedFill)
594 $(LREF initializeAll)
595 */
596 void fill(Range, Value)(auto ref Range range, auto ref Value value)
597 if ((isInputRange!Range && is(typeof(range.front = value)) ||
598 isSomeChar!Value && is(typeof(range[] = value))))
599 {
600 alias T = ElementType!Range;
601
602 static if (is(typeof(range[] = value)))
603 {
604 range[] = value;
605 }
606 else static if (is(typeof(range[] = T(value))))
607 {
608 range[] = T(value);
609 }
610 else
611 {
612 for ( ; !range.empty; range.popFront() )
613 {
614 range.front = value;
615 }
616 }
617 }
618
619 ///
620 @safe unittest
621 {
622 int[] a = [ 1, 2, 3, 4 ];
623 fill(a, 5);
624 assert(a == [ 5, 5, 5, 5 ]);
625 }
626
627 // test fallback on mutable narrow strings
628 // https://issues.dlang.org/show_bug.cgi?id=16342
629 @safe unittest
630 {
631 char[] chars = ['a', 'b'];
632 fill(chars, 'c');
633 assert(chars == "cc");
634
635 char[2] chars2 = ['a', 'b'];
636 fill(chars2, 'c');
637 assert(chars2 == "cc");
638
639 wchar[] wchars = ['a', 'b'];
640 fill(wchars, wchar('c'));
641 assert(wchars == "cc"w);
642
643 dchar[] dchars = ['a', 'b'];
644 fill(dchars, dchar('c'));
645 assert(dchars == "cc"d);
646 }
647
648 @nogc @safe unittest
649 {
650 const(char)[] chars;
651 assert(chars.length == 0);
652 static assert(!__traits(compiles, fill(chars, 'c')));
653 wstring wchars;
654 assert(wchars.length == 0);
655 static assert(!__traits(compiles, fill(wchars, wchar('c'))));
656 }
657
658 @nogc @safe unittest
659 {
660 char[] chars;
661 fill(chars, 'c');
662 assert(chars == ""c);
663 }
664
665 @safe unittest
666 {
667 shared(char)[] chrs = ['r'];
668 fill(chrs, 'c');
669 assert(chrs == [shared(char)('c')]);
670 }
671
672 @nogc @safe unittest
673 {
Str(size_t len)674 struct Str(size_t len)
675 {
676 private char[len] _data;
677 void opIndexAssign(char value) @safe @nogc
678 {_data[] = value;}
679 }
680 Str!2 str;
681 str.fill(':');
682 assert(str._data == "::");
683 }
684
685 @safe unittest
686 {
687 char[] chars = ['a','b','c','d'];
688 chars[1 .. 3].fill(':');
689 assert(chars == "a::d");
690 }
691 // end https://issues.dlang.org/show_bug.cgi?id=16342
692
693 @safe unittest
694 {
695 import std.conv : text;
696 import std.internal.test.dummyrange;
697
698 int[] a = [ 1, 2, 3 ];
699 fill(a, 6);
700 assert(a == [ 6, 6, 6 ], text(a));
701
fun0()702 void fun0()
703 {
704 foreach (i; 0 .. 1000)
705 {
706 foreach (ref e; a) e = 6;
707 }
708 }
fun1()709 void fun1() { foreach (i; 0 .. 1000) fill(a, 6); }
710
711 // fill should accept InputRange
712 alias InputRange = DummyRange!(ReturnBy.Reference, Length.No, RangeType.Input);
713 enum filler = uint.max;
714 InputRange range;
715 fill(range, filler);
716 foreach (value; range.arr)
717 assert(value == filler);
718 }
719
720 @safe unittest
721 {
722 //ER8638_1 IS_NOT self assignable
723 static struct ER8638_1
724 {
opAssignER8638_1725 void opAssign(int){}
726 }
727
728 //ER8638_1 IS self assignable
729 static struct ER8638_2
730 {
opAssign(ER8638_2)731 void opAssign(ER8638_2){}
opAssign(int)732 void opAssign(int){}
733 }
734
735 auto er8638_1 = new ER8638_1[](10);
736 auto er8638_2 = new ER8638_2[](10);
737 er8638_1.fill(5); //generic case
738 er8638_2.fill(5); //opSlice(T.init) case
739 }
740
741 @safe unittest
742 {
743 {
744 int[] a = [1, 2, 3];
745 immutable(int) b = 0;
746 a.fill(b);
747 assert(a == [0, 0, 0]);
748 }
749 {
750 double[] a = [1, 2, 3];
751 immutable(int) b = 0;
752 a.fill(b);
753 assert(a == [0, 0, 0]);
754 }
755 }
756
757 /// ditto
758 void fill(InputRange, ForwardRange)(InputRange range, ForwardRange filler)
759 if (isInputRange!InputRange
760 && (isForwardRange!ForwardRange
761 || (isInputRange!ForwardRange && isInfinite!ForwardRange))
762 && is(typeof(InputRange.init.front = ForwardRange.init.front)))
763 {
764 static if (isInfinite!ForwardRange)
765 {
766 //ForwardRange is infinite, no need for bounds checking or saving
767 static if (hasSlicing!ForwardRange && hasLength!InputRange
768 && is(typeof(filler[0 .. range.length])))
769 {
770 copy(filler[0 .. range.length], range);
771 }
772 else
773 {
774 //manual feed
775 for ( ; !range.empty; range.popFront(), filler.popFront())
776 {
777 range.front = filler.front;
778 }
779 }
780 }
781 else
782 {
783 import std.exception : enforce;
784
785 enforce(!filler.empty, "Cannot fill range with an empty filler");
786
787 static if (hasLength!InputRange && hasLength!ForwardRange
788 && is(typeof(range.length > filler.length)))
789 {
790 //Case we have access to length
791 immutable len = filler.length;
792 //Start by bulk copies
793 while (range.length > len)
794 {
795 range = copy(filler.save, range);
796 }
797
798 //and finally fill the partial range. No need to save here.
799 static if (hasSlicing!ForwardRange && is(typeof(filler[0 .. range.length])))
800 {
801 //use a quick copy
802 auto len2 = range.length;
803 range = copy(filler[0 .. len2], range);
804 }
805 else
806 {
807 //iterate. No need to check filler, it's length is longer than range's
808 for (; !range.empty; range.popFront(), filler.popFront())
809 {
810 range.front = filler.front;
811 }
812 }
813 }
814 else
815 {
816 //Most basic case.
817 auto bck = filler.save;
818 for (; !range.empty; range.popFront(), filler.popFront())
819 {
820 if (filler.empty) filler = bck.save;
821 range.front = filler.front;
822 }
823 }
824 }
825 }
826
827 ///
828 @safe unittest
829 {
830 int[] a = [ 1, 2, 3, 4, 5 ];
831 int[] b = [ 8, 9 ];
832 fill(a, b);
833 assert(a == [ 8, 9, 8, 9, 8 ]);
834 }
835
836 @safe unittest
837 {
838 import std.exception : assertThrown;
839 import std.internal.test.dummyrange;
840
841 int[] a = [ 1, 2, 3, 4, 5 ];
842 int[] b = [1, 2];
843 fill(a, b);
844 assert(a == [ 1, 2, 1, 2, 1 ]);
845
846 // fill should accept InputRange
847 alias InputRange = DummyRange!(ReturnBy.Reference, Length.No, RangeType.Input);
848 InputRange range;
849 fill(range,[1,2]);
850 foreach (i,value;range.arr)
851 assert(value == (i%2 == 0?1:2));
852
853 //test with a input being a "reference forward" range
854 fill(a, new ReferenceForwardRange!int([8, 9]));
855 assert(a == [8, 9, 8, 9, 8]);
856
857 //test with a input being an "infinite input" range
858 fill(a, new ReferenceInfiniteInputRange!int());
859 assert(a == [0, 1, 2, 3, 4]);
860
861 //empty filler test
862 assertThrown(fill(a, a[$..$]));
863 }
864
865 /**
866 Initializes all elements of `range` with their `.init` value.
867 Assumes that the elements of the range are uninitialized.
868
869 This function is unavailable if `T` is a `struct` and `T.this()` is annotated
870 with `@disable`.
871
872 Params:
873 range = An
874 $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
875 that exposes references to its elements and has assignable
876 elements
877
878 See_Also:
879 $(LREF fill)
880 $(LREF uninitializedFill)
881 */
882 void initializeAll(Range)(Range range)
883 if (isInputRange!Range && hasLvalueElements!Range && hasAssignableElements!Range
884 && __traits(compiles, { static ElementType!Range _; }))
885 {
886 import core.stdc.string : memset, memcpy;
887 import std.traits : hasElaborateAssign, isDynamicArray;
888
889 alias T = ElementType!Range;
890 static if (hasElaborateAssign!T)
891 {
892 import std.algorithm.internal : addressOf;
893 //Elaborate opAssign. Must go the memcpy/memset road.
894 static if (!__traits(isZeroInit, T))
895 {
896 for ( ; !range.empty ; range.popFront() )
897 {
898 import core.internal.lifetime : emplaceInitializer;
899 emplaceInitializer(range.front);
900 }
901 }
902 else
903 static if (isDynamicArray!Range)
904 memset(range.ptr, 0, range.length * T.sizeof);
905 else
906 for ( ; !range.empty ; range.popFront() )
907 memset(addressOf(range.front), 0, T.sizeof);
908 }
909 else
910 fill(range, T.init);
911 }
912
913 /// ditto
914 void initializeAll(Range)(Range range)
915 if (is(Range == char[]) || is(Range == wchar[]))
916 {
917 alias T = ElementEncodingType!Range;
918 range[] = T.init;
919 }
920
921 ///
922 @system unittest
923 {
924 import core.stdc.stdlib : malloc, free;
925
926 struct S
927 {
928 int a = 10;
929 }
930
931 auto s = (cast(S*) malloc(5 * S.sizeof))[0 .. 5];
932 initializeAll(s);
933 assert(s == [S(10), S(10), S(10), S(10), S(10)]);
934
935 scope(exit) free(s.ptr);
936 }
937
938 @system unittest
939 {
940 import std.algorithm.iteration : filter;
941 import std.meta : AliasSeq;
942 import std.traits : hasElaborateAssign;
943
944 //Test strings:
945 //Must work on narrow strings.
946 //Must reject const
947 char[3] a = void;
948 a[].initializeAll();
949 assert(a[] == [char.init, char.init, char.init]);
950 string s;
951 assert(!__traits(compiles, s.initializeAll()));
952 assert(!__traits(compiles, s.initializeAll()));
953 assert(s.empty);
954
955 //Note: Cannot call uninitializedFill on narrow strings
956
957 enum e {e1, e2}
958 e[3] b1 = void;
959 b1[].initializeAll();
960 assert(b1[] == [e.e1, e.e1, e.e1]);
961 e[3] b2 = void;
962 b2[].uninitializedFill(e.e2);
963 assert(b2[] == [e.e2, e.e2, e.e2]);
964
965 static struct S1
966 {
967 int i;
968 }
969 static struct S2
970 {
971 int i = 1;
972 }
973 static struct S3
974 {
975 int i;
thisS3976 this(this){}
977 }
978 static struct S4
979 {
980 int i = 1;
this(this)981 this(this){}
982 }
983 static assert(!hasElaborateAssign!S1);
984 static assert(!hasElaborateAssign!S2);
985 static assert( hasElaborateAssign!S3);
986 static assert( hasElaborateAssign!S4);
987 assert(!typeid(S1).initializer().ptr);
988 assert( typeid(S2).initializer().ptr);
989 assert(!typeid(S3).initializer().ptr);
990 assert( typeid(S4).initializer().ptr);
991
992 static foreach (S; AliasSeq!(S1, S2, S3, S4))
993 {
994 //initializeAll
995 {
996 //Array
997 S[3] ss1 = void;
998 ss1[].initializeAll();
999 assert(ss1[] == [S.init, S.init, S.init]);
1000
1001 //Not array
1002 S[3] ss2 = void;
1003 auto sf = ss2[].filter!"true"();
1004
1005 sf.initializeAll();
1006 assert(ss2[] == [S.init, S.init, S.init]);
1007 }
1008 //uninitializedFill
1009 {
1010 //Array
1011 S[3] ss1 = void;
1012 ss1[].uninitializedFill(S(2));
1013 assert(ss1[] == [S(2), S(2), S(2)]);
1014
1015 //Not array
1016 S[3] ss2 = void;
1017 auto sf = ss2[].filter!"true"();
1018 sf.uninitializedFill(S(2));
1019 assert(ss2[] == [S(2), S(2), S(2)]);
1020 }
1021 }
1022 }
1023
1024 // test that initializeAll works for arrays of static arrays of structs with
1025 // elaborate assigns.
1026 @system unittest
1027 {
1028 struct Int {
~thisInt1029 ~this() {}
1030 int x = 3;
1031 }
1032 Int[2] xs = [Int(1), Int(2)];
1033 struct R {
1034 bool done;
emptyR1035 bool empty() { return done; }
frontR1036 ref Int[2] front() { return xs; }
popFrontR1037 void popFront() { done = true; }
1038 }
1039 initializeAll(R());
1040 assert(xs[0].x == 3);
1041 assert(xs[1].x == 3);
1042 }
1043
1044 // https://issues.dlang.org/show_bug.cgi?id=22105
1045 @system unittest
1046 {
1047 struct NoDefaultCtor
1048 {
1049 @disable this();
1050 }
1051
1052 NoDefaultCtor[1] array = void;
1053 static assert(!__traits(compiles, array[].initializeAll));
1054 }
1055
1056 // move
1057 /**
1058 Moves `source` into `target`, via a destructive copy when necessary.
1059
1060 If `T` is a struct with a destructor or postblit defined, source is reset
1061 to its `.init` value after it is moved into target, otherwise it is
1062 left unchanged.
1063
1064 Preconditions:
1065 If source has internal pointers that point to itself and doesn't define
1066 opPostMove, it cannot be moved, and will trigger an assertion failure.
1067
1068 Params:
1069 source = Data to copy.
1070 target = Where to copy into. The destructor, if any, is invoked before the
1071 copy is performed.
1072 */
move(T)1073 void move(T)(ref T source, ref T target)
1074 {
1075 moveImpl(target, source);
1076 }
1077
1078 /// For non-struct types, `move` just performs `target = source`:
1079 @safe unittest
1080 {
1081 Object obj1 = new Object;
1082 Object obj2 = obj1;
1083 Object obj3;
1084
1085 move(obj2, obj3);
1086 assert(obj3 is obj1);
1087 // obj2 unchanged
1088 assert(obj2 is obj1);
1089 }
1090
1091 ///
1092 pure nothrow @safe @nogc unittest
1093 {
1094 // Structs without destructors are simply copied
1095 struct S1
1096 {
1097 int a = 1;
1098 int b = 2;
1099 }
1100 S1 s11 = { 10, 11 };
1101 S1 s12;
1102
1103 move(s11, s12);
1104
1105 assert(s12 == S1(10, 11));
1106 assert(s11 == s12);
1107
1108 // But structs with destructors or postblits are reset to their .init value
1109 // after copying to the target.
1110 struct S2
1111 {
1112 int a = 1;
1113 int b = 2;
1114
~thisS21115 ~this() pure nothrow @safe @nogc { }
1116 }
1117 S2 s21 = { 3, 4 };
1118 S2 s22;
1119
1120 move(s21, s22);
1121
1122 assert(s21 == S2(1, 2));
1123 assert(s22 == S2(3, 4));
1124 }
1125
1126 @safe unittest
1127 {
1128 import std.exception : assertCTFEable;
1129 import std.traits;
1130
1131 assertCTFEable!((){
1132 Object obj1 = new Object;
1133 Object obj2 = obj1;
1134 Object obj3;
1135 move(obj2, obj3);
1136 assert(obj3 is obj1);
1137
1138 static struct S1 { int a = 1, b = 2; }
1139 S1 s11 = { 10, 11 };
1140 S1 s12;
1141 move(s11, s12);
1142 assert(s11.a == 10 && s11.b == 11 && s12.a == 10 && s12.b == 11);
1143
1144 static struct S2 { int a = 1; int * b; }
1145 S2 s21 = { 10, null };
1146 s21.b = new int;
1147 S2 s22;
1148 move(s21, s22);
1149 assert(s21 == s22);
1150 });
1151 // https://issues.dlang.org/show_bug.cgi?id=5661 test(1)
1152 static struct S3
1153 {
~thisS3::X1154 static struct X { int n = 0; ~this(){n = 0;} }
1155 X x;
1156 }
1157 static assert(hasElaborateDestructor!S3);
1158 S3 s31, s32;
1159 s31.x.n = 1;
1160 move(s31, s32);
1161 assert(s31.x.n == 0);
1162 assert(s32.x.n == 1);
1163
1164 // https://issues.dlang.org/show_bug.cgi?id=5661 test(2)
1165 static struct S4
1166 {
thisS4::X1167 static struct X { int n = 0; this(this){n = 0;} }
1168 X x;
1169 }
1170 static assert(hasElaborateCopyConstructor!S4);
1171 S4 s41, s42;
1172 s41.x.n = 1;
1173 move(s41, s42);
1174 assert(s41.x.n == 0);
1175 assert(s42.x.n == 1);
1176
1177 // https://issues.dlang.org/show_bug.cgi?id=13990 test
1178 class S5;
1179
1180 S5 s51;
1181 S5 s52 = s51;
1182 S5 s53;
1183 move(s52, s53);
1184 assert(s53 is s51);
1185 }
1186
1187 /// Ditto
move(T)1188 T move(T)(return scope ref T source)
1189 {
1190 return moveImpl(source);
1191 }
1192
1193 /// Non-copyable structs can still be moved:
1194 pure nothrow @safe @nogc unittest
1195 {
1196 struct S
1197 {
1198 int a = 1;
1199 @disable this(this);
~thisS1200 ~this() pure nothrow @safe @nogc {}
1201 }
1202 S s1;
1203 s1.a = 2;
1204 S s2 = move(s1);
1205 assert(s1.a == 1);
1206 assert(s2.a == 2);
1207 }
1208
1209 /// `opPostMove` will be called if defined:
1210 pure nothrow @safe @nogc unittest
1211 {
1212 struct S
1213 {
1214 int a;
opPostMoveS1215 void opPostMove(const ref S old)
1216 {
1217 assert(a == old.a);
1218 a++;
1219 }
1220 }
1221 S s1;
1222 s1.a = 41;
1223 S s2 = move(s1);
1224 assert(s2.a == 42);
1225 }
1226
1227 // https://issues.dlang.org/show_bug.cgi?id=20869
1228 // `move` should propagate the attributes of `opPostMove`
1229 @system unittest
1230 {
1231 static struct S
1232 {
opPostMoveS1233 void opPostMove(const ref S old) nothrow @system
1234 {
1235 __gshared int i;
1236 new int(i++); // Force @gc impure @system
1237 }
1238 }
1239
1240 alias T = void function() @system nothrow;
1241 static assert(is(typeof({ S s; move(s); }) == T));
1242 static assert(is(typeof({ S s; move(s, s); }) == T));
1243 }
1244
moveImpl(T)1245 private void moveImpl(T)(ref scope T target, ref return scope T source)
1246 {
1247 import std.traits : hasElaborateDestructor;
1248
1249 static if (is(T == struct))
1250 {
1251 // Unsafe when compiling without -dip1000
1252 if ((() @trusted => &source == &target)()) return;
1253
1254 // Destroy target before overwriting it
1255 static if (hasElaborateDestructor!T) target.__xdtor();
1256 }
1257 // move and emplace source into target
1258 moveEmplaceImpl(target, source);
1259 }
1260
moveImpl(T)1261 private T moveImpl(T)(ref return scope T source)
1262 {
1263 // Properly infer safety from moveEmplaceImpl as the implementation below
1264 // might void-initialize pointers in result and hence needs to be @trusted
1265 if (false) moveEmplaceImpl(source, source);
1266
1267 return trustedMoveImpl(source);
1268 }
1269
trustedMoveImpl(T)1270 private T trustedMoveImpl(T)(ref return scope T source) @trusted
1271 {
1272 T result = void;
1273 moveEmplaceImpl(result, source);
1274 return result;
1275 }
1276
1277 @safe unittest
1278 {
1279 import std.exception : assertCTFEable;
1280 import std.traits;
1281
1282 assertCTFEable!((){
1283 Object obj1 = new Object;
1284 Object obj2 = obj1;
1285 Object obj3 = move(obj2);
1286 assert(obj3 is obj1);
1287
1288 static struct S1 { int a = 1, b = 2; }
1289 S1 s11 = { 10, 11 };
1290 S1 s12 = move(s11);
1291 assert(s11.a == 10 && s11.b == 11 && s12.a == 10 && s12.b == 11);
1292
1293 static struct S2 { int a = 1; int * b; }
1294 S2 s21 = { 10, null };
1295 s21.b = new int;
1296 S2 s22 = move(s21);
1297 assert(s21 == s22);
1298 });
1299
1300 // https://issues.dlang.org/show_bug.cgi?id=5661 test(1)
1301 static struct S3
1302 {
~thisS3::X1303 static struct X { int n = 0; ~this(){n = 0;} }
1304 X x;
1305 }
1306 static assert(hasElaborateDestructor!S3);
1307 S3 s31;
1308 s31.x.n = 1;
1309 S3 s32 = move(s31);
1310 assert(s31.x.n == 0);
1311 assert(s32.x.n == 1);
1312
1313 // https://issues.dlang.org/show_bug.cgi?id=5661 test(2)
1314 static struct S4
1315 {
thisS4::X1316 static struct X { int n = 0; this(this){n = 0;} }
1317 X x;
1318 }
1319 static assert(hasElaborateCopyConstructor!S4);
1320 S4 s41;
1321 s41.x.n = 1;
1322 S4 s42 = move(s41);
1323 assert(s41.x.n == 0);
1324 assert(s42.x.n == 1);
1325
1326 // https://issues.dlang.org/show_bug.cgi?id=13990 test
1327 class S5;
1328
1329 S5 s51;
1330 S5 s52 = s51;
1331 S5 s53;
1332 s53 = move(s52);
1333 assert(s53 is s51);
1334 }
1335
1336 @system unittest
1337 {
~thisS1338 static struct S { int n = 0; ~this() @system { n = 0; } }
1339 S a, b;
1340 static assert(!__traits(compiles, () @safe { move(a, b); }));
1341 static assert(!__traits(compiles, () @safe { move(a); }));
1342 a.n = 1;
1343 () @trusted { move(a, b); }();
1344 assert(a.n == 0);
1345 a.n = 1;
1346 () @trusted { move(a); }();
1347 assert(a.n == 0);
1348 }
1349
1350 // https://issues.dlang.org/show_bug.cgi?id=6217
1351 @safe unittest
1352 {
1353 import std.algorithm.iteration : map;
1354 auto x = map!"a"([1,2,3]);
1355 x = move(x);
1356 }
1357
1358 // https://issues.dlang.org/show_bug.cgi?id=8055
1359 @safe unittest
1360 {
1361 static struct S
1362 {
1363 int x;
~thisS1364 ~this()
1365 {
1366 assert(x == 0);
1367 }
1368 }
foo(S s)1369 S foo(S s)
1370 {
1371 return move(s);
1372 }
1373 S a;
1374 a.x = 0;
1375 auto b = foo(a);
1376 assert(b.x == 0);
1377 }
1378
1379 // https://issues.dlang.org/show_bug.cgi?id=8057
1380 @system unittest
1381 {
1382 int n = 10;
1383 struct S
1384 {
1385 int x;
~thisS1386 ~this()
1387 {
1388 // Access to enclosing scope
1389 assert(n == 10);
1390 }
1391 }
foo(S s)1392 S foo(S s)
1393 {
1394 // Move nested struct
1395 return move(s);
1396 }
1397 S a;
1398 a.x = 1;
1399 auto b = foo(a);
1400 assert(b.x == 1);
1401
1402 // Regression https://issues.dlang.org/show_bug.cgi?id=8171
Array(T)1403 static struct Array(T)
1404 {
1405 // nested struct has no member
1406 struct Payload
1407 {
1408 ~this() {}
1409 }
1410 }
1411 Array!int.Payload x = void;
1412 move(x);
1413 move(x, x);
1414 }
1415
1416 private void moveEmplaceImpl(T)(ref scope T target, ref return scope T source)
1417 {
1418 import core.stdc.string : memcpy, memset;
1419 import std.traits : hasAliasing, hasElaborateAssign,
1420 hasElaborateCopyConstructor, hasElaborateDestructor,
1421 hasElaborateMove,
1422 isAssignable, isStaticArray;
1423
1424 static if (!is(T == class) && hasAliasing!T) if (!__ctfe)
1425 {
1426 import std.exception : doesPointTo;
1427 assert(!(doesPointTo(source, source) && !hasElaborateMove!T),
1428 "Cannot move object of type " ~ T.stringof ~ " with internal pointer unless `opPostMove` is defined.");
1429 }
1430
1431 static if (is(T == struct))
1432 {
1433 // Unsafe when compiling without -dip1000
1434 assert((() @trusted => &source !is &target)(), "source and target must not be identical");
1435
1436 static if (hasElaborateAssign!T || !isAssignable!T)
1437 () @trusted { memcpy(&target, &source, T.sizeof); }();
1438 else
1439 target = source;
1440
1441 static if (hasElaborateMove!T)
1442 __move_post_blt(target, source);
1443
1444 // If the source defines a destructor or a postblit hook, we must obliterate the
1445 // object in order to avoid double freeing and undue aliasing
1446 static if (hasElaborateDestructor!T || hasElaborateCopyConstructor!T)
1447 {
1448 // If T is nested struct, keep original context pointer
1449 static if (__traits(isNested, T))
1450 enum sz = T.sizeof - (void*).sizeof;
1451 else
1452 enum sz = T.sizeof;
1453
1454 static if (__traits(isZeroInit, T))
1455 () @trusted { memset(&source, 0, sz); }();
1456 else
1457 () @trusted { memcpy(&source, __traits(initSymbol, T).ptr, sz); }();
1458 }
1459 }
1460 else static if (isStaticArray!T)
1461 {
1462 for (size_t i = 0; i < source.length; ++i)
1463 move(source[i], target[i]);
1464 }
1465 else
1466 {
1467 // Primitive data (including pointers and arrays) or class -
1468 // assignment works great
1469 target = source;
1470 }
1471 }
1472
1473 /**
1474 * Similar to $(LREF move) but assumes `target` is uninitialized. This
1475 * is more efficient because `source` can be blitted over `target`
1476 * without destroying or initializing it first.
1477 *
1478 * Params:
1479 * source = value to be moved into target
1480 * target = uninitialized value to be filled by source
1481 */
1482 void moveEmplace(T)(ref T source, ref T target) pure @system
1483 {
1484 moveEmplaceImpl(target, source);
1485 }
1486
1487 ///
1488 pure nothrow @nogc @system unittest
1489 {
1490 static struct Foo
1491 {
1492 pure nothrow @nogc:
1493 this(int* ptr) { _ptr = ptr; }
1494 ~this() { if (_ptr) ++*_ptr; }
1495 int* _ptr;
1496 }
1497
1498 int val;
1499 Foo foo1 = void; // uninitialized
1500 auto foo2 = Foo(&val); // initialized
1501 assert(foo2._ptr is &val);
1502
1503 // Using `move(foo2, foo1)` would have an undefined effect because it would destroy
1504 // the uninitialized foo1.
1505 // moveEmplace directly overwrites foo1 without destroying or initializing it first.
1506 moveEmplace(foo2, foo1);
1507 assert(foo1._ptr is &val);
1508 assert(foo2._ptr is null);
1509 assert(val == 0);
1510 }
1511
1512 // https://issues.dlang.org/show_bug.cgi?id=18913
1513 @safe unittest
1514 {
1515 static struct NoCopy
1516 {
1517 int payload;
1518 ~this() { }
1519 @disable this(this);
1520 }
1521
1522 static void f(NoCopy[2]) { }
1523
1524 NoCopy[2] ncarray = [ NoCopy(1), NoCopy(2) ];
1525
1526 static assert(!__traits(compiles, f(ncarray)));
1527 f(move(ncarray));
1528 }
1529
1530 // moveAll
1531 /**
1532 Calls `move(a, b)` for each element `a` in `src` and the corresponding
1533 element `b` in `tgt`, in increasing order.
1534
1535 Preconditions:
1536 `walkLength(src) <= walkLength(tgt)`.
1537 This precondition will be asserted. If you cannot ensure there is enough room in
1538 `tgt` to accommodate all of `src` use $(LREF moveSome) instead.
1539
1540 Params:
1541 src = An $(REF_ALTTEXT input range, isInputRange, std,range,primitives) with
1542 movable elements.
1543 tgt = An $(REF_ALTTEXT input range, isInputRange, std,range,primitives) with
1544 elements that elements from `src` can be moved into.
1545
1546 Returns: The leftover portion of `tgt` after all elements from `src` have
1547 been moved.
1548 */
1549 InputRange2 moveAll(InputRange1, InputRange2)(InputRange1 src, InputRange2 tgt)
1550 if (isInputRange!InputRange1 && isInputRange!InputRange2
1551 && is(typeof(move(src.front, tgt.front))))
1552 {
1553 return moveAllImpl!move(src, tgt);
1554 }
1555
1556 ///
1557 pure nothrow @safe @nogc unittest
1558 {
1559 int[3] a = [ 1, 2, 3 ];
1560 int[5] b;
1561 assert(moveAll(a[], b[]) is b[3 .. $]);
1562 assert(a[] == b[0 .. 3]);
1563 int[3] cmp = [ 1, 2, 3 ];
1564 assert(a[] == cmp[]);
1565 }
1566
1567 /**
1568 * Similar to $(LREF moveAll) but assumes all elements in `tgt` are
1569 * uninitialized. Uses $(LREF moveEmplace) to move elements from
1570 * `src` over elements from `tgt`.
1571 */
1572 InputRange2 moveEmplaceAll(InputRange1, InputRange2)(InputRange1 src, InputRange2 tgt) @system
1573 if (isInputRange!InputRange1 && isInputRange!InputRange2
1574 && is(typeof(moveEmplace(src.front, tgt.front))))
1575 {
1576 return moveAllImpl!moveEmplace(src, tgt);
1577 }
1578
1579 ///
1580 pure nothrow @nogc @system unittest
1581 {
1582 static struct Foo
1583 {
1584 ~this() pure nothrow @nogc { if (_ptr) ++*_ptr; }
1585 int* _ptr;
1586 }
1587 int[3] refs = [0, 1, 2];
1588 Foo[3] src = [Foo(&refs[0]), Foo(&refs[1]), Foo(&refs[2])];
1589 Foo[5] dst = void;
1590
1591 auto tail = moveEmplaceAll(src[], dst[]); // move 3 value from src over dst
1592 assert(tail.length == 2); // returns remaining uninitialized values
1593 initializeAll(tail);
1594
1595 import std.algorithm.searching : all;
1596 assert(src[].all!(e => e._ptr is null));
1597 assert(dst[0 .. 3].all!(e => e._ptr !is null));
1598 }
1599
1600 @system unittest
1601 {
1602 struct InputRange
1603 {
1604 ref int front() { return data[0]; }
1605 void popFront() { data.popFront; }
1606 bool empty() { return data.empty; }
1607 int[] data;
1608 }
1609 auto a = InputRange([ 1, 2, 3 ]);
1610 auto b = InputRange(new int[5]);
1611 moveAll(a, b);
1612 assert(a.data == b.data[0 .. 3]);
1613 assert(a.data == [ 1, 2, 3 ]);
1614 }
1615
1616 private InputRange2 moveAllImpl(alias moveOp, InputRange1, InputRange2)(
1617 ref InputRange1 src, ref InputRange2 tgt)
1618 {
1619 import std.exception : enforce;
1620
1621 static if (isRandomAccessRange!InputRange1 && hasLength!InputRange1 && hasLength!InputRange2
1622 && hasSlicing!InputRange2 && isRandomAccessRange!InputRange2)
1623 {
1624 auto toMove = src.length;
1625 assert(toMove <= tgt.length, "Source buffer needs to be smaller or equal to the target buffer.");
1626 foreach (idx; 0 .. toMove)
1627 moveOp(src[idx], tgt[idx]);
1628 return tgt[toMove .. tgt.length];
1629 }
1630 else
1631 {
1632 for (; !src.empty; src.popFront(), tgt.popFront())
1633 {
1634 assert(!tgt.empty, "Source buffer needs to be smaller or equal to the target buffer.");
1635 moveOp(src.front, tgt.front);
1636 }
1637 return tgt;
1638 }
1639 }
1640
1641 // moveSome
1642 /**
1643 Calls `move(a, b)` for each element `a` in `src` and the corresponding
1644 element `b` in `tgt`, in increasing order, stopping when either range has been
1645 exhausted.
1646
1647 Params:
1648 src = An $(REF_ALTTEXT input range, isInputRange, std,range,primitives) with
1649 movable elements.
1650 tgt = An $(REF_ALTTEXT input range, isInputRange, std,range,primitives) with
1651 elements that elements from `src` can be moved into.
1652
1653 Returns: The leftover portions of the two ranges after one or the other of the
1654 ranges have been exhausted.
1655 */
1656 Tuple!(InputRange1, InputRange2) moveSome(InputRange1, InputRange2)(InputRange1 src, InputRange2 tgt)
1657 if (isInputRange!InputRange1 && isInputRange!InputRange2
1658 && is(typeof(move(src.front, tgt.front))))
1659 {
1660 return moveSomeImpl!move(src, tgt);
1661 }
1662
1663 ///
1664 pure nothrow @safe @nogc unittest
1665 {
1666 int[5] a = [ 1, 2, 3, 4, 5 ];
1667 int[3] b;
1668 assert(moveSome(a[], b[])[0] is a[3 .. $]);
1669 assert(a[0 .. 3] == b);
1670 assert(a == [ 1, 2, 3, 4, 5 ]);
1671 }
1672
1673 /**
1674 * Same as $(LREF moveSome) but assumes all elements in `tgt` are
1675 * uninitialized. Uses $(LREF moveEmplace) to move elements from
1676 * `src` over elements from `tgt`.
1677 */
1678 Tuple!(InputRange1, InputRange2) moveEmplaceSome(InputRange1, InputRange2)(InputRange1 src, InputRange2 tgt) @system
1679 if (isInputRange!InputRange1 && isInputRange!InputRange2
1680 && is(typeof(move(src.front, tgt.front))))
1681 {
1682 return moveSomeImpl!moveEmplace(src, tgt);
1683 }
1684
1685 ///
1686 pure nothrow @nogc @system unittest
1687 {
1688 static struct Foo
1689 {
1690 ~this() pure nothrow @nogc { if (_ptr) ++*_ptr; }
1691 int* _ptr;
1692 }
1693 int[4] refs = [0, 1, 2, 3];
1694 Foo[4] src = [Foo(&refs[0]), Foo(&refs[1]), Foo(&refs[2]), Foo(&refs[3])];
1695 Foo[3] dst = void;
1696
1697 auto res = moveEmplaceSome(src[], dst[]);
1698 assert(res.length == 2);
1699
1700 import std.algorithm.searching : all;
1701 assert(src[0 .. 3].all!(e => e._ptr is null));
1702 assert(src[3]._ptr !is null);
1703 assert(dst[].all!(e => e._ptr !is null));
1704 }
1705
1706 private Tuple!(InputRange1, InputRange2) moveSomeImpl(alias moveOp, InputRange1, InputRange2)(
1707 ref InputRange1 src, ref InputRange2 tgt)
1708 {
1709 for (; !src.empty && !tgt.empty; src.popFront(), tgt.popFront())
1710 moveOp(src.front, tgt.front);
1711 return tuple(src, tgt);
1712 }
1713
1714
1715 // SwapStrategy
1716 /**
1717 Defines the swapping strategy for algorithms that need to swap
1718 elements in a range (such as partition and sort). The strategy
1719 concerns the swapping of elements that are not the core concern of the
1720 algorithm. For example, consider an algorithm that sorts $(D [ "abc",
1721 "b", "aBc" ]) according to `toUpper(a) < toUpper(b)`. That
1722 algorithm might choose to swap the two equivalent strings `"abc"`
1723 and `"aBc"`. That does not affect the sorting since both
1724 `["abc", "aBc", "b" ]` and `[ "aBc", "abc", "b" ]` are valid
1725 outcomes.
1726
1727 Some situations require that the algorithm must NOT ever change the
1728 relative ordering of equivalent elements (in the example above, only
1729 `[ "abc", "aBc", "b" ]` would be the correct result). Such
1730 algorithms are called $(B stable). If the ordering algorithm may swap
1731 equivalent elements discretionarily, the ordering is called $(B
1732 unstable).
1733
1734 Yet another class of algorithms may choose an intermediate tradeoff by
1735 being stable only on a well-defined subrange of the range. There is no
1736 established terminology for such behavior; this library calls it $(B
1737 semistable).
1738
1739 Generally, the `stable` ordering strategy may be more costly in
1740 time and/or space than the other two because it imposes additional
1741 constraints. Similarly, `semistable` may be costlier than $(D
1742 unstable). As (semi-)stability is not needed very often, the ordering
1743 algorithms in this module parameterized by `SwapStrategy` all
1744 choose `SwapStrategy.unstable` as the default.
1745 */
1746
1747 enum SwapStrategy
1748 {
1749 /**
1750 Allows freely swapping of elements as long as the output
1751 satisfies the algorithm's requirements.
1752 */
1753 unstable,
1754 /**
1755 In algorithms partitioning ranges in two, preserve relative
1756 ordering of elements only to the left of the partition point.
1757 */
1758 semistable,
1759 /**
1760 Preserve the relative ordering of elements to the largest
1761 extent allowed by the algorithm's requirements.
1762 */
1763 stable,
1764 }
1765
1766 ///
1767 @safe unittest
1768 {
1769 int[] a = [0, 1, 2, 3];
1770 assert(remove!(SwapStrategy.stable)(a, 1) == [0, 2, 3]);
1771 a = [0, 1, 2, 3];
1772 assert(remove!(SwapStrategy.unstable)(a, 1) == [0, 3, 2]);
1773 }
1774
1775 ///
1776 @safe unittest
1777 {
1778 import std.algorithm.sorting : partition;
1779
1780 // Put stuff greater than 3 on the left
1781 auto arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
1782 assert(partition!(a => a > 3, SwapStrategy.stable)(arr) == [1, 2, 3]);
1783 assert(arr == [4, 5, 6, 7, 8, 9, 10, 1, 2, 3]);
1784
1785 arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
1786 assert(partition!(a => a > 3, SwapStrategy.semistable)(arr) == [2, 3, 1]);
1787 assert(arr == [4, 5, 6, 7, 8, 9, 10, 2, 3, 1]);
1788
1789 arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
1790 assert(partition!(a => a > 3, SwapStrategy.unstable)(arr) == [3, 2, 1]);
1791 assert(arr == [10, 9, 8, 4, 5, 6, 7, 3, 2, 1]);
1792 }
1793
1794 private template isValidIntegralTuple(T)
1795 {
1796 import std.traits : isIntegral;
1797 import std.typecons : isTuple;
1798 static if (isTuple!T)
1799 {
1800 enum isValidIntegralTuple = T.length == 2 &&
1801 isIntegral!(typeof(T.init[0])) && isIntegral!(typeof(T.init[0]));
1802 }
1803 else
1804 {
1805 enum isValidIntegralTuple = isIntegral!T;
1806 }
1807 }
1808
1809
1810 /**
1811 Eliminates elements at given offsets from `range` and returns the shortened
1812 range.
1813
1814 For example, here is how to remove a single element from an array:
1815
1816 ----
1817 string[] a = [ "a", "b", "c", "d" ];
1818 a = a.remove(1); // remove element at offset 1
1819 assert(a == [ "a", "c", "d"]);
1820 ----
1821
1822 Note that `remove` does not change the length of the original range directly;
1823 instead, it returns the shortened range. If its return value is not assigned to
1824 the original range, the original range will retain its original length, though
1825 its contents will have changed:
1826
1827 ----
1828 int[] a = [ 3, 5, 7, 8 ];
1829 assert(remove(a, 1) == [ 3, 7, 8 ]);
1830 assert(a == [ 3, 7, 8, 8 ]);
1831 ----
1832
1833 The element at offset `1` has been removed and the rest of the elements have
1834 shifted up to fill its place, however, the original array remains of the same
1835 length. This is because all functions in `std.algorithm` only change $(I
1836 content), not $(I topology). The value `8` is repeated because $(LREF move) was
1837 invoked to rearrange elements, and on integers `move` simply copies the source
1838 to the destination. To replace `a` with the effect of the removal, simply
1839 assign the slice returned by `remove` to it, as shown in the first example.
1840
1841 Multiple indices can be passed into `remove`. In that case,
1842 elements at the respective indices are all removed. The indices must
1843 be passed in increasing order, otherwise an exception occurs.
1844
1845 ----
1846 int[] a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
1847 assert(remove(a, 1, 3, 5) ==
1848 [ 0, 2, 4, 6, 7, 8, 9, 10 ]);
1849 ----
1850
1851 (Note that all indices refer to slots in the $(I original) array, not
1852 in the array as it is being progressively shortened.)
1853
1854 Tuples of two integral offsets can be used to remove an indices range:
1855
1856 ----
1857 int[] a = [ 3, 4, 5, 6, 7];
1858 assert(remove(a, 1, tuple(1, 3), 9) == [ 3, 6, 7 ]);
1859 ----
1860
1861 The tuple passes in a range closed to the left and open to
1862 the right (consistent with built-in slices), e.g. `tuple(1, 3)`
1863 means indices `1` and `2` but not `3`.
1864
1865 Finally, any combination of integral offsets and tuples composed of two integral
1866 offsets can be passed in:
1867
1868 ----
1869 int[] a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
1870 assert(remove(a, 1, tuple(3, 5), 9) == [ 0, 2, 5, 6, 7, 8, 10 ]);
1871 ----
1872
1873 In this case, the slots at positions 1, 3, 4, and 9 are removed from
1874 the array.
1875
1876 If the need is to remove some elements in the range but the order of
1877 the remaining elements does not have to be preserved, you may want to
1878 pass `SwapStrategy.unstable` to `remove`.
1879
1880 ----
1881 int[] a = [ 0, 1, 2, 3 ];
1882 assert(remove!(SwapStrategy.unstable)(a, 1) == [ 0, 3, 2 ]);
1883 ----
1884
1885 In the case above, the element at slot `1` is removed, but replaced
1886 with the last element of the range. Taking advantage of the relaxation
1887 of the stability requirement, `remove` moved elements from the end
1888 of the array over the slots to be removed. This way there is less data
1889 movement to be done which improves the execution time of the function.
1890
1891 The function `remove` works on bidirectional ranges that have assignable
1892 lvalue elements. The moving strategy is (listed from fastest to slowest):
1893
1894 $(UL
1895 $(LI If $(D s == SwapStrategy.unstable && isRandomAccessRange!Range &&
1896 hasLength!Range && hasLvalueElements!Range), then elements are moved from the
1897 end of the range into the slots to be filled. In this case, the absolute
1898 minimum of moves is performed.)
1899 $(LI Otherwise, if $(D s ==
1900 SwapStrategy.unstable && isBidirectionalRange!Range && hasLength!Range
1901 && hasLvalueElements!Range), then elements are still moved from the
1902 end of the range, but time is spent on advancing between slots by repeated
1903 calls to `range.popFront`.)
1904 $(LI Otherwise, elements are moved
1905 incrementally towards the front of `range`; a given element is never
1906 moved several times, but more elements are moved than in the previous
1907 cases.)
1908 )
1909
1910 Params:
1911 s = a SwapStrategy to determine if the original order needs to be preserved
1912 range = a $(REF_ALTTEXT bidirectional range, isBidirectionalRange, std,range,primitives)
1913 with a length member
1914 offset = which element(s) to remove
1915
1916 Returns:
1917 A range containing all of the elements of range with offset removed.
1918 */
1919 Range remove
1920 (SwapStrategy s = SwapStrategy.stable, Range, Offset ...)
1921 (Range range, Offset offset)
1922 if (Offset.length >= 1 && allSatisfy!(isValidIntegralTuple, Offset))
1923 {
1924 // Activate this check when the deprecation of non-integral tuples is over
1925 //import std.traits : isIntegral;
1926 //import std.typecons : isTuple;
1927 //static foreach (T; Offset)
1928 //{
1929 //static if (isTuple!T)
1930 //{
1931 //static assert(T.length == 2 &&
1932 //isIntegral!(typeof(T.init[0])) && isIntegral!(typeof(T.init[0])),
1933 //"Each offset must be an integral or a tuple of two integrals." ~
1934 //"Use `arr.remove(pos1, pos2)` or `arr.remove(tuple(start, begin))`");
1935 //}
1936 //else
1937 //{
1938 //static assert(isIntegral!T,
1939 //"Each offset must be an integral or a tuple of two integrals." ~
1940 //"Use `arr.remove(pos1, pos2)` or `arr.remove(tuple(start, begin))`");
1941 //}
1942 //}
1943 return removeImpl!s(range, offset);
1944 }
1945
1946 deprecated("Use of non-integral tuples is deprecated. Use remove(tuple(start, end).")
1947 Range remove
1948 (SwapStrategy s = SwapStrategy.stable, Range, Offset ...)
1949 (Range range, Offset offset)
1950 if (Offset.length >= 1 && !allSatisfy!(isValidIntegralTuple, Offset))
1951 {
1952 return removeImpl!s(range, offset);
1953 }
1954
1955 ///
1956 @safe pure unittest
1957 {
1958 import std.typecons : tuple;
1959
1960 auto a = [ 0, 1, 2, 3, 4, 5 ];
1961 assert(remove!(SwapStrategy.stable)(a, 1) == [ 0, 2, 3, 4, 5 ]);
1962 a = [ 0, 1, 2, 3, 4, 5 ];
1963 assert(remove!(SwapStrategy.stable)(a, 1, 3) == [ 0, 2, 4, 5] );
1964 a = [ 0, 1, 2, 3, 4, 5 ];
1965 assert(remove!(SwapStrategy.stable)(a, 1, tuple(3, 6)) == [ 0, 2 ]);
1966
1967 a = [ 0, 1, 2, 3, 4, 5 ];
1968 assert(remove!(SwapStrategy.unstable)(a, 1) == [0, 5, 2, 3, 4]);
1969 a = [ 0, 1, 2, 3, 4, 5 ];
1970 assert(remove!(SwapStrategy.unstable)(a, tuple(1, 4)) == [0, 5, 4]);
1971 }
1972
1973 ///
1974 @safe pure unittest
1975 {
1976 import std.typecons : tuple;
1977
1978 // Delete an index
1979 assert([4, 5, 6].remove(1) == [4, 6]);
1980
1981 // Delete multiple indices
1982 assert([4, 5, 6, 7, 8].remove(1, 3) == [4, 6, 8]);
1983
1984 // Use an indices range
1985 assert([4, 5, 6, 7, 8].remove(tuple(1, 3)) == [4, 7, 8]);
1986
1987 // Use an indices range and individual indices
1988 assert([4, 5, 6, 7, 8].remove(0, tuple(1, 3), 4) == [7]);
1989 }
1990
1991 /// `SwapStrategy.unstable` is faster, but doesn't guarantee the same order of the original array
1992 @safe pure unittest
1993 {
1994 assert([5, 6, 7, 8].remove!(SwapStrategy.stable)(1) == [5, 7, 8]);
1995 assert([5, 6, 7, 8].remove!(SwapStrategy.unstable)(1) == [5, 8, 7]);
1996 }
1997
1998 private auto removeImpl(SwapStrategy s, Range, Offset...)(Range range, Offset offset)
1999 {
2000 static if (isNarrowString!Range)
2001 {
2002 static assert(isMutable!(typeof(range[0])),
2003 "Elements must be mutable to remove");
2004 static assert(s == SwapStrategy.stable,
2005 "Only stable removing can be done for character arrays");
2006 return removeStableString(range, offset);
2007 }
2008 else
2009 {
2010 static assert(isBidirectionalRange!Range,
2011 "Range must be bidirectional");
2012 static assert(hasLvalueElements!Range,
2013 "Range must have Lvalue elements (see std.range.hasLvalueElements)");
2014
2015 static if (s == SwapStrategy.unstable)
2016 {
2017 static assert(hasLength!Range,
2018 "Range must have `length` for unstable remove");
2019 return removeUnstable(range, offset);
2020 }
2021 else static if (s == SwapStrategy.stable)
2022 return removeStable(range, offset);
2023 else
2024 static assert(false,
2025 "Only SwapStrategy.stable and SwapStrategy.unstable are supported");
2026 }
2027 }
2028
2029 @safe unittest
2030 {
2031 import std.exception : assertThrown;
2032 import std.range;
2033
2034 // https://issues.dlang.org/show_bug.cgi?id=10173
2035 int[] test = iota(0, 10).array();
2036 assertThrown(remove!(SwapStrategy.stable)(test, tuple(2, 4), tuple(1, 3)));
2037 assertThrown(remove!(SwapStrategy.unstable)(test, tuple(2, 4), tuple(1, 3)));
2038 assertThrown(remove!(SwapStrategy.stable)(test, 2, 4, 1, 3));
2039 assertThrown(remove!(SwapStrategy.unstable)(test, 2, 4, 1, 3));
2040 }
2041
2042 @safe unittest
2043 {
2044 import std.range;
2045 int[] a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
2046 a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
2047 assert(remove!(SwapStrategy.stable)(a, 1) ==
2048 [ 0, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]);
2049
2050 a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
2051 assert(remove!(SwapStrategy.unstable)(a, 0, 10) ==
2052 [ 9, 1, 2, 3, 4, 5, 6, 7, 8 ]);
2053
2054 a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
2055 assert(remove!(SwapStrategy.unstable)(a, 0, tuple(9, 11)) ==
2056 [ 8, 1, 2, 3, 4, 5, 6, 7 ]);
2057 // https://issues.dlang.org/show_bug.cgi?id=5224
2058 a = [ 1, 2, 3, 4 ];
2059 assert(remove!(SwapStrategy.unstable)(a, 2) ==
2060 [ 1, 2, 4 ]);
2061
2062 a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
2063 assert(remove!(SwapStrategy.stable)(a, 1, 5) ==
2064 [ 0, 2, 3, 4, 6, 7, 8, 9, 10 ]);
2065
2066 a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
2067 assert(remove!(SwapStrategy.stable)(a, 1, 3, 5)
2068 == [ 0, 2, 4, 6, 7, 8, 9, 10]);
2069 a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
2070 assert(remove!(SwapStrategy.stable)(a, 1, tuple(3, 5))
2071 == [ 0, 2, 5, 6, 7, 8, 9, 10]);
2072
2073 a = iota(0, 10).array();
2074 assert(remove!(SwapStrategy.unstable)(a, tuple(1, 4), tuple(6, 7))
2075 == [0, 9, 8, 7, 4, 5]);
2076 }
2077
2078 // https://issues.dlang.org/show_bug.cgi?id=11576
2079 @safe unittest
2080 {
2081 auto arr = [1,2,3];
2082 arr = arr.remove!(SwapStrategy.unstable)(2);
2083 assert(arr == [1,2]);
2084
2085 }
2086
2087 // https://issues.dlang.org/show_bug.cgi?id=12889
2088 @safe unittest
2089 {
2090 import std.range;
2091 int[1][] arr = [[0], [1], [2], [3], [4], [5], [6]];
2092 auto orig = arr.dup;
2093 foreach (i; iota(arr.length))
2094 {
2095 assert(orig == arr.remove!(SwapStrategy.unstable)(tuple(i,i)));
2096 assert(orig == arr.remove!(SwapStrategy.stable)(tuple(i,i)));
2097 }
2098 }
2099
2100 @safe unittest
2101 {
2102 char[] chars = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
2103 remove(chars, 4);
2104 assert(chars == ['a', 'b', 'c', 'd', 'f', 'g', 'h', 'h']);
2105
2106 char[] bigChars = "∑œ∆¬é˚˙ƒé∂ß¡¡".dup;
2107 assert(remove(bigChars, tuple(4, 6), 8) == ("∑œ∆¬˙ƒ∂ß¡¡"));
2108
2109 import std.exception : assertThrown;
2110 assertThrown(remove(bigChars.dup, 1, 0));
2111 assertThrown(remove(bigChars.dup, tuple(4, 3)));
2112 }
2113
2114 private Range removeUnstable(Range, Offset...)(Range range, Offset offset)
2115 {
2116 Tuple!(size_t, "pos", size_t, "len")[offset.length] blackouts;
2117 foreach (i, v; offset)
2118 {
2119 static if (is(typeof(v[0]) : size_t) && is(typeof(v[1]) : size_t))
2120 {
2121 blackouts[i].pos = v[0];
2122 blackouts[i].len = v[1] - v[0];
2123 }
2124 else
2125 {
2126 static assert(is(typeof(v) : size_t), typeof(v).stringof);
2127 blackouts[i].pos = v;
2128 blackouts[i].len = 1;
2129 }
2130 static if (i > 0)
2131 {
2132 import std.exception : enforce;
2133
2134 enforce(blackouts[i - 1].pos + blackouts[i - 1].len
2135 <= blackouts[i].pos,
2136 "remove(): incorrect ordering of elements to remove");
2137 }
2138 }
2139
2140 size_t left = 0, right = offset.length - 1;
2141 auto tgt = range.save;
2142 size_t tgtPos = 0;
2143
2144 while (left <= right)
2145 {
2146 // Look for a blackout on the right
2147 if (blackouts[right].pos + blackouts[right].len >= range.length)
2148 {
2149 range.popBackExactly(blackouts[right].len);
2150
2151 // Since right is unsigned, we must check for this case, otherwise
2152 // we might turn it into size_t.max and the loop condition will not
2153 // fail when it should.
2154 if (right > 0)
2155 {
2156 --right;
2157 continue;
2158 }
2159 else
2160 break;
2161 }
2162 // Advance to next blackout on the left
2163 assert(blackouts[left].pos >= tgtPos, "Next blackout on the left shouldn't appear before the target.");
2164 tgt.popFrontExactly(blackouts[left].pos - tgtPos);
2165 tgtPos = blackouts[left].pos;
2166
2167 // Number of elements to the right of blackouts[right]
2168 immutable tailLen = range.length - (blackouts[right].pos + blackouts[right].len);
2169 size_t toMove = void;
2170 if (tailLen < blackouts[left].len)
2171 {
2172 toMove = tailLen;
2173 blackouts[left].pos += toMove;
2174 blackouts[left].len -= toMove;
2175 }
2176 else
2177 {
2178 toMove = blackouts[left].len;
2179 ++left;
2180 }
2181 tgtPos += toMove;
2182 foreach (i; 0 .. toMove)
2183 {
2184 move(range.back, tgt.front);
2185 range.popBack();
2186 tgt.popFront();
2187 }
2188 }
2189
2190 return range;
2191 }
2192
2193 private Range removeStable(Range, Offset...)(Range range, Offset offset)
2194 {
2195 auto result = range;
2196 auto src = range, tgt = range;
2197 size_t pos;
2198 foreach (pass, i; offset)
2199 {
2200 static if (is(typeof(i[0])) && is(typeof(i[1])))
2201 {
2202 auto from = i[0], delta = i[1] - i[0];
2203 }
2204 else
2205 {
2206 auto from = i;
2207 enum delta = 1;
2208 }
2209
2210 static if (pass > 0)
2211 {
2212 import std.exception : enforce;
2213 enforce(pos <= from,
2214 "remove(): incorrect ordering of elements to remove");
2215
2216 for (; pos < from; ++pos, src.popFront(), tgt.popFront())
2217 {
2218 move(src.front, tgt.front);
2219 }
2220 }
2221 else
2222 {
2223 src.popFrontExactly(from);
2224 tgt.popFrontExactly(from);
2225 pos = from;
2226 }
2227 // now skip source to the "to" position
2228 src.popFrontExactly(delta);
2229 result.popBackExactly(delta);
2230 pos += delta;
2231 }
2232 // leftover move
2233 moveAll(src, tgt);
2234 return result;
2235 }
2236
2237 private Range removeStableString(Range, Offset...)(Range range, Offset offsets)
2238 {
2239 import std.utf : stride;
2240 size_t charIdx = 0;
2241 size_t dcharIdx = 0;
2242 size_t charShift = 0;
2243
2244 void skipOne()
2245 {
2246 charIdx += stride(range[charIdx .. $]);
2247 ++dcharIdx;
2248 }
2249
2250 void copyBackOne()
2251 {
2252 auto encodedLen = stride(range[charIdx .. $]);
2253 foreach (j; charIdx .. charIdx + encodedLen)
2254 range[j - charShift] = range[j];
2255 charIdx += encodedLen;
2256 ++dcharIdx;
2257 }
2258
2259 foreach (pass, i; offsets)
2260 {
2261 static if (is(typeof(i[0])) && is(typeof(i[1])))
2262 {
2263 auto from = i[0];
2264 auto delta = i[1] - i[0];
2265 }
2266 else
2267 {
2268 auto from = i;
2269 enum delta = 1;
2270 }
2271
2272 import std.exception : enforce;
2273 enforce(dcharIdx <= from && delta >= 0,
2274 "remove(): incorrect ordering of elements to remove");
2275
2276 while (dcharIdx < from)
2277 static if (pass == 0)
2278 skipOne();
2279 else
2280 copyBackOne();
2281
2282 auto mark = charIdx;
2283 while (dcharIdx < from + delta)
2284 skipOne();
2285 charShift += charIdx - mark;
2286 }
2287
2288 foreach (i; charIdx .. range.length)
2289 range[i - charShift] = range[i];
2290
2291 return range[0 .. $ - charShift];
2292 }
2293
2294 // Use of dynamic arrays as offsets is too error-prone
2295 // https://issues.dlang.org/show_bug.cgi?id=12086
2296 // Activate these tests once the deprecation period of remove with non-integral tuples is over
2297 @safe unittest
2298 {
2299 //static assert(!__traits(compiles, [0, 1, 2, 3, 4].remove([1, 3]) == [0, 3, 4]));
2300 static assert(__traits(compiles, [0, 1, 2, 3, 4].remove(1, 3) == [0, 2, 4]));
2301 //static assert(!__traits(compiles, assert([0, 1, 2, 3, 4].remove([1, 3, 4]) == [0, 3, 4])));
2302 //static assert(!__traits(compiles, assert([0, 1, 2, 3, 4].remove(tuple(1, 3, 4)) == [0, 3, 4])));
2303
2304 import std.range : only;
2305 //static assert(!__traits(compiles, assert([0, 1, 2, 3, 4].remove(only(1, 3)) == [0, 3, 4])));
2306 static assert(__traits(compiles, assert([0, 1, 2, 3, 4].remove(1, 3) == [0, 2, 4])));
2307 }
2308
2309 /**
2310 Reduces the length of the
2311 $(REF_ALTTEXT bidirectional range, isBidirectionalRange, std,range,primitives) `range` by removing
2312 elements that satisfy `pred`. If `s = SwapStrategy.unstable`,
2313 elements are moved from the right end of the range over the elements
2314 to eliminate. If `s = SwapStrategy.stable` (the default),
2315 elements are moved progressively to front such that their relative
2316 order is preserved. Returns the filtered range.
2317
2318 Params:
2319 range = a bidirectional ranges with lvalue elements
2320 or mutable character arrays
2321
2322 Returns:
2323 the range with all of the elements where `pred` is `true`
2324 removed
2325 */
2326 Range remove(alias pred, SwapStrategy s = SwapStrategy.stable, Range)(Range range)
2327 {
2328 import std.functional : unaryFun;
2329 alias pred_ = unaryFun!pred;
2330 static if (isNarrowString!Range)
2331 {
2332 static assert(isMutable!(typeof(range[0])),
2333 "Elements must be mutable to remove");
2334 static assert(s == SwapStrategy.stable,
2335 "Only stable removing can be done for character arrays");
2336 return removePredString!pred_(range);
2337 }
2338 else
2339 {
2340 static assert(isBidirectionalRange!Range,
2341 "Range must be bidirectional");
2342 static assert(hasLvalueElements!Range,
2343 "Range must have Lvalue elements (see std.range.hasLvalueElements)");
2344 static if (s == SwapStrategy.unstable)
2345 return removePredUnstable!pred_(range);
2346 else static if (s == SwapStrategy.stable)
2347 return removePredStable!pred_(range);
2348 else
2349 static assert(false,
2350 "Only SwapStrategy.stable and SwapStrategy.unstable are supported");
2351 }
2352 }
2353
2354 ///
2355 @safe unittest
2356 {
2357 static immutable base = [1, 2, 3, 2, 4, 2, 5, 2];
2358
2359 int[] arr = base[].dup;
2360
2361 // using a string-based predicate
2362 assert(remove!("a == 2")(arr) == [ 1, 3, 4, 5 ]);
2363
2364 // The original array contents have been modified,
2365 // so we need to reset it to its original state.
2366 // The length is unmodified however.
2367 arr[] = base[];
2368
2369 // using a lambda predicate
2370 assert(remove!(a => a == 2)(arr) == [ 1, 3, 4, 5 ]);
2371 }
2372
2373 @safe unittest
2374 {
2375 int[] a = [ 1, 2, 3, 2, 3, 4, 5, 2, 5, 6 ];
2376 assert(remove!("a == 2", SwapStrategy.unstable)(a) ==
2377 [ 1, 6, 3, 5, 3, 4, 5 ]);
2378 a = [ 1, 2, 3, 2, 3, 4, 5, 2, 5, 6 ];
2379 assert(remove!("a == 2", SwapStrategy.stable)(a) ==
2380 [ 1, 3, 3, 4, 5, 5, 6 ]);
2381 }
2382
2383 @nogc @safe unittest
2384 {
2385 // @nogc test
2386 static int[] arr = [0,1,2,3,4,5,6,7,8,9];
2387 alias pred = e => e < 5;
2388
2389 auto r = arr[].remove!(SwapStrategy.unstable)(0);
2390 r = r.remove!(SwapStrategy.stable)(0);
2391 r = r.remove!(pred, SwapStrategy.unstable);
2392 r = r.remove!(pred, SwapStrategy.stable);
2393 }
2394
2395 @safe unittest
2396 {
2397 import std.algorithm.comparison : min;
2398 import std.algorithm.searching : all, any;
2399 import std.algorithm.sorting : isStrictlyMonotonic;
2400 import std.array : array;
2401 import std.meta : AliasSeq;
2402 import std.range : iota, only;
2403 import std.typecons : Tuple;
2404 alias E = Tuple!(int, int);
2405 alias S = Tuple!(E);
2406 S[] soffsets;
2407 foreach (start; 0 .. 5)
2408 foreach (end; min(start+1,5) .. 5)
2409 soffsets ~= S(E(start,end));
2410 alias D = Tuple!(E, E);
2411 D[] doffsets;
2412 foreach (start1; 0 .. 10)
2413 foreach (end1; min(start1+1,10) .. 10)
2414 foreach (start2; end1 .. 10)
2415 foreach (end2; min(start2+1,10) .. 10)
2416 doffsets ~= D(E(start1,end1),E(start2,end2));
2417 alias T = Tuple!(E, E, E);
2418 T[] toffsets;
2419 foreach (start1; 0 .. 15)
2420 foreach (end1; min(start1+1,15) .. 15)
2421 foreach (start2; end1 .. 15)
2422 foreach (end2; min(start2+1,15) .. 15)
2423 foreach (start3; end2 .. 15)
2424 foreach (end3; min(start3+1,15) .. 15)
2425 toffsets ~= T(E(start1,end1),E(start2,end2),E(start3,end3));
2426
2427 static void verify(O...)(int[] r, int len, int removed, bool stable, O offsets)
2428 {
2429 assert(r.length == len - removed);
2430 assert(!stable || r.isStrictlyMonotonic);
2431 assert(r.all!(e => all!(o => e < o[0] || e >= o[1])(offsets.only)));
2432 }
2433
2434 static foreach (offsets; AliasSeq!(soffsets,doffsets,toffsets))
2435 foreach (os; offsets)
2436 {
2437 int len = 5*os.length;
2438 auto w = iota(0, len).array;
2439 auto x = w.dup;
2440 auto y = w.dup;
2441 auto z = w.dup;
2442 alias pred = e => any!(o => o[0] <= e && e < o[1])(only(os.expand));
2443 w = w.remove!(SwapStrategy.unstable)(os.expand);
2444 x = x.remove!(SwapStrategy.stable)(os.expand);
2445 y = y.remove!(pred, SwapStrategy.unstable);
2446 z = z.remove!(pred, SwapStrategy.stable);
2447 int removed;
2448 foreach (o; os)
2449 removed += o[1] - o[0];
2450 verify(w, len, removed, false, os[]);
2451 verify(x, len, removed, true, os[]);
2452 verify(y, len, removed, false, os[]);
2453 verify(z, len, removed, true, os[]);
2454 assert(w == y);
2455 assert(x == z);
2456 }
2457 }
2458
2459 @safe unittest
2460 {
2461 char[] chars = "abcdefg".dup;
2462 assert(chars.remove!(dc => dc == 'c' || dc == 'f') == "abdeg");
2463 assert(chars == "abdegfg");
2464
2465 assert(chars.remove!"a == 'd'" == "abegfg");
2466
2467 char[] bigChars = "¥^¨^©é√∆π".dup;
2468 assert(bigChars.remove!(dc => dc == "¨"d[0] || dc == "é"d[0]) == "¥^^©√∆π");
2469 }
2470
2471 private Range removePredUnstable(alias pred, Range)(Range range)
2472 {
2473 auto result = range;
2474 for (;!range.empty;)
2475 {
2476 if (!pred(range.front))
2477 {
2478 range.popFront();
2479 continue;
2480 }
2481 move(range.back, range.front);
2482 range.popBack();
2483 result.popBack();
2484 }
2485 return result;
2486 }
2487
2488 private Range removePredStable(alias pred, Range)(Range range)
2489 {
2490 auto result = range;
2491 auto tgt = range;
2492 for (; !range.empty; range.popFront())
2493 {
2494 if (pred(range.front))
2495 {
2496 // yank this guy
2497 result.popBack();
2498 continue;
2499 }
2500 // keep this guy
2501 move(range.front, tgt.front);
2502 tgt.popFront();
2503 }
2504 return result;
2505 }
2506
2507 private Range removePredString(alias pred, SwapStrategy s = SwapStrategy.stable, Range)
2508 (Range range)
2509 {
2510 import std.utf : decode;
2511 import std.functional : unaryFun;
2512
2513 alias pred_ = unaryFun!pred;
2514
2515 size_t charIdx = 0;
2516 size_t charShift = 0;
2517 while (charIdx < range.length)
2518 {
2519 size_t start = charIdx;
2520 if (pred_(decode(range, charIdx)))
2521 {
2522 charShift += charIdx - start;
2523 break;
2524 }
2525 }
2526 while (charIdx < range.length)
2527 {
2528 size_t start = charIdx;
2529 auto doRemove = pred_(decode(range, charIdx));
2530 auto encodedLen = charIdx - start;
2531 if (doRemove)
2532 charShift += encodedLen;
2533 else
2534 foreach (i; start .. charIdx)
2535 range[i - charShift] = range[i];
2536 }
2537
2538 return range[0 .. $ - charShift];
2539 }
2540
2541 // reverse
2542 /**
2543 Reverses `r` in-place. Performs `r.length / 2` evaluations of `swap`.
2544 UTF sequences consisting of multiple code units are preserved properly.
2545
2546 Params:
2547 r = a $(REF_ALTTEXT bidirectional range, isBidirectionalRange, std,range,primitives)
2548 with either swappable elements, a random access range with a length member,
2549 or a narrow string
2550
2551 Returns: `r`
2552
2553 Note:
2554 When passing a string with unicode modifiers on characters, such as `\u0301`,
2555 this function will not properly keep the position of the modifier. For example,
2556 reversing `ba\u0301d` ("bád") will result in d\u0301ab ("d́ab") instead of
2557 `da\u0301b` ("dáb").
2558
2559 See_Also: $(REF retro, std,range) for a lazy reverse without changing `r`
2560 */
2561 Range reverse(Range)(Range r)
2562 if (isBidirectionalRange!Range &&
2563 (hasSwappableElements!Range ||
2564 (hasAssignableElements!Range && hasLength!Range && isRandomAccessRange!Range) ||
2565 (isNarrowString!Range && isAssignable!(ElementType!Range))))
2566 {
2567 static if (isRandomAccessRange!Range && hasLength!Range)
2568 {
2569 //swapAt is in fact the only way to swap non lvalue ranges
2570 immutable last = r.length - 1;
2571 immutable steps = r.length / 2;
2572 for (size_t i = 0; i < steps; i++)
2573 {
2574 r.swapAt(i, last - i);
2575 }
2576 return r;
2577 }
2578 else static if (isNarrowString!Range && isAssignable!(ElementType!Range))
2579 {
2580 import std.string : representation;
2581 import std.utf : stride;
2582
2583 auto raw = representation(r);
2584 for (size_t i = 0; i < r.length;)
2585 {
2586 immutable step = stride(r, i);
2587 if (step > 1)
2588 {
2589 .reverse(raw[i .. i + step]);
2590 i += step;
2591 }
2592 else
2593 {
2594 ++i;
2595 }
2596 }
2597 reverse(raw);
2598 return r;
2599 }
2600 else
2601 {
2602 while (!r.empty)
2603 {
2604 swap(r.front, r.back);
2605 r.popFront();
2606 if (r.empty) break;
2607 r.popBack();
2608 }
2609 return r;
2610 }
2611 }
2612
2613 ///
2614 @safe unittest
2615 {
2616 int[] arr = [ 1, 2, 3 ];
2617 assert(arr.reverse == [ 3, 2, 1 ]);
2618 }
2619
2620 @safe unittest
2621 {
2622 int[] range = null;
2623 reverse(range);
2624 range = [ 1 ];
2625 reverse(range);
2626 assert(range == [1]);
2627 range = [1, 2];
2628 reverse(range);
2629 assert(range == [2, 1]);
2630 range = [1, 2, 3];
2631 assert(range.reverse == [3, 2, 1]);
2632 }
2633
2634 ///
2635 @safe unittest
2636 {
2637 char[] arr = "hello\U00010143\u0100\U00010143".dup;
2638 assert(arr.reverse == "\U00010143\u0100\U00010143olleh");
2639 }
2640
2641 @safe unittest
2642 {
2643 void test(string a, string b)
2644 {
2645 auto c = a.dup;
2646 reverse(c);
2647 assert(c == b, c ~ " != " ~ b);
2648 }
2649
2650 test("a", "a");
2651 test(" ", " ");
2652 test("\u2029", "\u2029");
2653 test("\u0100", "\u0100");
2654 test("\u0430", "\u0430");
2655 test("\U00010143", "\U00010143");
2656 test("abcdefcdef", "fedcfedcba");
2657 test("hello\U00010143\u0100\U00010143", "\U00010143\u0100\U00010143olleh");
2658 }
2659
2660 /**
2661 The strip group of functions allow stripping of either leading, trailing,
2662 or both leading and trailing elements.
2663
2664 The `stripLeft` function will strip the `front` of the range,
2665 the `stripRight` function will strip the `back` of the range,
2666 while the `strip` function will strip both the `front` and `back`
2667 of the range.
2668
2669 Note that the `strip` and `stripRight` functions require the range to
2670 be a $(LREF BidirectionalRange) range.
2671
2672 All of these functions come in two varieties: one takes a target element,
2673 where the range will be stripped as long as this element can be found.
2674 The other takes a lambda predicate, where the range will be stripped as
2675 long as the predicate returns true.
2676
2677 Params:
2678 range = a $(REF_ALTTEXT bidirectional range, isBidirectionalRange, std,range,primitives)
2679 or $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
2680 element = the elements to remove
2681
2682 Returns:
2683 a Range with all of range except element at the start and end
2684 */
2685 Range strip(Range, E)(Range range, E element)
2686 if (isBidirectionalRange!Range && is(typeof(range.front == element) : bool))
2687 {
2688 return range.stripLeft(element).stripRight(element);
2689 }
2690
2691 /// ditto
2692 Range strip(alias pred, Range)(Range range)
2693 if (isBidirectionalRange!Range && is(typeof(pred(range.back)) : bool))
2694 {
2695 return range.stripLeft!pred().stripRight!pred();
2696 }
2697
2698 /// ditto
2699 Range stripLeft(Range, E)(Range range, E element)
2700 if (isInputRange!Range && is(typeof(range.front == element) : bool))
2701 {
2702 import std.algorithm.searching : find;
2703 return find!((auto ref a) => a != element)(range);
2704 }
2705
2706 /// ditto
2707 Range stripLeft(alias pred, Range)(Range range)
2708 if (isInputRange!Range && is(typeof(pred(range.front)) : bool))
2709 {
2710 import std.algorithm.searching : find;
2711 import std.functional : not;
2712
2713 return find!(not!pred)(range);
2714 }
2715
2716 /// ditto
2717 Range stripRight(Range, E)(Range range, E element)
2718 if (isBidirectionalRange!Range && is(typeof(range.back == element) : bool))
2719 {
2720 for (; !range.empty; range.popBack())
2721 {
2722 if (range.back != element)
2723 break;
2724 }
2725 return range;
2726 }
2727
2728 /// ditto
2729 Range stripRight(alias pred, Range)(Range range)
2730 if (isBidirectionalRange!Range && is(typeof(pred(range.back)) : bool))
2731 {
2732 for (; !range.empty; range.popBack())
2733 {
2734 if (!pred(range.back))
2735 break;
2736 }
2737 return range;
2738 }
2739
2740 /// Strip leading and trailing elements equal to the target element.
2741 @safe pure unittest
2742 {
2743 assert(" foobar ".strip(' ') == "foobar");
2744 assert("00223.444500".strip('0') == "223.4445");
2745 assert("ëëêéüŗōpéêëë".strip('ë') == "êéüŗōpéê");
2746 assert([1, 1, 0, 1, 1].strip(1) == [0]);
2747 assert([0.0, 0.01, 0.01, 0.0].strip(0).length == 2);
2748 }
2749
2750 /// Strip leading and trailing elements while the predicate returns true.
2751 @safe pure unittest
2752 {
2753 assert(" foobar ".strip!(a => a == ' ')() == "foobar");
2754 assert("00223.444500".strip!(a => a == '0')() == "223.4445");
2755 assert("ëëêéüŗōpéêëë".strip!(a => a == 'ë')() == "êéüŗōpéê");
2756 assert([1, 1, 0, 1, 1].strip!(a => a == 1)() == [0]);
2757 assert([0.0, 0.01, 0.5, 0.6, 0.01, 0.0].strip!(a => a < 0.4)().length == 2);
2758 }
2759
2760 /// Strip leading elements equal to the target element.
2761 @safe pure unittest
2762 {
2763 assert(" foobar ".stripLeft(' ') == "foobar ");
2764 assert("00223.444500".stripLeft('0') == "223.444500");
2765 assert("ůůűniçodêéé".stripLeft('ů') == "űniçodêéé");
2766 assert([1, 1, 0, 1, 1].stripLeft(1) == [0, 1, 1]);
2767 assert([0.0, 0.01, 0.01, 0.0].stripLeft(0).length == 3);
2768 }
2769
2770 /// Strip leading elements while the predicate returns true.
2771 @safe pure unittest
2772 {
2773 assert(" foobar ".stripLeft!(a => a == ' ')() == "foobar ");
2774 assert("00223.444500".stripLeft!(a => a == '0')() == "223.444500");
2775 assert("ůůűniçodêéé".stripLeft!(a => a == 'ů')() == "űniçodêéé");
2776 assert([1, 1, 0, 1, 1].stripLeft!(a => a == 1)() == [0, 1, 1]);
2777 assert([0.0, 0.01, 0.10, 0.5, 0.6].stripLeft!(a => a < 0.4)().length == 2);
2778 }
2779
2780 /// Strip trailing elements equal to the target element.
2781 @safe pure unittest
2782 {
2783 assert(" foobar ".stripRight(' ') == " foobar");
2784 assert("00223.444500".stripRight('0') == "00223.4445");
2785 assert("ùniçodêéé".stripRight('é') == "ùniçodê");
2786 assert([1, 1, 0, 1, 1].stripRight(1) == [1, 1, 0]);
2787 assert([0.0, 0.01, 0.01, 0.0].stripRight(0).length == 3);
2788 }
2789
2790 /// Strip trailing elements while the predicate returns true.
2791 @safe pure unittest
2792 {
2793 assert(" foobar ".stripRight!(a => a == ' ')() == " foobar");
2794 assert("00223.444500".stripRight!(a => a == '0')() == "00223.4445");
2795 assert("ùniçodêéé".stripRight!(a => a == 'é')() == "ùniçodê");
2796 assert([1, 1, 0, 1, 1].stripRight!(a => a == 1)() == [1, 1, 0]);
2797 assert([0.0, 0.01, 0.10, 0.5, 0.6].stripRight!(a => a > 0.4)().length == 3);
2798 }
2799
2800 // swap
2801 /**
2802 Swaps `lhs` and `rhs`. The instances `lhs` and `rhs` are moved in
2803 memory, without ever calling `opAssign`, nor any other function. `T`
2804 need not be assignable at all to be swapped.
2805
2806 If `lhs` and `rhs` reference the same instance, then nothing is done.
2807
2808 `lhs` and `rhs` must be mutable. If `T` is a struct or union, then
2809 its fields must also all be (recursively) mutable.
2810
2811 Params:
2812 lhs = Data to be swapped with `rhs`.
2813 rhs = Data to be swapped with `lhs`.
2814 */
2815 void swap(T)(ref T lhs, ref T rhs) @trusted pure nothrow @nogc
2816 if (isBlitAssignable!T && !is(typeof(lhs.proxySwap(rhs))))
2817 {
2818 import std.traits : hasAliasing, hasElaborateAssign, isAssignable,
2819 isStaticArray;
2820 static if (hasAliasing!T) if (!__ctfe)
2821 {
2822 import std.exception : doesPointTo;
2823 assert(!doesPointTo(lhs, lhs), "Swap: lhs internal pointer.");
2824 assert(!doesPointTo(rhs, rhs), "Swap: rhs internal pointer.");
2825 assert(!doesPointTo(lhs, rhs), "Swap: lhs points to rhs.");
2826 assert(!doesPointTo(rhs, lhs), "Swap: rhs points to lhs.");
2827 }
2828
2829 static if (hasElaborateAssign!T || !isAssignable!T)
2830 {
2831 if (&lhs != &rhs)
2832 {
2833 // For structs with non-trivial assignment, move memory directly
2834 ubyte[T.sizeof] t = void;
2835 auto a = (cast(ubyte*) &lhs)[0 .. T.sizeof];
2836 auto b = (cast(ubyte*) &rhs)[0 .. T.sizeof];
2837 t[] = a[];
2838 a[] = b[];
2839 b[] = t[];
2840 }
2841 }
2842 else
2843 {
2844 //Avoid assigning overlapping arrays. Dynamic arrays are fine, because
2845 //it's their ptr and length properties which get assigned rather
2846 //than their elements when assigning them, but static arrays are value
2847 //types and therefore all of their elements get copied as part of
2848 //assigning them, which would be assigning overlapping arrays if lhs
2849 //and rhs were the same array.
2850 static if (isStaticArray!T)
2851 {
2852 if (lhs.ptr == rhs.ptr)
2853 return;
2854 }
2855
2856 // For non-elaborate-assign types, suffice to do the classic swap
2857 static if (__traits(hasCopyConstructor, T))
2858 {
2859 // don't invoke any elaborate constructors either
2860 T tmp = void;
2861 tmp = lhs;
2862 }
2863 else
2864 auto tmp = lhs;
2865 lhs = rhs;
2866 rhs = tmp;
2867 }
2868 }
2869
2870 ///
2871 @safe unittest
2872 {
2873 // Swapping POD (plain old data) types:
2874 int a = 42, b = 34;
2875 swap(a, b);
2876 assert(a == 34 && b == 42);
2877
2878 // Swapping structs with indirection:
2879 static struct S { int x; char c; int[] y; }
2880 S s1 = { 0, 'z', [ 1, 2 ] };
2881 S s2 = { 42, 'a', [ 4, 6 ] };
2882 swap(s1, s2);
2883 assert(s1.x == 42);
2884 assert(s1.c == 'a');
2885 assert(s1.y == [ 4, 6 ]);
2886
2887 assert(s2.x == 0);
2888 assert(s2.c == 'z');
2889 assert(s2.y == [ 1, 2 ]);
2890
2891 // Immutables cannot be swapped:
2892 immutable int imm1 = 1, imm2 = 2;
2893 static assert(!__traits(compiles, swap(imm1, imm2)));
2894
2895 int c = imm1 + 0;
2896 int d = imm2 + 0;
2897 swap(c, d);
2898 assert(c == 2);
2899 assert(d == 1);
2900 }
2901
2902 ///
2903 @safe unittest
2904 {
2905 // Non-copyable types can still be swapped.
2906 static struct NoCopy
2907 {
2908 this(this) { assert(0); }
2909 int n;
2910 string s;
2911 }
2912 NoCopy nc1, nc2;
2913 nc1.n = 127; nc1.s = "abc";
2914 nc2.n = 513; nc2.s = "uvwxyz";
2915
2916 swap(nc1, nc2);
2917 assert(nc1.n == 513 && nc1.s == "uvwxyz");
2918 assert(nc2.n == 127 && nc2.s == "abc");
2919
2920 swap(nc1, nc1);
2921 swap(nc2, nc2);
2922 assert(nc1.n == 513 && nc1.s == "uvwxyz");
2923 assert(nc2.n == 127 && nc2.s == "abc");
2924
2925 // Types containing non-copyable fields can also be swapped.
2926 static struct NoCopyHolder
2927 {
2928 NoCopy noCopy;
2929 }
2930 NoCopyHolder h1, h2;
2931 h1.noCopy.n = 31; h1.noCopy.s = "abc";
2932 h2.noCopy.n = 65; h2.noCopy.s = null;
2933
2934 swap(h1, h2);
2935 assert(h1.noCopy.n == 65 && h1.noCopy.s == null);
2936 assert(h2.noCopy.n == 31 && h2.noCopy.s == "abc");
2937
2938 swap(h1, h1);
2939 swap(h2, h2);
2940 assert(h1.noCopy.n == 65 && h1.noCopy.s == null);
2941 assert(h2.noCopy.n == 31 && h2.noCopy.s == "abc");
2942
2943 // Const types cannot be swapped.
2944 const NoCopy const1, const2;
2945 assert(const1.n == 0 && const2.n == 0);
2946 static assert(!__traits(compiles, swap(const1, const2)));
2947 }
2948
2949 // https://issues.dlang.org/show_bug.cgi?id=4789
2950 @safe unittest
2951 {
2952 int[1] s = [1];
2953 swap(s, s);
2954
2955 int[3] a = [1, 2, 3];
2956 swap(a[1], a[2]);
2957 assert(a == [1, 3, 2]);
2958 }
2959
2960 @safe unittest
2961 {
2962 static struct NoAssign
2963 {
2964 int i;
2965 void opAssign(NoAssign) @disable;
2966 }
2967 auto s1 = NoAssign(1);
2968 auto s2 = NoAssign(2);
2969 swap(s1, s2);
2970 assert(s1.i == 2);
2971 assert(s2.i == 1);
2972 }
2973
2974 @safe unittest
2975 {
2976 struct S
2977 {
2978 const int i;
2979 int i2 = 2;
2980 int i3 = 3;
2981 }
2982 S s;
2983 static assert(!__traits(compiles, swap(s, s)));
2984 swap(s.i2, s.i3);
2985 assert(s.i2 == 3);
2986 assert(s.i3 == 2);
2987 }
2988
2989 // https://issues.dlang.org/show_bug.cgi?id=11853
2990 @safe unittest
2991 {
2992 import std.traits : isAssignable;
2993 alias T = Tuple!(int, double);
2994 static assert(isAssignable!T);
2995 }
2996
2997 // https://issues.dlang.org/show_bug.cgi?id=12024
2998 @safe unittest
2999 {
3000 import std.datetime;
3001 SysTime a, b;
3002 swap(a, b);
3003 }
3004
3005 // https://issues.dlang.org/show_bug.cgi?id=9975
3006 @system unittest
3007 {
3008 import std.exception : doesPointTo, mayPointTo;
3009 static struct S2
3010 {
3011 union
3012 {
3013 size_t sz;
3014 string s;
3015 }
3016 }
3017 S2 a , b;
3018 a.sz = -1;
3019 assert(!doesPointTo(a, b));
3020 assert( mayPointTo(a, b));
3021 swap(a, b);
3022
3023 //Note: we can catch an error here, because there is no RAII in this test
3024 import std.exception : assertThrown;
3025 void* p, pp;
3026 p = &p;
3027 assertThrown!Error(move(p));
3028 assertThrown!Error(move(p, pp));
3029 assertThrown!Error(swap(p, pp));
3030 }
3031
3032 @system unittest
3033 {
3034 static struct A
3035 {
3036 int* x;
3037 this(this) { x = new int; }
3038 }
3039 A a1, a2;
3040 swap(a1, a2);
3041
3042 static struct B
3043 {
3044 int* x;
3045 void opAssign(B) { x = new int; }
3046 }
3047 B b1, b2;
3048 swap(b1, b2);
3049 }
3050
3051 // issue 20732
3052 @safe unittest
3053 {
3054 static struct A
3055 {
3056 int x;
3057 this(scope ref return const A other)
3058 {
3059 import std.stdio;
3060 x = other.x;
3061 // note, struct functions inside @safe functions infer ALL
3062 // attributes, so the following 3 lines are meant to prevent this.
3063 new int; // prevent @nogc inference
3064 writeln("impure"); // prevent pure inference
3065 throw new Exception(""); // prevent nothrow inference
3066 }
3067 }
3068
3069 A a1, a2;
3070 swap(a1, a2);
3071
3072 A[1] a3, a4;
3073 swap(a3, a4);
3074 }
3075
3076 /// ditto
3077 void swap(T)(ref T lhs, ref T rhs)
3078 if (is(typeof(lhs.proxySwap(rhs))))
3079 {
3080 lhs.proxySwap(rhs);
3081 }
3082
3083 /**
3084 Swaps two elements in-place of a range `r`,
3085 specified by their indices `i1` and `i2`.
3086
3087 Params:
3088 r = a range with swappable elements
3089 i1 = first index
3090 i2 = second index
3091 */
3092 void swapAt(R)(auto ref R r, size_t i1, size_t i2)
3093 {
3094 static if (is(typeof(&r.swapAt)))
3095 {
3096 r.swapAt(i1, i2);
3097 }
3098 else static if (is(typeof(&r[i1])))
3099 {
3100 swap(r[i1], r[i2]);
3101 }
3102 else
3103 {
3104 if (i1 == i2) return;
3105 auto t1 = r.moveAt(i1);
3106 auto t2 = r.moveAt(i2);
3107 r[i2] = t1;
3108 r[i1] = t2;
3109 }
3110 }
3111
3112 ///
3113 pure @safe nothrow unittest
3114 {
3115 import std.algorithm.comparison : equal;
3116 auto a = [1, 2, 3];
3117 a.swapAt(1, 2);
3118 assert(a.equal([1, 3, 2]));
3119 }
3120
3121 pure @safe nothrow unittest
3122 {
3123 import std.algorithm.comparison : equal;
3124 auto a = [4, 5, 6];
3125 a.swapAt(1, 1);
3126 assert(a.equal([4, 5, 6]));
3127 }
3128
3129 pure @safe nothrow unittest
3130 {
3131 // test non random access ranges
3132 import std.algorithm.comparison : equal;
3133 import std.array : array;
3134
3135 char[] b = ['a', 'b', 'c'];
3136 b.swapAt(1, 2);
3137 assert(b.equal(['a', 'c', 'b']));
3138
3139 int[3] c = [1, 2, 3];
3140 c.swapAt(1, 2);
3141 assert(c.array.equal([1, 3, 2]));
3142
3143 // opIndex returns lvalue
3144 struct RandomIndexType(T)
3145 {
3146 T payload;
3147
3148 @property ref auto opIndex(size_t i)
3149 {
3150 return payload[i];
3151 }
3152
3153 }
3154 auto d = RandomIndexType!(int[])([4, 5, 6]);
3155 d.swapAt(1, 2);
3156 assert(d.payload.equal([4, 6, 5]));
3157
3158 // custom moveAt and opIndexAssign
3159 struct RandomMoveAtType(T)
3160 {
3161 T payload;
3162
3163 ElementType!T moveAt(size_t i)
3164 {
3165 return payload.moveAt(i);
3166 }
3167
3168 void opIndexAssign(ElementType!T val, size_t idx)
3169 {
3170 payload[idx] = val;
3171 }
3172 }
3173 auto e = RandomMoveAtType!(int[])([7, 8, 9]);
3174 e.swapAt(1, 2);
3175 assert(e.payload.equal([7, 9, 8]));
3176
3177
3178 // custom swapAt
3179 struct RandomSwapAtType(T)
3180 {
3181 T payload;
3182
3183 void swapAt(size_t i)
3184 {
3185 return payload.swapAt(i);
3186 }
3187 }
3188 auto f = RandomMoveAtType!(int[])([10, 11, 12]);
3189 swapAt(f, 1, 2);
3190 assert(f.payload.equal([10, 12, 11]));
3191 }
3192
3193 private void swapFront(R1, R2)(R1 r1, R2 r2)
3194 if (isInputRange!R1 && isInputRange!R2)
3195 {
3196 static if (is(typeof(swap(r1.front, r2.front))))
3197 {
3198 swap(r1.front, r2.front);
3199 }
3200 else
3201 {
3202 auto t1 = moveFront(r1), t2 = moveFront(r2);
3203 r1.front = move(t2);
3204 r2.front = move(t1);
3205 }
3206 }
3207
3208 // swapRanges
3209 /**
3210 Swaps all elements of `r1` with successive elements in `r2`.
3211 Returns a tuple containing the remainder portions of `r1` and $(D
3212 r2) that were not swapped (one of them will be empty). The ranges may
3213 be of different types but must have the same element type and support
3214 swapping.
3215
3216 Params:
3217 r1 = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
3218 with swappable elements
3219 r2 = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
3220 with swappable elements
3221
3222 Returns:
3223 Tuple containing the remainder portions of r1 and r2 that were not swapped
3224 */
3225 Tuple!(InputRange1, InputRange2)
3226 swapRanges(InputRange1, InputRange2)(InputRange1 r1, InputRange2 r2)
3227 if (hasSwappableElements!InputRange1 && hasSwappableElements!InputRange2
3228 && is(ElementType!InputRange1 == ElementType!InputRange2))
3229 {
3230 for (; !r1.empty && !r2.empty; r1.popFront(), r2.popFront())
3231 {
3232 swap(r1.front, r2.front);
3233 }
3234 return tuple(r1, r2);
3235 }
3236
3237 ///
3238 @safe unittest
3239 {
3240 import std.range : empty;
3241 int[] a = [ 100, 101, 102, 103 ];
3242 int[] b = [ 0, 1, 2, 3 ];
3243 auto c = swapRanges(a[1 .. 3], b[2 .. 4]);
3244 assert(c[0].empty && c[1].empty);
3245 assert(a == [ 100, 2, 3, 103 ]);
3246 assert(b == [ 0, 1, 101, 102 ]);
3247 }
3248
3249 /**
3250 Initializes each element of `range` with `value`.
3251 Assumes that the elements of the range are uninitialized.
3252 This is of interest for structs that
3253 define copy constructors (for all other types, $(LREF fill) and
3254 uninitializedFill are equivalent).
3255
3256 Params:
3257 range = An
3258 $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
3259 that exposes references to its elements and has assignable
3260 elements
3261 value = Assigned to each element of range
3262
3263 See_Also:
3264 $(LREF fill)
3265 $(LREF initializeAll)
3266 */
3267 void uninitializedFill(Range, Value)(Range range, Value value)
3268 if (isInputRange!Range && hasLvalueElements!Range && is(typeof(range.front = value)))
3269 {
3270 import std.traits : hasElaborateAssign;
3271
3272 alias T = ElementType!Range;
3273 static if (hasElaborateAssign!T)
3274 {
3275 import core.internal.lifetime : emplaceRef;
3276
3277 // Must construct stuff by the book
3278 for (; !range.empty; range.popFront())
3279 emplaceRef!T(range.front, value);
3280 }
3281 else
3282 // Doesn't matter whether fill is initialized or not
3283 return fill(range, value);
3284 }
3285
3286 ///
3287 nothrow @system unittest
3288 {
3289 import core.stdc.stdlib : malloc, free;
3290
3291 auto s = (cast(int*) malloc(5 * int.sizeof))[0 .. 5];
3292 uninitializedFill(s, 42);
3293 assert(s == [ 42, 42, 42, 42, 42 ]);
3294
3295 scope(exit) free(s.ptr);
3296 }
3297