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 $(D $(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 $(D $(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; input) 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 (!input[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 Convenience function which calls 3885 $(REF popFrontN, std, range, primitives)`(range, n)` and returns `range`. 3886 `drop` makes it easier to pop elements from a range 3887 and then pass it to another function within a single expression, 3888 whereas `popFrontN` would require multiple statements. 3889 3890 `dropBack` provides the same functionality but instead calls 3891 $(REF popBackN, std, range, primitives)`(range, n)` 3892 3893 Note: `drop` and `dropBack` will only pop $(I up to) 3894 `n` elements but will stop if the range is empty first. 3895 In other languages this is sometimes called `skip`. 3896 3897 Params: 3898 range = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to drop from 3899 n = the number of elements to drop 3900 3901 Returns: 3902 `range` with up to `n` elements dropped 3903 3904 See_Also: 3905 $(REF popFront, std, range, primitives), $(REF popBackN, std, range, primitives) 3906 +/ 3907 R drop(R)(R range, size_t n) 3908 if (isInputRange!R) 3909 { 3910 range.popFrontN(n); 3911 return range; 3912 } 3913 3914 /// 3915 @safe unittest 3916 { 3917 import std.algorithm.comparison : equal; 3918 3919 assert([0, 2, 1, 5, 0, 3].drop(3) == [5, 0, 3]); 3920 assert("hello world".drop(6) == "world"); 3921 assert("hello world".drop(50).empty); 3922 assert("hello world".take(6).drop(3).equal("lo ")); 3923 } 3924 3925 /// ditto 3926 R dropBack(R)(R range, size_t n) 3927 if (isBidirectionalRange!R) 3928 { 3929 range.popBackN(n); 3930 return range; 3931 } 3932 3933 /// 3934 @safe unittest 3935 { 3936 import std.algorithm.comparison : equal; 3937 3938 assert([0, 2, 1, 5, 0, 3].dropBack(3) == [0, 2, 1]); 3939 assert("hello world".dropBack(6) == "hello"); 3940 assert("hello world".dropBack(50).empty); 3941 assert("hello world".drop(4).dropBack(4).equal("o w")); 3942 } 3943 3944 @safe unittest 3945 { 3946 import std.algorithm.comparison : equal; 3947 import std.container.dlist : DList; 3948 3949 //Remove all but the first two elements 3950 auto a = DList!int(0, 1, 9, 9, 9, 9); 3951 a.remove(a[].drop(2)); 3952 assert(a[].equal(a[].take(2))); 3953 } 3954 3955 @safe unittest 3956 { 3957 import std.algorithm.comparison : equal; 3958 import std.algorithm.iteration : filter; 3959 3960 assert(drop("", 5).empty); 3961 assert(equal(drop(filter!"true"([0, 2, 1, 5, 0, 3]), 3), [5, 0, 3])); 3962 } 3963 3964 @safe unittest 3965 { 3966 import std.algorithm.comparison : equal; 3967 import std.container.dlist : DList; 3968 3969 //insert before the last two elements 3970 auto a = DList!int(0, 1, 2, 5, 6); 3971 a.insertAfter(a[].dropBack(2), [3, 4]); 3972 assert(a[].equal(iota(0, 7))); 3973 } 3974 3975 /++ 3976 Similar to $(LREF drop) and `dropBack` but they call 3977 $(D range.$(LREF popFrontExactly)(n)) and `range.popBackExactly(n)` 3978 instead. 3979 3980 Note: Unlike `drop`, `dropExactly` will assume that the 3981 range holds at least `n` elements. This makes `dropExactly` 3982 faster than `drop`, but it also means that if `range` does 3983 not contain at least `n` elements, it will attempt to call `popFront` 3984 on an empty range, which is undefined behavior. So, only use 3985 `popFrontExactly` when it is guaranteed that `range` holds at least 3986 `n` elements. 3987 3988 Params: 3989 range = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to drop from 3990 n = the number of elements to drop 3991 3992 Returns: 3993 `range` with `n` elements dropped 3994 3995 See_Also: 3996 $(REF popFrontExcatly, std, range, primitives), 3997 $(REF popBackExcatly, std, range, primitives) 3998 +/ 3999 R dropExactly(R)(R range, size_t n) 4000 if (isInputRange!R) 4001 { 4002 popFrontExactly(range, n); 4003 return range; 4004 } 4005 /// ditto 4006 R dropBackExactly(R)(R range, size_t n) 4007 if (isBidirectionalRange!R) 4008 { 4009 popBackExactly(range, n); 4010 return range; 4011 } 4012 4013 /// 4014 @safe unittest 4015 { 4016 import std.algorithm.comparison : equal; 4017 import std.algorithm.iteration : filterBidirectional; 4018 4019 auto a = [1, 2, 3]; 4020 assert(a.dropExactly(2) == [3]); 4021 assert(a.dropBackExactly(2) == [1]); 4022 4023 string s = "日本語"; 4024 assert(s.dropExactly(2) == "語"); 4025 assert(s.dropBackExactly(2) == "日"); 4026 4027 auto bd = filterBidirectional!"true"([1, 2, 3]); 4028 assert(bd.dropExactly(2).equal([3])); 4029 assert(bd.dropBackExactly(2).equal([1])); 4030 } 4031 4032 /++ 4033 Convenience function which calls 4034 `range.popFront()` and returns `range`. `dropOne` 4035 makes it easier to pop an element from a range 4036 and then pass it to another function within a single expression, 4037 whereas `popFront` would require multiple statements. 4038 4039 `dropBackOne` provides the same functionality but instead calls 4040 `range.popBack()`. 4041 +/ 4042 R dropOne(R)(R range) 4043 if (isInputRange!R) 4044 { 4045 range.popFront(); 4046 return range; 4047 } 4048 /// ditto 4049 R dropBackOne(R)(R range) 4050 if (isBidirectionalRange!R) 4051 { 4052 range.popBack(); 4053 return range; 4054 } 4055 4056 /// 4057 pure @safe nothrow unittest 4058 { 4059 import std.algorithm.comparison : equal; 4060 import std.algorithm.iteration : filterBidirectional; 4061 import std.container.dlist : DList; 4062 4063 auto dl = DList!int(9, 1, 2, 3, 9); 4064 assert(dl[].dropOne().dropBackOne().equal([1, 2, 3])); 4065 4066 auto a = [1, 2, 3]; 4067 assert(a.dropOne() == [2, 3]); 4068 assert(a.dropBackOne() == [1, 2]); 4069 4070 string s = "日本語"; 4071 import std.exception : assumeWontThrow; 4072 assert(assumeWontThrow(s.dropOne() == "本語")); 4073 assert(assumeWontThrow(s.dropBackOne() == "日本")); 4074 4075 auto bd = filterBidirectional!"true"([1, 2, 3]); 4076 assert(bd.dropOne().equal([2, 3])); 4077 assert(bd.dropBackOne().equal([1, 2])); 4078 } 4079 4080 /** 4081 Create a range which repeats one value. 4082 4083 Params: 4084 value = the _value to repeat 4085 n = the number of times to repeat `value` 4086 4087 Returns: 4088 If `n` is not defined, an infinite random access range 4089 with slicing. 4090 4091 If `n` is defined, a random access range with slicing. 4092 */ 4093 struct Repeat(T) 4094 { 4095 private: 4096 import std.typecons : Rebindable2; 4097 4098 // Store a rebindable T to make Repeat assignable. 4099 Rebindable2!T _value; 4100 4101 public: 4102 /// Range primitives 4103 @property inout(T) front() inout { return _value.get; } 4104 4105 /// ditto 4106 @property inout(T) back() inout { return _value.get; } 4107 4108 /// ditto 4109 enum bool empty = false; 4110 4111 /// ditto 4112 void popFront() {} 4113 4114 /// ditto 4115 void popBack() {} 4116 4117 /// ditto 4118 @property auto save() inout { return this; } 4119 4120 /// ditto 4121 inout(T) opIndex(size_t) inout { return _value.get; } 4122 4123 /// ditto 4124 auto opSlice(size_t i, size_t j) 4125 in 4126 { 4127 assert( 4128 i <= j, 4129 "Attempting to slice a Repeat with a larger first argument than the second." 4130 ); 4131 } 4132 do 4133 { 4134 return this.takeExactly(j - i); 4135 } 4136 private static struct DollarToken {} 4137 4138 /// ditto 4139 enum opDollar = DollarToken.init; 4140 4141 /// ditto 4142 auto opSlice(size_t, DollarToken) inout { return this; } 4143 } 4144 4145 /// Ditto 4146 Repeat!T repeat(T)(T value) 4147 { 4148 import std.typecons : Rebindable2; 4149 4150 return Repeat!T(Rebindable2!T(value)); 4151 } 4152 4153 /// 4154 pure @safe nothrow unittest 4155 { 4156 import std.algorithm.comparison : equal; 4157 4158 assert(5.repeat().take(4).equal([5, 5, 5, 5])); 4159 } 4160 4161 pure @safe nothrow unittest 4162 { 4163 import std.algorithm.comparison : equal; 4164 4165 auto r = repeat(5); 4166 alias R = typeof(r); 4167 static assert(isBidirectionalRange!R); 4168 static assert(isForwardRange!R); 4169 static assert(isInfinite!R); 4170 static assert(hasSlicing!R); 4171 4172 assert(r.back == 5); 4173 assert(r.front == 5); 4174 assert(r.take(4).equal([ 5, 5, 5, 5 ])); 4175 assert(r[0 .. 4].equal([ 5, 5, 5, 5 ])); 4176 4177 R r2 = r[5 .. $]; 4178 assert(r2.back == 5); 4179 assert(r2.front == 5); 4180 } 4181 4182 /// ditto 4183 Take!(Repeat!T) repeat(T)(T value, size_t n) 4184 { 4185 return take(repeat(value), n); 4186 } 4187 4188 /// 4189 pure @safe nothrow unittest 4190 { 4191 import std.algorithm.comparison : equal; 4192 4193 assert(5.repeat(4).equal([5, 5, 5, 5])); 4194 } 4195 4196 // https://issues.dlang.org/show_bug.cgi?id=12007 4197 pure @safe nothrow unittest 4198 { 4199 static class C{} 4200 Repeat!(immutable int) ri; 4201 ri = ri.save; 4202 Repeat!(immutable C) rc; 4203 rc = rc.save; 4204 4205 import std.algorithm.setops : cartesianProduct; 4206 import std.algorithm.comparison : equal; 4207 import std.typecons : tuple; 4208 immutable int[] A = [1,2,3]; 4209 immutable int[] B = [4,5,6]; 4210 4211 assert(equal(cartesianProduct(A,B), 4212 [ 4213 tuple(1, 4), tuple(1, 5), tuple(1, 6), 4214 tuple(2, 4), tuple(2, 5), tuple(2, 6), 4215 tuple(3, 4), tuple(3, 5), tuple(3, 6), 4216 ])); 4217 } 4218 4219 /** 4220 Given callable ($(REF isCallable, std,traits)) `fun`, create as a range 4221 whose front is defined by successive calls to `fun()`. 4222 This is especially useful to call function with global side effects (random 4223 functions), or to create ranges expressed as a single delegate, rather than 4224 an entire `front`/`popFront`/`empty` structure. 4225 `fun` maybe be passed either a template alias parameter (existing 4226 function, delegate, struct type defining `static opCall`) or 4227 a run-time value argument (delegate, function object). 4228 The result range models an InputRange 4229 ($(REF isInputRange, std,range,primitives)). 4230 The resulting range will call `fun()` on construction, and every call to 4231 `popFront`, and the cached value will be returned when `front` is called. 4232 4233 Returns: an `inputRange` where each element represents another call to fun. 4234 */ 4235 auto generate(Fun)(Fun fun) 4236 if (isCallable!fun) 4237 { 4238 auto gen = Generator!(Fun)(fun); 4239 gen.popFront(); // prime the first element 4240 return gen; 4241 } 4242 4243 /// ditto 4244 auto generate(alias fun)() 4245 if (isCallable!fun) 4246 { 4247 auto gen = Generator!(fun)(); 4248 gen.popFront(); // prime the first element 4249 return gen; 4250 } 4251 4252 /// 4253 @safe pure nothrow unittest 4254 { 4255 import std.algorithm.comparison : equal; 4256 import std.algorithm.iteration : map; 4257 4258 int i = 1; 4259 auto powersOfTwo = generate!(() => i *= 2)().take(10); 4260 assert(equal(powersOfTwo, iota(1, 11).map!"2^^a"())); 4261 } 4262 4263 /// 4264 @safe pure nothrow unittest 4265 { 4266 import std.algorithm.comparison : equal; 4267 4268 //Returns a run-time delegate 4269 auto infiniteIota(T)(T low, T high) 4270 { 4271 T i = high; 4272 return (){if (i == high) i = low; return i++;}; 4273 } 4274 //adapted as a range. 4275 assert(equal(generate(infiniteIota(1, 4)).take(10), [1, 2, 3, 1, 2, 3, 1, 2, 3, 1])); 4276 } 4277 4278 /// 4279 @safe unittest 4280 { 4281 import std.format : format; 4282 import std.random : uniform; 4283 4284 auto r = generate!(() => uniform(0, 6)).take(10); 4285 format("%(%s %)", r); 4286 } 4287 4288 private struct Generator(Fun...) 4289 { 4290 static assert(Fun.length == 1); 4291 static assert(isInputRange!Generator); 4292 import std.traits : FunctionAttribute, functionAttributes, ReturnType; 4293 4294 private: 4295 static if (is(Fun[0])) 4296 Fun[0] fun; 4297 else 4298 alias fun = Fun[0]; 4299 4300 enum returnByRef_ = (functionAttributes!fun & FunctionAttribute.ref_) ? true : false; 4301 4302 import std.traits : hasIndirections; 4303 static if (!hasIndirections!(ReturnType!fun)) 4304 alias RetType = Unqual!(ReturnType!fun); 4305 else 4306 alias RetType = ReturnType!fun; 4307 4308 static if (returnByRef_) 4309 RetType *elem_; 4310 else 4311 RetType elem_; 4312 public: 4313 /// Range primitives 4314 enum empty = false; 4315 4316 static if (returnByRef_) 4317 { 4318 /// ditto 4319 ref front() @property 4320 { 4321 return *elem_; 4322 } 4323 /// ditto 4324 void popFront() 4325 { 4326 elem_ = &fun(); 4327 } 4328 } 4329 else 4330 { 4331 /// ditto 4332 auto front() @property 4333 { 4334 return elem_; 4335 } 4336 /// ditto 4337 void popFront() 4338 { 4339 elem_ = fun(); 4340 } 4341 } 4342 } 4343 4344 @safe nothrow unittest 4345 { 4346 import std.algorithm.comparison : equal; 4347 4348 struct StaticOpCall 4349 { 4350 static ubyte opCall() { return 5 ; } 4351 } 4352 4353 assert(equal(generate!StaticOpCall().take(10), repeat(5).take(10))); 4354 } 4355 4356 @safe pure unittest 4357 { 4358 import std.algorithm.comparison : equal; 4359 4360 struct OpCall 4361 { 4362 ubyte opCall() @safe pure { return 5 ; } 4363 } 4364 4365 OpCall op; 4366 assert(equal(generate(op).take(10), repeat(5).take(10))); 4367 } 4368 4369 // verify ref mechanism works 4370 @system nothrow unittest 4371 { 4372 int[10] arr; 4373 int idx; 4374 4375 ref int fun() { 4376 auto x = idx++; 4377 idx %= arr.length; 4378 return arr[x]; 4379 } 4380 int y = 1; 4381 foreach (ref x; generate!(fun).take(20)) 4382 { 4383 x += y++; 4384 } 4385 import std.algorithm.comparison : equal; 4386 assert(equal(arr[], iota(12, 32, 2))); 4387 } 4388 4389 // assure front isn't the mechanism to make generate go to the next element. 4390 @safe unittest 4391 { 4392 int i; 4393 auto g = generate!(() => ++i); 4394 auto f = g.front; 4395 assert(f == g.front); 4396 g = g.drop(5); // reassign because generate caches 4397 assert(g.front == f + 5); 4398 } 4399 4400 // https://issues.dlang.org/show_bug.cgi?id=23319 4401 @safe pure nothrow unittest 4402 { 4403 auto b = generate!(() => const(int)(42)); 4404 assert(b.front == 42); 4405 } 4406 4407 /** 4408 Repeats the given forward range ad infinitum. If the original range is 4409 infinite (fact that would make `Cycle` the identity application), 4410 `Cycle` detects that and aliases itself to the range type 4411 itself. That works for non-forward ranges too. 4412 If the original range has random access, `Cycle` offers 4413 random access and also offers a constructor taking an initial position 4414 `index`. `Cycle` works with static arrays in addition to ranges, 4415 mostly for performance reasons. 4416 4417 Note: The input range must not be empty. 4418 4419 Tip: This is a great way to implement simple circular buffers. 4420 */ 4421 struct Cycle(R) 4422 if (isForwardRange!R && !isInfinite!R) 4423 { 4424 static if (isRandomAccessRange!R && hasLength!R) 4425 { 4426 private R _original; 4427 private size_t _index; 4428 4429 /// Range primitives 4430 this(R input, size_t index = 0) 4431 { 4432 _original = input; 4433 _index = index % _original.length; 4434 } 4435 4436 /// ditto 4437 @property auto ref front() 4438 { 4439 return _original[_index]; 4440 } 4441 4442 static if (is(typeof((cast(const R)_original)[_index]))) 4443 { 4444 /// ditto 4445 @property auto ref front() const 4446 { 4447 return _original[_index]; 4448 } 4449 } 4450 4451 static if (hasAssignableElements!R) 4452 { 4453 /// ditto 4454 @property void front(ElementType!R val) 4455 { 4456 import core.lifetime : forward; 4457 4458 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542 4459 _original[_index] = __ctfe ? val : forward!val; 4460 } 4461 } 4462 4463 /// ditto 4464 enum bool empty = false; 4465 4466 /// ditto 4467 void popFront() 4468 { 4469 ++_index; 4470 if (_index >= _original.length) 4471 _index = 0; 4472 } 4473 4474 /// ditto 4475 auto ref opIndex(size_t n) 4476 { 4477 return _original[(n + _index) % _original.length]; 4478 } 4479 4480 static if (is(typeof((cast(const R)_original)[_index])) && 4481 is(typeof((cast(const R)_original).length))) 4482 { 4483 /// ditto 4484 auto ref opIndex(size_t n) const 4485 { 4486 return _original[(n + _index) % _original.length]; 4487 } 4488 } 4489 4490 static if (hasAssignableElements!R) 4491 { 4492 /// ditto 4493 void opIndexAssign(ElementType!R val, size_t n) 4494 { 4495 _original[(n + _index) % _original.length] = val; 4496 } 4497 } 4498 4499 /// ditto 4500 @property Cycle save() 4501 { 4502 //No need to call _original.save, because Cycle never actually modifies _original 4503 return Cycle(_original, _index); 4504 } 4505 4506 private static struct DollarToken {} 4507 4508 /// ditto 4509 enum opDollar = DollarToken.init; 4510 4511 static if (hasSlicing!R) 4512 { 4513 /// ditto 4514 auto opSlice(size_t i, size_t j) 4515 in 4516 { 4517 assert(i <= j); 4518 } 4519 do 4520 { 4521 return this[i .. $].takeExactly(j - i); 4522 } 4523 4524 /// ditto 4525 auto opSlice(size_t i, DollarToken) 4526 { 4527 return typeof(this)(_original, _index + i); 4528 } 4529 } 4530 } 4531 else 4532 { 4533 private R _original; 4534 private R _current; 4535 4536 /// ditto 4537 this(R input) 4538 { 4539 _original = input; 4540 _current = input.save; 4541 } 4542 4543 private this(R original, R current) 4544 { 4545 _original = original; 4546 _current = current; 4547 } 4548 4549 /// ditto 4550 @property auto ref front() 4551 { 4552 return _current.front; 4553 } 4554 4555 static if (is(typeof((cast(const R)_current).front))) 4556 { 4557 /// ditto 4558 @property auto ref front() const 4559 { 4560 return _current.front; 4561 } 4562 } 4563 4564 static if (hasAssignableElements!R) 4565 { 4566 /// ditto 4567 @property auto front(ElementType!R val) 4568 { 4569 import core.lifetime : forward; 4570 4571 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542 4572 return _current.front = __ctfe ? val : forward!val; 4573 } 4574 } 4575 4576 /// ditto 4577 enum bool empty = false; 4578 4579 /// ditto 4580 void popFront() 4581 { 4582 _current.popFront(); 4583 if (_current.empty) 4584 _current = _original.save; 4585 } 4586 4587 /// ditto 4588 @property Cycle save() 4589 { 4590 //No need to call _original.save, because Cycle never actually modifies _original 4591 return Cycle(_original, _current.save); 4592 } 4593 } 4594 } 4595 4596 /// ditto 4597 template Cycle(R) 4598 if (isInfinite!R) 4599 { 4600 alias Cycle = R; 4601 } 4602 4603 /// ditto 4604 struct Cycle(R) 4605 if (isStaticArray!R) 4606 { 4607 private alias ElementType = typeof(R.init[0]); 4608 private ElementType* _ptr; 4609 private size_t _index; 4610 4611 nothrow: 4612 4613 /// Range primitives 4614 this(ref R input, size_t index = 0) @system 4615 { 4616 _ptr = input.ptr; 4617 _index = index % R.length; 4618 } 4619 4620 /// ditto 4621 @property ref inout(ElementType) front() inout @safe 4622 { 4623 static ref auto trustedPtrIdx(typeof(_ptr) p, size_t idx) @trusted 4624 { 4625 return p[idx]; 4626 } 4627 return trustedPtrIdx(_ptr, _index); 4628 } 4629 4630 /// ditto 4631 enum bool empty = false; 4632 4633 /// ditto 4634 void popFront() @safe 4635 { 4636 ++_index; 4637 if (_index >= R.length) 4638 _index = 0; 4639 } 4640 4641 /// ditto 4642 ref inout(ElementType) opIndex(size_t n) inout @safe 4643 { 4644 static ref auto trustedPtrIdx(typeof(_ptr) p, size_t idx) @trusted 4645 { 4646 return p[idx % R.length]; 4647 } 4648 return trustedPtrIdx(_ptr, n + _index); 4649 } 4650 4651 /// ditto 4652 @property inout(Cycle) save() inout @safe 4653 { 4654 return this; 4655 } 4656 4657 private static struct DollarToken {} 4658 /// ditto 4659 enum opDollar = DollarToken.init; 4660 4661 /// ditto 4662 auto opSlice(size_t i, size_t j) @safe 4663 in 4664 { 4665 assert( 4666 i <= j, 4667 "Attempting to slice a Repeat with a larger first argument than the second." 4668 ); 4669 } 4670 do 4671 { 4672 return this[i .. $].takeExactly(j - i); 4673 } 4674 4675 /// ditto 4676 inout(typeof(this)) opSlice(size_t i, DollarToken) inout @safe 4677 { 4678 static auto trustedCtor(typeof(_ptr) p, size_t idx) @trusted 4679 { 4680 return cast(inout) Cycle(*cast(R*)(p), idx); 4681 } 4682 return trustedCtor(_ptr, _index + i); 4683 } 4684 } 4685 4686 /// Ditto 4687 auto cycle(R)(R input) 4688 if (isInputRange!R) 4689 { 4690 static assert(isForwardRange!R || isInfinite!R, 4691 "Cycle requires a forward range argument unless it's statically known" 4692 ~ " to be infinite"); 4693 assert(!input.empty, "Attempting to pass an empty input to cycle"); 4694 static if (isInfinite!R) return input; 4695 else return Cycle!R(input); 4696 } 4697 4698 /// 4699 @safe unittest 4700 { 4701 import std.algorithm.comparison : equal; 4702 import std.range : cycle, take; 4703 4704 // Here we create an infinitive cyclic sequence from [1, 2] 4705 // (i.e. get here [1, 2, 1, 2, 1, 2 and so on]) then 4706 // take 5 elements of this sequence (so we have [1, 2, 1, 2, 1]) 4707 // and compare them with the expected values for equality. 4708 assert(cycle([1, 2]).take(5).equal([ 1, 2, 1, 2, 1 ])); 4709 } 4710 4711 /// Ditto 4712 Cycle!R cycle(R)(R input, size_t index = 0) 4713 if (isRandomAccessRange!R && !isInfinite!R) 4714 { 4715 assert(!input.empty, "Attempting to pass an empty input to cycle"); 4716 return Cycle!R(input, index); 4717 } 4718 4719 /// Ditto 4720 Cycle!R cycle(R)(ref R input, size_t index = 0) @system 4721 if (isStaticArray!R) 4722 { 4723 return Cycle!R(input, index); 4724 } 4725 4726 @safe nothrow unittest 4727 { 4728 import std.algorithm.comparison : equal; 4729 import std.internal.test.dummyrange : AllDummyRanges; 4730 4731 static assert(isForwardRange!(Cycle!(uint[]))); 4732 4733 // Make sure ref is getting propagated properly. 4734 int[] nums = [1,2,3]; 4735 auto c2 = cycle(nums); 4736 c2[3]++; 4737 assert(nums[0] == 2); 4738 4739 immutable int[] immarr = [1, 2, 3]; 4740 4741 foreach (DummyType; AllDummyRanges) 4742 { 4743 static if (isForwardRange!DummyType) 4744 { 4745 DummyType dummy; 4746 auto cy = cycle(dummy); 4747 static assert(isForwardRange!(typeof(cy))); 4748 auto t = take(cy, 20); 4749 assert(equal(t, [1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10])); 4750 4751 const cRange = cy; 4752 assert(cRange.front == 1); 4753 4754 static if (hasAssignableElements!DummyType) 4755 { 4756 { 4757 cy.front = 66; 4758 scope(exit) cy.front = 1; 4759 assert(dummy.front == 66); 4760 } 4761 4762 static if (isRandomAccessRange!DummyType) 4763 { 4764 { 4765 cy[10] = 66; 4766 scope(exit) cy[10] = 1; 4767 assert(dummy.front == 66); 4768 } 4769 4770 assert(cRange[10] == 1); 4771 } 4772 } 4773 4774 static if (hasSlicing!DummyType) 4775 { 4776 auto slice = cy[5 .. 15]; 4777 assert(equal(slice, [6, 7, 8, 9, 10, 1, 2, 3, 4, 5])); 4778 static assert(is(typeof(slice) == typeof(takeExactly(cy, 5)))); 4779 4780 auto infSlice = cy[7 .. $]; 4781 assert(equal(take(infSlice, 5), [8, 9, 10, 1, 2])); 4782 static assert(isInfinite!(typeof(infSlice))); 4783 } 4784 } 4785 } 4786 } 4787 4788 @system nothrow unittest // For static arrays. 4789 { 4790 import std.algorithm.comparison : equal; 4791 4792 int[3] a = [ 1, 2, 3 ]; 4793 static assert(isStaticArray!(typeof(a))); 4794 auto c = cycle(a); 4795 assert(a.ptr == c._ptr); 4796 assert(equal(take(cycle(a), 5), [ 1, 2, 3, 1, 2 ][])); 4797 static assert(isForwardRange!(typeof(c))); 4798 4799 // Test qualifiers on slicing. 4800 alias C = typeof(c); 4801 static assert(is(typeof(c[1 .. $]) == C)); 4802 const cConst = c; 4803 static assert(is(typeof(cConst[1 .. $]) == const(C))); 4804 } 4805 4806 @safe nothrow unittest // For infinite ranges 4807 { 4808 struct InfRange 4809 { 4810 void popFront() { } 4811 @property int front() { return 0; } 4812 enum empty = false; 4813 auto save() { return this; } 4814 } 4815 struct NonForwardInfRange 4816 { 4817 void popFront() { } 4818 @property int front() { return 0; } 4819 enum empty = false; 4820 } 4821 4822 InfRange i; 4823 NonForwardInfRange j; 4824 auto c = cycle(i); 4825 assert(c == i); 4826 //make sure it can alias out even non-forward infinite ranges 4827 static assert(is(typeof(j.cycle) == typeof(j))); 4828 } 4829 4830 @safe unittest 4831 { 4832 import std.algorithm.comparison : equal; 4833 4834 int[5] arr = [0, 1, 2, 3, 4]; 4835 auto cleD = cycle(arr[]); //Dynamic 4836 assert(equal(cleD[5 .. 10], arr[])); 4837 4838 //n is a multiple of 5 worth about 3/4 of size_t.max 4839 auto n = size_t.max/4 + size_t.max/2; 4840 n -= n % 5; 4841 4842 //Test index overflow 4843 foreach (_ ; 0 .. 10) 4844 { 4845 cleD = cleD[n .. $]; 4846 assert(equal(cleD[5 .. 10], arr[])); 4847 } 4848 } 4849 4850 @system @nogc nothrow unittest 4851 { 4852 import std.algorithm.comparison : equal; 4853 4854 int[5] arr = [0, 1, 2, 3, 4]; 4855 auto cleS = cycle(arr); //Static 4856 assert(equal(cleS[5 .. 10], arr[])); 4857 4858 //n is a multiple of 5 worth about 3/4 of size_t.max 4859 auto n = size_t.max/4 + size_t.max/2; 4860 n -= n % 5; 4861 4862 //Test index overflow 4863 foreach (_ ; 0 .. 10) 4864 { 4865 cleS = cleS[n .. $]; 4866 assert(equal(cleS[5 .. 10], arr[])); 4867 } 4868 } 4869 4870 @system unittest 4871 { 4872 import std.algorithm.comparison : equal; 4873 4874 int[1] arr = [0]; 4875 auto cleS = cycle(arr); 4876 cleS = cleS[10 .. $]; 4877 assert(equal(cleS[5 .. 10], 0.repeat(5))); 4878 assert(cleS.front == 0); 4879 } 4880 4881 // https://issues.dlang.org/show_bug.cgi?id=10845 4882 @system unittest 4883 { 4884 import std.algorithm.comparison : equal; 4885 import std.algorithm.iteration : filter; 4886 4887 auto a = inputRangeObject(iota(3).filter!"true"); 4888 assert(equal(cycle(a).take(10), [0, 1, 2, 0, 1, 2, 0, 1, 2, 0])); 4889 } 4890 4891 // https://issues.dlang.org/show_bug.cgi?id=12177 4892 @safe unittest 4893 { 4894 static assert(__traits(compiles, recurrence!q{a[n - 1] ~ a[n - 2]}("1", "0"))); 4895 } 4896 4897 // https://issues.dlang.org/show_bug.cgi?id=13390 4898 @system unittest 4899 { 4900 import core.exception : AssertError; 4901 import std.exception : assertThrown; 4902 assertThrown!AssertError(cycle([0, 1, 2][0 .. 0])); 4903 } 4904 4905 // https://issues.dlang.org/show_bug.cgi?id=18657 4906 pure @safe unittest 4907 { 4908 import std.algorithm.comparison : equal; 4909 string s = "foo"; 4910 auto r = refRange(&s).cycle.take(4); 4911 assert(equal(r.save, "foof")); 4912 assert(equal(r.save, "foof")); 4913 } 4914 4915 // https://issues.dlang.org/show_bug.cgi?id=24481 4916 @safe unittest 4917 { 4918 import std.algorithm.iteration : filter; 4919 4920 bool called; 4921 struct Handle 4922 { 4923 int entry; 4924 void opAssign()(auto ref const(typeof(this)) that) const { called = true; } 4925 } 4926 4927 const(Handle)[3] arr = [Handle(0), Handle(1), Handle(2)]; 4928 { 4929 auto range = arr[].cycle().take(5); 4930 4931 called = false; 4932 range.front = Handle(42); 4933 assert(called); 4934 } 4935 { 4936 auto range = arr[].filter!(a => true)().cycle().take(5); 4937 4938 called = false; 4939 range.front = Handle(42); 4940 assert(called); 4941 } 4942 } 4943 4944 private alias lengthType(R) = typeof(R.init.length.init); 4945 4946 /** 4947 Iterate several ranges in lockstep. The element type is a proxy tuple 4948 that allows accessing the current element in the `n`th range by 4949 using `e[n]`. 4950 4951 `zip` is similar to $(LREF lockstep), but `lockstep` doesn't 4952 bundle its elements and uses the `opApply` protocol. 4953 `lockstep` allows reference access to the elements in 4954 `foreach` iterations. 4955 4956 Params: 4957 sp = controls what `zip` will do if the ranges are different lengths 4958 ranges = the ranges to zip together 4959 Returns: 4960 At minimum, an input range. `Zip` offers the lowest range facilities 4961 of all components, e.g. it offers random access iff all ranges offer 4962 random access, and also offers mutation and swapping if all ranges offer 4963 it. Due to this, `Zip` is extremely powerful because it allows manipulating 4964 several ranges in lockstep. 4965 Throws: 4966 An `Exception` if all of the ranges are not the same length and 4967 `sp` is set to `StoppingPolicy.requireSameLength`. 4968 4969 Limitations: The `@nogc` and `nothrow` attributes cannot be inferred for 4970 the `Zip` struct because $(LREF StoppingPolicy) can vary at runtime. This 4971 limitation is not shared by the anonymous range returned by the `zip` 4972 function when not given an explicit `StoppingPolicy` as an argument. 4973 */ 4974 struct Zip(Ranges...) 4975 if (Ranges.length && allSatisfy!(isInputRange, Ranges)) 4976 { 4977 import std.format : format; //for generic mixins 4978 import std.typecons : Tuple; 4979 4980 alias R = Ranges; 4981 private R ranges; 4982 alias ElementType = Tuple!(staticMap!(.ElementType, R)); 4983 private StoppingPolicy stoppingPolicy = StoppingPolicy.shortest; 4984 4985 /** 4986 Builds an object. Usually this is invoked indirectly by using the 4987 $(LREF zip) function. 4988 */ 4989 this(R rs, StoppingPolicy s = StoppingPolicy.shortest) 4990 { 4991 ranges[] = rs[]; 4992 stoppingPolicy = s; 4993 } 4994 4995 /** 4996 Returns `true` if the range is at end. The test depends on the 4997 stopping policy. 4998 */ 4999 static if (allSatisfy!(isInfinite, R)) 5000 { 5001 // BUG: Doesn't propagate infiniteness if only some ranges are infinite 5002 // and s == StoppingPolicy.longest. This isn't fixable in the 5003 // current design since StoppingPolicy is known only at runtime. 5004 enum bool empty = false; 5005 } 5006 else 5007 { 5008 /// 5009 @property bool empty() 5010 { 5011 import std.exception : enforce; 5012 import std.meta : anySatisfy; 5013 5014 final switch (stoppingPolicy) 5015 { 5016 case StoppingPolicy.shortest: 5017 foreach (i, Unused; R) 5018 { 5019 if (ranges[i].empty) return true; 5020 } 5021 return false; 5022 case StoppingPolicy.longest: 5023 static if (anySatisfy!(isInfinite, R)) 5024 { 5025 return false; 5026 } 5027 else 5028 { 5029 foreach (i, Unused; R) 5030 { 5031 if (!ranges[i].empty) return false; 5032 } 5033 return true; 5034 } 5035 case StoppingPolicy.requireSameLength: 5036 foreach (i, Unused; R[1 .. $]) 5037 { 5038 enforce(ranges[0].empty == 5039 ranges[i + 1].empty, 5040 "Inequal-length ranges passed to Zip"); 5041 } 5042 return ranges[0].empty; 5043 } 5044 assert(false); 5045 } 5046 } 5047 5048 static if (allSatisfy!(isForwardRange, R)) 5049 { 5050 /// 5051 @property Zip save() 5052 { 5053 //Zip(ranges[0].save, ranges[1].save, ..., stoppingPolicy) 5054 return mixin (q{Zip(%(ranges[%s].save%|, %), stoppingPolicy)}.format(iota(0, R.length))); 5055 } 5056 } 5057 5058 private .ElementType!(R[i]) tryGetInit(size_t i)() 5059 { 5060 alias E = .ElementType!(R[i]); 5061 static if (!is(typeof({static E i;}))) 5062 throw new Exception("Range with non-default constructable elements exhausted."); 5063 else 5064 return E.init; 5065 } 5066 5067 /** 5068 Returns the current iterated element. 5069 */ 5070 @property ElementType front() 5071 { 5072 @property tryGetFront(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].front;} 5073 //ElementType(tryGetFront!0, tryGetFront!1, ...) 5074 return mixin(q{ElementType(%(tryGetFront!%s, %))}.format(iota(0, R.length))); 5075 } 5076 5077 /** 5078 Sets the front of all iterated ranges. 5079 */ 5080 static if (allSatisfy!(hasAssignableElements, R)) 5081 { 5082 @property void front(ElementType v) 5083 { 5084 foreach (i, Unused; R) 5085 { 5086 if (!ranges[i].empty) 5087 { 5088 ranges[i].front = v[i]; 5089 } 5090 } 5091 } 5092 } 5093 5094 /** 5095 Moves out the front. 5096 */ 5097 static if (allSatisfy!(hasMobileElements, R)) 5098 { 5099 ElementType moveFront() 5100 { 5101 @property tryMoveFront(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].moveFront();} 5102 //ElementType(tryMoveFront!0, tryMoveFront!1, ...) 5103 return mixin(q{ElementType(%(tryMoveFront!%s, %))}.format(iota(0, R.length))); 5104 } 5105 } 5106 5107 /** 5108 Returns the rightmost element. 5109 */ 5110 static if (allSatisfy!(isBidirectionalRange, R)) 5111 { 5112 @property ElementType back() 5113 { 5114 //TODO: Fixme! BackElement != back of all ranges in case of jagged-ness 5115 5116 @property tryGetBack(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].back;} 5117 //ElementType(tryGetBack!0, tryGetBack!1, ...) 5118 return mixin(q{ElementType(%(tryGetBack!%s, %))}.format(iota(0, R.length))); 5119 } 5120 5121 /** 5122 Moves out the back. 5123 */ 5124 static if (allSatisfy!(hasMobileElements, R)) 5125 { 5126 ElementType moveBack() 5127 { 5128 //TODO: Fixme! BackElement != back of all ranges in case of jagged-ness 5129 5130 @property tryMoveBack(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].moveBack();} 5131 //ElementType(tryMoveBack!0, tryMoveBack!1, ...) 5132 return mixin(q{ElementType(%(tryMoveBack!%s, %))}.format(iota(0, R.length))); 5133 } 5134 } 5135 5136 /** 5137 Returns the current iterated element. 5138 */ 5139 static if (allSatisfy!(hasAssignableElements, R)) 5140 { 5141 @property void back(ElementType v) 5142 { 5143 //TODO: Fixme! BackElement != back of all ranges in case of jagged-ness. 5144 //Not sure the call is even legal for StoppingPolicy.longest 5145 5146 foreach (i, Unused; R) 5147 { 5148 if (!ranges[i].empty) 5149 { 5150 ranges[i].back = v[i]; 5151 } 5152 } 5153 } 5154 } 5155 } 5156 5157 /** 5158 Advances to the next element in all controlled ranges. 5159 */ 5160 void popFront() 5161 { 5162 import std.exception : enforce; 5163 5164 final switch (stoppingPolicy) 5165 { 5166 case StoppingPolicy.shortest: 5167 foreach (i, Unused; R) 5168 { 5169 assert(!ranges[i].empty); 5170 ranges[i].popFront(); 5171 } 5172 break; 5173 case StoppingPolicy.longest: 5174 foreach (i, Unused; R) 5175 { 5176 if (!ranges[i].empty) ranges[i].popFront(); 5177 } 5178 break; 5179 case StoppingPolicy.requireSameLength: 5180 foreach (i, Unused; R) 5181 { 5182 enforce(!ranges[i].empty, "Invalid Zip object"); 5183 ranges[i].popFront(); 5184 } 5185 break; 5186 } 5187 } 5188 5189 /** 5190 Calls `popBack` for all controlled ranges. 5191 */ 5192 static if (allSatisfy!(isBidirectionalRange, R)) 5193 { 5194 void popBack() 5195 { 5196 //TODO: Fixme! In case of jaggedness, this is wrong. 5197 import std.exception : enforce; 5198 5199 final switch (stoppingPolicy) 5200 { 5201 case StoppingPolicy.shortest: 5202 foreach (i, Unused; R) 5203 { 5204 assert(!ranges[i].empty); 5205 ranges[i].popBack(); 5206 } 5207 break; 5208 case StoppingPolicy.longest: 5209 foreach (i, Unused; R) 5210 { 5211 if (!ranges[i].empty) ranges[i].popBack(); 5212 } 5213 break; 5214 case StoppingPolicy.requireSameLength: 5215 foreach (i, Unused; R) 5216 { 5217 enforce(!ranges[i].empty, "Invalid Zip object"); 5218 ranges[i].popBack(); 5219 } 5220 break; 5221 } 5222 } 5223 } 5224 5225 /** 5226 Returns the length of this range. Defined only if all ranges define 5227 `length`. 5228 */ 5229 static if (allSatisfy!(hasLength, R)) 5230 { 5231 @property auto length() 5232 { 5233 static if (Ranges.length == 1) 5234 return ranges[0].length; 5235 else 5236 { 5237 if (stoppingPolicy == StoppingPolicy.requireSameLength) 5238 return ranges[0].length; 5239 5240 //[min|max](ranges[0].length, ranges[1].length, ...) 5241 import std.algorithm.comparison : min, max; 5242 if (stoppingPolicy == StoppingPolicy.shortest) 5243 return mixin(q{min(%(ranges[%s].length%|, %))}.format(iota(0, R.length))); 5244 else 5245 return mixin(q{max(%(ranges[%s].length%|, %))}.format(iota(0, R.length))); 5246 } 5247 } 5248 5249 alias opDollar = length; 5250 } 5251 5252 /** 5253 Returns a slice of the range. Defined only if all range define 5254 slicing. 5255 */ 5256 static if (allSatisfy!(hasSlicing, R)) 5257 { 5258 auto opSlice(size_t from, size_t to) 5259 { 5260 //Slicing an infinite range yields the type Take!R 5261 //For finite ranges, the type Take!R aliases to R 5262 alias ZipResult = Zip!(staticMap!(Take, R)); 5263 5264 //ZipResult(ranges[0][from .. to], ranges[1][from .. to], ..., stoppingPolicy) 5265 return mixin (q{ZipResult(%(ranges[%s][from .. to]%|, %), stoppingPolicy)}.format(iota(0, R.length))); 5266 } 5267 } 5268 5269 /** 5270 Returns the `n`th element in the composite range. Defined if all 5271 ranges offer random access. 5272 */ 5273 static if (allSatisfy!(isRandomAccessRange, R)) 5274 { 5275 ElementType opIndex(size_t n) 5276 { 5277 //TODO: Fixme! This may create an out of bounds access 5278 //for StoppingPolicy.longest 5279 5280 //ElementType(ranges[0][n], ranges[1][n], ...) 5281 return mixin (q{ElementType(%(ranges[%s][n]%|, %))}.format(iota(0, R.length))); 5282 } 5283 5284 /** 5285 Assigns to the `n`th element in the composite range. Defined if 5286 all ranges offer random access. 5287 */ 5288 static if (allSatisfy!(hasAssignableElements, R)) 5289 { 5290 void opIndexAssign(ElementType v, size_t n) 5291 { 5292 //TODO: Fixme! Not sure the call is even legal for StoppingPolicy.longest 5293 foreach (i, Range; R) 5294 { 5295 ranges[i][n] = v[i]; 5296 } 5297 } 5298 } 5299 5300 /** 5301 Destructively reads the `n`th element in the composite 5302 range. Defined if all ranges offer random access. 5303 */ 5304 static if (allSatisfy!(hasMobileElements, R)) 5305 { 5306 ElementType moveAt(size_t n) 5307 { 5308 //TODO: Fixme! This may create an out of bounds access 5309 //for StoppingPolicy.longest 5310 5311 //ElementType(ranges[0].moveAt(n), ranges[1].moveAt(n), ..., ) 5312 return mixin (q{ElementType(%(ranges[%s].moveAt(n)%|, %))}.format(iota(0, R.length))); 5313 } 5314 } 5315 } 5316 } 5317 5318 /// Ditto 5319 auto zip(Ranges...)(Ranges ranges) 5320 if (Ranges.length && allSatisfy!(isInputRange, Ranges)) 5321 { 5322 import std.meta : anySatisfy, templateOr; 5323 static if (allSatisfy!(isInfinite, Ranges) || Ranges.length == 1) 5324 { 5325 return ZipShortest!(Ranges)(ranges); 5326 } 5327 else static if (allSatisfy!(isBidirectionalRange, Ranges)) 5328 { 5329 static if (allSatisfy!(templateOr!(isInfinite, hasLength), Ranges) 5330 && allSatisfy!(templateOr!(isInfinite, hasSlicing), Ranges) 5331 && allSatisfy!(isBidirectionalRange, staticMap!(Take, Ranges))) 5332 { 5333 // If all the ranges are bidirectional, if possible slice them to 5334 // the same length to simplify the implementation. 5335 static assert(anySatisfy!(hasLength, Ranges)); 5336 static foreach (i, Range; Ranges) 5337 static if (hasLength!Range) 5338 { 5339 static if (!is(typeof(minLen) == size_t)) 5340 size_t minLen = ranges[i].length; 5341 else 5342 {{ 5343 const x = ranges[i].length; 5344 if (x < minLen) minLen = x; 5345 }} 5346 } 5347 import std.format : format; 5348 static if (!anySatisfy!(isInfinite, Ranges)) 5349 return mixin(`ZipShortest!(Yes.allKnownSameLength, staticMap!(Take, Ranges))`~ 5350 `(%(ranges[%s][0 .. minLen]%|, %))`.format(iota(0, Ranges.length))); 5351 else 5352 return mixin(`ZipShortest!(Yes.allKnownSameLength, staticMap!(Take, Ranges))`~ 5353 `(%(take(ranges[%s], minLen)%|, %))`.format(iota(0, Ranges.length))); 5354 } 5355 else static if (allSatisfy!(isRandomAccessRange, Ranges)) 5356 { 5357 // We can't slice but we can still use random access to ensure 5358 // "back" is retrieving the same index for each range. 5359 return ZipShortest!(Ranges)(ranges); 5360 } 5361 else 5362 { 5363 // If bidirectional range operations would not be supported by 5364 // ZipShortest that might have actually been a bug since Zip 5365 // supported `back` without verifying that each range had the 5366 // same length, but for the sake of backwards compatibility 5367 // use the old Zip to continue supporting them. 5368 return Zip!Ranges(ranges); 5369 } 5370 } 5371 else 5372 { 5373 return ZipShortest!(Ranges)(ranges); 5374 } 5375 } 5376 5377 /// 5378 @nogc nothrow pure @safe unittest 5379 { 5380 import std.algorithm.comparison : equal; 5381 import std.algorithm.iteration : map; 5382 5383 // pairwise sum 5384 auto arr = only(0, 1, 2); 5385 auto part1 = zip(arr, arr.dropOne).map!"a[0] + a[1]"; 5386 assert(part1.equal(only(1, 3))); 5387 } 5388 5389 /// 5390 nothrow pure @safe unittest 5391 { 5392 import std.conv : to; 5393 5394 int[] a = [ 1, 2, 3 ]; 5395 string[] b = [ "a", "b", "c" ]; 5396 string[] result; 5397 5398 foreach (tup; zip(a, b)) 5399 { 5400 result ~= tup[0].to!string ~ tup[1]; 5401 } 5402 5403 assert(result == [ "1a", "2b", "3c" ]); 5404 5405 size_t idx = 0; 5406 // unpacking tuple elements with foreach 5407 foreach (e1, e2; zip(a, b)) 5408 { 5409 assert(e1 == a[idx]); 5410 assert(e2 == b[idx]); 5411 ++idx; 5412 } 5413 } 5414 5415 /// `zip` is powerful - the following code sorts two arrays in parallel: 5416 nothrow pure @safe unittest 5417 { 5418 import std.algorithm.sorting : sort; 5419 5420 int[] a = [ 1, 2, 3 ]; 5421 string[] b = [ "a", "c", "b" ]; 5422 zip(a, b).sort!((t1, t2) => t1[0] > t2[0]); 5423 5424 assert(a == [ 3, 2, 1 ]); 5425 // b is sorted according to a's sorting 5426 assert(b == [ "b", "c", "a" ]); 5427 } 5428 5429 /// Ditto 5430 auto zip(Ranges...)(StoppingPolicy sp, Ranges ranges) 5431 if (Ranges.length && allSatisfy!(isInputRange, Ranges)) 5432 { 5433 return Zip!Ranges(ranges, sp); 5434 } 5435 5436 /** 5437 Dictates how iteration in a $(LREF zip) and $(LREF lockstep) should stop. 5438 By default stop at the end of the shortest of all ranges. 5439 */ 5440 enum StoppingPolicy 5441 { 5442 /// Stop when the shortest range is exhausted 5443 shortest, 5444 /// Stop when the longest range is exhausted 5445 longest, 5446 /// Require that all ranges are equal 5447 requireSameLength, 5448 } 5449 5450 /// 5451 pure @safe unittest 5452 { 5453 import std.algorithm.comparison : equal; 5454 import std.exception : assertThrown; 5455 import std.range.primitives; 5456 import std.typecons : tuple; 5457 5458 auto a = [1, 2, 3]; 5459 auto b = [4, 5, 6, 7]; 5460 5461 auto shortest = zip(StoppingPolicy.shortest, a, b); 5462 assert(shortest.equal([ 5463 tuple(1, 4), 5464 tuple(2, 5), 5465 tuple(3, 6) 5466 ])); 5467 5468 auto longest = zip(StoppingPolicy.longest, a, b); 5469 assert(longest.equal([ 5470 tuple(1, 4), 5471 tuple(2, 5), 5472 tuple(3, 6), 5473 tuple(0, 7) 5474 ])); 5475 5476 auto same = zip(StoppingPolicy.requireSameLength, a, b); 5477 same.popFrontN(3); 5478 assertThrown!Exception(same.popFront); 5479 } 5480 5481 /+ 5482 Non-public. Like $(LREF Zip) with `StoppingPolicy.shortest` 5483 except it properly implements `back` and `popBack` in the 5484 case of uneven ranges or disables those operations when 5485 it is not possible to guarantee they are correct. 5486 +/ 5487 package template ZipShortest(Ranges...) 5488 if (Ranges.length && __traits(compiles, 5489 { 5490 static assert(allSatisfy!(isInputRange, Ranges)); 5491 })) 5492 { 5493 alias ZipShortest = .ZipShortest!( 5494 Ranges.length == 1 || allSatisfy!(isInfinite, Ranges) 5495 ? Yes.allKnownSameLength 5496 : No.allKnownSameLength, 5497 Ranges); 5498 } 5499 /+ non-public, ditto +/ 5500 package struct ZipShortest(Flag!"allKnownSameLength" allKnownSameLength, Ranges...) 5501 if (Ranges.length && allSatisfy!(isInputRange, Ranges)) 5502 { 5503 import std.format : format; //for generic mixins 5504 import std.meta : anySatisfy, templateOr; 5505 import std.typecons : Tuple; 5506 5507 deprecated("Use of an undocumented alias R.") 5508 alias R = Ranges; // Unused here but defined in case library users rely on it. 5509 private Ranges ranges; 5510 alias ElementType = Tuple!(staticMap!(.ElementType, Ranges)); 5511 5512 /+ 5513 Builds an object. Usually this is invoked indirectly by using the 5514 $(LREF zip) function. 5515 +/ 5516 this(Ranges rs) 5517 { 5518 ranges[] = rs[]; 5519 } 5520 5521 /+ 5522 Returns `true` if the range is at end. 5523 +/ 5524 static if (allKnownSameLength ? anySatisfy!(isInfinite, Ranges) 5525 : allSatisfy!(isInfinite, Ranges)) 5526 { 5527 enum bool empty = false; 5528 } 5529 else 5530 { 5531 @property bool empty() 5532 { 5533 static if (allKnownSameLength) 5534 { 5535 return ranges[0].empty; 5536 } 5537 else 5538 { 5539 static foreach (i; 0 .. Ranges.length) 5540 { 5541 if (ranges[i].empty) 5542 return true; 5543 } 5544 return false; 5545 } 5546 } 5547 } 5548 5549 /+ 5550 Forward range primitive. Only present if each constituent range is a 5551 forward range. 5552 +/ 5553 static if (allSatisfy!(isForwardRange, Ranges)) 5554 @property typeof(this) save() 5555 { 5556 return mixin(`typeof(return)(%(ranges[%s].save%|, %))`.format(iota(0, Ranges.length))); 5557 } 5558 5559 /+ 5560 Returns the current iterated element. 5561 +/ 5562 @property ElementType front() 5563 { 5564 return mixin(`typeof(return)(%(ranges[%s].front%|, %))`.format(iota(0, Ranges.length))); 5565 } 5566 5567 /+ 5568 Sets the front of all iterated ranges. Only present if each constituent 5569 range has assignable elements. 5570 +/ 5571 static if (allSatisfy!(hasAssignableElements, Ranges)) 5572 @property void front()(ElementType v) 5573 { 5574 static foreach (i; 0 .. Ranges.length) 5575 ranges[i].front = v[i]; 5576 } 5577 5578 /+ 5579 Moves out the front. Present if each constituent range has mobile elements. 5580 +/ 5581 static if (allSatisfy!(hasMobileElements, Ranges)) 5582 ElementType moveFront()() 5583 { 5584 return mixin(`typeof(return)(%(ranges[%s].moveFront()%|, %))`.format(iota(0, Ranges.length))); 5585 } 5586 5587 private enum bool isBackWellDefined = allSatisfy!(isBidirectionalRange, Ranges) 5588 && (allKnownSameLength 5589 || allSatisfy!(isRandomAccessRange, Ranges) 5590 // Could also add the case where there is one non-infinite bidirectional 5591 // range that defines `length` and all others are infinite random access 5592 // ranges. Adding this would require appropriate branches in 5593 // back/moveBack/popBack. 5594 ); 5595 5596 /+ 5597 Returns the rightmost element. Present if all constituent ranges are 5598 bidirectional and either there is a compile-time guarantee that all 5599 ranges have the same length (in `allKnownSameLength`) or all ranges 5600 provide random access to elements. 5601 +/ 5602 static if (isBackWellDefined) 5603 @property ElementType back() 5604 { 5605 static if (allKnownSameLength) 5606 { 5607 return mixin(`typeof(return)(%(ranges[%s].back()%|, %))`.format(iota(0, Ranges.length))); 5608 } 5609 else 5610 { 5611 const backIndex = length - 1; 5612 return mixin(`typeof(return)(%(ranges[%s][backIndex]%|, %))`.format(iota(0, Ranges.length))); 5613 } 5614 } 5615 5616 /+ 5617 Moves out the back. Present if `back` is defined and 5618 each constituent range has mobile elements. 5619 +/ 5620 static if (isBackWellDefined && allSatisfy!(hasMobileElements, Ranges)) 5621 ElementType moveBack()() 5622 { 5623 static if (allKnownSameLength) 5624 { 5625 return mixin(`typeof(return)(%(ranges[%s].moveBack()%|, %))`.format(iota(0, Ranges.length))); 5626 } 5627 else 5628 { 5629 const backIndex = length - 1; 5630 return mixin(`typeof(return)(%(ranges[%s].moveAt(backIndex)%|, %))`.format(iota(0, Ranges.length))); 5631 } 5632 } 5633 5634 /+ 5635 Sets the rightmost element. Only present if `back` is defined and 5636 each constituent range has assignable elements. 5637 +/ 5638 static if (isBackWellDefined && allSatisfy!(hasAssignableElements, Ranges)) 5639 @property void back()(ElementType v) 5640 { 5641 static if (allKnownSameLength) 5642 { 5643 static foreach (i; 0 .. Ranges.length) 5644 ranges[i].back = v[i]; 5645 } 5646 else 5647 { 5648 const backIndex = length - 1; 5649 static foreach (i; 0 .. Ranges.length) 5650 ranges[i][backIndex] = v[i]; 5651 } 5652 } 5653 5654 /+ 5655 Calls `popFront` on each constituent range. 5656 +/ 5657 void popFront() 5658 { 5659 static foreach (i; 0 .. Ranges.length) 5660 ranges[i].popFront(); 5661 } 5662 5663 /+ 5664 Pops the rightmost element. Present if `back` is defined. 5665 +/ 5666 static if (isBackWellDefined) 5667 void popBack() 5668 { 5669 static if (allKnownSameLength) 5670 { 5671 static foreach (i; 0 .. Ranges.length) 5672 ranges[i].popBack; 5673 } 5674 else 5675 { 5676 const len = length; 5677 static foreach (i; 0 .. Ranges.length) 5678 static if (!isInfinite!(Ranges[i])) 5679 if (ranges[i].length == len) 5680 ranges[i].popBack(); 5681 } 5682 } 5683 5684 /+ 5685 Returns the length of this range. Defined if at least one 5686 constituent range defines `length` and the other ranges all also 5687 define `length` or are infinite, or if at least one constituent 5688 range defines `length` and there is a compile-time guarantee that 5689 all ranges have the same length (in `allKnownSameLength`). 5690 +/ 5691 static if (allKnownSameLength 5692 ? anySatisfy!(hasLength, Ranges) 5693 : (anySatisfy!(hasLength, Ranges) 5694 && allSatisfy!(templateOr!(isInfinite, hasLength), Ranges))) 5695 { 5696 @property size_t length() 5697 { 5698 static foreach (i, Range; Ranges) 5699 { 5700 static if (hasLength!Range) 5701 { 5702 static if (!is(typeof(minLen) == size_t)) 5703 size_t minLen = ranges[i].length; 5704 else static if (!allKnownSameLength) 5705 {{ 5706 const x = ranges[i].length; 5707 if (x < minLen) minLen = x; 5708 }} 5709 } 5710 } 5711 return minLen; 5712 } 5713 5714 alias opDollar = length; 5715 } 5716 5717 /+ 5718 Returns a slice of the range. Defined if all constituent ranges 5719 support slicing. 5720 +/ 5721 static if (allSatisfy!(hasSlicing, Ranges)) 5722 { 5723 // Note: we will know that all elements of the resultant range 5724 // will have the same length but we cannot change `allKnownSameLength` 5725 // because the `hasSlicing` predicate tests that the result returned 5726 // by `opSlice` has the same type as the receiver. 5727 auto opSlice()(size_t from, size_t to) 5728 { 5729 //(ranges[0][from .. to], ranges[1][from .. to], ...) 5730 enum sliceArgs = `(%(ranges[%s][from .. to]%|, %))`.format(iota(0, Ranges.length)); 5731 static if (__traits(compiles, mixin(`typeof(this)`~sliceArgs))) 5732 return mixin(`typeof(this)`~sliceArgs); 5733 else 5734 // The type is different anyway so we might as well 5735 // explicitly set allKnownSameLength. 5736 return mixin(`ZipShortest!(Yes.allKnownSameLength, staticMap!(Take, Ranges))` 5737 ~sliceArgs); 5738 } 5739 } 5740 5741 /+ 5742 Returns the `n`th element in the composite range. Defined if all 5743 constituent ranges offer random access. 5744 +/ 5745 static if (allSatisfy!(isRandomAccessRange, Ranges)) 5746 ElementType opIndex()(size_t n) 5747 { 5748 return mixin(`typeof(return)(%(ranges[%s][n]%|, %))`.format(iota(0, Ranges.length))); 5749 } 5750 5751 /+ 5752 Sets the `n`th element in the composite range. Defined if all 5753 constituent ranges offer random access and have assignable elements. 5754 +/ 5755 static if (allSatisfy!(isRandomAccessRange, Ranges) 5756 && allSatisfy!(hasAssignableElements, Ranges)) 5757 void opIndexAssign()(ElementType v, size_t n) 5758 { 5759 static foreach (i; 0 .. Ranges.length) 5760 ranges[i][n] = v[i]; 5761 } 5762 5763 /+ 5764 Destructively reads the `n`th element in the composite 5765 range. Defined if all constituent ranges offer random 5766 access and have mobile elements. 5767 +/ 5768 static if (allSatisfy!(isRandomAccessRange, Ranges) 5769 && allSatisfy!(hasMobileElements, Ranges)) 5770 ElementType moveAt()(size_t n) 5771 { 5772 return mixin(`typeof(return)(%(ranges[%s].moveAt(n)%|, %))`.format(iota(0, Ranges.length))); 5773 } 5774 } 5775 5776 pure @system unittest 5777 { 5778 import std.algorithm.comparison : equal; 5779 import std.algorithm.iteration : filter, map; 5780 import std.algorithm.mutation : swap; 5781 import std.algorithm.sorting : sort; 5782 5783 import std.exception : assertThrown, assertNotThrown; 5784 import std.typecons : tuple; 5785 5786 int[] a = [ 1, 2, 3 ]; 5787 float[] b = [ 1.0, 2.0, 3.0 ]; 5788 foreach (e; zip(a, b)) 5789 { 5790 assert(e[0] == e[1]); 5791 } 5792 5793 swap(a[0], a[1]); 5794 { 5795 auto z = zip(a, b); 5796 } 5797 //swap(z.front(), z.back()); 5798 sort!("a[0] < b[0]")(zip(a, b)); 5799 assert(a == [1, 2, 3]); 5800 assert(b == [2.0, 1.0, 3.0]); 5801 5802 auto z = zip(StoppingPolicy.requireSameLength, a, b); 5803 assertNotThrown(z.popBack()); 5804 assertNotThrown(z.popBack()); 5805 assertNotThrown(z.popBack()); 5806 assert(z.empty); 5807 assertThrown(z.popBack()); 5808 5809 a = [ 1, 2, 3 ]; 5810 b = [ 1.0, 2.0, 3.0 ]; 5811 sort!("a[0] > b[0]")(zip(StoppingPolicy.requireSameLength, a, b)); 5812 assert(a == [3, 2, 1]); 5813 assert(b == [3.0, 2.0, 1.0]); 5814 5815 a = []; 5816 b = []; 5817 assert(zip(StoppingPolicy.requireSameLength, a, b).empty); 5818 5819 // Test infiniteness propagation. 5820 static assert(isInfinite!(typeof(zip(repeat(1), repeat(1))))); 5821 5822 // Test stopping policies with both value and reference. 5823 auto a1 = [1, 2]; 5824 auto a2 = [1, 2, 3]; 5825 auto stuff = tuple(tuple(a1, a2), 5826 tuple(filter!"a"(a1), filter!"a"(a2))); 5827 5828 alias FOO = Zip!(immutable(int)[], immutable(float)[]); 5829 5830 foreach (t; stuff.expand) 5831 { 5832 auto arr1 = t[0]; 5833 auto arr2 = t[1]; 5834 auto zShortest = zip(arr1, arr2); 5835 assert(equal(map!"a[0]"(zShortest), [1, 2])); 5836 assert(equal(map!"a[1]"(zShortest), [1, 2])); 5837 5838 try { 5839 auto zSame = zip(StoppingPolicy.requireSameLength, arr1, arr2); 5840 foreach (elem; zSame) {} 5841 assert(0); 5842 } catch (Throwable) { /* It's supposed to throw.*/ } 5843 5844 auto zLongest = zip(StoppingPolicy.longest, arr1, arr2); 5845 assert(!zLongest.ranges[0].empty); 5846 assert(!zLongest.ranges[1].empty); 5847 5848 zLongest.popFront(); 5849 zLongest.popFront(); 5850 assert(!zLongest.empty); 5851 assert(zLongest.ranges[0].empty); 5852 assert(!zLongest.ranges[1].empty); 5853 5854 zLongest.popFront(); 5855 assert(zLongest.empty); 5856 } 5857 5858 // https://issues.dlang.org/show_bug.cgi?id=8900 5859 assert(zip([1, 2], repeat('a')).array == [tuple(1, 'a'), tuple(2, 'a')]); 5860 assert(zip(repeat('a'), [1, 2]).array == [tuple('a', 1), tuple('a', 2)]); 5861 5862 // https://issues.dlang.org/show_bug.cgi?id=18524 5863 // moveBack instead performs moveFront 5864 { 5865 auto r = zip([1,2,3]); 5866 assert(r.moveBack()[0] == 3); 5867 assert(r.moveFront()[0] == 1); 5868 } 5869 5870 // Doesn't work yet. Issues w/ emplace. 5871 // static assert(is(Zip!(immutable int[], immutable float[]))); 5872 5873 5874 // These unittests pass, but make the compiler consume an absurd amount 5875 // of RAM and time. Therefore, they should only be run if explicitly 5876 // uncommented when making changes to Zip. Also, running them using 5877 // make -fwin32.mak unittest makes the compiler completely run out of RAM. 5878 // You need to test just this module. 5879 /+ 5880 foreach (DummyType1; AllDummyRanges) 5881 { 5882 DummyType1 d1; 5883 foreach (DummyType2; AllDummyRanges) 5884 { 5885 DummyType2 d2; 5886 auto r = zip(d1, d2); 5887 assert(equal(map!"a[0]"(r), [1,2,3,4,5,6,7,8,9,10])); 5888 assert(equal(map!"a[1]"(r), [1,2,3,4,5,6,7,8,9,10])); 5889 5890 static if (isForwardRange!DummyType1 && isForwardRange!DummyType2) 5891 { 5892 static assert(isForwardRange!(typeof(r))); 5893 } 5894 5895 static if (isBidirectionalRange!DummyType1 && 5896 isBidirectionalRange!DummyType2) { 5897 static assert(isBidirectionalRange!(typeof(r))); 5898 } 5899 static if (isRandomAccessRange!DummyType1 && 5900 isRandomAccessRange!DummyType2) { 5901 static assert(isRandomAccessRange!(typeof(r))); 5902 } 5903 } 5904 } 5905 +/ 5906 } 5907 5908 nothrow pure @safe unittest 5909 { 5910 import std.algorithm.sorting : sort; 5911 5912 auto a = [5,4,3,2,1]; 5913 auto b = [3,1,2,5,6]; 5914 auto z = zip(a, b); 5915 5916 sort!"a[0] < b[0]"(z); 5917 5918 assert(a == [1, 2, 3, 4, 5]); 5919 assert(b == [6, 5, 2, 1, 3]); 5920 } 5921 5922 nothrow pure @safe unittest 5923 { 5924 import std.algorithm.comparison : equal; 5925 import std.typecons : tuple; 5926 5927 auto LL = iota(1L, 1000L); 5928 auto z = zip(LL, [4]); 5929 5930 assert(equal(z, [tuple(1L,4)])); 5931 5932 auto LL2 = iota(0L, 500L); 5933 auto z2 = zip([7], LL2); 5934 assert(equal(z2, [tuple(7, 0L)])); 5935 } 5936 5937 // Test for https://issues.dlang.org/show_bug.cgi?id=11196 5938 @safe pure unittest 5939 { 5940 import std.exception : assertThrown; 5941 5942 static struct S { @disable this(); } 5943 assert(zip((S[5]).init[]).length == 5); 5944 assert(zip(StoppingPolicy.longest, cast(S[]) null, new int[1]).length == 1); 5945 assertThrown(zip(StoppingPolicy.longest, cast(S[]) null, new int[1]).front); 5946 } 5947 5948 // https://issues.dlang.org/show_bug.cgi?id=12007 5949 @nogc nothrow @safe pure unittest 5950 { 5951 static struct R 5952 { 5953 enum empty = false; 5954 void popFront(){} 5955 int front(){return 1;} @property 5956 R save(){return this;} @property 5957 void opAssign(R) @disable; 5958 } 5959 R r; 5960 auto z = zip(r, r); 5961 assert(z.save == z); 5962 } 5963 5964 nothrow pure @system unittest 5965 { 5966 import std.typecons : tuple; 5967 5968 auto r1 = [0,1,2]; 5969 auto r2 = [1,2,3]; 5970 auto z1 = zip(refRange(&r1), refRange(&r2)); 5971 auto z2 = z1.save; 5972 z1.popFront(); 5973 assert(z1.front == tuple(1,2)); 5974 assert(z2.front == tuple(0,1)); 5975 } 5976 5977 @nogc nothrow pure @safe unittest 5978 { 5979 // Test zip's `back` and `length` with non-equal ranges. 5980 static struct NonSliceableRandomAccess 5981 { 5982 private int[] a; 5983 @property ref front() 5984 { 5985 return a.front; 5986 } 5987 @property ref back() 5988 { 5989 return a.back; 5990 } 5991 ref opIndex(size_t i) 5992 { 5993 return a[i]; 5994 } 5995 void popFront() 5996 { 5997 a.popFront(); 5998 } 5999 void popBack() 6000 { 6001 a.popBack(); 6002 } 6003 auto moveFront() 6004 { 6005 return a.moveFront(); 6006 } 6007 auto moveBack() 6008 { 6009 return a.moveBack(); 6010 } 6011 auto moveAt(size_t i) 6012 { 6013 return a.moveAt(i); 6014 } 6015 bool empty() const 6016 { 6017 return a.empty; 6018 } 6019 size_t length() const 6020 { 6021 return a.length; 6022 } 6023 typeof(this) save() 6024 { 6025 return this; 6026 } 6027 } 6028 static assert(isRandomAccessRange!NonSliceableRandomAccess); 6029 static assert(!hasSlicing!NonSliceableRandomAccess); 6030 static foreach (iteration; 0 .. 2) 6031 {{ 6032 int[5] data = [101, 102, 103, 201, 202]; 6033 static if (iteration == 0) 6034 { 6035 auto r1 = NonSliceableRandomAccess(data[0 .. 3]); 6036 auto r2 = NonSliceableRandomAccess(data[3 .. 5]); 6037 } 6038 else 6039 { 6040 auto r1 = data[0 .. 3]; 6041 auto r2 = data[3 .. 5]; 6042 } 6043 auto z = zip(r1, r2); 6044 static assert(isRandomAccessRange!(typeof(z))); 6045 assert(z.length == 2); 6046 assert(z.back[0] == 102 && z.back[1] == 202); 6047 z.back = typeof(z.back)(-102, -202);// Assign to back. 6048 assert(z.back[0] == -102 && z.back[1] == -202); 6049 z.popBack(); 6050 assert(z.length == 1); 6051 assert(z.back[0] == 101 && z.back[1] == 201); 6052 z.front = typeof(z.front)(-101, -201); 6053 assert(z.moveBack() == typeof(z.back)(-101, -201)); 6054 z.popBack(); 6055 assert(z.empty); 6056 }} 6057 } 6058 6059 @nogc nothrow pure @safe unittest 6060 { 6061 // Test opSlice on infinite `zip`. 6062 auto z = zip(repeat(1), repeat(2)); 6063 assert(hasSlicing!(typeof(z))); 6064 auto slice = z[10 .. 20]; 6065 assert(slice.length == 10); 6066 static assert(!is(typeof(z) == typeof(slice))); 6067 } 6068 6069 /* 6070 Generate lockstep's opApply function as a mixin string. 6071 If withIndex is true prepend a size_t index to the delegate. 6072 */ 6073 private struct LockstepMixin(Ranges...) 6074 { 6075 import std.conv : text; 6076 import std.format : format; 6077 6078 string name; 6079 string implName; 6080 string[] params; 6081 string[] emptyChecks; 6082 string[] dgArgs; 6083 string[] popFronts; 6084 string indexDef; 6085 string indexInc; 6086 6087 @safe pure: 6088 this(bool withIndex, bool reverse) 6089 { 6090 if (withIndex) 6091 { 6092 params ~= "size_t"; 6093 dgArgs ~= "index"; 6094 if (reverse) 6095 { 6096 indexDef = q{ 6097 size_t index = ranges[0].length - 1; 6098 enforce( 6099 this.stoppingPolicy == StoppingPolicy.requireSameLength, 6100 "Indexed lockstep can only be used with foreach_reverse when " ~ 6101 "stoppingPolicy == requireSameLength"); 6102 6103 foreach (range; ranges[1 .. $]) 6104 enforce(range.length == ranges[0].length); 6105 }; 6106 indexInc = "--index;"; 6107 } 6108 else 6109 { 6110 indexDef = "size_t index = 0;"; 6111 indexInc = "++index;"; 6112 } 6113 } 6114 6115 foreach (idx, Range; Ranges) 6116 { 6117 params ~= format("%sElementType!(Ranges[%s])", hasLvalueElements!Range ? "ref " : "", idx); 6118 emptyChecks ~= format("!ranges[%s].empty", idx); 6119 if (reverse) 6120 { 6121 dgArgs ~= format("ranges[%s].back", idx); 6122 popFronts ~= format("ranges[%s].popBack();", idx); 6123 } 6124 else 6125 { 6126 dgArgs ~= format("ranges[%s].front", idx); 6127 popFronts ~= format("ranges[%s].popFront();", idx); 6128 } 6129 } 6130 6131 if (reverse) 6132 { 6133 name = "opApplyReverse"; 6134 if (withIndex) implName = "opApplyReverseIdxImpl"; 6135 else implName = "opApplyReverseImpl"; 6136 } 6137 else 6138 { 6139 name = "opApply"; 6140 if (withIndex) implName = "opApplyIdxImpl"; 6141 else implName = "opApplyImpl"; 6142 } 6143 } 6144 6145 const: 6146 string getAlias() 6147 { 6148 return format(q{ 6149 alias %s = %s!(int delegate(%-(%s%|, %))); 6150 }, 6151 name, implName, params 6152 ); 6153 } 6154 6155 string getImpl() 6156 { 6157 return format(q{ 6158 int %s(DG)(scope DG dg) scope 6159 { 6160 import std.exception : enforce; 6161 6162 auto ranges = this.ranges; 6163 %s 6164 6165 while (%-(%s%| && %)) 6166 { 6167 if (int result = dg(%-(%s%|, %))) return result; 6168 %-(%s%| 6169 %) 6170 %s 6171 } 6172 6173 if (this.stoppingPolicy == StoppingPolicy.requireSameLength) 6174 { 6175 foreach (range; ranges) 6176 enforce(range.empty); 6177 } 6178 return 0; 6179 } 6180 }, 6181 implName, indexDef, emptyChecks, dgArgs, popFronts, indexInc 6182 ); 6183 } 6184 } 6185 6186 /** 6187 Iterate multiple ranges in lockstep using a `foreach` loop. In contrast to 6188 $(LREF zip) it allows reference access to its elements. If only a single 6189 range is passed in, the `Lockstep` aliases itself away. If the 6190 ranges are of different lengths and `s` == `StoppingPolicy.shortest` 6191 stop after the shortest range is empty. If the ranges are of different 6192 lengths and `s` == `StoppingPolicy.requireSameLength`, throw an 6193 exception. `s` may not be `StoppingPolicy.longest`, and passing this 6194 will throw an exception. 6195 6196 Iterating over `Lockstep` in reverse and with an index is only possible 6197 when `s` == `StoppingPolicy.requireSameLength`, in order to preserve 6198 indexes. If an attempt is made at iterating in reverse when `s` == 6199 `StoppingPolicy.shortest`, an exception will be thrown. 6200 6201 By default `StoppingPolicy` is set to `StoppingPolicy.shortest`. 6202 6203 See_Also: $(LREF zip) 6204 6205 `lockstep` is similar to $(LREF zip), but `zip` bundles its 6206 elements and returns a range. 6207 `lockstep` also supports reference access. 6208 Use `zip` if you want to pass the result to a range function. 6209 */ 6210 struct Lockstep(Ranges...) 6211 if (Ranges.length > 1 && allSatisfy!(isInputRange, Ranges)) 6212 { 6213 private Ranges ranges; 6214 private StoppingPolicy stoppingPolicy; 6215 6216 /// 6217 this(Ranges ranges, StoppingPolicy sp = StoppingPolicy.shortest) 6218 { 6219 import std.exception : enforce; 6220 6221 this.ranges = ranges; 6222 enforce(sp != StoppingPolicy.longest, 6223 "Can't use StoppingPolicy.Longest on Lockstep."); 6224 this.stoppingPolicy = sp; 6225 } 6226 6227 private enum lockstepMixinFF = LockstepMixin!Ranges(withIndex: false, reverse: false); 6228 mixin(lockstepMixinFF.getImpl); 6229 6230 private enum lockstepMixinTF = LockstepMixin!Ranges(withIndex: true, reverse: false); 6231 mixin(lockstepMixinTF.getImpl); 6232 6233 mixin(lockstepMixinFF.getAlias); 6234 mixin(lockstepMixinTF.getAlias); 6235 6236 static if (allSatisfy!(isBidirectionalRange, Ranges)) 6237 { 6238 private enum lockstepMixinFT = LockstepMixin!Ranges(withIndex: false, reverse: true); 6239 mixin(lockstepMixinFT.getImpl); 6240 static if (allSatisfy!(hasLength, Ranges)) 6241 { 6242 private enum lockstepMixinTT = LockstepMixin!Ranges(withIndex: true, reverse: true); 6243 mixin(lockstepMixinTT.getImpl); 6244 mixin(lockstepMixinTT.getAlias); 6245 } 6246 else 6247 { 6248 mixin(lockstepReverseFailMixin!Ranges(withIndex: true)); 6249 alias opApplyReverse = opApplyReverseIdxFail; 6250 } 6251 mixin(lockstepMixinFT.getAlias); 6252 } 6253 else 6254 { 6255 mixin(lockstepReverseFailMixin!Ranges(withIndex: false)); 6256 mixin(lockstepReverseFailMixin!Ranges(withIndex: true)); 6257 alias opApplyReverse = opApplyReverseFail; 6258 alias opApplyReverse = opApplyReverseIdxFail; 6259 } 6260 } 6261 6262 /// Ditto 6263 Lockstep!(Ranges) lockstep(Ranges...)(Ranges ranges) 6264 if (allSatisfy!(isInputRange, Ranges)) 6265 { 6266 return Lockstep!(Ranges)(ranges); 6267 } 6268 /// Ditto 6269 Lockstep!(Ranges) lockstep(Ranges...)(Ranges ranges, StoppingPolicy s) 6270 if (allSatisfy!(isInputRange, Ranges)) 6271 { 6272 static if (Ranges.length > 1) 6273 return Lockstep!Ranges(ranges, s); 6274 else 6275 return ranges[0]; 6276 } 6277 6278 /// 6279 pure @safe unittest 6280 { 6281 int[6] arr1 = [1,2,3,4,5,100]; 6282 int[5] arr2 = [6,7,8,9,10]; 6283 6284 foreach (ref a, b; lockstep(arr1[], arr2[])) 6285 { 6286 a += b; 6287 } 6288 6289 assert(arr1 == [7,9,11,13,15,100]); 6290 } 6291 6292 /// Lockstep also supports iterating with an index variable: 6293 pure @safe unittest 6294 { 6295 int[3] arr1 = [1,2,3]; 6296 int[3] arr2 = [4,5,6]; 6297 6298 foreach (index, a, b; lockstep(arr1[], arr2[])) 6299 { 6300 assert(arr1[index] == a); 6301 assert(arr2[index] == b); 6302 } 6303 } 6304 6305 // https://issues.dlang.org/show_bug.cgi?id=15860: foreach_reverse on lockstep 6306 pure @safe unittest 6307 { 6308 auto arr1 = [0, 1, 2, 3]; 6309 auto arr2 = [4, 5, 6, 7]; 6310 6311 size_t n = arr1.length - 1; 6312 foreach_reverse (index, a, b; lockstep(arr1, arr2, StoppingPolicy.requireSameLength)) 6313 { 6314 assert(n == index); 6315 assert(index == a); 6316 assert(arr1[index] == a); 6317 assert(arr2[index] == b); 6318 n--; 6319 } 6320 6321 auto arr3 = [4, 5]; 6322 n = 1; 6323 foreach_reverse (a, b; lockstep(arr1, arr3)) 6324 { 6325 assert(a == arr1[$-n] && b == arr3[$-n]); 6326 n++; 6327 } 6328 } 6329 6330 pure @safe unittest 6331 { 6332 import std.algorithm.iteration : filter; 6333 import std.conv : to; 6334 6335 // The filters are to make these the lowest common forward denominator ranges, 6336 // i.e. w/o ref return, random access, length, etc. 6337 auto foo = filter!"a"([1,2,3,4,5]); 6338 immutable bar = [6f,7f,8f,9f,10f].idup; 6339 auto l = lockstep(foo, bar); 6340 6341 // Should work twice. These are forward ranges with implicit save. 6342 foreach (i; 0 .. 2) 6343 { 6344 uint[] res1; 6345 float[] res2; 6346 6347 foreach (a, ref b; l) 6348 { 6349 res1 ~= a; 6350 res2 ~= b; 6351 } 6352 6353 assert(res1 == [1,2,3,4,5]); 6354 assert(res2 == [6,7,8,9,10]); 6355 assert(bar == [6f,7f,8f,9f,10f]); 6356 } 6357 6358 // Doc example. 6359 auto arr1 = [1,2,3,4,5]; 6360 auto arr2 = [6,7,8,9,10]; 6361 6362 foreach (ref a, ref b; lockstep(arr1, arr2)) 6363 { 6364 a += b; 6365 } 6366 6367 assert(arr1 == [7,9,11,13,15]); 6368 6369 // Make sure StoppingPolicy.requireSameLength doesn't throw. 6370 auto ls = lockstep(arr1, arr2, StoppingPolicy.requireSameLength); 6371 6372 int k = 1; 6373 foreach (a, b; ls) 6374 { 6375 assert(a - b == k); 6376 ++k; 6377 } 6378 6379 // Make sure StoppingPolicy.requireSameLength throws. 6380 arr2.popBack(); 6381 ls = lockstep(arr1, arr2, StoppingPolicy.requireSameLength); 6382 6383 try { 6384 foreach (a, b; ls) {} 6385 assert(0); 6386 } catch (Exception) {} 6387 6388 // Just make sure 1-range case instantiates. This hangs the compiler 6389 // when no explicit stopping policy is specified due to 6390 // https://issues.dlang.org/show_bug.cgi?id=4652 6391 auto stuff = lockstep([1,2,3,4,5], StoppingPolicy.shortest); 6392 foreach (i, a; stuff) 6393 { 6394 assert(stuff[i] == a); 6395 } 6396 6397 // Test with indexing. 6398 uint[] res1; 6399 float[] res2; 6400 size_t[] indices; 6401 foreach (i, a, b; lockstep(foo, bar)) 6402 { 6403 indices ~= i; 6404 res1 ~= a; 6405 res2 ~= b; 6406 } 6407 6408 assert(indices == to!(size_t[])([0, 1, 2, 3, 4])); 6409 assert(res1 == [1,2,3,4,5]); 6410 assert(res2 == [6f,7f,8f,9f,10f]); 6411 6412 // Make sure we've worked around the relevant compiler bugs and this at least 6413 // compiles w/ >2 ranges. 6414 lockstep(foo, foo, foo); 6415 6416 // Make sure it works with const. 6417 const(int[])[] foo2 = [[1, 2, 3]]; 6418 const(int[])[] bar2 = [[4, 5, 6]]; 6419 auto c = chain(foo2, bar2); 6420 6421 foreach (f, b; lockstep(c, c)) {} 6422 6423 // Regression 10468 6424 foreach (x, y; lockstep(iota(0, 10), iota(0, 10))) { } 6425 } 6426 6427 pure @safe unittest 6428 { 6429 struct RvalueRange 6430 { 6431 int[] impl; 6432 @property bool empty() { return impl.empty; } 6433 @property int front() { return impl[0]; } // N.B. non-ref 6434 void popFront() { impl.popFront(); } 6435 } 6436 auto data1 = [ 1, 2, 3, 4 ]; 6437 auto data2 = [ 5, 6, 7, 8 ]; 6438 auto r1 = RvalueRange(data1); 6439 auto r2 = data2; 6440 foreach (a, ref b; lockstep(r1, r2)) 6441 { 6442 a++; 6443 b++; 6444 } 6445 assert(data1 == [ 1, 2, 3, 4 ]); // changes to a do not propagate to data 6446 assert(data2 == [ 6, 7, 8, 9 ]); // but changes to b do. 6447 6448 // Since r1 is by-value only, the compiler should reject attempts to 6449 // foreach over it with ref. 6450 static assert(!__traits(compiles, { 6451 foreach (ref a, ref b; lockstep(r1, r2)) { a++; } 6452 })); 6453 } 6454 6455 private string lockstepReverseFailMixin(Ranges...)(bool withIndex) 6456 { 6457 import std.format : format; 6458 string[] params; 6459 string message; 6460 6461 if (withIndex) 6462 { 6463 message = "Indexed reverse iteration with lockstep is only supported" 6464 ~"if all ranges are bidirectional and have a length.\n"; 6465 } 6466 else 6467 { 6468 message = "Reverse iteration with lockstep is only supported if all ranges are bidirectional.\n"; 6469 } 6470 6471 if (withIndex) 6472 { 6473 params ~= "size_t"; 6474 } 6475 6476 foreach (idx, Range; Ranges) 6477 { 6478 params ~= format("%sElementType!(Ranges[%s])", hasLvalueElements!Range ? "ref " : "", idx); 6479 } 6480 6481 return format( 6482 q{ 6483 int opApplyReverse%sFail()(scope int delegate(%s) dg) 6484 { 6485 static assert(false, "%s"); 6486 } 6487 }, withIndex ? "Idx" : "" , params.join(", "), message); 6488 } 6489 6490 // For generic programming, make sure Lockstep!(Range) is well defined for a 6491 // single range. 6492 template Lockstep(Range) 6493 { 6494 alias Lockstep = Range; 6495 } 6496 6497 /** 6498 Creates a mathematical sequence given the initial values and a 6499 recurrence function that computes the next value from the existing 6500 values. The sequence comes in the form of an infinite forward 6501 range. The type `Recurrence` itself is seldom used directly; most 6502 often, recurrences are obtained by calling the function $(D 6503 recurrence). 6504 6505 When calling `recurrence`, the function that computes the next 6506 value is specified as a template argument, and the initial values in 6507 the recurrence are passed as regular arguments. For example, in a 6508 Fibonacci sequence, there are two initial values (and therefore a 6509 state size of 2) because computing the next Fibonacci value needs the 6510 past two values. 6511 6512 The signature of this function should be: 6513 ---- 6514 auto fun(R)(R state, size_t n) 6515 ---- 6516 where `n` will be the index of the current value, and `state` will be an 6517 opaque state vector that can be indexed with array-indexing notation 6518 `state[i]`, where valid values of `i` range from $(D (n - 1)) to 6519 $(D (n - State.length)). 6520 6521 If the function is passed in string form, the state has name `"a"` 6522 and the zero-based index in the recurrence has name `"n"`. The 6523 given string must return the desired value for `a[n]` given 6524 `a[n - 1]`, `a[n - 2]`, `a[n - 3]`,..., `a[n - stateSize]`. The 6525 state size is dictated by the number of arguments passed to the call 6526 to `recurrence`. The `Recurrence` struct itself takes care of 6527 managing the recurrence's state and shifting it appropriately. 6528 */ 6529 struct Recurrence(alias fun, StateType, size_t stateSize) 6530 { 6531 import std.functional : binaryFun; 6532 6533 StateType[stateSize] _state; 6534 size_t _n; 6535 6536 this(StateType[stateSize] initial) { _state = initial; } 6537 6538 void popFront() 6539 { 6540 static auto trustedCycle(ref typeof(_state) s) @trusted 6541 { 6542 return cycle(s); 6543 } 6544 // The cast here is reasonable because fun may cause integer 6545 // promotion, but needs to return a StateType to make its operation 6546 // closed. Therefore, we have no other choice. 6547 _state[_n % stateSize] = cast(StateType) binaryFun!(fun, "a", "n")( 6548 trustedCycle(_state), _n + stateSize); 6549 ++_n; 6550 } 6551 6552 @property StateType front() 6553 { 6554 return _state[_n % stateSize]; 6555 } 6556 6557 @property typeof(this) save() 6558 { 6559 return this; 6560 } 6561 6562 enum bool empty = false; 6563 } 6564 6565 /// 6566 pure @safe nothrow unittest 6567 { 6568 import std.algorithm.comparison : equal; 6569 6570 // The Fibonacci numbers, using function in string form: 6571 // a[0] = 1, a[1] = 1, and compute a[n+1] = a[n-1] + a[n] 6572 auto fib = recurrence!("a[n-1] + a[n-2]")(1, 1); 6573 assert(fib.take(10).equal([1, 1, 2, 3, 5, 8, 13, 21, 34, 55])); 6574 6575 // The factorials, using function in lambda form: 6576 auto fac = recurrence!((a,n) => a[n-1] * n)(1); 6577 assert(take(fac, 10).equal([ 6578 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880 6579 ])); 6580 6581 // The triangular numbers, using function in explicit form: 6582 static size_t genTriangular(R)(R state, size_t n) 6583 { 6584 return state[n-1] + n; 6585 } 6586 auto tri = recurrence!genTriangular(0); 6587 assert(take(tri, 10).equal([0, 1, 3, 6, 10, 15, 21, 28, 36, 45])); 6588 } 6589 6590 /// Ditto 6591 Recurrence!(fun, CommonType!(State), State.length) 6592 recurrence(alias fun, State...)(State initial) 6593 { 6594 CommonType!(State)[State.length] state; 6595 foreach (i, Unused; State) 6596 { 6597 state[i] = initial[i]; 6598 } 6599 return typeof(return)(state); 6600 } 6601 6602 pure @safe nothrow unittest 6603 { 6604 import std.algorithm.comparison : equal; 6605 6606 auto fib = recurrence!("a[n-1] + a[n-2]")(1, 1); 6607 static assert(isForwardRange!(typeof(fib))); 6608 6609 int[] witness = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55 ]; 6610 assert(equal(take(fib, 10), witness)); 6611 foreach (e; take(fib, 10)) {} 6612 auto fact = recurrence!("n * a[n-1]")(1); 6613 assert( equal(take(fact, 10), [1, 1, 2, 2*3, 2*3*4, 2*3*4*5, 2*3*4*5*6, 6614 2*3*4*5*6*7, 2*3*4*5*6*7*8, 2*3*4*5*6*7*8*9][]) ); 6615 auto piapprox = recurrence!("a[n] + (n & 1 ? 4.0 : -4.0) / (2 * n + 3)")(4.0); 6616 foreach (e; take(piapprox, 20)) {} 6617 // Thanks to yebblies for this test and the associated fix 6618 auto r = recurrence!"a[n-2]"(1, 2); 6619 witness = [1, 2, 1, 2, 1]; 6620 assert(equal(take(r, 5), witness)); 6621 } 6622 6623 /** 6624 `Sequence` is similar to `Recurrence` except that iteration is 6625 presented in the so-called $(HTTP en.wikipedia.org/wiki/Closed_form, 6626 closed form). This means that the `n`th element in the series is 6627 computable directly from the initial values and `n` itself. This 6628 implies that the interface offered by `Sequence` is a random-access 6629 range, as opposed to the regular `Recurrence`, which only offers 6630 forward iteration. 6631 6632 The state of the sequence is stored as a `Tuple` so it can be 6633 heterogeneous. 6634 */ 6635 struct Sequence(alias fun, State) 6636 { 6637 private: 6638 import std.functional : binaryFun; 6639 6640 alias compute = binaryFun!(fun, "a", "n"); 6641 alias ElementType = typeof(compute(State.init, cast(size_t) 1)); 6642 State _state; 6643 size_t _n; 6644 6645 static struct DollarToken{} 6646 6647 public: 6648 this(State initial, size_t n = 0) 6649 { 6650 _state = initial; 6651 _n = n; 6652 } 6653 6654 @property ElementType front() 6655 { 6656 return compute(_state, _n); 6657 } 6658 6659 void popFront() 6660 { 6661 ++_n; 6662 } 6663 6664 enum opDollar = DollarToken(); 6665 6666 auto opSlice(size_t lower, size_t upper) 6667 in 6668 { 6669 assert( 6670 upper >= lower, 6671 "Attempting to slice a Sequence with a larger first argument than the second." 6672 ); 6673 } 6674 do 6675 { 6676 return typeof(this)(_state, _n + lower).take(upper - lower); 6677 } 6678 6679 auto opSlice(size_t lower, DollarToken) 6680 { 6681 return typeof(this)(_state, _n + lower); 6682 } 6683 6684 ElementType opIndex(size_t n) 6685 { 6686 return compute(_state, n + _n); 6687 } 6688 6689 enum bool empty = false; 6690 6691 @property Sequence save() { return this; } 6692 } 6693 6694 /// Ditto 6695 auto sequence(alias fun, State...)(State args) 6696 { 6697 import std.typecons : Tuple, tuple; 6698 alias Return = Sequence!(fun, Tuple!State); 6699 return Return(tuple(args)); 6700 } 6701 6702 /// Odd numbers, using function in string form: 6703 pure @safe nothrow @nogc unittest 6704 { 6705 auto odds = sequence!("a[0] + n * a[1]")(1, 2); 6706 assert(odds.front == 1); 6707 odds.popFront(); 6708 assert(odds.front == 3); 6709 odds.popFront(); 6710 assert(odds.front == 5); 6711 } 6712 6713 /// Triangular numbers, using function in lambda form: 6714 pure @safe nothrow @nogc unittest 6715 { 6716 auto tri = sequence!((a,n) => n*(n+1)/2)(); 6717 6718 // Note random access 6719 assert(tri[0] == 0); 6720 assert(tri[3] == 6); 6721 assert(tri[1] == 1); 6722 assert(tri[4] == 10); 6723 assert(tri[2] == 3); 6724 } 6725 6726 /// Fibonacci numbers, using function in explicit form: 6727 @safe nothrow @nogc unittest 6728 { 6729 import std.math.exponential : pow; 6730 import std.math.rounding : round; 6731 import std.math.algebraic : sqrt; 6732 static ulong computeFib(S)(S state, size_t n) 6733 { 6734 // Binet's formula 6735 return cast(ulong)(round((pow(state[0], n+1) - pow(state[1], n+1)) / 6736 state[2])); 6737 } 6738 auto fib = sequence!computeFib( 6739 (1.0 + sqrt(5.0)) / 2.0, // Golden Ratio 6740 (1.0 - sqrt(5.0)) / 2.0, // Conjugate of Golden Ratio 6741 sqrt(5.0)); 6742 6743 // Note random access with [] operator 6744 assert(fib[1] == 1); 6745 assert(fib[4] == 5); 6746 assert(fib[3] == 3); 6747 assert(fib[2] == 2); 6748 assert(fib[9] == 55); 6749 } 6750 6751 pure @safe nothrow @nogc unittest 6752 { 6753 import std.typecons : Tuple, tuple; 6754 auto y = Sequence!("a[0] + n * a[1]", Tuple!(int, int))(tuple(0, 4)); 6755 static assert(isForwardRange!(typeof(y))); 6756 6757 //@@BUG 6758 //auto y = sequence!("a[0] + n * a[1]")(0, 4); 6759 //foreach (e; take(y, 15)) 6760 {} //writeln(e); 6761 6762 auto odds = Sequence!("a[0] + n * a[1]", Tuple!(int, int))( 6763 tuple(1, 2)); 6764 for (int currentOdd = 1; currentOdd <= 21; currentOdd += 2) 6765 { 6766 assert(odds.front == odds[0]); 6767 assert(odds[0] == currentOdd); 6768 odds.popFront(); 6769 } 6770 } 6771 6772 pure @safe nothrow @nogc unittest 6773 { 6774 import std.algorithm.comparison : equal; 6775 6776 auto odds = sequence!("a[0] + n * a[1]")(1, 2); 6777 static assert(hasSlicing!(typeof(odds))); 6778 6779 //Note: don't use drop or take as the target of an equal, 6780 //since they'll both just forward to opSlice, making the tests irrelevant 6781 6782 // static slicing tests 6783 assert(equal(odds[0 .. 5], only(1, 3, 5, 7, 9))); 6784 assert(equal(odds[3 .. 7], only(7, 9, 11, 13))); 6785 6786 // relative slicing test, testing slicing is NOT agnostic of state 6787 auto odds_less5 = odds.drop(5); //this should actually call odds[5 .. $] 6788 assert(equal(odds_less5[0 .. 3], only(11, 13, 15))); 6789 assert(equal(odds_less5[0 .. 10], odds[5 .. 15])); 6790 6791 //Infinite slicing tests 6792 odds = odds[10 .. $]; 6793 assert(equal(odds.take(3), only(21, 23, 25))); 6794 } 6795 6796 // https://issues.dlang.org/show_bug.cgi?id=5036 6797 pure @safe nothrow unittest 6798 { 6799 auto s = sequence!((a, n) => new int)(0); 6800 assert(s.front != s.front); // no caching 6801 } 6802 6803 // iota 6804 /** 6805 Creates a range of values that span the given starting and stopping 6806 values. 6807 6808 Params: 6809 begin = The starting value. 6810 end = The value that serves as the stopping criterion. This value is not 6811 included in the range. 6812 step = The value to add to the current value at each iteration. 6813 6814 Returns: 6815 A range that goes through the numbers `begin`, $(D begin + step), 6816 $(D begin + 2 * step), `...`, up to and excluding `end`. 6817 6818 The two-argument overloads have $(D step = 1). If $(D begin < end && step < 6819 0) or $(D begin > end && step > 0) or $(D begin == end), then an empty range 6820 is returned. If $(D step == 0) then $(D begin == end) is an error. 6821 6822 For built-in types, the range returned is a random access range. For 6823 user-defined types that support `++`, the range is an input 6824 range. 6825 6826 An integral iota also supports `in` operator from the right. It takes 6827 the stepping into account, the integral won't be considered 6828 contained if it falls between two consecutive values of the range. 6829 `contains` does the same as in, but from lefthand side. 6830 6831 Example: 6832 --- 6833 void main() 6834 { 6835 import std.stdio; 6836 6837 // The following groups all produce the same output of: 6838 // 0 1 2 3 4 6839 6840 foreach (i; 0 .. 5) 6841 writef("%s ", i); 6842 writeln(); 6843 6844 import std.range : iota; 6845 foreach (i; iota(0, 5)) 6846 writef("%s ", i); 6847 writeln(); 6848 6849 writefln("%(%s %|%)", iota(0, 5)); 6850 6851 import std.algorithm.iteration : map; 6852 import std.algorithm.mutation : copy; 6853 import std.format; 6854 iota(0, 5).map!(i => format("%s ", i)).copy(stdout.lockingTextWriter()); 6855 writeln(); 6856 } 6857 --- 6858 */ 6859 auto iota(B, E, S)(B begin, E end, S step) 6860 if ((isIntegral!(CommonType!(B, E)) || isPointer!(CommonType!(B, E))) 6861 && isIntegral!S) 6862 { 6863 import std.conv : unsigned; 6864 6865 alias Value = CommonType!(Unqual!B, Unqual!E); 6866 alias StepType = Unqual!S; 6867 6868 assert(step != 0 || begin == end); 6869 6870 static struct Result 6871 { 6872 private Value current, last; 6873 private StepType step; // by convention, 0 if range is empty 6874 6875 this(Value current, Value pastLast, StepType step) 6876 { 6877 if (current < pastLast && step > 0) 6878 { 6879 // Iterating upward 6880 assert(unsigned((pastLast - current) / step) <= size_t.max); 6881 // Cast below can't fail because current < pastLast 6882 this.last = cast(Value) (pastLast - 1); 6883 this.last -= unsigned(this.last - current) % step; 6884 } 6885 else if (current > pastLast && step < 0) 6886 { 6887 // Iterating downward 6888 assert(unsigned((current - pastLast) / (0 - step)) <= size_t.max); 6889 // Cast below can't fail because current > pastLast 6890 this.last = cast(Value) (pastLast + 1); 6891 this.last += unsigned(current - this.last) % (0 - step); 6892 } 6893 else 6894 { 6895 // Initialize an empty range 6896 this.step = 0; 6897 return; 6898 } 6899 this.step = step; 6900 this.current = current; 6901 } 6902 6903 @property bool empty() const { return step == 0; } 6904 @property inout(Value) front() inout { assert(!empty); return current; } 6905 void popFront() 6906 { 6907 assert(!empty); 6908 if (current == last) step = 0; 6909 else current += step; 6910 } 6911 6912 @property inout(Value) back() inout 6913 { 6914 assert(!empty); 6915 return last; 6916 } 6917 void popBack() 6918 { 6919 assert(!empty); 6920 if (current == last) step = 0; 6921 else last -= step; 6922 } 6923 6924 @property auto save() { return this; } 6925 6926 inout(Value) opIndex(ulong n) inout 6927 { 6928 assert(n < this.length); 6929 6930 // Just cast to Value here because doing so gives overflow behavior 6931 // consistent with calling popFront() n times. 6932 return cast(inout Value) (current + step * n); 6933 } 6934 auto opBinaryRight(string op)(Value val) const 6935 if (op == "in") 6936 { 6937 if (empty) return false; 6938 //cast to avoid becoming unsigned 6939 auto supposedIndex = cast(StepType)(val - current) / step; 6940 return supposedIndex < length && supposedIndex * step + current == val; 6941 } 6942 auto contains(Value x){return x in this;} 6943 inout(Result) opSlice() inout { return this; } 6944 inout(Result) opSlice(ulong lower, ulong upper) inout 6945 { 6946 assert(upper >= lower && upper <= this.length); 6947 6948 return cast(inout Result) Result( 6949 cast(Value)(current + lower * step), 6950 cast(Value)(current + upper * step), 6951 step); 6952 } 6953 @property size_t length() const 6954 { 6955 if (step > 0) 6956 return 1 + cast(size_t) (unsigned(last - current) / step); 6957 if (step < 0) 6958 return 1 + cast(size_t) (unsigned(current - last) / (0 - step)); 6959 return 0; 6960 } 6961 6962 alias opDollar = length; 6963 } 6964 6965 return Result(begin, end, step); 6966 } 6967 6968 /// Ditto 6969 auto iota(B, E)(B begin, E end) 6970 if (isFloatingPoint!(CommonType!(B, E))) 6971 { 6972 return iota(begin, end, CommonType!(B, E)(1)); 6973 } 6974 6975 /// Ditto 6976 auto iota(B, E)(B begin, E end) 6977 if (isIntegral!(CommonType!(B, E)) || isPointer!(CommonType!(B, E))) 6978 { 6979 import std.conv : unsigned; 6980 6981 alias Value = CommonType!(Unqual!B, Unqual!E); 6982 6983 static struct Result 6984 { 6985 private Value current, pastLast; 6986 6987 this(Value current, Value pastLast) 6988 { 6989 if (current < pastLast) 6990 { 6991 assert(unsigned(pastLast - current) <= size_t.max, 6992 "`iota` range is too long"); 6993 6994 this.current = current; 6995 this.pastLast = pastLast; 6996 } 6997 else 6998 { 6999 // Initialize an empty range 7000 this.current = this.pastLast = current; 7001 } 7002 } 7003 7004 @property bool empty() const { return current == pastLast; } 7005 @property inout(Value) front() inout 7006 { 7007 assert(!empty, "Attempt to access `front` of empty `iota` range"); 7008 return current; 7009 } 7010 void popFront() 7011 { 7012 assert(!empty, "Attempt to `popFront` of empty `iota` range"); 7013 ++current; 7014 } 7015 7016 @property inout(Value) back() inout 7017 { 7018 assert(!empty, "Attempt to access `back` of empty `iota` range"); 7019 return cast(inout(Value))(pastLast - 1); 7020 } 7021 void popBack() 7022 { 7023 assert(!empty, "Attempt to `popBack` of empty `iota` range"); 7024 --pastLast; 7025 } 7026 7027 @property auto save() { return this; } 7028 7029 inout(Value) opIndex(size_t n) inout 7030 { 7031 assert(n < this.length, 7032 "Attempt to read out-of-bounds index of `iota` range"); 7033 7034 // Just cast to Value here because doing so gives overflow behavior 7035 // consistent with calling popFront() n times. 7036 return cast(inout Value) (current + n); 7037 } 7038 auto opBinaryRight(string op)(Value val) const 7039 if (op == "in") 7040 { 7041 return current <= val && val < pastLast; 7042 } 7043 auto contains(Value x){return x in this;} 7044 inout(Result) opSlice() inout { return this; } 7045 inout(Result) opSlice(ulong lower, ulong upper) inout 7046 { 7047 assert(upper >= lower && upper <= this.length, 7048 "Attempt to get out-of-bounds slice of `iota` range"); 7049 7050 return cast(inout Result) Result(cast(Value)(current + lower), 7051 cast(Value)(pastLast - (length - upper))); 7052 } 7053 @property size_t length() const 7054 { 7055 return cast(size_t)(pastLast - current); 7056 } 7057 7058 alias opDollar = length; 7059 } 7060 7061 return Result(begin, end); 7062 } 7063 7064 /// Ditto 7065 auto iota(E)(E end) 7066 if (is(typeof(iota(E(0), end)))) 7067 { 7068 E begin = E(0); 7069 return iota(begin, end); 7070 } 7071 7072 /// Ditto 7073 // Specialization for floating-point types 7074 auto iota(B, E, S)(B begin, E end, S step) 7075 if (isFloatingPoint!(CommonType!(B, E, S))) 7076 in 7077 { 7078 assert(step != 0, "iota: step must not be 0"); 7079 assert((end - begin) / step >= 0, "iota: incorrect startup parameters"); 7080 } 7081 do 7082 { 7083 alias Value = Unqual!(CommonType!(B, E, S)); 7084 static struct Result 7085 { 7086 private Value start, step; 7087 private size_t index, count; 7088 7089 this(Value start, Value end, Value step) 7090 { 7091 import std.conv : to; 7092 7093 this.start = start; 7094 this.step = step; 7095 immutable fcount = (end - start) / step; 7096 count = to!size_t(fcount); 7097 auto pastEnd = start + count * step; 7098 if (step > 0) 7099 { 7100 if (pastEnd < end) ++count; 7101 assert(start + count * step >= end); 7102 } 7103 else 7104 { 7105 if (pastEnd > end) ++count; 7106 assert(start + count * step <= end); 7107 } 7108 } 7109 7110 @property bool empty() const { return index == count; } 7111 @property Value front() const { assert(!empty); return start + step * index; } 7112 void popFront() 7113 { 7114 assert(!empty); 7115 ++index; 7116 } 7117 @property Value back() const 7118 { 7119 assert(!empty); 7120 return start + step * (count - 1); 7121 } 7122 void popBack() 7123 { 7124 assert(!empty); 7125 --count; 7126 } 7127 7128 @property auto save() { return this; } 7129 7130 Value opIndex(size_t n) const 7131 { 7132 assert(n < count); 7133 return start + step * (n + index); 7134 } 7135 inout(Result) opSlice() inout 7136 { 7137 return this; 7138 } 7139 inout(Result) opSlice(size_t lower, size_t upper) inout 7140 { 7141 assert(upper >= lower && upper <= count); 7142 7143 Result ret = this; 7144 ret.index += lower; 7145 ret.count = upper - lower + ret.index; 7146 return cast(inout Result) ret; 7147 } 7148 @property size_t length() const 7149 { 7150 return count - index; 7151 } 7152 7153 alias opDollar = length; 7154 } 7155 7156 return Result(begin, end, step); 7157 } 7158 7159 /// 7160 pure @safe unittest 7161 { 7162 import std.algorithm.comparison : equal; 7163 import std.math.operations : isClose; 7164 7165 auto r = iota(0, 10, 1); 7166 assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])); 7167 assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])); 7168 assert(3 in r); 7169 assert(r.contains(3)); //Same as above 7170 assert(!(10 in r)); 7171 assert(!(-8 in r)); 7172 r = iota(0, 11, 3); 7173 assert(equal(r, [0, 3, 6, 9])); 7174 assert(r[2] == 6); 7175 assert(!(2 in r)); 7176 auto rf = iota(0.0, 0.5, 0.1); 7177 assert(isClose(rf, [0.0, 0.1, 0.2, 0.3, 0.4])); 7178 } 7179 7180 pure nothrow @nogc @safe unittest 7181 { 7182 import std.traits : Signed; 7183 //float overloads use std.conv.to so can't be @nogc or nothrow 7184 alias ssize_t = Signed!size_t; 7185 assert(iota(ssize_t.max, 0, -1).length == ssize_t.max); 7186 assert(iota(ssize_t.max, ssize_t.min, -1).length == size_t.max); 7187 assert(iota(ssize_t.max, ssize_t.min, -2).length == 1 + size_t.max / 2); 7188 assert(iota(ssize_t.min, ssize_t.max, 2).length == 1 + size_t.max / 2); 7189 assert(iota(ssize_t.max, ssize_t.min, -3).length == size_t.max / 3); 7190 } 7191 7192 debug @system unittest 7193 {//check the contracts 7194 import core.exception : AssertError; 7195 import std.exception : assertThrown; 7196 assertThrown!AssertError(iota(1,2,0)); 7197 assertThrown!AssertError(iota(0f,1f,0f)); 7198 assertThrown!AssertError(iota(1f,0f,0.1f)); 7199 assertThrown!AssertError(iota(0f,1f,-0.1f)); 7200 } 7201 7202 pure @system nothrow unittest 7203 { 7204 int[] a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; 7205 auto r1 = iota(a.ptr, a.ptr + a.length, 1); 7206 assert(r1.front == a.ptr); 7207 assert(r1.back == a.ptr + a.length - 1); 7208 assert(&a[4] in r1); 7209 } 7210 7211 pure @safe nothrow @nogc unittest 7212 { 7213 assert(iota(1UL, 0UL).length == 0); 7214 assert(iota(1UL, 0UL, 1).length == 0); 7215 assert(iota(0, 1, 1).length == 1); 7216 assert(iota(1, 0, -1).length == 1); 7217 assert(iota(0, 1, -1).length == 0); 7218 assert(iota(ulong.max, 0).length == 0); 7219 } 7220 7221 pure @safe unittest 7222 { 7223 import std.algorithm.comparison : equal; 7224 import std.algorithm.searching : count; 7225 import std.math.operations : isClose, nextUp, nextDown; 7226 import std.meta : AliasSeq; 7227 7228 static assert(is(ElementType!(typeof(iota(0f))) == float)); 7229 7230 static assert(hasLength!(typeof(iota(0, 2)))); 7231 auto r = iota(0, 10, 1); 7232 assert(r[$ - 1] == 9); 7233 assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][])); 7234 7235 auto rSlice = r[2 .. 8]; 7236 assert(equal(rSlice, [2, 3, 4, 5, 6, 7])); 7237 7238 rSlice.popFront(); 7239 assert(rSlice[0] == rSlice.front); 7240 assert(rSlice.front == 3); 7241 7242 rSlice.popBack(); 7243 assert(rSlice[rSlice.length - 1] == rSlice.back); 7244 assert(rSlice.back == 6); 7245 7246 rSlice = r[0 .. 4]; 7247 assert(equal(rSlice, [0, 1, 2, 3])); 7248 assert(3 in rSlice); 7249 assert(!(4 in rSlice)); 7250 7251 auto rr = iota(10); 7252 assert(equal(rr, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][])); 7253 7254 r = iota(0, -10, -1); 7255 assert(equal(r, [0, -1, -2, -3, -4, -5, -6, -7, -8, -9][])); 7256 rSlice = r[3 .. 9]; 7257 assert(equal(rSlice, [-3, -4, -5, -6, -7, -8])); 7258 7259 r = iota(0, -6, -3); 7260 assert(equal(r, [0, -3][])); 7261 rSlice = r[1 .. 2]; 7262 assert(equal(rSlice, [-3])); 7263 7264 r = iota(0, -7, -3); 7265 assert(equal(r, [0, -3, -6][])); 7266 assert(0 in r); 7267 assert(-6 in r); 7268 rSlice = r[1 .. 3]; 7269 assert(equal(rSlice, [-3, -6])); 7270 assert(!(0 in rSlice)); 7271 assert(!(-2 in rSlice)); 7272 assert(!(-5 in rSlice)); 7273 assert(!(3 in rSlice)); 7274 assert(!(-9 in rSlice)); 7275 7276 r = iota(0, 11, 3); 7277 assert(equal(r, [0, 3, 6, 9][])); 7278 assert(r[2] == 6); 7279 rSlice = r[1 .. 3]; 7280 assert(equal(rSlice, [3, 6])); 7281 7282 auto rf = iota(0.0, 0.5, 0.1); 7283 assert(isClose(rf, [0.0, 0.1, 0.2, 0.3, 0.4][])); 7284 assert(rf.length == 5); 7285 7286 rf.popFront(); 7287 assert(rf.length == 4); 7288 7289 auto rfSlice = rf[1 .. 4]; 7290 assert(rfSlice.length == 3); 7291 assert(isClose(rfSlice, [0.2, 0.3, 0.4])); 7292 7293 rfSlice.popFront(); 7294 assert(isClose(rfSlice[0], 0.3)); 7295 7296 rf.popFront(); 7297 assert(rf.length == 3); 7298 7299 rfSlice = rf[1 .. 3]; 7300 assert(rfSlice.length == 2); 7301 assert(isClose(rfSlice, [0.3, 0.4])); 7302 assert(isClose(rfSlice[0], 0.3)); 7303 7304 // With something just above 0.5 7305 rf = iota(0.0, nextUp(0.5), 0.1); 7306 assert(isClose(rf, [0.0, 0.1, 0.2, 0.3, 0.4, 0.5][])); 7307 rf.popBack(); 7308 assert(rf[rf.length - 1] == rf.back); 7309 assert(isClose(rf.back, 0.4)); 7310 assert(rf.length == 5); 7311 7312 // going down 7313 rf = iota(0.0, -0.5, -0.1); 7314 assert(isClose(rf, [0.0, -0.1, -0.2, -0.3, -0.4][])); 7315 rfSlice = rf[2 .. 5]; 7316 assert(isClose(rfSlice, [-0.2, -0.3, -0.4])); 7317 7318 rf = iota(0.0, nextDown(-0.5), -0.1); 7319 assert(isClose(rf, [0.0, -0.1, -0.2, -0.3, -0.4, -0.5][])); 7320 7321 // iota of longs 7322 auto rl = iota(5_000_000L); 7323 assert(rl.length == 5_000_000L); 7324 assert(0 in rl); 7325 assert(4_000_000L in rl); 7326 assert(!(-4_000_000L in rl)); 7327 assert(!(5_000_000L in rl)); 7328 7329 // iota of longs with steps 7330 auto iota_of_longs_with_steps = iota(50L, 101L, 10); 7331 assert(iota_of_longs_with_steps.length == 6); 7332 assert(equal(iota_of_longs_with_steps, [50L, 60L, 70L, 80L, 90L, 100L])); 7333 7334 // iota of unsigned zero length (https://issues.dlang.org/show_bug.cgi?id=6222) 7335 // Actually trying to consume it is the only way to find something is wrong 7336 // because the public properties are all correct. 7337 auto iota_zero_unsigned = iota(0, 0u, 3); 7338 assert(count(iota_zero_unsigned) == 0); 7339 7340 // https://issues.dlang.org/show_bug.cgi?id=7982 7341 // unsigned reverse iota can be buggy if `.length` doesn't 7342 // take them into account 7343 assert(iota(10u, 0u, -1).length == 10); 7344 assert(iota(10u, 0u, -2).length == 5); 7345 assert(iota(uint.max, uint.max-10, -1).length == 10); 7346 assert(iota(uint.max, uint.max-10, -2).length == 5); 7347 assert(iota(uint.max, 0u, -1).length == uint.max); 7348 7349 assert(20 in iota(20u, 10u, -2)); 7350 assert(16 in iota(20u, 10u, -2)); 7351 assert(!(15 in iota(20u, 10u, -2))); 7352 assert(!(10 in iota(20u, 10u, -2))); 7353 assert(!(uint.max in iota(20u, 10u, -1))); 7354 assert(!(int.min in iota(20u, 10u, -1))); 7355 assert(!(int.max in iota(20u, 10u, -1))); 7356 7357 7358 // https://issues.dlang.org/show_bug.cgi?id=8920 7359 static foreach (Type; AliasSeq!(byte, ubyte, short, ushort, 7360 int, uint, long, ulong)) 7361 {{ 7362 Type val; 7363 foreach (i; iota(cast(Type) 0, cast(Type) 10)) { val++; } 7364 assert(val == 10); 7365 }} 7366 } 7367 7368 pure @safe nothrow unittest 7369 { 7370 import std.algorithm.mutation : copy; 7371 auto idx = new size_t[100]; 7372 copy(iota(0, idx.length), idx); 7373 } 7374 7375 @safe unittest 7376 { 7377 import std.meta : AliasSeq; 7378 static foreach (range; AliasSeq!(iota(2, 27, 4), 7379 iota(3, 9), 7380 iota(2.7, 12.3, .1), 7381 iota(3.2, 9.7))) 7382 {{ 7383 const cRange = range; 7384 const e = cRange.empty; 7385 const f = cRange.front; 7386 const b = cRange.back; 7387 const i = cRange[2]; 7388 const s1 = cRange[]; 7389 const s2 = cRange[0 .. 3]; 7390 const l = cRange.length; 7391 }} 7392 } 7393 7394 @system unittest 7395 { 7396 //The ptr stuff can't be done at compile time, so we unfortunately end 7397 //up with some code duplication here. 7398 auto arr = [0, 5, 3, 5, 5, 7, 9, 2, 0, 42, 7, 6]; 7399 7400 { 7401 const cRange = iota(arr.ptr, arr.ptr + arr.length, 3); 7402 const e = cRange.empty; 7403 const f = cRange.front; 7404 const b = cRange.back; 7405 const i = cRange[2]; 7406 const s1 = cRange[]; 7407 const s2 = cRange[0 .. 3]; 7408 const l = cRange.length; 7409 } 7410 7411 { 7412 const cRange = iota(arr.ptr, arr.ptr + arr.length); 7413 const e = cRange.empty; 7414 const f = cRange.front; 7415 const b = cRange.back; 7416 const i = cRange[2]; 7417 const s1 = cRange[]; 7418 const s2 = cRange[0 .. 3]; 7419 const l = cRange.length; 7420 } 7421 } 7422 7423 @nogc nothrow pure @safe unittest 7424 { 7425 { 7426 ushort start = 0, end = 10, step = 2; 7427 foreach (i; iota(start, end, step)) 7428 static assert(is(typeof(i) == ushort)); 7429 } 7430 { 7431 ubyte start = 0, end = 255, step = 128; 7432 uint x; 7433 foreach (i; iota(start, end, step)) 7434 { 7435 static assert(is(typeof(i) == ubyte)); 7436 ++x; 7437 } 7438 assert(x == 2); 7439 } 7440 } 7441 7442 /* Generic overload that handles arbitrary types that support arithmetic 7443 * operations. 7444 * 7445 * User-defined types such as $(REF BigInt, std,bigint) are also supported, as long 7446 * as they can be incremented with `++` and compared with `<` or `==`. 7447 */ 7448 /// ditto 7449 auto iota(B, E)(B begin, E end) 7450 if (!isIntegral!(CommonType!(B, E)) && 7451 !isFloatingPoint!(CommonType!(B, E)) && 7452 !isPointer!(CommonType!(B, E)) && 7453 is(typeof((ref B b) { ++b; })) && 7454 (is(typeof(B.init < E.init)) || is(typeof(B.init == E.init))) ) 7455 { 7456 static struct Result 7457 { 7458 B current; 7459 E end; 7460 7461 @property bool empty() 7462 { 7463 static if (is(typeof(B.init < E.init))) 7464 return !(current < end); 7465 else static if (is(typeof(B.init != E.init))) 7466 return current == end; 7467 else 7468 static assert(0); 7469 } 7470 @property auto front() { return current; } 7471 void popFront() 7472 { 7473 assert(!empty); 7474 ++current; 7475 } 7476 @property auto save() { return this; } 7477 } 7478 return Result(begin, end); 7479 } 7480 7481 @safe unittest 7482 { 7483 import std.algorithm.comparison : equal; 7484 7485 // Test iota() for a type that only supports ++ and != but does not have 7486 // '<'-ordering. 7487 struct Cyclic(int wrapAround) 7488 { 7489 int current; 7490 7491 this(int start) { current = start % wrapAround; } 7492 7493 bool opEquals(Cyclic c) const { return current == c.current; } 7494 bool opEquals(int i) const { return current == i; } 7495 void opUnary(string op)() 7496 if (op == "++") 7497 { 7498 current = (current + 1) % wrapAround; 7499 } 7500 } 7501 alias Cycle5 = Cyclic!5; 7502 7503 // Easy case 7504 auto i1 = iota(Cycle5(1), Cycle5(4)); 7505 assert(i1.equal([1, 2, 3])); 7506 7507 // Wraparound case 7508 auto i2 = iota(Cycle5(3), Cycle5(2)); 7509 assert(i2.equal([3, 4, 0, 1 ])); 7510 } 7511 7512 // https://issues.dlang.org/show_bug.cgi?id=23453 7513 @safe unittest 7514 { 7515 auto r = iota('a', 'z'); 7516 static assert(isForwardRange!(typeof(r))); 7517 } 7518 7519 /** 7520 Options for the $(LREF FrontTransversal) and $(LREF Transversal) ranges 7521 (below). 7522 */ 7523 enum TransverseOptions 7524 { 7525 /** 7526 When transversed, the elements of a range of ranges are assumed to 7527 have different lengths (e.g. a jagged array). 7528 */ 7529 assumeJagged, //default 7530 /** 7531 The transversal enforces that the elements of a range of ranges have 7532 all the same length (e.g. an array of arrays, all having the same 7533 length). Checking is done once upon construction of the transversal 7534 range. 7535 */ 7536 enforceNotJagged, 7537 /** 7538 The transversal assumes, without verifying, that the elements of a 7539 range of ranges have all the same length. This option is useful if 7540 checking was already done from the outside of the range. 7541 */ 7542 assumeNotJagged, 7543 } 7544 7545 /// 7546 @safe pure unittest 7547 { 7548 import std.algorithm.comparison : equal; 7549 import std.exception : assertThrown; 7550 7551 auto arr = [[1, 2], [3, 4, 5]]; 7552 7553 auto r1 = arr.frontTransversal!(TransverseOptions.assumeJagged); 7554 assert(r1.equal([1, 3])); 7555 7556 // throws on construction 7557 assertThrown!Exception(arr.frontTransversal!(TransverseOptions.enforceNotJagged)); 7558 7559 auto r2 = arr.frontTransversal!(TransverseOptions.assumeNotJagged); 7560 assert(r2.equal([1, 3])); 7561 7562 // either assuming or checking for equal lengths makes 7563 // the result a random access range 7564 assert(r2[0] == 1); 7565 static assert(!__traits(compiles, r1[0])); 7566 } 7567 7568 /** 7569 Given a range of ranges, iterate transversally through the first 7570 elements of each of the enclosed ranges. 7571 */ 7572 struct FrontTransversal(Ror, 7573 TransverseOptions opt = TransverseOptions.assumeJagged) 7574 { 7575 alias RangeOfRanges = Unqual!(Ror); 7576 alias RangeType = .ElementType!RangeOfRanges; 7577 alias ElementType = .ElementType!RangeType; 7578 7579 private void prime() 7580 { 7581 static if (opt == TransverseOptions.assumeJagged) 7582 { 7583 while (!_input.empty && _input.front.empty) 7584 { 7585 _input.popFront(); 7586 } 7587 static if (isBidirectionalRange!RangeOfRanges) 7588 { 7589 while (!_input.empty && _input.back.empty) 7590 { 7591 _input.popBack(); 7592 } 7593 } 7594 } 7595 } 7596 7597 /** 7598 Construction from an input. 7599 */ 7600 this(RangeOfRanges input) 7601 { 7602 _input = input; 7603 prime(); 7604 static if (opt == TransverseOptions.enforceNotJagged) 7605 // (isRandomAccessRange!RangeOfRanges 7606 // && hasLength!RangeType) 7607 { 7608 import std.exception : enforce; 7609 7610 if (empty) return; 7611 immutable commonLength = _input.front.length; 7612 foreach (e; _input) 7613 { 7614 enforce(e.length == commonLength); 7615 } 7616 } 7617 } 7618 7619 /** 7620 Forward range primitives. 7621 */ 7622 static if (isInfinite!RangeOfRanges) 7623 { 7624 enum bool empty = false; 7625 } 7626 else 7627 { 7628 @property bool empty() 7629 { 7630 static if (opt != TransverseOptions.assumeJagged) 7631 { 7632 if (!_input.empty) 7633 return _input.front.empty; 7634 } 7635 7636 return _input.empty; 7637 } 7638 } 7639 7640 /// Ditto 7641 @property auto ref front() 7642 { 7643 assert(!empty, "Attempting to fetch the front of an empty FrontTransversal"); 7644 return _input.front.front; 7645 } 7646 7647 /// Ditto 7648 static if (hasMobileElements!RangeType) 7649 { 7650 ElementType moveFront() 7651 { 7652 return _input.front.moveFront(); 7653 } 7654 } 7655 7656 static if (hasAssignableElements!RangeType) 7657 { 7658 @property void front(ElementType val) 7659 { 7660 import core.lifetime : forward; 7661 7662 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542 7663 _input.front.front = __ctfe ? val : forward!val; 7664 } 7665 } 7666 7667 /// Ditto 7668 void popFront() 7669 { 7670 assert(!empty, "Attempting to popFront an empty FrontTransversal"); 7671 _input.popFront(); 7672 prime(); 7673 } 7674 7675 /** 7676 Duplicates this `frontTransversal`. Note that only the encapsulating 7677 range of range will be duplicated. Underlying ranges will not be 7678 duplicated. 7679 */ 7680 static if (isForwardRange!RangeOfRanges) 7681 { 7682 @property FrontTransversal save() 7683 { 7684 return FrontTransversal(_input.save); 7685 } 7686 } 7687 7688 static if (isBidirectionalRange!RangeOfRanges) 7689 { 7690 /** 7691 Bidirectional primitives. They are offered if $(D 7692 isBidirectionalRange!RangeOfRanges). 7693 */ 7694 @property auto ref back() 7695 { 7696 assert(!empty, "Attempting to fetch the back of an empty FrontTransversal"); 7697 return _input.back.front; 7698 } 7699 /// Ditto 7700 void popBack() 7701 { 7702 assert(!empty, "Attempting to popBack an empty FrontTransversal"); 7703 _input.popBack(); 7704 prime(); 7705 } 7706 7707 /// Ditto 7708 static if (hasMobileElements!RangeType) 7709 { 7710 ElementType moveBack() 7711 { 7712 return _input.back.moveFront(); 7713 } 7714 } 7715 7716 static if (hasAssignableElements!RangeType) 7717 { 7718 @property void back(ElementType val) 7719 { 7720 import core.lifetime : forward; 7721 7722 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542 7723 _input.back.front = __ctfe ? val : forward!val; 7724 } 7725 } 7726 } 7727 7728 static if (isRandomAccessRange!RangeOfRanges && 7729 (opt == TransverseOptions.assumeNotJagged || 7730 opt == TransverseOptions.enforceNotJagged)) 7731 { 7732 /** 7733 Random-access primitive. It is offered if $(D 7734 isRandomAccessRange!RangeOfRanges && (opt == 7735 TransverseOptions.assumeNotJagged || opt == 7736 TransverseOptions.enforceNotJagged)). 7737 */ 7738 auto ref opIndex(size_t n) 7739 { 7740 return _input[n].front; 7741 } 7742 7743 /// Ditto 7744 static if (hasMobileElements!RangeType) 7745 { 7746 ElementType moveAt(size_t n) 7747 { 7748 return _input[n].moveFront(); 7749 } 7750 } 7751 /// Ditto 7752 static if (hasAssignableElements!RangeType) 7753 { 7754 void opIndexAssign(ElementType val, size_t n) 7755 { 7756 import core.lifetime : forward; 7757 7758 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542 7759 _input[n].front = __ctfe ? val : forward!val; 7760 } 7761 } 7762 mixin ImplementLength!_input; 7763 7764 /** 7765 Slicing if offered if `RangeOfRanges` supports slicing and all the 7766 conditions for supporting indexing are met. 7767 */ 7768 static if (hasSlicing!RangeOfRanges) 7769 { 7770 typeof(this) opSlice(size_t lower, size_t upper) 7771 { 7772 return typeof(this)(_input[lower .. upper]); 7773 } 7774 } 7775 } 7776 7777 auto opSlice() { return this; } 7778 7779 private: 7780 RangeOfRanges _input; 7781 } 7782 7783 /// Ditto 7784 FrontTransversal!(RangeOfRanges, opt) frontTransversal( 7785 TransverseOptions opt = TransverseOptions.assumeJagged, 7786 RangeOfRanges) 7787 (RangeOfRanges rr) 7788 { 7789 return typeof(return)(rr); 7790 } 7791 7792 /// 7793 pure @safe nothrow unittest 7794 { 7795 import std.algorithm.comparison : equal; 7796 int[][] x = new int[][2]; 7797 x[0] = [1, 2]; 7798 x[1] = [3, 4]; 7799 auto ror = frontTransversal(x); 7800 assert(equal(ror, [ 1, 3 ][])); 7801 } 7802 7803 @safe unittest 7804 { 7805 import std.algorithm.comparison : equal; 7806 import std.internal.test.dummyrange : AllDummyRanges, DummyRange, ReturnBy; 7807 7808 static assert(is(FrontTransversal!(immutable int[][]))); 7809 7810 foreach (DummyType; AllDummyRanges) 7811 { 7812 auto dummies = 7813 [DummyType.init, DummyType.init, DummyType.init, DummyType.init]; 7814 7815 foreach (i, ref elem; dummies) 7816 { 7817 // Just violate the DummyRange abstraction to get what I want. 7818 elem.arr = elem.arr[i..$ - (3 - i)]; 7819 } 7820 7821 auto ft = frontTransversal!(TransverseOptions.assumeNotJagged)(dummies); 7822 static if (isForwardRange!DummyType) 7823 { 7824 static assert(isForwardRange!(typeof(ft))); 7825 } 7826 7827 assert(equal(ft, [1, 2, 3, 4])); 7828 7829 // Test slicing. 7830 assert(equal(ft[0 .. 2], [1, 2])); 7831 assert(equal(ft[1 .. 3], [2, 3])); 7832 7833 assert(ft.front == ft.moveFront()); 7834 assert(ft.back == ft.moveBack()); 7835 assert(ft.moveAt(1) == ft[1]); 7836 7837 7838 // Test infiniteness propagation. 7839 static assert(isInfinite!(typeof(frontTransversal(repeat("foo"))))); 7840 7841 static if (DummyType.r == ReturnBy.Reference) 7842 { 7843 { 7844 ft.front++; 7845 scope(exit) ft.front--; 7846 assert(dummies.front.front == 2); 7847 } 7848 7849 { 7850 ft.front = 5; 7851 scope(exit) ft.front = 1; 7852 assert(dummies[0].front == 5); 7853 } 7854 7855 { 7856 ft.back = 88; 7857 scope(exit) ft.back = 4; 7858 assert(dummies.back.front == 88); 7859 } 7860 7861 { 7862 ft[1] = 99; 7863 scope(exit) ft[1] = 2; 7864 assert(dummies[1].front == 99); 7865 } 7866 } 7867 } 7868 } 7869 7870 // https://issues.dlang.org/show_bug.cgi?id=16363 7871 pure @safe nothrow unittest 7872 { 7873 import std.algorithm.comparison : equal; 7874 7875 int[][] darr = [[0, 1], [4, 5]]; 7876 auto ft = frontTransversal!(TransverseOptions.assumeNotJagged)(darr); 7877 7878 assert(equal(ft, [0, 4])); 7879 static assert(isRandomAccessRange!(typeof(ft))); 7880 } 7881 7882 // https://issues.dlang.org/show_bug.cgi?id=16442 7883 pure @safe nothrow unittest 7884 { 7885 int[][] arr = [[], []]; 7886 7887 auto ft = frontTransversal!(TransverseOptions.assumeNotJagged)(arr); 7888 assert(ft.empty); 7889 } 7890 7891 // ditto 7892 pure @safe unittest 7893 { 7894 int[][] arr = [[], []]; 7895 7896 auto ft = frontTransversal!(TransverseOptions.enforceNotJagged)(arr); 7897 assert(ft.empty); 7898 } 7899 7900 // https://issues.dlang.org/show_bug.cgi?id=24481 7901 @safe unittest 7902 { 7903 bool called; 7904 struct Handle 7905 { 7906 int entry; 7907 void opAssign()(auto ref const(typeof(this)) that) const { called = true; } 7908 } 7909 7910 const(Handle)[][] arr = [[Handle(0), Handle(10)], 7911 [Handle(1), Handle(11)], 7912 [Handle(2), Handle(12)], 7913 [Handle(3), Handle(13)], 7914 [Handle(4), Handle(14)]]; 7915 7916 { 7917 auto range = arr.frontTransversal(); 7918 7919 called = false; 7920 range.front = Handle(42); 7921 assert(called == true); 7922 7923 called = false; 7924 range.back = Handle(42); 7925 assert(called == true); 7926 } 7927 { 7928 auto range = arr.frontTransversal!(TransverseOptions.assumeNotJagged)(); 7929 7930 called = false; 7931 range.front = Handle(42); 7932 assert(called == true); 7933 7934 called = false; 7935 range.back = Handle(42); 7936 assert(called == true); 7937 7938 called = false; 7939 range[0] = Handle(42); 7940 assert(called == true); 7941 } 7942 } 7943 7944 /** 7945 Given a range of ranges, iterate transversally through the 7946 `n`th element of each of the enclosed ranges. This function 7947 is similar to `unzip` in other languages. 7948 7949 Params: 7950 opt = Controls the assumptions the function makes about the lengths 7951 of the ranges 7952 rr = An input range of random access ranges 7953 Returns: 7954 At minimum, an input range. Range primitives such as bidirectionality 7955 and random access are given if the element type of `rr` provides them. 7956 */ 7957 struct Transversal(Ror, 7958 TransverseOptions opt = TransverseOptions.assumeJagged) 7959 { 7960 private alias RangeOfRanges = Unqual!Ror; 7961 private alias InnerRange = ElementType!RangeOfRanges; 7962 private alias E = ElementType!InnerRange; 7963 7964 private void prime() 7965 { 7966 static if (opt == TransverseOptions.assumeJagged) 7967 { 7968 while (!_input.empty && _input.front.length <= _n) 7969 { 7970 _input.popFront(); 7971 } 7972 static if (isBidirectionalRange!RangeOfRanges) 7973 { 7974 while (!_input.empty && _input.back.length <= _n) 7975 { 7976 _input.popBack(); 7977 } 7978 } 7979 } 7980 } 7981 7982 /** 7983 Construction from an input and an index. 7984 */ 7985 this(RangeOfRanges input, size_t n) 7986 { 7987 _input = input; 7988 _n = n; 7989 prime(); 7990 static if (opt == TransverseOptions.enforceNotJagged) 7991 { 7992 import std.exception : enforce; 7993 7994 if (empty) return; 7995 immutable commonLength = _input.front.length; 7996 foreach (e; _input) 7997 { 7998 enforce(e.length == commonLength); 7999 } 8000 } 8001 } 8002 8003 /** 8004 Forward range primitives. 8005 */ 8006 static if (isInfinite!(RangeOfRanges)) 8007 { 8008 enum bool empty = false; 8009 } 8010 else 8011 { 8012 @property bool empty() 8013 { 8014 return _input.empty; 8015 } 8016 } 8017 8018 /// Ditto 8019 @property auto ref front() 8020 { 8021 assert(!empty, "Attempting to fetch the front of an empty Transversal"); 8022 return _input.front[_n]; 8023 } 8024 8025 /// Ditto 8026 static if (hasMobileElements!InnerRange) 8027 { 8028 E moveFront() 8029 { 8030 return _input.front.moveAt(_n); 8031 } 8032 } 8033 8034 /// Ditto 8035 static if (hasAssignableElements!InnerRange) 8036 { 8037 @property void front(E val) 8038 { 8039 _input.front[_n] = val; 8040 } 8041 } 8042 8043 8044 /// Ditto 8045 void popFront() 8046 { 8047 assert(!empty, "Attempting to popFront an empty Transversal"); 8048 _input.popFront(); 8049 prime(); 8050 } 8051 8052 /// Ditto 8053 static if (isForwardRange!RangeOfRanges) 8054 { 8055 @property typeof(this) save() 8056 { 8057 auto ret = this; 8058 ret._input = _input.save; 8059 return ret; 8060 } 8061 } 8062 8063 static if (isBidirectionalRange!RangeOfRanges) 8064 { 8065 /** 8066 Bidirectional primitives. They are offered if $(D 8067 isBidirectionalRange!RangeOfRanges). 8068 */ 8069 @property auto ref back() 8070 { 8071 assert(!empty, "Attempting to fetch the back of an empty Transversal"); 8072 return _input.back[_n]; 8073 } 8074 8075 /// Ditto 8076 void popBack() 8077 { 8078 assert(!empty, "Attempting to popBack an empty Transversal"); 8079 _input.popBack(); 8080 prime(); 8081 } 8082 8083 /// Ditto 8084 static if (hasMobileElements!InnerRange) 8085 { 8086 E moveBack() 8087 { 8088 return _input.back.moveAt(_n); 8089 } 8090 } 8091 8092 /// Ditto 8093 static if (hasAssignableElements!InnerRange) 8094 { 8095 @property void back(E val) 8096 { 8097 _input.back[_n] = val; 8098 } 8099 } 8100 8101 } 8102 8103 static if (isRandomAccessRange!RangeOfRanges && 8104 (opt == TransverseOptions.assumeNotJagged || 8105 opt == TransverseOptions.enforceNotJagged)) 8106 { 8107 /** 8108 Random-access primitive. It is offered if $(D 8109 isRandomAccessRange!RangeOfRanges && (opt == 8110 TransverseOptions.assumeNotJagged || opt == 8111 TransverseOptions.enforceNotJagged)). 8112 */ 8113 auto ref opIndex(size_t n) 8114 { 8115 return _input[n][_n]; 8116 } 8117 8118 /// Ditto 8119 static if (hasMobileElements!InnerRange) 8120 { 8121 E moveAt(size_t n) 8122 { 8123 return _input[n].moveAt(_n); 8124 } 8125 } 8126 8127 /// Ditto 8128 static if (hasAssignableElements!InnerRange) 8129 { 8130 void opIndexAssign(E val, size_t n) 8131 { 8132 _input[n][_n] = val; 8133 } 8134 } 8135 8136 mixin ImplementLength!_input; 8137 8138 /** 8139 Slicing if offered if `RangeOfRanges` supports slicing and all the 8140 conditions for supporting indexing are met. 8141 */ 8142 static if (hasSlicing!RangeOfRanges) 8143 { 8144 typeof(this) opSlice(size_t lower, size_t upper) 8145 { 8146 return typeof(this)(_input[lower .. upper], _n); 8147 } 8148 } 8149 } 8150 8151 auto opSlice() { return this; } 8152 8153 private: 8154 RangeOfRanges _input; 8155 size_t _n; 8156 } 8157 8158 /// Ditto 8159 Transversal!(RangeOfRanges, opt) transversal 8160 (TransverseOptions opt = TransverseOptions.assumeJagged, RangeOfRanges) 8161 (RangeOfRanges rr, size_t n) 8162 { 8163 return typeof(return)(rr, n); 8164 } 8165 8166 /// 8167 @safe unittest 8168 { 8169 import std.algorithm.comparison : equal; 8170 int[][] x = new int[][2]; 8171 x[0] = [1, 2]; 8172 x[1] = [3, 4]; 8173 auto ror = transversal(x, 1); 8174 assert(equal(ror, [ 2, 4 ])); 8175 } 8176 8177 /// The following code does a full unzip 8178 @safe unittest 8179 { 8180 import std.algorithm.comparison : equal; 8181 import std.algorithm.iteration : map; 8182 int[][] y = [[1, 2, 3], [4, 5, 6]]; 8183 auto z = y.front.walkLength.iota.map!(i => transversal(y, i)); 8184 assert(equal!equal(z, [[1, 4], [2, 5], [3, 6]])); 8185 } 8186 8187 @safe unittest 8188 { 8189 import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy; 8190 8191 int[][] x = new int[][2]; 8192 x[0] = [ 1, 2 ]; 8193 x[1] = [3, 4]; 8194 auto ror = transversal!(TransverseOptions.assumeNotJagged)(x, 1); 8195 auto witness = [ 2, 4 ]; 8196 uint i; 8197 foreach (e; ror) assert(e == witness[i++]); 8198 assert(i == 2); 8199 assert(ror.length == 2); 8200 8201 static assert(is(Transversal!(immutable int[][]))); 8202 8203 // Make sure ref, assign is being propagated. 8204 { 8205 ror.front++; 8206 scope(exit) ror.front--; 8207 assert(x[0][1] == 3); 8208 } 8209 { 8210 ror.front = 5; 8211 scope(exit) ror.front = 2; 8212 assert(x[0][1] == 5); 8213 assert(ror.moveFront() == 5); 8214 } 8215 { 8216 ror.back = 999; 8217 scope(exit) ror.back = 4; 8218 assert(x[1][1] == 999); 8219 assert(ror.moveBack() == 999); 8220 } 8221 { 8222 ror[0] = 999; 8223 scope(exit) ror[0] = 2; 8224 assert(x[0][1] == 999); 8225 assert(ror.moveAt(0) == 999); 8226 } 8227 8228 // Test w/o ref return. 8229 alias D = DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random); 8230 auto drs = [D.init, D.init]; 8231 foreach (num; 0 .. 10) 8232 { 8233 auto t = transversal!(TransverseOptions.enforceNotJagged)(drs, num); 8234 assert(t[0] == t[1]); 8235 assert(t[1] == num + 1); 8236 } 8237 8238 static assert(isInfinite!(typeof(transversal(repeat([1,2,3]), 1)))); 8239 8240 // Test slicing. 8241 auto mat = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]; 8242 auto mat1 = transversal!(TransverseOptions.assumeNotJagged)(mat, 1)[1 .. 3]; 8243 assert(mat1[0] == 6); 8244 assert(mat1[1] == 10); 8245 } 8246 8247 struct Transposed(RangeOfRanges, 8248 TransverseOptions opt = TransverseOptions.assumeJagged) 8249 if (isForwardRange!RangeOfRanges && 8250 isInputRange!(ElementType!RangeOfRanges) && 8251 hasAssignableElements!RangeOfRanges) 8252 { 8253 this(RangeOfRanges input) 8254 { 8255 this._input = input; 8256 static if (opt == TransverseOptions.enforceNotJagged) 8257 { 8258 import std.exception : enforce; 8259 8260 if (empty) return; 8261 immutable commonLength = _input.front.length; 8262 foreach (e; _input) 8263 { 8264 enforce(e.length == commonLength); 8265 } 8266 } 8267 } 8268 8269 @property auto front() 8270 { 8271 import std.algorithm.iteration : filter, map; 8272 return _input.save 8273 .filter!(a => !a.empty) 8274 .map!(a => a.front); 8275 } 8276 8277 void popFront() 8278 { 8279 // Advance the position of each subrange. 8280 auto r = _input.save; 8281 while (!r.empty) 8282 { 8283 auto e = r.front; 8284 if (!e.empty) 8285 { 8286 e.popFront(); 8287 r.front = e; 8288 } 8289 8290 r.popFront(); 8291 } 8292 } 8293 8294 static if (isRandomAccessRange!(ElementType!RangeOfRanges)) 8295 { 8296 auto ref opIndex(size_t n) 8297 { 8298 return transversal!opt(_input, n); 8299 } 8300 } 8301 8302 @property bool empty() 8303 { 8304 if (_input.empty) return true; 8305 foreach (e; _input.save) 8306 { 8307 if (!e.empty) return false; 8308 } 8309 return true; 8310 } 8311 8312 auto opSlice() { return this; } 8313 8314 private: 8315 RangeOfRanges _input; 8316 } 8317 8318 @safe unittest 8319 { 8320 // Boundary case: transpose of empty range should be empty 8321 int[][] ror = []; 8322 assert(transposed(ror).empty); 8323 } 8324 8325 // https://issues.dlang.org/show_bug.cgi?id=9507 8326 @safe unittest 8327 { 8328 import std.algorithm.comparison : equal; 8329 8330 auto r = [[1,2], [3], [4,5], [], [6]]; 8331 assert(r.transposed.equal!equal([ 8332 [1, 3, 4, 6], 8333 [2, 5] 8334 ])); 8335 } 8336 8337 // https://issues.dlang.org/show_bug.cgi?id=17742 8338 @safe unittest 8339 { 8340 import std.algorithm.iteration : map; 8341 import std.algorithm.comparison : equal; 8342 auto ror = 5.iota.map!(y => 5.iota.map!(x => x * y).array).array; 8343 assert(ror[3][2] == 6); 8344 auto result = transposed!(TransverseOptions.assumeNotJagged)(ror); 8345 assert(result[2][3] == 6); 8346 8347 auto x = [[1,2,3],[4,5,6]]; 8348 auto y = transposed!(TransverseOptions.assumeNotJagged)(x); 8349 assert(y.front.equal([1,4])); 8350 assert(y[0].equal([1,4])); 8351 assert(y[0][0] == 1); 8352 assert(y[1].equal([2,5])); 8353 assert(y[1][1] == 5); 8354 8355 auto yy = transposed!(TransverseOptions.enforceNotJagged)(x); 8356 assert(yy.front.equal([1,4])); 8357 assert(yy[0].equal([1,4])); 8358 assert(yy[0][0] == 1); 8359 assert(yy[1].equal([2,5])); 8360 assert(yy[1][1] == 5); 8361 8362 auto z = x.transposed; // assumeJagged 8363 assert(z.front.equal([1,4])); 8364 assert(z[0].equal([1,4])); 8365 assert(!is(typeof(z[0][0]))); 8366 } 8367 8368 @safe unittest 8369 { 8370 import std.exception : assertThrown; 8371 8372 auto r = [[1,2], [3], [4,5], [], [6]]; 8373 assertThrown(r.transposed!(TransverseOptions.enforceNotJagged)); 8374 } 8375 8376 /** 8377 Given a range of ranges, returns a range of ranges where the $(I i)'th subrange 8378 contains the $(I i)'th elements of the original subranges. 8379 8380 Params: 8381 opt = Controls the assumptions the function makes about the lengths of the ranges (i.e. jagged or not) 8382 rr = Range of ranges 8383 */ 8384 Transposed!(RangeOfRanges, opt) transposed 8385 (TransverseOptions opt = TransverseOptions.assumeJagged, RangeOfRanges) 8386 (RangeOfRanges rr) 8387 if (isForwardRange!RangeOfRanges && 8388 isInputRange!(ElementType!RangeOfRanges) && 8389 hasAssignableElements!RangeOfRanges) 8390 { 8391 return Transposed!(RangeOfRanges, opt)(rr); 8392 } 8393 8394 /// 8395 @safe unittest 8396 { 8397 import std.algorithm.comparison : equal; 8398 int[][] ror = [ 8399 [1, 2, 3], 8400 [4, 5, 6] 8401 ]; 8402 auto xp = transposed(ror); 8403 assert(equal!"a.equal(b)"(xp, [ 8404 [1, 4], 8405 [2, 5], 8406 [3, 6] 8407 ])); 8408 } 8409 8410 /// 8411 @safe unittest 8412 { 8413 int[][] x = new int[][2]; 8414 x[0] = [1, 2]; 8415 x[1] = [3, 4]; 8416 auto tr = transposed(x); 8417 int[][] witness = [ [ 1, 3 ], [ 2, 4 ] ]; 8418 uint i; 8419 8420 foreach (e; tr) 8421 { 8422 assert(array(e) == witness[i++]); 8423 } 8424 } 8425 8426 // https://issues.dlang.org/show_bug.cgi?id=8764 8427 @safe unittest 8428 { 8429 import std.algorithm.comparison : equal; 8430 ulong[] t0 = [ 123 ]; 8431 8432 assert(!hasAssignableElements!(typeof(t0[].chunks(1)))); 8433 assert(!is(typeof(transposed(t0[].chunks(1))))); 8434 assert(is(typeof(transposed(t0[].chunks(1).array())))); 8435 8436 auto t1 = transposed(t0[].chunks(1).array()); 8437 assert(equal!"a.equal(b)"(t1, [[123]])); 8438 } 8439 8440 /** 8441 This struct takes two ranges, `source` and `indices`, and creates a view 8442 of `source` as if its elements were reordered according to `indices`. 8443 `indices` may include only a subset of the elements of `source` and 8444 may also repeat elements. 8445 8446 `Source` must be a random access range. The returned range will be 8447 bidirectional or random-access if `Indices` is bidirectional or 8448 random-access, respectively. 8449 */ 8450 struct Indexed(Source, Indices) 8451 if (isRandomAccessRange!Source && isInputRange!Indices && 8452 is(typeof(Source.init[ElementType!(Indices).init]))) 8453 { 8454 this(Source source, Indices indices) 8455 { 8456 this._source = source; 8457 this._indices = indices; 8458 } 8459 8460 /// Range primitives 8461 @property auto ref front() 8462 { 8463 assert(!empty, "Attempting to fetch the front of an empty Indexed"); 8464 return _source[_indices.front]; 8465 } 8466 8467 /// Ditto 8468 void popFront() 8469 { 8470 assert(!empty, "Attempting to popFront an empty Indexed"); 8471 _indices.popFront(); 8472 } 8473 8474 static if (isInfinite!Indices) 8475 { 8476 enum bool empty = false; 8477 } 8478 else 8479 { 8480 /// Ditto 8481 @property bool empty() 8482 { 8483 return _indices.empty; 8484 } 8485 } 8486 8487 static if (isForwardRange!Indices) 8488 { 8489 /// Ditto 8490 @property typeof(this) save() 8491 { 8492 // Don't need to save _source because it's never consumed. 8493 return typeof(this)(_source, _indices.save); 8494 } 8495 } 8496 8497 /// Ditto 8498 static if (hasAssignableElements!Source) 8499 { 8500 @property auto ref front(ElementType!Source newVal) 8501 { 8502 assert(!empty); 8503 return _source[_indices.front] = newVal; 8504 } 8505 } 8506 8507 8508 static if (hasMobileElements!Source) 8509 { 8510 /// Ditto 8511 auto moveFront() 8512 { 8513 assert(!empty); 8514 return _source.moveAt(_indices.front); 8515 } 8516 } 8517 8518 static if (isBidirectionalRange!Indices) 8519 { 8520 /// Ditto 8521 @property auto ref back() 8522 { 8523 assert(!empty, "Attempting to fetch the back of an empty Indexed"); 8524 return _source[_indices.back]; 8525 } 8526 8527 /// Ditto 8528 void popBack() 8529 { 8530 assert(!empty, "Attempting to popBack an empty Indexed"); 8531 _indices.popBack(); 8532 } 8533 8534 /// Ditto 8535 static if (hasAssignableElements!Source) 8536 { 8537 @property auto ref back(ElementType!Source newVal) 8538 { 8539 assert(!empty); 8540 return _source[_indices.back] = newVal; 8541 } 8542 } 8543 8544 8545 static if (hasMobileElements!Source) 8546 { 8547 /// Ditto 8548 auto moveBack() 8549 { 8550 assert(!empty); 8551 return _source.moveAt(_indices.back); 8552 } 8553 } 8554 } 8555 8556 mixin ImplementLength!_indices; 8557 8558 static if (isRandomAccessRange!Indices) 8559 { 8560 /// Ditto 8561 auto ref opIndex(size_t index) 8562 { 8563 return _source[_indices[index]]; 8564 } 8565 8566 static if (hasSlicing!Indices) 8567 { 8568 /// Ditto 8569 typeof(this) opSlice(size_t a, size_t b) 8570 { 8571 return typeof(this)(_source, _indices[a .. b]); 8572 } 8573 } 8574 8575 8576 static if (hasAssignableElements!Source) 8577 { 8578 /// Ditto 8579 auto opIndexAssign(ElementType!Source newVal, size_t index) 8580 { 8581 return _source[_indices[index]] = newVal; 8582 } 8583 } 8584 8585 8586 static if (hasMobileElements!Source) 8587 { 8588 /// Ditto 8589 auto moveAt(size_t index) 8590 { 8591 return _source.moveAt(_indices[index]); 8592 } 8593 } 8594 } 8595 8596 // All this stuff is useful if someone wants to index an Indexed 8597 // without adding a layer of indirection. 8598 8599 /** 8600 Returns the source range. 8601 */ 8602 @property Source source() 8603 { 8604 return _source; 8605 } 8606 8607 /** 8608 Returns the indices range. 8609 */ 8610 @property Indices indices() 8611 { 8612 return _indices; 8613 } 8614 8615 static if (isRandomAccessRange!Indices) 8616 { 8617 /** 8618 Returns the physical index into the source range corresponding to a 8619 given logical index. This is useful, for example, when indexing 8620 an `Indexed` without adding another layer of indirection. 8621 */ 8622 size_t physicalIndex(size_t logicalIndex) 8623 { 8624 return _indices[logicalIndex]; 8625 } 8626 8627 /// 8628 @safe unittest 8629 { 8630 auto ind = indexed([1, 2, 3, 4, 5], [1, 3, 4]); 8631 assert(ind.physicalIndex(0) == 1); 8632 } 8633 } 8634 8635 private: 8636 Source _source; 8637 Indices _indices; 8638 8639 } 8640 8641 /// Ditto 8642 Indexed!(Source, Indices) indexed(Source, Indices)(Source source, Indices indices) 8643 { 8644 return typeof(return)(source, indices); 8645 } 8646 8647 /// 8648 @safe unittest 8649 { 8650 import std.algorithm.comparison : equal; 8651 auto source = [1, 2, 3, 4, 5]; 8652 auto indices = [4, 3, 1, 2, 0, 4]; 8653 auto ind = indexed(source, indices); 8654 assert(equal(ind, [5, 4, 2, 3, 1, 5])); 8655 assert(equal(retro(ind), [5, 1, 3, 2, 4, 5])); 8656 } 8657 8658 @safe unittest 8659 { 8660 { 8661 auto ind = indexed([1, 2, 3, 4, 5], [1, 3, 4]); 8662 assert(ind.physicalIndex(0) == 1); 8663 } 8664 8665 auto source = [1, 2, 3, 4, 5]; 8666 auto indices = [4, 3, 1, 2, 0, 4]; 8667 auto ind = indexed(source, indices); 8668 8669 // When elements of indices are duplicated and Source has lvalue elements, 8670 // these are aliased in ind. 8671 ind[0]++; 8672 assert(ind[0] == 6); 8673 assert(ind[5] == 6); 8674 } 8675 8676 @safe unittest 8677 { 8678 import std.internal.test.dummyrange : AllDummyRanges, propagatesLength, 8679 propagatesRangeType, RangeType; 8680 8681 foreach (DummyType; AllDummyRanges) 8682 { 8683 auto d = DummyType.init; 8684 auto r = indexed([1, 2, 3, 4, 5], d); 8685 static assert(propagatesRangeType!(DummyType, typeof(r))); 8686 static assert(propagatesLength!(DummyType, typeof(r))); 8687 } 8688 } 8689 8690 /** 8691 This range iterates over fixed-sized chunks of size `chunkSize` of a 8692 `source` range. `Source` must be an $(REF_ALTTEXT input range, isInputRange, std,range,primitives). 8693 `chunkSize` must be greater than zero. 8694 8695 If `!isInfinite!Source` and `source.walkLength` is not evenly 8696 divisible by `chunkSize`, the back element of this range will contain 8697 fewer than `chunkSize` elements. 8698 8699 If `Source` is a forward range, the resulting range will be forward ranges as 8700 well. Otherwise, the resulting chunks will be input ranges consuming the same 8701 input: iterating over `front` will shrink the chunk such that subsequent 8702 invocations of `front` will no longer return the full chunk, and calling 8703 `popFront` on the outer range will invalidate any lingering references to 8704 previous values of `front`. 8705 8706 Params: 8707 source = Range from which the chunks will be selected 8708 chunkSize = Chunk size 8709 8710 See_Also: $(LREF slide) 8711 8712 Returns: Range of chunks. 8713 */ 8714 struct Chunks(Source) 8715 if (isInputRange!Source) 8716 { 8717 static if (isForwardRange!Source) 8718 { 8719 /// Standard constructor 8720 this(Source source, size_t chunkSize) 8721 { 8722 assert(chunkSize != 0, "Cannot create a Chunk with an empty chunkSize"); 8723 _source = source; 8724 _chunkSize = chunkSize; 8725 } 8726 8727 /// Input range primitives. Always present. 8728 @property auto front() 8729 { 8730 assert(!empty, "Attempting to fetch the front of an empty Chunks"); 8731 return _source.save.take(_chunkSize); 8732 } 8733 8734 /// Ditto 8735 void popFront() 8736 { 8737 assert(!empty, "Attempting to popFront and empty Chunks"); 8738 _source.popFrontN(_chunkSize); 8739 } 8740 8741 static if (!isInfinite!Source) 8742 /// Ditto 8743 @property bool empty() 8744 { 8745 return _source.empty; 8746 } 8747 else 8748 // undocumented 8749 enum empty = false; 8750 8751 /// Forward range primitives. Only present if `Source` is a forward range. 8752 @property typeof(this) save() 8753 { 8754 return typeof(this)(_source.save, _chunkSize); 8755 } 8756 8757 static if (hasLength!Source) 8758 { 8759 /// Length. Only if `hasLength!Source` is `true` 8760 @property size_t length() 8761 { 8762 // Note: _source.length + _chunkSize may actually overflow. 8763 // We cast to ulong to mitigate the problem on x86 machines. 8764 // For x64 machines, we just suppose we'll never overflow. 8765 // The "safe" code would require either an extra branch, or a 8766 // modulo operation, which is too expensive for such a rare case 8767 return cast(size_t)((cast(ulong)(_source.length) + _chunkSize - 1) / _chunkSize); 8768 } 8769 //Note: No point in defining opDollar here without slicing. 8770 //opDollar is defined below in the hasSlicing!Source section 8771 } 8772 8773 static if (hasSlicing!Source) 8774 { 8775 //Used for various purposes 8776 private enum hasSliceToEnd = is(typeof(Source.init[_chunkSize .. $]) == Source); 8777 8778 /** 8779 Indexing and slicing operations. Provided only if 8780 `hasSlicing!Source` is `true`. 8781 */ 8782 auto opIndex(size_t index) 8783 { 8784 immutable start = index * _chunkSize; 8785 immutable end = start + _chunkSize; 8786 8787 static if (isInfinite!Source) 8788 return _source[start .. end]; 8789 else 8790 { 8791 import std.algorithm.comparison : min; 8792 immutable len = _source.length; 8793 assert(start < len, "chunks index out of bounds"); 8794 return _source[start .. min(end, len)]; 8795 } 8796 } 8797 8798 /// Ditto 8799 static if (hasLength!Source) 8800 typeof(this) opSlice(size_t lower, size_t upper) 8801 { 8802 import std.algorithm.comparison : min; 8803 assert(lower <= upper && upper <= length, "chunks slicing index out of bounds"); 8804 immutable len = _source.length; 8805 return chunks(_source[min(lower * _chunkSize, len) .. min(upper * _chunkSize, len)], _chunkSize); 8806 } 8807 else static if (hasSliceToEnd) 8808 //For slicing an infinite chunk, we need to slice the source to the end. 8809 typeof(takeExactly(this, 0)) opSlice(size_t lower, size_t upper) 8810 { 8811 assert(lower <= upper, "chunks slicing index out of bounds"); 8812 return chunks(_source[lower * _chunkSize .. $], _chunkSize).takeExactly(upper - lower); 8813 } 8814 8815 static if (isInfinite!Source) 8816 { 8817 static if (hasSliceToEnd) 8818 { 8819 private static struct DollarToken{} 8820 DollarToken opDollar() 8821 { 8822 return DollarToken(); 8823 } 8824 //Slice to dollar 8825 typeof(this) opSlice(size_t lower, DollarToken) 8826 { 8827 return typeof(this)(_source[lower * _chunkSize .. $], _chunkSize); 8828 } 8829 } 8830 } 8831 else 8832 { 8833 //Dollar token carries a static type, with no extra information. 8834 //It can lazily transform into _source.length on algorithmic 8835 //operations such as : chunks[$/2, $-1]; 8836 private static struct DollarToken 8837 { 8838 Chunks!Source* mom; 8839 @property size_t momLength() 8840 { 8841 return mom.length; 8842 } 8843 alias momLength this; 8844 } 8845 DollarToken opDollar() 8846 { 8847 return DollarToken(&this); 8848 } 8849 8850 //Slice overloads optimized for using dollar. Without this, to slice to end, we would... 8851 //1. Evaluate chunks.length 8852 //2. Multiply by _chunksSize 8853 //3. To finally just compare it (with min) to the original length of source (!) 8854 //These overloads avoid that. 8855 typeof(this) opSlice(DollarToken, DollarToken) 8856 { 8857 static if (hasSliceToEnd) 8858 return chunks(_source[$ .. $], _chunkSize); 8859 else 8860 { 8861 immutable len = _source.length; 8862 return chunks(_source[len .. len], _chunkSize); 8863 } 8864 } 8865 typeof(this) opSlice(size_t lower, DollarToken) 8866 { 8867 import std.algorithm.comparison : min; 8868 assert(lower <= length, "chunks slicing index out of bounds"); 8869 static if (hasSliceToEnd) 8870 return chunks(_source[min(lower * _chunkSize, _source.length) .. $], _chunkSize); 8871 else 8872 { 8873 immutable len = _source.length; 8874 return chunks(_source[min(lower * _chunkSize, len) .. len], _chunkSize); 8875 } 8876 } 8877 typeof(this) opSlice(DollarToken, size_t upper) 8878 { 8879 assert(upper == length, "chunks slicing index out of bounds"); 8880 return this[$ .. $]; 8881 } 8882 } 8883 } 8884 8885 //Bidirectional range primitives 8886 static if (hasSlicing!Source && hasLength!Source) 8887 { 8888 /** 8889 Bidirectional range primitives. Provided only if both 8890 `hasSlicing!Source` and `hasLength!Source` are `true`. 8891 */ 8892 @property auto back() 8893 { 8894 assert(!empty, "back called on empty chunks"); 8895 immutable len = _source.length; 8896 immutable start = (len - 1) / _chunkSize * _chunkSize; 8897 return _source[start .. len]; 8898 } 8899 8900 /// Ditto 8901 void popBack() 8902 { 8903 assert(!empty, "popBack() called on empty chunks"); 8904 immutable end = (_source.length - 1) / _chunkSize * _chunkSize; 8905 _source = _source[0 .. end]; 8906 } 8907 } 8908 8909 private: 8910 Source _source; 8911 size_t _chunkSize; 8912 } 8913 else // is input range only 8914 { 8915 import std.typecons : RefCounted; 8916 8917 static struct Chunk 8918 { 8919 private RefCounted!Impl impl; 8920 8921 @property bool empty() { return impl.curSizeLeft == 0 || impl.r.empty; } 8922 @property auto front() { return impl.r.front; } 8923 void popFront() 8924 { 8925 assert(impl.curSizeLeft > 0 && !impl.r.empty); 8926 impl.curSizeLeft--; 8927 impl.r.popFront(); 8928 } 8929 } 8930 8931 static struct Impl 8932 { 8933 private Source r; 8934 private size_t chunkSize; 8935 private size_t curSizeLeft; 8936 } 8937 8938 private RefCounted!Impl impl; 8939 8940 private this(Source r, size_t chunkSize) 8941 { 8942 impl = RefCounted!Impl(r, r.empty ? 0 : chunkSize, chunkSize); 8943 } 8944 8945 @property bool empty() { return impl.chunkSize == 0; } 8946 @property Chunk front() return { return Chunk(impl); } 8947 8948 void popFront() 8949 { 8950 impl.curSizeLeft -= impl.r.popFrontN(impl.curSizeLeft); 8951 if (!impl.r.empty) 8952 impl.curSizeLeft = impl.chunkSize; 8953 else 8954 impl.chunkSize = 0; 8955 } 8956 8957 static assert(isInputRange!(typeof(this))); 8958 } 8959 } 8960 8961 /// Ditto 8962 Chunks!Source chunks(Source)(Source source, size_t chunkSize) 8963 if (isInputRange!Source) 8964 { 8965 return typeof(return)(source, chunkSize); 8966 } 8967 8968 /// 8969 @safe unittest 8970 { 8971 import std.algorithm.comparison : equal; 8972 auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 8973 auto chunks = chunks(source, 4); 8974 assert(chunks[0] == [1, 2, 3, 4]); 8975 assert(chunks[1] == [5, 6, 7, 8]); 8976 assert(chunks[2] == [9, 10]); 8977 assert(chunks.back == chunks[2]); 8978 assert(chunks.front == chunks[0]); 8979 assert(chunks.length == 3); 8980 assert(equal(retro(array(chunks)), array(retro(chunks)))); 8981 } 8982 8983 /// Non-forward input ranges are supported, but with limited semantics. 8984 @system /*@safe*/ unittest // FIXME: can't be @safe because RefCounted isn't. 8985 { 8986 import std.algorithm.comparison : equal; 8987 8988 int i; 8989 8990 // The generator doesn't save state, so it cannot be a forward range. 8991 auto inputRange = generate!(() => ++i).take(10); 8992 8993 // We can still process it in chunks, but it will be single-pass only. 8994 auto chunked = inputRange.chunks(2); 8995 8996 assert(chunked.front.equal([1, 2])); 8997 assert(chunked.front.empty); // Iterating the chunk has consumed it 8998 chunked.popFront; 8999 assert(chunked.front.equal([3, 4])); 9000 } 9001 9002 @system /*@safe*/ unittest 9003 { 9004 import std.algorithm.comparison : equal; 9005 import std.internal.test.dummyrange : ReferenceInputRange; 9006 9007 auto data = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; 9008 auto r = new ReferenceInputRange!int(data).chunks(3); 9009 assert(r.equal!equal([ 9010 [ 1, 2, 3 ], 9011 [ 4, 5, 6 ], 9012 [ 7, 8, 9 ], 9013 [ 10 ] 9014 ])); 9015 9016 auto data2 = [ 1, 2, 3, 4, 5, 6 ]; 9017 auto r2 = new ReferenceInputRange!int(data2).chunks(3); 9018 assert(r2.equal!equal([ 9019 [ 1, 2, 3 ], 9020 [ 4, 5, 6 ] 9021 ])); 9022 9023 auto data3 = [ 1, 2, 3, 4, 5 ]; 9024 auto r3 = new ReferenceInputRange!int(data3).chunks(2); 9025 assert(r3.front.equal([1, 2])); 9026 r3.popFront(); 9027 assert(!r3.empty); 9028 r3.popFront(); 9029 assert(r3.front.equal([5])); 9030 } 9031 9032 @safe unittest 9033 { 9034 auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 9035 auto chunks = chunks(source, 4); 9036 auto chunks2 = chunks.save; 9037 chunks.popFront(); 9038 assert(chunks[0] == [5, 6, 7, 8]); 9039 assert(chunks[1] == [9, 10]); 9040 chunks2.popBack(); 9041 assert(chunks2[1] == [5, 6, 7, 8]); 9042 assert(chunks2.length == 2); 9043 9044 static assert(isRandomAccessRange!(typeof(chunks))); 9045 } 9046 9047 @safe unittest 9048 { 9049 import std.algorithm.comparison : equal; 9050 9051 //Extra toying with slicing and indexing. 9052 auto chunks1 = [0, 0, 1, 1, 2, 2, 3, 3, 4].chunks(2); 9053 auto chunks2 = [0, 0, 1, 1, 2, 2, 3, 3, 4, 4].chunks(2); 9054 9055 assert(chunks1.length == 5); 9056 assert(chunks2.length == 5); 9057 assert(chunks1[4] == [4]); 9058 assert(chunks2[4] == [4, 4]); 9059 assert(chunks1.back == [4]); 9060 assert(chunks2.back == [4, 4]); 9061 9062 assert(chunks1[0 .. 1].equal([[0, 0]])); 9063 assert(chunks1[0 .. 2].equal([[0, 0], [1, 1]])); 9064 assert(chunks1[4 .. 5].equal([[4]])); 9065 assert(chunks2[4 .. 5].equal([[4, 4]])); 9066 9067 assert(chunks1[0 .. 0].equal((int[][]).init)); 9068 assert(chunks1[5 .. 5].equal((int[][]).init)); 9069 assert(chunks2[5 .. 5].equal((int[][]).init)); 9070 9071 //Fun with opDollar 9072 assert(chunks1[$ .. $].equal((int[][]).init)); //Quick 9073 assert(chunks2[$ .. $].equal((int[][]).init)); //Quick 9074 assert(chunks1[$ - 1 .. $].equal([[4]])); //Semiquick 9075 assert(chunks2[$ - 1 .. $].equal([[4, 4]])); //Semiquick 9076 assert(chunks1[$ .. 5].equal((int[][]).init)); //Semiquick 9077 assert(chunks2[$ .. 5].equal((int[][]).init)); //Semiquick 9078 9079 assert(chunks1[$ / 2 .. $ - 1].equal([[2, 2], [3, 3]])); //Slow 9080 } 9081 9082 @safe unittest 9083 { 9084 import std.algorithm.comparison : equal; 9085 import std.algorithm.iteration : filter; 9086 9087 //ForwardRange 9088 auto r = filter!"true"([1, 2, 3, 4, 5]).chunks(2); 9089 assert(equal!"equal(a, b)"(r, [[1, 2], [3, 4], [5]])); 9090 9091 //InfiniteRange w/o RA 9092 auto fibsByPairs = recurrence!"a[n-1] + a[n-2]"(1, 1).chunks(2); 9093 assert(equal!`equal(a, b)`(fibsByPairs.take(2), [[ 1, 1], [ 2, 3]])); 9094 9095 //InfiniteRange w/ RA and slicing 9096 auto odds = sequence!("a[0] + n * a[1]")(1, 2); 9097 auto oddsByPairs = odds.chunks(2); 9098 assert(equal!`equal(a, b)`(oddsByPairs.take(2), [[ 1, 3], [ 5, 7]])); 9099 9100 //Requires phobos#991 for Sequence to have slice to end 9101 static assert(hasSlicing!(typeof(odds))); 9102 assert(equal!`equal(a, b)`(oddsByPairs[3 .. 5], [[13, 15], [17, 19]])); 9103 assert(equal!`equal(a, b)`(oddsByPairs[3 .. $].take(2), [[13, 15], [17, 19]])); 9104 } 9105 9106 9107 9108 /** 9109 This range splits a `source` range into `chunkCount` chunks of 9110 approximately equal length. `Source` must be a forward range with 9111 known length. 9112 9113 Unlike $(LREF chunks), `evenChunks` takes a chunk count (not size). 9114 The returned range will contain zero or more $(D source.length / 9115 chunkCount + 1) elements followed by $(D source.length / chunkCount) 9116 elements. If $(D source.length < chunkCount), some chunks will be empty. 9117 9118 `chunkCount` must not be zero, unless `source` is also empty. 9119 */ 9120 struct EvenChunks(Source) 9121 if (isForwardRange!Source && hasLength!Source) 9122 { 9123 /// Standard constructor 9124 this(Source source, size_t chunkCount) 9125 { 9126 assert(chunkCount != 0 || source.empty, "Cannot create EvenChunks with a zero chunkCount"); 9127 _source = source; 9128 _chunkCount = chunkCount; 9129 } 9130 9131 /// Forward range primitives. Always present. 9132 @property auto front() 9133 { 9134 assert(!empty, "Attempting to fetch the front of an empty evenChunks"); 9135 return _source.save.take(_chunkPos(1)); 9136 } 9137 9138 /// Ditto 9139 void popFront() 9140 { 9141 assert(!empty, "Attempting to popFront an empty evenChunks"); 9142 _source.popFrontN(_chunkPos(1)); 9143 _chunkCount--; 9144 } 9145 9146 /// Ditto 9147 @property bool empty() 9148 { 9149 return _chunkCount == 0; 9150 } 9151 9152 /// Ditto 9153 @property typeof(this) save() 9154 { 9155 return typeof(this)(_source.save, _chunkCount); 9156 } 9157 9158 /// Length 9159 @property size_t length() const 9160 { 9161 return _chunkCount; 9162 } 9163 //Note: No point in defining opDollar here without slicing. 9164 //opDollar is defined below in the hasSlicing!Source section 9165 9166 static if (hasSlicing!Source) 9167 { 9168 /** 9169 Indexing, slicing and bidirectional operations and range primitives. 9170 Provided only if `hasSlicing!Source` is `true`. 9171 */ 9172 auto opIndex(size_t index) 9173 { 9174 assert(index < _chunkCount, "evenChunks index out of bounds"); 9175 return _source[_chunkPos(index) .. _chunkPos(index+1)]; 9176 } 9177 9178 /// Ditto 9179 typeof(this) opSlice(size_t lower, size_t upper) 9180 { 9181 assert(lower <= upper && upper <= length, "evenChunks slicing index out of bounds"); 9182 return evenChunks(_source[_chunkPos(lower) .. _chunkPos(upper)], upper - lower); 9183 } 9184 9185 /// Ditto 9186 @property auto back() 9187 { 9188 assert(!empty, "back called on empty evenChunks"); 9189 return _source[_chunkPos(_chunkCount - 1) .. _source.length]; 9190 } 9191 9192 /// Ditto 9193 void popBack() 9194 { 9195 assert(!empty, "popBack() called on empty evenChunks"); 9196 _source = _source[0 .. _chunkPos(_chunkCount - 1)]; 9197 _chunkCount--; 9198 } 9199 } 9200 9201 private: 9202 Source _source; 9203 size_t _chunkCount; 9204 9205 size_t _chunkPos(size_t i) 9206 { 9207 /* 9208 _chunkCount = 5, _source.length = 13: 9209 9210 chunk0 9211 | chunk3 9212 | | 9213 v v 9214 +-+-+-+-+-+ ^ 9215 |0|3|.| | | | 9216 +-+-+-+-+-+ | div 9217 |1|4|.| | | | 9218 +-+-+-+-+-+ v 9219 |2|5|.| 9220 +-+-+-+ 9221 9222 <-----> 9223 mod 9224 9225 <---------> 9226 _chunkCount 9227 9228 One column is one chunk. 9229 popFront and popBack pop the left-most 9230 and right-most column, respectively. 9231 */ 9232 9233 auto div = _source.length / _chunkCount; 9234 auto mod = _source.length % _chunkCount; 9235 auto pos = i <= mod 9236 ? i * (div+1) 9237 : mod * (div+1) + (i-mod) * div 9238 ; 9239 //auto len = i < mod 9240 // ? div+1 9241 // : div 9242 //; 9243 return pos; 9244 } 9245 } 9246 9247 /// Ditto 9248 EvenChunks!Source evenChunks(Source)(Source source, size_t chunkCount) 9249 if (isForwardRange!Source && hasLength!Source) 9250 { 9251 return typeof(return)(source, chunkCount); 9252 } 9253 9254 /// 9255 @safe unittest 9256 { 9257 import std.algorithm.comparison : equal; 9258 auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 9259 auto chunks = evenChunks(source, 3); 9260 assert(chunks[0] == [1, 2, 3, 4]); 9261 assert(chunks[1] == [5, 6, 7]); 9262 assert(chunks[2] == [8, 9, 10]); 9263 } 9264 9265 @safe unittest 9266 { 9267 import std.algorithm.comparison : equal; 9268 9269 auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 9270 auto chunks = evenChunks(source, 3); 9271 assert(chunks.back == chunks[2]); 9272 assert(chunks.front == chunks[0]); 9273 assert(chunks.length == 3); 9274 assert(equal(retro(array(chunks)), array(retro(chunks)))); 9275 9276 auto chunks2 = chunks.save; 9277 chunks.popFront(); 9278 assert(chunks[0] == [5, 6, 7]); 9279 assert(chunks[1] == [8, 9, 10]); 9280 chunks2.popBack(); 9281 assert(chunks2[1] == [5, 6, 7]); 9282 assert(chunks2.length == 2); 9283 9284 static assert(isRandomAccessRange!(typeof(chunks))); 9285 } 9286 9287 @safe unittest 9288 { 9289 import std.algorithm.comparison : equal; 9290 9291 int[] source = []; 9292 auto chunks = source.evenChunks(0); 9293 assert(chunks.length == 0); 9294 chunks = source.evenChunks(3); 9295 assert(equal(chunks, [[], [], []])); 9296 chunks = [1, 2, 3].evenChunks(5); 9297 assert(equal(chunks, [[1], [2], [3], [], []])); 9298 } 9299 9300 /** 9301 A fixed-sized sliding window iteration 9302 of size `windowSize` over a `source` range by a custom `stepSize`. 9303 9304 The `Source` range must be at least a $(REF_ALTTEXT ForwardRange, isForwardRange, std,range,primitives) 9305 and the `windowSize` must be greater than zero. 9306 9307 For `windowSize = 1` it splits the range into single element groups (aka `unflatten`) 9308 For `windowSize = 2` it is similar to `zip(source, source.save.dropOne)`. 9309 9310 Params: 9311 f = Whether the last element has fewer elements than `windowSize` 9312 it should be be ignored (`No.withPartial`) or added (`Yes.withPartial`) 9313 source = Range from which the slide will be selected 9314 windowSize = Sliding window size 9315 stepSize = Steps between the windows (by default 1) 9316 9317 Returns: Range of all sliding windows with propagated bi-directionality, 9318 forwarding, random access, and slicing. 9319 9320 Note: To avoid performance overhead, $(REF_ALTTEXT bi-directionality, isBidirectionalRange, std,range,primitives) 9321 is only available when $(REF hasSlicing, std,range,primitives) 9322 and $(REF hasLength, std,range,primitives) are true. 9323 9324 See_Also: $(LREF chunks) 9325 */ 9326 auto slide(Flag!"withPartial" f = Yes.withPartial, 9327 Source)(Source source, size_t windowSize, size_t stepSize = 1) 9328 if (isForwardRange!Source) 9329 { 9330 return Slides!(f, Source)(source, windowSize, stepSize); 9331 } 9332 9333 /// Iterate over ranges with windows 9334 @safe pure nothrow unittest 9335 { 9336 import std.algorithm.comparison : equal; 9337 9338 assert([0, 1, 2, 3].slide(2).equal!equal( 9339 [[0, 1], [1, 2], [2, 3]] 9340 )); 9341 9342 assert(5.iota.slide(3).equal!equal( 9343 [[0, 1, 2], [1, 2, 3], [2, 3, 4]] 9344 )); 9345 } 9346 9347 /// set a custom stepsize (default 1) 9348 @safe pure nothrow unittest 9349 { 9350 import std.algorithm.comparison : equal; 9351 9352 assert(6.iota.slide(1, 2).equal!equal( 9353 [[0], [2], [4]] 9354 )); 9355 9356 assert(6.iota.slide(2, 4).equal!equal( 9357 [[0, 1], [4, 5]] 9358 )); 9359 9360 assert(iota(7).slide(2, 2).equal!equal( 9361 [[0, 1], [2, 3], [4, 5], [6]] 9362 )); 9363 9364 assert(iota(12).slide(2, 4).equal!equal( 9365 [[0, 1], [4, 5], [8, 9]] 9366 )); 9367 } 9368 9369 /// Allow the last slide to have fewer elements than windowSize 9370 @safe pure nothrow unittest 9371 { 9372 import std.algorithm.comparison : equal; 9373 9374 assert(3.iota.slide!(No.withPartial)(4).empty); 9375 assert(3.iota.slide!(Yes.withPartial)(4).equal!equal( 9376 [[0, 1, 2]] 9377 )); 9378 } 9379 9380 /// Count all the possible substrings of length 2 9381 @safe pure nothrow unittest 9382 { 9383 import std.algorithm.iteration : each; 9384 9385 int[dstring] d; 9386 "AGAGA"d.slide!(Yes.withPartial)(2).each!(a => d[a]++); 9387 assert(d == ["AG"d: 2, "GA"d: 2]); 9388 } 9389 9390 /// withPartial only has an effect if last element in the range doesn't have the full size 9391 @safe pure nothrow unittest 9392 { 9393 import std.algorithm.comparison : equal; 9394 9395 assert(5.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4]])); 9396 assert(6.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5]])); 9397 assert(7.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5, 6]])); 9398 9399 assert(5.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2]])); 9400 assert(6.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2]])); 9401 assert(7.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5, 6]])); 9402 } 9403 9404 private struct Slides(Flag!"withPartial" withPartial = Yes.withPartial, Source) 9405 if (isForwardRange!Source) 9406 { 9407 private: 9408 Source source; 9409 size_t windowSize; 9410 size_t stepSize; 9411 9412 static if (hasLength!Source) 9413 { 9414 enum needsEndTracker = false; 9415 } 9416 else 9417 { 9418 // If there's no information about the length, track needs to be kept manually 9419 Source nextSource; 9420 enum needsEndTracker = true; 9421 } 9422 9423 bool _empty; 9424 9425 static if (hasSlicing!Source) 9426 enum hasSliceToEnd = hasSlicing!Source && is(typeof(Source.init[0 .. $]) == Source); 9427 9428 static if (withPartial) 9429 bool hasShownPartialBefore; 9430 9431 public: 9432 /// Standard constructor 9433 this(Source source, size_t windowSize, size_t stepSize) 9434 { 9435 assert(windowSize > 0, "windowSize must be greater than zero"); 9436 assert(stepSize > 0, "stepSize must be greater than zero"); 9437 this.source = source; 9438 this.windowSize = windowSize; 9439 this.stepSize = stepSize; 9440 9441 static if (needsEndTracker) 9442 { 9443 // `nextSource` is used to "look one step into the future" and check for the end 9444 // this means `nextSource` is advanced by `stepSize` on every `popFront` 9445 nextSource = source.save; 9446 auto poppedElems = nextSource.popFrontN(windowSize); 9447 } 9448 9449 if (source.empty) 9450 { 9451 _empty = true; 9452 return; 9453 } 9454 9455 static if (withPartial) 9456 { 9457 static if (needsEndTracker) 9458 { 9459 if (nextSource.empty) 9460 hasShownPartialBefore = true; 9461 } 9462 else 9463 { 9464 if (source.length <= windowSize) 9465 hasShownPartialBefore = true; 9466 } 9467 } 9468 else 9469 { 9470 // empty source range is needed, s.t. length, slicing etc. works properly 9471 static if (needsEndTracker) 9472 { 9473 if (poppedElems < windowSize) 9474 _empty = true; 9475 } 9476 else 9477 { 9478 if (source.length < windowSize) 9479 _empty = true; 9480 } 9481 } 9482 } 9483 9484 /// Forward range primitives. Always present. 9485 @property auto front() 9486 { 9487 assert(!empty, "Attempting to access front on an empty slide."); 9488 static if (hasSlicing!Source && hasLength!Source) 9489 { 9490 static if (withPartial) 9491 { 9492 import std.algorithm.comparison : min; 9493 return source[0 .. min(windowSize, source.length)]; 9494 } 9495 else 9496 { 9497 assert(windowSize <= source.length, "The last element is smaller than the current windowSize."); 9498 return source[0 .. windowSize]; 9499 } 9500 } 9501 else 9502 { 9503 static if (withPartial) 9504 return source.save.take(windowSize); 9505 else 9506 return source.save.takeExactly(windowSize); 9507 } 9508 } 9509 9510 /// Ditto 9511 void popFront() 9512 { 9513 assert(!empty, "Attempting to call popFront() on an empty slide."); 9514 source.popFrontN(stepSize); 9515 9516 if (source.empty) 9517 { 9518 _empty = true; 9519 return; 9520 } 9521 9522 static if (withPartial) 9523 { 9524 if (hasShownPartialBefore) 9525 _empty = true; 9526 } 9527 9528 static if (needsEndTracker) 9529 { 9530 // Check the upcoming slide 9531 auto poppedElements = nextSource.popFrontN(stepSize); 9532 static if (withPartial) 9533 { 9534 if (poppedElements < stepSize || nextSource.empty) 9535 hasShownPartialBefore = true; 9536 } 9537 else 9538 { 9539 if (poppedElements < stepSize) 9540 _empty = true; 9541 } 9542 } 9543 else 9544 { 9545 static if (withPartial) 9546 { 9547 if (source.length <= windowSize) 9548 hasShownPartialBefore = true; 9549 } 9550 else 9551 { 9552 if (source.length < windowSize) 9553 _empty = true; 9554 } 9555 } 9556 } 9557 9558 static if (!isInfinite!Source) 9559 { 9560 /// Ditto 9561 @property bool empty() const 9562 { 9563 return _empty; 9564 } 9565 } 9566 else 9567 { 9568 // undocumented 9569 enum empty = false; 9570 } 9571 9572 /// Ditto 9573 @property typeof(this) save() 9574 { 9575 return typeof(this)(source.save, windowSize, stepSize); 9576 } 9577 9578 static if (hasLength!Source) 9579 { 9580 // gaps between the last element and the end of the range 9581 private size_t gap() 9582 { 9583 /* 9584 * Note: 9585 * - In the following `end` is the exclusive end as used in opSlice 9586 * - For the trivial case with `stepSize = 1` `end` is at `len`: 9587 * 9588 * iota(4).slide(2) = [[0, 1], [1, 2], [2, 3]] (end = 4) 9589 * iota(4).slide(3) = [[0, 1, 2], [1, 2, 3]] (end = 4) 9590 * 9591 * - For the non-trivial cases, we need to calculate the gap 9592 * between `len` and `end` - this is the number of missing elements 9593 * from the input range: 9594 * 9595 * iota(7).slide(2, 3) = [[0, 1], [3, 4]] || <gap: 2> 6 9596 * iota(7).slide(2, 4) = [[0, 1], [4, 5]] || <gap: 1> 6 9597 * iota(7).slide(1, 5) = [[0], [5]] || <gap: 1> 6 9598 * 9599 * As it can be seen `gap` can be at most `stepSize - 1` 9600 * More generally the elements of the sliding window with 9601 * `w = windowSize` and `s = stepSize` are: 9602 * 9603 * [0, w], [s, s + w], [2 * s, 2 * s + w], ... [n * s, n * s + w] 9604 * 9605 * We can thus calculate the gap between the `end` and `len` as: 9606 * 9607 * gap = len - (n * s + w) = len - w - (n * s) 9608 * 9609 * As we aren't interested in exact value of `n`, but the best 9610 * minimal `gap` value, we can use modulo to "cut" `len - w` optimally: 9611 * 9612 * gap = len - w - (s - s ... - s) = (len - w) % s 9613 * 9614 * So for example: 9615 * 9616 * iota(7).slide(2, 3) = [[0, 1], [3, 4]] 9617 * gap: (7 - 2) % 3 = 5 % 3 = 2 9618 * end: 7 - 2 = 5 9619 * 9620 * iota(7).slide(4, 2) = [[0, 1, 2, 3], [2, 3, 4, 5]] 9621 * gap: (7 - 4) % 2 = 3 % 2 = 1 9622 * end: 7 - 1 = 6 9623 */ 9624 return (source.length - windowSize) % stepSize; 9625 } 9626 9627 private size_t numberOfFullFrames() 9628 { 9629 /** 9630 5.iota.slides(2, 1) => [0, 1], [1, 2], [2, 3], [3, 4] (4) 9631 7.iota.slides(2, 2) => [0, 1], [2, 3], [4, 5], [6] (3) 9632 7.iota.slides(2, 3) => [0, 1], [3, 4], [6] (2) 9633 6.iota.slides(3, 2) => [0, 1, 2], [2, 3, 4], [4, 5] (2) 9634 7.iota.slides(3, 3) => [0, 1, 2], [3, 4, 5], [6] (2) 9635 9636 As the last window is only added iff its complete, 9637 we don't count the last window except if it's full due to integer rounding. 9638 */ 9639 return 1 + (source.length - windowSize) / stepSize; 9640 } 9641 9642 // Whether the last slide frame size is less than windowSize 9643 private bool hasPartialElements() 9644 { 9645 static if (withPartial) 9646 return gap != 0 && source.length > numberOfFullFrames * stepSize; 9647 else 9648 return 0; 9649 } 9650 9651 /// Length. Only if `hasLength!Source` is `true` 9652 @property size_t length() 9653 { 9654 if (source.length < windowSize) 9655 { 9656 static if (withPartial) 9657 return source.length > 0; 9658 else 9659 return 0; 9660 } 9661 else 9662 { 9663 /*** 9664 We bump the pointer by stepSize for every element. 9665 If withPartial, we don't count the last element if its size 9666 isn't windowSize 9667 9668 At most: 9669 [p, p + stepSize, ..., p + stepSize * n] 9670 9671 5.iota.slides(2, 1) => [0, 1], [1, 2], [2, 3], [3, 4] (4) 9672 7.iota.slides(2, 2) => [0, 1], [2, 3], [4, 5], [6] (4) 9673 7.iota.slides(2, 3) => [0, 1], [3, 4], [6] (3) 9674 7.iota.slides(3, 2) => [0, 1, 2], [2, 3, 4], [4, 5, 6] (3) 9675 7.iota.slides(3, 3) => [0, 1, 2], [3, 4, 5], [6] (3) 9676 */ 9677 return numberOfFullFrames + hasPartialElements; 9678 } 9679 } 9680 } 9681 9682 static if (hasSlicing!Source) 9683 { 9684 /** 9685 Indexing and slicing operations. Provided only if 9686 `hasSlicing!Source` is `true`. 9687 */ 9688 auto opIndex(size_t index) 9689 { 9690 immutable start = index * stepSize; 9691 9692 static if (isInfinite!Source) 9693 { 9694 immutable end = start + windowSize; 9695 } 9696 else 9697 { 9698 import std.algorithm.comparison : min; 9699 9700 immutable len = source.length; 9701 assert(start < len, "slide index out of bounds"); 9702 immutable end = min(start + windowSize, len); 9703 } 9704 9705 return source[start .. end]; 9706 } 9707 9708 static if (!isInfinite!Source) 9709 { 9710 /// ditto 9711 typeof(this) opSlice(size_t lower, size_t upper) 9712 { 9713 import std.algorithm.comparison : min; 9714 9715 assert(upper <= length, "slide slicing index out of bounds"); 9716 assert(lower <= upper, "slide slicing index out of bounds"); 9717 9718 lower *= stepSize; 9719 upper *= stepSize; 9720 9721 immutable len = source.length; 9722 9723 static if (withPartial) 9724 { 9725 import std.algorithm.comparison : max; 9726 9727 if (lower == upper) 9728 return this[$ .. $]; 9729 9730 /* 9731 A) If `stepSize` >= `windowSize` => `rightPos = upper` 9732 9733 [0, 1, 2, 3, 4, 5, 6].slide(2, 3) -> s = [[0, 1], [3, 4], [6]] 9734 rightPos for s[0 .. 2]: (upper=2) * (stepSize=3) = 6 9735 6.iota.slide(2, 3) = [[0, 1], [3, 4]] 9736 9737 B) If `stepSize` < `windowSize` => add `windowSize - stepSize` to `upper` 9738 9739 [0, 1, 2, 3].slide(2) = [[0, 1], [1, 2], [2, 3]] 9740 rightPos for s[0 .. 1]: = (upper=1) * (stepSize=1) = 1 9741 1.iota.slide(2) = [[0]] 9742 9743 rightPos for s[0 .. 1]: = (upper=1) * (stepSize=1) + (windowSize-stepSize=1) = 2 9744 1.iota.slide(2) = [[0, 1]] 9745 9746 More complex: 9747 9748 20.iota.slide(7, 6)[0 .. 2] 9749 rightPos: (upper=2) * (stepSize=6) = 12.iota 9750 12.iota.slide(7, 6) = [[0, 1, 2, 3, 4, 5, 6], [6, 7, 8, 9, 10, 11]] 9751 9752 Now we add up for the difference between `windowSize` and `stepSize`: 9753 9754 rightPos: (upper=2) * (stepSize=6) + (windowSize-stepSize=1) = 13.iota 9755 13.iota.slide(7, 6) = [[0, 1, 2, 3, 4, 5, 6], [6, 7, 8, 9, 10, 11, 12]] 9756 */ 9757 immutable rightPos = min(len, upper + max(0, windowSize - stepSize)); 9758 } 9759 else 9760 { 9761 /* 9762 After we have normalized `lower` and `upper` by `stepSize`, 9763 we only need to look at the case of `stepSize=1`. 9764 As `leftPos`, is equal to `lower`, we will only look `rightPos`. 9765 Notice that starting from `upper`, 9766 we only need to move for `windowSize - 1` to the right: 9767 9768 - [0, 1, 2, 3].slide(2) -> s = [[0, 1], [1, 2], [2, 3]] 9769 rightPos for s[0 .. 3]: (upper=3) + (windowSize=2) - 1 = 4 9770 9771 - [0, 1, 2, 3].slide(3) -> s = [[0, 1, 2], [1, 2, 3]] 9772 rightPos for s[0 .. 2]: (upper=2) + (windowSize=3) - 1 = 4 9773 9774 - [0, 1, 2, 3, 4].slide(4) -> s = [[0, 1, 2, 3], [1, 2, 3, 4]] 9775 rightPos for s[0 .. 2]: (upper=2) + (windowSize=4) - 1 = 5 9776 */ 9777 immutable rightPos = min(upper + windowSize - 1, len); 9778 } 9779 9780 return typeof(this)(source[min(lower, len) .. rightPos], windowSize, stepSize); 9781 } 9782 } 9783 else static if (hasSliceToEnd) 9784 { 9785 // For slicing an infinite chunk, we need to slice the source to the infinite end. 9786 auto opSlice(size_t lower, size_t upper) 9787 { 9788 assert(lower <= upper, "slide slicing index out of bounds"); 9789 return typeof(this)(source[lower * stepSize .. $], windowSize, stepSize) 9790 .takeExactly(upper - lower); 9791 } 9792 } 9793 9794 static if (isInfinite!Source) 9795 { 9796 static if (hasSliceToEnd) 9797 { 9798 private static struct DollarToken{} 9799 DollarToken opDollar() 9800 { 9801 return DollarToken(); 9802 } 9803 //Slice to dollar 9804 typeof(this) opSlice(size_t lower, DollarToken) 9805 { 9806 return typeof(this)(source[lower * stepSize .. $], windowSize, stepSize); 9807 } 9808 } 9809 } 9810 else 9811 { 9812 // Dollar token carries a static type, with no extra information. 9813 // It can lazily transform into source.length on algorithmic 9814 // operations such as : slide[$/2, $-1]; 9815 private static struct DollarToken 9816 { 9817 private size_t _length; 9818 alias _length this; 9819 } 9820 9821 DollarToken opDollar() 9822 { 9823 return DollarToken(this.length); 9824 } 9825 9826 // Optimized slice overloads optimized for using dollar. 9827 typeof(this) opSlice(DollarToken, DollarToken) 9828 { 9829 static if (hasSliceToEnd) 9830 { 9831 return typeof(this)(source[$ .. $], windowSize, stepSize); 9832 } 9833 else 9834 { 9835 immutable len = source.length; 9836 return typeof(this)(source[len .. len], windowSize, stepSize); 9837 } 9838 } 9839 9840 // Optimized slice overloads optimized for using dollar. 9841 typeof(this) opSlice(size_t lower, DollarToken) 9842 { 9843 import std.algorithm.comparison : min; 9844 assert(lower <= length, "slide slicing index out of bounds"); 9845 lower *= stepSize; 9846 static if (hasSliceToEnd) 9847 { 9848 return typeof(this)(source[min(lower, source.length) .. $], windowSize, stepSize); 9849 } 9850 else 9851 { 9852 immutable len = source.length; 9853 return typeof(this)(source[min(lower, len) .. len], windowSize, stepSize); 9854 } 9855 } 9856 9857 // Optimized slice overloads optimized for using dollar. 9858 typeof(this) opSlice(DollarToken, size_t upper) 9859 { 9860 assert(upper == length, "slide slicing index out of bounds"); 9861 return this[$ .. $]; 9862 } 9863 } 9864 9865 // Bidirectional range primitives 9866 static if (!isInfinite!Source) 9867 { 9868 /** 9869 Bidirectional range primitives. Provided only if both 9870 `hasSlicing!Source` and `!isInfinite!Source` are `true`. 9871 */ 9872 @property auto back() 9873 { 9874 import std.algorithm.comparison : max; 9875 9876 assert(!empty, "Attempting to access front on an empty slide"); 9877 9878 immutable len = source.length; 9879 9880 static if (withPartial) 9881 { 9882 if (source.length <= windowSize) 9883 return source[0 .. source.length]; 9884 9885 if (hasPartialElements) 9886 return source[numberOfFullFrames * stepSize .. len]; 9887 } 9888 9889 // check for underflow 9890 immutable start = (len > windowSize + gap) ? len - windowSize - gap : 0; 9891 return source[start .. len - gap]; 9892 } 9893 9894 /// Ditto 9895 void popBack() 9896 { 9897 assert(!empty, "Attempting to call popBack() on an empty slide"); 9898 9899 // Move by stepSize 9900 immutable end = source.length > stepSize ? source.length - stepSize : 0; 9901 9902 static if (withPartial) 9903 { 9904 if (hasShownPartialBefore || source.empty) 9905 { 9906 _empty = true; 9907 return; 9908 } 9909 9910 // pop by stepSize, except for the partial frame at the end 9911 if (hasPartialElements) 9912 source = source[0 .. source.length - gap]; 9913 else 9914 source = source[0 .. end]; 9915 } 9916 else 9917 { 9918 source = source[0 .. end]; 9919 } 9920 9921 if (source.length < windowSize) 9922 _empty = true; 9923 } 9924 } 9925 } 9926 } 9927 9928 // test @nogc 9929 @safe pure nothrow @nogc unittest 9930 { 9931 import std.algorithm.comparison : equal; 9932 9933 static immutable res1 = [[0], [1], [2], [3]]; 9934 assert(4.iota.slide!(Yes.withPartial)(1).equal!equal(res1)); 9935 9936 static immutable res2 = [[0, 1], [1, 2], [2, 3]]; 9937 assert(4.iota.slide!(Yes.withPartial)(2).equal!equal(res2)); 9938 } 9939 9940 // test different window sizes 9941 @safe pure nothrow unittest 9942 { 9943 import std.array : array; 9944 import std.algorithm.comparison : equal; 9945 9946 assert([0, 1, 2, 3].slide!(Yes.withPartial)(1).array == [[0], [1], [2], [3]]); 9947 assert([0, 1, 2, 3].slide!(Yes.withPartial)(2).array == [[0, 1], [1, 2], [2, 3]]); 9948 assert([0, 1, 2, 3].slide!(Yes.withPartial)(3).array == [[0, 1, 2], [1, 2, 3]]); 9949 assert([0, 1, 2, 3].slide!(Yes.withPartial)(4).array == [[0, 1, 2, 3]]); 9950 assert([0, 1, 2, 3].slide!(No.withPartial)(5).walkLength == 0); 9951 assert([0, 1, 2, 3].slide!(Yes.withPartial)(5).array == [[0, 1, 2, 3]]); 9952 9953 assert(iota(2).slide!(Yes.withPartial)(2).front.equal([0, 1])); 9954 assert(iota(3).slide!(Yes.withPartial)(2).equal!equal([[0, 1],[1, 2]])); 9955 assert(iota(3).slide!(Yes.withPartial)(3).equal!equal([[0, 1, 2]])); 9956 assert(iota(3).slide!(No.withPartial)(4).walkLength == 0); 9957 assert(iota(3).slide!(Yes.withPartial)(4).equal!equal([[0, 1, 2]])); 9958 assert(iota(1, 4).slide!(Yes.withPartial)(1).equal!equal([[1], [2], [3]])); 9959 assert(iota(1, 4).slide!(Yes.withPartial)(3).equal!equal([[1, 2, 3]])); 9960 } 9961 9962 // test combinations 9963 @safe pure nothrow unittest 9964 { 9965 import std.algorithm.comparison : equal; 9966 import std.typecons : tuple; 9967 9968 alias t = tuple; 9969 auto list = [ 9970 t(t(1, 1), [[0], [1], [2], [3], [4], [5]]), 9971 t(t(1, 2), [[0], [2], [4]]), 9972 t(t(1, 3), [[0], [3]]), 9973 t(t(1, 4), [[0], [4]]), 9974 t(t(1, 5), [[0], [5]]), 9975 t(t(2, 1), [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5]]), 9976 t(t(2, 2), [[0, 1], [2, 3], [4, 5]]), 9977 t(t(2, 3), [[0, 1], [3, 4]]), 9978 t(t(2, 4), [[0, 1], [4, 5]]), 9979 t(t(3, 1), [[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5]]), 9980 t(t(3, 3), [[0, 1, 2], [3, 4, 5]]), 9981 t(t(4, 1), [[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]), 9982 t(t(4, 2), [[0, 1, 2, 3], [2, 3, 4, 5]]), 9983 t(t(5, 1), [[0, 1, 2, 3, 4], [1, 2, 3, 4, 5]]), 9984 ]; 9985 9986 static foreach (Partial; [Yes.withPartial, No.withPartial]) 9987 foreach (e; list) 9988 assert(6.iota.slide!Partial(e[0].expand).equal!equal(e[1])); 9989 9990 auto listSpecial = [ 9991 t(t(2, 5), [[0, 1], [5]]), 9992 t(t(3, 2), [[0, 1, 2], [2, 3, 4], [4, 5]]), 9993 t(t(3, 4), [[0, 1, 2], [4, 5]]), 9994 t(t(4, 3), [[0, 1, 2, 3], [3, 4, 5]]), 9995 t(t(5, 2), [[0, 1, 2, 3, 4], [2, 3, 4, 5]]), 9996 t(t(5, 3), [[0, 1, 2, 3, 4], [3, 4, 5]]), 9997 ]; 9998 foreach (e; listSpecial) 9999 { 10000 assert(6.iota.slide!(Yes.withPartial)(e[0].expand).equal!equal(e[1])); 10001 assert(6.iota.slide!(No.withPartial)(e[0].expand).equal!equal(e[1].dropBackOne)); 10002 } 10003 } 10004 10005 // test emptiness and copyability 10006 @safe pure nothrow unittest 10007 { 10008 import std.algorithm.comparison : equal; 10009 import std.algorithm.iteration : map; 10010 10011 // check with empty input 10012 int[] d; 10013 assert(d.slide!(Yes.withPartial)(2).empty); 10014 assert(d.slide!(Yes.withPartial)(2, 2).empty); 10015 10016 // is copyable? 10017 auto e = iota(5).slide!(Yes.withPartial)(2); 10018 e.popFront; 10019 assert(e.save.equal!equal([[1, 2], [2, 3], [3, 4]])); 10020 assert(e.save.equal!equal([[1, 2], [2, 3], [3, 4]])); 10021 assert(e.map!"a.array".array == [[1, 2], [2, 3], [3, 4]]); 10022 } 10023 10024 // test with strings 10025 @safe pure nothrow unittest 10026 { 10027 import std.algorithm.iteration : each; 10028 10029 int[dstring] f; 10030 "AGAGA"d.slide!(Yes.withPartial)(3).each!(a => f[a]++); 10031 assert(f == ["AGA"d: 2, "GAG"d: 1]); 10032 10033 int[dstring] g; 10034 "ABCDEFG"d.slide!(Yes.withPartial)(3, 3).each!(a => g[a]++); 10035 assert(g == ["ABC"d:1, "DEF"d:1, "G": 1]); 10036 g = null; 10037 "ABCDEFG"d.slide!(No.withPartial)(3, 3).each!(a => g[a]++); 10038 assert(g == ["ABC"d:1, "DEF"d:1]); 10039 } 10040 10041 // test with utf8 strings 10042 @safe unittest 10043 { 10044 import std.stdio; 10045 import std.algorithm.comparison : equal; 10046 10047 assert("ä.ö.ü.".slide!(Yes.withPartial)(3, 2).equal!equal(["ä.ö", "ö.ü", "ü."])); 10048 assert("ä.ö.ü.".slide!(No.withPartial)(3, 2).equal!equal(["ä.ö", "ö.ü"])); 10049 10050 "😄😅😆😇😈😄😅😆😇😈".slide!(Yes.withPartial)(2, 4).equal!equal(["😄😅", "😈😄", "😇😈"]); 10051 "😄😅😆😇😈😄😅😆😇😈".slide!(No.withPartial)(2, 4).equal!equal(["😄😅", "😈😄", "😇😈"]); 10052 "😄😅😆😇😈😄😅😆😇😈".slide!(Yes.withPartial)(3, 3).equal!equal(["😄😅😆", "😇😈😄", "😅😆😇", "😈"]); 10053 "😄😅😆😇😈😄😅😆😇😈".slide!(No.withPartial)(3, 3).equal!equal(["😄😅😆", "😇😈😄", "😅😆😇"]); 10054 } 10055 10056 // test length 10057 @safe pure nothrow unittest 10058 { 10059 // Slides with fewer elements are empty or 1 for Yes.withPartial 10060 static foreach (expectedLength, Partial; [No.withPartial, Yes.withPartial]) 10061 {{ 10062 assert(3.iota.slide!(Partial)(4, 2).walkLength == expectedLength); 10063 assert(3.iota.slide!(Partial)(4).walkLength == expectedLength); 10064 assert(3.iota.slide!(Partial)(4, 3).walkLength == expectedLength); 10065 }} 10066 10067 static immutable list = [ 10068 // iota slide expected 10069 [4, 2, 1, 3, 3], 10070 [5, 3, 1, 3, 3], 10071 [7, 2, 2, 4, 3], 10072 [12, 2, 4, 3, 3], 10073 [6, 1, 2, 3, 3], 10074 [6, 2, 4, 2, 2], 10075 [3, 2, 4, 1, 1], 10076 [5, 2, 1, 4, 4], 10077 [7, 2, 2, 4, 3], 10078 [7, 2, 3, 3, 2], 10079 [7, 3, 2, 3, 3], 10080 [7, 3, 3, 3, 2], 10081 ]; 10082 foreach (e; list) 10083 { 10084 assert(e[0].iota.slide!(Yes.withPartial)(e[1], e[2]).length == e[3]); 10085 assert(e[0].iota.slide!(No.withPartial)(e[1], e[2]).length == e[4]); 10086 } 10087 } 10088 10089 // test index and slicing 10090 @safe pure nothrow unittest 10091 { 10092 import std.algorithm.comparison : equal; 10093 import std.array : array; 10094 10095 static foreach (Partial; [Yes.withPartial, No.withPartial]) 10096 { 10097 foreach (s; [5, 7, 10, 15, 20]) 10098 foreach (windowSize; 1 .. 10) 10099 foreach (stepSize; 1 .. 10) 10100 { 10101 auto r = s.iota.slide!Partial(windowSize, stepSize); 10102 auto arr = r.array; 10103 assert(r.length == arr.length); 10104 10105 // test indexing 10106 foreach (i; 0 .. arr.length) 10107 assert(r[i] == arr[i]); 10108 10109 // test slicing 10110 foreach (i; 0 .. arr.length) 10111 { 10112 foreach (j; i .. arr.length) 10113 assert(r[i .. j].equal(arr[i .. j])); 10114 10115 assert(r[i .. $].equal(arr[i .. $])); 10116 } 10117 10118 // test opDollar slicing 10119 assert(r[$/2 .. $].equal(arr[$/2 .. $])); 10120 assert(r[$ .. $].empty); 10121 if (arr.empty) 10122 { 10123 assert(r[$ .. 0].empty); 10124 assert(r[$/2 .. $].empty); 10125 10126 } 10127 } 10128 } 10129 } 10130 10131 // test with infinite ranges 10132 @safe pure nothrow unittest 10133 { 10134 import std.algorithm.comparison : equal; 10135 10136 static foreach (Partial; [Yes.withPartial, No.withPartial]) 10137 {{ 10138 // InfiniteRange without RandomAccess 10139 auto fibs = recurrence!"a[n-1] + a[n-2]"(1, 1); 10140 assert(fibs.slide!Partial(2).take(2).equal!equal([[1, 1], [1, 2]])); 10141 assert(fibs.slide!Partial(2, 3).take(2).equal!equal([[1, 1], [3, 5]])); 10142 10143 // InfiniteRange with RandomAccess and slicing 10144 auto odds = sequence!("a[0] + n * a[1]")(1, 2); 10145 auto oddsByPairs = odds.slide!Partial(2); 10146 assert(oddsByPairs.take(2).equal!equal([[ 1, 3], [ 3, 5]])); 10147 assert(oddsByPairs[1].equal([3, 5])); 10148 assert(oddsByPairs[4].equal([9, 11])); 10149 10150 static assert(hasSlicing!(typeof(odds))); 10151 assert(oddsByPairs[3 .. 5].equal!equal([[7, 9], [9, 11]])); 10152 assert(oddsByPairs[3 .. $].take(2).equal!equal([[7, 9], [9, 11]])); 10153 10154 auto oddsWithGaps = odds.slide!Partial(2, 4); 10155 assert(oddsWithGaps.take(3).equal!equal([[1, 3], [9, 11], [17, 19]])); 10156 assert(oddsWithGaps[2].equal([17, 19])); 10157 assert(oddsWithGaps[1 .. 3].equal!equal([[9, 11], [17, 19]])); 10158 assert(oddsWithGaps[1 .. $].take(2).equal!equal([[9, 11], [17, 19]])); 10159 }} 10160 } 10161 10162 // test reverse 10163 @safe pure nothrow unittest 10164 { 10165 import std.algorithm.comparison : equal; 10166 10167 static foreach (Partial; [Yes.withPartial, No.withPartial]) 10168 {{ 10169 foreach (windowSize; 1 .. 15) 10170 foreach (stepSize; 1 .. 15) 10171 { 10172 auto r = 20.iota.slide!Partial(windowSize, stepSize); 10173 auto rArr = r.array.retro; 10174 auto rRetro = r.retro; 10175 10176 assert(rRetro.length == rArr.length); 10177 assert(rRetro.equal(rArr)); 10178 assert(rRetro.array.retro.equal(r)); 10179 } 10180 }} 10181 } 10182 10183 // test with dummy ranges 10184 @safe pure nothrow unittest 10185 { 10186 import std.algorithm.comparison : equal; 10187 import std.internal.test.dummyrange : AllDummyRanges; 10188 import std.meta : Filter; 10189 10190 static foreach (Range; Filter!(isForwardRange, AllDummyRanges)) 10191 {{ 10192 Range r; 10193 10194 static foreach (Partial; [Yes.withPartial, No.withPartial]) 10195 { 10196 assert(r.slide!Partial(1).equal!equal( 10197 [[1], [2], [3], [4], [5], [6], [7], [8], [9], [10]] 10198 )); 10199 assert(r.slide!Partial(2).equal!equal( 10200 [[1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9], [9, 10]] 10201 )); 10202 assert(r.slide!Partial(3).equal!equal( 10203 [[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6], 10204 [5, 6, 7], [6, 7, 8], [7, 8, 9], [8, 9, 10]] 10205 )); 10206 assert(r.slide!Partial(6).equal!equal( 10207 [[1, 2, 3, 4, 5, 6], [2, 3, 4, 5, 6, 7], [3, 4, 5, 6, 7, 8], 10208 [4, 5, 6, 7, 8, 9], [5, 6, 7, 8, 9, 10]] 10209 )); 10210 } 10211 10212 // special cases 10213 assert(r.slide!(Yes.withPartial)(15).equal!equal(iota(1, 11).only)); 10214 assert(r.slide!(Yes.withPartial)(15).walkLength == 1); 10215 assert(r.slide!(No.withPartial)(15).empty); 10216 assert(r.slide!(No.withPartial)(15).walkLength == 0); 10217 }} 10218 } 10219 10220 // test with dummy ranges 10221 @safe pure nothrow unittest 10222 { 10223 import std.algorithm.comparison : equal; 10224 import std.internal.test.dummyrange : AllDummyRanges; 10225 import std.meta : Filter; 10226 import std.typecons : tuple; 10227 10228 alias t = tuple; 10229 static immutable list = [ 10230 // iota slide expected 10231 t(6, t(4, 2), [[1, 2, 3, 4], [3, 4, 5, 6]]), 10232 t(6, t(4, 6), [[1, 2, 3, 4]]), 10233 t(6, t(4, 1), [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6]]), 10234 t(7, t(4, 1), [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 6, 7]]), 10235 t(7, t(4, 3), [[1, 2, 3, 4], [4, 5, 6, 7]]), 10236 t(8, t(4, 2), [[1, 2, 3, 4], [3, 4, 5, 6], [5, 6, 7, 8]]), 10237 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]]), 10238 t(8, t(3, 4), [[1, 2, 3], [5, 6, 7]]), 10239 t(10, t(3, 7), [[1, 2, 3], [8, 9, 10]]), 10240 ]; 10241 10242 static foreach (Range; Filter!(isForwardRange, AllDummyRanges)) 10243 static foreach (Partial; [Yes.withPartial, No.withPartial]) 10244 foreach (e; list) 10245 assert(Range().take(e[0]).slide!Partial(e[1].expand).equal!equal(e[2])); 10246 10247 static immutable listSpecial = [ 10248 // iota slide expected 10249 t(6, t(4, 3), [[1, 2, 3, 4], [4, 5, 6]]), 10250 t(7, t(4, 5), [[1, 2, 3, 4], [6, 7]]), 10251 t(7, t(4, 4), [[1, 2, 3, 4], [5, 6, 7]]), 10252 t(7, t(4, 2), [[1, 2, 3, 4], [3, 4, 5, 6], [5, 6, 7]]), 10253 t(8, t(4, 3), [[1, 2, 3, 4], [4, 5, 6, 7], [7, 8]]), 10254 t(8, t(3, 3), [[1, 2, 3], [4, 5, 6], [7, 8]]), 10255 t(8, t(3, 6), [[1, 2, 3], [7, 8]]), 10256 t(10, t(7, 6), [[1, 2, 3, 4, 5, 6, 7], [7, 8, 9, 10]]), 10257 t(10, t(3, 8), [[1, 2, 3], [9, 10]]), 10258 ]; 10259 static foreach (Range; Filter!(isForwardRange, AllDummyRanges)) 10260 static foreach (Partial; [Yes.withPartial, No.withPartial]) 10261 foreach (e; listSpecial) 10262 { 10263 Range r; 10264 assert(r.take(e[0]).slide!(Yes.withPartial)(e[1].expand).equal!equal(e[2])); 10265 assert(r.take(e[0]).slide!(No.withPartial)(e[1].expand).equal!equal(e[2].dropBackOne)); 10266 } 10267 } 10268 10269 // test reverse with dummy ranges 10270 @safe pure nothrow unittest 10271 { 10272 import std.algorithm.comparison : equal; 10273 import std.internal.test.dummyrange : AllDummyRanges; 10274 import std.meta : Filter, templateAnd; 10275 import std.typecons : tuple; 10276 alias t = tuple; 10277 10278 static immutable list = [ 10279 // slide expected 10280 t(1, 1, [[10], [9], [8], [7], [6], [5], [4], [3], [2], [1]]), 10281 t(2, 1, [[9, 10], [8, 9], [7, 8], [6, 7], [5, 6], [4, 5], [3, 4], [2, 3], [1, 2]]), 10282 t(5, 1, [[6, 7, 8, 9, 10], [5, 6, 7, 8, 9], [4, 5, 6, 7, 8], 10283 [3, 4, 5, 6, 7], [2, 3, 4, 5, 6], [1, 2, 3, 4, 5]]), 10284 t(2, 2, [[9, 10], [7, 8], [5, 6], [3, 4], [1, 2]]), 10285 t(2, 4, [[9, 10], [5, 6], [1, 2]]), 10286 ]; 10287 10288 static foreach (Range; Filter!(templateAnd!(hasSlicing, hasLength, isBidirectionalRange), AllDummyRanges)) 10289 {{ 10290 Range r; 10291 static foreach (Partial; [Yes.withPartial, No.withPartial]) 10292 { 10293 foreach (e; list) 10294 assert(r.slide!Partial(e[0], e[1]).retro.equal!equal(e[2])); 10295 10296 // front = back 10297 foreach (windowSize; 1 .. 10) 10298 foreach (stepSize; 1 .. 10) 10299 { 10300 auto slider = r.slide!Partial(windowSize, stepSize); 10301 auto sliderRetro = slider.retro.array; 10302 assert(slider.length == sliderRetro.length); 10303 assert(sliderRetro.retro.equal!equal(slider)); 10304 } 10305 } 10306 10307 // special cases 10308 assert(r.slide!(No.withPartial)(15).retro.walkLength == 0); 10309 assert(r.slide!(Yes.withPartial)(15).retro.equal!equal(iota(1, 11).only)); 10310 }} 10311 } 10312 10313 // test different sliceable ranges 10314 @safe pure nothrow unittest 10315 { 10316 import std.algorithm.comparison : equal; 10317 import std.internal.test.dummyrange : AllDummyRanges; 10318 import std.meta : AliasSeq; 10319 10320 struct SliceableRange(Range, Flag!"withOpDollar" withOpDollar = No.withOpDollar, 10321 Flag!"withInfiniteness" withInfiniteness = No.withInfiniteness) 10322 { 10323 Range arr = 10.iota.array; // similar to DummyRange 10324 @property auto save() { return typeof(this)(arr); } 10325 @property auto front() { return arr[0]; } 10326 void popFront() { arr.popFront(); } 10327 auto opSlice(size_t i, size_t j) 10328 { 10329 // subslices can't be infinite 10330 return SliceableRange!(Range, withOpDollar, No.withInfiniteness)(arr[i .. j]); 10331 } 10332 10333 static if (withInfiniteness) 10334 { 10335 enum empty = false; 10336 } 10337 else 10338 { 10339 @property bool empty() { return arr.empty; } 10340 @property auto length() { return arr.length; } 10341 } 10342 10343 static if (withOpDollar) 10344 { 10345 static if (withInfiniteness) 10346 { 10347 struct Dollar {} 10348 Dollar opDollar() const { return Dollar.init; } 10349 10350 // Slice to dollar 10351 typeof(this) opSlice(size_t lower, Dollar) 10352 { 10353 return typeof(this)(arr[lower .. $]); 10354 } 10355 10356 } 10357 else 10358 { 10359 alias opDollar = length; 10360 } 10361 } 10362 } 10363 10364 import std.meta : Filter, templateNot; 10365 alias SliceableDummyRanges = Filter!(hasSlicing, AllDummyRanges); 10366 10367 static foreach (Partial; [Yes.withPartial, No.withPartial]) 10368 {{ 10369 static foreach (Range; SliceableDummyRanges) 10370 {{ 10371 Range r; 10372 r.reinit; 10373 r.arr[] -= 1; // use a 0-based array (for clarity) 10374 10375 assert(r.slide!Partial(2)[0].equal([0, 1])); 10376 assert(r.slide!Partial(2)[1].equal([1, 2])); 10377 10378 // saveable 10379 auto s = r.slide!Partial(2); 10380 assert(s[0 .. 2].equal!equal([[0, 1], [1, 2]])); 10381 s.save.popFront; 10382 assert(s[0 .. 2].equal!equal([[0, 1], [1, 2]])); 10383 10384 assert(r.slide!Partial(3)[1 .. 3].equal!equal([[1, 2, 3], [2, 3, 4]])); 10385 }} 10386 10387 static foreach (Range; Filter!(templateNot!isInfinite, SliceableDummyRanges)) 10388 {{ 10389 Range r; 10390 r.reinit; 10391 r.arr[] -= 1; // use a 0-based array (for clarity) 10392 10393 assert(r.slide!(No.withPartial)(6).equal!equal( 10394 [[0, 1, 2, 3, 4, 5], [1, 2, 3, 4, 5, 6], [2, 3, 4, 5, 6, 7], 10395 [3, 4, 5, 6, 7, 8], [4, 5, 6, 7, 8, 9]] 10396 )); 10397 assert(r.slide!(No.withPartial)(16).empty); 10398 10399 assert(r.slide!Partial(4)[0 .. $].equal(r.slide!Partial(4))); 10400 assert(r.slide!Partial(2)[$/2 .. $].equal!equal([[4, 5], [5, 6], [6, 7], [7, 8], [8, 9]])); 10401 assert(r.slide!Partial(2)[$ .. $].empty); 10402 10403 assert(r.slide!Partial(3).retro.equal!equal( 10404 [[7, 8, 9], [6, 7, 8], [5, 6, 7], [4, 5, 6], [3, 4, 5], [2, 3, 4], [1, 2, 3], [0, 1, 2]] 10405 )); 10406 }} 10407 10408 alias T = int[]; 10409 10410 // separate checks for infinity 10411 auto infIndex = SliceableRange!(T, No.withOpDollar, Yes.withInfiniteness)([0, 1, 2, 3]); 10412 assert(infIndex.slide!Partial(2)[0].equal([0, 1])); 10413 assert(infIndex.slide!Partial(2)[1].equal([1, 2])); 10414 10415 auto infDollar = SliceableRange!(T, Yes.withOpDollar, Yes.withInfiniteness)(); 10416 assert(infDollar.slide!Partial(2)[1 .. $].front.equal([1, 2])); 10417 assert(infDollar.slide!Partial(4)[0 .. $].front.equal([0, 1, 2, 3])); 10418 assert(infDollar.slide!Partial(4)[2 .. $].front.equal([2, 3, 4, 5])); 10419 }} 10420 } 10421 10422 // https://issues.dlang.org/show_bug.cgi?id=19082 10423 @safe unittest 10424 { 10425 import std.algorithm.comparison : equal; 10426 import std.algorithm.iteration : map; 10427 assert([1].map!(x => x).slide(2).equal!equal([[1]])); 10428 } 10429 10430 // https://issues.dlang.org/show_bug.cgi?id=19642 10431 @safe unittest 10432 { 10433 import std.algorithm.comparison : equal; 10434 import std.algorithm.iteration : splitter; 10435 10436 assert("ab cd".splitter(' ').slide!(No.withPartial)(2).equal!equal([["ab", "cd"]])); 10437 } 10438 10439 // https://issues.dlang.org/show_bug.cgi?id=23976 10440 @safe unittest 10441 { 10442 import std.algorithm.comparison : equal; 10443 import std.algorithm.iteration : splitter; 10444 10445 assert("1<2".splitter('<').slide(2).equal!equal([["1", "2"]])); 10446 } 10447 10448 private struct OnlyResult(Values...) 10449 if (Values.length > 1) 10450 { 10451 import std.meta : ApplyRight; 10452 import std.traits : isAssignable; 10453 10454 private enum arity = Values.length; 10455 10456 private alias UnqualValues = staticMap!(Unqual, Values); 10457 10458 private enum canAssignElements = allSatisfy!( 10459 ApplyRight!(isAssignable, CommonType!Values), 10460 Values 10461 ); 10462 10463 private this(return scope ref Values values) 10464 { 10465 ref @trusted unqual(T)(ref T x){return cast() x;} 10466 10467 // TODO: this calls any possible copy constructors without qualifiers. 10468 // Find a way to initialize values using qualified copy constructors. 10469 static foreach (i; 0 .. Values.length) 10470 { 10471 this.values[i] = unqual(values[i]); 10472 } 10473 this.backIndex = arity; 10474 } 10475 10476 bool empty() @property 10477 { 10478 return frontIndex >= backIndex; 10479 } 10480 10481 CommonType!Values front() @property 10482 { 10483 assert(!empty, "Attempting to fetch the front of an empty Only range"); 10484 return this[0]; 10485 } 10486 10487 static if (canAssignElements) 10488 { 10489 void front(CommonType!Values value) @property 10490 { 10491 assert(!empty, "Attempting to assign the front of an empty Only range"); 10492 this[0] = value; 10493 } 10494 } 10495 10496 void popFront() 10497 { 10498 assert(!empty, "Attempting to popFront an empty Only range"); 10499 ++frontIndex; 10500 } 10501 10502 CommonType!Values back() @property 10503 { 10504 assert(!empty, "Attempting to fetch the back of an empty Only range"); 10505 return this[$ - 1]; 10506 } 10507 10508 static if (canAssignElements) 10509 { 10510 void back(CommonType!Values value) @property 10511 { 10512 assert(!empty, "Attempting to assign the back of an empty Only range"); 10513 this[$ - 1] = value; 10514 } 10515 } 10516 10517 void popBack() 10518 { 10519 assert(!empty, "Attempting to popBack an empty Only range"); 10520 --backIndex; 10521 } 10522 10523 OnlyResult save() @property 10524 { 10525 return this; 10526 } 10527 10528 size_t length() const @property 10529 { 10530 return backIndex - frontIndex; 10531 } 10532 10533 alias opDollar = length; 10534 10535 @trusted CommonType!Values opIndex(size_t idx) 10536 { 10537 // when i + idx points to elements popped 10538 // with popBack 10539 assert(idx < length, "Attempting to fetch an out of bounds index from an Only range"); 10540 final switch (frontIndex + idx) 10541 static foreach (i, T; Values) 10542 case i: 10543 return cast(T) values[i]; 10544 } 10545 10546 static if (canAssignElements) 10547 { 10548 void opIndexAssign(CommonType!Values value, size_t idx) 10549 { 10550 assert(idx < length, "Attempting to assign to an out of bounds index of an Only range"); 10551 final switch (frontIndex + idx) 10552 static foreach (i; 0 .. Values.length) 10553 case i: 10554 values[i] = value; 10555 } 10556 } 10557 10558 OnlyResult opSlice() 10559 { 10560 return this; 10561 } 10562 10563 OnlyResult opSlice(size_t from, size_t to) 10564 { 10565 OnlyResult result = this; 10566 result.frontIndex += from; 10567 result.backIndex = this.frontIndex + to; 10568 assert( 10569 from <= to, 10570 "Attempting to slice an Only range with a larger first argument than the second." 10571 ); 10572 assert( 10573 to <= length, 10574 "Attempting to slice using an out of bounds index on an Only range" 10575 ); 10576 return result; 10577 } 10578 10579 private size_t frontIndex = 0; 10580 private size_t backIndex = 0; 10581 10582 // https://issues.dlang.org/show_bug.cgi?id=10643 10583 version (none) 10584 { 10585 import std.traits : hasElaborateAssign; 10586 static if (hasElaborateAssign!T) 10587 private UnqualValues values; 10588 else 10589 private UnqualValues values = void; 10590 } 10591 else 10592 // These may alias to shared or immutable data. Do not let the user 10593 // to access these directly, and do not allow mutation without checking 10594 // the qualifier. 10595 private UnqualValues values; 10596 } 10597 10598 // Specialize for single-element results 10599 private struct OnlyResult(T) 10600 { 10601 import std.traits : isAssignable; 10602 10603 @property T front() 10604 { 10605 assert(!empty, "Attempting to fetch the front of an empty Only range"); 10606 return fetchFront(); 10607 } 10608 static if (isAssignable!T) 10609 { 10610 @property void front(T value) 10611 { 10612 assert(!empty, "Attempting to assign the front of an empty Only range"); 10613 assignFront(value); 10614 } 10615 } 10616 @property T back() 10617 { 10618 assert(!empty, "Attempting to fetch the back of an empty Only range"); 10619 return fetchFront(); 10620 } 10621 static if (isAssignable!T) 10622 { 10623 @property void back(T value) 10624 { 10625 assert(!empty, "Attempting to assign the front of an empty Only range"); 10626 assignFront(value); 10627 } 10628 } 10629 @property bool empty() const { return _empty; } 10630 @property size_t length() const { return !_empty; } 10631 @property auto save() { return this; } 10632 void popFront() 10633 { 10634 assert(!_empty, "Attempting to popFront an empty Only range"); 10635 _empty = true; 10636 } 10637 void popBack() 10638 { 10639 assert(!_empty, "Attempting to popBack an empty Only range"); 10640 _empty = true; 10641 } 10642 alias opDollar = length; 10643 10644 // FIXME Workaround for https://issues.dlang.org/show_bug.cgi?id=24415 10645 import std.traits : hasElaborateCopyConstructor; 10646 static if (hasElaborateCopyConstructor!T) 10647 { 10648 private static struct WorkaroundBugzilla24415 {} 10649 public this()(WorkaroundBugzilla24415) {} 10650 } 10651 10652 private this()(return scope auto ref T value) 10653 { 10654 ref @trusted unqual(ref T x){return cast() x;} 10655 // TODO: this calls the possible copy constructor without qualifiers. 10656 // Find a way to initialize value using a qualified copy constructor. 10657 this._value = unqual(value); 10658 this._empty = false; 10659 } 10660 10661 T opIndex(size_t i) 10662 { 10663 assert(!_empty && i == 0, "Attempting to fetch an out of bounds index from an Only range"); 10664 return fetchFront(); 10665 } 10666 10667 static if (isAssignable!T) 10668 { 10669 void opIndexAssign(T value, size_t i) 10670 { 10671 assert(!_empty && i == 0, "Attempting to assign an out of bounds index of an Only range"); 10672 assignFront(value); 10673 } 10674 } 10675 10676 OnlyResult opSlice() 10677 { 10678 return this; 10679 } 10680 10681 OnlyResult opSlice(size_t from, size_t to) 10682 { 10683 assert( 10684 from <= to, 10685 "Attempting to slice an Only range with a larger first argument than the second." 10686 ); 10687 assert( 10688 to <= length, 10689 "Attempting to slice using an out of bounds index on an Only range" 10690 ); 10691 OnlyResult copy = this; 10692 copy._empty = _empty || from == to; 10693 return copy; 10694 } 10695 10696 // This may alias to shared or immutable data. Do not let the user 10697 // to access this directly, and do not allow mutation without checking 10698 // the qualifier. 10699 private Unqual!T _value; 10700 private bool _empty = true; 10701 private @trusted T fetchFront() 10702 { 10703 return *cast(T*)&_value; 10704 } 10705 static if (isAssignable!T) 10706 { 10707 private @trusted void assignFront(T newValue) 10708 { 10709 *cast(T*) &_value = newValue; 10710 } 10711 } 10712 } 10713 10714 /** 10715 Assemble `values` into a range that carries all its 10716 elements in-situ. 10717 10718 Useful when a single value or multiple disconnected values 10719 must be passed to an algorithm expecting a range, without 10720 having to perform dynamic memory allocation. 10721 10722 As copying the range means copying all elements, it can be 10723 safely returned from functions. For the same reason, copying 10724 the returned range may be expensive for a large number of arguments. 10725 10726 Params: 10727 values = the values to assemble together 10728 10729 Returns: 10730 A `RandomAccessRange` of the assembled values. 10731 10732 The returned range can be sliced. Its elements can be assigned to if every 10733 type in `Values` supports assignment from the range's element type. 10734 10735 See_Also: $(LREF chain) to chain ranges 10736 */ 10737 auto only(Values...)(return scope Values values) 10738 if (!is(CommonType!Values == void)) 10739 { 10740 return OnlyResult!Values(values); 10741 } 10742 10743 /// ditto 10744 auto only()() 10745 { 10746 // cannot use noreturn due to https://issues.dlang.org/show_bug.cgi?id=22383 10747 struct EmptyElementType {} 10748 EmptyElementType[] result; 10749 return result; 10750 } 10751 10752 /// 10753 @safe unittest 10754 { 10755 import std.algorithm.comparison : equal; 10756 import std.algorithm.iteration : filter, joiner, map; 10757 import std.algorithm.searching : findSplitBefore; 10758 import std.uni : isUpper; 10759 10760 assert(equal(only('♡'), "♡")); 10761 assert([1, 2, 3, 4].findSplitBefore(only(3))[0] == [1, 2]); 10762 10763 assert(only("one", "two", "three").joiner(" ").equal("one two three")); 10764 10765 string title = "The D Programming Language"; 10766 assert(title 10767 .filter!isUpper // take the upper case letters 10768 .map!only // make each letter its own range 10769 .joiner(".") // join the ranges together lazily 10770 .equal("T.D.P.L")); 10771 } 10772 10773 // https://issues.dlang.org/show_bug.cgi?id=20314 10774 @safe unittest 10775 { 10776 import std.algorithm.iteration : joiner; 10777 10778 const string s = "foo", t = "bar"; 10779 10780 assert([only(s, t), only(t, s)].joiner(only(", ")).join == "foobar, barfoo"); 10781 } 10782 10783 // Tests the zero-element result 10784 @safe unittest 10785 { 10786 import std.algorithm.comparison : equal; 10787 10788 auto emptyRange = only(); 10789 10790 alias EmptyRange = typeof(emptyRange); 10791 static assert(isInputRange!EmptyRange); 10792 static assert(isForwardRange!EmptyRange); 10793 static assert(isBidirectionalRange!EmptyRange); 10794 static assert(isRandomAccessRange!EmptyRange); 10795 static assert(hasLength!EmptyRange); 10796 static assert(hasSlicing!EmptyRange); 10797 10798 assert(emptyRange.empty); 10799 assert(emptyRange.length == 0); 10800 assert(emptyRange.equal(emptyRange[])); 10801 assert(emptyRange.equal(emptyRange.save)); 10802 assert(emptyRange[0 .. 0].equal(emptyRange)); 10803 } 10804 10805 // Tests the single-element result 10806 @safe unittest 10807 { 10808 import std.algorithm.comparison : equal; 10809 import std.typecons : tuple; 10810 foreach (x; tuple(1, '1', 1.0, "1", [1])) 10811 { 10812 auto a = only(x); 10813 typeof(x)[] e = []; 10814 assert(a.front == x); 10815 assert(a.back == x); 10816 assert(!a.empty); 10817 assert(a.length == 1); 10818 assert(equal(a, a[])); 10819 assert(equal(a, a[0 .. 1])); 10820 assert(equal(a[0 .. 0], e)); 10821 assert(equal(a[1 .. 1], e)); 10822 assert(a[0] == x); 10823 10824 auto b = a.save; 10825 assert(equal(a, b)); 10826 a.popFront(); 10827 assert(a.empty && a.length == 0 && a[].empty); 10828 b.popBack(); 10829 assert(b.empty && b.length == 0 && b[].empty); 10830 10831 alias A = typeof(a); 10832 static assert(isInputRange!A); 10833 static assert(isForwardRange!A); 10834 static assert(isBidirectionalRange!A); 10835 static assert(isRandomAccessRange!A); 10836 static assert(hasLength!A); 10837 static assert(hasSlicing!A); 10838 } 10839 10840 auto imm = only!(immutable int)(1); 10841 immutable int[] imme = []; 10842 assert(imm.front == 1); 10843 assert(imm.back == 1); 10844 assert(!imm.empty); 10845 assert(imm.init.empty); // https://issues.dlang.org/show_bug.cgi?id=13441 10846 assert(imm.length == 1); 10847 assert(equal(imm, imm[])); 10848 assert(equal(imm, imm[0 .. 1])); 10849 assert(equal(imm[0 .. 0], imme)); 10850 assert(equal(imm[1 .. 1], imme)); 10851 assert(imm[0] == 1); 10852 } 10853 10854 // Tests multiple-element results 10855 @safe unittest 10856 { 10857 import std.algorithm.comparison : equal; 10858 import std.algorithm.iteration : joiner; 10859 import std.meta : AliasSeq; 10860 static assert(!__traits(compiles, only(1, "1"))); 10861 10862 auto nums = only!(byte, uint, long)(1, 2, 3); 10863 static assert(is(ElementType!(typeof(nums)) == long)); 10864 assert(nums.length == 3); 10865 10866 foreach (i; 0 .. 3) 10867 assert(nums[i] == i + 1); 10868 10869 auto saved = nums.save; 10870 10871 foreach (i; 1 .. 4) 10872 { 10873 assert(nums.front == nums[0]); 10874 assert(nums.front == i); 10875 nums.popFront(); 10876 assert(nums.length == 3 - i); 10877 } 10878 10879 assert(nums.empty); 10880 10881 assert(saved.equal(only(1, 2, 3))); 10882 assert(saved.equal(saved[])); 10883 assert(saved[0 .. 1].equal(only(1))); 10884 assert(saved[0 .. 2].equal(only(1, 2))); 10885 assert(saved[0 .. 3].equal(saved)); 10886 assert(saved[1 .. 3].equal(only(2, 3))); 10887 assert(saved[2 .. 3].equal(only(3))); 10888 assert(saved[0 .. 0].empty); 10889 assert(saved[3 .. 3].empty); 10890 10891 alias data = AliasSeq!("one", "two", "three", "four"); 10892 static joined = 10893 ["one two", "one two three", "one two three four"]; 10894 string[] joinedRange = joined; 10895 10896 static foreach (argCount; 2 .. 5) 10897 {{ 10898 auto values = only(data[0 .. argCount]); 10899 alias Values = typeof(values); 10900 static assert(is(ElementType!Values == string)); 10901 static assert(isInputRange!Values); 10902 static assert(isForwardRange!Values); 10903 static assert(isBidirectionalRange!Values); 10904 static assert(isRandomAccessRange!Values); 10905 static assert(hasSlicing!Values); 10906 static assert(hasLength!Values); 10907 10908 assert(values.length == argCount); 10909 assert(values[0 .. $].equal(values[0 .. values.length])); 10910 assert(values.joiner(" ").equal(joinedRange.front)); 10911 joinedRange.popFront(); 10912 }} 10913 10914 assert(saved.retro.equal(only(3, 2, 1))); 10915 assert(saved.length == 3); 10916 10917 assert(saved.back == 3); 10918 saved.popBack(); 10919 assert(saved.length == 2); 10920 assert(saved.back == 2); 10921 10922 assert(saved.front == 1); 10923 saved.popFront(); 10924 assert(saved.length == 1); 10925 assert(saved.front == 2); 10926 10927 saved.popBack(); 10928 assert(saved.empty); 10929 10930 auto imm = only!(immutable int, immutable int)(42, 24); 10931 alias Imm = typeof(imm); 10932 static assert(is(ElementType!Imm == immutable(int))); 10933 assert(!imm.empty); 10934 assert(imm.init.empty); // https://issues.dlang.org/show_bug.cgi?id=13441 10935 assert(imm.front == 42); 10936 imm.popFront(); 10937 assert(imm.front == 24); 10938 imm.popFront(); 10939 assert(imm.empty); 10940 10941 static struct Test { int* a; } 10942 immutable(Test) test; 10943 cast(void) only(test, test); // Works with mutable indirection 10944 } 10945 10946 // https://issues.dlang.org/show_bug.cgi?id=21129 10947 @safe unittest 10948 { 10949 auto range = () @safe { 10950 const(char)[5] staticStr = "Hello"; 10951 10952 // `only` must store a char[5] - not a char[]! 10953 return only(staticStr, " World"); 10954 } (); 10955 10956 assert(range.join == "Hello World"); 10957 } 10958 10959 // https://issues.dlang.org/show_bug.cgi?id=21129 10960 @safe unittest 10961 { 10962 struct AliasedString 10963 { 10964 const(char)[5] staticStr = "Hello"; 10965 10966 @property const(char)[] slice() const 10967 { 10968 return staticStr[]; 10969 } 10970 alias slice this; 10971 } 10972 10973 auto range = () @safe { 10974 auto hello = AliasedString(); 10975 10976 // a copy of AliasedString is stored in the range. 10977 return only(hello, " World"); 10978 } (); 10979 10980 assert(range.join == "Hello World"); 10981 } 10982 10983 // https://issues.dlang.org/show_bug.cgi?id=21022 10984 @safe pure nothrow unittest 10985 { 10986 struct S 10987 { 10988 int* mem; 10989 } 10990 10991 immutable S x; 10992 immutable(S)[] arr; 10993 auto r1 = arr.chain(x.only, only(x, x)); 10994 } 10995 10996 // https://issues.dlang.org/show_bug.cgi?id=24382 10997 @safe unittest 10998 { 10999 auto r1 = only(123); 11000 r1.front = 456; 11001 r1.back = 456; 11002 r1[0] = 456; 11003 11004 auto r2 = only(123, 456); 11005 r2.front = 789; 11006 r2.back = 789; 11007 r2[0] = 789; 11008 11009 auto r3 = only(1.23, 456); 11010 // Can't assign double to int 11011 static assert(!__traits(compiles, r3.front = 7.89)); 11012 static assert(!__traits(compiles, r3.back = 7.89)); 11013 // Workaround https://issues.dlang.org/show_bug.cgi?id=24383 11014 static assert(!__traits(compiles, () { r3[0] = 7.89; })); 11015 // Can't assign type other than element type (even if compatible) 11016 static assert(!__traits(compiles, r3.front = 789)); 11017 static assert(!__traits(compiles, r3.back = 789)); 11018 // Workaround https://issues.dlang.org/show_bug.cgi?id=24383 11019 static assert(!__traits(compiles, () { r3[0] = 789; })); 11020 } 11021 11022 /** 11023 Iterate over `range` with an attached index variable. 11024 11025 Each element is a $(REF Tuple, std,typecons) containing the index 11026 and the element, in that order, where the index member is named `index` 11027 and the element member is named `value`. 11028 11029 The index starts at `start` and is incremented by one on every iteration. 11030 11031 Overflow: 11032 If `range` has length, then it is an error to pass a value for `start` 11033 so that `start + range.length` is bigger than `Enumerator.max`, thus 11034 it is ensured that overflow cannot happen. 11035 11036 If `range` does not have length, and `popFront` is called when 11037 `front.index == Enumerator.max`, the index will overflow and 11038 continue from `Enumerator.min`. 11039 11040 Params: 11041 range = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to attach indexes to 11042 start = the number to start the index counter from 11043 11044 Returns: 11045 At minimum, an input range. All other range primitives are given in the 11046 resulting range if `range` has them. The exceptions are the bidirectional 11047 primitives, which are propagated only if `range` has length. 11048 11049 Example: 11050 Useful for using `foreach` with an index loop variable: 11051 ---- 11052 import std.stdio : stdin, stdout; 11053 import std.range : enumerate; 11054 11055 foreach (lineNum, line; stdin.byLine().enumerate(1)) 11056 stdout.writefln("line #%s: %s", lineNum, line); 11057 ---- 11058 */ 11059 auto enumerate(Enumerator = size_t, Range)(Range range, Enumerator start = 0) 11060 if (isIntegral!Enumerator && isInputRange!Range) 11061 in 11062 { 11063 static if (hasLength!Range) 11064 { 11065 // TODO: core.checkedint supports mixed signedness yet? 11066 import core.checkedint : adds, addu; 11067 import std.conv : ConvException, to; 11068 import std.traits : isSigned, Largest, Signed; 11069 11070 alias LengthType = typeof(range.length); 11071 bool overflow; 11072 static if (isSigned!Enumerator && isSigned!LengthType) 11073 auto result = adds(start, range.length, overflow); 11074 else static if (isSigned!Enumerator) 11075 { 11076 alias signed_t = Largest!(Enumerator, Signed!LengthType); 11077 signed_t signedLength; 11078 //This is to trick the compiler because if length is enum 11079 //the compiler complains about unreachable code. 11080 auto getLength() 11081 { 11082 return range.length; 11083 } 11084 //Can length fit in the signed type 11085 assert(getLength() < signed_t.max, 11086 "a signed length type is required but the range's length() is too great"); 11087 signedLength = range.length; 11088 auto result = adds(start, signedLength, overflow); 11089 } 11090 else 11091 { 11092 static if (isSigned!LengthType) 11093 assert(range.length >= 0); 11094 auto result = addu(start, range.length, overflow); 11095 } 11096 11097 assert(!overflow && result <= Enumerator.max); 11098 } 11099 } 11100 do 11101 { 11102 // TODO: Relax isIntegral!Enumerator to allow user-defined integral types 11103 static struct Result 11104 { 11105 import std.typecons : Tuple; 11106 11107 private: 11108 alias ElemType = Tuple!(Enumerator, "index", ElementType!Range, "value"); 11109 Range range; 11110 Unqual!Enumerator index; 11111 11112 public: 11113 ElemType front() @property 11114 { 11115 assert(!range.empty, "Attempting to fetch the front of an empty enumerate"); 11116 return typeof(return)(index, range.front); 11117 } 11118 11119 static if (isInfinite!Range) 11120 enum bool empty = false; 11121 else 11122 { 11123 bool empty() @property 11124 { 11125 return range.empty; 11126 } 11127 } 11128 11129 void popFront() 11130 { 11131 assert(!range.empty, "Attempting to popFront an empty enumerate"); 11132 range.popFront(); 11133 ++index; // When !hasLength!Range, overflow is expected 11134 } 11135 11136 static if (isForwardRange!Range) 11137 { 11138 Result save() @property 11139 { 11140 return typeof(return)(range.save, index); 11141 } 11142 } 11143 11144 static if (hasLength!Range) 11145 { 11146 mixin ImplementLength!range; 11147 11148 static if (isBidirectionalRange!Range) 11149 { 11150 ElemType back() @property 11151 { 11152 assert(!range.empty, "Attempting to fetch the back of an empty enumerate"); 11153 return typeof(return)(cast(Enumerator)(index + range.length - 1), range.back); 11154 } 11155 11156 void popBack() 11157 { 11158 assert(!range.empty, "Attempting to popBack an empty enumerate"); 11159 range.popBack(); 11160 } 11161 } 11162 } 11163 11164 static if (isRandomAccessRange!Range) 11165 { 11166 ElemType opIndex(size_t i) 11167 { 11168 return typeof(return)(cast(Enumerator)(index + i), range[i]); 11169 } 11170 } 11171 11172 static if (hasSlicing!Range) 11173 { 11174 static if (hasLength!Range) 11175 { 11176 Result opSlice(size_t i, size_t j) 11177 { 11178 return typeof(return)(range[i .. j], cast(Enumerator)(index + i)); 11179 } 11180 } 11181 else 11182 { 11183 static struct DollarToken {} 11184 enum opDollar = DollarToken.init; 11185 11186 Result opSlice(size_t i, DollarToken) 11187 { 11188 return typeof(return)(range[i .. $], cast(Enumerator)(index + i)); 11189 } 11190 11191 auto opSlice(size_t i, size_t j) 11192 { 11193 return this[i .. $].takeExactly(j - 1); 11194 } 11195 } 11196 } 11197 } 11198 11199 return Result(range, start); 11200 } 11201 11202 /// Can start enumeration from a negative position: 11203 pure @safe nothrow unittest 11204 { 11205 import std.array : assocArray; 11206 import std.range : enumerate; 11207 11208 bool[int] aa = true.repeat(3).enumerate(-1).assocArray(); 11209 assert(aa[-1]); 11210 assert(aa[0]); 11211 assert(aa[1]); 11212 } 11213 11214 // Make sure passing qualified types works 11215 pure @safe nothrow unittest 11216 { 11217 char[4] v; 11218 immutable start = 2; 11219 v[2 .. $].enumerate(start); 11220 } 11221 11222 pure @safe nothrow unittest 11223 { 11224 import std.internal.test.dummyrange : AllDummyRanges; 11225 import std.meta : AliasSeq; 11226 import std.typecons : tuple; 11227 11228 static struct HasSlicing 11229 { 11230 typeof(this) front() @property { return typeof(this).init; } 11231 bool empty() @property { return true; } 11232 void popFront() {} 11233 11234 typeof(this) opSlice(size_t, size_t) 11235 { 11236 return typeof(this)(); 11237 } 11238 } 11239 11240 static foreach (DummyType; AliasSeq!(AllDummyRanges, HasSlicing)) 11241 {{ 11242 alias R = typeof(enumerate(DummyType.init)); 11243 static assert(isInputRange!R); 11244 static assert(isForwardRange!R == isForwardRange!DummyType); 11245 static assert(isRandomAccessRange!R == isRandomAccessRange!DummyType); 11246 static assert(!hasAssignableElements!R); 11247 11248 static if (hasLength!DummyType) 11249 { 11250 static assert(hasLength!R); 11251 static assert(isBidirectionalRange!R == 11252 isBidirectionalRange!DummyType); 11253 } 11254 11255 static assert(hasSlicing!R == hasSlicing!DummyType); 11256 }} 11257 11258 static immutable values = ["zero", "one", "two", "three"]; 11259 auto enumerated = values[].enumerate(); 11260 assert(!enumerated.empty); 11261 assert(enumerated.front == tuple(0, "zero")); 11262 assert(enumerated.back == tuple(3, "three")); 11263 11264 typeof(enumerated) saved = enumerated.save; 11265 saved.popFront(); 11266 assert(enumerated.front == tuple(0, "zero")); 11267 assert(saved.front == tuple(1, "one")); 11268 assert(saved.length == enumerated.length - 1); 11269 saved.popBack(); 11270 assert(enumerated.back == tuple(3, "three")); 11271 assert(saved.back == tuple(2, "two")); 11272 saved.popFront(); 11273 assert(saved.front == tuple(2, "two")); 11274 assert(saved.back == tuple(2, "two")); 11275 saved.popFront(); 11276 assert(saved.empty); 11277 11278 size_t control = 0; 11279 foreach (i, v; enumerated) 11280 { 11281 static assert(is(typeof(i) == size_t)); 11282 static assert(is(typeof(v) == typeof(values[0]))); 11283 assert(i == control); 11284 assert(v == values[i]); 11285 assert(tuple(i, v) == enumerated[i]); 11286 ++control; 11287 } 11288 11289 assert(enumerated[0 .. $].front == tuple(0, "zero")); 11290 assert(enumerated[$ - 1 .. $].front == tuple(3, "three")); 11291 11292 foreach (i; 0 .. 10) 11293 { 11294 auto shifted = values[0 .. 2].enumerate(i); 11295 assert(shifted.front == tuple(i, "zero")); 11296 assert(shifted[0] == shifted.front); 11297 11298 auto next = tuple(i + 1, "one"); 11299 assert(shifted[1] == next); 11300 shifted.popFront(); 11301 assert(shifted.front == next); 11302 shifted.popFront(); 11303 assert(shifted.empty); 11304 } 11305 11306 static foreach (T; AliasSeq!(ubyte, byte, uint, int)) 11307 {{ 11308 auto inf = 42.repeat().enumerate(T.max); 11309 alias Inf = typeof(inf); 11310 static assert(isInfinite!Inf); 11311 static assert(hasSlicing!Inf); 11312 11313 // test overflow 11314 assert(inf.front == tuple(T.max, 42)); 11315 inf.popFront(); 11316 assert(inf.front == tuple(T.min, 42)); 11317 11318 // test slicing 11319 inf = inf[42 .. $]; 11320 assert(inf.front == tuple(T.min + 42, 42)); 11321 auto window = inf[0 .. 2]; 11322 assert(window.length == 1); 11323 assert(window.front == inf.front); 11324 window.popFront(); 11325 assert(window.empty); 11326 }} 11327 } 11328 11329 pure @safe unittest 11330 { 11331 import std.algorithm.comparison : equal; 11332 import std.meta : AliasSeq; 11333 static immutable int[] values = [0, 1, 2, 3, 4]; 11334 static foreach (T; AliasSeq!(ubyte, ushort, uint, ulong)) 11335 {{ 11336 auto enumerated = values.enumerate!T(); 11337 static assert(is(typeof(enumerated.front.index) == T)); 11338 assert(enumerated.equal(values[].zip(values))); 11339 11340 foreach (T i; 0 .. 5) 11341 { 11342 auto subset = values[cast(size_t) i .. $]; 11343 auto offsetEnumerated = subset.enumerate(i); 11344 static assert(is(typeof(enumerated.front.index) == T)); 11345 assert(offsetEnumerated.equal(subset.zip(subset))); 11346 } 11347 }} 11348 } 11349 @nogc @safe unittest 11350 { 11351 const val = iota(1, 100).enumerate(1); 11352 } 11353 @nogc @safe unittest 11354 { 11355 import core.exception : AssertError; 11356 import std.exception : assertThrown; 11357 struct RangePayload { 11358 enum length = size_t.max; 11359 void popFront() {} 11360 int front() { return 0; } 11361 bool empty() { return true; } 11362 } 11363 RangePayload thePayload; 11364 //Assertion won't happen when contracts are disabled for -release. 11365 debug assertThrown!AssertError(enumerate(thePayload, -10)); 11366 } 11367 // https://issues.dlang.org/show_bug.cgi?id=10939 11368 version (none) 11369 { 11370 // Re-enable (or remove) if 10939 is resolved. 11371 /+pure+/ @safe unittest // Impure because of std.conv.to 11372 { 11373 import core.exception : RangeError; 11374 import std.exception : assertNotThrown, assertThrown; 11375 import std.meta : AliasSeq; 11376 11377 static immutable values = [42]; 11378 11379 static struct SignedLengthRange 11380 { 11381 immutable(int)[] _values = values; 11382 11383 int front() @property { assert(false); } 11384 bool empty() @property { assert(false); } 11385 void popFront() { assert(false); } 11386 11387 int length() @property 11388 { 11389 return cast(int)_values.length; 11390 } 11391 } 11392 11393 SignedLengthRange svalues; 11394 static foreach (Enumerator; AliasSeq!(ubyte, byte, ushort, short, uint, int, ulong, long)) 11395 { 11396 assertThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max)); 11397 assertNotThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max - values.length)); 11398 assertThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max - values.length + 1)); 11399 11400 assertThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max)); 11401 assertNotThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max - values.length)); 11402 assertThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max - values.length + 1)); 11403 } 11404 11405 static foreach (Enumerator; AliasSeq!(byte, short, int)) 11406 { 11407 assertThrown!RangeError(repeat(0, uint.max).enumerate!Enumerator()); 11408 } 11409 11410 assertNotThrown!RangeError(repeat(0, uint.max).enumerate!long()); 11411 } 11412 } 11413 11414 /** 11415 Returns true if `fn` accepts variables of type T1 and T2 in any order. 11416 The following code should compile: 11417 --- 11418 (ref T1 a, ref T2 b) 11419 { 11420 fn(a, b); 11421 fn(b, a); 11422 } 11423 --- 11424 */ 11425 template isTwoWayCompatible(alias fn, T1, T2) 11426 { 11427 enum isTwoWayCompatible = is(typeof((ref T1 a, ref T2 b) 11428 { 11429 cast(void) fn(a, b); 11430 cast(void) fn(b, a); 11431 } 11432 )); 11433 } 11434 11435 /// 11436 @safe unittest 11437 { 11438 void func1(int a, int b); 11439 void func2(int a, float b); 11440 11441 static assert(isTwoWayCompatible!(func1, int, int)); 11442 static assert(isTwoWayCompatible!(func1, short, int)); 11443 static assert(!isTwoWayCompatible!(func2, int, float)); 11444 11445 void func3(ref int a, ref int b); 11446 static assert( isTwoWayCompatible!(func3, int, int)); 11447 static assert(!isTwoWayCompatible!(func3, short, int)); 11448 } 11449 11450 11451 /** 11452 Policy used with the searching primitives `lowerBound`, $(D 11453 upperBound), and `equalRange` of $(LREF SortedRange) below. 11454 */ 11455 enum SearchPolicy 11456 { 11457 /** 11458 Searches in a linear fashion. 11459 */ 11460 linear, 11461 11462 /** 11463 Searches with a step that is grows linearly (1, 2, 3,...) 11464 leading to a quadratic search schedule (indexes tried are 0, 1, 11465 3, 6, 10, 15, 21, 28,...) Once the search overshoots its target, 11466 the remaining interval is searched using binary search. The 11467 search is completed in $(BIGOH sqrt(n)) time. Use it when you 11468 are reasonably confident that the value is around the beginning 11469 of the range. 11470 */ 11471 trot, 11472 11473 /** 11474 Performs a $(LINK2 https://en.wikipedia.org/wiki/Exponential_search, 11475 galloping search algorithm), i.e. searches 11476 with a step that doubles every time, (1, 2, 4, 8, ...) leading 11477 to an exponential search schedule (indexes tried are 0, 1, 3, 11478 7, 15, 31, 63,...) Once the search overshoots its target, the 11479 remaining interval is searched using binary search. A value is 11480 found in $(BIGOH log(n)) time. 11481 */ 11482 gallop, 11483 11484 /** 11485 Searches using a classic interval halving policy. The search 11486 starts in the middle of the range, and each search step cuts 11487 the range in half. This policy finds a value in $(BIGOH log(n)) 11488 time but is less cache friendly than `gallop` for large 11489 ranges. The `binarySearch` policy is used as the last step 11490 of `trot`, `gallop`, `trotBackwards`, and $(D 11491 gallopBackwards) strategies. 11492 */ 11493 binarySearch, 11494 11495 /** 11496 Similar to `trot` but starts backwards. Use it when 11497 confident that the value is around the end of the range. 11498 */ 11499 trotBackwards, 11500 11501 /** 11502 Similar to `gallop` but starts backwards. Use it when 11503 confident that the value is around the end of the range. 11504 */ 11505 gallopBackwards 11506 } 11507 11508 /// 11509 @safe unittest 11510 { 11511 import std.algorithm.comparison : equal; 11512 11513 auto a = assumeSorted([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); 11514 auto p1 = a.upperBound!(SearchPolicy.binarySearch)(3); 11515 assert(p1.equal([4, 5, 6, 7, 8, 9])); 11516 11517 auto p2 = a.lowerBound!(SearchPolicy.gallop)(4); 11518 assert(p2.equal([0, 1, 2, 3])); 11519 } 11520 11521 /** 11522 Options for $(LREF SortedRange) ranges (below). 11523 */ 11524 enum SortedRangeOptions 11525 { 11526 /** 11527 Assume, that the range is sorted without checking. 11528 */ 11529 assumeSorted, 11530 11531 /** 11532 All elements of the range are checked to be sorted. 11533 The check is performed in O(n) time. 11534 */ 11535 checkStrictly, 11536 11537 /** 11538 Some elements of the range are checked to be sorted. 11539 For ranges with random order, this will almost surely 11540 detect, that it is not sorted. For almost sorted ranges 11541 it's more likely to fail. The checked elements are choosen 11542 in a deterministic manner, which makes this check reproducable. 11543 The check is performed in O(log(n)) time. 11544 */ 11545 checkRoughly, 11546 } 11547 11548 /// 11549 @safe pure unittest 11550 { 11551 // create a SortedRange, that's checked strictly 11552 SortedRange!(int[],"a < b", SortedRangeOptions.checkStrictly)([ 1, 3, 5, 7, 9 ]); 11553 } 11554 11555 /** 11556 Represents a sorted range. In addition to the regular range 11557 primitives, supports additional operations that take advantage of the 11558 ordering, such as merge and binary search. To obtain a $(D 11559 SortedRange) from an unsorted range `r`, use 11560 $(REF sort, std,algorithm,sorting) which sorts `r` in place and returns the 11561 corresponding `SortedRange`. To construct a `SortedRange` from a range 11562 `r` that is known to be already sorted, use $(LREF assumeSorted). 11563 11564 Params: 11565 pred: The predicate used to define the sortedness 11566 opt: Controls how strongly the range is checked for sortedness. 11567 Will only be used for `RandomAccessRanges`. 11568 Will not be used in CTFE. 11569 */ 11570 struct SortedRange(Range, alias pred = "a < b", 11571 SortedRangeOptions opt = SortedRangeOptions.assumeSorted) 11572 if (isInputRange!Range && !isInstanceOf!(SortedRange, Range)) 11573 { 11574 import std.functional : binaryFun; 11575 11576 private alias predFun = binaryFun!pred; 11577 private bool geq(L, R)(L lhs, R rhs) 11578 { 11579 return !predFun(lhs, rhs); 11580 } 11581 private bool gt(L, R)(L lhs, R rhs) 11582 { 11583 return predFun(rhs, lhs); 11584 } 11585 private Range _input; 11586 11587 // Undocummented because a clearer way to invoke is by calling 11588 // assumeSorted. 11589 this(Range input) 11590 { 11591 static if (opt == SortedRangeOptions.checkRoughly) 11592 { 11593 roughlyVerifySorted(input); 11594 } 11595 static if (opt == SortedRangeOptions.checkStrictly) 11596 { 11597 strictlyVerifySorted(input); 11598 } 11599 this._input = input; 11600 } 11601 11602 // Assertion only. 11603 static if (opt == SortedRangeOptions.checkRoughly) 11604 private void roughlyVerifySorted(Range r) 11605 { 11606 if (!__ctfe) 11607 { 11608 static if (isRandomAccessRange!Range && hasLength!Range) 11609 { 11610 import core.bitop : bsr; 11611 import std.algorithm.sorting : isSorted; 11612 import std.exception : enforce; 11613 11614 // Check the sortedness of the input 11615 if (r.length < 2) return; 11616 11617 immutable size_t msb = bsr(r.length) + 1; 11618 assert(msb > 0 && msb <= r.length); 11619 immutable step = r.length / msb; 11620 auto st = stride(r, step); 11621 11622 enforce(isSorted!pred(st), "Range is not sorted"); 11623 } 11624 } 11625 } 11626 11627 // Assertion only. 11628 static if (opt == SortedRangeOptions.checkStrictly) 11629 private void strictlyVerifySorted(Range r) 11630 { 11631 if (!__ctfe) 11632 { 11633 static if (isRandomAccessRange!Range && hasLength!Range) 11634 { 11635 import std.algorithm.sorting : isSorted; 11636 import std.exception : enforce; 11637 11638 enforce(isSorted!pred(r), "Range is not sorted"); 11639 } 11640 } 11641 } 11642 11643 /// Range primitives. 11644 @property bool empty() //const 11645 { 11646 return this._input.empty; 11647 } 11648 11649 /// Ditto 11650 static if (isForwardRange!Range) 11651 @property auto save() 11652 { 11653 // Avoid the constructor 11654 typeof(this) result = this; 11655 result._input = _input.save; 11656 return result; 11657 } 11658 11659 /// Ditto 11660 @property auto ref front() 11661 { 11662 return _input.front; 11663 } 11664 11665 /// Ditto 11666 void popFront() 11667 { 11668 _input.popFront(); 11669 } 11670 11671 /// Ditto 11672 static if (isBidirectionalRange!Range) 11673 { 11674 @property auto ref back() 11675 { 11676 return _input.back; 11677 } 11678 11679 /// Ditto 11680 void popBack() 11681 { 11682 _input.popBack(); 11683 } 11684 } 11685 11686 /// Ditto 11687 static if (isRandomAccessRange!Range) 11688 auto ref opIndex(size_t i) 11689 { 11690 return _input[i]; 11691 } 11692 11693 /// Ditto 11694 static if (hasSlicing!Range) 11695 auto opSlice(size_t a, size_t b) return scope 11696 { 11697 assert( 11698 a <= b, 11699 "Attempting to slice a SortedRange with a larger first argument than the second." 11700 ); 11701 typeof(this) result = this; 11702 result._input = _input[a .. b];// skip checking 11703 return result; 11704 } 11705 11706 mixin ImplementLength!_input; 11707 11708 /** 11709 Releases the controlled range and returns it. 11710 11711 This does the opposite of $(LREF assumeSorted): instead of turning a range 11712 into a `SortedRange`, it extracts the original range back out of the `SortedRange` 11713 using $(REF, move, std,algorithm,mutation). 11714 */ 11715 auto release() return scope 11716 { 11717 import std.algorithm.mutation : move; 11718 return move(_input); 11719 } 11720 11721 /// 11722 static if (is(Range : int[])) 11723 @safe unittest 11724 { 11725 import std.algorithm.sorting : sort; 11726 int[3] data = [ 1, 2, 3 ]; 11727 auto a = assumeSorted(data[]); 11728 assert(a == sort!"a < b"(data[])); 11729 int[] p = a.release(); 11730 assert(p == [ 1, 2, 3 ]); 11731 } 11732 11733 // Assuming a predicate "test" that returns 0 for a left portion 11734 // of the range and then 1 for the rest, returns the index at 11735 // which the first 1 appears. Used internally by the search routines. 11736 private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v) 11737 if (sp == SearchPolicy.binarySearch && isRandomAccessRange!Range && hasLength!Range) 11738 { 11739 size_t first = 0, count = _input.length; 11740 while (count > 0) 11741 { 11742 immutable step = count / 2, it = first + step; 11743 if (!test(_input[it], v)) 11744 { 11745 first = it + 1; 11746 count -= step + 1; 11747 } 11748 else 11749 { 11750 count = step; 11751 } 11752 } 11753 return first; 11754 } 11755 11756 // Specialization for trot and gallop 11757 private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v) 11758 if ((sp == SearchPolicy.trot || sp == SearchPolicy.gallop) 11759 && isRandomAccessRange!Range) 11760 { 11761 if (empty || test(front, v)) return 0; 11762 immutable count = length; 11763 if (count == 1) return 1; 11764 size_t below = 0, above = 1, step = 2; 11765 while (!test(_input[above], v)) 11766 { 11767 // Still too small, update below and increase gait 11768 below = above; 11769 immutable next = above + step; 11770 if (next >= count) 11771 { 11772 // Overshot - the next step took us beyond the end. So 11773 // now adjust next and simply exit the loop to do the 11774 // binary search thingie. 11775 above = count; 11776 break; 11777 } 11778 // Still in business, increase step and continue 11779 above = next; 11780 static if (sp == SearchPolicy.trot) 11781 ++step; 11782 else 11783 step <<= 1; 11784 } 11785 return below + this[below .. above].getTransitionIndex!( 11786 SearchPolicy.binarySearch, test, V)(v); 11787 } 11788 11789 // Specialization for trotBackwards and gallopBackwards 11790 private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v) 11791 if ((sp == SearchPolicy.trotBackwards || sp == SearchPolicy.gallopBackwards) 11792 && isRandomAccessRange!Range) 11793 { 11794 immutable count = length; 11795 if (empty || !test(back, v)) return count; 11796 if (count == 1) return 0; 11797 size_t below = count - 2, above = count - 1, step = 2; 11798 while (test(_input[below], v)) 11799 { 11800 // Still too large, update above and increase gait 11801 above = below; 11802 if (below < step) 11803 { 11804 // Overshot - the next step took us beyond the end. So 11805 // now adjust next and simply fall through to do the 11806 // binary search thingie. 11807 below = 0; 11808 break; 11809 } 11810 // Still in business, increase step and continue 11811 below -= step; 11812 static if (sp == SearchPolicy.trot) 11813 ++step; 11814 else 11815 step <<= 1; 11816 } 11817 return below + this[below .. above].getTransitionIndex!( 11818 SearchPolicy.binarySearch, test, V)(v); 11819 } 11820 11821 // lowerBound 11822 /** 11823 This function uses a search with policy `sp` to find the 11824 largest left subrange on which $(D pred(x, value)) is `true` for 11825 all `x` (e.g., if `pred` is "less than", returns the portion of 11826 the range with elements strictly smaller than `value`). The search 11827 schedule and its complexity are documented in 11828 $(LREF SearchPolicy). 11829 */ 11830 auto lowerBound(SearchPolicy sp = SearchPolicy.binarySearch, V)(V value) 11831 if (isTwoWayCompatible!(predFun, ElementType!Range, V) 11832 && hasSlicing!Range) 11833 { 11834 return this[0 .. getTransitionIndex!(sp, geq)(value)]; 11835 } 11836 11837 /// 11838 static if (is(Range : int[])) 11839 @safe unittest 11840 { 11841 import std.algorithm.comparison : equal; 11842 auto a = assumeSorted([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]); 11843 auto p = a.lowerBound(4); 11844 assert(equal(p, [ 0, 1, 2, 3 ])); 11845 } 11846 11847 // upperBound 11848 /** 11849 This function searches with policy `sp` to find the largest right 11850 subrange on which $(D pred(value, x)) is `true` for all `x` 11851 (e.g., if `pred` is "less than", returns the portion of the range 11852 with elements strictly greater than `value`). The search schedule 11853 and its complexity are documented in $(LREF SearchPolicy). 11854 11855 For ranges that do not offer random access, `SearchPolicy.linear` 11856 is the only policy allowed (and it must be specified explicitly lest it exposes 11857 user code to unexpected inefficiencies). For random-access searches, all 11858 policies are allowed, and `SearchPolicy.binarySearch` is the default. 11859 */ 11860 auto upperBound(SearchPolicy sp = SearchPolicy.binarySearch, V)(V value) 11861 if (isTwoWayCompatible!(predFun, ElementType!Range, V)) 11862 { 11863 static assert(hasSlicing!Range || sp == SearchPolicy.linear, 11864 "Specify SearchPolicy.linear explicitly for " 11865 ~ typeof(this).stringof); 11866 static if (sp == SearchPolicy.linear) 11867 { 11868 for (; !_input.empty && !predFun(value, _input.front); 11869 _input.popFront()) 11870 { 11871 } 11872 return this; 11873 } 11874 else 11875 { 11876 return this[getTransitionIndex!(sp, gt)(value) .. length]; 11877 } 11878 } 11879 11880 /// 11881 static if (is(Range : int[])) 11882 @safe unittest 11883 { 11884 import std.algorithm.comparison : equal; 11885 auto a = assumeSorted([ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]); 11886 auto p = a.upperBound(3); 11887 assert(equal(p, [4, 4, 5, 6])); 11888 } 11889 11890 11891 // equalRange 11892 /** 11893 Returns the subrange containing all elements `e` for which both $(D 11894 pred(e, value)) and $(D pred(value, e)) evaluate to `false` (e.g., 11895 if `pred` is "less than", returns the portion of the range with 11896 elements equal to `value`). Uses a classic binary search with 11897 interval halving until it finds a value that satisfies the condition, 11898 then uses `SearchPolicy.gallopBackwards` to find the left boundary 11899 and `SearchPolicy.gallop` to find the right boundary. These 11900 policies are justified by the fact that the two boundaries are likely 11901 to be near the first found value (i.e., equal ranges are relatively 11902 small). Completes the entire search in $(BIGOH log(n)) time. 11903 */ 11904 auto equalRange(V)(V value) 11905 if (isTwoWayCompatible!(predFun, ElementType!Range, V) 11906 && isRandomAccessRange!Range) 11907 { 11908 size_t first = 0, count = _input.length; 11909 while (count > 0) 11910 { 11911 immutable step = count / 2; 11912 auto it = first + step; 11913 if (predFun(_input[it], value)) 11914 { 11915 // Less than value, bump left bound up 11916 first = it + 1; 11917 count -= step + 1; 11918 } 11919 else if (predFun(value, _input[it])) 11920 { 11921 // Greater than value, chop count 11922 count = step; 11923 } 11924 else 11925 { 11926 // Equal to value, do binary searches in the 11927 // leftover portions 11928 // Gallop towards the left end as it's likely nearby 11929 immutable left = first 11930 + this[first .. it] 11931 .lowerBound!(SearchPolicy.gallopBackwards)(value).length; 11932 first += count; 11933 // Gallop towards the right end as it's likely nearby 11934 immutable right = first 11935 - this[it + 1 .. first] 11936 .upperBound!(SearchPolicy.gallop)(value).length; 11937 return this[left .. right]; 11938 } 11939 } 11940 return this.init; 11941 } 11942 11943 /// 11944 static if (is(Range : int[])) 11945 @safe unittest 11946 { 11947 import std.algorithm.comparison : equal; 11948 auto a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]; 11949 auto r = a.assumeSorted.equalRange(3); 11950 assert(equal(r, [ 3, 3, 3 ])); 11951 } 11952 11953 // trisect 11954 /** 11955 Returns a tuple `r` such that `r[0]` is the same as the result 11956 of `lowerBound(value)`, `r[1]` is the same as the result of $(D 11957 equalRange(value)), and `r[2]` is the same as the result of $(D 11958 upperBound(value)). The call is faster than computing all three 11959 separately. Uses a search schedule similar to $(D 11960 equalRange). Completes the entire search in $(BIGOH log(n)) time. 11961 */ 11962 auto trisect(V)(V value) 11963 if (isTwoWayCompatible!(predFun, ElementType!Range, V) 11964 && isRandomAccessRange!Range && hasLength!Range) 11965 { 11966 import std.typecons : tuple; 11967 size_t first = 0, count = _input.length; 11968 while (count > 0) 11969 { 11970 immutable step = count / 2; 11971 auto it = first + step; 11972 if (predFun(_input[it], value)) 11973 { 11974 // Less than value, bump left bound up 11975 first = it + 1; 11976 count -= step + 1; 11977 } 11978 else if (predFun(value, _input[it])) 11979 { 11980 // Greater than value, chop count 11981 count = step; 11982 } 11983 else 11984 { 11985 // Equal to value, do binary searches in the 11986 // leftover portions 11987 // Gallop towards the left end as it's likely nearby 11988 immutable left = first 11989 + this[first .. it] 11990 .lowerBound!(SearchPolicy.gallopBackwards)(value).length; 11991 first += count; 11992 // Gallop towards the right end as it's likely nearby 11993 immutable right = first 11994 - this[it + 1 .. first] 11995 .upperBound!(SearchPolicy.gallop)(value).length; 11996 return tuple(this[0 .. left], this[left .. right], 11997 this[right .. length]); 11998 } 11999 } 12000 // No equal element was found 12001 return tuple(this[0 .. first], this.init, this[first .. length]); 12002 } 12003 12004 /// 12005 static if (is(Range : int[])) 12006 @safe unittest 12007 { 12008 import std.algorithm.comparison : equal; 12009 auto a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]; 12010 auto r = assumeSorted(a).trisect(3); 12011 assert(equal(r[0], [ 1, 2 ])); 12012 assert(equal(r[1], [ 3, 3, 3 ])); 12013 assert(equal(r[2], [ 4, 4, 5, 6 ])); 12014 } 12015 12016 // contains 12017 /** 12018 Returns `true` if and only if `value` can be found in $(D 12019 range), which is assumed to be sorted. Performs $(BIGOH log(r.length)) 12020 evaluations of `pred`. 12021 */ 12022 12023 bool contains(V)(V value) 12024 if (isRandomAccessRange!Range) 12025 { 12026 if (empty) return false; 12027 immutable i = getTransitionIndex!(SearchPolicy.binarySearch, geq)(value); 12028 if (i >= length) return false; 12029 return !predFun(value, _input[i]); 12030 } 12031 12032 /** 12033 Like `contains`, but the value is specified before the range. 12034 */ 12035 bool opBinaryRight(string op, V)(V value) 12036 if (op == "in" && isRandomAccessRange!Range) 12037 { 12038 return contains(value); 12039 } 12040 12041 // groupBy 12042 /** 12043 Returns a range of subranges of elements that are equivalent according to the 12044 sorting relation. 12045 */ 12046 auto groupBy()() 12047 { 12048 import std.algorithm.iteration : chunkBy; 12049 return _input.chunkBy!((a, b) => !predFun(a, b) && !predFun(b, a)); 12050 } 12051 } 12052 12053 /// ditto 12054 template SortedRange(Range, alias pred = "a < b", 12055 SortedRangeOptions opt = SortedRangeOptions.assumeSorted) 12056 if (isInstanceOf!(SortedRange, Range)) 12057 { 12058 // Avoid nesting SortedRange types (see https://issues.dlang.org/show_bug.cgi?id=18933); 12059 alias SortedRange = SortedRange!(Unqual!(typeof(Range._input)), pred, opt); 12060 } 12061 12062 /// 12063 @safe unittest 12064 { 12065 import std.algorithm.sorting : sort; 12066 auto a = [ 1, 2, 3, 42, 52, 64 ]; 12067 auto r = assumeSorted(a); 12068 assert(r.contains(3)); 12069 assert(!(32 in r)); 12070 auto r1 = sort!"a > b"(a); 12071 assert(3 in r1); 12072 assert(!r1.contains(32)); 12073 assert(r1.release() == [ 64, 52, 42, 3, 2, 1 ]); 12074 } 12075 12076 /** 12077 `SortedRange` could accept ranges weaker than random-access, but it 12078 is unable to provide interesting functionality for them. Therefore, 12079 `SortedRange` is currently restricted to random-access ranges. 12080 12081 No copy of the original range is ever made. If the underlying range is 12082 changed concurrently with its corresponding `SortedRange` in ways 12083 that break its sorted-ness, `SortedRange` will work erratically. 12084 */ 12085 @safe unittest 12086 { 12087 import std.algorithm.mutation : swap; 12088 auto a = [ 1, 2, 3, 42, 52, 64 ]; 12089 auto r = assumeSorted(a); 12090 assert(r.contains(42)); 12091 swap(a[3], a[5]); // illegal to break sortedness of original range 12092 assert(!r.contains(42)); // passes although it shouldn't 12093 } 12094 12095 /** 12096 `SortedRange` can be searched with predicates that do not take 12097 two elements of the underlying range as arguments. 12098 12099 This is useful, if a range of structs is sorted by a member and you 12100 want to search in that range by only providing a value for that member. 12101 12102 */ 12103 @safe unittest 12104 { 12105 import std.algorithm.comparison : equal; 12106 static struct S { int i; } 12107 static bool byI(A, B)(A a, B b) 12108 { 12109 static if (is(A == S)) 12110 return a.i < b; 12111 else 12112 return a < b.i; 12113 } 12114 auto r = assumeSorted!byI([S(1), S(2), S(3)]); 12115 auto lessThanTwo = r.lowerBound(2); 12116 assert(equal(lessThanTwo, [S(1)])); 12117 } 12118 12119 @safe unittest 12120 { 12121 import std.exception : assertThrown, assertNotThrown; 12122 12123 assertNotThrown(SortedRange!(int[])([ 1, 3, 10, 5, 7 ])); 12124 assertThrown(SortedRange!(int[],"a < b", SortedRangeOptions.checkStrictly)([ 1, 3, 10, 5, 7 ])); 12125 12126 // these two checks are implementation depended 12127 assertNotThrown(SortedRange!(int[],"a < b", SortedRangeOptions.checkRoughly)([ 1, 3, 10, 5, 12, 2 ])); 12128 assertThrown(SortedRange!(int[],"a < b", SortedRangeOptions.checkRoughly)([ 1, 3, 10, 5, 2, 12 ])); 12129 } 12130 12131 @safe unittest 12132 { 12133 import std.algorithm.comparison : equal; 12134 12135 auto a = [ 10, 20, 30, 30, 30, 40, 40, 50, 60 ]; 12136 auto r = assumeSorted(a).trisect(30); 12137 assert(equal(r[0], [ 10, 20 ])); 12138 assert(equal(r[1], [ 30, 30, 30 ])); 12139 assert(equal(r[2], [ 40, 40, 50, 60 ])); 12140 12141 r = assumeSorted(a).trisect(35); 12142 assert(equal(r[0], [ 10, 20, 30, 30, 30 ])); 12143 assert(r[1].empty); 12144 assert(equal(r[2], [ 40, 40, 50, 60 ])); 12145 } 12146 12147 @safe unittest 12148 { 12149 import std.algorithm.comparison : equal; 12150 auto a = [ "A", "AG", "B", "E", "F" ]; 12151 auto r = assumeSorted!"cmp(a,b) < 0"(a).trisect("B"w); 12152 assert(equal(r[0], [ "A", "AG" ])); 12153 assert(equal(r[1], [ "B" ])); 12154 assert(equal(r[2], [ "E", "F" ])); 12155 r = assumeSorted!"cmp(a,b) < 0"(a).trisect("A"d); 12156 assert(r[0].empty); 12157 assert(equal(r[1], [ "A" ])); 12158 assert(equal(r[2], [ "AG", "B", "E", "F" ])); 12159 } 12160 12161 @safe unittest 12162 { 12163 import std.algorithm.comparison : equal; 12164 static void test(SearchPolicy pol)() 12165 { 12166 auto a = [ 1, 2, 3, 42, 52, 64 ]; 12167 auto r = assumeSorted(a); 12168 assert(equal(r.lowerBound(42), [1, 2, 3])); 12169 12170 assert(equal(r.lowerBound!(pol)(42), [1, 2, 3])); 12171 assert(equal(r.lowerBound!(pol)(41), [1, 2, 3])); 12172 assert(equal(r.lowerBound!(pol)(43), [1, 2, 3, 42])); 12173 assert(equal(r.lowerBound!(pol)(51), [1, 2, 3, 42])); 12174 assert(equal(r.lowerBound!(pol)(3), [1, 2])); 12175 assert(equal(r.lowerBound!(pol)(55), [1, 2, 3, 42, 52])); 12176 assert(equal(r.lowerBound!(pol)(420), a)); 12177 assert(equal(r.lowerBound!(pol)(0), a[0 .. 0])); 12178 12179 assert(equal(r.upperBound!(pol)(42), [52, 64])); 12180 assert(equal(r.upperBound!(pol)(41), [42, 52, 64])); 12181 assert(equal(r.upperBound!(pol)(43), [52, 64])); 12182 assert(equal(r.upperBound!(pol)(51), [52, 64])); 12183 assert(equal(r.upperBound!(pol)(53), [64])); 12184 assert(equal(r.upperBound!(pol)(55), [64])); 12185 assert(equal(r.upperBound!(pol)(420), a[0 .. 0])); 12186 assert(equal(r.upperBound!(pol)(0), a)); 12187 } 12188 12189 test!(SearchPolicy.trot)(); 12190 test!(SearchPolicy.gallop)(); 12191 test!(SearchPolicy.trotBackwards)(); 12192 test!(SearchPolicy.gallopBackwards)(); 12193 test!(SearchPolicy.binarySearch)(); 12194 } 12195 12196 @safe unittest 12197 { 12198 // Check for small arrays 12199 int[] a; 12200 auto r = assumeSorted(a); 12201 a = [ 1 ]; 12202 r = assumeSorted(a); 12203 a = [ 1, 2 ]; 12204 r = assumeSorted(a); 12205 a = [ 1, 2, 3 ]; 12206 r = assumeSorted(a); 12207 } 12208 12209 @safe unittest 12210 { 12211 import std.algorithm.mutation : swap; 12212 auto a = [ 1, 2, 3, 42, 52, 64 ]; 12213 auto r = assumeSorted(a); 12214 assert(r.contains(42)); 12215 swap(a[3], a[5]); // illegal to break sortedness of original range 12216 assert(!r.contains(42)); // passes although it shouldn't 12217 } 12218 12219 @betterC @nogc nothrow @safe unittest 12220 { 12221 static immutable(int)[] arr = [ 1, 2, 3 ]; 12222 auto s = assumeSorted(arr); 12223 } 12224 12225 @system unittest 12226 { 12227 import std.algorithm.comparison : equal; 12228 int[] arr = [100, 101, 102, 200, 201, 300]; 12229 auto s = assumeSorted!((a, b) => a / 100 < b / 100)(arr); 12230 assert(s.groupBy.equal!equal([[100, 101, 102], [200, 201], [300]])); 12231 } 12232 12233 // Test on an input range 12234 @system unittest 12235 { 12236 import std.conv : text; 12237 import std.file : exists, remove, tempDir; 12238 import std.path : buildPath; 12239 import std.stdio : File; 12240 import std.uuid : randomUUID; 12241 auto name = buildPath(tempDir(), "test.std.range.line-" ~ text(__LINE__) ~ 12242 "." ~ randomUUID().toString()); 12243 auto f = File(name, "w"); 12244 scope(exit) if (exists(name)) remove(name); 12245 // write a sorted range of lines to the file 12246 f.write("abc\ndef\nghi\njkl"); 12247 f.close(); 12248 f.open(name, "r"); 12249 auto r = assumeSorted(f.byLine()); 12250 auto r1 = r.upperBound!(SearchPolicy.linear)("def"); 12251 assert(r1.front == "ghi", r1.front); 12252 f.close(); 12253 } 12254 12255 // https://issues.dlang.org/show_bug.cgi?id=19337 12256 @safe unittest 12257 { 12258 import std.algorithm.sorting : sort; 12259 auto a = [ 1, 2, 3, 42, 52, 64 ]; 12260 a.sort.sort!"a > b"; 12261 } 12262 12263 /** 12264 Assumes `r` is sorted by predicate `pred` and returns the 12265 corresponding $(D SortedRange!(pred, R)) having `r` as support. 12266 To check for sorted-ness at 12267 cost $(BIGOH n), use $(REF isSorted, std,algorithm,sorting). 12268 */ 12269 auto assumeSorted(alias pred = "a < b", R)(R r) 12270 if (isInputRange!(Unqual!R)) 12271 { 12272 // Avoid senseless `SortedRange!(SortedRange!(...), pred)` nesting. 12273 static if (is(R == SortedRange!(RRange, RPred), RRange, alias RPred)) 12274 { 12275 static if (isInputRange!R && __traits(isSame, pred, RPred)) 12276 // If the predicate is the same and we don't need to cast away 12277 // constness for the result to be an input range. 12278 return r; 12279 else 12280 return SortedRange!(Unqual!(typeof(r._input)), pred)(r._input); 12281 } 12282 else 12283 { 12284 return SortedRange!(Unqual!R, pred)(r); 12285 } 12286 } 12287 12288 /// 12289 @safe unittest 12290 { 12291 import std.algorithm.comparison : equal; 12292 12293 int[] a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; 12294 auto p = assumeSorted(a); 12295 12296 assert(equal(p.lowerBound(4), [0, 1, 2, 3])); 12297 assert(equal(p.lowerBound(5), [0, 1, 2, 3, 4])); 12298 assert(equal(p.lowerBound(6), [0, 1, 2, 3, 4, 5])); 12299 assert(equal(p.lowerBound(6.9), [0, 1, 2, 3, 4, 5, 6])); 12300 } 12301 12302 @safe unittest 12303 { 12304 import std.algorithm.comparison : equal; 12305 static assert(isRandomAccessRange!(SortedRange!(int[]))); 12306 int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]; 12307 auto p = assumeSorted(a).upperBound(3); 12308 assert(equal(p, [4, 4, 5, 6 ])); 12309 p = assumeSorted(a).upperBound(4.2); 12310 assert(equal(p, [ 5, 6 ])); 12311 12312 // https://issues.dlang.org/show_bug.cgi?id=18933 12313 // don't create senselessly nested SortedRange types. 12314 assert(is(typeof(assumeSorted(a)) == typeof(assumeSorted(assumeSorted(a))))); 12315 assert(is(typeof(assumeSorted(a)) == typeof(assumeSorted(assumeSorted!"a > b"(a))))); 12316 } 12317 12318 @safe unittest 12319 { 12320 import std.algorithm.comparison : equal; 12321 import std.conv : text; 12322 12323 int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]; 12324 auto p = assumeSorted(a).equalRange(3); 12325 assert(equal(p, [ 3, 3, 3 ]), text(p)); 12326 p = assumeSorted(a).equalRange(4); 12327 assert(equal(p, [ 4, 4 ]), text(p)); 12328 p = assumeSorted(a).equalRange(2); 12329 assert(equal(p, [ 2 ])); 12330 p = assumeSorted(a).equalRange(0); 12331 assert(p.empty); 12332 p = assumeSorted(a).equalRange(7); 12333 assert(p.empty); 12334 p = assumeSorted(a).equalRange(3.0); 12335 assert(equal(p, [ 3, 3, 3])); 12336 } 12337 12338 @safe unittest 12339 { 12340 int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]; 12341 if (a.length) 12342 { 12343 auto b = a[a.length / 2]; 12344 //auto r = sort(a); 12345 //assert(r.contains(b)); 12346 } 12347 } 12348 12349 @safe unittest 12350 { 12351 auto a = [ 5, 7, 34, 345, 677 ]; 12352 auto r = assumeSorted(a); 12353 a = null; 12354 r = assumeSorted(a); 12355 a = [ 1 ]; 12356 r = assumeSorted(a); 12357 } 12358 12359 // https://issues.dlang.org/show_bug.cgi?id=15003 12360 @nogc @safe unittest 12361 { 12362 static immutable a = [1, 2, 3, 4]; 12363 auto r = a.assumeSorted; 12364 } 12365 12366 /++ 12367 Wrapper which effectively makes it possible to pass a range by reference. 12368 Both the original range and the RefRange will always have the exact same 12369 elements. Any operation done on one will affect the other. So, for instance, 12370 if it's passed to a function which would implicitly copy the original range 12371 if it were passed to it, the original range is $(I not) copied but is 12372 consumed as if it were a reference type. 12373 12374 Note: 12375 `save` works as normal and operates on a new range, so if 12376 `save` is ever called on the `RefRange`, then no operations on the 12377 saved range will affect the original. 12378 12379 Params: 12380 range = the range to construct the `RefRange` from 12381 12382 Returns: 12383 A `RefRange`. If the given range is a class type 12384 (and thus is already a reference type), then the original 12385 range is returned rather than a `RefRange`. 12386 +/ 12387 struct RefRange(R) 12388 if (isInputRange!R) 12389 { 12390 public: 12391 12392 /++ +/ 12393 this(R* range) @safe pure nothrow 12394 { 12395 _range = range; 12396 } 12397 12398 12399 /++ 12400 This does not assign the pointer of `rhs` to this `RefRange`. 12401 Rather it assigns the range pointed to by `rhs` to the range pointed 12402 to by this `RefRange`. This is because $(I any) operation on a 12403 `RefRange` is the same is if it occurred to the original range. The 12404 one exception is when a `RefRange` is assigned `null` either 12405 directly or because `rhs` is `null`. In that case, `RefRange` 12406 no longer refers to the original range but is `null`. 12407 +/ 12408 auto opAssign(RefRange rhs) 12409 { 12410 if (_range && rhs._range) 12411 *_range = *rhs._range; 12412 else 12413 _range = rhs._range; 12414 12415 return this; 12416 } 12417 12418 /++ +/ 12419 void opAssign(typeof(null) rhs) 12420 { 12421 _range = null; 12422 } 12423 12424 12425 /++ 12426 A pointer to the wrapped range. 12427 +/ 12428 @property inout(R*) ptr() @safe inout pure nothrow 12429 { 12430 return _range; 12431 } 12432 12433 12434 version (StdDdoc) 12435 { 12436 /++ +/ 12437 @property auto front() {assert(0);} 12438 /++ Ditto +/ 12439 @property auto front() const {assert(0);} 12440 /++ Ditto +/ 12441 @property auto front(ElementType!R value) {assert(0);} 12442 } 12443 else 12444 { 12445 @property auto front() 12446 { 12447 return (*_range).front; 12448 } 12449 12450 static if (is(typeof(((const R* r) => (*r).front)(null)))) @property auto front() const 12451 { 12452 return (*_range).front; 12453 } 12454 12455 static if (is(typeof((*_range).front = (*_range).front))) @property auto front(ElementType!R value) 12456 { 12457 return (*_range).front = value; 12458 } 12459 } 12460 12461 12462 version (StdDdoc) 12463 { 12464 @property bool empty(); /// 12465 @property bool empty() const; ///Ditto 12466 } 12467 else static if (isInfinite!R) 12468 enum empty = false; 12469 else 12470 { 12471 @property bool empty() 12472 { 12473 return (*_range).empty; 12474 } 12475 12476 static if (is(typeof(((const R* r) => (*r).empty)(null)))) @property bool empty() const 12477 { 12478 return (*_range).empty; 12479 } 12480 } 12481 12482 12483 /++ +/ 12484 void popFront() 12485 { 12486 return (*_range).popFront(); 12487 } 12488 12489 12490 version (StdDdoc) 12491 { 12492 /++ 12493 Only defined if `isForwardRange!R` is `true`. 12494 +/ 12495 @property auto save() {assert(0);} 12496 /++ Ditto +/ 12497 @property auto save() const {assert(0);} 12498 /++ Ditto +/ 12499 auto opSlice() {assert(0);} 12500 /++ Ditto +/ 12501 auto opSlice() const {assert(0);} 12502 } 12503 else static if (isForwardRange!R) 12504 { 12505 import std.traits : isSafe; 12506 private alias S = typeof((() => (*_range).save)()); 12507 12508 static if (is(typeof(((const R* r) => (*r).save)(null)))) 12509 private alias CS = typeof(((const R* r) => (*r).save)(null)); 12510 12511 12512 static if (isSafe!((R* r) => (*r).save)) 12513 { 12514 @property RefRange!S save() @trusted 12515 { 12516 mixin(_genSave()); 12517 } 12518 12519 static if (is(typeof(((const R* r) => (*r).save)(null)))) @property RefRange!CS save() @trusted const 12520 { 12521 mixin(_genSave()); 12522 } 12523 } 12524 else 12525 { 12526 @property RefRange!S save() 12527 { 12528 mixin(_genSave()); 12529 } 12530 12531 static if (is(typeof(((const R* r) => (*r).save)(null)))) @property RefRange!CS save() const 12532 { 12533 mixin(_genSave()); 12534 } 12535 } 12536 12537 auto opSlice()() 12538 { 12539 return save; 12540 } 12541 12542 auto opSlice()() const 12543 { 12544 return save; 12545 } 12546 12547 private static string _genSave() @safe pure nothrow 12548 { 12549 return `import core.lifetime : emplace;` ~ 12550 `alias S = typeof((() => (*_range).save)());` ~ 12551 `static assert(isForwardRange!S, S.stringof ~ " is not a forward range.");` ~ 12552 `auto mem = new void[S.sizeof];` ~ 12553 `emplace!S(mem, cast(S)(*_range).save);` ~ 12554 `return RefRange!S(cast(S*) mem.ptr);`; 12555 } 12556 12557 static assert(isForwardRange!RefRange); 12558 } 12559 12560 12561 version (StdDdoc) 12562 { 12563 /++ 12564 Only defined if `isBidirectionalRange!R` is `true`. 12565 +/ 12566 @property auto back() {assert(0);} 12567 /++ Ditto +/ 12568 @property auto back() const {assert(0);} 12569 /++ Ditto +/ 12570 @property auto back(ElementType!R value) {assert(0);} 12571 } 12572 else static if (isBidirectionalRange!R) 12573 { 12574 @property auto back() 12575 { 12576 return (*_range).back; 12577 } 12578 12579 static if (is(typeof(((const R* r) => (*r).back)(null)))) @property auto back() const 12580 { 12581 return (*_range).back; 12582 } 12583 12584 static if (is(typeof((*_range).back = (*_range).back))) @property auto back(ElementType!R value) 12585 { 12586 return (*_range).back = value; 12587 } 12588 } 12589 12590 12591 /++ Ditto +/ 12592 static if (isBidirectionalRange!R) void popBack() 12593 { 12594 return (*_range).popBack(); 12595 } 12596 12597 12598 version (StdDdoc) 12599 { 12600 /++ 12601 Only defined if `isRandomAccessRange!R` is `true`. 12602 +/ 12603 auto ref opIndex(IndexType)(IndexType index) {assert(0);} 12604 12605 /++ Ditto +/ 12606 auto ref opIndex(IndexType)(IndexType index) const {assert(0);} 12607 } 12608 else static if (isRandomAccessRange!R) 12609 { 12610 auto ref opIndex(IndexType)(IndexType index) 12611 if (is(typeof((*_range)[index]))) 12612 { 12613 return (*_range)[index]; 12614 } 12615 12616 auto ref opIndex(IndexType)(IndexType index) const 12617 if (is(typeof((*cast(const R*)_range)[index]))) 12618 { 12619 return (*_range)[index]; 12620 } 12621 } 12622 12623 12624 /++ 12625 Only defined if `hasMobileElements!R` and `isForwardRange!R` are 12626 `true`. 12627 +/ 12628 static if (hasMobileElements!R && isForwardRange!R) auto moveFront() 12629 { 12630 return (*_range).moveFront(); 12631 } 12632 12633 12634 /++ 12635 Only defined if `hasMobileElements!R` and `isBidirectionalRange!R` 12636 are `true`. 12637 +/ 12638 static if (hasMobileElements!R && isBidirectionalRange!R) auto moveBack() 12639 { 12640 return (*_range).moveBack(); 12641 } 12642 12643 12644 /++ 12645 Only defined if `hasMobileElements!R` and `isRandomAccessRange!R` 12646 are `true`. 12647 +/ 12648 static if (hasMobileElements!R && isRandomAccessRange!R) auto moveAt(size_t index) 12649 { 12650 return (*_range).moveAt(index); 12651 } 12652 12653 12654 version (StdDdoc) 12655 { 12656 /// Only defined if `hasLength!R` is `true`. 12657 @property size_t length(); 12658 /// ditto 12659 @property size_t length() const; 12660 /// Ditto 12661 alias opDollar = length; 12662 } 12663 else static if (hasLength!R) 12664 { 12665 @property auto length() 12666 { 12667 return (*_range).length; 12668 } 12669 static if (is(typeof(((const R* r) => (*r).length)(null)))) @property auto length() const 12670 { 12671 return (*_range).length; 12672 } 12673 alias opDollar = length; 12674 } 12675 12676 12677 version (StdDdoc) 12678 { 12679 /++ 12680 Only defined if `hasSlicing!R` is `true`. 12681 +/ 12682 auto opSlice(IndexType1, IndexType2) 12683 (IndexType1 begin, IndexType2 end) {assert(0);} 12684 12685 /++ Ditto +/ 12686 auto opSlice(IndexType1, IndexType2) 12687 (IndexType1 begin, IndexType2 end) const {assert(0);} 12688 } 12689 else static if (hasSlicing!R) 12690 { 12691 private alias T = typeof((*_range)[1 .. 2]); 12692 static if (is(typeof((*cast(const R*)_range)[1 .. 2]))) 12693 { 12694 private alias CT = typeof((*cast(const R*)_range)[1 .. 2]); 12695 } 12696 12697 RefRange!T opSlice(IndexType1, IndexType2) 12698 (IndexType1 begin, IndexType2 end) 12699 if (is(typeof((*_range)[begin .. end]))) 12700 { 12701 mixin(_genOpSlice()); 12702 } 12703 12704 RefRange!CT opSlice(IndexType1, IndexType2) 12705 (IndexType1 begin, IndexType2 end) const 12706 if (is(typeof((*cast(const R*)_range)[begin .. end]))) 12707 { 12708 mixin(_genOpSlice()); 12709 } 12710 12711 private static string _genOpSlice() @safe pure nothrow 12712 { 12713 return `import core.lifetime : emplace;` ~ 12714 `alias S = typeof((*_range)[begin .. end]);` ~ 12715 `static assert(hasSlicing!S, S.stringof ~ " is not sliceable.");` ~ 12716 `auto mem = new void[S.sizeof];` ~ 12717 `emplace!S(mem, cast(S)(*_range)[begin .. end]);` ~ 12718 `return RefRange!S(cast(S*) mem.ptr);`; 12719 } 12720 } 12721 12722 12723 private: 12724 12725 R* _range; 12726 } 12727 12728 /// Basic Example 12729 @system unittest 12730 { 12731 import std.algorithm.searching : find; 12732 ubyte[] buffer = [1, 9, 45, 12, 22]; 12733 auto found1 = find(buffer, 45); 12734 assert(found1 == [45, 12, 22]); 12735 assert(buffer == [1, 9, 45, 12, 22]); 12736 12737 auto wrapped1 = refRange(&buffer); 12738 auto found2 = find(wrapped1, 45); 12739 assert(*found2.ptr == [45, 12, 22]); 12740 assert(buffer == [45, 12, 22]); 12741 12742 auto found3 = find(wrapped1.save, 22); 12743 assert(*found3.ptr == [22]); 12744 assert(buffer == [45, 12, 22]); 12745 12746 string str = "hello world"; 12747 auto wrappedStr = refRange(&str); 12748 assert(str.front == 'h'); 12749 str.popFrontN(5); 12750 assert(str == " world"); 12751 assert(wrappedStr.front == ' '); 12752 assert(*wrappedStr.ptr == " world"); 12753 } 12754 12755 /// opAssign Example. 12756 @system unittest 12757 { 12758 ubyte[] buffer1 = [1, 2, 3, 4, 5]; 12759 ubyte[] buffer2 = [6, 7, 8, 9, 10]; 12760 auto wrapped1 = refRange(&buffer1); 12761 auto wrapped2 = refRange(&buffer2); 12762 assert(wrapped1.ptr is &buffer1); 12763 assert(wrapped2.ptr is &buffer2); 12764 assert(wrapped1.ptr !is wrapped2.ptr); 12765 assert(buffer1 != buffer2); 12766 12767 wrapped1 = wrapped2; 12768 12769 //Everything points to the same stuff as before. 12770 assert(wrapped1.ptr is &buffer1); 12771 assert(wrapped2.ptr is &buffer2); 12772 assert(wrapped1.ptr !is wrapped2.ptr); 12773 12774 //But buffer1 has changed due to the assignment. 12775 assert(buffer1 == [6, 7, 8, 9, 10]); 12776 assert(buffer2 == [6, 7, 8, 9, 10]); 12777 12778 buffer2 = [11, 12, 13, 14, 15]; 12779 12780 //Everything points to the same stuff as before. 12781 assert(wrapped1.ptr is &buffer1); 12782 assert(wrapped2.ptr is &buffer2); 12783 assert(wrapped1.ptr !is wrapped2.ptr); 12784 12785 //But buffer2 has changed due to the assignment. 12786 assert(buffer1 == [6, 7, 8, 9, 10]); 12787 assert(buffer2 == [11, 12, 13, 14, 15]); 12788 12789 wrapped2 = null; 12790 12791 //The pointer changed for wrapped2 but not wrapped1. 12792 assert(wrapped1.ptr is &buffer1); 12793 assert(wrapped2.ptr is null); 12794 assert(wrapped1.ptr !is wrapped2.ptr); 12795 12796 //buffer2 is not affected by the assignment. 12797 assert(buffer1 == [6, 7, 8, 9, 10]); 12798 assert(buffer2 == [11, 12, 13, 14, 15]); 12799 } 12800 12801 @system unittest 12802 { 12803 import std.algorithm.iteration : filter; 12804 { 12805 ubyte[] buffer = [1, 2, 3, 4, 5]; 12806 auto wrapper = refRange(&buffer); 12807 auto p = wrapper.ptr; 12808 auto f = wrapper.front; 12809 wrapper.front = f; 12810 auto e = wrapper.empty; 12811 wrapper.popFront(); 12812 auto s = wrapper.save; 12813 auto b = wrapper.back; 12814 wrapper.back = b; 12815 wrapper.popBack(); 12816 auto i = wrapper[0]; 12817 wrapper.moveFront(); 12818 wrapper.moveBack(); 12819 wrapper.moveAt(0); 12820 auto l = wrapper.length; 12821 auto sl = wrapper[0 .. 1]; 12822 assert(wrapper[0 .. $].length == buffer[0 .. $].length); 12823 } 12824 12825 { 12826 ubyte[] buffer = [1, 2, 3, 4, 5]; 12827 const wrapper = refRange(&buffer); 12828 const p = wrapper.ptr; 12829 const f = wrapper.front; 12830 const e = wrapper.empty; 12831 const s = wrapper.save; 12832 const b = wrapper.back; 12833 const i = wrapper[0]; 12834 const l = wrapper.length; 12835 const sl = wrapper[0 .. 1]; 12836 } 12837 12838 { 12839 ubyte[] buffer = [1, 2, 3, 4, 5]; 12840 auto filtered = filter!"true"(buffer); 12841 auto wrapper = refRange(&filtered); 12842 auto p = wrapper.ptr; 12843 auto f = wrapper.front; 12844 wrapper.front = f; 12845 auto e = wrapper.empty; 12846 wrapper.popFront(); 12847 auto s = wrapper.save; 12848 wrapper.moveFront(); 12849 } 12850 12851 { 12852 ubyte[] buffer = [1, 2, 3, 4, 5]; 12853 auto filtered = filter!"true"(buffer); 12854 const wrapper = refRange(&filtered); 12855 const p = wrapper.ptr; 12856 12857 //Cannot currently be const. filter needs to be updated to handle const. 12858 /+ 12859 const f = wrapper.front; 12860 const e = wrapper.empty; 12861 const s = wrapper.save; 12862 +/ 12863 } 12864 12865 { 12866 string str = "hello world"; 12867 auto wrapper = refRange(&str); 12868 auto p = wrapper.ptr; 12869 auto f = wrapper.front; 12870 auto e = wrapper.empty; 12871 wrapper.popFront(); 12872 auto s = wrapper.save; 12873 auto b = wrapper.back; 12874 wrapper.popBack(); 12875 } 12876 12877 { 12878 // https://issues.dlang.org/show_bug.cgi?id=16534 12879 // opDollar should be defined if the wrapped range defines length. 12880 auto range = 10.iota.takeExactly(5); 12881 auto wrapper = refRange(&range); 12882 assert(wrapper.length == 5); 12883 assert(wrapper[0 .. $ - 1].length == 4); 12884 } 12885 } 12886 12887 //Test assignment. 12888 @system unittest 12889 { 12890 ubyte[] buffer1 = [1, 2, 3, 4, 5]; 12891 ubyte[] buffer2 = [6, 7, 8, 9, 10]; 12892 RefRange!(ubyte[]) wrapper1; 12893 RefRange!(ubyte[]) wrapper2 = refRange(&buffer2); 12894 assert(wrapper1.ptr is null); 12895 assert(wrapper2.ptr is &buffer2); 12896 12897 wrapper1 = refRange(&buffer1); 12898 assert(wrapper1.ptr is &buffer1); 12899 12900 wrapper1 = wrapper2; 12901 assert(wrapper1.ptr is &buffer1); 12902 assert(buffer1 == buffer2); 12903 12904 wrapper1 = RefRange!(ubyte[]).init; 12905 assert(wrapper1.ptr is null); 12906 assert(wrapper2.ptr is &buffer2); 12907 assert(buffer1 == buffer2); 12908 assert(buffer1 == [6, 7, 8, 9, 10]); 12909 12910 wrapper2 = null; 12911 assert(wrapper2.ptr is null); 12912 assert(buffer2 == [6, 7, 8, 9, 10]); 12913 } 12914 12915 @system unittest 12916 { 12917 import std.algorithm.comparison : equal; 12918 import std.algorithm.mutation : bringToFront; 12919 import std.algorithm.searching : commonPrefix, find, until; 12920 import std.algorithm.sorting : sort; 12921 12922 //Test that ranges are properly consumed. 12923 { 12924 int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9]; 12925 auto wrapper = refRange(&arr); 12926 12927 assert(*find(wrapper, 41).ptr == [41, 3, 40, 4, 42, 9]); 12928 assert(arr == [41, 3, 40, 4, 42, 9]); 12929 12930 assert(*drop(wrapper, 2).ptr == [40, 4, 42, 9]); 12931 assert(arr == [40, 4, 42, 9]); 12932 12933 assert(equal(until(wrapper, 42), [40, 4])); 12934 assert(arr == [42, 9]); 12935 12936 assert(find(wrapper, 12).empty); 12937 assert(arr.empty); 12938 } 12939 12940 { 12941 string str = "Hello, world-like object."; 12942 auto wrapper = refRange(&str); 12943 12944 assert(*find(wrapper, "l").ptr == "llo, world-like object."); 12945 assert(str == "llo, world-like object."); 12946 12947 assert(equal(take(wrapper, 5), "llo, ")); 12948 assert(str == "world-like object."); 12949 } 12950 12951 //Test that operating on saved ranges does not consume the original. 12952 { 12953 int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9]; 12954 auto wrapper = refRange(&arr); 12955 auto saved = wrapper.save; 12956 saved.popFrontN(3); 12957 assert(*saved.ptr == [41, 3, 40, 4, 42, 9]); 12958 assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]); 12959 } 12960 12961 { 12962 string str = "Hello, world-like object."; 12963 auto wrapper = refRange(&str); 12964 auto saved = wrapper.save; 12965 saved.popFrontN(13); 12966 assert(*saved.ptr == "like object."); 12967 assert(str == "Hello, world-like object."); 12968 } 12969 12970 //Test that functions which use save work properly. 12971 { 12972 int[] arr = [1, 42]; 12973 auto wrapper = refRange(&arr); 12974 assert(equal(commonPrefix(wrapper, [1, 27]), [1])); 12975 } 12976 12977 { 12978 int[] arr = [4, 5, 6, 7, 1, 2, 3]; 12979 auto wrapper = refRange(&arr); 12980 assert(bringToFront(wrapper[0 .. 4], wrapper[4 .. arr.length]) == 3); 12981 assert(arr == [1, 2, 3, 4, 5, 6, 7]); 12982 } 12983 12984 //Test bidirectional functions. 12985 { 12986 int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9]; 12987 auto wrapper = refRange(&arr); 12988 12989 assert(wrapper.back == 9); 12990 assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]); 12991 12992 wrapper.popBack(); 12993 assert(arr == [1, 42, 2, 41, 3, 40, 4, 42]); 12994 } 12995 12996 { 12997 string str = "Hello, world-like object."; 12998 auto wrapper = refRange(&str); 12999 13000 assert(wrapper.back == '.'); 13001 assert(str == "Hello, world-like object."); 13002 13003 wrapper.popBack(); 13004 assert(str == "Hello, world-like object"); 13005 } 13006 13007 //Test random access functions. 13008 { 13009 int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9]; 13010 auto wrapper = refRange(&arr); 13011 13012 assert(wrapper[2] == 2); 13013 assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]); 13014 13015 assert(*wrapper[3 .. 6].ptr != null, [41, 3, 40]); 13016 assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]); 13017 } 13018 13019 //Test move functions. 13020 { 13021 int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9]; 13022 auto wrapper = refRange(&arr); 13023 13024 auto t1 = wrapper.moveFront(); 13025 auto t2 = wrapper.moveBack(); 13026 wrapper.front = t2; 13027 wrapper.back = t1; 13028 assert(arr == [9, 42, 2, 41, 3, 40, 4, 42, 1]); 13029 13030 sort(wrapper.save); 13031 assert(arr == [1, 2, 3, 4, 9, 40, 41, 42, 42]); 13032 } 13033 } 13034 13035 @system unittest 13036 { 13037 struct S 13038 { 13039 @property int front() @safe const pure nothrow { return 0; } 13040 enum bool empty = false; 13041 void popFront() @safe pure nothrow { } 13042 @property auto save() @safe pure nothrow return scope { return this; } 13043 } 13044 13045 S s; 13046 auto wrapper = refRange(&s); 13047 static assert(isInfinite!(typeof(wrapper))); 13048 } 13049 13050 @system unittest 13051 { 13052 class C 13053 { 13054 @property int front() @safe const pure nothrow { return 0; } 13055 @property bool empty() @safe const pure nothrow { return false; } 13056 void popFront() @safe pure nothrow { } 13057 @property auto save() @safe pure nothrow return scope { return this; } 13058 } 13059 static assert(isForwardRange!C); 13060 13061 auto c = new C; 13062 auto cWrapper = refRange(&c); 13063 static assert(is(typeof(cWrapper) == C)); 13064 assert(cWrapper is c); 13065 } 13066 13067 // https://issues.dlang.org/show_bug.cgi?id=14373 13068 @system unittest 13069 { 13070 static struct R 13071 { 13072 @property int front() {return 0;} 13073 void popFront() {empty = true;} 13074 bool empty = false; 13075 } 13076 R r; 13077 refRange(&r).popFront(); 13078 assert(r.empty); 13079 } 13080 13081 // https://issues.dlang.org/show_bug.cgi?id=14575 13082 @system unittest 13083 { 13084 struct R 13085 { 13086 Object front; 13087 alias back = front; 13088 bool empty = false; 13089 void popFront() {empty = true;} 13090 alias popBack = popFront; 13091 @property R save() {return this;} 13092 } 13093 static assert(isBidirectionalRange!R); 13094 R r; 13095 auto rr = refRange(&r); 13096 13097 struct R2 13098 { 13099 @property Object front() {return null;} 13100 @property const(Object) front() const {return null;} 13101 alias back = front; 13102 bool empty = false; 13103 void popFront() {empty = true;} 13104 alias popBack = popFront; 13105 @property R2 save() {return this;} 13106 } 13107 static assert(isBidirectionalRange!R2); 13108 R2 r2; 13109 auto rr2 = refRange(&r2); 13110 } 13111 13112 // https://issues.dlang.org/show_bug.cgi?id=24801 13113 @safe unittest 13114 { 13115 13116 { 13117 static struct R 13118 { 13119 int front() => 0; 13120 void popFront() {} 13121 bool empty() => false; 13122 } 13123 R range; 13124 auto r = RefRange!R(&range); 13125 } 13126 13127 { 13128 static struct R 13129 { 13130 size_t start, end; 13131 size_t length() => end - start; 13132 int opIndex(size_t i) => 0; 13133 13134 13135 int front() => this[0]; 13136 int back() => this[length-1]; 13137 void popFront() { start++; } 13138 void popBack() { end--; } 13139 bool empty() => length == 0; 13140 R save() const => R(); 13141 } 13142 13143 R range; 13144 auto r = RefRange!R(&range); 13145 } 13146 13147 13148 } 13149 13150 /// ditto 13151 auto refRange(R)(R* range) 13152 if (isInputRange!R) 13153 { 13154 static if (!is(R == class)) 13155 return RefRange!R(range); 13156 else 13157 return *range; 13158 } 13159 13160 // https://issues.dlang.org/show_bug.cgi?id=9060 13161 @safe unittest 13162 { 13163 import std.algorithm.iteration : map, joiner, group; 13164 import std.algorithm.searching : until; 13165 // fix for std.algorithm 13166 auto r = map!(x => 0)([1]); 13167 chain(r, r); 13168 zip(r, r); 13169 roundRobin(r, r); 13170 13171 struct NRAR { 13172 typeof(r) input; 13173 @property empty() { return input.empty; } 13174 @property front() { return input.front; } 13175 void popFront() { input.popFront(); } 13176 @property save() { return NRAR(input.save); } 13177 } 13178 auto n1 = NRAR(r); 13179 cycle(n1); // non random access range version 13180 13181 assumeSorted(r); 13182 13183 // fix for std.range 13184 joiner([r], [9]); 13185 13186 struct NRAR2 { 13187 NRAR input; 13188 @property empty() { return true; } 13189 @property front() { return input; } 13190 void popFront() { } 13191 @property save() { return NRAR2(input.save); } 13192 } 13193 auto n2 = NRAR2(n1); 13194 joiner(n2); 13195 13196 group(r); 13197 13198 until(r, 7); 13199 static void foo(R)(R r) { until!(x => x > 7)(r); } 13200 foo(r); 13201 } 13202 13203 private struct Bitwise(R) 13204 if (isInputRange!R && isIntegral!(ElementType!R)) 13205 { 13206 import std.traits : Unsigned; 13207 private: 13208 alias ElemType = ElementType!R; 13209 alias UnsignedElemType = Unsigned!ElemType; 13210 13211 R parent; 13212 enum bitsNum = ElemType.sizeof * 8; 13213 size_t maskPos = 1; 13214 13215 static if (isBidirectionalRange!R) 13216 { 13217 size_t backMaskPos = bitsNum; 13218 } 13219 13220 public: 13221 this()(auto ref R range) 13222 { 13223 parent = range; 13224 } 13225 13226 static if (isInfinite!R) 13227 { 13228 enum empty = false; 13229 } 13230 else 13231 { 13232 /** 13233 * Check if the range is empty 13234 * 13235 * Returns: a boolean true or false 13236 */ 13237 bool empty() 13238 { 13239 static if (hasLength!R) 13240 { 13241 return length == 0; 13242 } 13243 else static if (isBidirectionalRange!R) 13244 { 13245 if (parent.empty) 13246 { 13247 return true; 13248 } 13249 else 13250 { 13251 /* 13252 If we have consumed the last element of the range both from 13253 the front and the back, then the masks positions will overlap 13254 */ 13255 return parent.save.dropOne.empty && (maskPos > backMaskPos); 13256 } 13257 } 13258 else 13259 { 13260 /* 13261 If we consumed the last element of the range, but not all the 13262 bits in the last element 13263 */ 13264 return parent.empty; 13265 } 13266 } 13267 } 13268 13269 bool front() 13270 { 13271 assert(!empty); 13272 return (parent.front & mask(maskPos)) != 0; 13273 } 13274 13275 void popFront() 13276 { 13277 assert(!empty); 13278 ++maskPos; 13279 if (maskPos > bitsNum) 13280 { 13281 parent.popFront; 13282 maskPos = 1; 13283 } 13284 } 13285 13286 static if (hasLength!R) 13287 { 13288 size_t length() 13289 { 13290 auto len = parent.length * bitsNum - (maskPos - 1); 13291 static if (isBidirectionalRange!R) 13292 { 13293 len -= bitsNum - backMaskPos; 13294 } 13295 return len; 13296 } 13297 13298 alias opDollar = length; 13299 } 13300 13301 static if (isForwardRange!R) 13302 { 13303 typeof(this) save() 13304 { 13305 auto result = this; 13306 result.parent = parent.save; 13307 return result; 13308 } 13309 } 13310 13311 static if (isBidirectionalRange!R) 13312 { 13313 bool back() 13314 { 13315 assert(!empty); 13316 return (parent.back & mask(backMaskPos)) != 0; 13317 } 13318 13319 void popBack() 13320 { 13321 assert(!empty); 13322 --backMaskPos; 13323 if (backMaskPos == 0) 13324 { 13325 parent.popBack; 13326 backMaskPos = bitsNum; 13327 } 13328 } 13329 } 13330 13331 static if (isRandomAccessRange!R) 13332 { 13333 /** 13334 Return the `n`th bit within the range 13335 */ 13336 bool opIndex(size_t n) 13337 in 13338 { 13339 /* 13340 If it does not have the length property, it means that R is 13341 an infinite range 13342 */ 13343 static if (hasLength!R) 13344 { 13345 assert(n < length, "Index out of bounds"); 13346 } 13347 } 13348 do 13349 { 13350 immutable size_t remainingBits = bitsNum - maskPos + 1; 13351 // If n >= maskPos, then the bit sign will be 1, otherwise 0 13352 immutable ptrdiff_t sign = (remainingBits - n - 1) >> (ptrdiff_t.sizeof * 8 - 1); 13353 /* 13354 By truncating n with remainingBits bits we have skipped the 13355 remaining bits in parent[0], so we need to add 1 to elemIndex. 13356 13357 Because bitsNum is a power of 2, n / bitsNum == n >> bitsNum.bsf 13358 */ 13359 import core.bitop : bsf; 13360 immutable size_t elemIndex = sign * (((n - remainingBits) >> bitsNum.bsf) + 1); 13361 13362 /* 13363 Since the indexing is from LSB to MSB, we need to index at the 13364 remainder of (n - remainingBits). 13365 13366 Because bitsNum is a power of 2, n % bitsNum == n & (bitsNum - 1) 13367 */ 13368 immutable size_t elemMaskPos = (sign ^ 1) * (maskPos + n) 13369 + sign * (1 + ((n - remainingBits) & (bitsNum - 1))); 13370 13371 return (parent[elemIndex] & mask(elemMaskPos)) != 0; 13372 } 13373 13374 static if (hasAssignableElements!R) 13375 { 13376 /** 13377 Assigns `flag` to the `n`th bit within the range 13378 */ 13379 void opIndexAssign(bool flag, size_t n) 13380 in 13381 { 13382 static if (hasLength!R) 13383 { 13384 assert(n < length, "Index out of bounds"); 13385 } 13386 } 13387 do 13388 { 13389 import core.bitop : bsf; 13390 13391 immutable size_t remainingBits = bitsNum - maskPos + 1; 13392 immutable ptrdiff_t sign = (remainingBits - n - 1) >> (ptrdiff_t.sizeof * 8 - 1); 13393 immutable size_t elemIndex = sign * (((n - remainingBits) >> bitsNum.bsf) + 1); 13394 immutable size_t elemMaskPos = (sign ^ 1) * (maskPos + n) 13395 + sign * (1 + ((n - remainingBits) & (bitsNum - 1))); 13396 13397 auto elem = parent[elemIndex]; 13398 auto elemMask = mask(elemMaskPos); 13399 parent[elemIndex] = cast(UnsignedElemType)(flag * (elem | elemMask) 13400 + (flag ^ 1) * (elem & ~elemMask)); 13401 } 13402 } 13403 13404 Bitwise!R opSlice() 13405 { 13406 return this.save; 13407 } 13408 13409 Bitwise!R opSlice(size_t start, size_t end) 13410 in 13411 { 13412 assert(start < end, "Invalid bounds: end <= start"); 13413 } 13414 do 13415 { 13416 import core.bitop : bsf; 13417 13418 size_t remainingBits = bitsNum - maskPos + 1; 13419 ptrdiff_t sign = (remainingBits - start - 1) >> (ptrdiff_t.sizeof * 8 - 1); 13420 immutable size_t startElemIndex = sign * (((start - remainingBits) >> bitsNum.bsf) + 1); 13421 immutable size_t startElemMaskPos = (sign ^ 1) * (maskPos + start) 13422 + sign * (1 + ((start - remainingBits) & (bitsNum - 1))); 13423 13424 immutable size_t sliceLen = end - start - 1; 13425 remainingBits = bitsNum - startElemMaskPos + 1; 13426 sign = (remainingBits - sliceLen - 1) >> (ptrdiff_t.sizeof * 8 - 1); 13427 immutable size_t endElemIndex = startElemIndex 13428 + sign * (((sliceLen - remainingBits) >> bitsNum.bsf) + 1); 13429 immutable size_t endElemMaskPos = (sign ^ 1) * (startElemMaskPos + sliceLen) 13430 + sign * (1 + ((sliceLen - remainingBits) & (bitsNum - 1))); 13431 13432 typeof(return) result; 13433 // Get the slice to be returned from the parent 13434 result.parent = (parent[startElemIndex .. endElemIndex + 1]).save; 13435 result.maskPos = startElemMaskPos; 13436 static if (isBidirectionalRange!R) 13437 { 13438 result.backMaskPos = endElemMaskPos; 13439 } 13440 return result; 13441 } 13442 } 13443 13444 private: 13445 auto mask(size_t maskPos) 13446 { 13447 return (1UL << (maskPos - 1UL)); 13448 } 13449 } 13450 13451 /** 13452 Bitwise adapter over an integral type range. Consumes the range elements bit by 13453 bit, from the least significant bit to the most significant bit. 13454 13455 Params: 13456 R = an integral $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to iterate over 13457 range = range to consume bit by by 13458 13459 Returns: 13460 A `Bitwise` input range with propagated forward, bidirectional 13461 and random access capabilities 13462 */ 13463 auto bitwise(R)(auto ref R range) 13464 if (isInputRange!R && isIntegral!(ElementType!R)) 13465 { 13466 return Bitwise!R(range); 13467 } 13468 13469 /// 13470 @safe pure unittest 13471 { 13472 import std.algorithm.comparison : equal; 13473 import std.format : format; 13474 13475 // 00000011 00001001 13476 ubyte[] arr = [3, 9]; 13477 auto r = arr.bitwise; 13478 13479 // iterate through it as with any other range 13480 assert(format("%(%d%)", r) == "1100000010010000"); 13481 assert(format("%(%d%)", r.retro).equal("1100000010010000".retro)); 13482 13483 auto r2 = r[5 .. $]; 13484 // set a bit 13485 r[2] = 1; 13486 assert(arr[0] == 7); 13487 assert(r[5] == r2[0]); 13488 } 13489 13490 /// You can use bitwise to implement an uniform bool generator 13491 @safe unittest 13492 { 13493 import std.algorithm.comparison : equal; 13494 import std.random : rndGen; 13495 13496 auto rb = rndGen.bitwise; 13497 static assert(isInfinite!(typeof(rb))); 13498 13499 auto rb2 = rndGen.bitwise; 13500 // Don't forget that structs are passed by value 13501 assert(rb.take(10).equal(rb2.take(10))); 13502 } 13503 13504 // Test nogc inference 13505 @safe @nogc unittest 13506 { 13507 static ubyte[] arr = [3, 9]; 13508 auto bw = arr.bitwise; 13509 auto bw2 = bw[]; 13510 auto bw3 = bw[8 .. $]; 13511 bw3[2] = true; 13512 13513 assert(arr[1] == 13); 13514 assert(bw[$ - 6]); 13515 assert(bw[$ - 6] == bw2[$ - 6]); 13516 assert(bw[$ - 6] == bw3[$ - 6]); 13517 } 13518 13519 // Test all range types over all integral types 13520 @safe pure nothrow unittest 13521 { 13522 import std.meta : AliasSeq; 13523 import std.internal.test.dummyrange; 13524 13525 alias IntegralTypes = AliasSeq!(byte, ubyte, short, ushort, int, uint, 13526 long, ulong); 13527 foreach (IntegralType; IntegralTypes) 13528 { 13529 foreach (T; AllDummyRangesType!(IntegralType[])) 13530 { 13531 T a; 13532 auto bw = Bitwise!T(a); 13533 13534 static if (isForwardRange!T) 13535 { 13536 auto bwFwdSave = bw.save; 13537 } 13538 13539 static if (isBidirectionalRange!T) 13540 { 13541 auto bwBack = bw.save; 13542 auto bwBackSave = bw.save; 13543 } 13544 13545 static if (hasLength!T) 13546 { 13547 auto bwLength = bw.length; 13548 assert(bw.length == (IntegralType.sizeof * 8 * a.length)); 13549 static if (isForwardRange!T) 13550 { 13551 assert(bw.length == bwFwdSave.length); 13552 } 13553 } 13554 13555 // Make sure front and back are not the mechanisms that modify the range 13556 long numCalls = 42; 13557 bool initialFrontValue; 13558 13559 if (!bw.empty) 13560 { 13561 initialFrontValue = bw.front; 13562 } 13563 13564 while (!bw.empty && (--numCalls)) 13565 { 13566 bw.front; 13567 assert(bw.front == initialFrontValue); 13568 } 13569 13570 /* 13571 Check that empty works properly and that popFront does not get called 13572 more times than it should 13573 */ 13574 numCalls = 0; 13575 while (!bw.empty) 13576 { 13577 ++numCalls; 13578 13579 static if (hasLength!T) 13580 { 13581 assert(bw.length == bwLength); 13582 --bwLength; 13583 } 13584 13585 static if (isForwardRange!T) 13586 { 13587 assert(bw.front == bwFwdSave.front); 13588 bwFwdSave.popFront(); 13589 } 13590 13591 static if (isBidirectionalRange!T) 13592 { 13593 assert(bwBack.front == bwBackSave.front); 13594 bwBack.popBack(); 13595 bwBackSave.popBack(); 13596 } 13597 bw.popFront(); 13598 } 13599 13600 auto rangeLen = numCalls / (IntegralType.sizeof * 8); 13601 assert(numCalls == (IntegralType.sizeof * 8 * rangeLen)); 13602 assert(bw.empty); 13603 static if (isForwardRange!T) 13604 { 13605 assert(bwFwdSave.empty); 13606 } 13607 13608 static if (isBidirectionalRange!T) 13609 { 13610 assert(bwBack.empty); 13611 } 13612 } 13613 } 13614 } 13615 13616 // Test opIndex and opSlice 13617 @system unittest 13618 { 13619 import std.meta : AliasSeq; 13620 alias IntegralTypes = AliasSeq!(byte, ubyte, short, ushort, int, uint, 13621 long, ulong); 13622 foreach (IntegralType; IntegralTypes) 13623 { 13624 size_t bitsNum = IntegralType.sizeof * 8; 13625 13626 auto first = IntegralType(1); 13627 13628 // 2 ^ (bitsNum - 1) 13629 auto second = cast(IntegralType)(IntegralType(1) << (bitsNum - 2)); 13630 13631 IntegralType[] a = [first, second]; 13632 auto bw = Bitwise!(IntegralType[])(a); 13633 13634 // Check against lsb of a[0] 13635 assert(bw[0] == true); 13636 // Check against msb - 1 of a[1] 13637 assert(bw[2 * bitsNum - 2] == true); 13638 13639 bw.popFront(); 13640 assert(bw[2 * bitsNum - 3] == true); 13641 13642 import std.exception : assertThrown; 13643 13644 version (D_NoBoundsChecks) {} 13645 else 13646 { 13647 // Check out of bounds error 13648 assertThrown!Error(bw[2 * bitsNum - 1]); 13649 } 13650 13651 bw[2] = true; 13652 assert(bw[2] == true); 13653 bw.popFront(); 13654 assert(bw[1] == true); 13655 13656 auto bw2 = bw[0 .. $ - 5]; 13657 auto bw3 = bw2[]; 13658 assert(bw2.length == bw.length - 5); 13659 assert(bw2.length == bw3.length); 13660 bw2.popFront(); 13661 assert(bw2.length != bw3.length); 13662 } 13663 } 13664 13665 /********************************* 13666 * An OutputRange that discards the data it receives. 13667 */ 13668 struct NullSink 13669 { 13670 void put(E)(scope const E) pure @safe @nogc nothrow {} 13671 } 13672 13673 /// ditto 13674 auto ref nullSink() 13675 { 13676 static NullSink sink; 13677 return sink; 13678 } 13679 13680 /// 13681 @safe nothrow unittest 13682 { 13683 import std.algorithm.iteration : map; 13684 import std.algorithm.mutation : copy; 13685 [4, 5, 6].map!(x => x * 2).copy(nullSink); // data is discarded 13686 } 13687 13688 /// 13689 @safe unittest 13690 { 13691 import std.csv : csvNextToken; 13692 13693 string line = "a,b,c"; 13694 13695 // ignore the first column 13696 line.csvNextToken(nullSink, ',', '"'); 13697 line.popFront; 13698 13699 // look at the second column 13700 Appender!string app; 13701 line.csvNextToken(app, ',', '"'); 13702 assert(app.data == "b"); 13703 } 13704 13705 @safe unittest 13706 { 13707 auto r = 10.iota 13708 .tee(nullSink) 13709 .dropOne; 13710 13711 assert(r.front == 1); 13712 } 13713 13714 /++ 13715 13716 Implements a "tee" style pipe, wrapping an input range so that elements of the 13717 range can be passed to a provided function or $(LREF OutputRange) as they are 13718 iterated over. This is useful for printing out intermediate values in a long 13719 chain of range code, performing some operation with side-effects on each call 13720 to `front` or `popFront`, or diverting the elements of a range into an 13721 auxiliary $(LREF OutputRange). 13722 13723 It is important to note that as the resultant range is evaluated lazily, 13724 in the case of the version of `tee` that takes a function, the function 13725 will not actually be executed until the range is "walked" using functions 13726 that evaluate ranges, such as $(REF array, std,array) or 13727 $(REF fold, std,algorithm,iteration). 13728 13729 Params: 13730 pipeOnPop = If `Yes.pipeOnPop`, simply iterating the range without ever 13731 calling `front` is enough to have `tee` mirror elements to `outputRange` (or, 13732 respectively, `fun`). Note that each `popFront()` call will mirror the 13733 old `front` value, not the new one. This means that the last value will 13734 not be forwarded if the range isn't iterated until empty. If 13735 `No.pipeOnPop`, only elements for which `front` does get called will be 13736 also sent to `outputRange`/`fun`. If `front` is called twice for the same 13737 element, it will still be sent only once. If this caching is undesired, 13738 consider using $(REF map, std,algorithm,iteration) instead. 13739 inputRange = The input range being passed through. 13740 outputRange = This range will receive elements of `inputRange` progressively 13741 as iteration proceeds. 13742 fun = This function will be called with elements of `inputRange` 13743 progressively as iteration proceeds. 13744 13745 Returns: 13746 An input range that offers the elements of `inputRange`. Regardless of 13747 whether `inputRange` is a more powerful range (forward, bidirectional etc), 13748 the result is always an input range. Reading this causes `inputRange` to be 13749 iterated and returns its elements in turn. In addition, the same elements 13750 will be passed to `outputRange` or `fun` as well. 13751 13752 See_Also: $(REF each, std,algorithm,iteration) 13753 +/ 13754 auto tee(Flag!"pipeOnPop" pipeOnPop = Yes.pipeOnPop, R1, R2)(R1 inputRange, R2 outputRange) 13755 if (isInputRange!R1 && isOutputRange!(R2, ElementType!R1)) 13756 { 13757 static struct Result 13758 { 13759 private R1 _input; 13760 private R2 _output; 13761 static if (!pipeOnPop) 13762 { 13763 private bool _frontAccessed; 13764 } 13765 13766 mixin ImplementLength!_input; 13767 13768 static if (isInfinite!R1) 13769 { 13770 enum bool empty = false; 13771 } 13772 else 13773 { 13774 @property bool empty() { return _input.empty; } 13775 } 13776 13777 void popFront() 13778 { 13779 assert(!_input.empty, "Attempting to popFront an empty tee"); 13780 static if (pipeOnPop) 13781 { 13782 put(_output, _input.front); 13783 } 13784 else 13785 { 13786 _frontAccessed = false; 13787 } 13788 _input.popFront(); 13789 } 13790 13791 @property auto ref front() 13792 { 13793 assert(!_input.empty, "Attempting to fetch the front of an empty tee"); 13794 static if (!pipeOnPop) 13795 { 13796 if (!_frontAccessed) 13797 { 13798 _frontAccessed = true; 13799 put(_output, _input.front); 13800 } 13801 } 13802 return _input.front; 13803 } 13804 } 13805 13806 return Result(inputRange, outputRange); 13807 } 13808 13809 /// Ditto 13810 auto tee(alias fun, Flag!"pipeOnPop" pipeOnPop = Yes.pipeOnPop, R1)(R1 inputRange) 13811 if (is(typeof(fun) == void) || isSomeFunction!fun) 13812 { 13813 import std.traits : isDelegate, isFunctionPointer; 13814 /* 13815 Distinguish between function literals and template lambdas 13816 when using either as an $(LREF OutputRange). Since a template 13817 has no type, typeof(template) will always return void. 13818 If it's a template lambda, it's first necessary to instantiate 13819 it with `ElementType!R1`. 13820 */ 13821 static if (is(typeof(fun) == void)) 13822 alias _fun = fun!(ElementType!R1); 13823 else 13824 alias _fun = fun; 13825 13826 static if (isFunctionPointer!_fun || isDelegate!_fun) 13827 { 13828 return tee!pipeOnPop(inputRange, _fun); 13829 } 13830 else 13831 { 13832 return tee!pipeOnPop(inputRange, &_fun); 13833 } 13834 } 13835 13836 /// 13837 @safe unittest 13838 { 13839 import std.algorithm.comparison : equal; 13840 import std.algorithm.iteration : filter, map; 13841 13842 // Sum values while copying 13843 int[] values = [1, 4, 9, 16, 25]; 13844 int sum = 0; 13845 auto newValues = values.tee!(a => sum += a).array; 13846 assert(equal(newValues, values)); 13847 assert(sum == 1 + 4 + 9 + 16 + 25); 13848 13849 // Count values that pass the first filter 13850 int count = 0; 13851 auto newValues4 = values.filter!(a => a < 10) 13852 .tee!(a => count++) 13853 .map!(a => a + 1) 13854 .filter!(a => a < 10); 13855 13856 //Fine, equal also evaluates any lazy ranges passed to it. 13857 //count is not 3 until equal evaluates newValues4 13858 assert(equal(newValues4, [2, 5])); 13859 assert(count == 3); 13860 } 13861 13862 // 13863 @safe unittest 13864 { 13865 import std.algorithm.comparison : equal; 13866 import std.algorithm.iteration : filter, map; 13867 13868 int[] values = [1, 4, 9, 16, 25]; 13869 13870 int count = 0; 13871 auto newValues = values.filter!(a => a < 10) 13872 .tee!(a => count++, No.pipeOnPop) 13873 .map!(a => a + 1) 13874 .filter!(a => a < 10); 13875 13876 auto val = newValues.front; 13877 assert(count == 1); 13878 //front is only evaluated once per element 13879 val = newValues.front; 13880 assert(count == 1); 13881 13882 //popFront() called, fun will be called 13883 //again on the next access to front 13884 newValues.popFront(); 13885 newValues.front; 13886 assert(count == 2); 13887 13888 int[] preMap = new int[](3), postMap = []; 13889 auto mappedValues = values.filter!(a => a < 10) 13890 //Note the two different ways of using tee 13891 .tee(preMap) 13892 .map!(a => a + 1) 13893 .tee!(a => postMap ~= a) 13894 .filter!(a => a < 10); 13895 assert(equal(mappedValues, [2, 5])); 13896 assert(equal(preMap, [1, 4, 9])); 13897 assert(equal(postMap, [2, 5, 10])); 13898 } 13899 13900 // 13901 @safe unittest 13902 { 13903 import std.algorithm.comparison : equal; 13904 import std.algorithm.iteration : filter, map; 13905 13906 char[] txt = "Line one, Line 2".dup; 13907 13908 bool isVowel(dchar c) 13909 { 13910 import std.string : indexOf; 13911 return "AaEeIiOoUu".indexOf(c) != -1; 13912 } 13913 13914 int vowelCount = 0; 13915 int shiftedCount = 0; 13916 auto removeVowels = txt.tee!(c => isVowel(c) ? vowelCount++ : 0) 13917 .filter!(c => !isVowel(c)) 13918 .map!(c => (c == ' ') ? c : c + 1) 13919 .tee!(c => isVowel(c) ? shiftedCount++ : 0); 13920 assert(equal(removeVowels, "Mo o- Mo 3")); 13921 assert(vowelCount == 6); 13922 assert(shiftedCount == 3); 13923 } 13924 13925 @safe unittest 13926 { 13927 // Manually stride to test different pipe behavior. 13928 void testRange(Range)(Range r) 13929 { 13930 const int strideLen = 3; 13931 int i = 0; 13932 ElementType!Range elem1; 13933 ElementType!Range elem2; 13934 while (!r.empty) 13935 { 13936 if (i % strideLen == 0) 13937 { 13938 //Make sure front is only 13939 //evaluated once per item 13940 elem1 = r.front; 13941 elem2 = r.front; 13942 assert(elem1 == elem2); 13943 } 13944 r.popFront(); 13945 i++; 13946 } 13947 } 13948 13949 string txt = "abcdefghijklmnopqrstuvwxyz"; 13950 13951 int popCount = 0; 13952 auto pipeOnPop = txt.tee!(a => popCount++); 13953 testRange(pipeOnPop); 13954 assert(popCount == 26); 13955 13956 int frontCount = 0; 13957 auto pipeOnFront = txt.tee!(a => frontCount++, No.pipeOnPop); 13958 testRange(pipeOnFront); 13959 assert(frontCount == 9); 13960 } 13961 13962 @safe unittest 13963 { 13964 import std.algorithm.comparison : equal; 13965 import std.meta : AliasSeq; 13966 13967 //Test diverting elements to an OutputRange 13968 string txt = "abcdefghijklmnopqrstuvwxyz"; 13969 13970 dchar[] asink1 = []; 13971 auto fsink = (dchar c) { asink1 ~= c; }; 13972 auto result1 = txt.tee(fsink).array; 13973 assert(equal(txt, result1) && (equal(result1, asink1))); 13974 13975 dchar[] _asink1 = []; 13976 auto _result1 = txt.tee!((dchar c) { _asink1 ~= c; })().array; 13977 assert(equal(txt, _result1) && (equal(_result1, _asink1))); 13978 13979 dchar[] asink2 = new dchar[](txt.length); 13980 void fsink2(dchar c) { static int i = 0; asink2[i] = c; i++; } 13981 auto result2 = txt.tee(&fsink2).array; 13982 assert(equal(txt, result2) && equal(result2, asink2)); 13983 13984 dchar[] asink3 = new dchar[](txt.length); 13985 auto result3 = txt.tee(asink3).array; 13986 assert(equal(txt, result3) && equal(result3, asink3)); 13987 13988 static foreach (CharType; AliasSeq!(char, wchar, dchar)) 13989 {{ 13990 auto appSink = appender!(CharType[])(); 13991 auto appResult = txt.tee(appSink).array; 13992 assert(equal(txt, appResult) && equal(appResult, appSink.data)); 13993 }} 13994 13995 static foreach (StringType; AliasSeq!(string, wstring, dstring)) 13996 {{ 13997 auto appSink = appender!StringType(); 13998 auto appResult = txt.tee(appSink).array; 13999 assert(equal(txt, appResult) && equal(appResult, appSink.data)); 14000 }} 14001 } 14002 14003 // https://issues.dlang.org/show_bug.cgi?id=13483 14004 @safe unittest 14005 { 14006 static void func1(T)(T x) {} 14007 void func2(int x) {} 14008 14009 auto r = [1, 2, 3, 4].tee!func1.tee!func2; 14010 } 14011 14012 /** 14013 Extends the length of the input range `r` by padding out the start of the 14014 range with the element `e`. The element `e` must be of a common type with 14015 the element type of the range `r` as defined by $(REF CommonType, std, traits). 14016 If `n` is less than the length of of `r`, then `r` is returned unmodified. 14017 14018 If `r` is a string with Unicode characters in it, `padLeft` follows D's rules 14019 about length for strings, which is not the number of characters, or 14020 graphemes, but instead the number of encoding units. If you want to treat each 14021 grapheme as only one encoding unit long, then call 14022 $(REF byGrapheme, std, uni) before calling this function. 14023 14024 If `r` has a length, then this is $(BIGOH 1). Otherwise, it's $(BIGOH r.length). 14025 14026 Params: 14027 r = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives) with a length, or a forward range 14028 e = element to pad the range with 14029 n = the length to pad to 14030 14031 Returns: 14032 A range containing the elements of the original range with the extra padding 14033 14034 See Also: 14035 $(REF leftJustifier, std, string) 14036 */ 14037 auto padLeft(R, E)(R r, E e, size_t n) 14038 if ( 14039 ((isInputRange!R && hasLength!R) || isForwardRange!R) && 14040 !is(CommonType!(ElementType!R, E) == void) 14041 ) 14042 { 14043 static if (hasLength!R) 14044 auto dataLength = r.length; 14045 else 14046 auto dataLength = r.save.walkLength(n); 14047 14048 return e.repeat(n > dataLength ? n - dataLength : 0).chain(r); 14049 } 14050 14051 /// 14052 @safe pure unittest 14053 { 14054 import std.algorithm.comparison : equal; 14055 14056 assert([1, 2, 3, 4].padLeft(0, 6).equal([0, 0, 1, 2, 3, 4])); 14057 assert([1, 2, 3, 4].padLeft(0, 3).equal([1, 2, 3, 4])); 14058 14059 assert("abc".padLeft('_', 6).equal("___abc")); 14060 } 14061 14062 @safe pure nothrow unittest 14063 { 14064 import std.algorithm.comparison : equal; 14065 import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy; 14066 import std.meta : AliasSeq; 14067 14068 alias DummyRanges = AliasSeq!( 14069 DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Input), 14070 DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Forward), 14071 DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Bidirectional), 14072 DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random), 14073 DummyRange!(ReturnBy.Reference, Length.No, RangeType.Forward), 14074 DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Input), 14075 DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Forward), 14076 DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Bidirectional), 14077 DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random), 14078 DummyRange!(ReturnBy.Value, Length.No, RangeType.Forward) 14079 ); 14080 14081 foreach (Range; DummyRanges) 14082 { 14083 Range r; 14084 assert(r 14085 .padLeft(0, 12) 14086 .equal([0, 0, 1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U]) 14087 ); 14088 } 14089 } 14090 14091 // Test nogc inference 14092 @safe @nogc pure unittest 14093 { 14094 import std.algorithm.comparison : equal; 14095 14096 static immutable r1 = [1, 2, 3, 4]; 14097 static immutable r2 = [0, 0, 1, 2, 3, 4]; 14098 assert(r1.padLeft(0, 6).equal(r2)); 14099 } 14100 14101 /** 14102 Extend the length of the input range `r` by padding out the end of the range 14103 with the element `e`. The element `e` must be of a common type with the 14104 element type of the range `r` as defined by $(REF CommonType, std, traits). 14105 If `n` is less than the length of of `r`, then the contents of `r` are 14106 returned. 14107 14108 The range primitives that the resulting range provides depends whether or not `r` 14109 provides them. Except the functions `back` and `popBack`, which also require 14110 the range to have a length as well as `back` and `popBack` 14111 14112 Params: 14113 r = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives) with a length 14114 e = element to pad the range with 14115 n = the length to pad to 14116 14117 Returns: 14118 A range containing the elements of the original range with the extra padding 14119 14120 See Also: 14121 $(REF rightJustifier, std, string) 14122 */ 14123 auto padRight(R, E)(R r, E e, size_t n) 14124 if ( 14125 isInputRange!R && 14126 !isInfinite!R && 14127 !is(CommonType!(ElementType!R, E) == void)) 14128 { 14129 static struct Result 14130 { 14131 private: 14132 R data; 14133 E element; 14134 static if (hasLength!R) 14135 { 14136 size_t padLength; 14137 } 14138 else 14139 { 14140 size_t minLength; 14141 size_t consumed; 14142 } 14143 14144 public: 14145 bool empty() @property 14146 { 14147 static if (hasLength!R) 14148 { 14149 return data.empty && padLength == 0; 14150 } 14151 else 14152 { 14153 return data.empty && consumed >= minLength; 14154 } 14155 } 14156 14157 auto front() @property 14158 { 14159 assert(!empty, "Attempting to fetch the front of an empty padRight"); 14160 return data.empty ? element : data.front; 14161 } 14162 14163 void popFront() 14164 { 14165 assert(!empty, "Attempting to popFront an empty padRight"); 14166 14167 static if (hasLength!R) 14168 { 14169 if (!data.empty) 14170 { 14171 data.popFront; 14172 } 14173 else 14174 { 14175 --padLength; 14176 } 14177 } 14178 else 14179 { 14180 ++consumed; 14181 if (!data.empty) 14182 { 14183 data.popFront; 14184 } 14185 } 14186 } 14187 14188 static if (hasLength!R) 14189 { 14190 size_t length() @property 14191 { 14192 return data.length + padLength; 14193 } 14194 } 14195 14196 static if (isForwardRange!R) 14197 { 14198 auto save() @property 14199 { 14200 typeof(this) result = this; 14201 data = data.save; 14202 return result; 14203 } 14204 } 14205 14206 static if (isBidirectionalRange!R && hasLength!R) 14207 { 14208 auto back() @property 14209 { 14210 assert(!empty, "Attempting to fetch the back of an empty padRight"); 14211 return padLength > 0 ? element : data.back; 14212 } 14213 14214 void popBack() 14215 { 14216 assert(!empty, "Attempting to popBack an empty padRight"); 14217 if (padLength > 0) 14218 { 14219 --padLength; 14220 } 14221 else 14222 { 14223 data.popBack; 14224 } 14225 } 14226 } 14227 14228 static if (isRandomAccessRange!R && hasLength!R) 14229 { 14230 E opIndex(size_t index) 14231 { 14232 assert(index <= this.length, "Index out of bounds"); 14233 return index >= data.length ? element : data[index]; 14234 } 14235 } 14236 14237 static if (hasSlicing!R && hasLength!R) 14238 { 14239 auto opSlice(size_t a, size_t b) 14240 { 14241 assert( 14242 a <= b, 14243 "Attempting to slice a padRight with a larger first argument than the second." 14244 ); 14245 assert( 14246 b <= length, 14247 "Attempting to slice using an out of bounds index on a padRight" 14248 ); 14249 return Result( 14250 a >= data.length ? data[0 .. 0] : b <= data.length ? data[a .. b] : data[a .. data.length], 14251 element, b - a); 14252 } 14253 14254 alias opDollar = length; 14255 } 14256 14257 this(R r, E e, size_t n) 14258 { 14259 data = r; 14260 element = e; 14261 static if (hasLength!R) 14262 { 14263 padLength = n > data.length ? n - data.length : 0; 14264 } 14265 else 14266 { 14267 minLength = n; 14268 } 14269 } 14270 14271 @disable this(); 14272 } 14273 14274 return Result(r, e, n); 14275 } 14276 14277 /// 14278 @safe pure unittest 14279 { 14280 import std.algorithm.comparison : equal; 14281 14282 assert([1, 2, 3, 4].padRight(0, 6).equal([1, 2, 3, 4, 0, 0])); 14283 assert([1, 2, 3, 4].padRight(0, 4).equal([1, 2, 3, 4])); 14284 14285 assert("abc".padRight('_', 6).equal("abc___")); 14286 } 14287 14288 pure @safe unittest 14289 { 14290 import std.algorithm.comparison : equal; 14291 import std.internal.test.dummyrange : AllDummyRanges, ReferenceInputRange; 14292 import std.meta : AliasSeq; 14293 14294 auto string_input_range = new ReferenceInputRange!dchar(['a', 'b', 'c']); 14295 dchar padding = '_'; 14296 assert(string_input_range.padRight(padding, 6).equal("abc___")); 14297 14298 foreach (RangeType; AllDummyRanges) 14299 { 14300 RangeType r1; 14301 assert(r1 14302 .padRight(0, 12) 14303 .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0, 0]) 14304 ); 14305 14306 // test if Result properly uses random access ranges 14307 static if (isRandomAccessRange!RangeType) 14308 { 14309 RangeType r3; 14310 assert(r3.padRight(0, 12)[0] == 1); 14311 assert(r3.padRight(0, 12)[2] == 3); 14312 assert(r3.padRight(0, 12)[9] == 10); 14313 assert(r3.padRight(0, 12)[10] == 0); 14314 assert(r3.padRight(0, 12)[11] == 0); 14315 } 14316 14317 // test if Result properly uses slicing and opDollar 14318 static if (hasSlicing!RangeType) 14319 { 14320 RangeType r4; 14321 assert(r4 14322 .padRight(0, 12)[0 .. 3] 14323 .equal([1, 2, 3]) 14324 ); 14325 assert(r4 14326 .padRight(0, 12)[0 .. 10] 14327 .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U]) 14328 ); 14329 assert(r4 14330 .padRight(0, 12)[0 .. 11] 14331 .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0]) 14332 ); 14333 assert(r4 14334 .padRight(0, 12)[2 .. $] 14335 .equal([3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0, 0]) 14336 ); 14337 assert(r4 14338 .padRight(0, 12)[0 .. $] 14339 .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0, 0]) 14340 ); 14341 } 14342 14343 // drop & dropBack test opslice ranges when available, popFront/popBack otherwise 14344 RangeType r5; 14345 foreach (i; 1 .. 13) assert(r5.padRight(0, 12).drop(i).walkLength == 12 - i); 14346 } 14347 } 14348 14349 // Test nogc inference 14350 @safe @nogc pure unittest 14351 { 14352 import std.algorithm.comparison : equal; 14353 14354 static immutable r1 = [1, 2, 3, 4]; 14355 static immutable r2 = [1, 2, 3, 4, 0, 0]; 14356 assert(r1.padRight(0, 6).equal(r2)); 14357 } 14358 14359 // Test back, popBack, and save 14360 @safe pure unittest 14361 { 14362 import std.algorithm.comparison : equal; 14363 14364 auto r1 = [1, 2, 3, 4].padRight(0, 6); 14365 assert(r1.back == 0); 14366 14367 r1.popBack; 14368 auto r2 = r1.save; 14369 assert(r1.equal([1, 2, 3, 4, 0])); 14370 assert(r2.equal([1, 2, 3, 4, 0])); 14371 14372 r1.popBackN(2); 14373 assert(r1.back == 3); 14374 assert(r1.length == 3); 14375 assert(r2.length == 5); 14376 assert(r2.equal([1, 2, 3, 4, 0])); 14377 14378 r2.popFront; 14379 assert(r2.length == 4); 14380 assert(r2[0] == 2); 14381 assert(r2[1] == 3); 14382 assert(r2[2] == 4); 14383 assert(r2[3] == 0); 14384 assert(r2.equal([2, 3, 4, 0])); 14385 14386 r2.popBack; 14387 assert(r2.equal([2, 3, 4])); 14388 14389 auto r3 = [1, 2, 3, 4].padRight(0, 6); 14390 size_t len = 0; 14391 while (!r3.empty) 14392 { 14393 ++len; 14394 r3.popBack; 14395 } 14396 assert(len == 6); 14397 } 14398 14399 // https://issues.dlang.org/show_bug.cgi?id=19042 14400 @safe pure unittest 14401 { 14402 import std.algorithm.comparison : equal; 14403 14404 assert([2, 5, 13].padRight(42, 10).chunks(5) 14405 .equal!equal([[2, 5, 13, 42, 42], [42, 42, 42, 42, 42]])); 14406 14407 assert([1, 2, 3, 4].padRight(0, 10)[7 .. 9].equal([0, 0])); 14408 } 14409 14410 /** 14411 This simplifies a commonly used idiom in phobos for accepting any kind of string 14412 parameter. The type `R` can for example be a simple string, chained string using 14413 $(REF chain, std,range), $(REF chainPath, std,path) or any other input range of 14414 characters. 14415 14416 Only finite length character ranges are allowed with this constraint. 14417 14418 This template is equivalent to: 14419 --- 14420 isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) 14421 --- 14422 14423 See_Also: 14424 $(REF isInputRange, std,range,primitives), 14425 $(REF isInfinite, std,range,primitives), 14426 $(LREF isSomeChar), 14427 $(REF ElementEncodingType, std,range,primitives) 14428 */ 14429 template isSomeFiniteCharInputRange(R) 14430 { 14431 import std.traits : isSomeChar; 14432 14433 enum isSomeFiniteCharInputRange = isInputRange!R && !isInfinite!R 14434 && isSomeChar!(ElementEncodingType!R); 14435 } 14436 14437 /// 14438 @safe unittest 14439 { 14440 import std.path : chainPath; 14441 import std.range : chain; 14442 14443 void someLibraryMethod(R)(R argument) 14444 if (isSomeFiniteCharInputRange!R) 14445 { 14446 // implementation detail, would iterate over each character of argument 14447 } 14448 14449 someLibraryMethod("simple strings work"); 14450 someLibraryMethod(chain("chained", " ", "strings", " ", "work")); 14451 someLibraryMethod(chainPath("chained", "paths", "work")); 14452 // you can also use custom structs implementing a char range 14453 } 14454