]> git.ipfire.org Git - thirdparty/gcc.git/blob - libphobos/src/std/algorithm/mutation.d
d: Import dmd b8384668f, druntime e6caaab9, phobos 5ab9ad256 (v2.098.0-beta.1)
[thirdparty/gcc.git] / libphobos / src / std / algorithm / mutation.d
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 {
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 {
558 void put(E)(E) {}
559 }
560 int line = 0;
561 struct R
562 {
563 int front;
564 @property bool empty() { return line == 1; }
565 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 {
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
702 void fun0()
703 {
704 foreach (i; 0 .. 1000)
705 {
706 foreach (ref e; a) e = 6;
707 }
708 }
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 {
725 void opAssign(int){}
726 }
727
728 //ER8638_1 IS self assignable
729 static struct ER8638_2
730 {
731 void opAssign(ER8638_2){}
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 Params:
870 range = An
871 $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
872 that exposes references to its elements and has assignable
873 elements
874
875 See_Also:
876 $(LREF fill)
877 $(LREF uninitializeFill)
878 */
879 void initializeAll(Range)(Range range)
880 if (isInputRange!Range && hasLvalueElements!Range && hasAssignableElements!Range)
881 {
882 import core.stdc.string : memset, memcpy;
883 import std.traits : hasElaborateAssign, isDynamicArray;
884
885 alias T = ElementType!Range;
886 static if (hasElaborateAssign!T)
887 {
888 import std.algorithm.internal : addressOf;
889 //Elaborate opAssign. Must go the memcpy road.
890 //We avoid calling emplace here, because our goal is to initialize to
891 //the static state of T.init,
892 //So we want to avoid any un-necassarilly CC'ing of T.init
893 static if (!__traits(isZeroInit, T))
894 {
895 auto p = typeid(T).initializer();
896 for ( ; !range.empty ; range.popFront() )
897 {
898 static if (__traits(isStaticArray, T))
899 {
900 // static array initializer only contains initialization
901 // for one element of the static array.
902 auto elemp = cast(void *) addressOf(range.front);
903 auto endp = elemp + T.sizeof;
904 while (elemp < endp)
905 {
906 memcpy(elemp, p.ptr, p.length);
907 elemp += p.length;
908 }
909 }
910 else
911 {
912 memcpy(addressOf(range.front), p.ptr, T.sizeof);
913 }
914 }
915 }
916 else
917 static if (isDynamicArray!Range)
918 memset(range.ptr, 0, range.length * T.sizeof);
919 else
920 for ( ; !range.empty ; range.popFront() )
921 memset(addressOf(range.front), 0, T.sizeof);
922 }
923 else
924 fill(range, T.init);
925 }
926
927 /// ditto
928 void initializeAll(Range)(Range range)
929 if (is(Range == char[]) || is(Range == wchar[]))
930 {
931 alias T = ElementEncodingType!Range;
932 range[] = T.init;
933 }
934
935 ///
936 @system unittest
937 {
938 import core.stdc.stdlib : malloc, free;
939
940 struct S
941 {
942 int a = 10;
943 }
944
945 auto s = (cast(S*) malloc(5 * S.sizeof))[0 .. 5];
946 initializeAll(s);
947 assert(s == [S(10), S(10), S(10), S(10), S(10)]);
948
949 scope(exit) free(s.ptr);
950 }
951
952 @system unittest
953 {
954 import std.algorithm.iteration : filter;
955 import std.meta : AliasSeq;
956 import std.traits : hasElaborateAssign;
957
958 //Test strings:
959 //Must work on narrow strings.
960 //Must reject const
961 char[3] a = void;
962 a[].initializeAll();
963 assert(a[] == [char.init, char.init, char.init]);
964 string s;
965 assert(!__traits(compiles, s.initializeAll()));
966 assert(!__traits(compiles, s.initializeAll()));
967 assert(s.empty);
968
969 //Note: Cannot call uninitializedFill on narrow strings
970
971 enum e {e1, e2}
972 e[3] b1 = void;
973 b1[].initializeAll();
974 assert(b1[] == [e.e1, e.e1, e.e1]);
975 e[3] b2 = void;
976 b2[].uninitializedFill(e.e2);
977 assert(b2[] == [e.e2, e.e2, e.e2]);
978
979 static struct S1
980 {
981 int i;
982 }
983 static struct S2
984 {
985 int i = 1;
986 }
987 static struct S3
988 {
989 int i;
990 this(this){}
991 }
992 static struct S4
993 {
994 int i = 1;
995 this(this){}
996 }
997 static assert(!hasElaborateAssign!S1);
998 static assert(!hasElaborateAssign!S2);
999 static assert( hasElaborateAssign!S3);
1000 static assert( hasElaborateAssign!S4);
1001 assert(!typeid(S1).initializer().ptr);
1002 assert( typeid(S2).initializer().ptr);
1003 assert(!typeid(S3).initializer().ptr);
1004 assert( typeid(S4).initializer().ptr);
1005
1006 static foreach (S; AliasSeq!(S1, S2, S3, S4))
1007 {
1008 //initializeAll
1009 {
1010 //Array
1011 S[3] ss1 = void;
1012 ss1[].initializeAll();
1013 assert(ss1[] == [S.init, S.init, S.init]);
1014
1015 //Not array
1016 S[3] ss2 = void;
1017 auto sf = ss2[].filter!"true"();
1018
1019 sf.initializeAll();
1020 assert(ss2[] == [S.init, S.init, S.init]);
1021 }
1022 //uninitializedFill
1023 {
1024 //Array
1025 S[3] ss1 = void;
1026 ss1[].uninitializedFill(S(2));
1027 assert(ss1[] == [S(2), S(2), S(2)]);
1028
1029 //Not array
1030 S[3] ss2 = void;
1031 auto sf = ss2[].filter!"true"();
1032 sf.uninitializedFill(S(2));
1033 assert(ss2[] == [S(2), S(2), S(2)]);
1034 }
1035 }
1036 }
1037
1038 // test that initializeAll works for arrays of static arrays of structs with
1039 // elaborate assigns.
1040 @system unittest
1041 {
1042 struct Int {
1043 ~this() {}
1044 int x = 3;
1045 }
1046 Int[2] xs = [Int(1), Int(2)];
1047 struct R {
1048 bool done;
1049 bool empty() { return done; }
1050 ref Int[2] front() { return xs; }
1051 void popFront() { done = true; }
1052 }
1053 initializeAll(R());
1054 assert(xs[0].x == 3);
1055 assert(xs[1].x == 3);
1056 }
1057
1058 // move
1059 /**
1060 Moves `source` into `target`, via a destructive copy when necessary.
1061
1062 If `T` is a struct with a destructor or postblit defined, source is reset
1063 to its `.init` value after it is moved into target, otherwise it is
1064 left unchanged.
1065
1066 Preconditions:
1067 If source has internal pointers that point to itself and doesn't define
1068 opPostMove, it cannot be moved, and will trigger an assertion failure.
1069
1070 Params:
1071 source = Data to copy.
1072 target = Where to copy into. The destructor, if any, is invoked before the
1073 copy is performed.
1074 */
1075 void move(T)(ref T source, ref T target)
1076 {
1077 moveImpl(target, source);
1078 }
1079
1080 /// For non-struct types, `move` just performs `target = source`:
1081 @safe unittest
1082 {
1083 Object obj1 = new Object;
1084 Object obj2 = obj1;
1085 Object obj3;
1086
1087 move(obj2, obj3);
1088 assert(obj3 is obj1);
1089 // obj2 unchanged
1090 assert(obj2 is obj1);
1091 }
1092
1093 ///
1094 pure nothrow @safe @nogc unittest
1095 {
1096 // Structs without destructors are simply copied
1097 struct S1
1098 {
1099 int a = 1;
1100 int b = 2;
1101 }
1102 S1 s11 = { 10, 11 };
1103 S1 s12;
1104
1105 move(s11, s12);
1106
1107 assert(s12 == S1(10, 11));
1108 assert(s11 == s12);
1109
1110 // But structs with destructors or postblits are reset to their .init value
1111 // after copying to the target.
1112 struct S2
1113 {
1114 int a = 1;
1115 int b = 2;
1116
1117 ~this() pure nothrow @safe @nogc { }
1118 }
1119 S2 s21 = { 3, 4 };
1120 S2 s22;
1121
1122 move(s21, s22);
1123
1124 assert(s21 == S2(1, 2));
1125 assert(s22 == S2(3, 4));
1126 }
1127
1128 @safe unittest
1129 {
1130 import std.exception : assertCTFEable;
1131 import std.traits;
1132
1133 assertCTFEable!((){
1134 Object obj1 = new Object;
1135 Object obj2 = obj1;
1136 Object obj3;
1137 move(obj2, obj3);
1138 assert(obj3 is obj1);
1139
1140 static struct S1 { int a = 1, b = 2; }
1141 S1 s11 = { 10, 11 };
1142 S1 s12;
1143 move(s11, s12);
1144 assert(s11.a == 10 && s11.b == 11 && s12.a == 10 && s12.b == 11);
1145
1146 static struct S2 { int a = 1; int * b; }
1147 S2 s21 = { 10, null };
1148 s21.b = new int;
1149 S2 s22;
1150 move(s21, s22);
1151 assert(s21 == s22);
1152 });
1153 // https://issues.dlang.org/show_bug.cgi?id=5661 test(1)
1154 static struct S3
1155 {
1156 static struct X { int n = 0; ~this(){n = 0;} }
1157 X x;
1158 }
1159 static assert(hasElaborateDestructor!S3);
1160 S3 s31, s32;
1161 s31.x.n = 1;
1162 move(s31, s32);
1163 assert(s31.x.n == 0);
1164 assert(s32.x.n == 1);
1165
1166 // https://issues.dlang.org/show_bug.cgi?id=5661 test(2)
1167 static struct S4
1168 {
1169 static struct X { int n = 0; this(this){n = 0;} }
1170 X x;
1171 }
1172 static assert(hasElaborateCopyConstructor!S4);
1173 S4 s41, s42;
1174 s41.x.n = 1;
1175 move(s41, s42);
1176 assert(s41.x.n == 0);
1177 assert(s42.x.n == 1);
1178
1179 // https://issues.dlang.org/show_bug.cgi?id=13990 test
1180 class S5;
1181
1182 S5 s51;
1183 S5 s52 = s51;
1184 S5 s53;
1185 move(s52, s53);
1186 assert(s53 is s51);
1187 }
1188
1189 /// Ditto
1190 T move(T)(return scope ref T source)
1191 {
1192 return moveImpl(source);
1193 }
1194
1195 /// Non-copyable structs can still be moved:
1196 pure nothrow @safe @nogc unittest
1197 {
1198 struct S
1199 {
1200 int a = 1;
1201 @disable this(this);
1202 ~this() pure nothrow @safe @nogc {}
1203 }
1204 S s1;
1205 s1.a = 2;
1206 S s2 = move(s1);
1207 assert(s1.a == 1);
1208 assert(s2.a == 2);
1209 }
1210
1211 /// `opPostMove` will be called if defined:
1212 pure nothrow @safe @nogc unittest
1213 {
1214 struct S
1215 {
1216 int a;
1217 void opPostMove(const ref S old)
1218 {
1219 assert(a == old.a);
1220 a++;
1221 }
1222 }
1223 S s1;
1224 s1.a = 41;
1225 S s2 = move(s1);
1226 assert(s2.a == 42);
1227 }
1228
1229 // https://issues.dlang.org/show_bug.cgi?id=20869
1230 // `move` should propagate the attributes of `opPostMove`
1231 @system unittest
1232 {
1233 static struct S
1234 {
1235 void opPostMove(const ref S old) nothrow @system
1236 {
1237 __gshared int i;
1238 new int(i++); // Force @gc impure @system
1239 }
1240 }
1241
1242 alias T = void function() @system nothrow;
1243 static assert(is(typeof({ S s; move(s); }) == T));
1244 static assert(is(typeof({ S s; move(s, s); }) == T));
1245 }
1246
1247 private void moveImpl(T)(ref scope T target, ref return scope T source)
1248 {
1249 import std.traits : hasElaborateDestructor;
1250
1251 static if (is(T == struct))
1252 {
1253 // Unsafe when compiling without -dip1000
1254 if ((() @trusted => &source == &target)()) return;
1255
1256 // Destroy target before overwriting it
1257 static if (hasElaborateDestructor!T) target.__xdtor();
1258 }
1259 // move and emplace source into target
1260 moveEmplaceImpl(target, source);
1261 }
1262
1263 private T moveImpl(T)(ref return scope T source)
1264 {
1265 // Properly infer safety from moveEmplaceImpl as the implementation below
1266 // might void-initialize pointers in result and hence needs to be @trusted
1267 if (false) moveEmplaceImpl(source, source);
1268
1269 return trustedMoveImpl(source);
1270 }
1271
1272 private T trustedMoveImpl(T)(ref return scope T source) @trusted
1273 {
1274 T result = void;
1275 moveEmplaceImpl(result, source);
1276 return result;
1277 }
1278
1279 @safe unittest
1280 {
1281 import std.exception : assertCTFEable;
1282 import std.traits;
1283
1284 assertCTFEable!((){
1285 Object obj1 = new Object;
1286 Object obj2 = obj1;
1287 Object obj3 = move(obj2);
1288 assert(obj3 is obj1);
1289
1290 static struct S1 { int a = 1, b = 2; }
1291 S1 s11 = { 10, 11 };
1292 S1 s12 = move(s11);
1293 assert(s11.a == 10 && s11.b == 11 && s12.a == 10 && s12.b == 11);
1294
1295 static struct S2 { int a = 1; int * b; }
1296 S2 s21 = { 10, null };
1297 s21.b = new int;
1298 S2 s22 = move(s21);
1299 assert(s21 == s22);
1300 });
1301
1302 // https://issues.dlang.org/show_bug.cgi?id=5661 test(1)
1303 static struct S3
1304 {
1305 static struct X { int n = 0; ~this(){n = 0;} }
1306 X x;
1307 }
1308 static assert(hasElaborateDestructor!S3);
1309 S3 s31;
1310 s31.x.n = 1;
1311 S3 s32 = move(s31);
1312 assert(s31.x.n == 0);
1313 assert(s32.x.n == 1);
1314
1315 // https://issues.dlang.org/show_bug.cgi?id=5661 test(2)
1316 static struct S4
1317 {
1318 static struct X { int n = 0; this(this){n = 0;} }
1319 X x;
1320 }
1321 static assert(hasElaborateCopyConstructor!S4);
1322 S4 s41;
1323 s41.x.n = 1;
1324 S4 s42 = move(s41);
1325 assert(s41.x.n == 0);
1326 assert(s42.x.n == 1);
1327
1328 // https://issues.dlang.org/show_bug.cgi?id=13990 test
1329 class S5;
1330
1331 S5 s51;
1332 S5 s52 = s51;
1333 S5 s53;
1334 s53 = move(s52);
1335 assert(s53 is s51);
1336 }
1337
1338 @system unittest
1339 {
1340 static struct S { int n = 0; ~this() @system { n = 0; } }
1341 S a, b;
1342 static assert(!__traits(compiles, () @safe { move(a, b); }));
1343 static assert(!__traits(compiles, () @safe { move(a); }));
1344 a.n = 1;
1345 () @trusted { move(a, b); }();
1346 assert(a.n == 0);
1347 a.n = 1;
1348 () @trusted { move(a); }();
1349 assert(a.n == 0);
1350 }
1351
1352 // https://issues.dlang.org/show_bug.cgi?id=6217
1353 @safe unittest
1354 {
1355 import std.algorithm.iteration : map;
1356 auto x = map!"a"([1,2,3]);
1357 x = move(x);
1358 }
1359
1360 // https://issues.dlang.org/show_bug.cgi?id=8055
1361 @safe unittest
1362 {
1363 static struct S
1364 {
1365 int x;
1366 ~this()
1367 {
1368 assert(x == 0);
1369 }
1370 }
1371 S foo(S s)
1372 {
1373 return move(s);
1374 }
1375 S a;
1376 a.x = 0;
1377 auto b = foo(a);
1378 assert(b.x == 0);
1379 }
1380
1381 // https://issues.dlang.org/show_bug.cgi?id=8057
1382 @system unittest
1383 {
1384 int n = 10;
1385 struct S
1386 {
1387 int x;
1388 ~this()
1389 {
1390 // Access to enclosing scope
1391 assert(n == 10);
1392 }
1393 }
1394 S foo(S s)
1395 {
1396 // Move nested struct
1397 return move(s);
1398 }
1399 S a;
1400 a.x = 1;
1401 auto b = foo(a);
1402 assert(b.x == 1);
1403
1404 // Regression https://issues.dlang.org/show_bug.cgi?id=8171
1405 static struct Array(T)
1406 {
1407 // nested struct has no member
1408 struct Payload
1409 {
1410 ~this() {}
1411 }
1412 }
1413 Array!int.Payload x = void;
1414 move(x);
1415 move(x, x);
1416 }
1417
1418 private void moveEmplaceImpl(T)(ref scope T target, ref return scope T source)
1419 {
1420 import core.stdc.string : memcpy, memset;
1421 import std.traits : hasAliasing, hasElaborateAssign,
1422 hasElaborateCopyConstructor, hasElaborateDestructor,
1423 hasElaborateMove,
1424 isAssignable, isStaticArray;
1425
1426 static if (!is(T == class) && hasAliasing!T) if (!__ctfe)
1427 {
1428 import std.exception : doesPointTo;
1429 assert(!(doesPointTo(source, source) && !hasElaborateMove!T),
1430 "Cannot move object with internal pointer unless `opPostMove` is defined.");
1431 }
1432
1433 static if (is(T == struct))
1434 {
1435 // Unsafe when compiling without -dip1000
1436 assert((() @trusted => &source !is &target)(), "source and target must not be identical");
1437
1438 static if (hasElaborateAssign!T || !isAssignable!T)
1439 () @trusted { memcpy(&target, &source, T.sizeof); }();
1440 else
1441 target = source;
1442
1443 static if (hasElaborateMove!T)
1444 __move_post_blt(target, source);
1445
1446 // If the source defines a destructor or a postblit hook, we must obliterate the
1447 // object in order to avoid double freeing and undue aliasing
1448 static if (hasElaborateDestructor!T || hasElaborateCopyConstructor!T)
1449 {
1450 // If T is nested struct, keep original context pointer
1451 static if (__traits(isNested, T))
1452 enum sz = T.sizeof - (void*).sizeof;
1453 else
1454 enum sz = T.sizeof;
1455
1456 static if (__traits(isZeroInit, T))
1457 () @trusted { memset(&source, 0, sz); }();
1458 else
1459 {
1460 auto init = typeid(T).initializer();
1461 () @trusted { memcpy(&source, init.ptr, sz); }();
1462 }
1463 }
1464 }
1465 else static if (isStaticArray!T)
1466 {
1467 for (size_t i = 0; i < source.length; ++i)
1468 move(source[i], target[i]);
1469 }
1470 else
1471 {
1472 // Primitive data (including pointers and arrays) or class -
1473 // assignment works great
1474 target = source;
1475 }
1476 }
1477
1478 /**
1479 * Similar to $(LREF move) but assumes `target` is uninitialized. This
1480 * is more efficient because `source` can be blitted over `target`
1481 * without destroying or initializing it first.
1482 *
1483 * Params:
1484 * source = value to be moved into target
1485 * target = uninitialized value to be filled by source
1486 */
1487 void moveEmplace(T)(ref T source, ref T target) pure @system
1488 {
1489 moveEmplaceImpl(target, source);
1490 }
1491
1492 ///
1493 pure nothrow @nogc @system unittest
1494 {
1495 static struct Foo
1496 {
1497 pure nothrow @nogc:
1498 this(int* ptr) { _ptr = ptr; }
1499 ~this() { if (_ptr) ++*_ptr; }
1500 int* _ptr;
1501 }
1502
1503 int val;
1504 Foo foo1 = void; // uninitialized
1505 auto foo2 = Foo(&val); // initialized
1506 assert(foo2._ptr is &val);
1507
1508 // Using `move(foo2, foo1)` would have an undefined effect because it would destroy
1509 // the uninitialized foo1.
1510 // moveEmplace directly overwrites foo1 without destroying or initializing it first.
1511 moveEmplace(foo2, foo1);
1512 assert(foo1._ptr is &val);
1513 assert(foo2._ptr is null);
1514 assert(val == 0);
1515 }
1516
1517 // https://issues.dlang.org/show_bug.cgi?id=18913
1518 @safe unittest
1519 {
1520 static struct NoCopy
1521 {
1522 int payload;
1523 ~this() { }
1524 @disable this(this);
1525 }
1526
1527 static void f(NoCopy[2]) { }
1528
1529 NoCopy[2] ncarray = [ NoCopy(1), NoCopy(2) ];
1530
1531 static assert(!__traits(compiles, f(ncarray)));
1532 f(move(ncarray));
1533 }
1534
1535 // moveAll
1536 /**
1537 Calls `move(a, b)` for each element `a` in `src` and the corresponding
1538 element `b` in `tgt`, in increasing order.
1539
1540 Preconditions:
1541 `walkLength(src) <= walkLength(tgt)`.
1542 This precondition will be asserted. If you cannot ensure there is enough room in
1543 `tgt` to accommodate all of `src` use $(LREF moveSome) instead.
1544
1545 Params:
1546 src = An $(REF_ALTTEXT input range, isInputRange, std,range,primitives) with
1547 movable elements.
1548 tgt = An $(REF_ALTTEXT input range, isInputRange, std,range,primitives) with
1549 elements that elements from `src` can be moved into.
1550
1551 Returns: The leftover portion of `tgt` after all elements from `src` have
1552 been moved.
1553 */
1554 InputRange2 moveAll(InputRange1, InputRange2)(InputRange1 src, InputRange2 tgt)
1555 if (isInputRange!InputRange1 && isInputRange!InputRange2
1556 && is(typeof(move(src.front, tgt.front))))
1557 {
1558 return moveAllImpl!move(src, tgt);
1559 }
1560
1561 ///
1562 pure nothrow @safe @nogc unittest
1563 {
1564 int[3] a = [ 1, 2, 3 ];
1565 int[5] b;
1566 assert(moveAll(a[], b[]) is b[3 .. $]);
1567 assert(a[] == b[0 .. 3]);
1568 int[3] cmp = [ 1, 2, 3 ];
1569 assert(a[] == cmp[]);
1570 }
1571
1572 /**
1573 * Similar to $(LREF moveAll) but assumes all elements in `tgt` are
1574 * uninitialized. Uses $(LREF moveEmplace) to move elements from
1575 * `src` over elements from `tgt`.
1576 */
1577 InputRange2 moveEmplaceAll(InputRange1, InputRange2)(InputRange1 src, InputRange2 tgt) @system
1578 if (isInputRange!InputRange1 && isInputRange!InputRange2
1579 && is(typeof(moveEmplace(src.front, tgt.front))))
1580 {
1581 return moveAllImpl!moveEmplace(src, tgt);
1582 }
1583
1584 ///
1585 pure nothrow @nogc @system unittest
1586 {
1587 static struct Foo
1588 {
1589 ~this() pure nothrow @nogc { if (_ptr) ++*_ptr; }
1590 int* _ptr;
1591 }
1592 int[3] refs = [0, 1, 2];
1593 Foo[3] src = [Foo(&refs[0]), Foo(&refs[1]), Foo(&refs[2])];
1594 Foo[5] dst = void;
1595
1596 auto tail = moveEmplaceAll(src[], dst[]); // move 3 value from src over dst
1597 assert(tail.length == 2); // returns remaining uninitialized values
1598 initializeAll(tail);
1599
1600 import std.algorithm.searching : all;
1601 assert(src[].all!(e => e._ptr is null));
1602 assert(dst[0 .. 3].all!(e => e._ptr !is null));
1603 }
1604
1605 @system unittest
1606 {
1607 struct InputRange
1608 {
1609 ref int front() { return data[0]; }
1610 void popFront() { data.popFront; }
1611 bool empty() { return data.empty; }
1612 int[] data;
1613 }
1614 auto a = InputRange([ 1, 2, 3 ]);
1615 auto b = InputRange(new int[5]);
1616 moveAll(a, b);
1617 assert(a.data == b.data[0 .. 3]);
1618 assert(a.data == [ 1, 2, 3 ]);
1619 }
1620
1621 private InputRange2 moveAllImpl(alias moveOp, InputRange1, InputRange2)(
1622 ref InputRange1 src, ref InputRange2 tgt)
1623 {
1624 import std.exception : enforce;
1625
1626 static if (isRandomAccessRange!InputRange1 && hasLength!InputRange1 && hasLength!InputRange2
1627 && hasSlicing!InputRange2 && isRandomAccessRange!InputRange2)
1628 {
1629 auto toMove = src.length;
1630 assert(toMove <= tgt.length, "Source buffer needs to be smaller or equal to the target buffer.");
1631 foreach (idx; 0 .. toMove)
1632 moveOp(src[idx], tgt[idx]);
1633 return tgt[toMove .. tgt.length];
1634 }
1635 else
1636 {
1637 for (; !src.empty; src.popFront(), tgt.popFront())
1638 {
1639 assert(!tgt.empty, "Source buffer needs to be smaller or equal to the target buffer.");
1640 moveOp(src.front, tgt.front);
1641 }
1642 return tgt;
1643 }
1644 }
1645
1646 // moveSome
1647 /**
1648 Calls `move(a, b)` for each element `a` in `src` and the corresponding
1649 element `b` in `tgt`, in increasing order, stopping when either range has been
1650 exhausted.
1651
1652 Params:
1653 src = An $(REF_ALTTEXT input range, isInputRange, std,range,primitives) with
1654 movable elements.
1655 tgt = An $(REF_ALTTEXT input range, isInputRange, std,range,primitives) with
1656 elements that elements from `src` can be moved into.
1657
1658 Returns: The leftover portions of the two ranges after one or the other of the
1659 ranges have been exhausted.
1660 */
1661 Tuple!(InputRange1, InputRange2) moveSome(InputRange1, InputRange2)(InputRange1 src, InputRange2 tgt)
1662 if (isInputRange!InputRange1 && isInputRange!InputRange2
1663 && is(typeof(move(src.front, tgt.front))))
1664 {
1665 return moveSomeImpl!move(src, tgt);
1666 }
1667
1668 ///
1669 pure nothrow @safe @nogc unittest
1670 {
1671 int[5] a = [ 1, 2, 3, 4, 5 ];
1672 int[3] b;
1673 assert(moveSome(a[], b[])[0] is a[3 .. $]);
1674 assert(a[0 .. 3] == b);
1675 assert(a == [ 1, 2, 3, 4, 5 ]);
1676 }
1677
1678 /**
1679 * Same as $(LREF moveSome) but assumes all elements in `tgt` are
1680 * uninitialized. Uses $(LREF moveEmplace) to move elements from
1681 * `src` over elements from `tgt`.
1682 */
1683 Tuple!(InputRange1, InputRange2) moveEmplaceSome(InputRange1, InputRange2)(InputRange1 src, InputRange2 tgt) @system
1684 if (isInputRange!InputRange1 && isInputRange!InputRange2
1685 && is(typeof(move(src.front, tgt.front))))
1686 {
1687 return moveSomeImpl!moveEmplace(src, tgt);
1688 }
1689
1690 ///
1691 pure nothrow @nogc @system unittest
1692 {
1693 static struct Foo
1694 {
1695 ~this() pure nothrow @nogc { if (_ptr) ++*_ptr; }
1696 int* _ptr;
1697 }
1698 int[4] refs = [0, 1, 2, 3];
1699 Foo[4] src = [Foo(&refs[0]), Foo(&refs[1]), Foo(&refs[2]), Foo(&refs[3])];
1700 Foo[3] dst = void;
1701
1702 auto res = moveEmplaceSome(src[], dst[]);
1703 assert(res.length == 2);
1704
1705 import std.algorithm.searching : all;
1706 assert(src[0 .. 3].all!(e => e._ptr is null));
1707 assert(src[3]._ptr !is null);
1708 assert(dst[].all!(e => e._ptr !is null));
1709 }
1710
1711 private Tuple!(InputRange1, InputRange2) moveSomeImpl(alias moveOp, InputRange1, InputRange2)(
1712 ref InputRange1 src, ref InputRange2 tgt)
1713 {
1714 for (; !src.empty && !tgt.empty; src.popFront(), tgt.popFront())
1715 moveOp(src.front, tgt.front);
1716 return tuple(src, tgt);
1717 }
1718
1719
1720 // SwapStrategy
1721 /**
1722 Defines the swapping strategy for algorithms that need to swap
1723 elements in a range (such as partition and sort). The strategy
1724 concerns the swapping of elements that are not the core concern of the
1725 algorithm. For example, consider an algorithm that sorts $(D [ "abc",
1726 "b", "aBc" ]) according to `toUpper(a) < toUpper(b)`. That
1727 algorithm might choose to swap the two equivalent strings `"abc"`
1728 and `"aBc"`. That does not affect the sorting since both
1729 `["abc", "aBc", "b" ]` and `[ "aBc", "abc", "b" ]` are valid
1730 outcomes.
1731
1732 Some situations require that the algorithm must NOT ever change the
1733 relative ordering of equivalent elements (in the example above, only
1734 `[ "abc", "aBc", "b" ]` would be the correct result). Such
1735 algorithms are called $(B stable). If the ordering algorithm may swap
1736 equivalent elements discretionarily, the ordering is called $(B
1737 unstable).
1738
1739 Yet another class of algorithms may choose an intermediate tradeoff by
1740 being stable only on a well-defined subrange of the range. There is no
1741 established terminology for such behavior; this library calls it $(B
1742 semistable).
1743
1744 Generally, the `stable` ordering strategy may be more costly in
1745 time and/or space than the other two because it imposes additional
1746 constraints. Similarly, `semistable` may be costlier than $(D
1747 unstable). As (semi-)stability is not needed very often, the ordering
1748 algorithms in this module parameterized by `SwapStrategy` all
1749 choose `SwapStrategy.unstable` as the default.
1750 */
1751
1752 enum SwapStrategy
1753 {
1754 /**
1755 Allows freely swapping of elements as long as the output
1756 satisfies the algorithm's requirements.
1757 */
1758 unstable,
1759 /**
1760 In algorithms partitioning ranges in two, preserve relative
1761 ordering of elements only to the left of the partition point.
1762 */
1763 semistable,
1764 /**
1765 Preserve the relative ordering of elements to the largest
1766 extent allowed by the algorithm's requirements.
1767 */
1768 stable,
1769 }
1770
1771 ///
1772 @safe unittest
1773 {
1774 int[] a = [0, 1, 2, 3];
1775 assert(remove!(SwapStrategy.stable)(a, 1) == [0, 2, 3]);
1776 a = [0, 1, 2, 3];
1777 assert(remove!(SwapStrategy.unstable)(a, 1) == [0, 3, 2]);
1778 }
1779
1780 ///
1781 @safe unittest
1782 {
1783 import std.algorithm.sorting : partition;
1784
1785 // Put stuff greater than 3 on the left
1786 auto arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
1787 assert(partition!(a => a > 3, SwapStrategy.stable)(arr) == [1, 2, 3]);
1788 assert(arr == [4, 5, 6, 7, 8, 9, 10, 1, 2, 3]);
1789
1790 arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
1791 assert(partition!(a => a > 3, SwapStrategy.semistable)(arr) == [2, 3, 1]);
1792 assert(arr == [4, 5, 6, 7, 8, 9, 10, 2, 3, 1]);
1793
1794 arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
1795 assert(partition!(a => a > 3, SwapStrategy.unstable)(arr) == [3, 2, 1]);
1796 assert(arr == [10, 9, 8, 4, 5, 6, 7, 3, 2, 1]);
1797 }
1798
1799 private template isValidIntegralTuple(T)
1800 {
1801 import std.traits : isIntegral;
1802 import std.typecons : isTuple;
1803 static if (isTuple!T)
1804 {
1805 enum isValidIntegralTuple = T.length == 2 &&
1806 isIntegral!(typeof(T.init[0])) && isIntegral!(typeof(T.init[0]));
1807 }
1808 else
1809 {
1810 enum isValidIntegralTuple = isIntegral!T;
1811 }
1812 }
1813
1814
1815 /**
1816 Eliminates elements at given offsets from `range` and returns the shortened
1817 range.
1818
1819 For example, here is how to remove a single element from an array:
1820
1821 ----
1822 string[] a = [ "a", "b", "c", "d" ];
1823 a = a.remove(1); // remove element at offset 1
1824 assert(a == [ "a", "c", "d"]);
1825 ----
1826
1827 Note that `remove` does not change the length of the original range directly;
1828 instead, it returns the shortened range. If its return value is not assigned to
1829 the original range, the original range will retain its original length, though
1830 its contents will have changed:
1831
1832 ----
1833 int[] a = [ 3, 5, 7, 8 ];
1834 assert(remove(a, 1) == [ 3, 7, 8 ]);
1835 assert(a == [ 3, 7, 8, 8 ]);
1836 ----
1837
1838 The element at offset `1` has been removed and the rest of the elements have
1839 shifted up to fill its place, however, the original array remains of the same
1840 length. This is because all functions in `std.algorithm` only change $(I
1841 content), not $(I topology). The value `8` is repeated because $(LREF move) was
1842 invoked to rearrange elements, and on integers `move` simply copies the source
1843 to the destination. To replace `a` with the effect of the removal, simply
1844 assign the slice returned by `remove` to it, as shown in the first example.
1845
1846 Multiple indices can be passed into `remove`. In that case,
1847 elements at the respective indices are all removed. The indices must
1848 be passed in increasing order, otherwise an exception occurs.
1849
1850 ----
1851 int[] a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
1852 assert(remove(a, 1, 3, 5) ==
1853 [ 0, 2, 4, 6, 7, 8, 9, 10 ]);
1854 ----
1855
1856 (Note that all indices refer to slots in the $(I original) array, not
1857 in the array as it is being progressively shortened.)
1858
1859 Tuples of two integral offsets can be used to remove an indices range:
1860
1861 ----
1862 int[] a = [ 3, 4, 5, 6, 7];
1863 assert(remove(a, 1, tuple(1, 3), 9) == [ 3, 6, 7 ]);
1864 ----
1865
1866 The tuple passes in a range closed to the left and open to
1867 the right (consistent with built-in slices), e.g. `tuple(1, 3)`
1868 means indices `1` and `2` but not `3`.
1869
1870 Finally, any combination of integral offsets and tuples composed of two integral
1871 offsets can be passed in:
1872
1873 ----
1874 int[] a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
1875 assert(remove(a, 1, tuple(3, 5), 9) == [ 0, 2, 5, 6, 7, 8, 10 ]);
1876 ----
1877
1878 In this case, the slots at positions 1, 3, 4, and 9 are removed from
1879 the array.
1880
1881 If the need is to remove some elements in the range but the order of
1882 the remaining elements does not have to be preserved, you may want to
1883 pass `SwapStrategy.unstable` to `remove`.
1884
1885 ----
1886 int[] a = [ 0, 1, 2, 3 ];
1887 assert(remove!(SwapStrategy.unstable)(a, 1) == [ 0, 3, 2 ]);
1888 ----
1889
1890 In the case above, the element at slot `1` is removed, but replaced
1891 with the last element of the range. Taking advantage of the relaxation
1892 of the stability requirement, `remove` moved elements from the end
1893 of the array over the slots to be removed. This way there is less data
1894 movement to be done which improves the execution time of the function.
1895
1896 The function `remove` works on bidirectional ranges that have assignable
1897 lvalue elements. The moving strategy is (listed from fastest to slowest):
1898
1899 $(UL
1900 $(LI If $(D s == SwapStrategy.unstable && isRandomAccessRange!Range &&
1901 hasLength!Range && hasLvalueElements!Range), then elements are moved from the
1902 end of the range into the slots to be filled. In this case, the absolute
1903 minimum of moves is performed.)
1904 $(LI Otherwise, if $(D s ==
1905 SwapStrategy.unstable && isBidirectionalRange!Range && hasLength!Range
1906 && hasLvalueElements!Range), then elements are still moved from the
1907 end of the range, but time is spent on advancing between slots by repeated
1908 calls to `range.popFront`.)
1909 $(LI Otherwise, elements are moved
1910 incrementally towards the front of `range`; a given element is never
1911 moved several times, but more elements are moved than in the previous
1912 cases.)
1913 )
1914
1915 Params:
1916 s = a SwapStrategy to determine if the original order needs to be preserved
1917 range = a $(REF_ALTTEXT bidirectional range, isBidirectionalRange, std,range,primitives)
1918 with a length member
1919 offset = which element(s) to remove
1920
1921 Returns:
1922 A range containing all of the elements of range with offset removed.
1923 */
1924 Range remove
1925 (SwapStrategy s = SwapStrategy.stable, Range, Offset ...)
1926 (Range range, Offset offset)
1927 if (Offset.length >= 1 && allSatisfy!(isValidIntegralTuple, Offset))
1928 {
1929 // Activate this check when the deprecation of non-integral tuples is over
1930 //import std.traits : isIntegral;
1931 //import std.typecons : isTuple;
1932 //static foreach (T; Offset)
1933 //{
1934 //static if (isTuple!T)
1935 //{
1936 //static assert(T.length == 2 &&
1937 //isIntegral!(typeof(T.init[0])) && isIntegral!(typeof(T.init[0])),
1938 //"Each offset must be an integral or a tuple of two integrals." ~
1939 //"Use `arr.remove(pos1, pos2)` or `arr.remove(tuple(start, begin))`");
1940 //}
1941 //else
1942 //{
1943 //static assert(isIntegral!T,
1944 //"Each offset must be an integral or a tuple of two integrals." ~
1945 //"Use `arr.remove(pos1, pos2)` or `arr.remove(tuple(start, begin))`");
1946 //}
1947 //}
1948 return removeImpl!s(range, offset);
1949 }
1950
1951 deprecated("Use of non-integral tuples is deprecated. Use remove(tuple(start, end).")
1952 Range remove
1953 (SwapStrategy s = SwapStrategy.stable, Range, Offset ...)
1954 (Range range, Offset offset)
1955 if (Offset.length >= 1 && !allSatisfy!(isValidIntegralTuple, Offset))
1956 {
1957 return removeImpl!s(range, offset);
1958 }
1959
1960 ///
1961 @safe pure unittest
1962 {
1963 import std.typecons : tuple;
1964
1965 auto a = [ 0, 1, 2, 3, 4, 5 ];
1966 assert(remove!(SwapStrategy.stable)(a, 1) == [ 0, 2, 3, 4, 5 ]);
1967 a = [ 0, 1, 2, 3, 4, 5 ];
1968 assert(remove!(SwapStrategy.stable)(a, 1, 3) == [ 0, 2, 4, 5] );
1969 a = [ 0, 1, 2, 3, 4, 5 ];
1970 assert(remove!(SwapStrategy.stable)(a, 1, tuple(3, 6)) == [ 0, 2 ]);
1971
1972 a = [ 0, 1, 2, 3, 4, 5 ];
1973 assert(remove!(SwapStrategy.unstable)(a, 1) == [0, 5, 2, 3, 4]);
1974 a = [ 0, 1, 2, 3, 4, 5 ];
1975 assert(remove!(SwapStrategy.unstable)(a, tuple(1, 4)) == [0, 5, 4]);
1976 }
1977
1978 ///
1979 @safe pure unittest
1980 {
1981 import std.typecons : tuple;
1982
1983 // Delete an index
1984 assert([4, 5, 6].remove(1) == [4, 6]);
1985
1986 // Delete multiple indices
1987 assert([4, 5, 6, 7, 8].remove(1, 3) == [4, 6, 8]);
1988
1989 // Use an indices range
1990 assert([4, 5, 6, 7, 8].remove(tuple(1, 3)) == [4, 7, 8]);
1991
1992 // Use an indices range and individual indices
1993 assert([4, 5, 6, 7, 8].remove(0, tuple(1, 3), 4) == [7]);
1994 }
1995
1996 /// `SwapStrategy.unstable` is faster, but doesn't guarantee the same order of the original array
1997 @safe pure unittest
1998 {
1999 assert([5, 6, 7, 8].remove!(SwapStrategy.stable)(1) == [5, 7, 8]);
2000 assert([5, 6, 7, 8].remove!(SwapStrategy.unstable)(1) == [5, 8, 7]);
2001 }
2002
2003 private auto removeImpl(SwapStrategy s, Range, Offset...)(Range range, Offset offset)
2004 {
2005 static if (isNarrowString!Range)
2006 {
2007 static assert(isMutable!(typeof(range[0])),
2008 "Elements must be mutable to remove");
2009 static assert(s == SwapStrategy.stable,
2010 "Only stable removing can be done for character arrays");
2011 return removeStableString(range, offset);
2012 }
2013 else
2014 {
2015 static assert(isBidirectionalRange!Range,
2016 "Range must be bidirectional");
2017 static assert(hasLvalueElements!Range,
2018 "Range must have Lvalue elements (see std.range.hasLvalueElements)");
2019
2020 static if (s == SwapStrategy.unstable)
2021 {
2022 static assert(hasLength!Range,
2023 "Range must have `length` for unstable remove");
2024 return removeUnstable(range, offset);
2025 }
2026 else static if (s == SwapStrategy.stable)
2027 return removeStable(range, offset);
2028 else
2029 static assert(false,
2030 "Only SwapStrategy.stable and SwapStrategy.unstable are supported");
2031 }
2032 }
2033
2034 @safe unittest
2035 {
2036 import std.exception : assertThrown;
2037 import std.range;
2038
2039 // https://issues.dlang.org/show_bug.cgi?id=10173
2040 int[] test = iota(0, 10).array();
2041 assertThrown(remove!(SwapStrategy.stable)(test, tuple(2, 4), tuple(1, 3)));
2042 assertThrown(remove!(SwapStrategy.unstable)(test, tuple(2, 4), tuple(1, 3)));
2043 assertThrown(remove!(SwapStrategy.stable)(test, 2, 4, 1, 3));
2044 assertThrown(remove!(SwapStrategy.unstable)(test, 2, 4, 1, 3));
2045 }
2046
2047 @safe unittest
2048 {
2049 import std.range;
2050 int[] a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
2051 a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
2052 assert(remove!(SwapStrategy.stable)(a, 1) ==
2053 [ 0, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]);
2054
2055 a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
2056 assert(remove!(SwapStrategy.unstable)(a, 0, 10) ==
2057 [ 9, 1, 2, 3, 4, 5, 6, 7, 8 ]);
2058
2059 a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
2060 assert(remove!(SwapStrategy.unstable)(a, 0, tuple(9, 11)) ==
2061 [ 8, 1, 2, 3, 4, 5, 6, 7 ]);
2062 // https://issues.dlang.org/show_bug.cgi?id=5224
2063 a = [ 1, 2, 3, 4 ];
2064 assert(remove!(SwapStrategy.unstable)(a, 2) ==
2065 [ 1, 2, 4 ]);
2066
2067 a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
2068 assert(remove!(SwapStrategy.stable)(a, 1, 5) ==
2069 [ 0, 2, 3, 4, 6, 7, 8, 9, 10 ]);
2070
2071 a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
2072 assert(remove!(SwapStrategy.stable)(a, 1, 3, 5)
2073 == [ 0, 2, 4, 6, 7, 8, 9, 10]);
2074 a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
2075 assert(remove!(SwapStrategy.stable)(a, 1, tuple(3, 5))
2076 == [ 0, 2, 5, 6, 7, 8, 9, 10]);
2077
2078 a = iota(0, 10).array();
2079 assert(remove!(SwapStrategy.unstable)(a, tuple(1, 4), tuple(6, 7))
2080 == [0, 9, 8, 7, 4, 5]);
2081 }
2082
2083 // https://issues.dlang.org/show_bug.cgi?id=11576
2084 @safe unittest
2085 {
2086 auto arr = [1,2,3];
2087 arr = arr.remove!(SwapStrategy.unstable)(2);
2088 assert(arr == [1,2]);
2089
2090 }
2091
2092 // https://issues.dlang.org/show_bug.cgi?id=12889
2093 @safe unittest
2094 {
2095 import std.range;
2096 int[1][] arr = [[0], [1], [2], [3], [4], [5], [6]];
2097 auto orig = arr.dup;
2098 foreach (i; iota(arr.length))
2099 {
2100 assert(orig == arr.remove!(SwapStrategy.unstable)(tuple(i,i)));
2101 assert(orig == arr.remove!(SwapStrategy.stable)(tuple(i,i)));
2102 }
2103 }
2104
2105 @safe unittest
2106 {
2107 char[] chars = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
2108 remove(chars, 4);
2109 assert(chars == ['a', 'b', 'c', 'd', 'f', 'g', 'h', 'h']);
2110
2111 char[] bigChars = "โˆ‘ล“โˆ†ยฌรฉหšห™ฦ’รฉโˆ‚รŸยกยก".dup;
2112 assert(remove(bigChars, tuple(4, 6), 8) == ("โˆ‘ล“โˆ†ยฌห™ฦ’โˆ‚รŸยกยก"));
2113
2114 import std.exception : assertThrown;
2115 assertThrown(remove(bigChars.dup, 1, 0));
2116 assertThrown(remove(bigChars.dup, tuple(4, 3)));
2117 }
2118
2119 private Range removeUnstable(Range, Offset...)(Range range, Offset offset)
2120 {
2121 Tuple!(size_t, "pos", size_t, "len")[offset.length] blackouts;
2122 foreach (i, v; offset)
2123 {
2124 static if (is(typeof(v[0]) : size_t) && is(typeof(v[1]) : size_t))
2125 {
2126 blackouts[i].pos = v[0];
2127 blackouts[i].len = v[1] - v[0];
2128 }
2129 else
2130 {
2131 static assert(is(typeof(v) : size_t), typeof(v).stringof);
2132 blackouts[i].pos = v;
2133 blackouts[i].len = 1;
2134 }
2135 static if (i > 0)
2136 {
2137 import std.exception : enforce;
2138
2139 enforce(blackouts[i - 1].pos + blackouts[i - 1].len
2140 <= blackouts[i].pos,
2141 "remove(): incorrect ordering of elements to remove");
2142 }
2143 }
2144
2145 size_t left = 0, right = offset.length - 1;
2146 auto tgt = range.save;
2147 size_t tgtPos = 0;
2148
2149 while (left <= right)
2150 {
2151 // Look for a blackout on the right
2152 if (blackouts[right].pos + blackouts[right].len >= range.length)
2153 {
2154 range.popBackExactly(blackouts[right].len);
2155
2156 // Since right is unsigned, we must check for this case, otherwise
2157 // we might turn it into size_t.max and the loop condition will not
2158 // fail when it should.
2159 if (right > 0)
2160 {
2161 --right;
2162 continue;
2163 }
2164 else
2165 break;
2166 }
2167 // Advance to next blackout on the left
2168 assert(blackouts[left].pos >= tgtPos, "Next blackout on the left shouldn't appear before the target.");
2169 tgt.popFrontExactly(blackouts[left].pos - tgtPos);
2170 tgtPos = blackouts[left].pos;
2171
2172 // Number of elements to the right of blackouts[right]
2173 immutable tailLen = range.length - (blackouts[right].pos + blackouts[right].len);
2174 size_t toMove = void;
2175 if (tailLen < blackouts[left].len)
2176 {
2177 toMove = tailLen;
2178 blackouts[left].pos += toMove;
2179 blackouts[left].len -= toMove;
2180 }
2181 else
2182 {
2183 toMove = blackouts[left].len;
2184 ++left;
2185 }
2186 tgtPos += toMove;
2187 foreach (i; 0 .. toMove)
2188 {
2189 move(range.back, tgt.front);
2190 range.popBack();
2191 tgt.popFront();
2192 }
2193 }
2194
2195 return range;
2196 }
2197
2198 private Range removeStable(Range, Offset...)(Range range, Offset offset)
2199 {
2200 auto result = range;
2201 auto src = range, tgt = range;
2202 size_t pos;
2203 foreach (pass, i; offset)
2204 {
2205 static if (is(typeof(i[0])) && is(typeof(i[1])))
2206 {
2207 auto from = i[0], delta = i[1] - i[0];
2208 }
2209 else
2210 {
2211 auto from = i;
2212 enum delta = 1;
2213 }
2214
2215 static if (pass > 0)
2216 {
2217 import std.exception : enforce;
2218 enforce(pos <= from,
2219 "remove(): incorrect ordering of elements to remove");
2220
2221 for (; pos < from; ++pos, src.popFront(), tgt.popFront())
2222 {
2223 move(src.front, tgt.front);
2224 }
2225 }
2226 else
2227 {
2228 src.popFrontExactly(from);
2229 tgt.popFrontExactly(from);
2230 pos = from;
2231 }
2232 // now skip source to the "to" position
2233 src.popFrontExactly(delta);
2234 result.popBackExactly(delta);
2235 pos += delta;
2236 }
2237 // leftover move
2238 moveAll(src, tgt);
2239 return result;
2240 }
2241
2242 private Range removeStableString(Range, Offset...)(Range range, Offset offsets)
2243 {
2244 import std.utf : stride;
2245 size_t charIdx = 0;
2246 size_t dcharIdx = 0;
2247 size_t charShift = 0;
2248
2249 void skipOne()
2250 {
2251 charIdx += stride(range[charIdx .. $]);
2252 ++dcharIdx;
2253 }
2254
2255 void copyBackOne()
2256 {
2257 auto encodedLen = stride(range[charIdx .. $]);
2258 foreach (j; charIdx .. charIdx + encodedLen)
2259 range[j - charShift] = range[j];
2260 charIdx += encodedLen;
2261 ++dcharIdx;
2262 }
2263
2264 foreach (pass, i; offsets)
2265 {
2266 static if (is(typeof(i[0])) && is(typeof(i[1])))
2267 {
2268 auto from = i[0];
2269 auto delta = i[1] - i[0];
2270 }
2271 else
2272 {
2273 auto from = i;
2274 enum delta = 1;
2275 }
2276
2277 import std.exception : enforce;
2278 enforce(dcharIdx <= from && delta >= 0,
2279 "remove(): incorrect ordering of elements to remove");
2280
2281 while (dcharIdx < from)
2282 static if (pass == 0)
2283 skipOne();
2284 else
2285 copyBackOne();
2286
2287 auto mark = charIdx;
2288 while (dcharIdx < from + delta)
2289 skipOne();
2290 charShift += charIdx - mark;
2291 }
2292
2293 foreach (i; charIdx .. range.length)
2294 range[i - charShift] = range[i];
2295
2296 return range[0 .. $ - charShift];
2297 }
2298
2299 // Use of dynamic arrays as offsets is too error-prone
2300 // https://issues.dlang.org/show_bug.cgi?id=12086
2301 // Activate these tests once the deprecation period of remove with non-integral tuples is over
2302 @safe unittest
2303 {
2304 //static assert(!__traits(compiles, [0, 1, 2, 3, 4].remove([1, 3]) == [0, 3, 4]));
2305 static assert(__traits(compiles, [0, 1, 2, 3, 4].remove(1, 3) == [0, 2, 4]));
2306 //static assert(!__traits(compiles, assert([0, 1, 2, 3, 4].remove([1, 3, 4]) == [0, 3, 4])));
2307 //static assert(!__traits(compiles, assert([0, 1, 2, 3, 4].remove(tuple(1, 3, 4)) == [0, 3, 4])));
2308
2309 import std.range : only;
2310 //static assert(!__traits(compiles, assert([0, 1, 2, 3, 4].remove(only(1, 3)) == [0, 3, 4])));
2311 static assert(__traits(compiles, assert([0, 1, 2, 3, 4].remove(1, 3) == [0, 2, 4])));
2312 }
2313
2314 /**
2315 Reduces the length of the
2316 $(REF_ALTTEXT bidirectional range, isBidirectionalRange, std,range,primitives) `range` by removing
2317 elements that satisfy `pred`. If `s = SwapStrategy.unstable`,
2318 elements are moved from the right end of the range over the elements
2319 to eliminate. If `s = SwapStrategy.stable` (the default),
2320 elements are moved progressively to front such that their relative
2321 order is preserved. Returns the filtered range.
2322
2323 Params:
2324 range = a bidirectional ranges with lvalue elements
2325 or mutable character arrays
2326
2327 Returns:
2328 the range with all of the elements where `pred` is `true`
2329 removed
2330 */
2331 Range remove(alias pred, SwapStrategy s = SwapStrategy.stable, Range)(Range range)
2332 {
2333 import std.functional : unaryFun;
2334 alias pred_ = unaryFun!pred;
2335 static if (isNarrowString!Range)
2336 {
2337 static assert(isMutable!(typeof(range[0])),
2338 "Elements must be mutable to remove");
2339 static assert(s == SwapStrategy.stable,
2340 "Only stable removing can be done for character arrays");
2341 return removePredString!pred_(range);
2342 }
2343 else
2344 {
2345 static assert(isBidirectionalRange!Range,
2346 "Range must be bidirectional");
2347 static assert(hasLvalueElements!Range,
2348 "Range must have Lvalue elements (see std.range.hasLvalueElements)");
2349 static if (s == SwapStrategy.unstable)
2350 return removePredUnstable!pred_(range);
2351 else static if (s == SwapStrategy.stable)
2352 return removePredStable!pred_(range);
2353 else
2354 static assert(false,
2355 "Only SwapStrategy.stable and SwapStrategy.unstable are supported");
2356 }
2357 }
2358
2359 ///
2360 @safe unittest
2361 {
2362 static immutable base = [1, 2, 3, 2, 4, 2, 5, 2];
2363
2364 int[] arr = base[].dup;
2365
2366 // using a string-based predicate
2367 assert(remove!("a == 2")(arr) == [ 1, 3, 4, 5 ]);
2368
2369 // The original array contents have been modified,
2370 // so we need to reset it to its original state.
2371 // The length is unmodified however.
2372 arr[] = base[];
2373
2374 // using a lambda predicate
2375 assert(remove!(a => a == 2)(arr) == [ 1, 3, 4, 5 ]);
2376 }
2377
2378 @safe unittest
2379 {
2380 int[] a = [ 1, 2, 3, 2, 3, 4, 5, 2, 5, 6 ];
2381 assert(remove!("a == 2", SwapStrategy.unstable)(a) ==
2382 [ 1, 6, 3, 5, 3, 4, 5 ]);
2383 a = [ 1, 2, 3, 2, 3, 4, 5, 2, 5, 6 ];
2384 assert(remove!("a == 2", SwapStrategy.stable)(a) ==
2385 [ 1, 3, 3, 4, 5, 5, 6 ]);
2386 }
2387
2388 @nogc @safe unittest
2389 {
2390 // @nogc test
2391 static int[] arr = [0,1,2,3,4,5,6,7,8,9];
2392 alias pred = e => e < 5;
2393
2394 auto r = arr[].remove!(SwapStrategy.unstable)(0);
2395 r = r.remove!(SwapStrategy.stable)(0);
2396 r = r.remove!(pred, SwapStrategy.unstable);
2397 r = r.remove!(pred, SwapStrategy.stable);
2398 }
2399
2400 @safe unittest
2401 {
2402 import std.algorithm.comparison : min;
2403 import std.algorithm.searching : all, any;
2404 import std.algorithm.sorting : isStrictlyMonotonic;
2405 import std.array : array;
2406 import std.meta : AliasSeq;
2407 import std.range : iota, only;
2408 import std.typecons : Tuple;
2409 alias E = Tuple!(int, int);
2410 alias S = Tuple!(E);
2411 S[] soffsets;
2412 foreach (start; 0 .. 5)
2413 foreach (end; min(start+1,5) .. 5)
2414 soffsets ~= S(E(start,end));
2415 alias D = Tuple!(E, E);
2416 D[] doffsets;
2417 foreach (start1; 0 .. 10)
2418 foreach (end1; min(start1+1,10) .. 10)
2419 foreach (start2; end1 .. 10)
2420 foreach (end2; min(start2+1,10) .. 10)
2421 doffsets ~= D(E(start1,end1),E(start2,end2));
2422 alias T = Tuple!(E, E, E);
2423 T[] toffsets;
2424 foreach (start1; 0 .. 15)
2425 foreach (end1; min(start1+1,15) .. 15)
2426 foreach (start2; end1 .. 15)
2427 foreach (end2; min(start2+1,15) .. 15)
2428 foreach (start3; end2 .. 15)
2429 foreach (end3; min(start3+1,15) .. 15)
2430 toffsets ~= T(E(start1,end1),E(start2,end2),E(start3,end3));
2431
2432 static void verify(O...)(int[] r, int len, int removed, bool stable, O offsets)
2433 {
2434 assert(r.length == len - removed);
2435 assert(!stable || r.isStrictlyMonotonic);
2436 assert(r.all!(e => all!(o => e < o[0] || e >= o[1])(offsets.only)));
2437 }
2438
2439 static foreach (offsets; AliasSeq!(soffsets,doffsets,toffsets))
2440 foreach (os; offsets)
2441 {
2442 int len = 5*os.length;
2443 auto w = iota(0, len).array;
2444 auto x = w.dup;
2445 auto y = w.dup;
2446 auto z = w.dup;
2447 alias pred = e => any!(o => o[0] <= e && e < o[1])(only(os.expand));
2448 w = w.remove!(SwapStrategy.unstable)(os.expand);
2449 x = x.remove!(SwapStrategy.stable)(os.expand);
2450 y = y.remove!(pred, SwapStrategy.unstable);
2451 z = z.remove!(pred, SwapStrategy.stable);
2452 int removed;
2453 foreach (o; os)
2454 removed += o[1] - o[0];
2455 verify(w, len, removed, false, os[]);
2456 verify(x, len, removed, true, os[]);
2457 verify(y, len, removed, false, os[]);
2458 verify(z, len, removed, true, os[]);
2459 assert(w == y);
2460 assert(x == z);
2461 }
2462 }
2463
2464 @safe unittest
2465 {
2466 char[] chars = "abcdefg".dup;
2467 assert(chars.remove!(dc => dc == 'c' || dc == 'f') == "abdeg");
2468 assert(chars == "abdegfg");
2469
2470 assert(chars.remove!"a == 'd'" == "abegfg");
2471
2472 char[] bigChars = "ยฅ^ยจ^ยฉรฉโˆšโˆ†ฯ€".dup;
2473 assert(bigChars.remove!(dc => dc == "ยจ"d[0] || dc == "รฉ"d[0]) == "ยฅ^^ยฉโˆšโˆ†ฯ€");
2474 }
2475
2476 private Range removePredUnstable(alias pred, Range)(Range range)
2477 {
2478 auto result = range;
2479 for (;!range.empty;)
2480 {
2481 if (!pred(range.front))
2482 {
2483 range.popFront();
2484 continue;
2485 }
2486 move(range.back, range.front);
2487 range.popBack();
2488 result.popBack();
2489 }
2490 return result;
2491 }
2492
2493 private Range removePredStable(alias pred, Range)(Range range)
2494 {
2495 auto result = range;
2496 auto tgt = range;
2497 for (; !range.empty; range.popFront())
2498 {
2499 if (pred(range.front))
2500 {
2501 // yank this guy
2502 result.popBack();
2503 continue;
2504 }
2505 // keep this guy
2506 move(range.front, tgt.front);
2507 tgt.popFront();
2508 }
2509 return result;
2510 }
2511
2512 private Range removePredString(alias pred, SwapStrategy s = SwapStrategy.stable, Range)
2513 (Range range)
2514 {
2515 import std.utf : decode;
2516 import std.functional : unaryFun;
2517
2518 alias pred_ = unaryFun!pred;
2519
2520 size_t charIdx = 0;
2521 size_t charShift = 0;
2522 while (charIdx < range.length)
2523 {
2524 size_t start = charIdx;
2525 if (pred_(decode(range, charIdx)))
2526 {
2527 charShift += charIdx - start;
2528 break;
2529 }
2530 }
2531 while (charIdx < range.length)
2532 {
2533 size_t start = charIdx;
2534 auto doRemove = pred_(decode(range, charIdx));
2535 auto encodedLen = charIdx - start;
2536 if (doRemove)
2537 charShift += encodedLen;
2538 else
2539 foreach (i; start .. charIdx)
2540 range[i - charShift] = range[i];
2541 }
2542
2543 return range[0 .. $ - charShift];
2544 }
2545
2546 // reverse
2547 /**
2548 Reverses `r` in-place. Performs `r.length / 2` evaluations of `swap`.
2549 UTF sequences consisting of multiple code units are preserved properly.
2550
2551 Params:
2552 r = a $(REF_ALTTEXT bidirectional range, isBidirectionalRange, std,range,primitives)
2553 with either swappable elements, a random access range with a length member,
2554 or a narrow string
2555
2556 Returns: `r`
2557
2558 Note:
2559 When passing a string with unicode modifiers on characters, such as `\u0301`,
2560 this function will not properly keep the position of the modifier. For example,
2561 reversing `ba\u0301d` ("bรกd") will result in d\u0301ab ("dฬab") instead of
2562 `da\u0301b` ("dรกb").
2563
2564 See_Also: $(REF retro, std,range) for a lazy reverse without changing `r`
2565 */
2566 Range reverse(Range)(Range r)
2567 if (isBidirectionalRange!Range &&
2568 (hasSwappableElements!Range ||
2569 (hasAssignableElements!Range && hasLength!Range && isRandomAccessRange!Range) ||
2570 (isNarrowString!Range && isAssignable!(ElementType!Range))))
2571 {
2572 static if (isRandomAccessRange!Range && hasLength!Range)
2573 {
2574 //swapAt is in fact the only way to swap non lvalue ranges
2575 immutable last = r.length - 1;
2576 immutable steps = r.length / 2;
2577 for (size_t i = 0; i < steps; i++)
2578 {
2579 r.swapAt(i, last - i);
2580 }
2581 return r;
2582 }
2583 else static if (isNarrowString!Range && isAssignable!(ElementType!Range))
2584 {
2585 import std.string : representation;
2586 import std.utf : stride;
2587
2588 auto raw = representation(r);
2589 for (size_t i = 0; i < r.length;)
2590 {
2591 immutable step = stride(r, i);
2592 if (step > 1)
2593 {
2594 .reverse(raw[i .. i + step]);
2595 i += step;
2596 }
2597 else
2598 {
2599 ++i;
2600 }
2601 }
2602 reverse(raw);
2603 return r;
2604 }
2605 else
2606 {
2607 while (!r.empty)
2608 {
2609 swap(r.front, r.back);
2610 r.popFront();
2611 if (r.empty) break;
2612 r.popBack();
2613 }
2614 return r;
2615 }
2616 }
2617
2618 ///
2619 @safe unittest
2620 {
2621 int[] arr = [ 1, 2, 3 ];
2622 assert(arr.reverse == [ 3, 2, 1 ]);
2623 }
2624
2625 @safe unittest
2626 {
2627 int[] range = null;
2628 reverse(range);
2629 range = [ 1 ];
2630 reverse(range);
2631 assert(range == [1]);
2632 range = [1, 2];
2633 reverse(range);
2634 assert(range == [2, 1]);
2635 range = [1, 2, 3];
2636 assert(range.reverse == [3, 2, 1]);
2637 }
2638
2639 ///
2640 @safe unittest
2641 {
2642 char[] arr = "hello\U00010143\u0100\U00010143".dup;
2643 assert(arr.reverse == "\U00010143\u0100\U00010143olleh");
2644 }
2645
2646 @safe unittest
2647 {
2648 void test(string a, string b)
2649 {
2650 auto c = a.dup;
2651 reverse(c);
2652 assert(c == b, c ~ " != " ~ b);
2653 }
2654
2655 test("a", "a");
2656 test(" ", " ");
2657 test("\u2029", "\u2029");
2658 test("\u0100", "\u0100");
2659 test("\u0430", "\u0430");
2660 test("\U00010143", "\U00010143");
2661 test("abcdefcdef", "fedcfedcba");
2662 test("hello\U00010143\u0100\U00010143", "\U00010143\u0100\U00010143olleh");
2663 }
2664
2665 /**
2666 The strip group of functions allow stripping of either leading, trailing,
2667 or both leading and trailing elements.
2668
2669 The `stripLeft` function will strip the `front` of the range,
2670 the `stripRight` function will strip the `back` of the range,
2671 while the `strip` function will strip both the `front` and `back`
2672 of the range.
2673
2674 Note that the `strip` and `stripRight` functions require the range to
2675 be a $(LREF BidirectionalRange) range.
2676
2677 All of these functions come in two varieties: one takes a target element,
2678 where the range will be stripped as long as this element can be found.
2679 The other takes a lambda predicate, where the range will be stripped as
2680 long as the predicate returns true.
2681
2682 Params:
2683 range = a $(REF_ALTTEXT bidirectional range, isBidirectionalRange, std,range,primitives)
2684 or $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
2685 element = the elements to remove
2686
2687 Returns:
2688 a Range with all of range except element at the start and end
2689 */
2690 Range strip(Range, E)(Range range, E element)
2691 if (isBidirectionalRange!Range && is(typeof(range.front == element) : bool))
2692 {
2693 return range.stripLeft(element).stripRight(element);
2694 }
2695
2696 /// ditto
2697 Range strip(alias pred, Range)(Range range)
2698 if (isBidirectionalRange!Range && is(typeof(pred(range.back)) : bool))
2699 {
2700 return range.stripLeft!pred().stripRight!pred();
2701 }
2702
2703 /// ditto
2704 Range stripLeft(Range, E)(Range range, E element)
2705 if (isInputRange!Range && is(typeof(range.front == element) : bool))
2706 {
2707 import std.algorithm.searching : find;
2708 return find!((auto ref a) => a != element)(range);
2709 }
2710
2711 /// ditto
2712 Range stripLeft(alias pred, Range)(Range range)
2713 if (isInputRange!Range && is(typeof(pred(range.front)) : bool))
2714 {
2715 import std.algorithm.searching : find;
2716 import std.functional : not;
2717
2718 return find!(not!pred)(range);
2719 }
2720
2721 /// ditto
2722 Range stripRight(Range, E)(Range range, E element)
2723 if (isBidirectionalRange!Range && is(typeof(range.back == element) : bool))
2724 {
2725 for (; !range.empty; range.popBack())
2726 {
2727 if (range.back != element)
2728 break;
2729 }
2730 return range;
2731 }
2732
2733 /// ditto
2734 Range stripRight(alias pred, Range)(Range range)
2735 if (isBidirectionalRange!Range && is(typeof(pred(range.back)) : bool))
2736 {
2737 for (; !range.empty; range.popBack())
2738 {
2739 if (!pred(range.back))
2740 break;
2741 }
2742 return range;
2743 }
2744
2745 /// Strip leading and trailing elements equal to the target element.
2746 @safe pure unittest
2747 {
2748 assert(" foobar ".strip(' ') == "foobar");
2749 assert("00223.444500".strip('0') == "223.4445");
2750 assert("รซรซรชรฉรผล—ลpรฉรชรซรซ".strip('รซ') == "รชรฉรผล—ลpรฉรช");
2751 assert([1, 1, 0, 1, 1].strip(1) == [0]);
2752 assert([0.0, 0.01, 0.01, 0.0].strip(0).length == 2);
2753 }
2754
2755 /// Strip leading and trailing elements while the predicate returns true.
2756 @safe pure unittest
2757 {
2758 assert(" foobar ".strip!(a => a == ' ')() == "foobar");
2759 assert("00223.444500".strip!(a => a == '0')() == "223.4445");
2760 assert("รซรซรชรฉรผล—ลpรฉรชรซรซ".strip!(a => a == 'รซ')() == "รชรฉรผล—ลpรฉรช");
2761 assert([1, 1, 0, 1, 1].strip!(a => a == 1)() == [0]);
2762 assert([0.0, 0.01, 0.5, 0.6, 0.01, 0.0].strip!(a => a < 0.4)().length == 2);
2763 }
2764
2765 /// Strip leading elements equal to the target element.
2766 @safe pure unittest
2767 {
2768 assert(" foobar ".stripLeft(' ') == "foobar ");
2769 assert("00223.444500".stripLeft('0') == "223.444500");
2770 assert("ลฏลฏลฑniรงodรชรฉรฉ".stripLeft('ลฏ') == "ลฑniรงodรชรฉรฉ");
2771 assert([1, 1, 0, 1, 1].stripLeft(1) == [0, 1, 1]);
2772 assert([0.0, 0.01, 0.01, 0.0].stripLeft(0).length == 3);
2773 }
2774
2775 /// Strip leading elements while the predicate returns true.
2776 @safe pure unittest
2777 {
2778 assert(" foobar ".stripLeft!(a => a == ' ')() == "foobar ");
2779 assert("00223.444500".stripLeft!(a => a == '0')() == "223.444500");
2780 assert("ลฏลฏลฑniรงodรชรฉรฉ".stripLeft!(a => a == 'ลฏ')() == "ลฑniรงodรชรฉรฉ");
2781 assert([1, 1, 0, 1, 1].stripLeft!(a => a == 1)() == [0, 1, 1]);
2782 assert([0.0, 0.01, 0.10, 0.5, 0.6].stripLeft!(a => a < 0.4)().length == 2);
2783 }
2784
2785 /// Strip trailing elements equal to the target element.
2786 @safe pure unittest
2787 {
2788 assert(" foobar ".stripRight(' ') == " foobar");
2789 assert("00223.444500".stripRight('0') == "00223.4445");
2790 assert("รนniรงodรชรฉรฉ".stripRight('รฉ') == "รนniรงodรช");
2791 assert([1, 1, 0, 1, 1].stripRight(1) == [1, 1, 0]);
2792 assert([0.0, 0.01, 0.01, 0.0].stripRight(0).length == 3);
2793 }
2794
2795 /// Strip trailing elements while the predicate returns true.
2796 @safe pure unittest
2797 {
2798 assert(" foobar ".stripRight!(a => a == ' ')() == " foobar");
2799 assert("00223.444500".stripRight!(a => a == '0')() == "00223.4445");
2800 assert("รนniรงodรชรฉรฉ".stripRight!(a => a == 'รฉ')() == "รนniรงodรช");
2801 assert([1, 1, 0, 1, 1].stripRight!(a => a == 1)() == [1, 1, 0]);
2802 assert([0.0, 0.01, 0.10, 0.5, 0.6].stripRight!(a => a > 0.4)().length == 3);
2803 }
2804
2805 // swap
2806 /**
2807 Swaps `lhs` and `rhs`. The instances `lhs` and `rhs` are moved in
2808 memory, without ever calling `opAssign`, nor any other function. `T`
2809 need not be assignable at all to be swapped.
2810
2811 If `lhs` and `rhs` reference the same instance, then nothing is done.
2812
2813 `lhs` and `rhs` must be mutable. If `T` is a struct or union, then
2814 its fields must also all be (recursively) mutable.
2815
2816 Params:
2817 lhs = Data to be swapped with `rhs`.
2818 rhs = Data to be swapped with `lhs`.
2819 */
2820 void swap(T)(ref T lhs, ref T rhs) @trusted pure nothrow @nogc
2821 if (isBlitAssignable!T && !is(typeof(lhs.proxySwap(rhs))))
2822 {
2823 import std.traits : hasAliasing, hasElaborateAssign, isAssignable,
2824 isStaticArray;
2825 static if (hasAliasing!T) if (!__ctfe)
2826 {
2827 import std.exception : doesPointTo;
2828 assert(!doesPointTo(lhs, lhs), "Swap: lhs internal pointer.");
2829 assert(!doesPointTo(rhs, rhs), "Swap: rhs internal pointer.");
2830 assert(!doesPointTo(lhs, rhs), "Swap: lhs points to rhs.");
2831 assert(!doesPointTo(rhs, lhs), "Swap: rhs points to lhs.");
2832 }
2833
2834 static if (hasElaborateAssign!T || !isAssignable!T)
2835 {
2836 if (&lhs != &rhs)
2837 {
2838 // For structs with non-trivial assignment, move memory directly
2839 ubyte[T.sizeof] t = void;
2840 auto a = (cast(ubyte*) &lhs)[0 .. T.sizeof];
2841 auto b = (cast(ubyte*) &rhs)[0 .. T.sizeof];
2842 t[] = a[];
2843 a[] = b[];
2844 b[] = t[];
2845 }
2846 }
2847 else
2848 {
2849 //Avoid assigning overlapping arrays. Dynamic arrays are fine, because
2850 //it's their ptr and length properties which get assigned rather
2851 //than their elements when assigning them, but static arrays are value
2852 //types and therefore all of their elements get copied as part of
2853 //assigning them, which would be assigning overlapping arrays if lhs
2854 //and rhs were the same array.
2855 static if (isStaticArray!T)
2856 {
2857 if (lhs.ptr == rhs.ptr)
2858 return;
2859 }
2860
2861 // For non-elaborate-assign types, suffice to do the classic swap
2862 static if (__traits(hasCopyConstructor, T))
2863 {
2864 // don't invoke any elaborate constructors either
2865 T tmp = void;
2866 tmp = lhs;
2867 }
2868 else
2869 auto tmp = lhs;
2870 lhs = rhs;
2871 rhs = tmp;
2872 }
2873 }
2874
2875 ///
2876 @safe unittest
2877 {
2878 // Swapping POD (plain old data) types:
2879 int a = 42, b = 34;
2880 swap(a, b);
2881 assert(a == 34 && b == 42);
2882
2883 // Swapping structs with indirection:
2884 static struct S { int x; char c; int[] y; }
2885 S s1 = { 0, 'z', [ 1, 2 ] };
2886 S s2 = { 42, 'a', [ 4, 6 ] };
2887 swap(s1, s2);
2888 assert(s1.x == 42);
2889 assert(s1.c == 'a');
2890 assert(s1.y == [ 4, 6 ]);
2891
2892 assert(s2.x == 0);
2893 assert(s2.c == 'z');
2894 assert(s2.y == [ 1, 2 ]);
2895
2896 // Immutables cannot be swapped:
2897 immutable int imm1 = 1, imm2 = 2;
2898 static assert(!__traits(compiles, swap(imm1, imm2)));
2899
2900 int c = imm1 + 0;
2901 int d = imm2 + 0;
2902 swap(c, d);
2903 assert(c == 2);
2904 assert(d == 1);
2905 }
2906
2907 ///
2908 @safe unittest
2909 {
2910 // Non-copyable types can still be swapped.
2911 static struct NoCopy
2912 {
2913 this(this) { assert(0); }
2914 int n;
2915 string s;
2916 }
2917 NoCopy nc1, nc2;
2918 nc1.n = 127; nc1.s = "abc";
2919 nc2.n = 513; nc2.s = "uvwxyz";
2920
2921 swap(nc1, nc2);
2922 assert(nc1.n == 513 && nc1.s == "uvwxyz");
2923 assert(nc2.n == 127 && nc2.s == "abc");
2924
2925 swap(nc1, nc1);
2926 swap(nc2, nc2);
2927 assert(nc1.n == 513 && nc1.s == "uvwxyz");
2928 assert(nc2.n == 127 && nc2.s == "abc");
2929
2930 // Types containing non-copyable fields can also be swapped.
2931 static struct NoCopyHolder
2932 {
2933 NoCopy noCopy;
2934 }
2935 NoCopyHolder h1, h2;
2936 h1.noCopy.n = 31; h1.noCopy.s = "abc";
2937 h2.noCopy.n = 65; h2.noCopy.s = null;
2938
2939 swap(h1, h2);
2940 assert(h1.noCopy.n == 65 && h1.noCopy.s == null);
2941 assert(h2.noCopy.n == 31 && h2.noCopy.s == "abc");
2942
2943 swap(h1, h1);
2944 swap(h2, h2);
2945 assert(h1.noCopy.n == 65 && h1.noCopy.s == null);
2946 assert(h2.noCopy.n == 31 && h2.noCopy.s == "abc");
2947
2948 // Const types cannot be swapped.
2949 const NoCopy const1, const2;
2950 assert(const1.n == 0 && const2.n == 0);
2951 static assert(!__traits(compiles, swap(const1, const2)));
2952 }
2953
2954 // https://issues.dlang.org/show_bug.cgi?id=4789
2955 @safe unittest
2956 {
2957 int[1] s = [1];
2958 swap(s, s);
2959
2960 int[3] a = [1, 2, 3];
2961 swap(a[1], a[2]);
2962 assert(a == [1, 3, 2]);
2963 }
2964
2965 @safe unittest
2966 {
2967 static struct NoAssign
2968 {
2969 int i;
2970 void opAssign(NoAssign) @disable;
2971 }
2972 auto s1 = NoAssign(1);
2973 auto s2 = NoAssign(2);
2974 swap(s1, s2);
2975 assert(s1.i == 2);
2976 assert(s2.i == 1);
2977 }
2978
2979 @safe unittest
2980 {
2981 struct S
2982 {
2983 const int i;
2984 int i2 = 2;
2985 int i3 = 3;
2986 }
2987 S s;
2988 static assert(!__traits(compiles, swap(s, s)));
2989 swap(s.i2, s.i3);
2990 assert(s.i2 == 3);
2991 assert(s.i3 == 2);
2992 }
2993
2994 // https://issues.dlang.org/show_bug.cgi?id=11853
2995 @safe unittest
2996 {
2997 import std.traits : isAssignable;
2998 alias T = Tuple!(int, double);
2999 static assert(isAssignable!T);
3000 }
3001
3002 // https://issues.dlang.org/show_bug.cgi?id=12024
3003 @safe unittest
3004 {
3005 import std.datetime;
3006 SysTime a, b;
3007 swap(a, b);
3008 }
3009
3010 // https://issues.dlang.org/show_bug.cgi?id=9975
3011 @system unittest
3012 {
3013 import std.exception : doesPointTo, mayPointTo;
3014 static struct S2
3015 {
3016 union
3017 {
3018 size_t sz;
3019 string s;
3020 }
3021 }
3022 S2 a , b;
3023 a.sz = -1;
3024 assert(!doesPointTo(a, b));
3025 assert( mayPointTo(a, b));
3026 swap(a, b);
3027
3028 //Note: we can catch an error here, because there is no RAII in this test
3029 import std.exception : assertThrown;
3030 void* p, pp;
3031 p = &p;
3032 assertThrown!Error(move(p));
3033 assertThrown!Error(move(p, pp));
3034 assertThrown!Error(swap(p, pp));
3035 }
3036
3037 @system unittest
3038 {
3039 static struct A
3040 {
3041 int* x;
3042 this(this) { x = new int; }
3043 }
3044 A a1, a2;
3045 swap(a1, a2);
3046
3047 static struct B
3048 {
3049 int* x;
3050 void opAssign(B) { x = new int; }
3051 }
3052 B b1, b2;
3053 swap(b1, b2);
3054 }
3055
3056 // issue 20732
3057 @safe unittest
3058 {
3059 static struct A
3060 {
3061 int x;
3062 this(scope ref return const A other)
3063 {
3064 import std.stdio;
3065 x = other.x;
3066 // note, struct functions inside @safe functions infer ALL
3067 // attributes, so the following 3 lines are meant to prevent this.
3068 new int; // prevent @nogc inference
3069 writeln("impure"); // prevent pure inference
3070 throw new Exception(""); // prevent nothrow inference
3071 }
3072 }
3073
3074 A a1, a2;
3075 swap(a1, a2);
3076
3077 A[1] a3, a4;
3078 swap(a3, a4);
3079 }
3080
3081 /// ditto
3082 void swap(T)(ref T lhs, ref T rhs)
3083 if (is(typeof(lhs.proxySwap(rhs))))
3084 {
3085 lhs.proxySwap(rhs);
3086 }
3087
3088 /**
3089 Swaps two elements in-place of a range `r`,
3090 specified by their indices `i1` and `i2`.
3091
3092 Params:
3093 r = a range with swappable elements
3094 i1 = first index
3095 i2 = second index
3096 */
3097 void swapAt(R)(auto ref R r, size_t i1, size_t i2)
3098 {
3099 static if (is(typeof(&r.swapAt)))
3100 {
3101 r.swapAt(i1, i2);
3102 }
3103 else static if (is(typeof(&r[i1])))
3104 {
3105 swap(r[i1], r[i2]);
3106 }
3107 else
3108 {
3109 if (i1 == i2) return;
3110 auto t1 = r.moveAt(i1);
3111 auto t2 = r.moveAt(i2);
3112 r[i2] = t1;
3113 r[i1] = t2;
3114 }
3115 }
3116
3117 ///
3118 pure @safe nothrow unittest
3119 {
3120 import std.algorithm.comparison : equal;
3121 auto a = [1, 2, 3];
3122 a.swapAt(1, 2);
3123 assert(a.equal([1, 3, 2]));
3124 }
3125
3126 pure @safe nothrow unittest
3127 {
3128 import std.algorithm.comparison : equal;
3129 auto a = [4, 5, 6];
3130 a.swapAt(1, 1);
3131 assert(a.equal([4, 5, 6]));
3132 }
3133
3134 pure @safe nothrow unittest
3135 {
3136 // test non random access ranges
3137 import std.algorithm.comparison : equal;
3138 import std.array : array;
3139
3140 char[] b = ['a', 'b', 'c'];
3141 b.swapAt(1, 2);
3142 assert(b.equal(['a', 'c', 'b']));
3143
3144 int[3] c = [1, 2, 3];
3145 c.swapAt(1, 2);
3146 assert(c.array.equal([1, 3, 2]));
3147
3148 // opIndex returns lvalue
3149 struct RandomIndexType(T)
3150 {
3151 T payload;
3152
3153 @property ref auto opIndex(size_t i)
3154 {
3155 return payload[i];
3156 }
3157
3158 }
3159 auto d = RandomIndexType!(int[])([4, 5, 6]);
3160 d.swapAt(1, 2);
3161 assert(d.payload.equal([4, 6, 5]));
3162
3163 // custom moveAt and opIndexAssign
3164 struct RandomMoveAtType(T)
3165 {
3166 T payload;
3167
3168 ElementType!T moveAt(size_t i)
3169 {
3170 return payload.moveAt(i);
3171 }
3172
3173 void opIndexAssign(ElementType!T val, size_t idx)
3174 {
3175 payload[idx] = val;
3176 }
3177 }
3178 auto e = RandomMoveAtType!(int[])([7, 8, 9]);
3179 e.swapAt(1, 2);
3180 assert(e.payload.equal([7, 9, 8]));
3181
3182
3183 // custom swapAt
3184 struct RandomSwapAtType(T)
3185 {
3186 T payload;
3187
3188 void swapAt(size_t i)
3189 {
3190 return payload.swapAt(i);
3191 }
3192 }
3193 auto f = RandomMoveAtType!(int[])([10, 11, 12]);
3194 swapAt(f, 1, 2);
3195 assert(f.payload.equal([10, 12, 11]));
3196 }
3197
3198 private void swapFront(R1, R2)(R1 r1, R2 r2)
3199 if (isInputRange!R1 && isInputRange!R2)
3200 {
3201 static if (is(typeof(swap(r1.front, r2.front))))
3202 {
3203 swap(r1.front, r2.front);
3204 }
3205 else
3206 {
3207 auto t1 = moveFront(r1), t2 = moveFront(r2);
3208 r1.front = move(t2);
3209 r2.front = move(t1);
3210 }
3211 }
3212
3213 // swapRanges
3214 /**
3215 Swaps all elements of `r1` with successive elements in `r2`.
3216 Returns a tuple containing the remainder portions of `r1` and $(D
3217 r2) that were not swapped (one of them will be empty). The ranges may
3218 be of different types but must have the same element type and support
3219 swapping.
3220
3221 Params:
3222 r1 = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
3223 with swappable elements
3224 r2 = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
3225 with swappable elements
3226
3227 Returns:
3228 Tuple containing the remainder portions of r1 and r2 that were not swapped
3229 */
3230 Tuple!(InputRange1, InputRange2)
3231 swapRanges(InputRange1, InputRange2)(InputRange1 r1, InputRange2 r2)
3232 if (hasSwappableElements!InputRange1 && hasSwappableElements!InputRange2
3233 && is(ElementType!InputRange1 == ElementType!InputRange2))
3234 {
3235 for (; !r1.empty && !r2.empty; r1.popFront(), r2.popFront())
3236 {
3237 swap(r1.front, r2.front);
3238 }
3239 return tuple(r1, r2);
3240 }
3241
3242 ///
3243 @safe unittest
3244 {
3245 import std.range : empty;
3246 int[] a = [ 100, 101, 102, 103 ];
3247 int[] b = [ 0, 1, 2, 3 ];
3248 auto c = swapRanges(a[1 .. 3], b[2 .. 4]);
3249 assert(c[0].empty && c[1].empty);
3250 assert(a == [ 100, 2, 3, 103 ]);
3251 assert(b == [ 0, 1, 101, 102 ]);
3252 }
3253
3254 /**
3255 Initializes each element of `range` with `value`.
3256 Assumes that the elements of the range are uninitialized.
3257 This is of interest for structs that
3258 define copy constructors (for all other types, $(LREF fill) and
3259 uninitializedFill are equivalent).
3260
3261 Params:
3262 range = An
3263 $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
3264 that exposes references to its elements and has assignable
3265 elements
3266 value = Assigned to each element of range
3267
3268 See_Also:
3269 $(LREF fill)
3270 $(LREF initializeAll)
3271 */
3272 void uninitializedFill(Range, Value)(Range range, Value value)
3273 if (isInputRange!Range && hasLvalueElements!Range && is(typeof(range.front = value)))
3274 {
3275 import std.traits : hasElaborateAssign;
3276
3277 alias T = ElementType!Range;
3278 static if (hasElaborateAssign!T)
3279 {
3280 import core.internal.lifetime : emplaceRef;
3281
3282 // Must construct stuff by the book
3283 for (; !range.empty; range.popFront())
3284 emplaceRef!T(range.front, value);
3285 }
3286 else
3287 // Doesn't matter whether fill is initialized or not
3288 return fill(range, value);
3289 }
3290
3291 ///
3292 nothrow @system unittest
3293 {
3294 import core.stdc.stdlib : malloc, free;
3295
3296 auto s = (cast(int*) malloc(5 * int.sizeof))[0 .. 5];
3297 uninitializedFill(s, 42);
3298 assert(s == [ 42, 42, 42, 42, 42 ]);
3299
3300 scope(exit) free(s.ptr);
3301 }