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; 236 237 import std.internal.attributes : betterC; 238 import std.meta : allSatisfy, 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 source.back = val; 317 } 318 319 @property void back(ElementType!R val) 320 { 321 source.front = val; 322 } 323 } 324 325 static if (isRandomAccessRange!(R) && hasLength!(R)) 326 { 327 auto ref opIndex(size_t n) { return source[retroIndex(n)]; } 328 329 static if (hasAssignableElements!R) 330 { 331 void opIndexAssign(ElementType!R val, size_t n) 332 { 333 source[retroIndex(n)] = val; 334 } 335 } 336 337 static if (is(typeof(source.moveAt(0)))) 338 { 339 ElementType!R moveAt(size_t index) 340 { 341 return source.moveAt(retroIndex(index)); 342 } 343 } 344 345 static if (hasSlicing!R) 346 typeof(this) opSlice(size_t a, size_t b) 347 { 348 return typeof(this)(source[source.length - b .. source.length - a]); 349 } 350 } 351 352 static if (hasLength!R) 353 { 354 @property auto length() 355 { 356 return source.length; 357 } 358 359 alias opDollar = length; 360 } 361 } 362 363 return Result!()(r); 364 } 365 } 366 367 368 /// 369 pure @safe nothrow @nogc unittest 370 { 371 import std.algorithm.comparison : equal; 372 int[5] a = [ 1, 2, 3, 4, 5 ]; 373 int[5] b = [ 5, 4, 3, 2, 1 ]; 374 assert(equal(retro(a[]), b[])); 375 assert(retro(a[]).source is a[]); 376 assert(retro(retro(a[])) is a[]); 377 } 378 379 pure @safe nothrow unittest 380 { 381 import std.algorithm.comparison : equal; 382 static assert(isBidirectionalRange!(typeof(retro("hello")))); 383 int[] a; 384 static assert(is(typeof(a) == typeof(retro(retro(a))))); 385 assert(retro(retro(a)) is a); 386 static assert(isRandomAccessRange!(typeof(retro([1, 2, 3])))); 387 void test(int[] input, int[] witness) 388 { 389 auto r = retro(input); 390 assert(r.front == witness.front); 391 assert(r.back == witness.back); 392 assert(equal(r, witness)); 393 } 394 test([ 1 ], [ 1 ]); 395 test([ 1, 2 ], [ 2, 1 ]); 396 test([ 1, 2, 3 ], [ 3, 2, 1 ]); 397 test([ 1, 2, 3, 4 ], [ 4, 3, 2, 1 ]); 398 test([ 1, 2, 3, 4, 5 ], [ 5, 4, 3, 2, 1 ]); 399 test([ 1, 2, 3, 4, 5, 6 ], [ 6, 5, 4, 3, 2, 1 ]); 400 401 immutable foo = [1,2,3].idup; 402 auto r = retro(foo); 403 assert(equal(r, [3, 2, 1])); 404 } 405 406 pure @safe nothrow unittest 407 { 408 import std.internal.test.dummyrange : AllDummyRanges, propagatesRangeType, 409 ReturnBy; 410 411 foreach (DummyType; AllDummyRanges) 412 { 413 static if (!isBidirectionalRange!DummyType) 414 { 415 static assert(!__traits(compiles, Retro!DummyType)); 416 } 417 else 418 { 419 DummyType dummyRange; 420 dummyRange.reinit(); 421 422 auto myRetro = retro(dummyRange); 423 static assert(propagatesRangeType!(typeof(myRetro), DummyType)); 424 assert(myRetro.front == 10); 425 assert(myRetro.back == 1); 426 assert(myRetro.moveFront() == 10); 427 assert(myRetro.moveBack() == 1); 428 429 static if (isRandomAccessRange!DummyType && hasLength!DummyType) 430 { 431 assert(myRetro[0] == myRetro.front); 432 assert(myRetro.moveAt(2) == 8); 433 434 static if (DummyType.r == ReturnBy.Reference) 435 { 436 { 437 myRetro[9]++; 438 scope(exit) myRetro[9]--; 439 assert(dummyRange[0] == 2); 440 myRetro.front++; 441 scope(exit) myRetro.front--; 442 assert(myRetro.front == 11); 443 myRetro.back++; 444 scope(exit) myRetro.back--; 445 assert(myRetro.back == 3); 446 } 447 448 { 449 myRetro.front = 0xFF; 450 scope(exit) myRetro.front = 10; 451 assert(dummyRange.back == 0xFF); 452 453 myRetro.back = 0xBB; 454 scope(exit) myRetro.back = 1; 455 assert(dummyRange.front == 0xBB); 456 457 myRetro[1] = 11; 458 scope(exit) myRetro[1] = 8; 459 assert(dummyRange[8] == 11); 460 } 461 } 462 } 463 } 464 } 465 } 466 467 pure @safe nothrow @nogc unittest 468 { 469 import std.algorithm.comparison : equal; 470 auto LL = iota(1L, 4L); 471 auto r = retro(LL); 472 long[3] excepted = [3, 2, 1]; 473 assert(equal(r, excepted[])); 474 } 475 476 // https://issues.dlang.org/show_bug.cgi?id=12662 477 pure @safe nothrow @nogc unittest 478 { 479 int[3] src = [1,2,3]; 480 int[] data = src[]; 481 foreach_reverse (x; data) {} 482 foreach (x; data.retro) {} 483 } 484 485 486 /** 487 Iterates range `r` with stride `n`. If the range is a 488 random-access range, moves by indexing into the range; otherwise, 489 moves by successive calls to `popFront`. Applying stride twice to 490 the same range results in a stride with a step that is the 491 product of the two applications. It is an error for `n` to be 0. 492 493 Params: 494 r = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to stride over 495 n = the number of elements to skip over 496 497 Returns: 498 At minimum, an input range. The resulting range will adopt the 499 range primitives of the underlying range as long as 500 $(REF hasLength, std,range,primitives) is `true`. 501 */ 502 auto stride(Range)(Range r, size_t n) 503 if (isInputRange!(Unqual!Range)) 504 in 505 { 506 assert(n != 0, "stride cannot have step zero."); 507 } 508 do 509 { 510 import std.algorithm.comparison : min; 511 512 static if (is(typeof(stride(r.source, n)) == Range)) 513 { 514 // stride(stride(r, n1), n2) is stride(r, n1 * n2) 515 return stride(r.source, r._n * n); 516 } 517 else 518 { 519 static struct Result 520 { 521 private alias R = Unqual!Range; 522 public R source; 523 private size_t _n; 524 525 // Chop off the slack elements at the end 526 static if (hasLength!R && 527 (isRandomAccessRange!R && hasSlicing!R 528 || isBidirectionalRange!R)) 529 private void eliminateSlackElements() 530 { 531 auto slack = source.length % _n; 532 533 if (slack) 534 { 535 slack--; 536 } 537 else if (!source.empty) 538 { 539 slack = min(_n, source.length) - 1; 540 } 541 else 542 { 543 slack = 0; 544 } 545 if (!slack) return; 546 static if (isRandomAccessRange!R && hasLength!R && hasSlicing!R) 547 { 548 source = source[0 .. source.length - slack]; 549 } 550 else static if (isBidirectionalRange!R) 551 { 552 foreach (i; 0 .. slack) 553 { 554 source.popBack(); 555 } 556 } 557 } 558 559 static if (isForwardRange!R) 560 { 561 @property auto save() 562 { 563 return Result(source.save, _n); 564 } 565 } 566 567 static if (isInfinite!R) 568 { 569 enum bool empty = false; 570 } 571 else 572 { 573 @property bool empty() 574 { 575 return source.empty; 576 } 577 } 578 579 @property auto ref front() 580 { 581 return source.front; 582 } 583 584 static if (is(typeof(.moveFront(source)))) 585 { 586 ElementType!R moveFront() 587 { 588 return source.moveFront(); 589 } 590 } 591 592 static if (hasAssignableElements!R) 593 { 594 @property void front(ElementType!R val) 595 { 596 source.front = val; 597 } 598 } 599 600 void popFront() 601 { 602 source.popFrontN(_n); 603 } 604 605 static if (isBidirectionalRange!R && hasLength!R) 606 { 607 void popBack() 608 { 609 popBackN(source, _n); 610 } 611 612 @property auto ref back() 613 { 614 eliminateSlackElements(); 615 return source.back; 616 } 617 618 static if (is(typeof(.moveBack(source)))) 619 { 620 ElementType!R moveBack() 621 { 622 eliminateSlackElements(); 623 return source.moveBack(); 624 } 625 } 626 627 static if (hasAssignableElements!R) 628 { 629 @property void back(ElementType!R val) 630 { 631 eliminateSlackElements(); 632 source.back = val; 633 } 634 } 635 } 636 637 static if (isRandomAccessRange!R && hasLength!R) 638 { 639 auto ref opIndex(size_t n) 640 { 641 return source[_n * n]; 642 } 643 644 /** 645 Forwards to $(D moveAt(source, n)). 646 */ 647 static if (is(typeof(source.moveAt(0)))) 648 { 649 ElementType!R moveAt(size_t n) 650 { 651 return source.moveAt(_n * n); 652 } 653 } 654 655 static if (hasAssignableElements!R) 656 { 657 void opIndexAssign(ElementType!R val, size_t n) 658 { 659 source[_n * n] = val; 660 } 661 } 662 } 663 664 static if (hasSlicing!R && hasLength!R) 665 typeof(this) opSlice(size_t lower, size_t upper) 666 { 667 assert(upper >= lower && upper <= length); 668 immutable translatedUpper = (upper == 0) ? 0 : 669 (upper * _n - (_n - 1)); 670 immutable translatedLower = min(lower * _n, translatedUpper); 671 672 assert(translatedLower <= translatedUpper); 673 674 return typeof(this)(source[translatedLower .. translatedUpper], _n); 675 } 676 677 static if (hasLength!R) 678 { 679 @property auto length() 680 { 681 return (source.length + _n - 1) / _n; 682 } 683 684 alias opDollar = length; 685 } 686 } 687 return Result(r, n); 688 } 689 } 690 691 /// 692 pure @safe nothrow unittest 693 { 694 import std.algorithm.comparison : equal; 695 696 int[] a = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ]; 697 assert(equal(stride(a, 3), [ 1, 4, 7, 10 ][])); 698 assert(stride(stride(a, 2), 3) == stride(a, 6)); 699 } 700 701 pure @safe nothrow @nogc unittest 702 { 703 import std.algorithm.comparison : equal; 704 705 int[4] testArr = [1,2,3,4]; 706 static immutable result = [1, 3]; 707 assert(equal(testArr[].stride(2), result)); 708 } 709 710 debug pure nothrow @system unittest 711 {//check the contract 712 int[4] testArr = [1,2,3,4]; 713 bool passed = false; 714 scope (success) assert(passed); 715 import core.exception : AssertError; 716 //std.exception.assertThrown won't do because it can't infer nothrow 717 // https://issues.dlang.org/show_bug.cgi?id=12647 718 try 719 { 720 auto unused = testArr[].stride(0); 721 } 722 catch (AssertError unused) 723 { 724 passed = true; 725 } 726 } 727 728 pure @safe nothrow unittest 729 { 730 import std.algorithm.comparison : equal; 731 import std.internal.test.dummyrange : AllDummyRanges, propagatesRangeType, 732 ReturnBy; 733 734 static assert(isRandomAccessRange!(typeof(stride([1, 2, 3], 2)))); 735 void test(size_t n, int[] input, int[] witness) 736 { 737 assert(equal(stride(input, n), witness)); 738 } 739 test(1, [], []); 740 int[] arr = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; 741 assert(stride(stride(arr, 2), 3) is stride(arr, 6)); 742 test(1, arr, arr); 743 test(2, arr, [1, 3, 5, 7, 9]); 744 test(3, arr, [1, 4, 7, 10]); 745 test(4, arr, [1, 5, 9]); 746 747 // Test slicing. 748 auto s1 = stride(arr, 1); 749 assert(equal(s1[1 .. 4], [2, 3, 4])); 750 assert(s1[1 .. 4].length == 3); 751 assert(equal(s1[1 .. 5], [2, 3, 4, 5])); 752 assert(s1[1 .. 5].length == 4); 753 assert(s1[0 .. 0].empty); 754 assert(s1[3 .. 3].empty); 755 // assert(s1[$ .. $].empty); 756 assert(s1[s1.opDollar .. s1.opDollar].empty); 757 758 auto s2 = stride(arr, 2); 759 assert(equal(s2[0 .. 2], [1,3])); 760 assert(s2[0 .. 2].length == 2); 761 assert(equal(s2[1 .. 5], [3, 5, 7, 9])); 762 assert(s2[1 .. 5].length == 4); 763 assert(s2[0 .. 0].empty); 764 assert(s2[3 .. 3].empty); 765 // assert(s2[$ .. $].empty); 766 assert(s2[s2.opDollar .. s2.opDollar].empty); 767 768 // Test fix for https://issues.dlang.org/show_bug.cgi?id=5035 769 auto m = [1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]; // 3 rows, 4 columns 770 auto col = stride(m, 4); 771 assert(equal(col, [1, 1, 1])); 772 assert(equal(retro(col), [1, 1, 1])); 773 774 immutable int[] immi = [ 1, 2, 3 ]; 775 static assert(isRandomAccessRange!(typeof(stride(immi, 1)))); 776 777 // Check for infiniteness propagation. 778 static assert(isInfinite!(typeof(stride(repeat(1), 3)))); 779 780 foreach (DummyType; AllDummyRanges) 781 { 782 DummyType dummyRange; 783 dummyRange.reinit(); 784 785 auto myStride = stride(dummyRange, 4); 786 787 // Should fail if no length and bidirectional b/c there's no way 788 // to know how much slack we have. 789 static if (hasLength!DummyType || !isBidirectionalRange!DummyType) 790 { 791 static assert(propagatesRangeType!(typeof(myStride), DummyType)); 792 } 793 assert(myStride.front == 1); 794 assert(myStride.moveFront() == 1); 795 assert(equal(myStride, [1, 5, 9])); 796 797 static if (hasLength!DummyType) 798 { 799 assert(myStride.length == 3); 800 } 801 802 static if (isBidirectionalRange!DummyType && hasLength!DummyType) 803 { 804 assert(myStride.back == 9); 805 assert(myStride.moveBack() == 9); 806 } 807 808 static if (isRandomAccessRange!DummyType && hasLength!DummyType) 809 { 810 assert(myStride[0] == 1); 811 assert(myStride[1] == 5); 812 assert(myStride.moveAt(1) == 5); 813 assert(myStride[2] == 9); 814 815 static assert(hasSlicing!(typeof(myStride))); 816 } 817 818 static if (DummyType.r == ReturnBy.Reference) 819 { 820 // Make sure reference is propagated. 821 822 { 823 myStride.front++; 824 scope(exit) myStride.front--; 825 assert(dummyRange.front == 2); 826 } 827 { 828 myStride.front = 4; 829 scope(exit) myStride.front = 1; 830 assert(dummyRange.front == 4); 831 } 832 833 static if (isBidirectionalRange!DummyType && hasLength!DummyType) 834 { 835 { 836 myStride.back++; 837 scope(exit) myStride.back--; 838 assert(myStride.back == 10); 839 } 840 { 841 myStride.back = 111; 842 scope(exit) myStride.back = 9; 843 assert(myStride.back == 111); 844 } 845 846 static if (isRandomAccessRange!DummyType) 847 { 848 { 849 myStride[1]++; 850 scope(exit) myStride[1]--; 851 assert(dummyRange[4] == 6); 852 } 853 { 854 myStride[1] = 55; 855 scope(exit) myStride[1] = 5; 856 assert(dummyRange[4] == 55); 857 } 858 } 859 } 860 } 861 } 862 } 863 864 pure @safe nothrow unittest 865 { 866 import std.algorithm.comparison : equal; 867 868 auto LL = iota(1L, 10L); 869 auto s = stride(LL, 3); 870 assert(equal(s, [1L, 4L, 7L])); 871 } 872 873 /** 874 Spans multiple ranges in sequence. The function `chain` takes any 875 number of ranges and returns a $(D Chain!(R1, R2,...)) object. The 876 ranges may be different, but they must have the same element type. The 877 result is a range that offers the `front`, `popFront`, and $(D 878 empty) primitives. If all input ranges offer random access and $(D 879 length), `Chain` offers them as well. 880 881 If only one range is offered to `Chain` or `chain`, the $(D 882 Chain) type exits the picture by aliasing itself directly to that 883 range's type. 884 885 Params: 886 rs = the $(REF_ALTTEXT input ranges, isInputRange, std,range,primitives) to chain together 887 888 Returns: 889 An input range at minimum. If all of the ranges in `rs` provide 890 a range primitive, the returned range will also provide that range 891 primitive. 892 893 See_Also: $(LREF only) to chain values to a range 894 */ 895 auto chain(Ranges...)(Ranges rs) 896 if (Ranges.length > 0 && 897 allSatisfy!(isInputRange, staticMap!(Unqual, Ranges)) && 898 !is(CommonType!(staticMap!(ElementType, staticMap!(Unqual, Ranges))) == void)) 899 { 900 static if (Ranges.length == 1) 901 { 902 return rs[0]; 903 } 904 else 905 { 906 static struct Result 907 { 908 private: 909 alias R = staticMap!(Unqual, Ranges); 910 alias RvalueElementType = CommonType!(staticMap!(.ElementType, R)); 911 private template sameET(A) 912 { 913 enum sameET = is(.ElementType!A == RvalueElementType); 914 } 915 916 enum bool allSameType = allSatisfy!(sameET, R); 917 alias ElementType = RvalueElementType; 918 919 static if (allSameType && allSatisfy!(hasLvalueElements, R)) 920 { 921 static ref RvalueElementType fixRef(ref RvalueElementType val) 922 { 923 return val; 924 } 925 } 926 else 927 { 928 static RvalueElementType fixRef(RvalueElementType val) 929 { 930 return val; 931 } 932 } 933 934 // This is the entire state 935 R source; 936 // TODO: use a vtable (or more) instead of linear iteration 937 938 public: 939 this(R input) 940 { 941 foreach (i, v; input) 942 { 943 source[i] = v; 944 } 945 } 946 947 import std.meta : anySatisfy; 948 949 static if (anySatisfy!(isInfinite, R)) 950 { 951 // Propagate infiniteness. 952 enum bool empty = false; 953 } 954 else 955 { 956 @property bool empty() 957 { 958 foreach (i, Unused; R) 959 { 960 if (!source[i].empty) return false; 961 } 962 return true; 963 } 964 } 965 966 static if (allSatisfy!(isForwardRange, R)) 967 @property auto save() 968 { 969 auto saveSource(size_t len)() 970 { 971 import std.typecons : tuple; 972 static assert(len > 0); 973 static if (len == 1) 974 { 975 return tuple(source[0].save); 976 } 977 else 978 { 979 return saveSource!(len - 1)() ~ 980 tuple(source[len - 1].save); 981 } 982 } 983 return Result(saveSource!(R.length).expand); 984 } 985 986 void popFront() 987 { 988 foreach (i, Unused; R) 989 { 990 if (source[i].empty) continue; 991 source[i].popFront(); 992 return; 993 } 994 } 995 996 @property auto ref front() 997 { 998 foreach (i, Unused; R) 999 { 1000 if (source[i].empty) continue; 1001 return fixRef(source[i].front); 1002 } 1003 assert(false); 1004 } 1005 1006 static if (allSameType && allSatisfy!(hasAssignableElements, R)) 1007 { 1008 // @@@BUG@@@ 1009 //@property void front(T)(T v) if (is(T : RvalueElementType)) 1010 1011 @property void front(RvalueElementType v) 1012 { 1013 foreach (i, Unused; R) 1014 { 1015 if (source[i].empty) continue; 1016 source[i].front = v; 1017 return; 1018 } 1019 assert(false); 1020 } 1021 } 1022 1023 static if (allSatisfy!(hasMobileElements, R)) 1024 { 1025 RvalueElementType moveFront() 1026 { 1027 foreach (i, Unused; R) 1028 { 1029 if (source[i].empty) continue; 1030 return source[i].moveFront(); 1031 } 1032 assert(false); 1033 } 1034 } 1035 1036 static if (allSatisfy!(isBidirectionalRange, R)) 1037 { 1038 @property auto ref back() 1039 { 1040 foreach_reverse (i, Unused; R) 1041 { 1042 if (source[i].empty) continue; 1043 return fixRef(source[i].back); 1044 } 1045 assert(false); 1046 } 1047 1048 void popBack() 1049 { 1050 foreach_reverse (i, Unused; R) 1051 { 1052 if (source[i].empty) continue; 1053 source[i].popBack(); 1054 return; 1055 } 1056 } 1057 1058 static if (allSatisfy!(hasMobileElements, R)) 1059 { 1060 RvalueElementType moveBack() 1061 { 1062 foreach_reverse (i, Unused; R) 1063 { 1064 if (source[i].empty) continue; 1065 return source[i].moveBack(); 1066 } 1067 assert(false); 1068 } 1069 } 1070 1071 static if (allSameType && allSatisfy!(hasAssignableElements, R)) 1072 { 1073 @property void back(RvalueElementType v) 1074 { 1075 foreach_reverse (i, Unused; R) 1076 { 1077 if (source[i].empty) continue; 1078 source[i].back = v; 1079 return; 1080 } 1081 assert(false); 1082 } 1083 } 1084 } 1085 1086 static if (allSatisfy!(hasLength, R)) 1087 { 1088 @property size_t length() 1089 { 1090 size_t result; 1091 foreach (i, Unused; R) 1092 { 1093 result += source[i].length; 1094 } 1095 return result; 1096 } 1097 1098 alias opDollar = length; 1099 } 1100 1101 static if (allSatisfy!(isRandomAccessRange, R)) 1102 { 1103 auto ref opIndex(size_t index) 1104 { 1105 foreach (i, Range; R) 1106 { 1107 static if (isInfinite!(Range)) 1108 { 1109 return source[i][index]; 1110 } 1111 else 1112 { 1113 immutable length = source[i].length; 1114 if (index < length) return fixRef(source[i][index]); 1115 index -= length; 1116 } 1117 } 1118 assert(false); 1119 } 1120 1121 static if (allSatisfy!(hasMobileElements, R)) 1122 { 1123 RvalueElementType moveAt(size_t index) 1124 { 1125 foreach (i, Range; R) 1126 { 1127 static if (isInfinite!(Range)) 1128 { 1129 return source[i].moveAt(index); 1130 } 1131 else 1132 { 1133 immutable length = source[i].length; 1134 if (index < length) return source[i].moveAt(index); 1135 index -= length; 1136 } 1137 } 1138 assert(false); 1139 } 1140 } 1141 1142 static if (allSameType && allSatisfy!(hasAssignableElements, R)) 1143 void opIndexAssign(ElementType v, size_t index) 1144 { 1145 foreach (i, Range; R) 1146 { 1147 static if (isInfinite!(Range)) 1148 { 1149 source[i][index] = v; 1150 } 1151 else 1152 { 1153 immutable length = source[i].length; 1154 if (index < length) 1155 { 1156 source[i][index] = v; 1157 return; 1158 } 1159 index -= length; 1160 } 1161 } 1162 assert(false); 1163 } 1164 } 1165 1166 static if (allSatisfy!(hasLength, R) && allSatisfy!(hasSlicing, R)) 1167 auto opSlice(size_t begin, size_t end) return scope 1168 { 1169 auto result = this; 1170 foreach (i, Unused; R) 1171 { 1172 immutable len = result.source[i].length; 1173 if (len < begin) 1174 { 1175 result.source[i] = result.source[i] 1176 [len .. len]; 1177 begin -= len; 1178 } 1179 else 1180 { 1181 result.source[i] = result.source[i] 1182 [begin .. len]; 1183 break; 1184 } 1185 } 1186 auto cut = length; 1187 cut = cut <= end ? 0 : cut - end; 1188 foreach_reverse (i, Unused; R) 1189 { 1190 immutable len = result.source[i].length; 1191 if (cut > len) 1192 { 1193 result.source[i] = result.source[i] 1194 [0 .. 0]; 1195 cut -= len; 1196 } 1197 else 1198 { 1199 result.source[i] = result.source[i] 1200 [0 .. len - cut]; 1201 break; 1202 } 1203 } 1204 return result; 1205 } 1206 } 1207 return Result(rs); 1208 } 1209 } 1210 1211 /// 1212 pure @safe nothrow unittest 1213 { 1214 import std.algorithm.comparison : equal; 1215 1216 int[] arr1 = [ 1, 2, 3, 4 ]; 1217 int[] arr2 = [ 5, 6 ]; 1218 int[] arr3 = [ 7 ]; 1219 auto s = chain(arr1, arr2, arr3); 1220 assert(s.length == 7); 1221 assert(s[5] == 6); 1222 assert(equal(s, [1, 2, 3, 4, 5, 6, 7][])); 1223 } 1224 1225 /** 1226 * Range primitives are carried over to the returned range if 1227 * all of the ranges provide them 1228 */ 1229 pure @safe nothrow unittest 1230 { 1231 import std.algorithm.comparison : equal; 1232 import std.algorithm.sorting : sort; 1233 1234 int[] arr1 = [5, 2, 8]; 1235 int[] arr2 = [3, 7, 9]; 1236 int[] arr3 = [1, 4, 6]; 1237 1238 // in-place sorting across all of the arrays 1239 auto s = arr1.chain(arr2, arr3).sort; 1240 1241 assert(s.equal([1, 2, 3, 4, 5, 6, 7, 8, 9])); 1242 assert(arr1.equal([1, 2, 3])); 1243 assert(arr2.equal([4, 5, 6])); 1244 assert(arr3.equal([7, 8, 9])); 1245 } 1246 1247 /** 1248 Due to safe type promotion in D, chaining together different 1249 character ranges results in a `uint` range. 1250 1251 Use $(REF_ALTTEXT byChar, byChar,std,utf), $(REF_ALTTEXT byWchar, byWchar,std,utf), 1252 and $(REF_ALTTEXT byDchar, byDchar,std,utf) on the ranges 1253 to get the type you need. 1254 */ 1255 pure @safe nothrow unittest 1256 { 1257 import std.utf : byChar, byCodeUnit; 1258 1259 auto s1 = "string one"; 1260 auto s2 = "string two"; 1261 // s1 and s2 front is dchar because of auto-decoding 1262 static assert(is(typeof(s1.front) == dchar) && is(typeof(s2.front) == dchar)); 1263 1264 auto r1 = s1.chain(s2); 1265 // chains of ranges of the same character type give that same type 1266 static assert(is(typeof(r1.front) == dchar)); 1267 1268 auto s3 = "string three".byCodeUnit; 1269 static assert(is(typeof(s3.front) == immutable char)); 1270 auto r2 = s1.chain(s3); 1271 // chaining ranges of mixed character types gives `dchar` 1272 static assert(is(typeof(r2.front) == dchar)); 1273 1274 // use byChar on character ranges to correctly convert them to UTF-8 1275 auto r3 = s1.byChar.chain(s3); 1276 static assert(is(typeof(r3.front) == immutable char)); 1277 } 1278 1279 pure @safe nothrow unittest 1280 { 1281 import std.algorithm.comparison : equal; 1282 import std.internal.test.dummyrange : AllDummyRanges, dummyLength, 1283 propagatesRangeType; 1284 1285 { 1286 int[] arr1 = [ 1, 2, 3, 4 ]; 1287 int[] arr2 = [ 5, 6 ]; 1288 int[] arr3 = [ 7 ]; 1289 int[] witness = [ 1, 2, 3, 4, 5, 6, 7 ]; 1290 auto s1 = chain(arr1); 1291 static assert(isRandomAccessRange!(typeof(s1))); 1292 auto s2 = chain(arr1, arr2); 1293 static assert(isBidirectionalRange!(typeof(s2))); 1294 static assert(isRandomAccessRange!(typeof(s2))); 1295 s2.front = 1; 1296 auto s = chain(arr1, arr2, arr3); 1297 assert(s[5] == 6); 1298 assert(equal(s, witness)); 1299 assert(s[5] == 6); 1300 } 1301 { 1302 int[] arr1 = [ 1, 2, 3, 4 ]; 1303 int[] witness = [ 1, 2, 3, 4 ]; 1304 assert(equal(chain(arr1), witness)); 1305 } 1306 { 1307 uint[] foo = [1,2,3,4,5]; 1308 uint[] bar = [1,2,3,4,5]; 1309 auto c = chain(foo, bar); 1310 c[3] = 42; 1311 assert(c[3] == 42); 1312 assert(c.moveFront() == 1); 1313 assert(c.moveBack() == 5); 1314 assert(c.moveAt(4) == 5); 1315 assert(c.moveAt(5) == 1); 1316 } 1317 1318 1319 // Make sure https://issues.dlang.org/show_bug.cgi?id=3311 is fixed. 1320 // elements are mutable. 1321 assert(equal(chain(iota(0, 3), iota(0, 3)), [0, 1, 2, 0, 1, 2])); 1322 1323 // Test the case where infinite ranges are present. 1324 auto inf = chain([0,1,2][], cycle([4,5,6][]), [7,8,9][]); // infinite range 1325 assert(inf[0] == 0); 1326 assert(inf[3] == 4); 1327 assert(inf[6] == 4); 1328 assert(inf[7] == 5); 1329 static assert(isInfinite!(typeof(inf))); 1330 1331 immutable int[] immi = [ 1, 2, 3 ]; 1332 immutable float[] immf = [ 1, 2, 3 ]; 1333 static assert(is(typeof(chain(immi, immf)))); 1334 1335 // Check that chain at least instantiates and compiles with every possible 1336 // pair of DummyRange types, in either order. 1337 1338 foreach (DummyType1; AllDummyRanges) 1339 (){ // workaround slow optimizations for large functions 1340 // https://issues.dlang.org/show_bug.cgi?id=2396 1341 DummyType1 dummy1; 1342 foreach (DummyType2; AllDummyRanges) 1343 { 1344 DummyType2 dummy2; 1345 auto myChain = chain(dummy1, dummy2); 1346 1347 static assert( 1348 propagatesRangeType!(typeof(myChain), DummyType1, DummyType2) 1349 ); 1350 1351 assert(myChain.front == 1); 1352 foreach (i; 0 .. dummyLength) 1353 { 1354 myChain.popFront(); 1355 } 1356 assert(myChain.front == 1); 1357 1358 static if (isBidirectionalRange!DummyType1 && 1359 isBidirectionalRange!DummyType2) { 1360 assert(myChain.back == 10); 1361 } 1362 1363 static if (isRandomAccessRange!DummyType1 && 1364 isRandomAccessRange!DummyType2) { 1365 assert(myChain[0] == 1); 1366 } 1367 1368 static if (hasLvalueElements!DummyType1 && hasLvalueElements!DummyType2) 1369 { 1370 static assert(hasLvalueElements!(typeof(myChain))); 1371 } 1372 else 1373 { 1374 static assert(!hasLvalueElements!(typeof(myChain))); 1375 } 1376 } 1377 }(); 1378 } 1379 1380 pure @safe nothrow @nogc unittest 1381 { 1382 class Foo{} 1383 immutable(Foo)[] a; 1384 immutable(Foo)[] b; 1385 assert(chain(a, b).empty); 1386 } 1387 1388 // https://issues.dlang.org/show_bug.cgi?id=18657 1389 pure @safe unittest 1390 { 1391 import std.algorithm.comparison : equal; 1392 string s = "foo"; 1393 auto r = refRange(&s).chain("bar"); 1394 assert(equal(r.save, "foobar")); 1395 assert(equal(r, "foobar")); 1396 } 1397 1398 /** 1399 Choose one of two ranges at runtime depending on a Boolean condition. 1400 1401 The ranges may be different, but they must have compatible element types (i.e. 1402 `CommonType` must exist for the two element types). The result is a range 1403 that offers the weakest capabilities of the two (e.g. `ForwardRange` if $(D 1404 R1) is a random-access range and `R2` is a forward range). 1405 1406 Params: 1407 condition = which range to choose: `r1` if `true`, `r2` otherwise 1408 r1 = the "true" range 1409 r2 = the "false" range 1410 1411 Returns: 1412 A range type dependent on `R1` and `R2`. 1413 */ 1414 auto choose(R1, R2)(bool condition, return scope R1 r1, return scope R2 r2) 1415 if (isInputRange!(Unqual!R1) && isInputRange!(Unqual!R2) && 1416 !is(CommonType!(ElementType!(Unqual!R1), ElementType!(Unqual!R2)) == void)) 1417 { 1418 return ChooseResult!(R1, R2)(condition, r1, r2); 1419 } 1420 1421 /// 1422 @safe nothrow pure @nogc unittest 1423 { 1424 import std.algorithm.comparison : equal; 1425 import std.algorithm.iteration : filter, map; 1426 1427 auto data1 = only(1, 2, 3, 4).filter!(a => a != 3); 1428 auto data2 = only(5, 6, 7, 8).map!(a => a + 1); 1429 1430 // choose() is primarily useful when you need to select one of two ranges 1431 // with different types at runtime. 1432 static assert(!is(typeof(data1) == typeof(data2))); 1433 1434 auto chooseRange(bool pickFirst) 1435 { 1436 // The returned range is a common wrapper type that can be used for 1437 // returning or storing either range without running into a type error. 1438 return choose(pickFirst, data1, data2); 1439 1440 // Simply returning the chosen range without using choose() does not 1441 // work, because map() and filter() return different types. 1442 //return pickFirst ? data1 : data2; // does not compile 1443 } 1444 1445 auto result = chooseRange(true); 1446 assert(result.equal(only(1, 2, 4))); 1447 1448 result = chooseRange(false); 1449 assert(result.equal(only(6, 7, 8, 9))); 1450 } 1451 1452 1453 private struct ChooseResult(R1, R2) 1454 { 1455 import std.traits : hasElaborateCopyConstructor, hasElaborateDestructor; 1456 1457 private union 1458 { 1459 R1 r1; 1460 R2 r2; 1461 } 1462 private bool r1Chosen; 1463 1464 private static auto ref actOnChosen(alias foo, ExtraArgs ...)(ref ChooseResult r, 1465 auto ref ExtraArgs extraArgs) 1466 { 1467 if (r.r1Chosen) 1468 { 1469 ref get1(return ref ChooseResult r) @trusted { return r.r1; } 1470 return foo(get1(r), extraArgs); 1471 } 1472 else 1473 { 1474 ref get2(return ref ChooseResult r) @trusted { return r.r2; } 1475 return foo(get2(r), extraArgs); 1476 } 1477 } 1478 1479 this(bool r1Chosen, return scope R1 r1, return scope R2 r2) @trusted 1480 { 1481 // @trusted because of assignment of r1 and r2 which overlap each other 1482 import std.conv : emplace; 1483 1484 // This should be the only place r1Chosen is ever assigned 1485 // independently 1486 this.r1Chosen = r1Chosen; 1487 if (r1Chosen) 1488 { 1489 this.r2 = R2.init; 1490 emplace(&this.r1, r1); 1491 } 1492 else 1493 { 1494 this.r1 = R1.init; 1495 emplace(&this.r2, r2); 1496 } 1497 } 1498 1499 void opAssign(ChooseResult r) 1500 { 1501 static if (hasElaborateDestructor!R1 || hasElaborateDestructor!R2) 1502 if (r1Chosen != r.r1Chosen) 1503 { 1504 // destroy the current item 1505 actOnChosen!((ref r) => destroy(r))(this); 1506 } 1507 r1Chosen = r.r1Chosen; 1508 if (r1Chosen) 1509 { 1510 ref get1(return ref ChooseResult r) @trusted { return r.r1; } 1511 get1(this) = get1(r); 1512 } 1513 else 1514 { 1515 ref get2(return ref ChooseResult r) @trusted { return r.r2; } 1516 get2(this) = get2(r); 1517 } 1518 } 1519 1520 // Carefully defined postblit to postblit the appropriate range 1521 static if (hasElaborateCopyConstructor!R1 1522 || hasElaborateCopyConstructor!R2) 1523 this(this) 1524 { 1525 actOnChosen!((ref r) { 1526 static if (hasElaborateCopyConstructor!(typeof(r))) r.__postblit(); 1527 })(this); 1528 } 1529 1530 static if (hasElaborateDestructor!R1 || hasElaborateDestructor!R2) 1531 ~this() 1532 { 1533 actOnChosen!((ref r) => destroy(r))(this); 1534 } 1535 1536 static if (isInfinite!R1 && isInfinite!R2) 1537 // Propagate infiniteness. 1538 enum bool empty = false; 1539 else 1540 @property bool empty() 1541 { 1542 return actOnChosen!(r => r.empty)(this); 1543 } 1544 1545 @property auto ref front() 1546 { 1547 static auto ref getFront(R)(ref R r) { return r.front; } 1548 return actOnChosen!getFront(this); 1549 } 1550 1551 void popFront() 1552 { 1553 return actOnChosen!((ref r) { r.popFront; })(this); 1554 } 1555 1556 static if (isForwardRange!R1 && isForwardRange!R2) 1557 @property auto save() return scope 1558 { 1559 if (r1Chosen) 1560 { 1561 ref R1 getR1() @trusted { return r1; } 1562 return ChooseResult(r1Chosen, getR1.save, R2.init); 1563 } 1564 else 1565 { 1566 ref R2 getR2() @trusted { return r2; } 1567 return ChooseResult(r1Chosen, R1.init, getR2.save); 1568 } 1569 } 1570 1571 @property void front(T)(T v) 1572 if (is(typeof({ r1.front = v; r2.front = v; }))) 1573 { 1574 actOnChosen!((ref r, T v) { r.front = v; })(this, v); 1575 } 1576 1577 static if (hasMobileElements!R1 && hasMobileElements!R2) 1578 auto moveFront() 1579 { 1580 return actOnChosen!((ref r) => r.moveFront)(this); 1581 } 1582 1583 static if (isBidirectionalRange!R1 && isBidirectionalRange!R2) 1584 { 1585 @property auto ref back() 1586 { 1587 static auto ref getBack(R)(ref R r) { return r.back; } 1588 return actOnChosen!getBack(this); 1589 } 1590 1591 void popBack() 1592 { 1593 actOnChosen!((ref r) { r.popBack; })(this); 1594 } 1595 1596 static if (hasMobileElements!R1 && hasMobileElements!R2) 1597 auto moveBack() 1598 { 1599 return actOnChosen!((ref r) => r.moveBack)(this); 1600 } 1601 1602 @property void back(T)(T v) 1603 if (is(typeof({ r1.back = v; r2.back = v; }))) 1604 { 1605 actOnChosen!((ref r, T v) { r.back = v; })(this, v); 1606 } 1607 } 1608 1609 static if (hasLength!R1 && hasLength!R2) 1610 { 1611 @property size_t length() 1612 { 1613 return actOnChosen!(r => r.length)(this); 1614 } 1615 alias opDollar = length; 1616 } 1617 1618 static if (isRandomAccessRange!R1 && isRandomAccessRange!R2) 1619 { 1620 auto ref opIndex(size_t index) 1621 { 1622 static auto ref get(R)(ref R r, size_t index) { return r[index]; } 1623 return actOnChosen!get(this, index); 1624 } 1625 1626 static if (hasMobileElements!R1 && hasMobileElements!R2) 1627 auto moveAt(size_t index) 1628 { 1629 return actOnChosen!((ref r, size_t index) => r.moveAt(index)) 1630 (this, index); 1631 } 1632 1633 void opIndexAssign(T)(T v, size_t index) 1634 if (is(typeof({ r1[1] = v; r2[1] = v; }))) 1635 { 1636 return actOnChosen!((ref r, size_t index, T v) { r[index] = v; }) 1637 (this, index, v); 1638 } 1639 } 1640 1641 static if (hasSlicing!R1 && hasSlicing!R2) 1642 auto opSlice(size_t begin, size_t end) 1643 { 1644 alias Slice1 = typeof(R1.init[0 .. 1]); 1645 alias Slice2 = typeof(R2.init[0 .. 1]); 1646 return actOnChosen!((r, size_t begin, size_t end) { 1647 static if (is(typeof(r) == Slice1)) 1648 return choose(true, r[begin .. end], Slice2.init); 1649 else 1650 return choose(false, Slice1.init, r[begin .. end]); 1651 })(this, begin, end); 1652 } 1653 } 1654 1655 // https://issues.dlang.org/show_bug.cgi?id=18657 1656 pure @safe unittest 1657 { 1658 import std.algorithm.comparison : equal; 1659 string s = "foo"; 1660 auto r = choose(true, refRange(&s), "bar"); 1661 assert(equal(r.save, "foo")); 1662 assert(equal(r, "foo")); 1663 } 1664 1665 @safe unittest 1666 { 1667 static void* p; 1668 static struct R 1669 { 1670 void* q; 1671 int front; 1672 bool empty; 1673 void popFront() {} 1674 @property R save() { p = q; return this; } 1675 // `p = q;` is only there to prevent inference of `scope return`. 1676 } 1677 R r; 1678 choose(true, r, r).save; 1679 } 1680 1681 // Make sure ChooseResult.save doesn't trust @system user code. 1682 @system unittest // copy is @system 1683 { 1684 static struct R 1685 { 1686 int front; 1687 bool empty; 1688 void popFront() {} 1689 this(this) @system {} 1690 @property R save() { return R(front, empty); } 1691 } 1692 choose(true, R(), R()).save; 1693 choose(true, [0], R()).save; 1694 choose(true, R(), [0]).save; 1695 } 1696 1697 @safe unittest // copy is @system 1698 { 1699 static struct R 1700 { 1701 int front; 1702 bool empty; 1703 void popFront() {} 1704 this(this) @system {} 1705 @property R save() { return R(front, empty); } 1706 } 1707 static assert(!__traits(compiles, choose(true, R(), R()).save)); 1708 static assert(!__traits(compiles, choose(true, [0], R()).save)); 1709 static assert(!__traits(compiles, choose(true, R(), [0]).save)); 1710 } 1711 1712 @system unittest // .save is @system 1713 { 1714 static struct R 1715 { 1716 int front; 1717 bool empty; 1718 void popFront() {} 1719 @property R save() @system { return this; } 1720 } 1721 choose(true, R(), R()).save; 1722 choose(true, [0], R()).save; 1723 choose(true, R(), [0]).save; 1724 } 1725 1726 @safe unittest // .save is @system 1727 { 1728 static struct R 1729 { 1730 int front; 1731 bool empty; 1732 void popFront() {} 1733 @property R save() @system { return this; } 1734 } 1735 static assert(!__traits(compiles, choose(true, R(), R()).save)); 1736 static assert(!__traits(compiles, choose(true, [0], R()).save)); 1737 static assert(!__traits(compiles, choose(true, R(), [0]).save)); 1738 } 1739 1740 //https://issues.dlang.org/show_bug.cgi?id=19738 1741 @safe nothrow pure @nogc unittest 1742 { 1743 static struct EvilRange 1744 { 1745 enum empty = true; 1746 int front; 1747 void popFront() @safe {} 1748 auto opAssign(const ref EvilRange other) 1749 { 1750 *(cast(uint*) 0xcafebabe) = 0xdeadbeef; 1751 return this; 1752 } 1753 } 1754 1755 static assert(!__traits(compiles, () @safe 1756 { 1757 auto c1 = choose(true, EvilRange(), EvilRange()); 1758 auto c2 = c1; 1759 c1 = c2; 1760 })); 1761 } 1762 1763 1764 // https://issues.dlang.org/show_bug.cgi?id=20495 1765 @safe unittest 1766 { 1767 static struct KillableRange 1768 { 1769 int *item; 1770 ref int front() { return *item; } 1771 bool empty() { return *item > 10; } 1772 void popFront() { ++(*item); } 1773 this(this) 1774 { 1775 assert(item is null || cast(size_t) item > 1000); 1776 item = new int(*item); 1777 } 1778 KillableRange save() { return this; } 1779 } 1780 1781 auto kr = KillableRange(new int(1)); 1782 int[] x = [1,2,3,4,5]; // length is first 1783 1784 auto chosen = choose(true, x, kr); 1785 auto chosen2 = chosen.save; 1786 } 1787 1788 /** 1789 Choose one of multiple ranges at runtime. 1790 1791 The ranges may be different, but they must have compatible element types. The 1792 result is a range that offers the weakest capabilities of all `Ranges`. 1793 1794 Params: 1795 index = which range to choose, must be less than the number of ranges 1796 rs = two or more ranges 1797 1798 Returns: 1799 The indexed range. If rs consists of only one range, the return type is an 1800 alias of that range's type. 1801 */ 1802 auto chooseAmong(Ranges...)(size_t index, return scope Ranges rs) 1803 if (Ranges.length >= 2 1804 && allSatisfy!(isInputRange, staticMap!(Unqual, Ranges)) 1805 && !is(CommonType!(staticMap!(ElementType, Ranges)) == void)) 1806 { 1807 static if (Ranges.length == 2) 1808 return choose(index == 0, rs[0], rs[1]); 1809 else 1810 return choose(index == 0, rs[0], chooseAmong(index - 1, rs[1 .. $])); 1811 } 1812 1813 /// 1814 @safe nothrow pure @nogc unittest 1815 { 1816 auto test() 1817 { 1818 import std.algorithm.comparison : equal; 1819 1820 int[4] sarr1 = [1, 2, 3, 4]; 1821 int[2] sarr2 = [5, 6]; 1822 int[1] sarr3 = [7]; 1823 auto arr1 = sarr1[]; 1824 auto arr2 = sarr2[]; 1825 auto arr3 = sarr3[]; 1826 1827 { 1828 auto s = chooseAmong(0, arr1, arr2, arr3); 1829 auto t = s.save; 1830 assert(s.length == 4); 1831 assert(s[2] == 3); 1832 s.popFront(); 1833 assert(equal(t, only(1, 2, 3, 4))); 1834 } 1835 { 1836 auto s = chooseAmong(1, arr1, arr2, arr3); 1837 assert(s.length == 2); 1838 s.front = 8; 1839 assert(equal(s, only(8, 6))); 1840 } 1841 { 1842 auto s = chooseAmong(1, arr1, arr2, arr3); 1843 assert(s.length == 2); 1844 s[1] = 9; 1845 assert(equal(s, only(8, 9))); 1846 } 1847 { 1848 auto s = chooseAmong(1, arr2, arr1, arr3)[1 .. 3]; 1849 assert(s.length == 2); 1850 assert(equal(s, only(2, 3))); 1851 } 1852 { 1853 auto s = chooseAmong(0, arr1, arr2, arr3); 1854 assert(s.length == 4); 1855 assert(s.back == 4); 1856 s.popBack(); 1857 s.back = 5; 1858 assert(equal(s, only(1, 2, 5))); 1859 s.back = 3; 1860 assert(equal(s, only(1, 2, 3))); 1861 } 1862 { 1863 uint[5] foo = [1, 2, 3, 4, 5]; 1864 uint[5] bar = [6, 7, 8, 9, 10]; 1865 auto c = chooseAmong(1, foo[], bar[]); 1866 assert(c[3] == 9); 1867 c[3] = 42; 1868 assert(c[3] == 42); 1869 assert(c.moveFront() == 6); 1870 assert(c.moveBack() == 10); 1871 assert(c.moveAt(4) == 10); 1872 } 1873 { 1874 import std.range : cycle; 1875 auto s = chooseAmong(0, cycle(arr2), cycle(arr3)); 1876 assert(isInfinite!(typeof(s))); 1877 assert(!s.empty); 1878 assert(s[100] == 8); 1879 assert(s[101] == 9); 1880 assert(s[0 .. 3].equal(only(8, 9, 8))); 1881 } 1882 return 0; 1883 } 1884 // works at runtime 1885 auto a = test(); 1886 // and at compile time 1887 static b = test(); 1888 } 1889 1890 @safe nothrow pure @nogc unittest 1891 { 1892 int[3] a = [1, 2, 3]; 1893 long[3] b = [4, 5, 6]; 1894 auto c = chooseAmong(0, a[], b[]); 1895 c[0] = 42; 1896 assert(c[0] == 42); 1897 } 1898 1899 @safe nothrow pure @nogc unittest 1900 { 1901 static struct RefAccessRange 1902 { 1903 int[] r; 1904 ref front() @property { return r[0]; } 1905 ref back() @property { return r[$ - 1]; } 1906 void popFront() { r = r[1 .. $]; } 1907 void popBack() { r = r[0 .. $ - 1]; } 1908 auto empty() @property { return r.empty; } 1909 ref opIndex(size_t i) { return r[i]; } 1910 auto length() @property { return r.length; } 1911 alias opDollar = length; 1912 auto save() { return this; } 1913 } 1914 static assert(isRandomAccessRange!RefAccessRange); 1915 static assert(isRandomAccessRange!RefAccessRange); 1916 int[4] a = [4, 3, 2, 1]; 1917 int[2] b = [6, 5]; 1918 auto c = chooseAmong(0, RefAccessRange(a[]), RefAccessRange(b[])); 1919 1920 void refFunc(ref int a, int target) { assert(a == target); } 1921 1922 refFunc(c[2], 2); 1923 refFunc(c.front, 4); 1924 refFunc(c.back, 1); 1925 } 1926 1927 1928 /** 1929 $(D roundRobin(r1, r2, r3)) yields `r1.front`, then `r2.front`, 1930 then `r3.front`, after which it pops off one element from each and 1931 continues again from `r1`. For example, if two ranges are involved, 1932 it alternately yields elements off the two ranges. `roundRobin` 1933 stops after it has consumed all ranges (skipping over the ones that 1934 finish early). 1935 */ 1936 auto roundRobin(Rs...)(Rs rs) 1937 if (Rs.length > 1 && allSatisfy!(isInputRange, staticMap!(Unqual, Rs))) 1938 { 1939 struct Result 1940 { 1941 import std.conv : to; 1942 1943 public Rs source; 1944 private size_t _current = size_t.max; 1945 1946 @property bool empty() 1947 { 1948 foreach (i, Unused; Rs) 1949 { 1950 if (!source[i].empty) return false; 1951 } 1952 return true; 1953 } 1954 1955 @property auto ref front() 1956 { 1957 final switch (_current) 1958 { 1959 foreach (i, R; Rs) 1960 { 1961 case i: 1962 assert( 1963 !source[i].empty, 1964 "Attempting to fetch the front of an empty roundRobin" 1965 ); 1966 return source[i].front; 1967 } 1968 } 1969 assert(0); 1970 } 1971 1972 void popFront() 1973 { 1974 final switch (_current) 1975 { 1976 foreach (i, R; Rs) 1977 { 1978 case i: 1979 source[i].popFront(); 1980 break; 1981 } 1982 } 1983 1984 auto next = _current == (Rs.length - 1) ? 0 : (_current + 1); 1985 final switch (next) 1986 { 1987 foreach (i, R; Rs) 1988 { 1989 case i: 1990 if (!source[i].empty) 1991 { 1992 _current = i; 1993 return; 1994 } 1995 if (i == _current) 1996 { 1997 _current = _current.max; 1998 return; 1999 } 2000 goto case (i + 1) % Rs.length; 2001 } 2002 } 2003 } 2004 2005 static if (allSatisfy!(isForwardRange, staticMap!(Unqual, Rs))) 2006 @property auto save() 2007 { 2008 auto saveSource(size_t len)() 2009 { 2010 import std.typecons : tuple; 2011 static assert(len > 0); 2012 static if (len == 1) 2013 { 2014 return tuple(source[0].save); 2015 } 2016 else 2017 { 2018 return saveSource!(len - 1)() ~ 2019 tuple(source[len - 1].save); 2020 } 2021 } 2022 return Result(saveSource!(Rs.length).expand, _current); 2023 } 2024 2025 static if (allSatisfy!(hasLength, Rs)) 2026 { 2027 @property size_t length() 2028 { 2029 size_t result; 2030 foreach (i, R; Rs) 2031 { 2032 result += source[i].length; 2033 } 2034 return result; 2035 } 2036 2037 alias opDollar = length; 2038 } 2039 } 2040 2041 return Result(rs, 0); 2042 } 2043 2044 /// 2045 @safe unittest 2046 { 2047 import std.algorithm.comparison : equal; 2048 2049 int[] a = [ 1, 2, 3 ]; 2050 int[] b = [ 10, 20, 30, 40 ]; 2051 auto r = roundRobin(a, b); 2052 assert(equal(r, [ 1, 10, 2, 20, 3, 30, 40 ])); 2053 } 2054 2055 /** 2056 * roundRobin can be used to create "interleave" functionality which inserts 2057 * an element between each element in a range. 2058 */ 2059 @safe unittest 2060 { 2061 import std.algorithm.comparison : equal; 2062 2063 auto interleave(R, E)(R range, E element) 2064 if ((isInputRange!R && hasLength!R) || isForwardRange!R) 2065 { 2066 static if (hasLength!R) 2067 immutable len = range.length; 2068 else 2069 immutable len = range.save.walkLength; 2070 2071 return roundRobin( 2072 range, 2073 element.repeat(len - 1) 2074 ); 2075 } 2076 2077 assert(interleave([1, 2, 3], 0).equal([1, 0, 2, 0, 3])); 2078 } 2079 2080 pure @safe unittest 2081 { 2082 import std.algorithm.comparison : equal; 2083 string f = "foo", b = "bar"; 2084 auto r = roundRobin(refRange(&f), refRange(&b)); 2085 assert(equal(r.save, "fboaor")); 2086 assert(equal(r.save, "fboaor")); 2087 } 2088 2089 /** 2090 Iterates a random-access range starting from a given point and 2091 progressively extending left and right from that point. If no initial 2092 point is given, iteration starts from the middle of the 2093 range. Iteration spans the entire range. 2094 2095 When `startingIndex` is 0 the range will be fully iterated in order 2096 and in reverse order when `r.length` is given. 2097 2098 Params: 2099 r = a random access range with length and slicing 2100 startingIndex = the index to begin iteration from 2101 2102 Returns: 2103 A forward range with length 2104 */ 2105 auto radial(Range, I)(Range r, I startingIndex) 2106 if (isRandomAccessRange!(Unqual!Range) && hasLength!(Unqual!Range) && hasSlicing!(Unqual!Range) && isIntegral!I) 2107 { 2108 if (startingIndex != r.length) ++startingIndex; 2109 return roundRobin(retro(r[0 .. startingIndex]), r[startingIndex .. r.length]); 2110 } 2111 2112 /// Ditto 2113 auto radial(R)(R r) 2114 if (isRandomAccessRange!(Unqual!R) && hasLength!(Unqual!R) && hasSlicing!(Unqual!R)) 2115 { 2116 return .radial(r, (r.length - !r.empty) / 2); 2117 } 2118 2119 /// 2120 @safe unittest 2121 { 2122 import std.algorithm.comparison : equal; 2123 int[] a = [ 1, 2, 3, 4, 5 ]; 2124 assert(equal(radial(a), [ 3, 4, 2, 5, 1 ])); 2125 a = [ 1, 2, 3, 4 ]; 2126 assert(equal(radial(a), [ 2, 3, 1, 4 ])); 2127 2128 // If the left end is reached first, the remaining elements on the right 2129 // are concatenated in order: 2130 a = [ 0, 1, 2, 3, 4, 5 ]; 2131 assert(equal(radial(a, 1), [ 1, 2, 0, 3, 4, 5 ])); 2132 2133 // If the right end is reached first, the remaining elements on the left 2134 // are concatenated in reverse order: 2135 assert(equal(radial(a, 4), [ 4, 5, 3, 2, 1, 0 ])); 2136 } 2137 2138 @safe unittest 2139 { 2140 import std.algorithm.comparison : equal; 2141 import std.conv : text; 2142 import std.exception : enforce; 2143 import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy; 2144 2145 void test(int[] input, int[] witness) 2146 { 2147 enforce(equal(radial(input), witness), 2148 text(radial(input), " vs. ", witness)); 2149 } 2150 test([], []); 2151 test([ 1 ], [ 1 ]); 2152 test([ 1, 2 ], [ 1, 2 ]); 2153 test([ 1, 2, 3 ], [ 2, 3, 1 ]); 2154 test([ 1, 2, 3, 4 ], [ 2, 3, 1, 4 ]); 2155 test([ 1, 2, 3, 4, 5 ], [ 3, 4, 2, 5, 1 ]); 2156 test([ 1, 2, 3, 4, 5, 6 ], [ 3, 4, 2, 5, 1, 6 ]); 2157 2158 int[] a = [ 1, 2, 3, 4, 5 ]; 2159 assert(equal(radial(a, 1), [ 2, 3, 1, 4, 5 ])); 2160 assert(equal(radial(a, 0), [ 1, 2, 3, 4, 5 ])); // only right subrange 2161 assert(equal(radial(a, a.length), [ 5, 4, 3, 2, 1 ])); // only left subrange 2162 static assert(isForwardRange!(typeof(radial(a, 1)))); 2163 2164 auto r = radial([1,2,3,4,5]); 2165 for (auto rr = r.save; !rr.empty; rr.popFront()) 2166 { 2167 assert(rr.front == moveFront(rr)); 2168 } 2169 r.front = 5; 2170 assert(r.front == 5); 2171 2172 // Test instantiation without lvalue elements. 2173 DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random) dummy; 2174 assert(equal(radial(dummy, 4), [5, 6, 4, 7, 3, 8, 2, 9, 1, 10])); 2175 2176 // immutable int[] immi = [ 1, 2 ]; 2177 // static assert(is(typeof(radial(immi)))); 2178 } 2179 2180 @safe unittest 2181 { 2182 import std.algorithm.comparison : equal; 2183 2184 auto LL = iota(1L, 6L); 2185 auto r = radial(LL); 2186 assert(equal(r, [3L, 4L, 2L, 5L, 1L])); 2187 } 2188 2189 /** 2190 Lazily takes only up to `n` elements of a range. This is 2191 particularly useful when using with infinite ranges. 2192 2193 Unlike $(LREF takeExactly), `take` does not require that there 2194 are `n` or more elements in `input`. As a consequence, length 2195 information is not applied to the result unless `input` also has 2196 length information. 2197 2198 Params: 2199 input = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives) 2200 to iterate over up to `n` times 2201 n = the number of elements to take 2202 2203 Returns: 2204 At minimum, an input range. If the range offers random access 2205 and `length`, `take` offers them as well. 2206 */ 2207 Take!R take(R)(R input, size_t n) 2208 if (isInputRange!(Unqual!R)) 2209 { 2210 alias U = Unqual!R; 2211 static if (is(R T == Take!T)) 2212 { 2213 import std.algorithm.comparison : min; 2214 return R(input.source, min(n, input._maxAvailable)); 2215 } 2216 else static if (!isInfinite!U && hasSlicing!U) 2217 { 2218 import std.algorithm.comparison : min; 2219 return input[0 .. min(n, input.length)]; 2220 } 2221 else 2222 { 2223 return Take!R(input, n); 2224 } 2225 } 2226 2227 /// ditto 2228 struct Take(Range) 2229 if (isInputRange!(Unqual!Range) && 2230 //take _cannot_ test hasSlicing on infinite ranges, because hasSlicing uses 2231 //take for slicing infinite ranges. 2232 !((!isInfinite!(Unqual!Range) && hasSlicing!(Unqual!Range)) || is(Range T == Take!T))) 2233 { 2234 private alias R = Unqual!Range; 2235 2236 /// User accessible in read and write 2237 public R source; 2238 2239 private size_t _maxAvailable; 2240 2241 alias Source = R; 2242 2243 /// Range primitives 2244 @property bool empty() 2245 { 2246 return _maxAvailable == 0 || source.empty; 2247 } 2248 2249 /// ditto 2250 @property auto ref front() 2251 { 2252 assert(!empty, 2253 "Attempting to fetch the front of an empty " 2254 ~ Take.stringof); 2255 return source.front; 2256 } 2257 2258 /// ditto 2259 void popFront() 2260 { 2261 assert(!empty, 2262 "Attempting to popFront() past the end of a " 2263 ~ Take.stringof); 2264 source.popFront(); 2265 --_maxAvailable; 2266 } 2267 2268 static if (isForwardRange!R) 2269 /// ditto 2270 @property Take save() 2271 { 2272 return Take(source.save, _maxAvailable); 2273 } 2274 2275 static if (hasAssignableElements!R) 2276 /// ditto 2277 @property void front(ElementType!R v) 2278 { 2279 assert(!empty, 2280 "Attempting to assign to the front of an empty " 2281 ~ Take.stringof); 2282 // This has to return auto instead of void because of 2283 // https://issues.dlang.org/show_bug.cgi?id=4706 2284 source.front = v; 2285 } 2286 2287 static if (hasMobileElements!R) 2288 { 2289 /// ditto 2290 auto moveFront() 2291 { 2292 assert(!empty, 2293 "Attempting to move the front of an empty " 2294 ~ Take.stringof); 2295 return source.moveFront(); 2296 } 2297 } 2298 2299 static if (isInfinite!R) 2300 { 2301 /// ditto 2302 @property size_t length() const 2303 { 2304 return _maxAvailable; 2305 } 2306 2307 /// ditto 2308 alias opDollar = length; 2309 2310 //Note: Due to Take/hasSlicing circular dependency, 2311 //This needs to be a restrained template. 2312 /// ditto 2313 auto opSlice()(size_t i, size_t j) 2314 if (hasSlicing!R) 2315 { 2316 assert(i <= j, "Invalid slice bounds"); 2317 assert(j <= length, "Attempting to slice past the end of a " 2318 ~ Take.stringof); 2319 return source[i .. j]; 2320 } 2321 } 2322 else static if (hasLength!R) 2323 { 2324 /// ditto 2325 @property size_t length() 2326 { 2327 import std.algorithm.comparison : min; 2328 return min(_maxAvailable, source.length); 2329 } 2330 2331 alias opDollar = length; 2332 } 2333 2334 static if (isRandomAccessRange!R) 2335 { 2336 /// ditto 2337 void popBack() 2338 { 2339 assert(!empty, 2340 "Attempting to popBack() past the beginning of a " 2341 ~ Take.stringof); 2342 --_maxAvailable; 2343 } 2344 2345 /// ditto 2346 @property auto ref back() 2347 { 2348 assert(!empty, 2349 "Attempting to fetch the back of an empty " 2350 ~ Take.stringof); 2351 return source[this.length - 1]; 2352 } 2353 2354 /// ditto 2355 auto ref opIndex(size_t index) 2356 { 2357 assert(index < length, 2358 "Attempting to index out of the bounds of a " 2359 ~ Take.stringof); 2360 return source[index]; 2361 } 2362 2363 static if (hasAssignableElements!R) 2364 { 2365 /// ditto 2366 @property void back(ElementType!R v) 2367 { 2368 // This has to return auto instead of void because of 2369 // https://issues.dlang.org/show_bug.cgi?id=4706 2370 assert(!empty, 2371 "Attempting to assign to the back of an empty " 2372 ~ Take.stringof); 2373 source[this.length - 1] = v; 2374 } 2375 2376 /// ditto 2377 void opIndexAssign(ElementType!R v, size_t index) 2378 { 2379 assert(index < length, 2380 "Attempting to index out of the bounds of a " 2381 ~ Take.stringof); 2382 source[index] = v; 2383 } 2384 } 2385 2386 static if (hasMobileElements!R) 2387 { 2388 /// ditto 2389 auto moveBack() 2390 { 2391 assert(!empty, 2392 "Attempting to move the back of an empty " 2393 ~ Take.stringof); 2394 return source.moveAt(this.length - 1); 2395 } 2396 2397 /// ditto 2398 auto moveAt(size_t index) 2399 { 2400 assert(index < length, 2401 "Attempting to index out of the bounds of a " 2402 ~ Take.stringof); 2403 return source.moveAt(index); 2404 } 2405 } 2406 } 2407 2408 /** 2409 Access to maximal length of the range. 2410 Note: the actual length of the range depends on the underlying range. 2411 If it has fewer elements, it will stop before maxLength is reached. 2412 */ 2413 @property size_t maxLength() const 2414 { 2415 return _maxAvailable; 2416 } 2417 } 2418 2419 /// ditto 2420 template Take(R) 2421 if (isInputRange!(Unqual!R) && 2422 ((!isInfinite!(Unqual!R) && hasSlicing!(Unqual!R)) || is(R T == Take!T))) 2423 { 2424 alias Take = R; 2425 } 2426 2427 /// 2428 pure @safe nothrow unittest 2429 { 2430 import std.algorithm.comparison : equal; 2431 2432 int[] arr1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; 2433 auto s = take(arr1, 5); 2434 assert(s.length == 5); 2435 assert(s[4] == 5); 2436 assert(equal(s, [ 1, 2, 3, 4, 5 ][])); 2437 } 2438 2439 /** 2440 * If the range runs out before `n` elements, `take` simply returns the entire 2441 * range (unlike $(LREF takeExactly), which will cause an assertion failure if 2442 * the range ends prematurely): 2443 */ 2444 pure @safe nothrow unittest 2445 { 2446 import std.algorithm.comparison : equal; 2447 2448 int[] arr2 = [ 1, 2, 3 ]; 2449 auto t = take(arr2, 5); 2450 assert(t.length == 3); 2451 assert(equal(t, [ 1, 2, 3 ])); 2452 } 2453 2454 pure @safe nothrow unittest 2455 { 2456 import std.algorithm.comparison : equal; 2457 import std.internal.test.dummyrange : AllDummyRanges; 2458 2459 int[] arr1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; 2460 auto s = take(arr1, 5); 2461 assert(s.length == 5); 2462 assert(s[4] == 5); 2463 assert(equal(s, [ 1, 2, 3, 4, 5 ][])); 2464 assert(equal(retro(s), [ 5, 4, 3, 2, 1 ][])); 2465 2466 // Test fix for bug 4464. 2467 static assert(is(typeof(s) == Take!(int[]))); 2468 static assert(is(typeof(s) == int[])); 2469 2470 // Test using narrow strings. 2471 import std.exception : assumeWontThrow; 2472 2473 auto myStr = "This is a string."; 2474 auto takeMyStr = take(myStr, 7); 2475 assert(assumeWontThrow(equal(takeMyStr, "This is"))); 2476 // Test fix for bug 5052. 2477 auto takeMyStrAgain = take(takeMyStr, 4); 2478 assert(assumeWontThrow(equal(takeMyStrAgain, "This"))); 2479 static assert(is (typeof(takeMyStrAgain) == typeof(takeMyStr))); 2480 takeMyStrAgain = take(takeMyStr, 10); 2481 assert(assumeWontThrow(equal(takeMyStrAgain, "This is"))); 2482 2483 foreach (DummyType; AllDummyRanges) 2484 { 2485 DummyType dummy; 2486 auto t = take(dummy, 5); 2487 alias T = typeof(t); 2488 2489 static if (isRandomAccessRange!DummyType) 2490 { 2491 static assert(isRandomAccessRange!T); 2492 assert(t[4] == 5); 2493 2494 assert(moveAt(t, 1) == t[1]); 2495 assert(t.back == moveBack(t)); 2496 } 2497 else static if (isForwardRange!DummyType) 2498 { 2499 static assert(isForwardRange!T); 2500 } 2501 2502 for (auto tt = t; !tt.empty; tt.popFront()) 2503 { 2504 assert(tt.front == moveFront(tt)); 2505 } 2506 2507 // Bidirectional ranges can't be propagated properly if they don't 2508 // also have random access. 2509 2510 assert(equal(t, [1,2,3,4,5])); 2511 2512 //Test that take doesn't wrap the result of take. 2513 assert(take(t, 4) == take(dummy, 4)); 2514 } 2515 2516 immutable myRepeat = repeat(1); 2517 static assert(is(Take!(typeof(myRepeat)))); 2518 } 2519 2520 pure @safe nothrow @nogc unittest 2521 { 2522 //check for correct slicing of Take on an infinite range 2523 import std.algorithm.comparison : equal; 2524 foreach (start; 0 .. 4) 2525 foreach (stop; start .. 4) 2526 assert(iota(4).cycle.take(4)[start .. stop] 2527 .equal(iota(start, stop))); 2528 } 2529 2530 pure @safe nothrow @nogc unittest 2531 { 2532 // Check that one can declare variables of all Take types, 2533 // and that they match the return type of the corresponding 2534 // take(). 2535 // See https://issues.dlang.org/show_bug.cgi?id=4464 2536 int[] r1; 2537 Take!(int[]) t1; 2538 t1 = take(r1, 1); 2539 assert(t1.empty); 2540 2541 string r2; 2542 Take!string t2; 2543 t2 = take(r2, 1); 2544 assert(t2.empty); 2545 2546 Take!(Take!string) t3; 2547 t3 = take(t2, 1); 2548 assert(t3.empty); 2549 } 2550 2551 pure @safe nothrow @nogc unittest 2552 { 2553 alias R1 = typeof(repeat(1)); 2554 alias R2 = typeof(cycle([1])); 2555 alias TR1 = Take!R1; 2556 alias TR2 = Take!R2; 2557 static assert(isBidirectionalRange!TR1); 2558 static assert(isBidirectionalRange!TR2); 2559 } 2560 2561 // https://issues.dlang.org/show_bug.cgi?id=12731 2562 pure @safe nothrow @nogc unittest 2563 { 2564 auto a = repeat(1); 2565 auto s = a[1 .. 5]; 2566 s = s[1 .. 3]; 2567 assert(s.length == 2); 2568 assert(s[0] == 1); 2569 assert(s[1] == 1); 2570 } 2571 2572 // https://issues.dlang.org/show_bug.cgi?id=13151 2573 pure @safe nothrow @nogc unittest 2574 { 2575 import std.algorithm.comparison : equal; 2576 2577 auto r = take(repeat(1, 4), 3); 2578 assert(r.take(2).equal(repeat(1, 2))); 2579 } 2580 2581 2582 /** 2583 Similar to $(LREF take), but assumes that `range` has at least $(D 2584 n) elements. Consequently, the result of $(D takeExactly(range, n)) 2585 always defines the `length` property (and initializes it to `n`) 2586 even when `range` itself does not define `length`. 2587 2588 The result of `takeExactly` is identical to that of $(LREF take) in 2589 cases where the original range defines `length` or is infinite. 2590 2591 Unlike $(LREF take), however, it is illegal to pass a range with less than 2592 `n` elements to `takeExactly`; this will cause an assertion failure. 2593 */ 2594 auto takeExactly(R)(R range, size_t n) 2595 if (isInputRange!R) 2596 { 2597 static if (is(typeof(takeExactly(range._input, n)) == R)) 2598 { 2599 assert(n <= range._n, 2600 "Attempted to take more than the length of the range with takeExactly."); 2601 // takeExactly(takeExactly(r, n1), n2) has the same type as 2602 // takeExactly(r, n1) and simply returns takeExactly(r, n2) 2603 range._n = n; 2604 return range; 2605 } 2606 //Also covers hasSlicing!R for finite ranges. 2607 else static if (hasLength!R) 2608 { 2609 assert(n <= range.length, 2610 "Attempted to take more than the length of the range with takeExactly."); 2611 return take(range, n); 2612 } 2613 else static if (isInfinite!R) 2614 return Take!R(range, n); 2615 else 2616 { 2617 static struct Result 2618 { 2619 R _input; 2620 private size_t _n; 2621 2622 @property bool empty() const { return !_n; } 2623 @property auto ref front() 2624 { 2625 assert(_n > 0, "front() on an empty " ~ Result.stringof); 2626 return _input.front; 2627 } 2628 void popFront() { _input.popFront(); --_n; } 2629 @property size_t length() const { return _n; } 2630 alias opDollar = length; 2631 2632 @property auto _takeExactly_Result_asTake() 2633 { 2634 return take(_input, _n); 2635 } 2636 2637 alias _takeExactly_Result_asTake this; 2638 2639 static if (isForwardRange!R) 2640 @property auto save() 2641 { 2642 return Result(_input.save, _n); 2643 } 2644 2645 static if (hasMobileElements!R) 2646 { 2647 auto moveFront() 2648 { 2649 assert(!empty, 2650 "Attempting to move the front of an empty " 2651 ~ typeof(this).stringof); 2652 return _input.moveFront(); 2653 } 2654 } 2655 2656 static if (hasAssignableElements!R) 2657 { 2658 @property auto ref front(ElementType!R v) 2659 { 2660 assert(!empty, 2661 "Attempting to assign to the front of an empty " 2662 ~ typeof(this).stringof); 2663 return _input.front = v; 2664 } 2665 } 2666 } 2667 2668 return Result(range, n); 2669 } 2670 } 2671 2672 /// 2673 pure @safe nothrow unittest 2674 { 2675 import std.algorithm.comparison : equal; 2676 2677 auto a = [ 1, 2, 3, 4, 5 ]; 2678 2679 auto b = takeExactly(a, 3); 2680 assert(equal(b, [1, 2, 3])); 2681 static assert(is(typeof(b.length) == size_t)); 2682 assert(b.length == 3); 2683 assert(b.front == 1); 2684 assert(b.back == 3); 2685 } 2686 2687 pure @safe nothrow unittest 2688 { 2689 import std.algorithm.comparison : equal; 2690 import std.algorithm.iteration : filter; 2691 2692 auto a = [ 1, 2, 3, 4, 5 ]; 2693 auto b = takeExactly(a, 3); 2694 assert(equal(b, [1, 2, 3])); 2695 auto c = takeExactly(b, 2); 2696 assert(equal(c, [1, 2])); 2697 2698 2699 2700 auto d = filter!"a > 2"(a); 2701 auto e = takeExactly(d, 3); 2702 assert(equal(e, [3, 4, 5])); 2703 static assert(is(typeof(e.length) == size_t)); 2704 assert(e.length == 3); 2705 assert(e.front == 3); 2706 2707 assert(equal(takeExactly(e, 3), [3, 4, 5])); 2708 } 2709 2710 pure @safe nothrow unittest 2711 { 2712 import std.algorithm.comparison : equal; 2713 import std.internal.test.dummyrange : AllDummyRanges; 2714 2715 auto a = [ 1, 2, 3, 4, 5 ]; 2716 //Test that take and takeExactly are the same for ranges which define length 2717 //but aren't sliceable. 2718 struct L 2719 { 2720 @property auto front() { return _arr[0]; } 2721 @property bool empty() { return _arr.empty; } 2722 void popFront() { _arr.popFront(); } 2723 @property size_t length() { return _arr.length; } 2724 int[] _arr; 2725 } 2726 static assert(is(typeof(take(L(a), 3)) == typeof(takeExactly(L(a), 3)))); 2727 assert(take(L(a), 3) == takeExactly(L(a), 3)); 2728 2729 //Test that take and takeExactly are the same for ranges which are sliceable. 2730 static assert(is(typeof(take(a, 3)) == typeof(takeExactly(a, 3)))); 2731 assert(take(a, 3) == takeExactly(a, 3)); 2732 2733 //Test that take and takeExactly are the same for infinite ranges. 2734 auto inf = repeat(1); 2735 static assert(is(typeof(take(inf, 5)) == Take!(typeof(inf)))); 2736 assert(take(inf, 5) == takeExactly(inf, 5)); 2737 2738 //Test that take and takeExactly are _not_ the same for ranges which don't 2739 //define length. 2740 static assert(!is(typeof(take(filter!"true"(a), 3)) == typeof(takeExactly(filter!"true"(a), 3)))); 2741 2742 foreach (DummyType; AllDummyRanges) 2743 { 2744 { 2745 DummyType dummy; 2746 auto t = takeExactly(dummy, 5); 2747 2748 //Test that takeExactly doesn't wrap the result of takeExactly. 2749 assert(takeExactly(t, 4) == takeExactly(dummy, 4)); 2750 } 2751 2752 static if (hasMobileElements!DummyType) 2753 { 2754 { 2755 auto t = takeExactly(DummyType.init, 4); 2756 assert(t.moveFront() == 1); 2757 assert(equal(t, [1, 2, 3, 4])); 2758 } 2759 } 2760 2761 static if (hasAssignableElements!DummyType) 2762 { 2763 { 2764 auto t = takeExactly(DummyType.init, 4); 2765 t.front = 9; 2766 assert(equal(t, [9, 2, 3, 4])); 2767 } 2768 } 2769 } 2770 } 2771 2772 pure @safe nothrow unittest 2773 { 2774 import std.algorithm.comparison : equal; 2775 import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy; 2776 2777 alias DummyType = DummyRange!(ReturnBy.Value, Length.No, RangeType.Forward); 2778 auto te = takeExactly(DummyType(), 5); 2779 Take!DummyType t = te; 2780 assert(equal(t, [1, 2, 3, 4, 5])); 2781 assert(equal(t, te)); 2782 } 2783 2784 // https://issues.dlang.org/show_bug.cgi?id=18092 2785 // can't combine take and takeExactly 2786 @safe unittest 2787 { 2788 import std.algorithm.comparison : equal; 2789 import std.internal.test.dummyrange : AllDummyRanges; 2790 2791 static foreach (Range; AllDummyRanges) 2792 {{ 2793 Range r; 2794 assert(r.take(6).takeExactly(2).equal([1, 2])); 2795 assert(r.takeExactly(6).takeExactly(2).equal([1, 2])); 2796 assert(r.takeExactly(6).take(2).equal([1, 2])); 2797 }} 2798 } 2799 2800 /** 2801 Returns a range with at most one element; for example, $(D 2802 takeOne([42, 43, 44])) returns a range consisting of the integer $(D 2803 42). Calling `popFront()` off that range renders it empty. 2804 2805 In effect `takeOne(r)` is somewhat equivalent to $(D take(r, 1)) but in 2806 certain interfaces it is important to know statically that the range may only 2807 have at most one element. 2808 2809 The type returned by `takeOne` is a random-access range with length 2810 regardless of `R`'s capabilities, as long as it is a forward range. 2811 (another feature that distinguishes `takeOne` from `take`). If 2812 (D R) is an input range but not a forward range, return type is an input 2813 range with all random-access capabilities except save. 2814 */ 2815 auto takeOne(R)(R source) 2816 if (isInputRange!R) 2817 { 2818 static if (hasSlicing!R) 2819 { 2820 return source[0 .. !source.empty]; 2821 } 2822 else 2823 { 2824 static struct Result 2825 { 2826 private R _source; 2827 private bool _empty = true; 2828 @property bool empty() const { return _empty; } 2829 @property auto ref front() 2830 { 2831 assert(!empty, "Attempting to fetch the front of an empty takeOne"); 2832 return _source.front; 2833 } 2834 void popFront() 2835 { 2836 assert(!empty, "Attempting to popFront an empty takeOne"); 2837 _source.popFront(); 2838 _empty = true; 2839 } 2840 void popBack() 2841 { 2842 assert(!empty, "Attempting to popBack an empty takeOne"); 2843 _source.popFront(); 2844 _empty = true; 2845 } 2846 static if (isForwardRange!(Unqual!R)) 2847 { 2848 @property auto save() { return Result(_source.save, empty); } 2849 } 2850 @property auto ref back() 2851 { 2852 assert(!empty, "Attempting to fetch the back of an empty takeOne"); 2853 return _source.front; 2854 } 2855 @property size_t length() const { return !empty; } 2856 alias opDollar = length; 2857 auto ref opIndex(size_t n) 2858 { 2859 assert(n < length, "Attempting to index a takeOne out of bounds"); 2860 return _source.front; 2861 } 2862 auto opSlice(size_t m, size_t n) 2863 { 2864 assert( 2865 m <= n, 2866 "Attempting to slice a takeOne range with a larger first argument than the second." 2867 ); 2868 assert( 2869 n <= length, 2870 "Attempting to slice using an out of bounds index on a takeOne range." 2871 ); 2872 return n > m ? this : Result(_source, true); 2873 } 2874 // Non-standard property 2875 @property R source() { return _source; } 2876 } 2877 2878 return Result(source, source.empty); 2879 } 2880 } 2881 2882 /// 2883 pure @safe nothrow unittest 2884 { 2885 auto s = takeOne([42, 43, 44]); 2886 static assert(isRandomAccessRange!(typeof(s))); 2887 assert(s.length == 1); 2888 assert(!s.empty); 2889 assert(s.front == 42); 2890 s.front = 43; 2891 assert(s.front == 43); 2892 assert(s.back == 43); 2893 assert(s[0] == 43); 2894 s.popFront(); 2895 assert(s.length == 0); 2896 assert(s.empty); 2897 } 2898 2899 pure @safe nothrow @nogc unittest 2900 { 2901 struct NonForwardRange 2902 { 2903 enum empty = false; 2904 int front() { return 42; } 2905 void popFront() {} 2906 } 2907 2908 static assert(!isForwardRange!NonForwardRange); 2909 2910 auto s = takeOne(NonForwardRange()); 2911 assert(s.length == 1); 2912 assert(!s.empty); 2913 assert(s.front == 42); 2914 assert(s.back == 42); 2915 assert(s[0] == 42); 2916 2917 auto t = s[0 .. 0]; 2918 assert(t.empty); 2919 assert(t.length == 0); 2920 2921 auto u = s[1 .. 1]; 2922 assert(u.empty); 2923 assert(u.length == 0); 2924 2925 auto v = s[0 .. 1]; 2926 s.popFront(); 2927 assert(s.length == 0); 2928 assert(s.empty); 2929 assert(!v.empty); 2930 assert(v.front == 42); 2931 v.popBack(); 2932 assert(v.empty); 2933 assert(v.length == 0); 2934 } 2935 2936 pure @safe nothrow @nogc unittest 2937 { 2938 struct NonSlicingForwardRange 2939 { 2940 enum empty = false; 2941 int front() { return 42; } 2942 void popFront() {} 2943 @property auto save() { return this; } 2944 } 2945 2946 static assert(isForwardRange!NonSlicingForwardRange); 2947 static assert(!hasSlicing!NonSlicingForwardRange); 2948 2949 auto s = takeOne(NonSlicingForwardRange()); 2950 assert(s.length == 1); 2951 assert(!s.empty); 2952 assert(s.front == 42); 2953 assert(s.back == 42); 2954 assert(s[0] == 42); 2955 auto t = s.save; 2956 s.popFront(); 2957 assert(s.length == 0); 2958 assert(s.empty); 2959 assert(!t.empty); 2960 assert(t.front == 42); 2961 t.popBack(); 2962 assert(t.empty); 2963 assert(t.length == 0); 2964 } 2965 2966 // Test that asserts trigger correctly 2967 @system unittest 2968 { 2969 import std.exception : assertThrown; 2970 import core.exception : AssertError; 2971 2972 struct NonForwardRange 2973 { 2974 enum empty = false; 2975 int front() { return 42; } 2976 void popFront() {} 2977 } 2978 2979 auto s = takeOne(NonForwardRange()); 2980 2981 assertThrown!AssertError(s[1]); 2982 assertThrown!AssertError(s[0 .. 2]); 2983 2984 size_t one = 1; // Avoid style warnings triggered by literals 2985 size_t zero = 0; 2986 assertThrown!AssertError(s[one .. zero]); 2987 2988 s.popFront; 2989 assert(s.empty); 2990 assertThrown!AssertError(s.front); 2991 assertThrown!AssertError(s.back); 2992 assertThrown!AssertError(s.popFront); 2993 assertThrown!AssertError(s.popBack); 2994 } 2995 2996 // https://issues.dlang.org/show_bug.cgi?id=16999 2997 pure @safe unittest 2998 { 2999 auto myIota = new class 3000 { 3001 int front = 0; 3002 @safe void popFront(){front++;} 3003 enum empty = false; 3004 }; 3005 auto iotaPart = myIota.takeOne; 3006 int sum; 3007 foreach (var; chain(iotaPart, iotaPart, iotaPart)) 3008 { 3009 sum += var; 3010 } 3011 assert(sum == 3); 3012 assert(iotaPart.front == 3); 3013 } 3014 3015 /++ 3016 Returns an empty range which is statically known to be empty and is 3017 guaranteed to have `length` and be random access regardless of `R`'s 3018 capabilities. 3019 +/ 3020 auto takeNone(R)() 3021 if (isInputRange!R) 3022 { 3023 return typeof(takeOne(R.init)).init; 3024 } 3025 3026 /// 3027 pure @safe nothrow @nogc unittest 3028 { 3029 auto range = takeNone!(int[])(); 3030 assert(range.length == 0); 3031 assert(range.empty); 3032 } 3033 3034 pure @safe nothrow @nogc unittest 3035 { 3036 enum ctfe = takeNone!(int[])(); 3037 static assert(ctfe.length == 0); 3038 static assert(ctfe.empty); 3039 } 3040 3041 3042 /++ 3043 Creates an empty range from the given range in $(BIGOH 1). If it can, it 3044 will return the same range type. If not, it will return 3045 $(D takeExactly(range, 0)). 3046 +/ 3047 auto takeNone(R)(R range) 3048 if (isInputRange!R) 3049 { 3050 import std.traits : isDynamicArray; 3051 //Makes it so that calls to takeNone which don't use UFCS still work with a 3052 //member version if it's defined. 3053 static if (is(typeof(R.takeNone))) 3054 auto retval = range.takeNone(); 3055 // https://issues.dlang.org/show_bug.cgi?id=8339 3056 else static if (isDynamicArray!R)/+ || 3057 (is(R == struct) && __traits(compiles, {auto r = R.init;}) && R.init.empty))+/ 3058 { 3059 auto retval = R.init; 3060 } 3061 //An infinite range sliced at [0 .. 0] would likely still not be empty... 3062 else static if (hasSlicing!R && !isInfinite!R) 3063 auto retval = range[0 .. 0]; 3064 else 3065 auto retval = takeExactly(range, 0); 3066 3067 // https://issues.dlang.org/show_bug.cgi?id=7892 prevents this from being 3068 // done in an out block. 3069 assert(retval.empty); 3070 return retval; 3071 } 3072 3073 /// 3074 pure @safe nothrow unittest 3075 { 3076 import std.algorithm.iteration : filter; 3077 assert(takeNone([42, 27, 19]).empty); 3078 assert(takeNone("dlang.org").empty); 3079 assert(takeNone(filter!"true"([42, 27, 19])).empty); 3080 } 3081 3082 @safe unittest 3083 { 3084 import std.algorithm.iteration : filter; 3085 import std.meta : AliasSeq; 3086 3087 struct Dummy 3088 { 3089 mixin template genInput() 3090 { 3091 @safe: 3092 @property bool empty() { return _arr.empty; } 3093 @property auto front() { return _arr.front; } 3094 void popFront() { _arr.popFront(); } 3095 static assert(isInputRange!(typeof(this))); 3096 } 3097 } 3098 alias genInput = Dummy.genInput; 3099 3100 static struct NormalStruct 3101 { 3102 //Disabled to make sure that the takeExactly version is used. 3103 @disable this(); 3104 this(int[] arr) { _arr = arr; } 3105 mixin genInput; 3106 int[] _arr; 3107 } 3108 3109 static struct SliceStruct 3110 { 3111 @disable this(); 3112 this(int[] arr) { _arr = arr; } 3113 mixin genInput; 3114 @property auto save() { return this; } 3115 auto opSlice(size_t i, size_t j) { return typeof(this)(_arr[i .. j]); } 3116 @property size_t length() { return _arr.length; } 3117 int[] _arr; 3118 } 3119 3120 static struct InitStruct 3121 { 3122 mixin genInput; 3123 int[] _arr; 3124 } 3125 3126 static struct TakeNoneStruct 3127 { 3128 this(int[] arr) { _arr = arr; } 3129 @disable this(); 3130 mixin genInput; 3131 auto takeNone() { return typeof(this)(null); } 3132 int[] _arr; 3133 } 3134 3135 static class NormalClass 3136 { 3137 this(int[] arr) {_arr = arr;} 3138 mixin genInput; 3139 int[] _arr; 3140 } 3141 3142 static class SliceClass 3143 { 3144 @safe: 3145 this(int[] arr) { _arr = arr; } 3146 mixin genInput; 3147 @property auto save() { return new typeof(this)(_arr); } 3148 auto opSlice(size_t i, size_t j) { return new typeof(this)(_arr[i .. j]); } 3149 @property size_t length() { return _arr.length; } 3150 int[] _arr; 3151 } 3152 3153 static class TakeNoneClass 3154 { 3155 @safe: 3156 this(int[] arr) { _arr = arr; } 3157 mixin genInput; 3158 auto takeNone() { return new typeof(this)(null); } 3159 int[] _arr; 3160 } 3161 3162 import std.format : format; 3163 3164 static foreach (range; AliasSeq!([1, 2, 3, 4, 5], 3165 "hello world", 3166 "hello world"w, 3167 "hello world"d, 3168 SliceStruct([1, 2, 3]), 3169 // https://issues.dlang.org/show_bug.cgi?id=8339 3170 // forces this to be takeExactly `InitStruct([1, 2, 3]), 3171 TakeNoneStruct([1, 2, 3]))) 3172 { 3173 static assert(takeNone(range).empty, typeof(range).stringof); 3174 assert(takeNone(range).empty); 3175 static assert(is(typeof(range) == typeof(takeNone(range))), typeof(range).stringof); 3176 } 3177 3178 static foreach (range; AliasSeq!(NormalStruct([1, 2, 3]), 3179 InitStruct([1, 2, 3]))) 3180 { 3181 static assert(takeNone(range).empty, typeof(range).stringof); 3182 assert(takeNone(range).empty); 3183 static assert(is(typeof(takeExactly(range, 0)) == typeof(takeNone(range))), typeof(range).stringof); 3184 } 3185 3186 //Don't work in CTFE. 3187 auto normal = new NormalClass([1, 2, 3]); 3188 assert(takeNone(normal).empty); 3189 static assert(is(typeof(takeExactly(normal, 0)) == typeof(takeNone(normal))), typeof(normal).stringof); 3190 3191 auto slice = new SliceClass([1, 2, 3]); 3192 assert(takeNone(slice).empty); 3193 static assert(is(SliceClass == typeof(takeNone(slice))), typeof(slice).stringof); 3194 3195 auto taken = new TakeNoneClass([1, 2, 3]); 3196 assert(takeNone(taken).empty); 3197 static assert(is(TakeNoneClass == typeof(takeNone(taken))), typeof(taken).stringof); 3198 3199 auto filtered = filter!"true"([1, 2, 3, 4, 5]); 3200 assert(takeNone(filtered).empty); 3201 // https://issues.dlang.org/show_bug.cgi?id=8339 and 3202 // https://issues.dlang.org/show_bug.cgi?id=5941 force this to be takeExactly 3203 //static assert(is(typeof(filtered) == typeof(takeNone(filtered))), typeof(filtered).stringof); 3204 } 3205 3206 /++ 3207 + Return a range advanced to within `_n` elements of the end of 3208 + `range`. 3209 + 3210 + Intended as the range equivalent of the Unix 3211 + $(HTTP en.wikipedia.org/wiki/Tail_%28Unix%29, _tail) utility. When the length 3212 + of `range` is less than or equal to `_n`, `range` is returned 3213 + as-is. 3214 + 3215 + Completes in $(BIGOH 1) steps for ranges that support slicing and have 3216 + length. Completes in $(BIGOH range.length) time for all other ranges. 3217 + 3218 + Params: 3219 + range = range to get _tail of 3220 + n = maximum number of elements to include in _tail 3221 + 3222 + Returns: 3223 + Returns the _tail of `range` augmented with length information 3224 +/ 3225 auto tail(Range)(Range range, size_t n) 3226 if (isInputRange!Range && !isInfinite!Range && 3227 (hasLength!Range || isForwardRange!Range)) 3228 { 3229 static if (hasLength!Range) 3230 { 3231 immutable length = range.length; 3232 if (n >= length) 3233 return range.takeExactly(length); 3234 else 3235 return range.drop(length - n).takeExactly(n); 3236 } 3237 else 3238 { 3239 Range scout = range.save; 3240 foreach (immutable i; 0 .. n) 3241 { 3242 if (scout.empty) 3243 return range.takeExactly(i); 3244 scout.popFront(); 3245 } 3246 3247 auto tail = range.save; 3248 while (!scout.empty) 3249 { 3250 assert(!tail.empty); 3251 scout.popFront(); 3252 tail.popFront(); 3253 } 3254 3255 return tail.takeExactly(n); 3256 } 3257 } 3258 3259 /// 3260 pure @safe nothrow unittest 3261 { 3262 // tail -c n 3263 assert([1, 2, 3].tail(1) == [3]); 3264 assert([1, 2, 3].tail(2) == [2, 3]); 3265 assert([1, 2, 3].tail(3) == [1, 2, 3]); 3266 assert([1, 2, 3].tail(4) == [1, 2, 3]); 3267 assert([1, 2, 3].tail(0).length == 0); 3268 3269 // tail --lines=n 3270 import std.algorithm.comparison : equal; 3271 import std.algorithm.iteration : joiner; 3272 import std.exception : assumeWontThrow; 3273 import std..string : lineSplitter; 3274 assert("one\ntwo\nthree" 3275 .lineSplitter 3276 .tail(2) 3277 .joiner("\n") 3278 .equal("two\nthree") 3279 .assumeWontThrow); 3280 } 3281 3282 // @nogc prevented by https://issues.dlang.org/show_bug.cgi?id=15408 3283 pure nothrow @safe /+@nogc+/ unittest 3284 { 3285 import std.algorithm.comparison : equal; 3286 import std.internal.test.dummyrange : AllDummyRanges, DummyRange, Length, 3287 RangeType, ReturnBy; 3288 3289 static immutable cheatsheet = [6, 7, 8, 9, 10]; 3290 3291 foreach (R; AllDummyRanges) 3292 { 3293 static if (isInputRange!R && !isInfinite!R && 3294 (hasLength!R || isForwardRange!R)) 3295 { 3296 assert(R.init.tail(5).equal(cheatsheet)); 3297 static assert(R.init.tail(5).equal(cheatsheet)); 3298 3299 assert(R.init.tail(0).length == 0); 3300 assert(R.init.tail(10).equal(R.init)); 3301 assert(R.init.tail(11).equal(R.init)); 3302 } 3303 } 3304 3305 // Infinite ranges are not supported 3306 static assert(!__traits(compiles, repeat(0).tail(0))); 3307 3308 // Neither are non-forward ranges without length 3309 static assert(!__traits(compiles, DummyRange!(ReturnBy.Value, Length.No, 3310 RangeType.Input).init.tail(5))); 3311 } 3312 3313 pure @safe nothrow @nogc unittest 3314 { 3315 static immutable input = [1, 2, 3]; 3316 static immutable expectedOutput = [2, 3]; 3317 assert(input.tail(2) == expectedOutput); 3318 } 3319 3320 /++ 3321 Convenience function which calls 3322 $(REF popFrontN, std, range, primitives)`(range, n)` and returns `range`. 3323 `drop` makes it easier to pop elements from a range 3324 and then pass it to another function within a single expression, 3325 whereas `popFrontN` would require multiple statements. 3326 3327 `dropBack` provides the same functionality but instead calls 3328 $(REF popBackN, std, range, primitives)`(range, n)` 3329 3330 Note: `drop` and `dropBack` will only pop $(I up to) 3331 `n` elements but will stop if the range is empty first. 3332 In other languages this is sometimes called `skip`. 3333 3334 Params: 3335 range = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to drop from 3336 n = the number of elements to drop 3337 3338 Returns: 3339 `range` with up to `n` elements dropped 3340 3341 See_Also: 3342 $(REF popFront, std, range, primitives), $(REF popBackN, std, range, primitives) 3343 +/ 3344 R drop(R)(R range, size_t n) 3345 if (isInputRange!R) 3346 { 3347 range.popFrontN(n); 3348 return range; 3349 } 3350 3351 /// 3352 @safe unittest 3353 { 3354 import std.algorithm.comparison : equal; 3355 3356 assert([0, 2, 1, 5, 0, 3].drop(3) == [5, 0, 3]); 3357 assert("hello world".drop(6) == "world"); 3358 assert("hello world".drop(50).empty); 3359 assert("hello world".take(6).drop(3).equal("lo ")); 3360 } 3361 3362 /// ditto 3363 R dropBack(R)(R range, size_t n) 3364 if (isBidirectionalRange!R) 3365 { 3366 range.popBackN(n); 3367 return range; 3368 } 3369 3370 /// 3371 @safe unittest 3372 { 3373 import std.algorithm.comparison : equal; 3374 3375 assert([0, 2, 1, 5, 0, 3].dropBack(3) == [0, 2, 1]); 3376 assert("hello world".dropBack(6) == "hello"); 3377 assert("hello world".dropBack(50).empty); 3378 assert("hello world".drop(4).dropBack(4).equal("o w")); 3379 } 3380 3381 @safe unittest 3382 { 3383 import std.algorithm.comparison : equal; 3384 import std.container.dlist : DList; 3385 3386 //Remove all but the first two elements 3387 auto a = DList!int(0, 1, 9, 9, 9, 9); 3388 a.remove(a[].drop(2)); 3389 assert(a[].equal(a[].take(2))); 3390 } 3391 3392 @safe unittest 3393 { 3394 import std.algorithm.comparison : equal; 3395 import std.algorithm.iteration : filter; 3396 3397 assert(drop("", 5).empty); 3398 assert(equal(drop(filter!"true"([0, 2, 1, 5, 0, 3]), 3), [5, 0, 3])); 3399 } 3400 3401 @safe unittest 3402 { 3403 import std.algorithm.comparison : equal; 3404 import std.container.dlist : DList; 3405 3406 //insert before the last two elements 3407 auto a = DList!int(0, 1, 2, 5, 6); 3408 a.insertAfter(a[].dropBack(2), [3, 4]); 3409 assert(a[].equal(iota(0, 7))); 3410 } 3411 3412 /++ 3413 Similar to $(LREF drop) and `dropBack` but they call 3414 $(D range.$(LREF popFrontExactly)(n)) and `range.popBackExactly(n)` 3415 instead. 3416 3417 Note: Unlike `drop`, `dropExactly` will assume that the 3418 range holds at least `n` elements. This makes `dropExactly` 3419 faster than `drop`, but it also means that if `range` does 3420 not contain at least `n` elements, it will attempt to call `popFront` 3421 on an empty range, which is undefined behavior. So, only use 3422 `popFrontExactly` when it is guaranteed that `range` holds at least 3423 `n` elements. 3424 3425 Params: 3426 range = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to drop from 3427 n = the number of elements to drop 3428 3429 Returns: 3430 `range` with `n` elements dropped 3431 3432 See_Also: 3433 $(REF popFrontExcatly, std, range, primitives), 3434 $(REF popBackExcatly, std, range, primitives) 3435 +/ 3436 R dropExactly(R)(R range, size_t n) 3437 if (isInputRange!R) 3438 { 3439 popFrontExactly(range, n); 3440 return range; 3441 } 3442 /// ditto 3443 R dropBackExactly(R)(R range, size_t n) 3444 if (isBidirectionalRange!R) 3445 { 3446 popBackExactly(range, n); 3447 return range; 3448 } 3449 3450 /// 3451 @safe unittest 3452 { 3453 import std.algorithm.comparison : equal; 3454 import std.algorithm.iteration : filterBidirectional; 3455 3456 auto a = [1, 2, 3]; 3457 assert(a.dropExactly(2) == [3]); 3458 assert(a.dropBackExactly(2) == [1]); 3459 3460 string s = "日本語"; 3461 assert(s.dropExactly(2) == "語"); 3462 assert(s.dropBackExactly(2) == "日"); 3463 3464 auto bd = filterBidirectional!"true"([1, 2, 3]); 3465 assert(bd.dropExactly(2).equal([3])); 3466 assert(bd.dropBackExactly(2).equal([1])); 3467 } 3468 3469 /++ 3470 Convenience function which calls 3471 `range.popFront()` and returns `range`. `dropOne` 3472 makes it easier to pop an element from a range 3473 and then pass it to another function within a single expression, 3474 whereas `popFront` would require multiple statements. 3475 3476 `dropBackOne` provides the same functionality but instead calls 3477 `range.popBack()`. 3478 +/ 3479 R dropOne(R)(R range) 3480 if (isInputRange!R) 3481 { 3482 range.popFront(); 3483 return range; 3484 } 3485 /// ditto 3486 R dropBackOne(R)(R range) 3487 if (isBidirectionalRange!R) 3488 { 3489 range.popBack(); 3490 return range; 3491 } 3492 3493 /// 3494 pure @safe nothrow unittest 3495 { 3496 import std.algorithm.comparison : equal; 3497 import std.algorithm.iteration : filterBidirectional; 3498 import std.container.dlist : DList; 3499 3500 auto dl = DList!int(9, 1, 2, 3, 9); 3501 assert(dl[].dropOne().dropBackOne().equal([1, 2, 3])); 3502 3503 auto a = [1, 2, 3]; 3504 assert(a.dropOne() == [2, 3]); 3505 assert(a.dropBackOne() == [1, 2]); 3506 3507 string s = "日本語"; 3508 import std.exception : assumeWontThrow; 3509 assert(assumeWontThrow(s.dropOne() == "本語")); 3510 assert(assumeWontThrow(s.dropBackOne() == "日本")); 3511 3512 auto bd = filterBidirectional!"true"([1, 2, 3]); 3513 assert(bd.dropOne().equal([2, 3])); 3514 assert(bd.dropBackOne().equal([1, 2])); 3515 } 3516 3517 /** 3518 Create a range which repeats one value. 3519 3520 Params: 3521 value = the _value to repeat 3522 n = the number of times to repeat `value` 3523 3524 Returns: 3525 If `n` is not defined, an infinite random access range 3526 with slicing. 3527 3528 If `n` is defined, a random access range with slicing. 3529 */ 3530 struct Repeat(T) 3531 { 3532 private: 3533 //Store a non-qualified T when possible: This is to make Repeat assignable 3534 static if ((is(T == class) || is(T == interface)) && (is(T == const) || is(T == immutable))) 3535 { 3536 import std.typecons : Rebindable; 3537 alias UT = Rebindable!T; 3538 } 3539 else static if (is(T : Unqual!T) && is(Unqual!T : T)) 3540 alias UT = Unqual!T; 3541 else 3542 alias UT = T; 3543 UT _value; 3544 3545 public: 3546 /// Range primitives 3547 @property inout(T) front() inout { return _value; } 3548 3549 /// ditto 3550 @property inout(T) back() inout { return _value; } 3551 3552 /// ditto 3553 enum bool empty = false; 3554 3555 /// ditto 3556 void popFront() {} 3557 3558 /// ditto 3559 void popBack() {} 3560 3561 /// ditto 3562 @property auto save() inout { return this; } 3563 3564 /// ditto 3565 inout(T) opIndex(size_t) inout { return _value; } 3566 3567 /// ditto 3568 auto opSlice(size_t i, size_t j) 3569 in 3570 { 3571 assert( 3572 i <= j, 3573 "Attempting to slice a Repeat with a larger first argument than the second." 3574 ); 3575 } 3576 do 3577 { 3578 return this.takeExactly(j - i); 3579 } 3580 private static struct DollarToken {} 3581 3582 /// ditto 3583 enum opDollar = DollarToken.init; 3584 3585 /// ditto 3586 auto opSlice(size_t, DollarToken) inout { return this; } 3587 } 3588 3589 /// Ditto 3590 Repeat!T repeat(T)(T value) { return Repeat!T(value); } 3591 3592 /// 3593 pure @safe nothrow unittest 3594 { 3595 import std.algorithm.comparison : equal; 3596 3597 assert(5.repeat().take(4).equal([5, 5, 5, 5])); 3598 } 3599 3600 pure @safe nothrow unittest 3601 { 3602 import std.algorithm.comparison : equal; 3603 3604 auto r = repeat(5); 3605 alias R = typeof(r); 3606 static assert(isBidirectionalRange!R); 3607 static assert(isForwardRange!R); 3608 static assert(isInfinite!R); 3609 static assert(hasSlicing!R); 3610 3611 assert(r.back == 5); 3612 assert(r.front == 5); 3613 assert(r.take(4).equal([ 5, 5, 5, 5 ])); 3614 assert(r[0 .. 4].equal([ 5, 5, 5, 5 ])); 3615 3616 R r2 = r[5 .. $]; 3617 assert(r2.back == 5); 3618 assert(r2.front == 5); 3619 } 3620 3621 /// ditto 3622 Take!(Repeat!T) repeat(T)(T value, size_t n) 3623 { 3624 return take(repeat(value), n); 3625 } 3626 3627 /// 3628 pure @safe nothrow unittest 3629 { 3630 import std.algorithm.comparison : equal; 3631 3632 assert(5.repeat(4).equal([5, 5, 5, 5])); 3633 } 3634 3635 // https://issues.dlang.org/show_bug.cgi?id=12007 3636 pure @safe nothrow unittest 3637 { 3638 static class C{} 3639 Repeat!(immutable int) ri; 3640 ri = ri.save; 3641 Repeat!(immutable C) rc; 3642 rc = rc.save; 3643 3644 import std.algorithm.setops : cartesianProduct; 3645 import std.algorithm.comparison : equal; 3646 import std.typecons : tuple; 3647 immutable int[] A = [1,2,3]; 3648 immutable int[] B = [4,5,6]; 3649 3650 assert(equal(cartesianProduct(A,B), 3651 [ 3652 tuple(1, 4), tuple(1, 5), tuple(1, 6), 3653 tuple(2, 4), tuple(2, 5), tuple(2, 6), 3654 tuple(3, 4), tuple(3, 5), tuple(3, 6), 3655 ])); 3656 } 3657 3658 /** 3659 Given callable ($(REF isCallable, std,traits)) `fun`, create as a range 3660 whose front is defined by successive calls to `fun()`. 3661 This is especially useful to call function with global side effects (random 3662 functions), or to create ranges expressed as a single delegate, rather than 3663 an entire `front`/`popFront`/`empty` structure. 3664 `fun` maybe be passed either a template alias parameter (existing 3665 function, delegate, struct type defining `static opCall`) or 3666 a run-time value argument (delegate, function object). 3667 The result range models an InputRange 3668 ($(REF isInputRange, std,range,primitives)). 3669 The resulting range will call `fun()` on construction, and every call to 3670 `popFront`, and the cached value will be returned when `front` is called. 3671 3672 Returns: an `inputRange` where each element represents another call to fun. 3673 */ 3674 auto generate(Fun)(Fun fun) 3675 if (isCallable!fun) 3676 { 3677 auto gen = Generator!(Fun)(fun); 3678 gen.popFront(); // prime the first element 3679 return gen; 3680 } 3681 3682 /// ditto 3683 auto generate(alias fun)() 3684 if (isCallable!fun) 3685 { 3686 auto gen = Generator!(fun)(); 3687 gen.popFront(); // prime the first element 3688 return gen; 3689 } 3690 3691 /// 3692 @safe pure nothrow unittest 3693 { 3694 import std.algorithm.comparison : equal; 3695 import std.algorithm.iteration : map; 3696 3697 int i = 1; 3698 auto powersOfTwo = generate!(() => i *= 2)().take(10); 3699 assert(equal(powersOfTwo, iota(1, 11).map!"2^^a"())); 3700 } 3701 3702 /// 3703 @safe pure nothrow unittest 3704 { 3705 import std.algorithm.comparison : equal; 3706 3707 //Returns a run-time delegate 3708 auto infiniteIota(T)(T low, T high) 3709 { 3710 T i = high; 3711 return (){if (i == high) i = low; return i++;}; 3712 } 3713 //adapted as a range. 3714 assert(equal(generate(infiniteIota(1, 4)).take(10), [1, 2, 3, 1, 2, 3, 1, 2, 3, 1])); 3715 } 3716 3717 /// 3718 @safe unittest 3719 { 3720 import std.format : format; 3721 import std.random : uniform; 3722 3723 auto r = generate!(() => uniform(0, 6)).take(10); 3724 format("%(%s %)", r); 3725 } 3726 3727 private struct Generator(Fun...) 3728 { 3729 static assert(Fun.length == 1); 3730 static assert(isInputRange!Generator); 3731 import std.traits : FunctionAttribute, functionAttributes, ReturnType; 3732 3733 private: 3734 static if (is(Fun[0])) 3735 Fun[0] fun; 3736 else 3737 alias fun = Fun[0]; 3738 3739 enum returnByRef_ = (functionAttributes!fun & FunctionAttribute.ref_) ? true : false; 3740 static if (returnByRef_) 3741 ReturnType!fun *elem_; 3742 else 3743 ReturnType!fun elem_; 3744 public: 3745 /// Range primitives 3746 enum empty = false; 3747 3748 static if (returnByRef_) 3749 { 3750 /// ditto 3751 ref front() @property 3752 { 3753 return *elem_; 3754 } 3755 /// ditto 3756 void popFront() 3757 { 3758 elem_ = &fun(); 3759 } 3760 } 3761 else 3762 { 3763 /// ditto 3764 auto front() @property 3765 { 3766 return elem_; 3767 } 3768 /// ditto 3769 void popFront() 3770 { 3771 elem_ = fun(); 3772 } 3773 } 3774 } 3775 3776 @safe nothrow unittest 3777 { 3778 import std.algorithm.comparison : equal; 3779 3780 struct StaticOpCall 3781 { 3782 static ubyte opCall() { return 5 ; } 3783 } 3784 3785 assert(equal(generate!StaticOpCall().take(10), repeat(5).take(10))); 3786 } 3787 3788 @safe pure unittest 3789 { 3790 import std.algorithm.comparison : equal; 3791 3792 struct OpCall 3793 { 3794 ubyte opCall() @safe pure { return 5 ; } 3795 } 3796 3797 OpCall op; 3798 assert(equal(generate(op).take(10), repeat(5).take(10))); 3799 } 3800 3801 // verify ref mechanism works 3802 @system nothrow unittest 3803 { 3804 int[10] arr; 3805 int idx; 3806 3807 ref int fun() { 3808 auto x = idx++; 3809 idx %= arr.length; 3810 return arr[x]; 3811 } 3812 int y = 1; 3813 foreach (ref x; generate!(fun).take(20)) 3814 { 3815 x += y++; 3816 } 3817 import std.algorithm.comparison : equal; 3818 assert(equal(arr[], iota(12, 32, 2))); 3819 } 3820 3821 // assure front isn't the mechanism to make generate go to the next element. 3822 @safe unittest 3823 { 3824 int i; 3825 auto g = generate!(() => ++i); 3826 auto f = g.front; 3827 assert(f == g.front); 3828 g = g.drop(5); // reassign because generate caches 3829 assert(g.front == f + 5); 3830 } 3831 3832 /** 3833 Repeats the given forward range ad infinitum. If the original range is 3834 infinite (fact that would make `Cycle` the identity application), 3835 `Cycle` detects that and aliases itself to the range type 3836 itself. That works for non-forward ranges too. 3837 If the original range has random access, `Cycle` offers 3838 random access and also offers a constructor taking an initial position 3839 `index`. `Cycle` works with static arrays in addition to ranges, 3840 mostly for performance reasons. 3841 3842 Note: The input range must not be empty. 3843 3844 Tip: This is a great way to implement simple circular buffers. 3845 */ 3846 struct Cycle(R) 3847 if (isForwardRange!R && !isInfinite!R) 3848 { 3849 static if (isRandomAccessRange!R && hasLength!R) 3850 { 3851 private R _original; 3852 private size_t _index; 3853 3854 /// Range primitives 3855 this(R input, size_t index = 0) 3856 { 3857 _original = input; 3858 _index = index % _original.length; 3859 } 3860 3861 /// ditto 3862 @property auto ref front() 3863 { 3864 return _original[_index]; 3865 } 3866 3867 static if (is(typeof((cast(const R)_original)[_index]))) 3868 { 3869 /// ditto 3870 @property auto ref front() const 3871 { 3872 return _original[_index]; 3873 } 3874 } 3875 3876 static if (hasAssignableElements!R) 3877 { 3878 /// ditto 3879 @property void front(ElementType!R val) 3880 { 3881 _original[_index] = val; 3882 } 3883 } 3884 3885 /// ditto 3886 enum bool empty = false; 3887 3888 /// ditto 3889 void popFront() 3890 { 3891 ++_index; 3892 if (_index >= _original.length) 3893 _index = 0; 3894 } 3895 3896 /// ditto 3897 auto ref opIndex(size_t n) 3898 { 3899 return _original[(n + _index) % _original.length]; 3900 } 3901 3902 static if (is(typeof((cast(const R)_original)[_index])) && 3903 is(typeof((cast(const R)_original).length))) 3904 { 3905 /// ditto 3906 auto ref opIndex(size_t n) const 3907 { 3908 return _original[(n + _index) % _original.length]; 3909 } 3910 } 3911 3912 static if (hasAssignableElements!R) 3913 { 3914 /// ditto 3915 void opIndexAssign(ElementType!R val, size_t n) 3916 { 3917 _original[(n + _index) % _original.length] = val; 3918 } 3919 } 3920 3921 /// ditto 3922 @property Cycle save() 3923 { 3924 //No need to call _original.save, because Cycle never actually modifies _original 3925 return Cycle(_original, _index); 3926 } 3927 3928 private static struct DollarToken {} 3929 3930 /// ditto 3931 enum opDollar = DollarToken.init; 3932 3933 static if (hasSlicing!R) 3934 { 3935 /// ditto 3936 auto opSlice(size_t i, size_t j) 3937 in 3938 { 3939 assert(i <= j); 3940 } 3941 do 3942 { 3943 return this[i .. $].takeExactly(j - i); 3944 } 3945 3946 /// ditto 3947 auto opSlice(size_t i, DollarToken) 3948 { 3949 return typeof(this)(_original, _index + i); 3950 } 3951 } 3952 } 3953 else 3954 { 3955 private R _original; 3956 private R _current; 3957 3958 /// ditto 3959 this(R input) 3960 { 3961 _original = input; 3962 _current = input.save; 3963 } 3964 3965 private this(R original, R current) 3966 { 3967 _original = original; 3968 _current = current; 3969 } 3970 3971 /// ditto 3972 @property auto ref front() 3973 { 3974 return _current.front; 3975 } 3976 3977 static if (is(typeof((cast(const R)_current).front))) 3978 { 3979 /// ditto 3980 @property auto ref front() const 3981 { 3982 return _current.front; 3983 } 3984 } 3985 3986 static if (hasAssignableElements!R) 3987 { 3988 /// ditto 3989 @property auto front(ElementType!R val) 3990 { 3991 return _current.front = val; 3992 } 3993 } 3994 3995 /// ditto 3996 enum bool empty = false; 3997 3998 /// ditto 3999 void popFront() 4000 { 4001 _current.popFront(); 4002 if (_current.empty) 4003 _current = _original.save; 4004 } 4005 4006 /// ditto 4007 @property Cycle save() 4008 { 4009 //No need to call _original.save, because Cycle never actually modifies _original 4010 return Cycle(_original, _current.save); 4011 } 4012 } 4013 } 4014 4015 /// ditto 4016 template Cycle(R) 4017 if (isInfinite!R) 4018 { 4019 alias Cycle = R; 4020 } 4021 4022 /// ditto 4023 struct Cycle(R) 4024 if (isStaticArray!R) 4025 { 4026 private alias ElementType = typeof(R.init[0]); 4027 private ElementType* _ptr; 4028 private size_t _index; 4029 4030 nothrow: 4031 4032 /// Range primitives 4033 this(ref R input, size_t index = 0) @system 4034 { 4035 _ptr = input.ptr; 4036 _index = index % R.length; 4037 } 4038 4039 /// ditto 4040 @property ref inout(ElementType) front() inout @safe 4041 { 4042 static ref auto trustedPtrIdx(typeof(_ptr) p, size_t idx) @trusted 4043 { 4044 return p[idx]; 4045 } 4046 return trustedPtrIdx(_ptr, _index); 4047 } 4048 4049 /// ditto 4050 enum bool empty = false; 4051 4052 /// ditto 4053 void popFront() @safe 4054 { 4055 ++_index; 4056 if (_index >= R.length) 4057 _index = 0; 4058 } 4059 4060 /// ditto 4061 ref inout(ElementType) opIndex(size_t n) inout @safe 4062 { 4063 static ref auto trustedPtrIdx(typeof(_ptr) p, size_t idx) @trusted 4064 { 4065 return p[idx % R.length]; 4066 } 4067 return trustedPtrIdx(_ptr, n + _index); 4068 } 4069 4070 /// ditto 4071 @property inout(Cycle) save() inout @safe 4072 { 4073 return this; 4074 } 4075 4076 private static struct DollarToken {} 4077 /// ditto 4078 enum opDollar = DollarToken.init; 4079 4080 /// ditto 4081 auto opSlice(size_t i, size_t j) @safe 4082 in 4083 { 4084 assert( 4085 i <= j, 4086 "Attempting to slice a Repeat with a larger first argument than the second." 4087 ); 4088 } 4089 do 4090 { 4091 return this[i .. $].takeExactly(j - i); 4092 } 4093 4094 /// ditto 4095 inout(typeof(this)) opSlice(size_t i, DollarToken) inout @safe 4096 { 4097 static auto trustedCtor(typeof(_ptr) p, size_t idx) @trusted 4098 { 4099 return cast(inout) Cycle(*cast(R*)(p), idx); 4100 } 4101 return trustedCtor(_ptr, _index + i); 4102 } 4103 } 4104 4105 /// Ditto 4106 auto cycle(R)(R input) 4107 if (isInputRange!R) 4108 { 4109 static assert(isForwardRange!R || isInfinite!R, 4110 "Cycle requires a forward range argument unless it's statically known" 4111 ~ " to be infinite"); 4112 assert(!input.empty, "Attempting to pass an empty input to cycle"); 4113 static if (isInfinite!R) return input; 4114 else return Cycle!R(input); 4115 } 4116 4117 /// 4118 @safe unittest 4119 { 4120 import std.algorithm.comparison : equal; 4121 import std.range : cycle, take; 4122 4123 // Here we create an infinitive cyclic sequence from [1, 2] 4124 // (i.e. get here [1, 2, 1, 2, 1, 2 and so on]) then 4125 // take 5 elements of this sequence (so we have [1, 2, 1, 2, 1]) 4126 // and compare them with the expected values for equality. 4127 assert(cycle([1, 2]).take(5).equal([ 1, 2, 1, 2, 1 ])); 4128 } 4129 4130 /// Ditto 4131 Cycle!R cycle(R)(R input, size_t index = 0) 4132 if (isRandomAccessRange!R && !isInfinite!R) 4133 { 4134 assert(!input.empty, "Attempting to pass an empty input to cycle"); 4135 return Cycle!R(input, index); 4136 } 4137 4138 /// Ditto 4139 Cycle!R cycle(R)(ref R input, size_t index = 0) @system 4140 if (isStaticArray!R) 4141 { 4142 return Cycle!R(input, index); 4143 } 4144 4145 @safe nothrow unittest 4146 { 4147 import std.algorithm.comparison : equal; 4148 import std.internal.test.dummyrange : AllDummyRanges; 4149 4150 static assert(isForwardRange!(Cycle!(uint[]))); 4151 4152 // Make sure ref is getting propagated properly. 4153 int[] nums = [1,2,3]; 4154 auto c2 = cycle(nums); 4155 c2[3]++; 4156 assert(nums[0] == 2); 4157 4158 immutable int[] immarr = [1, 2, 3]; 4159 4160 foreach (DummyType; AllDummyRanges) 4161 { 4162 static if (isForwardRange!DummyType) 4163 { 4164 DummyType dummy; 4165 auto cy = cycle(dummy); 4166 static assert(isForwardRange!(typeof(cy))); 4167 auto t = take(cy, 20); 4168 assert(equal(t, [1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10])); 4169 4170 const cRange = cy; 4171 assert(cRange.front == 1); 4172 4173 static if (hasAssignableElements!DummyType) 4174 { 4175 { 4176 cy.front = 66; 4177 scope(exit) cy.front = 1; 4178 assert(dummy.front == 66); 4179 } 4180 4181 static if (isRandomAccessRange!DummyType) 4182 { 4183 { 4184 cy[10] = 66; 4185 scope(exit) cy[10] = 1; 4186 assert(dummy.front == 66); 4187 } 4188 4189 assert(cRange[10] == 1); 4190 } 4191 } 4192 4193 static if (hasSlicing!DummyType) 4194 { 4195 auto slice = cy[5 .. 15]; 4196 assert(equal(slice, [6, 7, 8, 9, 10, 1, 2, 3, 4, 5])); 4197 static assert(is(typeof(slice) == typeof(takeExactly(cy, 5)))); 4198 4199 auto infSlice = cy[7 .. $]; 4200 assert(equal(take(infSlice, 5), [8, 9, 10, 1, 2])); 4201 static assert(isInfinite!(typeof(infSlice))); 4202 } 4203 } 4204 } 4205 } 4206 4207 @system nothrow unittest // For static arrays. 4208 { 4209 import std.algorithm.comparison : equal; 4210 4211 int[3] a = [ 1, 2, 3 ]; 4212 static assert(isStaticArray!(typeof(a))); 4213 auto c = cycle(a); 4214 assert(a.ptr == c._ptr); 4215 assert(equal(take(cycle(a), 5), [ 1, 2, 3, 1, 2 ][])); 4216 static assert(isForwardRange!(typeof(c))); 4217 4218 // Test qualifiers on slicing. 4219 alias C = typeof(c); 4220 static assert(is(typeof(c[1 .. $]) == C)); 4221 const cConst = c; 4222 static assert(is(typeof(cConst[1 .. $]) == const(C))); 4223 } 4224 4225 @safe nothrow unittest // For infinite ranges 4226 { 4227 struct InfRange 4228 { 4229 void popFront() { } 4230 @property int front() { return 0; } 4231 enum empty = false; 4232 auto save() { return this; } 4233 } 4234 struct NonForwardInfRange 4235 { 4236 void popFront() { } 4237 @property int front() { return 0; } 4238 enum empty = false; 4239 } 4240 4241 InfRange i; 4242 NonForwardInfRange j; 4243 auto c = cycle(i); 4244 assert(c == i); 4245 //make sure it can alias out even non-forward infinite ranges 4246 static assert(is(typeof(j.cycle) == typeof(j))); 4247 } 4248 4249 @safe unittest 4250 { 4251 import std.algorithm.comparison : equal; 4252 4253 int[5] arr = [0, 1, 2, 3, 4]; 4254 auto cleD = cycle(arr[]); //Dynamic 4255 assert(equal(cleD[5 .. 10], arr[])); 4256 4257 //n is a multiple of 5 worth about 3/4 of size_t.max 4258 auto n = size_t.max/4 + size_t.max/2; 4259 n -= n % 5; 4260 4261 //Test index overflow 4262 foreach (_ ; 0 .. 10) 4263 { 4264 cleD = cleD[n .. $]; 4265 assert(equal(cleD[5 .. 10], arr[])); 4266 } 4267 } 4268 4269 @system @nogc nothrow unittest 4270 { 4271 import std.algorithm.comparison : equal; 4272 4273 int[5] arr = [0, 1, 2, 3, 4]; 4274 auto cleS = cycle(arr); //Static 4275 assert(equal(cleS[5 .. 10], arr[])); 4276 4277 //n is a multiple of 5 worth about 3/4 of size_t.max 4278 auto n = size_t.max/4 + size_t.max/2; 4279 n -= n % 5; 4280 4281 //Test index overflow 4282 foreach (_ ; 0 .. 10) 4283 { 4284 cleS = cleS[n .. $]; 4285 assert(equal(cleS[5 .. 10], arr[])); 4286 } 4287 } 4288 4289 @system unittest 4290 { 4291 import std.algorithm.comparison : equal; 4292 4293 int[1] arr = [0]; 4294 auto cleS = cycle(arr); 4295 cleS = cleS[10 .. $]; 4296 assert(equal(cleS[5 .. 10], 0.repeat(5))); 4297 assert(cleS.front == 0); 4298 } 4299 4300 // https://issues.dlang.org/show_bug.cgi?id=10845 4301 @system unittest 4302 { 4303 import std.algorithm.comparison : equal; 4304 import std.algorithm.iteration : filter; 4305 4306 auto a = inputRangeObject(iota(3).filter!"true"); 4307 assert(equal(cycle(a).take(10), [0, 1, 2, 0, 1, 2, 0, 1, 2, 0])); 4308 } 4309 4310 // https://issues.dlang.org/show_bug.cgi?id=12177 4311 @safe unittest 4312 { 4313 static assert(__traits(compiles, recurrence!q{a[n - 1] ~ a[n - 2]}("1", "0"))); 4314 } 4315 4316 // https://issues.dlang.org/show_bug.cgi?id=13390 4317 @system unittest 4318 { 4319 import core.exception : AssertError; 4320 import std.exception : assertThrown; 4321 assertThrown!AssertError(cycle([0, 1, 2][0 .. 0])); 4322 } 4323 4324 // https://issues.dlang.org/show_bug.cgi?id=18657 4325 pure @safe unittest 4326 { 4327 import std.algorithm.comparison : equal; 4328 string s = "foo"; 4329 auto r = refRange(&s).cycle.take(4); 4330 assert(equal(r.save, "foof")); 4331 assert(equal(r.save, "foof")); 4332 } 4333 4334 private alias lengthType(R) = typeof(R.init.length.init); 4335 4336 /** 4337 Iterate several ranges in lockstep. The element type is a proxy tuple 4338 that allows accessing the current element in the `n`th range by 4339 using `e[n]`. 4340 4341 `zip` is similar to $(LREF lockstep), but `lockstep` doesn't 4342 bundle its elements and uses the `opApply` protocol. 4343 `lockstep` allows reference access to the elements in 4344 `foreach` iterations. 4345 4346 Params: 4347 sp = controls what `zip` will do if the ranges are different lengths 4348 ranges = the ranges to zip together 4349 Returns: 4350 At minimum, an input range. `Zip` offers the lowest range facilities 4351 of all components, e.g. it offers random access iff all ranges offer 4352 random access, and also offers mutation and swapping if all ranges offer 4353 it. Due to this, `Zip` is extremely powerful because it allows manipulating 4354 several ranges in lockstep. 4355 Throws: 4356 An `Exception` if all of the ranges are not the same length and 4357 `sp` is set to `StoppingPolicy.requireSameLength`. 4358 4359 Limitations: The `@nogc` and `nothrow` attributes cannot be inferred for 4360 the `Zip` struct because $(LREF StoppingPolicy) can vary at runtime. This 4361 limitation is not shared by the anonymous range returned by the `zip` 4362 function when not given an explicit `StoppingPolicy` as an argument. 4363 */ 4364 struct Zip(Ranges...) 4365 if (Ranges.length && allSatisfy!(isInputRange, Ranges)) 4366 { 4367 import std.format : format; //for generic mixins 4368 import std.typecons : Tuple; 4369 4370 alias R = Ranges; 4371 private R ranges; 4372 alias ElementType = Tuple!(staticMap!(.ElementType, R)); 4373 private StoppingPolicy stoppingPolicy = StoppingPolicy.shortest; 4374 4375 /** 4376 Builds an object. Usually this is invoked indirectly by using the 4377 $(LREF zip) function. 4378 */ 4379 this(R rs, StoppingPolicy s = StoppingPolicy.shortest) 4380 { 4381 ranges[] = rs[]; 4382 stoppingPolicy = s; 4383 } 4384 4385 /** 4386 Returns `true` if the range is at end. The test depends on the 4387 stopping policy. 4388 */ 4389 static if (allSatisfy!(isInfinite, R)) 4390 { 4391 // BUG: Doesn't propagate infiniteness if only some ranges are infinite 4392 // and s == StoppingPolicy.longest. This isn't fixable in the 4393 // current design since StoppingPolicy is known only at runtime. 4394 enum bool empty = false; 4395 } 4396 else 4397 { 4398 /// 4399 @property bool empty() 4400 { 4401 import std.exception : enforce; 4402 import std.meta : anySatisfy; 4403 4404 final switch (stoppingPolicy) 4405 { 4406 case StoppingPolicy.shortest: 4407 foreach (i, Unused; R) 4408 { 4409 if (ranges[i].empty) return true; 4410 } 4411 return false; 4412 case StoppingPolicy.longest: 4413 static if (anySatisfy!(isInfinite, R)) 4414 { 4415 return false; 4416 } 4417 else 4418 { 4419 foreach (i, Unused; R) 4420 { 4421 if (!ranges[i].empty) return false; 4422 } 4423 return true; 4424 } 4425 case StoppingPolicy.requireSameLength: 4426 foreach (i, Unused; R[1 .. $]) 4427 { 4428 enforce(ranges[0].empty == 4429 ranges[i + 1].empty, 4430 "Inequal-length ranges passed to Zip"); 4431 } 4432 return ranges[0].empty; 4433 } 4434 assert(false); 4435 } 4436 } 4437 4438 static if (allSatisfy!(isForwardRange, R)) 4439 { 4440 /// 4441 @property Zip save() 4442 { 4443 //Zip(ranges[0].save, ranges[1].save, ..., stoppingPolicy) 4444 return mixin (q{Zip(%(ranges[%s].save%|, %), stoppingPolicy)}.format(iota(0, R.length))); 4445 } 4446 } 4447 4448 private .ElementType!(R[i]) tryGetInit(size_t i)() 4449 { 4450 alias E = .ElementType!(R[i]); 4451 static if (!is(typeof({static E i;}))) 4452 throw new Exception("Range with non-default constructable elements exhausted."); 4453 else 4454 return E.init; 4455 } 4456 4457 /** 4458 Returns the current iterated element. 4459 */ 4460 @property ElementType front() 4461 { 4462 @property tryGetFront(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].front;} 4463 //ElementType(tryGetFront!0, tryGetFront!1, ...) 4464 return mixin(q{ElementType(%(tryGetFront!%s, %))}.format(iota(0, R.length))); 4465 } 4466 4467 /** 4468 Sets the front of all iterated ranges. 4469 */ 4470 static if (allSatisfy!(hasAssignableElements, R)) 4471 { 4472 @property void front(ElementType v) 4473 { 4474 foreach (i, Unused; R) 4475 { 4476 if (!ranges[i].empty) 4477 { 4478 ranges[i].front = v[i]; 4479 } 4480 } 4481 } 4482 } 4483 4484 /** 4485 Moves out the front. 4486 */ 4487 static if (allSatisfy!(hasMobileElements, R)) 4488 { 4489 ElementType moveFront() 4490 { 4491 @property tryMoveFront(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].moveFront();} 4492 //ElementType(tryMoveFront!0, tryMoveFront!1, ...) 4493 return mixin(q{ElementType(%(tryMoveFront!%s, %))}.format(iota(0, R.length))); 4494 } 4495 } 4496 4497 /** 4498 Returns the rightmost element. 4499 */ 4500 static if (allSatisfy!(isBidirectionalRange, R)) 4501 { 4502 @property ElementType back() 4503 { 4504 //TODO: Fixme! BackElement != back of all ranges in case of jagged-ness 4505 4506 @property tryGetBack(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].back;} 4507 //ElementType(tryGetBack!0, tryGetBack!1, ...) 4508 return mixin(q{ElementType(%(tryGetBack!%s, %))}.format(iota(0, R.length))); 4509 } 4510 4511 /** 4512 Moves out the back. 4513 */ 4514 static if (allSatisfy!(hasMobileElements, R)) 4515 { 4516 ElementType moveBack() 4517 { 4518 //TODO: Fixme! BackElement != back of all ranges in case of jagged-ness 4519 4520 @property tryMoveBack(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].moveBack();} 4521 //ElementType(tryMoveBack!0, tryMoveBack!1, ...) 4522 return mixin(q{ElementType(%(tryMoveBack!%s, %))}.format(iota(0, R.length))); 4523 } 4524 } 4525 4526 /** 4527 Returns the current iterated element. 4528 */ 4529 static if (allSatisfy!(hasAssignableElements, R)) 4530 { 4531 @property void back(ElementType v) 4532 { 4533 //TODO: Fixme! BackElement != back of all ranges in case of jagged-ness. 4534 //Not sure the call is even legal for StoppingPolicy.longest 4535 4536 foreach (i, Unused; R) 4537 { 4538 if (!ranges[i].empty) 4539 { 4540 ranges[i].back = v[i]; 4541 } 4542 } 4543 } 4544 } 4545 } 4546 4547 /** 4548 Advances to the next element in all controlled ranges. 4549 */ 4550 void popFront() 4551 { 4552 import std.exception : enforce; 4553 4554 final switch (stoppingPolicy) 4555 { 4556 case StoppingPolicy.shortest: 4557 foreach (i, Unused; R) 4558 { 4559 assert(!ranges[i].empty); 4560 ranges[i].popFront(); 4561 } 4562 break; 4563 case StoppingPolicy.longest: 4564 foreach (i, Unused; R) 4565 { 4566 if (!ranges[i].empty) ranges[i].popFront(); 4567 } 4568 break; 4569 case StoppingPolicy.requireSameLength: 4570 foreach (i, Unused; R) 4571 { 4572 enforce(!ranges[i].empty, "Invalid Zip object"); 4573 ranges[i].popFront(); 4574 } 4575 break; 4576 } 4577 } 4578 4579 /** 4580 Calls `popBack` for all controlled ranges. 4581 */ 4582 static if (allSatisfy!(isBidirectionalRange, R)) 4583 { 4584 void popBack() 4585 { 4586 //TODO: Fixme! In case of jaggedness, this is wrong. 4587 import std.exception : enforce; 4588 4589 final switch (stoppingPolicy) 4590 { 4591 case StoppingPolicy.shortest: 4592 foreach (i, Unused; R) 4593 { 4594 assert(!ranges[i].empty); 4595 ranges[i].popBack(); 4596 } 4597 break; 4598 case StoppingPolicy.longest: 4599 foreach (i, Unused; R) 4600 { 4601 if (!ranges[i].empty) ranges[i].popBack(); 4602 } 4603 break; 4604 case StoppingPolicy.requireSameLength: 4605 foreach (i, Unused; R) 4606 { 4607 enforce(!ranges[i].empty, "Invalid Zip object"); 4608 ranges[i].popBack(); 4609 } 4610 break; 4611 } 4612 } 4613 } 4614 4615 /** 4616 Returns the length of this range. Defined only if all ranges define 4617 `length`. 4618 */ 4619 static if (allSatisfy!(hasLength, R)) 4620 { 4621 @property auto length() 4622 { 4623 static if (Ranges.length == 1) 4624 return ranges[0].length; 4625 else 4626 { 4627 if (stoppingPolicy == StoppingPolicy.requireSameLength) 4628 return ranges[0].length; 4629 4630 //[min|max](ranges[0].length, ranges[1].length, ...) 4631 import std.algorithm.comparison : min, max; 4632 if (stoppingPolicy == StoppingPolicy.shortest) 4633 return mixin(q{min(%(ranges[%s].length%|, %))}.format(iota(0, R.length))); 4634 else 4635 return mixin(q{max(%(ranges[%s].length%|, %))}.format(iota(0, R.length))); 4636 } 4637 } 4638 4639 alias opDollar = length; 4640 } 4641 4642 /** 4643 Returns a slice of the range. Defined only if all range define 4644 slicing. 4645 */ 4646 static if (allSatisfy!(hasSlicing, R)) 4647 { 4648 auto opSlice(size_t from, size_t to) 4649 { 4650 //Slicing an infinite range yields the type Take!R 4651 //For finite ranges, the type Take!R aliases to R 4652 alias ZipResult = Zip!(staticMap!(Take, R)); 4653 4654 //ZipResult(ranges[0][from .. to], ranges[1][from .. to], ..., stoppingPolicy) 4655 return mixin (q{ZipResult(%(ranges[%s][from .. to]%|, %), stoppingPolicy)}.format(iota(0, R.length))); 4656 } 4657 } 4658 4659 /** 4660 Returns the `n`th element in the composite range. Defined if all 4661 ranges offer random access. 4662 */ 4663 static if (allSatisfy!(isRandomAccessRange, R)) 4664 { 4665 ElementType opIndex(size_t n) 4666 { 4667 //TODO: Fixme! This may create an out of bounds access 4668 //for StoppingPolicy.longest 4669 4670 //ElementType(ranges[0][n], ranges[1][n], ...) 4671 return mixin (q{ElementType(%(ranges[%s][n]%|, %))}.format(iota(0, R.length))); 4672 } 4673 4674 /** 4675 Assigns to the `n`th element in the composite range. Defined if 4676 all ranges offer random access. 4677 */ 4678 static if (allSatisfy!(hasAssignableElements, R)) 4679 { 4680 void opIndexAssign(ElementType v, size_t n) 4681 { 4682 //TODO: Fixme! Not sure the call is even legal for StoppingPolicy.longest 4683 foreach (i, Range; R) 4684 { 4685 ranges[i][n] = v[i]; 4686 } 4687 } 4688 } 4689 4690 /** 4691 Destructively reads the `n`th element in the composite 4692 range. Defined if all ranges offer random access. 4693 */ 4694 static if (allSatisfy!(hasMobileElements, R)) 4695 { 4696 ElementType moveAt(size_t n) 4697 { 4698 //TODO: Fixme! This may create an out of bounds access 4699 //for StoppingPolicy.longest 4700 4701 //ElementType(ranges[0].moveAt(n), ranges[1].moveAt(n), ..., ) 4702 return mixin (q{ElementType(%(ranges[%s].moveAt(n)%|, %))}.format(iota(0, R.length))); 4703 } 4704 } 4705 } 4706 } 4707 4708 /// Ditto 4709 auto zip(Ranges...)(Ranges ranges) 4710 if (Ranges.length && allSatisfy!(isInputRange, Ranges)) 4711 { 4712 import std.meta : anySatisfy, templateOr; 4713 static if (allSatisfy!(isInfinite, Ranges) || Ranges.length == 1) 4714 { 4715 return ZipShortest!(Ranges)(ranges); 4716 } 4717 else static if (allSatisfy!(isBidirectionalRange, Ranges)) 4718 { 4719 static if (allSatisfy!(templateOr!(isInfinite, hasLength), Ranges) 4720 && allSatisfy!(templateOr!(isInfinite, hasSlicing), Ranges) 4721 && allSatisfy!(isBidirectionalRange, staticMap!(Take, Ranges))) 4722 { 4723 // If all the ranges are bidirectional, if possible slice them to 4724 // the same length to simplify the implementation. 4725 static assert(anySatisfy!(hasLength, Ranges)); 4726 static foreach (i, Range; Ranges) 4727 static if (hasLength!Range) 4728 { 4729 static if (!anySatisfy!(hasLength, Ranges[0 .. i])) 4730 size_t minLen = ranges[i].length; 4731 else 4732 {{ 4733 const x = ranges[i].length; 4734 if (x < minLen) minLen = x; 4735 }} 4736 } 4737 import std.format : format; 4738 static if (!anySatisfy!(isInfinite, Ranges)) 4739 return mixin(`ZipShortest!(Yes.allKnownSameLength, staticMap!(Take, Ranges))`~ 4740 `(%(ranges[%s][0 .. minLen]%|, %))`.format(iota(0, Ranges.length))); 4741 else 4742 return mixin(`ZipShortest!(Yes.allKnownSameLength, staticMap!(Take, Ranges))`~ 4743 `(%(take(ranges[%s], minLen)%|, %))`.format(iota(0, Ranges.length))); 4744 } 4745 else static if (allSatisfy!(isRandomAccessRange, Ranges)) 4746 { 4747 // We can't slice but we can still use random access to ensure 4748 // "back" is retrieving the same index for each range. 4749 return ZipShortest!(Ranges)(ranges); 4750 } 4751 else 4752 { 4753 // If bidirectional range operations would not be supported by 4754 // ZipShortest that might have actually been a bug since Zip 4755 // supported `back` without verifying that each range had the 4756 // same length, but for the sake of backwards compatibility 4757 // use the old Zip to continue supporting them. 4758 return Zip!Ranges(ranges); 4759 } 4760 } 4761 else 4762 { 4763 return ZipShortest!(Ranges)(ranges); 4764 } 4765 } 4766 4767 /// 4768 @nogc nothrow pure @safe unittest 4769 { 4770 import std.algorithm.comparison : equal; 4771 import std.algorithm.iteration : map; 4772 4773 // pairwise sum 4774 auto arr = only(0, 1, 2); 4775 auto part1 = zip(arr, arr.dropOne).map!"a[0] + a[1]"; 4776 assert(part1.equal(only(1, 3))); 4777 } 4778 4779 /// 4780 nothrow pure @safe unittest 4781 { 4782 import std.conv : to; 4783 4784 int[] a = [ 1, 2, 3 ]; 4785 string[] b = [ "a", "b", "c" ]; 4786 string[] result; 4787 4788 foreach (tup; zip(a, b)) 4789 { 4790 result ~= tup[0].to!string ~ tup[1]; 4791 } 4792 4793 assert(result == [ "1a", "2b", "3c" ]); 4794 4795 size_t idx = 0; 4796 // unpacking tuple elements with foreach 4797 foreach (e1, e2; zip(a, b)) 4798 { 4799 assert(e1 == a[idx]); 4800 assert(e2 == b[idx]); 4801 ++idx; 4802 } 4803 } 4804 4805 /// `zip` is powerful - the following code sorts two arrays in parallel: 4806 nothrow pure @safe unittest 4807 { 4808 import std.algorithm.sorting : sort; 4809 4810 int[] a = [ 1, 2, 3 ]; 4811 string[] b = [ "a", "c", "b" ]; 4812 zip(a, b).sort!((t1, t2) => t1[0] > t2[0]); 4813 4814 assert(a == [ 3, 2, 1 ]); 4815 // b is sorted according to a's sorting 4816 assert(b == [ "b", "c", "a" ]); 4817 } 4818 4819 /// Ditto 4820 auto zip(Ranges...)(StoppingPolicy sp, Ranges ranges) 4821 if (Ranges.length && allSatisfy!(isInputRange, Ranges)) 4822 { 4823 return Zip!Ranges(ranges, sp); 4824 } 4825 4826 /** 4827 Dictates how iteration in a $(LREF zip) and $(LREF lockstep) should stop. 4828 By default stop at the end of the shortest of all ranges. 4829 */ 4830 enum StoppingPolicy 4831 { 4832 /// Stop when the shortest range is exhausted 4833 shortest, 4834 /// Stop when the longest range is exhausted 4835 longest, 4836 /// Require that all ranges are equal 4837 requireSameLength, 4838 } 4839 4840 /// 4841 pure @safe unittest 4842 { 4843 import std.algorithm.comparison : equal; 4844 import std.exception : assertThrown; 4845 import std.range.primitives; 4846 import std.typecons : tuple; 4847 4848 auto a = [1, 2, 3]; 4849 auto b = [4, 5, 6, 7]; 4850 4851 auto shortest = zip(StoppingPolicy.shortest, a, b); 4852 assert(shortest.equal([ 4853 tuple(1, 4), 4854 tuple(2, 5), 4855 tuple(3, 6) 4856 ])); 4857 4858 auto longest = zip(StoppingPolicy.longest, a, b); 4859 assert(longest.equal([ 4860 tuple(1, 4), 4861 tuple(2, 5), 4862 tuple(3, 6), 4863 tuple(0, 7) 4864 ])); 4865 4866 auto same = zip(StoppingPolicy.requireSameLength, a, b); 4867 same.popFrontN(3); 4868 assertThrown!Exception(same.popFront); 4869 } 4870 4871 /+ 4872 Non-public. Like $(LREF Zip) with `StoppingPolicy.shortest` 4873 except it properly implements `back` and `popBack` in the 4874 case of uneven ranges or disables those operations when 4875 it is not possible to guarantee they are correct. 4876 +/ 4877 package template ZipShortest(Ranges...) 4878 if (Ranges.length && __traits(compiles, 4879 { 4880 static assert(allSatisfy!(isInputRange, Ranges)); 4881 })) 4882 { 4883 alias ZipShortest = .ZipShortest!( 4884 Ranges.length == 1 || allSatisfy!(isInfinite, Ranges) 4885 ? Yes.allKnownSameLength 4886 : No.allKnownSameLength, 4887 Ranges); 4888 } 4889 /+ non-public, ditto +/ 4890 package struct ZipShortest(Flag!"allKnownSameLength" allKnownSameLength, Ranges...) 4891 if (Ranges.length && allSatisfy!(isInputRange, Ranges)) 4892 { 4893 import std.format : format; //for generic mixins 4894 import std.meta : anySatisfy, templateOr; 4895 import std.typecons : Tuple; 4896 4897 deprecated("Use of an undocumented alias R.") 4898 alias R = Ranges; // Unused here but defined in case library users rely on it. 4899 private Ranges ranges; 4900 alias ElementType = Tuple!(staticMap!(.ElementType, Ranges)); 4901 4902 /+ 4903 Builds an object. Usually this is invoked indirectly by using the 4904 $(LREF zip) function. 4905 +/ 4906 this(Ranges rs) 4907 { 4908 ranges[] = rs[]; 4909 } 4910 4911 /+ 4912 Returns `true` if the range is at end. 4913 +/ 4914 static if (allKnownSameLength ? anySatisfy!(isInfinite, Ranges) 4915 : allSatisfy!(isInfinite, Ranges)) 4916 { 4917 enum bool empty = false; 4918 } 4919 else 4920 { 4921 @property bool empty() 4922 { 4923 static if (allKnownSameLength) 4924 { 4925 return ranges[0].empty; 4926 } 4927 else 4928 { 4929 static foreach (i; 0 .. Ranges.length) 4930 { 4931 if (ranges[i].empty) 4932 return true; 4933 } 4934 return false; 4935 } 4936 } 4937 } 4938 4939 /+ 4940 Forward range primitive. Only present if each constituent range is a 4941 forward range. 4942 +/ 4943 static if (allSatisfy!(isForwardRange, Ranges)) 4944 @property typeof(this) save() 4945 { 4946 return mixin(`typeof(return)(%(ranges[%s].save%|, %))`.format(iota(0, Ranges.length))); 4947 } 4948 4949 /+ 4950 Returns the current iterated element. 4951 +/ 4952 @property ElementType front() 4953 { 4954 return mixin(`typeof(return)(%(ranges[%s].front%|, %))`.format(iota(0, Ranges.length))); 4955 } 4956 4957 /+ 4958 Sets the front of all iterated ranges. Only present if each constituent 4959 range has assignable elements. 4960 +/ 4961 static if (allSatisfy!(hasAssignableElements, Ranges)) 4962 @property void front()(ElementType v) 4963 { 4964 static foreach (i; 0 .. Ranges.length) 4965 ranges[i].front = v[i]; 4966 } 4967 4968 /+ 4969 Moves out the front. Present if each constituent range has mobile elements. 4970 +/ 4971 static if (allSatisfy!(hasMobileElements, Ranges)) 4972 ElementType moveFront()() 4973 { 4974 return mixin(`typeof(return)(%(ranges[%s].moveFront()%|, %))`.format(iota(0, Ranges.length))); 4975 } 4976 4977 private enum bool isBackWellDefined = allSatisfy!(isBidirectionalRange, Ranges) 4978 && (allKnownSameLength 4979 || allSatisfy!(isRandomAccessRange, Ranges) 4980 // Could also add the case where there is one non-infinite bidirectional 4981 // range that defines `length` and all others are infinite random access 4982 // ranges. Adding this would require appropriate branches in 4983 // back/moveBack/popBack. 4984 ); 4985 4986 /+ 4987 Returns the rightmost element. Present if all constituent ranges are 4988 bidirectional and either there is a compile-time guarantee that all 4989 ranges have the same length (in `allKnownSameLength`) or all ranges 4990 provide random access to elements. 4991 +/ 4992 static if (isBackWellDefined) 4993 @property ElementType back() 4994 { 4995 static if (allKnownSameLength) 4996 { 4997 return mixin(`typeof(return)(%(ranges[%s].back()%|, %))`.format(iota(0, Ranges.length))); 4998 } 4999 else 5000 { 5001 const backIndex = length - 1; 5002 return mixin(`typeof(return)(%(ranges[%s][backIndex]%|, %))`.format(iota(0, Ranges.length))); 5003 } 5004 } 5005 5006 /+ 5007 Moves out the back. Present if `back` is defined and 5008 each constituent range has mobile elements. 5009 +/ 5010 static if (isBackWellDefined && allSatisfy!(hasMobileElements, Ranges)) 5011 ElementType moveBack()() 5012 { 5013 static if (allKnownSameLength) 5014 { 5015 return mixin(`typeof(return)(%(ranges[%s].moveBack()%|, %))`.format(iota(0, Ranges.length))); 5016 } 5017 else 5018 { 5019 const backIndex = length - 1; 5020 return mixin(`typeof(return)(%(ranges[%s].moveAt(backIndex)%|, %))`.format(iota(0, Ranges.length))); 5021 } 5022 } 5023 5024 /+ 5025 Sets the rightmost element. Only present if `back` is defined and 5026 each constituent range has assignable elements. 5027 +/ 5028 static if (isBackWellDefined && allSatisfy!(hasAssignableElements, Ranges)) 5029 @property void back()(ElementType v) 5030 { 5031 static if (allKnownSameLength) 5032 { 5033 static foreach (i; 0 .. Ranges.length) 5034 ranges[i].back = v[i]; 5035 } 5036 else 5037 { 5038 const backIndex = length - 1; 5039 static foreach (i; 0 .. Ranges.length) 5040 ranges[i][backIndex] = v[i]; 5041 } 5042 } 5043 5044 /+ 5045 Calls `popFront` on each constituent range. 5046 +/ 5047 void popFront() 5048 { 5049 static foreach (i; 0 .. Ranges.length) 5050 ranges[i].popFront(); 5051 } 5052 5053 /+ 5054 Pops the rightmost element. Present if `back` is defined. 5055 +/ 5056 static if (isBackWellDefined) 5057 void popBack() 5058 { 5059 static if (allKnownSameLength) 5060 { 5061 static foreach (i; 0 .. Ranges.length) 5062 ranges[i].popBack; 5063 } 5064 else 5065 { 5066 const len = length; 5067 static foreach (i; 0 .. Ranges.length) 5068 static if (!isInfinite!(Ranges[i])) 5069 if (ranges[i].length == len) 5070 ranges[i].popBack(); 5071 } 5072 } 5073 5074 /+ 5075 Returns the length of this range. Defined if at least one 5076 constituent range defines `length` and the other ranges all also 5077 define `length` or are infinite, or if at least one constituent 5078 range defines `length` and there is a compile-time guarantee that 5079 all ranges have the same length (in `allKnownSameLength`). 5080 +/ 5081 static if (allKnownSameLength 5082 ? anySatisfy!(hasLength, Ranges) 5083 : (anySatisfy!(hasLength, Ranges) 5084 && allSatisfy!(templateOr!(isInfinite, hasLength), Ranges))) 5085 { 5086 @property size_t length() 5087 { 5088 static if (allKnownSameLength) 5089 { 5090 static foreach (i, Range; Ranges) 5091 { 5092 static if (hasLength!Range && !anySatisfy!(hasLength, Ranges[0 .. i])) 5093 return ranges[i].length; 5094 } 5095 } 5096 else 5097 { 5098 static foreach (i, Range; Ranges) 5099 static if (hasLength!Range) 5100 { 5101 static if (!anySatisfy!(hasLength, Ranges[0 .. i])) 5102 size_t minLen = ranges[i].length; 5103 else 5104 {{ 5105 const x = ranges[i].length; 5106 if (x < minLen) minLen = x; 5107 }} 5108 } 5109 return minLen; 5110 } 5111 } 5112 5113 alias opDollar = length; 5114 } 5115 5116 /+ 5117 Returns a slice of the range. Defined if all constituent ranges 5118 support slicing. 5119 +/ 5120 static if (allSatisfy!(hasSlicing, Ranges)) 5121 { 5122 // Note: we will know that all elements of the resultant range 5123 // will have the same length but we cannot change `allKnownSameLength` 5124 // because the `hasSlicing` predicate tests that the result returned 5125 // by `opSlice` has the same type as the receiver. 5126 auto opSlice()(size_t from, size_t to) 5127 { 5128 //(ranges[0][from .. to], ranges[1][from .. to], ...) 5129 enum sliceArgs = `(%(ranges[%s][from .. to]%|, %))`.format(iota(0, Ranges.length)); 5130 static if (__traits(compiles, mixin(`typeof(this)`~sliceArgs))) 5131 return mixin(`typeof(this)`~sliceArgs); 5132 else 5133 // The type is different anyway so we might as well 5134 // explicitly set allKnownSameLength. 5135 return mixin(`ZipShortest!(Yes.allKnownSameLength, staticMap!(Take, Ranges))` 5136 ~sliceArgs); 5137 } 5138 } 5139 5140 /+ 5141 Returns the `n`th element in the composite range. Defined if all 5142 constituent ranges offer random access. 5143 +/ 5144 static if (allSatisfy!(isRandomAccessRange, Ranges)) 5145 ElementType opIndex()(size_t n) 5146 { 5147 return mixin(`typeof(return)(%(ranges[%s][n]%|, %))`.format(iota(0, Ranges.length))); 5148 } 5149 5150 /+ 5151 Sets the `n`th element in the composite range. Defined if all 5152 constituent ranges offer random access and have assignable elements. 5153 +/ 5154 static if (allSatisfy!(isRandomAccessRange, Ranges) 5155 && allSatisfy!(hasAssignableElements, Ranges)) 5156 void opIndexAssign()(ElementType v, size_t n) 5157 { 5158 static foreach (i; 0 .. Ranges.length) 5159 ranges[i][n] = v[i]; 5160 } 5161 5162 /+ 5163 Destructively reads the `n`th element in the composite 5164 range. Defined if all constituent ranges offer random 5165 access and have mobile elements. 5166 +/ 5167 static if (allSatisfy!(isRandomAccessRange, Ranges) 5168 && allSatisfy!(hasMobileElements, Ranges)) 5169 ElementType moveAt()(size_t n) 5170 { 5171 return mixin(`typeof(return)(%(ranges[%s].moveAt(n)%|, %))`.format(iota(0, Ranges.length))); 5172 } 5173 } 5174 5175 pure @system unittest 5176 { 5177 import std.algorithm.comparison : equal; 5178 import std.algorithm.iteration : filter, map; 5179 import std.algorithm.mutation : swap; 5180 import std.algorithm.sorting : sort; 5181 5182 import std.exception : assertThrown, assertNotThrown; 5183 import std.typecons : tuple; 5184 5185 int[] a = [ 1, 2, 3 ]; 5186 float[] b = [ 1.0, 2.0, 3.0 ]; 5187 foreach (e; zip(a, b)) 5188 { 5189 assert(e[0] == e[1]); 5190 } 5191 5192 swap(a[0], a[1]); 5193 { 5194 auto z = zip(a, b); 5195 } 5196 //swap(z.front(), z.back()); 5197 sort!("a[0] < b[0]")(zip(a, b)); 5198 assert(a == [1, 2, 3]); 5199 assert(b == [2.0, 1.0, 3.0]); 5200 5201 auto z = zip(StoppingPolicy.requireSameLength, a, b); 5202 assertNotThrown(z.popBack()); 5203 assertNotThrown(z.popBack()); 5204 assertNotThrown(z.popBack()); 5205 assert(z.empty); 5206 assertThrown(z.popBack()); 5207 5208 a = [ 1, 2, 3 ]; 5209 b = [ 1.0, 2.0, 3.0 ]; 5210 sort!("a[0] > b[0]")(zip(StoppingPolicy.requireSameLength, a, b)); 5211 assert(a == [3, 2, 1]); 5212 assert(b == [3.0, 2.0, 1.0]); 5213 5214 a = []; 5215 b = []; 5216 assert(zip(StoppingPolicy.requireSameLength, a, b).empty); 5217 5218 // Test infiniteness propagation. 5219 static assert(isInfinite!(typeof(zip(repeat(1), repeat(1))))); 5220 5221 // Test stopping policies with both value and reference. 5222 auto a1 = [1, 2]; 5223 auto a2 = [1, 2, 3]; 5224 auto stuff = tuple(tuple(a1, a2), 5225 tuple(filter!"a"(a1), filter!"a"(a2))); 5226 5227 alias FOO = Zip!(immutable(int)[], immutable(float)[]); 5228 5229 foreach (t; stuff.expand) 5230 { 5231 auto arr1 = t[0]; 5232 auto arr2 = t[1]; 5233 auto zShortest = zip(arr1, arr2); 5234 assert(equal(map!"a[0]"(zShortest), [1, 2])); 5235 assert(equal(map!"a[1]"(zShortest), [1, 2])); 5236 5237 try { 5238 auto zSame = zip(StoppingPolicy.requireSameLength, arr1, arr2); 5239 foreach (elem; zSame) {} 5240 assert(0); 5241 } catch (Throwable) { /* It's supposed to throw.*/ } 5242 5243 auto zLongest = zip(StoppingPolicy.longest, arr1, arr2); 5244 assert(!zLongest.ranges[0].empty); 5245 assert(!zLongest.ranges[1].empty); 5246 5247 zLongest.popFront(); 5248 zLongest.popFront(); 5249 assert(!zLongest.empty); 5250 assert(zLongest.ranges[0].empty); 5251 assert(!zLongest.ranges[1].empty); 5252 5253 zLongest.popFront(); 5254 assert(zLongest.empty); 5255 } 5256 5257 // https://issues.dlang.org/show_bug.cgi?id=8900 5258 assert(zip([1, 2], repeat('a')).array == [tuple(1, 'a'), tuple(2, 'a')]); 5259 assert(zip(repeat('a'), [1, 2]).array == [tuple('a', 1), tuple('a', 2)]); 5260 5261 // https://issues.dlang.org/show_bug.cgi?id=18524 5262 // moveBack instead performs moveFront 5263 { 5264 auto r = zip([1,2,3]); 5265 assert(r.moveBack()[0] == 3); 5266 assert(r.moveFront()[0] == 1); 5267 } 5268 5269 // Doesn't work yet. Issues w/ emplace. 5270 // static assert(is(Zip!(immutable int[], immutable float[]))); 5271 5272 5273 // These unittests pass, but make the compiler consume an absurd amount 5274 // of RAM and time. Therefore, they should only be run if explicitly 5275 // uncommented when making changes to Zip. Also, running them using 5276 // make -fwin32.mak unittest makes the compiler completely run out of RAM. 5277 // You need to test just this module. 5278 /+ 5279 foreach (DummyType1; AllDummyRanges) 5280 { 5281 DummyType1 d1; 5282 foreach (DummyType2; AllDummyRanges) 5283 { 5284 DummyType2 d2; 5285 auto r = zip(d1, d2); 5286 assert(equal(map!"a[0]"(r), [1,2,3,4,5,6,7,8,9,10])); 5287 assert(equal(map!"a[1]"(r), [1,2,3,4,5,6,7,8,9,10])); 5288 5289 static if (isForwardRange!DummyType1 && isForwardRange!DummyType2) 5290 { 5291 static assert(isForwardRange!(typeof(r))); 5292 } 5293 5294 static if (isBidirectionalRange!DummyType1 && 5295 isBidirectionalRange!DummyType2) { 5296 static assert(isBidirectionalRange!(typeof(r))); 5297 } 5298 static if (isRandomAccessRange!DummyType1 && 5299 isRandomAccessRange!DummyType2) { 5300 static assert(isRandomAccessRange!(typeof(r))); 5301 } 5302 } 5303 } 5304 +/ 5305 } 5306 5307 nothrow pure @safe unittest 5308 { 5309 import std.algorithm.sorting : sort; 5310 5311 auto a = [5,4,3,2,1]; 5312 auto b = [3,1,2,5,6]; 5313 auto z = zip(a, b); 5314 5315 sort!"a[0] < b[0]"(z); 5316 5317 assert(a == [1, 2, 3, 4, 5]); 5318 assert(b == [6, 5, 2, 1, 3]); 5319 } 5320 5321 nothrow pure @safe unittest 5322 { 5323 import std.algorithm.comparison : equal; 5324 import std.typecons : tuple; 5325 5326 auto LL = iota(1L, 1000L); 5327 auto z = zip(LL, [4]); 5328 5329 assert(equal(z, [tuple(1L,4)])); 5330 5331 auto LL2 = iota(0L, 500L); 5332 auto z2 = zip([7], LL2); 5333 assert(equal(z2, [tuple(7, 0L)])); 5334 } 5335 5336 // Test for https://issues.dlang.org/show_bug.cgi?id=11196 5337 @safe pure unittest 5338 { 5339 import std.exception : assertThrown; 5340 5341 static struct S { @disable this(); } 5342 assert(zip((S[5]).init[]).length == 5); 5343 assert(zip(StoppingPolicy.longest, cast(S[]) null, new int[1]).length == 1); 5344 assertThrown(zip(StoppingPolicy.longest, cast(S[]) null, new int[1]).front); 5345 } 5346 5347 // https://issues.dlang.org/show_bug.cgi?id=12007 5348 @nogc nothrow @safe pure unittest 5349 { 5350 static struct R 5351 { 5352 enum empty = false; 5353 void popFront(){} 5354 int front(){return 1;} @property 5355 R save(){return this;} @property 5356 void opAssign(R) @disable; 5357 } 5358 R r; 5359 auto z = zip(r, r); 5360 assert(z.save == z); 5361 } 5362 5363 nothrow pure @system unittest 5364 { 5365 import std.typecons : tuple; 5366 5367 auto r1 = [0,1,2]; 5368 auto r2 = [1,2,3]; 5369 auto z1 = zip(refRange(&r1), refRange(&r2)); 5370 auto z2 = z1.save; 5371 z1.popFront(); 5372 assert(z1.front == tuple(1,2)); 5373 assert(z2.front == tuple(0,1)); 5374 } 5375 5376 @nogc nothrow pure @safe unittest 5377 { 5378 // Test zip's `back` and `length` with non-equal ranges. 5379 static struct NonSliceableRandomAccess 5380 { 5381 private int[] a; 5382 @property ref front() 5383 { 5384 return a.front; 5385 } 5386 @property ref back() 5387 { 5388 return a.back; 5389 } 5390 ref opIndex(size_t i) 5391 { 5392 return a[i]; 5393 } 5394 void popFront() 5395 { 5396 a.popFront(); 5397 } 5398 void popBack() 5399 { 5400 a.popBack(); 5401 } 5402 auto moveFront() 5403 { 5404 return a.moveFront(); 5405 } 5406 auto moveBack() 5407 { 5408 return a.moveBack(); 5409 } 5410 auto moveAt(size_t i) 5411 { 5412 return a.moveAt(i); 5413 } 5414 bool empty() const 5415 { 5416 return a.empty; 5417 } 5418 size_t length() const 5419 { 5420 return a.length; 5421 } 5422 typeof(this) save() 5423 { 5424 return this; 5425 } 5426 } 5427 static assert(isRandomAccessRange!NonSliceableRandomAccess); 5428 static assert(!hasSlicing!NonSliceableRandomAccess); 5429 static foreach (iteration; 0 .. 2) 5430 {{ 5431 int[5] data = [101, 102, 103, 201, 202]; 5432 static if (iteration == 0) 5433 { 5434 auto r1 = NonSliceableRandomAccess(data[0 .. 3]); 5435 auto r2 = NonSliceableRandomAccess(data[3 .. 5]); 5436 } 5437 else 5438 { 5439 auto r1 = data[0 .. 3]; 5440 auto r2 = data[3 .. 5]; 5441 } 5442 auto z = zip(r1, r2); 5443 static assert(isRandomAccessRange!(typeof(z))); 5444 assert(z.length == 2); 5445 assert(z.back[0] == 102 && z.back[1] == 202); 5446 z.back = typeof(z.back)(-102, -202);// Assign to back. 5447 assert(z.back[0] == -102 && z.back[1] == -202); 5448 z.popBack(); 5449 assert(z.length == 1); 5450 assert(z.back[0] == 101 && z.back[1] == 201); 5451 z.front = typeof(z.front)(-101, -201); 5452 assert(z.moveBack() == typeof(z.back)(-101, -201)); 5453 z.popBack(); 5454 assert(z.empty); 5455 }} 5456 } 5457 5458 @nogc nothrow pure @safe unittest 5459 { 5460 // Test opSlice on infinite `zip`. 5461 auto z = zip(repeat(1), repeat(2)); 5462 assert(hasSlicing!(typeof(z))); 5463 auto slice = z[10 .. 20]; 5464 assert(slice.length == 10); 5465 static assert(!is(typeof(z) == typeof(slice))); 5466 } 5467 5468 /* 5469 Generate lockstep's opApply function as a mixin string. 5470 If withIndex is true prepend a size_t index to the delegate. 5471 */ 5472 private string lockstepMixin(Ranges...)(bool withIndex, bool reverse) 5473 { 5474 import std.format : format; 5475 5476 string[] params; 5477 string[] emptyChecks; 5478 string[] dgArgs; 5479 string[] popFronts; 5480 string indexDef; 5481 string indexInc; 5482 5483 if (withIndex) 5484 { 5485 params ~= "size_t"; 5486 dgArgs ~= "index"; 5487 if (reverse) 5488 { 5489 indexDef = q{ 5490 size_t index = ranges[0].length-1; 5491 enforce(_stoppingPolicy == StoppingPolicy.requireSameLength, 5492 "lockstep can only be used with foreach_reverse when stoppingPolicy == requireSameLength"); 5493 5494 foreach (range; ranges[1..$]) 5495 enforce(range.length == ranges[0].length); 5496 }; 5497 indexInc = "--index;"; 5498 } 5499 else 5500 { 5501 indexDef = "size_t index = 0;"; 5502 indexInc = "++index;"; 5503 } 5504 } 5505 5506 foreach (idx, Range; Ranges) 5507 { 5508 params ~= format("%sElementType!(Ranges[%s])", hasLvalueElements!Range ? "ref " : "", idx); 5509 emptyChecks ~= format("!ranges[%s].empty", idx); 5510 if (reverse) 5511 { 5512 dgArgs ~= format("ranges[%s].back", idx); 5513 popFronts ~= format("ranges[%s].popBack();", idx); 5514 } 5515 else 5516 { 5517 dgArgs ~= format("ranges[%s].front", idx); 5518 popFronts ~= format("ranges[%s].popFront();", idx); 5519 } 5520 } 5521 5522 string name = reverse ? "opApplyReverse" : "opApply"; 5523 5524 return format( 5525 q{ 5526 int %s(scope int delegate(%s) dg) 5527 { 5528 import std.exception : enforce; 5529 5530 auto ranges = _ranges; 5531 int res; 5532 %s 5533 5534 while (%s) 5535 { 5536 res = dg(%s); 5537 if (res) break; 5538 %s 5539 %s 5540 } 5541 5542 if (_stoppingPolicy == StoppingPolicy.requireSameLength) 5543 { 5544 foreach (range; ranges) 5545 enforce(range.empty); 5546 } 5547 return res; 5548 } 5549 }, name, params.join(", "), indexDef, 5550 emptyChecks.join(" && "), dgArgs.join(", "), 5551 popFronts.join("\n "), 5552 indexInc); 5553 } 5554 5555 /** 5556 Iterate multiple ranges in lockstep using a `foreach` loop. In contrast to 5557 $(LREF zip) it allows reference access to its elements. If only a single 5558 range is passed in, the `Lockstep` aliases itself away. If the 5559 ranges are of different lengths and `s` == `StoppingPolicy.shortest` 5560 stop after the shortest range is empty. If the ranges are of different 5561 lengths and `s` == `StoppingPolicy.requireSameLength`, throw an 5562 exception. `s` may not be `StoppingPolicy.longest`, and passing this 5563 will throw an exception. 5564 5565 Iterating over `Lockstep` in reverse and with an index is only possible 5566 when `s` == `StoppingPolicy.requireSameLength`, in order to preserve 5567 indexes. If an attempt is made at iterating in reverse when `s` == 5568 `StoppingPolicy.shortest`, an exception will be thrown. 5569 5570 By default `StoppingPolicy` is set to `StoppingPolicy.shortest`. 5571 5572 Limitations: The `pure`, `@safe`, `@nogc`, or `nothrow` attributes cannot be 5573 inferred for `lockstep` iteration. $(LREF zip) can infer the first two due to 5574 a different implementation. 5575 5576 See_Also: $(LREF zip) 5577 5578 `lockstep` is similar to $(LREF zip), but `zip` bundles its 5579 elements and returns a range. 5580 `lockstep` also supports reference access. 5581 Use `zip` if you want to pass the result to a range function. 5582 */ 5583 struct Lockstep(Ranges...) 5584 if (Ranges.length > 1 && allSatisfy!(isInputRange, Ranges)) 5585 { 5586 /// 5587 this(R ranges, StoppingPolicy sp = StoppingPolicy.shortest) 5588 { 5589 import std.exception : enforce; 5590 5591 _ranges = ranges; 5592 enforce(sp != StoppingPolicy.longest, 5593 "Can't use StoppingPolicy.Longest on Lockstep."); 5594 _stoppingPolicy = sp; 5595 } 5596 5597 mixin(lockstepMixin!Ranges(false, false)); 5598 mixin(lockstepMixin!Ranges(true, false)); 5599 static if (allSatisfy!(isBidirectionalRange, Ranges)) 5600 { 5601 mixin(lockstepMixin!Ranges(false, true)); 5602 static if (allSatisfy!(hasLength, Ranges)) 5603 { 5604 mixin(lockstepMixin!Ranges(true, true)); 5605 } 5606 else 5607 { 5608 mixin(lockstepReverseFailMixin!Ranges(true)); 5609 } 5610 } 5611 else 5612 { 5613 mixin(lockstepReverseFailMixin!Ranges(false)); 5614 mixin(lockstepReverseFailMixin!Ranges(true)); 5615 } 5616 5617 private: 5618 alias R = Ranges; 5619 R _ranges; 5620 StoppingPolicy _stoppingPolicy; 5621 } 5622 5623 /// Ditto 5624 Lockstep!(Ranges) lockstep(Ranges...)(Ranges ranges) 5625 if (allSatisfy!(isInputRange, Ranges)) 5626 { 5627 return Lockstep!(Ranges)(ranges); 5628 } 5629 /// Ditto 5630 Lockstep!(Ranges) lockstep(Ranges...)(Ranges ranges, StoppingPolicy s) 5631 if (allSatisfy!(isInputRange, Ranges)) 5632 { 5633 static if (Ranges.length > 1) 5634 return Lockstep!Ranges(ranges, s); 5635 else 5636 return ranges[0]; 5637 } 5638 5639 /// 5640 @system unittest 5641 { 5642 auto arr1 = [1,2,3,4,5,100]; 5643 auto arr2 = [6,7,8,9,10]; 5644 5645 foreach (ref a, b; lockstep(arr1, arr2)) 5646 { 5647 a += b; 5648 } 5649 5650 assert(arr1 == [7,9,11,13,15,100]); 5651 5652 /// Lockstep also supports iterating with an index variable: 5653 foreach (index, a, b; lockstep(arr1, arr2)) 5654 { 5655 assert(arr1[index] == a); 5656 assert(arr2[index] == b); 5657 } 5658 } 5659 5660 // https://issues.dlang.org/show_bug.cgi?id=15860: foreach_reverse on lockstep 5661 @system unittest 5662 { 5663 auto arr1 = [0, 1, 2, 3]; 5664 auto arr2 = [4, 5, 6, 7]; 5665 5666 size_t n = arr1.length -1; 5667 foreach_reverse (index, a, b; lockstep(arr1, arr2, StoppingPolicy.requireSameLength)) 5668 { 5669 assert(n == index); 5670 assert(index == a); 5671 assert(arr1[index] == a); 5672 assert(arr2[index] == b); 5673 n--; 5674 } 5675 5676 auto arr3 = [4, 5]; 5677 n = 1; 5678 foreach_reverse (a, b; lockstep(arr1, arr3)) 5679 { 5680 assert(a == arr1[$-n] && b == arr3[$-n]); 5681 n++; 5682 } 5683 } 5684 5685 @system unittest 5686 { 5687 import std.algorithm.iteration : filter; 5688 import std.conv : to; 5689 5690 // The filters are to make these the lowest common forward denominator ranges, 5691 // i.e. w/o ref return, random access, length, etc. 5692 auto foo = filter!"a"([1,2,3,4,5]); 5693 immutable bar = [6f,7f,8f,9f,10f].idup; 5694 auto l = lockstep(foo, bar); 5695 5696 // Should work twice. These are forward ranges with implicit save. 5697 foreach (i; 0 .. 2) 5698 { 5699 uint[] res1; 5700 float[] res2; 5701 5702 foreach (a, ref b; l) 5703 { 5704 res1 ~= a; 5705 res2 ~= b; 5706 } 5707 5708 assert(res1 == [1,2,3,4,5]); 5709 assert(res2 == [6,7,8,9,10]); 5710 assert(bar == [6f,7f,8f,9f,10f]); 5711 } 5712 5713 // Doc example. 5714 auto arr1 = [1,2,3,4,5]; 5715 auto arr2 = [6,7,8,9,10]; 5716 5717 foreach (ref a, ref b; lockstep(arr1, arr2)) 5718 { 5719 a += b; 5720 } 5721 5722 assert(arr1 == [7,9,11,13,15]); 5723 5724 // Make sure StoppingPolicy.requireSameLength doesn't throw. 5725 auto ls = lockstep(arr1, arr2, StoppingPolicy.requireSameLength); 5726 5727 int k = 1; 5728 foreach (a, b; ls) 5729 { 5730 assert(a - b == k); 5731 ++k; 5732 } 5733 5734 // Make sure StoppingPolicy.requireSameLength throws. 5735 arr2.popBack(); 5736 ls = lockstep(arr1, arr2, StoppingPolicy.requireSameLength); 5737 5738 try { 5739 foreach (a, b; ls) {} 5740 assert(0); 5741 } catch (Exception) {} 5742 5743 // Just make sure 1-range case instantiates. This hangs the compiler 5744 // when no explicit stopping policy is specified due to 5745 // https://issues.dlang.org/show_bug.cgi?id=4652 5746 auto stuff = lockstep([1,2,3,4,5], StoppingPolicy.shortest); 5747 foreach (i, a; stuff) 5748 { 5749 assert(stuff[i] == a); 5750 } 5751 5752 // Test with indexing. 5753 uint[] res1; 5754 float[] res2; 5755 size_t[] indices; 5756 foreach (i, a, b; lockstep(foo, bar)) 5757 { 5758 indices ~= i; 5759 res1 ~= a; 5760 res2 ~= b; 5761 } 5762 5763 assert(indices == to!(size_t[])([0, 1, 2, 3, 4])); 5764 assert(res1 == [1,2,3,4,5]); 5765 assert(res2 == [6f,7f,8f,9f,10f]); 5766 5767 // Make sure we've worked around the relevant compiler bugs and this at least 5768 // compiles w/ >2 ranges. 5769 lockstep(foo, foo, foo); 5770 5771 // Make sure it works with const. 5772 const(int[])[] foo2 = [[1, 2, 3]]; 5773 const(int[])[] bar2 = [[4, 5, 6]]; 5774 auto c = chain(foo2, bar2); 5775 5776 foreach (f, b; lockstep(c, c)) {} 5777 5778 // Regression 10468 5779 foreach (x, y; lockstep(iota(0, 10), iota(0, 10))) { } 5780 } 5781 5782 @system unittest 5783 { 5784 struct RvalueRange 5785 { 5786 int[] impl; 5787 @property bool empty() { return impl.empty; } 5788 @property int front() { return impl[0]; } // N.B. non-ref 5789 void popFront() { impl.popFront(); } 5790 } 5791 auto data1 = [ 1, 2, 3, 4 ]; 5792 auto data2 = [ 5, 6, 7, 8 ]; 5793 auto r1 = RvalueRange(data1); 5794 auto r2 = data2; 5795 foreach (a, ref b; lockstep(r1, r2)) 5796 { 5797 a++; 5798 b++; 5799 } 5800 assert(data1 == [ 1, 2, 3, 4 ]); // changes to a do not propagate to data 5801 assert(data2 == [ 6, 7, 8, 9 ]); // but changes to b do. 5802 5803 // Since r1 is by-value only, the compiler should reject attempts to 5804 // foreach over it with ref. 5805 static assert(!__traits(compiles, { 5806 foreach (ref a, ref b; lockstep(r1, r2)) { a++; } 5807 })); 5808 } 5809 5810 private string lockstepReverseFailMixin(Ranges...)(bool withIndex) 5811 { 5812 import std.format : format; 5813 string[] params; 5814 string message; 5815 5816 if (withIndex) 5817 { 5818 message = "Indexed reverse iteration with lockstep is only supported" 5819 ~"if all ranges are bidirectional and have a length.\n"; 5820 } 5821 else 5822 { 5823 message = "Reverse iteration with lockstep is only supported if all ranges are bidirectional.\n"; 5824 } 5825 5826 if (withIndex) 5827 { 5828 params ~= "size_t"; 5829 } 5830 5831 foreach (idx, Range; Ranges) 5832 { 5833 params ~= format("%sElementType!(Ranges[%s])", hasLvalueElements!Range ? "ref " : "", idx); 5834 } 5835 5836 return format( 5837 q{ 5838 int opApplyReverse()(scope int delegate(%s) dg) 5839 { 5840 static assert(false, "%s"); 5841 } 5842 }, params.join(", "), message); 5843 } 5844 5845 // For generic programming, make sure Lockstep!(Range) is well defined for a 5846 // single range. 5847 template Lockstep(Range) 5848 { 5849 alias Lockstep = Range; 5850 } 5851 5852 /** 5853 Creates a mathematical sequence given the initial values and a 5854 recurrence function that computes the next value from the existing 5855 values. The sequence comes in the form of an infinite forward 5856 range. The type `Recurrence` itself is seldom used directly; most 5857 often, recurrences are obtained by calling the function $(D 5858 recurrence). 5859 5860 When calling `recurrence`, the function that computes the next 5861 value is specified as a template argument, and the initial values in 5862 the recurrence are passed as regular arguments. For example, in a 5863 Fibonacci sequence, there are two initial values (and therefore a 5864 state size of 2) because computing the next Fibonacci value needs the 5865 past two values. 5866 5867 The signature of this function should be: 5868 ---- 5869 auto fun(R)(R state, size_t n) 5870 ---- 5871 where `n` will be the index of the current value, and `state` will be an 5872 opaque state vector that can be indexed with array-indexing notation 5873 `state[i]`, where valid values of `i` range from $(D (n - 1)) to 5874 $(D (n - State.length)). 5875 5876 If the function is passed in string form, the state has name `"a"` 5877 and the zero-based index in the recurrence has name `"n"`. The 5878 given string must return the desired value for `a[n]` given 5879 `a[n - 1]`, `a[n - 2]`, `a[n - 3]`,..., `a[n - stateSize]`. The 5880 state size is dictated by the number of arguments passed to the call 5881 to `recurrence`. The `Recurrence` struct itself takes care of 5882 managing the recurrence's state and shifting it appropriately. 5883 */ 5884 struct Recurrence(alias fun, StateType, size_t stateSize) 5885 { 5886 import std.functional : binaryFun; 5887 5888 StateType[stateSize] _state; 5889 size_t _n; 5890 5891 this(StateType[stateSize] initial) { _state = initial; } 5892 5893 void popFront() 5894 { 5895 static auto trustedCycle(ref typeof(_state) s) @trusted 5896 { 5897 return cycle(s); 5898 } 5899 // The cast here is reasonable because fun may cause integer 5900 // promotion, but needs to return a StateType to make its operation 5901 // closed. Therefore, we have no other choice. 5902 _state[_n % stateSize] = cast(StateType) binaryFun!(fun, "a", "n")( 5903 trustedCycle(_state), _n + stateSize); 5904 ++_n; 5905 } 5906 5907 @property StateType front() 5908 { 5909 return _state[_n % stateSize]; 5910 } 5911 5912 @property typeof(this) save() 5913 { 5914 return this; 5915 } 5916 5917 enum bool empty = false; 5918 } 5919 5920 /// 5921 pure @safe nothrow unittest 5922 { 5923 import std.algorithm.comparison : equal; 5924 5925 // The Fibonacci numbers, using function in string form: 5926 // a[0] = 1, a[1] = 1, and compute a[n+1] = a[n-1] + a[n] 5927 auto fib = recurrence!("a[n-1] + a[n-2]")(1, 1); 5928 assert(fib.take(10).equal([1, 1, 2, 3, 5, 8, 13, 21, 34, 55])); 5929 5930 // The factorials, using function in lambda form: 5931 auto fac = recurrence!((a,n) => a[n-1] * n)(1); 5932 assert(take(fac, 10).equal([ 5933 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880 5934 ])); 5935 5936 // The triangular numbers, using function in explicit form: 5937 static size_t genTriangular(R)(R state, size_t n) 5938 { 5939 return state[n-1] + n; 5940 } 5941 auto tri = recurrence!genTriangular(0); 5942 assert(take(tri, 10).equal([0, 1, 3, 6, 10, 15, 21, 28, 36, 45])); 5943 } 5944 5945 /// Ditto 5946 Recurrence!(fun, CommonType!(State), State.length) 5947 recurrence(alias fun, State...)(State initial) 5948 { 5949 CommonType!(State)[State.length] state; 5950 foreach (i, Unused; State) 5951 { 5952 state[i] = initial[i]; 5953 } 5954 return typeof(return)(state); 5955 } 5956 5957 pure @safe nothrow unittest 5958 { 5959 import std.algorithm.comparison : equal; 5960 5961 auto fib = recurrence!("a[n-1] + a[n-2]")(1, 1); 5962 static assert(isForwardRange!(typeof(fib))); 5963 5964 int[] witness = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55 ]; 5965 assert(equal(take(fib, 10), witness)); 5966 foreach (e; take(fib, 10)) {} 5967 auto fact = recurrence!("n * a[n-1]")(1); 5968 assert( equal(take(fact, 10), [1, 1, 2, 2*3, 2*3*4, 2*3*4*5, 2*3*4*5*6, 5969 2*3*4*5*6*7, 2*3*4*5*6*7*8, 2*3*4*5*6*7*8*9][]) ); 5970 auto piapprox = recurrence!("a[n] + (n & 1 ? 4.0 : -4.0) / (2 * n + 3)")(4.0); 5971 foreach (e; take(piapprox, 20)) {} 5972 // Thanks to yebblies for this test and the associated fix 5973 auto r = recurrence!"a[n-2]"(1, 2); 5974 witness = [1, 2, 1, 2, 1]; 5975 assert(equal(take(r, 5), witness)); 5976 } 5977 5978 /** 5979 `Sequence` is similar to `Recurrence` except that iteration is 5980 presented in the so-called $(HTTP en.wikipedia.org/wiki/Closed_form, 5981 closed form). This means that the `n`th element in the series is 5982 computable directly from the initial values and `n` itself. This 5983 implies that the interface offered by `Sequence` is a random-access 5984 range, as opposed to the regular `Recurrence`, which only offers 5985 forward iteration. 5986 5987 The state of the sequence is stored as a `Tuple` so it can be 5988 heterogeneous. 5989 */ 5990 struct Sequence(alias fun, State) 5991 { 5992 private: 5993 import std.functional : binaryFun; 5994 5995 alias compute = binaryFun!(fun, "a", "n"); 5996 alias ElementType = typeof(compute(State.init, cast(size_t) 1)); 5997 State _state; 5998 size_t _n; 5999 6000 static struct DollarToken{} 6001 6002 public: 6003 this(State initial, size_t n = 0) 6004 { 6005 _state = initial; 6006 _n = n; 6007 } 6008 6009 @property ElementType front() 6010 { 6011 return compute(_state, _n); 6012 } 6013 6014 void popFront() 6015 { 6016 ++_n; 6017 } 6018 6019 enum opDollar = DollarToken(); 6020 6021 auto opSlice(size_t lower, size_t upper) 6022 in 6023 { 6024 assert( 6025 upper >= lower, 6026 "Attempting to slice a Sequence with a larger first argument than the second." 6027 ); 6028 } 6029 do 6030 { 6031 return typeof(this)(_state, _n + lower).take(upper - lower); 6032 } 6033 6034 auto opSlice(size_t lower, DollarToken) 6035 { 6036 return typeof(this)(_state, _n + lower); 6037 } 6038 6039 ElementType opIndex(size_t n) 6040 { 6041 return compute(_state, n + _n); 6042 } 6043 6044 enum bool empty = false; 6045 6046 @property Sequence save() { return this; } 6047 } 6048 6049 /// Ditto 6050 auto sequence(alias fun, State...)(State args) 6051 { 6052 import std.typecons : Tuple, tuple; 6053 alias Return = Sequence!(fun, Tuple!State); 6054 return Return(tuple(args)); 6055 } 6056 6057 /// Odd numbers, using function in string form: 6058 pure @safe nothrow @nogc unittest 6059 { 6060 auto odds = sequence!("a[0] + n * a[1]")(1, 2); 6061 assert(odds.front == 1); 6062 odds.popFront(); 6063 assert(odds.front == 3); 6064 odds.popFront(); 6065 assert(odds.front == 5); 6066 } 6067 6068 /// Triangular numbers, using function in lambda form: 6069 pure @safe nothrow @nogc unittest 6070 { 6071 auto tri = sequence!((a,n) => n*(n+1)/2)(); 6072 6073 // Note random access 6074 assert(tri[0] == 0); 6075 assert(tri[3] == 6); 6076 assert(tri[1] == 1); 6077 assert(tri[4] == 10); 6078 assert(tri[2] == 3); 6079 } 6080 6081 /// Fibonacci numbers, using function in explicit form: 6082 @safe nothrow @nogc unittest 6083 { 6084 import std.math : pow, round, sqrt; 6085 static ulong computeFib(S)(S state, size_t n) 6086 { 6087 // Binet's formula 6088 return cast(ulong)(round((pow(state[0], n+1) - pow(state[1], n+1)) / 6089 state[2])); 6090 } 6091 auto fib = sequence!computeFib( 6092 (1.0 + sqrt(5.0)) / 2.0, // Golden Ratio 6093 (1.0 - sqrt(5.0)) / 2.0, // Conjugate of Golden Ratio 6094 sqrt(5.0)); 6095 6096 // Note random access with [] operator 6097 assert(fib[1] == 1); 6098 assert(fib[4] == 5); 6099 assert(fib[3] == 3); 6100 assert(fib[2] == 2); 6101 assert(fib[9] == 55); 6102 } 6103 6104 pure @safe nothrow @nogc unittest 6105 { 6106 import std.typecons : Tuple, tuple; 6107 auto y = Sequence!("a[0] + n * a[1]", Tuple!(int, int))(tuple(0, 4)); 6108 static assert(isForwardRange!(typeof(y))); 6109 6110 //@@BUG 6111 //auto y = sequence!("a[0] + n * a[1]")(0, 4); 6112 //foreach (e; take(y, 15)) 6113 {} //writeln(e); 6114 6115 auto odds = Sequence!("a[0] + n * a[1]", Tuple!(int, int))( 6116 tuple(1, 2)); 6117 for (int currentOdd = 1; currentOdd <= 21; currentOdd += 2) 6118 { 6119 assert(odds.front == odds[0]); 6120 assert(odds[0] == currentOdd); 6121 odds.popFront(); 6122 } 6123 } 6124 6125 pure @safe nothrow @nogc unittest 6126 { 6127 import std.algorithm.comparison : equal; 6128 6129 auto odds = sequence!("a[0] + n * a[1]")(1, 2); 6130 static assert(hasSlicing!(typeof(odds))); 6131 6132 //Note: don't use drop or take as the target of an equal, 6133 //since they'll both just forward to opSlice, making the tests irrelevant 6134 6135 // static slicing tests 6136 assert(equal(odds[0 .. 5], only(1, 3, 5, 7, 9))); 6137 assert(equal(odds[3 .. 7], only(7, 9, 11, 13))); 6138 6139 // relative slicing test, testing slicing is NOT agnostic of state 6140 auto odds_less5 = odds.drop(5); //this should actually call odds[5 .. $] 6141 assert(equal(odds_less5[0 .. 3], only(11, 13, 15))); 6142 assert(equal(odds_less5[0 .. 10], odds[5 .. 15])); 6143 6144 //Infinite slicing tests 6145 odds = odds[10 .. $]; 6146 assert(equal(odds.take(3), only(21, 23, 25))); 6147 } 6148 6149 // https://issues.dlang.org/show_bug.cgi?id=5036 6150 pure @safe nothrow unittest 6151 { 6152 auto s = sequence!((a, n) => new int)(0); 6153 assert(s.front != s.front); // no caching 6154 } 6155 6156 // iota 6157 /** 6158 Creates a range of values that span the given starting and stopping 6159 values. 6160 6161 Params: 6162 begin = The starting value. 6163 end = The value that serves as the stopping criterion. This value is not 6164 included in the range. 6165 step = The value to add to the current value at each iteration. 6166 6167 Returns: 6168 A range that goes through the numbers `begin`, $(D begin + step), 6169 $(D begin + 2 * step), `...`, up to and excluding `end`. 6170 6171 The two-argument overloads have $(D step = 1). If $(D begin < end && step < 6172 0) or $(D begin > end && step > 0) or $(D begin == end), then an empty range 6173 is returned. If $(D step == 0) then $(D begin == end) is an error. 6174 6175 For built-in types, the range returned is a random access range. For 6176 user-defined types that support `++`, the range is an input 6177 range. 6178 6179 An integral iota also supports `in` operator from the right. It takes 6180 the stepping into account, the integral won't be considered 6181 contained if it falls between two consecutive values of the range. 6182 `contains` does the same as in, but from lefthand side. 6183 6184 Example: 6185 --- 6186 void main() 6187 { 6188 import std.stdio; 6189 6190 // The following groups all produce the same output of: 6191 // 0 1 2 3 4 6192 6193 foreach (i; 0 .. 5) 6194 writef("%s ", i); 6195 writeln(); 6196 6197 import std.range : iota; 6198 foreach (i; iota(0, 5)) 6199 writef("%s ", i); 6200 writeln(); 6201 6202 writefln("%(%s %|%)", iota(0, 5)); 6203 6204 import std.algorithm.iteration : map; 6205 import std.algorithm.mutation : copy; 6206 import std.format; 6207 iota(0, 5).map!(i => format("%s ", i)).copy(stdout.lockingTextWriter()); 6208 writeln(); 6209 } 6210 --- 6211 */ 6212 auto iota(B, E, S)(B begin, E end, S step) 6213 if ((isIntegral!(CommonType!(B, E)) || isPointer!(CommonType!(B, E))) 6214 && isIntegral!S) 6215 { 6216 import std.conv : unsigned; 6217 6218 alias Value = CommonType!(Unqual!B, Unqual!E); 6219 alias StepType = Unqual!S; 6220 6221 assert(step != 0 || begin == end); 6222 6223 static struct Result 6224 { 6225 private Value current, last; 6226 private StepType step; // by convention, 0 if range is empty 6227 6228 this(Value current, Value pastLast, StepType step) 6229 { 6230 if (current < pastLast && step > 0) 6231 { 6232 // Iterating upward 6233 assert(unsigned((pastLast - current) / step) <= size_t.max); 6234 // Cast below can't fail because current < pastLast 6235 this.last = cast(Value) (pastLast - 1); 6236 this.last -= unsigned(this.last - current) % step; 6237 } 6238 else if (current > pastLast && step < 0) 6239 { 6240 // Iterating downward 6241 assert(unsigned((current - pastLast) / (0 - step)) <= size_t.max); 6242 // Cast below can't fail because current > pastLast 6243 this.last = cast(Value) (pastLast + 1); 6244 this.last += unsigned(current - this.last) % (0 - step); 6245 } 6246 else 6247 { 6248 // Initialize an empty range 6249 this.step = 0; 6250 return; 6251 } 6252 this.step = step; 6253 this.current = current; 6254 } 6255 6256 @property bool empty() const { return step == 0; } 6257 @property inout(Value) front() inout { assert(!empty); return current; } 6258 void popFront() 6259 { 6260 assert(!empty); 6261 if (current == last) step = 0; 6262 else current += step; 6263 } 6264 6265 @property inout(Value) back() inout 6266 { 6267 assert(!empty); 6268 return last; 6269 } 6270 void popBack() 6271 { 6272 assert(!empty); 6273 if (current == last) step = 0; 6274 else last -= step; 6275 } 6276 6277 @property auto save() { return this; } 6278 6279 inout(Value) opIndex(ulong n) inout 6280 { 6281 assert(n < this.length); 6282 6283 // Just cast to Value here because doing so gives overflow behavior 6284 // consistent with calling popFront() n times. 6285 return cast(inout Value) (current + step * n); 6286 } 6287 auto opBinaryRight(string op)(Value val) const 6288 if (op == "in") 6289 { 6290 if (empty) return false; 6291 //cast to avoid becoming unsigned 6292 auto supposedIndex = cast(StepType)(val - current) / step; 6293 return supposedIndex < length && supposedIndex * step + current == val; 6294 } 6295 auto contains(Value x){return x in this;} 6296 inout(Result) opSlice() inout { return this; } 6297 inout(Result) opSlice(ulong lower, ulong upper) inout 6298 { 6299 assert(upper >= lower && upper <= this.length); 6300 6301 return cast(inout Result) Result( 6302 cast(Value)(current + lower * step), 6303 cast(Value)(current + upper * step), 6304 step); 6305 } 6306 @property size_t length() const 6307 { 6308 if (step > 0) 6309 return 1 + cast(size_t) (unsigned(last - current) / step); 6310 if (step < 0) 6311 return 1 + cast(size_t) (unsigned(current - last) / (0 - step)); 6312 return 0; 6313 } 6314 6315 alias opDollar = length; 6316 } 6317 6318 return Result(begin, end, step); 6319 } 6320 6321 /// Ditto 6322 auto iota(B, E)(B begin, E end) 6323 if (isFloatingPoint!(CommonType!(B, E))) 6324 { 6325 return iota(begin, end, CommonType!(B, E)(1)); 6326 } 6327 6328 /// Ditto 6329 auto iota(B, E)(B begin, E end) 6330 if (isIntegral!(CommonType!(B, E)) || isPointer!(CommonType!(B, E))) 6331 { 6332 import std.conv : unsigned; 6333 6334 alias Value = CommonType!(Unqual!B, Unqual!E); 6335 6336 static struct Result 6337 { 6338 private Value current, pastLast; 6339 6340 this(Value current, Value pastLast) 6341 { 6342 if (current < pastLast) 6343 { 6344 assert(unsigned(pastLast - current) <= size_t.max); 6345 6346 this.current = current; 6347 this.pastLast = pastLast; 6348 } 6349 else 6350 { 6351 // Initialize an empty range 6352 this.current = this.pastLast = current; 6353 } 6354 } 6355 6356 @property bool empty() const { return current == pastLast; } 6357 @property inout(Value) front() inout { assert(!empty); return current; } 6358 void popFront() { assert(!empty); ++current; } 6359 6360 @property inout(Value) back() inout { assert(!empty); return cast(inout(Value))(pastLast - 1); } 6361 void popBack() { assert(!empty); --pastLast; } 6362 6363 @property auto save() { return this; } 6364 6365 inout(Value) opIndex(size_t n) inout 6366 { 6367 assert(n < this.length); 6368 6369 // Just cast to Value here because doing so gives overflow behavior 6370 // consistent with calling popFront() n times. 6371 return cast(inout Value) (current + n); 6372 } 6373 auto opBinaryRight(string op)(Value val) const 6374 if (op == "in") 6375 { 6376 return current <= val && val < pastLast; 6377 } 6378 auto contains(Value x){return x in this;} 6379 inout(Result) opSlice() inout { return this; } 6380 inout(Result) opSlice(ulong lower, ulong upper) inout 6381 { 6382 assert(upper >= lower && upper <= this.length); 6383 6384 return cast(inout Result) Result(cast(Value)(current + lower), 6385 cast(Value)(pastLast - (length - upper))); 6386 } 6387 @property size_t length() const 6388 { 6389 return cast(size_t)(pastLast - current); 6390 } 6391 6392 alias opDollar = length; 6393 } 6394 6395 return Result(begin, end); 6396 } 6397 6398 /// Ditto 6399 auto iota(E)(E end) 6400 if (is(typeof(iota(E(0), end)))) 6401 { 6402 E begin = E(0); 6403 return iota(begin, end); 6404 } 6405 6406 /// Ditto 6407 // Specialization for floating-point types 6408 auto iota(B, E, S)(B begin, E end, S step) 6409 if (isFloatingPoint!(CommonType!(B, E, S))) 6410 in 6411 { 6412 assert(step != 0, "iota: step must not be 0"); 6413 assert((end - begin) / step >= 0, "iota: incorrect startup parameters"); 6414 } 6415 do 6416 { 6417 alias Value = Unqual!(CommonType!(B, E, S)); 6418 static struct Result 6419 { 6420 private Value start, step; 6421 private size_t index, count; 6422 6423 this(Value start, Value end, Value step) 6424 { 6425 import std.conv : to; 6426 6427 this.start = start; 6428 this.step = step; 6429 immutable fcount = (end - start) / step; 6430 count = to!size_t(fcount); 6431 auto pastEnd = start + count * step; 6432 if (step > 0) 6433 { 6434 if (pastEnd < end) ++count; 6435 assert(start + count * step >= end); 6436 } 6437 else 6438 { 6439 if (pastEnd > end) ++count; 6440 assert(start + count * step <= end); 6441 } 6442 } 6443 6444 @property bool empty() const { return index == count; } 6445 @property Value front() const { assert(!empty); return start + step * index; } 6446 void popFront() 6447 { 6448 assert(!empty); 6449 ++index; 6450 } 6451 @property Value back() const 6452 { 6453 assert(!empty); 6454 return start + step * (count - 1); 6455 } 6456 void popBack() 6457 { 6458 assert(!empty); 6459 --count; 6460 } 6461 6462 @property auto save() { return this; } 6463 6464 Value opIndex(size_t n) const 6465 { 6466 assert(n < count); 6467 return start + step * (n + index); 6468 } 6469 inout(Result) opSlice() inout 6470 { 6471 return this; 6472 } 6473 inout(Result) opSlice(size_t lower, size_t upper) inout 6474 { 6475 assert(upper >= lower && upper <= count); 6476 6477 Result ret = this; 6478 ret.index += lower; 6479 ret.count = upper - lower + ret.index; 6480 return cast(inout Result) ret; 6481 } 6482 @property size_t length() const 6483 { 6484 return count - index; 6485 } 6486 6487 alias opDollar = length; 6488 } 6489 6490 return Result(begin, end, step); 6491 } 6492 6493 /// 6494 pure @safe unittest 6495 { 6496 import std.algorithm.comparison : equal; 6497 import std.math : approxEqual; 6498 6499 auto r = iota(0, 10, 1); 6500 assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])); 6501 assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])); 6502 assert(3 in r); 6503 assert(r.contains(3)); //Same as above 6504 assert(!(10 in r)); 6505 assert(!(-8 in r)); 6506 r = iota(0, 11, 3); 6507 assert(equal(r, [0, 3, 6, 9])); 6508 assert(r[2] == 6); 6509 assert(!(2 in r)); 6510 auto rf = iota(0.0, 0.5, 0.1); 6511 assert(approxEqual(rf, [0.0, 0.1, 0.2, 0.3, 0.4])); 6512 } 6513 6514 pure nothrow @nogc @safe unittest 6515 { 6516 import std.traits : Signed; 6517 //float overloads use std.conv.to so can't be @nogc or nothrow 6518 alias ssize_t = Signed!size_t; 6519 assert(iota(ssize_t.max, 0, -1).length == ssize_t.max); 6520 assert(iota(ssize_t.max, ssize_t.min, -1).length == size_t.max); 6521 assert(iota(ssize_t.max, ssize_t.min, -2).length == 1 + size_t.max / 2); 6522 assert(iota(ssize_t.min, ssize_t.max, 2).length == 1 + size_t.max / 2); 6523 assert(iota(ssize_t.max, ssize_t.min, -3).length == size_t.max / 3); 6524 } 6525 6526 debug @system unittest 6527 {//check the contracts 6528 import core.exception : AssertError; 6529 import std.exception : assertThrown; 6530 assertThrown!AssertError(iota(1,2,0)); 6531 assertThrown!AssertError(iota(0f,1f,0f)); 6532 assertThrown!AssertError(iota(1f,0f,0.1f)); 6533 assertThrown!AssertError(iota(0f,1f,-0.1f)); 6534 } 6535 6536 pure @system nothrow unittest 6537 { 6538 int[] a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; 6539 auto r1 = iota(a.ptr, a.ptr + a.length, 1); 6540 assert(r1.front == a.ptr); 6541 assert(r1.back == a.ptr + a.length - 1); 6542 assert(&a[4] in r1); 6543 } 6544 6545 pure @safe nothrow @nogc unittest 6546 { 6547 assert(iota(1UL, 0UL).length == 0); 6548 assert(iota(1UL, 0UL, 1).length == 0); 6549 assert(iota(0, 1, 1).length == 1); 6550 assert(iota(1, 0, -1).length == 1); 6551 assert(iota(0, 1, -1).length == 0); 6552 assert(iota(ulong.max, 0).length == 0); 6553 } 6554 6555 pure @safe unittest 6556 { 6557 import std.algorithm.comparison : equal; 6558 import std.algorithm.searching : count; 6559 import std.math : approxEqual, nextUp, nextDown; 6560 import std.meta : AliasSeq; 6561 6562 static assert(is(ElementType!(typeof(iota(0f))) == float)); 6563 6564 static assert(hasLength!(typeof(iota(0, 2)))); 6565 auto r = iota(0, 10, 1); 6566 assert(r[$ - 1] == 9); 6567 assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][])); 6568 6569 auto rSlice = r[2 .. 8]; 6570 assert(equal(rSlice, [2, 3, 4, 5, 6, 7])); 6571 6572 rSlice.popFront(); 6573 assert(rSlice[0] == rSlice.front); 6574 assert(rSlice.front == 3); 6575 6576 rSlice.popBack(); 6577 assert(rSlice[rSlice.length - 1] == rSlice.back); 6578 assert(rSlice.back == 6); 6579 6580 rSlice = r[0 .. 4]; 6581 assert(equal(rSlice, [0, 1, 2, 3])); 6582 assert(3 in rSlice); 6583 assert(!(4 in rSlice)); 6584 6585 auto rr = iota(10); 6586 assert(equal(rr, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][])); 6587 6588 r = iota(0, -10, -1); 6589 assert(equal(r, [0, -1, -2, -3, -4, -5, -6, -7, -8, -9][])); 6590 rSlice = r[3 .. 9]; 6591 assert(equal(rSlice, [-3, -4, -5, -6, -7, -8])); 6592 6593 r = iota(0, -6, -3); 6594 assert(equal(r, [0, -3][])); 6595 rSlice = r[1 .. 2]; 6596 assert(equal(rSlice, [-3])); 6597 6598 r = iota(0, -7, -3); 6599 assert(equal(r, [0, -3, -6][])); 6600 assert(0 in r); 6601 assert(-6 in r); 6602 rSlice = r[1 .. 3]; 6603 assert(equal(rSlice, [-3, -6])); 6604 assert(!(0 in rSlice)); 6605 assert(!(-2 in rSlice)); 6606 assert(!(-5 in rSlice)); 6607 assert(!(3 in rSlice)); 6608 assert(!(-9 in rSlice)); 6609 6610 r = iota(0, 11, 3); 6611 assert(equal(r, [0, 3, 6, 9][])); 6612 assert(r[2] == 6); 6613 rSlice = r[1 .. 3]; 6614 assert(equal(rSlice, [3, 6])); 6615 6616 auto rf = iota(0.0, 0.5, 0.1); 6617 assert(approxEqual(rf, [0.0, 0.1, 0.2, 0.3, 0.4][])); 6618 assert(rf.length == 5); 6619 6620 rf.popFront(); 6621 assert(rf.length == 4); 6622 6623 auto rfSlice = rf[1 .. 4]; 6624 assert(rfSlice.length == 3); 6625 assert(approxEqual(rfSlice, [0.2, 0.3, 0.4])); 6626 6627 rfSlice.popFront(); 6628 assert(approxEqual(rfSlice[0], 0.3)); 6629 6630 rf.popFront(); 6631 assert(rf.length == 3); 6632 6633 rfSlice = rf[1 .. 3]; 6634 assert(rfSlice.length == 2); 6635 assert(approxEqual(rfSlice, [0.3, 0.4])); 6636 assert(approxEqual(rfSlice[0], 0.3)); 6637 6638 // With something just above 0.5 6639 rf = iota(0.0, nextUp(0.5), 0.1); 6640 assert(approxEqual(rf, [0.0, 0.1, 0.2, 0.3, 0.4, 0.5][])); 6641 rf.popBack(); 6642 assert(rf[rf.length - 1] == rf.back); 6643 assert(approxEqual(rf.back, 0.4)); 6644 assert(rf.length == 5); 6645 6646 // going down 6647 rf = iota(0.0, -0.5, -0.1); 6648 assert(approxEqual(rf, [0.0, -0.1, -0.2, -0.3, -0.4][])); 6649 rfSlice = rf[2 .. 5]; 6650 assert(approxEqual(rfSlice, [-0.2, -0.3, -0.4])); 6651 6652 rf = iota(0.0, nextDown(-0.5), -0.1); 6653 assert(approxEqual(rf, [0.0, -0.1, -0.2, -0.3, -0.4, -0.5][])); 6654 6655 // iota of longs 6656 auto rl = iota(5_000_000L); 6657 assert(rl.length == 5_000_000L); 6658 assert(0 in rl); 6659 assert(4_000_000L in rl); 6660 assert(!(-4_000_000L in rl)); 6661 assert(!(5_000_000L in rl)); 6662 6663 // iota of longs with steps 6664 auto iota_of_longs_with_steps = iota(50L, 101L, 10); 6665 assert(iota_of_longs_with_steps.length == 6); 6666 assert(equal(iota_of_longs_with_steps, [50L, 60L, 70L, 80L, 90L, 100L])); 6667 6668 // iota of unsigned zero length (https://issues.dlang.org/show_bug.cgi?id=6222) 6669 // Actually trying to consume it is the only way to find something is wrong 6670 // because the public properties are all correct. 6671 auto iota_zero_unsigned = iota(0, 0u, 3); 6672 assert(count(iota_zero_unsigned) == 0); 6673 6674 // https://issues.dlang.org/show_bug.cgi?id=7982 6675 // unsigned reverse iota can be buggy if `.length` doesn't 6676 // take them into account 6677 assert(iota(10u, 0u, -1).length == 10); 6678 assert(iota(10u, 0u, -2).length == 5); 6679 assert(iota(uint.max, uint.max-10, -1).length == 10); 6680 assert(iota(uint.max, uint.max-10, -2).length == 5); 6681 assert(iota(uint.max, 0u, -1).length == uint.max); 6682 6683 assert(20 in iota(20u, 10u, -2)); 6684 assert(16 in iota(20u, 10u, -2)); 6685 assert(!(15 in iota(20u, 10u, -2))); 6686 assert(!(10 in iota(20u, 10u, -2))); 6687 assert(!(uint.max in iota(20u, 10u, -1))); 6688 assert(!(int.min in iota(20u, 10u, -1))); 6689 assert(!(int.max in iota(20u, 10u, -1))); 6690 6691 6692 // https://issues.dlang.org/show_bug.cgi?id=8920 6693 static foreach (Type; AliasSeq!(byte, ubyte, short, ushort, 6694 int, uint, long, ulong)) 6695 {{ 6696 Type val; 6697 foreach (i; iota(cast(Type) 0, cast(Type) 10)) { val++; } 6698 assert(val == 10); 6699 }} 6700 } 6701 6702 pure @safe nothrow unittest 6703 { 6704 import std.algorithm.mutation : copy; 6705 auto idx = new size_t[100]; 6706 copy(iota(0, idx.length), idx); 6707 } 6708 6709 @safe unittest 6710 { 6711 import std.meta : AliasSeq; 6712 static foreach (range; AliasSeq!(iota(2, 27, 4), 6713 iota(3, 9), 6714 iota(2.7, 12.3, .1), 6715 iota(3.2, 9.7))) 6716 {{ 6717 const cRange = range; 6718 const e = cRange.empty; 6719 const f = cRange.front; 6720 const b = cRange.back; 6721 const i = cRange[2]; 6722 const s1 = cRange[]; 6723 const s2 = cRange[0 .. 3]; 6724 const l = cRange.length; 6725 }} 6726 } 6727 6728 @system unittest 6729 { 6730 //The ptr stuff can't be done at compile time, so we unfortunately end 6731 //up with some code duplication here. 6732 auto arr = [0, 5, 3, 5, 5, 7, 9, 2, 0, 42, 7, 6]; 6733 6734 { 6735 const cRange = iota(arr.ptr, arr.ptr + arr.length, 3); 6736 const e = cRange.empty; 6737 const f = cRange.front; 6738 const b = cRange.back; 6739 const i = cRange[2]; 6740 const s1 = cRange[]; 6741 const s2 = cRange[0 .. 3]; 6742 const l = cRange.length; 6743 } 6744 6745 { 6746 const cRange = iota(arr.ptr, arr.ptr + arr.length); 6747 const e = cRange.empty; 6748 const f = cRange.front; 6749 const b = cRange.back; 6750 const i = cRange[2]; 6751 const s1 = cRange[]; 6752 const s2 = cRange[0 .. 3]; 6753 const l = cRange.length; 6754 } 6755 } 6756 6757 @nogc nothrow pure @safe unittest 6758 { 6759 { 6760 ushort start = 0, end = 10, step = 2; 6761 foreach (i; iota(start, end, step)) 6762 static assert(is(typeof(i) == ushort)); 6763 } 6764 { 6765 ubyte start = 0, end = 255, step = 128; 6766 uint x; 6767 foreach (i; iota(start, end, step)) 6768 { 6769 static assert(is(typeof(i) == ubyte)); 6770 ++x; 6771 } 6772 assert(x == 2); 6773 } 6774 } 6775 6776 /* Generic overload that handles arbitrary types that support arithmetic 6777 * operations. 6778 * 6779 * User-defined types such as $(REF BigInt, std,bigint) are also supported, as long 6780 * as they can be incremented with `++` and compared with `<` or `==`. 6781 */ 6782 /// ditto 6783 auto iota(B, E)(B begin, E end) 6784 if (!isIntegral!(CommonType!(B, E)) && 6785 !isFloatingPoint!(CommonType!(B, E)) && 6786 !isPointer!(CommonType!(B, E)) && 6787 is(typeof((ref B b) { ++b; })) && 6788 (is(typeof(B.init < E.init)) || is(typeof(B.init == E.init))) ) 6789 { 6790 static struct Result 6791 { 6792 B current; 6793 E end; 6794 6795 @property bool empty() 6796 { 6797 static if (is(typeof(B.init < E.init))) 6798 return !(current < end); 6799 else static if (is(typeof(B.init != E.init))) 6800 return current == end; 6801 else 6802 static assert(0); 6803 } 6804 @property auto front() { return current; } 6805 void popFront() 6806 { 6807 assert(!empty); 6808 ++current; 6809 } 6810 } 6811 return Result(begin, end); 6812 } 6813 6814 @safe unittest 6815 { 6816 import std.algorithm.comparison : equal; 6817 6818 // Test iota() for a type that only supports ++ and != but does not have 6819 // '<'-ordering. 6820 struct Cyclic(int wrapAround) 6821 { 6822 int current; 6823 6824 this(int start) { current = start % wrapAround; } 6825 6826 bool opEquals(Cyclic c) const { return current == c.current; } 6827 bool opEquals(int i) const { return current == i; } 6828 void opUnary(string op)() if (op == "++") 6829 { 6830 current = (current + 1) % wrapAround; 6831 } 6832 } 6833 alias Cycle5 = Cyclic!5; 6834 6835 // Easy case 6836 auto i1 = iota(Cycle5(1), Cycle5(4)); 6837 assert(i1.equal([1, 2, 3])); 6838 6839 // Wraparound case 6840 auto i2 = iota(Cycle5(3), Cycle5(2)); 6841 assert(i2.equal([3, 4, 0, 1 ])); 6842 } 6843 6844 /** 6845 Options for the $(LREF FrontTransversal) and $(LREF Transversal) ranges 6846 (below). 6847 */ 6848 enum TransverseOptions 6849 { 6850 /** 6851 When transversed, the elements of a range of ranges are assumed to 6852 have different lengths (e.g. a jagged array). 6853 */ 6854 assumeJagged, //default 6855 /** 6856 The transversal enforces that the elements of a range of ranges have 6857 all the same length (e.g. an array of arrays, all having the same 6858 length). Checking is done once upon construction of the transversal 6859 range. 6860 */ 6861 enforceNotJagged, 6862 /** 6863 The transversal assumes, without verifying, that the elements of a 6864 range of ranges have all the same length. This option is useful if 6865 checking was already done from the outside of the range. 6866 */ 6867 assumeNotJagged, 6868 } 6869 6870 /// 6871 @safe pure unittest 6872 { 6873 import std.algorithm.comparison : equal; 6874 import std.exception : assertThrown; 6875 6876 auto arr = [[1, 2], [3, 4, 5]]; 6877 6878 auto r1 = arr.frontTransversal!(TransverseOptions.assumeJagged); 6879 assert(r1.equal([1, 3])); 6880 6881 // throws on construction 6882 assertThrown!Exception(arr.frontTransversal!(TransverseOptions.enforceNotJagged)); 6883 6884 auto r2 = arr.frontTransversal!(TransverseOptions.assumeNotJagged); 6885 assert(r2.equal([1, 3])); 6886 6887 // either assuming or checking for equal lengths makes 6888 // the result a random access range 6889 assert(r2[0] == 1); 6890 static assert(!__traits(compiles, r1[0])); 6891 } 6892 6893 /** 6894 Given a range of ranges, iterate transversally through the first 6895 elements of each of the enclosed ranges. 6896 */ 6897 struct FrontTransversal(Ror, 6898 TransverseOptions opt = TransverseOptions.assumeJagged) 6899 { 6900 alias RangeOfRanges = Unqual!(Ror); 6901 alias RangeType = .ElementType!RangeOfRanges; 6902 alias ElementType = .ElementType!RangeType; 6903 6904 private void prime() 6905 { 6906 static if (opt == TransverseOptions.assumeJagged) 6907 { 6908 while (!_input.empty && _input.front.empty) 6909 { 6910 _input.popFront(); 6911 } 6912 static if (isBidirectionalRange!RangeOfRanges) 6913 { 6914 while (!_input.empty && _input.back.empty) 6915 { 6916 _input.popBack(); 6917 } 6918 } 6919 } 6920 } 6921 6922 /** 6923 Construction from an input. 6924 */ 6925 this(RangeOfRanges input) 6926 { 6927 _input = input; 6928 prime(); 6929 static if (opt == TransverseOptions.enforceNotJagged) 6930 // (isRandomAccessRange!RangeOfRanges 6931 // && hasLength!RangeType) 6932 { 6933 import std.exception : enforce; 6934 6935 if (empty) return; 6936 immutable commonLength = _input.front.length; 6937 foreach (e; _input) 6938 { 6939 enforce(e.length == commonLength); 6940 } 6941 } 6942 } 6943 6944 /** 6945 Forward range primitives. 6946 */ 6947 static if (isInfinite!RangeOfRanges) 6948 { 6949 enum bool empty = false; 6950 } 6951 else 6952 { 6953 @property bool empty() 6954 { 6955 static if (opt != TransverseOptions.assumeJagged) 6956 { 6957 if (!_input.empty) 6958 return _input.front.empty; 6959 } 6960 6961 return _input.empty; 6962 } 6963 } 6964 6965 /// Ditto 6966 @property auto ref front() 6967 { 6968 assert(!empty, "Attempting to fetch the front of an empty FrontTransversal"); 6969 return _input.front.front; 6970 } 6971 6972 /// Ditto 6973 static if (hasMobileElements!RangeType) 6974 { 6975 ElementType moveFront() 6976 { 6977 return _input.front.moveFront(); 6978 } 6979 } 6980 6981 static if (hasAssignableElements!RangeType) 6982 { 6983 @property void front(ElementType val) 6984 { 6985 _input.front.front = val; 6986 } 6987 } 6988 6989 /// Ditto 6990 void popFront() 6991 { 6992 assert(!empty, "Attempting to popFront an empty FrontTransversal"); 6993 _input.popFront(); 6994 prime(); 6995 } 6996 6997 /** 6998 Duplicates this `frontTransversal`. Note that only the encapsulating 6999 range of range will be duplicated. Underlying ranges will not be 7000 duplicated. 7001 */ 7002 static if (isForwardRange!RangeOfRanges) 7003 { 7004 @property FrontTransversal save() 7005 { 7006 return FrontTransversal(_input.save); 7007 } 7008 } 7009 7010 static if (isBidirectionalRange!RangeOfRanges) 7011 { 7012 /** 7013 Bidirectional primitives. They are offered if $(D 7014 isBidirectionalRange!RangeOfRanges). 7015 */ 7016 @property auto ref back() 7017 { 7018 assert(!empty, "Attempting to fetch the back of an empty FrontTransversal"); 7019 return _input.back.front; 7020 } 7021 /// Ditto 7022 void popBack() 7023 { 7024 assert(!empty, "Attempting to popBack an empty FrontTransversal"); 7025 _input.popBack(); 7026 prime(); 7027 } 7028 7029 /// Ditto 7030 static if (hasMobileElements!RangeType) 7031 { 7032 ElementType moveBack() 7033 { 7034 return _input.back.moveFront(); 7035 } 7036 } 7037 7038 static if (hasAssignableElements!RangeType) 7039 { 7040 @property void back(ElementType val) 7041 { 7042 _input.back.front = val; 7043 } 7044 } 7045 } 7046 7047 static if (isRandomAccessRange!RangeOfRanges && 7048 (opt == TransverseOptions.assumeNotJagged || 7049 opt == TransverseOptions.enforceNotJagged)) 7050 { 7051 /** 7052 Random-access primitive. It is offered if $(D 7053 isRandomAccessRange!RangeOfRanges && (opt == 7054 TransverseOptions.assumeNotJagged || opt == 7055 TransverseOptions.enforceNotJagged)). 7056 */ 7057 auto ref opIndex(size_t n) 7058 { 7059 return _input[n].front; 7060 } 7061 7062 /// Ditto 7063 static if (hasMobileElements!RangeType) 7064 { 7065 ElementType moveAt(size_t n) 7066 { 7067 return _input[n].moveFront(); 7068 } 7069 } 7070 /// Ditto 7071 static if (hasAssignableElements!RangeType) 7072 { 7073 void opIndexAssign(ElementType val, size_t n) 7074 { 7075 _input[n].front = val; 7076 } 7077 } 7078 /// Ditto 7079 static if (hasLength!RangeOfRanges) 7080 { 7081 @property size_t length() 7082 { 7083 return _input.length; 7084 } 7085 7086 alias opDollar = length; 7087 } 7088 7089 /** 7090 Slicing if offered if `RangeOfRanges` supports slicing and all the 7091 conditions for supporting indexing are met. 7092 */ 7093 static if (hasSlicing!RangeOfRanges) 7094 { 7095 typeof(this) opSlice(size_t lower, size_t upper) 7096 { 7097 return typeof(this)(_input[lower .. upper]); 7098 } 7099 } 7100 } 7101 7102 auto opSlice() { return this; } 7103 7104 private: 7105 RangeOfRanges _input; 7106 } 7107 7108 /// Ditto 7109 FrontTransversal!(RangeOfRanges, opt) frontTransversal( 7110 TransverseOptions opt = TransverseOptions.assumeJagged, 7111 RangeOfRanges) 7112 (RangeOfRanges rr) 7113 { 7114 return typeof(return)(rr); 7115 } 7116 7117 /// 7118 pure @safe nothrow unittest 7119 { 7120 import std.algorithm.comparison : equal; 7121 int[][] x = new int[][2]; 7122 x[0] = [1, 2]; 7123 x[1] = [3, 4]; 7124 auto ror = frontTransversal(x); 7125 assert(equal(ror, [ 1, 3 ][])); 7126 } 7127 7128 @safe unittest 7129 { 7130 import std.algorithm.comparison : equal; 7131 import std.internal.test.dummyrange : AllDummyRanges, DummyRange, ReturnBy; 7132 7133 static assert(is(FrontTransversal!(immutable int[][]))); 7134 7135 foreach (DummyType; AllDummyRanges) 7136 { 7137 auto dummies = 7138 [DummyType.init, DummyType.init, DummyType.init, DummyType.init]; 7139 7140 foreach (i, ref elem; dummies) 7141 { 7142 // Just violate the DummyRange abstraction to get what I want. 7143 elem.arr = elem.arr[i..$ - (3 - i)]; 7144 } 7145 7146 auto ft = frontTransversal!(TransverseOptions.assumeNotJagged)(dummies); 7147 static if (isForwardRange!DummyType) 7148 { 7149 static assert(isForwardRange!(typeof(ft))); 7150 } 7151 7152 assert(equal(ft, [1, 2, 3, 4])); 7153 7154 // Test slicing. 7155 assert(equal(ft[0 .. 2], [1, 2])); 7156 assert(equal(ft[1 .. 3], [2, 3])); 7157 7158 assert(ft.front == ft.moveFront()); 7159 assert(ft.back == ft.moveBack()); 7160 assert(ft.moveAt(1) == ft[1]); 7161 7162 7163 // Test infiniteness propagation. 7164 static assert(isInfinite!(typeof(frontTransversal(repeat("foo"))))); 7165 7166 static if (DummyType.r == ReturnBy.Reference) 7167 { 7168 { 7169 ft.front++; 7170 scope(exit) ft.front--; 7171 assert(dummies.front.front == 2); 7172 } 7173 7174 { 7175 ft.front = 5; 7176 scope(exit) ft.front = 1; 7177 assert(dummies[0].front == 5); 7178 } 7179 7180 { 7181 ft.back = 88; 7182 scope(exit) ft.back = 4; 7183 assert(dummies.back.front == 88); 7184 } 7185 7186 { 7187 ft[1] = 99; 7188 scope(exit) ft[1] = 2; 7189 assert(dummies[1].front == 99); 7190 } 7191 } 7192 } 7193 } 7194 7195 // https://issues.dlang.org/show_bug.cgi?id=16363 7196 pure @safe nothrow unittest 7197 { 7198 import std.algorithm.comparison : equal; 7199 7200 int[][] darr = [[0, 1], [4, 5]]; 7201 auto ft = frontTransversal!(TransverseOptions.assumeNotJagged)(darr); 7202 7203 assert(equal(ft, [0, 4])); 7204 static assert(isRandomAccessRange!(typeof(ft))); 7205 } 7206 7207 // https://issues.dlang.org/show_bug.cgi?id=16442 7208 pure @safe nothrow unittest 7209 { 7210 int[][] arr = [[], []]; 7211 7212 auto ft = frontTransversal!(TransverseOptions.assumeNotJagged)(arr); 7213 assert(ft.empty); 7214 } 7215 7216 // ditto 7217 pure @safe unittest 7218 { 7219 int[][] arr = [[], []]; 7220 7221 auto ft = frontTransversal!(TransverseOptions.enforceNotJagged)(arr); 7222 assert(ft.empty); 7223 } 7224 7225 /** 7226 Given a range of ranges, iterate transversally through the 7227 `n`th element of each of the enclosed ranges. This function 7228 is similar to `unzip` in other languages. 7229 7230 Params: 7231 opt = Controls the assumptions the function makes about the lengths 7232 of the ranges 7233 rr = An input range of random access ranges 7234 Returns: 7235 At minimum, an input range. Range primitives such as bidirectionality 7236 and random access are given if the element type of `rr` provides them. 7237 */ 7238 struct Transversal(Ror, 7239 TransverseOptions opt = TransverseOptions.assumeJagged) 7240 { 7241 private alias RangeOfRanges = Unqual!Ror; 7242 private alias InnerRange = ElementType!RangeOfRanges; 7243 private alias E = ElementType!InnerRange; 7244 7245 private void prime() 7246 { 7247 static if (opt == TransverseOptions.assumeJagged) 7248 { 7249 while (!_input.empty && _input.front.length <= _n) 7250 { 7251 _input.popFront(); 7252 } 7253 static if (isBidirectionalRange!RangeOfRanges) 7254 { 7255 while (!_input.empty && _input.back.length <= _n) 7256 { 7257 _input.popBack(); 7258 } 7259 } 7260 } 7261 } 7262 7263 /** 7264 Construction from an input and an index. 7265 */ 7266 this(RangeOfRanges input, size_t n) 7267 { 7268 _input = input; 7269 _n = n; 7270 prime(); 7271 static if (opt == TransverseOptions.enforceNotJagged) 7272 { 7273 import std.exception : enforce; 7274 7275 if (empty) return; 7276 immutable commonLength = _input.front.length; 7277 foreach (e; _input) 7278 { 7279 enforce(e.length == commonLength); 7280 } 7281 } 7282 } 7283 7284 /** 7285 Forward range primitives. 7286 */ 7287 static if (isInfinite!(RangeOfRanges)) 7288 { 7289 enum bool empty = false; 7290 } 7291 else 7292 { 7293 @property bool empty() 7294 { 7295 return _input.empty; 7296 } 7297 } 7298 7299 /// Ditto 7300 @property auto ref front() 7301 { 7302 assert(!empty, "Attempting to fetch the front of an empty Transversal"); 7303 return _input.front[_n]; 7304 } 7305 7306 /// Ditto 7307 static if (hasMobileElements!InnerRange) 7308 { 7309 E moveFront() 7310 { 7311 return _input.front.moveAt(_n); 7312 } 7313 } 7314 7315 /// Ditto 7316 static if (hasAssignableElements!InnerRange) 7317 { 7318 @property void front(E val) 7319 { 7320 _input.front[_n] = val; 7321 } 7322 } 7323 7324 7325 /// Ditto 7326 void popFront() 7327 { 7328 assert(!empty, "Attempting to popFront an empty Transversal"); 7329 _input.popFront(); 7330 prime(); 7331 } 7332 7333 /// Ditto 7334 static if (isForwardRange!RangeOfRanges) 7335 { 7336 @property typeof(this) save() 7337 { 7338 auto ret = this; 7339 ret._input = _input.save; 7340 return ret; 7341 } 7342 } 7343 7344 static if (isBidirectionalRange!RangeOfRanges) 7345 { 7346 /** 7347 Bidirectional primitives. They are offered if $(D 7348 isBidirectionalRange!RangeOfRanges). 7349 */ 7350 @property auto ref back() 7351 { 7352 assert(!empty, "Attempting to fetch the back of an empty Transversal"); 7353 return _input.back[_n]; 7354 } 7355 7356 /// Ditto 7357 void popBack() 7358 { 7359 assert(!empty, "Attempting to popBack an empty Transversal"); 7360 _input.popBack(); 7361 prime(); 7362 } 7363 7364 /// Ditto 7365 static if (hasMobileElements!InnerRange) 7366 { 7367 E moveBack() 7368 { 7369 return _input.back.moveAt(_n); 7370 } 7371 } 7372 7373 /// Ditto 7374 static if (hasAssignableElements!InnerRange) 7375 { 7376 @property void back(E val) 7377 { 7378 _input.back[_n] = val; 7379 } 7380 } 7381 7382 } 7383 7384 static if (isRandomAccessRange!RangeOfRanges && 7385 (opt == TransverseOptions.assumeNotJagged || 7386 opt == TransverseOptions.enforceNotJagged)) 7387 { 7388 /** 7389 Random-access primitive. It is offered if $(D 7390 isRandomAccessRange!RangeOfRanges && (opt == 7391 TransverseOptions.assumeNotJagged || opt == 7392 TransverseOptions.enforceNotJagged)). 7393 */ 7394 auto ref opIndex(size_t n) 7395 { 7396 return _input[n][_n]; 7397 } 7398 7399 /// Ditto 7400 static if (hasMobileElements!InnerRange) 7401 { 7402 E moveAt(size_t n) 7403 { 7404 return _input[n].moveAt(_n); 7405 } 7406 } 7407 7408 /// Ditto 7409 static if (hasAssignableElements!InnerRange) 7410 { 7411 void opIndexAssign(E val, size_t n) 7412 { 7413 _input[n][_n] = val; 7414 } 7415 } 7416 7417 /// Ditto 7418 static if (hasLength!RangeOfRanges) 7419 { 7420 @property size_t length() 7421 { 7422 return _input.length; 7423 } 7424 7425 alias opDollar = length; 7426 } 7427 7428 /** 7429 Slicing if offered if `RangeOfRanges` supports slicing and all the 7430 conditions for supporting indexing are met. 7431 */ 7432 static if (hasSlicing!RangeOfRanges) 7433 { 7434 typeof(this) opSlice(size_t lower, size_t upper) 7435 { 7436 return typeof(this)(_input[lower .. upper], _n); 7437 } 7438 } 7439 } 7440 7441 auto opSlice() { return this; } 7442 7443 private: 7444 RangeOfRanges _input; 7445 size_t _n; 7446 } 7447 7448 /// Ditto 7449 Transversal!(RangeOfRanges, opt) transversal 7450 (TransverseOptions opt = TransverseOptions.assumeJagged, RangeOfRanges) 7451 (RangeOfRanges rr, size_t n) 7452 { 7453 return typeof(return)(rr, n); 7454 } 7455 7456 /// 7457 @safe unittest 7458 { 7459 import std.algorithm.comparison : equal; 7460 int[][] x = new int[][2]; 7461 x[0] = [1, 2]; 7462 x[1] = [3, 4]; 7463 auto ror = transversal(x, 1); 7464 assert(equal(ror, [ 2, 4 ])); 7465 } 7466 7467 /// The following code does a full unzip 7468 @safe unittest 7469 { 7470 import std.algorithm.comparison : equal; 7471 import std.algorithm.iteration : map; 7472 int[][] y = [[1, 2, 3], [4, 5, 6]]; 7473 auto z = y.front.walkLength.iota.map!(i => transversal(y, i)); 7474 assert(equal!equal(z, [[1, 4], [2, 5], [3, 6]])); 7475 } 7476 7477 @safe unittest 7478 { 7479 import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy; 7480 7481 int[][] x = new int[][2]; 7482 x[0] = [ 1, 2 ]; 7483 x[1] = [3, 4]; 7484 auto ror = transversal!(TransverseOptions.assumeNotJagged)(x, 1); 7485 auto witness = [ 2, 4 ]; 7486 uint i; 7487 foreach (e; ror) assert(e == witness[i++]); 7488 assert(i == 2); 7489 assert(ror.length == 2); 7490 7491 static assert(is(Transversal!(immutable int[][]))); 7492 7493 // Make sure ref, assign is being propagated. 7494 { 7495 ror.front++; 7496 scope(exit) ror.front--; 7497 assert(x[0][1] == 3); 7498 } 7499 { 7500 ror.front = 5; 7501 scope(exit) ror.front = 2; 7502 assert(x[0][1] == 5); 7503 assert(ror.moveFront() == 5); 7504 } 7505 { 7506 ror.back = 999; 7507 scope(exit) ror.back = 4; 7508 assert(x[1][1] == 999); 7509 assert(ror.moveBack() == 999); 7510 } 7511 { 7512 ror[0] = 999; 7513 scope(exit) ror[0] = 2; 7514 assert(x[0][1] == 999); 7515 assert(ror.moveAt(0) == 999); 7516 } 7517 7518 // Test w/o ref return. 7519 alias D = DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random); 7520 auto drs = [D.init, D.init]; 7521 foreach (num; 0 .. 10) 7522 { 7523 auto t = transversal!(TransverseOptions.enforceNotJagged)(drs, num); 7524 assert(t[0] == t[1]); 7525 assert(t[1] == num + 1); 7526 } 7527 7528 static assert(isInfinite!(typeof(transversal(repeat([1,2,3]), 1)))); 7529 7530 // Test slicing. 7531 auto mat = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]; 7532 auto mat1 = transversal!(TransverseOptions.assumeNotJagged)(mat, 1)[1 .. 3]; 7533 assert(mat1[0] == 6); 7534 assert(mat1[1] == 10); 7535 } 7536 7537 struct Transposed(RangeOfRanges, 7538 TransverseOptions opt = TransverseOptions.assumeJagged) 7539 if (isForwardRange!RangeOfRanges && 7540 isInputRange!(ElementType!RangeOfRanges) && 7541 hasAssignableElements!RangeOfRanges) 7542 { 7543 this(RangeOfRanges input) 7544 { 7545 this._input = input; 7546 static if (opt == TransverseOptions.enforceNotJagged) 7547 { 7548 import std.exception : enforce; 7549 7550 if (empty) return; 7551 immutable commonLength = _input.front.length; 7552 foreach (e; _input) 7553 { 7554 enforce(e.length == commonLength); 7555 } 7556 } 7557 } 7558 7559 @property auto front() 7560 { 7561 import std.algorithm.iteration : filter, map; 7562 return _input.save 7563 .filter!(a => !a.empty) 7564 .map!(a => a.front); 7565 } 7566 7567 void popFront() 7568 { 7569 // Advance the position of each subrange. 7570 auto r = _input.save; 7571 while (!r.empty) 7572 { 7573 auto e = r.front; 7574 if (!e.empty) 7575 { 7576 e.popFront(); 7577 r.front = e; 7578 } 7579 7580 r.popFront(); 7581 } 7582 } 7583 7584 static if (isRandomAccessRange!(ElementType!RangeOfRanges)) 7585 { 7586 auto ref opIndex(size_t n) 7587 { 7588 return transversal!opt(_input, n); 7589 } 7590 } 7591 7592 @property bool empty() 7593 { 7594 if (_input.empty) return true; 7595 foreach (e; _input.save) 7596 { 7597 if (!e.empty) return false; 7598 } 7599 return true; 7600 } 7601 7602 deprecated("This function is incorrect and will be removed November 2018. See the docs for more details.") 7603 @property Transposed save() 7604 { 7605 return Transposed(_input.save); 7606 } 7607 7608 auto opSlice() { return this; } 7609 7610 private: 7611 RangeOfRanges _input; 7612 } 7613 7614 @safe unittest 7615 { 7616 // Boundary case: transpose of empty range should be empty 7617 int[][] ror = []; 7618 assert(transposed(ror).empty); 7619 } 7620 7621 // https://issues.dlang.org/show_bug.cgi?id=9507 7622 @safe unittest 7623 { 7624 import std.algorithm.comparison : equal; 7625 7626 auto r = [[1,2], [3], [4,5], [], [6]]; 7627 assert(r.transposed.equal!equal([ 7628 [1, 3, 4, 6], 7629 [2, 5] 7630 ])); 7631 } 7632 7633 // https://issues.dlang.org/show_bug.cgi?id=17742 7634 @safe unittest 7635 { 7636 import std.algorithm.iteration : map; 7637 import std.algorithm.comparison : equal; 7638 auto ror = 5.iota.map!(y => 5.iota.map!(x => x * y).array).array; 7639 assert(ror[3][2] == 6); 7640 auto result = transposed!(TransverseOptions.assumeNotJagged)(ror); 7641 assert(result[2][3] == 6); 7642 7643 auto x = [[1,2,3],[4,5,6]]; 7644 auto y = transposed!(TransverseOptions.assumeNotJagged)(x); 7645 assert(y.front.equal([1,4])); 7646 assert(y[0].equal([1,4])); 7647 assert(y[0][0] == 1); 7648 assert(y[1].equal([2,5])); 7649 assert(y[1][1] == 5); 7650 7651 auto yy = transposed!(TransverseOptions.enforceNotJagged)(x); 7652 assert(yy.front.equal([1,4])); 7653 assert(yy[0].equal([1,4])); 7654 assert(yy[0][0] == 1); 7655 assert(yy[1].equal([2,5])); 7656 assert(yy[1][1] == 5); 7657 7658 auto z = x.transposed; // assumeJagged 7659 assert(z.front.equal([1,4])); 7660 assert(z[0].equal([1,4])); 7661 assert(!is(typeof(z[0][0]))); 7662 } 7663 7664 @safe unittest 7665 { 7666 import std.exception : assertThrown; 7667 7668 auto r = [[1,2], [3], [4,5], [], [6]]; 7669 assertThrown(r.transposed!(TransverseOptions.enforceNotJagged)); 7670 } 7671 7672 /** 7673 Given a range of ranges, returns a range of ranges where the $(I i)'th subrange 7674 contains the $(I i)'th elements of the original subranges. 7675 7676 $(RED `Transposed` currently defines `save`, but does not work as a forward range. 7677 Consuming a copy made with `save` will consume all copies, even the original sub-ranges 7678 fed into `Transposed`.) 7679 7680 Params: 7681 opt = Controls the assumptions the function makes about the lengths of the ranges (i.e. jagged or not) 7682 rr = Range of ranges 7683 */ 7684 Transposed!(RangeOfRanges, opt) transposed 7685 (TransverseOptions opt = TransverseOptions.assumeJagged, RangeOfRanges) 7686 (RangeOfRanges rr) 7687 if (isForwardRange!RangeOfRanges && 7688 isInputRange!(ElementType!RangeOfRanges) && 7689 hasAssignableElements!RangeOfRanges) 7690 { 7691 return Transposed!(RangeOfRanges, opt)(rr); 7692 } 7693 7694 /// 7695 @safe unittest 7696 { 7697 import std.algorithm.comparison : equal; 7698 int[][] ror = [ 7699 [1, 2, 3], 7700 [4, 5, 6] 7701 ]; 7702 auto xp = transposed(ror); 7703 assert(equal!"a.equal(b)"(xp, [ 7704 [1, 4], 7705 [2, 5], 7706 [3, 6] 7707 ])); 7708 } 7709 7710 /// 7711 @safe unittest 7712 { 7713 int[][] x = new int[][2]; 7714 x[0] = [1, 2]; 7715 x[1] = [3, 4]; 7716 auto tr = transposed(x); 7717 int[][] witness = [ [ 1, 3 ], [ 2, 4 ] ]; 7718 uint i; 7719 7720 foreach (e; tr) 7721 { 7722 assert(array(e) == witness[i++]); 7723 } 7724 } 7725 7726 // https://issues.dlang.org/show_bug.cgi?id=8764 7727 @safe unittest 7728 { 7729 import std.algorithm.comparison : equal; 7730 ulong[1] t0 = [ 123 ]; 7731 7732 assert(!hasAssignableElements!(typeof(t0[].chunks(1)))); 7733 assert(!is(typeof(transposed(t0[].chunks(1))))); 7734 assert(is(typeof(transposed(t0[].chunks(1).array())))); 7735 7736 auto t1 = transposed(t0[].chunks(1).array()); 7737 assert(equal!"a.equal(b)"(t1, [[123]])); 7738 } 7739 7740 /** 7741 This struct takes two ranges, `source` and `indices`, and creates a view 7742 of `source` as if its elements were reordered according to `indices`. 7743 `indices` may include only a subset of the elements of `source` and 7744 may also repeat elements. 7745 7746 `Source` must be a random access range. The returned range will be 7747 bidirectional or random-access if `Indices` is bidirectional or 7748 random-access, respectively. 7749 */ 7750 struct Indexed(Source, Indices) 7751 if (isRandomAccessRange!Source && isInputRange!Indices && 7752 is(typeof(Source.init[ElementType!(Indices).init]))) 7753 { 7754 this(Source source, Indices indices) 7755 { 7756 this._source = source; 7757 this._indices = indices; 7758 } 7759 7760 /// Range primitives 7761 @property auto ref front() 7762 { 7763 assert(!empty, "Attempting to fetch the front of an empty Indexed"); 7764 return _source[_indices.front]; 7765 } 7766 7767 /// Ditto 7768 void popFront() 7769 { 7770 assert(!empty, "Attempting to popFront an empty Indexed"); 7771 _indices.popFront(); 7772 } 7773 7774 static if (isInfinite!Indices) 7775 { 7776 enum bool empty = false; 7777 } 7778 else 7779 { 7780 /// Ditto 7781 @property bool empty() 7782 { 7783 return _indices.empty; 7784 } 7785 } 7786 7787 static if (isForwardRange!Indices) 7788 { 7789 /// Ditto 7790 @property typeof(this) save() 7791 { 7792 // Don't need to save _source because it's never consumed. 7793 return typeof(this)(_source, _indices.save); 7794 } 7795 } 7796 7797 /// Ditto 7798 static if (hasAssignableElements!Source) 7799 { 7800 @property auto ref front(ElementType!Source newVal) 7801 { 7802 assert(!empty); 7803 return _source[_indices.front] = newVal; 7804 } 7805 } 7806 7807 7808 static if (hasMobileElements!Source) 7809 { 7810 /// Ditto 7811 auto moveFront() 7812 { 7813 assert(!empty); 7814 return _source.moveAt(_indices.front); 7815 } 7816 } 7817 7818 static if (isBidirectionalRange!Indices) 7819 { 7820 /// Ditto 7821 @property auto ref back() 7822 { 7823 assert(!empty, "Attempting to fetch the back of an empty Indexed"); 7824 return _source[_indices.back]; 7825 } 7826 7827 /// Ditto 7828 void popBack() 7829 { 7830 assert(!empty, "Attempting to popBack an empty Indexed"); 7831 _indices.popBack(); 7832 } 7833 7834 /// Ditto 7835 static if (hasAssignableElements!Source) 7836 { 7837 @property auto ref back(ElementType!Source newVal) 7838 { 7839 assert(!empty); 7840 return _source[_indices.back] = newVal; 7841 } 7842 } 7843 7844 7845 static if (hasMobileElements!Source) 7846 { 7847 /// Ditto 7848 auto moveBack() 7849 { 7850 assert(!empty); 7851 return _source.moveAt(_indices.back); 7852 } 7853 } 7854 } 7855 7856 static if (hasLength!Indices) 7857 { 7858 /// Ditto 7859 @property size_t length() 7860 { 7861 return _indices.length; 7862 } 7863 7864 alias opDollar = length; 7865 } 7866 7867 static if (isRandomAccessRange!Indices) 7868 { 7869 /// Ditto 7870 auto ref opIndex(size_t index) 7871 { 7872 return _source[_indices[index]]; 7873 } 7874 7875 static if (hasSlicing!Indices) 7876 { 7877 /// Ditto 7878 typeof(this) opSlice(size_t a, size_t b) 7879 { 7880 return typeof(this)(_source, _indices[a .. b]); 7881 } 7882 } 7883 7884 7885 static if (hasAssignableElements!Source) 7886 { 7887 /// Ditto 7888 auto opIndexAssign(ElementType!Source newVal, size_t index) 7889 { 7890 return _source[_indices[index]] = newVal; 7891 } 7892 } 7893 7894 7895 static if (hasMobileElements!Source) 7896 { 7897 /// Ditto 7898 auto moveAt(size_t index) 7899 { 7900 return _source.moveAt(_indices[index]); 7901 } 7902 } 7903 } 7904 7905 // All this stuff is useful if someone wants to index an Indexed 7906 // without adding a layer of indirection. 7907 7908 /** 7909 Returns the source range. 7910 */ 7911 @property Source source() 7912 { 7913 return _source; 7914 } 7915 7916 /** 7917 Returns the indices range. 7918 */ 7919 @property Indices indices() 7920 { 7921 return _indices; 7922 } 7923 7924 static if (isRandomAccessRange!Indices) 7925 { 7926 /** 7927 Returns the physical index into the source range corresponding to a 7928 given logical index. This is useful, for example, when indexing 7929 an `Indexed` without adding another layer of indirection. 7930 */ 7931 size_t physicalIndex(size_t logicalIndex) 7932 { 7933 return _indices[logicalIndex]; 7934 } 7935 7936 /// 7937 @safe unittest 7938 { 7939 auto ind = indexed([1, 2, 3, 4, 5], [1, 3, 4]); 7940 assert(ind.physicalIndex(0) == 1); 7941 } 7942 } 7943 7944 private: 7945 Source _source; 7946 Indices _indices; 7947 7948 } 7949 7950 /// Ditto 7951 Indexed!(Source, Indices) indexed(Source, Indices)(Source source, Indices indices) 7952 { 7953 return typeof(return)(source, indices); 7954 } 7955 7956 /// 7957 @safe unittest 7958 { 7959 import std.algorithm.comparison : equal; 7960 auto source = [1, 2, 3, 4, 5]; 7961 auto indices = [4, 3, 1, 2, 0, 4]; 7962 auto ind = indexed(source, indices); 7963 assert(equal(ind, [5, 4, 2, 3, 1, 5])); 7964 assert(equal(retro(ind), [5, 1, 3, 2, 4, 5])); 7965 } 7966 7967 @safe unittest 7968 { 7969 { 7970 auto ind = indexed([1, 2, 3, 4, 5], [1, 3, 4]); 7971 assert(ind.physicalIndex(0) == 1); 7972 } 7973 7974 auto source = [1, 2, 3, 4, 5]; 7975 auto indices = [4, 3, 1, 2, 0, 4]; 7976 auto ind = indexed(source, indices); 7977 7978 // When elements of indices are duplicated and Source has lvalue elements, 7979 // these are aliased in ind. 7980 ind[0]++; 7981 assert(ind[0] == 6); 7982 assert(ind[5] == 6); 7983 } 7984 7985 @safe unittest 7986 { 7987 import std.internal.test.dummyrange : AllDummyRanges, propagatesLength, 7988 propagatesRangeType, RangeType; 7989 7990 foreach (DummyType; AllDummyRanges) 7991 { 7992 auto d = DummyType.init; 7993 auto r = indexed([1, 2, 3, 4, 5], d); 7994 static assert(propagatesRangeType!(DummyType, typeof(r))); 7995 static assert(propagatesLength!(DummyType, typeof(r))); 7996 } 7997 } 7998 7999 /** 8000 This range iterates over fixed-sized chunks of size `chunkSize` of a 8001 `source` range. `Source` must be an $(REF_ALTTEXT input range, isInputRange, std,range,primitives). 8002 `chunkSize` must be greater than zero. 8003 8004 If `!isInfinite!Source` and `source.walkLength` is not evenly 8005 divisible by `chunkSize`, the back element of this range will contain 8006 fewer than `chunkSize` elements. 8007 8008 If `Source` is a forward range, the resulting range will be forward ranges as 8009 well. Otherwise, the resulting chunks will be input ranges consuming the same 8010 input: iterating over `front` will shrink the chunk such that subsequent 8011 invocations of `front` will no longer return the full chunk, and calling 8012 `popFront` on the outer range will invalidate any lingering references to 8013 previous values of `front`. 8014 8015 Params: 8016 source = Range from which the chunks will be selected 8017 chunkSize = Chunk size 8018 8019 See_Also: $(LREF slide) 8020 8021 Returns: Range of chunks. 8022 */ 8023 struct Chunks(Source) 8024 if (isInputRange!Source) 8025 { 8026 static if (isForwardRange!Source) 8027 { 8028 /// Standard constructor 8029 this(Source source, size_t chunkSize) 8030 { 8031 assert(chunkSize != 0, "Cannot create a Chunk with an empty chunkSize"); 8032 _source = source; 8033 _chunkSize = chunkSize; 8034 } 8035 8036 /// Input range primitives. Always present. 8037 @property auto front() 8038 { 8039 assert(!empty, "Attempting to fetch the front of an empty Chunks"); 8040 return _source.save.take(_chunkSize); 8041 } 8042 8043 /// Ditto 8044 void popFront() 8045 { 8046 assert(!empty, "Attempting to popFront and empty Chunks"); 8047 _source.popFrontN(_chunkSize); 8048 } 8049 8050 static if (!isInfinite!Source) 8051 /// Ditto 8052 @property bool empty() 8053 { 8054 return _source.empty; 8055 } 8056 else 8057 // undocumented 8058 enum empty = false; 8059 8060 /// Forward range primitives. Only present if `Source` is a forward range. 8061 @property typeof(this) save() 8062 { 8063 return typeof(this)(_source.save, _chunkSize); 8064 } 8065 8066 static if (hasLength!Source) 8067 { 8068 /// Length. Only if `hasLength!Source` is `true` 8069 @property size_t length() 8070 { 8071 // Note: _source.length + _chunkSize may actually overflow. 8072 // We cast to ulong to mitigate the problem on x86 machines. 8073 // For x64 machines, we just suppose we'll never overflow. 8074 // The "safe" code would require either an extra branch, or a 8075 // modulo operation, which is too expensive for such a rare case 8076 return cast(size_t)((cast(ulong)(_source.length) + _chunkSize - 1) / _chunkSize); 8077 } 8078 //Note: No point in defining opDollar here without slicing. 8079 //opDollar is defined below in the hasSlicing!Source section 8080 } 8081 8082 static if (hasSlicing!Source) 8083 { 8084 //Used for various purposes 8085 private enum hasSliceToEnd = is(typeof(Source.init[_chunkSize .. $]) == Source); 8086 8087 /** 8088 Indexing and slicing operations. Provided only if 8089 `hasSlicing!Source` is `true`. 8090 */ 8091 auto opIndex(size_t index) 8092 { 8093 immutable start = index * _chunkSize; 8094 immutable end = start + _chunkSize; 8095 8096 static if (isInfinite!Source) 8097 return _source[start .. end]; 8098 else 8099 { 8100 import std.algorithm.comparison : min; 8101 immutable len = _source.length; 8102 assert(start < len, "chunks index out of bounds"); 8103 return _source[start .. min(end, len)]; 8104 } 8105 } 8106 8107 /// Ditto 8108 static if (hasLength!Source) 8109 typeof(this) opSlice(size_t lower, size_t upper) 8110 { 8111 import std.algorithm.comparison : min; 8112 assert(lower <= upper && upper <= length, "chunks slicing index out of bounds"); 8113 immutable len = _source.length; 8114 return chunks(_source[min(lower * _chunkSize, len) .. min(upper * _chunkSize, len)], _chunkSize); 8115 } 8116 else static if (hasSliceToEnd) 8117 //For slicing an infinite chunk, we need to slice the source to the end. 8118 typeof(takeExactly(this, 0)) opSlice(size_t lower, size_t upper) 8119 { 8120 assert(lower <= upper, "chunks slicing index out of bounds"); 8121 return chunks(_source[lower * _chunkSize .. $], _chunkSize).takeExactly(upper - lower); 8122 } 8123 8124 static if (isInfinite!Source) 8125 { 8126 static if (hasSliceToEnd) 8127 { 8128 private static struct DollarToken{} 8129 DollarToken opDollar() 8130 { 8131 return DollarToken(); 8132 } 8133 //Slice to dollar 8134 typeof(this) opSlice(size_t lower, DollarToken) 8135 { 8136 return typeof(this)(_source[lower * _chunkSize .. $], _chunkSize); 8137 } 8138 } 8139 } 8140 else 8141 { 8142 //Dollar token carries a static type, with no extra information. 8143 //It can lazily transform into _source.length on algorithmic 8144 //operations such as : chunks[$/2, $-1]; 8145 private static struct DollarToken 8146 { 8147 Chunks!Source* mom; 8148 @property size_t momLength() 8149 { 8150 return mom.length; 8151 } 8152 alias momLength this; 8153 } 8154 DollarToken opDollar() 8155 { 8156 return DollarToken(&this); 8157 } 8158 8159 //Slice overloads optimized for using dollar. Without this, to slice to end, we would... 8160 //1. Evaluate chunks.length 8161 //2. Multiply by _chunksSize 8162 //3. To finally just compare it (with min) to the original length of source (!) 8163 //These overloads avoid that. 8164 typeof(this) opSlice(DollarToken, DollarToken) 8165 { 8166 static if (hasSliceToEnd) 8167 return chunks(_source[$ .. $], _chunkSize); 8168 else 8169 { 8170 immutable len = _source.length; 8171 return chunks(_source[len .. len], _chunkSize); 8172 } 8173 } 8174 typeof(this) opSlice(size_t lower, DollarToken) 8175 { 8176 import std.algorithm.comparison : min; 8177 assert(lower <= length, "chunks slicing index out of bounds"); 8178 static if (hasSliceToEnd) 8179 return chunks(_source[min(lower * _chunkSize, _source.length) .. $], _chunkSize); 8180 else 8181 { 8182 immutable len = _source.length; 8183 return chunks(_source[min(lower * _chunkSize, len) .. len], _chunkSize); 8184 } 8185 } 8186 typeof(this) opSlice(DollarToken, size_t upper) 8187 { 8188 assert(upper == length, "chunks slicing index out of bounds"); 8189 return this[$ .. $]; 8190 } 8191 } 8192 } 8193 8194 //Bidirectional range primitives 8195 static if (hasSlicing!Source && hasLength!Source) 8196 { 8197 /** 8198 Bidirectional range primitives. Provided only if both 8199 `hasSlicing!Source` and `hasLength!Source` are `true`. 8200 */ 8201 @property auto back() 8202 { 8203 assert(!empty, "back called on empty chunks"); 8204 immutable len = _source.length; 8205 immutable start = (len - 1) / _chunkSize * _chunkSize; 8206 return _source[start .. len]; 8207 } 8208 8209 /// Ditto 8210 void popBack() 8211 { 8212 assert(!empty, "popBack() called on empty chunks"); 8213 immutable end = (_source.length - 1) / _chunkSize * _chunkSize; 8214 _source = _source[0 .. end]; 8215 } 8216 } 8217 8218 private: 8219 Source _source; 8220 size_t _chunkSize; 8221 } 8222 else // is input range only 8223 { 8224 import std.typecons : RefCounted; 8225 8226 static struct Chunk 8227 { 8228 private RefCounted!Impl impl; 8229 8230 @property bool empty() { return impl.curSizeLeft == 0 || impl.r.empty; } 8231 @property auto front() { return impl.r.front; } 8232 void popFront() 8233 { 8234 assert(impl.curSizeLeft > 0 && !impl.r.empty); 8235 impl.curSizeLeft--; 8236 impl.r.popFront(); 8237 } 8238 } 8239 8240 static struct Impl 8241 { 8242 private Source r; 8243 private size_t chunkSize; 8244 private size_t curSizeLeft; 8245 } 8246 8247 private RefCounted!Impl impl; 8248 8249 private this(Source r, size_t chunkSize) 8250 { 8251 impl = RefCounted!Impl(r, r.empty ? 0 : chunkSize, chunkSize); 8252 } 8253 8254 @property bool empty() { return impl.chunkSize == 0; } 8255 @property Chunk front() return { return Chunk(impl); } 8256 8257 void popFront() 8258 { 8259 impl.curSizeLeft -= impl.r.popFrontN(impl.curSizeLeft); 8260 if (!impl.r.empty) 8261 impl.curSizeLeft = impl.chunkSize; 8262 else 8263 impl.chunkSize = 0; 8264 } 8265 8266 static assert(isInputRange!(typeof(this))); 8267 } 8268 } 8269 8270 /// Ditto 8271 Chunks!Source chunks(Source)(Source source, size_t chunkSize) 8272 if (isInputRange!Source) 8273 { 8274 return typeof(return)(source, chunkSize); 8275 } 8276 8277 /// 8278 @safe unittest 8279 { 8280 import std.algorithm.comparison : equal; 8281 auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 8282 auto chunks = chunks(source, 4); 8283 assert(chunks[0] == [1, 2, 3, 4]); 8284 assert(chunks[1] == [5, 6, 7, 8]); 8285 assert(chunks[2] == [9, 10]); 8286 assert(chunks.back == chunks[2]); 8287 assert(chunks.front == chunks[0]); 8288 assert(chunks.length == 3); 8289 assert(equal(retro(array(chunks)), array(retro(chunks)))); 8290 } 8291 8292 /// Non-forward input ranges are supported, but with limited semantics. 8293 @system /*@safe*/ unittest // FIXME: can't be @safe because RefCounted isn't. 8294 { 8295 import std.algorithm.comparison : equal; 8296 8297 int i; 8298 8299 // The generator doesn't save state, so it cannot be a forward range. 8300 auto inputRange = generate!(() => ++i).take(10); 8301 8302 // We can still process it in chunks, but it will be single-pass only. 8303 auto chunked = inputRange.chunks(2); 8304 8305 assert(chunked.front.equal([1, 2])); 8306 assert(chunked.front.empty); // Iterating the chunk has consumed it 8307 chunked.popFront; 8308 assert(chunked.front.equal([3, 4])); 8309 } 8310 8311 @system /*@safe*/ unittest 8312 { 8313 import std.algorithm.comparison : equal; 8314 import std.internal.test.dummyrange : ReferenceInputRange; 8315 8316 auto data = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; 8317 auto r = new ReferenceInputRange!int(data).chunks(3); 8318 assert(r.equal!equal([ 8319 [ 1, 2, 3 ], 8320 [ 4, 5, 6 ], 8321 [ 7, 8, 9 ], 8322 [ 10 ] 8323 ])); 8324 8325 auto data2 = [ 1, 2, 3, 4, 5, 6 ]; 8326 auto r2 = new ReferenceInputRange!int(data2).chunks(3); 8327 assert(r2.equal!equal([ 8328 [ 1, 2, 3 ], 8329 [ 4, 5, 6 ] 8330 ])); 8331 8332 auto data3 = [ 1, 2, 3, 4, 5 ]; 8333 auto r3 = new ReferenceInputRange!int(data3).chunks(2); 8334 assert(r3.front.equal([1, 2])); 8335 r3.popFront(); 8336 assert(!r3.empty); 8337 r3.popFront(); 8338 assert(r3.front.equal([5])); 8339 } 8340 8341 @safe unittest 8342 { 8343 auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 8344 auto chunks = chunks(source, 4); 8345 auto chunks2 = chunks.save; 8346 chunks.popFront(); 8347 assert(chunks[0] == [5, 6, 7, 8]); 8348 assert(chunks[1] == [9, 10]); 8349 chunks2.popBack(); 8350 assert(chunks2[1] == [5, 6, 7, 8]); 8351 assert(chunks2.length == 2); 8352 8353 static assert(isRandomAccessRange!(typeof(chunks))); 8354 } 8355 8356 @safe unittest 8357 { 8358 import std.algorithm.comparison : equal; 8359 8360 //Extra toying with slicing and indexing. 8361 auto chunks1 = [0, 0, 1, 1, 2, 2, 3, 3, 4].chunks(2); 8362 auto chunks2 = [0, 0, 1, 1, 2, 2, 3, 3, 4, 4].chunks(2); 8363 8364 assert(chunks1.length == 5); 8365 assert(chunks2.length == 5); 8366 assert(chunks1[4] == [4]); 8367 assert(chunks2[4] == [4, 4]); 8368 assert(chunks1.back == [4]); 8369 assert(chunks2.back == [4, 4]); 8370 8371 assert(chunks1[0 .. 1].equal([[0, 0]])); 8372 assert(chunks1[0 .. 2].equal([[0, 0], [1, 1]])); 8373 assert(chunks1[4 .. 5].equal([[4]])); 8374 assert(chunks2[4 .. 5].equal([[4, 4]])); 8375 8376 assert(chunks1[0 .. 0].equal((int[][]).init)); 8377 assert(chunks1[5 .. 5].equal((int[][]).init)); 8378 assert(chunks2[5 .. 5].equal((int[][]).init)); 8379 8380 //Fun with opDollar 8381 assert(chunks1[$ .. $].equal((int[][]).init)); //Quick 8382 assert(chunks2[$ .. $].equal((int[][]).init)); //Quick 8383 assert(chunks1[$ - 1 .. $].equal([[4]])); //Semiquick 8384 assert(chunks2[$ - 1 .. $].equal([[4, 4]])); //Semiquick 8385 assert(chunks1[$ .. 5].equal((int[][]).init)); //Semiquick 8386 assert(chunks2[$ .. 5].equal((int[][]).init)); //Semiquick 8387 8388 assert(chunks1[$ / 2 .. $ - 1].equal([[2, 2], [3, 3]])); //Slow 8389 } 8390 8391 @safe unittest 8392 { 8393 import std.algorithm.comparison : equal; 8394 import std.algorithm.iteration : filter; 8395 8396 //ForwardRange 8397 auto r = filter!"true"([1, 2, 3, 4, 5]).chunks(2); 8398 assert(equal!"equal(a, b)"(r, [[1, 2], [3, 4], [5]])); 8399 8400 //InfiniteRange w/o RA 8401 auto fibsByPairs = recurrence!"a[n-1] + a[n-2]"(1, 1).chunks(2); 8402 assert(equal!`equal(a, b)`(fibsByPairs.take(2), [[ 1, 1], [ 2, 3]])); 8403 8404 //InfiniteRange w/ RA and slicing 8405 auto odds = sequence!("a[0] + n * a[1]")(1, 2); 8406 auto oddsByPairs = odds.chunks(2); 8407 assert(equal!`equal(a, b)`(oddsByPairs.take(2), [[ 1, 3], [ 5, 7]])); 8408 8409 //Requires phobos#991 for Sequence to have slice to end 8410 static assert(hasSlicing!(typeof(odds))); 8411 assert(equal!`equal(a, b)`(oddsByPairs[3 .. 5], [[13, 15], [17, 19]])); 8412 assert(equal!`equal(a, b)`(oddsByPairs[3 .. $].take(2), [[13, 15], [17, 19]])); 8413 } 8414 8415 8416 8417 /** 8418 This range splits a `source` range into `chunkCount` chunks of 8419 approximately equal length. `Source` must be a forward range with 8420 known length. 8421 8422 Unlike $(LREF chunks), `evenChunks` takes a chunk count (not size). 8423 The returned range will contain zero or more $(D source.length / 8424 chunkCount + 1) elements followed by $(D source.length / chunkCount) 8425 elements. If $(D source.length < chunkCount), some chunks will be empty. 8426 8427 `chunkCount` must not be zero, unless `source` is also empty. 8428 */ 8429 struct EvenChunks(Source) 8430 if (isForwardRange!Source && hasLength!Source) 8431 { 8432 /// Standard constructor 8433 this(Source source, size_t chunkCount) 8434 { 8435 assert(chunkCount != 0 || source.empty, "Cannot create EvenChunks with a zero chunkCount"); 8436 _source = source; 8437 _chunkCount = chunkCount; 8438 } 8439 8440 /// Forward range primitives. Always present. 8441 @property auto front() 8442 { 8443 assert(!empty, "Attempting to fetch the front of an empty evenChunks"); 8444 return _source.save.take(_chunkPos(1)); 8445 } 8446 8447 /// Ditto 8448 void popFront() 8449 { 8450 assert(!empty, "Attempting to popFront an empty evenChunks"); 8451 _source.popFrontN(_chunkPos(1)); 8452 _chunkCount--; 8453 } 8454 8455 /// Ditto 8456 @property bool empty() 8457 { 8458 return _source.empty; 8459 } 8460 8461 /// Ditto 8462 @property typeof(this) save() 8463 { 8464 return typeof(this)(_source.save, _chunkCount); 8465 } 8466 8467 /// Length 8468 @property size_t length() const 8469 { 8470 return _chunkCount; 8471 } 8472 //Note: No point in defining opDollar here without slicing. 8473 //opDollar is defined below in the hasSlicing!Source section 8474 8475 static if (hasSlicing!Source) 8476 { 8477 /** 8478 Indexing, slicing and bidirectional operations and range primitives. 8479 Provided only if `hasSlicing!Source` is `true`. 8480 */ 8481 auto opIndex(size_t index) 8482 { 8483 assert(index < _chunkCount, "evenChunks index out of bounds"); 8484 return _source[_chunkPos(index) .. _chunkPos(index+1)]; 8485 } 8486 8487 /// Ditto 8488 typeof(this) opSlice(size_t lower, size_t upper) 8489 { 8490 assert(lower <= upper && upper <= length, "evenChunks slicing index out of bounds"); 8491 return evenChunks(_source[_chunkPos(lower) .. _chunkPos(upper)], upper - lower); 8492 } 8493 8494 /// Ditto 8495 @property auto back() 8496 { 8497 assert(!empty, "back called on empty evenChunks"); 8498 return _source[_chunkPos(_chunkCount - 1) .. _source.length]; 8499 } 8500 8501 /// Ditto 8502 void popBack() 8503 { 8504 assert(!empty, "popBack() called on empty evenChunks"); 8505 _source = _source[0 .. _chunkPos(_chunkCount - 1)]; 8506 _chunkCount--; 8507 } 8508 } 8509 8510 private: 8511 Source _source; 8512 size_t _chunkCount; 8513 8514 size_t _chunkPos(size_t i) 8515 { 8516 /* 8517 _chunkCount = 5, _source.length = 13: 8518 8519 chunk0 8520 | chunk3 8521 | | 8522 v v 8523 +-+-+-+-+-+ ^ 8524 |0|3|.| | | | 8525 +-+-+-+-+-+ | div 8526 |1|4|.| | | | 8527 +-+-+-+-+-+ v 8528 |2|5|.| 8529 +-+-+-+ 8530 8531 <-----> 8532 mod 8533 8534 <---------> 8535 _chunkCount 8536 8537 One column is one chunk. 8538 popFront and popBack pop the left-most 8539 and right-most column, respectively. 8540 */ 8541 8542 auto div = _source.length / _chunkCount; 8543 auto mod = _source.length % _chunkCount; 8544 auto pos = i <= mod 8545 ? i * (div+1) 8546 : mod * (div+1) + (i-mod) * div 8547 ; 8548 //auto len = i < mod 8549 // ? div+1 8550 // : div 8551 //; 8552 return pos; 8553 } 8554 } 8555 8556 /// Ditto 8557 EvenChunks!Source evenChunks(Source)(Source source, size_t chunkCount) 8558 if (isForwardRange!Source && hasLength!Source) 8559 { 8560 return typeof(return)(source, chunkCount); 8561 } 8562 8563 /// 8564 @safe unittest 8565 { 8566 import std.algorithm.comparison : equal; 8567 auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 8568 auto chunks = evenChunks(source, 3); 8569 assert(chunks[0] == [1, 2, 3, 4]); 8570 assert(chunks[1] == [5, 6, 7]); 8571 assert(chunks[2] == [8, 9, 10]); 8572 } 8573 8574 @safe unittest 8575 { 8576 import std.algorithm.comparison : equal; 8577 8578 auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 8579 auto chunks = evenChunks(source, 3); 8580 assert(chunks.back == chunks[2]); 8581 assert(chunks.front == chunks[0]); 8582 assert(chunks.length == 3); 8583 assert(equal(retro(array(chunks)), array(retro(chunks)))); 8584 8585 auto chunks2 = chunks.save; 8586 chunks.popFront(); 8587 assert(chunks[0] == [5, 6, 7]); 8588 assert(chunks[1] == [8, 9, 10]); 8589 chunks2.popBack(); 8590 assert(chunks2[1] == [5, 6, 7]); 8591 assert(chunks2.length == 2); 8592 8593 static assert(isRandomAccessRange!(typeof(chunks))); 8594 } 8595 8596 @safe unittest 8597 { 8598 import std.algorithm.comparison : equal; 8599 8600 int[] source = []; 8601 auto chunks = source.evenChunks(0); 8602 assert(chunks.length == 0); 8603 chunks = source.evenChunks(3); 8604 assert(equal(chunks, [[], [], []])); 8605 chunks = [1, 2, 3].evenChunks(5); 8606 assert(equal(chunks, [[1], [2], [3], [], []])); 8607 } 8608 8609 /** 8610 A fixed-sized sliding window iteration 8611 of size `windowSize` over a `source` range by a custom `stepSize`. 8612 8613 The `Source` range must be at least a $(REF_ALTTEXT ForwardRange, isForwardRange, std,range,primitives) 8614 and the `windowSize` must be greater than zero. 8615 8616 For `windowSize = 1` it splits the range into single element groups (aka `unflatten`) 8617 For `windowSize = 2` it is similar to `zip(source, source.save.dropOne)`. 8618 8619 Params: 8620 f = Whether the last element has fewer elements than `windowSize` 8621 it should be be ignored (`No.withPartial`) or added (`Yes.withPartial`) 8622 source = Range from which the slide will be selected 8623 windowSize = Sliding window size 8624 stepSize = Steps between the windows (by default 1) 8625 8626 Returns: Range of all sliding windows with propagated bi-directionality, 8627 forwarding, random access, and slicing. 8628 8629 Note: To avoid performance overhead, $(REF_ALTTEXT bi-directionality, isBidirectionalRange, std,range,primitives) 8630 is only available when $(REF hasSlicing, std,range,primitives) 8631 and $(REF hasLength, std,range,primitives) are true. 8632 8633 See_Also: $(LREF chunks) 8634 */ 8635 auto slide(Flag!"withPartial" f = Yes.withPartial, 8636 Source)(Source source, size_t windowSize, size_t stepSize = 1) 8637 if (isForwardRange!Source) 8638 { 8639 return Slides!(f, Source)(source, windowSize, stepSize); 8640 } 8641 8642 /// Iterate over ranges with windows 8643 @safe pure nothrow unittest 8644 { 8645 import std.algorithm.comparison : equal; 8646 8647 assert([0, 1, 2, 3].slide(2).equal!equal( 8648 [[0, 1], [1, 2], [2, 3]] 8649 )); 8650 8651 assert(5.iota.slide(3).equal!equal( 8652 [[0, 1, 2], [1, 2, 3], [2, 3, 4]] 8653 )); 8654 } 8655 8656 /// set a custom stepsize (default 1) 8657 @safe pure nothrow unittest 8658 { 8659 import std.algorithm.comparison : equal; 8660 8661 assert(6.iota.slide(1, 2).equal!equal( 8662 [[0], [2], [4]] 8663 )); 8664 8665 assert(6.iota.slide(2, 4).equal!equal( 8666 [[0, 1], [4, 5]] 8667 )); 8668 8669 assert(iota(7).slide(2, 2).equal!equal( 8670 [[0, 1], [2, 3], [4, 5], [6]] 8671 )); 8672 8673 assert(iota(12).slide(2, 4).equal!equal( 8674 [[0, 1], [4, 5], [8, 9]] 8675 )); 8676 } 8677 8678 /// Allow the last slide to have fewer elements than windowSize 8679 @safe pure nothrow unittest 8680 { 8681 import std.algorithm.comparison : equal; 8682 8683 assert(3.iota.slide!(No.withPartial)(4).empty); 8684 assert(3.iota.slide!(Yes.withPartial)(4).equal!equal( 8685 [[0, 1, 2]] 8686 )); 8687 } 8688 8689 /// Count all the possible substrings of length 2 8690 @safe pure nothrow unittest 8691 { 8692 import std.algorithm.iteration : each; 8693 8694 int[dstring] d; 8695 "AGAGA"d.slide!(Yes.withPartial)(2).each!(a => d[a]++); 8696 assert(d == ["AG"d: 2, "GA"d: 2]); 8697 } 8698 8699 /// withPartial only has an effect if last element in the range doesn't have the full size 8700 @safe pure nothrow unittest 8701 { 8702 import std.algorithm.comparison : equal; 8703 8704 assert(5.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4]])); 8705 assert(6.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5]])); 8706 assert(7.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5, 6]])); 8707 8708 assert(5.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2]])); 8709 assert(6.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2]])); 8710 assert(7.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5, 6]])); 8711 } 8712 8713 private struct Slides(Flag!"withPartial" withPartial = Yes.withPartial, Source) 8714 if (isForwardRange!Source) 8715 { 8716 private: 8717 Source source; 8718 size_t windowSize; 8719 size_t stepSize; 8720 8721 static if (hasLength!Source) 8722 { 8723 enum needsEndTracker = false; 8724 } 8725 else 8726 { 8727 // If there's no information about the length, track needs to be kept manually 8728 Source nextSource; 8729 enum needsEndTracker = true; 8730 } 8731 8732 bool _empty; 8733 8734 static if (hasSlicing!Source) 8735 enum hasSliceToEnd = hasSlicing!Source && is(typeof(Source.init[0 .. $]) == Source); 8736 8737 static if (withPartial) 8738 bool hasShownPartialBefore; 8739 8740 public: 8741 /// Standard constructor 8742 this(Source source, size_t windowSize, size_t stepSize) 8743 { 8744 assert(windowSize > 0, "windowSize must be greater than zero"); 8745 assert(stepSize > 0, "stepSize must be greater than zero"); 8746 this.source = source; 8747 this.windowSize = windowSize; 8748 this.stepSize = stepSize; 8749 8750 static if (needsEndTracker) 8751 { 8752 // `nextSource` is used to "look one step into the future" and check for the end 8753 // this means `nextSource` is advanced by `stepSize` on every `popFront` 8754 nextSource = source.save.drop(windowSize); 8755 } 8756 8757 if (source.empty) 8758 { 8759 _empty = true; 8760 return; 8761 } 8762 8763 static if (withPartial) 8764 { 8765 static if (needsEndTracker) 8766 { 8767 if (nextSource.empty) 8768 hasShownPartialBefore = true; 8769 } 8770 else 8771 { 8772 if (source.length <= windowSize) 8773 hasShownPartialBefore = true; 8774 } 8775 8776 } 8777 else 8778 { 8779 // empty source range is needed, s.t. length, slicing etc. works properly 8780 static if (needsEndTracker) 8781 { 8782 if (nextSource.empty) 8783 _empty = true; 8784 } 8785 else 8786 { 8787 if (source.length < windowSize) 8788 _empty = true; 8789 } 8790 } 8791 } 8792 8793 /// Forward range primitives. Always present. 8794 @property auto front() 8795 { 8796 assert(!empty, "Attempting to access front on an empty slide."); 8797 static if (hasSlicing!Source && hasLength!Source) 8798 { 8799 static if (withPartial) 8800 { 8801 import std.algorithm.comparison : min; 8802 return source[0 .. min(windowSize, source.length)]; 8803 } 8804 else 8805 { 8806 assert(windowSize <= source.length, "The last element is smaller than the current windowSize."); 8807 return source[0 .. windowSize]; 8808 } 8809 } 8810 else 8811 { 8812 static if (withPartial) 8813 return source.save.take(windowSize); 8814 else 8815 return source.save.takeExactly(windowSize); 8816 } 8817 } 8818 8819 /// Ditto 8820 void popFront() 8821 { 8822 assert(!empty, "Attempting to call popFront() on an empty slide."); 8823 source.popFrontN(stepSize); 8824 8825 if (source.empty) 8826 { 8827 _empty = true; 8828 return; 8829 } 8830 8831 static if (withPartial) 8832 { 8833 if (hasShownPartialBefore) 8834 _empty = true; 8835 } 8836 8837 static if (needsEndTracker) 8838 { 8839 // Check the upcoming slide 8840 auto poppedElements = nextSource.popFrontN(stepSize); 8841 static if (withPartial) 8842 { 8843 if (poppedElements < stepSize || nextSource.empty) 8844 hasShownPartialBefore = true; 8845 } 8846 else 8847 { 8848 if (poppedElements < stepSize) 8849 _empty = true; 8850 } 8851 } 8852 else 8853 { 8854 static if (withPartial) 8855 { 8856 if (source.length <= windowSize) 8857 hasShownPartialBefore = true; 8858 } 8859 else 8860 { 8861 if (source.length < windowSize) 8862 _empty = true; 8863 } 8864 } 8865 } 8866 8867 static if (!isInfinite!Source) 8868 { 8869 /// Ditto 8870 @property bool empty() const 8871 { 8872 return _empty; 8873 } 8874 } 8875 else 8876 { 8877 // undocumented 8878 enum empty = false; 8879 } 8880 8881 /// Ditto 8882 @property typeof(this) save() 8883 { 8884 return typeof(this)(source.save, windowSize, stepSize); 8885 } 8886 8887 static if (hasLength!Source) 8888 { 8889 // gaps between the last element and the end of the range 8890 private size_t gap() 8891 { 8892 /* 8893 * Note: 8894 * - In the following `end` is the exclusive end as used in opSlice 8895 * - For the trivial case with `stepSize = 1` `end` is at `len`: 8896 * 8897 * iota(4).slide(2) = [[0, 1], [1, 2], [2, 3]] (end = 4) 8898 * iota(4).slide(3) = [[0, 1, 2], [1, 2, 3]] (end = 4) 8899 * 8900 * - For the non-trivial cases, we need to calculate the gap 8901 * between `len` and `end` - this is the number of missing elements 8902 * from the input range: 8903 * 8904 * iota(7).slide(2, 3) = [[0, 1], [3, 4]] || <gap: 2> 6 8905 * iota(7).slide(2, 4) = [[0, 1], [4, 5]] || <gap: 1> 6 8906 * iota(7).slide(1, 5) = [[0], [5]] || <gap: 1> 6 8907 * 8908 * As it can be seen `gap` can be at most `stepSize - 1` 8909 * More generally the elements of the sliding window with 8910 * `w = windowSize` and `s = stepSize` are: 8911 * 8912 * [0, w], [s, s + w], [2 * s, 2 * s + w], ... [n * s, n * s + w] 8913 * 8914 * We can thus calculate the gap between the `end` and `len` as: 8915 * 8916 * gap = len - (n * s + w) = len - w - (n * s) 8917 * 8918 * As we aren't interested in exact value of `n`, but the best 8919 * minimal `gap` value, we can use modulo to "cut" `len - w` optimally: 8920 * 8921 * gap = len - w - (s - s ... - s) = (len - w) % s 8922 * 8923 * So for example: 8924 * 8925 * iota(7).slide(2, 3) = [[0, 1], [3, 4]] 8926 * gap: (7 - 2) % 3 = 5 % 3 = 2 8927 * end: 7 - 2 = 5 8928 * 8929 * iota(7).slide(4, 2) = [[0, 1, 2, 3], [2, 3, 4, 5]] 8930 * gap: (7 - 4) % 2 = 3 % 2 = 1 8931 * end: 7 - 1 = 6 8932 */ 8933 return (source.length - windowSize) % stepSize; 8934 } 8935 8936 private size_t numberOfFullFrames() 8937 { 8938 /** 8939 5.iota.slides(2, 1) => [0, 1], [1, 2], [2, 3], [3, 4] (4) 8940 7.iota.slides(2, 2) => [0, 1], [2, 3], [4, 5], [6] (3) 8941 7.iota.slides(2, 3) => [0, 1], [3, 4], [6] (2) 8942 6.iota.slides(3, 2) => [0, 1, 2], [2, 3, 4], [4, 5] (2) 8943 7.iota.slides(3, 3) => [0, 1, 2], [3, 4, 5], [6] (2) 8944 8945 As the last window is only added iff its complete, 8946 we don't count the last window except if it's full due to integer rounding. 8947 */ 8948 return 1 + (source.length - windowSize) / stepSize; 8949 } 8950 8951 // Whether the last slide frame size is less than windowSize 8952 private bool hasPartialElements() 8953 { 8954 static if (withPartial) 8955 return gap != 0 && source.length > numberOfFullFrames * stepSize; 8956 else 8957 return 0; 8958 } 8959 8960 /// Length. Only if `hasLength!Source` is `true` 8961 @property size_t length() 8962 { 8963 if (source.length < windowSize) 8964 { 8965 static if (withPartial) 8966 return source.length > 0; 8967 else 8968 return 0; 8969 } 8970 else 8971 { 8972 /*** 8973 We bump the pointer by stepSize for every element. 8974 If withPartial, we don't count the last element if its size 8975 isn't windowSize 8976 8977 At most: 8978 [p, p + stepSize, ..., p + stepSize * n] 8979 8980 5.iota.slides(2, 1) => [0, 1], [1, 2], [2, 3], [3, 4] (4) 8981 7.iota.slides(2, 2) => [0, 1], [2, 3], [4, 5], [6] (4) 8982 7.iota.slides(2, 3) => [0, 1], [3, 4], [6] (3) 8983 7.iota.slides(3, 2) => [0, 1, 2], [2, 3, 4], [4, 5, 6] (3) 8984 7.iota.slides(3, 3) => [0, 1, 2], [3, 4, 5], [6] (3) 8985 */ 8986 return numberOfFullFrames + hasPartialElements; 8987 } 8988 } 8989 } 8990 8991 static if (hasSlicing!Source) 8992 { 8993 /** 8994 Indexing and slicing operations. Provided only if 8995 `hasSlicing!Source` is `true`. 8996 */ 8997 auto opIndex(size_t index) 8998 { 8999 immutable start = index * stepSize; 9000 9001 static if (isInfinite!Source) 9002 { 9003 immutable end = start + windowSize; 9004 } 9005 else 9006 { 9007 import std.algorithm.comparison : min; 9008 9009 immutable len = source.length; 9010 assert(start < len, "slide index out of bounds"); 9011 immutable end = min(start + windowSize, len); 9012 } 9013 9014 return source[start .. end]; 9015 } 9016 9017 static if (!isInfinite!Source) 9018 { 9019 /// ditto 9020 typeof(this) opSlice(size_t lower, size_t upper) 9021 { 9022 import std.algorithm.comparison : min; 9023 9024 assert(upper <= length, "slide slicing index out of bounds"); 9025 assert(lower <= upper, "slide slicing index out of bounds"); 9026 9027 lower *= stepSize; 9028 upper *= stepSize; 9029 9030 immutable len = source.length; 9031 9032 static if (withPartial) 9033 { 9034 import std.algorithm.comparison : max; 9035 9036 if (lower == upper) 9037 return this[$ .. $]; 9038 9039 /* 9040 A) If `stepSize` >= `windowSize` => `rightPos = upper` 9041 9042 [0, 1, 2, 3, 4, 5, 6].slide(2, 3) -> s = [[0, 1], [3, 4], [6]] 9043 rightPos for s[0 .. 2]: (upper=2) * (stepSize=3) = 6 9044 6.iota.slide(2, 3) = [[0, 1], [3, 4]] 9045 9046 B) If `stepSize` < `windowSize` => add `windowSize - stepSize` to `upper` 9047 9048 [0, 1, 2, 3].slide(2) = [[0, 1], [1, 2], [2, 3]] 9049 rightPos for s[0 .. 1]: = (upper=1) * (stepSize=1) = 1 9050 1.iota.slide(2) = [[0]] 9051 9052 rightPos for s[0 .. 1]: = (upper=1) * (stepSize=1) + (windowSize-stepSize=1) = 2 9053 1.iota.slide(2) = [[0, 1]] 9054 9055 More complex: 9056 9057 20.iota.slide(7, 6)[0 .. 2] 9058 rightPos: (upper=2) * (stepSize=6) = 12.iota 9059 12.iota.slide(7, 6) = [[0, 1, 2, 3, 4, 5, 6], [6, 7, 8, 9, 10, 11]] 9060 9061 Now we add up for the difference between `windowSize` and `stepSize`: 9062 9063 rightPos: (upper=2) * (stepSize=6) + (windowSize-stepSize=1) = 13.iota 9064 13.iota.slide(7, 6) = [[0, 1, 2, 3, 4, 5, 6], [6, 7, 8, 9, 10, 11, 12]] 9065 */ 9066 immutable rightPos = min(len, upper + max(0, windowSize - stepSize)); 9067 } 9068 else 9069 { 9070 /* 9071 After we have normalized `lower` and `upper` by `stepSize`, 9072 we only need to look at the case of `stepSize=1`. 9073 As `leftPos`, is equal to `lower`, we will only look `rightPos`. 9074 Notice that starting from `upper`, 9075 we only need to move for `windowSize - 1` to the right: 9076 9077 - [0, 1, 2, 3].slide(2) -> s = [[0, 1], [1, 2], [2, 3]] 9078 rightPos for s[0 .. 3]: (upper=3) + (windowSize=2) - 1 = 4 9079 9080 - [0, 1, 2, 3].slide(3) -> s = [[0, 1, 2], [1, 2, 3]] 9081 rightPos for s[0 .. 2]: (upper=2) + (windowSize=3) - 1 = 4 9082 9083 - [0, 1, 2, 3, 4].slide(4) -> s = [[0, 1, 2, 3], [1, 2, 3, 4]] 9084 rightPos for s[0 .. 2]: (upper=2) + (windowSize=4) - 1 = 5 9085 */ 9086 immutable rightPos = min(upper + windowSize - 1, len); 9087 } 9088 9089 return typeof(this)(source[min(lower, len) .. rightPos], windowSize, stepSize); 9090 } 9091 } 9092 else static if (hasSliceToEnd) 9093 { 9094 // For slicing an infinite chunk, we need to slice the source to the infinite end. 9095 auto opSlice(size_t lower, size_t upper) 9096 { 9097 assert(lower <= upper, "slide slicing index out of bounds"); 9098 return typeof(this)(source[lower * stepSize .. $], windowSize, stepSize) 9099 .takeExactly(upper - lower); 9100 } 9101 } 9102 9103 static if (isInfinite!Source) 9104 { 9105 static if (hasSliceToEnd) 9106 { 9107 private static struct DollarToken{} 9108 DollarToken opDollar() 9109 { 9110 return DollarToken(); 9111 } 9112 //Slice to dollar 9113 typeof(this) opSlice(size_t lower, DollarToken) 9114 { 9115 return typeof(this)(source[lower * stepSize .. $], windowSize, stepSize); 9116 } 9117 } 9118 } 9119 else 9120 { 9121 // Dollar token carries a static type, with no extra information. 9122 // It can lazily transform into source.length on algorithmic 9123 // operations such as : slide[$/2, $-1]; 9124 private static struct DollarToken 9125 { 9126 private size_t _length; 9127 alias _length this; 9128 } 9129 9130 DollarToken opDollar() 9131 { 9132 return DollarToken(this.length); 9133 } 9134 9135 // Optimized slice overloads optimized for using dollar. 9136 typeof(this) opSlice(DollarToken, DollarToken) 9137 { 9138 static if (hasSliceToEnd) 9139 { 9140 return typeof(this)(source[$ .. $], windowSize, stepSize); 9141 } 9142 else 9143 { 9144 immutable len = source.length; 9145 return typeof(this)(source[len .. len], windowSize, stepSize); 9146 } 9147 } 9148 9149 // Optimized slice overloads optimized for using dollar. 9150 typeof(this) opSlice(size_t lower, DollarToken) 9151 { 9152 import std.algorithm.comparison : min; 9153 assert(lower <= length, "slide slicing index out of bounds"); 9154 lower *= stepSize; 9155 static if (hasSliceToEnd) 9156 { 9157 return typeof(this)(source[min(lower, source.length) .. $], windowSize, stepSize); 9158 } 9159 else 9160 { 9161 immutable len = source.length; 9162 return typeof(this)(source[min(lower, len) .. len], windowSize, stepSize); 9163 } 9164 } 9165 9166 // Optimized slice overloads optimized for using dollar. 9167 typeof(this) opSlice(DollarToken, size_t upper) 9168 { 9169 assert(upper == length, "slide slicing index out of bounds"); 9170 return this[$ .. $]; 9171 } 9172 } 9173 9174 // Bidirectional range primitives 9175 static if (!isInfinite!Source) 9176 { 9177 /** 9178 Bidirectional range primitives. Provided only if both 9179 `hasSlicing!Source` and `!isInfinite!Source` are `true`. 9180 */ 9181 @property auto back() 9182 { 9183 import std.algorithm.comparison : max; 9184 9185 assert(!empty, "Attempting to access front on an empty slide"); 9186 9187 immutable len = source.length; 9188 9189 static if (withPartial) 9190 { 9191 if (source.length <= windowSize) 9192 return source[0 .. source.length]; 9193 9194 if (hasPartialElements) 9195 return source[numberOfFullFrames * stepSize .. len]; 9196 } 9197 9198 // check for underflow 9199 immutable start = (len > windowSize + gap) ? len - windowSize - gap : 0; 9200 return source[start .. len - gap]; 9201 } 9202 9203 /// Ditto 9204 void popBack() 9205 { 9206 assert(!empty, "Attempting to call popBack() on an empty slide"); 9207 9208 // Move by stepSize 9209 immutable end = source.length > stepSize ? source.length - stepSize : 0; 9210 9211 static if (withPartial) 9212 { 9213 if (hasShownPartialBefore || source.empty) 9214 { 9215 _empty = true; 9216 return; 9217 } 9218 9219 // pop by stepSize, except for the partial frame at the end 9220 if (hasPartialElements) 9221 source = source[0 .. source.length - gap]; 9222 else 9223 source = source[0 .. end]; 9224 } 9225 else 9226 { 9227 source = source[0 .. end]; 9228 } 9229 9230 if (source.length < windowSize) 9231 _empty = true; 9232 } 9233 } 9234 } 9235 } 9236 9237 // test @nogc 9238 @safe pure nothrow @nogc unittest 9239 { 9240 import std.algorithm.comparison : equal; 9241 9242 static immutable res1 = [[0], [1], [2], [3]]; 9243 assert(4.iota.slide!(Yes.withPartial)(1).equal!equal(res1)); 9244 9245 static immutable res2 = [[0, 1], [1, 2], [2, 3]]; 9246 assert(4.iota.slide!(Yes.withPartial)(2).equal!equal(res2)); 9247 } 9248 9249 // test different window sizes 9250 @safe pure nothrow unittest 9251 { 9252 import std.array : array; 9253 import std.algorithm.comparison : equal; 9254 9255 assert([0, 1, 2, 3].slide!(Yes.withPartial)(1).array == [[0], [1], [2], [3]]); 9256 assert([0, 1, 2, 3].slide!(Yes.withPartial)(2).array == [[0, 1], [1, 2], [2, 3]]); 9257 assert([0, 1, 2, 3].slide!(Yes.withPartial)(3).array == [[0, 1, 2], [1, 2, 3]]); 9258 assert([0, 1, 2, 3].slide!(Yes.withPartial)(4).array == [[0, 1, 2, 3]]); 9259 assert([0, 1, 2, 3].slide!(No.withPartial)(5).walkLength == 0); 9260 assert([0, 1, 2, 3].slide!(Yes.withPartial)(5).array == [[0, 1, 2, 3]]); 9261 9262 assert(iota(2).slide!(Yes.withPartial)(2).front.equal([0, 1])); 9263 assert(iota(3).slide!(Yes.withPartial)(2).equal!equal([[0, 1],[1, 2]])); 9264 assert(iota(3).slide!(Yes.withPartial)(3).equal!equal([[0, 1, 2]])); 9265 assert(iota(3).slide!(No.withPartial)(4).walkLength == 0); 9266 assert(iota(3).slide!(Yes.withPartial)(4).equal!equal([[0, 1, 2]])); 9267 assert(iota(1, 4).slide!(Yes.withPartial)(1).equal!equal([[1], [2], [3]])); 9268 assert(iota(1, 4).slide!(Yes.withPartial)(3).equal!equal([[1, 2, 3]])); 9269 } 9270 9271 // test combinations 9272 @safe pure nothrow unittest 9273 { 9274 import std.algorithm.comparison : equal; 9275 import std.typecons : tuple; 9276 9277 alias t = tuple; 9278 auto list = [ 9279 t(t(1, 1), [[0], [1], [2], [3], [4], [5]]), 9280 t(t(1, 2), [[0], [2], [4]]), 9281 t(t(1, 3), [[0], [3]]), 9282 t(t(1, 4), [[0], [4]]), 9283 t(t(1, 5), [[0], [5]]), 9284 t(t(2, 1), [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5]]), 9285 t(t(2, 2), [[0, 1], [2, 3], [4, 5]]), 9286 t(t(2, 3), [[0, 1], [3, 4]]), 9287 t(t(2, 4), [[0, 1], [4, 5]]), 9288 t(t(3, 1), [[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5]]), 9289 t(t(3, 3), [[0, 1, 2], [3, 4, 5]]), 9290 t(t(4, 1), [[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]), 9291 t(t(4, 2), [[0, 1, 2, 3], [2, 3, 4, 5]]), 9292 t(t(5, 1), [[0, 1, 2, 3, 4], [1, 2, 3, 4, 5]]), 9293 ]; 9294 9295 static foreach (Partial; [Yes.withPartial, No.withPartial]) 9296 foreach (e; list) 9297 assert(6.iota.slide!Partial(e[0].expand).equal!equal(e[1])); 9298 9299 auto listSpecial = [ 9300 t(t(2, 5), [[0, 1], [5]]), 9301 t(t(3, 2), [[0, 1, 2], [2, 3, 4], [4, 5]]), 9302 t(t(3, 4), [[0, 1, 2], [4, 5]]), 9303 t(t(4, 3), [[0, 1, 2, 3], [3, 4, 5]]), 9304 t(t(5, 2), [[0, 1, 2, 3, 4], [2, 3, 4, 5]]), 9305 t(t(5, 3), [[0, 1, 2, 3, 4], [3, 4, 5]]), 9306 ]; 9307 foreach (e; listSpecial) 9308 { 9309 assert(6.iota.slide!(Yes.withPartial)(e[0].expand).equal!equal(e[1])); 9310 assert(6.iota.slide!(No.withPartial)(e[0].expand).equal!equal(e[1].dropBackOne)); 9311 } 9312 } 9313 9314 // test emptiness and copyability 9315 @safe pure nothrow unittest 9316 { 9317 import std.algorithm.comparison : equal; 9318 import std.algorithm.iteration : map; 9319 9320 // check with empty input 9321 int[] d; 9322 assert(d.slide!(Yes.withPartial)(2).empty); 9323 assert(d.slide!(Yes.withPartial)(2, 2).empty); 9324 9325 // is copyable? 9326 auto e = iota(5).slide!(Yes.withPartial)(2); 9327 e.popFront; 9328 assert(e.save.equal!equal([[1, 2], [2, 3], [3, 4]])); 9329 assert(e.save.equal!equal([[1, 2], [2, 3], [3, 4]])); 9330 assert(e.map!"a.array".array == [[1, 2], [2, 3], [3, 4]]); 9331 } 9332 9333 // test with strings 9334 @safe pure nothrow unittest 9335 { 9336 import std.algorithm.iteration : each; 9337 9338 int[dstring] f; 9339 "AGAGA"d.slide!(Yes.withPartial)(3).each!(a => f[a]++); 9340 assert(f == ["AGA"d: 2, "GAG"d: 1]); 9341 9342 int[dstring] g; 9343 "ABCDEFG"d.slide!(Yes.withPartial)(3, 3).each!(a => g[a]++); 9344 assert(g == ["ABC"d:1, "DEF"d:1, "G": 1]); 9345 g = null; 9346 "ABCDEFG"d.slide!(No.withPartial)(3, 3).each!(a => g[a]++); 9347 assert(g == ["ABC"d:1, "DEF"d:1]); 9348 } 9349 9350 // test with utf8 strings 9351 @safe unittest 9352 { 9353 import std.stdio; 9354 import std.algorithm.comparison : equal; 9355 9356 assert("ä.ö.ü.".slide!(Yes.withPartial)(3, 2).equal!equal(["ä.ö", "ö.ü", "ü."])); 9357 assert("ä.ö.ü.".slide!(No.withPartial)(3, 2).equal!equal(["ä.ö", "ö.ü"])); 9358 9359 "😄😅😆😇😈😄😅😆😇😈".slide!(Yes.withPartial)(2, 4).equal!equal(["😄😅", "😈😄", "😇😈"]); 9360 "😄😅😆😇😈😄😅😆😇😈".slide!(No.withPartial)(2, 4).equal!equal(["😄😅", "😈😄", "😇😈"]); 9361 "😄😅😆😇😈😄😅😆😇😈".slide!(Yes.withPartial)(3, 3).equal!equal(["😄😅😆", "😇😈😄", "😅😆😇", "😈"]); 9362 "😄😅😆😇😈😄😅😆😇😈".slide!(No.withPartial)(3, 3).equal!equal(["😄😅😆", "😇😈😄", "😅😆😇"]); 9363 } 9364 9365 // test length 9366 @safe pure nothrow unittest 9367 { 9368 // Slides with fewer elements are empty or 1 for Yes.withPartial 9369 static foreach (expectedLength, Partial; [No.withPartial, Yes.withPartial]) 9370 {{ 9371 assert(3.iota.slide!(Partial)(4, 2).walkLength == expectedLength); 9372 assert(3.iota.slide!(Partial)(4).walkLength == expectedLength); 9373 assert(3.iota.slide!(Partial)(4, 3).walkLength == expectedLength); 9374 }} 9375 9376 static immutable list = [ 9377 // iota slide expected 9378 [4, 2, 1, 3, 3], 9379 [5, 3, 1, 3, 3], 9380 [7, 2, 2, 4, 3], 9381 [12, 2, 4, 3, 3], 9382 [6, 1, 2, 3, 3], 9383 [6, 2, 4, 2, 2], 9384 [3, 2, 4, 1, 1], 9385 [5, 2, 1, 4, 4], 9386 [7, 2, 2, 4, 3], 9387 [7, 2, 3, 3, 2], 9388 [7, 3, 2, 3, 3], 9389 [7, 3, 3, 3, 2], 9390 ]; 9391 foreach (e; list) 9392 { 9393 assert(e[0].iota.slide!(Yes.withPartial)(e[1], e[2]).length == e[3]); 9394 assert(e[0].iota.slide!(No.withPartial)(e[1], e[2]).length == e[4]); 9395 } 9396 } 9397 9398 // test index and slicing 9399 @safe pure nothrow unittest 9400 { 9401 import std.algorithm.comparison : equal; 9402 import std.array : array; 9403 9404 static foreach (Partial; [Yes.withPartial, No.withPartial]) 9405 { 9406 foreach (s; [5, 7, 10, 15, 20]) 9407 foreach (windowSize; 1 .. 10) 9408 foreach (stepSize; 1 .. 10) 9409 { 9410 auto r = s.iota.slide!Partial(windowSize, stepSize); 9411 auto arr = r.array; 9412 assert(r.length == arr.length); 9413 9414 // test indexing 9415 foreach (i; 0 .. arr.length) 9416 assert(r[i] == arr[i]); 9417 9418 // test slicing 9419 foreach (i; 0 .. arr.length) 9420 { 9421 foreach (j; i .. arr.length) 9422 assert(r[i .. j].equal(arr[i .. j])); 9423 9424 assert(r[i .. $].equal(arr[i .. $])); 9425 } 9426 9427 // test opDollar slicing 9428 assert(r[$/2 .. $].equal(arr[$/2 .. $])); 9429 assert(r[$ .. $].empty); 9430 if (arr.empty) 9431 { 9432 assert(r[$ .. 0].empty); 9433 assert(r[$/2 .. $].empty); 9434 9435 } 9436 } 9437 } 9438 } 9439 9440 // test with infinite ranges 9441 @safe pure nothrow unittest 9442 { 9443 import std.algorithm.comparison : equal; 9444 9445 static foreach (Partial; [Yes.withPartial, No.withPartial]) 9446 {{ 9447 // InfiniteRange without RandomAccess 9448 auto fibs = recurrence!"a[n-1] + a[n-2]"(1, 1); 9449 assert(fibs.slide!Partial(2).take(2).equal!equal([[1, 1], [1, 2]])); 9450 assert(fibs.slide!Partial(2, 3).take(2).equal!equal([[1, 1], [3, 5]])); 9451 9452 // InfiniteRange with RandomAccess and slicing 9453 auto odds = sequence!("a[0] + n * a[1]")(1, 2); 9454 auto oddsByPairs = odds.slide!Partial(2); 9455 assert(oddsByPairs.take(2).equal!equal([[ 1, 3], [ 3, 5]])); 9456 assert(oddsByPairs[1].equal([3, 5])); 9457 assert(oddsByPairs[4].equal([9, 11])); 9458 9459 static assert(hasSlicing!(typeof(odds))); 9460 assert(oddsByPairs[3 .. 5].equal!equal([[7, 9], [9, 11]])); 9461 assert(oddsByPairs[3 .. $].take(2).equal!equal([[7, 9], [9, 11]])); 9462 9463 auto oddsWithGaps = odds.slide!Partial(2, 4); 9464 assert(oddsWithGaps.take(3).equal!equal([[1, 3], [9, 11], [17, 19]])); 9465 assert(oddsWithGaps[2].equal([17, 19])); 9466 assert(oddsWithGaps[1 .. 3].equal!equal([[9, 11], [17, 19]])); 9467 assert(oddsWithGaps[1 .. $].take(2).equal!equal([[9, 11], [17, 19]])); 9468 }} 9469 } 9470 9471 // test reverse 9472 @safe pure nothrow unittest 9473 { 9474 import std.algorithm.comparison : equal; 9475 9476 static foreach (Partial; [Yes.withPartial, No.withPartial]) 9477 {{ 9478 foreach (windowSize; 1 .. 15) 9479 foreach (stepSize; 1 .. 15) 9480 { 9481 auto r = 20.iota.slide!Partial(windowSize, stepSize); 9482 auto rArr = r.array.retro; 9483 auto rRetro = r.retro; 9484 9485 assert(rRetro.length == rArr.length); 9486 assert(rRetro.equal(rArr)); 9487 assert(rRetro.array.retro.equal(r)); 9488 } 9489 }} 9490 } 9491 9492 // test with dummy ranges 9493 @safe pure nothrow unittest 9494 { 9495 import std.algorithm.comparison : equal; 9496 import std.internal.test.dummyrange : AllDummyRanges; 9497 import std.meta : Filter; 9498 9499 static foreach (Range; Filter!(isForwardRange, AllDummyRanges)) 9500 {{ 9501 Range r; 9502 9503 static foreach (Partial; [Yes.withPartial, No.withPartial]) 9504 { 9505 assert(r.slide!Partial(1).equal!equal( 9506 [[1], [2], [3], [4], [5], [6], [7], [8], [9], [10]] 9507 )); 9508 assert(r.slide!Partial(2).equal!equal( 9509 [[1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9], [9, 10]] 9510 )); 9511 assert(r.slide!Partial(3).equal!equal( 9512 [[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6], 9513 [5, 6, 7], [6, 7, 8], [7, 8, 9], [8, 9, 10]] 9514 )); 9515 assert(r.slide!Partial(6).equal!equal( 9516 [[1, 2, 3, 4, 5, 6], [2, 3, 4, 5, 6, 7], [3, 4, 5, 6, 7, 8], 9517 [4, 5, 6, 7, 8, 9], [5, 6, 7, 8, 9, 10]] 9518 )); 9519 } 9520 9521 // special cases 9522 assert(r.slide!(Yes.withPartial)(15).equal!equal(iota(1, 11).only)); 9523 assert(r.slide!(Yes.withPartial)(15).walkLength == 1); 9524 assert(r.slide!(No.withPartial)(15).empty); 9525 assert(r.slide!(No.withPartial)(15).walkLength == 0); 9526 }} 9527 } 9528 9529 // test with dummy ranges 9530 @safe pure nothrow unittest 9531 { 9532 import std.algorithm.comparison : equal; 9533 import std.internal.test.dummyrange : AllDummyRanges; 9534 import std.meta : Filter; 9535 import std.typecons : tuple; 9536 9537 alias t = tuple; 9538 static immutable list = [ 9539 // iota slide expected 9540 t(6, t(4, 2), [[1, 2, 3, 4], [3, 4, 5, 6]]), 9541 t(6, t(4, 6), [[1, 2, 3, 4]]), 9542 t(6, t(4, 1), [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6]]), 9543 t(7, t(4, 1), [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 6, 7]]), 9544 t(7, t(4, 3), [[1, 2, 3, 4], [4, 5, 6, 7]]), 9545 t(8, t(4, 2), [[1, 2, 3, 4], [3, 4, 5, 6], [5, 6, 7, 8]]), 9546 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]]), 9547 t(8, t(3, 4), [[1, 2, 3], [5, 6, 7]]), 9548 t(10, t(3, 7), [[1, 2, 3], [8, 9, 10]]), 9549 ]; 9550 9551 static foreach (Range; Filter!(isForwardRange, AllDummyRanges)) 9552 static foreach (Partial; [Yes.withPartial, No.withPartial]) 9553 foreach (e; list) 9554 assert(Range().take(e[0]).slide!Partial(e[1].expand).equal!equal(e[2])); 9555 9556 static immutable listSpecial = [ 9557 // iota slide expected 9558 t(6, t(4, 3), [[1, 2, 3, 4], [4, 5, 6]]), 9559 t(7, t(4, 5), [[1, 2, 3, 4], [6, 7]]), 9560 t(7, t(4, 4), [[1, 2, 3, 4], [5, 6, 7]]), 9561 t(7, t(4, 2), [[1, 2, 3, 4], [3, 4, 5, 6], [5, 6, 7]]), 9562 t(8, t(4, 3), [[1, 2, 3, 4], [4, 5, 6, 7], [7, 8]]), 9563 t(8, t(3, 3), [[1, 2, 3], [4, 5, 6], [7, 8]]), 9564 t(8, t(3, 6), [[1, 2, 3], [7, 8]]), 9565 t(10, t(7, 6), [[1, 2, 3, 4, 5, 6, 7], [7, 8, 9, 10]]), 9566 t(10, t(3, 8), [[1, 2, 3], [9, 10]]), 9567 ]; 9568 static foreach (Range; Filter!(isForwardRange, AllDummyRanges)) 9569 static foreach (Partial; [Yes.withPartial, No.withPartial]) 9570 foreach (e; listSpecial) 9571 { 9572 Range r; 9573 assert(r.take(e[0]).slide!(Yes.withPartial)(e[1].expand).equal!equal(e[2])); 9574 assert(r.take(e[0]).slide!(No.withPartial)(e[1].expand).equal!equal(e[2].dropBackOne)); 9575 } 9576 } 9577 9578 // test reverse with dummy ranges 9579 @safe pure nothrow unittest 9580 { 9581 import std.algorithm.comparison : equal; 9582 import std.internal.test.dummyrange : AllDummyRanges; 9583 import std.meta : Filter, templateAnd; 9584 import std.typecons : tuple; 9585 alias t = tuple; 9586 9587 static immutable list = [ 9588 // slide expected 9589 t(1, 1, [[10], [9], [8], [7], [6], [5], [4], [3], [2], [1]]), 9590 t(2, 1, [[9, 10], [8, 9], [7, 8], [6, 7], [5, 6], [4, 5], [3, 4], [2, 3], [1, 2]]), 9591 t(5, 1, [[6, 7, 8, 9, 10], [5, 6, 7, 8, 9], [4, 5, 6, 7, 8], 9592 [3, 4, 5, 6, 7], [2, 3, 4, 5, 6], [1, 2, 3, 4, 5]]), 9593 t(2, 2, [[9, 10], [7, 8], [5, 6], [3, 4], [1, 2]]), 9594 t(2, 4, [[9, 10], [5, 6], [1, 2]]), 9595 ]; 9596 9597 static foreach (Range; Filter!(templateAnd!(hasSlicing, hasLength, isBidirectionalRange), AllDummyRanges)) 9598 {{ 9599 Range r; 9600 static foreach (Partial; [Yes.withPartial, No.withPartial]) 9601 { 9602 foreach (e; list) 9603 assert(r.slide!Partial(e[0], e[1]).retro.equal!equal(e[2])); 9604 9605 // front = back 9606 foreach (windowSize; 1 .. 10) 9607 foreach (stepSize; 1 .. 10) 9608 { 9609 auto slider = r.slide!Partial(windowSize, stepSize); 9610 auto sliderRetro = slider.retro.array; 9611 assert(slider.length == sliderRetro.length); 9612 assert(sliderRetro.retro.equal!equal(slider)); 9613 } 9614 } 9615 9616 // special cases 9617 assert(r.slide!(No.withPartial)(15).retro.walkLength == 0); 9618 assert(r.slide!(Yes.withPartial)(15).retro.equal!equal(iota(1, 11).only)); 9619 }} 9620 } 9621 9622 // test different sliceable ranges 9623 @safe pure nothrow unittest 9624 { 9625 import std.algorithm.comparison : equal; 9626 import std.internal.test.dummyrange : AllDummyRanges; 9627 import std.meta : AliasSeq; 9628 9629 struct SliceableRange(Range, Flag!"withOpDollar" withOpDollar = No.withOpDollar, 9630 Flag!"withInfiniteness" withInfiniteness = No.withInfiniteness) 9631 { 9632 Range arr = 10.iota.array; // similar to DummyRange 9633 @property auto save() { return typeof(this)(arr); } 9634 @property auto front() { return arr[0]; } 9635 void popFront() { arr.popFront(); } 9636 auto opSlice(size_t i, size_t j) 9637 { 9638 // subslices can't be infinite 9639 return SliceableRange!(Range, withOpDollar, No.withInfiniteness)(arr[i .. j]); 9640 } 9641 9642 static if (withInfiniteness) 9643 { 9644 enum empty = false; 9645 } 9646 else 9647 { 9648 @property bool empty() { return arr.empty; } 9649 @property auto length() { return arr.length; } 9650 } 9651 9652 static if (withOpDollar) 9653 { 9654 static if (withInfiniteness) 9655 { 9656 struct Dollar {} 9657 Dollar opDollar() const { return Dollar.init; } 9658 9659 // Slice to dollar 9660 typeof(this) opSlice(size_t lower, Dollar) 9661 { 9662 return typeof(this)(arr[lower .. $]); 9663 } 9664 9665 } 9666 else 9667 { 9668 alias opDollar = length; 9669 } 9670 } 9671 } 9672 9673 import std.meta : Filter, templateNot; 9674 alias SliceableDummyRanges = Filter!(hasSlicing, AllDummyRanges); 9675 9676 static foreach (Partial; [Yes.withPartial, No.withPartial]) 9677 {{ 9678 static foreach (Range; SliceableDummyRanges) 9679 {{ 9680 Range r; 9681 r.reinit; 9682 r.arr[] -= 1; // use a 0-based array (for clarity) 9683 9684 assert(r.slide!Partial(2)[0].equal([0, 1])); 9685 assert(r.slide!Partial(2)[1].equal([1, 2])); 9686 9687 // saveable 9688 auto s = r.slide!Partial(2); 9689 assert(s[0 .. 2].equal!equal([[0, 1], [1, 2]])); 9690 s.save.popFront; 9691 assert(s[0 .. 2].equal!equal([[0, 1], [1, 2]])); 9692 9693 assert(r.slide!Partial(3)[1 .. 3].equal!equal([[1, 2, 3], [2, 3, 4]])); 9694 }} 9695 9696 static foreach (Range; Filter!(templateNot!isInfinite, SliceableDummyRanges)) 9697 {{ 9698 Range r; 9699 r.reinit; 9700 r.arr[] -= 1; // use a 0-based array (for clarity) 9701 9702 assert(r.slide!(No.withPartial)(6).equal!equal( 9703 [[0, 1, 2, 3, 4, 5], [1, 2, 3, 4, 5, 6], [2, 3, 4, 5, 6, 7], 9704 [3, 4, 5, 6, 7, 8], [4, 5, 6, 7, 8, 9]] 9705 )); 9706 assert(r.slide!(No.withPartial)(16).empty); 9707 9708 assert(r.slide!Partial(4)[0 .. $].equal(r.slide!Partial(4))); 9709 assert(r.slide!Partial(2)[$/2 .. $].equal!equal([[4, 5], [5, 6], [6, 7], [7, 8], [8, 9]])); 9710 assert(r.slide!Partial(2)[$ .. $].empty); 9711 9712 assert(r.slide!Partial(3).retro.equal!equal( 9713 [[7, 8, 9], [6, 7, 8], [5, 6, 7], [4, 5, 6], [3, 4, 5], [2, 3, 4], [1, 2, 3], [0, 1, 2]] 9714 )); 9715 }} 9716 9717 alias T = int[]; 9718 9719 // separate checks for infinity 9720 auto infIndex = SliceableRange!(T, No.withOpDollar, Yes.withInfiniteness)([0, 1, 2, 3]); 9721 assert(infIndex.slide!Partial(2)[0].equal([0, 1])); 9722 assert(infIndex.slide!Partial(2)[1].equal([1, 2])); 9723 9724 auto infDollar = SliceableRange!(T, Yes.withOpDollar, Yes.withInfiniteness)(); 9725 assert(infDollar.slide!Partial(2)[1 .. $].front.equal([1, 2])); 9726 assert(infDollar.slide!Partial(4)[0 .. $].front.equal([0, 1, 2, 3])); 9727 assert(infDollar.slide!Partial(4)[2 .. $].front.equal([2, 3, 4, 5])); 9728 }} 9729 } 9730 9731 // https://issues.dlang.org/show_bug.cgi?id=19082 9732 @safe unittest 9733 { 9734 import std.algorithm.comparison : equal; 9735 import std.algorithm.iteration : map; 9736 assert([1].map!(x => x).slide(2).equal!equal([[1]])); 9737 } 9738 9739 private struct OnlyResult(T, size_t arity) 9740 { 9741 private this(Values...)(return scope auto ref Values values) 9742 { 9743 this.data = [values]; 9744 this.backIndex = arity; 9745 } 9746 9747 bool empty() @property 9748 { 9749 return frontIndex >= backIndex; 9750 } 9751 9752 T front() @property 9753 { 9754 assert(!empty, "Attempting to fetch the front of an empty Only range"); 9755 return data[frontIndex]; 9756 } 9757 9758 void popFront() 9759 { 9760 assert(!empty, "Attempting to popFront an empty Only range"); 9761 ++frontIndex; 9762 } 9763 9764 T back() @property 9765 { 9766 assert(!empty, "Attempting to fetch the back of an empty Only range"); 9767 return data[backIndex - 1]; 9768 } 9769 9770 void popBack() 9771 { 9772 assert(!empty, "Attempting to popBack an empty Only range"); 9773 --backIndex; 9774 } 9775 9776 OnlyResult save() @property 9777 { 9778 return this; 9779 } 9780 9781 size_t length() const @property 9782 { 9783 return backIndex - frontIndex; 9784 } 9785 9786 alias opDollar = length; 9787 9788 T opIndex(size_t idx) 9789 { 9790 // when i + idx points to elements popped 9791 // with popBack 9792 assert(idx < length, "Attempting to fetch an out of bounds index from an Only range"); 9793 return data[frontIndex + idx]; 9794 } 9795 9796 OnlyResult opSlice() 9797 { 9798 return this; 9799 } 9800 9801 OnlyResult opSlice(size_t from, size_t to) 9802 { 9803 OnlyResult result = this; 9804 result.frontIndex += from; 9805 result.backIndex = this.frontIndex + to; 9806 assert( 9807 from <= to, 9808 "Attempting to slice an Only range with a larger first argument than the second." 9809 ); 9810 assert( 9811 to <= length, 9812 "Attempting to slice using an out of bounds index on an Only range" 9813 ); 9814 return result; 9815 } 9816 9817 private size_t frontIndex = 0; 9818 private size_t backIndex = 0; 9819 9820 // https://issues.dlang.org/show_bug.cgi?id=10643 9821 version (none) 9822 { 9823 import std.traits : hasElaborateAssign; 9824 static if (hasElaborateAssign!T) 9825 private T[arity] data; 9826 else 9827 private T[arity] data = void; 9828 } 9829 else 9830 private T[arity] data; 9831 } 9832 9833 // Specialize for single-element results 9834 private struct OnlyResult(T, size_t arity : 1) 9835 { 9836 @property T front() 9837 { 9838 assert(!empty, "Attempting to fetch the front of an empty Only range"); 9839 return _value; 9840 } 9841 @property T back() 9842 { 9843 assert(!empty, "Attempting to fetch the back of an empty Only range"); 9844 return _value; 9845 } 9846 @property bool empty() const { return _empty; } 9847 @property size_t length() const { return !_empty; } 9848 @property auto save() { return this; } 9849 void popFront() 9850 { 9851 assert(!_empty, "Attempting to popFront an empty Only range"); 9852 _empty = true; 9853 } 9854 void popBack() 9855 { 9856 assert(!_empty, "Attempting to popBack an empty Only range"); 9857 _empty = true; 9858 } 9859 alias opDollar = length; 9860 9861 private this()(return scope auto ref T value) 9862 { 9863 this._value = value; 9864 this._empty = false; 9865 } 9866 9867 T opIndex(size_t i) 9868 { 9869 assert(!_empty && i == 0, "Attempting to fetch an out of bounds index from an Only range"); 9870 return _value; 9871 } 9872 9873 OnlyResult opSlice() 9874 { 9875 return this; 9876 } 9877 9878 OnlyResult opSlice(size_t from, size_t to) 9879 { 9880 assert( 9881 from <= to, 9882 "Attempting to slice an Only range with a larger first argument than the second." 9883 ); 9884 assert( 9885 to <= length, 9886 "Attempting to slice using an out of bounds index on an Only range" 9887 ); 9888 OnlyResult copy = this; 9889 copy._empty = _empty || from == to; 9890 return copy; 9891 } 9892 9893 private Unqual!T _value; 9894 private bool _empty = true; 9895 } 9896 9897 // Specialize for the empty range 9898 private struct OnlyResult(T, size_t arity : 0) 9899 { 9900 private static struct EmptyElementType {} 9901 9902 bool empty() @property { return true; } 9903 size_t length() const @property { return 0; } 9904 alias opDollar = length; 9905 EmptyElementType front() @property { assert(false); } 9906 void popFront() { assert(false); } 9907 EmptyElementType back() @property { assert(false); } 9908 void popBack() { assert(false); } 9909 OnlyResult save() @property { return this; } 9910 9911 EmptyElementType opIndex(size_t i) 9912 { 9913 assert(false); 9914 } 9915 9916 OnlyResult opSlice() { return this; } 9917 9918 OnlyResult opSlice(size_t from, size_t to) 9919 { 9920 assert(from == 0 && to == 0); 9921 return this; 9922 } 9923 } 9924 9925 /** 9926 Assemble `values` into a range that carries all its 9927 elements in-situ. 9928 9929 Useful when a single value or multiple disconnected values 9930 must be passed to an algorithm expecting a range, without 9931 having to perform dynamic memory allocation. 9932 9933 As copying the range means copying all elements, it can be 9934 safely returned from functions. For the same reason, copying 9935 the returned range may be expensive for a large number of arguments. 9936 9937 Params: 9938 values = the values to assemble together 9939 9940 Returns: 9941 A `RandomAccessRange` of the assembled values. 9942 9943 See_Also: $(LREF chain) to chain ranges 9944 */ 9945 auto only(Values...)(return scope Values values) 9946 if (!is(CommonType!Values == void) || Values.length == 0) 9947 { 9948 return OnlyResult!(CommonType!Values, Values.length)(values); 9949 } 9950 9951 /// 9952 @safe unittest 9953 { 9954 import std.algorithm.comparison : equal; 9955 import std.algorithm.iteration : filter, joiner, map; 9956 import std.algorithm.searching : findSplitBefore; 9957 import std.uni : isUpper; 9958 9959 assert(equal(only('♡'), "♡")); 9960 assert([1, 2, 3, 4].findSplitBefore(only(3))[0] == [1, 2]); 9961 9962 assert(only("one", "two", "three").joiner(" ").equal("one two three")); 9963 9964 string title = "The D Programming Language"; 9965 assert(title 9966 .filter!isUpper // take the upper case letters 9967 .map!only // make each letter its own range 9968 .joiner(".") // join the ranges together lazily 9969 .equal("T.D.P.L")); 9970 } 9971 9972 @safe unittest 9973 { 9974 // Verify that the same common type and same arity 9975 // results in the same template instantiation 9976 static assert(is(typeof(only(byte.init, int.init)) == 9977 typeof(only(int.init, byte.init)))); 9978 9979 static assert(is(typeof(only((const(char)[]).init, string.init)) == 9980 typeof(only((const(char)[]).init, (const(char)[]).init)))); 9981 } 9982 9983 // https://issues.dlang.org/show_bug.cgi?id=20314 9984 @safe unittest 9985 { 9986 import std.algorithm.iteration : joiner; 9987 9988 const string s = "foo", t = "bar"; 9989 9990 assert([only(s, t), only(t, s)].joiner(only(", ")).join == "foobar, barfoo"); 9991 } 9992 9993 // Tests the zero-element result 9994 @safe unittest 9995 { 9996 import std.algorithm.comparison : equal; 9997 9998 auto emptyRange = only(); 9999 10000 alias EmptyRange = typeof(emptyRange); 10001 static assert(isInputRange!EmptyRange); 10002 static assert(isForwardRange!EmptyRange); 10003 static assert(isBidirectionalRange!EmptyRange); 10004 static assert(isRandomAccessRange!EmptyRange); 10005 static assert(hasLength!EmptyRange); 10006 static assert(hasSlicing!EmptyRange); 10007 10008 assert(emptyRange.empty); 10009 assert(emptyRange.length == 0); 10010 assert(emptyRange.equal(emptyRange[])); 10011 assert(emptyRange.equal(emptyRange.save)); 10012 assert(emptyRange[0 .. 0].equal(emptyRange)); 10013 } 10014 10015 // Tests the single-element result 10016 @safe unittest 10017 { 10018 import std.algorithm.comparison : equal; 10019 import std.typecons : tuple; 10020 foreach (x; tuple(1, '1', 1.0, "1", [1])) 10021 { 10022 auto a = only(x); 10023 typeof(x)[] e = []; 10024 assert(a.front == x); 10025 assert(a.back == x); 10026 assert(!a.empty); 10027 assert(a.length == 1); 10028 assert(equal(a, a[])); 10029 assert(equal(a, a[0 .. 1])); 10030 assert(equal(a[0 .. 0], e)); 10031 assert(equal(a[1 .. 1], e)); 10032 assert(a[0] == x); 10033 10034 auto b = a.save; 10035 assert(equal(a, b)); 10036 a.popFront(); 10037 assert(a.empty && a.length == 0 && a[].empty); 10038 b.popBack(); 10039 assert(b.empty && b.length == 0 && b[].empty); 10040 10041 alias A = typeof(a); 10042 static assert(isInputRange!A); 10043 static assert(isForwardRange!A); 10044 static assert(isBidirectionalRange!A); 10045 static assert(isRandomAccessRange!A); 10046 static assert(hasLength!A); 10047 static assert(hasSlicing!A); 10048 } 10049 10050 auto imm = only!(immutable int)(1); 10051 immutable int[] imme = []; 10052 assert(imm.front == 1); 10053 assert(imm.back == 1); 10054 assert(!imm.empty); 10055 assert(imm.init.empty); // https://issues.dlang.org/show_bug.cgi?id=13441 10056 assert(imm.length == 1); 10057 assert(equal(imm, imm[])); 10058 assert(equal(imm, imm[0 .. 1])); 10059 assert(equal(imm[0 .. 0], imme)); 10060 assert(equal(imm[1 .. 1], imme)); 10061 assert(imm[0] == 1); 10062 } 10063 10064 // Tests multiple-element results 10065 @safe unittest 10066 { 10067 import std.algorithm.comparison : equal; 10068 import std.algorithm.iteration : joiner; 10069 import std.meta : AliasSeq; 10070 static assert(!__traits(compiles, only(1, "1"))); 10071 10072 auto nums = only!(byte, uint, long)(1, 2, 3); 10073 static assert(is(ElementType!(typeof(nums)) == long)); 10074 assert(nums.length == 3); 10075 10076 foreach (i; 0 .. 3) 10077 assert(nums[i] == i + 1); 10078 10079 auto saved = nums.save; 10080 10081 foreach (i; 1 .. 4) 10082 { 10083 assert(nums.front == nums[0]); 10084 assert(nums.front == i); 10085 nums.popFront(); 10086 assert(nums.length == 3 - i); 10087 } 10088 10089 assert(nums.empty); 10090 10091 assert(saved.equal(only(1, 2, 3))); 10092 assert(saved.equal(saved[])); 10093 assert(saved[0 .. 1].equal(only(1))); 10094 assert(saved[0 .. 2].equal(only(1, 2))); 10095 assert(saved[0 .. 3].equal(saved)); 10096 assert(saved[1 .. 3].equal(only(2, 3))); 10097 assert(saved[2 .. 3].equal(only(3))); 10098 assert(saved[0 .. 0].empty); 10099 assert(saved[3 .. 3].empty); 10100 10101 alias data = AliasSeq!("one", "two", "three", "four"); 10102 static joined = 10103 ["one two", "one two three", "one two three four"]; 10104 string[] joinedRange = joined; 10105 10106 static foreach (argCount; 2 .. 5) 10107 {{ 10108 auto values = only(data[0 .. argCount]); 10109 alias Values = typeof(values); 10110 static assert(is(ElementType!Values == string)); 10111 static assert(isInputRange!Values); 10112 static assert(isForwardRange!Values); 10113 static assert(isBidirectionalRange!Values); 10114 static assert(isRandomAccessRange!Values); 10115 static assert(hasSlicing!Values); 10116 static assert(hasLength!Values); 10117 10118 assert(values.length == argCount); 10119 assert(values[0 .. $].equal(values[0 .. values.length])); 10120 assert(values.joiner(" ").equal(joinedRange.front)); 10121 joinedRange.popFront(); 10122 }} 10123 10124 assert(saved.retro.equal(only(3, 2, 1))); 10125 assert(saved.length == 3); 10126 10127 assert(saved.back == 3); 10128 saved.popBack(); 10129 assert(saved.length == 2); 10130 assert(saved.back == 2); 10131 10132 assert(saved.front == 1); 10133 saved.popFront(); 10134 assert(saved.length == 1); 10135 assert(saved.front == 2); 10136 10137 saved.popBack(); 10138 assert(saved.empty); 10139 10140 auto imm = only!(immutable int, immutable int)(42, 24); 10141 alias Imm = typeof(imm); 10142 static assert(is(ElementType!Imm == immutable(int))); 10143 assert(!imm.empty); 10144 assert(imm.init.empty); // https://issues.dlang.org/show_bug.cgi?id=13441 10145 assert(imm.front == 42); 10146 imm.popFront(); 10147 assert(imm.front == 24); 10148 imm.popFront(); 10149 assert(imm.empty); 10150 10151 static struct Test { int* a; } 10152 immutable(Test) test; 10153 cast(void) only(test, test); // Works with mutable indirection 10154 } 10155 10156 /** 10157 Iterate over `range` with an attached index variable. 10158 10159 Each element is a $(REF Tuple, std,typecons) containing the index 10160 and the element, in that order, where the index member is named `index` 10161 and the element member is named `value`. 10162 10163 The index starts at `start` and is incremented by one on every iteration. 10164 10165 Overflow: 10166 If `range` has length, then it is an error to pass a value for `start` 10167 so that `start + range.length` is bigger than `Enumerator.max`, thus 10168 it is ensured that overflow cannot happen. 10169 10170 If `range` does not have length, and `popFront` is called when 10171 `front.index == Enumerator.max`, the index will overflow and 10172 continue from `Enumerator.min`. 10173 10174 Params: 10175 range = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to attach indexes to 10176 start = the number to start the index counter from 10177 10178 Returns: 10179 At minimum, an input range. All other range primitives are given in the 10180 resulting range if `range` has them. The exceptions are the bidirectional 10181 primitives, which are propagated only if `range` has length. 10182 10183 Example: 10184 Useful for using `foreach` with an index loop variable: 10185 ---- 10186 import std.stdio : stdin, stdout; 10187 import std.range : enumerate; 10188 10189 foreach (lineNum, line; stdin.byLine().enumerate(1)) 10190 stdout.writefln("line #%s: %s", lineNum, line); 10191 ---- 10192 */ 10193 auto enumerate(Enumerator = size_t, Range)(Range range, Enumerator start = 0) 10194 if (isIntegral!Enumerator && isInputRange!Range) 10195 in 10196 { 10197 static if (hasLength!Range) 10198 { 10199 // TODO: core.checkedint supports mixed signedness yet? 10200 import core.checkedint : adds, addu; 10201 import std.conv : ConvException, to; 10202 import std.traits : isSigned, Largest, Signed; 10203 10204 alias LengthType = typeof(range.length); 10205 bool overflow; 10206 static if (isSigned!Enumerator && isSigned!LengthType) 10207 auto result = adds(start, range.length, overflow); 10208 else static if (isSigned!Enumerator) 10209 { 10210 Largest!(Enumerator, Signed!LengthType) signedLength; 10211 try signedLength = to!(typeof(signedLength))(range.length); 10212 catch (ConvException) 10213 overflow = true; 10214 catch (Exception) 10215 assert(false); 10216 10217 auto result = adds(start, signedLength, overflow); 10218 } 10219 else 10220 { 10221 static if (isSigned!LengthType) 10222 assert(range.length >= 0); 10223 auto result = addu(start, range.length, overflow); 10224 } 10225 10226 assert(!overflow && result <= Enumerator.max); 10227 } 10228 } 10229 do 10230 { 10231 // TODO: Relax isIntegral!Enumerator to allow user-defined integral types 10232 static struct Result 10233 { 10234 import std.typecons : Tuple; 10235 10236 private: 10237 alias ElemType = Tuple!(Enumerator, "index", ElementType!Range, "value"); 10238 Range range; 10239 Unqual!Enumerator index; 10240 10241 public: 10242 ElemType front() @property 10243 { 10244 assert(!range.empty, "Attempting to fetch the front of an empty enumerate"); 10245 return typeof(return)(index, range.front); 10246 } 10247 10248 static if (isInfinite!Range) 10249 enum bool empty = false; 10250 else 10251 { 10252 bool empty() @property 10253 { 10254 return range.empty; 10255 } 10256 } 10257 10258 void popFront() 10259 { 10260 assert(!range.empty, "Attempting to popFront an empty enumerate"); 10261 range.popFront(); 10262 ++index; // When !hasLength!Range, overflow is expected 10263 } 10264 10265 static if (isForwardRange!Range) 10266 { 10267 Result save() @property 10268 { 10269 return typeof(return)(range.save, index); 10270 } 10271 } 10272 10273 static if (hasLength!Range) 10274 { 10275 size_t length() @property 10276 { 10277 return range.length; 10278 } 10279 10280 alias opDollar = length; 10281 10282 static if (isBidirectionalRange!Range) 10283 { 10284 ElemType back() @property 10285 { 10286 assert(!range.empty, "Attempting to fetch the back of an empty enumerate"); 10287 return typeof(return)(cast(Enumerator)(index + range.length - 1), range.back); 10288 } 10289 10290 void popBack() 10291 { 10292 assert(!range.empty, "Attempting to popBack an empty enumerate"); 10293 range.popBack(); 10294 } 10295 } 10296 } 10297 10298 static if (isRandomAccessRange!Range) 10299 { 10300 ElemType opIndex(size_t i) 10301 { 10302 return typeof(return)(cast(Enumerator)(index + i), range[i]); 10303 } 10304 } 10305 10306 static if (hasSlicing!Range) 10307 { 10308 static if (hasLength!Range) 10309 { 10310 Result opSlice(size_t i, size_t j) 10311 { 10312 return typeof(return)(range[i .. j], cast(Enumerator)(index + i)); 10313 } 10314 } 10315 else 10316 { 10317 static struct DollarToken {} 10318 enum opDollar = DollarToken.init; 10319 10320 Result opSlice(size_t i, DollarToken) 10321 { 10322 return typeof(return)(range[i .. $], cast(Enumerator)(index + i)); 10323 } 10324 10325 auto opSlice(size_t i, size_t j) 10326 { 10327 return this[i .. $].takeExactly(j - 1); 10328 } 10329 } 10330 } 10331 } 10332 10333 return Result(range, start); 10334 } 10335 10336 /// Can start enumeration from a negative position: 10337 pure @safe nothrow unittest 10338 { 10339 import std.array : assocArray; 10340 import std.range : enumerate; 10341 10342 bool[int] aa = true.repeat(3).enumerate(-1).assocArray(); 10343 assert(aa[-1]); 10344 assert(aa[0]); 10345 assert(aa[1]); 10346 } 10347 10348 // Make sure passing qualified types works 10349 pure @safe nothrow unittest 10350 { 10351 char[4] v; 10352 immutable start = 2; 10353 v[2 .. $].enumerate(start); 10354 } 10355 10356 pure @safe nothrow unittest 10357 { 10358 import std.internal.test.dummyrange : AllDummyRanges; 10359 import std.meta : AliasSeq; 10360 import std.typecons : tuple; 10361 10362 static struct HasSlicing 10363 { 10364 typeof(this) front() @property { return typeof(this).init; } 10365 bool empty() @property { return true; } 10366 void popFront() {} 10367 10368 typeof(this) opSlice(size_t, size_t) 10369 { 10370 return typeof(this)(); 10371 } 10372 } 10373 10374 static foreach (DummyType; AliasSeq!(AllDummyRanges, HasSlicing)) 10375 {{ 10376 alias R = typeof(enumerate(DummyType.init)); 10377 static assert(isInputRange!R); 10378 static assert(isForwardRange!R == isForwardRange!DummyType); 10379 static assert(isRandomAccessRange!R == isRandomAccessRange!DummyType); 10380 static assert(!hasAssignableElements!R); 10381 10382 static if (hasLength!DummyType) 10383 { 10384 static assert(hasLength!R); 10385 static assert(isBidirectionalRange!R == 10386 isBidirectionalRange!DummyType); 10387 } 10388 10389 static assert(hasSlicing!R == hasSlicing!DummyType); 10390 }} 10391 10392 static immutable values = ["zero", "one", "two", "three"]; 10393 auto enumerated = values[].enumerate(); 10394 assert(!enumerated.empty); 10395 assert(enumerated.front == tuple(0, "zero")); 10396 assert(enumerated.back == tuple(3, "three")); 10397 10398 typeof(enumerated) saved = enumerated.save; 10399 saved.popFront(); 10400 assert(enumerated.front == tuple(0, "zero")); 10401 assert(saved.front == tuple(1, "one")); 10402 assert(saved.length == enumerated.length - 1); 10403 saved.popBack(); 10404 assert(enumerated.back == tuple(3, "three")); 10405 assert(saved.back == tuple(2, "two")); 10406 saved.popFront(); 10407 assert(saved.front == tuple(2, "two")); 10408 assert(saved.back == tuple(2, "two")); 10409 saved.popFront(); 10410 assert(saved.empty); 10411 10412 size_t control = 0; 10413 foreach (i, v; enumerated) 10414 { 10415 static assert(is(typeof(i) == size_t)); 10416 static assert(is(typeof(v) == typeof(values[0]))); 10417 assert(i == control); 10418 assert(v == values[i]); 10419 assert(tuple(i, v) == enumerated[i]); 10420 ++control; 10421 } 10422 10423 assert(enumerated[0 .. $].front == tuple(0, "zero")); 10424 assert(enumerated[$ - 1 .. $].front == tuple(3, "three")); 10425 10426 foreach (i; 0 .. 10) 10427 { 10428 auto shifted = values[0 .. 2].enumerate(i); 10429 assert(shifted.front == tuple(i, "zero")); 10430 assert(shifted[0] == shifted.front); 10431 10432 auto next = tuple(i + 1, "one"); 10433 assert(shifted[1] == next); 10434 shifted.popFront(); 10435 assert(shifted.front == next); 10436 shifted.popFront(); 10437 assert(shifted.empty); 10438 } 10439 10440 static foreach (T; AliasSeq!(ubyte, byte, uint, int)) 10441 {{ 10442 auto inf = 42.repeat().enumerate(T.max); 10443 alias Inf = typeof(inf); 10444 static assert(isInfinite!Inf); 10445 static assert(hasSlicing!Inf); 10446 10447 // test overflow 10448 assert(inf.front == tuple(T.max, 42)); 10449 inf.popFront(); 10450 assert(inf.front == tuple(T.min, 42)); 10451 10452 // test slicing 10453 inf = inf[42 .. $]; 10454 assert(inf.front == tuple(T.min + 42, 42)); 10455 auto window = inf[0 .. 2]; 10456 assert(window.length == 1); 10457 assert(window.front == inf.front); 10458 window.popFront(); 10459 assert(window.empty); 10460 }} 10461 } 10462 10463 pure @safe unittest 10464 { 10465 import std.algorithm.comparison : equal; 10466 import std.meta : AliasSeq; 10467 static immutable int[] values = [0, 1, 2, 3, 4]; 10468 static foreach (T; AliasSeq!(ubyte, ushort, uint, ulong)) 10469 {{ 10470 auto enumerated = values.enumerate!T(); 10471 static assert(is(typeof(enumerated.front.index) == T)); 10472 assert(enumerated.equal(values[].zip(values))); 10473 10474 foreach (T i; 0 .. 5) 10475 { 10476 auto subset = values[cast(size_t) i .. $]; 10477 auto offsetEnumerated = subset.enumerate(i); 10478 static assert(is(typeof(enumerated.front.index) == T)); 10479 assert(offsetEnumerated.equal(subset.zip(subset))); 10480 } 10481 }} 10482 } 10483 10484 // https://issues.dlang.org/show_bug.cgi?id=10939 10485 version (none) 10486 { 10487 // Re-enable (or remove) if 10939 is resolved. 10488 /+pure+/ @safe unittest // Impure because of std.conv.to 10489 { 10490 import core.exception : RangeError; 10491 import std.exception : assertNotThrown, assertThrown; 10492 import std.meta : AliasSeq; 10493 10494 static immutable values = [42]; 10495 10496 static struct SignedLengthRange 10497 { 10498 immutable(int)[] _values = values; 10499 10500 int front() @property { assert(false); } 10501 bool empty() @property { assert(false); } 10502 void popFront() { assert(false); } 10503 10504 int length() @property 10505 { 10506 return cast(int)_values.length; 10507 } 10508 } 10509 10510 SignedLengthRange svalues; 10511 static foreach (Enumerator; AliasSeq!(ubyte, byte, ushort, short, uint, int, ulong, long)) 10512 { 10513 assertThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max)); 10514 assertNotThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max - values.length)); 10515 assertThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max - values.length + 1)); 10516 10517 assertThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max)); 10518 assertNotThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max - values.length)); 10519 assertThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max - values.length + 1)); 10520 } 10521 10522 static foreach (Enumerator; AliasSeq!(byte, short, int)) 10523 { 10524 assertThrown!RangeError(repeat(0, uint.max).enumerate!Enumerator()); 10525 } 10526 10527 assertNotThrown!RangeError(repeat(0, uint.max).enumerate!long()); 10528 } 10529 } 10530 10531 /** 10532 Returns true if `fn` accepts variables of type T1 and T2 in any order. 10533 The following code should compile: 10534 --- 10535 (ref T1 a, ref T2 b) 10536 { 10537 fn(a, b); 10538 fn(b, a); 10539 } 10540 --- 10541 */ 10542 template isTwoWayCompatible(alias fn, T1, T2) 10543 { 10544 enum isTwoWayCompatible = is(typeof((ref T1 a, ref T2 b) 10545 { 10546 cast(void) fn(a, b); 10547 cast(void) fn(b, a); 10548 } 10549 )); 10550 } 10551 10552 /// 10553 @safe unittest 10554 { 10555 void func1(int a, int b); 10556 void func2(int a, float b); 10557 10558 static assert(isTwoWayCompatible!(func1, int, int)); 10559 static assert(isTwoWayCompatible!(func1, short, int)); 10560 static assert(!isTwoWayCompatible!(func2, int, float)); 10561 10562 void func3(ref int a, ref int b); 10563 static assert( isTwoWayCompatible!(func3, int, int)); 10564 static assert(!isTwoWayCompatible!(func3, short, int)); 10565 } 10566 10567 10568 /** 10569 Policy used with the searching primitives `lowerBound`, $(D 10570 upperBound), and `equalRange` of $(LREF SortedRange) below. 10571 */ 10572 enum SearchPolicy 10573 { 10574 /** 10575 Searches in a linear fashion. 10576 */ 10577 linear, 10578 10579 /** 10580 Searches with a step that is grows linearly (1, 2, 3,...) 10581 leading to a quadratic search schedule (indexes tried are 0, 1, 10582 3, 6, 10, 15, 21, 28,...) Once the search overshoots its target, 10583 the remaining interval is searched using binary search. The 10584 search is completed in $(BIGOH sqrt(n)) time. Use it when you 10585 are reasonably confident that the value is around the beginning 10586 of the range. 10587 */ 10588 trot, 10589 10590 /** 10591 Performs a $(LINK2 https://en.wikipedia.org/wiki/Exponential_search, 10592 galloping search algorithm), i.e. searches 10593 with a step that doubles every time, (1, 2, 4, 8, ...) leading 10594 to an exponential search schedule (indexes tried are 0, 1, 3, 10595 7, 15, 31, 63,...) Once the search overshoots its target, the 10596 remaining interval is searched using binary search. A value is 10597 found in $(BIGOH log(n)) time. 10598 */ 10599 gallop, 10600 10601 /** 10602 Searches using a classic interval halving policy. The search 10603 starts in the middle of the range, and each search step cuts 10604 the range in half. This policy finds a value in $(BIGOH log(n)) 10605 time but is less cache friendly than `gallop` for large 10606 ranges. The `binarySearch` policy is used as the last step 10607 of `trot`, `gallop`, `trotBackwards`, and $(D 10608 gallopBackwards) strategies. 10609 */ 10610 binarySearch, 10611 10612 /** 10613 Similar to `trot` but starts backwards. Use it when 10614 confident that the value is around the end of the range. 10615 */ 10616 trotBackwards, 10617 10618 /** 10619 Similar to `gallop` but starts backwards. Use it when 10620 confident that the value is around the end of the range. 10621 */ 10622 gallopBackwards 10623 } 10624 10625 /// 10626 @safe unittest 10627 { 10628 import std.algorithm.comparison : equal; 10629 10630 auto a = assumeSorted([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); 10631 auto p1 = a.upperBound!(SearchPolicy.binarySearch)(3); 10632 assert(p1.equal([4, 5, 6, 7, 8, 9])); 10633 10634 auto p2 = a.lowerBound!(SearchPolicy.gallop)(4); 10635 assert(p2.equal([0, 1, 2, 3])); 10636 } 10637 10638 /** 10639 Options for $(LREF SortedRange) ranges (below). 10640 */ 10641 enum SortedRangeOptions 10642 { 10643 /** 10644 Assume, that the range is sorted without checking. 10645 */ 10646 assumeSorted, 10647 10648 /** 10649 All elements of the range are checked to be sorted. 10650 The check is performed in O(n) time. 10651 */ 10652 checkStrictly, 10653 10654 /** 10655 Some elements of the range are checked to be sorted. 10656 For ranges with random order, this will almost surely 10657 detect, that it is not sorted. For almost sorted ranges 10658 it's more likely to fail. The checked elements are choosen 10659 in a deterministic manner, which makes this check reproducable. 10660 The check is performed in O(log(n)) time. 10661 */ 10662 checkRoughly, 10663 } 10664 10665 /// 10666 @safe pure unittest 10667 { 10668 // create a SortedRange, that's checked strictly 10669 SortedRange!(int[],"a < b", SortedRangeOptions.checkStrictly)([ 1, 3, 5, 7, 9 ]); 10670 } 10671 10672 /** 10673 Represents a sorted range. In addition to the regular range 10674 primitives, supports additional operations that take advantage of the 10675 ordering, such as merge and binary search. To obtain a $(D 10676 SortedRange) from an unsorted range `r`, use 10677 $(REF sort, std,algorithm,sorting) which sorts `r` in place and returns the 10678 corresponding `SortedRange`. To construct a `SortedRange` from a range 10679 `r` that is known to be already sorted, use $(LREF assumeSorted). 10680 10681 Params: 10682 pred: The predicate used to define the sortedness 10683 opt: Controls how strongly the range is checked for sortedness. 10684 Will only be used for `RandomAccessRanges`. 10685 Will not be used in CTFE. 10686 */ 10687 struct SortedRange(Range, alias pred = "a < b", 10688 SortedRangeOptions opt = SortedRangeOptions.assumeSorted) 10689 if (isInputRange!Range && !isInstanceOf!(SortedRange, Range)) 10690 { 10691 import std.functional : binaryFun; 10692 10693 private alias predFun = binaryFun!pred; 10694 private bool geq(L, R)(L lhs, R rhs) 10695 { 10696 return !predFun(lhs, rhs); 10697 } 10698 private bool gt(L, R)(L lhs, R rhs) 10699 { 10700 return predFun(rhs, lhs); 10701 } 10702 private Range _input; 10703 10704 // Undocummented because a clearer way to invoke is by calling 10705 // assumeSorted. 10706 this(Range input) 10707 { 10708 static if (opt == SortedRangeOptions.checkRoughly) 10709 { 10710 roughlyVerifySorted(input); 10711 } 10712 static if (opt == SortedRangeOptions.checkStrictly) 10713 { 10714 strictlyVerifySorted(input); 10715 } 10716 this._input = input; 10717 } 10718 10719 // Assertion only. 10720 static if (opt == SortedRangeOptions.checkRoughly) 10721 private void roughlyVerifySorted(Range r) 10722 { 10723 if (!__ctfe) 10724 { 10725 static if (isRandomAccessRange!Range && hasLength!Range) 10726 { 10727 import core.bitop : bsr; 10728 import std.algorithm.sorting : isSorted; 10729 import std.exception : enforce; 10730 10731 // Check the sortedness of the input 10732 if (r.length < 2) return; 10733 10734 immutable size_t msb = bsr(r.length) + 1; 10735 assert(msb > 0 && msb <= r.length); 10736 immutable step = r.length / msb; 10737 auto st = stride(r, step); 10738 10739 enforce(isSorted!pred(st), "Range is not sorted"); 10740 } 10741 } 10742 } 10743 10744 // Assertion only. 10745 static if (opt == SortedRangeOptions.checkStrictly) 10746 private void strictlyVerifySorted(Range r) 10747 { 10748 if (!__ctfe) 10749 { 10750 static if (isRandomAccessRange!Range && hasLength!Range) 10751 { 10752 import std.algorithm.sorting : isSorted; 10753 import std.exception : enforce; 10754 10755 enforce(isSorted!pred(r), "Range is not sorted"); 10756 } 10757 } 10758 } 10759 10760 /// Range primitives. 10761 @property bool empty() //const 10762 { 10763 return this._input.empty; 10764 } 10765 10766 /// Ditto 10767 static if (isForwardRange!Range) 10768 @property auto save() 10769 { 10770 // Avoid the constructor 10771 typeof(this) result = this; 10772 result._input = _input.save; 10773 return result; 10774 } 10775 10776 /// Ditto 10777 @property auto ref front() 10778 { 10779 return _input.front; 10780 } 10781 10782 /// Ditto 10783 void popFront() 10784 { 10785 _input.popFront(); 10786 } 10787 10788 /// Ditto 10789 static if (isBidirectionalRange!Range) 10790 { 10791 @property auto ref back() 10792 { 10793 return _input.back; 10794 } 10795 10796 /// Ditto 10797 void popBack() 10798 { 10799 _input.popBack(); 10800 } 10801 } 10802 10803 /// Ditto 10804 static if (isRandomAccessRange!Range) 10805 auto ref opIndex(size_t i) 10806 { 10807 return _input[i]; 10808 } 10809 10810 /// Ditto 10811 static if (hasSlicing!Range) 10812 auto opSlice(size_t a, size_t b) return scope 10813 { 10814 assert( 10815 a <= b, 10816 "Attempting to slice a SortedRange with a larger first argument than the second." 10817 ); 10818 typeof(this) result = this; 10819 result._input = _input[a .. b];// skip checking 10820 return result; 10821 } 10822 10823 /// Ditto 10824 static if (hasLength!Range) 10825 { 10826 @property size_t length() //const 10827 { 10828 return _input.length; 10829 } 10830 alias opDollar = length; 10831 } 10832 10833 /** 10834 Releases the controlled range and returns it. 10835 */ 10836 auto release() 10837 { 10838 import std.algorithm.mutation : move; 10839 return move(_input); 10840 } 10841 10842 // Assuming a predicate "test" that returns 0 for a left portion 10843 // of the range and then 1 for the rest, returns the index at 10844 // which the first 1 appears. Used internally by the search routines. 10845 private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v) 10846 if (sp == SearchPolicy.binarySearch && isRandomAccessRange!Range && hasLength!Range) 10847 { 10848 size_t first = 0, count = _input.length; 10849 while (count > 0) 10850 { 10851 immutable step = count / 2, it = first + step; 10852 if (!test(_input[it], v)) 10853 { 10854 first = it + 1; 10855 count -= step + 1; 10856 } 10857 else 10858 { 10859 count = step; 10860 } 10861 } 10862 return first; 10863 } 10864 10865 // Specialization for trot and gallop 10866 private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v) 10867 if ((sp == SearchPolicy.trot || sp == SearchPolicy.gallop) 10868 && isRandomAccessRange!Range) 10869 { 10870 if (empty || test(front, v)) return 0; 10871 immutable count = length; 10872 if (count == 1) return 1; 10873 size_t below = 0, above = 1, step = 2; 10874 while (!test(_input[above], v)) 10875 { 10876 // Still too small, update below and increase gait 10877 below = above; 10878 immutable next = above + step; 10879 if (next >= count) 10880 { 10881 // Overshot - the next step took us beyond the end. So 10882 // now adjust next and simply exit the loop to do the 10883 // binary search thingie. 10884 above = count; 10885 break; 10886 } 10887 // Still in business, increase step and continue 10888 above = next; 10889 static if (sp == SearchPolicy.trot) 10890 ++step; 10891 else 10892 step <<= 1; 10893 } 10894 return below + this[below .. above].getTransitionIndex!( 10895 SearchPolicy.binarySearch, test, V)(v); 10896 } 10897 10898 // Specialization for trotBackwards and gallopBackwards 10899 private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v) 10900 if ((sp == SearchPolicy.trotBackwards || sp == SearchPolicy.gallopBackwards) 10901 && isRandomAccessRange!Range) 10902 { 10903 immutable count = length; 10904 if (empty || !test(back, v)) return count; 10905 if (count == 1) return 0; 10906 size_t below = count - 2, above = count - 1, step = 2; 10907 while (test(_input[below], v)) 10908 { 10909 // Still too large, update above and increase gait 10910 above = below; 10911 if (below < step) 10912 { 10913 // Overshot - the next step took us beyond the end. So 10914 // now adjust next and simply fall through to do the 10915 // binary search thingie. 10916 below = 0; 10917 break; 10918 } 10919 // Still in business, increase step and continue 10920 below -= step; 10921 static if (sp == SearchPolicy.trot) 10922 ++step; 10923 else 10924 step <<= 1; 10925 } 10926 return below + this[below .. above].getTransitionIndex!( 10927 SearchPolicy.binarySearch, test, V)(v); 10928 } 10929 10930 // lowerBound 10931 /** 10932 This function uses a search with policy `sp` to find the 10933 largest left subrange on which $(D pred(x, value)) is `true` for 10934 all `x` (e.g., if `pred` is "less than", returns the portion of 10935 the range with elements strictly smaller than `value`). The search 10936 schedule and its complexity are documented in 10937 $(LREF SearchPolicy). 10938 */ 10939 auto lowerBound(SearchPolicy sp = SearchPolicy.binarySearch, V)(V value) 10940 if (isTwoWayCompatible!(predFun, ElementType!Range, V) 10941 && hasSlicing!Range) 10942 { 10943 return this[0 .. getTransitionIndex!(sp, geq)(value)]; 10944 } 10945 10946 /// 10947 static if (is(Range : int[])) 10948 @safe unittest 10949 { 10950 import std.algorithm.comparison : equal; 10951 auto a = assumeSorted([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]); 10952 auto p = a.lowerBound(4); 10953 assert(equal(p, [ 0, 1, 2, 3 ])); 10954 } 10955 10956 // upperBound 10957 /** 10958 This function searches with policy `sp` to find the largest right 10959 subrange on which $(D pred(value, x)) is `true` for all `x` 10960 (e.g., if `pred` is "less than", returns the portion of the range 10961 with elements strictly greater than `value`). The search schedule 10962 and its complexity are documented in $(LREF SearchPolicy). 10963 10964 For ranges that do not offer random access, `SearchPolicy.linear` 10965 is the only policy allowed (and it must be specified explicitly lest it exposes 10966 user code to unexpected inefficiencies). For random-access searches, all 10967 policies are allowed, and `SearchPolicy.binarySearch` is the default. 10968 */ 10969 auto upperBound(SearchPolicy sp = SearchPolicy.binarySearch, V)(V value) 10970 if (isTwoWayCompatible!(predFun, ElementType!Range, V)) 10971 { 10972 static assert(hasSlicing!Range || sp == SearchPolicy.linear, 10973 "Specify SearchPolicy.linear explicitly for " 10974 ~ typeof(this).stringof); 10975 static if (sp == SearchPolicy.linear) 10976 { 10977 for (; !_input.empty && !predFun(value, _input.front); 10978 _input.popFront()) 10979 { 10980 } 10981 return this; 10982 } 10983 else 10984 { 10985 return this[getTransitionIndex!(sp, gt)(value) .. length]; 10986 } 10987 } 10988 10989 /// 10990 static if (is(Range : int[])) 10991 @safe unittest 10992 { 10993 import std.algorithm.comparison : equal; 10994 auto a = assumeSorted([ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]); 10995 auto p = a.upperBound(3); 10996 assert(equal(p, [4, 4, 5, 6])); 10997 } 10998 10999 11000 // equalRange 11001 /** 11002 Returns the subrange containing all elements `e` for which both $(D 11003 pred(e, value)) and $(D pred(value, e)) evaluate to `false` (e.g., 11004 if `pred` is "less than", returns the portion of the range with 11005 elements equal to `value`). Uses a classic binary search with 11006 interval halving until it finds a value that satisfies the condition, 11007 then uses `SearchPolicy.gallopBackwards` to find the left boundary 11008 and `SearchPolicy.gallop` to find the right boundary. These 11009 policies are justified by the fact that the two boundaries are likely 11010 to be near the first found value (i.e., equal ranges are relatively 11011 small). Completes the entire search in $(BIGOH log(n)) time. 11012 */ 11013 auto equalRange(V)(V value) 11014 if (isTwoWayCompatible!(predFun, ElementType!Range, V) 11015 && isRandomAccessRange!Range) 11016 { 11017 size_t first = 0, count = _input.length; 11018 while (count > 0) 11019 { 11020 immutable step = count / 2; 11021 auto it = first + step; 11022 if (predFun(_input[it], value)) 11023 { 11024 // Less than value, bump left bound up 11025 first = it + 1; 11026 count -= step + 1; 11027 } 11028 else if (predFun(value, _input[it])) 11029 { 11030 // Greater than value, chop count 11031 count = step; 11032 } 11033 else 11034 { 11035 // Equal to value, do binary searches in the 11036 // leftover portions 11037 // Gallop towards the left end as it's likely nearby 11038 immutable left = first 11039 + this[first .. it] 11040 .lowerBound!(SearchPolicy.gallopBackwards)(value).length; 11041 first += count; 11042 // Gallop towards the right end as it's likely nearby 11043 immutable right = first 11044 - this[it + 1 .. first] 11045 .upperBound!(SearchPolicy.gallop)(value).length; 11046 return this[left .. right]; 11047 } 11048 } 11049 return this.init; 11050 } 11051 11052 /// 11053 static if (is(Range : int[])) 11054 @safe unittest 11055 { 11056 import std.algorithm.comparison : equal; 11057 auto a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]; 11058 auto r = a.assumeSorted.equalRange(3); 11059 assert(equal(r, [ 3, 3, 3 ])); 11060 } 11061 11062 // trisect 11063 /** 11064 Returns a tuple `r` such that `r[0]` is the same as the result 11065 of `lowerBound(value)`, `r[1]` is the same as the result of $(D 11066 equalRange(value)), and `r[2]` is the same as the result of $(D 11067 upperBound(value)). The call is faster than computing all three 11068 separately. Uses a search schedule similar to $(D 11069 equalRange). Completes the entire search in $(BIGOH log(n)) time. 11070 */ 11071 auto trisect(V)(V value) 11072 if (isTwoWayCompatible!(predFun, ElementType!Range, V) 11073 && isRandomAccessRange!Range && hasLength!Range) 11074 { 11075 import std.typecons : tuple; 11076 size_t first = 0, count = _input.length; 11077 while (count > 0) 11078 { 11079 immutable step = count / 2; 11080 auto it = first + step; 11081 if (predFun(_input[it], value)) 11082 { 11083 // Less than value, bump left bound up 11084 first = it + 1; 11085 count -= step + 1; 11086 } 11087 else if (predFun(value, _input[it])) 11088 { 11089 // Greater than value, chop count 11090 count = step; 11091 } 11092 else 11093 { 11094 // Equal to value, do binary searches in the 11095 // leftover portions 11096 // Gallop towards the left end as it's likely nearby 11097 immutable left = first 11098 + this[first .. it] 11099 .lowerBound!(SearchPolicy.gallopBackwards)(value).length; 11100 first += count; 11101 // Gallop towards the right end as it's likely nearby 11102 immutable right = first 11103 - this[it + 1 .. first] 11104 .upperBound!(SearchPolicy.gallop)(value).length; 11105 return tuple(this[0 .. left], this[left .. right], 11106 this[right .. length]); 11107 } 11108 } 11109 // No equal element was found 11110 return tuple(this[0 .. first], this.init, this[first .. length]); 11111 } 11112 11113 /// 11114 static if (is(Range : int[])) 11115 @safe unittest 11116 { 11117 import std.algorithm.comparison : equal; 11118 auto a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]; 11119 auto r = assumeSorted(a).trisect(3); 11120 assert(equal(r[0], [ 1, 2 ])); 11121 assert(equal(r[1], [ 3, 3, 3 ])); 11122 assert(equal(r[2], [ 4, 4, 5, 6 ])); 11123 } 11124 11125 // contains 11126 /** 11127 Returns `true` if and only if `value` can be found in $(D 11128 range), which is assumed to be sorted. Performs $(BIGOH log(r.length)) 11129 evaluations of `pred`. 11130 */ 11131 11132 bool contains(V)(V value) 11133 if (isRandomAccessRange!Range) 11134 { 11135 if (empty) return false; 11136 immutable i = getTransitionIndex!(SearchPolicy.binarySearch, geq)(value); 11137 if (i >= length) return false; 11138 return !predFun(value, _input[i]); 11139 } 11140 11141 /** 11142 Like `contains`, but the value is specified before the range. 11143 */ 11144 bool opBinaryRight(string op, V)(V value) 11145 if (op == "in" && isRandomAccessRange!Range) 11146 { 11147 return contains(value); 11148 } 11149 11150 // groupBy 11151 /** 11152 Returns a range of subranges of elements that are equivalent according to the 11153 sorting relation. 11154 */ 11155 auto groupBy()() 11156 { 11157 import std.algorithm.iteration : chunkBy; 11158 return _input.chunkBy!((a, b) => !predFun(a, b) && !predFun(b, a)); 11159 } 11160 } 11161 11162 /// ditto 11163 template SortedRange(Range, alias pred = "a < b", 11164 SortedRangeOptions opt = SortedRangeOptions.assumeSorted) 11165 if (isInstanceOf!(SortedRange, Range)) 11166 { 11167 // Avoid nesting SortedRange types (see https://issues.dlang.org/show_bug.cgi?id=18933); 11168 alias SortedRange = SortedRange!(Unqual!(typeof(Range._input)), pred, opt); 11169 } 11170 11171 /// 11172 @safe unittest 11173 { 11174 import std.algorithm.sorting : sort; 11175 auto a = [ 1, 2, 3, 42, 52, 64 ]; 11176 auto r = assumeSorted(a); 11177 assert(r.contains(3)); 11178 assert(!(32 in r)); 11179 auto r1 = sort!"a > b"(a); 11180 assert(3 in r1); 11181 assert(!r1.contains(32)); 11182 assert(r1.release() == [ 64, 52, 42, 3, 2, 1 ]); 11183 } 11184 11185 /** 11186 `SortedRange` could accept ranges weaker than random-access, but it 11187 is unable to provide interesting functionality for them. Therefore, 11188 `SortedRange` is currently restricted to random-access ranges. 11189 11190 No copy of the original range is ever made. If the underlying range is 11191 changed concurrently with its corresponding `SortedRange` in ways 11192 that break its sorted-ness, `SortedRange` will work erratically. 11193 */ 11194 @safe unittest 11195 { 11196 import std.algorithm.mutation : swap; 11197 auto a = [ 1, 2, 3, 42, 52, 64 ]; 11198 auto r = assumeSorted(a); 11199 assert(r.contains(42)); 11200 swap(a[3], a[5]); // illegal to break sortedness of original range 11201 assert(!r.contains(42)); // passes although it shouldn't 11202 } 11203 11204 @safe unittest 11205 { 11206 import std.exception : assertThrown, assertNotThrown; 11207 11208 assertNotThrown(SortedRange!(int[])([ 1, 3, 10, 5, 7 ])); 11209 assertThrown(SortedRange!(int[],"a < b", SortedRangeOptions.checkStrictly)([ 1, 3, 10, 5, 7 ])); 11210 11211 // these two checks are implementation depended 11212 assertNotThrown(SortedRange!(int[],"a < b", SortedRangeOptions.checkRoughly)([ 1, 3, 10, 5, 12, 2 ])); 11213 assertThrown(SortedRange!(int[],"a < b", SortedRangeOptions.checkRoughly)([ 1, 3, 10, 5, 2, 12 ])); 11214 } 11215 11216 @safe unittest 11217 { 11218 import std.algorithm.comparison : equal; 11219 11220 auto a = [ 10, 20, 30, 30, 30, 40, 40, 50, 60 ]; 11221 auto r = assumeSorted(a).trisect(30); 11222 assert(equal(r[0], [ 10, 20 ])); 11223 assert(equal(r[1], [ 30, 30, 30 ])); 11224 assert(equal(r[2], [ 40, 40, 50, 60 ])); 11225 11226 r = assumeSorted(a).trisect(35); 11227 assert(equal(r[0], [ 10, 20, 30, 30, 30 ])); 11228 assert(r[1].empty); 11229 assert(equal(r[2], [ 40, 40, 50, 60 ])); 11230 } 11231 11232 @safe unittest 11233 { 11234 import std.algorithm.comparison : equal; 11235 auto a = [ "A", "AG", "B", "E", "F" ]; 11236 auto r = assumeSorted!"cmp(a,b) < 0"(a).trisect("B"w); 11237 assert(equal(r[0], [ "A", "AG" ])); 11238 assert(equal(r[1], [ "B" ])); 11239 assert(equal(r[2], [ "E", "F" ])); 11240 r = assumeSorted!"cmp(a,b) < 0"(a).trisect("A"d); 11241 assert(r[0].empty); 11242 assert(equal(r[1], [ "A" ])); 11243 assert(equal(r[2], [ "AG", "B", "E", "F" ])); 11244 } 11245 11246 @safe unittest 11247 { 11248 import std.algorithm.comparison : equal; 11249 static void test(SearchPolicy pol)() 11250 { 11251 auto a = [ 1, 2, 3, 42, 52, 64 ]; 11252 auto r = assumeSorted(a); 11253 assert(equal(r.lowerBound(42), [1, 2, 3])); 11254 11255 assert(equal(r.lowerBound!(pol)(42), [1, 2, 3])); 11256 assert(equal(r.lowerBound!(pol)(41), [1, 2, 3])); 11257 assert(equal(r.lowerBound!(pol)(43), [1, 2, 3, 42])); 11258 assert(equal(r.lowerBound!(pol)(51), [1, 2, 3, 42])); 11259 assert(equal(r.lowerBound!(pol)(3), [1, 2])); 11260 assert(equal(r.lowerBound!(pol)(55), [1, 2, 3, 42, 52])); 11261 assert(equal(r.lowerBound!(pol)(420), a)); 11262 assert(equal(r.lowerBound!(pol)(0), a[0 .. 0])); 11263 11264 assert(equal(r.upperBound!(pol)(42), [52, 64])); 11265 assert(equal(r.upperBound!(pol)(41), [42, 52, 64])); 11266 assert(equal(r.upperBound!(pol)(43), [52, 64])); 11267 assert(equal(r.upperBound!(pol)(51), [52, 64])); 11268 assert(equal(r.upperBound!(pol)(53), [64])); 11269 assert(equal(r.upperBound!(pol)(55), [64])); 11270 assert(equal(r.upperBound!(pol)(420), a[0 .. 0])); 11271 assert(equal(r.upperBound!(pol)(0), a)); 11272 } 11273 11274 test!(SearchPolicy.trot)(); 11275 test!(SearchPolicy.gallop)(); 11276 test!(SearchPolicy.trotBackwards)(); 11277 test!(SearchPolicy.gallopBackwards)(); 11278 test!(SearchPolicy.binarySearch)(); 11279 } 11280 11281 @safe unittest 11282 { 11283 // Check for small arrays 11284 int[] a; 11285 auto r = assumeSorted(a); 11286 a = [ 1 ]; 11287 r = assumeSorted(a); 11288 a = [ 1, 2 ]; 11289 r = assumeSorted(a); 11290 a = [ 1, 2, 3 ]; 11291 r = assumeSorted(a); 11292 } 11293 11294 @safe unittest 11295 { 11296 import std.algorithm.mutation : swap; 11297 auto a = [ 1, 2, 3, 42, 52, 64 ]; 11298 auto r = assumeSorted(a); 11299 assert(r.contains(42)); 11300 swap(a[3], a[5]); // illegal to break sortedness of original range 11301 assert(!r.contains(42)); // passes although it shouldn't 11302 } 11303 11304 @betterC @nogc nothrow @safe unittest 11305 { 11306 static immutable(int)[] arr = [ 1, 2, 3 ]; 11307 auto s = assumeSorted(arr); 11308 } 11309 11310 @system unittest 11311 { 11312 import std.algorithm.comparison : equal; 11313 int[] arr = [100, 101, 102, 200, 201, 300]; 11314 auto s = assumeSorted!((a, b) => a / 100 < b / 100)(arr); 11315 assert(s.groupBy.equal!equal([[100, 101, 102], [200, 201], [300]])); 11316 } 11317 11318 // Test on an input range 11319 @system unittest 11320 { 11321 import std.conv : text; 11322 import std.file : exists, remove, tempDir; 11323 import std.path : buildPath; 11324 import std.stdio : File; 11325 import std.uuid : randomUUID; 11326 auto name = buildPath(tempDir(), "test.std.range.line-" ~ text(__LINE__) ~ 11327 "." ~ randomUUID().toString()); 11328 auto f = File(name, "w"); 11329 scope(exit) if (exists(name)) remove(name); 11330 // write a sorted range of lines to the file 11331 f.write("abc\ndef\nghi\njkl"); 11332 f.close(); 11333 f.open(name, "r"); 11334 auto r = assumeSorted(f.byLine()); 11335 auto r1 = r.upperBound!(SearchPolicy.linear)("def"); 11336 assert(r1.front == "ghi", r1.front); 11337 f.close(); 11338 } 11339 11340 // https://issues.dlang.org/show_bug.cgi?id=19337 11341 @safe unittest 11342 { 11343 import std.algorithm.sorting : sort; 11344 auto a = [ 1, 2, 3, 42, 52, 64 ]; 11345 a.sort.sort!"a > b"; 11346 } 11347 11348 /** 11349 Assumes `r` is sorted by predicate `pred` and returns the 11350 corresponding $(D SortedRange!(pred, R)) having `r` as support. 11351 To check for sorted-ness at 11352 cost $(BIGOH n), use $(REF isSorted, std,algorithm,sorting). 11353 */ 11354 auto assumeSorted(alias pred = "a < b", R)(R r) 11355 if (isInputRange!(Unqual!R)) 11356 { 11357 // Avoid senseless `SortedRange!(SortedRange!(...), pred)` nesting. 11358 static if (is(R == SortedRange!(RRange, RPred), RRange, alias RPred)) 11359 { 11360 static if (isInputRange!R && __traits(isSame, pred, RPred)) 11361 // If the predicate is the same and we don't need to cast away 11362 // constness for the result to be an input range. 11363 return r; 11364 else 11365 return SortedRange!(Unqual!(typeof(r._input)), pred)(r._input); 11366 } 11367 else 11368 { 11369 return SortedRange!(Unqual!R, pred)(r); 11370 } 11371 } 11372 11373 /// 11374 @safe unittest 11375 { 11376 import std.algorithm.comparison : equal; 11377 11378 int[] a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; 11379 auto p = assumeSorted(a); 11380 11381 assert(equal(p.lowerBound(4), [0, 1, 2, 3])); 11382 assert(equal(p.lowerBound(5), [0, 1, 2, 3, 4])); 11383 assert(equal(p.lowerBound(6), [0, 1, 2, 3, 4, 5])); 11384 assert(equal(p.lowerBound(6.9), [0, 1, 2, 3, 4, 5, 6])); 11385 } 11386 11387 @safe unittest 11388 { 11389 import std.algorithm.comparison : equal; 11390 static assert(isRandomAccessRange!(SortedRange!(int[]))); 11391 int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]; 11392 auto p = assumeSorted(a).upperBound(3); 11393 assert(equal(p, [4, 4, 5, 6 ])); 11394 p = assumeSorted(a).upperBound(4.2); 11395 assert(equal(p, [ 5, 6 ])); 11396 11397 // https://issues.dlang.org/show_bug.cgi?id=18933 11398 // don't create senselessly nested SortedRange types. 11399 assert(is(typeof(assumeSorted(a)) == typeof(assumeSorted(assumeSorted(a))))); 11400 assert(is(typeof(assumeSorted(a)) == typeof(assumeSorted(assumeSorted!"a > b"(a))))); 11401 } 11402 11403 @safe unittest 11404 { 11405 import std.algorithm.comparison : equal; 11406 import std.conv : text; 11407 11408 int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]; 11409 auto p = assumeSorted(a).equalRange(3); 11410 assert(equal(p, [ 3, 3, 3 ]), text(p)); 11411 p = assumeSorted(a).equalRange(4); 11412 assert(equal(p, [ 4, 4 ]), text(p)); 11413 p = assumeSorted(a).equalRange(2); 11414 assert(equal(p, [ 2 ])); 11415 p = assumeSorted(a).equalRange(0); 11416 assert(p.empty); 11417 p = assumeSorted(a).equalRange(7); 11418 assert(p.empty); 11419 p = assumeSorted(a).equalRange(3.0); 11420 assert(equal(p, [ 3, 3, 3])); 11421 } 11422 11423 @safe unittest 11424 { 11425 int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]; 11426 if (a.length) 11427 { 11428 auto b = a[a.length / 2]; 11429 //auto r = sort(a); 11430 //assert(r.contains(b)); 11431 } 11432 } 11433 11434 @safe unittest 11435 { 11436 auto a = [ 5, 7, 34, 345, 677 ]; 11437 auto r = assumeSorted(a); 11438 a = null; 11439 r = assumeSorted(a); 11440 a = [ 1 ]; 11441 r = assumeSorted(a); 11442 } 11443 11444 // https://issues.dlang.org/show_bug.cgi?id=15003 11445 @nogc @safe unittest 11446 { 11447 static immutable a = [1, 2, 3, 4]; 11448 auto r = a.assumeSorted; 11449 } 11450 11451 /++ 11452 Wrapper which effectively makes it possible to pass a range by reference. 11453 Both the original range and the RefRange will always have the exact same 11454 elements. Any operation done on one will affect the other. So, for instance, 11455 if it's passed to a function which would implicitly copy the original range 11456 if it were passed to it, the original range is $(I not) copied but is 11457 consumed as if it were a reference type. 11458 11459 Note: 11460 `save` works as normal and operates on a new range, so if 11461 `save` is ever called on the `RefRange`, then no operations on the 11462 saved range will affect the original. 11463 11464 Params: 11465 range = the range to construct the `RefRange` from 11466 11467 Returns: 11468 A `RefRange`. If the given range is a class type 11469 (and thus is already a reference type), then the original 11470 range is returned rather than a `RefRange`. 11471 +/ 11472 struct RefRange(R) 11473 if (isInputRange!R) 11474 { 11475 public: 11476 11477 /++ +/ 11478 this(R* range) @safe pure nothrow 11479 { 11480 _range = range; 11481 } 11482 11483 11484 /++ 11485 This does not assign the pointer of `rhs` to this `RefRange`. 11486 Rather it assigns the range pointed to by `rhs` to the range pointed 11487 to by this `RefRange`. This is because $(I any) operation on a 11488 `RefRange` is the same is if it occurred to the original range. The 11489 one exception is when a `RefRange` is assigned `null` either 11490 directly or because `rhs` is `null`. In that case, `RefRange` 11491 no longer refers to the original range but is `null`. 11492 +/ 11493 auto opAssign(RefRange rhs) 11494 { 11495 if (_range && rhs._range) 11496 *_range = *rhs._range; 11497 else 11498 _range = rhs._range; 11499 11500 return this; 11501 } 11502 11503 /++ +/ 11504 void opAssign(typeof(null) rhs) 11505 { 11506 _range = null; 11507 } 11508 11509 11510 /++ 11511 A pointer to the wrapped range. 11512 +/ 11513 @property inout(R*) ptr() @safe inout pure nothrow 11514 { 11515 return _range; 11516 } 11517 11518 11519 version (StdDdoc) 11520 { 11521 /++ +/ 11522 @property auto front() {assert(0);} 11523 /++ Ditto +/ 11524 @property auto front() const {assert(0);} 11525 /++ Ditto +/ 11526 @property auto front(ElementType!R value) {assert(0);} 11527 } 11528 else 11529 { 11530 @property auto front() 11531 { 11532 return (*_range).front; 11533 } 11534 11535 static if (is(typeof((*(cast(const R*)_range)).front))) @property auto front() const 11536 { 11537 return (*_range).front; 11538 } 11539 11540 static if (is(typeof((*_range).front = (*_range).front))) @property auto front(ElementType!R value) 11541 { 11542 return (*_range).front = value; 11543 } 11544 } 11545 11546 11547 version (StdDdoc) 11548 { 11549 @property bool empty(); /// 11550 @property bool empty() const; ///Ditto 11551 } 11552 else static if (isInfinite!R) 11553 enum empty = false; 11554 else 11555 { 11556 @property bool empty() 11557 { 11558 return (*_range).empty; 11559 } 11560 11561 static if (is(typeof((*cast(const R*)_range).empty))) @property bool empty() const 11562 { 11563 return (*_range).empty; 11564 } 11565 } 11566 11567 11568 /++ +/ 11569 void popFront() 11570 { 11571 return (*_range).popFront(); 11572 } 11573 11574 11575 version (StdDdoc) 11576 { 11577 /++ 11578 Only defined if `isForwardRange!R` is `true`. 11579 +/ 11580 @property auto save() {assert(0);} 11581 /++ Ditto +/ 11582 @property auto save() const {assert(0);} 11583 /++ Ditto +/ 11584 auto opSlice() {assert(0);} 11585 /++ Ditto +/ 11586 auto opSlice() const {assert(0);} 11587 } 11588 else static if (isForwardRange!R) 11589 { 11590 import std.traits : isSafe; 11591 private alias S = typeof((*_range).save); 11592 11593 static if (is(typeof((*cast(const R*)_range).save))) 11594 private alias CS = typeof((*cast(const R*)_range).save); 11595 11596 static if (isSafe!((R* r) => (*r).save)) 11597 { 11598 @property RefRange!S save() @trusted 11599 { 11600 mixin(_genSave()); 11601 } 11602 11603 static if (is(typeof((*cast(const R*)_range).save))) @property RefRange!CS save() @trusted const 11604 { 11605 mixin(_genSave()); 11606 } 11607 } 11608 else 11609 { 11610 @property RefRange!S save() 11611 { 11612 mixin(_genSave()); 11613 } 11614 11615 static if (is(typeof((*cast(const R*)_range).save))) @property RefRange!CS save() const 11616 { 11617 mixin(_genSave()); 11618 } 11619 } 11620 11621 auto opSlice()() 11622 { 11623 return save; 11624 } 11625 11626 auto opSlice()() const 11627 { 11628 return save; 11629 } 11630 11631 private static string _genSave() @safe pure nothrow 11632 { 11633 return `import std.conv : emplace;` ~ 11634 `alias S = typeof((*_range).save);` ~ 11635 `static assert(isForwardRange!S, S.stringof ~ " is not a forward range.");` ~ 11636 `auto mem = new void[S.sizeof];` ~ 11637 `emplace!S(mem, cast(S)(*_range).save);` ~ 11638 `return RefRange!S(cast(S*) mem.ptr);`; 11639 } 11640 11641 static assert(isForwardRange!RefRange); 11642 } 11643 11644 11645 version (StdDdoc) 11646 { 11647 /++ 11648 Only defined if `isBidirectionalRange!R` is `true`. 11649 +/ 11650 @property auto back() {assert(0);} 11651 /++ Ditto +/ 11652 @property auto back() const {assert(0);} 11653 /++ Ditto +/ 11654 @property auto back(ElementType!R value) {assert(0);} 11655 } 11656 else static if (isBidirectionalRange!R) 11657 { 11658 @property auto back() 11659 { 11660 return (*_range).back; 11661 } 11662 11663 static if (is(typeof((*(cast(const R*)_range)).back))) @property auto back() const 11664 { 11665 return (*_range).back; 11666 } 11667 11668 static if (is(typeof((*_range).back = (*_range).back))) @property auto back(ElementType!R value) 11669 { 11670 return (*_range).back = value; 11671 } 11672 } 11673 11674 11675 /++ Ditto +/ 11676 static if (isBidirectionalRange!R) void popBack() 11677 { 11678 return (*_range).popBack(); 11679 } 11680 11681 11682 version (StdDdoc) 11683 { 11684 /++ 11685 Only defined if `isRandomAccesRange!R` is `true`. 11686 +/ 11687 auto ref opIndex(IndexType)(IndexType index) {assert(0);} 11688 11689 /++ Ditto +/ 11690 auto ref opIndex(IndexType)(IndexType index) const {assert(0);} 11691 } 11692 else static if (isRandomAccessRange!R) 11693 { 11694 auto ref opIndex(IndexType)(IndexType index) 11695 if (is(typeof((*_range)[index]))) 11696 { 11697 return (*_range)[index]; 11698 } 11699 11700 auto ref opIndex(IndexType)(IndexType index) const 11701 if (is(typeof((*cast(const R*)_range)[index]))) 11702 { 11703 return (*_range)[index]; 11704 } 11705 } 11706 11707 11708 /++ 11709 Only defined if `hasMobileElements!R` and `isForwardRange!R` are 11710 `true`. 11711 +/ 11712 static if (hasMobileElements!R && isForwardRange!R) auto moveFront() 11713 { 11714 return (*_range).moveFront(); 11715 } 11716 11717 11718 /++ 11719 Only defined if `hasMobileElements!R` and `isBidirectionalRange!R` 11720 are `true`. 11721 +/ 11722 static if (hasMobileElements!R && isBidirectionalRange!R) auto moveBack() 11723 { 11724 return (*_range).moveBack(); 11725 } 11726 11727 11728 /++ 11729 Only defined if `hasMobileElements!R` and `isRandomAccessRange!R` 11730 are `true`. 11731 +/ 11732 static if (hasMobileElements!R && isRandomAccessRange!R) auto moveAt(size_t index) 11733 { 11734 return (*_range).moveAt(index); 11735 } 11736 11737 11738 version (StdDdoc) 11739 { 11740 /++ 11741 Only defined if `hasLength!R` is `true`. 11742 +/ 11743 @property auto length() {assert(0);} 11744 11745 /++ Ditto +/ 11746 @property auto length() const {assert(0);} 11747 11748 /++ Ditto +/ 11749 alias opDollar = length; 11750 } 11751 else static if (hasLength!R) 11752 { 11753 @property auto length() 11754 { 11755 return (*_range).length; 11756 } 11757 11758 static if (is(typeof((*cast(const R*)_range).length))) @property auto length() const 11759 { 11760 return (*_range).length; 11761 } 11762 11763 alias opDollar = length; 11764 } 11765 11766 11767 version (StdDdoc) 11768 { 11769 /++ 11770 Only defined if `hasSlicing!R` is `true`. 11771 +/ 11772 auto opSlice(IndexType1, IndexType2) 11773 (IndexType1 begin, IndexType2 end) {assert(0);} 11774 11775 /++ Ditto +/ 11776 auto opSlice(IndexType1, IndexType2) 11777 (IndexType1 begin, IndexType2 end) const {assert(0);} 11778 } 11779 else static if (hasSlicing!R) 11780 { 11781 private alias T = typeof((*_range)[1 .. 2]); 11782 static if (is(typeof((*cast(const R*)_range)[1 .. 2]))) 11783 { 11784 private alias CT = typeof((*cast(const R*)_range)[1 .. 2]); 11785 } 11786 11787 RefRange!T opSlice(IndexType1, IndexType2) 11788 (IndexType1 begin, IndexType2 end) 11789 if (is(typeof((*_range)[begin .. end]))) 11790 { 11791 mixin(_genOpSlice()); 11792 } 11793 11794 RefRange!CT opSlice(IndexType1, IndexType2) 11795 (IndexType1 begin, IndexType2 end) const 11796 if (is(typeof((*cast(const R*)_range)[begin .. end]))) 11797 { 11798 mixin(_genOpSlice()); 11799 } 11800 11801 private static string _genOpSlice() @safe pure nothrow 11802 { 11803 return `import std.conv : emplace;` ~ 11804 `alias S = typeof((*_range)[begin .. end]);` ~ 11805 `static assert(hasSlicing!S, S.stringof ~ " is not sliceable.");` ~ 11806 `auto mem = new void[S.sizeof];` ~ 11807 `emplace!S(mem, cast(S)(*_range)[begin .. end]);` ~ 11808 `return RefRange!S(cast(S*) mem.ptr);`; 11809 } 11810 } 11811 11812 11813 private: 11814 11815 R* _range; 11816 } 11817 11818 /// Basic Example 11819 @system unittest 11820 { 11821 import std.algorithm.searching : find; 11822 ubyte[] buffer = [1, 9, 45, 12, 22]; 11823 auto found1 = find(buffer, 45); 11824 assert(found1 == [45, 12, 22]); 11825 assert(buffer == [1, 9, 45, 12, 22]); 11826 11827 auto wrapped1 = refRange(&buffer); 11828 auto found2 = find(wrapped1, 45); 11829 assert(*found2.ptr == [45, 12, 22]); 11830 assert(buffer == [45, 12, 22]); 11831 11832 auto found3 = find(wrapped1.save, 22); 11833 assert(*found3.ptr == [22]); 11834 assert(buffer == [45, 12, 22]); 11835 11836 string str = "hello world"; 11837 auto wrappedStr = refRange(&str); 11838 assert(str.front == 'h'); 11839 str.popFrontN(5); 11840 assert(str == " world"); 11841 assert(wrappedStr.front == ' '); 11842 assert(*wrappedStr.ptr == " world"); 11843 } 11844 11845 /// opAssign Example. 11846 @system unittest 11847 { 11848 ubyte[] buffer1 = [1, 2, 3, 4, 5]; 11849 ubyte[] buffer2 = [6, 7, 8, 9, 10]; 11850 auto wrapped1 = refRange(&buffer1); 11851 auto wrapped2 = refRange(&buffer2); 11852 assert(wrapped1.ptr is &buffer1); 11853 assert(wrapped2.ptr is &buffer2); 11854 assert(wrapped1.ptr !is wrapped2.ptr); 11855 assert(buffer1 != buffer2); 11856 11857 wrapped1 = wrapped2; 11858 11859 //Everything points to the same stuff as before. 11860 assert(wrapped1.ptr is &buffer1); 11861 assert(wrapped2.ptr is &buffer2); 11862 assert(wrapped1.ptr !is wrapped2.ptr); 11863 11864 //But buffer1 has changed due to the assignment. 11865 assert(buffer1 == [6, 7, 8, 9, 10]); 11866 assert(buffer2 == [6, 7, 8, 9, 10]); 11867 11868 buffer2 = [11, 12, 13, 14, 15]; 11869 11870 //Everything points to the same stuff as before. 11871 assert(wrapped1.ptr is &buffer1); 11872 assert(wrapped2.ptr is &buffer2); 11873 assert(wrapped1.ptr !is wrapped2.ptr); 11874 11875 //But buffer2 has changed due to the assignment. 11876 assert(buffer1 == [6, 7, 8, 9, 10]); 11877 assert(buffer2 == [11, 12, 13, 14, 15]); 11878 11879 wrapped2 = null; 11880 11881 //The pointer changed for wrapped2 but not wrapped1. 11882 assert(wrapped1.ptr is &buffer1); 11883 assert(wrapped2.ptr is null); 11884 assert(wrapped1.ptr !is wrapped2.ptr); 11885 11886 //buffer2 is not affected by the assignment. 11887 assert(buffer1 == [6, 7, 8, 9, 10]); 11888 assert(buffer2 == [11, 12, 13, 14, 15]); 11889 } 11890 11891 @system unittest 11892 { 11893 import std.algorithm.iteration : filter; 11894 { 11895 ubyte[] buffer = [1, 2, 3, 4, 5]; 11896 auto wrapper = refRange(&buffer); 11897 auto p = wrapper.ptr; 11898 auto f = wrapper.front; 11899 wrapper.front = f; 11900 auto e = wrapper.empty; 11901 wrapper.popFront(); 11902 auto s = wrapper.save; 11903 auto b = wrapper.back; 11904 wrapper.back = b; 11905 wrapper.popBack(); 11906 auto i = wrapper[0]; 11907 wrapper.moveFront(); 11908 wrapper.moveBack(); 11909 wrapper.moveAt(0); 11910 auto l = wrapper.length; 11911 auto sl = wrapper[0 .. 1]; 11912 assert(wrapper[0 .. $].length == buffer[0 .. $].length); 11913 } 11914 11915 { 11916 ubyte[] buffer = [1, 2, 3, 4, 5]; 11917 const wrapper = refRange(&buffer); 11918 const p = wrapper.ptr; 11919 const f = wrapper.front; 11920 const e = wrapper.empty; 11921 const s = wrapper.save; 11922 const b = wrapper.back; 11923 const i = wrapper[0]; 11924 const l = wrapper.length; 11925 const sl = wrapper[0 .. 1]; 11926 } 11927 11928 { 11929 ubyte[] buffer = [1, 2, 3, 4, 5]; 11930 auto filtered = filter!"true"(buffer); 11931 auto wrapper = refRange(&filtered); 11932 auto p = wrapper.ptr; 11933 auto f = wrapper.front; 11934 wrapper.front = f; 11935 auto e = wrapper.empty; 11936 wrapper.popFront(); 11937 auto s = wrapper.save; 11938 wrapper.moveFront(); 11939 } 11940 11941 { 11942 ubyte[] buffer = [1, 2, 3, 4, 5]; 11943 auto filtered = filter!"true"(buffer); 11944 const wrapper = refRange(&filtered); 11945 const p = wrapper.ptr; 11946 11947 //Cannot currently be const. filter needs to be updated to handle const. 11948 /+ 11949 const f = wrapper.front; 11950 const e = wrapper.empty; 11951 const s = wrapper.save; 11952 +/ 11953 } 11954 11955 { 11956 string str = "hello world"; 11957 auto wrapper = refRange(&str); 11958 auto p = wrapper.ptr; 11959 auto f = wrapper.front; 11960 auto e = wrapper.empty; 11961 wrapper.popFront(); 11962 auto s = wrapper.save; 11963 auto b = wrapper.back; 11964 wrapper.popBack(); 11965 } 11966 11967 { 11968 // https://issues.dlang.org/show_bug.cgi?id=16534 11969 // opDollar should be defined if the wrapped range defines length. 11970 auto range = 10.iota.takeExactly(5); 11971 auto wrapper = refRange(&range); 11972 assert(wrapper.length == 5); 11973 assert(wrapper[0 .. $ - 1].length == 4); 11974 } 11975 } 11976 11977 //Test assignment. 11978 @system unittest 11979 { 11980 ubyte[] buffer1 = [1, 2, 3, 4, 5]; 11981 ubyte[] buffer2 = [6, 7, 8, 9, 10]; 11982 RefRange!(ubyte[]) wrapper1; 11983 RefRange!(ubyte[]) wrapper2 = refRange(&buffer2); 11984 assert(wrapper1.ptr is null); 11985 assert(wrapper2.ptr is &buffer2); 11986 11987 wrapper1 = refRange(&buffer1); 11988 assert(wrapper1.ptr is &buffer1); 11989 11990 wrapper1 = wrapper2; 11991 assert(wrapper1.ptr is &buffer1); 11992 assert(buffer1 == buffer2); 11993 11994 wrapper1 = RefRange!(ubyte[]).init; 11995 assert(wrapper1.ptr is null); 11996 assert(wrapper2.ptr is &buffer2); 11997 assert(buffer1 == buffer2); 11998 assert(buffer1 == [6, 7, 8, 9, 10]); 11999 12000 wrapper2 = null; 12001 assert(wrapper2.ptr is null); 12002 assert(buffer2 == [6, 7, 8, 9, 10]); 12003 } 12004 12005 @system unittest 12006 { 12007 import std.algorithm.comparison : equal; 12008 import std.algorithm.mutation : bringToFront; 12009 import std.algorithm.searching : commonPrefix, find, until; 12010 import std.algorithm.sorting : sort; 12011 12012 //Test that ranges are properly consumed. 12013 { 12014 int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9]; 12015 auto wrapper = refRange(&arr); 12016 12017 assert(*find(wrapper, 41).ptr == [41, 3, 40, 4, 42, 9]); 12018 assert(arr == [41, 3, 40, 4, 42, 9]); 12019 12020 assert(*drop(wrapper, 2).ptr == [40, 4, 42, 9]); 12021 assert(arr == [40, 4, 42, 9]); 12022 12023 assert(equal(until(wrapper, 42), [40, 4])); 12024 assert(arr == [42, 9]); 12025 12026 assert(find(wrapper, 12).empty); 12027 assert(arr.empty); 12028 } 12029 12030 { 12031 string str = "Hello, world-like object."; 12032 auto wrapper = refRange(&str); 12033 12034 assert(*find(wrapper, "l").ptr == "llo, world-like object."); 12035 assert(str == "llo, world-like object."); 12036 12037 assert(equal(take(wrapper, 5), "llo, ")); 12038 assert(str == "world-like object."); 12039 } 12040 12041 //Test that operating on saved ranges does not consume the original. 12042 { 12043 int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9]; 12044 auto wrapper = refRange(&arr); 12045 auto saved = wrapper.save; 12046 saved.popFrontN(3); 12047 assert(*saved.ptr == [41, 3, 40, 4, 42, 9]); 12048 assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]); 12049 } 12050 12051 { 12052 string str = "Hello, world-like object."; 12053 auto wrapper = refRange(&str); 12054 auto saved = wrapper.save; 12055 saved.popFrontN(13); 12056 assert(*saved.ptr == "like object."); 12057 assert(str == "Hello, world-like object."); 12058 } 12059 12060 //Test that functions which use save work properly. 12061 { 12062 int[] arr = [1, 42]; 12063 auto wrapper = refRange(&arr); 12064 assert(equal(commonPrefix(wrapper, [1, 27]), [1])); 12065 } 12066 12067 { 12068 int[] arr = [4, 5, 6, 7, 1, 2, 3]; 12069 auto wrapper = refRange(&arr); 12070 assert(bringToFront(wrapper[0 .. 4], wrapper[4 .. arr.length]) == 3); 12071 assert(arr == [1, 2, 3, 4, 5, 6, 7]); 12072 } 12073 12074 //Test bidirectional functions. 12075 { 12076 int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9]; 12077 auto wrapper = refRange(&arr); 12078 12079 assert(wrapper.back == 9); 12080 assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]); 12081 12082 wrapper.popBack(); 12083 assert(arr == [1, 42, 2, 41, 3, 40, 4, 42]); 12084 } 12085 12086 { 12087 string str = "Hello, world-like object."; 12088 auto wrapper = refRange(&str); 12089 12090 assert(wrapper.back == '.'); 12091 assert(str == "Hello, world-like object."); 12092 12093 wrapper.popBack(); 12094 assert(str == "Hello, world-like object"); 12095 } 12096 12097 //Test random access functions. 12098 { 12099 int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9]; 12100 auto wrapper = refRange(&arr); 12101 12102 assert(wrapper[2] == 2); 12103 assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]); 12104 12105 assert(*wrapper[3 .. 6].ptr != null, [41, 3, 40]); 12106 assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]); 12107 } 12108 12109 //Test move functions. 12110 { 12111 int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9]; 12112 auto wrapper = refRange(&arr); 12113 12114 auto t1 = wrapper.moveFront(); 12115 auto t2 = wrapper.moveBack(); 12116 wrapper.front = t2; 12117 wrapper.back = t1; 12118 assert(arr == [9, 42, 2, 41, 3, 40, 4, 42, 1]); 12119 12120 sort(wrapper.save); 12121 assert(arr == [1, 2, 3, 4, 9, 40, 41, 42, 42]); 12122 } 12123 } 12124 12125 @system unittest 12126 { 12127 struct S 12128 { 12129 @property int front() @safe const pure nothrow { return 0; } 12130 enum bool empty = false; 12131 void popFront() @safe pure nothrow { } 12132 @property auto save() @safe pure nothrow { return this; } 12133 } 12134 12135 S s; 12136 auto wrapper = refRange(&s); 12137 static assert(isInfinite!(typeof(wrapper))); 12138 } 12139 12140 @system unittest 12141 { 12142 class C 12143 { 12144 @property int front() @safe const pure nothrow { return 0; } 12145 @property bool empty() @safe const pure nothrow { return false; } 12146 void popFront() @safe pure nothrow { } 12147 @property auto save() @safe pure nothrow { return this; } 12148 } 12149 static assert(isForwardRange!C); 12150 12151 auto c = new C; 12152 auto cWrapper = refRange(&c); 12153 static assert(is(typeof(cWrapper) == C)); 12154 assert(cWrapper is c); 12155 } 12156 12157 // https://issues.dlang.org/show_bug.cgi?id=14373 12158 @system unittest 12159 { 12160 static struct R 12161 { 12162 @property int front() {return 0;} 12163 void popFront() {empty = true;} 12164 bool empty = false; 12165 } 12166 R r; 12167 refRange(&r).popFront(); 12168 assert(r.empty); 12169 } 12170 12171 // https://issues.dlang.org/show_bug.cgi?id=14575 12172 @system unittest 12173 { 12174 struct R 12175 { 12176 Object front; 12177 alias back = front; 12178 bool empty = false; 12179 void popFront() {empty = true;} 12180 alias popBack = popFront; 12181 @property R save() {return this;} 12182 } 12183 static assert(isBidirectionalRange!R); 12184 R r; 12185 auto rr = refRange(&r); 12186 12187 struct R2 12188 { 12189 @property Object front() {return null;} 12190 @property const(Object) front() const {return null;} 12191 alias back = front; 12192 bool empty = false; 12193 void popFront() {empty = true;} 12194 alias popBack = popFront; 12195 @property R2 save() {return this;} 12196 } 12197 static assert(isBidirectionalRange!R2); 12198 R2 r2; 12199 auto rr2 = refRange(&r2); 12200 } 12201 12202 /// ditto 12203 auto refRange(R)(R* range) 12204 if (isInputRange!R) 12205 { 12206 static if (!is(R == class)) 12207 return RefRange!R(range); 12208 else 12209 return *range; 12210 } 12211 12212 // https://issues.dlang.org/show_bug.cgi?id=9060 12213 @safe unittest 12214 { 12215 import std.algorithm.iteration : map, joiner, group; 12216 import std.algorithm.searching : until; 12217 // fix for std.algorithm 12218 auto r = map!(x => 0)([1]); 12219 chain(r, r); 12220 zip(r, r); 12221 roundRobin(r, r); 12222 12223 struct NRAR { 12224 typeof(r) input; 12225 @property empty() { return input.empty; } 12226 @property front() { return input.front; } 12227 void popFront() { input.popFront(); } 12228 @property save() { return NRAR(input.save); } 12229 } 12230 auto n1 = NRAR(r); 12231 cycle(n1); // non random access range version 12232 12233 assumeSorted(r); 12234 12235 // fix for std.range 12236 joiner([r], [9]); 12237 12238 struct NRAR2 { 12239 NRAR input; 12240 @property empty() { return true; } 12241 @property front() { return input; } 12242 void popFront() { } 12243 @property save() { return NRAR2(input.save); } 12244 } 12245 auto n2 = NRAR2(n1); 12246 joiner(n2); 12247 12248 group(r); 12249 12250 until(r, 7); 12251 static void foo(R)(R r) { until!(x => x > 7)(r); } 12252 foo(r); 12253 } 12254 12255 private struct Bitwise(R) 12256 if (isInputRange!R && isIntegral!(ElementType!R)) 12257 { 12258 import std.traits : Unsigned; 12259 private: 12260 alias ElemType = ElementType!R; 12261 alias UnsignedElemType = Unsigned!ElemType; 12262 12263 R parent; 12264 enum bitsNum = ElemType.sizeof * 8; 12265 size_t maskPos = 1; 12266 12267 static if (isBidirectionalRange!R) 12268 { 12269 size_t backMaskPos = bitsNum; 12270 } 12271 12272 public: 12273 this()(auto ref R range) 12274 { 12275 parent = range; 12276 } 12277 12278 static if (isInfinite!R) 12279 { 12280 enum empty = false; 12281 } 12282 else 12283 { 12284 /** 12285 * Check if the range is empty 12286 * 12287 * Returns: a boolean true or false 12288 */ 12289 bool empty() 12290 { 12291 static if (hasLength!R) 12292 { 12293 return length == 0; 12294 } 12295 else static if (isBidirectionalRange!R) 12296 { 12297 if (parent.empty) 12298 { 12299 return true; 12300 } 12301 else 12302 { 12303 /* 12304 If we have consumed the last element of the range both from 12305 the front and the back, then the masks positions will overlap 12306 */ 12307 return parent.save.dropOne.empty && (maskPos > backMaskPos); 12308 } 12309 } 12310 else 12311 { 12312 /* 12313 If we consumed the last element of the range, but not all the 12314 bits in the last element 12315 */ 12316 return parent.empty; 12317 } 12318 } 12319 } 12320 12321 bool front() 12322 { 12323 assert(!empty); 12324 return (parent.front & mask(maskPos)) != 0; 12325 } 12326 12327 void popFront() 12328 { 12329 assert(!empty); 12330 ++maskPos; 12331 if (maskPos > bitsNum) 12332 { 12333 parent.popFront; 12334 maskPos = 1; 12335 } 12336 } 12337 12338 static if (hasLength!R) 12339 { 12340 size_t length() 12341 { 12342 auto len = parent.length * bitsNum - (maskPos - 1); 12343 static if (isBidirectionalRange!R) 12344 { 12345 len -= bitsNum - backMaskPos; 12346 } 12347 return len; 12348 } 12349 12350 alias opDollar = length; 12351 } 12352 12353 static if (isForwardRange!R) 12354 { 12355 typeof(this) save() 12356 { 12357 auto result = this; 12358 result.parent = parent.save; 12359 return result; 12360 } 12361 } 12362 12363 static if (isBidirectionalRange!R) 12364 { 12365 bool back() 12366 { 12367 assert(!empty); 12368 return (parent.back & mask(backMaskPos)) != 0; 12369 } 12370 12371 void popBack() 12372 { 12373 assert(!empty); 12374 --backMaskPos; 12375 if (backMaskPos == 0) 12376 { 12377 parent.popBack; 12378 backMaskPos = bitsNum; 12379 } 12380 } 12381 } 12382 12383 static if (isRandomAccessRange!R) 12384 { 12385 /** 12386 Return the `n`th bit within the range 12387 */ 12388 bool opIndex(size_t n) 12389 in 12390 { 12391 /* 12392 If it does not have the length property, it means that R is 12393 an infinite range 12394 */ 12395 static if (hasLength!R) 12396 { 12397 assert(n < length, "Index out of bounds"); 12398 } 12399 } 12400 do 12401 { 12402 immutable size_t remainingBits = bitsNum - maskPos + 1; 12403 // If n >= maskPos, then the bit sign will be 1, otherwise 0 12404 immutable ptrdiff_t sign = (remainingBits - n - 1) >> (ptrdiff_t.sizeof * 8 - 1); 12405 /* 12406 By truncating n with remainingBits bits we have skipped the 12407 remaining bits in parent[0], so we need to add 1 to elemIndex. 12408 12409 Because bitsNum is a power of 2, n / bitsNum == n >> bitsNum.bsf 12410 */ 12411 import core.bitop : bsf; 12412 immutable size_t elemIndex = sign * (((n - remainingBits) >> bitsNum.bsf) + 1); 12413 12414 /* 12415 Since the indexing is from LSB to MSB, we need to index at the 12416 remainder of (n - remainingBits). 12417 12418 Because bitsNum is a power of 2, n % bitsNum == n & (bitsNum - 1) 12419 */ 12420 immutable size_t elemMaskPos = (sign ^ 1) * (maskPos + n) 12421 + sign * (1 + ((n - remainingBits) & (bitsNum - 1))); 12422 12423 return (parent[elemIndex] & mask(elemMaskPos)) != 0; 12424 } 12425 12426 static if (hasAssignableElements!R) 12427 { 12428 /** 12429 Assigns `flag` to the `n`th bit within the range 12430 */ 12431 void opIndexAssign(bool flag, size_t n) 12432 in 12433 { 12434 static if (hasLength!R) 12435 { 12436 assert(n < length, "Index out of bounds"); 12437 } 12438 } 12439 do 12440 { 12441 import core.bitop : bsf; 12442 12443 immutable size_t remainingBits = bitsNum - maskPos + 1; 12444 immutable ptrdiff_t sign = (remainingBits - n - 1) >> (ptrdiff_t.sizeof * 8 - 1); 12445 immutable size_t elemIndex = sign * (((n - remainingBits) >> bitsNum.bsf) + 1); 12446 immutable size_t elemMaskPos = (sign ^ 1) * (maskPos + n) 12447 + sign * (1 + ((n - remainingBits) & (bitsNum - 1))); 12448 12449 auto elem = parent[elemIndex]; 12450 auto elemMask = mask(elemMaskPos); 12451 parent[elemIndex] = cast(UnsignedElemType)(flag * (elem | elemMask) 12452 + (flag ^ 1) * (elem & ~elemMask)); 12453 } 12454 } 12455 12456 Bitwise!R opSlice() 12457 { 12458 return this.save; 12459 } 12460 12461 Bitwise!R opSlice(size_t start, size_t end) 12462 in 12463 { 12464 assert(start < end, "Invalid bounds: end <= start"); 12465 } 12466 do 12467 { 12468 import core.bitop : bsf; 12469 12470 size_t remainingBits = bitsNum - maskPos + 1; 12471 ptrdiff_t sign = (remainingBits - start - 1) >> (ptrdiff_t.sizeof * 8 - 1); 12472 immutable size_t startElemIndex = sign * (((start - remainingBits) >> bitsNum.bsf) + 1); 12473 immutable size_t startElemMaskPos = (sign ^ 1) * (maskPos + start) 12474 + sign * (1 + ((start - remainingBits) & (bitsNum - 1))); 12475 12476 immutable size_t sliceLen = end - start - 1; 12477 remainingBits = bitsNum - startElemMaskPos + 1; 12478 sign = (remainingBits - sliceLen - 1) >> (ptrdiff_t.sizeof * 8 - 1); 12479 immutable size_t endElemIndex = startElemIndex 12480 + sign * (((sliceLen - remainingBits) >> bitsNum.bsf) + 1); 12481 immutable size_t endElemMaskPos = (sign ^ 1) * (startElemMaskPos + sliceLen) 12482 + sign * (1 + ((sliceLen - remainingBits) & (bitsNum - 1))); 12483 12484 typeof(return) result; 12485 // Get the slice to be returned from the parent 12486 result.parent = (parent[startElemIndex .. endElemIndex + 1]).save; 12487 result.maskPos = startElemMaskPos; 12488 static if (isBidirectionalRange!R) 12489 { 12490 result.backMaskPos = endElemMaskPos; 12491 } 12492 return result; 12493 } 12494 } 12495 12496 private: 12497 auto mask(size_t maskPos) 12498 { 12499 return (1UL << (maskPos - 1UL)); 12500 } 12501 } 12502 12503 /** 12504 Bitwise adapter over an integral type range. Consumes the range elements bit by 12505 bit, from the least significant bit to the most significant bit. 12506 12507 Params: 12508 R = an integral $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to iterate over 12509 range = range to consume bit by by 12510 12511 Returns: 12512 A `Bitwise` input range with propagated forward, bidirectional 12513 and random access capabilities 12514 */ 12515 auto bitwise(R)(auto ref R range) 12516 if (isInputRange!R && isIntegral!(ElementType!R)) 12517 { 12518 return Bitwise!R(range); 12519 } 12520 12521 /// 12522 @safe pure unittest 12523 { 12524 import std.algorithm.comparison : equal; 12525 import std.format : format; 12526 12527 // 00000011 00001001 12528 ubyte[] arr = [3, 9]; 12529 auto r = arr.bitwise; 12530 12531 // iterate through it as with any other range 12532 assert(format("%(%d%)", r) == "1100000010010000"); 12533 assert(format("%(%d%)", r.retro).equal("1100000010010000".retro)); 12534 12535 auto r2 = r[5 .. $]; 12536 // set a bit 12537 r[2] = 1; 12538 assert(arr[0] == 7); 12539 assert(r[5] == r2[0]); 12540 } 12541 12542 /// You can use bitwise to implement an uniform bool generator 12543 @safe unittest 12544 { 12545 import std.algorithm.comparison : equal; 12546 import std.random : rndGen; 12547 12548 auto rb = rndGen.bitwise; 12549 static assert(isInfinite!(typeof(rb))); 12550 12551 auto rb2 = rndGen.bitwise; 12552 // Don't forget that structs are passed by value 12553 assert(rb.take(10).equal(rb2.take(10))); 12554 } 12555 12556 // Test nogc inference 12557 @safe @nogc unittest 12558 { 12559 static ubyte[] arr = [3, 9]; 12560 auto bw = arr.bitwise; 12561 auto bw2 = bw[]; 12562 auto bw3 = bw[8 .. $]; 12563 bw3[2] = true; 12564 12565 assert(arr[1] == 13); 12566 assert(bw[$ - 6]); 12567 assert(bw[$ - 6] == bw2[$ - 6]); 12568 assert(bw[$ - 6] == bw3[$ - 6]); 12569 } 12570 12571 // Test all range types over all integral types 12572 @safe pure nothrow unittest 12573 { 12574 import std.meta : AliasSeq; 12575 import std.internal.test.dummyrange; 12576 12577 alias IntegralTypes = AliasSeq!(byte, ubyte, short, ushort, int, uint, 12578 long, ulong); 12579 foreach (IntegralType; IntegralTypes) 12580 { 12581 foreach (T; AllDummyRangesType!(IntegralType[])) 12582 { 12583 T a; 12584 auto bw = Bitwise!T(a); 12585 12586 static if (isForwardRange!T) 12587 { 12588 auto bwFwdSave = bw.save; 12589 } 12590 12591 static if (isBidirectionalRange!T) 12592 { 12593 auto bwBack = bw.save; 12594 auto bwBackSave = bw.save; 12595 } 12596 12597 static if (hasLength!T) 12598 { 12599 auto bwLength = bw.length; 12600 assert(bw.length == (IntegralType.sizeof * 8 * a.length)); 12601 static if (isForwardRange!T) 12602 { 12603 assert(bw.length == bwFwdSave.length); 12604 } 12605 } 12606 12607 // Make sure front and back are not the mechanisms that modify the range 12608 long numCalls = 42; 12609 bool initialFrontValue; 12610 12611 if (!bw.empty) 12612 { 12613 initialFrontValue = bw.front; 12614 } 12615 12616 while (!bw.empty && (--numCalls)) 12617 { 12618 bw.front; 12619 assert(bw.front == initialFrontValue); 12620 } 12621 12622 /* 12623 Check that empty works properly and that popFront does not get called 12624 more times than it should 12625 */ 12626 numCalls = 0; 12627 while (!bw.empty) 12628 { 12629 ++numCalls; 12630 12631 static if (hasLength!T) 12632 { 12633 assert(bw.length == bwLength); 12634 --bwLength; 12635 } 12636 12637 static if (isForwardRange!T) 12638 { 12639 assert(bw.front == bwFwdSave.front); 12640 bwFwdSave.popFront(); 12641 } 12642 12643 static if (isBidirectionalRange!T) 12644 { 12645 assert(bwBack.front == bwBackSave.front); 12646 bwBack.popBack(); 12647 bwBackSave.popBack(); 12648 } 12649 bw.popFront(); 12650 } 12651 12652 auto rangeLen = numCalls / (IntegralType.sizeof * 8); 12653 assert(numCalls == (IntegralType.sizeof * 8 * rangeLen)); 12654 assert(bw.empty); 12655 static if (isForwardRange!T) 12656 { 12657 assert(bwFwdSave.empty); 12658 } 12659 12660 static if (isBidirectionalRange!T) 12661 { 12662 assert(bwBack.empty); 12663 } 12664 } 12665 } 12666 } 12667 12668 // Test opIndex and opSlice 12669 @system unittest 12670 { 12671 import std.meta : AliasSeq; 12672 alias IntegralTypes = AliasSeq!(byte, ubyte, short, ushort, int, uint, 12673 long, ulong); 12674 foreach (IntegralType; IntegralTypes) 12675 { 12676 size_t bitsNum = IntegralType.sizeof * 8; 12677 12678 auto first = cast(IntegralType)(1); 12679 12680 // 2 ^ (bitsNum - 1) 12681 auto second = cast(IntegralType)(cast(IntegralType)(1) << (bitsNum - 2)); 12682 12683 IntegralType[] a = [first, second]; 12684 auto bw = Bitwise!(IntegralType[])(a); 12685 12686 // Check against lsb of a[0] 12687 assert(bw[0] == true); 12688 // Check against msb - 1 of a[1] 12689 assert(bw[2 * bitsNum - 2] == true); 12690 12691 bw.popFront(); 12692 assert(bw[2 * bitsNum - 3] == true); 12693 12694 import std.exception : assertThrown; 12695 12696 // Check out of bounds error 12697 assertThrown!Error(bw[2 * bitsNum - 1]); 12698 12699 bw[2] = true; 12700 assert(bw[2] == true); 12701 bw.popFront(); 12702 assert(bw[1] == true); 12703 12704 auto bw2 = bw[0 .. $ - 5]; 12705 auto bw3 = bw2[]; 12706 assert(bw2.length == (bw.length - 5)); 12707 assert(bw2.length == bw3.length); 12708 bw2.popFront(); 12709 assert(bw2.length != bw3.length); 12710 } 12711 } 12712 12713 /********************************* 12714 * An OutputRange that discards the data it receives. 12715 */ 12716 struct NullSink 12717 { 12718 void put(E)(scope const E) pure @safe @nogc nothrow {} 12719 } 12720 12721 /// ditto 12722 auto ref nullSink() 12723 { 12724 static NullSink sink; 12725 return sink; 12726 } 12727 12728 /// 12729 @safe nothrow unittest 12730 { 12731 import std.algorithm.iteration : map; 12732 import std.algorithm.mutation : copy; 12733 [4, 5, 6].map!(x => x * 2).copy(nullSink); // data is discarded 12734 } 12735 12736 /// 12737 @safe unittest 12738 { 12739 import std.csv : csvNextToken; 12740 12741 string line = "a,b,c"; 12742 12743 // ignore the first column 12744 line.csvNextToken(nullSink, ',', '"'); 12745 line.popFront; 12746 12747 // look at the second column 12748 Appender!string app; 12749 line.csvNextToken(app, ',', '"'); 12750 assert(app.data == "b"); 12751 } 12752 12753 @safe unittest 12754 { 12755 auto r = 10.iota 12756 .tee(nullSink) 12757 .dropOne; 12758 12759 assert(r.front == 1); 12760 } 12761 12762 /++ 12763 12764 Implements a "tee" style pipe, wrapping an input range so that elements of the 12765 range can be passed to a provided function or $(LREF OutputRange) as they are 12766 iterated over. This is useful for printing out intermediate values in a long 12767 chain of range code, performing some operation with side-effects on each call 12768 to `front` or `popFront`, or diverting the elements of a range into an 12769 auxiliary $(LREF OutputRange). 12770 12771 It is important to note that as the resultant range is evaluated lazily, 12772 in the case of the version of `tee` that takes a function, the function 12773 will not actually be executed until the range is "walked" using functions 12774 that evaluate ranges, such as $(REF array, std,array) or 12775 $(REF fold, std,algorithm,iteration). 12776 12777 Params: 12778 pipeOnPop = If `Yes.pipeOnPop`, simply iterating the range without ever 12779 calling `front` is enough to have `tee` mirror elements to `outputRange` (or, 12780 respectively, `fun`). Note that each `popFront()` call will mirror the 12781 old `front` value, not the new one. This means that the last value will 12782 not be forwarded if the range isn't iterated until empty. If 12783 `No.pipeOnPop`, only elements for which `front` does get called will be 12784 also sent to `outputRange`/`fun`. If `front` is called twice for the same 12785 element, it will still be sent only once. If this caching is undesired, 12786 consider using $(REF map, std,algorithm,iteration) instead. 12787 inputRange = The input range being passed through. 12788 outputRange = This range will receive elements of `inputRange` progressively 12789 as iteration proceeds. 12790 fun = This function will be called with elements of `inputRange` 12791 progressively as iteration proceeds. 12792 12793 Returns: 12794 An input range that offers the elements of `inputRange`. Regardless of 12795 whether `inputRange` is a more powerful range (forward, bidirectional etc), 12796 the result is always an input range. Reading this causes `inputRange` to be 12797 iterated and returns its elements in turn. In addition, the same elements 12798 will be passed to `outputRange` or `fun` as well. 12799 12800 See_Also: $(REF each, std,algorithm,iteration) 12801 +/ 12802 auto tee(Flag!"pipeOnPop" pipeOnPop = Yes.pipeOnPop, R1, R2)(R1 inputRange, R2 outputRange) 12803 if (isInputRange!R1 && isOutputRange!(R2, ElementType!R1)) 12804 { 12805 static struct Result 12806 { 12807 private R1 _input; 12808 private R2 _output; 12809 static if (!pipeOnPop) 12810 { 12811 private bool _frontAccessed; 12812 } 12813 12814 static if (hasLength!R1) 12815 { 12816 @property auto length() 12817 { 12818 return _input.length; 12819 } 12820 } 12821 12822 static if (isInfinite!R1) 12823 { 12824 enum bool empty = false; 12825 } 12826 else 12827 { 12828 @property bool empty() { return _input.empty; } 12829 } 12830 12831 void popFront() 12832 { 12833 assert(!_input.empty, "Attempting to popFront an empty tee"); 12834 static if (pipeOnPop) 12835 { 12836 put(_output, _input.front); 12837 } 12838 else 12839 { 12840 _frontAccessed = false; 12841 } 12842 _input.popFront(); 12843 } 12844 12845 @property auto ref front() 12846 { 12847 assert(!_input.empty, "Attempting to fetch the front of an empty tee"); 12848 static if (!pipeOnPop) 12849 { 12850 if (!_frontAccessed) 12851 { 12852 _frontAccessed = true; 12853 put(_output, _input.front); 12854 } 12855 } 12856 return _input.front; 12857 } 12858 } 12859 12860 return Result(inputRange, outputRange); 12861 } 12862 12863 /// Ditto 12864 auto tee(alias fun, Flag!"pipeOnPop" pipeOnPop = Yes.pipeOnPop, R1)(R1 inputRange) 12865 if (is(typeof(fun) == void) || isSomeFunction!fun) 12866 { 12867 import std.traits : isDelegate, isFunctionPointer; 12868 /* 12869 Distinguish between function literals and template lambdas 12870 when using either as an $(LREF OutputRange). Since a template 12871 has no type, typeof(template) will always return void. 12872 If it's a template lambda, it's first necessary to instantiate 12873 it with `ElementType!R1`. 12874 */ 12875 static if (is(typeof(fun) == void)) 12876 alias _fun = fun!(ElementType!R1); 12877 else 12878 alias _fun = fun; 12879 12880 static if (isFunctionPointer!_fun || isDelegate!_fun) 12881 { 12882 return tee!pipeOnPop(inputRange, _fun); 12883 } 12884 else 12885 { 12886 return tee!pipeOnPop(inputRange, &_fun); 12887 } 12888 } 12889 12890 /// 12891 @safe unittest 12892 { 12893 import std.algorithm.comparison : equal; 12894 import std.algorithm.iteration : filter, map; 12895 12896 // Sum values while copying 12897 int[] values = [1, 4, 9, 16, 25]; 12898 int sum = 0; 12899 auto newValues = values.tee!(a => sum += a).array; 12900 assert(equal(newValues, values)); 12901 assert(sum == 1 + 4 + 9 + 16 + 25); 12902 12903 // Count values that pass the first filter 12904 int count = 0; 12905 auto newValues4 = values.filter!(a => a < 10) 12906 .tee!(a => count++) 12907 .map!(a => a + 1) 12908 .filter!(a => a < 10); 12909 12910 //Fine, equal also evaluates any lazy ranges passed to it. 12911 //count is not 3 until equal evaluates newValues4 12912 assert(equal(newValues4, [2, 5])); 12913 assert(count == 3); 12914 } 12915 12916 // 12917 @safe unittest 12918 { 12919 import std.algorithm.comparison : equal; 12920 import std.algorithm.iteration : filter, map; 12921 12922 int[] values = [1, 4, 9, 16, 25]; 12923 12924 int count = 0; 12925 auto newValues = values.filter!(a => a < 10) 12926 .tee!(a => count++, No.pipeOnPop) 12927 .map!(a => a + 1) 12928 .filter!(a => a < 10); 12929 12930 auto val = newValues.front; 12931 assert(count == 1); 12932 //front is only evaluated once per element 12933 val = newValues.front; 12934 assert(count == 1); 12935 12936 //popFront() called, fun will be called 12937 //again on the next access to front 12938 newValues.popFront(); 12939 newValues.front; 12940 assert(count == 2); 12941 12942 int[] preMap = new int[](3), postMap = []; 12943 auto mappedValues = values.filter!(a => a < 10) 12944 //Note the two different ways of using tee 12945 .tee(preMap) 12946 .map!(a => a + 1) 12947 .tee!(a => postMap ~= a) 12948 .filter!(a => a < 10); 12949 assert(equal(mappedValues, [2, 5])); 12950 assert(equal(preMap, [1, 4, 9])); 12951 assert(equal(postMap, [2, 5, 10])); 12952 } 12953 12954 // 12955 @safe unittest 12956 { 12957 import std.algorithm.comparison : equal; 12958 import std.algorithm.iteration : filter, map; 12959 12960 char[] txt = "Line one, Line 2".dup; 12961 12962 bool isVowel(dchar c) 12963 { 12964 import std..string : indexOf; 12965 return "AaEeIiOoUu".indexOf(c) != -1; 12966 } 12967 12968 int vowelCount = 0; 12969 int shiftedCount = 0; 12970 auto removeVowels = txt.tee!(c => isVowel(c) ? vowelCount++ : 0) 12971 .filter!(c => !isVowel(c)) 12972 .map!(c => (c == ' ') ? c : c + 1) 12973 .tee!(c => isVowel(c) ? shiftedCount++ : 0); 12974 assert(equal(removeVowels, "Mo o- Mo 3")); 12975 assert(vowelCount == 6); 12976 assert(shiftedCount == 3); 12977 } 12978 12979 @safe unittest 12980 { 12981 // Manually stride to test different pipe behavior. 12982 void testRange(Range)(Range r) 12983 { 12984 const int strideLen = 3; 12985 int i = 0; 12986 ElementType!Range elem1; 12987 ElementType!Range elem2; 12988 while (!r.empty) 12989 { 12990 if (i % strideLen == 0) 12991 { 12992 //Make sure front is only 12993 //evaluated once per item 12994 elem1 = r.front; 12995 elem2 = r.front; 12996 assert(elem1 == elem2); 12997 } 12998 r.popFront(); 12999 i++; 13000 } 13001 } 13002 13003 string txt = "abcdefghijklmnopqrstuvwxyz"; 13004 13005 int popCount = 0; 13006 auto pipeOnPop = txt.tee!(a => popCount++); 13007 testRange(pipeOnPop); 13008 assert(popCount == 26); 13009 13010 int frontCount = 0; 13011 auto pipeOnFront = txt.tee!(a => frontCount++, No.pipeOnPop); 13012 testRange(pipeOnFront); 13013 assert(frontCount == 9); 13014 } 13015 13016 @safe unittest 13017 { 13018 import std.algorithm.comparison : equal; 13019 import std.meta : AliasSeq; 13020 13021 //Test diverting elements to an OutputRange 13022 string txt = "abcdefghijklmnopqrstuvwxyz"; 13023 13024 dchar[] asink1 = []; 13025 auto fsink = (dchar c) { asink1 ~= c; }; 13026 auto result1 = txt.tee(fsink).array; 13027 assert(equal(txt, result1) && (equal(result1, asink1))); 13028 13029 dchar[] _asink1 = []; 13030 auto _result1 = txt.tee!((dchar c) { _asink1 ~= c; })().array; 13031 assert(equal(txt, _result1) && (equal(_result1, _asink1))); 13032 13033 dchar[] asink2 = new dchar[](txt.length); 13034 void fsink2(dchar c) { static int i = 0; asink2[i] = c; i++; } 13035 auto result2 = txt.tee(&fsink2).array; 13036 assert(equal(txt, result2) && equal(result2, asink2)); 13037 13038 dchar[] asink3 = new dchar[](txt.length); 13039 auto result3 = txt.tee(asink3).array; 13040 assert(equal(txt, result3) && equal(result3, asink3)); 13041 13042 static foreach (CharType; AliasSeq!(char, wchar, dchar)) 13043 {{ 13044 auto appSink = appender!(CharType[])(); 13045 auto appResult = txt.tee(appSink).array; 13046 assert(equal(txt, appResult) && equal(appResult, appSink.data)); 13047 }} 13048 13049 static foreach (StringType; AliasSeq!(string, wstring, dstring)) 13050 {{ 13051 auto appSink = appender!StringType(); 13052 auto appResult = txt.tee(appSink).array; 13053 assert(equal(txt, appResult) && equal(appResult, appSink.data)); 13054 }} 13055 } 13056 13057 // https://issues.dlang.org/show_bug.cgi?id=13483 13058 @safe unittest 13059 { 13060 static void func1(T)(T x) {} 13061 void func2(int x) {} 13062 13063 auto r = [1, 2, 3, 4].tee!func1.tee!func2; 13064 } 13065 13066 /** 13067 Extends the length of the input range `r` by padding out the start of the 13068 range with the element `e`. The element `e` must be of a common type with 13069 the element type of the range `r` as defined by $(REF CommonType, std, traits). 13070 If `n` is less than the length of of `r`, then `r` is returned unmodified. 13071 13072 If `r` is a string with Unicode characters in it, `padLeft` follows D's rules 13073 about length for strings, which is not the number of characters, or 13074 graphemes, but instead the number of encoding units. If you want to treat each 13075 grapheme as only one encoding unit long, then call 13076 $(REF byGrapheme, std, uni) before calling this function. 13077 13078 If `r` has a length, then this is $(BIGOH 1). Otherwise, it's $(BIGOH r.length). 13079 13080 Params: 13081 r = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives) with a length, or a forward range 13082 e = element to pad the range with 13083 n = the length to pad to 13084 13085 Returns: 13086 A range containing the elements of the original range with the extra padding 13087 13088 See Also: 13089 $(REF leftJustifier, std, string) 13090 */ 13091 auto padLeft(R, E)(R r, E e, size_t n) 13092 if ( 13093 ((isInputRange!R && hasLength!R) || isForwardRange!R) && 13094 !is(CommonType!(ElementType!R, E) == void) 13095 ) 13096 { 13097 static if (hasLength!R) 13098 auto dataLength = r.length; 13099 else 13100 auto dataLength = r.save.walkLength(n); 13101 13102 return e.repeat(n > dataLength ? n - dataLength : 0).chain(r); 13103 } 13104 13105 /// 13106 @safe pure unittest 13107 { 13108 import std.algorithm.comparison : equal; 13109 13110 assert([1, 2, 3, 4].padLeft(0, 6).equal([0, 0, 1, 2, 3, 4])); 13111 assert([1, 2, 3, 4].padLeft(0, 3).equal([1, 2, 3, 4])); 13112 13113 assert("abc".padLeft('_', 6).equal("___abc")); 13114 } 13115 13116 @safe pure nothrow unittest 13117 { 13118 import std.algorithm.comparison : equal; 13119 import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy; 13120 import std.meta : AliasSeq; 13121 13122 alias DummyRanges = AliasSeq!( 13123 DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Input), 13124 DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Forward), 13125 DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Bidirectional), 13126 DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random), 13127 DummyRange!(ReturnBy.Reference, Length.No, RangeType.Forward), 13128 DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Input), 13129 DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Forward), 13130 DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Bidirectional), 13131 DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random), 13132 DummyRange!(ReturnBy.Value, Length.No, RangeType.Forward) 13133 ); 13134 13135 foreach (Range; DummyRanges) 13136 { 13137 Range r; 13138 assert(r 13139 .padLeft(0, 12) 13140 .equal([0, 0, 1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U]) 13141 ); 13142 } 13143 } 13144 13145 // Test nogc inference 13146 @safe @nogc pure unittest 13147 { 13148 import std.algorithm.comparison : equal; 13149 13150 static immutable r1 = [1, 2, 3, 4]; 13151 static immutable r2 = [0, 0, 1, 2, 3, 4]; 13152 assert(r1.padLeft(0, 6).equal(r2)); 13153 } 13154 13155 /** 13156 Extend the length of the input range `r` by padding out the end of the range 13157 with the element `e`. The element `e` must be of a common type with the 13158 element type of the range `r` as defined by $(REF CommonType, std, traits). 13159 If `n` is less than the length of of `r`, then the contents of `r` are 13160 returned. 13161 13162 The range primitives that the resulting range provides depends whether or not `r` 13163 provides them. Except the functions `back` and `popBack`, which also require 13164 the range to have a length as well as `back` and `popBack` 13165 13166 Params: 13167 r = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives) with a length 13168 e = element to pad the range with 13169 n = the length to pad to 13170 13171 Returns: 13172 A range containing the elements of the original range with the extra padding 13173 13174 See Also: 13175 $(REF rightJustifier, std, string) 13176 */ 13177 auto padRight(R, E)(R r, E e, size_t n) 13178 if ( 13179 isInputRange!R && 13180 !isInfinite!R && 13181 !is(CommonType!(ElementType!R, E) == void)) 13182 { 13183 static struct Result 13184 { 13185 private: 13186 R data; 13187 E element; 13188 static if (hasLength!R) 13189 { 13190 size_t padLength; 13191 } 13192 else 13193 { 13194 size_t minLength; 13195 size_t consumed; 13196 } 13197 13198 public: 13199 bool empty() @property 13200 { 13201 static if (hasLength!R) 13202 { 13203 return data.empty && padLength == 0; 13204 } 13205 else 13206 { 13207 return data.empty && consumed >= minLength; 13208 } 13209 } 13210 13211 auto front() @property 13212 { 13213 assert(!empty, "Attempting to fetch the front of an empty padRight"); 13214 return data.empty ? element : data.front; 13215 } 13216 13217 void popFront() 13218 { 13219 assert(!empty, "Attempting to popFront an empty padRight"); 13220 13221 static if (hasLength!R) 13222 { 13223 if (!data.empty) 13224 { 13225 data.popFront; 13226 } 13227 else 13228 { 13229 --padLength; 13230 } 13231 } 13232 else 13233 { 13234 ++consumed; 13235 if (!data.empty) 13236 { 13237 data.popFront; 13238 } 13239 } 13240 } 13241 13242 static if (hasLength!R) 13243 { 13244 size_t length() @property 13245 { 13246 return data.length + padLength; 13247 } 13248 } 13249 13250 static if (isForwardRange!R) 13251 { 13252 auto save() @property 13253 { 13254 typeof(this) result = this; 13255 data = data.save; 13256 return result; 13257 } 13258 } 13259 13260 static if (isBidirectionalRange!R && hasLength!R) 13261 { 13262 auto back() @property 13263 { 13264 assert(!empty, "Attempting to fetch the back of an empty padRight"); 13265 return padLength > 0 ? element : data.back; 13266 } 13267 13268 void popBack() 13269 { 13270 assert(!empty, "Attempting to popBack an empty padRight"); 13271 if (padLength > 0) 13272 { 13273 --padLength; 13274 } 13275 else 13276 { 13277 data.popBack; 13278 } 13279 } 13280 } 13281 13282 static if (isRandomAccessRange!R && hasLength!R) 13283 { 13284 E opIndex(size_t index) 13285 { 13286 assert(index <= this.length, "Index out of bounds"); 13287 return index >= data.length ? element : data[index]; 13288 } 13289 } 13290 13291 static if (hasSlicing!R && hasLength!R) 13292 { 13293 auto opSlice(size_t a, size_t b) 13294 { 13295 assert( 13296 a <= b, 13297 "Attempting to slice a padRight with a larger first argument than the second." 13298 ); 13299 assert( 13300 b <= length, 13301 "Attempting to slice using an out of bounds index on a padRight" 13302 ); 13303 return Result( 13304 a >= data.length ? data[0 .. 0] : b <= data.length ? data[a .. b] : data[a .. data.length], 13305 element, b - a); 13306 } 13307 13308 alias opDollar = length; 13309 } 13310 13311 this(R r, E e, size_t n) 13312 { 13313 data = r; 13314 element = e; 13315 static if (hasLength!R) 13316 { 13317 padLength = n > data.length ? n - data.length : 0; 13318 } 13319 else 13320 { 13321 minLength = n; 13322 } 13323 } 13324 13325 @disable this(); 13326 } 13327 13328 return Result(r, e, n); 13329 } 13330 13331 /// 13332 @safe pure unittest 13333 { 13334 import std.algorithm.comparison : equal; 13335 13336 assert([1, 2, 3, 4].padRight(0, 6).equal([1, 2, 3, 4, 0, 0])); 13337 assert([1, 2, 3, 4].padRight(0, 4).equal([1, 2, 3, 4])); 13338 13339 assert("abc".padRight('_', 6).equal("abc___")); 13340 } 13341 13342 pure @safe unittest 13343 { 13344 import std.algorithm.comparison : equal; 13345 import std.internal.test.dummyrange : AllDummyRanges, ReferenceInputRange; 13346 import std.meta : AliasSeq; 13347 13348 auto string_input_range = new ReferenceInputRange!dchar(['a', 'b', 'c']); 13349 dchar padding = '_'; 13350 assert(string_input_range.padRight(padding, 6).equal("abc___")); 13351 13352 foreach (RangeType; AllDummyRanges) 13353 { 13354 RangeType r1; 13355 assert(r1 13356 .padRight(0, 12) 13357 .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0, 0]) 13358 ); 13359 13360 // test if Result properly uses random access ranges 13361 static if (isRandomAccessRange!RangeType) 13362 { 13363 RangeType r3; 13364 assert(r3.padRight(0, 12)[0] == 1); 13365 assert(r3.padRight(0, 12)[2] == 3); 13366 assert(r3.padRight(0, 12)[9] == 10); 13367 assert(r3.padRight(0, 12)[10] == 0); 13368 assert(r3.padRight(0, 12)[11] == 0); 13369 } 13370 13371 // test if Result properly uses slicing and opDollar 13372 static if (hasSlicing!RangeType) 13373 { 13374 RangeType r4; 13375 assert(r4 13376 .padRight(0, 12)[0 .. 3] 13377 .equal([1, 2, 3]) 13378 ); 13379 assert(r4 13380 .padRight(0, 12)[0 .. 10] 13381 .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U]) 13382 ); 13383 assert(r4 13384 .padRight(0, 12)[0 .. 11] 13385 .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0]) 13386 ); 13387 assert(r4 13388 .padRight(0, 12)[2 .. $] 13389 .equal([3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0, 0]) 13390 ); 13391 assert(r4 13392 .padRight(0, 12)[0 .. $] 13393 .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0, 0]) 13394 ); 13395 } 13396 13397 // drop & dropBack test opslice ranges when available, popFront/popBack otherwise 13398 RangeType r5; 13399 foreach (i; 1 .. 13) assert(r5.padRight(0, 12).drop(i).walkLength == 12 - i); 13400 } 13401 } 13402 13403 // Test nogc inference 13404 @safe @nogc pure unittest 13405 { 13406 import std.algorithm.comparison : equal; 13407 13408 static immutable r1 = [1, 2, 3, 4]; 13409 static immutable r2 = [1, 2, 3, 4, 0, 0]; 13410 assert(r1.padRight(0, 6).equal(r2)); 13411 } 13412 13413 // Test back, popBack, and save 13414 @safe pure unittest 13415 { 13416 import std.algorithm.comparison : equal; 13417 13418 auto r1 = [1, 2, 3, 4].padRight(0, 6); 13419 assert(r1.back == 0); 13420 13421 r1.popBack; 13422 auto r2 = r1.save; 13423 assert(r1.equal([1, 2, 3, 4, 0])); 13424 assert(r2.equal([1, 2, 3, 4, 0])); 13425 13426 r1.popBackN(2); 13427 assert(r1.back == 3); 13428 assert(r1.length == 3); 13429 assert(r2.length == 5); 13430 assert(r2.equal([1, 2, 3, 4, 0])); 13431 13432 r2.popFront; 13433 assert(r2.length == 4); 13434 assert(r2[0] == 2); 13435 assert(r2[1] == 3); 13436 assert(r2[2] == 4); 13437 assert(r2[3] == 0); 13438 assert(r2.equal([2, 3, 4, 0])); 13439 13440 r2.popBack; 13441 assert(r2.equal([2, 3, 4])); 13442 13443 auto r3 = [1, 2, 3, 4].padRight(0, 6); 13444 size_t len = 0; 13445 while (!r3.empty) 13446 { 13447 ++len; 13448 r3.popBack; 13449 } 13450 assert(len == 6); 13451 } 13452 13453 // https://issues.dlang.org/show_bug.cgi?id=19042 13454 @safe pure unittest 13455 { 13456 import std.algorithm.comparison : equal; 13457 13458 assert([2, 5, 13].padRight(42, 10).chunks(5) 13459 .equal!equal([[2, 5, 13, 42, 42], [42, 42, 42, 42, 42]])); 13460 13461 assert([1, 2, 3, 4].padRight(0, 10)[7 .. 9].equal([0, 0])); 13462 }