1 // Written in the D programming language. 2 3 /** 4 This module defines the notion of a range. Ranges generalize the concept of 5 arrays, lists, or anything that involves sequential access. This abstraction 6 enables the same set of algorithms (see $(MREF std, algorithm)) to be used 7 with a vast variety of different concrete types. For example, 8 a linear search algorithm such as $(REF find, std, algorithm, searching) 9 works not just for arrays, but for linked-lists, input files, 10 incoming network data, etc. 11 12 Guides: 13 14 There are many articles available that can bolster understanding ranges: 15 16 $(UL 17 $(LI Ali Çehreli's $(HTTP ddili.org/ders/d.en/ranges.html, tutorial on ranges) 18 for the basics of working with and creating range-based code.) 19 $(LI Jonathan M. Davis $(LINK2 http://dconf.org/2015/talks/davis.html, $(I Introduction to Ranges)) 20 talk at DConf 2015 a vivid introduction from its core constructs to practical advice.) 21 $(LI The DLang Tour's $(LINK2 http://tour.dlang.org/tour/en/basics/ranges, chapter on ranges) 22 for an interactive introduction.) 23 $(LI H. S. Teoh's $(LINK2 http://wiki.dlang.org/Component_programming_with_ranges, tutorial on 24 component programming with ranges) for a real-world showcase of the influence 25 of range-based programming on complex algorithms.) 26 $(LI Andrei Alexandrescu's article 27 $(LINK2 http://www.informit.com/articles/printerfriendly.aspx?p=1407357$(AMP)rll=1, 28 $(I On Iteration)) for conceptual aspect of ranges and the motivation 29 ) 30 ) 31 32 Submodules: 33 34 This module has two submodules: 35 36 The $(MREF std, range, primitives) submodule 37 provides basic range functionality. It defines several templates for testing 38 whether a given object is a range, what kind of range it is, and provides 39 some common range operations. 40 41 The $(MREF std, range, interfaces) submodule 42 provides object-based interfaces for working with ranges via runtime 43 polymorphism. 44 45 The remainder of this module provides a rich set of range creation and 46 composition templates that let you construct new ranges out of existing ranges: 47 48 49 $(SCRIPT inhibitQuickIndex = 1;) 50 $(DIVC quickindex, 51 $(BOOKTABLE , 52 $(TR $(TD $(LREF chain)) 53 $(TD Concatenates several ranges into a single range. 54 )) 55 $(TR $(TD $(LREF choose)) 56 $(TD Chooses one of two ranges at runtime based on a boolean condition. 57 )) 58 $(TR $(TD $(LREF chooseAmong)) 59 $(TD Chooses one of several ranges at runtime based on an index. 60 )) 61 $(TR $(TD $(LREF chunks)) 62 $(TD Creates a range that returns fixed-size chunks of the original 63 range. 64 )) 65 $(TR $(TD $(LREF cycle)) 66 $(TD Creates an infinite range that repeats the given forward range 67 indefinitely. Good for implementing circular buffers. 68 )) 69 $(TR $(TD $(LREF drop)) 70 $(TD Creates the range that results from discarding the first $(I n) 71 elements from the given range. 72 )) 73 $(TR $(TD $(LREF dropBack)) 74 $(TD Creates the range that results from discarding the last $(I n) 75 elements from the given range. 76 )) 77 $(TR $(TD $(LREF dropExactly)) 78 $(TD Creates the range that results from discarding exactly $(I n) 79 of the first elements from the given range. 80 )) 81 $(TR $(TD $(LREF dropBackExactly)) 82 $(TD Creates the range that results from discarding exactly $(I n) 83 of the last elements from the given range. 84 )) 85 $(TR $(TD $(LREF dropOne)) 86 $(TD Creates the range that results from discarding 87 the first element from the given range. 88 )) 89 $(TR $(TD $(LREF dropBackOne)) 90 $(TD Creates the range that results from discarding 91 the last element from the given range. 92 )) 93 $(TR $(TD $(LREF enumerate)) 94 $(TD Iterates a range with an attached index variable. 95 )) 96 $(TR $(TD $(LREF evenChunks)) 97 $(TD Creates a range that returns a number of chunks of 98 approximately equal length from the original range. 99 )) 100 $(TR $(TD $(LREF frontTransversal)) 101 $(TD Creates a range that iterates over the first elements of the 102 given ranges. 103 )) 104 $(TR $(TD $(LREF generate)) 105 $(TD Creates a range by successive calls to a given function. This 106 allows to create ranges as a single delegate. 107 )) 108 $(TR $(TD $(LREF indexed)) 109 $(TD Creates a range that offers a view of a given range as though 110 its elements were reordered according to a given range of indices. 111 )) 112 $(TR $(TD $(LREF iota)) 113 $(TD Creates a range consisting of numbers between a starting point 114 and ending point, spaced apart by a given interval. 115 )) 116 $(TR $(TD $(LREF lockstep)) 117 $(TD Iterates $(I n) ranges in lockstep, for use in a `foreach` 118 loop. Similar to `zip`, except that `lockstep` is designed 119 especially for `foreach` loops. 120 )) 121 $(TR $(TD $(LREF nullSink)) 122 $(TD An output range that discards the data it receives. 123 )) 124 $(TR $(TD $(LREF only)) 125 $(TD Creates a range that iterates over the given arguments. 126 )) 127 $(TR $(TD $(LREF padLeft)) 128 $(TD Pads a range to a specified length by adding a given element to 129 the front of the range. Is lazy if the range has a known length. 130 )) 131 $(TR $(TD $(LREF padRight)) 132 $(TD Lazily pads a range to a specified length by adding a given element to 133 the back of the range. 134 )) 135 $(TR $(TD $(LREF radial)) 136 $(TD Given a random-access range and a starting point, creates a 137 range that alternately returns the next left and next right element to 138 the starting point. 139 )) 140 $(TR $(TD $(LREF recurrence)) 141 $(TD Creates a forward range whose values are defined by a 142 mathematical recurrence relation. 143 )) 144 $(TR $(TD $(LREF refRange)) 145 $(TD Pass a range by reference. Both the original range and the RefRange 146 will always have the exact same elements. 147 Any operation done on one will affect the other. 148 )) 149 $(TR $(TD $(LREF repeat)) 150 $(TD Creates a range that consists of a single element repeated $(I n) 151 times, or an infinite range repeating that element indefinitely. 152 )) 153 $(TR $(TD $(LREF retro)) 154 $(TD Iterates a bidirectional range backwards. 155 )) 156 $(TR $(TD $(LREF roundRobin)) 157 $(TD Given $(I n) ranges, creates a new range that return the $(I n) 158 first elements of each range, in turn, then the second element of each 159 range, and so on, in a round-robin fashion. 160 )) 161 $(TR $(TD $(LREF sequence)) 162 $(TD Similar to `recurrence`, except that a random-access range is 163 created. 164 )) 165 $(TR $(TD $(LREF slide)) 166 $(TD Creates a range that returns a fixed-size sliding window 167 over the original range. Unlike chunks, 168 it advances a configurable number of items at a time, 169 not one chunk at a time. 170 )) 171 $(TR $(TD $(LREF stride)) 172 $(TD Iterates a range with stride $(I n). 173 )) 174 $(TR $(TD $(LREF tail)) 175 $(TD Return a range advanced to within `n` elements of the end of 176 the given range. 177 )) 178 $(TR $(TD $(LREF take)) 179 $(TD Creates a sub-range consisting of only up to the first $(I n) 180 elements of the given range. 181 )) 182 $(TR $(TD $(LREF takeExactly)) 183 $(TD Like `take`, but assumes the given range actually has $(I n) 184 elements, and therefore also defines the `length` property. 185 )) 186 $(TR $(TD $(LREF takeNone)) 187 $(TD Creates a random-access range consisting of zero elements of the 188 given range. 189 )) 190 $(TR $(TD $(LREF takeOne)) 191 $(TD Creates a random-access range consisting of exactly the first 192 element of the given range. 193 )) 194 $(TR $(TD $(LREF tee)) 195 $(TD Creates a range that wraps a given range, forwarding along 196 its elements while also calling a provided function with each element. 197 )) 198 $(TR $(TD $(LREF transposed)) 199 $(TD Transposes a range of ranges. 200 )) 201 $(TR $(TD $(LREF transversal)) 202 $(TD Creates a range that iterates over the $(I n)'th elements of the 203 given random-access ranges. 204 )) 205 $(TR $(TD $(LREF zip)) 206 $(TD Given $(I n) ranges, creates a range that successively returns a 207 tuple of all the first elements, a tuple of all the second elements, 208 etc. 209 )) 210 )) 211 212 Sortedness: 213 214 Ranges whose elements are sorted afford better efficiency with certain 215 operations. For this, the $(LREF assumeSorted) function can be used to 216 construct a $(LREF SortedRange) from a pre-sorted range. The $(REF 217 sort, std, algorithm, sorting) function also conveniently 218 returns a $(LREF SortedRange). $(LREF SortedRange) objects provide some additional 219 range operations that take advantage of the fact that the range is sorted. 220 221 Source: $(PHOBOSSRC std/range/package.d) 222 223 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0). 224 225 Authors: $(HTTP erdani.com, Andrei Alexandrescu), David Simcha, 226 $(HTTP jmdavisprog.com, Jonathan M Davis), and Jack Stouffer. Credit 227 for some of the ideas in building this module goes to 228 $(HTTP fantascienza.net/leonardo/so/, Leonardo Maffi). 229 */ 230 module std.range; 231 232 public import std.array; 233 public import std.range.interfaces; 234 public import std.range.primitives; 235 public import std.typecons : Flag, Yes, No, Rebindable, rebindable; 236 237 import std.internal.attributes : betterC; 238 import std.meta : aliasSeqOf, allSatisfy, anySatisfy, staticMap; 239 import std.traits : CommonType, isCallable, isFloatingPoint, isIntegral, 240 isPointer, isSomeFunction, isStaticArray, Unqual, isInstanceOf; 241 242 243 /** 244 Iterates a bidirectional range backwards. The original range can be 245 accessed by using the `source` property. Applying retro twice to 246 the same range yields the original range. 247 248 Params: 249 r = the bidirectional range to iterate backwards 250 251 Returns: 252 A bidirectional range with length if `r` also provides a length. Or, 253 if `r` is a random access range, then the return value will be random 254 access as well. 255 See_Also: 256 $(REF reverse, std,algorithm,mutation) for mutating the source range directly. 257 */ 258 auto retro(Range)(Range r) 259 if (isBidirectionalRange!(Unqual!Range)) 260 { 261 // Check for retro(retro(r)) and just return r in that case 262 static if (is(typeof(retro(r.source)) == Range)) 263 { 264 return r.source; 265 } 266 else 267 { 268 static struct Result() 269 { 270 private alias R = Unqual!Range; 271 272 // User code can get and set source, too 273 R source; 274 275 static if (hasLength!R) 276 { 277 size_t retroIndex(size_t n) 278 { 279 return source.length - n - 1; 280 } 281 } 282 283 public: 284 alias Source = R; 285 286 @property bool empty() { return source.empty; } 287 @property auto save() 288 { 289 return Result(source.save); 290 } 291 @property auto ref front() { return source.back; } 292 void popFront() { source.popBack(); } 293 @property auto ref back() { return source.front; } 294 void popBack() { source.popFront(); } 295 296 static if (is(typeof(source.moveBack()))) 297 { 298 ElementType!R moveFront() 299 { 300 return source.moveBack(); 301 } 302 } 303 304 static if (is(typeof(source.moveFront()))) 305 { 306 ElementType!R moveBack() 307 { 308 return source.moveFront(); 309 } 310 } 311 312 static if (hasAssignableElements!R) 313 { 314 @property void front(ElementType!R val) 315 { 316 import core.lifetime : forward; 317 318 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542 319 source.back = __ctfe ? val : forward!val; 320 } 321 322 @property void back(ElementType!R val) 323 { 324 import core.lifetime : forward; 325 326 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542 327 source.front = __ctfe ? val : forward!val; 328 } 329 } 330 331 static if (isRandomAccessRange!(R) && hasLength!(R)) 332 { 333 auto ref opIndex(size_t n) { return source[retroIndex(n)]; } 334 335 static if (hasAssignableElements!R) 336 { 337 void opIndexAssign(ElementType!R val, size_t n) 338 { 339 import core.lifetime : forward; 340 341 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542 342 source[retroIndex(n)] = __ctfe ? val : forward!val; 343 } 344 } 345 346 static if (is(typeof(source.moveAt(0)))) 347 { 348 ElementType!R moveAt(size_t index) 349 { 350 return source.moveAt(retroIndex(index)); 351 } 352 } 353 354 static if (hasSlicing!R) 355 typeof(this) opSlice(size_t a, size_t b) 356 { 357 return typeof(this)(source[source.length - b .. source.length - a]); 358 } 359 } 360 361 mixin ImplementLength!source; 362 } 363 364 return Result!()(r); 365 } 366 } 367 368 369 /// 370 pure @safe nothrow @nogc unittest 371 { 372 import std.algorithm.comparison : equal; 373 int[5] a = [ 1, 2, 3, 4, 5 ]; 374 int[5] b = [ 5, 4, 3, 2, 1 ]; 375 assert(equal(retro(a[]), b[])); 376 assert(retro(a[]).source is a[]); 377 assert(retro(retro(a[])) is a[]); 378 } 379 380 pure @safe nothrow unittest 381 { 382 import std.algorithm.comparison : equal; 383 static assert(isBidirectionalRange!(typeof(retro("hello")))); 384 int[] a; 385 static assert(is(typeof(a) == typeof(retro(retro(a))))); 386 assert(retro(retro(a)) is a); 387 static assert(isRandomAccessRange!(typeof(retro([1, 2, 3])))); 388 void test(int[] input, int[] witness) 389 { 390 auto r = retro(input); 391 assert(r.front == witness.front); 392 assert(r.back == witness.back); 393 assert(equal(r, witness)); 394 } 395 test([ 1 ], [ 1 ]); 396 test([ 1, 2 ], [ 2, 1 ]); 397 test([ 1, 2, 3 ], [ 3, 2, 1 ]); 398 test([ 1, 2, 3, 4 ], [ 4, 3, 2, 1 ]); 399 test([ 1, 2, 3, 4, 5 ], [ 5, 4, 3, 2, 1 ]); 400 test([ 1, 2, 3, 4, 5, 6 ], [ 6, 5, 4, 3, 2, 1 ]); 401 402 immutable foo = [1,2,3].idup; 403 auto r = retro(foo); 404 assert(equal(r, [3, 2, 1])); 405 } 406 407 pure @safe nothrow unittest 408 { 409 import std.internal.test.dummyrange : AllDummyRanges, propagatesRangeType, 410 ReturnBy; 411 412 foreach (DummyType; AllDummyRanges) 413 { 414 static if (!isBidirectionalRange!DummyType) 415 { 416 static assert(!__traits(compiles, Retro!DummyType)); 417 } 418 else 419 { 420 DummyType dummyRange; 421 dummyRange.reinit(); 422 423 auto myRetro = retro(dummyRange); 424 static assert(propagatesRangeType!(typeof(myRetro), DummyType)); 425 assert(myRetro.front == 10); 426 assert(myRetro.back == 1); 427 assert(myRetro.moveFront() == 10); 428 assert(myRetro.moveBack() == 1); 429 430 static if (isRandomAccessRange!DummyType && hasLength!DummyType) 431 { 432 assert(myRetro[0] == myRetro.front); 433 assert(myRetro.moveAt(2) == 8); 434 435 static if (DummyType.r == ReturnBy.Reference) 436 { 437 { 438 myRetro[9]++; 439 scope(exit) myRetro[9]--; 440 assert(dummyRange[0] == 2); 441 myRetro.front++; 442 scope(exit) myRetro.front--; 443 assert(myRetro.front == 11); 444 myRetro.back++; 445 scope(exit) myRetro.back--; 446 assert(myRetro.back == 3); 447 } 448 449 { 450 myRetro.front = 0xFF; 451 scope(exit) myRetro.front = 10; 452 assert(dummyRange.back == 0xFF); 453 454 myRetro.back = 0xBB; 455 scope(exit) myRetro.back = 1; 456 assert(dummyRange.front == 0xBB); 457 458 myRetro[1] = 11; 459 scope(exit) myRetro[1] = 8; 460 assert(dummyRange[8] == 11); 461 } 462 } 463 } 464 } 465 } 466 } 467 468 pure @safe nothrow @nogc unittest 469 { 470 import std.algorithm.comparison : equal; 471 auto LL = iota(1L, 4L); 472 auto r = retro(LL); 473 long[3] excepted = [3, 2, 1]; 474 assert(equal(r, excepted[])); 475 } 476 477 // https://issues.dlang.org/show_bug.cgi?id=12662 478 pure @safe nothrow @nogc unittest 479 { 480 int[3] src = [1,2,3]; 481 int[] data = src[]; 482 foreach_reverse (x; data) {} 483 foreach (x; data.retro) {} 484 } 485 486 pure @safe nothrow unittest 487 { 488 import std.algorithm.comparison : equal; 489 490 static struct S { 491 int v; 492 @disable this(this); 493 } 494 495 immutable foo = [S(1), S(2), S(3)]; 496 auto r = retro(foo); 497 assert(equal(r, [S(3), S(2), S(1)])); 498 } 499 500 // https://issues.dlang.org/show_bug.cgi?id=24481 501 @safe unittest 502 { 503 bool called; 504 struct Handle 505 { 506 int entry; 507 void opAssign()(auto ref const(typeof(this)) that) const { called = true; } 508 } 509 510 const(Handle)[5] arr = [Handle(0), Handle(1), Handle(2), Handle(3), Handle(4)]; 511 auto range = arr[].retro(); 512 513 called = false; 514 range.front = Handle(42); 515 assert(called); 516 517 called = false; 518 range.back = Handle(42); 519 assert(called); 520 521 called = false; 522 range[2] = Handle(42); 523 assert(called); 524 } 525 526 /** 527 Iterates range `r` with stride `n`. If the range is a 528 random-access range, moves by indexing into the range; otherwise, 529 moves by successive calls to `popFront`. Applying stride twice to 530 the same range results in a stride with a step that is the 531 product of the two applications. It is an error for `n` to be 0. 532 533 Params: 534 r = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to stride over 535 n = the number of elements to skip over 536 537 Returns: 538 At minimum, an input range. The resulting range will adopt the 539 range primitives of the underlying range as long as 540 $(REF hasLength, std,range,primitives) is `true`. 541 */ 542 auto stride(Range)(Range r, size_t n) 543 if (isInputRange!(Unqual!Range)) 544 in 545 { 546 assert(n != 0, "stride cannot have step zero."); 547 } 548 do 549 { 550 import std.algorithm.comparison : min; 551 552 static if (is(typeof(stride(r.source, n)) == Range)) 553 { 554 // stride(stride(r, n1), n2) is stride(r, n1 * n2) 555 return stride(r.source, r._n * n); 556 } 557 else 558 { 559 static struct Result 560 { 561 private alias R = Unqual!Range; 562 public R source; 563 private size_t _n; 564 565 // Chop off the slack elements at the end 566 static if (hasLength!R && 567 (isRandomAccessRange!R && hasSlicing!R 568 || isBidirectionalRange!R)) 569 private void eliminateSlackElements() 570 { 571 auto slack = source.length % _n; 572 573 if (slack) 574 { 575 slack--; 576 } 577 else if (!source.empty) 578 { 579 slack = min(_n, source.length) - 1; 580 } 581 else 582 { 583 slack = 0; 584 } 585 if (!slack) return; 586 static if (isRandomAccessRange!R && hasLength!R && hasSlicing!R) 587 { 588 source = source[0 .. source.length - slack]; 589 } 590 else static if (isBidirectionalRange!R) 591 { 592 foreach (i; 0 .. slack) 593 { 594 source.popBack(); 595 } 596 } 597 } 598 599 static if (isForwardRange!R) 600 { 601 @property auto save() 602 { 603 return Result(source.save, _n); 604 } 605 } 606 607 static if (isInfinite!R) 608 { 609 enum bool empty = false; 610 } 611 else 612 { 613 @property bool empty() 614 { 615 return source.empty; 616 } 617 } 618 619 @property auto ref front() 620 { 621 return source.front; 622 } 623 624 static if (is(typeof(.moveFront(source)))) 625 { 626 ElementType!R moveFront() 627 { 628 return source.moveFront(); 629 } 630 } 631 632 static if (hasAssignableElements!R) 633 { 634 @property void front(ElementType!R val) 635 { 636 import core.lifetime : forward; 637 638 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542 639 source.front = __ctfe ? val : forward!val; 640 } 641 } 642 643 void popFront() 644 { 645 source.popFrontN(_n); 646 } 647 648 static if (isBidirectionalRange!R && hasLength!R) 649 { 650 void popBack() 651 { 652 popBackN(source, _n); 653 } 654 655 @property auto ref back() 656 { 657 eliminateSlackElements(); 658 return source.back; 659 } 660 661 static if (is(typeof(.moveBack(source)))) 662 { 663 ElementType!R moveBack() 664 { 665 eliminateSlackElements(); 666 return source.moveBack(); 667 } 668 } 669 670 static if (hasAssignableElements!R) 671 { 672 @property void back(ElementType!R val) 673 { 674 eliminateSlackElements(); 675 source.back = val; 676 } 677 } 678 } 679 680 static if (isRandomAccessRange!R && hasLength!R) 681 { 682 auto ref opIndex(size_t n) 683 { 684 return source[_n * n]; 685 } 686 687 /** 688 Forwards to $(D moveAt(source, n)). 689 */ 690 static if (is(typeof(source.moveAt(0)))) 691 { 692 ElementType!R moveAt(size_t n) 693 { 694 return source.moveAt(_n * n); 695 } 696 } 697 698 static if (hasAssignableElements!R) 699 { 700 void opIndexAssign(ElementType!R val, size_t n) 701 { 702 source[_n * n] = val; 703 } 704 } 705 } 706 707 static if (hasSlicing!R && hasLength!R) 708 typeof(this) opSlice(size_t lower, size_t upper) 709 { 710 assert(upper >= lower && upper <= length, 711 "Attempt to get out-of-bounds slice of `stride` range"); 712 immutable translatedUpper = (upper == 0) ? 0 : 713 (upper * _n - (_n - 1)); 714 immutable translatedLower = min(lower * _n, translatedUpper); 715 716 assert(translatedLower <= translatedUpper, 717 "Overflow when calculating slice of `stride` range"); 718 719 return typeof(this)(source[translatedLower .. translatedUpper], _n); 720 } 721 722 static if (hasLength!R) 723 { 724 @property auto length() 725 { 726 return (source.length + _n - 1) / _n; 727 } 728 729 alias opDollar = length; 730 } 731 } 732 return Result(r, n); 733 } 734 } 735 736 /// 737 pure @safe nothrow unittest 738 { 739 import std.algorithm.comparison : equal; 740 741 int[] a = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ]; 742 assert(equal(stride(a, 3), [ 1, 4, 7, 10 ][])); 743 assert(stride(stride(a, 2), 3) == stride(a, 6)); 744 } 745 746 pure @safe nothrow @nogc unittest 747 { 748 import std.algorithm.comparison : equal; 749 750 int[4] testArr = [1,2,3,4]; 751 static immutable result = [1, 3]; 752 assert(equal(testArr[].stride(2), result)); 753 } 754 755 debug pure nothrow @system unittest 756 {//check the contract 757 int[4] testArr = [1,2,3,4]; 758 bool passed = false; 759 scope (success) assert(passed); 760 import core.exception : AssertError; 761 //std.exception.assertThrown won't do because it can't infer nothrow 762 // https://issues.dlang.org/show_bug.cgi?id=12647 763 try 764 { 765 auto unused = testArr[].stride(0); 766 } 767 catch (AssertError unused) 768 { 769 passed = true; 770 } 771 } 772 773 pure @safe nothrow unittest 774 { 775 import std.algorithm.comparison : equal; 776 import std.internal.test.dummyrange : AllDummyRanges, propagatesRangeType, 777 ReturnBy; 778 779 static assert(isRandomAccessRange!(typeof(stride([1, 2, 3], 2)))); 780 void test(size_t n, int[] input, int[] witness) 781 { 782 assert(equal(stride(input, n), witness)); 783 } 784 test(1, [], []); 785 int[] arr = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; 786 assert(stride(stride(arr, 2), 3) is stride(arr, 6)); 787 test(1, arr, arr); 788 test(2, arr, [1, 3, 5, 7, 9]); 789 test(3, arr, [1, 4, 7, 10]); 790 test(4, arr, [1, 5, 9]); 791 792 // Test slicing. 793 auto s1 = stride(arr, 1); 794 assert(equal(s1[1 .. 4], [2, 3, 4])); 795 assert(s1[1 .. 4].length == 3); 796 assert(equal(s1[1 .. 5], [2, 3, 4, 5])); 797 assert(s1[1 .. 5].length == 4); 798 assert(s1[0 .. 0].empty); 799 assert(s1[3 .. 3].empty); 800 // assert(s1[$ .. $].empty); 801 assert(s1[s1.opDollar .. s1.opDollar].empty); 802 803 auto s2 = stride(arr, 2); 804 assert(equal(s2[0 .. 2], [1,3])); 805 assert(s2[0 .. 2].length == 2); 806 assert(equal(s2[1 .. 5], [3, 5, 7, 9])); 807 assert(s2[1 .. 5].length == 4); 808 assert(s2[0 .. 0].empty); 809 assert(s2[3 .. 3].empty); 810 // assert(s2[$ .. $].empty); 811 assert(s2[s2.opDollar .. s2.opDollar].empty); 812 813 // Test fix for https://issues.dlang.org/show_bug.cgi?id=5035 814 auto m = [1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]; // 3 rows, 4 columns 815 auto col = stride(m, 4); 816 assert(equal(col, [1, 1, 1])); 817 assert(equal(retro(col), [1, 1, 1])); 818 819 immutable int[] immi = [ 1, 2, 3 ]; 820 static assert(isRandomAccessRange!(typeof(stride(immi, 1)))); 821 822 // Check for infiniteness propagation. 823 static assert(isInfinite!(typeof(stride(repeat(1), 3)))); 824 825 foreach (DummyType; AllDummyRanges) 826 { 827 DummyType dummyRange; 828 dummyRange.reinit(); 829 830 auto myStride = stride(dummyRange, 4); 831 832 // Should fail if no length and bidirectional b/c there's no way 833 // to know how much slack we have. 834 static if (hasLength!DummyType || !isBidirectionalRange!DummyType) 835 { 836 static assert(propagatesRangeType!(typeof(myStride), DummyType)); 837 } 838 assert(myStride.front == 1); 839 assert(myStride.moveFront() == 1); 840 assert(equal(myStride, [1, 5, 9])); 841 842 static if (hasLength!DummyType) 843 { 844 assert(myStride.length == 3); 845 } 846 847 static if (isBidirectionalRange!DummyType && hasLength!DummyType) 848 { 849 assert(myStride.back == 9); 850 assert(myStride.moveBack() == 9); 851 } 852 853 static if (isRandomAccessRange!DummyType && hasLength!DummyType) 854 { 855 assert(myStride[0] == 1); 856 assert(myStride[1] == 5); 857 assert(myStride.moveAt(1) == 5); 858 assert(myStride[2] == 9); 859 860 static assert(hasSlicing!(typeof(myStride))); 861 } 862 863 static if (DummyType.r == ReturnBy.Reference) 864 { 865 // Make sure reference is propagated. 866 867 { 868 myStride.front++; 869 scope(exit) myStride.front--; 870 assert(dummyRange.front == 2); 871 } 872 { 873 myStride.front = 4; 874 scope(exit) myStride.front = 1; 875 assert(dummyRange.front == 4); 876 } 877 878 static if (isBidirectionalRange!DummyType && hasLength!DummyType) 879 { 880 { 881 myStride.back++; 882 scope(exit) myStride.back--; 883 assert(myStride.back == 10); 884 } 885 { 886 myStride.back = 111; 887 scope(exit) myStride.back = 9; 888 assert(myStride.back == 111); 889 } 890 891 static if (isRandomAccessRange!DummyType) 892 { 893 { 894 myStride[1]++; 895 scope(exit) myStride[1]--; 896 assert(dummyRange[4] == 6); 897 } 898 { 899 myStride[1] = 55; 900 scope(exit) myStride[1] = 5; 901 assert(dummyRange[4] == 55); 902 } 903 } 904 } 905 } 906 } 907 } 908 909 pure @safe nothrow unittest 910 { 911 import std.algorithm.comparison : equal; 912 913 auto LL = iota(1L, 10L); 914 auto s = stride(LL, 3); 915 assert(equal(s, [1L, 4L, 7L])); 916 } 917 918 pure @safe nothrow unittest 919 { 920 import std.algorithm.comparison : equal; 921 922 static struct S { 923 int v; 924 @disable this(this); 925 } 926 927 immutable foo = [S(1), S(2), S(3), S(4), S(5)]; 928 auto r = stride(foo, 3); 929 assert(equal(r, [S(1), S(4)])); 930 } 931 932 // https://issues.dlang.org/show_bug.cgi?id=24481 933 @safe unittest 934 { 935 bool called; 936 struct Handle 937 { 938 int entry; 939 void opAssign()(auto ref const(typeof(this)) that) const { called = true; } 940 } 941 942 const(Handle)[5] arr = [Handle(0), Handle(1), Handle(2), Handle(3), Handle(4)]; 943 auto range = arr[].stride(2); 944 945 called = false; 946 range.front = Handle(42); 947 assert(called); 948 } 949 950 /** 951 Spans multiple ranges in sequence. The function `chain` takes any 952 number of ranges and returns a $(D Chain!(R1, R2,...)) object. The 953 ranges may be different, but they must have the same element type. The 954 result is a range that offers the `front`, `popFront`, and $(D 955 empty) primitives. If all input ranges offer random access and $(D 956 length), `Chain` offers them as well. 957 958 Note that repeated random access of the resulting range is likely 959 to perform somewhat badly since lengths of the ranges in the chain have to be 960 added up for each random access operation. Random access to elements of 961 the first remaining range is still efficient. 962 963 If only one range is offered to `Chain` or `chain`, the $(D 964 Chain) type exits the picture by aliasing itself directly to that 965 range's type. 966 967 Params: 968 rs = the $(REF_ALTTEXT input ranges, isInputRange, std,range,primitives) to chain together 969 970 Returns: 971 An input range at minimum. If all of the ranges in `rs` provide 972 a range primitive, the returned range will also provide that range 973 primitive. 974 975 See_Also: $(LREF only) to chain values to a range 976 */ 977 auto chain(Ranges...)(Ranges rs) 978 if (Ranges.length > 0 && 979 allSatisfy!(isInputRange, staticMap!(Unqual, Ranges)) && 980 !is(CommonType!(staticMap!(ElementType, staticMap!(Unqual, Ranges))) == void)) 981 { 982 static if (Ranges.length == 1) 983 { 984 return rs[0]; 985 } 986 else 987 { 988 static struct Result 989 { 990 private: 991 alias R = staticMap!(Unqual, Ranges); 992 alias RvalueElementType = CommonType!(staticMap!(.ElementType, R)); 993 template sameET(A) 994 { 995 enum sameET = is(.ElementType!A == RvalueElementType); 996 } 997 998 enum bool allSameType = allSatisfy!(sameET, R), 999 bidirectional = allSatisfy!(isBidirectionalRange, R), 1000 mobileElements = allSatisfy!(hasMobileElements, R), 1001 assignableElements = allSameType 1002 && allSatisfy!(hasAssignableElements, R); 1003 1004 alias ElementType = RvalueElementType; 1005 1006 static if (allSameType && allSatisfy!(hasLvalueElements, R)) 1007 { 1008 static ref RvalueElementType fixRef(ref RvalueElementType val) 1009 { 1010 return val; 1011 } 1012 } 1013 else 1014 { 1015 static RvalueElementType fixRef(RvalueElementType val) 1016 { 1017 return val; 1018 } 1019 } 1020 1021 R source; 1022 size_t frontIndex; 1023 // Always points to index one past the last non-empty range, 1024 // because otherwise decrementing while pointing to first range 1025 // would overflow to size_t.max. 1026 static if (bidirectional) size_t backIndex; 1027 else enum backIndex = source.length; 1028 1029 this(typeof(Result.tupleof) fields) 1030 { 1031 this.tupleof = fields; 1032 } 1033 1034 public: 1035 this(R input) 1036 { 1037 frontIndex = source.length; 1038 static if (bidirectional) backIndex = 0; 1039 1040 foreach (i, ref v; input) source[i] = v; 1041 1042 // We do this separately to avoid invoking `empty` needlessly. 1043 // While not recommended, a range may depend on side effects of 1044 // `empty` call. 1045 foreach (i, ref v; source) if (!v.empty) 1046 { 1047 frontIndex = i; 1048 static if (bidirectional) backIndex = i+1; 1049 break; 1050 } 1051 1052 // backIndex is already set in the first loop to 1053 // as frontIndex+1, so we'll use that if we don't find a 1054 // non-empty range here. 1055 static if (bidirectional) 1056 static foreach_reverse (i; 1 .. R.length + 1) 1057 { 1058 if (i <= frontIndex + 1) return; 1059 if (!source[i-1].empty) 1060 { 1061 backIndex = i; 1062 return; 1063 } 1064 } 1065 } 1066 1067 import std.meta : anySatisfy; 1068 1069 static if (anySatisfy!(isInfinite, R)) 1070 { 1071 // Propagate infiniteness. 1072 enum bool empty = false; 1073 } 1074 else 1075 { 1076 @property bool empty() 1077 { 1078 if (frontIndex == 0) 1079 { 1080 // special handling: we might be in Range.init state! 1081 // For instance, `format!"%s"` uses Range.init to ensure 1082 // that formatting is possible. 1083 // In that case, we must still behave in an internally consistent way. 1084 return source[0].empty; 1085 } 1086 return frontIndex >= backIndex; 1087 } 1088 } 1089 1090 static if (allSatisfy!(isForwardRange, R)) 1091 { 1092 @property auto save() 1093 { 1094 auto saveI(size_t i)() => source[i].save; 1095 1096 // TODO: this has the constructor needlessly refind 1097 // frontIndex and backIndex. It'd be better to just copy 1098 // those from `.this`. 1099 auto saveResult = 1100 Result(staticMap!(saveI, aliasSeqOf!(R.length.iota))); 1101 1102 return saveResult; 1103 } 1104 } 1105 1106 void popFront() 1107 { 1108 sw1: switch (frontIndex) 1109 { 1110 static foreach (i; 0 .. R.length) 1111 { 1112 case i: 1113 source[i].popFront(); 1114 break sw1; 1115 } 1116 1117 case R.length: 1118 assert(0, "Attempt to `popFront` of empty `chain` range"); 1119 1120 default: 1121 assert(0, "Internal library error. Please report it."); 1122 } 1123 1124 sw2: switch (frontIndex) 1125 { 1126 static foreach (i; 0 .. R.length) 1127 { 1128 case i: 1129 if (source[i].empty) 1130 { 1131 frontIndex++; 1132 goto case; 1133 } 1134 else break sw2; 1135 } 1136 1137 // Only possible to reach from goto of previous case. 1138 case R.length: 1139 break; 1140 1141 default: 1142 assert(0, "Internal library error. Please report it."); 1143 } 1144 } 1145 1146 @property auto ref front() 1147 { 1148 switch (frontIndex) 1149 { 1150 static foreach (i; 0 .. R.length) 1151 { 1152 case i: 1153 return fixRef(source[i].front); 1154 } 1155 1156 case R.length: 1157 assert(0, "Attempt to get `front` of empty `chain` range"); 1158 1159 default: 1160 assert(0, "Internal library error. Please report it."); 1161 } 1162 } 1163 1164 static if (assignableElements) 1165 { 1166 // @@@BUG@@@ 1167 //@property void front(T)(T v) if (is(T : RvalueElementType)) 1168 1169 @property void front(RvalueElementType v) 1170 { 1171 import core.lifetime : forward; 1172 1173 sw: switch (frontIndex) 1174 { 1175 static foreach (i; 0 .. R.length) 1176 { 1177 case i: 1178 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542 1179 source[i].front = __ctfe ? v : forward!v; 1180 break sw; 1181 } 1182 1183 case R.length: 1184 assert(0, "Attempt to set `front` of empty `chain` range"); 1185 1186 default: 1187 assert(0, "Internal library error. Please report it."); 1188 } 1189 } 1190 } 1191 1192 static if (mobileElements) 1193 { 1194 RvalueElementType moveFront() 1195 { 1196 switch (frontIndex) 1197 { 1198 static foreach (i; 0 .. R.length) 1199 { 1200 case i: 1201 return source[i].moveFront(); 1202 } 1203 1204 case R.length: 1205 assert(0, "Attempt to `moveFront` of empty `chain` range"); 1206 1207 default: 1208 assert(0, "Internal library error. Please report it."); 1209 } 1210 } 1211 } 1212 1213 static if (bidirectional) 1214 { 1215 @property auto ref back() 1216 { 1217 switch (backIndex) 1218 { 1219 static foreach_reverse (i; 1 .. R.length + 1) 1220 { 1221 case i: 1222 return fixRef(source[i-1].back); 1223 } 1224 1225 case 0: 1226 assert(0, "Attempt to get `back` of empty `chain` range"); 1227 1228 default: 1229 assert(0, "Internal library error. Please report it."); 1230 } 1231 } 1232 1233 void popBack() 1234 { 1235 sw1: switch (backIndex) 1236 { 1237 static foreach_reverse (i; 1 .. R.length + 1) 1238 { 1239 case i: 1240 source[i-1].popBack(); 1241 break sw1; 1242 } 1243 1244 case 0: 1245 assert(0, "Attempt to `popFront` of empty `chain` range"); 1246 1247 default: 1248 assert(0, "Internal library error. Please report it."); 1249 } 1250 1251 sw2: switch (backIndex) 1252 { 1253 static foreach_reverse (i; 1 .. R.length + 1) 1254 { 1255 case i: 1256 if (source[i-1].empty) 1257 { 1258 backIndex--; 1259 goto case; 1260 } 1261 else break sw2; 1262 } 1263 1264 // Only possible to reach from goto of previous case. 1265 case 0: 1266 break; 1267 1268 default: 1269 assert(0, "Internal library error. Please report it."); 1270 } 1271 } 1272 1273 static if (mobileElements) 1274 { 1275 RvalueElementType moveBack() 1276 { 1277 switch (backIndex) 1278 { 1279 static foreach_reverse (i; 1 .. R.length + 1) 1280 { 1281 case i: 1282 return source[i-1].moveBack(); 1283 } 1284 1285 case 0: 1286 assert(0, "Attempt to `moveBack` of empty `chain` range"); 1287 1288 default: 1289 assert(0, "Internal library error. Please report it."); 1290 } 1291 } 1292 } 1293 1294 static if (allSameType && allSatisfy!(hasAssignableElements, R)) 1295 { 1296 @property void back(RvalueElementType v) 1297 { 1298 import core.lifetime : forward; 1299 1300 sw: switch (backIndex) 1301 { 1302 static foreach_reverse (i; 1 .. R.length + 1) 1303 { 1304 case i: 1305 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542 1306 source[i - 1].back = __ctfe ? v : forward!v; 1307 break sw; 1308 } 1309 1310 case 0: 1311 assert(0, "Attempt to set `back` of empty `chain` range"); 1312 1313 default: 1314 assert(0, "Internal library error. Please report it."); 1315 } 1316 } 1317 } 1318 } 1319 1320 static if (allSatisfy!(hasLength, R)) 1321 { 1322 @property size_t length() 1323 { 1324 size_t result = 0; 1325 sw: switch (frontIndex) 1326 { 1327 static foreach (i; 0 .. R.length) 1328 { 1329 case i: 1330 result += source[i].length; 1331 if (backIndex == i+1) break sw; 1332 else goto case; 1333 } 1334 1335 case R.length: 1336 break; 1337 1338 default: 1339 assert(0, "Internal library error. Please report it."); 1340 } 1341 1342 return result; 1343 } 1344 1345 alias opDollar = length; 1346 } 1347 1348 static if (allSatisfy!(isRandomAccessRange, R)) 1349 { 1350 auto ref opIndex(size_t index) 1351 { 1352 switch (frontIndex) 1353 { 1354 static foreach (i; 0 .. R.length) 1355 { 1356 case i: 1357 static if (!isInfinite!(R[i])) 1358 { 1359 immutable length = source[i].length; 1360 if (index >= length) 1361 { 1362 index -= length; 1363 goto case; 1364 } 1365 } 1366 1367 return fixRef(source[i][index]); 1368 } 1369 1370 case R.length: 1371 assert(0, "Attempt to access out-of-bounds index of `chain` range"); 1372 1373 default: 1374 assert(0, "Internal library error. Please report it."); 1375 } 1376 } 1377 1378 static if (mobileElements) 1379 { 1380 RvalueElementType moveAt(size_t index) 1381 { 1382 switch (frontIndex) 1383 { 1384 static foreach (i; 0 .. R.length) 1385 { 1386 case i: 1387 static if (!isInfinite!(R[i])) 1388 { 1389 immutable length = source[i].length; 1390 if (index >= length) 1391 { 1392 index -= length; 1393 goto case; 1394 } 1395 } 1396 1397 return source[i].moveAt(index); 1398 } 1399 1400 case R.length: 1401 assert(0, "Attempt to move out-of-bounds index of `chain` range"); 1402 1403 default: 1404 assert(0, "Internal library error. Please report it."); 1405 } 1406 } 1407 } 1408 1409 static if (allSameType && allSatisfy!(hasAssignableElements, R)) 1410 void opIndexAssign(ElementType v, size_t index) 1411 { 1412 import core.lifetime : forward; 1413 1414 sw: switch (frontIndex) 1415 { 1416 static foreach (i; 0 .. R.length) 1417 { 1418 case i: 1419 static if (!isInfinite!(R[i])) 1420 { 1421 immutable length = source[i].length; 1422 if (index >= length) 1423 { 1424 index -= length; 1425 goto case; 1426 } 1427 } 1428 1429 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542 1430 source[i][index] = __ctfe ? v : forward!v; 1431 break sw; 1432 } 1433 1434 case R.length: 1435 assert(0, "Attempt to write out-of-bounds index of `chain` range"); 1436 1437 default: 1438 assert(0, "Internal library error. Please report it."); 1439 } 1440 } 1441 } 1442 1443 static if (allSatisfy!(hasLength, R) && allSatisfy!(hasSlicing, R)) 1444 auto opSlice(size_t begin, size_t end) return scope 1445 { 1446 // force staticMap type conversion to Rebindable 1447 static struct ResultRanges 1448 { 1449 staticMap!(Rebindable, typeof(source)) fields; 1450 } 1451 auto sourceI(size_t i)() => rebindable(this.source[i]); 1452 auto resultRanges = ResultRanges(staticMap!(sourceI, aliasSeqOf!(R.length.iota))).fields; 1453 size_t resultFrontIndex = this.frontIndex; 1454 static if (bidirectional) 1455 size_t resultBackIndex = this.backIndex; 1456 1457 sw: switch (frontIndex) 1458 { 1459 static foreach (i; 0 .. R.length) 1460 { 1461 case i: 1462 immutable len = resultRanges[i].length; 1463 if (len <= begin) 1464 { 1465 resultRanges[i] = resultRanges[i] 1466 [len .. len]; 1467 begin -= len; 1468 resultFrontIndex++; 1469 goto case; 1470 } 1471 else 1472 { 1473 resultRanges[i] = resultRanges[i] 1474 [begin .. len]; 1475 break sw; 1476 } 1477 } 1478 1479 case R.length: 1480 assert(begin == 0, 1481 "Attempt to access out-of-bounds slice of `chain` range"); 1482 break; 1483 1484 default: 1485 assert(0, "Internal library error. Please report it."); 1486 } 1487 1488 // Overflow intentional if end index too big. 1489 // This will trigger the bounds check failure below. 1490 auto cut = length - end; 1491 1492 sw2: switch (backIndex) 1493 { 1494 static foreach_reverse (i; 1 .. R.length + 1) 1495 { 1496 case i: 1497 immutable len = resultRanges[i-1].length; 1498 if (len <= cut) 1499 { 1500 resultRanges[i-1] = resultRanges[i-1] 1501 [0 .. 0]; 1502 cut -= len; 1503 resultBackIndex--; 1504 goto case; 1505 } 1506 else 1507 { 1508 resultRanges[i-1] = resultRanges[i-1] 1509 [0 .. len - cut]; 1510 break sw2; 1511 } 1512 } 1513 1514 case 0: 1515 assert(cut == 0, end > length? 1516 "Attempt to access out-of-bounds slice of `chain` range": 1517 "Attempt to access negative length slice of `chain` range"); 1518 break sw2; 1519 1520 default: 1521 assert(0, "Internal library error. Please report it."); 1522 } 1523 1524 static if (bidirectional) 1525 return Result(resultRanges, resultFrontIndex, resultBackIndex); 1526 else 1527 return Result(resultRanges, resultFrontIndex); 1528 } 1529 } 1530 return Result(rs); 1531 } 1532 } 1533 1534 /// 1535 pure @safe nothrow unittest 1536 { 1537 import std.algorithm.comparison : equal; 1538 1539 int[] arr1 = [ 1, 2, 3, 4 ]; 1540 int[] arr2 = [ 5, 6 ]; 1541 int[] arr3 = [ 7 ]; 1542 auto s = chain(arr1, arr2, arr3); 1543 assert(s.length == 7); 1544 assert(s[5] == 6); 1545 assert(equal(s, [1, 2, 3, 4, 5, 6, 7][])); 1546 } 1547 1548 /** 1549 * Range primitives are carried over to the returned range if 1550 * all of the ranges provide them 1551 */ 1552 pure @safe nothrow unittest 1553 { 1554 import std.algorithm.comparison : equal; 1555 import std.algorithm.sorting : sort; 1556 1557 int[] arr1 = [5, 2, 8]; 1558 int[] arr2 = [3, 7, 9]; 1559 int[] arr3 = [1, 4, 6]; 1560 1561 // in-place sorting across all of the arrays 1562 auto s = arr1.chain(arr2, arr3).sort; 1563 1564 assert(s.equal([1, 2, 3, 4, 5, 6, 7, 8, 9])); 1565 assert(arr1.equal([1, 2, 3])); 1566 assert(arr2.equal([4, 5, 6])); 1567 assert(arr3.equal([7, 8, 9])); 1568 } 1569 1570 /** 1571 Due to safe type promotion in D, chaining together different 1572 character ranges results in a `uint` range. 1573 1574 Use $(REF_ALTTEXT byChar, byChar,std,utf), $(REF_ALTTEXT byWchar, byWchar,std,utf), 1575 and $(REF_ALTTEXT byDchar, byDchar,std,utf) on the ranges 1576 to get the type you need. 1577 */ 1578 pure @safe nothrow unittest 1579 { 1580 import std.utf : byChar, byCodeUnit; 1581 1582 auto s1 = "string one"; 1583 auto s2 = "string two"; 1584 // s1 and s2 front is dchar because of auto-decoding 1585 static assert(is(typeof(s1.front) == dchar) && is(typeof(s2.front) == dchar)); 1586 1587 auto r1 = s1.chain(s2); 1588 // chains of ranges of the same character type give that same type 1589 static assert(is(typeof(r1.front) == dchar)); 1590 1591 auto s3 = "string three".byCodeUnit; 1592 static assert(is(typeof(s3.front) == immutable char)); 1593 auto r2 = s1.chain(s3); 1594 // chaining ranges of mixed character types gives `dchar` 1595 static assert(is(typeof(r2.front) == dchar)); 1596 1597 // use byChar on character ranges to correctly convert them to UTF-8 1598 auto r3 = s1.byChar.chain(s3); 1599 static assert(is(typeof(r3.front) == immutable char)); 1600 } 1601 1602 pure @safe nothrow unittest 1603 { 1604 import std.algorithm.comparison : equal; 1605 import std.internal.test.dummyrange : AllDummyRanges, dummyLength, 1606 propagatesRangeType; 1607 1608 { 1609 int[] arr1 = [ 1, 2, 3, 4 ]; 1610 int[] arr2 = [ 5, 6 ]; 1611 int[] arr3 = [ 7 ]; 1612 int[] witness = [ 1, 2, 3, 4, 5, 6, 7 ]; 1613 auto s1 = chain(arr1); 1614 static assert(isRandomAccessRange!(typeof(s1))); 1615 auto s2 = chain(arr1, arr2); 1616 static assert(isBidirectionalRange!(typeof(s2))); 1617 static assert(isRandomAccessRange!(typeof(s2))); 1618 s2.front = 1; 1619 auto s = chain(arr1, arr2, arr3); 1620 assert(s[5] == 6); 1621 assert(equal(s, witness)); 1622 assert(s[4 .. 6].equal(arr2)); 1623 assert(s[2 .. 5].equal([3, 4, 5])); 1624 assert(s[0 .. 0].empty); 1625 assert(s[7 .. $].empty); 1626 assert(s[5] == 6); 1627 } 1628 { 1629 int[] arr1 = [ 1, 2, 3, 4 ]; 1630 int[] witness = [ 1, 2, 3, 4 ]; 1631 assert(equal(chain(arr1), witness)); 1632 } 1633 { 1634 uint[] foo = [1,2,3,4,5]; 1635 uint[] bar = [1,2,3,4,5]; 1636 auto c = chain(foo, bar); 1637 c[3] = 42; 1638 assert(c[3] == 42); 1639 assert(c.moveFront() == 1); 1640 assert(c.moveBack() == 5); 1641 assert(c.moveAt(4) == 5); 1642 assert(c.moveAt(5) == 1); 1643 } 1644 1645 1646 // Make sure https://issues.dlang.org/show_bug.cgi?id=3311 is fixed. 1647 // elements are mutable. 1648 assert(equal(chain(iota(0, 3), iota(0, 3)), [0, 1, 2, 0, 1, 2])); 1649 1650 // Test the case where infinite ranges are present. 1651 auto inf = chain([0,1,2][], cycle([4,5,6][]), [7,8,9][]); // infinite range 1652 assert(inf[0] == 0); 1653 assert(inf[3] == 4); 1654 assert(inf[6] == 4); 1655 assert(inf[7] == 5); 1656 static assert(isInfinite!(typeof(inf))); 1657 1658 immutable int[] immi = [ 1, 2, 3 ]; 1659 immutable float[] immf = [ 1, 2, 3 ]; 1660 static assert(is(typeof(chain(immi, immf)))); 1661 1662 // Check that chain at least instantiates and compiles with every possible 1663 // pair of DummyRange types, in either order. 1664 1665 foreach (DummyType1; AllDummyRanges) 1666 (){ // workaround slow optimizations for large functions 1667 // https://issues.dlang.org/show_bug.cgi?id=2396 1668 DummyType1 dummy1; 1669 foreach (DummyType2; AllDummyRanges) 1670 { 1671 DummyType2 dummy2; 1672 auto myChain = chain(dummy1, dummy2); 1673 1674 static assert( 1675 propagatesRangeType!(typeof(myChain), DummyType1, DummyType2) 1676 ); 1677 1678 assert(myChain.front == 1); 1679 foreach (i; 0 .. dummyLength) 1680 { 1681 myChain.popFront(); 1682 } 1683 assert(myChain.front == 1); 1684 1685 static if (isBidirectionalRange!DummyType1 && 1686 isBidirectionalRange!DummyType2) { 1687 assert(myChain.back == 10); 1688 } 1689 1690 static if (isRandomAccessRange!DummyType1 && 1691 isRandomAccessRange!DummyType2) { 1692 assert(myChain[0] == 1); 1693 } 1694 1695 static if (hasLvalueElements!DummyType1 && hasLvalueElements!DummyType2) 1696 { 1697 static assert(hasLvalueElements!(typeof(myChain))); 1698 } 1699 else 1700 { 1701 static assert(!hasLvalueElements!(typeof(myChain))); 1702 } 1703 } 1704 }(); 1705 } 1706 1707 pure @safe nothrow @nogc unittest 1708 { 1709 class Foo{} 1710 immutable(Foo)[] a; 1711 immutable(Foo)[] b; 1712 assert(chain(a, b).empty); 1713 } 1714 1715 // https://issues.dlang.org/show_bug.cgi?id=18657 1716 pure @safe unittest 1717 { 1718 import std.algorithm.comparison : equal; 1719 string s = "foo"; 1720 auto r = refRange(&s).chain("bar"); 1721 assert(equal(r.save, "foobar")); 1722 assert(equal(r, "foobar")); 1723 } 1724 1725 // https://issues.dlang.org/show_bug.cgi?id=23844 1726 pure @safe unittest 1727 { 1728 struct S 1729 { 1730 immutable int value; 1731 } 1732 1733 auto range = chain(only(S(5)), only(S(6))); 1734 assert(range.array == [S(5), S(6)]); 1735 } 1736 1737 // https://issues.dlang.org/show_bug.cgi?id=24064 1738 pure @safe nothrow unittest 1739 { 1740 import std.algorithm.comparison : equal; 1741 import std.typecons : Nullable; 1742 1743 immutable Nullable!string foo = "b"; 1744 string[] bar = ["a"]; 1745 assert(chain(bar, foo).equal(["a", "b"])); 1746 } 1747 1748 pure @safe nothrow @nogc unittest 1749 { 1750 // support non-copyable items 1751 1752 static struct S { 1753 int v; 1754 @disable this(this); 1755 } 1756 1757 S[2] s0, s1; 1758 foreach (ref el; chain(s0[], s1[])) 1759 { 1760 int n = el.v; 1761 } 1762 1763 S[] s2, s3; 1764 foreach (ref el; chain(s2, s3)) 1765 { 1766 int n = el.v; 1767 } 1768 } 1769 1770 // https://issues.dlang.org/show_bug.cgi?id=24243 1771 pure @safe nothrow unittest 1772 { 1773 import std.algorithm.iteration : filter; 1774 1775 auto range = chain([2], [3].filter!"a"); 1776 1777 // This might happen in format!"%s"(range), for instance. 1778 assert(typeof(range).init.empty); 1779 } 1780 1781 // https://issues.dlang.org/show_bug.cgi?id=24481 1782 @safe unittest 1783 { 1784 bool called; 1785 struct Handle 1786 { 1787 int entry; 1788 void opAssign()(auto ref const(typeof(this)) that) const { called = true; } 1789 } 1790 1791 const(Handle)[5] arr = [Handle(0), Handle(1), Handle(2), Handle(3), Handle(4)]; 1792 auto range = arr[0 .. 2].chain(arr[4 .. 5]); 1793 1794 called = false; 1795 range.front = Handle(42); 1796 assert(called); 1797 1798 called = false; 1799 range.back = Handle(42); 1800 assert(called); 1801 1802 called = false; 1803 range[2] = Handle(42); 1804 assert(called); 1805 } 1806 1807 /** 1808 Choose one of two ranges at runtime depending on a Boolean condition. 1809 1810 The ranges may be different, but they must have compatible element types (i.e. 1811 `CommonType` must exist for the two element types). The result is a range 1812 that offers the weakest capabilities of the two (e.g. `ForwardRange` if $(D 1813 R1) is a random-access range and `R2` is a forward range). 1814 1815 Params: 1816 condition = which range to choose: `r1` if `true`, `r2` otherwise 1817 r1 = the "true" range 1818 r2 = the "false" range 1819 1820 Returns: 1821 A range type dependent on `R1` and `R2`. 1822 */ 1823 auto choose(R1, R2)(bool condition, return scope R1 r1, return scope R2 r2) 1824 if (isInputRange!(Unqual!R1) && isInputRange!(Unqual!R2) && 1825 !is(CommonType!(ElementType!(Unqual!R1), ElementType!(Unqual!R2)) == void)) 1826 { 1827 size_t choice = condition? 0: 1; 1828 return ChooseResult!(R1, R2)(choice, r1, r2); 1829 } 1830 1831 /// 1832 @safe nothrow pure @nogc unittest 1833 { 1834 import std.algorithm.comparison : equal; 1835 import std.algorithm.iteration : filter, map; 1836 1837 auto data1 = only(1, 2, 3, 4).filter!(a => a != 3); 1838 auto data2 = only(5, 6, 7, 8).map!(a => a + 1); 1839 1840 // choose() is primarily useful when you need to select one of two ranges 1841 // with different types at runtime. 1842 static assert(!is(typeof(data1) == typeof(data2))); 1843 1844 auto chooseRange(bool pickFirst) 1845 { 1846 // The returned range is a common wrapper type that can be used for 1847 // returning or storing either range without running into a type error. 1848 return choose(pickFirst, data1, data2); 1849 1850 // Simply returning the chosen range without using choose() does not 1851 // work, because map() and filter() return different types. 1852 //return pickFirst ? data1 : data2; // does not compile 1853 } 1854 1855 auto result = chooseRange(true); 1856 assert(result.equal(only(1, 2, 4))); 1857 1858 result = chooseRange(false); 1859 assert(result.equal(only(6, 7, 8, 9))); 1860 } 1861 1862 1863 private struct ChooseResult(Ranges...) 1864 { 1865 import std.meta : aliasSeqOf, ApplyLeft; 1866 import std.traits : hasElaborateCopyConstructor, hasElaborateDestructor, 1867 lvalueOf; 1868 1869 private union 1870 { 1871 Ranges rs; 1872 } 1873 private size_t chosenI; 1874 1875 private static auto ref actOnChosen(alias foo, ExtraArgs ...) 1876 (ref ChooseResult r, auto ref ExtraArgs extraArgs) 1877 { 1878 ref getI(size_t i)(return ref ChooseResult r) @trusted { return r.rs[i]; } 1879 1880 switch (r.chosenI) 1881 { 1882 static foreach (candI; 0 .. rs.length) 1883 { 1884 case candI: return foo(getI!candI(r), extraArgs); 1885 } 1886 1887 default: assert(false); 1888 } 1889 } 1890 1891 // @trusted because of assignment of r which overlap each other 1892 this(size_t chosen, return scope Ranges rs) @trusted 1893 { 1894 import core.lifetime : emplace; 1895 1896 // This should be the only place chosenI is ever assigned 1897 // independently 1898 this.chosenI = chosen; 1899 1900 // Otherwise the compiler will complain about skipping these fields 1901 static foreach (i; 0 .. rs.length) 1902 { 1903 this.rs[i] = Ranges[i].init; 1904 } 1905 1906 // The relevant field needs to be initialized last so it will overwrite 1907 // the other initializations and not the other way around. 1908 sw: switch (chosenI) 1909 { 1910 static foreach (i; 0 .. rs.length) 1911 { 1912 case i: 1913 emplace(&this.rs[i], rs[i]); 1914 break sw; 1915 } 1916 1917 default: assert(false); 1918 } 1919 } 1920 1921 // Some legacy code may still call this with typeof(choose(/*...*/))(/*...*/) 1922 // without this overload the regular constructor would invert the meaning of 1923 // the boolean 1924 static if (rs.length == 2) 1925 pragma(inline, true) 1926 deprecated("Call with size_t (0 = first), or use the choose function") 1927 this(bool firstChosen, Ranges rs) 1928 { 1929 import core.lifetime : move; 1930 this(cast(size_t)(firstChosen? 0: 1), rs[0].move, rs[1].move); 1931 } 1932 1933 void opAssign(ChooseResult r) 1934 { 1935 ref getI(size_t i)(return ref ChooseResult r) @trusted { return r.rs[i]; } 1936 1937 static if (anySatisfy!(hasElaborateDestructor, Ranges)) 1938 if (chosenI != r.chosenI) 1939 { 1940 // destroy the current item 1941 actOnChosen!((ref r) => destroy(r))(this); 1942 } 1943 chosenI = r.chosenI; 1944 1945 sw: switch (chosenI) 1946 { 1947 static foreach (candI; 0 .. rs.length) 1948 { 1949 case candI: getI!candI(this) = getI!candI(r); 1950 break sw; 1951 } 1952 1953 default: assert(false); 1954 } 1955 } 1956 1957 // Carefully defined postblit to postblit the appropriate range 1958 static if (anySatisfy!(hasElaborateCopyConstructor, Ranges)) 1959 this(this) 1960 { 1961 actOnChosen!((ref r) { 1962 static if (hasElaborateCopyConstructor!(typeof(r))) r.__xpostblit(); 1963 })(this); 1964 } 1965 1966 static if (anySatisfy!(hasElaborateDestructor, Ranges)) 1967 ~this() 1968 { 1969 actOnChosen!((ref r) => destroy(r))(this); 1970 } 1971 1972 // Propagate infiniteness. 1973 static if (allSatisfy!(isInfinite, Ranges)) enum bool empty = false; 1974 else @property bool empty() 1975 { 1976 return actOnChosen!(r => r.empty)(this); 1977 } 1978 1979 @property auto ref front() 1980 { 1981 static auto ref getFront(R)(ref R r) { return r.front; } 1982 return actOnChosen!getFront(this); 1983 } 1984 1985 void popFront() 1986 { 1987 return actOnChosen!((ref r) { r.popFront; })(this); 1988 } 1989 1990 static if (allSatisfy!(isForwardRange, Ranges)) 1991 @property auto save() // return scope inferred 1992 { 1993 auto saveOrInit(size_t i)() 1994 { 1995 ref getI() @trusted { return rs[i]; } 1996 if (i == chosenI) return getI().save; 1997 else return Ranges[i].init; 1998 } 1999 2000 return typeof(this)(chosenI, staticMap!(saveOrInit, 2001 aliasSeqOf!(rs.length.iota))); 2002 } 2003 2004 template front(T) 2005 { 2006 private enum overloadValidFor(alias r) = is(typeof(r.front = T.init)); 2007 2008 static if (allSatisfy!(overloadValidFor, rs)) 2009 void front(T v) 2010 { 2011 actOnChosen!((ref r, T v) { r.front = v; })(this, v); 2012 } 2013 } 2014 2015 static if (allSatisfy!(hasMobileElements, Ranges)) 2016 auto moveFront() 2017 { 2018 return actOnChosen!((ref r) => r.moveFront)(this); 2019 } 2020 2021 static if (allSatisfy!(isBidirectionalRange, Ranges)) 2022 { 2023 @property auto ref back() 2024 { 2025 static auto ref getBack(R)(ref R r) { return r.back; } 2026 return actOnChosen!getBack(this); 2027 } 2028 2029 void popBack() 2030 { 2031 actOnChosen!((ref r) { r.popBack; })(this); 2032 } 2033 2034 static if (allSatisfy!(hasMobileElements, Ranges)) 2035 auto moveBack() 2036 { 2037 return actOnChosen!((ref r) => r.moveBack)(this); 2038 } 2039 2040 template back(T) 2041 { 2042 private enum overloadValidFor(alias r) = is(typeof(r.back = T.init)); 2043 2044 static if (allSatisfy!(overloadValidFor, rs)) 2045 void back(T v) 2046 { 2047 actOnChosen!((ref r, T v) { r.back = v; })(this, v); 2048 } 2049 } 2050 } 2051 2052 static if (allSatisfy!(hasLength, Ranges)) 2053 { 2054 @property size_t length() 2055 { 2056 return actOnChosen!(r => r.length)(this); 2057 } 2058 alias opDollar = length; 2059 } 2060 2061 static if (allSatisfy!(isRandomAccessRange, Ranges)) 2062 { 2063 auto ref opIndex(size_t index) 2064 { 2065 static auto ref get(R)(ref R r, size_t index) { return r[index]; } 2066 return actOnChosen!get(this, index); 2067 } 2068 2069 static if (allSatisfy!(hasMobileElements, Ranges)) 2070 auto moveAt(size_t index) 2071 { 2072 return actOnChosen!((ref r, size_t index) => r.moveAt(index)) 2073 (this, index); 2074 } 2075 2076 private enum indexAssignable(T, R) = is(typeof(lvalueOf!R[1] = T.init)); 2077 2078 template opIndexAssign(T) 2079 if (allSatisfy!(ApplyLeft!(indexAssignable, T), Ranges)) 2080 { 2081 void opIndexAssign(T v, size_t index) 2082 { 2083 return actOnChosen!((ref r, size_t index, T v) { r[index] = v; }) 2084 (this, index, v); 2085 } 2086 } 2087 } 2088 2089 static if (allSatisfy!(hasSlicing, Ranges)) 2090 auto opSlice(size_t begin, size_t end) 2091 { 2092 alias Slice(R) = typeof(R.init[0 .. 1]); 2093 alias Slices = staticMap!(Slice, Ranges); 2094 2095 auto sliceOrInit(size_t i)() 2096 { 2097 ref getI() @trusted { return rs[i]; } 2098 return i == chosenI? getI()[begin .. end]: Slices[i].init; 2099 } 2100 2101 return chooseAmong(chosenI, staticMap!(sliceOrInit, 2102 aliasSeqOf!(rs.length.iota))); 2103 } 2104 } 2105 2106 // https://issues.dlang.org/show_bug.cgi?id=18657 2107 pure @safe unittest 2108 { 2109 import std.algorithm.comparison : equal; 2110 string s = "foo"; 2111 auto r = choose(true, refRange(&s), "bar"); 2112 assert(equal(r.save, "foo")); 2113 assert(equal(r, "foo")); 2114 } 2115 2116 @safe unittest 2117 { 2118 static void* p; 2119 static struct R 2120 { 2121 void* q; 2122 int front; 2123 bool empty; 2124 void popFront() {} 2125 // `p = q;` is only there to prevent inference of `scope return`. 2126 @property @safe R save() { p = q; return this; } 2127 2128 } 2129 R r; 2130 choose(true, r, r).save; 2131 } 2132 2133 // Make sure ChooseResult.save doesn't trust @system user code. 2134 @system unittest // copy is @system 2135 { 2136 static struct R 2137 { 2138 int front; 2139 bool empty; 2140 void popFront() {} 2141 this(this) @system {} 2142 @property R save() { return R(front, empty); } 2143 } 2144 choose(true, R(), R()).save; 2145 choose(true, [0], R()).save; 2146 choose(true, R(), [0]).save; 2147 } 2148 2149 @safe unittest // copy is @system 2150 { 2151 static struct R 2152 { 2153 int front; 2154 bool empty; 2155 void popFront() {} 2156 this(this) @system {} 2157 @property R save() { return R(front, empty); } 2158 } 2159 static assert(!__traits(compiles, choose(true, R(), R()).save)); 2160 static assert(!__traits(compiles, choose(true, [0], R()).save)); 2161 static assert(!__traits(compiles, choose(true, R(), [0]).save)); 2162 } 2163 2164 @system unittest // .save is @system 2165 { 2166 static struct R 2167 { 2168 int front; 2169 bool empty; 2170 void popFront() {} 2171 @property R save() @system { return this; } 2172 } 2173 choose(true, R(), R()).save; 2174 choose(true, [0], R()).save; 2175 choose(true, R(), [0]).save; 2176 } 2177 2178 @safe unittest // .save is @system 2179 { 2180 static struct R 2181 { 2182 int front; 2183 bool empty; 2184 void popFront() {} 2185 @property R save() @system { return this; } 2186 } 2187 static assert(!__traits(compiles, choose(true, R(), R()).save)); 2188 static assert(!__traits(compiles, choose(true, [0], R()).save)); 2189 static assert(!__traits(compiles, choose(true, R(), [0]).save)); 2190 } 2191 2192 //https://issues.dlang.org/show_bug.cgi?id=19738 2193 @safe nothrow pure @nogc unittest 2194 { 2195 static struct EvilRange 2196 { 2197 enum empty = true; 2198 int front; 2199 void popFront() @safe {} 2200 auto opAssign(const ref EvilRange other) 2201 { 2202 *(cast(uint*) 0xcafebabe) = 0xdeadbeef; 2203 return this; 2204 } 2205 } 2206 2207 static assert(!__traits(compiles, () @safe 2208 { 2209 auto c1 = choose(true, EvilRange(), EvilRange()); 2210 auto c2 = c1; 2211 c1 = c2; 2212 })); 2213 } 2214 2215 2216 // https://issues.dlang.org/show_bug.cgi?id=20495 2217 @safe unittest 2218 { 2219 static struct KillableRange 2220 { 2221 int *item; 2222 ref int front() { return *item; } 2223 bool empty() { return *item > 10; } 2224 void popFront() { ++(*item); } 2225 this(this) 2226 { 2227 assert(item is null || cast(size_t) item > 1000); 2228 item = new int(*item); 2229 } 2230 KillableRange save() { return this; } 2231 } 2232 2233 auto kr = KillableRange(new int(1)); 2234 int[] x = [1,2,3,4,5]; // length is first 2235 2236 auto chosen = choose(true, x, kr); 2237 auto chosen2 = chosen.save; 2238 } 2239 2240 pure @safe nothrow unittest 2241 { 2242 static struct S { 2243 int v; 2244 @disable this(this); 2245 } 2246 2247 auto a = [S(1), S(2), S(3)]; 2248 auto b = [S(4), S(5), S(6)]; 2249 2250 auto chosen = choose(true, a, b); 2251 assert(chosen.front.v == 1); 2252 2253 auto chosen2 = choose(false, a, b); 2254 assert(chosen2.front.v == 4); 2255 } 2256 2257 // https://issues.dlang.org/show_bug.cgi?id=15708 2258 @safe unittest 2259 { 2260 static struct HasPostblit 2261 { 2262 this(this) {} 2263 } 2264 2265 static struct Range 2266 { 2267 bool empty; 2268 int front; 2269 void popFront() {} 2270 HasPostblit member; 2271 } 2272 2273 Range range; 2274 int[] arr; 2275 2276 auto chosen = choose(true, range, arr); 2277 auto copy = chosen; 2278 } 2279 2280 /** 2281 Choose one of multiple ranges at runtime. 2282 2283 The ranges may be different, but they must have compatible element types. The 2284 result is a range that offers the weakest capabilities of all `Ranges`. 2285 2286 Params: 2287 index = which range to choose, must be less than the number of ranges 2288 rs = two or more ranges 2289 2290 Returns: 2291 The indexed range. If rs consists of only one range, the return type is an 2292 alias of that range's type. 2293 */ 2294 auto chooseAmong(Ranges...)(size_t index, return scope Ranges rs) 2295 if (Ranges.length >= 2 2296 && allSatisfy!(isInputRange, staticMap!(Unqual, Ranges)) 2297 && !is(CommonType!(staticMap!(ElementType, Ranges)) == void)) 2298 { 2299 return ChooseResult!Ranges(index, rs); 2300 } 2301 2302 /// 2303 @safe nothrow pure @nogc unittest 2304 { 2305 auto test() 2306 { 2307 import std.algorithm.comparison : equal; 2308 2309 int[4] sarr1 = [1, 2, 3, 4]; 2310 int[2] sarr2 = [5, 6]; 2311 int[1] sarr3 = [7]; 2312 auto arr1 = sarr1[]; 2313 auto arr2 = sarr2[]; 2314 auto arr3 = sarr3[]; 2315 2316 { 2317 auto s = chooseAmong(0, arr1, arr2, arr3); 2318 auto t = s.save; 2319 assert(s.length == 4); 2320 assert(s[2] == 3); 2321 s.popFront(); 2322 assert(equal(t, only(1, 2, 3, 4))); 2323 } 2324 { 2325 auto s = chooseAmong(1, arr1, arr2, arr3); 2326 assert(s.length == 2); 2327 s.front = 8; 2328 assert(equal(s, only(8, 6))); 2329 } 2330 { 2331 auto s = chooseAmong(1, arr1, arr2, arr3); 2332 assert(s.length == 2); 2333 s[1] = 9; 2334 assert(equal(s, only(8, 9))); 2335 } 2336 { 2337 auto s = chooseAmong(1, arr2, arr1, arr3)[1 .. 3]; 2338 assert(s.length == 2); 2339 assert(equal(s, only(2, 3))); 2340 } 2341 { 2342 auto s = chooseAmong(0, arr1, arr2, arr3); 2343 assert(s.length == 4); 2344 assert(s.back == 4); 2345 s.popBack(); 2346 s.back = 5; 2347 assert(equal(s, only(1, 2, 5))); 2348 s.back = 3; 2349 assert(equal(s, only(1, 2, 3))); 2350 } 2351 { 2352 uint[5] foo = [1, 2, 3, 4, 5]; 2353 uint[5] bar = [6, 7, 8, 9, 10]; 2354 auto c = chooseAmong(1, foo[], bar[]); 2355 assert(c[3] == 9); 2356 c[3] = 42; 2357 assert(c[3] == 42); 2358 assert(c.moveFront() == 6); 2359 assert(c.moveBack() == 10); 2360 assert(c.moveAt(4) == 10); 2361 } 2362 { 2363 import std.range : cycle; 2364 auto s = chooseAmong(0, cycle(arr2), cycle(arr3)); 2365 assert(isInfinite!(typeof(s))); 2366 assert(!s.empty); 2367 assert(s[100] == 8); 2368 assert(s[101] == 9); 2369 assert(s[0 .. 3].equal(only(8, 9, 8))); 2370 } 2371 return 0; 2372 } 2373 // works at runtime 2374 auto a = test(); 2375 // and at compile time 2376 static b = test(); 2377 } 2378 2379 @safe nothrow pure @nogc unittest 2380 { 2381 int[3] a = [1, 2, 3]; 2382 long[3] b = [4, 5, 6]; 2383 auto c = chooseAmong(0, a[], b[]); 2384 c[0] = 42; 2385 assert(c[0] == 42); 2386 } 2387 2388 @safe nothrow pure @nogc unittest 2389 { 2390 static struct RefAccessRange 2391 { 2392 int[] r; 2393 ref front() @property { return r[0]; } 2394 ref back() @property { return r[$ - 1]; } 2395 void popFront() { r = r[1 .. $]; } 2396 void popBack() { r = r[0 .. $ - 1]; } 2397 auto empty() @property { return r.empty; } 2398 ref opIndex(size_t i) { return r[i]; } 2399 auto length() @property { return r.length; } 2400 alias opDollar = length; 2401 auto save() { return this; } 2402 } 2403 static assert(isRandomAccessRange!RefAccessRange); 2404 static assert(isRandomAccessRange!RefAccessRange); 2405 int[4] a = [4, 3, 2, 1]; 2406 int[2] b = [6, 5]; 2407 auto c = chooseAmong(0, RefAccessRange(a[]), RefAccessRange(b[])); 2408 2409 void refFunc(ref int a, int target) { assert(a == target); } 2410 2411 refFunc(c[2], 2); 2412 refFunc(c.front, 4); 2413 refFunc(c.back, 1); 2414 } 2415 2416 2417 /** 2418 $(D roundRobin(r1, r2, r3)) yields `r1.front`, then `r2.front`, 2419 then `r3.front`, after which it pops off one element from each and 2420 continues again from `r1`. For example, if two ranges are involved, 2421 it alternately yields elements off the two ranges. `roundRobin` 2422 stops after it has consumed all ranges (skipping over the ones that 2423 finish early). 2424 */ 2425 auto roundRobin(Rs...)(Rs rs) 2426 if (Rs.length > 1 && allSatisfy!(isInputRange, staticMap!(Unqual, Rs))) 2427 { 2428 struct Result 2429 { 2430 import std.conv : to; 2431 2432 public Rs source; 2433 private size_t _current = size_t.max; 2434 2435 @property bool empty() 2436 { 2437 foreach (i, Unused; Rs) 2438 { 2439 if (!source[i].empty) return false; 2440 } 2441 return true; 2442 } 2443 2444 @property auto ref front() 2445 { 2446 final switch (_current) 2447 { 2448 foreach (i, R; Rs) 2449 { 2450 case i: 2451 assert( 2452 !source[i].empty, 2453 "Attempting to fetch the front of an empty roundRobin" 2454 ); 2455 return source[i].front; 2456 } 2457 } 2458 assert(0); 2459 } 2460 2461 void popFront() 2462 { 2463 final switch (_current) 2464 { 2465 foreach (i, R; Rs) 2466 { 2467 case i: 2468 source[i].popFront(); 2469 break; 2470 } 2471 } 2472 2473 auto next = _current == (Rs.length - 1) ? 0 : (_current + 1); 2474 final switch (next) 2475 { 2476 foreach (i, R; Rs) 2477 { 2478 case i: 2479 if (!source[i].empty) 2480 { 2481 _current = i; 2482 return; 2483 } 2484 if (i == _current) 2485 { 2486 _current = _current.max; 2487 return; 2488 } 2489 goto case (i + 1) % Rs.length; 2490 } 2491 } 2492 } 2493 2494 static if (allSatisfy!(isForwardRange, staticMap!(Unqual, Rs))) 2495 @property auto save() 2496 { 2497 auto saveSource(size_t len)() 2498 { 2499 import std.typecons : tuple; 2500 static assert(len > 0); 2501 static if (len == 1) 2502 { 2503 return tuple(source[0].save); 2504 } 2505 else 2506 { 2507 return saveSource!(len - 1)() ~ 2508 tuple(source[len - 1].save); 2509 } 2510 } 2511 return Result(saveSource!(Rs.length).expand, _current); 2512 } 2513 2514 static if (allSatisfy!(hasLength, Rs)) 2515 { 2516 @property size_t length() 2517 { 2518 size_t result; 2519 foreach (i, R; Rs) 2520 { 2521 result += source[i].length; 2522 } 2523 return result; 2524 } 2525 2526 alias opDollar = length; 2527 } 2528 } 2529 2530 size_t firstNonEmpty = size_t.max; 2531 static foreach (i; 0 .. Rs.length) 2532 { 2533 if (firstNonEmpty == size_t.max && !rs[i].empty) 2534 firstNonEmpty = i; 2535 } 2536 2537 return Result(rs, firstNonEmpty); 2538 } 2539 2540 /// 2541 @safe unittest 2542 { 2543 import std.algorithm.comparison : equal; 2544 2545 int[] a = [ 1, 2, 3 ]; 2546 int[] b = [ 10, 20, 30, 40 ]; 2547 auto r = roundRobin(a, b); 2548 assert(equal(r, [ 1, 10, 2, 20, 3, 30, 40 ])); 2549 } 2550 2551 /** 2552 * roundRobin can be used to create "interleave" functionality which inserts 2553 * an element between each element in a range. 2554 */ 2555 @safe unittest 2556 { 2557 import std.algorithm.comparison : equal; 2558 2559 auto interleave(R, E)(R range, E element) 2560 if ((isInputRange!R && hasLength!R) || isForwardRange!R) 2561 { 2562 static if (hasLength!R) 2563 immutable len = range.length; 2564 else 2565 immutable len = range.save.walkLength; 2566 2567 return roundRobin( 2568 range, 2569 element.repeat(len - 1) 2570 ); 2571 } 2572 2573 assert(interleave([1, 2, 3], 0).equal([1, 0, 2, 0, 3])); 2574 } 2575 2576 pure @safe unittest 2577 { 2578 import std.algorithm.comparison : equal; 2579 string f = "foo", b = "bar"; 2580 auto r = roundRobin(refRange(&f), refRange(&b)); 2581 assert(equal(r.save, "fboaor")); 2582 assert(equal(r.save, "fboaor")); 2583 } 2584 pure @safe nothrow unittest 2585 { 2586 import std.algorithm.comparison : equal; 2587 2588 static struct S { 2589 int v; 2590 @disable this(this); 2591 } 2592 2593 S[] a = [ S(1), S(2) ]; 2594 S[] b = [ S(10), S(20) ]; 2595 auto r = roundRobin(a, b); 2596 assert(equal(r, [ S(1), S(10), S(2), S(20) ])); 2597 } 2598 2599 // https://issues.dlang.org/show_bug.cgi?id=24384 2600 @safe unittest 2601 { 2602 auto r = roundRobin("", "a"); 2603 assert(!r.empty); 2604 auto e = r.front; 2605 } 2606 2607 /** 2608 Iterates a random-access range starting from a given point and 2609 progressively extending left and right from that point. If no initial 2610 point is given, iteration starts from the middle of the 2611 range. Iteration spans the entire range. 2612 2613 When `startingIndex` is 0 the range will be fully iterated in order 2614 and in reverse order when `r.length` is given. 2615 2616 Params: 2617 r = a random access range with length and slicing 2618 startingIndex = the index to begin iteration from 2619 2620 Returns: 2621 A forward range with length 2622 */ 2623 auto radial(Range, I)(Range r, I startingIndex) 2624 if (isRandomAccessRange!(Unqual!Range) && hasLength!(Unqual!Range) && hasSlicing!(Unqual!Range) && isIntegral!I) 2625 { 2626 if (startingIndex != r.length) ++startingIndex; 2627 return roundRobin(retro(r[0 .. startingIndex]), r[startingIndex .. r.length]); 2628 } 2629 2630 /// Ditto 2631 auto radial(R)(R r) 2632 if (isRandomAccessRange!(Unqual!R) && hasLength!(Unqual!R) && hasSlicing!(Unqual!R)) 2633 { 2634 return .radial(r, (r.length - !r.empty) / 2); 2635 } 2636 2637 /// 2638 @safe unittest 2639 { 2640 import std.algorithm.comparison : equal; 2641 int[] a = [ 1, 2, 3, 4, 5 ]; 2642 assert(equal(radial(a), [ 3, 4, 2, 5, 1 ])); 2643 a = [ 1, 2, 3, 4 ]; 2644 assert(equal(radial(a), [ 2, 3, 1, 4 ])); 2645 2646 // If the left end is reached first, the remaining elements on the right 2647 // are concatenated in order: 2648 a = [ 0, 1, 2, 3, 4, 5 ]; 2649 assert(equal(radial(a, 1), [ 1, 2, 0, 3, 4, 5 ])); 2650 2651 // If the right end is reached first, the remaining elements on the left 2652 // are concatenated in reverse order: 2653 assert(equal(radial(a, 4), [ 4, 5, 3, 2, 1, 0 ])); 2654 } 2655 2656 @safe unittest 2657 { 2658 import std.algorithm.comparison : equal; 2659 import std.conv : text; 2660 import std.exception : enforce; 2661 import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy; 2662 2663 void test(int[] input, int[] witness) 2664 { 2665 enforce(equal(radial(input), witness), 2666 text(radial(input), " vs. ", witness)); 2667 } 2668 test([], []); 2669 test([ 1 ], [ 1 ]); 2670 test([ 1, 2 ], [ 1, 2 ]); 2671 test([ 1, 2, 3 ], [ 2, 3, 1 ]); 2672 test([ 1, 2, 3, 4 ], [ 2, 3, 1, 4 ]); 2673 test([ 1, 2, 3, 4, 5 ], [ 3, 4, 2, 5, 1 ]); 2674 test([ 1, 2, 3, 4, 5, 6 ], [ 3, 4, 2, 5, 1, 6 ]); 2675 2676 int[] a = [ 1, 2, 3, 4, 5 ]; 2677 assert(equal(radial(a, 1), [ 2, 3, 1, 4, 5 ])); 2678 assert(equal(radial(a, 0), [ 1, 2, 3, 4, 5 ])); // only right subrange 2679 assert(equal(radial(a, a.length), [ 5, 4, 3, 2, 1 ])); // only left subrange 2680 static assert(isForwardRange!(typeof(radial(a, 1)))); 2681 2682 auto r = radial([1,2,3,4,5]); 2683 for (auto rr = r.save; !rr.empty; rr.popFront()) 2684 { 2685 assert(rr.front == moveFront(rr)); 2686 } 2687 r.front = 5; 2688 assert(r.front == 5); 2689 2690 // Test instantiation without lvalue elements. 2691 DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random) dummy; 2692 assert(equal(radial(dummy, 4), [5, 6, 4, 7, 3, 8, 2, 9, 1, 10])); 2693 2694 // immutable int[] immi = [ 1, 2 ]; 2695 // static assert(is(typeof(radial(immi)))); 2696 } 2697 2698 @safe unittest 2699 { 2700 import std.algorithm.comparison : equal; 2701 2702 auto LL = iota(1L, 6L); 2703 auto r = radial(LL); 2704 assert(equal(r, [3L, 4L, 2L, 5L, 1L])); 2705 } 2706 2707 /** 2708 Lazily takes only up to `n` elements of a range. This is 2709 particularly useful when using with infinite ranges. 2710 2711 Unlike $(LREF takeExactly), `take` does not require that there 2712 are `n` or more elements in `input`. As a consequence, length 2713 information is not applied to the result unless `input` also has 2714 length information. 2715 2716 Params: 2717 input = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives) 2718 to iterate over up to `n` times 2719 n = the number of elements to take 2720 2721 Returns: 2722 At minimum, an input range. If the range offers random access 2723 and `length`, `take` offers them as well. 2724 */ 2725 Take!R take(R)(R input, size_t n) 2726 if (isInputRange!(Unqual!R)) 2727 { 2728 alias U = Unqual!R; 2729 static if (is(R T == Take!T)) 2730 { 2731 import std.algorithm.comparison : min; 2732 return R(input.source, min(n, input._maxAvailable)); 2733 } 2734 else static if (!isInfinite!U && hasSlicing!U) 2735 { 2736 import std.algorithm.comparison : min; 2737 return input[0 .. min(n, input.length)]; 2738 } 2739 else 2740 { 2741 return Take!R(input, n); 2742 } 2743 } 2744 2745 /// ditto 2746 struct Take(Range) 2747 if (isInputRange!(Unqual!Range) && 2748 //take _cannot_ test hasSlicing on infinite ranges, because hasSlicing uses 2749 //take for slicing infinite ranges. 2750 !((!isInfinite!(Unqual!Range) && hasSlicing!(Unqual!Range)) || is(Range T == Take!T))) 2751 { 2752 private alias R = Unqual!Range; 2753 2754 /// User accessible in read and write 2755 public R source; 2756 2757 private size_t _maxAvailable; 2758 2759 alias Source = R; 2760 2761 /// Range primitives 2762 @property bool empty() 2763 { 2764 return _maxAvailable == 0 || source.empty; 2765 } 2766 2767 /// ditto 2768 @property auto ref front() 2769 { 2770 assert(!empty, 2771 "Attempting to fetch the front of an empty " 2772 ~ Take.stringof); 2773 return source.front; 2774 } 2775 2776 /// ditto 2777 void popFront() 2778 { 2779 assert(!empty, 2780 "Attempting to popFront() past the end of a " 2781 ~ Take.stringof); 2782 source.popFront(); 2783 --_maxAvailable; 2784 } 2785 2786 static if (isForwardRange!R) 2787 /// ditto 2788 @property Take save() 2789 { 2790 return Take(source.save, _maxAvailable); 2791 } 2792 2793 static if (hasAssignableElements!R) 2794 /// ditto 2795 @property void front(ElementType!R v) 2796 { 2797 import core.lifetime : forward; 2798 2799 assert(!empty, 2800 "Attempting to assign to the front of an empty " 2801 ~ Take.stringof); 2802 2803 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542 2804 source.front = __ctfe ? v : forward!v; 2805 } 2806 2807 static if (hasMobileElements!R) 2808 { 2809 /// ditto 2810 auto moveFront() 2811 { 2812 assert(!empty, 2813 "Attempting to move the front of an empty " 2814 ~ Take.stringof); 2815 return source.moveFront(); 2816 } 2817 } 2818 2819 static if (isInfinite!R) 2820 { 2821 /// ditto 2822 @property size_t length() const 2823 { 2824 return _maxAvailable; 2825 } 2826 2827 /// ditto 2828 alias opDollar = length; 2829 2830 //Note: Due to Take/hasSlicing circular dependency, 2831 //This needs to be a restrained template. 2832 /// ditto 2833 auto opSlice()(size_t i, size_t j) 2834 if (hasSlicing!R) 2835 { 2836 assert(i <= j, "Invalid slice bounds"); 2837 assert(j <= length, "Attempting to slice past the end of a " 2838 ~ Take.stringof); 2839 return source[i .. j]; 2840 } 2841 } 2842 else static if (hasLength!R) 2843 { 2844 /// ditto 2845 @property size_t length() 2846 { 2847 import std.algorithm.comparison : min; 2848 return min(_maxAvailable, source.length); 2849 } 2850 2851 alias opDollar = length; 2852 } 2853 2854 static if (isRandomAccessRange!R) 2855 { 2856 /// ditto 2857 void popBack() 2858 { 2859 assert(!empty, 2860 "Attempting to popBack() past the beginning of a " 2861 ~ Take.stringof); 2862 --_maxAvailable; 2863 } 2864 2865 /// ditto 2866 @property auto ref back() 2867 { 2868 assert(!empty, 2869 "Attempting to fetch the back of an empty " 2870 ~ Take.stringof); 2871 return source[this.length - 1]; 2872 } 2873 2874 /// ditto 2875 auto ref opIndex(size_t index) 2876 { 2877 assert(index < length, 2878 "Attempting to index out of the bounds of a " 2879 ~ Take.stringof); 2880 return source[index]; 2881 } 2882 2883 static if (hasAssignableElements!R) 2884 { 2885 /// ditto 2886 @property void back(ElementType!R v) 2887 { 2888 // This has to return auto instead of void because of 2889 // https://issues.dlang.org/show_bug.cgi?id=4706 2890 assert(!empty, 2891 "Attempting to assign to the back of an empty " 2892 ~ Take.stringof); 2893 source[this.length - 1] = v; 2894 } 2895 2896 /// ditto 2897 void opIndexAssign(ElementType!R v, size_t index) 2898 { 2899 assert(index < length, 2900 "Attempting to index out of the bounds of a " 2901 ~ Take.stringof); 2902 source[index] = v; 2903 } 2904 } 2905 2906 static if (hasMobileElements!R) 2907 { 2908 /// ditto 2909 auto moveBack() 2910 { 2911 assert(!empty, 2912 "Attempting to move the back of an empty " 2913 ~ Take.stringof); 2914 return source.moveAt(this.length - 1); 2915 } 2916 2917 /// ditto 2918 auto moveAt(size_t index) 2919 { 2920 assert(index < length, 2921 "Attempting to index out of the bounds of a " 2922 ~ Take.stringof); 2923 return source.moveAt(index); 2924 } 2925 } 2926 } 2927 2928 /** 2929 Access to maximal length of the range. 2930 Note: the actual length of the range depends on the underlying range. 2931 If it has fewer elements, it will stop before maxLength is reached. 2932 */ 2933 @property size_t maxLength() const 2934 { 2935 return _maxAvailable; 2936 } 2937 } 2938 2939 /// ditto 2940 template Take(R) 2941 if (isInputRange!(Unqual!R) && 2942 ((!isInfinite!(Unqual!R) && hasSlicing!(Unqual!R)) || is(R T == Take!T))) 2943 { 2944 alias Take = R; 2945 } 2946 2947 /// 2948 pure @safe nothrow unittest 2949 { 2950 import std.algorithm.comparison : equal; 2951 2952 int[] arr1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; 2953 auto s = take(arr1, 5); 2954 assert(s.length == 5); 2955 assert(s[4] == 5); 2956 assert(equal(s, [ 1, 2, 3, 4, 5 ][])); 2957 } 2958 2959 /** 2960 * If the range runs out before `n` elements, `take` simply returns the entire 2961 * range (unlike $(LREF takeExactly), which will cause an assertion failure if 2962 * the range ends prematurely): 2963 */ 2964 pure @safe nothrow unittest 2965 { 2966 import std.algorithm.comparison : equal; 2967 2968 int[] arr2 = [ 1, 2, 3 ]; 2969 auto t = take(arr2, 5); 2970 assert(t.length == 3); 2971 assert(equal(t, [ 1, 2, 3 ])); 2972 } 2973 2974 pure @safe nothrow unittest 2975 { 2976 import std.algorithm.comparison : equal; 2977 import std.internal.test.dummyrange : AllDummyRanges; 2978 2979 int[] arr1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; 2980 auto s = take(arr1, 5); 2981 assert(s.length == 5); 2982 assert(s[4] == 5); 2983 assert(equal(s, [ 1, 2, 3, 4, 5 ][])); 2984 assert(equal(retro(s), [ 5, 4, 3, 2, 1 ][])); 2985 2986 // Test fix for bug 4464. 2987 static assert(is(typeof(s) == Take!(int[]))); 2988 static assert(is(typeof(s) == int[])); 2989 2990 // Test using narrow strings. 2991 import std.exception : assumeWontThrow; 2992 2993 auto myStr = "This is a string."; 2994 auto takeMyStr = take(myStr, 7); 2995 assert(assumeWontThrow(equal(takeMyStr, "This is"))); 2996 // Test fix for bug 5052. 2997 auto takeMyStrAgain = take(takeMyStr, 4); 2998 assert(assumeWontThrow(equal(takeMyStrAgain, "This"))); 2999 static assert(is (typeof(takeMyStrAgain) == typeof(takeMyStr))); 3000 takeMyStrAgain = take(takeMyStr, 10); 3001 assert(assumeWontThrow(equal(takeMyStrAgain, "This is"))); 3002 3003 foreach (DummyType; AllDummyRanges) 3004 { 3005 DummyType dummy; 3006 auto t = take(dummy, 5); 3007 alias T = typeof(t); 3008 3009 static if (isRandomAccessRange!DummyType) 3010 { 3011 static assert(isRandomAccessRange!T); 3012 assert(t[4] == 5); 3013 3014 assert(moveAt(t, 1) == t[1]); 3015 assert(t.back == moveBack(t)); 3016 } 3017 else static if (isForwardRange!DummyType) 3018 { 3019 static assert(isForwardRange!T); 3020 } 3021 3022 for (auto tt = t; !tt.empty; tt.popFront()) 3023 { 3024 assert(tt.front == moveFront(tt)); 3025 } 3026 3027 // Bidirectional ranges can't be propagated properly if they don't 3028 // also have random access. 3029 3030 assert(equal(t, [1,2,3,4,5])); 3031 3032 //Test that take doesn't wrap the result of take. 3033 assert(take(t, 4) == take(dummy, 4)); 3034 } 3035 3036 immutable myRepeat = repeat(1); 3037 static assert(is(Take!(typeof(myRepeat)))); 3038 } 3039 3040 pure @safe nothrow @nogc unittest 3041 { 3042 //check for correct slicing of Take on an infinite range 3043 import std.algorithm.comparison : equal; 3044 foreach (start; 0 .. 4) 3045 foreach (stop; start .. 4) 3046 assert(iota(4).cycle.take(4)[start .. stop] 3047 .equal(iota(start, stop))); 3048 } 3049 3050 pure @safe nothrow @nogc unittest 3051 { 3052 // Check that one can declare variables of all Take types, 3053 // and that they match the return type of the corresponding 3054 // take(). 3055 // See https://issues.dlang.org/show_bug.cgi?id=4464 3056 int[] r1; 3057 Take!(int[]) t1; 3058 t1 = take(r1, 1); 3059 assert(t1.empty); 3060 3061 string r2; 3062 Take!string t2; 3063 t2 = take(r2, 1); 3064 assert(t2.empty); 3065 3066 Take!(Take!string) t3; 3067 t3 = take(t2, 1); 3068 assert(t3.empty); 3069 } 3070 3071 pure @safe nothrow @nogc unittest 3072 { 3073 alias R1 = typeof(repeat(1)); 3074 alias R2 = typeof(cycle([1])); 3075 alias TR1 = Take!R1; 3076 alias TR2 = Take!R2; 3077 static assert(isBidirectionalRange!TR1); 3078 static assert(isBidirectionalRange!TR2); 3079 } 3080 3081 // https://issues.dlang.org/show_bug.cgi?id=12731 3082 pure @safe nothrow @nogc unittest 3083 { 3084 auto a = repeat(1); 3085 auto s = a[1 .. 5]; 3086 s = s[1 .. 3]; 3087 assert(s.length == 2); 3088 assert(s[0] == 1); 3089 assert(s[1] == 1); 3090 } 3091 3092 // https://issues.dlang.org/show_bug.cgi?id=13151 3093 pure @safe nothrow @nogc unittest 3094 { 3095 import std.algorithm.comparison : equal; 3096 3097 auto r = take(repeat(1, 4), 3); 3098 assert(r.take(2).equal(repeat(1, 2))); 3099 } 3100 3101 // https://issues.dlang.org/show_bug.cgi?id=24481 3102 @safe unittest 3103 { 3104 import std.algorithm.iteration : filter; 3105 3106 bool called; 3107 struct Handle 3108 { 3109 int entry; 3110 void opAssign()(auto ref const(typeof(this)) that) const { called = true; } 3111 } 3112 3113 const(Handle)[5] arr = [Handle(0), Handle(1), Handle(2), Handle(3), Handle(4)]; 3114 auto range = arr[].filter!(a => true)().take(3); 3115 3116 called = false; 3117 range.front = Handle(42); 3118 assert(called); 3119 } 3120 3121 /** 3122 Similar to $(LREF take), but assumes that `range` has at least $(D 3123 n) elements. Consequently, the result of $(D takeExactly(range, n)) 3124 always defines the `length` property (and initializes it to `n`) 3125 even when `range` itself does not define `length`. 3126 3127 The result of `takeExactly` is identical to that of $(LREF take) in 3128 cases where the original range defines `length` or is infinite. 3129 3130 Unlike $(LREF take), however, it is illegal to pass a range with less than 3131 `n` elements to `takeExactly`; this will cause an assertion failure. 3132 */ 3133 auto takeExactly(R)(R range, size_t n) 3134 if (isInputRange!R) 3135 { 3136 static if (is(typeof(takeExactly(range._input, n)) == R)) 3137 { 3138 assert(n <= range._n, 3139 "Attempted to take more than the length of the range with takeExactly."); 3140 // takeExactly(takeExactly(r, n1), n2) has the same type as 3141 // takeExactly(r, n1) and simply returns takeExactly(r, n2) 3142 range._n = n; 3143 return range; 3144 } 3145 //Also covers hasSlicing!R for finite ranges. 3146 else static if (hasLength!R) 3147 { 3148 assert(n <= range.length, 3149 "Attempted to take more than the length of the range with takeExactly."); 3150 return take(range, n); 3151 } 3152 else static if (isInfinite!R) 3153 return Take!R(range, n); 3154 else 3155 { 3156 static struct Result 3157 { 3158 R _input; 3159 private size_t _n; 3160 3161 @property bool empty() const { return !_n; } 3162 @property auto ref front() 3163 { 3164 assert(_n > 0, "front() on an empty " ~ Result.stringof); 3165 return _input.front; 3166 } 3167 void popFront() { _input.popFront(); --_n; } 3168 @property size_t length() const { return _n; } 3169 alias opDollar = length; 3170 3171 @property auto _takeExactly_Result_asTake() 3172 { 3173 return take(_input, _n); 3174 } 3175 3176 alias _takeExactly_Result_asTake this; 3177 3178 static if (isForwardRange!R) 3179 @property auto save() 3180 { 3181 return Result(_input.save, _n); 3182 } 3183 3184 static if (hasMobileElements!R) 3185 { 3186 auto moveFront() 3187 { 3188 assert(!empty, 3189 "Attempting to move the front of an empty " 3190 ~ typeof(this).stringof); 3191 return _input.moveFront(); 3192 } 3193 } 3194 3195 static if (hasAssignableElements!R) 3196 { 3197 @property auto ref front(ElementType!R v) 3198 { 3199 import core.lifetime : forward; 3200 3201 assert(!empty, 3202 "Attempting to assign to the front of an empty " 3203 ~ typeof(this).stringof); 3204 3205 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542 3206 return _input.front = __ctfe ? v : forward!v; 3207 } 3208 } 3209 } 3210 3211 return Result(range, n); 3212 } 3213 } 3214 3215 /// 3216 pure @safe nothrow unittest 3217 { 3218 import std.algorithm.comparison : equal; 3219 3220 auto a = [ 1, 2, 3, 4, 5 ]; 3221 3222 auto b = takeExactly(a, 3); 3223 assert(equal(b, [1, 2, 3])); 3224 static assert(is(typeof(b.length) == size_t)); 3225 assert(b.length == 3); 3226 assert(b.front == 1); 3227 assert(b.back == 3); 3228 } 3229 3230 pure @safe nothrow unittest 3231 { 3232 import std.algorithm.comparison : equal; 3233 import std.algorithm.iteration : filter; 3234 3235 auto a = [ 1, 2, 3, 4, 5 ]; 3236 auto b = takeExactly(a, 3); 3237 assert(equal(b, [1, 2, 3])); 3238 auto c = takeExactly(b, 2); 3239 assert(equal(c, [1, 2])); 3240 3241 3242 3243 auto d = filter!"a > 2"(a); 3244 auto e = takeExactly(d, 3); 3245 assert(equal(e, [3, 4, 5])); 3246 static assert(is(typeof(e.length) == size_t)); 3247 assert(e.length == 3); 3248 assert(e.front == 3); 3249 3250 assert(equal(takeExactly(e, 3), [3, 4, 5])); 3251 } 3252 3253 pure @safe nothrow unittest 3254 { 3255 import std.algorithm.comparison : equal; 3256 import std.internal.test.dummyrange : AllDummyRanges; 3257 3258 auto a = [ 1, 2, 3, 4, 5 ]; 3259 //Test that take and takeExactly are the same for ranges which define length 3260 //but aren't sliceable. 3261 struct L 3262 { 3263 @property auto front() { return _arr[0]; } 3264 @property bool empty() { return _arr.empty; } 3265 void popFront() { _arr.popFront(); } 3266 @property size_t length() { return _arr.length; } 3267 int[] _arr; 3268 } 3269 static assert(is(typeof(take(L(a), 3)) == typeof(takeExactly(L(a), 3)))); 3270 assert(take(L(a), 3) == takeExactly(L(a), 3)); 3271 3272 //Test that take and takeExactly are the same for ranges which are sliceable. 3273 static assert(is(typeof(take(a, 3)) == typeof(takeExactly(a, 3)))); 3274 assert(take(a, 3) == takeExactly(a, 3)); 3275 3276 //Test that take and takeExactly are the same for infinite ranges. 3277 auto inf = repeat(1); 3278 static assert(is(typeof(take(inf, 5)) == Take!(typeof(inf)))); 3279 assert(take(inf, 5) == takeExactly(inf, 5)); 3280 3281 //Test that take and takeExactly are _not_ the same for ranges which don't 3282 //define length. 3283 static assert(!is(typeof(take(filter!"true"(a), 3)) == typeof(takeExactly(filter!"true"(a), 3)))); 3284 3285 foreach (DummyType; AllDummyRanges) 3286 { 3287 { 3288 DummyType dummy; 3289 auto t = takeExactly(dummy, 5); 3290 3291 //Test that takeExactly doesn't wrap the result of takeExactly. 3292 assert(takeExactly(t, 4) == takeExactly(dummy, 4)); 3293 } 3294 3295 static if (hasMobileElements!DummyType) 3296 { 3297 { 3298 auto t = takeExactly(DummyType.init, 4); 3299 assert(t.moveFront() == 1); 3300 assert(equal(t, [1, 2, 3, 4])); 3301 } 3302 } 3303 3304 static if (hasAssignableElements!DummyType) 3305 { 3306 { 3307 auto t = takeExactly(DummyType.init, 4); 3308 t.front = 9; 3309 assert(equal(t, [9, 2, 3, 4])); 3310 } 3311 } 3312 } 3313 } 3314 3315 pure @safe nothrow unittest 3316 { 3317 import std.algorithm.comparison : equal; 3318 import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy; 3319 3320 alias DummyType = DummyRange!(ReturnBy.Value, Length.No, RangeType.Forward); 3321 auto te = takeExactly(DummyType(), 5); 3322 Take!DummyType t = te; 3323 assert(equal(t, [1, 2, 3, 4, 5])); 3324 assert(equal(t, te)); 3325 } 3326 3327 // https://issues.dlang.org/show_bug.cgi?id=18092 3328 // can't combine take and takeExactly 3329 @safe unittest 3330 { 3331 import std.algorithm.comparison : equal; 3332 import std.internal.test.dummyrange : AllDummyRanges; 3333 3334 static foreach (Range; AllDummyRanges) 3335 {{ 3336 Range r; 3337 assert(r.take(6).takeExactly(2).equal([1, 2])); 3338 assert(r.takeExactly(6).takeExactly(2).equal([1, 2])); 3339 assert(r.takeExactly(6).take(2).equal([1, 2])); 3340 }} 3341 } 3342 3343 // https://issues.dlang.org/show_bug.cgi?id=24481 3344 @safe unittest 3345 { 3346 import std.algorithm.iteration : filter; 3347 3348 bool called; 3349 struct Handle 3350 { 3351 int entry; 3352 void opAssign()(auto ref const(typeof(this)) that) const { called = true; } 3353 } 3354 3355 const(Handle)[5] arr = [Handle(0), Handle(1), Handle(2), Handle(3), Handle(4)]; 3356 auto range = arr[].filter!(a => true)().takeExactly(3); 3357 3358 called = false; 3359 range.front = Handle(42); 3360 assert(called); 3361 } 3362 3363 /** 3364 Returns a range with at most one element; for example, $(D 3365 takeOne([42, 43, 44])) returns a range consisting of the integer $(D 3366 42). Calling `popFront()` off that range renders it empty. 3367 3368 In effect `takeOne(r)` is somewhat equivalent to $(D take(r, 1)) but in 3369 certain interfaces it is important to know statically that the range may only 3370 have at most one element. 3371 3372 The type returned by `takeOne` is a random-access range with length 3373 regardless of `R`'s capabilities, as long as it is a forward range. 3374 (another feature that distinguishes `takeOne` from `take`). If 3375 (D R) is an input range but not a forward range, return type is an input 3376 range with all random-access capabilities except save. 3377 */ 3378 auto takeOne(R)(R source) 3379 if (isInputRange!R) 3380 { 3381 static if (hasSlicing!R) 3382 { 3383 return source[0 .. !source.empty]; 3384 } 3385 else 3386 { 3387 static struct Result 3388 { 3389 private R _source; 3390 private bool _empty = true; 3391 @property bool empty() const { return _empty; } 3392 @property auto ref front() 3393 { 3394 assert(!empty, "Attempting to fetch the front of an empty takeOne"); 3395 return _source.front; 3396 } 3397 void popFront() 3398 { 3399 assert(!empty, "Attempting to popFront an empty takeOne"); 3400 _source.popFront(); 3401 _empty = true; 3402 } 3403 void popBack() 3404 { 3405 assert(!empty, "Attempting to popBack an empty takeOne"); 3406 _source.popFront(); 3407 _empty = true; 3408 } 3409 static if (isForwardRange!(Unqual!R)) 3410 { 3411 @property auto save() { return Result(_source.save, empty); } 3412 } 3413 @property auto ref back() 3414 { 3415 assert(!empty, "Attempting to fetch the back of an empty takeOne"); 3416 return _source.front; 3417 } 3418 @property size_t length() const { return !empty; } 3419 alias opDollar = length; 3420 auto ref opIndex(size_t n) 3421 { 3422 assert(n < length, "Attempting to index a takeOne out of bounds"); 3423 return _source.front; 3424 } 3425 auto opSlice(size_t m, size_t n) 3426 { 3427 assert( 3428 m <= n, 3429 "Attempting to slice a takeOne range with a larger first argument than the second." 3430 ); 3431 assert( 3432 n <= length, 3433 "Attempting to slice using an out of bounds index on a takeOne range." 3434 ); 3435 return n > m ? this : Result(_source, true); 3436 } 3437 // Non-standard property 3438 @property R source() { return _source; } 3439 } 3440 3441 return Result(source, source.empty); 3442 } 3443 } 3444 3445 /// 3446 pure @safe nothrow unittest 3447 { 3448 auto s = takeOne([42, 43, 44]); 3449 static assert(isRandomAccessRange!(typeof(s))); 3450 assert(s.length == 1); 3451 assert(!s.empty); 3452 assert(s.front == 42); 3453 s.front = 43; 3454 assert(s.front == 43); 3455 assert(s.back == 43); 3456 assert(s[0] == 43); 3457 s.popFront(); 3458 assert(s.length == 0); 3459 assert(s.empty); 3460 } 3461 3462 pure @safe nothrow @nogc unittest 3463 { 3464 struct NonForwardRange 3465 { 3466 enum empty = false; 3467 int front() { return 42; } 3468 void popFront() {} 3469 } 3470 3471 static assert(!isForwardRange!NonForwardRange); 3472 3473 auto s = takeOne(NonForwardRange()); 3474 assert(s.length == 1); 3475 assert(!s.empty); 3476 assert(s.front == 42); 3477 assert(s.back == 42); 3478 assert(s[0] == 42); 3479 3480 auto t = s[0 .. 0]; 3481 assert(t.empty); 3482 assert(t.length == 0); 3483 3484 auto u = s[1 .. 1]; 3485 assert(u.empty); 3486 assert(u.length == 0); 3487 3488 auto v = s[0 .. 1]; 3489 s.popFront(); 3490 assert(s.length == 0); 3491 assert(s.empty); 3492 assert(!v.empty); 3493 assert(v.front == 42); 3494 v.popBack(); 3495 assert(v.empty); 3496 assert(v.length == 0); 3497 } 3498 3499 pure @safe nothrow @nogc unittest 3500 { 3501 struct NonSlicingForwardRange 3502 { 3503 enum empty = false; 3504 int front() { return 42; } 3505 void popFront() {} 3506 @property auto save() { return this; } 3507 } 3508 3509 static assert(isForwardRange!NonSlicingForwardRange); 3510 static assert(!hasSlicing!NonSlicingForwardRange); 3511 3512 auto s = takeOne(NonSlicingForwardRange()); 3513 assert(s.length == 1); 3514 assert(!s.empty); 3515 assert(s.front == 42); 3516 assert(s.back == 42); 3517 assert(s[0] == 42); 3518 auto t = s.save; 3519 s.popFront(); 3520 assert(s.length == 0); 3521 assert(s.empty); 3522 assert(!t.empty); 3523 assert(t.front == 42); 3524 t.popBack(); 3525 assert(t.empty); 3526 assert(t.length == 0); 3527 } 3528 3529 // Test that asserts trigger correctly 3530 @system unittest 3531 { 3532 import std.exception : assertThrown; 3533 import core.exception : AssertError; 3534 3535 struct NonForwardRange 3536 { 3537 enum empty = false; 3538 int front() { return 42; } 3539 void popFront() {} 3540 } 3541 3542 auto s = takeOne(NonForwardRange()); 3543 3544 assertThrown!AssertError(s[1]); 3545 assertThrown!AssertError(s[0 .. 2]); 3546 3547 size_t one = 1; // Avoid style warnings triggered by literals 3548 size_t zero = 0; 3549 assertThrown!AssertError(s[one .. zero]); 3550 3551 s.popFront; 3552 assert(s.empty); 3553 assertThrown!AssertError(s.front); 3554 assertThrown!AssertError(s.back); 3555 assertThrown!AssertError(s.popFront); 3556 assertThrown!AssertError(s.popBack); 3557 } 3558 3559 // https://issues.dlang.org/show_bug.cgi?id=16999 3560 pure @safe unittest 3561 { 3562 auto myIota = new class 3563 { 3564 int front = 0; 3565 @safe void popFront(){front++;} 3566 enum empty = false; 3567 }; 3568 auto iotaPart = myIota.takeOne; 3569 int sum; 3570 foreach (var; chain(iotaPart, iotaPart, iotaPart)) 3571 { 3572 sum += var; 3573 } 3574 assert(sum == 3); 3575 assert(iotaPart.front == 3); 3576 } 3577 3578 /++ 3579 Returns an empty range which is statically known to be empty and is 3580 guaranteed to have `length` and be random access regardless of `R`'s 3581 capabilities. 3582 +/ 3583 auto takeNone(R)() 3584 if (isInputRange!R) 3585 { 3586 return typeof(takeOne(R.init)).init; 3587 } 3588 3589 /// 3590 pure @safe nothrow @nogc unittest 3591 { 3592 auto range = takeNone!(int[])(); 3593 assert(range.length == 0); 3594 assert(range.empty); 3595 } 3596 3597 pure @safe nothrow @nogc unittest 3598 { 3599 enum ctfe = takeNone!(int[])(); 3600 static assert(ctfe.length == 0); 3601 static assert(ctfe.empty); 3602 } 3603 3604 3605 /++ 3606 Creates an empty range from the given range in $(BIGOH 1). If it can, it 3607 will return the same range type. If not, it will return 3608 $(D takeExactly(range, 0)). 3609 +/ 3610 auto takeNone(R)(R range) 3611 if (isInputRange!R) 3612 { 3613 import std.traits : isDynamicArray; 3614 //Makes it so that calls to takeNone which don't use UFCS still work with a 3615 //member version if it's defined. 3616 static if (is(typeof(R.takeNone))) 3617 auto retval = range.takeNone(); 3618 // https://issues.dlang.org/show_bug.cgi?id=8339 3619 else static if (isDynamicArray!R)/+ || 3620 (is(R == struct) && __traits(compiles, {auto r = R.init;}) && R.init.empty))+/ 3621 { 3622 auto retval = R.init; 3623 } 3624 //An infinite range sliced at [0 .. 0] would likely still not be empty... 3625 else static if (hasSlicing!R && !isInfinite!R) 3626 auto retval = range[0 .. 0]; 3627 else 3628 auto retval = takeExactly(range, 0); 3629 3630 // https://issues.dlang.org/show_bug.cgi?id=7892 prevents this from being 3631 // done in an out block. 3632 assert(retval.empty); 3633 return retval; 3634 } 3635 3636 /// 3637 pure @safe nothrow unittest 3638 { 3639 import std.algorithm.iteration : filter; 3640 assert(takeNone([42, 27, 19]).empty); 3641 assert(takeNone("dlang.org").empty); 3642 assert(takeNone(filter!"true"([42, 27, 19])).empty); 3643 } 3644 3645 @safe unittest 3646 { 3647 import std.algorithm.iteration : filter; 3648 import std.meta : AliasSeq; 3649 3650 struct Dummy 3651 { 3652 mixin template genInput() 3653 { 3654 @safe: 3655 @property bool empty() { return _arr.empty; } 3656 @property auto front() { return _arr.front; } 3657 void popFront() { _arr.popFront(); } 3658 static assert(isInputRange!(typeof(this))); 3659 } 3660 } 3661 alias genInput = Dummy.genInput; 3662 3663 static struct NormalStruct 3664 { 3665 //Disabled to make sure that the takeExactly version is used. 3666 @disable this(); 3667 this(int[] arr) { _arr = arr; } 3668 mixin genInput; 3669 int[] _arr; 3670 } 3671 3672 static struct SliceStruct 3673 { 3674 @disable this(); 3675 this(int[] arr) { _arr = arr; } 3676 mixin genInput; 3677 @property auto save() { return this; } 3678 auto opSlice(size_t i, size_t j) { return typeof(this)(_arr[i .. j]); } 3679 @property size_t length() { return _arr.length; } 3680 int[] _arr; 3681 } 3682 3683 static struct InitStruct 3684 { 3685 mixin genInput; 3686 int[] _arr; 3687 } 3688 3689 static struct TakeNoneStruct 3690 { 3691 this(int[] arr) { _arr = arr; } 3692 @disable this(); 3693 mixin genInput; 3694 auto takeNone() { return typeof(this)(null); } 3695 int[] _arr; 3696 } 3697 3698 static class NormalClass 3699 { 3700 this(int[] arr) {_arr = arr;} 3701 mixin genInput; 3702 int[] _arr; 3703 } 3704 3705 static class SliceClass 3706 { 3707 @safe: 3708 this(int[] arr) { _arr = arr; } 3709 mixin genInput; 3710 @property auto save() { return new typeof(this)(_arr); } 3711 auto opSlice(size_t i, size_t j) { return new typeof(this)(_arr[i .. j]); } 3712 @property size_t length() { return _arr.length; } 3713 int[] _arr; 3714 } 3715 3716 static class TakeNoneClass 3717 { 3718 @safe: 3719 this(int[] arr) { _arr = arr; } 3720 mixin genInput; 3721 auto takeNone() { return new typeof(this)(null); } 3722 int[] _arr; 3723 } 3724 3725 import std.format : format; 3726 3727 static foreach (range; AliasSeq!([1, 2, 3, 4, 5], 3728 "hello world", 3729 "hello world"w, 3730 "hello world"d, 3731 SliceStruct([1, 2, 3]), 3732 // https://issues.dlang.org/show_bug.cgi?id=8339 3733 // forces this to be takeExactly `InitStruct([1, 2, 3]), 3734 TakeNoneStruct([1, 2, 3]))) 3735 { 3736 static assert(takeNone(range).empty, typeof(range).stringof); 3737 assert(takeNone(range).empty); 3738 static assert(is(typeof(range) == typeof(takeNone(range))), typeof(range).stringof); 3739 } 3740 3741 static foreach (range; AliasSeq!(NormalStruct([1, 2, 3]), 3742 InitStruct([1, 2, 3]))) 3743 { 3744 static assert(takeNone(range).empty, typeof(range).stringof); 3745 assert(takeNone(range).empty); 3746 static assert(is(typeof(takeExactly(range, 0)) == typeof(takeNone(range))), typeof(range).stringof); 3747 } 3748 3749 //Don't work in CTFE. 3750 auto normal = new NormalClass([1, 2, 3]); 3751 assert(takeNone(normal).empty); 3752 static assert(is(typeof(takeExactly(normal, 0)) == typeof(takeNone(normal))), typeof(normal).stringof); 3753 3754 auto slice = new SliceClass([1, 2, 3]); 3755 assert(takeNone(slice).empty); 3756 static assert(is(SliceClass == typeof(takeNone(slice))), typeof(slice).stringof); 3757 3758 auto taken = new TakeNoneClass([1, 2, 3]); 3759 assert(takeNone(taken).empty); 3760 static assert(is(TakeNoneClass == typeof(takeNone(taken))), typeof(taken).stringof); 3761 3762 auto filtered = filter!"true"([1, 2, 3, 4, 5]); 3763 assert(takeNone(filtered).empty); 3764 // https://issues.dlang.org/show_bug.cgi?id=8339 and 3765 // https://issues.dlang.org/show_bug.cgi?id=5941 force this to be takeExactly 3766 //static assert(is(typeof(filtered) == typeof(takeNone(filtered))), typeof(filtered).stringof); 3767 } 3768 3769 /++ 3770 + Return a range advanced to within `_n` elements of the end of 3771 + `range`. 3772 + 3773 + Intended as the range equivalent of the Unix 3774 + $(HTTP en.wikipedia.org/wiki/Tail_%28Unix%29, _tail) utility. When the length 3775 + of `range` is less than or equal to `_n`, `range` is returned 3776 + as-is. 3777 + 3778 + Completes in $(BIGOH 1) steps for ranges that support slicing and have 3779 + length. Completes in $(BIGOH range.length) time for all other ranges. 3780 + 3781 + Params: 3782 + range = range to get _tail of 3783 + n = maximum number of elements to include in _tail 3784 + 3785 + Returns: 3786 + Returns the _tail of `range` augmented with length information 3787 +/ 3788 auto tail(Range)(Range range, size_t n) 3789 if (isInputRange!Range && !isInfinite!Range && 3790 (hasLength!Range || isForwardRange!Range)) 3791 { 3792 static if (hasLength!Range) 3793 { 3794 immutable length = range.length; 3795 if (n >= length) 3796 return range.takeExactly(length); 3797 else 3798 return range.drop(length - n).takeExactly(n); 3799 } 3800 else 3801 { 3802 Range scout = range.save; 3803 foreach (immutable i; 0 .. n) 3804 { 3805 if (scout.empty) 3806 return range.takeExactly(i); 3807 scout.popFront(); 3808 } 3809 3810 auto tail = range.save; 3811 while (!scout.empty) 3812 { 3813 assert(!tail.empty); 3814 scout.popFront(); 3815 tail.popFront(); 3816 } 3817 3818 return tail.takeExactly(n); 3819 } 3820 } 3821 3822 /// 3823 pure @safe nothrow unittest 3824 { 3825 // tail -c n 3826 assert([1, 2, 3].tail(1) == [3]); 3827 assert([1, 2, 3].tail(2) == [2, 3]); 3828 assert([1, 2, 3].tail(3) == [1, 2, 3]); 3829 assert([1, 2, 3].tail(4) == [1, 2, 3]); 3830 assert([1, 2, 3].tail(0).length == 0); 3831 3832 // tail --lines=n 3833 import std.algorithm.comparison : equal; 3834 import std.algorithm.iteration : joiner; 3835 import std.exception : assumeWontThrow; 3836 import std.string : lineSplitter; 3837 assert("one\ntwo\nthree" 3838 .lineSplitter 3839 .tail(2) 3840 .joiner("\n") 3841 .equal("two\nthree") 3842 .assumeWontThrow); 3843 } 3844 3845 // @nogc prevented by https://issues.dlang.org/show_bug.cgi?id=15408 3846 pure nothrow @safe /+@nogc+/ unittest 3847 { 3848 import std.algorithm.comparison : equal; 3849 import std.internal.test.dummyrange : AllDummyRanges, DummyRange, Length, 3850 RangeType, ReturnBy; 3851 3852 static immutable cheatsheet = [6, 7, 8, 9, 10]; 3853 3854 foreach (R; AllDummyRanges) 3855 { 3856 static if (isInputRange!R && !isInfinite!R && 3857 (hasLength!R || isForwardRange!R)) 3858 { 3859 assert(R.init.tail(5).equal(cheatsheet)); 3860 static assert(R.init.tail(5).equal(cheatsheet)); 3861 3862 assert(R.init.tail(0).length == 0); 3863 assert(R.init.tail(10).equal(R.init)); 3864 assert(R.init.tail(11).equal(R.init)); 3865 } 3866 } 3867 3868 // Infinite ranges are not supported 3869 static assert(!__traits(compiles, repeat(0).tail(0))); 3870 3871 // Neither are non-forward ranges without length 3872 static assert(!__traits(compiles, DummyRange!(ReturnBy.Value, Length.No, 3873 RangeType.Input).init.tail(5))); 3874 } 3875 3876 pure @safe nothrow @nogc unittest 3877 { 3878 static immutable input = [1, 2, 3]; 3879 static immutable expectedOutput = [2, 3]; 3880 assert(input.tail(2) == expectedOutput); 3881 } 3882 3883 /++ 3884 `drop` is a convenience function which calls 3885 $(REF popFrontN, std, range, primitives)`(range, n)` and returns `range`. 3886 Unlike `popFrontN`, the range argument is passed by copy, not by `ref`. 3887 3888 `drop` makes it easier to pop elements from a range rvalue 3889 and then pass it to another function within a single expression, 3890 whereas `popFrontN` would require multiple statements. 3891 3892 `dropBack` provides the same functionality but instead calls 3893 $(REF popBackN, std, range, primitives)`(range, n)` 3894 3895 Note: `drop` and `dropBack` will only pop $(I up to) 3896 `n` elements but will stop if the range is empty first. 3897 In other languages this is sometimes called `skip`. 3898 3899 Params: 3900 range = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to drop from 3901 n = the number of elements to drop 3902 3903 Returns: 3904 `range` with up to `n` elements dropped 3905 3906 See_Also: 3907 $(REF popFront, std, range, primitives), $(REF popBackN, std, range, primitives) 3908 +/ 3909 R drop(R)(R range, size_t n) 3910 if (isInputRange!R) 3911 { 3912 range.popFrontN(n); 3913 return range; 3914 } 3915 3916 /// 3917 @safe unittest 3918 { 3919 import std.algorithm.comparison : equal; 3920 3921 auto a = [0, 2, 1, 5, 0, 3]; 3922 assert(a.drop(3) == [5, 0, 3]); 3923 assert(a.length == 6); // original unchanged 3924 3925 assert("hello world".drop(6) == "world"); 3926 assert("hello world".drop(50).empty); 3927 assert("hello world".take(6).drop(3).equal("lo ")); 3928 } 3929 3930 /// ditto 3931 R dropBack(R)(R range, size_t n) 3932 if (isBidirectionalRange!R) 3933 { 3934 range.popBackN(n); 3935 return range; 3936 } 3937 3938 /// 3939 @safe unittest 3940 { 3941 import std.algorithm.comparison : equal; 3942 3943 assert([0, 2, 1, 5, 0, 3].dropBack(3) == [0, 2, 1]); 3944 assert("hello world".dropBack(6) == "hello"); 3945 assert("hello world".dropBack(50).empty); 3946 assert("hello world".drop(4).dropBack(4).equal("o w")); 3947 } 3948 3949 @safe unittest 3950 { 3951 import std.algorithm.comparison : equal; 3952 import std.container.dlist : DList; 3953 3954 //Remove all but the first two elements 3955 auto a = DList!int(0, 1, 9, 9, 9, 9); 3956 a.remove(a[].drop(2)); 3957 assert(a[].equal(a[].take(2))); 3958 } 3959 3960 @safe unittest 3961 { 3962 import std.algorithm.comparison : equal; 3963 import std.algorithm.iteration : filter; 3964 3965 assert(drop("", 5).empty); 3966 assert(equal(drop(filter!"true"([0, 2, 1, 5, 0, 3]), 3), [5, 0, 3])); 3967 } 3968 3969 @safe unittest 3970 { 3971 import std.algorithm.comparison : equal; 3972 import std.container.dlist : DList; 3973 3974 //insert before the last two elements 3975 auto a = DList!int(0, 1, 2, 5, 6); 3976 a.insertAfter(a[].dropBack(2), [3, 4]); 3977 assert(a[].equal(iota(0, 7))); 3978 } 3979 3980 /++ 3981 Similar to $(LREF drop) and `dropBack` but they call 3982 $(D range.$(LREF popFrontExactly)(n)) and `range.popBackExactly(n)` 3983 instead. 3984 3985 Note: Unlike `drop`, `dropExactly` will assume that the 3986 range holds at least `n` elements. This makes `dropExactly` 3987 faster than `drop`, but it also means that if `range` does 3988 not contain at least `n` elements, it will attempt to call `popFront` 3989 on an empty range, which is undefined behavior. So, only use 3990 `popFrontExactly` when it is guaranteed that `range` holds at least 3991 `n` elements. 3992 3993 Params: 3994 range = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to drop from 3995 n = the number of elements to drop 3996 3997 Returns: 3998 `range` with `n` elements dropped 3999 4000 See_Also: 4001 $(REF popFrontExactly, std, range, primitives), 4002 $(REF popBackExactly, std, range, primitives) 4003 +/ 4004 R dropExactly(R)(R range, size_t n) 4005 if (isInputRange!R) 4006 { 4007 popFrontExactly(range, n); 4008 return range; 4009 } 4010 /// ditto 4011 R dropBackExactly(R)(R range, size_t n) 4012 if (isBidirectionalRange!R) 4013 { 4014 popBackExactly(range, n); 4015 return range; 4016 } 4017 4018 /// 4019 @safe unittest 4020 { 4021 import std.algorithm.comparison : equal; 4022 import std.algorithm.iteration : filterBidirectional; 4023 4024 auto a = [1, 2, 3]; 4025 assert(a.dropExactly(2) == [3]); 4026 assert(a.dropBackExactly(2) == [1]); 4027 4028 string s = "日本語"; 4029 assert(s.dropExactly(2) == "語"); 4030 assert(s.dropBackExactly(2) == "日"); 4031 4032 auto bd = filterBidirectional!"true"([1, 2, 3]); 4033 assert(bd.dropExactly(2).equal([3])); 4034 assert(bd.dropBackExactly(2).equal([1])); 4035 } 4036 4037 /++ 4038 `dropOne` is a convenience function which calls 4039 `range.popFront()` and returns `range`. 4040 Unlike `popFront`, the range argument is passed by copy, not by `ref`. 4041 4042 `dropOne` makes it easier to pop an element from a range rvalue 4043 and then pass it to another function within a single expression, 4044 whereas `popFront` would require multiple statements. 4045 4046 `dropBackOne` provides the same functionality but instead calls 4047 `range.popBack()`. 4048 +/ 4049 R dropOne(R)(R range) 4050 if (isInputRange!R) 4051 { 4052 range.popFront(); 4053 return range; 4054 } 4055 /// ditto 4056 R dropBackOne(R)(R range) 4057 if (isBidirectionalRange!R) 4058 { 4059 range.popBack(); 4060 return range; 4061 } 4062 4063 /// 4064 pure @safe nothrow unittest 4065 { 4066 import std.algorithm.comparison : equal; 4067 import std.algorithm.iteration : filterBidirectional; 4068 import std.container.dlist : DList; 4069 4070 auto dl = DList!int(9, 1, 2, 3, 9); 4071 assert(dl[].dropOne().dropBackOne().equal([1, 2, 3])); 4072 4073 auto a = [1, 2, 3]; 4074 assert(a.dropOne() == [2, 3]); 4075 assert(a.dropBackOne() == [1, 2]); 4076 4077 string s = "日本語"; 4078 import std.exception : assumeWontThrow; 4079 assert(assumeWontThrow(s.dropOne() == "本語")); 4080 assert(assumeWontThrow(s.dropBackOne() == "日本")); 4081 4082 auto bd = filterBidirectional!"true"([1, 2, 3]); 4083 assert(bd.dropOne().equal([2, 3])); 4084 assert(bd.dropBackOne().equal([1, 2])); 4085 } 4086 4087 /** 4088 Create a range which repeats one value. 4089 4090 Params: 4091 value = the _value to repeat 4092 n = the number of times to repeat `value` 4093 4094 Returns: 4095 If `n` is not defined, an infinite random access range 4096 with slicing. 4097 4098 If `n` is defined, a random access range with slicing. 4099 */ 4100 struct Repeat(T) 4101 { 4102 private: 4103 import std.typecons : Rebindable2; 4104 4105 // Store a rebindable T to make Repeat assignable. 4106 Rebindable2!T _value; 4107 4108 public: 4109 /// Range primitives 4110 @property inout(T) front() inout { return _value.get; } 4111 4112 /// ditto 4113 @property inout(T) back() inout { return _value.get; } 4114 4115 /// ditto 4116 enum bool empty = false; 4117 4118 /// ditto 4119 void popFront() {} 4120 4121 /// ditto 4122 void popBack() {} 4123 4124 /// ditto 4125 @property auto save() inout { return this; } 4126 4127 /// ditto 4128 inout(T) opIndex(size_t) inout { return _value.get; } 4129 4130 /// ditto 4131 auto opSlice(size_t i, size_t j) 4132 in 4133 { 4134 assert( 4135 i <= j, 4136 "Attempting to slice a Repeat with a larger first argument than the second." 4137 ); 4138 } 4139 do 4140 { 4141 return this.takeExactly(j - i); 4142 } 4143 private static struct DollarToken {} 4144 4145 /// ditto 4146 enum opDollar = DollarToken.init; 4147 4148 /// ditto 4149 auto opSlice(size_t, DollarToken) inout { return this; } 4150 } 4151 4152 /// Ditto 4153 Repeat!T repeat(T)(T value) 4154 { 4155 import std.typecons : Rebindable2; 4156 4157 return Repeat!T(Rebindable2!T(value)); 4158 } 4159 4160 /// 4161 pure @safe nothrow unittest 4162 { 4163 import std.algorithm.comparison : equal; 4164 4165 assert(5.repeat().take(4).equal([5, 5, 5, 5])); 4166 } 4167 4168 pure @safe nothrow unittest 4169 { 4170 import std.algorithm.comparison : equal; 4171 4172 auto r = repeat(5); 4173 alias R = typeof(r); 4174 static assert(isBidirectionalRange!R); 4175 static assert(isForwardRange!R); 4176 static assert(isInfinite!R); 4177 static assert(hasSlicing!R); 4178 4179 assert(r.back == 5); 4180 assert(r.front == 5); 4181 assert(r.take(4).equal([ 5, 5, 5, 5 ])); 4182 assert(r[0 .. 4].equal([ 5, 5, 5, 5 ])); 4183 4184 R r2 = r[5 .. $]; 4185 assert(r2.back == 5); 4186 assert(r2.front == 5); 4187 } 4188 4189 /// ditto 4190 Take!(Repeat!T) repeat(T)(T value, size_t n) 4191 { 4192 return take(repeat(value), n); 4193 } 4194 4195 /// 4196 pure @safe nothrow unittest 4197 { 4198 import std.algorithm.comparison : equal; 4199 4200 assert(5.repeat(4).equal([5, 5, 5, 5])); 4201 } 4202 4203 // https://issues.dlang.org/show_bug.cgi?id=12007 4204 pure @safe nothrow unittest 4205 { 4206 static class C{} 4207 Repeat!(immutable int) ri; 4208 ri = ri.save; 4209 Repeat!(immutable C) rc; 4210 rc = rc.save; 4211 4212 import std.algorithm.setops : cartesianProduct; 4213 import std.algorithm.comparison : equal; 4214 import std.typecons : tuple; 4215 immutable int[] A = [1,2,3]; 4216 immutable int[] B = [4,5,6]; 4217 4218 assert(equal(cartesianProduct(A,B), 4219 [ 4220 tuple(1, 4), tuple(1, 5), tuple(1, 6), 4221 tuple(2, 4), tuple(2, 5), tuple(2, 6), 4222 tuple(3, 4), tuple(3, 5), tuple(3, 6), 4223 ])); 4224 } 4225 4226 /** 4227 Given callable ($(REF isCallable, std,traits)) `fun`, create as a range 4228 whose front is defined by successive calls to `fun()`. 4229 This is especially useful to call function with global side effects (random 4230 functions), or to create ranges expressed as a single delegate, rather than 4231 an entire `front`/`popFront`/`empty` structure. 4232 `fun` maybe be passed either a template alias parameter (existing 4233 function, delegate, struct type defining `static opCall`) or 4234 a run-time value argument (delegate, function object). 4235 The result range models an InputRange 4236 ($(REF isInputRange, std,range,primitives)). 4237 The resulting range will call `fun()` on construction, and every call to 4238 `popFront`, and the cached value will be returned when `front` is called. 4239 4240 Returns: an `inputRange` where each element represents another call to fun. 4241 */ 4242 auto generate(Fun)(Fun fun) 4243 if (isCallable!fun) 4244 { 4245 auto gen = Generator!(Fun)(fun); 4246 gen.popFront(); // prime the first element 4247 return gen; 4248 } 4249 4250 /// ditto 4251 auto generate(alias fun)() 4252 if (isCallable!fun) 4253 { 4254 auto gen = Generator!(fun)(); 4255 gen.popFront(); // prime the first element 4256 return gen; 4257 } 4258 4259 /// 4260 @safe pure nothrow unittest 4261 { 4262 import std.algorithm.comparison : equal; 4263 import std.algorithm.iteration : map; 4264 4265 int i = 1; 4266 auto powersOfTwo = generate!(() => i *= 2)().take(10); 4267 assert(equal(powersOfTwo, iota(1, 11).map!"2^^a"())); 4268 } 4269 4270 /// 4271 @safe pure nothrow unittest 4272 { 4273 import std.algorithm.comparison : equal; 4274 4275 //Returns a run-time delegate 4276 auto infiniteIota(T)(T low, T high) 4277 { 4278 T i = high; 4279 return (){if (i == high) i = low; return i++;}; 4280 } 4281 //adapted as a range. 4282 assert(equal(generate(infiniteIota(1, 4)).take(10), [1, 2, 3, 1, 2, 3, 1, 2, 3, 1])); 4283 } 4284 4285 /// 4286 @safe unittest 4287 { 4288 import std.format : format; 4289 import std.random : uniform; 4290 4291 auto r = generate!(() => uniform(0, 6)).take(10); 4292 format("%(%s %)", r); 4293 } 4294 4295 private struct Generator(Fun...) 4296 { 4297 static assert(Fun.length == 1); 4298 static assert(isInputRange!Generator); 4299 import std.traits : FunctionAttribute, functionAttributes, ReturnType; 4300 4301 private: 4302 static if (is(Fun[0])) 4303 Fun[0] fun; 4304 else 4305 alias fun = Fun[0]; 4306 4307 enum returnByRef_ = (functionAttributes!fun & FunctionAttribute.ref_) ? true : false; 4308 4309 import std.traits : hasIndirections; 4310 static if (!hasIndirections!(ReturnType!fun)) 4311 alias RetType = Unqual!(ReturnType!fun); 4312 else 4313 alias RetType = ReturnType!fun; 4314 4315 static if (returnByRef_) 4316 RetType *elem_; 4317 else 4318 RetType elem_; 4319 public: 4320 /// Range primitives 4321 enum empty = false; 4322 4323 static if (returnByRef_) 4324 { 4325 /// ditto 4326 ref front() @property 4327 { 4328 return *elem_; 4329 } 4330 /// ditto 4331 void popFront() 4332 { 4333 elem_ = &fun(); 4334 } 4335 } 4336 else 4337 { 4338 /// ditto 4339 auto front() @property 4340 { 4341 return elem_; 4342 } 4343 /// ditto 4344 void popFront() 4345 { 4346 elem_ = fun(); 4347 } 4348 } 4349 } 4350 4351 @safe nothrow unittest 4352 { 4353 import std.algorithm.comparison : equal; 4354 4355 struct StaticOpCall 4356 { 4357 static ubyte opCall() { return 5 ; } 4358 } 4359 4360 assert(equal(generate!StaticOpCall().take(10), repeat(5).take(10))); 4361 } 4362 4363 @safe pure unittest 4364 { 4365 import std.algorithm.comparison : equal; 4366 4367 struct OpCall 4368 { 4369 ubyte opCall() @safe pure { return 5 ; } 4370 } 4371 4372 OpCall op; 4373 assert(equal(generate(op).take(10), repeat(5).take(10))); 4374 } 4375 4376 // verify ref mechanism works 4377 @system nothrow unittest 4378 { 4379 int[10] arr; 4380 int idx; 4381 4382 ref int fun() { 4383 auto x = idx++; 4384 idx %= arr.length; 4385 return arr[x]; 4386 } 4387 int y = 1; 4388 foreach (ref x; generate!(fun).take(20)) 4389 { 4390 x += y++; 4391 } 4392 import std.algorithm.comparison : equal; 4393 assert(equal(arr[], iota(12, 32, 2))); 4394 } 4395 4396 // assure front isn't the mechanism to make generate go to the next element. 4397 @safe unittest 4398 { 4399 int i; 4400 auto g = generate!(() => ++i); 4401 auto f = g.front; 4402 assert(f == g.front); 4403 g = g.drop(5); // reassign because generate caches 4404 assert(g.front == f + 5); 4405 } 4406 4407 // https://issues.dlang.org/show_bug.cgi?id=23319 4408 @safe pure nothrow unittest 4409 { 4410 auto b = generate!(() => const(int)(42)); 4411 assert(b.front == 42); 4412 } 4413 4414 /** 4415 Repeats the given forward range ad infinitum. If the original range is 4416 infinite (fact that would make `Cycle` the identity application), 4417 `Cycle` detects that and aliases itself to the range type 4418 itself. That works for non-forward ranges too. 4419 If the original range has random access, `Cycle` offers 4420 random access and also offers a constructor taking an initial position 4421 `index`. `Cycle` works with static arrays in addition to ranges, 4422 mostly for performance reasons. 4423 4424 Note: The input range must not be empty. 4425 4426 Tip: This is a great way to implement simple circular buffers. 4427 */ 4428 struct Cycle(R) 4429 if (isForwardRange!R && !isInfinite!R) 4430 { 4431 static if (isRandomAccessRange!R && hasLength!R) 4432 { 4433 private R _original; 4434 private size_t _index; 4435 4436 /// Range primitives 4437 this(R input, size_t index = 0) 4438 { 4439 _original = input; 4440 _index = index % _original.length; 4441 } 4442 4443 /// ditto 4444 @property auto ref front() 4445 { 4446 return _original[_index]; 4447 } 4448 4449 static if (__traits(compiles, (const R r) => r[0])) 4450 { 4451 /// ditto 4452 @property auto ref front() const 4453 { 4454 return _original[_index]; 4455 } 4456 } 4457 4458 static if (hasAssignableElements!R) 4459 { 4460 /// ditto 4461 @property void front(ElementType!R val) 4462 { 4463 import core.lifetime : forward; 4464 4465 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542 4466 _original[_index] = __ctfe ? val : forward!val; 4467 } 4468 } 4469 4470 /// ditto 4471 enum bool empty = false; 4472 4473 /// ditto 4474 void popFront() 4475 { 4476 ++_index; 4477 if (_index >= _original.length) 4478 _index = 0; 4479 } 4480 4481 /// ditto 4482 auto ref opIndex(size_t n) 4483 { 4484 return _original[(n + _index) % _original.length]; 4485 } 4486 4487 static if (__traits(compiles, (const R r) => r[0]) && 4488 __traits(compiles, (const R r) => r.length)) 4489 { 4490 /// ditto 4491 auto ref opIndex(size_t n) const 4492 { 4493 return _original[(n + _index) % _original.length]; 4494 } 4495 } 4496 4497 static if (hasAssignableElements!R) 4498 { 4499 /// ditto 4500 void opIndexAssign(ElementType!R val, size_t n) 4501 { 4502 _original[(n + _index) % _original.length] = val; 4503 } 4504 } 4505 4506 /// ditto 4507 @property Cycle save() 4508 { 4509 //No need to call _original.save, because Cycle never actually modifies _original 4510 return Cycle(_original, _index); 4511 } 4512 4513 private static struct DollarToken {} 4514 4515 /// ditto 4516 enum opDollar = DollarToken.init; 4517 4518 static if (hasSlicing!R) 4519 { 4520 /// ditto 4521 auto opSlice(size_t i, size_t j) 4522 in 4523 { 4524 assert(i <= j); 4525 } 4526 do 4527 { 4528 return this[i .. $].takeExactly(j - i); 4529 } 4530 4531 /// ditto 4532 auto opSlice(size_t i, DollarToken) 4533 { 4534 return typeof(this)(_original, _index + i); 4535 } 4536 } 4537 } 4538 else 4539 { 4540 private R _original; 4541 private R _current; 4542 4543 /// ditto 4544 this(R input) 4545 { 4546 _original = input; 4547 _current = input.save; 4548 } 4549 4550 private this(R original, R current) 4551 { 4552 _original = original; 4553 _current = current; 4554 } 4555 4556 /// ditto 4557 @property auto ref front() 4558 { 4559 return _current.front; 4560 } 4561 4562 static if (__traits(compiles, (const R r) => r.front)) 4563 { 4564 /// ditto 4565 @property auto ref front() const 4566 { 4567 return _current.front; 4568 } 4569 } 4570 4571 static if (hasAssignableElements!R) 4572 { 4573 /// ditto 4574 @property auto front(ElementType!R val) 4575 { 4576 import core.lifetime : forward; 4577 4578 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542 4579 return _current.front = __ctfe ? val : forward!val; 4580 } 4581 } 4582 4583 /// ditto 4584 enum bool empty = false; 4585 4586 /// ditto 4587 void popFront() 4588 { 4589 _current.popFront(); 4590 if (_current.empty) 4591 _current = _original.save; 4592 } 4593 4594 /// ditto 4595 @property Cycle save() 4596 { 4597 //No need to call _original.save, because Cycle never actually modifies _original 4598 return Cycle(_original, _current.save); 4599 } 4600 } 4601 } 4602 4603 /// ditto 4604 template Cycle(R) 4605 if (isInfinite!R) 4606 { 4607 alias Cycle = R; 4608 } 4609 4610 /// ditto 4611 struct Cycle(R) 4612 if (isStaticArray!R) 4613 { 4614 private alias ElementType = typeof(R.init[0]); 4615 private ElementType* _ptr; 4616 private size_t _index; 4617 4618 nothrow: 4619 4620 /// Range primitives 4621 this(ref R input, size_t index = 0) @system 4622 { 4623 _ptr = input.ptr; 4624 _index = index % R.length; 4625 } 4626 4627 /// ditto 4628 @property ref inout(ElementType) front() inout @safe 4629 { 4630 static ref auto trustedPtrIdx(typeof(_ptr) p, size_t idx) @trusted 4631 { 4632 return p[idx]; 4633 } 4634 return trustedPtrIdx(_ptr, _index); 4635 } 4636 4637 /// ditto 4638 enum bool empty = false; 4639 4640 /// ditto 4641 void popFront() @safe 4642 { 4643 ++_index; 4644 if (_index >= R.length) 4645 _index = 0; 4646 } 4647 4648 /// ditto 4649 ref inout(ElementType) opIndex(size_t n) inout @safe 4650 { 4651 static ref auto trustedPtrIdx(typeof(_ptr) p, size_t idx) @trusted 4652 { 4653 return p[idx % R.length]; 4654 } 4655 return trustedPtrIdx(_ptr, n + _index); 4656 } 4657 4658 /// ditto 4659 @property inout(Cycle) save() inout @safe 4660 { 4661 return this; 4662 } 4663 4664 private static struct DollarToken {} 4665 /// ditto 4666 enum opDollar = DollarToken.init; 4667 4668 /// ditto 4669 auto opSlice(size_t i, size_t j) @safe 4670 in 4671 { 4672 assert( 4673 i <= j, 4674 "Attempting to slice a Repeat with a larger first argument than the second." 4675 ); 4676 } 4677 do 4678 { 4679 return this[i .. $].takeExactly(j - i); 4680 } 4681 4682 /// ditto 4683 inout(typeof(this)) opSlice(size_t i, DollarToken) inout @safe 4684 { 4685 static auto trustedCtor(typeof(_ptr) p, size_t idx) @trusted 4686 { 4687 return cast(inout) Cycle(*cast(R*)(p), idx); 4688 } 4689 return trustedCtor(_ptr, _index + i); 4690 } 4691 } 4692 4693 /// Ditto 4694 auto cycle(R)(R input) 4695 if (isInputRange!R) 4696 { 4697 static assert(isForwardRange!R || isInfinite!R, 4698 "Cycle requires a forward range argument unless it's statically known" 4699 ~ " to be infinite"); 4700 assert(!input.empty, "Attempting to pass an empty input to cycle"); 4701 static if (isInfinite!R) return input; 4702 else return Cycle!R(input); 4703 } 4704 4705 /// 4706 @safe unittest 4707 { 4708 import std.algorithm.comparison : equal; 4709 import std.range : cycle, take; 4710 4711 // Here we create an infinitive cyclic sequence from [1, 2] 4712 // (i.e. get here [1, 2, 1, 2, 1, 2 and so on]) then 4713 // take 5 elements of this sequence (so we have [1, 2, 1, 2, 1]) 4714 // and compare them with the expected values for equality. 4715 assert(cycle([1, 2]).take(5).equal([ 1, 2, 1, 2, 1 ])); 4716 } 4717 4718 /// Ditto 4719 Cycle!R cycle(R)(R input, size_t index = 0) 4720 if (isRandomAccessRange!R && !isInfinite!R) 4721 { 4722 assert(!input.empty, "Attempting to pass an empty input to cycle"); 4723 return Cycle!R(input, index); 4724 } 4725 4726 /// Ditto 4727 Cycle!R cycle(R)(ref R input, size_t index = 0) @system 4728 if (isStaticArray!R) 4729 { 4730 return Cycle!R(input, index); 4731 } 4732 4733 @safe nothrow unittest 4734 { 4735 import std.algorithm.comparison : equal; 4736 import std.internal.test.dummyrange : AllDummyRanges; 4737 4738 static assert(isForwardRange!(Cycle!(uint[]))); 4739 4740 // Make sure ref is getting propagated properly. 4741 int[] nums = [1,2,3]; 4742 auto c2 = cycle(nums); 4743 c2[3]++; 4744 assert(nums[0] == 2); 4745 4746 immutable int[] immarr = [1, 2, 3]; 4747 4748 foreach (DummyType; AllDummyRanges) 4749 { 4750 static if (isForwardRange!DummyType) 4751 { 4752 DummyType dummy; 4753 auto cy = cycle(dummy); 4754 static assert(isForwardRange!(typeof(cy))); 4755 auto t = take(cy, 20); 4756 assert(equal(t, [1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10])); 4757 4758 const cRange = cy; 4759 assert(cRange.front == 1); 4760 4761 static if (hasAssignableElements!DummyType) 4762 { 4763 { 4764 cy.front = 66; 4765 scope(exit) cy.front = 1; 4766 assert(dummy.front == 66); 4767 } 4768 4769 static if (isRandomAccessRange!DummyType) 4770 { 4771 { 4772 cy[10] = 66; 4773 scope(exit) cy[10] = 1; 4774 assert(dummy.front == 66); 4775 } 4776 4777 assert(cRange[10] == 1); 4778 } 4779 } 4780 4781 static if (hasSlicing!DummyType) 4782 { 4783 auto slice = cy[5 .. 15]; 4784 assert(equal(slice, [6, 7, 8, 9, 10, 1, 2, 3, 4, 5])); 4785 static assert(is(typeof(slice) == typeof(takeExactly(cy, 5)))); 4786 4787 auto infSlice = cy[7 .. $]; 4788 assert(equal(take(infSlice, 5), [8, 9, 10, 1, 2])); 4789 static assert(isInfinite!(typeof(infSlice))); 4790 } 4791 } 4792 } 4793 } 4794 4795 @system nothrow unittest // For static arrays. 4796 { 4797 import std.algorithm.comparison : equal; 4798 4799 int[3] a = [ 1, 2, 3 ]; 4800 static assert(isStaticArray!(typeof(a))); 4801 auto c = cycle(a); 4802 assert(a.ptr == c._ptr); 4803 assert(equal(take(cycle(a), 5), [ 1, 2, 3, 1, 2 ][])); 4804 static assert(isForwardRange!(typeof(c))); 4805 4806 // Test qualifiers on slicing. 4807 alias C = typeof(c); 4808 static assert(is(typeof(c[1 .. $]) == C)); 4809 const cConst = c; 4810 static assert(is(typeof(cConst[1 .. $]) == const(C))); 4811 } 4812 4813 @safe nothrow unittest // For infinite ranges 4814 { 4815 struct InfRange 4816 { 4817 void popFront() { } 4818 @property int front() { return 0; } 4819 enum empty = false; 4820 auto save() { return this; } 4821 } 4822 struct NonForwardInfRange 4823 { 4824 void popFront() { } 4825 @property int front() { return 0; } 4826 enum empty = false; 4827 } 4828 4829 InfRange i; 4830 NonForwardInfRange j; 4831 auto c = cycle(i); 4832 assert(c == i); 4833 //make sure it can alias out even non-forward infinite ranges 4834 static assert(is(typeof(j.cycle) == typeof(j))); 4835 } 4836 4837 @safe unittest 4838 { 4839 import std.algorithm.comparison : equal; 4840 4841 int[5] arr = [0, 1, 2, 3, 4]; 4842 auto cleD = cycle(arr[]); //Dynamic 4843 assert(equal(cleD[5 .. 10], arr[])); 4844 4845 //n is a multiple of 5 worth about 3/4 of size_t.max 4846 auto n = size_t.max/4 + size_t.max/2; 4847 n -= n % 5; 4848 4849 //Test index overflow 4850 foreach (_ ; 0 .. 10) 4851 { 4852 cleD = cleD[n .. $]; 4853 assert(equal(cleD[5 .. 10], arr[])); 4854 } 4855 } 4856 4857 @system @nogc nothrow unittest 4858 { 4859 import std.algorithm.comparison : equal; 4860 4861 int[5] arr = [0, 1, 2, 3, 4]; 4862 auto cleS = cycle(arr); //Static 4863 assert(equal(cleS[5 .. 10], arr[])); 4864 4865 //n is a multiple of 5 worth about 3/4 of size_t.max 4866 auto n = size_t.max/4 + size_t.max/2; 4867 n -= n % 5; 4868 4869 //Test index overflow 4870 foreach (_ ; 0 .. 10) 4871 { 4872 cleS = cleS[n .. $]; 4873 assert(equal(cleS[5 .. 10], arr[])); 4874 } 4875 } 4876 4877 @system unittest 4878 { 4879 import std.algorithm.comparison : equal; 4880 4881 int[1] arr = [0]; 4882 auto cleS = cycle(arr); 4883 cleS = cleS[10 .. $]; 4884 assert(equal(cleS[5 .. 10], 0.repeat(5))); 4885 assert(cleS.front == 0); 4886 } 4887 4888 // https://issues.dlang.org/show_bug.cgi?id=10845 4889 @system unittest 4890 { 4891 import std.algorithm.comparison : equal; 4892 import std.algorithm.iteration : filter; 4893 4894 auto a = inputRangeObject(iota(3).filter!"true"); 4895 assert(equal(cycle(a).take(10), [0, 1, 2, 0, 1, 2, 0, 1, 2, 0])); 4896 } 4897 4898 // https://issues.dlang.org/show_bug.cgi?id=12177 4899 @safe unittest 4900 { 4901 static assert(__traits(compiles, recurrence!q{a[n - 1] ~ a[n - 2]}("1", "0"))); 4902 } 4903 4904 // https://issues.dlang.org/show_bug.cgi?id=13390 4905 @system unittest 4906 { 4907 import core.exception : AssertError; 4908 import std.exception : assertThrown; 4909 assertThrown!AssertError(cycle([0, 1, 2][0 .. 0])); 4910 } 4911 4912 // https://issues.dlang.org/show_bug.cgi?id=18657 4913 pure @safe unittest 4914 { 4915 import std.algorithm.comparison : equal; 4916 string s = "foo"; 4917 auto r = refRange(&s).cycle.take(4); 4918 assert(equal(r.save, "foof")); 4919 assert(equal(r.save, "foof")); 4920 } 4921 4922 // https://issues.dlang.org/show_bug.cgi?id=24481 4923 @safe unittest 4924 { 4925 import std.algorithm.iteration : filter; 4926 4927 bool called; 4928 struct Handle 4929 { 4930 int entry; 4931 void opAssign()(auto ref const(typeof(this)) that) const { called = true; } 4932 } 4933 4934 const(Handle)[3] arr = [Handle(0), Handle(1), Handle(2)]; 4935 { 4936 auto range = arr[].cycle().take(5); 4937 4938 called = false; 4939 range.front = Handle(42); 4940 assert(called); 4941 } 4942 { 4943 auto range = arr[].filter!(a => true)().cycle().take(5); 4944 4945 called = false; 4946 range.front = Handle(42); 4947 assert(called); 4948 } 4949 } 4950 4951 // https://github.com/dlang/phobos/issues/10852 4952 @safe unittest 4953 { 4954 // forward range 4955 struct R 4956 { 4957 int i; 4958 int front() => i; 4959 bool empty() => i == 0; 4960 void popFront() {--i;} 4961 R save() => this; 4962 } 4963 4964 auto r = R(10).cycle.take(20); 4965 assert(r.array == [10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]); 4966 } 4967 4968 private alias lengthType(R) = typeof(R.init.length.init); 4969 4970 /** 4971 Iterate several ranges in lockstep. The element type is a proxy tuple 4972 that allows accessing the current element in the `n`th range by 4973 using `e[n]`. 4974 4975 `zip` is similar to $(LREF lockstep), but `lockstep` doesn't 4976 bundle its elements and uses the `opApply` protocol. 4977 `lockstep` allows reference access to the elements in 4978 `foreach` iterations. 4979 4980 Params: 4981 sp = controls what `zip` will do if the ranges are different lengths 4982 ranges = the ranges to zip together 4983 Returns: 4984 At minimum, an input range. `Zip` offers the lowest range facilities 4985 of all components, e.g. it offers random access iff all ranges offer 4986 random access, and also offers mutation and swapping if all ranges offer 4987 it. Due to this, `Zip` is extremely powerful because it allows manipulating 4988 several ranges in lockstep. 4989 Throws: 4990 An `Exception` if all of the ranges are not the same length and 4991 `sp` is set to `StoppingPolicy.requireSameLength`. 4992 4993 Limitations: The `@nogc` and `nothrow` attributes cannot be inferred for 4994 the `Zip` struct because $(LREF StoppingPolicy) can vary at runtime. This 4995 limitation is not shared by the anonymous range returned by the `zip` 4996 function when not given an explicit `StoppingPolicy` as an argument. 4997 */ 4998 struct Zip(Ranges...) 4999 if (Ranges.length && allSatisfy!(isInputRange, Ranges)) 5000 { 5001 import std.format : format; //for generic mixins 5002 import std.typecons : Tuple; 5003 5004 alias R = Ranges; 5005 private R ranges; 5006 alias ElementType = Tuple!(staticMap!(.ElementType, R)); 5007 private StoppingPolicy stoppingPolicy = StoppingPolicy.shortest; 5008 5009 /** 5010 Builds an object. Usually this is invoked indirectly by using the 5011 $(LREF zip) function. 5012 */ 5013 this(R rs, StoppingPolicy s = StoppingPolicy.shortest) 5014 { 5015 ranges[] = rs[]; 5016 stoppingPolicy = s; 5017 } 5018 5019 /** 5020 Returns `true` if the range is at end. The test depends on the 5021 stopping policy. 5022 */ 5023 static if (allSatisfy!(isInfinite, R)) 5024 { 5025 // BUG: Doesn't propagate infiniteness if only some ranges are infinite 5026 // and s == StoppingPolicy.longest. This isn't fixable in the 5027 // current design since StoppingPolicy is known only at runtime. 5028 enum bool empty = false; 5029 } 5030 else 5031 { 5032 /// 5033 @property bool empty() 5034 { 5035 import std.exception : enforce; 5036 import std.meta : anySatisfy; 5037 5038 final switch (stoppingPolicy) 5039 { 5040 case StoppingPolicy.shortest: 5041 foreach (i, Unused; R) 5042 { 5043 if (ranges[i].empty) return true; 5044 } 5045 return false; 5046 case StoppingPolicy.longest: 5047 static if (anySatisfy!(isInfinite, R)) 5048 { 5049 return false; 5050 } 5051 else 5052 { 5053 foreach (i, Unused; R) 5054 { 5055 if (!ranges[i].empty) return false; 5056 } 5057 return true; 5058 } 5059 case StoppingPolicy.requireSameLength: 5060 foreach (i, Unused; R[1 .. $]) 5061 { 5062 enforce(ranges[0].empty == 5063 ranges[i + 1].empty, 5064 "Inequal-length ranges passed to Zip"); 5065 } 5066 return ranges[0].empty; 5067 } 5068 assert(false); 5069 } 5070 } 5071 5072 static if (allSatisfy!(isForwardRange, R)) 5073 { 5074 /// 5075 @property Zip save() 5076 { 5077 //Zip(ranges[0].save, ranges[1].save, ..., stoppingPolicy) 5078 return mixin (q{Zip(%(ranges[%s].save%|, %), stoppingPolicy)}.format(iota(0, R.length))); 5079 } 5080 } 5081 5082 private .ElementType!(R[i]) tryGetInit(size_t i)() 5083 { 5084 alias E = .ElementType!(R[i]); 5085 static if (!is(typeof({static E i;}))) 5086 throw new Exception("Range with non-default constructable elements exhausted."); 5087 else 5088 return E.init; 5089 } 5090 5091 /** 5092 Returns the current iterated element. 5093 */ 5094 @property ElementType front() 5095 { 5096 @property tryGetFront(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].front;} 5097 //ElementType(tryGetFront!0, tryGetFront!1, ...) 5098 return mixin(q{ElementType(%(tryGetFront!%s, %))}.format(iota(0, R.length))); 5099 } 5100 5101 /** 5102 Sets the front of all iterated ranges. 5103 */ 5104 static if (allSatisfy!(hasAssignableElements, R)) 5105 { 5106 @property void front(ElementType v) 5107 { 5108 foreach (i, Unused; R) 5109 { 5110 if (!ranges[i].empty) 5111 { 5112 ranges[i].front = v[i]; 5113 } 5114 } 5115 } 5116 } 5117 5118 /** 5119 Moves out the front. 5120 */ 5121 static if (allSatisfy!(hasMobileElements, R)) 5122 { 5123 ElementType moveFront() 5124 { 5125 @property tryMoveFront(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].moveFront();} 5126 //ElementType(tryMoveFront!0, tryMoveFront!1, ...) 5127 return mixin(q{ElementType(%(tryMoveFront!%s, %))}.format(iota(0, R.length))); 5128 } 5129 } 5130 5131 /** 5132 Returns the rightmost element. 5133 */ 5134 static if (allSatisfy!(isBidirectionalRange, R)) 5135 { 5136 @property ElementType back() 5137 { 5138 //TODO: Fixme! BackElement != back of all ranges in case of jagged-ness 5139 5140 @property tryGetBack(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].back;} 5141 //ElementType(tryGetBack!0, tryGetBack!1, ...) 5142 return mixin(q{ElementType(%(tryGetBack!%s, %))}.format(iota(0, R.length))); 5143 } 5144 5145 /** 5146 Moves out the back. 5147 */ 5148 static if (allSatisfy!(hasMobileElements, R)) 5149 { 5150 ElementType moveBack() 5151 { 5152 //TODO: Fixme! BackElement != back of all ranges in case of jagged-ness 5153 5154 @property tryMoveBack(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].moveBack();} 5155 //ElementType(tryMoveBack!0, tryMoveBack!1, ...) 5156 return mixin(q{ElementType(%(tryMoveBack!%s, %))}.format(iota(0, R.length))); 5157 } 5158 } 5159 5160 /** 5161 Returns the current iterated element. 5162 */ 5163 static if (allSatisfy!(hasAssignableElements, R)) 5164 { 5165 @property void back(ElementType v) 5166 { 5167 //TODO: Fixme! BackElement != back of all ranges in case of jagged-ness. 5168 //Not sure the call is even legal for StoppingPolicy.longest 5169 5170 foreach (i, Unused; R) 5171 { 5172 if (!ranges[i].empty) 5173 { 5174 ranges[i].back = v[i]; 5175 } 5176 } 5177 } 5178 } 5179 } 5180 5181 /** 5182 Advances to the next element in all controlled ranges. 5183 */ 5184 void popFront() 5185 { 5186 import std.exception : enforce; 5187 5188 final switch (stoppingPolicy) 5189 { 5190 case StoppingPolicy.shortest: 5191 foreach (i, Unused; R) 5192 { 5193 assert(!ranges[i].empty); 5194 ranges[i].popFront(); 5195 } 5196 break; 5197 case StoppingPolicy.longest: 5198 foreach (i, Unused; R) 5199 { 5200 if (!ranges[i].empty) ranges[i].popFront(); 5201 } 5202 break; 5203 case StoppingPolicy.requireSameLength: 5204 foreach (i, Unused; R) 5205 { 5206 enforce(!ranges[i].empty, "Invalid Zip object"); 5207 ranges[i].popFront(); 5208 } 5209 break; 5210 } 5211 } 5212 5213 /** 5214 Calls `popBack` for all controlled ranges. 5215 */ 5216 static if (allSatisfy!(isBidirectionalRange, R)) 5217 { 5218 void popBack() 5219 { 5220 //TODO: Fixme! In case of jaggedness, this is wrong. 5221 import std.exception : enforce; 5222 5223 final switch (stoppingPolicy) 5224 { 5225 case StoppingPolicy.shortest: 5226 foreach (i, Unused; R) 5227 { 5228 assert(!ranges[i].empty); 5229 ranges[i].popBack(); 5230 } 5231 break; 5232 case StoppingPolicy.longest: 5233 foreach (i, Unused; R) 5234 { 5235 if (!ranges[i].empty) ranges[i].popBack(); 5236 } 5237 break; 5238 case StoppingPolicy.requireSameLength: 5239 foreach (i, Unused; R) 5240 { 5241 enforce(!ranges[i].empty, "Invalid Zip object"); 5242 ranges[i].popBack(); 5243 } 5244 break; 5245 } 5246 } 5247 } 5248 5249 /** 5250 Returns the length of this range. Defined only if all ranges define 5251 `length`. 5252 */ 5253 static if (allSatisfy!(hasLength, R)) 5254 { 5255 @property auto length() 5256 { 5257 static if (Ranges.length == 1) 5258 return ranges[0].length; 5259 else 5260 { 5261 if (stoppingPolicy == StoppingPolicy.requireSameLength) 5262 return ranges[0].length; 5263 5264 //[min|max](ranges[0].length, ranges[1].length, ...) 5265 import std.algorithm.comparison : min, max; 5266 if (stoppingPolicy == StoppingPolicy.shortest) 5267 return mixin(q{min(%(ranges[%s].length%|, %))}.format(iota(0, R.length))); 5268 else 5269 return mixin(q{max(%(ranges[%s].length%|, %))}.format(iota(0, R.length))); 5270 } 5271 } 5272 5273 alias opDollar = length; 5274 } 5275 5276 /** 5277 Returns a slice of the range. Defined only if all range define 5278 slicing. 5279 */ 5280 static if (allSatisfy!(hasSlicing, R)) 5281 { 5282 auto opSlice(size_t from, size_t to) 5283 { 5284 //Slicing an infinite range yields the type Take!R 5285 //For finite ranges, the type Take!R aliases to R 5286 alias ZipResult = Zip!(staticMap!(Take, R)); 5287 5288 //ZipResult(ranges[0][from .. to], ranges[1][from .. to], ..., stoppingPolicy) 5289 return mixin (q{ZipResult(%(ranges[%s][from .. to]%|, %), stoppingPolicy)}.format(iota(0, R.length))); 5290 } 5291 } 5292 5293 /** 5294 Returns the `n`th element in the composite range. Defined if all 5295 ranges offer random access. 5296 */ 5297 static if (allSatisfy!(isRandomAccessRange, R)) 5298 { 5299 ElementType opIndex(size_t n) 5300 { 5301 //TODO: Fixme! This may create an out of bounds access 5302 //for StoppingPolicy.longest 5303 5304 //ElementType(ranges[0][n], ranges[1][n], ...) 5305 return mixin (q{ElementType(%(ranges[%s][n]%|, %))}.format(iota(0, R.length))); 5306 } 5307 5308 /** 5309 Assigns to the `n`th element in the composite range. Defined if 5310 all ranges offer random access. 5311 */ 5312 static if (allSatisfy!(hasAssignableElements, R)) 5313 { 5314 void opIndexAssign(ElementType v, size_t n) 5315 { 5316 //TODO: Fixme! Not sure the call is even legal for StoppingPolicy.longest 5317 foreach (i, Range; R) 5318 { 5319 ranges[i][n] = v[i]; 5320 } 5321 } 5322 } 5323 5324 /** 5325 Destructively reads the `n`th element in the composite 5326 range. Defined if all ranges offer random access. 5327 */ 5328 static if (allSatisfy!(hasMobileElements, R)) 5329 { 5330 ElementType moveAt(size_t n) 5331 { 5332 //TODO: Fixme! This may create an out of bounds access 5333 //for StoppingPolicy.longest 5334 5335 //ElementType(ranges[0].moveAt(n), ranges[1].moveAt(n), ..., ) 5336 return mixin (q{ElementType(%(ranges[%s].moveAt(n)%|, %))}.format(iota(0, R.length))); 5337 } 5338 } 5339 } 5340 } 5341 5342 /// Ditto 5343 auto zip(Ranges...)(Ranges ranges) 5344 if (Ranges.length && allSatisfy!(isInputRange, Ranges)) 5345 { 5346 import std.meta : anySatisfy, templateOr; 5347 static if (allSatisfy!(isInfinite, Ranges) || Ranges.length == 1) 5348 { 5349 return ZipShortest!(Ranges)(ranges); 5350 } 5351 else static if (allSatisfy!(isBidirectionalRange, Ranges)) 5352 { 5353 static if (allSatisfy!(templateOr!(isInfinite, hasLength), Ranges) 5354 && allSatisfy!(templateOr!(isInfinite, hasSlicing), Ranges) 5355 && allSatisfy!(isBidirectionalRange, staticMap!(Take, Ranges))) 5356 { 5357 // If all the ranges are bidirectional, if possible slice them to 5358 // the same length to simplify the implementation. 5359 static assert(anySatisfy!(hasLength, Ranges)); 5360 static foreach (i, Range; Ranges) 5361 static if (hasLength!Range) 5362 { 5363 static if (!is(typeof(minLen) == size_t)) 5364 size_t minLen = ranges[i].length; 5365 else 5366 {{ 5367 const x = ranges[i].length; 5368 if (x < minLen) minLen = x; 5369 }} 5370 } 5371 import std.format : format; 5372 static if (!anySatisfy!(isInfinite, Ranges)) 5373 return mixin(`ZipShortest!(Yes.allKnownSameLength, staticMap!(Take, Ranges))`~ 5374 `(%(ranges[%s][0 .. minLen]%|, %))`.format(iota(0, Ranges.length))); 5375 else 5376 return mixin(`ZipShortest!(Yes.allKnownSameLength, staticMap!(Take, Ranges))`~ 5377 `(%(take(ranges[%s], minLen)%|, %))`.format(iota(0, Ranges.length))); 5378 } 5379 else static if (allSatisfy!(isRandomAccessRange, Ranges)) 5380 { 5381 // We can't slice but we can still use random access to ensure 5382 // "back" is retrieving the same index for each range. 5383 return ZipShortest!(Ranges)(ranges); 5384 } 5385 else 5386 { 5387 // If bidirectional range operations would not be supported by 5388 // ZipShortest that might have actually been a bug since Zip 5389 // supported `back` without verifying that each range had the 5390 // same length, but for the sake of backwards compatibility 5391 // use the old Zip to continue supporting them. 5392 return Zip!Ranges(ranges); 5393 } 5394 } 5395 else 5396 { 5397 return ZipShortest!(Ranges)(ranges); 5398 } 5399 } 5400 5401 /// 5402 @nogc nothrow pure @safe unittest 5403 { 5404 import std.algorithm.comparison : equal; 5405 import std.algorithm.iteration : map; 5406 5407 // pairwise sum 5408 auto arr = only(0, 1, 2); 5409 auto part1 = zip(arr, arr.dropOne).map!"a[0] + a[1]"; 5410 assert(part1.equal(only(1, 3))); 5411 } 5412 5413 /// 5414 nothrow pure @safe unittest 5415 { 5416 import std.conv : to; 5417 5418 int[] a = [ 1, 2, 3 ]; 5419 string[] b = [ "a", "b", "c" ]; 5420 string[] result; 5421 5422 foreach (tup; zip(a, b)) 5423 { 5424 result ~= tup[0].to!string ~ tup[1]; 5425 } 5426 5427 assert(result == [ "1a", "2b", "3c" ]); 5428 5429 size_t idx = 0; 5430 // unpacking tuple elements with foreach 5431 foreach (e1, e2; zip(a, b)) 5432 { 5433 assert(e1 == a[idx]); 5434 assert(e2 == b[idx]); 5435 ++idx; 5436 } 5437 } 5438 5439 /// `zip` is powerful - the following code sorts two arrays in parallel: 5440 nothrow pure @safe unittest 5441 { 5442 import std.algorithm.sorting : sort; 5443 5444 int[] a = [ 1, 2, 3 ]; 5445 string[] b = [ "a", "c", "b" ]; 5446 zip(a, b).sort!((t1, t2) => t1[0] > t2[0]); 5447 5448 assert(a == [ 3, 2, 1 ]); 5449 // b is sorted according to a's sorting 5450 assert(b == [ "b", "c", "a" ]); 5451 } 5452 5453 /// Ditto 5454 auto zip(Ranges...)(StoppingPolicy sp, Ranges ranges) 5455 if (Ranges.length && allSatisfy!(isInputRange, Ranges)) 5456 { 5457 return Zip!Ranges(ranges, sp); 5458 } 5459 5460 /** 5461 Dictates how iteration in a $(LREF zip) and $(LREF lockstep) should stop. 5462 By default stop at the end of the shortest of all ranges. 5463 */ 5464 enum StoppingPolicy 5465 { 5466 /// Stop when the shortest range is exhausted 5467 shortest, 5468 /// Stop when the longest range is exhausted 5469 longest, 5470 /// Require that all ranges are equal 5471 requireSameLength, 5472 } 5473 5474 /// 5475 pure @safe unittest 5476 { 5477 import std.algorithm.comparison : equal; 5478 import std.exception : assertThrown; 5479 import std.range.primitives; 5480 import std.typecons : tuple; 5481 5482 auto a = [1, 2, 3]; 5483 auto b = [4, 5, 6, 7]; 5484 5485 auto shortest = zip(StoppingPolicy.shortest, a, b); 5486 assert(shortest.equal([ 5487 tuple(1, 4), 5488 tuple(2, 5), 5489 tuple(3, 6) 5490 ])); 5491 5492 auto longest = zip(StoppingPolicy.longest, a, b); 5493 assert(longest.equal([ 5494 tuple(1, 4), 5495 tuple(2, 5), 5496 tuple(3, 6), 5497 tuple(0, 7) 5498 ])); 5499 5500 auto same = zip(StoppingPolicy.requireSameLength, a, b); 5501 same.popFrontN(3); 5502 assertThrown!Exception(same.popFront); 5503 } 5504 5505 /+ 5506 Non-public. Like $(LREF Zip) with `StoppingPolicy.shortest` 5507 except it properly implements `back` and `popBack` in the 5508 case of uneven ranges or disables those operations when 5509 it is not possible to guarantee they are correct. 5510 +/ 5511 package template ZipShortest(Ranges...) 5512 if (Ranges.length && __traits(compiles, 5513 { 5514 static assert(allSatisfy!(isInputRange, Ranges)); 5515 })) 5516 { 5517 alias ZipShortest = .ZipShortest!( 5518 Ranges.length == 1 || allSatisfy!(isInfinite, Ranges) 5519 ? Yes.allKnownSameLength 5520 : No.allKnownSameLength, 5521 Ranges); 5522 } 5523 /+ non-public, ditto +/ 5524 package struct ZipShortest(Flag!"allKnownSameLength" allKnownSameLength, Ranges...) 5525 if (Ranges.length && allSatisfy!(isInputRange, Ranges)) 5526 { 5527 import std.format : format; //for generic mixins 5528 import std.meta : anySatisfy, templateOr; 5529 import std.typecons : Tuple; 5530 5531 deprecated("Use of an undocumented alias R.") 5532 alias R = Ranges; // Unused here but defined in case library users rely on it. 5533 private Ranges ranges; 5534 alias ElementType = Tuple!(staticMap!(.ElementType, Ranges)); 5535 5536 /+ 5537 Builds an object. Usually this is invoked indirectly by using the 5538 $(LREF zip) function. 5539 +/ 5540 this(Ranges rs) 5541 { 5542 ranges[] = rs[]; 5543 } 5544 5545 /+ 5546 Returns `true` if the range is at end. 5547 +/ 5548 static if (allKnownSameLength ? anySatisfy!(isInfinite, Ranges) 5549 : allSatisfy!(isInfinite, Ranges)) 5550 { 5551 enum bool empty = false; 5552 } 5553 else 5554 { 5555 @property bool empty() 5556 { 5557 static if (allKnownSameLength) 5558 { 5559 return ranges[0].empty; 5560 } 5561 else 5562 { 5563 static foreach (i; 0 .. Ranges.length) 5564 { 5565 if (ranges[i].empty) 5566 return true; 5567 } 5568 return false; 5569 } 5570 } 5571 } 5572 5573 /+ 5574 Forward range primitive. Only present if each constituent range is a 5575 forward range. 5576 +/ 5577 static if (allSatisfy!(isForwardRange, Ranges)) 5578 @property typeof(this) save() 5579 { 5580 return mixin(`typeof(return)(%(ranges[%s].save%|, %))`.format(iota(0, Ranges.length))); 5581 } 5582 5583 /+ 5584 Returns the current iterated element. 5585 +/ 5586 @property ElementType front() 5587 { 5588 return mixin(`typeof(return)(%(ranges[%s].front%|, %))`.format(iota(0, Ranges.length))); 5589 } 5590 5591 /+ 5592 Sets the front of all iterated ranges. Only present if each constituent 5593 range has assignable elements. 5594 +/ 5595 static if (allSatisfy!(hasAssignableElements, Ranges)) 5596 @property void front()(ElementType v) 5597 { 5598 static foreach (i; 0 .. Ranges.length) 5599 ranges[i].front = v[i]; 5600 } 5601 5602 /+ 5603 Moves out the front. Present if each constituent range has mobile elements. 5604 +/ 5605 static if (allSatisfy!(hasMobileElements, Ranges)) 5606 ElementType moveFront()() 5607 { 5608 return mixin(`typeof(return)(%(ranges[%s].moveFront()%|, %))`.format(iota(0, Ranges.length))); 5609 } 5610 5611 private enum bool isBackWellDefined = allSatisfy!(isBidirectionalRange, Ranges) 5612 && (allKnownSameLength 5613 || allSatisfy!(isRandomAccessRange, Ranges) 5614 // Could also add the case where there is one non-infinite bidirectional 5615 // range that defines `length` and all others are infinite random access 5616 // ranges. Adding this would require appropriate branches in 5617 // back/moveBack/popBack. 5618 ); 5619 5620 /+ 5621 Returns the rightmost element. Present if all constituent ranges are 5622 bidirectional and either there is a compile-time guarantee that all 5623 ranges have the same length (in `allKnownSameLength`) or all ranges 5624 provide random access to elements. 5625 +/ 5626 static if (isBackWellDefined) 5627 @property ElementType back() 5628 { 5629 static if (allKnownSameLength) 5630 { 5631 return mixin(`typeof(return)(%(ranges[%s].back()%|, %))`.format(iota(0, Ranges.length))); 5632 } 5633 else 5634 { 5635 const backIndex = length - 1; 5636 return mixin(`typeof(return)(%(ranges[%s][backIndex]%|, %))`.format(iota(0, Ranges.length))); 5637 } 5638 } 5639 5640 /+ 5641 Moves out the back. Present if `back` is defined and 5642 each constituent range has mobile elements. 5643 +/ 5644 static if (isBackWellDefined && allSatisfy!(hasMobileElements, Ranges)) 5645 ElementType moveBack()() 5646 { 5647 static if (allKnownSameLength) 5648 { 5649 return mixin(`typeof(return)(%(ranges[%s].moveBack()%|, %))`.format(iota(0, Ranges.length))); 5650 } 5651 else 5652 { 5653 const backIndex = length - 1; 5654 return mixin(`typeof(return)(%(ranges[%s].moveAt(backIndex)%|, %))`.format(iota(0, Ranges.length))); 5655 } 5656 } 5657 5658 /+ 5659 Sets the rightmost element. Only present if `back` is defined and 5660 each constituent range has assignable elements. 5661 +/ 5662 static if (isBackWellDefined && allSatisfy!(hasAssignableElements, Ranges)) 5663 @property void back()(ElementType v) 5664 { 5665 static if (allKnownSameLength) 5666 { 5667 static foreach (i; 0 .. Ranges.length) 5668 ranges[i].back = v[i]; 5669 } 5670 else 5671 { 5672 const backIndex = length - 1; 5673 static foreach (i; 0 .. Ranges.length) 5674 ranges[i][backIndex] = v[i]; 5675 } 5676 } 5677 5678 /+ 5679 Calls `popFront` on each constituent range. 5680 +/ 5681 void popFront() 5682 { 5683 static foreach (i; 0 .. Ranges.length) 5684 ranges[i].popFront(); 5685 } 5686 5687 /+ 5688 Pops the rightmost element. Present if `back` is defined. 5689 +/ 5690 static if (isBackWellDefined) 5691 void popBack() 5692 { 5693 static if (allKnownSameLength) 5694 { 5695 static foreach (i; 0 .. Ranges.length) 5696 ranges[i].popBack; 5697 } 5698 else 5699 { 5700 const len = length; 5701 static foreach (i; 0 .. Ranges.length) 5702 static if (!isInfinite!(Ranges[i])) 5703 if (ranges[i].length == len) 5704 ranges[i].popBack(); 5705 } 5706 } 5707 5708 /+ 5709 Returns the length of this range. Defined if at least one 5710 constituent range defines `length` and the other ranges all also 5711 define `length` or are infinite, or if at least one constituent 5712 range defines `length` and there is a compile-time guarantee that 5713 all ranges have the same length (in `allKnownSameLength`). 5714 +/ 5715 static if (allKnownSameLength 5716 ? anySatisfy!(hasLength, Ranges) 5717 : (anySatisfy!(hasLength, Ranges) 5718 && allSatisfy!(templateOr!(isInfinite, hasLength), Ranges))) 5719 { 5720 @property size_t length() 5721 { 5722 static foreach (i, Range; Ranges) 5723 { 5724 static if (hasLength!Range) 5725 { 5726 static if (!is(typeof(minLen) == size_t)) 5727 size_t minLen = ranges[i].length; 5728 else static if (!allKnownSameLength) 5729 {{ 5730 const x = ranges[i].length; 5731 if (x < minLen) minLen = x; 5732 }} 5733 } 5734 } 5735 return minLen; 5736 } 5737 5738 alias opDollar = length; 5739 } 5740 5741 /+ 5742 Returns a slice of the range. Defined if all constituent ranges 5743 support slicing. 5744 +/ 5745 static if (allSatisfy!(hasSlicing, Ranges)) 5746 { 5747 // Note: we will know that all elements of the resultant range 5748 // will have the same length but we cannot change `allKnownSameLength` 5749 // because the `hasSlicing` predicate tests that the result returned 5750 // by `opSlice` has the same type as the receiver. 5751 auto opSlice()(size_t from, size_t to) 5752 { 5753 //(ranges[0][from .. to], ranges[1][from .. to], ...) 5754 enum sliceArgs = `(%(ranges[%s][from .. to]%|, %))`.format(iota(0, Ranges.length)); 5755 static if (__traits(compiles, mixin(`typeof(this)`~sliceArgs))) 5756 return mixin(`typeof(this)`~sliceArgs); 5757 else 5758 // The type is different anyway so we might as well 5759 // explicitly set allKnownSameLength. 5760 return mixin(`ZipShortest!(Yes.allKnownSameLength, staticMap!(Take, Ranges))` 5761 ~sliceArgs); 5762 } 5763 } 5764 5765 /+ 5766 Returns the `n`th element in the composite range. Defined if all 5767 constituent ranges offer random access. 5768 +/ 5769 static if (allSatisfy!(isRandomAccessRange, Ranges)) 5770 ElementType opIndex()(size_t n) 5771 { 5772 return mixin(`typeof(return)(%(ranges[%s][n]%|, %))`.format(iota(0, Ranges.length))); 5773 } 5774 5775 /+ 5776 Sets the `n`th element in the composite range. Defined if all 5777 constituent ranges offer random access and have assignable elements. 5778 +/ 5779 static if (allSatisfy!(isRandomAccessRange, Ranges) 5780 && allSatisfy!(hasAssignableElements, Ranges)) 5781 void opIndexAssign()(ElementType v, size_t n) 5782 { 5783 static foreach (i; 0 .. Ranges.length) 5784 ranges[i][n] = v[i]; 5785 } 5786 5787 /+ 5788 Destructively reads the `n`th element in the composite 5789 range. Defined if all constituent ranges offer random 5790 access and have mobile elements. 5791 +/ 5792 static if (allSatisfy!(isRandomAccessRange, Ranges) 5793 && allSatisfy!(hasMobileElements, Ranges)) 5794 ElementType moveAt()(size_t n) 5795 { 5796 return mixin(`typeof(return)(%(ranges[%s].moveAt(n)%|, %))`.format(iota(0, Ranges.length))); 5797 } 5798 } 5799 5800 pure @system unittest 5801 { 5802 import std.algorithm.comparison : equal; 5803 import std.algorithm.iteration : filter, map; 5804 import std.algorithm.mutation : swap; 5805 import std.algorithm.sorting : sort; 5806 5807 import std.exception : assertThrown, assertNotThrown; 5808 import std.typecons : tuple; 5809 5810 int[] a = [ 1, 2, 3 ]; 5811 float[] b = [ 1.0, 2.0, 3.0 ]; 5812 foreach (e; zip(a, b)) 5813 { 5814 assert(e[0] == e[1]); 5815 } 5816 5817 swap(a[0], a[1]); 5818 { 5819 auto z = zip(a, b); 5820 } 5821 //swap(z.front(), z.back()); 5822 sort!("a[0] < b[0]")(zip(a, b)); 5823 assert(a == [1, 2, 3]); 5824 assert(b == [2.0, 1.0, 3.0]); 5825 5826 auto z = zip(StoppingPolicy.requireSameLength, a, b); 5827 assertNotThrown(z.popBack()); 5828 assertNotThrown(z.popBack()); 5829 assertNotThrown(z.popBack()); 5830 assert(z.empty); 5831 assertThrown(z.popBack()); 5832 5833 a = [ 1, 2, 3 ]; 5834 b = [ 1.0, 2.0, 3.0 ]; 5835 sort!("a[0] > b[0]")(zip(StoppingPolicy.requireSameLength, a, b)); 5836 assert(a == [3, 2, 1]); 5837 assert(b == [3.0, 2.0, 1.0]); 5838 5839 a = []; 5840 b = []; 5841 assert(zip(StoppingPolicy.requireSameLength, a, b).empty); 5842 5843 // Test infiniteness propagation. 5844 static assert(isInfinite!(typeof(zip(repeat(1), repeat(1))))); 5845 5846 // Test stopping policies with both value and reference. 5847 auto a1 = [1, 2]; 5848 auto a2 = [1, 2, 3]; 5849 auto stuff = tuple(tuple(a1, a2), 5850 tuple(filter!"a"(a1), filter!"a"(a2))); 5851 5852 alias FOO = Zip!(immutable(int)[], immutable(float)[]); 5853 5854 foreach (t; stuff.expand) 5855 { 5856 auto arr1 = t[0]; 5857 auto arr2 = t[1]; 5858 auto zShortest = zip(arr1, arr2); 5859 assert(equal(map!"a[0]"(zShortest), [1, 2])); 5860 assert(equal(map!"a[1]"(zShortest), [1, 2])); 5861 5862 try { 5863 auto zSame = zip(StoppingPolicy.requireSameLength, arr1, arr2); 5864 foreach (elem; zSame) {} 5865 assert(0); 5866 } catch (Throwable) { /* It's supposed to throw.*/ } 5867 5868 auto zLongest = zip(StoppingPolicy.longest, arr1, arr2); 5869 assert(!zLongest.ranges[0].empty); 5870 assert(!zLongest.ranges[1].empty); 5871 5872 zLongest.popFront(); 5873 zLongest.popFront(); 5874 assert(!zLongest.empty); 5875 assert(zLongest.ranges[0].empty); 5876 assert(!zLongest.ranges[1].empty); 5877 5878 zLongest.popFront(); 5879 assert(zLongest.empty); 5880 } 5881 5882 // https://issues.dlang.org/show_bug.cgi?id=8900 5883 assert(zip([1, 2], repeat('a')).array == [tuple(1, 'a'), tuple(2, 'a')]); 5884 assert(zip(repeat('a'), [1, 2]).array == [tuple('a', 1), tuple('a', 2)]); 5885 5886 // https://issues.dlang.org/show_bug.cgi?id=18524 5887 // moveBack instead performs moveFront 5888 { 5889 auto r = zip([1,2,3]); 5890 assert(r.moveBack()[0] == 3); 5891 assert(r.moveFront()[0] == 1); 5892 } 5893 5894 // Doesn't work yet. Issues w/ emplace. 5895 // static assert(is(Zip!(immutable int[], immutable float[]))); 5896 5897 5898 // These unittests pass, but make the compiler consume an absurd amount 5899 // of RAM and time. Therefore, they should only be run if explicitly 5900 // uncommented when making changes to Zip. Also, running them using 5901 // make -fwin32.mak unittest makes the compiler completely run out of RAM. 5902 // You need to test just this module. 5903 /+ 5904 foreach (DummyType1; AllDummyRanges) 5905 { 5906 DummyType1 d1; 5907 foreach (DummyType2; AllDummyRanges) 5908 { 5909 DummyType2 d2; 5910 auto r = zip(d1, d2); 5911 assert(equal(map!"a[0]"(r), [1,2,3,4,5,6,7,8,9,10])); 5912 assert(equal(map!"a[1]"(r), [1,2,3,4,5,6,7,8,9,10])); 5913 5914 static if (isForwardRange!DummyType1 && isForwardRange!DummyType2) 5915 { 5916 static assert(isForwardRange!(typeof(r))); 5917 } 5918 5919 static if (isBidirectionalRange!DummyType1 && 5920 isBidirectionalRange!DummyType2) { 5921 static assert(isBidirectionalRange!(typeof(r))); 5922 } 5923 static if (isRandomAccessRange!DummyType1 && 5924 isRandomAccessRange!DummyType2) { 5925 static assert(isRandomAccessRange!(typeof(r))); 5926 } 5927 } 5928 } 5929 +/ 5930 } 5931 5932 nothrow pure @safe unittest 5933 { 5934 import std.algorithm.sorting : sort; 5935 5936 auto a = [5,4,3,2,1]; 5937 auto b = [3,1,2,5,6]; 5938 auto z = zip(a, b); 5939 5940 sort!"a[0] < b[0]"(z); 5941 5942 assert(a == [1, 2, 3, 4, 5]); 5943 assert(b == [6, 5, 2, 1, 3]); 5944 } 5945 5946 nothrow pure @safe unittest 5947 { 5948 import std.algorithm.comparison : equal; 5949 import std.typecons : tuple; 5950 5951 auto LL = iota(1L, 1000L); 5952 auto z = zip(LL, [4]); 5953 5954 assert(equal(z, [tuple(1L,4)])); 5955 5956 auto LL2 = iota(0L, 500L); 5957 auto z2 = zip([7], LL2); 5958 assert(equal(z2, [tuple(7, 0L)])); 5959 } 5960 5961 // Test for https://issues.dlang.org/show_bug.cgi?id=11196 5962 @safe pure unittest 5963 { 5964 import std.exception : assertThrown; 5965 5966 static struct S { @disable this(); } 5967 assert(zip((S[5]).init[]).length == 5); 5968 assert(zip(StoppingPolicy.longest, cast(S[]) null, new int[1]).length == 1); 5969 assertThrown(zip(StoppingPolicy.longest, cast(S[]) null, new int[1]).front); 5970 } 5971 5972 // https://issues.dlang.org/show_bug.cgi?id=12007 5973 @nogc nothrow @safe pure unittest 5974 { 5975 static struct R 5976 { 5977 enum empty = false; 5978 void popFront(){} 5979 int front(){return 1;} @property 5980 R save(){return this;} @property 5981 void opAssign(R) @disable; 5982 } 5983 R r; 5984 auto z = zip(r, r); 5985 assert(z.save == z); 5986 } 5987 5988 nothrow pure @system unittest 5989 { 5990 import std.typecons : tuple; 5991 5992 auto r1 = [0,1,2]; 5993 auto r2 = [1,2,3]; 5994 auto z1 = zip(refRange(&r1), refRange(&r2)); 5995 auto z2 = z1.save; 5996 z1.popFront(); 5997 assert(z1.front == tuple(1,2)); 5998 assert(z2.front == tuple(0,1)); 5999 } 6000 6001 @nogc nothrow pure @safe unittest 6002 { 6003 // Test zip's `back` and `length` with non-equal ranges. 6004 static struct NonSliceableRandomAccess 6005 { 6006 private int[] a; 6007 @property ref front() 6008 { 6009 return a.front; 6010 } 6011 @property ref back() 6012 { 6013 return a.back; 6014 } 6015 ref opIndex(size_t i) 6016 { 6017 return a[i]; 6018 } 6019 void popFront() 6020 { 6021 a.popFront(); 6022 } 6023 void popBack() 6024 { 6025 a.popBack(); 6026 } 6027 auto moveFront() 6028 { 6029 return a.moveFront(); 6030 } 6031 auto moveBack() 6032 { 6033 return a.moveBack(); 6034 } 6035 auto moveAt(size_t i) 6036 { 6037 return a.moveAt(i); 6038 } 6039 bool empty() const 6040 { 6041 return a.empty; 6042 } 6043 size_t length() const 6044 { 6045 return a.length; 6046 } 6047 typeof(this) save() 6048 { 6049 return this; 6050 } 6051 } 6052 static assert(isRandomAccessRange!NonSliceableRandomAccess); 6053 static assert(!hasSlicing!NonSliceableRandomAccess); 6054 static foreach (iteration; 0 .. 2) 6055 {{ 6056 int[5] data = [101, 102, 103, 201, 202]; 6057 static if (iteration == 0) 6058 { 6059 auto r1 = NonSliceableRandomAccess(data[0 .. 3]); 6060 auto r2 = NonSliceableRandomAccess(data[3 .. 5]); 6061 } 6062 else 6063 { 6064 auto r1 = data[0 .. 3]; 6065 auto r2 = data[3 .. 5]; 6066 } 6067 auto z = zip(r1, r2); 6068 static assert(isRandomAccessRange!(typeof(z))); 6069 assert(z.length == 2); 6070 assert(z.back[0] == 102 && z.back[1] == 202); 6071 z.back = typeof(z.back)(-102, -202);// Assign to back. 6072 assert(z.back[0] == -102 && z.back[1] == -202); 6073 z.popBack(); 6074 assert(z.length == 1); 6075 assert(z.back[0] == 101 && z.back[1] == 201); 6076 z.front = typeof(z.front)(-101, -201); 6077 assert(z.moveBack() == typeof(z.back)(-101, -201)); 6078 z.popBack(); 6079 assert(z.empty); 6080 }} 6081 } 6082 6083 @nogc nothrow pure @safe unittest 6084 { 6085 // Test opSlice on infinite `zip`. 6086 auto z = zip(repeat(1), repeat(2)); 6087 assert(hasSlicing!(typeof(z))); 6088 auto slice = z[10 .. 20]; 6089 assert(slice.length == 10); 6090 static assert(!is(typeof(z) == typeof(slice))); 6091 } 6092 6093 /* 6094 Generate lockstep's opApply function as a mixin string. 6095 If withIndex is true prepend a size_t index to the delegate. 6096 */ 6097 private struct LockstepMixin(Ranges...) 6098 { 6099 import std.conv : text; 6100 import std.format : format; 6101 6102 string name; 6103 string implName; 6104 string[] params; 6105 string[] emptyChecks; 6106 string[] dgArgs; 6107 string[] popFronts; 6108 string indexDef; 6109 string indexInc; 6110 6111 @safe pure: 6112 this(bool withIndex, bool reverse) 6113 { 6114 if (withIndex) 6115 { 6116 params ~= "size_t"; 6117 dgArgs ~= "index"; 6118 if (reverse) 6119 { 6120 indexDef = q{ 6121 size_t index = ranges[0].length - 1; 6122 enforce( 6123 this.stoppingPolicy == StoppingPolicy.requireSameLength, 6124 "Indexed lockstep can only be used with foreach_reverse when " ~ 6125 "stoppingPolicy == requireSameLength"); 6126 6127 foreach (range; ranges[1 .. $]) 6128 enforce(range.length == ranges[0].length); 6129 }; 6130 indexInc = "--index;"; 6131 } 6132 else 6133 { 6134 indexDef = "size_t index = 0;"; 6135 indexInc = "++index;"; 6136 } 6137 } 6138 6139 foreach (idx, Range; Ranges) 6140 { 6141 params ~= format("%sElementType!(Ranges[%s])", hasLvalueElements!Range ? "ref " : "", idx); 6142 emptyChecks ~= format("!ranges[%s].empty", idx); 6143 if (reverse) 6144 { 6145 dgArgs ~= format("ranges[%s].back", idx); 6146 popFronts ~= format("ranges[%s].popBack();", idx); 6147 } 6148 else 6149 { 6150 dgArgs ~= format("ranges[%s].front", idx); 6151 popFronts ~= format("ranges[%s].popFront();", idx); 6152 } 6153 } 6154 6155 if (reverse) 6156 { 6157 name = "opApplyReverse"; 6158 if (withIndex) implName = "opApplyReverseIdxImpl"; 6159 else implName = "opApplyReverseImpl"; 6160 } 6161 else 6162 { 6163 name = "opApply"; 6164 if (withIndex) implName = "opApplyIdxImpl"; 6165 else implName = "opApplyImpl"; 6166 } 6167 } 6168 6169 const: 6170 string getAlias() 6171 { 6172 return format(q{ 6173 alias %s = %s!(int delegate(%-(%s%|, %))); 6174 }, 6175 name, implName, params 6176 ); 6177 } 6178 6179 string getImpl() 6180 { 6181 return format(q{ 6182 int %s(DG)(scope DG dg) scope 6183 { 6184 import std.exception : enforce; 6185 6186 auto ranges = this.ranges; 6187 %s 6188 6189 while (%-(%s%| && %)) 6190 { 6191 if (int result = dg(%-(%s%|, %))) return result; 6192 %-(%s%| 6193 %) 6194 %s 6195 } 6196 6197 if (this.stoppingPolicy == StoppingPolicy.requireSameLength) 6198 { 6199 foreach (range; ranges) 6200 enforce(range.empty); 6201 } 6202 return 0; 6203 } 6204 }, 6205 implName, indexDef, emptyChecks, dgArgs, popFronts, indexInc 6206 ); 6207 } 6208 } 6209 6210 /** 6211 Iterate multiple ranges in lockstep using a `foreach` loop. In contrast to 6212 $(LREF zip) it allows reference access to its elements. If only a single 6213 range is passed in, the `Lockstep` aliases itself away. If the 6214 ranges are of different lengths and `s` == `StoppingPolicy.shortest` 6215 stop after the shortest range is empty. If the ranges are of different 6216 lengths and `s` == `StoppingPolicy.requireSameLength`, throw an 6217 exception. `s` may not be `StoppingPolicy.longest`, and passing this 6218 will throw an exception. 6219 6220 Iterating over `Lockstep` in reverse and with an index is only possible 6221 when `s` == `StoppingPolicy.requireSameLength`, in order to preserve 6222 indexes. If an attempt is made at iterating in reverse when `s` == 6223 `StoppingPolicy.shortest`, an exception will be thrown. 6224 6225 By default `StoppingPolicy` is set to `StoppingPolicy.shortest`. 6226 6227 See_Also: $(LREF zip) 6228 6229 `lockstep` is similar to $(LREF zip), but `zip` bundles its 6230 elements and returns a range. 6231 `lockstep` also supports reference access. 6232 Use `zip` if you want to pass the result to a range function. 6233 */ 6234 struct Lockstep(Ranges...) 6235 if (Ranges.length > 1 && allSatisfy!(isInputRange, Ranges)) 6236 { 6237 private Ranges ranges; 6238 private StoppingPolicy stoppingPolicy; 6239 6240 /// 6241 this(Ranges ranges, StoppingPolicy sp = StoppingPolicy.shortest) 6242 { 6243 import std.exception : enforce; 6244 6245 this.ranges = ranges; 6246 enforce(sp != StoppingPolicy.longest, 6247 "Can't use StoppingPolicy.Longest on Lockstep."); 6248 this.stoppingPolicy = sp; 6249 } 6250 6251 private enum lockstepMixinFF = LockstepMixin!Ranges(withIndex: false, reverse: false); 6252 mixin(lockstepMixinFF.getImpl); 6253 6254 private enum lockstepMixinTF = LockstepMixin!Ranges(withIndex: true, reverse: false); 6255 mixin(lockstepMixinTF.getImpl); 6256 6257 mixin(lockstepMixinFF.getAlias); 6258 mixin(lockstepMixinTF.getAlias); 6259 6260 static if (allSatisfy!(isBidirectionalRange, Ranges)) 6261 { 6262 private enum lockstepMixinFT = LockstepMixin!Ranges(withIndex: false, reverse: true); 6263 mixin(lockstepMixinFT.getImpl); 6264 static if (allSatisfy!(hasLength, Ranges)) 6265 { 6266 private enum lockstepMixinTT = LockstepMixin!Ranges(withIndex: true, reverse: true); 6267 mixin(lockstepMixinTT.getImpl); 6268 mixin(lockstepMixinTT.getAlias); 6269 } 6270 else 6271 { 6272 mixin(lockstepReverseFailMixin!Ranges(withIndex: true)); 6273 alias opApplyReverse = opApplyReverseIdxFail; 6274 } 6275 mixin(lockstepMixinFT.getAlias); 6276 } 6277 else 6278 { 6279 mixin(lockstepReverseFailMixin!Ranges(withIndex: false)); 6280 mixin(lockstepReverseFailMixin!Ranges(withIndex: true)); 6281 alias opApplyReverse = opApplyReverseFail; 6282 alias opApplyReverse = opApplyReverseIdxFail; 6283 } 6284 } 6285 6286 /// Ditto 6287 Lockstep!(Ranges) lockstep(Ranges...)(Ranges ranges) 6288 if (allSatisfy!(isInputRange, Ranges)) 6289 { 6290 return Lockstep!(Ranges)(ranges); 6291 } 6292 /// Ditto 6293 Lockstep!(Ranges) lockstep(Ranges...)(Ranges ranges, StoppingPolicy s) 6294 if (allSatisfy!(isInputRange, Ranges)) 6295 { 6296 static if (Ranges.length > 1) 6297 return Lockstep!Ranges(ranges, s); 6298 else 6299 return ranges[0]; 6300 } 6301 6302 /// 6303 pure @safe unittest 6304 { 6305 int[6] arr1 = [1,2,3,4,5,100]; 6306 int[5] arr2 = [6,7,8,9,10]; 6307 6308 foreach (ref a, b; lockstep(arr1[], arr2[])) 6309 { 6310 a += b; 6311 } 6312 6313 assert(arr1 == [7,9,11,13,15,100]); 6314 } 6315 6316 /// Lockstep also supports iterating with an index variable: 6317 pure @safe unittest 6318 { 6319 int[3] arr1 = [1,2,3]; 6320 int[3] arr2 = [4,5,6]; 6321 6322 foreach (index, a, b; lockstep(arr1[], arr2[])) 6323 { 6324 assert(arr1[index] == a); 6325 assert(arr2[index] == b); 6326 } 6327 } 6328 6329 // https://issues.dlang.org/show_bug.cgi?id=15860: foreach_reverse on lockstep 6330 pure @safe unittest 6331 { 6332 auto arr1 = [0, 1, 2, 3]; 6333 auto arr2 = [4, 5, 6, 7]; 6334 6335 size_t n = arr1.length - 1; 6336 foreach_reverse (index, a, b; lockstep(arr1, arr2, StoppingPolicy.requireSameLength)) 6337 { 6338 assert(n == index); 6339 assert(index == a); 6340 assert(arr1[index] == a); 6341 assert(arr2[index] == b); 6342 n--; 6343 } 6344 6345 auto arr3 = [4, 5]; 6346 n = 1; 6347 foreach_reverse (a, b; lockstep(arr1, arr3)) 6348 { 6349 assert(a == arr1[$-n] && b == arr3[$-n]); 6350 n++; 6351 } 6352 } 6353 6354 pure @safe unittest 6355 { 6356 import std.algorithm.iteration : filter; 6357 import std.conv : to; 6358 6359 // The filters are to make these the lowest common forward denominator ranges, 6360 // i.e. w/o ref return, random access, length, etc. 6361 auto foo = filter!"a"([1,2,3,4,5]); 6362 immutable bar = [6f,7f,8f,9f,10f].idup; 6363 auto l = lockstep(foo, bar); 6364 6365 // Should work twice. These are forward ranges with implicit save. 6366 foreach (i; 0 .. 2) 6367 { 6368 uint[] res1; 6369 float[] res2; 6370 6371 foreach (a, ref b; l) 6372 { 6373 res1 ~= a; 6374 res2 ~= b; 6375 } 6376 6377 assert(res1 == [1,2,3,4,5]); 6378 assert(res2 == [6,7,8,9,10]); 6379 assert(bar == [6f,7f,8f,9f,10f]); 6380 } 6381 6382 // Doc example. 6383 auto arr1 = [1,2,3,4,5]; 6384 auto arr2 = [6,7,8,9,10]; 6385 6386 foreach (ref a, ref b; lockstep(arr1, arr2)) 6387 { 6388 a += b; 6389 } 6390 6391 assert(arr1 == [7,9,11,13,15]); 6392 6393 // Make sure StoppingPolicy.requireSameLength doesn't throw. 6394 auto ls = lockstep(arr1, arr2, StoppingPolicy.requireSameLength); 6395 6396 int k = 1; 6397 foreach (a, b; ls) 6398 { 6399 assert(a - b == k); 6400 ++k; 6401 } 6402 6403 // Make sure StoppingPolicy.requireSameLength throws. 6404 arr2.popBack(); 6405 ls = lockstep(arr1, arr2, StoppingPolicy.requireSameLength); 6406 6407 try { 6408 foreach (a, b; ls) {} 6409 assert(0); 6410 } catch (Exception) {} 6411 6412 // Just make sure 1-range case instantiates. This hangs the compiler 6413 // when no explicit stopping policy is specified due to 6414 // https://issues.dlang.org/show_bug.cgi?id=4652 6415 auto stuff = lockstep([1,2,3,4,5], StoppingPolicy.shortest); 6416 foreach (i, a; stuff) 6417 { 6418 assert(stuff[i] == a); 6419 } 6420 6421 // Test with indexing. 6422 uint[] res1; 6423 float[] res2; 6424 size_t[] indices; 6425 foreach (i, a, b; lockstep(foo, bar)) 6426 { 6427 indices ~= i; 6428 res1 ~= a; 6429 res2 ~= b; 6430 } 6431 6432 assert(indices == to!(size_t[])([0, 1, 2, 3, 4])); 6433 assert(res1 == [1,2,3,4,5]); 6434 assert(res2 == [6f,7f,8f,9f,10f]); 6435 6436 // Make sure we've worked around the relevant compiler bugs and this at least 6437 // compiles w/ >2 ranges. 6438 lockstep(foo, foo, foo); 6439 6440 // Make sure it works with const. 6441 const(int[])[] foo2 = [[1, 2, 3]]; 6442 const(int[])[] bar2 = [[4, 5, 6]]; 6443 auto c = chain(foo2, bar2); 6444 6445 foreach (f, b; lockstep(c, c)) {} 6446 6447 // Regression 10468 6448 foreach (x, y; lockstep(iota(0, 10), iota(0, 10))) { } 6449 } 6450 6451 pure @safe unittest 6452 { 6453 struct RvalueRange 6454 { 6455 int[] impl; 6456 @property bool empty() { return impl.empty; } 6457 @property int front() { return impl[0]; } // N.B. non-ref 6458 void popFront() { impl.popFront(); } 6459 } 6460 auto data1 = [ 1, 2, 3, 4 ]; 6461 auto data2 = [ 5, 6, 7, 8 ]; 6462 auto r1 = RvalueRange(data1); 6463 auto r2 = data2; 6464 foreach (a, ref b; lockstep(r1, r2)) 6465 { 6466 a++; 6467 b++; 6468 } 6469 assert(data1 == [ 1, 2, 3, 4 ]); // changes to a do not propagate to data 6470 assert(data2 == [ 6, 7, 8, 9 ]); // but changes to b do. 6471 6472 // Since r1 is by-value only, the compiler should reject attempts to 6473 // foreach over it with ref. 6474 static assert(!__traits(compiles, { 6475 foreach (ref a, ref b; lockstep(r1, r2)) { a++; } 6476 })); 6477 } 6478 6479 private string lockstepReverseFailMixin(Ranges...)(bool withIndex) 6480 { 6481 import std.format : format; 6482 string[] params; 6483 string message; 6484 6485 if (withIndex) 6486 { 6487 message = "Indexed reverse iteration with lockstep is only supported" 6488 ~"if all ranges are bidirectional and have a length.\n"; 6489 } 6490 else 6491 { 6492 message = "Reverse iteration with lockstep is only supported if all ranges are bidirectional.\n"; 6493 } 6494 6495 if (withIndex) 6496 { 6497 params ~= "size_t"; 6498 } 6499 6500 foreach (idx, Range; Ranges) 6501 { 6502 params ~= format("%sElementType!(Ranges[%s])", hasLvalueElements!Range ? "ref " : "", idx); 6503 } 6504 6505 return format( 6506 q{ 6507 int opApplyReverse%sFail()(scope int delegate(%s) dg) 6508 { 6509 static assert(false, "%s"); 6510 } 6511 }, withIndex ? "Idx" : "" , params.join(", "), message); 6512 } 6513 6514 // For generic programming, make sure Lockstep!(Range) is well defined for a 6515 // single range. 6516 template Lockstep(Range) 6517 { 6518 alias Lockstep = Range; 6519 } 6520 6521 /** 6522 Creates a mathematical sequence given the initial values and a 6523 recurrence function that computes the next value from the existing 6524 values. The sequence comes in the form of an infinite forward 6525 range. The type `Recurrence` itself is seldom used directly; most 6526 often, recurrences are obtained by calling the function $(D 6527 recurrence). 6528 6529 When calling `recurrence`, the function that computes the next 6530 value is specified as a template argument, and the initial values in 6531 the recurrence are passed as regular arguments. For example, in a 6532 Fibonacci sequence, there are two initial values (and therefore a 6533 state size of 2) because computing the next Fibonacci value needs the 6534 past two values. 6535 6536 The signature of this function should be: 6537 ---- 6538 auto fun(R)(R state, size_t n) 6539 ---- 6540 where `n` will be the index of the current value, and `state` will be an 6541 opaque state vector that can be indexed with array-indexing notation 6542 `state[i]`, where valid values of `i` range from $(D (n - 1)) to 6543 $(D (n - State.length)). 6544 6545 If the function is passed in string form, the state has name `"a"` 6546 and the zero-based index in the recurrence has name `"n"`. The 6547 given string must return the desired value for `a[n]` given 6548 `a[n - 1]`, `a[n - 2]`, `a[n - 3]`,..., `a[n - stateSize]`. The 6549 state size is dictated by the number of arguments passed to the call 6550 to `recurrence`. The `Recurrence` struct itself takes care of 6551 managing the recurrence's state and shifting it appropriately. 6552 */ 6553 struct Recurrence(alias fun, StateType, size_t stateSize) 6554 { 6555 import std.functional : binaryFun; 6556 6557 StateType[stateSize] _state; 6558 size_t _n; 6559 6560 this(StateType[stateSize] initial) { _state = initial; } 6561 6562 void popFront() 6563 { 6564 static auto trustedCycle(ref typeof(_state) s) @trusted 6565 { 6566 return cycle(s); 6567 } 6568 // The cast here is reasonable because fun may cause integer 6569 // promotion, but needs to return a StateType to make its operation 6570 // closed. Therefore, we have no other choice. 6571 _state[_n % stateSize] = cast(StateType) binaryFun!(fun, "a", "n")( 6572 trustedCycle(_state), _n + stateSize); 6573 ++_n; 6574 } 6575 6576 @property StateType front() 6577 { 6578 return _state[_n % stateSize]; 6579 } 6580 6581 @property typeof(this) save() 6582 { 6583 return this; 6584 } 6585 6586 enum bool empty = false; 6587 } 6588 6589 /// 6590 pure @safe nothrow unittest 6591 { 6592 import std.algorithm.comparison : equal; 6593 6594 // The Fibonacci numbers, using function in string form: 6595 // a[0] = 1, a[1] = 1, and compute a[n+1] = a[n-1] + a[n] 6596 auto fib = recurrence!("a[n-1] + a[n-2]")(1, 1); 6597 assert(fib.take(10).equal([1, 1, 2, 3, 5, 8, 13, 21, 34, 55])); 6598 6599 // The factorials, using function in lambda form: 6600 auto fac = recurrence!((a,n) => a[n-1] * n)(1); 6601 assert(take(fac, 10).equal([ 6602 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880 6603 ])); 6604 6605 // The triangular numbers, using function in explicit form: 6606 static size_t genTriangular(R)(R state, size_t n) 6607 { 6608 return state[n-1] + n; 6609 } 6610 auto tri = recurrence!genTriangular(0); 6611 assert(take(tri, 10).equal([0, 1, 3, 6, 10, 15, 21, 28, 36, 45])); 6612 } 6613 6614 /// Ditto 6615 Recurrence!(fun, CommonType!(State), State.length) 6616 recurrence(alias fun, State...)(State initial) 6617 { 6618 CommonType!(State)[State.length] state; 6619 foreach (i, Unused; State) 6620 { 6621 state[i] = initial[i]; 6622 } 6623 return typeof(return)(state); 6624 } 6625 6626 pure @safe nothrow unittest 6627 { 6628 import std.algorithm.comparison : equal; 6629 6630 auto fib = recurrence!("a[n-1] + a[n-2]")(1, 1); 6631 static assert(isForwardRange!(typeof(fib))); 6632 6633 int[] witness = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55 ]; 6634 assert(equal(take(fib, 10), witness)); 6635 foreach (e; take(fib, 10)) {} 6636 auto fact = recurrence!("n * a[n-1]")(1); 6637 assert( equal(take(fact, 10), [1, 1, 2, 2*3, 2*3*4, 2*3*4*5, 2*3*4*5*6, 6638 2*3*4*5*6*7, 2*3*4*5*6*7*8, 2*3*4*5*6*7*8*9][]) ); 6639 auto piapprox = recurrence!("a[n] + (n & 1 ? 4.0 : -4.0) / (2 * n + 3)")(4.0); 6640 foreach (e; take(piapprox, 20)) {} 6641 // Thanks to yebblies for this test and the associated fix 6642 auto r = recurrence!"a[n-2]"(1, 2); 6643 witness = [1, 2, 1, 2, 1]; 6644 assert(equal(take(r, 5), witness)); 6645 } 6646 6647 /** 6648 `Sequence` is similar to `Recurrence` except that iteration is 6649 presented in the so-called $(HTTP en.wikipedia.org/wiki/Closed_form, 6650 closed form). This means that the `n`th element in the series is 6651 computable directly from the initial values and `n` itself. This 6652 implies that the interface offered by `Sequence` is a random-access 6653 range, as opposed to the regular `Recurrence`, which only offers 6654 forward iteration. 6655 6656 The state of the sequence is stored as a `Tuple` so it can be 6657 heterogeneous. 6658 */ 6659 struct Sequence(alias fun, State) 6660 { 6661 private: 6662 import std.functional : binaryFun; 6663 6664 alias compute = binaryFun!(fun, "a", "n"); 6665 alias ElementType = typeof(compute(State.init, cast(size_t) 1)); 6666 State _state; 6667 size_t _n; 6668 6669 static struct DollarToken{} 6670 6671 public: 6672 this(State initial, size_t n = 0) 6673 { 6674 _state = initial; 6675 _n = n; 6676 } 6677 6678 @property ElementType front() 6679 { 6680 return compute(_state, _n); 6681 } 6682 6683 void popFront() 6684 { 6685 ++_n; 6686 } 6687 6688 enum opDollar = DollarToken(); 6689 6690 auto opSlice(size_t lower, size_t upper) 6691 in 6692 { 6693 assert( 6694 upper >= lower, 6695 "Attempting to slice a Sequence with a larger first argument than the second." 6696 ); 6697 } 6698 do 6699 { 6700 return typeof(this)(_state, _n + lower).take(upper - lower); 6701 } 6702 6703 auto opSlice(size_t lower, DollarToken) 6704 { 6705 return typeof(this)(_state, _n + lower); 6706 } 6707 6708 ElementType opIndex(size_t n) 6709 { 6710 return compute(_state, n + _n); 6711 } 6712 6713 enum bool empty = false; 6714 6715 @property Sequence save() { return this; } 6716 } 6717 6718 /// Ditto 6719 auto sequence(alias fun, State...)(State args) 6720 { 6721 import std.typecons : Tuple, tuple; 6722 alias Return = Sequence!(fun, Tuple!State); 6723 return Return(tuple(args)); 6724 } 6725 6726 /// Odd numbers, using function in string form: 6727 pure @safe nothrow @nogc unittest 6728 { 6729 auto odds = sequence!("a[0] + n * a[1]")(1, 2); 6730 assert(odds.front == 1); 6731 odds.popFront(); 6732 assert(odds.front == 3); 6733 odds.popFront(); 6734 assert(odds.front == 5); 6735 } 6736 6737 /// Triangular numbers, using function in lambda form: 6738 pure @safe nothrow @nogc unittest 6739 { 6740 auto tri = sequence!((a,n) => n*(n+1)/2)(); 6741 6742 // Note random access 6743 assert(tri[0] == 0); 6744 assert(tri[3] == 6); 6745 assert(tri[1] == 1); 6746 assert(tri[4] == 10); 6747 assert(tri[2] == 3); 6748 } 6749 6750 /// Fibonacci numbers, using function in explicit form: 6751 @safe nothrow @nogc unittest 6752 { 6753 import std.math.exponential : pow; 6754 import std.math.rounding : round; 6755 import std.math.algebraic : sqrt; 6756 static ulong computeFib(S)(S state, size_t n) 6757 { 6758 // Binet's formula 6759 return cast(ulong)(round((pow(state[0], n+1) - pow(state[1], n+1)) / 6760 state[2])); 6761 } 6762 auto fib = sequence!computeFib( 6763 (1.0 + sqrt(5.0)) / 2.0, // Golden Ratio 6764 (1.0 - sqrt(5.0)) / 2.0, // Conjugate of Golden Ratio 6765 sqrt(5.0)); 6766 6767 // Note random access with [] operator 6768 assert(fib[1] == 1); 6769 assert(fib[4] == 5); 6770 assert(fib[3] == 3); 6771 assert(fib[2] == 2); 6772 assert(fib[9] == 55); 6773 } 6774 6775 pure @safe nothrow @nogc unittest 6776 { 6777 import std.typecons : Tuple, tuple; 6778 auto y = Sequence!("a[0] + n * a[1]", Tuple!(int, int))(tuple(0, 4)); 6779 static assert(isForwardRange!(typeof(y))); 6780 6781 //@@BUG 6782 //auto y = sequence!("a[0] + n * a[1]")(0, 4); 6783 //foreach (e; take(y, 15)) 6784 {} //writeln(e); 6785 6786 auto odds = Sequence!("a[0] + n * a[1]", Tuple!(int, int))( 6787 tuple(1, 2)); 6788 for (int currentOdd = 1; currentOdd <= 21; currentOdd += 2) 6789 { 6790 assert(odds.front == odds[0]); 6791 assert(odds[0] == currentOdd); 6792 odds.popFront(); 6793 } 6794 } 6795 6796 pure @safe nothrow @nogc unittest 6797 { 6798 import std.algorithm.comparison : equal; 6799 6800 auto odds = sequence!("a[0] + n * a[1]")(1, 2); 6801 static assert(hasSlicing!(typeof(odds))); 6802 6803 //Note: don't use drop or take as the target of an equal, 6804 //since they'll both just forward to opSlice, making the tests irrelevant 6805 6806 // static slicing tests 6807 assert(equal(odds[0 .. 5], only(1, 3, 5, 7, 9))); 6808 assert(equal(odds[3 .. 7], only(7, 9, 11, 13))); 6809 6810 // relative slicing test, testing slicing is NOT agnostic of state 6811 auto odds_less5 = odds.drop(5); //this should actually call odds[5 .. $] 6812 assert(equal(odds_less5[0 .. 3], only(11, 13, 15))); 6813 assert(equal(odds_less5[0 .. 10], odds[5 .. 15])); 6814 6815 //Infinite slicing tests 6816 odds = odds[10 .. $]; 6817 assert(equal(odds.take(3), only(21, 23, 25))); 6818 } 6819 6820 // https://issues.dlang.org/show_bug.cgi?id=5036 6821 pure @safe nothrow unittest 6822 { 6823 auto s = sequence!((a, n) => new int)(0); 6824 assert(s.front != s.front); // no caching 6825 } 6826 6827 // iota 6828 /** 6829 Creates a range of values that span the given starting and stopping 6830 values. 6831 6832 Params: 6833 begin = The starting value. 6834 end = The value that serves as the stopping criterion. This value is not 6835 included in the range. 6836 step = The value to add to the current value at each iteration. 6837 6838 Returns: 6839 A range that goes through the numbers `begin`, $(D begin + step), 6840 $(D begin + 2 * step), `...`, up to and excluding `end`. 6841 6842 The two-argument overloads have $(D step = 1). If $(D begin < end && step < 6843 0) or $(D begin > end && step > 0) or $(D begin == end), then an empty range 6844 is returned. If $(D step == 0) then $(D begin == end) is an error. 6845 6846 For built-in types, the range returned is a random access range. For 6847 user-defined types that support `++`, the range is an input 6848 range. 6849 6850 $(DDOC_SECTION_H `in` operator and `contains`:) 6851 `iota` over an integral/pointer type defines the `in` operator from the right. 6852 `val in iota(...)` is true when `val` occurs in the range. When present, it takes 6853 `step` into account - `val` won't be considered 6854 contained if it falls between two consecutive elements of the range. 6855 The `contains` method does the same as `in`, but from the left-hand side. 6856 6857 Example: 6858 $(RUNNABLE_EXAMPLE 6859 --- 6860 void main() 6861 { 6862 import std.stdio; 6863 6864 // The following groups all produce the same output of: 6865 // 0 1 2 3 4 6866 6867 foreach (i; 0 .. 5) 6868 writef("%s ", i); 6869 writeln(); 6870 6871 import std.range : iota; 6872 foreach (i; iota(0, 5)) 6873 writef("%s ", i); 6874 writeln(); 6875 6876 writefln("%(%s %|%)", iota(0, 5)); 6877 6878 import std.algorithm.iteration : map; 6879 import std.algorithm.mutation : copy; 6880 import std.format; 6881 iota(0, 5).map!(i => format("%s ", i)).copy(stdout.lockingTextWriter()); 6882 writeln(); 6883 } 6884 --- 6885 ) 6886 */ 6887 auto iota(B, E, S)(B begin, E end, S step) 6888 if ((isIntegral!(CommonType!(B, E)) || isPointer!(CommonType!(B, E))) 6889 && isIntegral!S) 6890 { 6891 import std.conv : unsigned; 6892 6893 alias Value = CommonType!(Unqual!B, Unqual!E); 6894 alias StepType = Unqual!S; 6895 6896 assert(step != 0 || begin == end); 6897 6898 static struct Result 6899 { 6900 private Value current, last; 6901 private StepType step; // by convention, 0 if range is empty 6902 6903 this(Value current, Value pastLast, StepType step) 6904 { 6905 if (current < pastLast && step > 0) 6906 { 6907 // Iterating upward 6908 assert(unsigned((pastLast - current) / step) <= size_t.max); 6909 // Cast below can't fail because current < pastLast 6910 this.last = cast(Value) (pastLast - 1); 6911 this.last -= unsigned(this.last - current) % step; 6912 } 6913 else if (current > pastLast && step < 0) 6914 { 6915 // Iterating downward 6916 assert(unsigned((current - pastLast) / (0 - step)) <= size_t.max); 6917 // Cast below can't fail because current > pastLast 6918 this.last = cast(Value) (pastLast + 1); 6919 this.last += unsigned(current - this.last) % (0 - step); 6920 } 6921 else 6922 { 6923 // Initialize an empty range 6924 this.step = 0; 6925 return; 6926 } 6927 this.step = step; 6928 this.current = current; 6929 } 6930 6931 @property bool empty() const { return step == 0; } 6932 @property inout(Value) front() inout { assert(!empty); return current; } 6933 void popFront() 6934 { 6935 assert(!empty); 6936 if (current == last) step = 0; 6937 else current += step; 6938 } 6939 6940 @property inout(Value) back() inout 6941 { 6942 assert(!empty); 6943 return last; 6944 } 6945 void popBack() 6946 { 6947 assert(!empty); 6948 if (current == last) step = 0; 6949 else last -= step; 6950 } 6951 6952 @property auto save() { return this; } 6953 6954 inout(Value) opIndex(ulong n) inout 6955 { 6956 assert(n < this.length); 6957 6958 // Just cast to Value here because doing so gives overflow behavior 6959 // consistent with calling popFront() n times. 6960 return cast(inout Value) (current + step * n); 6961 } 6962 auto opBinaryRight(string op)(Value val) const 6963 if (op == "in") 6964 { 6965 if (empty) return false; 6966 //cast to avoid becoming unsigned 6967 auto supposedIndex = cast(StepType)(val - current) / step; 6968 return supposedIndex < length && supposedIndex * step + current == val; 6969 } 6970 auto contains(Value x){return x in this;} 6971 inout(Result) opSlice() inout { return this; } 6972 inout(Result) opSlice(ulong lower, ulong upper) inout 6973 { 6974 assert(upper >= lower && upper <= this.length); 6975 6976 return cast(inout Result) Result( 6977 cast(Value)(current + lower * step), 6978 cast(Value)(current + upper * step), 6979 step); 6980 } 6981 @property size_t length() const 6982 { 6983 if (step > 0) 6984 return 1 + cast(size_t) (unsigned(last - current) / step); 6985 if (step < 0) 6986 return 1 + cast(size_t) (unsigned(current - last) / (0 - step)); 6987 return 0; 6988 } 6989 6990 alias opDollar = length; 6991 } 6992 6993 return Result(begin, end, step); 6994 } 6995 6996 /// Ditto 6997 auto iota(B, E)(B begin, E end) 6998 if (isFloatingPoint!(CommonType!(B, E))) 6999 { 7000 return iota(begin, end, CommonType!(B, E)(1)); 7001 } 7002 7003 /// Ditto 7004 auto iota(B, E)(B begin, E end) 7005 if (isIntegral!(CommonType!(B, E)) || isPointer!(CommonType!(B, E))) 7006 { 7007 import std.conv : unsigned; 7008 7009 alias Value = CommonType!(Unqual!B, Unqual!E); 7010 7011 static struct Result 7012 { 7013 private Value current, pastLast; 7014 7015 this(Value current, Value pastLast) 7016 { 7017 if (current < pastLast) 7018 { 7019 assert(unsigned(pastLast - current) <= size_t.max, 7020 "`iota` range is too long"); 7021 7022 this.current = current; 7023 this.pastLast = pastLast; 7024 } 7025 else 7026 { 7027 // Initialize an empty range 7028 this.current = this.pastLast = current; 7029 } 7030 } 7031 7032 @property bool empty() const { return current == pastLast; } 7033 @property inout(Value) front() inout 7034 { 7035 assert(!empty, "Attempt to access `front` of empty `iota` range"); 7036 return current; 7037 } 7038 void popFront() 7039 { 7040 assert(!empty, "Attempt to `popFront` of empty `iota` range"); 7041 ++current; 7042 } 7043 7044 @property inout(Value) back() inout 7045 { 7046 assert(!empty, "Attempt to access `back` of empty `iota` range"); 7047 return cast(inout(Value))(pastLast - 1); 7048 } 7049 void popBack() 7050 { 7051 assert(!empty, "Attempt to `popBack` of empty `iota` range"); 7052 --pastLast; 7053 } 7054 7055 @property auto save() { return this; } 7056 7057 inout(Value) opIndex(size_t n) inout 7058 { 7059 assert(n < this.length, 7060 "Attempt to read out-of-bounds index of `iota` range"); 7061 7062 // Just cast to Value here because doing so gives overflow behavior 7063 // consistent with calling popFront() n times. 7064 return cast(inout Value) (current + n); 7065 } 7066 auto opBinaryRight(string op)(Value val) const 7067 if (op == "in") 7068 { 7069 return current <= val && val < pastLast; 7070 } 7071 auto contains(Value x){return x in this;} 7072 inout(Result) opSlice() inout { return this; } 7073 inout(Result) opSlice(ulong lower, ulong upper) inout 7074 { 7075 assert(upper >= lower && upper <= this.length, 7076 "Attempt to get out-of-bounds slice of `iota` range"); 7077 7078 return cast(inout Result) Result(cast(Value)(current + lower), 7079 cast(Value)(pastLast - (length - upper))); 7080 } 7081 @property size_t length() const 7082 { 7083 return cast(size_t)(pastLast - current); 7084 } 7085 7086 alias opDollar = length; 7087 } 7088 7089 return Result(begin, end); 7090 } 7091 7092 /// Ditto 7093 auto iota(E)(E end) 7094 if (is(typeof(iota(E(0), end)))) 7095 { 7096 E begin = E(0); 7097 return iota(begin, end); 7098 } 7099 7100 /// Ditto 7101 // Specialization for floating-point types 7102 auto iota(B, E, S)(B begin, E end, S step) 7103 if (isFloatingPoint!(CommonType!(B, E, S))) 7104 in 7105 { 7106 assert(step != 0, "iota: step must not be 0"); 7107 assert((end - begin) / step >= 0, "iota: incorrect startup parameters"); 7108 } 7109 do 7110 { 7111 alias Value = Unqual!(CommonType!(B, E, S)); 7112 static struct Result 7113 { 7114 private Value start, step; 7115 private size_t index, count; 7116 7117 this(Value start, Value end, Value step) 7118 { 7119 import std.conv : to; 7120 7121 this.start = start; 7122 this.step = step; 7123 immutable fcount = (end - start) / step; 7124 count = to!size_t(fcount); 7125 auto pastEnd = start + count * step; 7126 if (step > 0) 7127 { 7128 if (pastEnd < end) ++count; 7129 assert(start + count * step >= end); 7130 } 7131 else 7132 { 7133 if (pastEnd > end) ++count; 7134 assert(start + count * step <= end); 7135 } 7136 } 7137 7138 @property bool empty() const { return index == count; } 7139 @property Value front() const { assert(!empty); return start + step * index; } 7140 void popFront() 7141 { 7142 assert(!empty); 7143 ++index; 7144 } 7145 @property Value back() const 7146 { 7147 assert(!empty); 7148 return start + step * (count - 1); 7149 } 7150 void popBack() 7151 { 7152 assert(!empty); 7153 --count; 7154 } 7155 7156 @property auto save() { return this; } 7157 7158 Value opIndex(size_t n) const 7159 { 7160 assert(n < count); 7161 return start + step * (n + index); 7162 } 7163 inout(Result) opSlice() inout 7164 { 7165 return this; 7166 } 7167 inout(Result) opSlice(size_t lower, size_t upper) inout 7168 { 7169 assert(upper >= lower && upper <= count); 7170 7171 Result ret = this; 7172 ret.index += lower; 7173 ret.count = upper - lower + ret.index; 7174 return cast(inout Result) ret; 7175 } 7176 @property size_t length() const 7177 { 7178 return count - index; 7179 } 7180 7181 alias opDollar = length; 7182 } 7183 7184 return Result(begin, end, step); 7185 } 7186 7187 /// 7188 pure @safe unittest 7189 { 7190 import std.algorithm.comparison : equal; 7191 import std.math.operations : isClose; 7192 7193 auto r = iota(0, 10, 1); 7194 assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])); 7195 assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])); 7196 assert(3 in r); 7197 assert(r.contains(3)); //Same as above 7198 assert(!(10 in r)); 7199 assert(!(-8 in r)); 7200 r = iota(0, 11, 3); 7201 assert(equal(r, [0, 3, 6, 9])); 7202 assert(r[2] == 6); 7203 assert(!(2 in r)); 7204 auto rf = iota(0.0, 0.5, 0.1); 7205 assert(isClose(rf, [0.0, 0.1, 0.2, 0.3, 0.4])); 7206 } 7207 7208 pure nothrow @nogc @safe unittest 7209 { 7210 import std.traits : Signed; 7211 //float overloads use std.conv.to so can't be @nogc or nothrow 7212 alias ssize_t = Signed!size_t; 7213 assert(iota(ssize_t.max, 0, -1).length == ssize_t.max); 7214 assert(iota(ssize_t.max, ssize_t.min, -1).length == size_t.max); 7215 assert(iota(ssize_t.max, ssize_t.min, -2).length == 1 + size_t.max / 2); 7216 assert(iota(ssize_t.min, ssize_t.max, 2).length == 1 + size_t.max / 2); 7217 assert(iota(ssize_t.max, ssize_t.min, -3).length == size_t.max / 3); 7218 } 7219 7220 debug @system unittest 7221 {//check the contracts 7222 import core.exception : AssertError; 7223 import std.exception : assertThrown; 7224 assertThrown!AssertError(iota(1,2,0)); 7225 assertThrown!AssertError(iota(0f,1f,0f)); 7226 assertThrown!AssertError(iota(1f,0f,0.1f)); 7227 assertThrown!AssertError(iota(0f,1f,-0.1f)); 7228 } 7229 7230 pure @system nothrow unittest 7231 { 7232 int[] a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; 7233 auto r1 = iota(a.ptr, a.ptr + a.length, 1); 7234 assert(r1.front == a.ptr); 7235 assert(r1.back == a.ptr + a.length - 1); 7236 assert(&a[4] in r1); 7237 } 7238 7239 pure @safe nothrow @nogc unittest 7240 { 7241 assert(iota(1UL, 0UL).length == 0); 7242 assert(iota(1UL, 0UL, 1).length == 0); 7243 assert(iota(0, 1, 1).length == 1); 7244 assert(iota(1, 0, -1).length == 1); 7245 assert(iota(0, 1, -1).length == 0); 7246 assert(iota(ulong.max, 0).length == 0); 7247 } 7248 7249 pure @safe unittest 7250 { 7251 import std.algorithm.comparison : equal; 7252 import std.algorithm.searching : count; 7253 import std.math.operations : isClose, nextUp, nextDown; 7254 import std.meta : AliasSeq; 7255 7256 static assert(is(ElementType!(typeof(iota(0f))) == float)); 7257 7258 static assert(hasLength!(typeof(iota(0, 2)))); 7259 auto r = iota(0, 10, 1); 7260 assert(r[$ - 1] == 9); 7261 assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][])); 7262 7263 auto rSlice = r[2 .. 8]; 7264 assert(equal(rSlice, [2, 3, 4, 5, 6, 7])); 7265 7266 rSlice.popFront(); 7267 assert(rSlice[0] == rSlice.front); 7268 assert(rSlice.front == 3); 7269 7270 rSlice.popBack(); 7271 assert(rSlice[rSlice.length - 1] == rSlice.back); 7272 assert(rSlice.back == 6); 7273 7274 rSlice = r[0 .. 4]; 7275 assert(equal(rSlice, [0, 1, 2, 3])); 7276 assert(3 in rSlice); 7277 assert(!(4 in rSlice)); 7278 7279 auto rr = iota(10); 7280 assert(equal(rr, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][])); 7281 7282 r = iota(0, -10, -1); 7283 assert(equal(r, [0, -1, -2, -3, -4, -5, -6, -7, -8, -9][])); 7284 rSlice = r[3 .. 9]; 7285 assert(equal(rSlice, [-3, -4, -5, -6, -7, -8])); 7286 7287 r = iota(0, -6, -3); 7288 assert(equal(r, [0, -3][])); 7289 rSlice = r[1 .. 2]; 7290 assert(equal(rSlice, [-3])); 7291 7292 r = iota(0, -7, -3); 7293 assert(equal(r, [0, -3, -6][])); 7294 assert(0 in r); 7295 assert(-6 in r); 7296 rSlice = r[1 .. 3]; 7297 assert(equal(rSlice, [-3, -6])); 7298 assert(!(0 in rSlice)); 7299 assert(!(-2 in rSlice)); 7300 assert(!(-5 in rSlice)); 7301 assert(!(3 in rSlice)); 7302 assert(!(-9 in rSlice)); 7303 7304 r = iota(0, 11, 3); 7305 assert(equal(r, [0, 3, 6, 9][])); 7306 assert(r[2] == 6); 7307 rSlice = r[1 .. 3]; 7308 assert(equal(rSlice, [3, 6])); 7309 7310 auto rf = iota(0.0, 0.5, 0.1); 7311 assert(isClose(rf, [0.0, 0.1, 0.2, 0.3, 0.4][])); 7312 assert(rf.length == 5); 7313 7314 rf.popFront(); 7315 assert(rf.length == 4); 7316 7317 auto rfSlice = rf[1 .. 4]; 7318 assert(rfSlice.length == 3); 7319 assert(isClose(rfSlice, [0.2, 0.3, 0.4])); 7320 7321 rfSlice.popFront(); 7322 assert(isClose(rfSlice[0], 0.3)); 7323 7324 rf.popFront(); 7325 assert(rf.length == 3); 7326 7327 rfSlice = rf[1 .. 3]; 7328 assert(rfSlice.length == 2); 7329 assert(isClose(rfSlice, [0.3, 0.4])); 7330 assert(isClose(rfSlice[0], 0.3)); 7331 7332 // With something just above 0.5 7333 rf = iota(0.0, nextUp(0.5), 0.1); 7334 assert(isClose(rf, [0.0, 0.1, 0.2, 0.3, 0.4, 0.5][])); 7335 rf.popBack(); 7336 assert(rf[rf.length - 1] == rf.back); 7337 assert(isClose(rf.back, 0.4)); 7338 assert(rf.length == 5); 7339 7340 // going down 7341 rf = iota(0.0, -0.5, -0.1); 7342 assert(isClose(rf, [0.0, -0.1, -0.2, -0.3, -0.4][])); 7343 rfSlice = rf[2 .. 5]; 7344 assert(isClose(rfSlice, [-0.2, -0.3, -0.4])); 7345 7346 rf = iota(0.0, nextDown(-0.5), -0.1); 7347 assert(isClose(rf, [0.0, -0.1, -0.2, -0.3, -0.4, -0.5][])); 7348 7349 // iota of longs 7350 auto rl = iota(5_000_000L); 7351 assert(rl.length == 5_000_000L); 7352 assert(0 in rl); 7353 assert(4_000_000L in rl); 7354 assert(!(-4_000_000L in rl)); 7355 assert(!(5_000_000L in rl)); 7356 7357 // iota of longs with steps 7358 auto iota_of_longs_with_steps = iota(50L, 101L, 10); 7359 assert(iota_of_longs_with_steps.length == 6); 7360 assert(equal(iota_of_longs_with_steps, [50L, 60L, 70L, 80L, 90L, 100L])); 7361 7362 // iota of unsigned zero length (https://issues.dlang.org/show_bug.cgi?id=6222) 7363 // Actually trying to consume it is the only way to find something is wrong 7364 // because the public properties are all correct. 7365 auto iota_zero_unsigned = iota(0, 0u, 3); 7366 assert(count(iota_zero_unsigned) == 0); 7367 7368 // https://issues.dlang.org/show_bug.cgi?id=7982 7369 // unsigned reverse iota can be buggy if `.length` doesn't 7370 // take them into account 7371 assert(iota(10u, 0u, -1).length == 10); 7372 assert(iota(10u, 0u, -2).length == 5); 7373 assert(iota(uint.max, uint.max-10, -1).length == 10); 7374 assert(iota(uint.max, uint.max-10, -2).length == 5); 7375 assert(iota(uint.max, 0u, -1).length == uint.max); 7376 7377 assert(20 in iota(20u, 10u, -2)); 7378 assert(16 in iota(20u, 10u, -2)); 7379 assert(!(15 in iota(20u, 10u, -2))); 7380 assert(!(10 in iota(20u, 10u, -2))); 7381 assert(!(uint.max in iota(20u, 10u, -1))); 7382 assert(!(int.min in iota(20u, 10u, -1))); 7383 assert(!(int.max in iota(20u, 10u, -1))); 7384 7385 7386 // https://issues.dlang.org/show_bug.cgi?id=8920 7387 static foreach (Type; AliasSeq!(byte, ubyte, short, ushort, 7388 int, uint, long, ulong)) 7389 {{ 7390 Type val; 7391 foreach (i; iota(cast(Type) 0, cast(Type) 10)) { val++; } 7392 assert(val == 10); 7393 }} 7394 } 7395 7396 pure @safe nothrow unittest 7397 { 7398 import std.algorithm.mutation : copy; 7399 auto idx = new size_t[100]; 7400 copy(iota(0, idx.length), idx); 7401 } 7402 7403 @safe unittest 7404 { 7405 import std.meta : AliasSeq; 7406 static foreach (range; AliasSeq!(iota(2, 27, 4), 7407 iota(3, 9), 7408 iota(2.7, 12.3, .1), 7409 iota(3.2, 9.7))) 7410 {{ 7411 const cRange = range; 7412 const e = cRange.empty; 7413 const f = cRange.front; 7414 const b = cRange.back; 7415 const i = cRange[2]; 7416 const s1 = cRange[]; 7417 const s2 = cRange[0 .. 3]; 7418 const l = cRange.length; 7419 }} 7420 } 7421 7422 @system unittest 7423 { 7424 //The ptr stuff can't be done at compile time, so we unfortunately end 7425 //up with some code duplication here. 7426 auto arr = [0, 5, 3, 5, 5, 7, 9, 2, 0, 42, 7, 6]; 7427 7428 { 7429 const cRange = iota(arr.ptr, arr.ptr + arr.length, 3); 7430 const e = cRange.empty; 7431 const f = cRange.front; 7432 const b = cRange.back; 7433 const i = cRange[2]; 7434 const s1 = cRange[]; 7435 const s2 = cRange[0 .. 3]; 7436 const l = cRange.length; 7437 } 7438 7439 { 7440 const cRange = iota(arr.ptr, arr.ptr + arr.length); 7441 const e = cRange.empty; 7442 const f = cRange.front; 7443 const b = cRange.back; 7444 const i = cRange[2]; 7445 const s1 = cRange[]; 7446 const s2 = cRange[0 .. 3]; 7447 const l = cRange.length; 7448 } 7449 } 7450 7451 @nogc nothrow pure @safe unittest 7452 { 7453 { 7454 ushort start = 0, end = 10, step = 2; 7455 foreach (i; iota(start, end, step)) 7456 static assert(is(typeof(i) == ushort)); 7457 } 7458 { 7459 ubyte start = 0, end = 255, step = 128; 7460 uint x; 7461 foreach (i; iota(start, end, step)) 7462 { 7463 static assert(is(typeof(i) == ubyte)); 7464 ++x; 7465 } 7466 assert(x == 2); 7467 } 7468 } 7469 7470 /* Generic overload that handles arbitrary types that support arithmetic 7471 * operations. 7472 * 7473 * User-defined types such as $(REF BigInt, std,bigint) are also supported, as long 7474 * as they can be incremented with `++` and compared with `<` or `==`. 7475 */ 7476 /// ditto 7477 auto iota(B, E)(B begin, E end) 7478 if (!isIntegral!(CommonType!(B, E)) && 7479 !isFloatingPoint!(CommonType!(B, E)) && 7480 !isPointer!(CommonType!(B, E)) && 7481 is(typeof((ref B b) { ++b; })) && 7482 (is(typeof(B.init < E.init)) || is(typeof(B.init == E.init))) ) 7483 { 7484 static struct Result 7485 { 7486 B current; 7487 E end; 7488 7489 @property bool empty() 7490 { 7491 static if (is(typeof(B.init < E.init))) 7492 return !(current < end); 7493 else static if (is(typeof(B.init != E.init))) 7494 return current == end; 7495 else 7496 static assert(0); 7497 } 7498 @property auto front() { return current; } 7499 void popFront() 7500 { 7501 assert(!empty); 7502 ++current; 7503 } 7504 @property auto save() { return this; } 7505 } 7506 return Result(begin, end); 7507 } 7508 7509 @safe unittest 7510 { 7511 import std.algorithm.comparison : equal; 7512 7513 // Test iota() for a type that only supports ++ and != but does not have 7514 // '<'-ordering. 7515 struct Cyclic(int wrapAround) 7516 { 7517 int current; 7518 7519 this(int start) { current = start % wrapAround; } 7520 7521 bool opEquals(Cyclic c) const { return current == c.current; } 7522 bool opEquals(int i) const { return current == i; } 7523 void opUnary(string op)() 7524 if (op == "++") 7525 { 7526 current = (current + 1) % wrapAround; 7527 } 7528 } 7529 alias Cycle5 = Cyclic!5; 7530 7531 // Easy case 7532 auto i1 = iota(Cycle5(1), Cycle5(4)); 7533 assert(i1.equal([1, 2, 3])); 7534 7535 // Wraparound case 7536 auto i2 = iota(Cycle5(3), Cycle5(2)); 7537 assert(i2.equal([3, 4, 0, 1 ])); 7538 } 7539 7540 // https://issues.dlang.org/show_bug.cgi?id=23453 7541 @safe unittest 7542 { 7543 auto r = iota('a', 'z'); 7544 static assert(isForwardRange!(typeof(r))); 7545 } 7546 7547 /** 7548 Options for the $(LREF FrontTransversal) and $(LREF Transversal) ranges 7549 (below). 7550 */ 7551 enum TransverseOptions 7552 { 7553 /** 7554 When transversed, the elements of a range of ranges are assumed to 7555 have different lengths (e.g. a jagged array). 7556 */ 7557 assumeJagged, //default 7558 /** 7559 The transversal enforces that the elements of a range of ranges have 7560 all the same length (e.g. an array of arrays, all having the same 7561 length). Checking is done once upon construction of the transversal 7562 range. 7563 */ 7564 enforceNotJagged, 7565 /** 7566 The transversal assumes, without verifying, that the elements of a 7567 range of ranges have all the same length. This option is useful if 7568 checking was already done from the outside of the range. 7569 */ 7570 assumeNotJagged, 7571 } 7572 7573 /// 7574 @safe pure unittest 7575 { 7576 import std.algorithm.comparison : equal; 7577 import std.exception : assertThrown; 7578 7579 auto arr = [[1, 2], [3, 4, 5]]; 7580 7581 auto r1 = arr.frontTransversal!(TransverseOptions.assumeJagged); 7582 assert(r1.equal([1, 3])); 7583 7584 // throws on construction 7585 assertThrown!Exception(arr.frontTransversal!(TransverseOptions.enforceNotJagged)); 7586 7587 auto r2 = arr.frontTransversal!(TransverseOptions.assumeNotJagged); 7588 assert(r2.equal([1, 3])); 7589 7590 // either assuming or checking for equal lengths makes 7591 // the result a random access range 7592 assert(r2[0] == 1); 7593 static assert(!__traits(compiles, r1[0])); 7594 } 7595 7596 /** 7597 Given a range of ranges, iterate transversally through the first 7598 elements of each of the enclosed ranges. 7599 */ 7600 struct FrontTransversal(Ror, 7601 TransverseOptions opt = TransverseOptions.assumeJagged) 7602 { 7603 alias RangeOfRanges = Unqual!(Ror); 7604 alias RangeType = .ElementType!RangeOfRanges; 7605 alias ElementType = .ElementType!RangeType; 7606 7607 private void prime() 7608 { 7609 static if (opt == TransverseOptions.assumeJagged) 7610 { 7611 while (!_input.empty && _input.front.empty) 7612 { 7613 _input.popFront(); 7614 } 7615 static if (isBidirectionalRange!RangeOfRanges) 7616 { 7617 while (!_input.empty && _input.back.empty) 7618 { 7619 _input.popBack(); 7620 } 7621 } 7622 } 7623 } 7624 7625 /** 7626 Construction from an input. 7627 */ 7628 this(RangeOfRanges input) 7629 { 7630 _input = input; 7631 prime(); 7632 static if (opt == TransverseOptions.enforceNotJagged) 7633 // (isRandomAccessRange!RangeOfRanges 7634 // && hasLength!RangeType) 7635 { 7636 import std.exception : enforce; 7637 7638 if (empty) return; 7639 immutable commonLength = _input.front.length; 7640 foreach (e; _input) 7641 { 7642 enforce(e.length == commonLength); 7643 } 7644 } 7645 } 7646 7647 /** 7648 Forward range primitives. 7649 */ 7650 static if (isInfinite!RangeOfRanges) 7651 { 7652 enum bool empty = false; 7653 } 7654 else 7655 { 7656 @property bool empty() 7657 { 7658 static if (opt != TransverseOptions.assumeJagged) 7659 { 7660 if (!_input.empty) 7661 return _input.front.empty; 7662 } 7663 7664 return _input.empty; 7665 } 7666 } 7667 7668 /// Ditto 7669 @property auto ref front() 7670 { 7671 assert(!empty, "Attempting to fetch the front of an empty FrontTransversal"); 7672 return _input.front.front; 7673 } 7674 7675 /// Ditto 7676 static if (hasMobileElements!RangeType) 7677 { 7678 ElementType moveFront() 7679 { 7680 return _input.front.moveFront(); 7681 } 7682 } 7683 7684 static if (hasAssignableElements!RangeType) 7685 { 7686 @property void front(ElementType val) 7687 { 7688 import core.lifetime : forward; 7689 7690 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542 7691 _input.front.front = __ctfe ? val : forward!val; 7692 } 7693 } 7694 7695 /// Ditto 7696 void popFront() 7697 { 7698 assert(!empty, "Attempting to popFront an empty FrontTransversal"); 7699 _input.popFront(); 7700 prime(); 7701 } 7702 7703 /** 7704 Duplicates this `frontTransversal`. Note that only the encapsulating 7705 range of range will be duplicated. Underlying ranges will not be 7706 duplicated. 7707 */ 7708 static if (isForwardRange!RangeOfRanges) 7709 { 7710 @property FrontTransversal save() 7711 { 7712 return FrontTransversal(_input.save); 7713 } 7714 } 7715 7716 static if (isBidirectionalRange!RangeOfRanges) 7717 { 7718 /** 7719 Bidirectional primitives. They are offered if $(D 7720 isBidirectionalRange!RangeOfRanges). 7721 */ 7722 @property auto ref back() 7723 { 7724 assert(!empty, "Attempting to fetch the back of an empty FrontTransversal"); 7725 return _input.back.front; 7726 } 7727 /// Ditto 7728 void popBack() 7729 { 7730 assert(!empty, "Attempting to popBack an empty FrontTransversal"); 7731 _input.popBack(); 7732 prime(); 7733 } 7734 7735 /// Ditto 7736 static if (hasMobileElements!RangeType) 7737 { 7738 ElementType moveBack() 7739 { 7740 return _input.back.moveFront(); 7741 } 7742 } 7743 7744 static if (hasAssignableElements!RangeType) 7745 { 7746 @property void back(ElementType val) 7747 { 7748 import core.lifetime : forward; 7749 7750 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542 7751 _input.back.front = __ctfe ? val : forward!val; 7752 } 7753 } 7754 } 7755 7756 static if (isRandomAccessRange!RangeOfRanges && 7757 (opt == TransverseOptions.assumeNotJagged || 7758 opt == TransverseOptions.enforceNotJagged)) 7759 { 7760 /** 7761 Random-access primitive. It is offered if $(D 7762 isRandomAccessRange!RangeOfRanges && (opt == 7763 TransverseOptions.assumeNotJagged || opt == 7764 TransverseOptions.enforceNotJagged)). 7765 */ 7766 auto ref opIndex(size_t n) 7767 { 7768 return _input[n].front; 7769 } 7770 7771 /// Ditto 7772 static if (hasMobileElements!RangeType) 7773 { 7774 ElementType moveAt(size_t n) 7775 { 7776 return _input[n].moveFront(); 7777 } 7778 } 7779 /// Ditto 7780 static if (hasAssignableElements!RangeType) 7781 { 7782 void opIndexAssign(ElementType val, size_t n) 7783 { 7784 import core.lifetime : forward; 7785 7786 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542 7787 _input[n].front = __ctfe ? val : forward!val; 7788 } 7789 } 7790 mixin ImplementLength!_input; 7791 7792 /** 7793 Slicing if offered if `RangeOfRanges` supports slicing and all the 7794 conditions for supporting indexing are met. 7795 */ 7796 static if (hasSlicing!RangeOfRanges) 7797 { 7798 typeof(this) opSlice(size_t lower, size_t upper) 7799 { 7800 return typeof(this)(_input[lower .. upper]); 7801 } 7802 } 7803 } 7804 7805 auto opSlice() { return this; } 7806 7807 private: 7808 RangeOfRanges _input; 7809 } 7810 7811 /// Ditto 7812 FrontTransversal!(RangeOfRanges, opt) frontTransversal( 7813 TransverseOptions opt = TransverseOptions.assumeJagged, 7814 RangeOfRanges) 7815 (RangeOfRanges rr) 7816 { 7817 return typeof(return)(rr); 7818 } 7819 7820 /// 7821 pure @safe nothrow unittest 7822 { 7823 import std.algorithm.comparison : equal; 7824 int[][] x = new int[][2]; 7825 x[0] = [1, 2]; 7826 x[1] = [3, 4]; 7827 auto ror = frontTransversal(x); 7828 assert(equal(ror, [ 1, 3 ][])); 7829 } 7830 7831 @safe unittest 7832 { 7833 import std.algorithm.comparison : equal; 7834 import std.internal.test.dummyrange : AllDummyRanges, DummyRange, ReturnBy; 7835 7836 static assert(is(FrontTransversal!(immutable int[][]))); 7837 7838 foreach (DummyType; AllDummyRanges) 7839 { 7840 auto dummies = 7841 [DummyType.init, DummyType.init, DummyType.init, DummyType.init]; 7842 7843 foreach (i, ref elem; dummies) 7844 { 7845 // Just violate the DummyRange abstraction to get what I want. 7846 elem.arr = elem.arr[i..$ - (3 - i)]; 7847 } 7848 7849 auto ft = frontTransversal!(TransverseOptions.assumeNotJagged)(dummies); 7850 static if (isForwardRange!DummyType) 7851 { 7852 static assert(isForwardRange!(typeof(ft))); 7853 } 7854 7855 assert(equal(ft, [1, 2, 3, 4])); 7856 7857 // Test slicing. 7858 assert(equal(ft[0 .. 2], [1, 2])); 7859 assert(equal(ft[1 .. 3], [2, 3])); 7860 7861 assert(ft.front == ft.moveFront()); 7862 assert(ft.back == ft.moveBack()); 7863 assert(ft.moveAt(1) == ft[1]); 7864 7865 7866 // Test infiniteness propagation. 7867 static assert(isInfinite!(typeof(frontTransversal(repeat("foo"))))); 7868 7869 static if (DummyType.r == ReturnBy.Reference) 7870 { 7871 { 7872 ft.front++; 7873 scope(exit) ft.front--; 7874 assert(dummies.front.front == 2); 7875 } 7876 7877 { 7878 ft.front = 5; 7879 scope(exit) ft.front = 1; 7880 assert(dummies[0].front == 5); 7881 } 7882 7883 { 7884 ft.back = 88; 7885 scope(exit) ft.back = 4; 7886 assert(dummies.back.front == 88); 7887 } 7888 7889 { 7890 ft[1] = 99; 7891 scope(exit) ft[1] = 2; 7892 assert(dummies[1].front == 99); 7893 } 7894 } 7895 } 7896 } 7897 7898 // https://issues.dlang.org/show_bug.cgi?id=16363 7899 pure @safe nothrow unittest 7900 { 7901 import std.algorithm.comparison : equal; 7902 7903 int[][] darr = [[0, 1], [4, 5]]; 7904 auto ft = frontTransversal!(TransverseOptions.assumeNotJagged)(darr); 7905 7906 assert(equal(ft, [0, 4])); 7907 static assert(isRandomAccessRange!(typeof(ft))); 7908 } 7909 7910 // https://issues.dlang.org/show_bug.cgi?id=16442 7911 pure @safe nothrow unittest 7912 { 7913 int[][] arr = [[], []]; 7914 7915 auto ft = frontTransversal!(TransverseOptions.assumeNotJagged)(arr); 7916 assert(ft.empty); 7917 } 7918 7919 // ditto 7920 pure @safe unittest 7921 { 7922 int[][] arr = [[], []]; 7923 7924 auto ft = frontTransversal!(TransverseOptions.enforceNotJagged)(arr); 7925 assert(ft.empty); 7926 } 7927 7928 // https://issues.dlang.org/show_bug.cgi?id=24481 7929 @safe unittest 7930 { 7931 bool called; 7932 struct Handle 7933 { 7934 int entry; 7935 void opAssign()(auto ref const(typeof(this)) that) const { called = true; } 7936 } 7937 7938 const(Handle)[][] arr = [[Handle(0), Handle(10)], 7939 [Handle(1), Handle(11)], 7940 [Handle(2), Handle(12)], 7941 [Handle(3), Handle(13)], 7942 [Handle(4), Handle(14)]]; 7943 7944 { 7945 auto range = arr.frontTransversal(); 7946 7947 called = false; 7948 range.front = Handle(42); 7949 assert(called == true); 7950 7951 called = false; 7952 range.back = Handle(42); 7953 assert(called == true); 7954 } 7955 { 7956 auto range = arr.frontTransversal!(TransverseOptions.assumeNotJagged)(); 7957 7958 called = false; 7959 range.front = Handle(42); 7960 assert(called == true); 7961 7962 called = false; 7963 range.back = Handle(42); 7964 assert(called == true); 7965 7966 called = false; 7967 range[0] = Handle(42); 7968 assert(called == true); 7969 } 7970 } 7971 7972 /** 7973 Given a range of ranges, iterate transversally through the 7974 `n`th element of each of the enclosed ranges. This function 7975 is similar to `unzip` in other languages. 7976 7977 Params: 7978 opt = Controls the assumptions the function makes about the lengths 7979 of the ranges 7980 rr = An input range of random access ranges 7981 Returns: 7982 At minimum, an input range. Range primitives such as bidirectionality 7983 and random access are given if the element type of `rr` provides them. 7984 */ 7985 struct Transversal(Ror, 7986 TransverseOptions opt = TransverseOptions.assumeJagged) 7987 { 7988 private alias RangeOfRanges = Unqual!Ror; 7989 private alias InnerRange = ElementType!RangeOfRanges; 7990 private alias E = ElementType!InnerRange; 7991 7992 private void prime() 7993 { 7994 static if (opt == TransverseOptions.assumeJagged) 7995 { 7996 while (!_input.empty && _input.front.length <= _n) 7997 { 7998 _input.popFront(); 7999 } 8000 static if (isBidirectionalRange!RangeOfRanges) 8001 { 8002 while (!_input.empty && _input.back.length <= _n) 8003 { 8004 _input.popBack(); 8005 } 8006 } 8007 } 8008 } 8009 8010 /** 8011 Construction from an input and an index. 8012 */ 8013 this(RangeOfRanges input, size_t n) 8014 { 8015 _input = input; 8016 _n = n; 8017 prime(); 8018 static if (opt == TransverseOptions.enforceNotJagged) 8019 { 8020 import std.exception : enforce; 8021 8022 if (empty) return; 8023 immutable commonLength = _input.front.length; 8024 foreach (e; _input) 8025 { 8026 enforce(e.length == commonLength); 8027 } 8028 } 8029 } 8030 8031 /** 8032 Forward range primitives. 8033 */ 8034 static if (isInfinite!(RangeOfRanges)) 8035 { 8036 enum bool empty = false; 8037 } 8038 else 8039 { 8040 @property bool empty() 8041 { 8042 return _input.empty; 8043 } 8044 } 8045 8046 /// Ditto 8047 @property auto ref front() 8048 { 8049 assert(!empty, "Attempting to fetch the front of an empty Transversal"); 8050 return _input.front[_n]; 8051 } 8052 8053 /// Ditto 8054 static if (hasMobileElements!InnerRange) 8055 { 8056 E moveFront() 8057 { 8058 return _input.front.moveAt(_n); 8059 } 8060 } 8061 8062 /// Ditto 8063 static if (hasAssignableElements!InnerRange) 8064 { 8065 @property void front(E val) 8066 { 8067 _input.front[_n] = val; 8068 } 8069 } 8070 8071 8072 /// Ditto 8073 void popFront() 8074 { 8075 assert(!empty, "Attempting to popFront an empty Transversal"); 8076 _input.popFront(); 8077 prime(); 8078 } 8079 8080 /// Ditto 8081 static if (isForwardRange!RangeOfRanges) 8082 { 8083 @property typeof(this) save() 8084 { 8085 auto ret = this; 8086 ret._input = _input.save; 8087 return ret; 8088 } 8089 } 8090 8091 static if (isBidirectionalRange!RangeOfRanges) 8092 { 8093 /** 8094 Bidirectional primitives. They are offered if $(D 8095 isBidirectionalRange!RangeOfRanges). 8096 */ 8097 @property auto ref back() 8098 { 8099 assert(!empty, "Attempting to fetch the back of an empty Transversal"); 8100 return _input.back[_n]; 8101 } 8102 8103 /// Ditto 8104 void popBack() 8105 { 8106 assert(!empty, "Attempting to popBack an empty Transversal"); 8107 _input.popBack(); 8108 prime(); 8109 } 8110 8111 /// Ditto 8112 static if (hasMobileElements!InnerRange) 8113 { 8114 E moveBack() 8115 { 8116 return _input.back.moveAt(_n); 8117 } 8118 } 8119 8120 /// Ditto 8121 static if (hasAssignableElements!InnerRange) 8122 { 8123 @property void back(E val) 8124 { 8125 _input.back[_n] = val; 8126 } 8127 } 8128 8129 } 8130 8131 static if (isRandomAccessRange!RangeOfRanges && 8132 (opt == TransverseOptions.assumeNotJagged || 8133 opt == TransverseOptions.enforceNotJagged)) 8134 { 8135 /** 8136 Random-access primitive. It is offered if $(D 8137 isRandomAccessRange!RangeOfRanges && (opt == 8138 TransverseOptions.assumeNotJagged || opt == 8139 TransverseOptions.enforceNotJagged)). 8140 */ 8141 auto ref opIndex(size_t n) 8142 { 8143 return _input[n][_n]; 8144 } 8145 8146 /// Ditto 8147 static if (hasMobileElements!InnerRange) 8148 { 8149 E moveAt(size_t n) 8150 { 8151 return _input[n].moveAt(_n); 8152 } 8153 } 8154 8155 /// Ditto 8156 static if (hasAssignableElements!InnerRange) 8157 { 8158 void opIndexAssign(E val, size_t n) 8159 { 8160 _input[n][_n] = val; 8161 } 8162 } 8163 8164 mixin ImplementLength!_input; 8165 8166 /** 8167 Slicing if offered if `RangeOfRanges` supports slicing and all the 8168 conditions for supporting indexing are met. 8169 */ 8170 static if (hasSlicing!RangeOfRanges) 8171 { 8172 typeof(this) opSlice(size_t lower, size_t upper) 8173 { 8174 return typeof(this)(_input[lower .. upper], _n); 8175 } 8176 } 8177 } 8178 8179 auto opSlice() { return this; } 8180 8181 private: 8182 RangeOfRanges _input; 8183 size_t _n; 8184 } 8185 8186 /// Ditto 8187 Transversal!(RangeOfRanges, opt) transversal 8188 (TransverseOptions opt = TransverseOptions.assumeJagged, RangeOfRanges) 8189 (RangeOfRanges rr, size_t n) 8190 { 8191 return typeof(return)(rr, n); 8192 } 8193 8194 /// 8195 @safe unittest 8196 { 8197 import std.algorithm.comparison : equal; 8198 int[][] x = new int[][2]; 8199 x[0] = [1, 2]; 8200 x[1] = [3, 4]; 8201 auto ror = transversal(x, 1); 8202 assert(equal(ror, [ 2, 4 ])); 8203 } 8204 8205 /// The following code does a full unzip 8206 @safe unittest 8207 { 8208 import std.algorithm.comparison : equal; 8209 import std.algorithm.iteration : map; 8210 int[][] y = [[1, 2, 3], [4, 5, 6]]; 8211 auto z = y.front.walkLength.iota.map!(i => transversal(y, i)); 8212 assert(equal!equal(z, [[1, 4], [2, 5], [3, 6]])); 8213 } 8214 8215 @safe unittest 8216 { 8217 import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy; 8218 8219 int[][] x = new int[][2]; 8220 x[0] = [ 1, 2 ]; 8221 x[1] = [3, 4]; 8222 auto ror = transversal!(TransverseOptions.assumeNotJagged)(x, 1); 8223 auto witness = [ 2, 4 ]; 8224 uint i; 8225 foreach (e; ror) assert(e == witness[i++]); 8226 assert(i == 2); 8227 assert(ror.length == 2); 8228 8229 static assert(is(Transversal!(immutable int[][]))); 8230 8231 // Make sure ref, assign is being propagated. 8232 { 8233 ror.front++; 8234 scope(exit) ror.front--; 8235 assert(x[0][1] == 3); 8236 } 8237 { 8238 ror.front = 5; 8239 scope(exit) ror.front = 2; 8240 assert(x[0][1] == 5); 8241 assert(ror.moveFront() == 5); 8242 } 8243 { 8244 ror.back = 999; 8245 scope(exit) ror.back = 4; 8246 assert(x[1][1] == 999); 8247 assert(ror.moveBack() == 999); 8248 } 8249 { 8250 ror[0] = 999; 8251 scope(exit) ror[0] = 2; 8252 assert(x[0][1] == 999); 8253 assert(ror.moveAt(0) == 999); 8254 } 8255 8256 // Test w/o ref return. 8257 alias D = DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random); 8258 auto drs = [D.init, D.init]; 8259 foreach (num; 0 .. 10) 8260 { 8261 auto t = transversal!(TransverseOptions.enforceNotJagged)(drs, num); 8262 assert(t[0] == t[1]); 8263 assert(t[1] == num + 1); 8264 } 8265 8266 static assert(isInfinite!(typeof(transversal(repeat([1,2,3]), 1)))); 8267 8268 // Test slicing. 8269 auto mat = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]; 8270 auto mat1 = transversal!(TransverseOptions.assumeNotJagged)(mat, 1)[1 .. 3]; 8271 assert(mat1[0] == 6); 8272 assert(mat1[1] == 10); 8273 } 8274 8275 struct Transposed(RangeOfRanges, 8276 TransverseOptions opt = TransverseOptions.assumeJagged) 8277 if (isForwardRange!RangeOfRanges && 8278 isInputRange!(ElementType!RangeOfRanges) && 8279 hasAssignableElements!RangeOfRanges) 8280 { 8281 this(RangeOfRanges input) 8282 { 8283 this._input = input; 8284 static if (opt == TransverseOptions.enforceNotJagged) 8285 { 8286 import std.exception : enforce; 8287 8288 if (empty) return; 8289 immutable commonLength = _input.front.length; 8290 foreach (e; _input) 8291 { 8292 enforce(e.length == commonLength); 8293 } 8294 } 8295 } 8296 8297 @property auto front() 8298 { 8299 import std.algorithm.iteration : filter, map; 8300 return _input.save 8301 .filter!(a => !a.empty) 8302 .map!(a => a.front); 8303 } 8304 8305 void popFront() 8306 { 8307 // Advance the position of each subrange. 8308 auto r = _input.save; 8309 while (!r.empty) 8310 { 8311 auto e = r.front; 8312 if (!e.empty) 8313 { 8314 e.popFront(); 8315 r.front = e; 8316 } 8317 8318 r.popFront(); 8319 } 8320 } 8321 8322 static if (isRandomAccessRange!(ElementType!RangeOfRanges)) 8323 { 8324 auto ref opIndex(size_t n) 8325 { 8326 return transversal!opt(_input, n); 8327 } 8328 } 8329 8330 @property bool empty() 8331 { 8332 if (_input.empty) return true; 8333 foreach (e; _input.save) 8334 { 8335 if (!e.empty) return false; 8336 } 8337 return true; 8338 } 8339 8340 auto opSlice() { return this; } 8341 8342 private: 8343 RangeOfRanges _input; 8344 } 8345 8346 @safe unittest 8347 { 8348 // Boundary case: transpose of empty range should be empty 8349 int[][] ror = []; 8350 assert(transposed(ror).empty); 8351 } 8352 8353 // https://issues.dlang.org/show_bug.cgi?id=9507 8354 @safe unittest 8355 { 8356 import std.algorithm.comparison : equal; 8357 8358 auto r = [[1,2], [3], [4,5], [], [6]]; 8359 assert(r.transposed.equal!equal([ 8360 [1, 3, 4, 6], 8361 [2, 5] 8362 ])); 8363 } 8364 8365 // https://issues.dlang.org/show_bug.cgi?id=17742 8366 @safe unittest 8367 { 8368 import std.algorithm.iteration : map; 8369 import std.algorithm.comparison : equal; 8370 auto ror = 5.iota.map!(y => 5.iota.map!(x => x * y).array).array; 8371 assert(ror[3][2] == 6); 8372 auto result = transposed!(TransverseOptions.assumeNotJagged)(ror); 8373 assert(result[2][3] == 6); 8374 8375 auto x = [[1,2,3],[4,5,6]]; 8376 auto y = transposed!(TransverseOptions.assumeNotJagged)(x); 8377 assert(y.front.equal([1,4])); 8378 assert(y[0].equal([1,4])); 8379 assert(y[0][0] == 1); 8380 assert(y[1].equal([2,5])); 8381 assert(y[1][1] == 5); 8382 8383 auto yy = transposed!(TransverseOptions.enforceNotJagged)(x); 8384 assert(yy.front.equal([1,4])); 8385 assert(yy[0].equal([1,4])); 8386 assert(yy[0][0] == 1); 8387 assert(yy[1].equal([2,5])); 8388 assert(yy[1][1] == 5); 8389 8390 auto z = x.transposed; // assumeJagged 8391 assert(z.front.equal([1,4])); 8392 assert(z[0].equal([1,4])); 8393 assert(!is(typeof(z[0][0]))); 8394 } 8395 8396 @safe unittest 8397 { 8398 import std.exception : assertThrown; 8399 8400 auto r = [[1,2], [3], [4,5], [], [6]]; 8401 assertThrown(r.transposed!(TransverseOptions.enforceNotJagged)); 8402 } 8403 8404 /** 8405 Given a range of ranges, returns a range of ranges where the $(I i)'th subrange 8406 contains the $(I i)'th elements of the original subranges. 8407 8408 Params: 8409 opt = Controls the assumptions the function makes about the lengths of the ranges (i.e. jagged or not) 8410 rr = Range of ranges 8411 */ 8412 Transposed!(RangeOfRanges, opt) transposed 8413 (TransverseOptions opt = TransverseOptions.assumeJagged, RangeOfRanges) 8414 (RangeOfRanges rr) 8415 if (isForwardRange!RangeOfRanges && 8416 isInputRange!(ElementType!RangeOfRanges) && 8417 hasAssignableElements!RangeOfRanges) 8418 { 8419 return Transposed!(RangeOfRanges, opt)(rr); 8420 } 8421 8422 /// 8423 @safe unittest 8424 { 8425 import std.algorithm.comparison : equal; 8426 int[][] ror = [ 8427 [1, 2, 3], 8428 [4, 5, 6] 8429 ]; 8430 auto xp = transposed(ror); 8431 assert(equal!"a.equal(b)"(xp, [ 8432 [1, 4], 8433 [2, 5], 8434 [3, 6] 8435 ])); 8436 } 8437 8438 /// 8439 @safe unittest 8440 { 8441 int[][] x = new int[][2]; 8442 x[0] = [1, 2]; 8443 x[1] = [3, 4]; 8444 auto tr = transposed(x); 8445 int[][] witness = [ [ 1, 3 ], [ 2, 4 ] ]; 8446 uint i; 8447 8448 foreach (e; tr) 8449 { 8450 assert(array(e) == witness[i++]); 8451 } 8452 } 8453 8454 // https://issues.dlang.org/show_bug.cgi?id=8764 8455 @safe unittest 8456 { 8457 import std.algorithm.comparison : equal; 8458 ulong[] t0 = [ 123 ]; 8459 8460 assert(!hasAssignableElements!(typeof(t0[].chunks(1)))); 8461 assert(!is(typeof(transposed(t0[].chunks(1))))); 8462 assert(is(typeof(transposed(t0[].chunks(1).array())))); 8463 8464 auto t1 = transposed(t0[].chunks(1).array()); 8465 assert(equal!"a.equal(b)"(t1, [[123]])); 8466 } 8467 8468 /** 8469 This struct takes two ranges, `source` and `indices`, and creates a view 8470 of `source` as if its elements were reordered according to `indices`. 8471 `indices` may include only a subset of the elements of `source` and 8472 may also repeat elements. 8473 8474 `Source` must be a random access range. The returned range will be 8475 bidirectional or random-access if `Indices` is bidirectional or 8476 random-access, respectively. 8477 */ 8478 struct Indexed(Source, Indices) 8479 if (isRandomAccessRange!Source && isInputRange!Indices && 8480 is(typeof(Source.init[ElementType!(Indices).init]))) 8481 { 8482 this(Source source, Indices indices) 8483 { 8484 this._source = source; 8485 this._indices = indices; 8486 } 8487 8488 /// Range primitives 8489 @property auto ref front() 8490 { 8491 assert(!empty, "Attempting to fetch the front of an empty Indexed"); 8492 return _source[_indices.front]; 8493 } 8494 8495 /// Ditto 8496 void popFront() 8497 { 8498 assert(!empty, "Attempting to popFront an empty Indexed"); 8499 _indices.popFront(); 8500 } 8501 8502 static if (isInfinite!Indices) 8503 { 8504 enum bool empty = false; 8505 } 8506 else 8507 { 8508 /// Ditto 8509 @property bool empty() 8510 { 8511 return _indices.empty; 8512 } 8513 } 8514 8515 static if (isForwardRange!Indices) 8516 { 8517 /// Ditto 8518 @property typeof(this) save() 8519 { 8520 // Don't need to save _source because it's never consumed. 8521 return typeof(this)(_source, _indices.save); 8522 } 8523 } 8524 8525 /// Ditto 8526 static if (hasAssignableElements!Source) 8527 { 8528 @property auto ref front(ElementType!Source newVal) 8529 { 8530 assert(!empty); 8531 return _source[_indices.front] = newVal; 8532 } 8533 } 8534 8535 8536 static if (hasMobileElements!Source) 8537 { 8538 /// Ditto 8539 auto moveFront() 8540 { 8541 assert(!empty); 8542 return _source.moveAt(_indices.front); 8543 } 8544 } 8545 8546 static if (isBidirectionalRange!Indices) 8547 { 8548 /// Ditto 8549 @property auto ref back() 8550 { 8551 assert(!empty, "Attempting to fetch the back of an empty Indexed"); 8552 return _source[_indices.back]; 8553 } 8554 8555 /// Ditto 8556 void popBack() 8557 { 8558 assert(!empty, "Attempting to popBack an empty Indexed"); 8559 _indices.popBack(); 8560 } 8561 8562 /// Ditto 8563 static if (hasAssignableElements!Source) 8564 { 8565 @property auto ref back(ElementType!Source newVal) 8566 { 8567 assert(!empty); 8568 return _source[_indices.back] = newVal; 8569 } 8570 } 8571 8572 8573 static if (hasMobileElements!Source) 8574 { 8575 /// Ditto 8576 auto moveBack() 8577 { 8578 assert(!empty); 8579 return _source.moveAt(_indices.back); 8580 } 8581 } 8582 } 8583 8584 mixin ImplementLength!_indices; 8585 8586 static if (isRandomAccessRange!Indices) 8587 { 8588 /// Ditto 8589 auto ref opIndex(size_t index) 8590 { 8591 return _source[_indices[index]]; 8592 } 8593 8594 static if (hasSlicing!Indices) 8595 { 8596 /// Ditto 8597 typeof(this) opSlice(size_t a, size_t b) 8598 { 8599 return typeof(this)(_source, _indices[a .. b]); 8600 } 8601 } 8602 8603 8604 static if (hasAssignableElements!Source) 8605 { 8606 /// Ditto 8607 auto opIndexAssign(ElementType!Source newVal, size_t index) 8608 { 8609 return _source[_indices[index]] = newVal; 8610 } 8611 } 8612 8613 8614 static if (hasMobileElements!Source) 8615 { 8616 /// Ditto 8617 auto moveAt(size_t index) 8618 { 8619 return _source.moveAt(_indices[index]); 8620 } 8621 } 8622 } 8623 8624 // All this stuff is useful if someone wants to index an Indexed 8625 // without adding a layer of indirection. 8626 8627 /** 8628 Returns the source range. 8629 */ 8630 @property Source source() 8631 { 8632 return _source; 8633 } 8634 8635 /** 8636 Returns the indices range. 8637 */ 8638 @property Indices indices() 8639 { 8640 return _indices; 8641 } 8642 8643 static if (isRandomAccessRange!Indices) 8644 { 8645 /** 8646 Returns the physical index into the source range corresponding to a 8647 given logical index. This is useful, for example, when indexing 8648 an `Indexed` without adding another layer of indirection. 8649 */ 8650 size_t physicalIndex(size_t logicalIndex) 8651 { 8652 return _indices[logicalIndex]; 8653 } 8654 8655 /// 8656 @safe unittest 8657 { 8658 auto ind = indexed([1, 2, 3, 4, 5], [1, 3, 4]); 8659 assert(ind.physicalIndex(0) == 1); 8660 } 8661 } 8662 8663 private: 8664 Source _source; 8665 Indices _indices; 8666 8667 } 8668 8669 /// Ditto 8670 Indexed!(Source, Indices) indexed(Source, Indices)(Source source, Indices indices) 8671 { 8672 return typeof(return)(source, indices); 8673 } 8674 8675 /// 8676 @safe unittest 8677 { 8678 import std.algorithm.comparison : equal; 8679 auto source = [1, 2, 3, 4, 5]; 8680 auto indices = [4, 3, 1, 2, 0, 4]; 8681 auto ind = indexed(source, indices); 8682 assert(equal(ind, [5, 4, 2, 3, 1, 5])); 8683 assert(equal(retro(ind), [5, 1, 3, 2, 4, 5])); 8684 } 8685 8686 @safe unittest 8687 { 8688 { 8689 auto ind = indexed([1, 2, 3, 4, 5], [1, 3, 4]); 8690 assert(ind.physicalIndex(0) == 1); 8691 } 8692 8693 auto source = [1, 2, 3, 4, 5]; 8694 auto indices = [4, 3, 1, 2, 0, 4]; 8695 auto ind = indexed(source, indices); 8696 8697 // When elements of indices are duplicated and Source has lvalue elements, 8698 // these are aliased in ind. 8699 ind[0]++; 8700 assert(ind[0] == 6); 8701 assert(ind[5] == 6); 8702 } 8703 8704 @safe unittest 8705 { 8706 import std.internal.test.dummyrange : AllDummyRanges, propagatesLength, 8707 propagatesRangeType, RangeType; 8708 8709 foreach (DummyType; AllDummyRanges) 8710 { 8711 auto d = DummyType.init; 8712 auto r = indexed([1, 2, 3, 4, 5], d); 8713 static assert(propagatesRangeType!(DummyType, typeof(r))); 8714 static assert(propagatesLength!(DummyType, typeof(r))); 8715 } 8716 } 8717 8718 /** 8719 This range iterates over fixed-sized chunks of size `chunkSize` of a 8720 `source` range. `Source` must be an $(REF_ALTTEXT input range, isInputRange, std,range,primitives). 8721 `chunkSize` must be greater than zero. 8722 8723 If `!isInfinite!Source` and `source.walkLength` is not evenly 8724 divisible by `chunkSize`, the back element of this range will contain 8725 fewer than `chunkSize` elements. 8726 8727 If `Source` is a forward range, the resulting range will be forward ranges as 8728 well. Otherwise, the resulting chunks will be input ranges consuming the same 8729 input: iterating over `front` will shrink the chunk such that subsequent 8730 invocations of `front` will no longer return the full chunk, and calling 8731 `popFront` on the outer range will invalidate any lingering references to 8732 previous values of `front`. 8733 8734 Params: 8735 source = Range from which the chunks will be selected 8736 chunkSize = Chunk size 8737 8738 See_Also: $(LREF slide) 8739 8740 Returns: Range of chunks. 8741 */ 8742 struct Chunks(Source) 8743 if (isInputRange!Source) 8744 { 8745 static if (isForwardRange!Source) 8746 { 8747 /// Standard constructor 8748 this(Source source, size_t chunkSize) 8749 { 8750 assert(chunkSize != 0, "Cannot create a Chunk with an empty chunkSize"); 8751 _source = source; 8752 _chunkSize = chunkSize; 8753 } 8754 8755 /// Input range primitives. Always present. 8756 @property auto front() 8757 { 8758 assert(!empty, "Attempting to fetch the front of an empty Chunks"); 8759 return _source.save.take(_chunkSize); 8760 } 8761 8762 /// Ditto 8763 void popFront() 8764 { 8765 assert(!empty, "Attempting to popFront and empty Chunks"); 8766 _source.popFrontN(_chunkSize); 8767 } 8768 8769 static if (!isInfinite!Source) 8770 /// Ditto 8771 @property bool empty() 8772 { 8773 return _source.empty; 8774 } 8775 else 8776 // undocumented 8777 enum empty = false; 8778 8779 /// Forward range primitives. Only present if `Source` is a forward range. 8780 @property typeof(this) save() 8781 { 8782 return typeof(this)(_source.save, _chunkSize); 8783 } 8784 8785 static if (hasLength!Source) 8786 { 8787 /// Length. Only if `hasLength!Source` is `true` 8788 @property size_t length() 8789 { 8790 // Note: _source.length + _chunkSize may actually overflow. 8791 // We cast to ulong to mitigate the problem on x86 machines. 8792 // For x64 machines, we just suppose we'll never overflow. 8793 // The "safe" code would require either an extra branch, or a 8794 // modulo operation, which is too expensive for such a rare case 8795 return cast(size_t)((cast(ulong)(_source.length) + _chunkSize - 1) / _chunkSize); 8796 } 8797 //Note: No point in defining opDollar here without slicing. 8798 //opDollar is defined below in the hasSlicing!Source section 8799 } 8800 8801 static if (hasSlicing!Source) 8802 { 8803 //Used for various purposes 8804 private enum hasSliceToEnd = is(typeof(Source.init[_chunkSize .. $]) == Source); 8805 8806 /** 8807 Indexing and slicing operations. Provided only if 8808 `hasSlicing!Source` is `true`. 8809 */ 8810 auto opIndex(size_t index) 8811 { 8812 immutable start = index * _chunkSize; 8813 immutable end = start + _chunkSize; 8814 8815 static if (isInfinite!Source) 8816 return _source[start .. end]; 8817 else 8818 { 8819 import std.algorithm.comparison : min; 8820 immutable len = _source.length; 8821 assert(start < len, "chunks index out of bounds"); 8822 return _source[start .. min(end, len)]; 8823 } 8824 } 8825 8826 /// Ditto 8827 static if (hasLength!Source) 8828 typeof(this) opSlice(size_t lower, size_t upper) 8829 { 8830 import std.algorithm.comparison : min; 8831 assert(lower <= upper && upper <= length, "chunks slicing index out of bounds"); 8832 immutable len = _source.length; 8833 return chunks(_source[min(lower * _chunkSize, len) .. min(upper * _chunkSize, len)], _chunkSize); 8834 } 8835 else static if (hasSliceToEnd) 8836 //For slicing an infinite chunk, we need to slice the source to the end. 8837 typeof(takeExactly(this, 0)) opSlice(size_t lower, size_t upper) 8838 { 8839 assert(lower <= upper, "chunks slicing index out of bounds"); 8840 return chunks(_source[lower * _chunkSize .. $], _chunkSize).takeExactly(upper - lower); 8841 } 8842 8843 static if (isInfinite!Source) 8844 { 8845 static if (hasSliceToEnd) 8846 { 8847 private static struct DollarToken{} 8848 DollarToken opDollar() 8849 { 8850 return DollarToken(); 8851 } 8852 //Slice to dollar 8853 typeof(this) opSlice(size_t lower, DollarToken) 8854 { 8855 return typeof(this)(_source[lower * _chunkSize .. $], _chunkSize); 8856 } 8857 } 8858 } 8859 else 8860 { 8861 //Dollar token carries a static type, with no extra information. 8862 //It can lazily transform into _source.length on algorithmic 8863 //operations such as : chunks[$/2, $-1]; 8864 private static struct DollarToken 8865 { 8866 Chunks!Source* mom; 8867 @property size_t momLength() 8868 { 8869 return mom.length; 8870 } 8871 alias momLength this; 8872 } 8873 DollarToken opDollar() 8874 { 8875 return DollarToken(&this); 8876 } 8877 8878 //Slice overloads optimized for using dollar. Without this, to slice to end, we would... 8879 //1. Evaluate chunks.length 8880 //2. Multiply by _chunksSize 8881 //3. To finally just compare it (with min) to the original length of source (!) 8882 //These overloads avoid that. 8883 typeof(this) opSlice(DollarToken, DollarToken) 8884 { 8885 static if (hasSliceToEnd) 8886 return chunks(_source[$ .. $], _chunkSize); 8887 else 8888 { 8889 immutable len = _source.length; 8890 return chunks(_source[len .. len], _chunkSize); 8891 } 8892 } 8893 typeof(this) opSlice(size_t lower, DollarToken) 8894 { 8895 import std.algorithm.comparison : min; 8896 assert(lower <= length, "chunks slicing index out of bounds"); 8897 static if (hasSliceToEnd) 8898 return chunks(_source[min(lower * _chunkSize, _source.length) .. $], _chunkSize); 8899 else 8900 { 8901 immutable len = _source.length; 8902 return chunks(_source[min(lower * _chunkSize, len) .. len], _chunkSize); 8903 } 8904 } 8905 typeof(this) opSlice(DollarToken, size_t upper) 8906 { 8907 assert(upper == length, "chunks slicing index out of bounds"); 8908 return this[$ .. $]; 8909 } 8910 } 8911 } 8912 8913 //Bidirectional range primitives 8914 static if (hasSlicing!Source && hasLength!Source) 8915 { 8916 /** 8917 Bidirectional range primitives. Provided only if both 8918 `hasSlicing!Source` and `hasLength!Source` are `true`. 8919 */ 8920 @property auto back() 8921 { 8922 assert(!empty, "back called on empty chunks"); 8923 immutable len = _source.length; 8924 immutable start = (len - 1) / _chunkSize * _chunkSize; 8925 return _source[start .. len]; 8926 } 8927 8928 /// Ditto 8929 void popBack() 8930 { 8931 assert(!empty, "popBack() called on empty chunks"); 8932 immutable end = (_source.length - 1) / _chunkSize * _chunkSize; 8933 _source = _source[0 .. end]; 8934 } 8935 } 8936 8937 private: 8938 Source _source; 8939 size_t _chunkSize; 8940 } 8941 else // is input range only 8942 { 8943 import std.typecons : RefCounted; 8944 8945 static struct Chunk 8946 { 8947 private RefCounted!Impl impl; 8948 8949 @property bool empty() { return impl.curSizeLeft == 0 || impl.r.empty; } 8950 @property auto front() { return impl.r.front; } 8951 void popFront() 8952 { 8953 assert(impl.curSizeLeft > 0 && !impl.r.empty); 8954 impl.curSizeLeft--; 8955 impl.r.popFront(); 8956 } 8957 } 8958 8959 static struct Impl 8960 { 8961 private Source r; 8962 private size_t chunkSize; 8963 private size_t curSizeLeft; 8964 } 8965 8966 private RefCounted!Impl impl; 8967 8968 private this(Source r, size_t chunkSize) 8969 { 8970 impl = RefCounted!Impl(r, r.empty ? 0 : chunkSize, chunkSize); 8971 } 8972 8973 @property bool empty() { return impl.chunkSize == 0; } 8974 @property Chunk front() return { return Chunk(impl); } 8975 8976 void popFront() 8977 { 8978 impl.curSizeLeft -= impl.r.popFrontN(impl.curSizeLeft); 8979 if (!impl.r.empty) 8980 impl.curSizeLeft = impl.chunkSize; 8981 else 8982 impl.chunkSize = 0; 8983 } 8984 8985 static assert(isInputRange!(typeof(this))); 8986 } 8987 } 8988 8989 /// Ditto 8990 Chunks!Source chunks(Source)(Source source, size_t chunkSize) 8991 if (isInputRange!Source) 8992 { 8993 return typeof(return)(source, chunkSize); 8994 } 8995 8996 /// 8997 @safe unittest 8998 { 8999 import std.algorithm.comparison : equal; 9000 auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 9001 auto chunks = chunks(source, 4); 9002 assert(chunks[0] == [1, 2, 3, 4]); 9003 assert(chunks[1] == [5, 6, 7, 8]); 9004 assert(chunks[2] == [9, 10]); 9005 assert(chunks.back == chunks[2]); 9006 assert(chunks.front == chunks[0]); 9007 assert(chunks.length == 3); 9008 assert(equal(retro(array(chunks)), array(retro(chunks)))); 9009 } 9010 9011 /// Non-forward input ranges are supported, but with limited semantics. 9012 @system /*@safe*/ unittest // FIXME: can't be @safe because RefCounted isn't. 9013 { 9014 import std.algorithm.comparison : equal; 9015 9016 int i; 9017 9018 // The generator doesn't save state, so it cannot be a forward range. 9019 auto inputRange = generate!(() => ++i).take(10); 9020 9021 // We can still process it in chunks, but it will be single-pass only. 9022 auto chunked = inputRange.chunks(2); 9023 9024 assert(chunked.front.equal([1, 2])); 9025 assert(chunked.front.empty); // Iterating the chunk has consumed it 9026 chunked.popFront; 9027 assert(chunked.front.equal([3, 4])); 9028 } 9029 9030 @system /*@safe*/ unittest 9031 { 9032 import std.algorithm.comparison : equal; 9033 import std.internal.test.dummyrange : ReferenceInputRange; 9034 9035 auto data = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; 9036 auto r = new ReferenceInputRange!int(data).chunks(3); 9037 assert(r.equal!equal([ 9038 [ 1, 2, 3 ], 9039 [ 4, 5, 6 ], 9040 [ 7, 8, 9 ], 9041 [ 10 ] 9042 ])); 9043 9044 auto data2 = [ 1, 2, 3, 4, 5, 6 ]; 9045 auto r2 = new ReferenceInputRange!int(data2).chunks(3); 9046 assert(r2.equal!equal([ 9047 [ 1, 2, 3 ], 9048 [ 4, 5, 6 ] 9049 ])); 9050 9051 auto data3 = [ 1, 2, 3, 4, 5 ]; 9052 auto r3 = new ReferenceInputRange!int(data3).chunks(2); 9053 assert(r3.front.equal([1, 2])); 9054 r3.popFront(); 9055 assert(!r3.empty); 9056 r3.popFront(); 9057 assert(r3.front.equal([5])); 9058 } 9059 9060 @safe unittest 9061 { 9062 auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 9063 auto chunks = chunks(source, 4); 9064 auto chunks2 = chunks.save; 9065 chunks.popFront(); 9066 assert(chunks[0] == [5, 6, 7, 8]); 9067 assert(chunks[1] == [9, 10]); 9068 chunks2.popBack(); 9069 assert(chunks2[1] == [5, 6, 7, 8]); 9070 assert(chunks2.length == 2); 9071 9072 static assert(isRandomAccessRange!(typeof(chunks))); 9073 } 9074 9075 @safe unittest 9076 { 9077 import std.algorithm.comparison : equal; 9078 9079 //Extra toying with slicing and indexing. 9080 auto chunks1 = [0, 0, 1, 1, 2, 2, 3, 3, 4].chunks(2); 9081 auto chunks2 = [0, 0, 1, 1, 2, 2, 3, 3, 4, 4].chunks(2); 9082 9083 assert(chunks1.length == 5); 9084 assert(chunks2.length == 5); 9085 assert(chunks1[4] == [4]); 9086 assert(chunks2[4] == [4, 4]); 9087 assert(chunks1.back == [4]); 9088 assert(chunks2.back == [4, 4]); 9089 9090 assert(chunks1[0 .. 1].equal([[0, 0]])); 9091 assert(chunks1[0 .. 2].equal([[0, 0], [1, 1]])); 9092 assert(chunks1[4 .. 5].equal([[4]])); 9093 assert(chunks2[4 .. 5].equal([[4, 4]])); 9094 9095 assert(chunks1[0 .. 0].equal((int[][]).init)); 9096 assert(chunks1[5 .. 5].equal((int[][]).init)); 9097 assert(chunks2[5 .. 5].equal((int[][]).init)); 9098 9099 //Fun with opDollar 9100 assert(chunks1[$ .. $].equal((int[][]).init)); //Quick 9101 assert(chunks2[$ .. $].equal((int[][]).init)); //Quick 9102 assert(chunks1[$ - 1 .. $].equal([[4]])); //Semiquick 9103 assert(chunks2[$ - 1 .. $].equal([[4, 4]])); //Semiquick 9104 assert(chunks1[$ .. 5].equal((int[][]).init)); //Semiquick 9105 assert(chunks2[$ .. 5].equal((int[][]).init)); //Semiquick 9106 9107 assert(chunks1[$ / 2 .. $ - 1].equal([[2, 2], [3, 3]])); //Slow 9108 } 9109 9110 @safe unittest 9111 { 9112 import std.algorithm.comparison : equal; 9113 import std.algorithm.iteration : filter; 9114 9115 //ForwardRange 9116 auto r = filter!"true"([1, 2, 3, 4, 5]).chunks(2); 9117 assert(equal!"equal(a, b)"(r, [[1, 2], [3, 4], [5]])); 9118 9119 //InfiniteRange w/o RA 9120 auto fibsByPairs = recurrence!"a[n-1] + a[n-2]"(1, 1).chunks(2); 9121 assert(equal!`equal(a, b)`(fibsByPairs.take(2), [[ 1, 1], [ 2, 3]])); 9122 9123 //InfiniteRange w/ RA and slicing 9124 auto odds = sequence!("a[0] + n * a[1]")(1, 2); 9125 auto oddsByPairs = odds.chunks(2); 9126 assert(equal!`equal(a, b)`(oddsByPairs.take(2), [[ 1, 3], [ 5, 7]])); 9127 9128 //Requires phobos#991 for Sequence to have slice to end 9129 static assert(hasSlicing!(typeof(odds))); 9130 assert(equal!`equal(a, b)`(oddsByPairs[3 .. 5], [[13, 15], [17, 19]])); 9131 assert(equal!`equal(a, b)`(oddsByPairs[3 .. $].take(2), [[13, 15], [17, 19]])); 9132 } 9133 9134 9135 9136 /** 9137 This range splits a `source` range into `chunkCount` chunks of 9138 approximately equal length. `Source` must be a forward range with 9139 known length. 9140 9141 Unlike $(LREF chunks), `evenChunks` takes a chunk count (not size). 9142 The returned range will contain zero or more $(D source.length / 9143 chunkCount + 1) elements followed by $(D source.length / chunkCount) 9144 elements. If $(D source.length < chunkCount), some chunks will be empty. 9145 9146 `chunkCount` must not be zero, unless `source` is also empty. 9147 */ 9148 struct EvenChunks(Source) 9149 if (isForwardRange!Source && hasLength!Source) 9150 { 9151 /// Standard constructor 9152 this(Source source, size_t chunkCount) 9153 { 9154 assert(chunkCount != 0 || source.empty, "Cannot create EvenChunks with a zero chunkCount"); 9155 _source = source; 9156 _chunkCount = chunkCount; 9157 } 9158 9159 /// Forward range primitives. Always present. 9160 @property auto front() 9161 { 9162 assert(!empty, "Attempting to fetch the front of an empty evenChunks"); 9163 return _source.save.take(_chunkPos(1)); 9164 } 9165 9166 /// Ditto 9167 void popFront() 9168 { 9169 assert(!empty, "Attempting to popFront an empty evenChunks"); 9170 _source.popFrontN(_chunkPos(1)); 9171 _chunkCount--; 9172 } 9173 9174 /// Ditto 9175 @property bool empty() 9176 { 9177 return _chunkCount == 0; 9178 } 9179 9180 /// Ditto 9181 @property typeof(this) save() 9182 { 9183 return typeof(this)(_source.save, _chunkCount); 9184 } 9185 9186 /// Length 9187 @property size_t length() const 9188 { 9189 return _chunkCount; 9190 } 9191 //Note: No point in defining opDollar here without slicing. 9192 //opDollar is defined below in the hasSlicing!Source section 9193 9194 static if (hasSlicing!Source) 9195 { 9196 /** 9197 Indexing, slicing and bidirectional operations and range primitives. 9198 Provided only if `hasSlicing!Source` is `true`. 9199 */ 9200 auto opIndex(size_t index) 9201 { 9202 assert(index < _chunkCount, "evenChunks index out of bounds"); 9203 return _source[_chunkPos(index) .. _chunkPos(index+1)]; 9204 } 9205 9206 /// Ditto 9207 typeof(this) opSlice(size_t lower, size_t upper) 9208 { 9209 assert(lower <= upper && upper <= length, "evenChunks slicing index out of bounds"); 9210 return evenChunks(_source[_chunkPos(lower) .. _chunkPos(upper)], upper - lower); 9211 } 9212 9213 /// Ditto 9214 @property auto back() 9215 { 9216 assert(!empty, "back called on empty evenChunks"); 9217 return _source[_chunkPos(_chunkCount - 1) .. _source.length]; 9218 } 9219 9220 /// Ditto 9221 void popBack() 9222 { 9223 assert(!empty, "popBack() called on empty evenChunks"); 9224 _source = _source[0 .. _chunkPos(_chunkCount - 1)]; 9225 _chunkCount--; 9226 } 9227 } 9228 9229 private: 9230 Source _source; 9231 size_t _chunkCount; 9232 9233 size_t _chunkPos(size_t i) 9234 { 9235 /* 9236 _chunkCount = 5, _source.length = 13: 9237 9238 chunk0 9239 | chunk3 9240 | | 9241 v v 9242 +-+-+-+-+-+ ^ 9243 |0|3|.| | | | 9244 +-+-+-+-+-+ | div 9245 |1|4|.| | | | 9246 +-+-+-+-+-+ v 9247 |2|5|.| 9248 +-+-+-+ 9249 9250 <-----> 9251 mod 9252 9253 <---------> 9254 _chunkCount 9255 9256 One column is one chunk. 9257 popFront and popBack pop the left-most 9258 and right-most column, respectively. 9259 */ 9260 9261 auto div = _source.length / _chunkCount; 9262 auto mod = _source.length % _chunkCount; 9263 auto pos = i <= mod 9264 ? i * (div+1) 9265 : mod * (div+1) + (i-mod) * div 9266 ; 9267 //auto len = i < mod 9268 // ? div+1 9269 // : div 9270 //; 9271 return pos; 9272 } 9273 } 9274 9275 /// Ditto 9276 EvenChunks!Source evenChunks(Source)(Source source, size_t chunkCount) 9277 if (isForwardRange!Source && hasLength!Source) 9278 { 9279 return typeof(return)(source, chunkCount); 9280 } 9281 9282 /// 9283 @safe unittest 9284 { 9285 import std.algorithm.comparison : equal; 9286 auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 9287 auto chunks = evenChunks(source, 3); 9288 assert(chunks[0] == [1, 2, 3, 4]); 9289 assert(chunks[1] == [5, 6, 7]); 9290 assert(chunks[2] == [8, 9, 10]); 9291 } 9292 9293 @safe unittest 9294 { 9295 import std.algorithm.comparison : equal; 9296 9297 auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 9298 auto chunks = evenChunks(source, 3); 9299 assert(chunks.back == chunks[2]); 9300 assert(chunks.front == chunks[0]); 9301 assert(chunks.length == 3); 9302 assert(equal(retro(array(chunks)), array(retro(chunks)))); 9303 9304 auto chunks2 = chunks.save; 9305 chunks.popFront(); 9306 assert(chunks[0] == [5, 6, 7]); 9307 assert(chunks[1] == [8, 9, 10]); 9308 chunks2.popBack(); 9309 assert(chunks2[1] == [5, 6, 7]); 9310 assert(chunks2.length == 2); 9311 9312 static assert(isRandomAccessRange!(typeof(chunks))); 9313 } 9314 9315 @safe unittest 9316 { 9317 import std.algorithm.comparison : equal; 9318 9319 int[] source = []; 9320 auto chunks = source.evenChunks(0); 9321 assert(chunks.length == 0); 9322 chunks = source.evenChunks(3); 9323 assert(equal(chunks, [[], [], []])); 9324 chunks = [1, 2, 3].evenChunks(5); 9325 assert(equal(chunks, [[1], [2], [3], [], []])); 9326 } 9327 9328 /** 9329 A fixed-sized sliding window iteration 9330 of size `windowSize` over a `source` range by a custom `stepSize`. 9331 9332 The `Source` range must be at least a $(REF_ALTTEXT ForwardRange, isForwardRange, std,range,primitives) 9333 and the `windowSize` must be greater than zero. 9334 9335 For `windowSize = 1` it splits the range into single element groups (aka `unflatten`) 9336 For `windowSize = 2` it is similar to `zip(source, source.save.dropOne)`. 9337 9338 Params: 9339 f = Whether the last element has fewer elements than `windowSize` 9340 it should be be ignored (`No.withPartial`) or added (`Yes.withPartial`) 9341 source = Range from which the slide will be selected 9342 windowSize = Sliding window size 9343 stepSize = Steps between the windows (by default 1) 9344 9345 Returns: Range of all sliding windows with propagated bi-directionality, 9346 forwarding, random access, and slicing. 9347 9348 Note: To avoid performance overhead, $(REF_ALTTEXT bi-directionality, isBidirectionalRange, std,range,primitives) 9349 is only available when $(REF hasSlicing, std,range,primitives) 9350 and $(REF hasLength, std,range,primitives) are true. 9351 9352 See_Also: $(LREF chunks) 9353 */ 9354 auto slide(Flag!"withPartial" f = Yes.withPartial, 9355 Source)(Source source, size_t windowSize, size_t stepSize = 1) 9356 if (isForwardRange!Source) 9357 { 9358 return Slides!(f, Source)(source, windowSize, stepSize); 9359 } 9360 9361 /// Iterate over ranges with windows 9362 @safe pure nothrow unittest 9363 { 9364 import std.algorithm.comparison : equal; 9365 9366 assert([0, 1, 2, 3].slide(2).equal!equal( 9367 [[0, 1], [1, 2], [2, 3]] 9368 )); 9369 9370 assert(5.iota.slide(3).equal!equal( 9371 [[0, 1, 2], [1, 2, 3], [2, 3, 4]] 9372 )); 9373 } 9374 9375 /// set a custom stepsize (default 1) 9376 @safe pure nothrow unittest 9377 { 9378 import std.algorithm.comparison : equal; 9379 9380 assert(6.iota.slide(1, 2).equal!equal( 9381 [[0], [2], [4]] 9382 )); 9383 9384 assert(6.iota.slide(2, 4).equal!equal( 9385 [[0, 1], [4, 5]] 9386 )); 9387 9388 assert(iota(7).slide(2, 2).equal!equal( 9389 [[0, 1], [2, 3], [4, 5], [6]] 9390 )); 9391 9392 assert(iota(12).slide(2, 4).equal!equal( 9393 [[0, 1], [4, 5], [8, 9]] 9394 )); 9395 } 9396 9397 /// Allow the last slide to have fewer elements than windowSize 9398 @safe pure nothrow unittest 9399 { 9400 import std.algorithm.comparison : equal; 9401 9402 assert(3.iota.slide!(No.withPartial)(4).empty); 9403 assert(3.iota.slide!(Yes.withPartial)(4).equal!equal( 9404 [[0, 1, 2]] 9405 )); 9406 } 9407 9408 /// Count all the possible substrings of length 2 9409 @safe pure nothrow unittest 9410 { 9411 import std.algorithm.iteration : each; 9412 9413 int[dstring] d; 9414 "AGAGA"d.slide!(Yes.withPartial)(2).each!(a => d[a]++); 9415 assert(d == ["AG"d: 2, "GA"d: 2]); 9416 } 9417 9418 /// withPartial only has an effect if last element in the range doesn't have the full size 9419 @safe pure nothrow unittest 9420 { 9421 import std.algorithm.comparison : equal; 9422 9423 assert(5.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4]])); 9424 assert(6.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5]])); 9425 assert(7.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5, 6]])); 9426 9427 assert(5.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2]])); 9428 assert(6.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2]])); 9429 assert(7.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5, 6]])); 9430 } 9431 9432 private struct Slides(Flag!"withPartial" withPartial = Yes.withPartial, Source) 9433 if (isForwardRange!Source) 9434 { 9435 private: 9436 Source source; 9437 size_t windowSize; 9438 size_t stepSize; 9439 9440 static if (hasLength!Source) 9441 { 9442 enum needsEndTracker = false; 9443 } 9444 else 9445 { 9446 // If there's no information about the length, track needs to be kept manually 9447 Source nextSource; 9448 enum needsEndTracker = true; 9449 } 9450 9451 bool _empty; 9452 9453 static if (hasSlicing!Source) 9454 enum hasSliceToEnd = hasSlicing!Source && is(typeof(Source.init[0 .. $]) == Source); 9455 9456 static if (withPartial) 9457 bool hasShownPartialBefore; 9458 9459 public: 9460 /// Standard constructor 9461 this(Source source, size_t windowSize, size_t stepSize) 9462 { 9463 assert(windowSize > 0, "windowSize must be greater than zero"); 9464 assert(stepSize > 0, "stepSize must be greater than zero"); 9465 this.source = source; 9466 this.windowSize = windowSize; 9467 this.stepSize = stepSize; 9468 9469 static if (needsEndTracker) 9470 { 9471 // `nextSource` is used to "look one step into the future" and check for the end 9472 // this means `nextSource` is advanced by `stepSize` on every `popFront` 9473 nextSource = source.save; 9474 auto poppedElems = nextSource.popFrontN(windowSize); 9475 } 9476 9477 if (source.empty) 9478 { 9479 _empty = true; 9480 return; 9481 } 9482 9483 static if (withPartial) 9484 { 9485 static if (needsEndTracker) 9486 { 9487 if (nextSource.empty) 9488 hasShownPartialBefore = true; 9489 } 9490 else 9491 { 9492 if (source.length <= windowSize) 9493 hasShownPartialBefore = true; 9494 } 9495 } 9496 else 9497 { 9498 // empty source range is needed, s.t. length, slicing etc. works properly 9499 static if (needsEndTracker) 9500 { 9501 if (poppedElems < windowSize) 9502 _empty = true; 9503 } 9504 else 9505 { 9506 if (source.length < windowSize) 9507 _empty = true; 9508 } 9509 } 9510 } 9511 9512 /// Forward range primitives. Always present. 9513 @property auto front() 9514 { 9515 assert(!empty, "Attempting to access front on an empty slide."); 9516 static if (hasSlicing!Source && hasLength!Source) 9517 { 9518 static if (withPartial) 9519 { 9520 import std.algorithm.comparison : min; 9521 return source[0 .. min(windowSize, source.length)]; 9522 } 9523 else 9524 { 9525 assert(windowSize <= source.length, "The last element is smaller than the current windowSize."); 9526 return source[0 .. windowSize]; 9527 } 9528 } 9529 else 9530 { 9531 static if (withPartial) 9532 return source.save.take(windowSize); 9533 else 9534 return source.save.takeExactly(windowSize); 9535 } 9536 } 9537 9538 /// Ditto 9539 void popFront() 9540 { 9541 assert(!empty, "Attempting to call popFront() on an empty slide."); 9542 source.popFrontN(stepSize); 9543 9544 if (source.empty) 9545 { 9546 _empty = true; 9547 return; 9548 } 9549 9550 static if (withPartial) 9551 { 9552 if (hasShownPartialBefore) 9553 _empty = true; 9554 } 9555 9556 static if (needsEndTracker) 9557 { 9558 // Check the upcoming slide 9559 auto poppedElements = nextSource.popFrontN(stepSize); 9560 static if (withPartial) 9561 { 9562 if (poppedElements < stepSize || nextSource.empty) 9563 hasShownPartialBefore = true; 9564 } 9565 else 9566 { 9567 if (poppedElements < stepSize) 9568 _empty = true; 9569 } 9570 } 9571 else 9572 { 9573 static if (withPartial) 9574 { 9575 if (source.length <= windowSize) 9576 hasShownPartialBefore = true; 9577 } 9578 else 9579 { 9580 if (source.length < windowSize) 9581 _empty = true; 9582 } 9583 } 9584 } 9585 9586 static if (!isInfinite!Source) 9587 { 9588 /// Ditto 9589 @property bool empty() const 9590 { 9591 return _empty; 9592 } 9593 } 9594 else 9595 { 9596 // undocumented 9597 enum empty = false; 9598 } 9599 9600 /// Ditto 9601 @property typeof(this) save() 9602 { 9603 return typeof(this)(source.save, windowSize, stepSize); 9604 } 9605 9606 static if (hasLength!Source) 9607 { 9608 // gaps between the last element and the end of the range 9609 private size_t gap() 9610 { 9611 /* 9612 * Note: 9613 * - In the following `end` is the exclusive end as used in opSlice 9614 * - For the trivial case with `stepSize = 1` `end` is at `len`: 9615 * 9616 * iota(4).slide(2) = [[0, 1], [1, 2], [2, 3]] (end = 4) 9617 * iota(4).slide(3) = [[0, 1, 2], [1, 2, 3]] (end = 4) 9618 * 9619 * - For the non-trivial cases, we need to calculate the gap 9620 * between `len` and `end` - this is the number of missing elements 9621 * from the input range: 9622 * 9623 * iota(7).slide(2, 3) = [[0, 1], [3, 4]] || <gap: 2> 6 9624 * iota(7).slide(2, 4) = [[0, 1], [4, 5]] || <gap: 1> 6 9625 * iota(7).slide(1, 5) = [[0], [5]] || <gap: 1> 6 9626 * 9627 * As it can be seen `gap` can be at most `stepSize - 1` 9628 * More generally the elements of the sliding window with 9629 * `w = windowSize` and `s = stepSize` are: 9630 * 9631 * [0, w], [s, s + w], [2 * s, 2 * s + w], ... [n * s, n * s + w] 9632 * 9633 * We can thus calculate the gap between the `end` and `len` as: 9634 * 9635 * gap = len - (n * s + w) = len - w - (n * s) 9636 * 9637 * As we aren't interested in exact value of `n`, but the best 9638 * minimal `gap` value, we can use modulo to "cut" `len - w` optimally: 9639 * 9640 * gap = len - w - (s - s ... - s) = (len - w) % s 9641 * 9642 * So for example: 9643 * 9644 * iota(7).slide(2, 3) = [[0, 1], [3, 4]] 9645 * gap: (7 - 2) % 3 = 5 % 3 = 2 9646 * end: 7 - 2 = 5 9647 * 9648 * iota(7).slide(4, 2) = [[0, 1, 2, 3], [2, 3, 4, 5]] 9649 * gap: (7 - 4) % 2 = 3 % 2 = 1 9650 * end: 7 - 1 = 6 9651 */ 9652 return (source.length - windowSize) % stepSize; 9653 } 9654 9655 private size_t numberOfFullFrames() 9656 { 9657 /** 9658 5.iota.slides(2, 1) => [0, 1], [1, 2], [2, 3], [3, 4] (4) 9659 7.iota.slides(2, 2) => [0, 1], [2, 3], [4, 5], [6] (3) 9660 7.iota.slides(2, 3) => [0, 1], [3, 4], [6] (2) 9661 6.iota.slides(3, 2) => [0, 1, 2], [2, 3, 4], [4, 5] (2) 9662 7.iota.slides(3, 3) => [0, 1, 2], [3, 4, 5], [6] (2) 9663 9664 As the last window is only added iff its complete, 9665 we don't count the last window except if it's full due to integer rounding. 9666 */ 9667 return 1 + (source.length - windowSize) / stepSize; 9668 } 9669 9670 // Whether the last slide frame size is less than windowSize 9671 private bool hasPartialElements() 9672 { 9673 static if (withPartial) 9674 return gap != 0 && source.length > numberOfFullFrames * stepSize; 9675 else 9676 return 0; 9677 } 9678 9679 /// Length. Only if `hasLength!Source` is `true` 9680 @property size_t length() 9681 { 9682 if (source.length < windowSize) 9683 { 9684 static if (withPartial) 9685 return source.length > 0; 9686 else 9687 return 0; 9688 } 9689 else 9690 { 9691 /*** 9692 We bump the pointer by stepSize for every element. 9693 If withPartial, we don't count the last element if its size 9694 isn't windowSize 9695 9696 At most: 9697 [p, p + stepSize, ..., p + stepSize * n] 9698 9699 5.iota.slides(2, 1) => [0, 1], [1, 2], [2, 3], [3, 4] (4) 9700 7.iota.slides(2, 2) => [0, 1], [2, 3], [4, 5], [6] (4) 9701 7.iota.slides(2, 3) => [0, 1], [3, 4], [6] (3) 9702 7.iota.slides(3, 2) => [0, 1, 2], [2, 3, 4], [4, 5, 6] (3) 9703 7.iota.slides(3, 3) => [0, 1, 2], [3, 4, 5], [6] (3) 9704 */ 9705 return numberOfFullFrames + hasPartialElements; 9706 } 9707 } 9708 } 9709 9710 static if (hasSlicing!Source) 9711 { 9712 /** 9713 Indexing and slicing operations. Provided only if 9714 `hasSlicing!Source` is `true`. 9715 */ 9716 auto opIndex(size_t index) 9717 { 9718 immutable start = index * stepSize; 9719 9720 static if (isInfinite!Source) 9721 { 9722 immutable end = start + windowSize; 9723 } 9724 else 9725 { 9726 import std.algorithm.comparison : min; 9727 9728 immutable len = source.length; 9729 assert(start < len, "slide index out of bounds"); 9730 immutable end = min(start + windowSize, len); 9731 } 9732 9733 return source[start .. end]; 9734 } 9735 9736 static if (!isInfinite!Source) 9737 { 9738 /// ditto 9739 typeof(this) opSlice(size_t lower, size_t upper) 9740 { 9741 import std.algorithm.comparison : min; 9742 9743 assert(upper <= length, "slide slicing index out of bounds"); 9744 assert(lower <= upper, "slide slicing index out of bounds"); 9745 9746 lower *= stepSize; 9747 upper *= stepSize; 9748 9749 immutable len = source.length; 9750 9751 static if (withPartial) 9752 { 9753 import std.algorithm.comparison : max; 9754 9755 if (lower == upper) 9756 return this[$ .. $]; 9757 9758 /* 9759 A) If `stepSize` >= `windowSize` => `rightPos = upper` 9760 9761 [0, 1, 2, 3, 4, 5, 6].slide(2, 3) -> s = [[0, 1], [3, 4], [6]] 9762 rightPos for s[0 .. 2]: (upper=2) * (stepSize=3) = 6 9763 6.iota.slide(2, 3) = [[0, 1], [3, 4]] 9764 9765 B) If `stepSize` < `windowSize` => add `windowSize - stepSize` to `upper` 9766 9767 [0, 1, 2, 3].slide(2) = [[0, 1], [1, 2], [2, 3]] 9768 rightPos for s[0 .. 1]: = (upper=1) * (stepSize=1) = 1 9769 1.iota.slide(2) = [[0]] 9770 9771 rightPos for s[0 .. 1]: = (upper=1) * (stepSize=1) + (windowSize-stepSize=1) = 2 9772 1.iota.slide(2) = [[0, 1]] 9773 9774 More complex: 9775 9776 20.iota.slide(7, 6)[0 .. 2] 9777 rightPos: (upper=2) * (stepSize=6) = 12.iota 9778 12.iota.slide(7, 6) = [[0, 1, 2, 3, 4, 5, 6], [6, 7, 8, 9, 10, 11]] 9779 9780 Now we add up for the difference between `windowSize` and `stepSize`: 9781 9782 rightPos: (upper=2) * (stepSize=6) + (windowSize-stepSize=1) = 13.iota 9783 13.iota.slide(7, 6) = [[0, 1, 2, 3, 4, 5, 6], [6, 7, 8, 9, 10, 11, 12]] 9784 */ 9785 immutable rightPos = min(len, upper + max(0, windowSize - stepSize)); 9786 } 9787 else 9788 { 9789 /* 9790 After we have normalized `lower` and `upper` by `stepSize`, 9791 we only need to look at the case of `stepSize=1`. 9792 As `leftPos`, is equal to `lower`, we will only look `rightPos`. 9793 Notice that starting from `upper`, 9794 we only need to move for `windowSize - 1` to the right: 9795 9796 - [0, 1, 2, 3].slide(2) -> s = [[0, 1], [1, 2], [2, 3]] 9797 rightPos for s[0 .. 3]: (upper=3) + (windowSize=2) - 1 = 4 9798 9799 - [0, 1, 2, 3].slide(3) -> s = [[0, 1, 2], [1, 2, 3]] 9800 rightPos for s[0 .. 2]: (upper=2) + (windowSize=3) - 1 = 4 9801 9802 - [0, 1, 2, 3, 4].slide(4) -> s = [[0, 1, 2, 3], [1, 2, 3, 4]] 9803 rightPos for s[0 .. 2]: (upper=2) + (windowSize=4) - 1 = 5 9804 */ 9805 immutable rightPos = min(upper + windowSize - 1, len); 9806 } 9807 9808 return typeof(this)(source[min(lower, len) .. rightPos], windowSize, stepSize); 9809 } 9810 } 9811 else static if (hasSliceToEnd) 9812 { 9813 // For slicing an infinite chunk, we need to slice the source to the infinite end. 9814 auto opSlice(size_t lower, size_t upper) 9815 { 9816 assert(lower <= upper, "slide slicing index out of bounds"); 9817 return typeof(this)(source[lower * stepSize .. $], windowSize, stepSize) 9818 .takeExactly(upper - lower); 9819 } 9820 } 9821 9822 static if (isInfinite!Source) 9823 { 9824 static if (hasSliceToEnd) 9825 { 9826 private static struct DollarToken{} 9827 DollarToken opDollar() 9828 { 9829 return DollarToken(); 9830 } 9831 //Slice to dollar 9832 typeof(this) opSlice(size_t lower, DollarToken) 9833 { 9834 return typeof(this)(source[lower * stepSize .. $], windowSize, stepSize); 9835 } 9836 } 9837 } 9838 else 9839 { 9840 // Dollar token carries a static type, with no extra information. 9841 // It can lazily transform into source.length on algorithmic 9842 // operations such as : slide[$/2, $-1]; 9843 private static struct DollarToken 9844 { 9845 private size_t _length; 9846 alias _length this; 9847 } 9848 9849 DollarToken opDollar() 9850 { 9851 return DollarToken(this.length); 9852 } 9853 9854 // Optimized slice overloads optimized for using dollar. 9855 typeof(this) opSlice(DollarToken, DollarToken) 9856 { 9857 static if (hasSliceToEnd) 9858 { 9859 return typeof(this)(source[$ .. $], windowSize, stepSize); 9860 } 9861 else 9862 { 9863 immutable len = source.length; 9864 return typeof(this)(source[len .. len], windowSize, stepSize); 9865 } 9866 } 9867 9868 // Optimized slice overloads optimized for using dollar. 9869 typeof(this) opSlice(size_t lower, DollarToken) 9870 { 9871 import std.algorithm.comparison : min; 9872 assert(lower <= length, "slide slicing index out of bounds"); 9873 lower *= stepSize; 9874 static if (hasSliceToEnd) 9875 { 9876 return typeof(this)(source[min(lower, source.length) .. $], windowSize, stepSize); 9877 } 9878 else 9879 { 9880 immutable len = source.length; 9881 return typeof(this)(source[min(lower, len) .. len], windowSize, stepSize); 9882 } 9883 } 9884 9885 // Optimized slice overloads optimized for using dollar. 9886 typeof(this) opSlice(DollarToken, size_t upper) 9887 { 9888 assert(upper == length, "slide slicing index out of bounds"); 9889 return this[$ .. $]; 9890 } 9891 } 9892 9893 // Bidirectional range primitives 9894 static if (!isInfinite!Source) 9895 { 9896 /** 9897 Bidirectional range primitives. Provided only if both 9898 `hasSlicing!Source` and `!isInfinite!Source` are `true`. 9899 */ 9900 @property auto back() 9901 { 9902 import std.algorithm.comparison : max; 9903 9904 assert(!empty, "Attempting to access front on an empty slide"); 9905 9906 immutable len = source.length; 9907 9908 static if (withPartial) 9909 { 9910 if (source.length <= windowSize) 9911 return source[0 .. source.length]; 9912 9913 if (hasPartialElements) 9914 return source[numberOfFullFrames * stepSize .. len]; 9915 } 9916 9917 // check for underflow 9918 immutable start = (len > windowSize + gap) ? len - windowSize - gap : 0; 9919 return source[start .. len - gap]; 9920 } 9921 9922 /// Ditto 9923 void popBack() 9924 { 9925 assert(!empty, "Attempting to call popBack() on an empty slide"); 9926 9927 // Move by stepSize 9928 immutable end = source.length > stepSize ? source.length - stepSize : 0; 9929 9930 static if (withPartial) 9931 { 9932 if (hasShownPartialBefore || source.empty) 9933 { 9934 _empty = true; 9935 return; 9936 } 9937 9938 // pop by stepSize, except for the partial frame at the end 9939 if (hasPartialElements) 9940 source = source[0 .. source.length - gap]; 9941 else 9942 source = source[0 .. end]; 9943 } 9944 else 9945 { 9946 source = source[0 .. end]; 9947 } 9948 9949 if (source.length < windowSize) 9950 _empty = true; 9951 } 9952 } 9953 } 9954 } 9955 9956 // test @nogc 9957 @safe pure nothrow @nogc unittest 9958 { 9959 import std.algorithm.comparison : equal; 9960 9961 static immutable res1 = [[0], [1], [2], [3]]; 9962 assert(4.iota.slide!(Yes.withPartial)(1).equal!equal(res1)); 9963 9964 static immutable res2 = [[0, 1], [1, 2], [2, 3]]; 9965 assert(4.iota.slide!(Yes.withPartial)(2).equal!equal(res2)); 9966 } 9967 9968 // test different window sizes 9969 @safe pure nothrow unittest 9970 { 9971 import std.array : array; 9972 import std.algorithm.comparison : equal; 9973 9974 assert([0, 1, 2, 3].slide!(Yes.withPartial)(1).array == [[0], [1], [2], [3]]); 9975 assert([0, 1, 2, 3].slide!(Yes.withPartial)(2).array == [[0, 1], [1, 2], [2, 3]]); 9976 assert([0, 1, 2, 3].slide!(Yes.withPartial)(3).array == [[0, 1, 2], [1, 2, 3]]); 9977 assert([0, 1, 2, 3].slide!(Yes.withPartial)(4).array == [[0, 1, 2, 3]]); 9978 assert([0, 1, 2, 3].slide!(No.withPartial)(5).walkLength == 0); 9979 assert([0, 1, 2, 3].slide!(Yes.withPartial)(5).array == [[0, 1, 2, 3]]); 9980 9981 assert(iota(2).slide!(Yes.withPartial)(2).front.equal([0, 1])); 9982 assert(iota(3).slide!(Yes.withPartial)(2).equal!equal([[0, 1],[1, 2]])); 9983 assert(iota(3).slide!(Yes.withPartial)(3).equal!equal([[0, 1, 2]])); 9984 assert(iota(3).slide!(No.withPartial)(4).walkLength == 0); 9985 assert(iota(3).slide!(Yes.withPartial)(4).equal!equal([[0, 1, 2]])); 9986 assert(iota(1, 4).slide!(Yes.withPartial)(1).equal!equal([[1], [2], [3]])); 9987 assert(iota(1, 4).slide!(Yes.withPartial)(3).equal!equal([[1, 2, 3]])); 9988 } 9989 9990 // test combinations 9991 @safe pure nothrow unittest 9992 { 9993 import std.algorithm.comparison : equal; 9994 import std.typecons : tuple; 9995 9996 alias t = tuple; 9997 auto list = [ 9998 t(t(1, 1), [[0], [1], [2], [3], [4], [5]]), 9999 t(t(1, 2), [[0], [2], [4]]), 10000 t(t(1, 3), [[0], [3]]), 10001 t(t(1, 4), [[0], [4]]), 10002 t(t(1, 5), [[0], [5]]), 10003 t(t(2, 1), [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5]]), 10004 t(t(2, 2), [[0, 1], [2, 3], [4, 5]]), 10005 t(t(2, 3), [[0, 1], [3, 4]]), 10006 t(t(2, 4), [[0, 1], [4, 5]]), 10007 t(t(3, 1), [[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5]]), 10008 t(t(3, 3), [[0, 1, 2], [3, 4, 5]]), 10009 t(t(4, 1), [[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]), 10010 t(t(4, 2), [[0, 1, 2, 3], [2, 3, 4, 5]]), 10011 t(t(5, 1), [[0, 1, 2, 3, 4], [1, 2, 3, 4, 5]]), 10012 ]; 10013 10014 static foreach (Partial; [Yes.withPartial, No.withPartial]) 10015 foreach (e; list) 10016 assert(6.iota.slide!Partial(e[0].expand).equal!equal(e[1])); 10017 10018 auto listSpecial = [ 10019 t(t(2, 5), [[0, 1], [5]]), 10020 t(t(3, 2), [[0, 1, 2], [2, 3, 4], [4, 5]]), 10021 t(t(3, 4), [[0, 1, 2], [4, 5]]), 10022 t(t(4, 3), [[0, 1, 2, 3], [3, 4, 5]]), 10023 t(t(5, 2), [[0, 1, 2, 3, 4], [2, 3, 4, 5]]), 10024 t(t(5, 3), [[0, 1, 2, 3, 4], [3, 4, 5]]), 10025 ]; 10026 foreach (e; listSpecial) 10027 { 10028 assert(6.iota.slide!(Yes.withPartial)(e[0].expand).equal!equal(e[1])); 10029 assert(6.iota.slide!(No.withPartial)(e[0].expand).equal!equal(e[1].dropBackOne)); 10030 } 10031 } 10032 10033 // test emptiness and copyability 10034 @safe pure nothrow unittest 10035 { 10036 import std.algorithm.comparison : equal; 10037 import std.algorithm.iteration : map; 10038 10039 // check with empty input 10040 int[] d; 10041 assert(d.slide!(Yes.withPartial)(2).empty); 10042 assert(d.slide!(Yes.withPartial)(2, 2).empty); 10043 10044 // is copyable? 10045 auto e = iota(5).slide!(Yes.withPartial)(2); 10046 e.popFront; 10047 assert(e.save.equal!equal([[1, 2], [2, 3], [3, 4]])); 10048 assert(e.save.equal!equal([[1, 2], [2, 3], [3, 4]])); 10049 assert(e.map!"a.array".array == [[1, 2], [2, 3], [3, 4]]); 10050 } 10051 10052 // test with strings 10053 @safe pure nothrow unittest 10054 { 10055 import std.algorithm.iteration : each; 10056 10057 int[dstring] f; 10058 "AGAGA"d.slide!(Yes.withPartial)(3).each!(a => f[a]++); 10059 assert(f == ["AGA"d: 2, "GAG"d: 1]); 10060 10061 int[dstring] g; 10062 "ABCDEFG"d.slide!(Yes.withPartial)(3, 3).each!(a => g[a]++); 10063 assert(g == ["ABC"d:1, "DEF"d:1, "G": 1]); 10064 g = null; 10065 "ABCDEFG"d.slide!(No.withPartial)(3, 3).each!(a => g[a]++); 10066 assert(g == ["ABC"d:1, "DEF"d:1]); 10067 } 10068 10069 // test with utf8 strings 10070 @safe unittest 10071 { 10072 import std.stdio; 10073 import std.algorithm.comparison : equal; 10074 10075 assert("ä.ö.ü.".slide!(Yes.withPartial)(3, 2).equal!equal(["ä.ö", "ö.ü", "ü."])); 10076 assert("ä.ö.ü.".slide!(No.withPartial)(3, 2).equal!equal(["ä.ö", "ö.ü"])); 10077 10078 "😄😅😆😇😈😄😅😆😇😈".slide!(Yes.withPartial)(2, 4).equal!equal(["😄😅", "😈😄", "😇😈"]); 10079 "😄😅😆😇😈😄😅😆😇😈".slide!(No.withPartial)(2, 4).equal!equal(["😄😅", "😈😄", "😇😈"]); 10080 "😄😅😆😇😈😄😅😆😇😈".slide!(Yes.withPartial)(3, 3).equal!equal(["😄😅😆", "😇😈😄", "😅😆😇", "😈"]); 10081 "😄😅😆😇😈😄😅😆😇😈".slide!(No.withPartial)(3, 3).equal!equal(["😄😅😆", "😇😈😄", "😅😆😇"]); 10082 } 10083 10084 // test length 10085 @safe pure nothrow unittest 10086 { 10087 // Slides with fewer elements are empty or 1 for Yes.withPartial 10088 static foreach (expectedLength, Partial; [No.withPartial, Yes.withPartial]) 10089 {{ 10090 assert(3.iota.slide!(Partial)(4, 2).walkLength == expectedLength); 10091 assert(3.iota.slide!(Partial)(4).walkLength == expectedLength); 10092 assert(3.iota.slide!(Partial)(4, 3).walkLength == expectedLength); 10093 }} 10094 10095 static immutable list = [ 10096 // iota slide expected 10097 [4, 2, 1, 3, 3], 10098 [5, 3, 1, 3, 3], 10099 [7, 2, 2, 4, 3], 10100 [12, 2, 4, 3, 3], 10101 [6, 1, 2, 3, 3], 10102 [6, 2, 4, 2, 2], 10103 [3, 2, 4, 1, 1], 10104 [5, 2, 1, 4, 4], 10105 [7, 2, 2, 4, 3], 10106 [7, 2, 3, 3, 2], 10107 [7, 3, 2, 3, 3], 10108 [7, 3, 3, 3, 2], 10109 ]; 10110 foreach (e; list) 10111 { 10112 assert(e[0].iota.slide!(Yes.withPartial)(e[1], e[2]).length == e[3]); 10113 assert(e[0].iota.slide!(No.withPartial)(e[1], e[2]).length == e[4]); 10114 } 10115 } 10116 10117 // test index and slicing 10118 @safe pure nothrow unittest 10119 { 10120 import std.algorithm.comparison : equal; 10121 import std.array : array; 10122 10123 static foreach (Partial; [Yes.withPartial, No.withPartial]) 10124 { 10125 foreach (s; [5, 7, 10, 15, 20]) 10126 foreach (windowSize; 1 .. 10) 10127 foreach (stepSize; 1 .. 10) 10128 { 10129 auto r = s.iota.slide!Partial(windowSize, stepSize); 10130 auto arr = r.array; 10131 assert(r.length == arr.length); 10132 10133 // test indexing 10134 foreach (i; 0 .. arr.length) 10135 assert(r[i] == arr[i]); 10136 10137 // test slicing 10138 foreach (i; 0 .. arr.length) 10139 { 10140 foreach (j; i .. arr.length) 10141 assert(r[i .. j].equal(arr[i .. j])); 10142 10143 assert(r[i .. $].equal(arr[i .. $])); 10144 } 10145 10146 // test opDollar slicing 10147 assert(r[$/2 .. $].equal(arr[$/2 .. $])); 10148 assert(r[$ .. $].empty); 10149 if (arr.empty) 10150 { 10151 assert(r[$ .. 0].empty); 10152 assert(r[$/2 .. $].empty); 10153 10154 } 10155 } 10156 } 10157 } 10158 10159 // test with infinite ranges 10160 @safe pure nothrow unittest 10161 { 10162 import std.algorithm.comparison : equal; 10163 10164 static foreach (Partial; [Yes.withPartial, No.withPartial]) 10165 {{ 10166 // InfiniteRange without RandomAccess 10167 auto fibs = recurrence!"a[n-1] + a[n-2]"(1, 1); 10168 assert(fibs.slide!Partial(2).take(2).equal!equal([[1, 1], [1, 2]])); 10169 assert(fibs.slide!Partial(2, 3).take(2).equal!equal([[1, 1], [3, 5]])); 10170 10171 // InfiniteRange with RandomAccess and slicing 10172 auto odds = sequence!("a[0] + n * a[1]")(1, 2); 10173 auto oddsByPairs = odds.slide!Partial(2); 10174 assert(oddsByPairs.take(2).equal!equal([[ 1, 3], [ 3, 5]])); 10175 assert(oddsByPairs[1].equal([3, 5])); 10176 assert(oddsByPairs[4].equal([9, 11])); 10177 10178 static assert(hasSlicing!(typeof(odds))); 10179 assert(oddsByPairs[3 .. 5].equal!equal([[7, 9], [9, 11]])); 10180 assert(oddsByPairs[3 .. $].take(2).equal!equal([[7, 9], [9, 11]])); 10181 10182 auto oddsWithGaps = odds.slide!Partial(2, 4); 10183 assert(oddsWithGaps.take(3).equal!equal([[1, 3], [9, 11], [17, 19]])); 10184 assert(oddsWithGaps[2].equal([17, 19])); 10185 assert(oddsWithGaps[1 .. 3].equal!equal([[9, 11], [17, 19]])); 10186 assert(oddsWithGaps[1 .. $].take(2).equal!equal([[9, 11], [17, 19]])); 10187 }} 10188 } 10189 10190 // test reverse 10191 @safe pure nothrow unittest 10192 { 10193 import std.algorithm.comparison : equal; 10194 10195 static foreach (Partial; [Yes.withPartial, No.withPartial]) 10196 {{ 10197 foreach (windowSize; 1 .. 15) 10198 foreach (stepSize; 1 .. 15) 10199 { 10200 auto r = 20.iota.slide!Partial(windowSize, stepSize); 10201 auto rArr = r.array.retro; 10202 auto rRetro = r.retro; 10203 10204 assert(rRetro.length == rArr.length); 10205 assert(rRetro.equal(rArr)); 10206 assert(rRetro.array.retro.equal(r)); 10207 } 10208 }} 10209 } 10210 10211 // test with dummy ranges 10212 @safe pure nothrow unittest 10213 { 10214 import std.algorithm.comparison : equal; 10215 import std.internal.test.dummyrange : AllDummyRanges; 10216 import std.meta : Filter; 10217 10218 static foreach (Range; Filter!(isForwardRange, AllDummyRanges)) 10219 {{ 10220 Range r; 10221 10222 static foreach (Partial; [Yes.withPartial, No.withPartial]) 10223 { 10224 assert(r.slide!Partial(1).equal!equal( 10225 [[1], [2], [3], [4], [5], [6], [7], [8], [9], [10]] 10226 )); 10227 assert(r.slide!Partial(2).equal!equal( 10228 [[1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9], [9, 10]] 10229 )); 10230 assert(r.slide!Partial(3).equal!equal( 10231 [[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6], 10232 [5, 6, 7], [6, 7, 8], [7, 8, 9], [8, 9, 10]] 10233 )); 10234 assert(r.slide!Partial(6).equal!equal( 10235 [[1, 2, 3, 4, 5, 6], [2, 3, 4, 5, 6, 7], [3, 4, 5, 6, 7, 8], 10236 [4, 5, 6, 7, 8, 9], [5, 6, 7, 8, 9, 10]] 10237 )); 10238 } 10239 10240 // special cases 10241 assert(r.slide!(Yes.withPartial)(15).equal!equal(iota(1, 11).only)); 10242 assert(r.slide!(Yes.withPartial)(15).walkLength == 1); 10243 assert(r.slide!(No.withPartial)(15).empty); 10244 assert(r.slide!(No.withPartial)(15).walkLength == 0); 10245 }} 10246 } 10247 10248 // test with dummy ranges 10249 @safe pure nothrow unittest 10250 { 10251 import std.algorithm.comparison : equal; 10252 import std.internal.test.dummyrange : AllDummyRanges; 10253 import std.meta : Filter; 10254 import std.typecons : tuple; 10255 10256 alias t = tuple; 10257 static immutable list = [ 10258 // iota slide expected 10259 t(6, t(4, 2), [[1, 2, 3, 4], [3, 4, 5, 6]]), 10260 t(6, t(4, 6), [[1, 2, 3, 4]]), 10261 t(6, t(4, 1), [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6]]), 10262 t(7, t(4, 1), [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 6, 7]]), 10263 t(7, t(4, 3), [[1, 2, 3, 4], [4, 5, 6, 7]]), 10264 t(8, t(4, 2), [[1, 2, 3, 4], [3, 4, 5, 6], [5, 6, 7, 8]]), 10265 t(8, t(4, 1), [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 6, 7], [5, 6, 7, 8]]), 10266 t(8, t(3, 4), [[1, 2, 3], [5, 6, 7]]), 10267 t(10, t(3, 7), [[1, 2, 3], [8, 9, 10]]), 10268 ]; 10269 10270 static foreach (Range; Filter!(isForwardRange, AllDummyRanges)) 10271 static foreach (Partial; [Yes.withPartial, No.withPartial]) 10272 foreach (e; list) 10273 assert(Range().take(e[0]).slide!Partial(e[1].expand).equal!equal(e[2])); 10274 10275 static immutable listSpecial = [ 10276 // iota slide expected 10277 t(6, t(4, 3), [[1, 2, 3, 4], [4, 5, 6]]), 10278 t(7, t(4, 5), [[1, 2, 3, 4], [6, 7]]), 10279 t(7, t(4, 4), [[1, 2, 3, 4], [5, 6, 7]]), 10280 t(7, t(4, 2), [[1, 2, 3, 4], [3, 4, 5, 6], [5, 6, 7]]), 10281 t(8, t(4, 3), [[1, 2, 3, 4], [4, 5, 6, 7], [7, 8]]), 10282 t(8, t(3, 3), [[1, 2, 3], [4, 5, 6], [7, 8]]), 10283 t(8, t(3, 6), [[1, 2, 3], [7, 8]]), 10284 t(10, t(7, 6), [[1, 2, 3, 4, 5, 6, 7], [7, 8, 9, 10]]), 10285 t(10, t(3, 8), [[1, 2, 3], [9, 10]]), 10286 ]; 10287 static foreach (Range; Filter!(isForwardRange, AllDummyRanges)) 10288 static foreach (Partial; [Yes.withPartial, No.withPartial]) 10289 foreach (e; listSpecial) 10290 { 10291 Range r; 10292 assert(r.take(e[0]).slide!(Yes.withPartial)(e[1].expand).equal!equal(e[2])); 10293 assert(r.take(e[0]).slide!(No.withPartial)(e[1].expand).equal!equal(e[2].dropBackOne)); 10294 } 10295 } 10296 10297 // test reverse with dummy ranges 10298 @safe pure nothrow unittest 10299 { 10300 import std.algorithm.comparison : equal; 10301 import std.internal.test.dummyrange : AllDummyRanges; 10302 import std.meta : Filter, templateAnd; 10303 import std.typecons : tuple; 10304 alias t = tuple; 10305 10306 static immutable list = [ 10307 // slide expected 10308 t(1, 1, [[10], [9], [8], [7], [6], [5], [4], [3], [2], [1]]), 10309 t(2, 1, [[9, 10], [8, 9], [7, 8], [6, 7], [5, 6], [4, 5], [3, 4], [2, 3], [1, 2]]), 10310 t(5, 1, [[6, 7, 8, 9, 10], [5, 6, 7, 8, 9], [4, 5, 6, 7, 8], 10311 [3, 4, 5, 6, 7], [2, 3, 4, 5, 6], [1, 2, 3, 4, 5]]), 10312 t(2, 2, [[9, 10], [7, 8], [5, 6], [3, 4], [1, 2]]), 10313 t(2, 4, [[9, 10], [5, 6], [1, 2]]), 10314 ]; 10315 10316 static foreach (Range; Filter!(templateAnd!(hasSlicing, hasLength, isBidirectionalRange), AllDummyRanges)) 10317 {{ 10318 Range r; 10319 static foreach (Partial; [Yes.withPartial, No.withPartial]) 10320 { 10321 foreach (e; list) 10322 assert(r.slide!Partial(e[0], e[1]).retro.equal!equal(e[2])); 10323 10324 // front = back 10325 foreach (windowSize; 1 .. 10) 10326 foreach (stepSize; 1 .. 10) 10327 { 10328 auto slider = r.slide!Partial(windowSize, stepSize); 10329 auto sliderRetro = slider.retro.array; 10330 assert(slider.length == sliderRetro.length); 10331 assert(sliderRetro.retro.equal!equal(slider)); 10332 } 10333 } 10334 10335 // special cases 10336 assert(r.slide!(No.withPartial)(15).retro.walkLength == 0); 10337 assert(r.slide!(Yes.withPartial)(15).retro.equal!equal(iota(1, 11).only)); 10338 }} 10339 } 10340 10341 // test different sliceable ranges 10342 @safe pure nothrow unittest 10343 { 10344 import std.algorithm.comparison : equal; 10345 import std.internal.test.dummyrange : AllDummyRanges; 10346 import std.meta : AliasSeq; 10347 10348 struct SliceableRange(Range, Flag!"withOpDollar" withOpDollar = No.withOpDollar, 10349 Flag!"withInfiniteness" withInfiniteness = No.withInfiniteness) 10350 { 10351 Range arr = 10.iota.array; // similar to DummyRange 10352 @property auto save() { return typeof(this)(arr); } 10353 @property auto front() { return arr[0]; } 10354 void popFront() { arr.popFront(); } 10355 auto opSlice(size_t i, size_t j) 10356 { 10357 // subslices can't be infinite 10358 return SliceableRange!(Range, withOpDollar, No.withInfiniteness)(arr[i .. j]); 10359 } 10360 10361 static if (withInfiniteness) 10362 { 10363 enum empty = false; 10364 } 10365 else 10366 { 10367 @property bool empty() { return arr.empty; } 10368 @property auto length() { return arr.length; } 10369 } 10370 10371 static if (withOpDollar) 10372 { 10373 static if (withInfiniteness) 10374 { 10375 struct Dollar {} 10376 Dollar opDollar() const { return Dollar.init; } 10377 10378 // Slice to dollar 10379 typeof(this) opSlice(size_t lower, Dollar) 10380 { 10381 return typeof(this)(arr[lower .. $]); 10382 } 10383 10384 } 10385 else 10386 { 10387 alias opDollar = length; 10388 } 10389 } 10390 } 10391 10392 import std.meta : Filter, templateNot; 10393 alias SliceableDummyRanges = Filter!(hasSlicing, AllDummyRanges); 10394 10395 static foreach (Partial; [Yes.withPartial, No.withPartial]) 10396 {{ 10397 static foreach (Range; SliceableDummyRanges) 10398 {{ 10399 Range r; 10400 r.reinit; 10401 r.arr[] -= 1; // use a 0-based array (for clarity) 10402 10403 assert(r.slide!Partial(2)[0].equal([0, 1])); 10404 assert(r.slide!Partial(2)[1].equal([1, 2])); 10405 10406 // saveable 10407 auto s = r.slide!Partial(2); 10408 assert(s[0 .. 2].equal!equal([[0, 1], [1, 2]])); 10409 s.save.popFront; 10410 assert(s[0 .. 2].equal!equal([[0, 1], [1, 2]])); 10411 10412 assert(r.slide!Partial(3)[1 .. 3].equal!equal([[1, 2, 3], [2, 3, 4]])); 10413 }} 10414 10415 static foreach (Range; Filter!(templateNot!isInfinite, SliceableDummyRanges)) 10416 {{ 10417 Range r; 10418 r.reinit; 10419 r.arr[] -= 1; // use a 0-based array (for clarity) 10420 10421 assert(r.slide!(No.withPartial)(6).equal!equal( 10422 [[0, 1, 2, 3, 4, 5], [1, 2, 3, 4, 5, 6], [2, 3, 4, 5, 6, 7], 10423 [3, 4, 5, 6, 7, 8], [4, 5, 6, 7, 8, 9]] 10424 )); 10425 assert(r.slide!(No.withPartial)(16).empty); 10426 10427 assert(r.slide!Partial(4)[0 .. $].equal(r.slide!Partial(4))); 10428 assert(r.slide!Partial(2)[$/2 .. $].equal!equal([[4, 5], [5, 6], [6, 7], [7, 8], [8, 9]])); 10429 assert(r.slide!Partial(2)[$ .. $].empty); 10430 10431 assert(r.slide!Partial(3).retro.equal!equal( 10432 [[7, 8, 9], [6, 7, 8], [5, 6, 7], [4, 5, 6], [3, 4, 5], [2, 3, 4], [1, 2, 3], [0, 1, 2]] 10433 )); 10434 }} 10435 10436 alias T = int[]; 10437 10438 // separate checks for infinity 10439 auto infIndex = SliceableRange!(T, No.withOpDollar, Yes.withInfiniteness)([0, 1, 2, 3]); 10440 assert(infIndex.slide!Partial(2)[0].equal([0, 1])); 10441 assert(infIndex.slide!Partial(2)[1].equal([1, 2])); 10442 10443 auto infDollar = SliceableRange!(T, Yes.withOpDollar, Yes.withInfiniteness)(); 10444 assert(infDollar.slide!Partial(2)[1 .. $].front.equal([1, 2])); 10445 assert(infDollar.slide!Partial(4)[0 .. $].front.equal([0, 1, 2, 3])); 10446 assert(infDollar.slide!Partial(4)[2 .. $].front.equal([2, 3, 4, 5])); 10447 }} 10448 } 10449 10450 // https://issues.dlang.org/show_bug.cgi?id=19082 10451 @safe unittest 10452 { 10453 import std.algorithm.comparison : equal; 10454 import std.algorithm.iteration : map; 10455 assert([1].map!(x => x).slide(2).equal!equal([[1]])); 10456 } 10457 10458 // https://issues.dlang.org/show_bug.cgi?id=19642 10459 @safe unittest 10460 { 10461 import std.algorithm.comparison : equal; 10462 import std.algorithm.iteration : splitter; 10463 10464 assert("ab cd".splitter(' ').slide!(No.withPartial)(2).equal!equal([["ab", "cd"]])); 10465 } 10466 10467 // https://issues.dlang.org/show_bug.cgi?id=23976 10468 @safe unittest 10469 { 10470 import std.algorithm.comparison : equal; 10471 import std.algorithm.iteration : splitter; 10472 10473 assert("1<2".splitter('<').slide(2).equal!equal([["1", "2"]])); 10474 } 10475 10476 private struct OnlyResult(Values...) 10477 if (Values.length > 1) 10478 { 10479 import std.meta : ApplyRight; 10480 import std.traits : isAssignable; 10481 10482 private enum arity = Values.length; 10483 10484 private alias UnqualValues = staticMap!(Unqual, Values); 10485 10486 private enum canAssignElements = allSatisfy!( 10487 ApplyRight!(isAssignable, CommonType!Values), 10488 Values 10489 ); 10490 10491 private this(return scope ref Values values) 10492 { 10493 ref @trusted unqual(T)(ref T x){return cast() x;} 10494 10495 // TODO: this calls any possible copy constructors without qualifiers. 10496 // Find a way to initialize values using qualified copy constructors. 10497 static foreach (i; 0 .. Values.length) 10498 { 10499 this.values[i] = unqual(values[i]); 10500 } 10501 this.backIndex = arity; 10502 } 10503 10504 bool empty() @property 10505 { 10506 return frontIndex >= backIndex; 10507 } 10508 10509 CommonType!Values front() @property 10510 { 10511 assert(!empty, "Attempting to fetch the front of an empty Only range"); 10512 return this[0]; 10513 } 10514 10515 static if (canAssignElements) 10516 { 10517 void front(CommonType!Values value) @property 10518 { 10519 assert(!empty, "Attempting to assign the front of an empty Only range"); 10520 this[0] = value; 10521 } 10522 } 10523 10524 void popFront() 10525 { 10526 assert(!empty, "Attempting to popFront an empty Only range"); 10527 ++frontIndex; 10528 } 10529 10530 CommonType!Values back() @property 10531 { 10532 assert(!empty, "Attempting to fetch the back of an empty Only range"); 10533 return this[$ - 1]; 10534 } 10535 10536 static if (canAssignElements) 10537 { 10538 void back(CommonType!Values value) @property 10539 { 10540 assert(!empty, "Attempting to assign the back of an empty Only range"); 10541 this[$ - 1] = value; 10542 } 10543 } 10544 10545 void popBack() 10546 { 10547 assert(!empty, "Attempting to popBack an empty Only range"); 10548 --backIndex; 10549 } 10550 10551 OnlyResult save() @property 10552 { 10553 return this; 10554 } 10555 10556 size_t length() const @property 10557 { 10558 return backIndex - frontIndex; 10559 } 10560 10561 alias opDollar = length; 10562 10563 @trusted CommonType!Values opIndex(size_t idx) 10564 { 10565 // when i + idx points to elements popped 10566 // with popBack 10567 assert(idx < length, "Attempting to fetch an out of bounds index from an Only range"); 10568 final switch (frontIndex + idx) 10569 static foreach (i, T; Values) 10570 case i: 10571 return cast(T) values[i]; 10572 } 10573 10574 static if (canAssignElements) 10575 { 10576 void opIndexAssign(CommonType!Values value, size_t idx) 10577 { 10578 assert(idx < length, "Attempting to assign to an out of bounds index of an Only range"); 10579 final switch (frontIndex + idx) 10580 static foreach (i; 0 .. Values.length) 10581 case i: 10582 values[i] = value; 10583 } 10584 } 10585 10586 OnlyResult opSlice() 10587 { 10588 return this; 10589 } 10590 10591 OnlyResult opSlice(size_t from, size_t to) 10592 { 10593 OnlyResult result = this; 10594 result.frontIndex += from; 10595 result.backIndex = this.frontIndex + to; 10596 assert( 10597 from <= to, 10598 "Attempting to slice an Only range with a larger first argument than the second." 10599 ); 10600 assert( 10601 to <= length, 10602 "Attempting to slice using an out of bounds index on an Only range" 10603 ); 10604 return result; 10605 } 10606 10607 private size_t frontIndex = 0; 10608 private size_t backIndex = 0; 10609 10610 // https://issues.dlang.org/show_bug.cgi?id=10643 10611 version (none) 10612 { 10613 import std.traits : hasElaborateAssign; 10614 static if (hasElaborateAssign!T) 10615 private UnqualValues values; 10616 else 10617 private UnqualValues values = void; 10618 } 10619 else 10620 // These may alias to shared or immutable data. Do not let the user 10621 // to access these directly, and do not allow mutation without checking 10622 // the qualifier. 10623 private UnqualValues values; 10624 } 10625 10626 // Specialize for single-element results 10627 private struct OnlyResult(T) 10628 { 10629 import std.traits : isAssignable; 10630 10631 @property T front() 10632 { 10633 assert(!empty, "Attempting to fetch the front of an empty Only range"); 10634 return fetchFront(); 10635 } 10636 static if (isAssignable!T) 10637 { 10638 @property void front(T value) 10639 { 10640 assert(!empty, "Attempting to assign the front of an empty Only range"); 10641 assignFront(value); 10642 } 10643 } 10644 @property T back() 10645 { 10646 assert(!empty, "Attempting to fetch the back of an empty Only range"); 10647 return fetchFront(); 10648 } 10649 static if (isAssignable!T) 10650 { 10651 @property void back(T value) 10652 { 10653 assert(!empty, "Attempting to assign the front of an empty Only range"); 10654 assignFront(value); 10655 } 10656 } 10657 @property bool empty() const { return _empty; } 10658 @property size_t length() const { return !_empty; } 10659 @property auto save() { return this; } 10660 void popFront() 10661 { 10662 assert(!_empty, "Attempting to popFront an empty Only range"); 10663 _empty = true; 10664 } 10665 void popBack() 10666 { 10667 assert(!_empty, "Attempting to popBack an empty Only range"); 10668 _empty = true; 10669 } 10670 alias opDollar = length; 10671 10672 // FIXME Workaround for https://issues.dlang.org/show_bug.cgi?id=24415 10673 import std.traits : hasElaborateCopyConstructor; 10674 static if (hasElaborateCopyConstructor!T) 10675 { 10676 private static struct WorkaroundBugzilla24415 {} 10677 public this()(WorkaroundBugzilla24415) {} 10678 } 10679 10680 private this()(return scope auto ref T value) 10681 { 10682 ref @trusted unqual(ref T x){return cast() x;} 10683 // TODO: this calls the possible copy constructor without qualifiers. 10684 // Find a way to initialize value using a qualified copy constructor. 10685 this._value = unqual(value); 10686 this._empty = false; 10687 } 10688 10689 T opIndex(size_t i) 10690 { 10691 assert(!_empty && i == 0, "Attempting to fetch an out of bounds index from an Only range"); 10692 return fetchFront(); 10693 } 10694 10695 static if (isAssignable!T) 10696 { 10697 void opIndexAssign(T value, size_t i) 10698 { 10699 assert(!_empty && i == 0, "Attempting to assign an out of bounds index of an Only range"); 10700 assignFront(value); 10701 } 10702 } 10703 10704 OnlyResult opSlice() 10705 { 10706 return this; 10707 } 10708 10709 OnlyResult opSlice(size_t from, size_t to) 10710 { 10711 assert( 10712 from <= to, 10713 "Attempting to slice an Only range with a larger first argument than the second." 10714 ); 10715 assert( 10716 to <= length, 10717 "Attempting to slice using an out of bounds index on an Only range" 10718 ); 10719 OnlyResult copy = this; 10720 copy._empty = _empty || from == to; 10721 return copy; 10722 } 10723 10724 // This may alias to shared or immutable data. Do not let the user 10725 // to access this directly, and do not allow mutation without checking 10726 // the qualifier. 10727 private Unqual!T _value; 10728 private bool _empty = true; 10729 private @trusted T fetchFront() 10730 { 10731 return *cast(T*)&_value; 10732 } 10733 static if (isAssignable!T) 10734 { 10735 private @trusted void assignFront(T newValue) 10736 { 10737 *cast(T*) &_value = newValue; 10738 } 10739 } 10740 } 10741 10742 /** 10743 Assemble `values` into a range that carries all its 10744 elements in-situ. 10745 10746 Useful when a single value or multiple disconnected values 10747 must be passed to an algorithm expecting a range, without 10748 having to perform dynamic memory allocation. 10749 10750 As copying the range means copying all elements, it can be 10751 safely returned from functions. For the same reason, copying 10752 the returned range may be expensive for a large number of arguments. 10753 10754 Params: 10755 values = the values to assemble together 10756 10757 Returns: 10758 A `RandomAccessRange` of the assembled values. 10759 10760 The returned range can be sliced. Its elements can be assigned to if every 10761 type in `Values` supports assignment from the range's element type. 10762 10763 See_Also: $(LREF chain) to chain ranges 10764 */ 10765 auto only(Values...)(return scope Values values) 10766 if (!is(CommonType!Values == void)) 10767 { 10768 return OnlyResult!Values(values); 10769 } 10770 10771 /// ditto 10772 auto only()() 10773 { 10774 // cannot use noreturn due to https://issues.dlang.org/show_bug.cgi?id=22383 10775 struct EmptyElementType {} 10776 EmptyElementType[] result; 10777 return result; 10778 } 10779 10780 /// 10781 @safe unittest 10782 { 10783 import std.algorithm.comparison : equal; 10784 import std.algorithm.iteration : filter, joiner, map; 10785 import std.algorithm.searching : findSplitBefore; 10786 import std.uni : isUpper; 10787 10788 assert(equal(only('♡'), "♡")); 10789 assert([1, 2, 3, 4].findSplitBefore(only(3))[0] == [1, 2]); 10790 10791 assert(only("one", "two", "three").joiner(" ").equal("one two three")); 10792 10793 string title = "The D Programming Language"; 10794 assert(title 10795 .filter!isUpper // take the upper case letters 10796 .map!only // make each letter its own range 10797 .joiner(".") // join the ranges together lazily 10798 .equal("T.D.P.L")); 10799 } 10800 10801 // https://issues.dlang.org/show_bug.cgi?id=20314 10802 @safe unittest 10803 { 10804 import std.algorithm.iteration : joiner; 10805 10806 const string s = "foo", t = "bar"; 10807 10808 assert([only(s, t), only(t, s)].joiner(only(", ")).join == "foobar, barfoo"); 10809 } 10810 10811 // Tests the zero-element result 10812 @safe unittest 10813 { 10814 import std.algorithm.comparison : equal; 10815 10816 auto emptyRange = only(); 10817 10818 alias EmptyRange = typeof(emptyRange); 10819 static assert(isInputRange!EmptyRange); 10820 static assert(isForwardRange!EmptyRange); 10821 static assert(isBidirectionalRange!EmptyRange); 10822 static assert(isRandomAccessRange!EmptyRange); 10823 static assert(hasLength!EmptyRange); 10824 static assert(hasSlicing!EmptyRange); 10825 10826 assert(emptyRange.empty); 10827 assert(emptyRange.length == 0); 10828 assert(emptyRange.equal(emptyRange[])); 10829 assert(emptyRange.equal(emptyRange.save)); 10830 assert(emptyRange[0 .. 0].equal(emptyRange)); 10831 } 10832 10833 // Tests the single-element result 10834 @safe unittest 10835 { 10836 import std.algorithm.comparison : equal; 10837 import std.typecons : tuple; 10838 foreach (x; tuple(1, '1', 1.0, "1", [1])) 10839 { 10840 auto a = only(x); 10841 typeof(x)[] e = []; 10842 assert(a.front == x); 10843 assert(a.back == x); 10844 assert(!a.empty); 10845 assert(a.length == 1); 10846 assert(equal(a, a[])); 10847 assert(equal(a, a[0 .. 1])); 10848 assert(equal(a[0 .. 0], e)); 10849 assert(equal(a[1 .. 1], e)); 10850 assert(a[0] == x); 10851 10852 auto b = a.save; 10853 assert(equal(a, b)); 10854 a.popFront(); 10855 assert(a.empty && a.length == 0 && a[].empty); 10856 b.popBack(); 10857 assert(b.empty && b.length == 0 && b[].empty); 10858 10859 alias A = typeof(a); 10860 static assert(isInputRange!A); 10861 static assert(isForwardRange!A); 10862 static assert(isBidirectionalRange!A); 10863 static assert(isRandomAccessRange!A); 10864 static assert(hasLength!A); 10865 static assert(hasSlicing!A); 10866 } 10867 10868 auto imm = only!(immutable int)(1); 10869 immutable int[] imme = []; 10870 assert(imm.front == 1); 10871 assert(imm.back == 1); 10872 assert(!imm.empty); 10873 assert(imm.init.empty); // https://issues.dlang.org/show_bug.cgi?id=13441 10874 assert(imm.length == 1); 10875 assert(equal(imm, imm[])); 10876 assert(equal(imm, imm[0 .. 1])); 10877 assert(equal(imm[0 .. 0], imme)); 10878 assert(equal(imm[1 .. 1], imme)); 10879 assert(imm[0] == 1); 10880 } 10881 10882 // Tests multiple-element results 10883 @safe unittest 10884 { 10885 import std.algorithm.comparison : equal; 10886 import std.algorithm.iteration : joiner; 10887 import std.meta : AliasSeq; 10888 static assert(!__traits(compiles, only(1, "1"))); 10889 10890 auto nums = only!(byte, uint, long)(1, 2, 3); 10891 static assert(is(ElementType!(typeof(nums)) == long)); 10892 assert(nums.length == 3); 10893 10894 foreach (i; 0 .. 3) 10895 assert(nums[i] == i + 1); 10896 10897 auto saved = nums.save; 10898 10899 foreach (i; 1 .. 4) 10900 { 10901 assert(nums.front == nums[0]); 10902 assert(nums.front == i); 10903 nums.popFront(); 10904 assert(nums.length == 3 - i); 10905 } 10906 10907 assert(nums.empty); 10908 10909 assert(saved.equal(only(1, 2, 3))); 10910 assert(saved.equal(saved[])); 10911 assert(saved[0 .. 1].equal(only(1))); 10912 assert(saved[0 .. 2].equal(only(1, 2))); 10913 assert(saved[0 .. 3].equal(saved)); 10914 assert(saved[1 .. 3].equal(only(2, 3))); 10915 assert(saved[2 .. 3].equal(only(3))); 10916 assert(saved[0 .. 0].empty); 10917 assert(saved[3 .. 3].empty); 10918 10919 alias data = AliasSeq!("one", "two", "three", "four"); 10920 static joined = 10921 ["one two", "one two three", "one two three four"]; 10922 string[] joinedRange = joined; 10923 10924 static foreach (argCount; 2 .. 5) 10925 {{ 10926 auto values = only(data[0 .. argCount]); 10927 alias Values = typeof(values); 10928 static assert(is(ElementType!Values == string)); 10929 static assert(isInputRange!Values); 10930 static assert(isForwardRange!Values); 10931 static assert(isBidirectionalRange!Values); 10932 static assert(isRandomAccessRange!Values); 10933 static assert(hasSlicing!Values); 10934 static assert(hasLength!Values); 10935 10936 assert(values.length == argCount); 10937 assert(values[0 .. $].equal(values[0 .. values.length])); 10938 assert(values.joiner(" ").equal(joinedRange.front)); 10939 joinedRange.popFront(); 10940 }} 10941 10942 assert(saved.retro.equal(only(3, 2, 1))); 10943 assert(saved.length == 3); 10944 10945 assert(saved.back == 3); 10946 saved.popBack(); 10947 assert(saved.length == 2); 10948 assert(saved.back == 2); 10949 10950 assert(saved.front == 1); 10951 saved.popFront(); 10952 assert(saved.length == 1); 10953 assert(saved.front == 2); 10954 10955 saved.popBack(); 10956 assert(saved.empty); 10957 10958 auto imm = only!(immutable int, immutable int)(42, 24); 10959 alias Imm = typeof(imm); 10960 static assert(is(ElementType!Imm == immutable(int))); 10961 assert(!imm.empty); 10962 assert(imm.init.empty); // https://issues.dlang.org/show_bug.cgi?id=13441 10963 assert(imm.front == 42); 10964 imm.popFront(); 10965 assert(imm.front == 24); 10966 imm.popFront(); 10967 assert(imm.empty); 10968 10969 static struct Test { int* a; } 10970 immutable(Test) test; 10971 cast(void) only(test, test); // Works with mutable indirection 10972 } 10973 10974 // https://issues.dlang.org/show_bug.cgi?id=21129 10975 @safe unittest 10976 { 10977 auto range = () @safe { 10978 const(char)[5] staticStr = "Hello"; 10979 10980 // `only` must store a char[5] - not a char[]! 10981 return only(staticStr, " World"); 10982 } (); 10983 10984 assert(range.join == "Hello World"); 10985 } 10986 10987 // https://issues.dlang.org/show_bug.cgi?id=21129 10988 @safe unittest 10989 { 10990 struct AliasedString 10991 { 10992 const(char)[5] staticStr = "Hello"; 10993 10994 @property const(char)[] slice() const 10995 { 10996 return staticStr[]; 10997 } 10998 alias slice this; 10999 } 11000 11001 auto range = () @safe { 11002 auto hello = AliasedString(); 11003 11004 // a copy of AliasedString is stored in the range. 11005 return only(hello, " World"); 11006 } (); 11007 11008 assert(range.join == "Hello World"); 11009 } 11010 11011 // https://issues.dlang.org/show_bug.cgi?id=21022 11012 @safe pure nothrow unittest 11013 { 11014 struct S 11015 { 11016 int* mem; 11017 } 11018 11019 immutable S x; 11020 immutable(S)[] arr; 11021 auto r1 = arr.chain(x.only, only(x, x)); 11022 } 11023 11024 // https://issues.dlang.org/show_bug.cgi?id=24382 11025 @safe unittest 11026 { 11027 auto r1 = only(123); 11028 r1.front = 456; 11029 r1.back = 456; 11030 r1[0] = 456; 11031 11032 auto r2 = only(123, 456); 11033 r2.front = 789; 11034 r2.back = 789; 11035 r2[0] = 789; 11036 11037 auto r3 = only(1.23, 456); 11038 // Can't assign double to int 11039 static assert(!__traits(compiles, r3.front = 7.89)); 11040 static assert(!__traits(compiles, r3.back = 7.89)); 11041 // Workaround https://issues.dlang.org/show_bug.cgi?id=24383 11042 static assert(!__traits(compiles, () { r3[0] = 7.89; })); 11043 // Can't assign type other than element type (even if compatible) 11044 static assert(!__traits(compiles, r3.front = 789)); 11045 static assert(!__traits(compiles, r3.back = 789)); 11046 // Workaround https://issues.dlang.org/show_bug.cgi?id=24383 11047 static assert(!__traits(compiles, () { r3[0] = 789; })); 11048 } 11049 11050 // https://github.com/dlang/phobos/issues/10561 11051 @safe unittest 11052 { 11053 static struct Range 11054 { 11055 private int i; 11056 11057 enum bool empty = false; 11058 int front() => i; 11059 void popFront() { ++i; } 11060 } 11061 import std.algorithm; 11062 11063 assert(Range().take(10).filter!"a>8".chain(only(100)).equal([9,100])); 11064 assert((new Range()).take(10).filter!"a>8".chain(only(100)).equal([9,100])); 11065 } 11066 11067 /** 11068 Iterate over `range` with an attached index variable. 11069 11070 Each element is a $(REF Tuple, std,typecons) containing the index 11071 and the element, in that order, where the index member is named `index` 11072 and the element member is named `value`. 11073 11074 The index starts at `start` and is incremented by one on every iteration. 11075 11076 Overflow: 11077 If `range` has length, then it is an error to pass a value for `start` 11078 so that `start + range.length` is bigger than `Enumerator.max`, thus 11079 it is ensured that overflow cannot happen. 11080 11081 If `range` does not have length, and `popFront` is called when 11082 `front.index == Enumerator.max`, the index will overflow and 11083 continue from `Enumerator.min`. 11084 11085 Params: 11086 range = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to attach indexes to 11087 start = the number to start the index counter from 11088 11089 Returns: 11090 At minimum, an input range. All other range primitives are given in the 11091 resulting range if `range` has them. The exceptions are the bidirectional 11092 primitives, which are propagated only if `range` has length. 11093 11094 Example: 11095 Useful for using `foreach` with an index loop variable: 11096 ---- 11097 import std.stdio : stdin, stdout; 11098 import std.range : enumerate; 11099 11100 foreach (lineNum, line; stdin.byLine().enumerate(1)) 11101 stdout.writefln("line #%s: %s", lineNum, line); 11102 ---- 11103 */ 11104 auto enumerate(Enumerator = size_t, Range)(Range range, Enumerator start = 0) 11105 if (isIntegral!Enumerator && isInputRange!Range) 11106 in 11107 { 11108 static if (hasLength!Range) 11109 { 11110 // TODO: core.checkedint supports mixed signedness yet? 11111 import core.checkedint : adds, addu; 11112 import std.conv : ConvException, to; 11113 import std.traits : isSigned, Largest, Signed; 11114 11115 alias LengthType = typeof(range.length); 11116 bool overflow; 11117 static if (isSigned!Enumerator && isSigned!LengthType) 11118 auto result = adds(start, range.length, overflow); 11119 else static if (isSigned!Enumerator) 11120 { 11121 alias signed_t = Largest!(Enumerator, Signed!LengthType); 11122 signed_t signedLength; 11123 //This is to trick the compiler because if length is enum 11124 //the compiler complains about unreachable code. 11125 auto getLength() 11126 { 11127 return range.length; 11128 } 11129 //Can length fit in the signed type 11130 assert(getLength() < signed_t.max, 11131 "a signed length type is required but the range's length() is too great"); 11132 signedLength = range.length; 11133 auto result = adds(start, signedLength, overflow); 11134 } 11135 else 11136 { 11137 static if (isSigned!LengthType) 11138 assert(range.length >= 0); 11139 auto result = addu(start, range.length, overflow); 11140 } 11141 11142 assert(!overflow && result <= Enumerator.max); 11143 } 11144 } 11145 do 11146 { 11147 // TODO: Relax isIntegral!Enumerator to allow user-defined integral types 11148 static struct Result 11149 { 11150 import std.typecons : Tuple; 11151 11152 private: 11153 alias ElemType = Tuple!(Enumerator, "index", ElementType!Range, "value"); 11154 Range range; 11155 Unqual!Enumerator index; 11156 11157 public: 11158 ElemType front() @property 11159 { 11160 assert(!range.empty, "Attempting to fetch the front of an empty enumerate"); 11161 return typeof(return)(index, range.front); 11162 } 11163 11164 static if (isInfinite!Range) 11165 enum bool empty = false; 11166 else 11167 { 11168 bool empty() @property 11169 { 11170 return range.empty; 11171 } 11172 } 11173 11174 void popFront() 11175 { 11176 assert(!range.empty, "Attempting to popFront an empty enumerate"); 11177 range.popFront(); 11178 ++index; // When !hasLength!Range, overflow is expected 11179 } 11180 11181 static if (isForwardRange!Range) 11182 { 11183 Result save() @property 11184 { 11185 return typeof(return)(range.save, index); 11186 } 11187 } 11188 11189 static if (hasLength!Range) 11190 { 11191 mixin ImplementLength!range; 11192 11193 static if (isBidirectionalRange!Range) 11194 { 11195 ElemType back() @property 11196 { 11197 assert(!range.empty, "Attempting to fetch the back of an empty enumerate"); 11198 return typeof(return)(cast(Enumerator)(index + range.length - 1), range.back); 11199 } 11200 11201 void popBack() 11202 { 11203 assert(!range.empty, "Attempting to popBack an empty enumerate"); 11204 range.popBack(); 11205 } 11206 } 11207 } 11208 11209 static if (isRandomAccessRange!Range) 11210 { 11211 ElemType opIndex(size_t i) 11212 { 11213 return typeof(return)(cast(Enumerator)(index + i), range[i]); 11214 } 11215 } 11216 11217 static if (hasSlicing!Range) 11218 { 11219 static if (hasLength!Range) 11220 { 11221 Result opSlice(size_t i, size_t j) 11222 { 11223 return typeof(return)(range[i .. j], cast(Enumerator)(index + i)); 11224 } 11225 } 11226 else 11227 { 11228 static struct DollarToken {} 11229 enum opDollar = DollarToken.init; 11230 11231 Result opSlice(size_t i, DollarToken) 11232 { 11233 return typeof(return)(range[i .. $], cast(Enumerator)(index + i)); 11234 } 11235 11236 auto opSlice(size_t i, size_t j) 11237 { 11238 return this[i .. $].takeExactly(j - 1); 11239 } 11240 } 11241 } 11242 } 11243 11244 return Result(range, start); 11245 } 11246 11247 /// Can start enumeration from a negative position: 11248 pure @safe nothrow unittest 11249 { 11250 import std.array : assocArray; 11251 import std.range : enumerate; 11252 11253 bool[int] aa = true.repeat(3).enumerate(-1).assocArray(); 11254 assert(aa[-1]); 11255 assert(aa[0]); 11256 assert(aa[1]); 11257 } 11258 11259 // Make sure passing qualified types works 11260 pure @safe nothrow unittest 11261 { 11262 char[4] v; 11263 immutable start = 2; 11264 v[2 .. $].enumerate(start); 11265 } 11266 11267 pure @safe nothrow unittest 11268 { 11269 import std.internal.test.dummyrange : AllDummyRanges; 11270 import std.meta : AliasSeq; 11271 import std.typecons : tuple; 11272 11273 static struct HasSlicing 11274 { 11275 typeof(this) front() @property { return typeof(this).init; } 11276 bool empty() @property { return true; } 11277 void popFront() {} 11278 11279 typeof(this) opSlice(size_t, size_t) 11280 { 11281 return typeof(this)(); 11282 } 11283 } 11284 11285 static foreach (DummyType; AliasSeq!(AllDummyRanges, HasSlicing)) 11286 {{ 11287 alias R = typeof(enumerate(DummyType.init)); 11288 static assert(isInputRange!R); 11289 static assert(isForwardRange!R == isForwardRange!DummyType); 11290 static assert(isRandomAccessRange!R == isRandomAccessRange!DummyType); 11291 static assert(!hasAssignableElements!R); 11292 11293 static if (hasLength!DummyType) 11294 { 11295 static assert(hasLength!R); 11296 static assert(isBidirectionalRange!R == 11297 isBidirectionalRange!DummyType); 11298 } 11299 11300 static assert(hasSlicing!R == hasSlicing!DummyType); 11301 }} 11302 11303 static immutable values = ["zero", "one", "two", "three"]; 11304 auto enumerated = values[].enumerate(); 11305 assert(!enumerated.empty); 11306 assert(enumerated.front == tuple(0, "zero")); 11307 assert(enumerated.back == tuple(3, "three")); 11308 11309 typeof(enumerated) saved = enumerated.save; 11310 saved.popFront(); 11311 assert(enumerated.front == tuple(0, "zero")); 11312 assert(saved.front == tuple(1, "one")); 11313 assert(saved.length == enumerated.length - 1); 11314 saved.popBack(); 11315 assert(enumerated.back == tuple(3, "three")); 11316 assert(saved.back == tuple(2, "two")); 11317 saved.popFront(); 11318 assert(saved.front == tuple(2, "two")); 11319 assert(saved.back == tuple(2, "two")); 11320 saved.popFront(); 11321 assert(saved.empty); 11322 11323 size_t control = 0; 11324 foreach (i, v; enumerated) 11325 { 11326 static assert(is(typeof(i) == size_t)); 11327 static assert(is(typeof(v) == typeof(values[0]))); 11328 assert(i == control); 11329 assert(v == values[i]); 11330 assert(tuple(i, v) == enumerated[i]); 11331 ++control; 11332 } 11333 11334 assert(enumerated[0 .. $].front == tuple(0, "zero")); 11335 assert(enumerated[$ - 1 .. $].front == tuple(3, "three")); 11336 11337 foreach (i; 0 .. 10) 11338 { 11339 auto shifted = values[0 .. 2].enumerate(i); 11340 assert(shifted.front == tuple(i, "zero")); 11341 assert(shifted[0] == shifted.front); 11342 11343 auto next = tuple(i + 1, "one"); 11344 assert(shifted[1] == next); 11345 shifted.popFront(); 11346 assert(shifted.front == next); 11347 shifted.popFront(); 11348 assert(shifted.empty); 11349 } 11350 11351 static foreach (T; AliasSeq!(ubyte, byte, uint, int)) 11352 {{ 11353 auto inf = 42.repeat().enumerate(T.max); 11354 alias Inf = typeof(inf); 11355 static assert(isInfinite!Inf); 11356 static assert(hasSlicing!Inf); 11357 11358 // test overflow 11359 assert(inf.front == tuple(T.max, 42)); 11360 inf.popFront(); 11361 assert(inf.front == tuple(T.min, 42)); 11362 11363 // test slicing 11364 inf = inf[42 .. $]; 11365 assert(inf.front == tuple(T.min + 42, 42)); 11366 auto window = inf[0 .. 2]; 11367 assert(window.length == 1); 11368 assert(window.front == inf.front); 11369 window.popFront(); 11370 assert(window.empty); 11371 }} 11372 } 11373 11374 pure @safe unittest 11375 { 11376 import std.algorithm.comparison : equal; 11377 import std.meta : AliasSeq; 11378 static immutable int[] values = [0, 1, 2, 3, 4]; 11379 static foreach (T; AliasSeq!(ubyte, ushort, uint, ulong)) 11380 {{ 11381 auto enumerated = values.enumerate!T(); 11382 static assert(is(typeof(enumerated.front.index) == T)); 11383 assert(enumerated.equal(values[].zip(values))); 11384 11385 foreach (T i; 0 .. 5) 11386 { 11387 auto subset = values[cast(size_t) i .. $]; 11388 auto offsetEnumerated = subset.enumerate(i); 11389 static assert(is(typeof(enumerated.front.index) == T)); 11390 assert(offsetEnumerated.equal(subset.zip(subset))); 11391 } 11392 }} 11393 } 11394 @nogc @safe unittest 11395 { 11396 const val = iota(1, 100).enumerate(1); 11397 } 11398 @nogc @safe unittest 11399 { 11400 import core.exception : AssertError; 11401 import std.exception : assertThrown; 11402 struct RangePayload { 11403 enum length = size_t.max; 11404 void popFront() {} 11405 int front() { return 0; } 11406 bool empty() { return true; } 11407 } 11408 RangePayload thePayload; 11409 //Assertion won't happen when contracts are disabled for -release. 11410 debug assertThrown!AssertError(enumerate(thePayload, -10)); 11411 } 11412 // https://issues.dlang.org/show_bug.cgi?id=10939 11413 version (none) 11414 { 11415 // Re-enable (or remove) if 10939 is resolved. 11416 /+pure+/ @safe unittest // Impure because of std.conv.to 11417 { 11418 import core.exception : RangeError; 11419 import std.exception : assertNotThrown, assertThrown; 11420 import std.meta : AliasSeq; 11421 11422 static immutable values = [42]; 11423 11424 static struct SignedLengthRange 11425 { 11426 immutable(int)[] _values = values; 11427 11428 int front() @property { assert(false); } 11429 bool empty() @property { assert(false); } 11430 void popFront() { assert(false); } 11431 11432 int length() @property 11433 { 11434 return cast(int)_values.length; 11435 } 11436 } 11437 11438 SignedLengthRange svalues; 11439 static foreach (Enumerator; AliasSeq!(ubyte, byte, ushort, short, uint, int, ulong, long)) 11440 { 11441 assertThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max)); 11442 assertNotThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max - values.length)); 11443 assertThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max - values.length + 1)); 11444 11445 assertThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max)); 11446 assertNotThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max - values.length)); 11447 assertThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max - values.length + 1)); 11448 } 11449 11450 static foreach (Enumerator; AliasSeq!(byte, short, int)) 11451 { 11452 assertThrown!RangeError(repeat(0, uint.max).enumerate!Enumerator()); 11453 } 11454 11455 assertNotThrown!RangeError(repeat(0, uint.max).enumerate!long()); 11456 } 11457 } 11458 11459 /** 11460 Returns true if `fn` accepts variables of type T1 and T2 in any order. 11461 The following code should compile: 11462 --- 11463 (ref T1 a, ref T2 b) 11464 { 11465 fn(a, b); 11466 fn(b, a); 11467 } 11468 --- 11469 */ 11470 template isTwoWayCompatible(alias fn, T1, T2) 11471 { 11472 enum isTwoWayCompatible = is(typeof((ref T1 a, ref T2 b) 11473 { 11474 cast(void) fn(a, b); 11475 cast(void) fn(b, a); 11476 } 11477 )); 11478 } 11479 11480 /// 11481 @safe unittest 11482 { 11483 void func1(int a, int b); 11484 void func2(int a, float b); 11485 11486 static assert(isTwoWayCompatible!(func1, int, int)); 11487 static assert(isTwoWayCompatible!(func1, short, int)); 11488 static assert(!isTwoWayCompatible!(func2, int, float)); 11489 11490 void func3(ref int a, ref int b); 11491 static assert( isTwoWayCompatible!(func3, int, int)); 11492 static assert(!isTwoWayCompatible!(func3, short, int)); 11493 } 11494 11495 11496 /** 11497 Policy used with the searching primitives `lowerBound`, $(D 11498 upperBound), and `equalRange` of $(LREF SortedRange) below. 11499 */ 11500 enum SearchPolicy 11501 { 11502 /** 11503 Searches in a linear fashion. 11504 */ 11505 linear, 11506 11507 /** 11508 Searches with a step that is grows linearly (1, 2, 3,...) 11509 leading to a quadratic search schedule (indexes tried are 0, 1, 11510 3, 6, 10, 15, 21, 28,...) Once the search overshoots its target, 11511 the remaining interval is searched using binary search. The 11512 search is completed in $(BIGOH sqrt(n)) time. Use it when you 11513 are reasonably confident that the value is around the beginning 11514 of the range. 11515 */ 11516 trot, 11517 11518 /** 11519 Performs a $(LINK2 https://en.wikipedia.org/wiki/Exponential_search, 11520 galloping search algorithm), i.e. searches 11521 with a step that doubles every time, (1, 2, 4, 8, ...) leading 11522 to an exponential search schedule (indexes tried are 0, 1, 3, 11523 7, 15, 31, 63,...) Once the search overshoots its target, the 11524 remaining interval is searched using binary search. A value is 11525 found in $(BIGOH log(n)) time. 11526 */ 11527 gallop, 11528 11529 /** 11530 Searches using a classic interval halving policy. The search 11531 starts in the middle of the range, and each search step cuts 11532 the range in half. This policy finds a value in $(BIGOH log(n)) 11533 time but is less cache friendly than `gallop` for large 11534 ranges. The `binarySearch` policy is used as the last step 11535 of `trot`, `gallop`, `trotBackwards`, and $(D 11536 gallopBackwards) strategies. 11537 */ 11538 binarySearch, 11539 11540 /** 11541 Similar to `trot` but starts backwards. Use it when 11542 confident that the value is around the end of the range. 11543 */ 11544 trotBackwards, 11545 11546 /** 11547 Similar to `gallop` but starts backwards. Use it when 11548 confident that the value is around the end of the range. 11549 */ 11550 gallopBackwards 11551 } 11552 11553 /// 11554 @safe unittest 11555 { 11556 import std.algorithm.comparison : equal; 11557 11558 auto a = assumeSorted([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); 11559 auto p1 = a.upperBound!(SearchPolicy.binarySearch)(3); 11560 assert(p1.equal([4, 5, 6, 7, 8, 9])); 11561 11562 auto p2 = a.lowerBound!(SearchPolicy.gallop)(4); 11563 assert(p2.equal([0, 1, 2, 3])); 11564 } 11565 11566 /** 11567 Options for $(LREF SortedRange) ranges (below). 11568 */ 11569 enum SortedRangeOptions 11570 { 11571 /** 11572 Assume, that the range is sorted without checking. 11573 */ 11574 assumeSorted, 11575 11576 /** 11577 All elements of the range are checked to be sorted. 11578 The check is performed in O(n) time. 11579 */ 11580 checkStrictly, 11581 11582 /** 11583 Some elements of the range are checked to be sorted. 11584 For ranges with random order, this will almost surely 11585 detect, that it is not sorted. For almost sorted ranges 11586 it's more likely to fail. The checked elements are choosen 11587 in a deterministic manner, which makes this check reproducable. 11588 The check is performed in O(log(n)) time. 11589 */ 11590 checkRoughly, 11591 } 11592 11593 /// 11594 @safe pure unittest 11595 { 11596 // create a SortedRange, that's checked strictly 11597 SortedRange!(int[],"a < b", SortedRangeOptions.checkStrictly)([ 1, 3, 5, 7, 9 ]); 11598 } 11599 11600 /** 11601 Represents a sorted range. In addition to the regular range 11602 primitives, supports additional operations that take advantage of the 11603 ordering, such as merge and binary search. To obtain a $(D 11604 SortedRange) from an unsorted range `r`, use 11605 $(REF sort, std,algorithm,sorting) which sorts `r` in place and returns the 11606 corresponding `SortedRange`. To construct a `SortedRange` from a range 11607 `r` that is known to be already sorted, use $(LREF assumeSorted). 11608 11609 Params: 11610 pred: The predicate used to define the sortedness 11611 opt: Controls how strongly the range is checked for sortedness. 11612 Will only be used for `RandomAccessRanges`. 11613 Will not be used in CTFE. 11614 */ 11615 struct SortedRange(Range, alias pred = "a < b", 11616 SortedRangeOptions opt = SortedRangeOptions.assumeSorted) 11617 if (isInputRange!Range && !isInstanceOf!(SortedRange, Range)) 11618 { 11619 import std.functional : binaryFun; 11620 11621 private alias predFun = binaryFun!pred; 11622 private bool geq(L, R)(L lhs, R rhs) 11623 { 11624 return !predFun(lhs, rhs); 11625 } 11626 private bool gt(L, R)(L lhs, R rhs) 11627 { 11628 return predFun(rhs, lhs); 11629 } 11630 private Range _input; 11631 11632 // Undocummented because a clearer way to invoke is by calling 11633 // assumeSorted. 11634 this(Range input) 11635 { 11636 static if (opt == SortedRangeOptions.checkRoughly) 11637 { 11638 roughlyVerifySorted(input); 11639 } 11640 static if (opt == SortedRangeOptions.checkStrictly) 11641 { 11642 strictlyVerifySorted(input); 11643 } 11644 this._input = input; 11645 } 11646 11647 // Assertion only. 11648 static if (opt == SortedRangeOptions.checkRoughly) 11649 private void roughlyVerifySorted(Range r) 11650 { 11651 if (!__ctfe) 11652 { 11653 static if (isRandomAccessRange!Range && hasLength!Range) 11654 { 11655 import core.bitop : bsr; 11656 import std.algorithm.sorting : isSorted; 11657 import std.exception : enforce; 11658 11659 // Check the sortedness of the input 11660 if (r.length < 2) return; 11661 11662 immutable size_t msb = bsr(r.length) + 1; 11663 assert(msb > 0 && msb <= r.length); 11664 immutable step = r.length / msb; 11665 auto st = stride(r, step); 11666 11667 enforce(isSorted!pred(st), "Range is not sorted"); 11668 } 11669 } 11670 } 11671 11672 // Assertion only. 11673 static if (opt == SortedRangeOptions.checkStrictly) 11674 private void strictlyVerifySorted(Range r) 11675 { 11676 if (!__ctfe) 11677 { 11678 static if (isRandomAccessRange!Range && hasLength!Range) 11679 { 11680 import std.algorithm.sorting : isSorted; 11681 import std.exception : enforce; 11682 11683 enforce(isSorted!pred(r), "Range is not sorted"); 11684 } 11685 } 11686 } 11687 11688 /// Range primitives. 11689 @property bool empty() //const 11690 { 11691 return this._input.empty; 11692 } 11693 11694 /// Ditto 11695 static if (isForwardRange!Range) 11696 @property auto save() 11697 { 11698 // Avoid the constructor 11699 typeof(this) result = this; 11700 result._input = _input.save; 11701 return result; 11702 } 11703 11704 /// Ditto 11705 @property auto ref front() 11706 { 11707 return _input.front; 11708 } 11709 11710 /// Ditto 11711 void popFront() 11712 { 11713 _input.popFront(); 11714 } 11715 11716 /// Ditto 11717 static if (isBidirectionalRange!Range) 11718 { 11719 @property auto ref back() 11720 { 11721 return _input.back; 11722 } 11723 11724 /// Ditto 11725 void popBack() 11726 { 11727 _input.popBack(); 11728 } 11729 } 11730 11731 /// Ditto 11732 static if (isRandomAccessRange!Range) 11733 auto ref opIndex(size_t i) 11734 { 11735 return _input[i]; 11736 } 11737 11738 /// Ditto 11739 static if (hasSlicing!Range) 11740 auto opSlice(size_t a, size_t b) return scope 11741 { 11742 assert( 11743 a <= b, 11744 "Attempting to slice a SortedRange with a larger first argument than the second." 11745 ); 11746 typeof(this) result = this; 11747 result._input = _input[a .. b];// skip checking 11748 return result; 11749 } 11750 11751 mixin ImplementLength!_input; 11752 11753 /** 11754 Releases the controlled range and returns it. 11755 11756 This does the opposite of $(LREF assumeSorted): instead of turning a range 11757 into a `SortedRange`, it extracts the original range back out of the `SortedRange` 11758 using $(REF, move, std,algorithm,mutation). 11759 */ 11760 auto release() return scope 11761 { 11762 import std.algorithm.mutation : move; 11763 return move(_input); 11764 } 11765 11766 /// 11767 static if (is(Range : int[])) 11768 @safe unittest 11769 { 11770 import std.algorithm.sorting : sort; 11771 int[3] data = [ 1, 2, 3 ]; 11772 auto a = assumeSorted(data[]); 11773 assert(a == sort!"a < b"(data[])); 11774 int[] p = a.release(); 11775 assert(p == [ 1, 2, 3 ]); 11776 } 11777 11778 // Assuming a predicate "test" that returns 0 for a left portion 11779 // of the range and then 1 for the rest, returns the index at 11780 // which the first 1 appears. Used internally by the search routines. 11781 private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v) 11782 if (sp == SearchPolicy.binarySearch && isRandomAccessRange!Range && hasLength!Range) 11783 { 11784 size_t first = 0, count = _input.length; 11785 while (count > 0) 11786 { 11787 immutable step = count / 2, it = first + step; 11788 if (!test(_input[it], v)) 11789 { 11790 first = it + 1; 11791 count -= step + 1; 11792 } 11793 else 11794 { 11795 count = step; 11796 } 11797 } 11798 return first; 11799 } 11800 11801 // Specialization for trot and gallop 11802 private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v) 11803 if ((sp == SearchPolicy.trot || sp == SearchPolicy.gallop) 11804 && isRandomAccessRange!Range) 11805 { 11806 if (empty || test(front, v)) return 0; 11807 immutable count = length; 11808 if (count == 1) return 1; 11809 size_t below = 0, above = 1, step = 2; 11810 while (!test(_input[above], v)) 11811 { 11812 // Still too small, update below and increase gait 11813 below = above; 11814 immutable next = above + step; 11815 if (next >= count) 11816 { 11817 // Overshot - the next step took us beyond the end. So 11818 // now adjust next and simply exit the loop to do the 11819 // binary search thingie. 11820 above = count; 11821 break; 11822 } 11823 // Still in business, increase step and continue 11824 above = next; 11825 static if (sp == SearchPolicy.trot) 11826 ++step; 11827 else 11828 step <<= 1; 11829 } 11830 return below + this[below .. above].getTransitionIndex!( 11831 SearchPolicy.binarySearch, test, V)(v); 11832 } 11833 11834 // Specialization for trotBackwards and gallopBackwards 11835 private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v) 11836 if ((sp == SearchPolicy.trotBackwards || sp == SearchPolicy.gallopBackwards) 11837 && isRandomAccessRange!Range) 11838 { 11839 immutable count = length; 11840 if (empty || !test(back, v)) return count; 11841 if (count == 1) return 0; 11842 size_t below = count - 2, above = count - 1, step = 2; 11843 while (test(_input[below], v)) 11844 { 11845 // Still too large, update above and increase gait 11846 above = below; 11847 if (below < step) 11848 { 11849 // Overshot - the next step took us beyond the end. So 11850 // now adjust next and simply fall through to do the 11851 // binary search thingie. 11852 below = 0; 11853 break; 11854 } 11855 // Still in business, increase step and continue 11856 below -= step; 11857 static if (sp == SearchPolicy.trot) 11858 ++step; 11859 else 11860 step <<= 1; 11861 } 11862 return below + this[below .. above].getTransitionIndex!( 11863 SearchPolicy.binarySearch, test, V)(v); 11864 } 11865 11866 // lowerBound 11867 /** 11868 This function uses a search with policy `sp` to find the 11869 largest left subrange on which $(D pred(x, value)) is `true` for 11870 all `x` (e.g., if `pred` is "less than", returns the portion of 11871 the range with elements strictly smaller than `value`). The search 11872 schedule and its complexity are documented in 11873 $(LREF SearchPolicy). 11874 */ 11875 auto lowerBound(SearchPolicy sp = SearchPolicy.binarySearch, V)(V value) 11876 if (isTwoWayCompatible!(predFun, ElementType!Range, V) 11877 && hasSlicing!Range) 11878 { 11879 return this[0 .. getTransitionIndex!(sp, geq)(value)]; 11880 } 11881 11882 /// 11883 static if (is(Range : int[])) 11884 @safe unittest 11885 { 11886 import std.algorithm.comparison : equal; 11887 auto a = assumeSorted([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]); 11888 auto p = a.lowerBound(4); 11889 assert(equal(p, [ 0, 1, 2, 3 ])); 11890 } 11891 11892 // upperBound 11893 /** 11894 This function searches with policy `sp` to find the largest right 11895 subrange on which $(D pred(value, x)) is `true` for all `x` 11896 (e.g., if `pred` is "less than", returns the portion of the range 11897 with elements strictly greater than `value`). The search schedule 11898 and its complexity are documented in $(LREF SearchPolicy). 11899 11900 For ranges that do not offer random access, `SearchPolicy.linear` 11901 is the only policy allowed (and it must be specified explicitly lest it exposes 11902 user code to unexpected inefficiencies). For random-access searches, all 11903 policies are allowed, and `SearchPolicy.binarySearch` is the default. 11904 */ 11905 auto upperBound(SearchPolicy sp = SearchPolicy.binarySearch, V)(V value) 11906 if (isTwoWayCompatible!(predFun, ElementType!Range, V)) 11907 { 11908 static assert(hasSlicing!Range || sp == SearchPolicy.linear, 11909 "Specify SearchPolicy.linear explicitly for " 11910 ~ typeof(this).stringof); 11911 static if (sp == SearchPolicy.linear) 11912 { 11913 for (; !_input.empty && !predFun(value, _input.front); 11914 _input.popFront()) 11915 { 11916 } 11917 return this; 11918 } 11919 else 11920 { 11921 return this[getTransitionIndex!(sp, gt)(value) .. length]; 11922 } 11923 } 11924 11925 /// 11926 static if (is(Range : int[])) 11927 @safe unittest 11928 { 11929 import std.algorithm.comparison : equal; 11930 auto a = assumeSorted([ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]); 11931 auto p = a.upperBound(3); 11932 assert(equal(p, [4, 4, 5, 6])); 11933 } 11934 11935 11936 // equalRange 11937 /** 11938 Returns the subrange containing all elements `e` for which both $(D 11939 pred(e, value)) and $(D pred(value, e)) evaluate to `false` (e.g., 11940 if `pred` is "less than", returns the portion of the range with 11941 elements equal to `value`). Uses a classic binary search with 11942 interval halving until it finds a value that satisfies the condition, 11943 then uses `SearchPolicy.gallopBackwards` to find the left boundary 11944 and `SearchPolicy.gallop` to find the right boundary. These 11945 policies are justified by the fact that the two boundaries are likely 11946 to be near the first found value (i.e., equal ranges are relatively 11947 small). Completes the entire search in $(BIGOH log(n)) time. 11948 */ 11949 auto equalRange(V)(V value) 11950 if (isTwoWayCompatible!(predFun, ElementType!Range, V) 11951 && isRandomAccessRange!Range) 11952 { 11953 size_t first = 0, count = _input.length; 11954 while (count > 0) 11955 { 11956 immutable step = count / 2; 11957 auto it = first + step; 11958 if (predFun(_input[it], value)) 11959 { 11960 // Less than value, bump left bound up 11961 first = it + 1; 11962 count -= step + 1; 11963 } 11964 else if (predFun(value, _input[it])) 11965 { 11966 // Greater than value, chop count 11967 count = step; 11968 } 11969 else 11970 { 11971 // Equal to value, do binary searches in the 11972 // leftover portions 11973 // Gallop towards the left end as it's likely nearby 11974 immutable left = first 11975 + this[first .. it] 11976 .lowerBound!(SearchPolicy.gallopBackwards)(value).length; 11977 first += count; 11978 // Gallop towards the right end as it's likely nearby 11979 immutable right = first 11980 - this[it + 1 .. first] 11981 .upperBound!(SearchPolicy.gallop)(value).length; 11982 return this[left .. right]; 11983 } 11984 } 11985 return this.init; 11986 } 11987 11988 /// 11989 static if (is(Range : int[])) 11990 @safe unittest 11991 { 11992 import std.algorithm.comparison : equal; 11993 auto a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]; 11994 auto r = a.assumeSorted.equalRange(3); 11995 assert(equal(r, [ 3, 3, 3 ])); 11996 } 11997 11998 // trisect 11999 /** 12000 Returns a tuple `r` such that `r[0]` is the same as the result 12001 of `lowerBound(value)`, `r[1]` is the same as the result of $(D 12002 equalRange(value)), and `r[2]` is the same as the result of $(D 12003 upperBound(value)). The call is faster than computing all three 12004 separately. Uses a search schedule similar to $(D 12005 equalRange). Completes the entire search in $(BIGOH log(n)) time. 12006 */ 12007 auto trisect(V)(V value) 12008 if (isTwoWayCompatible!(predFun, ElementType!Range, V) 12009 && isRandomAccessRange!Range && hasLength!Range) 12010 { 12011 import std.typecons : tuple; 12012 size_t first = 0, count = _input.length; 12013 while (count > 0) 12014 { 12015 immutable step = count / 2; 12016 auto it = first + step; 12017 if (predFun(_input[it], value)) 12018 { 12019 // Less than value, bump left bound up 12020 first = it + 1; 12021 count -= step + 1; 12022 } 12023 else if (predFun(value, _input[it])) 12024 { 12025 // Greater than value, chop count 12026 count = step; 12027 } 12028 else 12029 { 12030 // Equal to value, do binary searches in the 12031 // leftover portions 12032 // Gallop towards the left end as it's likely nearby 12033 immutable left = first 12034 + this[first .. it] 12035 .lowerBound!(SearchPolicy.gallopBackwards)(value).length; 12036 first += count; 12037 // Gallop towards the right end as it's likely nearby 12038 immutable right = first 12039 - this[it + 1 .. first] 12040 .upperBound!(SearchPolicy.gallop)(value).length; 12041 return tuple(this[0 .. left], this[left .. right], 12042 this[right .. length]); 12043 } 12044 } 12045 // No equal element was found 12046 return tuple(this[0 .. first], this.init, this[first .. length]); 12047 } 12048 12049 /// 12050 static if (is(Range : int[])) 12051 @safe unittest 12052 { 12053 import std.algorithm.comparison : equal; 12054 auto a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]; 12055 auto r = assumeSorted(a).trisect(3); 12056 assert(equal(r[0], [ 1, 2 ])); 12057 assert(equal(r[1], [ 3, 3, 3 ])); 12058 assert(equal(r[2], [ 4, 4, 5, 6 ])); 12059 } 12060 12061 // contains 12062 /** 12063 Returns `true` if and only if `value` can be found in $(D 12064 range), which is assumed to be sorted. Performs $(BIGOH log(r.length)) 12065 evaluations of `pred`. 12066 */ 12067 12068 bool contains(V)(V value) 12069 if (isRandomAccessRange!Range) 12070 { 12071 if (empty) return false; 12072 immutable i = getTransitionIndex!(SearchPolicy.binarySearch, geq)(value); 12073 if (i >= length) return false; 12074 return !predFun(value, _input[i]); 12075 } 12076 12077 /** 12078 Like `contains`, but the value is specified before the range. 12079 */ 12080 bool opBinaryRight(string op, V)(V value) 12081 if (op == "in" && isRandomAccessRange!Range) 12082 { 12083 return contains(value); 12084 } 12085 12086 // groupBy 12087 /** 12088 Returns a range of subranges of elements that are equivalent according to the 12089 sorting relation. 12090 */ 12091 auto groupBy()() 12092 { 12093 import std.algorithm.iteration : chunkBy; 12094 return _input.chunkBy!((a, b) => !predFun(a, b) && !predFun(b, a)); 12095 } 12096 } 12097 12098 /// ditto 12099 template SortedRange(Range, alias pred = "a < b", 12100 SortedRangeOptions opt = SortedRangeOptions.assumeSorted) 12101 if (isInstanceOf!(SortedRange, Range)) 12102 { 12103 // Avoid nesting SortedRange types (see https://issues.dlang.org/show_bug.cgi?id=18933); 12104 alias SortedRange = SortedRange!(Unqual!(typeof(Range._input)), pred, opt); 12105 } 12106 12107 /// 12108 @safe unittest 12109 { 12110 import std.algorithm.sorting : sort; 12111 auto a = [ 1, 2, 3, 42, 52, 64 ]; 12112 auto r = assumeSorted(a); 12113 assert(r.contains(3)); 12114 assert(!(32 in r)); 12115 auto r1 = sort!"a > b"(a); 12116 assert(3 in r1); 12117 assert(!r1.contains(32)); 12118 assert(r1.release() == [ 64, 52, 42, 3, 2, 1 ]); 12119 } 12120 12121 /** 12122 `SortedRange` could accept ranges weaker than random-access, but it 12123 is unable to provide interesting functionality for them. Therefore, 12124 `SortedRange` is currently restricted to random-access ranges. 12125 12126 No copy of the original range is ever made. If the underlying range is 12127 changed concurrently with its corresponding `SortedRange` in ways 12128 that break its sorted-ness, `SortedRange` will work erratically. 12129 */ 12130 @safe unittest 12131 { 12132 import std.algorithm.mutation : swap; 12133 auto a = [ 1, 2, 3, 42, 52, 64 ]; 12134 auto r = assumeSorted(a); 12135 assert(r.contains(42)); 12136 swap(a[3], a[5]); // illegal to break sortedness of original range 12137 assert(!r.contains(42)); // passes although it shouldn't 12138 } 12139 12140 /** 12141 `SortedRange` can be searched with predicates that do not take 12142 two elements of the underlying range as arguments. 12143 12144 This is useful, if a range of structs is sorted by a member and you 12145 want to search in that range by only providing a value for that member. 12146 12147 */ 12148 @safe unittest 12149 { 12150 import std.algorithm.comparison : equal; 12151 static struct S { int i; } 12152 static bool byI(A, B)(A a, B b) 12153 { 12154 static if (is(A == S)) 12155 return a.i < b; 12156 else 12157 return a < b.i; 12158 } 12159 auto r = assumeSorted!byI([S(1), S(2), S(3)]); 12160 auto lessThanTwo = r.lowerBound(2); 12161 assert(equal(lessThanTwo, [S(1)])); 12162 } 12163 12164 @safe unittest 12165 { 12166 import std.exception : assertThrown, assertNotThrown; 12167 12168 assertNotThrown(SortedRange!(int[])([ 1, 3, 10, 5, 7 ])); 12169 assertThrown(SortedRange!(int[],"a < b", SortedRangeOptions.checkStrictly)([ 1, 3, 10, 5, 7 ])); 12170 12171 // these two checks are implementation depended 12172 assertNotThrown(SortedRange!(int[],"a < b", SortedRangeOptions.checkRoughly)([ 1, 3, 10, 5, 12, 2 ])); 12173 assertThrown(SortedRange!(int[],"a < b", SortedRangeOptions.checkRoughly)([ 1, 3, 10, 5, 2, 12 ])); 12174 } 12175 12176 @safe unittest 12177 { 12178 import std.algorithm.comparison : equal; 12179 12180 auto a = [ 10, 20, 30, 30, 30, 40, 40, 50, 60 ]; 12181 auto r = assumeSorted(a).trisect(30); 12182 assert(equal(r[0], [ 10, 20 ])); 12183 assert(equal(r[1], [ 30, 30, 30 ])); 12184 assert(equal(r[2], [ 40, 40, 50, 60 ])); 12185 12186 r = assumeSorted(a).trisect(35); 12187 assert(equal(r[0], [ 10, 20, 30, 30, 30 ])); 12188 assert(r[1].empty); 12189 assert(equal(r[2], [ 40, 40, 50, 60 ])); 12190 } 12191 12192 @safe unittest 12193 { 12194 import std.algorithm.comparison : equal; 12195 auto a = [ "A", "AG", "B", "E", "F" ]; 12196 auto r = assumeSorted!"cmp(a,b) < 0"(a).trisect("B"w); 12197 assert(equal(r[0], [ "A", "AG" ])); 12198 assert(equal(r[1], [ "B" ])); 12199 assert(equal(r[2], [ "E", "F" ])); 12200 r = assumeSorted!"cmp(a,b) < 0"(a).trisect("A"d); 12201 assert(r[0].empty); 12202 assert(equal(r[1], [ "A" ])); 12203 assert(equal(r[2], [ "AG", "B", "E", "F" ])); 12204 } 12205 12206 @safe unittest 12207 { 12208 import std.algorithm.comparison : equal; 12209 static void test(SearchPolicy pol)() 12210 { 12211 auto a = [ 1, 2, 3, 42, 52, 64 ]; 12212 auto r = assumeSorted(a); 12213 assert(equal(r.lowerBound(42), [1, 2, 3])); 12214 12215 assert(equal(r.lowerBound!(pol)(42), [1, 2, 3])); 12216 assert(equal(r.lowerBound!(pol)(41), [1, 2, 3])); 12217 assert(equal(r.lowerBound!(pol)(43), [1, 2, 3, 42])); 12218 assert(equal(r.lowerBound!(pol)(51), [1, 2, 3, 42])); 12219 assert(equal(r.lowerBound!(pol)(3), [1, 2])); 12220 assert(equal(r.lowerBound!(pol)(55), [1, 2, 3, 42, 52])); 12221 assert(equal(r.lowerBound!(pol)(420), a)); 12222 assert(equal(r.lowerBound!(pol)(0), a[0 .. 0])); 12223 12224 assert(equal(r.upperBound!(pol)(42), [52, 64])); 12225 assert(equal(r.upperBound!(pol)(41), [42, 52, 64])); 12226 assert(equal(r.upperBound!(pol)(43), [52, 64])); 12227 assert(equal(r.upperBound!(pol)(51), [52, 64])); 12228 assert(equal(r.upperBound!(pol)(53), [64])); 12229 assert(equal(r.upperBound!(pol)(55), [64])); 12230 assert(equal(r.upperBound!(pol)(420), a[0 .. 0])); 12231 assert(equal(r.upperBound!(pol)(0), a)); 12232 } 12233 12234 test!(SearchPolicy.trot)(); 12235 test!(SearchPolicy.gallop)(); 12236 test!(SearchPolicy.trotBackwards)(); 12237 test!(SearchPolicy.gallopBackwards)(); 12238 test!(SearchPolicy.binarySearch)(); 12239 } 12240 12241 @safe unittest 12242 { 12243 // Check for small arrays 12244 int[] a; 12245 auto r = assumeSorted(a); 12246 a = [ 1 ]; 12247 r = assumeSorted(a); 12248 a = [ 1, 2 ]; 12249 r = assumeSorted(a); 12250 a = [ 1, 2, 3 ]; 12251 r = assumeSorted(a); 12252 } 12253 12254 @safe unittest 12255 { 12256 import std.algorithm.mutation : swap; 12257 auto a = [ 1, 2, 3, 42, 52, 64 ]; 12258 auto r = assumeSorted(a); 12259 assert(r.contains(42)); 12260 swap(a[3], a[5]); // illegal to break sortedness of original range 12261 assert(!r.contains(42)); // passes although it shouldn't 12262 } 12263 12264 @betterC @nogc nothrow @safe unittest 12265 { 12266 static immutable(int)[] arr = [ 1, 2, 3 ]; 12267 auto s = assumeSorted(arr); 12268 } 12269 12270 @system unittest 12271 { 12272 import std.algorithm.comparison : equal; 12273 int[] arr = [100, 101, 102, 200, 201, 300]; 12274 auto s = assumeSorted!((a, b) => a / 100 < b / 100)(arr); 12275 assert(s.groupBy.equal!equal([[100, 101, 102], [200, 201], [300]])); 12276 } 12277 12278 // Test on an input range 12279 @system unittest 12280 { 12281 import std.conv : text; 12282 import std.file : exists, remove, tempDir; 12283 import std.path : buildPath; 12284 import std.stdio : File; 12285 import std.uuid : randomUUID; 12286 auto name = buildPath(tempDir(), "test.std.range.line-" ~ text(__LINE__) ~ 12287 "." ~ randomUUID().toString()); 12288 auto f = File(name, "w"); 12289 scope(exit) if (exists(name)) remove(name); 12290 // write a sorted range of lines to the file 12291 f.write("abc\ndef\nghi\njkl"); 12292 f.close(); 12293 f.open(name, "r"); 12294 auto r = assumeSorted(f.byLine()); 12295 auto r1 = r.upperBound!(SearchPolicy.linear)("def"); 12296 assert(r1.front == "ghi", r1.front); 12297 f.close(); 12298 } 12299 12300 // https://issues.dlang.org/show_bug.cgi?id=19337 12301 @safe unittest 12302 { 12303 import std.algorithm.sorting : sort; 12304 auto a = [ 1, 2, 3, 42, 52, 64 ]; 12305 a.sort.sort!"a > b"; 12306 } 12307 12308 /** 12309 Assumes `r` is sorted by predicate `pred` and returns the 12310 corresponding $(D SortedRange!(pred, R)) having `r` as support. 12311 To check for sorted-ness at 12312 cost $(BIGOH n), use $(REF isSorted, std,algorithm,sorting). 12313 */ 12314 auto assumeSorted(alias pred = "a < b", R)(R r) 12315 if (isInputRange!(Unqual!R)) 12316 { 12317 // Avoid senseless `SortedRange!(SortedRange!(...), pred)` nesting. 12318 static if (is(R == SortedRange!(RRange, RPred), RRange, alias RPred)) 12319 { 12320 static if (isInputRange!R && __traits(isSame, pred, RPred)) 12321 // If the predicate is the same and we don't need to cast away 12322 // constness for the result to be an input range. 12323 return r; 12324 else 12325 return SortedRange!(Unqual!(typeof(r._input)), pred)(r._input); 12326 } 12327 else 12328 { 12329 return SortedRange!(Unqual!R, pred)(r); 12330 } 12331 } 12332 12333 /// 12334 @safe unittest 12335 { 12336 import std.algorithm.comparison : equal; 12337 12338 int[] a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; 12339 auto p = assumeSorted(a); 12340 12341 assert(equal(p.lowerBound(4), [0, 1, 2, 3])); 12342 assert(equal(p.lowerBound(5), [0, 1, 2, 3, 4])); 12343 assert(equal(p.lowerBound(6), [0, 1, 2, 3, 4, 5])); 12344 assert(equal(p.lowerBound(6.9), [0, 1, 2, 3, 4, 5, 6])); 12345 } 12346 12347 @safe unittest 12348 { 12349 import std.algorithm.comparison : equal; 12350 static assert(isRandomAccessRange!(SortedRange!(int[]))); 12351 int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]; 12352 auto p = assumeSorted(a).upperBound(3); 12353 assert(equal(p, [4, 4, 5, 6 ])); 12354 p = assumeSorted(a).upperBound(4.2); 12355 assert(equal(p, [ 5, 6 ])); 12356 12357 // https://issues.dlang.org/show_bug.cgi?id=18933 12358 // don't create senselessly nested SortedRange types. 12359 assert(is(typeof(assumeSorted(a)) == typeof(assumeSorted(assumeSorted(a))))); 12360 assert(is(typeof(assumeSorted(a)) == typeof(assumeSorted(assumeSorted!"a > b"(a))))); 12361 } 12362 12363 @safe unittest 12364 { 12365 import std.algorithm.comparison : equal; 12366 import std.conv : text; 12367 12368 int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]; 12369 auto p = assumeSorted(a).equalRange(3); 12370 assert(equal(p, [ 3, 3, 3 ]), text(p)); 12371 p = assumeSorted(a).equalRange(4); 12372 assert(equal(p, [ 4, 4 ]), text(p)); 12373 p = assumeSorted(a).equalRange(2); 12374 assert(equal(p, [ 2 ])); 12375 p = assumeSorted(a).equalRange(0); 12376 assert(p.empty); 12377 p = assumeSorted(a).equalRange(7); 12378 assert(p.empty); 12379 p = assumeSorted(a).equalRange(3.0); 12380 assert(equal(p, [ 3, 3, 3])); 12381 } 12382 12383 @safe unittest 12384 { 12385 int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]; 12386 if (a.length) 12387 { 12388 auto b = a[a.length / 2]; 12389 //auto r = sort(a); 12390 //assert(r.contains(b)); 12391 } 12392 } 12393 12394 @safe unittest 12395 { 12396 auto a = [ 5, 7, 34, 345, 677 ]; 12397 auto r = assumeSorted(a); 12398 a = null; 12399 r = assumeSorted(a); 12400 a = [ 1 ]; 12401 r = assumeSorted(a); 12402 } 12403 12404 // https://issues.dlang.org/show_bug.cgi?id=15003 12405 @nogc @safe unittest 12406 { 12407 static immutable a = [1, 2, 3, 4]; 12408 auto r = a.assumeSorted; 12409 } 12410 12411 /++ 12412 Wrapper which effectively makes it possible to pass a range by reference. 12413 Both the original range and the RefRange will always have the exact same 12414 elements. Any operation done on one will affect the other. So, for instance, 12415 if it's passed to a function which would implicitly copy the original range 12416 if it were passed to it, the original range is $(I not) copied but is 12417 consumed as if it were a reference type. 12418 12419 Note: 12420 `save` works as normal and operates on a new range, so if 12421 `save` is ever called on the `RefRange`, then no operations on the 12422 saved range will affect the original. 12423 12424 Params: 12425 range = the range to construct the `RefRange` from 12426 12427 Returns: 12428 A `RefRange`. If the given range is a class type 12429 (and thus is already a reference type), then the original 12430 range is returned rather than a `RefRange`. 12431 +/ 12432 struct RefRange(R) 12433 if (isInputRange!R) 12434 { 12435 public: 12436 12437 /++ +/ 12438 this(R* range) @safe pure nothrow 12439 { 12440 _range = range; 12441 } 12442 12443 12444 /++ 12445 This does not assign the pointer of `rhs` to this `RefRange`. 12446 Rather it assigns the range pointed to by `rhs` to the range pointed 12447 to by this `RefRange`. This is because $(I any) operation on a 12448 `RefRange` is the same is if it occurred to the original range. The 12449 one exception is when a `RefRange` is assigned `null` either 12450 directly or because `rhs` is `null`. In that case, `RefRange` 12451 no longer refers to the original range but is `null`. 12452 +/ 12453 auto opAssign(RefRange rhs) 12454 { 12455 if (_range && rhs._range) 12456 *_range = *rhs._range; 12457 else 12458 _range = rhs._range; 12459 12460 return this; 12461 } 12462 12463 /++ +/ 12464 void opAssign(typeof(null) rhs) 12465 { 12466 _range = null; 12467 } 12468 12469 12470 /++ 12471 A pointer to the wrapped range. 12472 +/ 12473 @property inout(R*) ptr() @safe inout pure nothrow 12474 { 12475 return _range; 12476 } 12477 12478 12479 version (StdDdoc) 12480 { 12481 /++ +/ 12482 @property auto front() {assert(0);} 12483 /++ Ditto +/ 12484 @property auto front() const {assert(0);} 12485 /++ Ditto +/ 12486 @property auto front(ElementType!R value) {assert(0);} 12487 } 12488 else 12489 { 12490 @property auto front() 12491 { 12492 return (*_range).front; 12493 } 12494 12495 static if (is(typeof(((const R* r) => (*r).front)(null)))) @property auto front() const 12496 { 12497 return (*_range).front; 12498 } 12499 12500 static if (is(typeof((*_range).front = (*_range).front))) @property auto front(ElementType!R value) 12501 { 12502 return (*_range).front = value; 12503 } 12504 } 12505 12506 12507 version (StdDdoc) 12508 { 12509 @property bool empty(); /// 12510 @property bool empty() const; ///Ditto 12511 } 12512 else static if (isInfinite!R) 12513 enum empty = false; 12514 else 12515 { 12516 @property bool empty() 12517 { 12518 return (*_range).empty; 12519 } 12520 12521 static if (is(typeof(((const R* r) => (*r).empty)(null)))) @property bool empty() const 12522 { 12523 return (*_range).empty; 12524 } 12525 } 12526 12527 12528 /++ +/ 12529 void popFront() 12530 { 12531 return (*_range).popFront(); 12532 } 12533 12534 12535 version (StdDdoc) 12536 { 12537 /++ 12538 Only defined if `isForwardRange!R` is `true`. 12539 +/ 12540 @property auto save() {assert(0);} 12541 /++ Ditto +/ 12542 @property auto save() const {assert(0);} 12543 /++ Ditto +/ 12544 auto opSlice() {assert(0);} 12545 /++ Ditto +/ 12546 auto opSlice() const {assert(0);} 12547 } 12548 else static if (isForwardRange!R) 12549 { 12550 import std.traits : isSafe; 12551 private alias S = typeof((() => (*_range).save)()); 12552 12553 static if (is(typeof(((const R* r) => (*r).save)(null)))) 12554 private alias CS = typeof(((const R* r) => (*r).save)(null)); 12555 12556 12557 static if (isSafe!((R* r) => (*r).save)) 12558 { 12559 @property RefRange!S save() @trusted 12560 { 12561 mixin(_genSave()); 12562 } 12563 12564 static if (is(typeof(((const R* r) => (*r).save)(null)))) @property RefRange!CS save() @trusted const 12565 { 12566 mixin(_genSave()); 12567 } 12568 } 12569 else 12570 { 12571 @property RefRange!S save() 12572 { 12573 mixin(_genSave()); 12574 } 12575 12576 static if (is(typeof(((const R* r) => (*r).save)(null)))) @property RefRange!CS save() const 12577 { 12578 mixin(_genSave()); 12579 } 12580 } 12581 12582 auto opSlice()() 12583 { 12584 return save; 12585 } 12586 12587 auto opSlice()() const 12588 { 12589 return save; 12590 } 12591 12592 private static string _genSave() @safe pure nothrow 12593 { 12594 return `import core.lifetime : emplace;` ~ 12595 `alias S = typeof((() => (*_range).save)());` ~ 12596 `static assert(isForwardRange!S, S.stringof ~ " is not a forward range.");` ~ 12597 `auto mem = new void[S.sizeof];` ~ 12598 `emplace!S(mem, cast(S)(*_range).save);` ~ 12599 `return RefRange!S(cast(S*) mem.ptr);`; 12600 } 12601 12602 static assert(isForwardRange!RefRange); 12603 } 12604 12605 12606 version (StdDdoc) 12607 { 12608 /++ 12609 Only defined if `isBidirectionalRange!R` is `true`. 12610 +/ 12611 @property auto back() {assert(0);} 12612 /++ Ditto +/ 12613 @property auto back() const {assert(0);} 12614 /++ Ditto +/ 12615 @property auto back(ElementType!R value) {assert(0);} 12616 } 12617 else static if (isBidirectionalRange!R) 12618 { 12619 @property auto back() 12620 { 12621 return (*_range).back; 12622 } 12623 12624 static if (is(typeof(((const R* r) => (*r).back)(null)))) @property auto back() const 12625 { 12626 return (*_range).back; 12627 } 12628 12629 static if (is(typeof((*_range).back = (*_range).back))) @property auto back(ElementType!R value) 12630 { 12631 return (*_range).back = value; 12632 } 12633 } 12634 12635 12636 /++ Ditto +/ 12637 static if (isBidirectionalRange!R) void popBack() 12638 { 12639 return (*_range).popBack(); 12640 } 12641 12642 12643 version (StdDdoc) 12644 { 12645 /++ 12646 Only defined if `isRandomAccessRange!R` is `true`. 12647 +/ 12648 auto ref opIndex(IndexType)(IndexType index) {assert(0);} 12649 12650 /++ Ditto +/ 12651 auto ref opIndex(IndexType)(IndexType index) const {assert(0);} 12652 } 12653 else static if (isRandomAccessRange!R) 12654 { 12655 auto ref opIndex(IndexType)(IndexType index) 12656 if (is(typeof((*_range)[index]))) 12657 { 12658 return (*_range)[index]; 12659 } 12660 12661 auto ref opIndex(IndexType)(IndexType index) const 12662 if (is(typeof((*cast(const R*)_range)[index]))) 12663 { 12664 return (*_range)[index]; 12665 } 12666 } 12667 12668 12669 /++ 12670 Only defined if `hasMobileElements!R` and `isForwardRange!R` are 12671 `true`. 12672 +/ 12673 static if (hasMobileElements!R && isForwardRange!R) auto moveFront() 12674 { 12675 return (*_range).moveFront(); 12676 } 12677 12678 12679 /++ 12680 Only defined if `hasMobileElements!R` and `isBidirectionalRange!R` 12681 are `true`. 12682 +/ 12683 static if (hasMobileElements!R && isBidirectionalRange!R) auto moveBack() 12684 { 12685 return (*_range).moveBack(); 12686 } 12687 12688 12689 /++ 12690 Only defined if `hasMobileElements!R` and `isRandomAccessRange!R` 12691 are `true`. 12692 +/ 12693 static if (hasMobileElements!R && isRandomAccessRange!R) auto moveAt(size_t index) 12694 { 12695 return (*_range).moveAt(index); 12696 } 12697 12698 12699 version (StdDdoc) 12700 { 12701 /// Only defined if `hasLength!R` is `true`. 12702 @property size_t length(); 12703 /// ditto 12704 @property size_t length() const; 12705 /// Ditto 12706 alias opDollar = length; 12707 } 12708 else static if (hasLength!R) 12709 { 12710 @property auto length() 12711 { 12712 return (*_range).length; 12713 } 12714 static if (is(typeof(((const R* r) => (*r).length)(null)))) @property auto length() const 12715 { 12716 return (*_range).length; 12717 } 12718 alias opDollar = length; 12719 } 12720 12721 12722 version (StdDdoc) 12723 { 12724 /++ 12725 Only defined if `hasSlicing!R` is `true`. 12726 +/ 12727 auto opSlice(IndexType1, IndexType2) 12728 (IndexType1 begin, IndexType2 end) {assert(0);} 12729 12730 /++ Ditto +/ 12731 auto opSlice(IndexType1, IndexType2) 12732 (IndexType1 begin, IndexType2 end) const {assert(0);} 12733 } 12734 else static if (hasSlicing!R) 12735 { 12736 private alias T = typeof((*_range)[1 .. 2]); 12737 static if (is(typeof((*cast(const R*)_range)[1 .. 2]))) 12738 { 12739 private alias CT = typeof((*cast(const R*)_range)[1 .. 2]); 12740 } 12741 12742 RefRange!T opSlice(IndexType1, IndexType2) 12743 (IndexType1 begin, IndexType2 end) 12744 if (is(typeof((*_range)[begin .. end]))) 12745 { 12746 mixin(_genOpSlice()); 12747 } 12748 12749 RefRange!CT opSlice(IndexType1, IndexType2) 12750 (IndexType1 begin, IndexType2 end) const 12751 if (is(typeof((*cast(const R*)_range)[begin .. end]))) 12752 { 12753 mixin(_genOpSlice()); 12754 } 12755 12756 private static string _genOpSlice() @safe pure nothrow 12757 { 12758 return `import core.lifetime : emplace;` ~ 12759 `alias S = typeof((*_range)[begin .. end]);` ~ 12760 `static assert(hasSlicing!S, S.stringof ~ " is not sliceable.");` ~ 12761 `auto mem = new void[S.sizeof];` ~ 12762 `emplace!S(mem, cast(S)(*_range)[begin .. end]);` ~ 12763 `return RefRange!S(cast(S*) mem.ptr);`; 12764 } 12765 } 12766 12767 12768 private: 12769 12770 R* _range; 12771 } 12772 12773 /// Basic Example 12774 @system unittest 12775 { 12776 import std.algorithm.searching : find; 12777 ubyte[] buffer = [1, 9, 45, 12, 22]; 12778 auto found1 = find(buffer, 45); 12779 assert(found1 == [45, 12, 22]); 12780 assert(buffer == [1, 9, 45, 12, 22]); 12781 12782 auto wrapped1 = refRange(&buffer); 12783 auto found2 = find(wrapped1, 45); 12784 assert(*found2.ptr == [45, 12, 22]); 12785 assert(buffer == [45, 12, 22]); 12786 12787 auto found3 = find(wrapped1.save, 22); 12788 assert(*found3.ptr == [22]); 12789 assert(buffer == [45, 12, 22]); 12790 12791 string str = "hello world"; 12792 auto wrappedStr = refRange(&str); 12793 assert(str.front == 'h'); 12794 str.popFrontN(5); 12795 assert(str == " world"); 12796 assert(wrappedStr.front == ' '); 12797 assert(*wrappedStr.ptr == " world"); 12798 } 12799 12800 /// opAssign Example. 12801 @system unittest 12802 { 12803 ubyte[] buffer1 = [1, 2, 3, 4, 5]; 12804 ubyte[] buffer2 = [6, 7, 8, 9, 10]; 12805 auto wrapped1 = refRange(&buffer1); 12806 auto wrapped2 = refRange(&buffer2); 12807 assert(wrapped1.ptr is &buffer1); 12808 assert(wrapped2.ptr is &buffer2); 12809 assert(wrapped1.ptr !is wrapped2.ptr); 12810 assert(buffer1 != buffer2); 12811 12812 wrapped1 = wrapped2; 12813 12814 //Everything points to the same stuff as before. 12815 assert(wrapped1.ptr is &buffer1); 12816 assert(wrapped2.ptr is &buffer2); 12817 assert(wrapped1.ptr !is wrapped2.ptr); 12818 12819 //But buffer1 has changed due to the assignment. 12820 assert(buffer1 == [6, 7, 8, 9, 10]); 12821 assert(buffer2 == [6, 7, 8, 9, 10]); 12822 12823 buffer2 = [11, 12, 13, 14, 15]; 12824 12825 //Everything points to the same stuff as before. 12826 assert(wrapped1.ptr is &buffer1); 12827 assert(wrapped2.ptr is &buffer2); 12828 assert(wrapped1.ptr !is wrapped2.ptr); 12829 12830 //But buffer2 has changed due to the assignment. 12831 assert(buffer1 == [6, 7, 8, 9, 10]); 12832 assert(buffer2 == [11, 12, 13, 14, 15]); 12833 12834 wrapped2 = null; 12835 12836 //The pointer changed for wrapped2 but not wrapped1. 12837 assert(wrapped1.ptr is &buffer1); 12838 assert(wrapped2.ptr is null); 12839 assert(wrapped1.ptr !is wrapped2.ptr); 12840 12841 //buffer2 is not affected by the assignment. 12842 assert(buffer1 == [6, 7, 8, 9, 10]); 12843 assert(buffer2 == [11, 12, 13, 14, 15]); 12844 } 12845 12846 @system unittest 12847 { 12848 import std.algorithm.iteration : filter; 12849 { 12850 ubyte[] buffer = [1, 2, 3, 4, 5]; 12851 auto wrapper = refRange(&buffer); 12852 auto p = wrapper.ptr; 12853 auto f = wrapper.front; 12854 wrapper.front = f; 12855 auto e = wrapper.empty; 12856 wrapper.popFront(); 12857 auto s = wrapper.save; 12858 auto b = wrapper.back; 12859 wrapper.back = b; 12860 wrapper.popBack(); 12861 auto i = wrapper[0]; 12862 wrapper.moveFront(); 12863 wrapper.moveBack(); 12864 wrapper.moveAt(0); 12865 auto l = wrapper.length; 12866 auto sl = wrapper[0 .. 1]; 12867 assert(wrapper[0 .. $].length == buffer[0 .. $].length); 12868 } 12869 12870 { 12871 ubyte[] buffer = [1, 2, 3, 4, 5]; 12872 const wrapper = refRange(&buffer); 12873 const p = wrapper.ptr; 12874 const f = wrapper.front; 12875 const e = wrapper.empty; 12876 const s = wrapper.save; 12877 const b = wrapper.back; 12878 const i = wrapper[0]; 12879 const l = wrapper.length; 12880 const sl = wrapper[0 .. 1]; 12881 } 12882 12883 { 12884 ubyte[] buffer = [1, 2, 3, 4, 5]; 12885 auto filtered = filter!"true"(buffer); 12886 auto wrapper = refRange(&filtered); 12887 auto p = wrapper.ptr; 12888 auto f = wrapper.front; 12889 wrapper.front = f; 12890 auto e = wrapper.empty; 12891 wrapper.popFront(); 12892 auto s = wrapper.save; 12893 wrapper.moveFront(); 12894 } 12895 12896 { 12897 ubyte[] buffer = [1, 2, 3, 4, 5]; 12898 auto filtered = filter!"true"(buffer); 12899 const wrapper = refRange(&filtered); 12900 const p = wrapper.ptr; 12901 12902 //Cannot currently be const. filter needs to be updated to handle const. 12903 /+ 12904 const f = wrapper.front; 12905 const e = wrapper.empty; 12906 const s = wrapper.save; 12907 +/ 12908 } 12909 12910 { 12911 string str = "hello world"; 12912 auto wrapper = refRange(&str); 12913 auto p = wrapper.ptr; 12914 auto f = wrapper.front; 12915 auto e = wrapper.empty; 12916 wrapper.popFront(); 12917 auto s = wrapper.save; 12918 auto b = wrapper.back; 12919 wrapper.popBack(); 12920 } 12921 12922 { 12923 // https://issues.dlang.org/show_bug.cgi?id=16534 12924 // opDollar should be defined if the wrapped range defines length. 12925 auto range = 10.iota.takeExactly(5); 12926 auto wrapper = refRange(&range); 12927 assert(wrapper.length == 5); 12928 assert(wrapper[0 .. $ - 1].length == 4); 12929 } 12930 } 12931 12932 //Test assignment. 12933 @system unittest 12934 { 12935 ubyte[] buffer1 = [1, 2, 3, 4, 5]; 12936 ubyte[] buffer2 = [6, 7, 8, 9, 10]; 12937 RefRange!(ubyte[]) wrapper1; 12938 RefRange!(ubyte[]) wrapper2 = refRange(&buffer2); 12939 assert(wrapper1.ptr is null); 12940 assert(wrapper2.ptr is &buffer2); 12941 12942 wrapper1 = refRange(&buffer1); 12943 assert(wrapper1.ptr is &buffer1); 12944 12945 wrapper1 = wrapper2; 12946 assert(wrapper1.ptr is &buffer1); 12947 assert(buffer1 == buffer2); 12948 12949 wrapper1 = RefRange!(ubyte[]).init; 12950 assert(wrapper1.ptr is null); 12951 assert(wrapper2.ptr is &buffer2); 12952 assert(buffer1 == buffer2); 12953 assert(buffer1 == [6, 7, 8, 9, 10]); 12954 12955 wrapper2 = null; 12956 assert(wrapper2.ptr is null); 12957 assert(buffer2 == [6, 7, 8, 9, 10]); 12958 } 12959 12960 @system unittest 12961 { 12962 import std.algorithm.comparison : equal; 12963 import std.algorithm.mutation : bringToFront; 12964 import std.algorithm.searching : commonPrefix, find, until; 12965 import std.algorithm.sorting : sort; 12966 12967 //Test that ranges are properly consumed. 12968 { 12969 int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9]; 12970 auto wrapper = refRange(&arr); 12971 12972 assert(*find(wrapper, 41).ptr == [41, 3, 40, 4, 42, 9]); 12973 assert(arr == [41, 3, 40, 4, 42, 9]); 12974 12975 assert(*drop(wrapper, 2).ptr == [40, 4, 42, 9]); 12976 assert(arr == [40, 4, 42, 9]); 12977 12978 assert(equal(until(wrapper, 42), [40, 4])); 12979 assert(arr == [42, 9]); 12980 12981 assert(find(wrapper, 12).empty); 12982 assert(arr.empty); 12983 } 12984 12985 { 12986 string str = "Hello, world-like object."; 12987 auto wrapper = refRange(&str); 12988 12989 assert(*find(wrapper, "l").ptr == "llo, world-like object."); 12990 assert(str == "llo, world-like object."); 12991 12992 assert(equal(take(wrapper, 5), "llo, ")); 12993 assert(str == "world-like object."); 12994 } 12995 12996 //Test that operating on saved ranges does not consume the original. 12997 { 12998 int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9]; 12999 auto wrapper = refRange(&arr); 13000 auto saved = wrapper.save; 13001 saved.popFrontN(3); 13002 assert(*saved.ptr == [41, 3, 40, 4, 42, 9]); 13003 assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]); 13004 } 13005 13006 { 13007 string str = "Hello, world-like object."; 13008 auto wrapper = refRange(&str); 13009 auto saved = wrapper.save; 13010 saved.popFrontN(13); 13011 assert(*saved.ptr == "like object."); 13012 assert(str == "Hello, world-like object."); 13013 } 13014 13015 //Test that functions which use save work properly. 13016 { 13017 int[] arr = [1, 42]; 13018 auto wrapper = refRange(&arr); 13019 assert(equal(commonPrefix(wrapper, [1, 27]), [1])); 13020 } 13021 13022 { 13023 int[] arr = [4, 5, 6, 7, 1, 2, 3]; 13024 auto wrapper = refRange(&arr); 13025 assert(bringToFront(wrapper[0 .. 4], wrapper[4 .. arr.length]) == 3); 13026 assert(arr == [1, 2, 3, 4, 5, 6, 7]); 13027 } 13028 13029 //Test bidirectional functions. 13030 { 13031 int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9]; 13032 auto wrapper = refRange(&arr); 13033 13034 assert(wrapper.back == 9); 13035 assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]); 13036 13037 wrapper.popBack(); 13038 assert(arr == [1, 42, 2, 41, 3, 40, 4, 42]); 13039 } 13040 13041 { 13042 string str = "Hello, world-like object."; 13043 auto wrapper = refRange(&str); 13044 13045 assert(wrapper.back == '.'); 13046 assert(str == "Hello, world-like object."); 13047 13048 wrapper.popBack(); 13049 assert(str == "Hello, world-like object"); 13050 } 13051 13052 //Test random access functions. 13053 { 13054 int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9]; 13055 auto wrapper = refRange(&arr); 13056 13057 assert(wrapper[2] == 2); 13058 assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]); 13059 13060 assert(*wrapper[3 .. 6].ptr != null, [41, 3, 40]); 13061 assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]); 13062 } 13063 13064 //Test move functions. 13065 { 13066 int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9]; 13067 auto wrapper = refRange(&arr); 13068 13069 auto t1 = wrapper.moveFront(); 13070 auto t2 = wrapper.moveBack(); 13071 wrapper.front = t2; 13072 wrapper.back = t1; 13073 assert(arr == [9, 42, 2, 41, 3, 40, 4, 42, 1]); 13074 13075 sort(wrapper.save); 13076 assert(arr == [1, 2, 3, 4, 9, 40, 41, 42, 42]); 13077 } 13078 } 13079 13080 @system unittest 13081 { 13082 struct S 13083 { 13084 @property int front() @safe const pure nothrow { return 0; } 13085 enum bool empty = false; 13086 void popFront() @safe pure nothrow { } 13087 @property auto save() @safe pure nothrow return scope { return this; } 13088 } 13089 13090 S s; 13091 auto wrapper = refRange(&s); 13092 static assert(isInfinite!(typeof(wrapper))); 13093 } 13094 13095 @system unittest 13096 { 13097 class C 13098 { 13099 @property int front() @safe const pure nothrow { return 0; } 13100 @property bool empty() @safe const pure nothrow { return false; } 13101 void popFront() @safe pure nothrow { } 13102 @property auto save() @safe pure nothrow return scope { return this; } 13103 } 13104 static assert(isForwardRange!C); 13105 13106 auto c = new C; 13107 auto cWrapper = refRange(&c); 13108 static assert(is(typeof(cWrapper) == C)); 13109 assert(cWrapper is c); 13110 } 13111 13112 // https://issues.dlang.org/show_bug.cgi?id=14373 13113 @system unittest 13114 { 13115 static struct R 13116 { 13117 @property int front() {return 0;} 13118 void popFront() {empty = true;} 13119 bool empty = false; 13120 } 13121 R r; 13122 refRange(&r).popFront(); 13123 assert(r.empty); 13124 } 13125 13126 // https://issues.dlang.org/show_bug.cgi?id=14575 13127 @system unittest 13128 { 13129 struct R 13130 { 13131 Object front; 13132 alias back = front; 13133 bool empty = false; 13134 void popFront() {empty = true;} 13135 alias popBack = popFront; 13136 @property R save() {return this;} 13137 } 13138 static assert(isBidirectionalRange!R); 13139 R r; 13140 auto rr = refRange(&r); 13141 13142 struct R2 13143 { 13144 @property Object front() {return null;} 13145 @property const(Object) front() const {return null;} 13146 alias back = front; 13147 bool empty = false; 13148 void popFront() {empty = true;} 13149 alias popBack = popFront; 13150 @property R2 save() {return this;} 13151 } 13152 static assert(isBidirectionalRange!R2); 13153 R2 r2; 13154 auto rr2 = refRange(&r2); 13155 } 13156 13157 // https://issues.dlang.org/show_bug.cgi?id=24801 13158 @safe unittest 13159 { 13160 13161 { 13162 static struct R 13163 { 13164 int front() => 0; 13165 void popFront() {} 13166 bool empty() => false; 13167 } 13168 R range; 13169 auto r = RefRange!R(&range); 13170 } 13171 13172 { 13173 static struct R 13174 { 13175 size_t start, end; 13176 size_t length() => end - start; 13177 int opIndex(size_t i) => 0; 13178 13179 13180 int front() => this[0]; 13181 int back() => this[length-1]; 13182 void popFront() { start++; } 13183 void popBack() { end--; } 13184 bool empty() => length == 0; 13185 R save() const => R(); 13186 } 13187 13188 R range; 13189 auto r = RefRange!R(&range); 13190 } 13191 13192 13193 } 13194 13195 /// ditto 13196 auto refRange(R)(R* range) 13197 if (isInputRange!R) 13198 { 13199 static if (!is(R == class)) 13200 return RefRange!R(range); 13201 else 13202 return *range; 13203 } 13204 13205 // https://issues.dlang.org/show_bug.cgi?id=9060 13206 @safe unittest 13207 { 13208 import std.algorithm.iteration : map, joiner, group; 13209 import std.algorithm.searching : until; 13210 // fix for std.algorithm 13211 auto r = map!(x => 0)([1]); 13212 chain(r, r); 13213 zip(r, r); 13214 roundRobin(r, r); 13215 13216 struct NRAR { 13217 typeof(r) input; 13218 @property empty() { return input.empty; } 13219 @property front() { return input.front; } 13220 void popFront() { input.popFront(); } 13221 @property save() { return NRAR(input.save); } 13222 } 13223 auto n1 = NRAR(r); 13224 cycle(n1); // non random access range version 13225 13226 assumeSorted(r); 13227 13228 // fix for std.range 13229 joiner([r], [9]); 13230 13231 struct NRAR2 { 13232 NRAR input; 13233 @property empty() { return true; } 13234 @property front() { return input; } 13235 void popFront() { } 13236 @property save() { return NRAR2(input.save); } 13237 } 13238 auto n2 = NRAR2(n1); 13239 joiner(n2); 13240 13241 group(r); 13242 13243 until(r, 7); 13244 static void foo(R)(R r) { until!(x => x > 7)(r); } 13245 foo(r); 13246 } 13247 13248 private struct Bitwise(R) 13249 if (isInputRange!R && isIntegral!(ElementType!R)) 13250 { 13251 import std.traits : Unsigned; 13252 private: 13253 alias ElemType = ElementType!R; 13254 alias UnsignedElemType = Unsigned!ElemType; 13255 13256 R parent; 13257 enum bitsNum = ElemType.sizeof * 8; 13258 size_t maskPos = 1; 13259 13260 static if (isBidirectionalRange!R) 13261 { 13262 size_t backMaskPos = bitsNum; 13263 } 13264 13265 public: 13266 this()(auto ref R range) 13267 { 13268 parent = range; 13269 } 13270 13271 static if (isInfinite!R) 13272 { 13273 enum empty = false; 13274 } 13275 else 13276 { 13277 /** 13278 * Check if the range is empty 13279 * 13280 * Returns: a boolean true or false 13281 */ 13282 bool empty() 13283 { 13284 static if (hasLength!R) 13285 { 13286 return length == 0; 13287 } 13288 else static if (isBidirectionalRange!R) 13289 { 13290 if (parent.empty) 13291 { 13292 return true; 13293 } 13294 else 13295 { 13296 /* 13297 If we have consumed the last element of the range both from 13298 the front and the back, then the masks positions will overlap 13299 */ 13300 return parent.save.dropOne.empty && (maskPos > backMaskPos); 13301 } 13302 } 13303 else 13304 { 13305 /* 13306 If we consumed the last element of the range, but not all the 13307 bits in the last element 13308 */ 13309 return parent.empty; 13310 } 13311 } 13312 } 13313 13314 bool front() 13315 { 13316 assert(!empty); 13317 return (parent.front & mask(maskPos)) != 0; 13318 } 13319 13320 void popFront() 13321 { 13322 assert(!empty); 13323 ++maskPos; 13324 if (maskPos > bitsNum) 13325 { 13326 parent.popFront; 13327 maskPos = 1; 13328 } 13329 } 13330 13331 static if (hasLength!R) 13332 { 13333 size_t length() 13334 { 13335 auto len = parent.length * bitsNum - (maskPos - 1); 13336 static if (isBidirectionalRange!R) 13337 { 13338 len -= bitsNum - backMaskPos; 13339 } 13340 return len; 13341 } 13342 13343 alias opDollar = length; 13344 } 13345 13346 static if (isForwardRange!R) 13347 { 13348 typeof(this) save() 13349 { 13350 auto result = this; 13351 result.parent = parent.save; 13352 return result; 13353 } 13354 } 13355 13356 static if (isBidirectionalRange!R) 13357 { 13358 bool back() 13359 { 13360 assert(!empty); 13361 return (parent.back & mask(backMaskPos)) != 0; 13362 } 13363 13364 void popBack() 13365 { 13366 assert(!empty); 13367 --backMaskPos; 13368 if (backMaskPos == 0) 13369 { 13370 parent.popBack; 13371 backMaskPos = bitsNum; 13372 } 13373 } 13374 } 13375 13376 static if (isRandomAccessRange!R) 13377 { 13378 /** 13379 Return the `n`th bit within the range 13380 */ 13381 bool opIndex(size_t n) 13382 in 13383 { 13384 /* 13385 If it does not have the length property, it means that R is 13386 an infinite range 13387 */ 13388 static if (hasLength!R) 13389 { 13390 assert(n < length, "Index out of bounds"); 13391 } 13392 } 13393 do 13394 { 13395 immutable size_t remainingBits = bitsNum - maskPos + 1; 13396 // If n >= maskPos, then the bit sign will be 1, otherwise 0 13397 immutable ptrdiff_t sign = (remainingBits - n - 1) >> (ptrdiff_t.sizeof * 8 - 1); 13398 /* 13399 By truncating n with remainingBits bits we have skipped the 13400 remaining bits in parent[0], so we need to add 1 to elemIndex. 13401 13402 Because bitsNum is a power of 2, n / bitsNum == n >> bitsNum.bsf 13403 */ 13404 import core.bitop : bsf; 13405 immutable size_t elemIndex = sign * (((n - remainingBits) >> bitsNum.bsf) + 1); 13406 13407 /* 13408 Since the indexing is from LSB to MSB, we need to index at the 13409 remainder of (n - remainingBits). 13410 13411 Because bitsNum is a power of 2, n % bitsNum == n & (bitsNum - 1) 13412 */ 13413 immutable size_t elemMaskPos = (sign ^ 1) * (maskPos + n) 13414 + sign * (1 + ((n - remainingBits) & (bitsNum - 1))); 13415 13416 return (parent[elemIndex] & mask(elemMaskPos)) != 0; 13417 } 13418 13419 static if (hasAssignableElements!R) 13420 { 13421 /** 13422 Assigns `flag` to the `n`th bit within the range 13423 */ 13424 void opIndexAssign(bool flag, size_t n) 13425 in 13426 { 13427 static if (hasLength!R) 13428 { 13429 assert(n < length, "Index out of bounds"); 13430 } 13431 } 13432 do 13433 { 13434 import core.bitop : bsf; 13435 13436 immutable size_t remainingBits = bitsNum - maskPos + 1; 13437 immutable ptrdiff_t sign = (remainingBits - n - 1) >> (ptrdiff_t.sizeof * 8 - 1); 13438 immutable size_t elemIndex = sign * (((n - remainingBits) >> bitsNum.bsf) + 1); 13439 immutable size_t elemMaskPos = (sign ^ 1) * (maskPos + n) 13440 + sign * (1 + ((n - remainingBits) & (bitsNum - 1))); 13441 13442 auto elem = parent[elemIndex]; 13443 auto elemMask = mask(elemMaskPos); 13444 parent[elemIndex] = cast(UnsignedElemType)(flag * (elem | elemMask) 13445 + (flag ^ 1) * (elem & ~elemMask)); 13446 } 13447 } 13448 13449 Bitwise!R opSlice() 13450 { 13451 return this.save; 13452 } 13453 13454 Bitwise!R opSlice(size_t start, size_t end) 13455 in 13456 { 13457 assert(start < end, "Invalid bounds: end <= start"); 13458 } 13459 do 13460 { 13461 import core.bitop : bsf; 13462 13463 size_t remainingBits = bitsNum - maskPos + 1; 13464 ptrdiff_t sign = (remainingBits - start - 1) >> (ptrdiff_t.sizeof * 8 - 1); 13465 immutable size_t startElemIndex = sign * (((start - remainingBits) >> bitsNum.bsf) + 1); 13466 immutable size_t startElemMaskPos = (sign ^ 1) * (maskPos + start) 13467 + sign * (1 + ((start - remainingBits) & (bitsNum - 1))); 13468 13469 immutable size_t sliceLen = end - start - 1; 13470 remainingBits = bitsNum - startElemMaskPos + 1; 13471 sign = (remainingBits - sliceLen - 1) >> (ptrdiff_t.sizeof * 8 - 1); 13472 immutable size_t endElemIndex = startElemIndex 13473 + sign * (((sliceLen - remainingBits) >> bitsNum.bsf) + 1); 13474 immutable size_t endElemMaskPos = (sign ^ 1) * (startElemMaskPos + sliceLen) 13475 + sign * (1 + ((sliceLen - remainingBits) & (bitsNum - 1))); 13476 13477 typeof(return) result; 13478 // Get the slice to be returned from the parent 13479 result.parent = (parent[startElemIndex .. endElemIndex + 1]).save; 13480 result.maskPos = startElemMaskPos; 13481 static if (isBidirectionalRange!R) 13482 { 13483 result.backMaskPos = endElemMaskPos; 13484 } 13485 return result; 13486 } 13487 } 13488 13489 private: 13490 auto mask(size_t maskPos) 13491 { 13492 return (1UL << (maskPos - 1UL)); 13493 } 13494 } 13495 13496 /** 13497 Bitwise adapter over an integral type range. Consumes the range elements bit by 13498 bit, from the least significant bit to the most significant bit. 13499 13500 Params: 13501 R = an integral $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to iterate over 13502 range = range to consume bit by by 13503 13504 Returns: 13505 A `Bitwise` input range with propagated forward, bidirectional 13506 and random access capabilities 13507 */ 13508 auto bitwise(R)(auto ref R range) 13509 if (isInputRange!R && isIntegral!(ElementType!R)) 13510 { 13511 return Bitwise!R(range); 13512 } 13513 13514 /// 13515 @safe pure unittest 13516 { 13517 import std.algorithm.comparison : equal; 13518 import std.format : format; 13519 13520 // 00000011 00001001 13521 ubyte[] arr = [3, 9]; 13522 auto r = arr.bitwise; 13523 13524 // iterate through it as with any other range 13525 assert(format("%(%d%)", r) == "1100000010010000"); 13526 assert(format("%(%d%)", r.retro).equal("1100000010010000".retro)); 13527 13528 auto r2 = r[5 .. $]; 13529 // set a bit 13530 r[2] = 1; 13531 assert(arr[0] == 7); 13532 assert(r[5] == r2[0]); 13533 } 13534 13535 /// You can use bitwise to implement an uniform bool generator 13536 @safe unittest 13537 { 13538 import std.algorithm.comparison : equal; 13539 import std.random : rndGen; 13540 13541 auto rb = rndGen.bitwise; 13542 static assert(isInfinite!(typeof(rb))); 13543 13544 auto rb2 = rndGen.bitwise; 13545 // Don't forget that structs are passed by value 13546 assert(rb.take(10).equal(rb2.take(10))); 13547 } 13548 13549 // Test nogc inference 13550 @safe @nogc unittest 13551 { 13552 static ubyte[] arr = [3, 9]; 13553 auto bw = arr.bitwise; 13554 auto bw2 = bw[]; 13555 auto bw3 = bw[8 .. $]; 13556 bw3[2] = true; 13557 13558 assert(arr[1] == 13); 13559 assert(bw[$ - 6]); 13560 assert(bw[$ - 6] == bw2[$ - 6]); 13561 assert(bw[$ - 6] == bw3[$ - 6]); 13562 } 13563 13564 // Test all range types over all integral types 13565 @safe pure nothrow unittest 13566 { 13567 import std.meta : AliasSeq; 13568 import std.internal.test.dummyrange; 13569 13570 alias IntegralTypes = AliasSeq!(byte, ubyte, short, ushort, int, uint, 13571 long, ulong); 13572 foreach (IntegralType; IntegralTypes) 13573 { 13574 foreach (T; AllDummyRangesType!(IntegralType[])) 13575 { 13576 T a; 13577 auto bw = Bitwise!T(a); 13578 13579 static if (isForwardRange!T) 13580 { 13581 auto bwFwdSave = bw.save; 13582 } 13583 13584 static if (isBidirectionalRange!T) 13585 { 13586 auto bwBack = bw.save; 13587 auto bwBackSave = bw.save; 13588 } 13589 13590 static if (hasLength!T) 13591 { 13592 auto bwLength = bw.length; 13593 assert(bw.length == (IntegralType.sizeof * 8 * a.length)); 13594 static if (isForwardRange!T) 13595 { 13596 assert(bw.length == bwFwdSave.length); 13597 } 13598 } 13599 13600 // Make sure front and back are not the mechanisms that modify the range 13601 long numCalls = 42; 13602 bool initialFrontValue; 13603 13604 if (!bw.empty) 13605 { 13606 initialFrontValue = bw.front; 13607 } 13608 13609 while (!bw.empty && (--numCalls)) 13610 { 13611 bw.front; 13612 assert(bw.front == initialFrontValue); 13613 } 13614 13615 /* 13616 Check that empty works properly and that popFront does not get called 13617 more times than it should 13618 */ 13619 numCalls = 0; 13620 while (!bw.empty) 13621 { 13622 ++numCalls; 13623 13624 static if (hasLength!T) 13625 { 13626 assert(bw.length == bwLength); 13627 --bwLength; 13628 } 13629 13630 static if (isForwardRange!T) 13631 { 13632 assert(bw.front == bwFwdSave.front); 13633 bwFwdSave.popFront(); 13634 } 13635 13636 static if (isBidirectionalRange!T) 13637 { 13638 assert(bwBack.front == bwBackSave.front); 13639 bwBack.popBack(); 13640 bwBackSave.popBack(); 13641 } 13642 bw.popFront(); 13643 } 13644 13645 auto rangeLen = numCalls / (IntegralType.sizeof * 8); 13646 assert(numCalls == (IntegralType.sizeof * 8 * rangeLen)); 13647 assert(bw.empty); 13648 static if (isForwardRange!T) 13649 { 13650 assert(bwFwdSave.empty); 13651 } 13652 13653 static if (isBidirectionalRange!T) 13654 { 13655 assert(bwBack.empty); 13656 } 13657 } 13658 } 13659 } 13660 13661 // Test opIndex and opSlice 13662 @system unittest 13663 { 13664 import std.meta : AliasSeq; 13665 alias IntegralTypes = AliasSeq!(byte, ubyte, short, ushort, int, uint, 13666 long, ulong); 13667 foreach (IntegralType; IntegralTypes) 13668 { 13669 size_t bitsNum = IntegralType.sizeof * 8; 13670 13671 auto first = IntegralType(1); 13672 13673 // 2 ^ (bitsNum - 1) 13674 auto second = cast(IntegralType)(IntegralType(1) << (bitsNum - 2)); 13675 13676 IntegralType[] a = [first, second]; 13677 auto bw = Bitwise!(IntegralType[])(a); 13678 13679 // Check against lsb of a[0] 13680 assert(bw[0] == true); 13681 // Check against msb - 1 of a[1] 13682 assert(bw[2 * bitsNum - 2] == true); 13683 13684 bw.popFront(); 13685 assert(bw[2 * bitsNum - 3] == true); 13686 13687 import std.exception : assertThrown; 13688 13689 version (D_NoBoundsChecks) {} 13690 else 13691 { 13692 // Check out of bounds error 13693 assertThrown!Error(bw[2 * bitsNum - 1]); 13694 } 13695 13696 bw[2] = true; 13697 assert(bw[2] == true); 13698 bw.popFront(); 13699 assert(bw[1] == true); 13700 13701 auto bw2 = bw[0 .. $ - 5]; 13702 auto bw3 = bw2[]; 13703 assert(bw2.length == bw.length - 5); 13704 assert(bw2.length == bw3.length); 13705 bw2.popFront(); 13706 assert(bw2.length != bw3.length); 13707 } 13708 } 13709 13710 /********************************* 13711 * An OutputRange that discards the data it receives. 13712 */ 13713 struct NullSink 13714 { 13715 void put(E)(scope const E) pure @safe @nogc nothrow {} 13716 } 13717 13718 /// ditto 13719 auto ref nullSink() 13720 { 13721 static NullSink sink; 13722 return sink; 13723 } 13724 13725 /// 13726 @safe nothrow unittest 13727 { 13728 import std.algorithm.iteration : map; 13729 import std.algorithm.mutation : copy; 13730 [4, 5, 6].map!(x => x * 2).copy(nullSink); // data is discarded 13731 } 13732 13733 /// 13734 @safe unittest 13735 { 13736 import std.csv : csvNextToken; 13737 13738 string line = "a,b,c"; 13739 13740 // ignore the first column 13741 line.csvNextToken(nullSink, ',', '"'); 13742 line.popFront; 13743 13744 // look at the second column 13745 Appender!string app; 13746 line.csvNextToken(app, ',', '"'); 13747 assert(app.data == "b"); 13748 } 13749 13750 @safe unittest 13751 { 13752 auto r = 10.iota 13753 .tee(nullSink) 13754 .dropOne; 13755 13756 assert(r.front == 1); 13757 } 13758 13759 /++ 13760 13761 Implements a "tee" style pipe, wrapping an input range so that elements of the 13762 range can be passed to a provided function or $(LREF OutputRange) as they are 13763 iterated over. This is useful for printing out intermediate values in a long 13764 chain of range code, performing some operation with side-effects on each call 13765 to `front` or `popFront`, or diverting the elements of a range into an 13766 auxiliary $(LREF OutputRange). 13767 13768 It is important to note that as the resultant range is evaluated lazily, 13769 in the case of the version of `tee` that takes a function, the function 13770 will not actually be executed until the range is "walked" using functions 13771 that evaluate ranges, such as $(REF array, std,array) or 13772 $(REF fold, std,algorithm,iteration). 13773 13774 Params: 13775 pipeOnPop = If `Yes.pipeOnPop`, simply iterating the range without ever 13776 calling `front` is enough to have `tee` mirror elements to `outputRange` (or, 13777 respectively, `fun`). Note that each `popFront()` call will mirror the 13778 old `front` value, not the new one. This means that the last value will 13779 not be forwarded if the range isn't iterated until empty. If 13780 `No.pipeOnPop`, only elements for which `front` does get called will be 13781 also sent to `outputRange`/`fun`. If `front` is called twice for the same 13782 element, it will still be sent only once. If this caching is undesired, 13783 consider using $(REF map, std,algorithm,iteration) instead. 13784 inputRange = The input range being passed through. 13785 outputRange = This range will receive elements of `inputRange` progressively 13786 as iteration proceeds. 13787 fun = This function will be called with elements of `inputRange` 13788 progressively as iteration proceeds. 13789 13790 Returns: 13791 An input range that offers the elements of `inputRange`. Regardless of 13792 whether `inputRange` is a more powerful range (forward, bidirectional etc), 13793 the result is always an input range. Reading this causes `inputRange` to be 13794 iterated and returns its elements in turn. In addition, the same elements 13795 will be passed to `outputRange` or `fun` as well. 13796 13797 See_Also: $(REF each, std,algorithm,iteration) 13798 +/ 13799 auto tee(Flag!"pipeOnPop" pipeOnPop = Yes.pipeOnPop, R1, R2)(R1 inputRange, R2 outputRange) 13800 if (isInputRange!R1 && isOutputRange!(R2, ElementType!R1)) 13801 { 13802 static struct Result 13803 { 13804 private R1 _input; 13805 private R2 _output; 13806 static if (!pipeOnPop) 13807 { 13808 private bool _frontAccessed; 13809 } 13810 13811 mixin ImplementLength!_input; 13812 13813 static if (isInfinite!R1) 13814 { 13815 enum bool empty = false; 13816 } 13817 else 13818 { 13819 @property bool empty() { return _input.empty; } 13820 } 13821 13822 void popFront() 13823 { 13824 assert(!_input.empty, "Attempting to popFront an empty tee"); 13825 static if (pipeOnPop) 13826 { 13827 put(_output, _input.front); 13828 } 13829 else 13830 { 13831 _frontAccessed = false; 13832 } 13833 _input.popFront(); 13834 } 13835 13836 @property auto ref front() 13837 { 13838 assert(!_input.empty, "Attempting to fetch the front of an empty tee"); 13839 static if (!pipeOnPop) 13840 { 13841 if (!_frontAccessed) 13842 { 13843 _frontAccessed = true; 13844 put(_output, _input.front); 13845 } 13846 } 13847 return _input.front; 13848 } 13849 } 13850 13851 return Result(inputRange, outputRange); 13852 } 13853 13854 /// Ditto 13855 auto tee(alias fun, Flag!"pipeOnPop" pipeOnPop = Yes.pipeOnPop, R1)(R1 inputRange) 13856 if (is(typeof(fun) == void) || isSomeFunction!fun) 13857 { 13858 import std.traits : isDelegate, isFunctionPointer; 13859 /* 13860 Distinguish between function literals and template lambdas 13861 when using either as an $(LREF OutputRange). Since a template 13862 has no type, typeof(template) will always return void. 13863 If it's a template lambda, it's first necessary to instantiate 13864 it with `ElementType!R1`. 13865 */ 13866 static if (is(typeof(fun) == void)) 13867 alias _fun = fun!(ElementType!R1); 13868 else 13869 alias _fun = fun; 13870 13871 static if (isFunctionPointer!_fun || isDelegate!_fun) 13872 { 13873 return tee!pipeOnPop(inputRange, _fun); 13874 } 13875 else 13876 { 13877 return tee!pipeOnPop(inputRange, &_fun); 13878 } 13879 } 13880 13881 /// 13882 @safe unittest 13883 { 13884 import std.algorithm.comparison : equal; 13885 import std.algorithm.iteration : filter, map; 13886 13887 // Sum values while copying 13888 int[] values = [1, 4, 9, 16, 25]; 13889 int sum = 0; 13890 auto newValues = values.tee!(a => sum += a).array; 13891 assert(equal(newValues, values)); 13892 assert(sum == 1 + 4 + 9 + 16 + 25); 13893 13894 // Count values that pass the first filter 13895 int count = 0; 13896 auto newValues4 = values.filter!(a => a < 10) 13897 .tee!(a => count++) 13898 .map!(a => a + 1) 13899 .filter!(a => a < 10); 13900 13901 //Fine, equal also evaluates any lazy ranges passed to it. 13902 //count is not 3 until equal evaluates newValues4 13903 assert(equal(newValues4, [2, 5])); 13904 assert(count == 3); 13905 } 13906 13907 // 13908 @safe unittest 13909 { 13910 import std.algorithm.comparison : equal; 13911 import std.algorithm.iteration : filter, map; 13912 13913 int[] values = [1, 4, 9, 16, 25]; 13914 13915 int count = 0; 13916 auto newValues = values.filter!(a => a < 10) 13917 .tee!(a => count++, No.pipeOnPop) 13918 .map!(a => a + 1) 13919 .filter!(a => a < 10); 13920 13921 auto val = newValues.front; 13922 assert(count == 1); 13923 //front is only evaluated once per element 13924 val = newValues.front; 13925 assert(count == 1); 13926 13927 //popFront() called, fun will be called 13928 //again on the next access to front 13929 newValues.popFront(); 13930 newValues.front; 13931 assert(count == 2); 13932 13933 int[] preMap = new int[](3), postMap = []; 13934 auto mappedValues = values.filter!(a => a < 10) 13935 //Note the two different ways of using tee 13936 .tee(preMap) 13937 .map!(a => a + 1) 13938 .tee!(a => postMap ~= a) 13939 .filter!(a => a < 10); 13940 assert(equal(mappedValues, [2, 5])); 13941 assert(equal(preMap, [1, 4, 9])); 13942 assert(equal(postMap, [2, 5, 10])); 13943 } 13944 13945 // 13946 @safe unittest 13947 { 13948 import std.algorithm.comparison : equal; 13949 import std.algorithm.iteration : filter, map; 13950 13951 char[] txt = "Line one, Line 2".dup; 13952 13953 bool isVowel(dchar c) 13954 { 13955 import std.string : indexOf; 13956 return "AaEeIiOoUu".indexOf(c) != -1; 13957 } 13958 13959 int vowelCount = 0; 13960 int shiftedCount = 0; 13961 auto removeVowels = txt.tee!(c => isVowel(c) ? vowelCount++ : 0) 13962 .filter!(c => !isVowel(c)) 13963 .map!(c => (c == ' ') ? c : c + 1) 13964 .tee!(c => isVowel(c) ? shiftedCount++ : 0); 13965 assert(equal(removeVowels, "Mo o- Mo 3")); 13966 assert(vowelCount == 6); 13967 assert(shiftedCount == 3); 13968 } 13969 13970 @safe unittest 13971 { 13972 // Manually stride to test different pipe behavior. 13973 void testRange(Range)(Range r) 13974 { 13975 const int strideLen = 3; 13976 int i = 0; 13977 ElementType!Range elem1; 13978 ElementType!Range elem2; 13979 while (!r.empty) 13980 { 13981 if (i % strideLen == 0) 13982 { 13983 //Make sure front is only 13984 //evaluated once per item 13985 elem1 = r.front; 13986 elem2 = r.front; 13987 assert(elem1 == elem2); 13988 } 13989 r.popFront(); 13990 i++; 13991 } 13992 } 13993 13994 string txt = "abcdefghijklmnopqrstuvwxyz"; 13995 13996 int popCount = 0; 13997 auto pipeOnPop = txt.tee!(a => popCount++); 13998 testRange(pipeOnPop); 13999 assert(popCount == 26); 14000 14001 int frontCount = 0; 14002 auto pipeOnFront = txt.tee!(a => frontCount++, No.pipeOnPop); 14003 testRange(pipeOnFront); 14004 assert(frontCount == 9); 14005 } 14006 14007 @safe unittest 14008 { 14009 import std.algorithm.comparison : equal; 14010 import std.meta : AliasSeq; 14011 14012 //Test diverting elements to an OutputRange 14013 string txt = "abcdefghijklmnopqrstuvwxyz"; 14014 14015 dchar[] asink1 = []; 14016 auto fsink = (dchar c) { asink1 ~= c; }; 14017 auto result1 = txt.tee(fsink).array; 14018 assert(equal(txt, result1) && (equal(result1, asink1))); 14019 14020 dchar[] _asink1 = []; 14021 auto _result1 = txt.tee!((dchar c) { _asink1 ~= c; })().array; 14022 assert(equal(txt, _result1) && (equal(_result1, _asink1))); 14023 14024 dchar[] asink2 = new dchar[](txt.length); 14025 void fsink2(dchar c) { static int i = 0; asink2[i] = c; i++; } 14026 auto result2 = txt.tee(&fsink2).array; 14027 assert(equal(txt, result2) && equal(result2, asink2)); 14028 14029 dchar[] asink3 = new dchar[](txt.length); 14030 auto result3 = txt.tee(asink3).array; 14031 assert(equal(txt, result3) && equal(result3, asink3)); 14032 14033 static foreach (CharType; AliasSeq!(char, wchar, dchar)) 14034 {{ 14035 auto appSink = appender!(CharType[])(); 14036 auto appResult = txt.tee(appSink).array; 14037 assert(equal(txt, appResult) && equal(appResult, appSink.data)); 14038 }} 14039 14040 static foreach (StringType; AliasSeq!(string, wstring, dstring)) 14041 {{ 14042 auto appSink = appender!StringType(); 14043 auto appResult = txt.tee(appSink).array; 14044 assert(equal(txt, appResult) && equal(appResult, appSink.data)); 14045 }} 14046 } 14047 14048 // https://issues.dlang.org/show_bug.cgi?id=13483 14049 @safe unittest 14050 { 14051 static void func1(T)(T x) {} 14052 void func2(int x) {} 14053 14054 auto r = [1, 2, 3, 4].tee!func1.tee!func2; 14055 } 14056 14057 /** 14058 Extends the length of the input range `r` by padding out the start of the 14059 range with the element `e`. The element `e` must be of a common type with 14060 the element type of the range `r` as defined by $(REF CommonType, std, traits). 14061 If `n` is less than the length of of `r`, then `r` is returned unmodified. 14062 14063 If `r` is a string with Unicode characters in it, `padLeft` follows D's rules 14064 about length for strings, which is not the number of characters, or 14065 graphemes, but instead the number of encoding units. If you want to treat each 14066 grapheme as only one encoding unit long, then call 14067 $(REF byGrapheme, std, uni) before calling this function. 14068 14069 If `r` has a length, then this is $(BIGOH 1). Otherwise, it's $(BIGOH r.length). 14070 14071 Params: 14072 r = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives) with a length, or a forward range 14073 e = element to pad the range with 14074 n = the length to pad to 14075 14076 Returns: 14077 A range containing the elements of the original range with the extra padding 14078 14079 See Also: 14080 $(REF leftJustifier, std, string) 14081 */ 14082 auto padLeft(R, E)(R r, E e, size_t n) 14083 if ( 14084 ((isInputRange!R && hasLength!R) || isForwardRange!R) && 14085 !is(CommonType!(ElementType!R, E) == void) 14086 ) 14087 { 14088 static if (hasLength!R) 14089 auto dataLength = r.length; 14090 else 14091 auto dataLength = r.save.walkLength(n); 14092 14093 return e.repeat(n > dataLength ? n - dataLength : 0).chain(r); 14094 } 14095 14096 /// 14097 @safe pure unittest 14098 { 14099 import std.algorithm.comparison : equal; 14100 14101 assert([1, 2, 3, 4].padLeft(0, 6).equal([0, 0, 1, 2, 3, 4])); 14102 assert([1, 2, 3, 4].padLeft(0, 3).equal([1, 2, 3, 4])); 14103 14104 assert("abc".padLeft('_', 6).equal("___abc")); 14105 } 14106 14107 @safe pure nothrow unittest 14108 { 14109 import std.algorithm.comparison : equal; 14110 import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy; 14111 import std.meta : AliasSeq; 14112 14113 alias DummyRanges = AliasSeq!( 14114 DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Input), 14115 DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Forward), 14116 DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Bidirectional), 14117 DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random), 14118 DummyRange!(ReturnBy.Reference, Length.No, RangeType.Forward), 14119 DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Input), 14120 DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Forward), 14121 DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Bidirectional), 14122 DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random), 14123 DummyRange!(ReturnBy.Value, Length.No, RangeType.Forward) 14124 ); 14125 14126 foreach (Range; DummyRanges) 14127 { 14128 Range r; 14129 assert(r 14130 .padLeft(0, 12) 14131 .equal([0, 0, 1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U]) 14132 ); 14133 } 14134 } 14135 14136 // Test nogc inference 14137 @safe @nogc pure unittest 14138 { 14139 import std.algorithm.comparison : equal; 14140 14141 static immutable r1 = [1, 2, 3, 4]; 14142 static immutable r2 = [0, 0, 1, 2, 3, 4]; 14143 assert(r1.padLeft(0, 6).equal(r2)); 14144 } 14145 14146 /** 14147 Extend the length of the input range `r` by padding out the end of the range 14148 with the element `e`. The element `e` must be of a common type with the 14149 element type of the range `r` as defined by $(REF CommonType, std, traits). 14150 If `n` is less than the length of of `r`, then the contents of `r` are 14151 returned. 14152 14153 The range primitives that the resulting range provides depends whether or not `r` 14154 provides them. Except the functions `back` and `popBack`, which also require 14155 the range to have a length as well as `back` and `popBack` 14156 14157 Params: 14158 r = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives) with a length 14159 e = element to pad the range with 14160 n = the length to pad to 14161 14162 Returns: 14163 A range containing the elements of the original range with the extra padding 14164 14165 See Also: 14166 $(REF rightJustifier, std, string) 14167 */ 14168 auto padRight(R, E)(R r, E e, size_t n) 14169 if ( 14170 isInputRange!R && 14171 !isInfinite!R && 14172 !is(CommonType!(ElementType!R, E) == void)) 14173 { 14174 static struct Result 14175 { 14176 private: 14177 R data; 14178 E element; 14179 static if (hasLength!R) 14180 { 14181 size_t padLength; 14182 } 14183 else 14184 { 14185 size_t minLength; 14186 size_t consumed; 14187 } 14188 14189 public: 14190 bool empty() @property 14191 { 14192 static if (hasLength!R) 14193 { 14194 return data.empty && padLength == 0; 14195 } 14196 else 14197 { 14198 return data.empty && consumed >= minLength; 14199 } 14200 } 14201 14202 auto front() @property 14203 { 14204 assert(!empty, "Attempting to fetch the front of an empty padRight"); 14205 return data.empty ? element : data.front; 14206 } 14207 14208 void popFront() 14209 { 14210 assert(!empty, "Attempting to popFront an empty padRight"); 14211 14212 static if (hasLength!R) 14213 { 14214 if (!data.empty) 14215 { 14216 data.popFront; 14217 } 14218 else 14219 { 14220 --padLength; 14221 } 14222 } 14223 else 14224 { 14225 ++consumed; 14226 if (!data.empty) 14227 { 14228 data.popFront; 14229 } 14230 } 14231 } 14232 14233 static if (hasLength!R) 14234 { 14235 size_t length() @property 14236 { 14237 return data.length + padLength; 14238 } 14239 } 14240 14241 static if (isForwardRange!R) 14242 { 14243 auto save() @property 14244 { 14245 typeof(this) result = this; 14246 data = data.save; 14247 return result; 14248 } 14249 } 14250 14251 static if (isBidirectionalRange!R && hasLength!R) 14252 { 14253 auto back() @property 14254 { 14255 assert(!empty, "Attempting to fetch the back of an empty padRight"); 14256 return padLength > 0 ? element : data.back; 14257 } 14258 14259 void popBack() 14260 { 14261 assert(!empty, "Attempting to popBack an empty padRight"); 14262 if (padLength > 0) 14263 { 14264 --padLength; 14265 } 14266 else 14267 { 14268 data.popBack; 14269 } 14270 } 14271 } 14272 14273 static if (isRandomAccessRange!R && hasLength!R) 14274 { 14275 E opIndex(size_t index) 14276 { 14277 assert(index <= this.length, "Index out of bounds"); 14278 return index >= data.length ? element : data[index]; 14279 } 14280 } 14281 14282 static if (hasSlicing!R && hasLength!R) 14283 { 14284 auto opSlice(size_t a, size_t b) 14285 { 14286 assert( 14287 a <= b, 14288 "Attempting to slice a padRight with a larger first argument than the second." 14289 ); 14290 assert( 14291 b <= length, 14292 "Attempting to slice using an out of bounds index on a padRight" 14293 ); 14294 return Result( 14295 a >= data.length ? data[0 .. 0] : b <= data.length ? data[a .. b] : data[a .. data.length], 14296 element, b - a); 14297 } 14298 14299 alias opDollar = length; 14300 } 14301 14302 this(R r, E e, size_t n) 14303 { 14304 data = r; 14305 element = e; 14306 static if (hasLength!R) 14307 { 14308 padLength = n > data.length ? n - data.length : 0; 14309 } 14310 else 14311 { 14312 minLength = n; 14313 } 14314 } 14315 14316 @disable this(); 14317 } 14318 14319 return Result(r, e, n); 14320 } 14321 14322 /// 14323 @safe pure unittest 14324 { 14325 import std.algorithm.comparison : equal; 14326 14327 assert([1, 2, 3, 4].padRight(0, 6).equal([1, 2, 3, 4, 0, 0])); 14328 assert([1, 2, 3, 4].padRight(0, 4).equal([1, 2, 3, 4])); 14329 14330 assert("abc".padRight('_', 6).equal("abc___")); 14331 } 14332 14333 pure @safe unittest 14334 { 14335 import std.algorithm.comparison : equal; 14336 import std.internal.test.dummyrange : AllDummyRanges, ReferenceInputRange; 14337 import std.meta : AliasSeq; 14338 14339 auto string_input_range = new ReferenceInputRange!dchar(['a', 'b', 'c']); 14340 dchar padding = '_'; 14341 assert(string_input_range.padRight(padding, 6).equal("abc___")); 14342 14343 foreach (RangeType; AllDummyRanges) 14344 { 14345 RangeType r1; 14346 assert(r1 14347 .padRight(0, 12) 14348 .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0, 0]) 14349 ); 14350 14351 // test if Result properly uses random access ranges 14352 static if (isRandomAccessRange!RangeType) 14353 { 14354 RangeType r3; 14355 assert(r3.padRight(0, 12)[0] == 1); 14356 assert(r3.padRight(0, 12)[2] == 3); 14357 assert(r3.padRight(0, 12)[9] == 10); 14358 assert(r3.padRight(0, 12)[10] == 0); 14359 assert(r3.padRight(0, 12)[11] == 0); 14360 } 14361 14362 // test if Result properly uses slicing and opDollar 14363 static if (hasSlicing!RangeType) 14364 { 14365 RangeType r4; 14366 assert(r4 14367 .padRight(0, 12)[0 .. 3] 14368 .equal([1, 2, 3]) 14369 ); 14370 assert(r4 14371 .padRight(0, 12)[0 .. 10] 14372 .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U]) 14373 ); 14374 assert(r4 14375 .padRight(0, 12)[0 .. 11] 14376 .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0]) 14377 ); 14378 assert(r4 14379 .padRight(0, 12)[2 .. $] 14380 .equal([3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0, 0]) 14381 ); 14382 assert(r4 14383 .padRight(0, 12)[0 .. $] 14384 .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0, 0]) 14385 ); 14386 } 14387 14388 // drop & dropBack test opslice ranges when available, popFront/popBack otherwise 14389 RangeType r5; 14390 foreach (i; 1 .. 13) assert(r5.padRight(0, 12).drop(i).walkLength == 12 - i); 14391 } 14392 } 14393 14394 // Test nogc inference 14395 @safe @nogc pure unittest 14396 { 14397 import std.algorithm.comparison : equal; 14398 14399 static immutable r1 = [1, 2, 3, 4]; 14400 static immutable r2 = [1, 2, 3, 4, 0, 0]; 14401 assert(r1.padRight(0, 6).equal(r2)); 14402 } 14403 14404 // Test back, popBack, and save 14405 @safe pure unittest 14406 { 14407 import std.algorithm.comparison : equal; 14408 14409 auto r1 = [1, 2, 3, 4].padRight(0, 6); 14410 assert(r1.back == 0); 14411 14412 r1.popBack; 14413 auto r2 = r1.save; 14414 assert(r1.equal([1, 2, 3, 4, 0])); 14415 assert(r2.equal([1, 2, 3, 4, 0])); 14416 14417 r1.popBackN(2); 14418 assert(r1.back == 3); 14419 assert(r1.length == 3); 14420 assert(r2.length == 5); 14421 assert(r2.equal([1, 2, 3, 4, 0])); 14422 14423 r2.popFront; 14424 assert(r2.length == 4); 14425 assert(r2[0] == 2); 14426 assert(r2[1] == 3); 14427 assert(r2[2] == 4); 14428 assert(r2[3] == 0); 14429 assert(r2.equal([2, 3, 4, 0])); 14430 14431 r2.popBack; 14432 assert(r2.equal([2, 3, 4])); 14433 14434 auto r3 = [1, 2, 3, 4].padRight(0, 6); 14435 size_t len = 0; 14436 while (!r3.empty) 14437 { 14438 ++len; 14439 r3.popBack; 14440 } 14441 assert(len == 6); 14442 } 14443 14444 // https://issues.dlang.org/show_bug.cgi?id=19042 14445 @safe pure unittest 14446 { 14447 import std.algorithm.comparison : equal; 14448 14449 assert([2, 5, 13].padRight(42, 10).chunks(5) 14450 .equal!equal([[2, 5, 13, 42, 42], [42, 42, 42, 42, 42]])); 14451 14452 assert([1, 2, 3, 4].padRight(0, 10)[7 .. 9].equal([0, 0])); 14453 } 14454 14455 /** 14456 This simplifies a commonly used idiom in phobos for accepting any kind of string 14457 parameter. The type `R` can for example be a simple string, chained string using 14458 $(REF chain, std,range), $(REF chainPath, std,path) or any other input range of 14459 characters. 14460 14461 Only finite length character ranges are allowed with this constraint. 14462 14463 This template is equivalent to: 14464 --- 14465 isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) 14466 --- 14467 14468 See_Also: 14469 $(REF isInputRange, std,range,primitives), 14470 $(REF isInfinite, std,range,primitives), 14471 $(LREF isSomeChar), 14472 $(REF ElementEncodingType, std,range,primitives) 14473 */ 14474 template isSomeFiniteCharInputRange(R) 14475 { 14476 import std.traits : isSomeChar; 14477 14478 enum isSomeFiniteCharInputRange = isInputRange!R && !isInfinite!R 14479 && isSomeChar!(ElementEncodingType!R); 14480 } 14481 14482 /// 14483 @safe unittest 14484 { 14485 import std.path : chainPath; 14486 import std.range : chain; 14487 14488 void someLibraryMethod(R)(R argument) 14489 if (isSomeFiniteCharInputRange!R) 14490 { 14491 // implementation detail, would iterate over each character of argument 14492 } 14493 14494 someLibraryMethod("simple strings work"); 14495 someLibraryMethod(chain("chained", " ", "strings", " ", "work")); 14496 someLibraryMethod(chainPath("chained", "paths", "work")); 14497 // you can also use custom structs implementing a char range 14498 } 14499