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