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