1// Written in the D programming language. 2 3/** 4This module defines the notion of a range. Ranges generalize the concept of 5arrays, lists, or anything that involves sequential access. This abstraction 6enables the same set of algorithms (see $(MREF std, algorithm)) to be used 7with a vast variety of different concrete types. For example, 8a linear search algorithm such as $(REF find, std, algorithm, searching) 9works not just for arrays, but for linked-lists, input files, 10incoming network data, etc. 11 12Guides: 13 14There 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 32Submodules: 33 34This module has two submodules: 35 36The $(MREF std, range, primitives) submodule 37provides basic range functionality. It defines several templates for testing 38whether a given object is a range, what kind of range it is, and provides 39some common range operations. 40 41The $(MREF std, range, interfaces) submodule 42provides object-based interfaces for working with ranges via runtime 43polymorphism. 44 45The remainder of this module provides a rich set of range creation and 46composition 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 212Sortedness: 213 214Ranges whose elements are sorted afford better efficiency with certain 215operations. For this, the $(LREF assumeSorted) function can be used to 216construct a $(LREF SortedRange) from a pre-sorted range. The $(REF 217sort, std, algorithm, sorting) function also conveniently 218returns a $(LREF SortedRange). $(LREF SortedRange) objects provide some additional 219range operations that take advantage of the fact that the range is sorted. 220 221Source: $(PHOBOSSRC std/range/package.d) 222 223License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0). 224 225Authors: $(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 */ 230module std.range; 231 232public import std.array; 233public import std.range.interfaces; 234public import std.range.primitives; 235public import std.typecons : Flag, Yes, No; 236 237import std.internal.attributes : betterC; 238import std.meta : allSatisfy, anySatisfy, staticMap; 239import std.traits : CommonType, isCallable, isFloatingPoint, isIntegral, 240 isPointer, isSomeFunction, isStaticArray, Unqual, isInstanceOf; 241 242 243/** 244Iterates a bidirectional range backwards. The original range can be 245accessed by using the `source` property. Applying retro twice to 246the same range yields the original range. 247 248Params: 249 r = the bidirectional range to iterate backwards 250 251Returns: 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. 255See_Also: 256 $(REF reverse, std,algorithm,mutation) for mutating the source range directly. 257 */ 258auto retro(Range)(Range r) 259if (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 mixin ImplementLength!source; 353 } 354 355 return Result!()(r); 356 } 357} 358 359 360/// 361pure @safe nothrow @nogc unittest 362{ 363 import std.algorithm.comparison : equal; 364 int[5] a = [ 1, 2, 3, 4, 5 ]; 365 int[5] b = [ 5, 4, 3, 2, 1 ]; 366 assert(equal(retro(a[]), b[])); 367 assert(retro(a[]).source is a[]); 368 assert(retro(retro(a[])) is a[]); 369} 370 371pure @safe nothrow unittest 372{ 373 import std.algorithm.comparison : equal; 374 static assert(isBidirectionalRange!(typeof(retro("hello")))); 375 int[] a; 376 static assert(is(typeof(a) == typeof(retro(retro(a))))); 377 assert(retro(retro(a)) is a); 378 static assert(isRandomAccessRange!(typeof(retro([1, 2, 3])))); 379 void test(int[] input, int[] witness) 380 { 381 auto r = retro(input); 382 assert(r.front == witness.front); 383 assert(r.back == witness.back); 384 assert(equal(r, witness)); 385 } 386 test([ 1 ], [ 1 ]); 387 test([ 1, 2 ], [ 2, 1 ]); 388 test([ 1, 2, 3 ], [ 3, 2, 1 ]); 389 test([ 1, 2, 3, 4 ], [ 4, 3, 2, 1 ]); 390 test([ 1, 2, 3, 4, 5 ], [ 5, 4, 3, 2, 1 ]); 391 test([ 1, 2, 3, 4, 5, 6 ], [ 6, 5, 4, 3, 2, 1 ]); 392 393 immutable foo = [1,2,3].idup; 394 auto r = retro(foo); 395 assert(equal(r, [3, 2, 1])); 396} 397 398pure @safe nothrow unittest 399{ 400 import std.internal.test.dummyrange : AllDummyRanges, propagatesRangeType, 401 ReturnBy; 402 403 foreach (DummyType; AllDummyRanges) 404 { 405 static if (!isBidirectionalRange!DummyType) 406 { 407 static assert(!__traits(compiles, Retro!DummyType)); 408 } 409 else 410 { 411 DummyType dummyRange; 412 dummyRange.reinit(); 413 414 auto myRetro = retro(dummyRange); 415 static assert(propagatesRangeType!(typeof(myRetro), DummyType)); 416 assert(myRetro.front == 10); 417 assert(myRetro.back == 1); 418 assert(myRetro.moveFront() == 10); 419 assert(myRetro.moveBack() == 1); 420 421 static if (isRandomAccessRange!DummyType && hasLength!DummyType) 422 { 423 assert(myRetro[0] == myRetro.front); 424 assert(myRetro.moveAt(2) == 8); 425 426 static if (DummyType.r == ReturnBy.Reference) 427 { 428 { 429 myRetro[9]++; 430 scope(exit) myRetro[9]--; 431 assert(dummyRange[0] == 2); 432 myRetro.front++; 433 scope(exit) myRetro.front--; 434 assert(myRetro.front == 11); 435 myRetro.back++; 436 scope(exit) myRetro.back--; 437 assert(myRetro.back == 3); 438 } 439 440 { 441 myRetro.front = 0xFF; 442 scope(exit) myRetro.front = 10; 443 assert(dummyRange.back == 0xFF); 444 445 myRetro.back = 0xBB; 446 scope(exit) myRetro.back = 1; 447 assert(dummyRange.front == 0xBB); 448 449 myRetro[1] = 11; 450 scope(exit) myRetro[1] = 8; 451 assert(dummyRange[8] == 11); 452 } 453 } 454 } 455 } 456 } 457} 458 459pure @safe nothrow @nogc unittest 460{ 461 import std.algorithm.comparison : equal; 462 auto LL = iota(1L, 4L); 463 auto r = retro(LL); 464 long[3] excepted = [3, 2, 1]; 465 assert(equal(r, excepted[])); 466} 467 468// https://issues.dlang.org/show_bug.cgi?id=12662 469pure @safe nothrow @nogc unittest 470{ 471 int[3] src = [1,2,3]; 472 int[] data = src[]; 473 foreach_reverse (x; data) {} 474 foreach (x; data.retro) {} 475} 476 477 478/** 479Iterates range `r` with stride `n`. If the range is a 480random-access range, moves by indexing into the range; otherwise, 481moves by successive calls to `popFront`. Applying stride twice to 482the same range results in a stride with a step that is the 483product of the two applications. It is an error for `n` to be 0. 484 485Params: 486 r = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to stride over 487 n = the number of elements to skip over 488 489Returns: 490 At minimum, an input range. The resulting range will adopt the 491 range primitives of the underlying range as long as 492 $(REF hasLength, std,range,primitives) is `true`. 493 */ 494auto stride(Range)(Range r, size_t n) 495if (isInputRange!(Unqual!Range)) 496in 497{ 498 assert(n != 0, "stride cannot have step zero."); 499} 500do 501{ 502 import std.algorithm.comparison : min; 503 504 static if (is(typeof(stride(r.source, n)) == Range)) 505 { 506 // stride(stride(r, n1), n2) is stride(r, n1 * n2) 507 return stride(r.source, r._n * n); 508 } 509 else 510 { 511 static struct Result 512 { 513 private alias R = Unqual!Range; 514 public R source; 515 private size_t _n; 516 517 // Chop off the slack elements at the end 518 static if (hasLength!R && 519 (isRandomAccessRange!R && hasSlicing!R 520 || isBidirectionalRange!R)) 521 private void eliminateSlackElements() 522 { 523 auto slack = source.length % _n; 524 525 if (slack) 526 { 527 slack--; 528 } 529 else if (!source.empty) 530 { 531 slack = min(_n, source.length) - 1; 532 } 533 else 534 { 535 slack = 0; 536 } 537 if (!slack) return; 538 static if (isRandomAccessRange!R && hasLength!R && hasSlicing!R) 539 { 540 source = source[0 .. source.length - slack]; 541 } 542 else static if (isBidirectionalRange!R) 543 { 544 foreach (i; 0 .. slack) 545 { 546 source.popBack(); 547 } 548 } 549 } 550 551 static if (isForwardRange!R) 552 { 553 @property auto save() 554 { 555 return Result(source.save, _n); 556 } 557 } 558 559 static if (isInfinite!R) 560 { 561 enum bool empty = false; 562 } 563 else 564 { 565 @property bool empty() 566 { 567 return source.empty; 568 } 569 } 570 571 @property auto ref front() 572 { 573 return source.front; 574 } 575 576 static if (is(typeof(.moveFront(source)))) 577 { 578 ElementType!R moveFront() 579 { 580 return source.moveFront(); 581 } 582 } 583 584 static if (hasAssignableElements!R) 585 { 586 @property void front(ElementType!R val) 587 { 588 source.front = val; 589 } 590 } 591 592 void popFront() 593 { 594 source.popFrontN(_n); 595 } 596 597 static if (isBidirectionalRange!R && hasLength!R) 598 { 599 void popBack() 600 { 601 popBackN(source, _n); 602 } 603 604 @property auto ref back() 605 { 606 eliminateSlackElements(); 607 return source.back; 608 } 609 610 static if (is(typeof(.moveBack(source)))) 611 { 612 ElementType!R moveBack() 613 { 614 eliminateSlackElements(); 615 return source.moveBack(); 616 } 617 } 618 619 static if (hasAssignableElements!R) 620 { 621 @property void back(ElementType!R val) 622 { 623 eliminateSlackElements(); 624 source.back = val; 625 } 626 } 627 } 628 629 static if (isRandomAccessRange!R && hasLength!R) 630 { 631 auto ref opIndex(size_t n) 632 { 633 return source[_n * n]; 634 } 635 636 /** 637 Forwards to $(D moveAt(source, n)). 638 */ 639 static if (is(typeof(source.moveAt(0)))) 640 { 641 ElementType!R moveAt(size_t n) 642 { 643 return source.moveAt(_n * n); 644 } 645 } 646 647 static if (hasAssignableElements!R) 648 { 649 void opIndexAssign(ElementType!R val, size_t n) 650 { 651 source[_n * n] = val; 652 } 653 } 654 } 655 656 static if (hasSlicing!R && hasLength!R) 657 typeof(this) opSlice(size_t lower, size_t upper) 658 { 659 assert(upper >= lower && upper <= length, 660 "Attempt to get out-of-bounds slice of `stride` range"); 661 immutable translatedUpper = (upper == 0) ? 0 : 662 (upper * _n - (_n - 1)); 663 immutable translatedLower = min(lower * _n, translatedUpper); 664 665 assert(translatedLower <= translatedUpper, 666 "Overflow when calculating slice of `stride` range"); 667 668 return typeof(this)(source[translatedLower .. translatedUpper], _n); 669 } 670 671 static if (hasLength!R) 672 { 673 @property auto length() 674 { 675 return (source.length + _n - 1) / _n; 676 } 677 678 alias opDollar = length; 679 } 680 } 681 return Result(r, n); 682 } 683} 684 685/// 686pure @safe nothrow unittest 687{ 688 import std.algorithm.comparison : equal; 689 690 int[] a = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ]; 691 assert(equal(stride(a, 3), [ 1, 4, 7, 10 ][])); 692 assert(stride(stride(a, 2), 3) == stride(a, 6)); 693} 694 695pure @safe nothrow @nogc unittest 696{ 697 import std.algorithm.comparison : equal; 698 699 int[4] testArr = [1,2,3,4]; 700 static immutable result = [1, 3]; 701 assert(equal(testArr[].stride(2), result)); 702} 703 704debug pure nothrow @system unittest 705{//check the contract 706 int[4] testArr = [1,2,3,4]; 707 bool passed = false; 708 scope (success) assert(passed); 709 import core.exception : AssertError; 710 //std.exception.assertThrown won't do because it can't infer nothrow 711 // https://issues.dlang.org/show_bug.cgi?id=12647 712 try 713 { 714 auto unused = testArr[].stride(0); 715 } 716 catch (AssertError unused) 717 { 718 passed = true; 719 } 720} 721 722pure @safe nothrow unittest 723{ 724 import std.algorithm.comparison : equal; 725 import std.internal.test.dummyrange : AllDummyRanges, propagatesRangeType, 726 ReturnBy; 727 728 static assert(isRandomAccessRange!(typeof(stride([1, 2, 3], 2)))); 729 void test(size_t n, int[] input, int[] witness) 730 { 731 assert(equal(stride(input, n), witness)); 732 } 733 test(1, [], []); 734 int[] arr = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; 735 assert(stride(stride(arr, 2), 3) is stride(arr, 6)); 736 test(1, arr, arr); 737 test(2, arr, [1, 3, 5, 7, 9]); 738 test(3, arr, [1, 4, 7, 10]); 739 test(4, arr, [1, 5, 9]); 740 741 // Test slicing. 742 auto s1 = stride(arr, 1); 743 assert(equal(s1[1 .. 4], [2, 3, 4])); 744 assert(s1[1 .. 4].length == 3); 745 assert(equal(s1[1 .. 5], [2, 3, 4, 5])); 746 assert(s1[1 .. 5].length == 4); 747 assert(s1[0 .. 0].empty); 748 assert(s1[3 .. 3].empty); 749 // assert(s1[$ .. $].empty); 750 assert(s1[s1.opDollar .. s1.opDollar].empty); 751 752 auto s2 = stride(arr, 2); 753 assert(equal(s2[0 .. 2], [1,3])); 754 assert(s2[0 .. 2].length == 2); 755 assert(equal(s2[1 .. 5], [3, 5, 7, 9])); 756 assert(s2[1 .. 5].length == 4); 757 assert(s2[0 .. 0].empty); 758 assert(s2[3 .. 3].empty); 759 // assert(s2[$ .. $].empty); 760 assert(s2[s2.opDollar .. s2.opDollar].empty); 761 762 // Test fix for https://issues.dlang.org/show_bug.cgi?id=5035 763 auto m = [1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]; // 3 rows, 4 columns 764 auto col = stride(m, 4); 765 assert(equal(col, [1, 1, 1])); 766 assert(equal(retro(col), [1, 1, 1])); 767 768 immutable int[] immi = [ 1, 2, 3 ]; 769 static assert(isRandomAccessRange!(typeof(stride(immi, 1)))); 770 771 // Check for infiniteness propagation. 772 static assert(isInfinite!(typeof(stride(repeat(1), 3)))); 773 774 foreach (DummyType; AllDummyRanges) 775 { 776 DummyType dummyRange; 777 dummyRange.reinit(); 778 779 auto myStride = stride(dummyRange, 4); 780 781 // Should fail if no length and bidirectional b/c there's no way 782 // to know how much slack we have. 783 static if (hasLength!DummyType || !isBidirectionalRange!DummyType) 784 { 785 static assert(propagatesRangeType!(typeof(myStride), DummyType)); 786 } 787 assert(myStride.front == 1); 788 assert(myStride.moveFront() == 1); 789 assert(equal(myStride, [1, 5, 9])); 790 791 static if (hasLength!DummyType) 792 { 793 assert(myStride.length == 3); 794 } 795 796 static if (isBidirectionalRange!DummyType && hasLength!DummyType) 797 { 798 assert(myStride.back == 9); 799 assert(myStride.moveBack() == 9); 800 } 801 802 static if (isRandomAccessRange!DummyType && hasLength!DummyType) 803 { 804 assert(myStride[0] == 1); 805 assert(myStride[1] == 5); 806 assert(myStride.moveAt(1) == 5); 807 assert(myStride[2] == 9); 808 809 static assert(hasSlicing!(typeof(myStride))); 810 } 811 812 static if (DummyType.r == ReturnBy.Reference) 813 { 814 // Make sure reference is propagated. 815 816 { 817 myStride.front++; 818 scope(exit) myStride.front--; 819 assert(dummyRange.front == 2); 820 } 821 { 822 myStride.front = 4; 823 scope(exit) myStride.front = 1; 824 assert(dummyRange.front == 4); 825 } 826 827 static if (isBidirectionalRange!DummyType && hasLength!DummyType) 828 { 829 { 830 myStride.back++; 831 scope(exit) myStride.back--; 832 assert(myStride.back == 10); 833 } 834 { 835 myStride.back = 111; 836 scope(exit) myStride.back = 9; 837 assert(myStride.back == 111); 838 } 839 840 static if (isRandomAccessRange!DummyType) 841 { 842 { 843 myStride[1]++; 844 scope(exit) myStride[1]--; 845 assert(dummyRange[4] == 6); 846 } 847 { 848 myStride[1] = 55; 849 scope(exit) myStride[1] = 5; 850 assert(dummyRange[4] == 55); 851 } 852 } 853 } 854 } 855 } 856} 857 858pure @safe nothrow unittest 859{ 860 import std.algorithm.comparison : equal; 861 862 auto LL = iota(1L, 10L); 863 auto s = stride(LL, 3); 864 assert(equal(s, [1L, 4L, 7L])); 865} 866 867/** 868Spans multiple ranges in sequence. The function `chain` takes any 869number of ranges and returns a $(D Chain!(R1, R2,...)) object. The 870ranges may be different, but they must have the same element type. The 871result is a range that offers the `front`, `popFront`, and $(D 872empty) primitives. If all input ranges offer random access and $(D 873length), `Chain` offers them as well. 874 875If only one range is offered to `Chain` or `chain`, the $(D 876Chain) type exits the picture by aliasing itself directly to that 877range's type. 878 879Params: 880 rs = the $(REF_ALTTEXT input ranges, isInputRange, std,range,primitives) to chain together 881 882Returns: 883 An input range at minimum. If all of the ranges in `rs` provide 884 a range primitive, the returned range will also provide that range 885 primitive. 886 887See_Also: $(LREF only) to chain values to a range 888 */ 889auto chain(Ranges...)(Ranges rs) 890if (Ranges.length > 0 && 891 allSatisfy!(isInputRange, staticMap!(Unqual, Ranges)) && 892 !is(CommonType!(staticMap!(ElementType, staticMap!(Unqual, Ranges))) == void)) 893{ 894 static if (Ranges.length == 1) 895 { 896 return rs[0]; 897 } 898 else 899 { 900 static struct Result 901 { 902 private: 903 alias R = staticMap!(Unqual, Ranges); 904 alias RvalueElementType = CommonType!(staticMap!(.ElementType, R)); 905 template sameET(A) 906 { 907 enum sameET = is(.ElementType!A == RvalueElementType); 908 } 909 910 enum bool allSameType = allSatisfy!(sameET, R); 911 alias ElementType = RvalueElementType; 912 913 static if (allSameType && allSatisfy!(hasLvalueElements, R)) 914 { 915 static ref RvalueElementType fixRef(ref RvalueElementType val) 916 { 917 return val; 918 } 919 } 920 else 921 { 922 static RvalueElementType fixRef(RvalueElementType val) 923 { 924 return val; 925 } 926 } 927 928 // This is the entire state 929 R source; 930 // TODO: use a vtable (or more) instead of linear iteration 931 932 public: 933 this(R input) 934 { 935 // Must be static foreach because of https://issues.dlang.org/show_bug.cgi?id=21209 936 static foreach (i, v; input) 937 { 938 source[i] = v; 939 } 940 } 941 942 import std.meta : anySatisfy; 943 944 static if (anySatisfy!(isInfinite, R)) 945 { 946 // Propagate infiniteness. 947 enum bool empty = false; 948 } 949 else 950 { 951 @property bool empty() 952 { 953 foreach (i, Unused; R) 954 { 955 if (!source[i].empty) return false; 956 } 957 return true; 958 } 959 } 960 961 static if (allSatisfy!(isForwardRange, R)) 962 @property auto save() 963 { 964 auto saveSource(size_t len)() 965 { 966 import std.typecons : tuple; 967 static assert(len > 0); 968 static if (len == 1) 969 { 970 return tuple(source[0].save); 971 } 972 else 973 { 974 return saveSource!(len - 1)() ~ 975 tuple(source[len - 1].save); 976 } 977 } 978 return Result(saveSource!(R.length).expand); 979 } 980 981 void popFront() 982 { 983 foreach (i, Unused; R) 984 { 985 if (source[i].empty) continue; 986 source[i].popFront(); 987 return; 988 } 989 assert(false, "Attempt to `popFront` of empty `chain` range"); 990 } 991 992 @property auto ref front() 993 { 994 foreach (i, Unused; R) 995 { 996 if (source[i].empty) continue; 997 return fixRef(source[i].front); 998 } 999 assert(false, "Attempt to get `front` of empty `chain` range"); 1000 } 1001 1002 static if (allSameType && allSatisfy!(hasAssignableElements, R)) 1003 { 1004 // @@@BUG@@@ 1005 //@property void front(T)(T v) if (is(T : RvalueElementType)) 1006 1007 @property void front(RvalueElementType v) 1008 { 1009 foreach (i, Unused; R) 1010 { 1011 if (source[i].empty) continue; 1012 source[i].front = v; 1013 return; 1014 } 1015 assert(false, "Attempt to set `front` of empty `chain` range"); 1016 } 1017 } 1018 1019 static if (allSatisfy!(hasMobileElements, R)) 1020 { 1021 RvalueElementType moveFront() 1022 { 1023 foreach (i, Unused; R) 1024 { 1025 if (source[i].empty) continue; 1026 return source[i].moveFront(); 1027 } 1028 assert(false, "Attempt to `moveFront` of empty `chain` range"); 1029 } 1030 } 1031 1032 static if (allSatisfy!(isBidirectionalRange, R)) 1033 { 1034 @property auto ref back() 1035 { 1036 foreach_reverse (i, Unused; R) 1037 { 1038 if (source[i].empty) continue; 1039 return fixRef(source[i].back); 1040 } 1041 assert(false, "Attempt to get `back` of empty `chain` range"); 1042 } 1043 1044 void popBack() 1045 { 1046 foreach_reverse (i, Unused; R) 1047 { 1048 if (source[i].empty) continue; 1049 source[i].popBack(); 1050 return; 1051 } 1052 assert(false, "Attempt to `popBack` of empty `chain` range"); 1053 } 1054 1055 static if (allSatisfy!(hasMobileElements, R)) 1056 { 1057 RvalueElementType moveBack() 1058 { 1059 foreach_reverse (i, Unused; R) 1060 { 1061 if (source[i].empty) continue; 1062 return source[i].moveBack(); 1063 } 1064 assert(false, "Attempt to `moveBack` of empty `chain` range"); 1065 } 1066 } 1067 1068 static if (allSameType && allSatisfy!(hasAssignableElements, R)) 1069 { 1070 @property void back(RvalueElementType v) 1071 { 1072 foreach_reverse (i, Unused; R) 1073 { 1074 if (source[i].empty) continue; 1075 source[i].back = v; 1076 return; 1077 } 1078 assert(false, "Attempt to set `back` of empty `chain` range"); 1079 } 1080 } 1081 } 1082 1083 static if (allSatisfy!(hasLength, R)) 1084 { 1085 @property size_t length() 1086 { 1087 size_t result; 1088 foreach (i, Unused; R) 1089 { 1090 result += source[i].length; 1091 } 1092 return result; 1093 } 1094 1095 alias opDollar = length; 1096 } 1097 1098 static if (allSatisfy!(isRandomAccessRange, R)) 1099 { 1100 auto ref opIndex(size_t index) 1101 { 1102 foreach (i, Range; R) 1103 { 1104 static if (isInfinite!(Range)) 1105 { 1106 return source[i][index]; 1107 } 1108 else 1109 { 1110 immutable length = source[i].length; 1111 if (index < length) return fixRef(source[i][index]); 1112 index -= length; 1113 } 1114 } 1115 assert(false, "Attempt to access out-of-bounds index of `chain` range"); 1116 } 1117 1118 static if (allSatisfy!(hasMobileElements, R)) 1119 { 1120 RvalueElementType moveAt(size_t index) 1121 { 1122 foreach (i, Range; R) 1123 { 1124 static if (isInfinite!(Range)) 1125 { 1126 return source[i].moveAt(index); 1127 } 1128 else 1129 { 1130 immutable length = source[i].length; 1131 if (index < length) return source[i].moveAt(index); 1132 index -= length; 1133 } 1134 } 1135 assert(false, "Attempt to move out-of-bounds index of `chain` range"); 1136 } 1137 } 1138 1139 static if (allSameType && allSatisfy!(hasAssignableElements, R)) 1140 void opIndexAssign(ElementType v, size_t index) 1141 { 1142 foreach (i, Range; R) 1143 { 1144 static if (isInfinite!(Range)) 1145 { 1146 source[i][index] = v; 1147 } 1148 else 1149 { 1150 immutable length = source[i].length; 1151 if (index < length) 1152 { 1153 source[i][index] = v; 1154 return; 1155 } 1156 index -= length; 1157 } 1158 } 1159 assert(false, "Attempt to write out-of-bounds index of `chain` range"); 1160 } 1161 } 1162 1163 static if (allSatisfy!(hasLength, R) && allSatisfy!(hasSlicing, R)) 1164 auto opSlice(size_t begin, size_t end) return scope 1165 { 1166 auto result = this; 1167 foreach (i, Unused; R) 1168 { 1169 immutable len = result.source[i].length; 1170 if (len < begin) 1171 { 1172 result.source[i] = result.source[i] 1173 [len .. len]; 1174 begin -= len; 1175 } 1176 else 1177 { 1178 result.source[i] = result.source[i] 1179 [begin .. len]; 1180 break; 1181 } 1182 } 1183 auto cut = length; 1184 cut = cut <= end ? 0 : cut - end; 1185 foreach_reverse (i, Unused; R) 1186 { 1187 immutable len = result.source[i].length; 1188 if (cut > len) 1189 { 1190 result.source[i] = result.source[i] 1191 [0 .. 0]; 1192 cut -= len; 1193 } 1194 else 1195 { 1196 result.source[i] = result.source[i] 1197 [0 .. len - cut]; 1198 break; 1199 } 1200 } 1201 return result; 1202 } 1203 } 1204 return Result(rs); 1205 } 1206} 1207 1208/// 1209pure @safe nothrow unittest 1210{ 1211 import std.algorithm.comparison : equal; 1212 1213 int[] arr1 = [ 1, 2, 3, 4 ]; 1214 int[] arr2 = [ 5, 6 ]; 1215 int[] arr3 = [ 7 ]; 1216 auto s = chain(arr1, arr2, arr3); 1217 assert(s.length == 7); 1218 assert(s[5] == 6); 1219 assert(equal(s, [1, 2, 3, 4, 5, 6, 7][])); 1220} 1221 1222/** 1223 * Range primitives are carried over to the returned range if 1224 * all of the ranges provide them 1225 */ 1226pure @safe nothrow unittest 1227{ 1228 import std.algorithm.comparison : equal; 1229 import std.algorithm.sorting : sort; 1230 1231 int[] arr1 = [5, 2, 8]; 1232 int[] arr2 = [3, 7, 9]; 1233 int[] arr3 = [1, 4, 6]; 1234 1235 // in-place sorting across all of the arrays 1236 auto s = arr1.chain(arr2, arr3).sort; 1237 1238 assert(s.equal([1, 2, 3, 4, 5, 6, 7, 8, 9])); 1239 assert(arr1.equal([1, 2, 3])); 1240 assert(arr2.equal([4, 5, 6])); 1241 assert(arr3.equal([7, 8, 9])); 1242} 1243 1244/** 1245Due to safe type promotion in D, chaining together different 1246character ranges results in a `uint` range. 1247 1248Use $(REF_ALTTEXT byChar, byChar,std,utf), $(REF_ALTTEXT byWchar, byWchar,std,utf), 1249and $(REF_ALTTEXT byDchar, byDchar,std,utf) on the ranges 1250to get the type you need. 1251 */ 1252pure @safe nothrow unittest 1253{ 1254 import std.utf : byChar, byCodeUnit; 1255 1256 auto s1 = "string one"; 1257 auto s2 = "string two"; 1258 // s1 and s2 front is dchar because of auto-decoding 1259 static assert(is(typeof(s1.front) == dchar) && is(typeof(s2.front) == dchar)); 1260 1261 auto r1 = s1.chain(s2); 1262 // chains of ranges of the same character type give that same type 1263 static assert(is(typeof(r1.front) == dchar)); 1264 1265 auto s3 = "string three".byCodeUnit; 1266 static assert(is(typeof(s3.front) == immutable char)); 1267 auto r2 = s1.chain(s3); 1268 // chaining ranges of mixed character types gives `dchar` 1269 static assert(is(typeof(r2.front) == dchar)); 1270 1271 // use byChar on character ranges to correctly convert them to UTF-8 1272 auto r3 = s1.byChar.chain(s3); 1273 static assert(is(typeof(r3.front) == immutable char)); 1274} 1275 1276pure @safe nothrow unittest 1277{ 1278 import std.algorithm.comparison : equal; 1279 import std.internal.test.dummyrange : AllDummyRanges, dummyLength, 1280 propagatesRangeType; 1281 1282 { 1283 int[] arr1 = [ 1, 2, 3, 4 ]; 1284 int[] arr2 = [ 5, 6 ]; 1285 int[] arr3 = [ 7 ]; 1286 int[] witness = [ 1, 2, 3, 4, 5, 6, 7 ]; 1287 auto s1 = chain(arr1); 1288 static assert(isRandomAccessRange!(typeof(s1))); 1289 auto s2 = chain(arr1, arr2); 1290 static assert(isBidirectionalRange!(typeof(s2))); 1291 static assert(isRandomAccessRange!(typeof(s2))); 1292 s2.front = 1; 1293 auto s = chain(arr1, arr2, arr3); 1294 assert(s[5] == 6); 1295 assert(equal(s, witness)); 1296 assert(s[5] == 6); 1297 } 1298 { 1299 int[] arr1 = [ 1, 2, 3, 4 ]; 1300 int[] witness = [ 1, 2, 3, 4 ]; 1301 assert(equal(chain(arr1), witness)); 1302 } 1303 { 1304 uint[] foo = [1,2,3,4,5]; 1305 uint[] bar = [1,2,3,4,5]; 1306 auto c = chain(foo, bar); 1307 c[3] = 42; 1308 assert(c[3] == 42); 1309 assert(c.moveFront() == 1); 1310 assert(c.moveBack() == 5); 1311 assert(c.moveAt(4) == 5); 1312 assert(c.moveAt(5) == 1); 1313 } 1314 1315 1316 // Make sure https://issues.dlang.org/show_bug.cgi?id=3311 is fixed. 1317 // elements are mutable. 1318 assert(equal(chain(iota(0, 3), iota(0, 3)), [0, 1, 2, 0, 1, 2])); 1319 1320 // Test the case where infinite ranges are present. 1321 auto inf = chain([0,1,2][], cycle([4,5,6][]), [7,8,9][]); // infinite range 1322 assert(inf[0] == 0); 1323 assert(inf[3] == 4); 1324 assert(inf[6] == 4); 1325 assert(inf[7] == 5); 1326 static assert(isInfinite!(typeof(inf))); 1327 1328 immutable int[] immi = [ 1, 2, 3 ]; 1329 immutable float[] immf = [ 1, 2, 3 ]; 1330 static assert(is(typeof(chain(immi, immf)))); 1331 1332 // Check that chain at least instantiates and compiles with every possible 1333 // pair of DummyRange types, in either order. 1334 1335 foreach (DummyType1; AllDummyRanges) 1336 (){ // workaround slow optimizations for large functions 1337 // https://issues.dlang.org/show_bug.cgi?id=2396 1338 DummyType1 dummy1; 1339 foreach (DummyType2; AllDummyRanges) 1340 { 1341 DummyType2 dummy2; 1342 auto myChain = chain(dummy1, dummy2); 1343 1344 static assert( 1345 propagatesRangeType!(typeof(myChain), DummyType1, DummyType2) 1346 ); 1347 1348 assert(myChain.front == 1); 1349 foreach (i; 0 .. dummyLength) 1350 { 1351 myChain.popFront(); 1352 } 1353 assert(myChain.front == 1); 1354 1355 static if (isBidirectionalRange!DummyType1 && 1356 isBidirectionalRange!DummyType2) { 1357 assert(myChain.back == 10); 1358 } 1359 1360 static if (isRandomAccessRange!DummyType1 && 1361 isRandomAccessRange!DummyType2) { 1362 assert(myChain[0] == 1); 1363 } 1364 1365 static if (hasLvalueElements!DummyType1 && hasLvalueElements!DummyType2) 1366 { 1367 static assert(hasLvalueElements!(typeof(myChain))); 1368 } 1369 else 1370 { 1371 static assert(!hasLvalueElements!(typeof(myChain))); 1372 } 1373 } 1374 }(); 1375} 1376 1377pure @safe nothrow @nogc unittest 1378{ 1379 class Foo{} 1380 immutable(Foo)[] a; 1381 immutable(Foo)[] b; 1382 assert(chain(a, b).empty); 1383} 1384 1385// https://issues.dlang.org/show_bug.cgi?id=18657 1386pure @safe unittest 1387{ 1388 import std.algorithm.comparison : equal; 1389 string s = "foo"; 1390 auto r = refRange(&s).chain("bar"); 1391 assert(equal(r.save, "foobar")); 1392 assert(equal(r, "foobar")); 1393} 1394 1395/** 1396Choose one of two ranges at runtime depending on a Boolean condition. 1397 1398The ranges may be different, but they must have compatible element types (i.e. 1399`CommonType` must exist for the two element types). The result is a range 1400that offers the weakest capabilities of the two (e.g. `ForwardRange` if $(D 1401R1) is a random-access range and `R2` is a forward range). 1402 1403Params: 1404 condition = which range to choose: `r1` if `true`, `r2` otherwise 1405 r1 = the "true" range 1406 r2 = the "false" range 1407 1408Returns: 1409 A range type dependent on `R1` and `R2`. 1410 */ 1411auto choose(R1, R2)(bool condition, return scope R1 r1, return scope R2 r2) 1412if (isInputRange!(Unqual!R1) && isInputRange!(Unqual!R2) && 1413 !is(CommonType!(ElementType!(Unqual!R1), ElementType!(Unqual!R2)) == void)) 1414{ 1415 size_t choice = condition? 0: 1; 1416 return ChooseResult!(R1, R2)(choice, r1, r2); 1417} 1418 1419/// 1420@safe nothrow pure @nogc unittest 1421{ 1422 import std.algorithm.comparison : equal; 1423 import std.algorithm.iteration : filter, map; 1424 1425 auto data1 = only(1, 2, 3, 4).filter!(a => a != 3); 1426 auto data2 = only(5, 6, 7, 8).map!(a => a + 1); 1427 1428 // choose() is primarily useful when you need to select one of two ranges 1429 // with different types at runtime. 1430 static assert(!is(typeof(data1) == typeof(data2))); 1431 1432 auto chooseRange(bool pickFirst) 1433 { 1434 // The returned range is a common wrapper type that can be used for 1435 // returning or storing either range without running into a type error. 1436 return choose(pickFirst, data1, data2); 1437 1438 // Simply returning the chosen range without using choose() does not 1439 // work, because map() and filter() return different types. 1440 //return pickFirst ? data1 : data2; // does not compile 1441 } 1442 1443 auto result = chooseRange(true); 1444 assert(result.equal(only(1, 2, 4))); 1445 1446 result = chooseRange(false); 1447 assert(result.equal(only(6, 7, 8, 9))); 1448} 1449 1450 1451private struct ChooseResult(Ranges...) 1452{ 1453 import std.meta : aliasSeqOf, ApplyLeft; 1454 import std.traits : hasElaborateCopyConstructor, hasElaborateDestructor, 1455 lvalueOf; 1456 1457 private union 1458 { 1459 Ranges rs; 1460 } 1461 private size_t chosenI; 1462 1463 private static auto ref actOnChosen(alias foo, ExtraArgs ...) 1464 (ref ChooseResult r, auto ref ExtraArgs extraArgs) 1465 { 1466 ref getI(size_t i)(return ref ChooseResult r) @trusted { return r.rs[i]; } 1467 1468 switch (r.chosenI) 1469 { 1470 static foreach (candI; 0 .. rs.length) 1471 { 1472 case candI: return foo(getI!candI(r), extraArgs); 1473 } 1474 1475 default: assert(false); 1476 } 1477 } 1478 1479 // @trusted because of assignment of r which overlap each other 1480 this(size_t chosen, return scope Ranges rs) @trusted 1481 { 1482 import core.lifetime : emplace; 1483 1484 // This should be the only place chosenI is ever assigned 1485 // independently 1486 this.chosenI = chosen; 1487 1488 // Otherwise the compiler will complain about skipping these fields 1489 static foreach (i; 0 .. rs.length) 1490 { 1491 this.rs[i] = Ranges[i].init; 1492 } 1493 1494 // The relevant field needs to be initialized last so it will overwrite 1495 // the other initializations and not the other way around. 1496 sw: switch (chosenI) 1497 { 1498 static foreach (i; 0 .. rs.length) 1499 { 1500 case i: 1501 emplace(&this.rs[i], rs[i]); 1502 break sw; 1503 } 1504 1505 default: assert(false); 1506 } 1507 } 1508 1509 // Some legacy code may still call this with typeof(choose(/*...*/))(/*...*/) 1510 // without this overload the regular constructor would invert the meaning of 1511 // the boolean 1512 static if (rs.length == 2) 1513 pragma(inline, true) 1514 deprecated("Call with size_t (0 = first), or use the choose function") 1515 this(bool firstChosen, Ranges rs) 1516 { 1517 import core.lifetime : move; 1518 this(cast(size_t)(firstChosen? 0: 1), rs[0].move, rs[1].move); 1519 } 1520 1521 void opAssign(ChooseResult r) 1522 { 1523 ref getI(size_t i)(return ref ChooseResult r) @trusted { return r.rs[i]; } 1524 1525 static if (anySatisfy!(hasElaborateDestructor, Ranges)) 1526 if (chosenI != r.chosenI) 1527 { 1528 // destroy the current item 1529 actOnChosen!((ref r) => destroy(r))(this); 1530 } 1531 chosenI = r.chosenI; 1532 1533 sw: switch (chosenI) 1534 { 1535 static foreach (candI; 0 .. rs.length) 1536 { 1537 case candI: getI!candI(this) = getI!candI(r); 1538 break sw; 1539 } 1540 1541 default: assert(false); 1542 } 1543 } 1544 1545 // Carefully defined postblit to postblit the appropriate range 1546 static if (anySatisfy!(hasElaborateCopyConstructor, Ranges)) 1547 this(this) 1548 { 1549 actOnChosen!((ref r) { 1550 static if (hasElaborateCopyConstructor!(typeof(r))) r.__postblit(); 1551 })(this); 1552 } 1553 1554 static if (anySatisfy!(hasElaborateDestructor, Ranges)) 1555 ~this() 1556 { 1557 actOnChosen!((ref r) => destroy(r))(this); 1558 } 1559 1560 // Propagate infiniteness. 1561 static if (allSatisfy!(isInfinite, Ranges)) enum bool empty = false; 1562 else @property bool empty() 1563 { 1564 return actOnChosen!(r => r.empty)(this); 1565 } 1566 1567 @property auto ref front() 1568 { 1569 static auto ref getFront(R)(ref R r) { return r.front; } 1570 return actOnChosen!getFront(this); 1571 } 1572 1573 void popFront() 1574 { 1575 return actOnChosen!((ref r) { r.popFront; })(this); 1576 } 1577 1578 static if (allSatisfy!(isForwardRange, Ranges)) 1579 @property auto save() // return scope inferred 1580 { 1581 auto saveOrInit(size_t i)() 1582 { 1583 ref getI() @trusted { return rs[i]; } 1584 if (i == chosenI) return getI().save; 1585 else return Ranges[i].init; 1586 } 1587 1588 return typeof(this)(chosenI, staticMap!(saveOrInit, 1589 aliasSeqOf!(rs.length.iota))); 1590 } 1591 1592 template front(T) 1593 { 1594 private enum overloadValidFor(alias r) = is(typeof(r.front = T.init)); 1595 1596 static if (allSatisfy!(overloadValidFor, rs)) 1597 void front(T v) 1598 { 1599 actOnChosen!((ref r, T v) { r.front = v; })(this, v); 1600 } 1601 } 1602 1603 static if (allSatisfy!(hasMobileElements, Ranges)) 1604 auto moveFront() 1605 { 1606 return actOnChosen!((ref r) => r.moveFront)(this); 1607 } 1608 1609 static if (allSatisfy!(isBidirectionalRange, Ranges)) 1610 { 1611 @property auto ref back() 1612 { 1613 static auto ref getBack(R)(ref R r) { return r.back; } 1614 return actOnChosen!getBack(this); 1615 } 1616 1617 void popBack() 1618 { 1619 actOnChosen!((ref r) { r.popBack; })(this); 1620 } 1621 1622 static if (allSatisfy!(hasMobileElements, Ranges)) 1623 auto moveBack() 1624 { 1625 return actOnChosen!((ref r) => r.moveBack)(this); 1626 } 1627 1628 template back(T) 1629 { 1630 private enum overloadValidFor(alias r) = is(typeof(r.back = T.init)); 1631 1632 static if (allSatisfy!(overloadValidFor, rs)) 1633 void back(T v) 1634 { 1635 actOnChosen!((ref r, T v) { r.back = v; })(this, v); 1636 } 1637 } 1638 } 1639 1640 static if (allSatisfy!(hasLength, Ranges)) 1641 { 1642 @property size_t length() 1643 { 1644 return actOnChosen!(r => r.length)(this); 1645 } 1646 alias opDollar = length; 1647 } 1648 1649 static if (allSatisfy!(isRandomAccessRange, Ranges)) 1650 { 1651 auto ref opIndex(size_t index) 1652 { 1653 static auto ref get(R)(ref R r, size_t index) { return r[index]; } 1654 return actOnChosen!get(this, index); 1655 } 1656 1657 static if (allSatisfy!(hasMobileElements, Ranges)) 1658 auto moveAt(size_t index) 1659 { 1660 return actOnChosen!((ref r, size_t index) => r.moveAt(index)) 1661 (this, index); 1662 } 1663 1664 private enum indexAssignable(T, R) = is(typeof(lvalueOf!R[1] = T.init)); 1665 1666 template opIndexAssign(T) 1667 if (allSatisfy!(ApplyLeft!(indexAssignable, T), Ranges)) 1668 { 1669 void opIndexAssign(T v, size_t index) 1670 { 1671 return actOnChosen!((ref r, size_t index, T v) { r[index] = v; }) 1672 (this, index, v); 1673 } 1674 } 1675 } 1676 1677 static if (allSatisfy!(hasSlicing, Ranges)) 1678 auto opSlice(size_t begin, size_t end) 1679 { 1680 alias Slice(R) = typeof(R.init[0 .. 1]); 1681 alias Slices = staticMap!(Slice, Ranges); 1682 1683 auto sliceOrInit(size_t i)() 1684 { 1685 ref getI() @trusted { return rs[i]; } 1686 return i == chosenI? getI()[begin .. end]: Slices[i].init; 1687 } 1688 1689 return chooseAmong(chosenI, staticMap!(sliceOrInit, 1690 aliasSeqOf!(rs.length.iota))); 1691 } 1692} 1693 1694// https://issues.dlang.org/show_bug.cgi?id=18657 1695pure @safe unittest 1696{ 1697 import std.algorithm.comparison : equal; 1698 string s = "foo"; 1699 auto r = choose(true, refRange(&s), "bar"); 1700 assert(equal(r.save, "foo")); 1701 assert(equal(r, "foo")); 1702} 1703 1704@safe unittest 1705{ 1706 static void* p; 1707 static struct R 1708 { 1709 void* q; 1710 int front; 1711 bool empty; 1712 void popFront() {} 1713 // `p = q;` is only there to prevent inference of `scope return`. 1714 @property @safe R save() { p = q; return this; } 1715 1716 } 1717 R r; 1718 choose(true, r, r).save; 1719} 1720 1721// Make sure ChooseResult.save doesn't trust @system user code. 1722@system unittest // copy is @system 1723{ 1724 static struct R 1725 { 1726 int front; 1727 bool empty; 1728 void popFront() {} 1729 this(this) @system {} 1730 @property R save() { return R(front, empty); } 1731 } 1732 choose(true, R(), R()).save; 1733 choose(true, [0], R()).save; 1734 choose(true, R(), [0]).save; 1735} 1736 1737@safe unittest // copy is @system 1738{ 1739 static struct R 1740 { 1741 int front; 1742 bool empty; 1743 void popFront() {} 1744 this(this) @system {} 1745 @property R save() { return R(front, empty); } 1746 } 1747 static assert(!__traits(compiles, choose(true, R(), R()).save)); 1748 static assert(!__traits(compiles, choose(true, [0], R()).save)); 1749 static assert(!__traits(compiles, choose(true, R(), [0]).save)); 1750} 1751 1752@system unittest // .save is @system 1753{ 1754 static struct R 1755 { 1756 int front; 1757 bool empty; 1758 void popFront() {} 1759 @property R save() @system { return this; } 1760 } 1761 choose(true, R(), R()).save; 1762 choose(true, [0], R()).save; 1763 choose(true, R(), [0]).save; 1764} 1765 1766@safe unittest // .save is @system 1767{ 1768 static struct R 1769 { 1770 int front; 1771 bool empty; 1772 void popFront() {} 1773 @property R save() @system { return this; } 1774 } 1775 static assert(!__traits(compiles, choose(true, R(), R()).save)); 1776 static assert(!__traits(compiles, choose(true, [0], R()).save)); 1777 static assert(!__traits(compiles, choose(true, R(), [0]).save)); 1778} 1779 1780//https://issues.dlang.org/show_bug.cgi?id=19738 1781@safe nothrow pure @nogc unittest 1782{ 1783 static struct EvilRange 1784 { 1785 enum empty = true; 1786 int front; 1787 void popFront() @safe {} 1788 auto opAssign(const ref EvilRange other) 1789 { 1790 *(cast(uint*) 0xcafebabe) = 0xdeadbeef; 1791 return this; 1792 } 1793 } 1794 1795 static assert(!__traits(compiles, () @safe 1796 { 1797 auto c1 = choose(true, EvilRange(), EvilRange()); 1798 auto c2 = c1; 1799 c1 = c2; 1800 })); 1801} 1802 1803 1804// https://issues.dlang.org/show_bug.cgi?id=20495 1805@safe unittest 1806{ 1807 static struct KillableRange 1808 { 1809 int *item; 1810 ref int front() { return *item; } 1811 bool empty() { return *item > 10; } 1812 void popFront() { ++(*item); } 1813 this(this) 1814 { 1815 assert(item is null || cast(size_t) item > 1000); 1816 item = new int(*item); 1817 } 1818 KillableRange save() { return this; } 1819 } 1820 1821 auto kr = KillableRange(new int(1)); 1822 int[] x = [1,2,3,4,5]; // length is first 1823 1824 auto chosen = choose(true, x, kr); 1825 auto chosen2 = chosen.save; 1826} 1827 1828/** 1829Choose one of multiple ranges at runtime. 1830 1831The ranges may be different, but they must have compatible element types. The 1832result is a range that offers the weakest capabilities of all `Ranges`. 1833 1834Params: 1835 index = which range to choose, must be less than the number of ranges 1836 rs = two or more ranges 1837 1838Returns: 1839 The indexed range. If rs consists of only one range, the return type is an 1840 alias of that range's type. 1841 */ 1842auto chooseAmong(Ranges...)(size_t index, return scope Ranges rs) 1843if (Ranges.length >= 2 1844 && allSatisfy!(isInputRange, staticMap!(Unqual, Ranges)) 1845 && !is(CommonType!(staticMap!(ElementType, Ranges)) == void)) 1846{ 1847 return ChooseResult!Ranges(index, rs); 1848} 1849 1850/// 1851@safe nothrow pure @nogc unittest 1852{ 1853 auto test() 1854 { 1855 import std.algorithm.comparison : equal; 1856 1857 int[4] sarr1 = [1, 2, 3, 4]; 1858 int[2] sarr2 = [5, 6]; 1859 int[1] sarr3 = [7]; 1860 auto arr1 = sarr1[]; 1861 auto arr2 = sarr2[]; 1862 auto arr3 = sarr3[]; 1863 1864 { 1865 auto s = chooseAmong(0, arr1, arr2, arr3); 1866 auto t = s.save; 1867 assert(s.length == 4); 1868 assert(s[2] == 3); 1869 s.popFront(); 1870 assert(equal(t, only(1, 2, 3, 4))); 1871 } 1872 { 1873 auto s = chooseAmong(1, arr1, arr2, arr3); 1874 assert(s.length == 2); 1875 s.front = 8; 1876 assert(equal(s, only(8, 6))); 1877 } 1878 { 1879 auto s = chooseAmong(1, arr1, arr2, arr3); 1880 assert(s.length == 2); 1881 s[1] = 9; 1882 assert(equal(s, only(8, 9))); 1883 } 1884 { 1885 auto s = chooseAmong(1, arr2, arr1, arr3)[1 .. 3]; 1886 assert(s.length == 2); 1887 assert(equal(s, only(2, 3))); 1888 } 1889 { 1890 auto s = chooseAmong(0, arr1, arr2, arr3); 1891 assert(s.length == 4); 1892 assert(s.back == 4); 1893 s.popBack(); 1894 s.back = 5; 1895 assert(equal(s, only(1, 2, 5))); 1896 s.back = 3; 1897 assert(equal(s, only(1, 2, 3))); 1898 } 1899 { 1900 uint[5] foo = [1, 2, 3, 4, 5]; 1901 uint[5] bar = [6, 7, 8, 9, 10]; 1902 auto c = chooseAmong(1, foo[], bar[]); 1903 assert(c[3] == 9); 1904 c[3] = 42; 1905 assert(c[3] == 42); 1906 assert(c.moveFront() == 6); 1907 assert(c.moveBack() == 10); 1908 assert(c.moveAt(4) == 10); 1909 } 1910 { 1911 import std.range : cycle; 1912 auto s = chooseAmong(0, cycle(arr2), cycle(arr3)); 1913 assert(isInfinite!(typeof(s))); 1914 assert(!s.empty); 1915 assert(s[100] == 8); 1916 assert(s[101] == 9); 1917 assert(s[0 .. 3].equal(only(8, 9, 8))); 1918 } 1919 return 0; 1920 } 1921 // works at runtime 1922 auto a = test(); 1923 // and at compile time 1924 static b = test(); 1925} 1926 1927@safe nothrow pure @nogc unittest 1928{ 1929 int[3] a = [1, 2, 3]; 1930 long[3] b = [4, 5, 6]; 1931 auto c = chooseAmong(0, a[], b[]); 1932 c[0] = 42; 1933 assert(c[0] == 42); 1934} 1935 1936@safe nothrow pure @nogc unittest 1937{ 1938 static struct RefAccessRange 1939 { 1940 int[] r; 1941 ref front() @property { return r[0]; } 1942 ref back() @property { return r[$ - 1]; } 1943 void popFront() { r = r[1 .. $]; } 1944 void popBack() { r = r[0 .. $ - 1]; } 1945 auto empty() @property { return r.empty; } 1946 ref opIndex(size_t i) { return r[i]; } 1947 auto length() @property { return r.length; } 1948 alias opDollar = length; 1949 auto save() { return this; } 1950 } 1951 static assert(isRandomAccessRange!RefAccessRange); 1952 static assert(isRandomAccessRange!RefAccessRange); 1953 int[4] a = [4, 3, 2, 1]; 1954 int[2] b = [6, 5]; 1955 auto c = chooseAmong(0, RefAccessRange(a[]), RefAccessRange(b[])); 1956 1957 void refFunc(ref int a, int target) { assert(a == target); } 1958 1959 refFunc(c[2], 2); 1960 refFunc(c.front, 4); 1961 refFunc(c.back, 1); 1962} 1963 1964 1965/** 1966$(D roundRobin(r1, r2, r3)) yields `r1.front`, then `r2.front`, 1967then `r3.front`, after which it pops off one element from each and 1968continues again from `r1`. For example, if two ranges are involved, 1969it alternately yields elements off the two ranges. `roundRobin` 1970stops after it has consumed all ranges (skipping over the ones that 1971finish early). 1972 */ 1973auto roundRobin(Rs...)(Rs rs) 1974if (Rs.length > 1 && allSatisfy!(isInputRange, staticMap!(Unqual, Rs))) 1975{ 1976 struct Result 1977 { 1978 import std.conv : to; 1979 1980 public Rs source; 1981 private size_t _current = size_t.max; 1982 1983 @property bool empty() 1984 { 1985 foreach (i, Unused; Rs) 1986 { 1987 if (!source[i].empty) return false; 1988 } 1989 return true; 1990 } 1991 1992 @property auto ref front() 1993 { 1994 final switch (_current) 1995 { 1996 foreach (i, R; Rs) 1997 { 1998 case i: 1999 assert( 2000 !source[i].empty, 2001 "Attempting to fetch the front of an empty roundRobin" 2002 ); 2003 return source[i].front; 2004 } 2005 } 2006 assert(0); 2007 } 2008 2009 void popFront() 2010 { 2011 final switch (_current) 2012 { 2013 foreach (i, R; Rs) 2014 { 2015 case i: 2016 source[i].popFront(); 2017 break; 2018 } 2019 } 2020 2021 auto next = _current == (Rs.length - 1) ? 0 : (_current + 1); 2022 final switch (next) 2023 { 2024 foreach (i, R; Rs) 2025 { 2026 case i: 2027 if (!source[i].empty) 2028 { 2029 _current = i; 2030 return; 2031 } 2032 if (i == _current) 2033 { 2034 _current = _current.max; 2035 return; 2036 } 2037 goto case (i + 1) % Rs.length; 2038 } 2039 } 2040 } 2041 2042 static if (allSatisfy!(isForwardRange, staticMap!(Unqual, Rs))) 2043 @property auto save() 2044 { 2045 auto saveSource(size_t len)() 2046 { 2047 import std.typecons : tuple; 2048 static assert(len > 0); 2049 static if (len == 1) 2050 { 2051 return tuple(source[0].save); 2052 } 2053 else 2054 { 2055 return saveSource!(len - 1)() ~ 2056 tuple(source[len - 1].save); 2057 } 2058 } 2059 return Result(saveSource!(Rs.length).expand, _current); 2060 } 2061 2062 static if (allSatisfy!(hasLength, Rs)) 2063 { 2064 @property size_t length() 2065 { 2066 size_t result; 2067 foreach (i, R; Rs) 2068 { 2069 result += source[i].length; 2070 } 2071 return result; 2072 } 2073 2074 alias opDollar = length; 2075 } 2076 } 2077 2078 return Result(rs, 0); 2079} 2080 2081/// 2082@safe unittest 2083{ 2084 import std.algorithm.comparison : equal; 2085 2086 int[] a = [ 1, 2, 3 ]; 2087 int[] b = [ 10, 20, 30, 40 ]; 2088 auto r = roundRobin(a, b); 2089 assert(equal(r, [ 1, 10, 2, 20, 3, 30, 40 ])); 2090} 2091 2092/** 2093 * roundRobin can be used to create "interleave" functionality which inserts 2094 * an element between each element in a range. 2095 */ 2096@safe unittest 2097{ 2098 import std.algorithm.comparison : equal; 2099 2100 auto interleave(R, E)(R range, E element) 2101 if ((isInputRange!R && hasLength!R) || isForwardRange!R) 2102 { 2103 static if (hasLength!R) 2104 immutable len = range.length; 2105 else 2106 immutable len = range.save.walkLength; 2107 2108 return roundRobin( 2109 range, 2110 element.repeat(len - 1) 2111 ); 2112 } 2113 2114 assert(interleave([1, 2, 3], 0).equal([1, 0, 2, 0, 3])); 2115} 2116 2117pure @safe unittest 2118{ 2119 import std.algorithm.comparison : equal; 2120 string f = "foo", b = "bar"; 2121 auto r = roundRobin(refRange(&f), refRange(&b)); 2122 assert(equal(r.save, "fboaor")); 2123 assert(equal(r.save, "fboaor")); 2124} 2125 2126/** 2127Iterates a random-access range starting from a given point and 2128progressively extending left and right from that point. If no initial 2129point is given, iteration starts from the middle of the 2130range. Iteration spans the entire range. 2131 2132When `startingIndex` is 0 the range will be fully iterated in order 2133and in reverse order when `r.length` is given. 2134 2135Params: 2136 r = a random access range with length and slicing 2137 startingIndex = the index to begin iteration from 2138 2139Returns: 2140 A forward range with length 2141 */ 2142auto radial(Range, I)(Range r, I startingIndex) 2143if (isRandomAccessRange!(Unqual!Range) && hasLength!(Unqual!Range) && hasSlicing!(Unqual!Range) && isIntegral!I) 2144{ 2145 if (startingIndex != r.length) ++startingIndex; 2146 return roundRobin(retro(r[0 .. startingIndex]), r[startingIndex .. r.length]); 2147} 2148 2149/// Ditto 2150auto radial(R)(R r) 2151if (isRandomAccessRange!(Unqual!R) && hasLength!(Unqual!R) && hasSlicing!(Unqual!R)) 2152{ 2153 return .radial(r, (r.length - !r.empty) / 2); 2154} 2155 2156/// 2157@safe unittest 2158{ 2159 import std.algorithm.comparison : equal; 2160 int[] a = [ 1, 2, 3, 4, 5 ]; 2161 assert(equal(radial(a), [ 3, 4, 2, 5, 1 ])); 2162 a = [ 1, 2, 3, 4 ]; 2163 assert(equal(radial(a), [ 2, 3, 1, 4 ])); 2164 2165 // If the left end is reached first, the remaining elements on the right 2166 // are concatenated in order: 2167 a = [ 0, 1, 2, 3, 4, 5 ]; 2168 assert(equal(radial(a, 1), [ 1, 2, 0, 3, 4, 5 ])); 2169 2170 // If the right end is reached first, the remaining elements on the left 2171 // are concatenated in reverse order: 2172 assert(equal(radial(a, 4), [ 4, 5, 3, 2, 1, 0 ])); 2173} 2174 2175@safe unittest 2176{ 2177 import std.algorithm.comparison : equal; 2178 import std.conv : text; 2179 import std.exception : enforce; 2180 import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy; 2181 2182 void test(int[] input, int[] witness) 2183 { 2184 enforce(equal(radial(input), witness), 2185 text(radial(input), " vs. ", witness)); 2186 } 2187 test([], []); 2188 test([ 1 ], [ 1 ]); 2189 test([ 1, 2 ], [ 1, 2 ]); 2190 test([ 1, 2, 3 ], [ 2, 3, 1 ]); 2191 test([ 1, 2, 3, 4 ], [ 2, 3, 1, 4 ]); 2192 test([ 1, 2, 3, 4, 5 ], [ 3, 4, 2, 5, 1 ]); 2193 test([ 1, 2, 3, 4, 5, 6 ], [ 3, 4, 2, 5, 1, 6 ]); 2194 2195 int[] a = [ 1, 2, 3, 4, 5 ]; 2196 assert(equal(radial(a, 1), [ 2, 3, 1, 4, 5 ])); 2197 assert(equal(radial(a, 0), [ 1, 2, 3, 4, 5 ])); // only right subrange 2198 assert(equal(radial(a, a.length), [ 5, 4, 3, 2, 1 ])); // only left subrange 2199 static assert(isForwardRange!(typeof(radial(a, 1)))); 2200 2201 auto r = radial([1,2,3,4,5]); 2202 for (auto rr = r.save; !rr.empty; rr.popFront()) 2203 { 2204 assert(rr.front == moveFront(rr)); 2205 } 2206 r.front = 5; 2207 assert(r.front == 5); 2208 2209 // Test instantiation without lvalue elements. 2210 DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random) dummy; 2211 assert(equal(radial(dummy, 4), [5, 6, 4, 7, 3, 8, 2, 9, 1, 10])); 2212 2213 // immutable int[] immi = [ 1, 2 ]; 2214 // static assert(is(typeof(radial(immi)))); 2215} 2216 2217@safe unittest 2218{ 2219 import std.algorithm.comparison : equal; 2220 2221 auto LL = iota(1L, 6L); 2222 auto r = radial(LL); 2223 assert(equal(r, [3L, 4L, 2L, 5L, 1L])); 2224} 2225 2226/** 2227Lazily takes only up to `n` elements of a range. This is 2228particularly useful when using with infinite ranges. 2229 2230Unlike $(LREF takeExactly), `take` does not require that there 2231are `n` or more elements in `input`. As a consequence, length 2232information is not applied to the result unless `input` also has 2233length information. 2234 2235Params: 2236 input = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives) 2237 to iterate over up to `n` times 2238 n = the number of elements to take 2239 2240Returns: 2241 At minimum, an input range. If the range offers random access 2242 and `length`, `take` offers them as well. 2243 */ 2244Take!R take(R)(R input, size_t n) 2245if (isInputRange!(Unqual!R)) 2246{ 2247 alias U = Unqual!R; 2248 static if (is(R T == Take!T)) 2249 { 2250 import std.algorithm.comparison : min; 2251 return R(input.source, min(n, input._maxAvailable)); 2252 } 2253 else static if (!isInfinite!U && hasSlicing!U) 2254 { 2255 import std.algorithm.comparison : min; 2256 return input[0 .. min(n, input.length)]; 2257 } 2258 else 2259 { 2260 return Take!R(input, n); 2261 } 2262} 2263 2264/// ditto 2265struct Take(Range) 2266if (isInputRange!(Unqual!Range) && 2267 //take _cannot_ test hasSlicing on infinite ranges, because hasSlicing uses 2268 //take for slicing infinite ranges. 2269 !((!isInfinite!(Unqual!Range) && hasSlicing!(Unqual!Range)) || is(Range T == Take!T))) 2270{ 2271 private alias R = Unqual!Range; 2272 2273 /// User accessible in read and write 2274 public R source; 2275 2276 private size_t _maxAvailable; 2277 2278 alias Source = R; 2279 2280 /// Range primitives 2281 @property bool empty() 2282 { 2283 return _maxAvailable == 0 || source.empty; 2284 } 2285 2286 /// ditto 2287 @property auto ref front() 2288 { 2289 assert(!empty, 2290 "Attempting to fetch the front of an empty " 2291 ~ Take.stringof); 2292 return source.front; 2293 } 2294 2295 /// ditto 2296 void popFront() 2297 { 2298 assert(!empty, 2299 "Attempting to popFront() past the end of a " 2300 ~ Take.stringof); 2301 source.popFront(); 2302 --_maxAvailable; 2303 } 2304 2305 static if (isForwardRange!R) 2306 /// ditto 2307 @property Take save() 2308 { 2309 return Take(source.save, _maxAvailable); 2310 } 2311 2312 static if (hasAssignableElements!R) 2313 /// ditto 2314 @property void front(ElementType!R v) 2315 { 2316 assert(!empty, 2317 "Attempting to assign to the front of an empty " 2318 ~ Take.stringof); 2319 // This has to return auto instead of void because of 2320 // https://issues.dlang.org/show_bug.cgi?id=4706 2321 source.front = v; 2322 } 2323 2324 static if (hasMobileElements!R) 2325 { 2326 /// ditto 2327 auto moveFront() 2328 { 2329 assert(!empty, 2330 "Attempting to move the front of an empty " 2331 ~ Take.stringof); 2332 return source.moveFront(); 2333 } 2334 } 2335 2336 static if (isInfinite!R) 2337 { 2338 /// ditto 2339 @property size_t length() const 2340 { 2341 return _maxAvailable; 2342 } 2343 2344 /// ditto 2345 alias opDollar = length; 2346 2347 //Note: Due to Take/hasSlicing circular dependency, 2348 //This needs to be a restrained template. 2349 /// ditto 2350 auto opSlice()(size_t i, size_t j) 2351 if (hasSlicing!R) 2352 { 2353 assert(i <= j, "Invalid slice bounds"); 2354 assert(j <= length, "Attempting to slice past the end of a " 2355 ~ Take.stringof); 2356 return source[i .. j]; 2357 } 2358 } 2359 else static if (hasLength!R) 2360 { 2361 /// ditto 2362 @property size_t length() 2363 { 2364 import std.algorithm.comparison : min; 2365 return min(_maxAvailable, source.length); 2366 } 2367 2368 alias opDollar = length; 2369 } 2370 2371 static if (isRandomAccessRange!R) 2372 { 2373 /// ditto 2374 void popBack() 2375 { 2376 assert(!empty, 2377 "Attempting to popBack() past the beginning of a " 2378 ~ Take.stringof); 2379 --_maxAvailable; 2380 } 2381 2382 /// ditto 2383 @property auto ref back() 2384 { 2385 assert(!empty, 2386 "Attempting to fetch the back of an empty " 2387 ~ Take.stringof); 2388 return source[this.length - 1]; 2389 } 2390 2391 /// ditto 2392 auto ref opIndex(size_t index) 2393 { 2394 assert(index < length, 2395 "Attempting to index out of the bounds of a " 2396 ~ Take.stringof); 2397 return source[index]; 2398 } 2399 2400 static if (hasAssignableElements!R) 2401 { 2402 /// ditto 2403 @property void back(ElementType!R v) 2404 { 2405 // This has to return auto instead of void because of 2406 // https://issues.dlang.org/show_bug.cgi?id=4706 2407 assert(!empty, 2408 "Attempting to assign to the back of an empty " 2409 ~ Take.stringof); 2410 source[this.length - 1] = v; 2411 } 2412 2413 /// ditto 2414 void opIndexAssign(ElementType!R v, size_t index) 2415 { 2416 assert(index < length, 2417 "Attempting to index out of the bounds of a " 2418 ~ Take.stringof); 2419 source[index] = v; 2420 } 2421 } 2422 2423 static if (hasMobileElements!R) 2424 { 2425 /// ditto 2426 auto moveBack() 2427 { 2428 assert(!empty, 2429 "Attempting to move the back of an empty " 2430 ~ Take.stringof); 2431 return source.moveAt(this.length - 1); 2432 } 2433 2434 /// ditto 2435 auto moveAt(size_t index) 2436 { 2437 assert(index < length, 2438 "Attempting to index out of the bounds of a " 2439 ~ Take.stringof); 2440 return source.moveAt(index); 2441 } 2442 } 2443 } 2444 2445 /** 2446 Access to maximal length of the range. 2447 Note: the actual length of the range depends on the underlying range. 2448 If it has fewer elements, it will stop before maxLength is reached. 2449 */ 2450 @property size_t maxLength() const 2451 { 2452 return _maxAvailable; 2453 } 2454} 2455 2456/// ditto 2457template Take(R) 2458if (isInputRange!(Unqual!R) && 2459 ((!isInfinite!(Unqual!R) && hasSlicing!(Unqual!R)) || is(R T == Take!T))) 2460{ 2461 alias Take = R; 2462} 2463 2464/// 2465pure @safe nothrow unittest 2466{ 2467 import std.algorithm.comparison : equal; 2468 2469 int[] arr1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; 2470 auto s = take(arr1, 5); 2471 assert(s.length == 5); 2472 assert(s[4] == 5); 2473 assert(equal(s, [ 1, 2, 3, 4, 5 ][])); 2474} 2475 2476/** 2477 * If the range runs out before `n` elements, `take` simply returns the entire 2478 * range (unlike $(LREF takeExactly), which will cause an assertion failure if 2479 * the range ends prematurely): 2480 */ 2481pure @safe nothrow unittest 2482{ 2483 import std.algorithm.comparison : equal; 2484 2485 int[] arr2 = [ 1, 2, 3 ]; 2486 auto t = take(arr2, 5); 2487 assert(t.length == 3); 2488 assert(equal(t, [ 1, 2, 3 ])); 2489} 2490 2491pure @safe nothrow unittest 2492{ 2493 import std.algorithm.comparison : equal; 2494 import std.internal.test.dummyrange : AllDummyRanges; 2495 2496 int[] arr1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; 2497 auto s = take(arr1, 5); 2498 assert(s.length == 5); 2499 assert(s[4] == 5); 2500 assert(equal(s, [ 1, 2, 3, 4, 5 ][])); 2501 assert(equal(retro(s), [ 5, 4, 3, 2, 1 ][])); 2502 2503 // Test fix for bug 4464. 2504 static assert(is(typeof(s) == Take!(int[]))); 2505 static assert(is(typeof(s) == int[])); 2506 2507 // Test using narrow strings. 2508 import std.exception : assumeWontThrow; 2509 2510 auto myStr = "This is a string."; 2511 auto takeMyStr = take(myStr, 7); 2512 assert(assumeWontThrow(equal(takeMyStr, "This is"))); 2513 // Test fix for bug 5052. 2514 auto takeMyStrAgain = take(takeMyStr, 4); 2515 assert(assumeWontThrow(equal(takeMyStrAgain, "This"))); 2516 static assert(is (typeof(takeMyStrAgain) == typeof(takeMyStr))); 2517 takeMyStrAgain = take(takeMyStr, 10); 2518 assert(assumeWontThrow(equal(takeMyStrAgain, "This is"))); 2519 2520 foreach (DummyType; AllDummyRanges) 2521 { 2522 DummyType dummy; 2523 auto t = take(dummy, 5); 2524 alias T = typeof(t); 2525 2526 static if (isRandomAccessRange!DummyType) 2527 { 2528 static assert(isRandomAccessRange!T); 2529 assert(t[4] == 5); 2530 2531 assert(moveAt(t, 1) == t[1]); 2532 assert(t.back == moveBack(t)); 2533 } 2534 else static if (isForwardRange!DummyType) 2535 { 2536 static assert(isForwardRange!T); 2537 } 2538 2539 for (auto tt = t; !tt.empty; tt.popFront()) 2540 { 2541 assert(tt.front == moveFront(tt)); 2542 } 2543 2544 // Bidirectional ranges can't be propagated properly if they don't 2545 // also have random access. 2546 2547 assert(equal(t, [1,2,3,4,5])); 2548 2549 //Test that take doesn't wrap the result of take. 2550 assert(take(t, 4) == take(dummy, 4)); 2551 } 2552 2553 immutable myRepeat = repeat(1); 2554 static assert(is(Take!(typeof(myRepeat)))); 2555} 2556 2557pure @safe nothrow @nogc unittest 2558{ 2559 //check for correct slicing of Take on an infinite range 2560 import std.algorithm.comparison : equal; 2561 foreach (start; 0 .. 4) 2562 foreach (stop; start .. 4) 2563 assert(iota(4).cycle.take(4)[start .. stop] 2564 .equal(iota(start, stop))); 2565} 2566 2567pure @safe nothrow @nogc unittest 2568{ 2569 // Check that one can declare variables of all Take types, 2570 // and that they match the return type of the corresponding 2571 // take(). 2572 // See https://issues.dlang.org/show_bug.cgi?id=4464 2573 int[] r1; 2574 Take!(int[]) t1; 2575 t1 = take(r1, 1); 2576 assert(t1.empty); 2577 2578 string r2; 2579 Take!string t2; 2580 t2 = take(r2, 1); 2581 assert(t2.empty); 2582 2583 Take!(Take!string) t3; 2584 t3 = take(t2, 1); 2585 assert(t3.empty); 2586} 2587 2588pure @safe nothrow @nogc unittest 2589{ 2590 alias R1 = typeof(repeat(1)); 2591 alias R2 = typeof(cycle([1])); 2592 alias TR1 = Take!R1; 2593 alias TR2 = Take!R2; 2594 static assert(isBidirectionalRange!TR1); 2595 static assert(isBidirectionalRange!TR2); 2596} 2597 2598// https://issues.dlang.org/show_bug.cgi?id=12731 2599pure @safe nothrow @nogc unittest 2600{ 2601 auto a = repeat(1); 2602 auto s = a[1 .. 5]; 2603 s = s[1 .. 3]; 2604 assert(s.length == 2); 2605 assert(s[0] == 1); 2606 assert(s[1] == 1); 2607} 2608 2609// https://issues.dlang.org/show_bug.cgi?id=13151 2610pure @safe nothrow @nogc unittest 2611{ 2612 import std.algorithm.comparison : equal; 2613 2614 auto r = take(repeat(1, 4), 3); 2615 assert(r.take(2).equal(repeat(1, 2))); 2616} 2617 2618 2619/** 2620Similar to $(LREF take), but assumes that `range` has at least $(D 2621n) elements. Consequently, the result of $(D takeExactly(range, n)) 2622always defines the `length` property (and initializes it to `n`) 2623even when `range` itself does not define `length`. 2624 2625The result of `takeExactly` is identical to that of $(LREF take) in 2626cases where the original range defines `length` or is infinite. 2627 2628Unlike $(LREF take), however, it is illegal to pass a range with less than 2629`n` elements to `takeExactly`; this will cause an assertion failure. 2630 */ 2631auto takeExactly(R)(R range, size_t n) 2632if (isInputRange!R) 2633{ 2634 static if (is(typeof(takeExactly(range._input, n)) == R)) 2635 { 2636 assert(n <= range._n, 2637 "Attempted to take more than the length of the range with takeExactly."); 2638 // takeExactly(takeExactly(r, n1), n2) has the same type as 2639 // takeExactly(r, n1) and simply returns takeExactly(r, n2) 2640 range._n = n; 2641 return range; 2642 } 2643 //Also covers hasSlicing!R for finite ranges. 2644 else static if (hasLength!R) 2645 { 2646 assert(n <= range.length, 2647 "Attempted to take more than the length of the range with takeExactly."); 2648 return take(range, n); 2649 } 2650 else static if (isInfinite!R) 2651 return Take!R(range, n); 2652 else 2653 { 2654 static struct Result 2655 { 2656 R _input; 2657 private size_t _n; 2658 2659 @property bool empty() const { return !_n; } 2660 @property auto ref front() 2661 { 2662 assert(_n > 0, "front() on an empty " ~ Result.stringof); 2663 return _input.front; 2664 } 2665 void popFront() { _input.popFront(); --_n; } 2666 @property size_t length() const { return _n; } 2667 alias opDollar = length; 2668 2669 @property auto _takeExactly_Result_asTake() 2670 { 2671 return take(_input, _n); 2672 } 2673 2674 alias _takeExactly_Result_asTake this; 2675 2676 static if (isForwardRange!R) 2677 @property auto save() 2678 { 2679 return Result(_input.save, _n); 2680 } 2681 2682 static if (hasMobileElements!R) 2683 { 2684 auto moveFront() 2685 { 2686 assert(!empty, 2687 "Attempting to move the front of an empty " 2688 ~ typeof(this).stringof); 2689 return _input.moveFront(); 2690 } 2691 } 2692 2693 static if (hasAssignableElements!R) 2694 { 2695 @property auto ref front(ElementType!R v) 2696 { 2697 assert(!empty, 2698 "Attempting to assign to the front of an empty " 2699 ~ typeof(this).stringof); 2700 return _input.front = v; 2701 } 2702 } 2703 } 2704 2705 return Result(range, n); 2706 } 2707} 2708 2709/// 2710pure @safe nothrow unittest 2711{ 2712 import std.algorithm.comparison : equal; 2713 2714 auto a = [ 1, 2, 3, 4, 5 ]; 2715 2716 auto b = takeExactly(a, 3); 2717 assert(equal(b, [1, 2, 3])); 2718 static assert(is(typeof(b.length) == size_t)); 2719 assert(b.length == 3); 2720 assert(b.front == 1); 2721 assert(b.back == 3); 2722} 2723 2724pure @safe nothrow unittest 2725{ 2726 import std.algorithm.comparison : equal; 2727 import std.algorithm.iteration : filter; 2728 2729 auto a = [ 1, 2, 3, 4, 5 ]; 2730 auto b = takeExactly(a, 3); 2731 assert(equal(b, [1, 2, 3])); 2732 auto c = takeExactly(b, 2); 2733 assert(equal(c, [1, 2])); 2734 2735 2736 2737 auto d = filter!"a > 2"(a); 2738 auto e = takeExactly(d, 3); 2739 assert(equal(e, [3, 4, 5])); 2740 static assert(is(typeof(e.length) == size_t)); 2741 assert(e.length == 3); 2742 assert(e.front == 3); 2743 2744 assert(equal(takeExactly(e, 3), [3, 4, 5])); 2745} 2746 2747pure @safe nothrow unittest 2748{ 2749 import std.algorithm.comparison : equal; 2750 import std.internal.test.dummyrange : AllDummyRanges; 2751 2752 auto a = [ 1, 2, 3, 4, 5 ]; 2753 //Test that take and takeExactly are the same for ranges which define length 2754 //but aren't sliceable. 2755 struct L 2756 { 2757 @property auto front() { return _arr[0]; } 2758 @property bool empty() { return _arr.empty; } 2759 void popFront() { _arr.popFront(); } 2760 @property size_t length() { return _arr.length; } 2761 int[] _arr; 2762 } 2763 static assert(is(typeof(take(L(a), 3)) == typeof(takeExactly(L(a), 3)))); 2764 assert(take(L(a), 3) == takeExactly(L(a), 3)); 2765 2766 //Test that take and takeExactly are the same for ranges which are sliceable. 2767 static assert(is(typeof(take(a, 3)) == typeof(takeExactly(a, 3)))); 2768 assert(take(a, 3) == takeExactly(a, 3)); 2769 2770 //Test that take and takeExactly are the same for infinite ranges. 2771 auto inf = repeat(1); 2772 static assert(is(typeof(take(inf, 5)) == Take!(typeof(inf)))); 2773 assert(take(inf, 5) == takeExactly(inf, 5)); 2774 2775 //Test that take and takeExactly are _not_ the same for ranges which don't 2776 //define length. 2777 static assert(!is(typeof(take(filter!"true"(a), 3)) == typeof(takeExactly(filter!"true"(a), 3)))); 2778 2779 foreach (DummyType; AllDummyRanges) 2780 { 2781 { 2782 DummyType dummy; 2783 auto t = takeExactly(dummy, 5); 2784 2785 //Test that takeExactly doesn't wrap the result of takeExactly. 2786 assert(takeExactly(t, 4) == takeExactly(dummy, 4)); 2787 } 2788 2789 static if (hasMobileElements!DummyType) 2790 { 2791 { 2792 auto t = takeExactly(DummyType.init, 4); 2793 assert(t.moveFront() == 1); 2794 assert(equal(t, [1, 2, 3, 4])); 2795 } 2796 } 2797 2798 static if (hasAssignableElements!DummyType) 2799 { 2800 { 2801 auto t = takeExactly(DummyType.init, 4); 2802 t.front = 9; 2803 assert(equal(t, [9, 2, 3, 4])); 2804 } 2805 } 2806 } 2807} 2808 2809pure @safe nothrow unittest 2810{ 2811 import std.algorithm.comparison : equal; 2812 import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy; 2813 2814 alias DummyType = DummyRange!(ReturnBy.Value, Length.No, RangeType.Forward); 2815 auto te = takeExactly(DummyType(), 5); 2816 Take!DummyType t = te; 2817 assert(equal(t, [1, 2, 3, 4, 5])); 2818 assert(equal(t, te)); 2819} 2820 2821// https://issues.dlang.org/show_bug.cgi?id=18092 2822// can't combine take and takeExactly 2823@safe unittest 2824{ 2825 import std.algorithm.comparison : equal; 2826 import std.internal.test.dummyrange : AllDummyRanges; 2827 2828 static foreach (Range; AllDummyRanges) 2829 {{ 2830 Range r; 2831 assert(r.take(6).takeExactly(2).equal([1, 2])); 2832 assert(r.takeExactly(6).takeExactly(2).equal([1, 2])); 2833 assert(r.takeExactly(6).take(2).equal([1, 2])); 2834 }} 2835} 2836 2837/** 2838Returns a range with at most one element; for example, $(D 2839takeOne([42, 43, 44])) returns a range consisting of the integer $(D 284042). Calling `popFront()` off that range renders it empty. 2841 2842In effect `takeOne(r)` is somewhat equivalent to $(D take(r, 1)) but in 2843certain interfaces it is important to know statically that the range may only 2844have at most one element. 2845 2846The type returned by `takeOne` is a random-access range with length 2847regardless of `R`'s capabilities, as long as it is a forward range. 2848(another feature that distinguishes `takeOne` from `take`). If 2849(D R) is an input range but not a forward range, return type is an input 2850range with all random-access capabilities except save. 2851 */ 2852auto takeOne(R)(R source) 2853if (isInputRange!R) 2854{ 2855 static if (hasSlicing!R) 2856 { 2857 return source[0 .. !source.empty]; 2858 } 2859 else 2860 { 2861 static struct Result 2862 { 2863 private R _source; 2864 private bool _empty = true; 2865 @property bool empty() const { return _empty; } 2866 @property auto ref front() 2867 { 2868 assert(!empty, "Attempting to fetch the front of an empty takeOne"); 2869 return _source.front; 2870 } 2871 void popFront() 2872 { 2873 assert(!empty, "Attempting to popFront an empty takeOne"); 2874 _source.popFront(); 2875 _empty = true; 2876 } 2877 void popBack() 2878 { 2879 assert(!empty, "Attempting to popBack an empty takeOne"); 2880 _source.popFront(); 2881 _empty = true; 2882 } 2883 static if (isForwardRange!(Unqual!R)) 2884 { 2885 @property auto save() { return Result(_source.save, empty); } 2886 } 2887 @property auto ref back() 2888 { 2889 assert(!empty, "Attempting to fetch the back of an empty takeOne"); 2890 return _source.front; 2891 } 2892 @property size_t length() const { return !empty; } 2893 alias opDollar = length; 2894 auto ref opIndex(size_t n) 2895 { 2896 assert(n < length, "Attempting to index a takeOne out of bounds"); 2897 return _source.front; 2898 } 2899 auto opSlice(size_t m, size_t n) 2900 { 2901 assert( 2902 m <= n, 2903 "Attempting to slice a takeOne range with a larger first argument than the second." 2904 ); 2905 assert( 2906 n <= length, 2907 "Attempting to slice using an out of bounds index on a takeOne range." 2908 ); 2909 return n > m ? this : Result(_source, true); 2910 } 2911 // Non-standard property 2912 @property R source() { return _source; } 2913 } 2914 2915 return Result(source, source.empty); 2916 } 2917} 2918 2919/// 2920pure @safe nothrow unittest 2921{ 2922 auto s = takeOne([42, 43, 44]); 2923 static assert(isRandomAccessRange!(typeof(s))); 2924 assert(s.length == 1); 2925 assert(!s.empty); 2926 assert(s.front == 42); 2927 s.front = 43; 2928 assert(s.front == 43); 2929 assert(s.back == 43); 2930 assert(s[0] == 43); 2931 s.popFront(); 2932 assert(s.length == 0); 2933 assert(s.empty); 2934} 2935 2936pure @safe nothrow @nogc unittest 2937{ 2938 struct NonForwardRange 2939 { 2940 enum empty = false; 2941 int front() { return 42; } 2942 void popFront() {} 2943 } 2944 2945 static assert(!isForwardRange!NonForwardRange); 2946 2947 auto s = takeOne(NonForwardRange()); 2948 assert(s.length == 1); 2949 assert(!s.empty); 2950 assert(s.front == 42); 2951 assert(s.back == 42); 2952 assert(s[0] == 42); 2953 2954 auto t = s[0 .. 0]; 2955 assert(t.empty); 2956 assert(t.length == 0); 2957 2958 auto u = s[1 .. 1]; 2959 assert(u.empty); 2960 assert(u.length == 0); 2961 2962 auto v = s[0 .. 1]; 2963 s.popFront(); 2964 assert(s.length == 0); 2965 assert(s.empty); 2966 assert(!v.empty); 2967 assert(v.front == 42); 2968 v.popBack(); 2969 assert(v.empty); 2970 assert(v.length == 0); 2971} 2972 2973pure @safe nothrow @nogc unittest 2974{ 2975 struct NonSlicingForwardRange 2976 { 2977 enum empty = false; 2978 int front() { return 42; } 2979 void popFront() {} 2980 @property auto save() { return this; } 2981 } 2982 2983 static assert(isForwardRange!NonSlicingForwardRange); 2984 static assert(!hasSlicing!NonSlicingForwardRange); 2985 2986 auto s = takeOne(NonSlicingForwardRange()); 2987 assert(s.length == 1); 2988 assert(!s.empty); 2989 assert(s.front == 42); 2990 assert(s.back == 42); 2991 assert(s[0] == 42); 2992 auto t = s.save; 2993 s.popFront(); 2994 assert(s.length == 0); 2995 assert(s.empty); 2996 assert(!t.empty); 2997 assert(t.front == 42); 2998 t.popBack(); 2999 assert(t.empty); 3000 assert(t.length == 0); 3001} 3002 3003// Test that asserts trigger correctly 3004@system unittest 3005{ 3006 import std.exception : assertThrown; 3007 import core.exception : AssertError; 3008 3009 struct NonForwardRange 3010 { 3011 enum empty = false; 3012 int front() { return 42; } 3013 void popFront() {} 3014 } 3015 3016 auto s = takeOne(NonForwardRange()); 3017 3018 assertThrown!AssertError(s[1]); 3019 assertThrown!AssertError(s[0 .. 2]); 3020 3021 size_t one = 1; // Avoid style warnings triggered by literals 3022 size_t zero = 0; 3023 assertThrown!AssertError(s[one .. zero]); 3024 3025 s.popFront; 3026 assert(s.empty); 3027 assertThrown!AssertError(s.front); 3028 assertThrown!AssertError(s.back); 3029 assertThrown!AssertError(s.popFront); 3030 assertThrown!AssertError(s.popBack); 3031} 3032 3033// https://issues.dlang.org/show_bug.cgi?id=16999 3034pure @safe unittest 3035{ 3036 auto myIota = new class 3037 { 3038 int front = 0; 3039 @safe void popFront(){front++;} 3040 enum empty = false; 3041 }; 3042 auto iotaPart = myIota.takeOne; 3043 int sum; 3044 foreach (var; chain(iotaPart, iotaPart, iotaPart)) 3045 { 3046 sum += var; 3047 } 3048 assert(sum == 3); 3049 assert(iotaPart.front == 3); 3050} 3051 3052/++ 3053 Returns an empty range which is statically known to be empty and is 3054 guaranteed to have `length` and be random access regardless of `R`'s 3055 capabilities. 3056 +/ 3057auto takeNone(R)() 3058if (isInputRange!R) 3059{ 3060 return typeof(takeOne(R.init)).init; 3061} 3062 3063/// 3064pure @safe nothrow @nogc unittest 3065{ 3066 auto range = takeNone!(int[])(); 3067 assert(range.length == 0); 3068 assert(range.empty); 3069} 3070 3071pure @safe nothrow @nogc unittest 3072{ 3073 enum ctfe = takeNone!(int[])(); 3074 static assert(ctfe.length == 0); 3075 static assert(ctfe.empty); 3076} 3077 3078 3079/++ 3080 Creates an empty range from the given range in $(BIGOH 1). If it can, it 3081 will return the same range type. If not, it will return 3082 $(D takeExactly(range, 0)). 3083 +/ 3084auto takeNone(R)(R range) 3085if (isInputRange!R) 3086{ 3087 import std.traits : isDynamicArray; 3088 //Makes it so that calls to takeNone which don't use UFCS still work with a 3089 //member version if it's defined. 3090 static if (is(typeof(R.takeNone))) 3091 auto retval = range.takeNone(); 3092 // https://issues.dlang.org/show_bug.cgi?id=8339 3093 else static if (isDynamicArray!R)/+ || 3094 (is(R == struct) && __traits(compiles, {auto r = R.init;}) && R.init.empty))+/ 3095 { 3096 auto retval = R.init; 3097 } 3098 //An infinite range sliced at [0 .. 0] would likely still not be empty... 3099 else static if (hasSlicing!R && !isInfinite!R) 3100 auto retval = range[0 .. 0]; 3101 else 3102 auto retval = takeExactly(range, 0); 3103 3104 // https://issues.dlang.org/show_bug.cgi?id=7892 prevents this from being 3105 // done in an out block. 3106 assert(retval.empty); 3107 return retval; 3108} 3109 3110/// 3111pure @safe nothrow unittest 3112{ 3113 import std.algorithm.iteration : filter; 3114 assert(takeNone([42, 27, 19]).empty); 3115 assert(takeNone("dlang.org").empty); 3116 assert(takeNone(filter!"true"([42, 27, 19])).empty); 3117} 3118 3119@safe unittest 3120{ 3121 import std.algorithm.iteration : filter; 3122 import std.meta : AliasSeq; 3123 3124 struct Dummy 3125 { 3126 mixin template genInput() 3127 { 3128 @safe: 3129 @property bool empty() { return _arr.empty; } 3130 @property auto front() { return _arr.front; } 3131 void popFront() { _arr.popFront(); } 3132 static assert(isInputRange!(typeof(this))); 3133 } 3134 } 3135 alias genInput = Dummy.genInput; 3136 3137 static struct NormalStruct 3138 { 3139 //Disabled to make sure that the takeExactly version is used. 3140 @disable this(); 3141 this(int[] arr) { _arr = arr; } 3142 mixin genInput; 3143 int[] _arr; 3144 } 3145 3146 static struct SliceStruct 3147 { 3148 @disable this(); 3149 this(int[] arr) { _arr = arr; } 3150 mixin genInput; 3151 @property auto save() { return this; } 3152 auto opSlice(size_t i, size_t j) { return typeof(this)(_arr[i .. j]); } 3153 @property size_t length() { return _arr.length; } 3154 int[] _arr; 3155 } 3156 3157 static struct InitStruct 3158 { 3159 mixin genInput; 3160 int[] _arr; 3161 } 3162 3163 static struct TakeNoneStruct 3164 { 3165 this(int[] arr) { _arr = arr; } 3166 @disable this(); 3167 mixin genInput; 3168 auto takeNone() { return typeof(this)(null); } 3169 int[] _arr; 3170 } 3171 3172 static class NormalClass 3173 { 3174 this(int[] arr) {_arr = arr;} 3175 mixin genInput; 3176 int[] _arr; 3177 } 3178 3179 static class SliceClass 3180 { 3181 @safe: 3182 this(int[] arr) { _arr = arr; } 3183 mixin genInput; 3184 @property auto save() { return new typeof(this)(_arr); } 3185 auto opSlice(size_t i, size_t j) { return new typeof(this)(_arr[i .. j]); } 3186 @property size_t length() { return _arr.length; } 3187 int[] _arr; 3188 } 3189 3190 static class TakeNoneClass 3191 { 3192 @safe: 3193 this(int[] arr) { _arr = arr; } 3194 mixin genInput; 3195 auto takeNone() { return new typeof(this)(null); } 3196 int[] _arr; 3197 } 3198 3199 import std.format : format; 3200 3201 static foreach (range; AliasSeq!([1, 2, 3, 4, 5], 3202 "hello world", 3203 "hello world"w, 3204 "hello world"d, 3205 SliceStruct([1, 2, 3]), 3206 // https://issues.dlang.org/show_bug.cgi?id=8339 3207 // forces this to be takeExactly `InitStruct([1, 2, 3]), 3208 TakeNoneStruct([1, 2, 3]))) 3209 { 3210 static assert(takeNone(range).empty, typeof(range).stringof); 3211 assert(takeNone(range).empty); 3212 static assert(is(typeof(range) == typeof(takeNone(range))), typeof(range).stringof); 3213 } 3214 3215 static foreach (range; AliasSeq!(NormalStruct([1, 2, 3]), 3216 InitStruct([1, 2, 3]))) 3217 { 3218 static assert(takeNone(range).empty, typeof(range).stringof); 3219 assert(takeNone(range).empty); 3220 static assert(is(typeof(takeExactly(range, 0)) == typeof(takeNone(range))), typeof(range).stringof); 3221 } 3222 3223 //Don't work in CTFE. 3224 auto normal = new NormalClass([1, 2, 3]); 3225 assert(takeNone(normal).empty); 3226 static assert(is(typeof(takeExactly(normal, 0)) == typeof(takeNone(normal))), typeof(normal).stringof); 3227 3228 auto slice = new SliceClass([1, 2, 3]); 3229 assert(takeNone(slice).empty); 3230 static assert(is(SliceClass == typeof(takeNone(slice))), typeof(slice).stringof); 3231 3232 auto taken = new TakeNoneClass([1, 2, 3]); 3233 assert(takeNone(taken).empty); 3234 static assert(is(TakeNoneClass == typeof(takeNone(taken))), typeof(taken).stringof); 3235 3236 auto filtered = filter!"true"([1, 2, 3, 4, 5]); 3237 assert(takeNone(filtered).empty); 3238 // https://issues.dlang.org/show_bug.cgi?id=8339 and 3239 // https://issues.dlang.org/show_bug.cgi?id=5941 force this to be takeExactly 3240 //static assert(is(typeof(filtered) == typeof(takeNone(filtered))), typeof(filtered).stringof); 3241} 3242 3243/++ 3244 + Return a range advanced to within `_n` elements of the end of 3245 + `range`. 3246 + 3247 + Intended as the range equivalent of the Unix 3248 + $(HTTP en.wikipedia.org/wiki/Tail_%28Unix%29, _tail) utility. When the length 3249 + of `range` is less than or equal to `_n`, `range` is returned 3250 + as-is. 3251 + 3252 + Completes in $(BIGOH 1) steps for ranges that support slicing and have 3253 + length. Completes in $(BIGOH range.length) time for all other ranges. 3254 + 3255 + Params: 3256 + range = range to get _tail of 3257 + n = maximum number of elements to include in _tail 3258 + 3259 + Returns: 3260 + Returns the _tail of `range` augmented with length information 3261 +/ 3262auto tail(Range)(Range range, size_t n) 3263if (isInputRange!Range && !isInfinite!Range && 3264 (hasLength!Range || isForwardRange!Range)) 3265{ 3266 static if (hasLength!Range) 3267 { 3268 immutable length = range.length; 3269 if (n >= length) 3270 return range.takeExactly(length); 3271 else 3272 return range.drop(length - n).takeExactly(n); 3273 } 3274 else 3275 { 3276 Range scout = range.save; 3277 foreach (immutable i; 0 .. n) 3278 { 3279 if (scout.empty) 3280 return range.takeExactly(i); 3281 scout.popFront(); 3282 } 3283 3284 auto tail = range.save; 3285 while (!scout.empty) 3286 { 3287 assert(!tail.empty); 3288 scout.popFront(); 3289 tail.popFront(); 3290 } 3291 3292 return tail.takeExactly(n); 3293 } 3294} 3295 3296/// 3297pure @safe nothrow unittest 3298{ 3299 // tail -c n 3300 assert([1, 2, 3].tail(1) == [3]); 3301 assert([1, 2, 3].tail(2) == [2, 3]); 3302 assert([1, 2, 3].tail(3) == [1, 2, 3]); 3303 assert([1, 2, 3].tail(4) == [1, 2, 3]); 3304 assert([1, 2, 3].tail(0).length == 0); 3305 3306 // tail --lines=n 3307 import std.algorithm.comparison : equal; 3308 import std.algorithm.iteration : joiner; 3309 import std.exception : assumeWontThrow; 3310 import std.string : lineSplitter; 3311 assert("one\ntwo\nthree" 3312 .lineSplitter 3313 .tail(2) 3314 .joiner("\n") 3315 .equal("two\nthree") 3316 .assumeWontThrow); 3317} 3318 3319// @nogc prevented by https://issues.dlang.org/show_bug.cgi?id=15408 3320pure nothrow @safe /+@nogc+/ unittest 3321{ 3322 import std.algorithm.comparison : equal; 3323 import std.internal.test.dummyrange : AllDummyRanges, DummyRange, Length, 3324 RangeType, ReturnBy; 3325 3326 static immutable cheatsheet = [6, 7, 8, 9, 10]; 3327 3328 foreach (R; AllDummyRanges) 3329 { 3330 static if (isInputRange!R && !isInfinite!R && 3331 (hasLength!R || isForwardRange!R)) 3332 { 3333 assert(R.init.tail(5).equal(cheatsheet)); 3334 static assert(R.init.tail(5).equal(cheatsheet)); 3335 3336 assert(R.init.tail(0).length == 0); 3337 assert(R.init.tail(10).equal(R.init)); 3338 assert(R.init.tail(11).equal(R.init)); 3339 } 3340 } 3341 3342 // Infinite ranges are not supported 3343 static assert(!__traits(compiles, repeat(0).tail(0))); 3344 3345 // Neither are non-forward ranges without length 3346 static assert(!__traits(compiles, DummyRange!(ReturnBy.Value, Length.No, 3347 RangeType.Input).init.tail(5))); 3348} 3349 3350pure @safe nothrow @nogc unittest 3351{ 3352 static immutable input = [1, 2, 3]; 3353 static immutable expectedOutput = [2, 3]; 3354 assert(input.tail(2) == expectedOutput); 3355} 3356 3357/++ 3358 Convenience function which calls 3359 $(REF popFrontN, std, range, primitives)`(range, n)` and returns `range`. 3360 `drop` makes it easier to pop elements from a range 3361 and then pass it to another function within a single expression, 3362 whereas `popFrontN` would require multiple statements. 3363 3364 `dropBack` provides the same functionality but instead calls 3365 $(REF popBackN, std, range, primitives)`(range, n)` 3366 3367 Note: `drop` and `dropBack` will only pop $(I up to) 3368 `n` elements but will stop if the range is empty first. 3369 In other languages this is sometimes called `skip`. 3370 3371 Params: 3372 range = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to drop from 3373 n = the number of elements to drop 3374 3375 Returns: 3376 `range` with up to `n` elements dropped 3377 3378 See_Also: 3379 $(REF popFront, std, range, primitives), $(REF popBackN, std, range, primitives) 3380 +/ 3381R drop(R)(R range, size_t n) 3382if (isInputRange!R) 3383{ 3384 range.popFrontN(n); 3385 return range; 3386} 3387 3388/// 3389@safe unittest 3390{ 3391 import std.algorithm.comparison : equal; 3392 3393 assert([0, 2, 1, 5, 0, 3].drop(3) == [5, 0, 3]); 3394 assert("hello world".drop(6) == "world"); 3395 assert("hello world".drop(50).empty); 3396 assert("hello world".take(6).drop(3).equal("lo ")); 3397} 3398 3399/// ditto 3400R dropBack(R)(R range, size_t n) 3401if (isBidirectionalRange!R) 3402{ 3403 range.popBackN(n); 3404 return range; 3405} 3406 3407/// 3408@safe unittest 3409{ 3410 import std.algorithm.comparison : equal; 3411 3412 assert([0, 2, 1, 5, 0, 3].dropBack(3) == [0, 2, 1]); 3413 assert("hello world".dropBack(6) == "hello"); 3414 assert("hello world".dropBack(50).empty); 3415 assert("hello world".drop(4).dropBack(4).equal("o w")); 3416} 3417 3418@safe unittest 3419{ 3420 import std.algorithm.comparison : equal; 3421 import std.container.dlist : DList; 3422 3423 //Remove all but the first two elements 3424 auto a = DList!int(0, 1, 9, 9, 9, 9); 3425 a.remove(a[].drop(2)); 3426 assert(a[].equal(a[].take(2))); 3427} 3428 3429@safe unittest 3430{ 3431 import std.algorithm.comparison : equal; 3432 import std.algorithm.iteration : filter; 3433 3434 assert(drop("", 5).empty); 3435 assert(equal(drop(filter!"true"([0, 2, 1, 5, 0, 3]), 3), [5, 0, 3])); 3436} 3437 3438@safe unittest 3439{ 3440 import std.algorithm.comparison : equal; 3441 import std.container.dlist : DList; 3442 3443 //insert before the last two elements 3444 auto a = DList!int(0, 1, 2, 5, 6); 3445 a.insertAfter(a[].dropBack(2), [3, 4]); 3446 assert(a[].equal(iota(0, 7))); 3447} 3448 3449/++ 3450 Similar to $(LREF drop) and `dropBack` but they call 3451 $(D range.$(LREF popFrontExactly)(n)) and `range.popBackExactly(n)` 3452 instead. 3453 3454 Note: Unlike `drop`, `dropExactly` will assume that the 3455 range holds at least `n` elements. This makes `dropExactly` 3456 faster than `drop`, but it also means that if `range` does 3457 not contain at least `n` elements, it will attempt to call `popFront` 3458 on an empty range, which is undefined behavior. So, only use 3459 `popFrontExactly` when it is guaranteed that `range` holds at least 3460 `n` elements. 3461 3462 Params: 3463 range = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to drop from 3464 n = the number of elements to drop 3465 3466 Returns: 3467 `range` with `n` elements dropped 3468 3469 See_Also: 3470 $(REF popFrontExcatly, std, range, primitives), 3471 $(REF popBackExcatly, std, range, primitives) 3472+/ 3473R dropExactly(R)(R range, size_t n) 3474if (isInputRange!R) 3475{ 3476 popFrontExactly(range, n); 3477 return range; 3478} 3479/// ditto 3480R dropBackExactly(R)(R range, size_t n) 3481if (isBidirectionalRange!R) 3482{ 3483 popBackExactly(range, n); 3484 return range; 3485} 3486 3487/// 3488@safe unittest 3489{ 3490 import std.algorithm.comparison : equal; 3491 import std.algorithm.iteration : filterBidirectional; 3492 3493 auto a = [1, 2, 3]; 3494 assert(a.dropExactly(2) == [3]); 3495 assert(a.dropBackExactly(2) == [1]); 3496 3497 string s = "���������"; 3498 assert(s.dropExactly(2) == "���"); 3499 assert(s.dropBackExactly(2) == "���"); 3500 3501 auto bd = filterBidirectional!"true"([1, 2, 3]); 3502 assert(bd.dropExactly(2).equal([3])); 3503 assert(bd.dropBackExactly(2).equal([1])); 3504} 3505 3506/++ 3507 Convenience function which calls 3508 `range.popFront()` and returns `range`. `dropOne` 3509 makes it easier to pop an element from a range 3510 and then pass it to another function within a single expression, 3511 whereas `popFront` would require multiple statements. 3512 3513 `dropBackOne` provides the same functionality but instead calls 3514 `range.popBack()`. 3515+/ 3516R dropOne(R)(R range) 3517if (isInputRange!R) 3518{ 3519 range.popFront(); 3520 return range; 3521} 3522/// ditto 3523R dropBackOne(R)(R range) 3524if (isBidirectionalRange!R) 3525{ 3526 range.popBack(); 3527 return range; 3528} 3529 3530/// 3531pure @safe nothrow unittest 3532{ 3533 import std.algorithm.comparison : equal; 3534 import std.algorithm.iteration : filterBidirectional; 3535 import std.container.dlist : DList; 3536 3537 auto dl = DList!int(9, 1, 2, 3, 9); 3538 assert(dl[].dropOne().dropBackOne().equal([1, 2, 3])); 3539 3540 auto a = [1, 2, 3]; 3541 assert(a.dropOne() == [2, 3]); 3542 assert(a.dropBackOne() == [1, 2]); 3543 3544 string s = "���������"; 3545 import std.exception : assumeWontThrow; 3546 assert(assumeWontThrow(s.dropOne() == "������")); 3547 assert(assumeWontThrow(s.dropBackOne() == "������")); 3548 3549 auto bd = filterBidirectional!"true"([1, 2, 3]); 3550 assert(bd.dropOne().equal([2, 3])); 3551 assert(bd.dropBackOne().equal([1, 2])); 3552} 3553 3554/** 3555Create a range which repeats one value. 3556 3557Params: 3558 value = the _value to repeat 3559 n = the number of times to repeat `value` 3560 3561Returns: 3562 If `n` is not defined, an infinite random access range 3563 with slicing. 3564 3565 If `n` is defined, a random access range with slicing. 3566*/ 3567struct Repeat(T) 3568{ 3569private: 3570 //Store a non-qualified T when possible: This is to make Repeat assignable 3571 static if ((is(T == class) || is(T == interface)) && (is(T == const) || is(T == immutable))) 3572 { 3573 import std.typecons : Rebindable; 3574 alias UT = Rebindable!T; 3575 } 3576 else static if (is(T : Unqual!T) && is(Unqual!T : T)) 3577 alias UT = Unqual!T; 3578 else 3579 alias UT = T; 3580 UT _value; 3581 3582public: 3583 /// Range primitives 3584 @property inout(T) front() inout { return _value; } 3585 3586 /// ditto 3587 @property inout(T) back() inout { return _value; } 3588 3589 /// ditto 3590 enum bool empty = false; 3591 3592 /// ditto 3593 void popFront() {} 3594 3595 /// ditto 3596 void popBack() {} 3597 3598 /// ditto 3599 @property auto save() inout { return this; } 3600 3601 /// ditto 3602 inout(T) opIndex(size_t) inout { return _value; } 3603 3604 /// ditto 3605 auto opSlice(size_t i, size_t j) 3606 in 3607 { 3608 assert( 3609 i <= j, 3610 "Attempting to slice a Repeat with a larger first argument than the second." 3611 ); 3612 } 3613 do 3614 { 3615 return this.takeExactly(j - i); 3616 } 3617 private static struct DollarToken {} 3618 3619 /// ditto 3620 enum opDollar = DollarToken.init; 3621 3622 /// ditto 3623 auto opSlice(size_t, DollarToken) inout { return this; } 3624} 3625 3626/// Ditto 3627Repeat!T repeat(T)(T value) { return Repeat!T(value); } 3628 3629/// 3630pure @safe nothrow unittest 3631{ 3632 import std.algorithm.comparison : equal; 3633 3634 assert(5.repeat().take(4).equal([5, 5, 5, 5])); 3635} 3636 3637pure @safe nothrow unittest 3638{ 3639 import std.algorithm.comparison : equal; 3640 3641 auto r = repeat(5); 3642 alias R = typeof(r); 3643 static assert(isBidirectionalRange!R); 3644 static assert(isForwardRange!R); 3645 static assert(isInfinite!R); 3646 static assert(hasSlicing!R); 3647 3648 assert(r.back == 5); 3649 assert(r.front == 5); 3650 assert(r.take(4).equal([ 5, 5, 5, 5 ])); 3651 assert(r[0 .. 4].equal([ 5, 5, 5, 5 ])); 3652 3653 R r2 = r[5 .. $]; 3654 assert(r2.back == 5); 3655 assert(r2.front == 5); 3656} 3657 3658/// ditto 3659Take!(Repeat!T) repeat(T)(T value, size_t n) 3660{ 3661 return take(repeat(value), n); 3662} 3663 3664/// 3665pure @safe nothrow unittest 3666{ 3667 import std.algorithm.comparison : equal; 3668 3669 assert(5.repeat(4).equal([5, 5, 5, 5])); 3670} 3671 3672// https://issues.dlang.org/show_bug.cgi?id=12007 3673pure @safe nothrow unittest 3674{ 3675 static class C{} 3676 Repeat!(immutable int) ri; 3677 ri = ri.save; 3678 Repeat!(immutable C) rc; 3679 rc = rc.save; 3680 3681 import std.algorithm.setops : cartesianProduct; 3682 import std.algorithm.comparison : equal; 3683 import std.typecons : tuple; 3684 immutable int[] A = [1,2,3]; 3685 immutable int[] B = [4,5,6]; 3686 3687 assert(equal(cartesianProduct(A,B), 3688 [ 3689 tuple(1, 4), tuple(1, 5), tuple(1, 6), 3690 tuple(2, 4), tuple(2, 5), tuple(2, 6), 3691 tuple(3, 4), tuple(3, 5), tuple(3, 6), 3692 ])); 3693} 3694 3695/** 3696Given callable ($(REF isCallable, std,traits)) `fun`, create as a range 3697whose front is defined by successive calls to `fun()`. 3698This is especially useful to call function with global side effects (random 3699functions), or to create ranges expressed as a single delegate, rather than 3700an entire `front`/`popFront`/`empty` structure. 3701`fun` maybe be passed either a template alias parameter (existing 3702function, delegate, struct type defining `static opCall`) or 3703a run-time value argument (delegate, function object). 3704The result range models an InputRange 3705($(REF isInputRange, std,range,primitives)). 3706The resulting range will call `fun()` on construction, and every call to 3707`popFront`, and the cached value will be returned when `front` is called. 3708 3709Returns: an `inputRange` where each element represents another call to fun. 3710*/ 3711auto generate(Fun)(Fun fun) 3712if (isCallable!fun) 3713{ 3714 auto gen = Generator!(Fun)(fun); 3715 gen.popFront(); // prime the first element 3716 return gen; 3717} 3718 3719/// ditto 3720auto generate(alias fun)() 3721if (isCallable!fun) 3722{ 3723 auto gen = Generator!(fun)(); 3724 gen.popFront(); // prime the first element 3725 return gen; 3726} 3727 3728/// 3729@safe pure nothrow unittest 3730{ 3731 import std.algorithm.comparison : equal; 3732 import std.algorithm.iteration : map; 3733 3734 int i = 1; 3735 auto powersOfTwo = generate!(() => i *= 2)().take(10); 3736 assert(equal(powersOfTwo, iota(1, 11).map!"2^^a"())); 3737} 3738 3739/// 3740@safe pure nothrow unittest 3741{ 3742 import std.algorithm.comparison : equal; 3743 3744 //Returns a run-time delegate 3745 auto infiniteIota(T)(T low, T high) 3746 { 3747 T i = high; 3748 return (){if (i == high) i = low; return i++;}; 3749 } 3750 //adapted as a range. 3751 assert(equal(generate(infiniteIota(1, 4)).take(10), [1, 2, 3, 1, 2, 3, 1, 2, 3, 1])); 3752} 3753 3754/// 3755@safe unittest 3756{ 3757 import std.format : format; 3758 import std.random : uniform; 3759 3760 auto r = generate!(() => uniform(0, 6)).take(10); 3761 format("%(%s %)", r); 3762} 3763 3764private struct Generator(Fun...) 3765{ 3766 static assert(Fun.length == 1); 3767 static assert(isInputRange!Generator); 3768 import std.traits : FunctionAttribute, functionAttributes, ReturnType; 3769 3770private: 3771 static if (is(Fun[0])) 3772 Fun[0] fun; 3773 else 3774 alias fun = Fun[0]; 3775 3776 enum returnByRef_ = (functionAttributes!fun & FunctionAttribute.ref_) ? true : false; 3777 static if (returnByRef_) 3778 ReturnType!fun *elem_; 3779 else 3780 ReturnType!fun elem_; 3781public: 3782 /// Range primitives 3783 enum empty = false; 3784 3785 static if (returnByRef_) 3786 { 3787 /// ditto 3788 ref front() @property 3789 { 3790 return *elem_; 3791 } 3792 /// ditto 3793 void popFront() 3794 { 3795 elem_ = &fun(); 3796 } 3797 } 3798 else 3799 { 3800 /// ditto 3801 auto front() @property 3802 { 3803 return elem_; 3804 } 3805 /// ditto 3806 void popFront() 3807 { 3808 elem_ = fun(); 3809 } 3810 } 3811} 3812 3813@safe nothrow unittest 3814{ 3815 import std.algorithm.comparison : equal; 3816 3817 struct StaticOpCall 3818 { 3819 static ubyte opCall() { return 5 ; } 3820 } 3821 3822 assert(equal(generate!StaticOpCall().take(10), repeat(5).take(10))); 3823} 3824 3825@safe pure unittest 3826{ 3827 import std.algorithm.comparison : equal; 3828 3829 struct OpCall 3830 { 3831 ubyte opCall() @safe pure { return 5 ; } 3832 } 3833 3834 OpCall op; 3835 assert(equal(generate(op).take(10), repeat(5).take(10))); 3836} 3837 3838// verify ref mechanism works 3839@system nothrow unittest 3840{ 3841 int[10] arr; 3842 int idx; 3843 3844 ref int fun() { 3845 auto x = idx++; 3846 idx %= arr.length; 3847 return arr[x]; 3848 } 3849 int y = 1; 3850 foreach (ref x; generate!(fun).take(20)) 3851 { 3852 x += y++; 3853 } 3854 import std.algorithm.comparison : equal; 3855 assert(equal(arr[], iota(12, 32, 2))); 3856} 3857 3858// assure front isn't the mechanism to make generate go to the next element. 3859@safe unittest 3860{ 3861 int i; 3862 auto g = generate!(() => ++i); 3863 auto f = g.front; 3864 assert(f == g.front); 3865 g = g.drop(5); // reassign because generate caches 3866 assert(g.front == f + 5); 3867} 3868 3869/** 3870Repeats the given forward range ad infinitum. If the original range is 3871infinite (fact that would make `Cycle` the identity application), 3872`Cycle` detects that and aliases itself to the range type 3873itself. That works for non-forward ranges too. 3874If the original range has random access, `Cycle` offers 3875random access and also offers a constructor taking an initial position 3876`index`. `Cycle` works with static arrays in addition to ranges, 3877mostly for performance reasons. 3878 3879Note: The input range must not be empty. 3880 3881Tip: This is a great way to implement simple circular buffers. 3882*/ 3883struct Cycle(R) 3884if (isForwardRange!R && !isInfinite!R) 3885{ 3886 static if (isRandomAccessRange!R && hasLength!R) 3887 { 3888 private R _original; 3889 private size_t _index; 3890 3891 /// Range primitives 3892 this(R input, size_t index = 0) 3893 { 3894 _original = input; 3895 _index = index % _original.length; 3896 } 3897 3898 /// ditto 3899 @property auto ref front() 3900 { 3901 return _original[_index]; 3902 } 3903 3904 static if (is(typeof((cast(const R)_original)[_index]))) 3905 { 3906 /// ditto 3907 @property auto ref front() const 3908 { 3909 return _original[_index]; 3910 } 3911 } 3912 3913 static if (hasAssignableElements!R) 3914 { 3915 /// ditto 3916 @property void front(ElementType!R val) 3917 { 3918 _original[_index] = val; 3919 } 3920 } 3921 3922 /// ditto 3923 enum bool empty = false; 3924 3925 /// ditto 3926 void popFront() 3927 { 3928 ++_index; 3929 if (_index >= _original.length) 3930 _index = 0; 3931 } 3932 3933 /// ditto 3934 auto ref opIndex(size_t n) 3935 { 3936 return _original[(n + _index) % _original.length]; 3937 } 3938 3939 static if (is(typeof((cast(const R)_original)[_index])) && 3940 is(typeof((cast(const R)_original).length))) 3941 { 3942 /// ditto 3943 auto ref opIndex(size_t n) const 3944 { 3945 return _original[(n + _index) % _original.length]; 3946 } 3947 } 3948 3949 static if (hasAssignableElements!R) 3950 { 3951 /// ditto 3952 void opIndexAssign(ElementType!R val, size_t n) 3953 { 3954 _original[(n + _index) % _original.length] = val; 3955 } 3956 } 3957 3958 /// ditto 3959 @property Cycle save() 3960 { 3961 //No need to call _original.save, because Cycle never actually modifies _original 3962 return Cycle(_original, _index); 3963 } 3964 3965 private static struct DollarToken {} 3966 3967 /// ditto 3968 enum opDollar = DollarToken.init; 3969 3970 static if (hasSlicing!R) 3971 { 3972 /// ditto 3973 auto opSlice(size_t i, size_t j) 3974 in 3975 { 3976 assert(i <= j); 3977 } 3978 do 3979 { 3980 return this[i .. $].takeExactly(j - i); 3981 } 3982 3983 /// ditto 3984 auto opSlice(size_t i, DollarToken) 3985 { 3986 return typeof(this)(_original, _index + i); 3987 } 3988 } 3989 } 3990 else 3991 { 3992 private R _original; 3993 private R _current; 3994 3995 /// ditto 3996 this(R input) 3997 { 3998 _original = input; 3999 _current = input.save; 4000 } 4001 4002 private this(R original, R current) 4003 { 4004 _original = original; 4005 _current = current; 4006 } 4007 4008 /// ditto 4009 @property auto ref front() 4010 { 4011 return _current.front; 4012 } 4013 4014 static if (is(typeof((cast(const R)_current).front))) 4015 { 4016 /// ditto 4017 @property auto ref front() const 4018 { 4019 return _current.front; 4020 } 4021 } 4022 4023 static if (hasAssignableElements!R) 4024 { 4025 /// ditto 4026 @property auto front(ElementType!R val) 4027 { 4028 return _current.front = val; 4029 } 4030 } 4031 4032 /// ditto 4033 enum bool empty = false; 4034 4035 /// ditto 4036 void popFront() 4037 { 4038 _current.popFront(); 4039 if (_current.empty) 4040 _current = _original.save; 4041 } 4042 4043 /// ditto 4044 @property Cycle save() 4045 { 4046 //No need to call _original.save, because Cycle never actually modifies _original 4047 return Cycle(_original, _current.save); 4048 } 4049 } 4050} 4051 4052/// ditto 4053template Cycle(R) 4054if (isInfinite!R) 4055{ 4056 alias Cycle = R; 4057} 4058 4059/// ditto 4060struct Cycle(R) 4061if (isStaticArray!R) 4062{ 4063 private alias ElementType = typeof(R.init[0]); 4064 private ElementType* _ptr; 4065 private size_t _index; 4066 4067nothrow: 4068 4069 /// Range primitives 4070 this(ref R input, size_t index = 0) @system 4071 { 4072 _ptr = input.ptr; 4073 _index = index % R.length; 4074 } 4075 4076 /// ditto 4077 @property ref inout(ElementType) front() inout @safe 4078 { 4079 static ref auto trustedPtrIdx(typeof(_ptr) p, size_t idx) @trusted 4080 { 4081 return p[idx]; 4082 } 4083 return trustedPtrIdx(_ptr, _index); 4084 } 4085 4086 /// ditto 4087 enum bool empty = false; 4088 4089 /// ditto 4090 void popFront() @safe 4091 { 4092 ++_index; 4093 if (_index >= R.length) 4094 _index = 0; 4095 } 4096 4097 /// ditto 4098 ref inout(ElementType) opIndex(size_t n) inout @safe 4099 { 4100 static ref auto trustedPtrIdx(typeof(_ptr) p, size_t idx) @trusted 4101 { 4102 return p[idx % R.length]; 4103 } 4104 return trustedPtrIdx(_ptr, n + _index); 4105 } 4106 4107 /// ditto 4108 @property inout(Cycle) save() inout @safe 4109 { 4110 return this; 4111 } 4112 4113 private static struct DollarToken {} 4114 /// ditto 4115 enum opDollar = DollarToken.init; 4116 4117 /// ditto 4118 auto opSlice(size_t i, size_t j) @safe 4119 in 4120 { 4121 assert( 4122 i <= j, 4123 "Attempting to slice a Repeat with a larger first argument than the second." 4124 ); 4125 } 4126 do 4127 { 4128 return this[i .. $].takeExactly(j - i); 4129 } 4130 4131 /// ditto 4132 inout(typeof(this)) opSlice(size_t i, DollarToken) inout @safe 4133 { 4134 static auto trustedCtor(typeof(_ptr) p, size_t idx) @trusted 4135 { 4136 return cast(inout) Cycle(*cast(R*)(p), idx); 4137 } 4138 return trustedCtor(_ptr, _index + i); 4139 } 4140} 4141 4142/// Ditto 4143auto cycle(R)(R input) 4144if (isInputRange!R) 4145{ 4146 static assert(isForwardRange!R || isInfinite!R, 4147 "Cycle requires a forward range argument unless it's statically known" 4148 ~ " to be infinite"); 4149 assert(!input.empty, "Attempting to pass an empty input to cycle"); 4150 static if (isInfinite!R) return input; 4151 else return Cycle!R(input); 4152} 4153 4154/// 4155@safe unittest 4156{ 4157 import std.algorithm.comparison : equal; 4158 import std.range : cycle, take; 4159 4160 // Here we create an infinitive cyclic sequence from [1, 2] 4161 // (i.e. get here [1, 2, 1, 2, 1, 2 and so on]) then 4162 // take 5 elements of this sequence (so we have [1, 2, 1, 2, 1]) 4163 // and compare them with the expected values for equality. 4164 assert(cycle([1, 2]).take(5).equal([ 1, 2, 1, 2, 1 ])); 4165} 4166 4167/// Ditto 4168Cycle!R cycle(R)(R input, size_t index = 0) 4169if (isRandomAccessRange!R && !isInfinite!R) 4170{ 4171 assert(!input.empty, "Attempting to pass an empty input to cycle"); 4172 return Cycle!R(input, index); 4173} 4174 4175/// Ditto 4176Cycle!R cycle(R)(ref R input, size_t index = 0) @system 4177if (isStaticArray!R) 4178{ 4179 return Cycle!R(input, index); 4180} 4181 4182@safe nothrow unittest 4183{ 4184 import std.algorithm.comparison : equal; 4185 import std.internal.test.dummyrange : AllDummyRanges; 4186 4187 static assert(isForwardRange!(Cycle!(uint[]))); 4188 4189 // Make sure ref is getting propagated properly. 4190 int[] nums = [1,2,3]; 4191 auto c2 = cycle(nums); 4192 c2[3]++; 4193 assert(nums[0] == 2); 4194 4195 immutable int[] immarr = [1, 2, 3]; 4196 4197 foreach (DummyType; AllDummyRanges) 4198 { 4199 static if (isForwardRange!DummyType) 4200 { 4201 DummyType dummy; 4202 auto cy = cycle(dummy); 4203 static assert(isForwardRange!(typeof(cy))); 4204 auto t = take(cy, 20); 4205 assert(equal(t, [1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10])); 4206 4207 const cRange = cy; 4208 assert(cRange.front == 1); 4209 4210 static if (hasAssignableElements!DummyType) 4211 { 4212 { 4213 cy.front = 66; 4214 scope(exit) cy.front = 1; 4215 assert(dummy.front == 66); 4216 } 4217 4218 static if (isRandomAccessRange!DummyType) 4219 { 4220 { 4221 cy[10] = 66; 4222 scope(exit) cy[10] = 1; 4223 assert(dummy.front == 66); 4224 } 4225 4226 assert(cRange[10] == 1); 4227 } 4228 } 4229 4230 static if (hasSlicing!DummyType) 4231 { 4232 auto slice = cy[5 .. 15]; 4233 assert(equal(slice, [6, 7, 8, 9, 10, 1, 2, 3, 4, 5])); 4234 static assert(is(typeof(slice) == typeof(takeExactly(cy, 5)))); 4235 4236 auto infSlice = cy[7 .. $]; 4237 assert(equal(take(infSlice, 5), [8, 9, 10, 1, 2])); 4238 static assert(isInfinite!(typeof(infSlice))); 4239 } 4240 } 4241 } 4242} 4243 4244@system nothrow unittest // For static arrays. 4245{ 4246 import std.algorithm.comparison : equal; 4247 4248 int[3] a = [ 1, 2, 3 ]; 4249 static assert(isStaticArray!(typeof(a))); 4250 auto c = cycle(a); 4251 assert(a.ptr == c._ptr); 4252 assert(equal(take(cycle(a), 5), [ 1, 2, 3, 1, 2 ][])); 4253 static assert(isForwardRange!(typeof(c))); 4254 4255 // Test qualifiers on slicing. 4256 alias C = typeof(c); 4257 static assert(is(typeof(c[1 .. $]) == C)); 4258 const cConst = c; 4259 static assert(is(typeof(cConst[1 .. $]) == const(C))); 4260} 4261 4262@safe nothrow unittest // For infinite ranges 4263{ 4264 struct InfRange 4265 { 4266 void popFront() { } 4267 @property int front() { return 0; } 4268 enum empty = false; 4269 auto save() { return this; } 4270 } 4271 struct NonForwardInfRange 4272 { 4273 void popFront() { } 4274 @property int front() { return 0; } 4275 enum empty = false; 4276 } 4277 4278 InfRange i; 4279 NonForwardInfRange j; 4280 auto c = cycle(i); 4281 assert(c == i); 4282 //make sure it can alias out even non-forward infinite ranges 4283 static assert(is(typeof(j.cycle) == typeof(j))); 4284} 4285 4286@safe unittest 4287{ 4288 import std.algorithm.comparison : equal; 4289 4290 int[5] arr = [0, 1, 2, 3, 4]; 4291 auto cleD = cycle(arr[]); //Dynamic 4292 assert(equal(cleD[5 .. 10], arr[])); 4293 4294 //n is a multiple of 5 worth about 3/4 of size_t.max 4295 auto n = size_t.max/4 + size_t.max/2; 4296 n -= n % 5; 4297 4298 //Test index overflow 4299 foreach (_ ; 0 .. 10) 4300 { 4301 cleD = cleD[n .. $]; 4302 assert(equal(cleD[5 .. 10], arr[])); 4303 } 4304} 4305 4306@system @nogc nothrow unittest 4307{ 4308 import std.algorithm.comparison : equal; 4309 4310 int[5] arr = [0, 1, 2, 3, 4]; 4311 auto cleS = cycle(arr); //Static 4312 assert(equal(cleS[5 .. 10], arr[])); 4313 4314 //n is a multiple of 5 worth about 3/4 of size_t.max 4315 auto n = size_t.max/4 + size_t.max/2; 4316 n -= n % 5; 4317 4318 //Test index overflow 4319 foreach (_ ; 0 .. 10) 4320 { 4321 cleS = cleS[n .. $]; 4322 assert(equal(cleS[5 .. 10], arr[])); 4323 } 4324} 4325 4326@system unittest 4327{ 4328 import std.algorithm.comparison : equal; 4329 4330 int[1] arr = [0]; 4331 auto cleS = cycle(arr); 4332 cleS = cleS[10 .. $]; 4333 assert(equal(cleS[5 .. 10], 0.repeat(5))); 4334 assert(cleS.front == 0); 4335} 4336 4337// https://issues.dlang.org/show_bug.cgi?id=10845 4338@system unittest 4339{ 4340 import std.algorithm.comparison : equal; 4341 import std.algorithm.iteration : filter; 4342 4343 auto a = inputRangeObject(iota(3).filter!"true"); 4344 assert(equal(cycle(a).take(10), [0, 1, 2, 0, 1, 2, 0, 1, 2, 0])); 4345} 4346 4347// https://issues.dlang.org/show_bug.cgi?id=12177 4348@safe unittest 4349{ 4350 static assert(__traits(compiles, recurrence!q{a[n - 1] ~ a[n - 2]}("1", "0"))); 4351} 4352 4353// https://issues.dlang.org/show_bug.cgi?id=13390 4354@system unittest 4355{ 4356 import core.exception : AssertError; 4357 import std.exception : assertThrown; 4358 assertThrown!AssertError(cycle([0, 1, 2][0 .. 0])); 4359} 4360 4361// https://issues.dlang.org/show_bug.cgi?id=18657 4362pure @safe unittest 4363{ 4364 import std.algorithm.comparison : equal; 4365 string s = "foo"; 4366 auto r = refRange(&s).cycle.take(4); 4367 assert(equal(r.save, "foof")); 4368 assert(equal(r.save, "foof")); 4369} 4370 4371private alias lengthType(R) = typeof(R.init.length.init); 4372 4373/** 4374 Iterate several ranges in lockstep. The element type is a proxy tuple 4375 that allows accessing the current element in the `n`th range by 4376 using `e[n]`. 4377 4378 `zip` is similar to $(LREF lockstep), but `lockstep` doesn't 4379 bundle its elements and uses the `opApply` protocol. 4380 `lockstep` allows reference access to the elements in 4381 `foreach` iterations. 4382 4383 Params: 4384 sp = controls what `zip` will do if the ranges are different lengths 4385 ranges = the ranges to zip together 4386 Returns: 4387 At minimum, an input range. `Zip` offers the lowest range facilities 4388 of all components, e.g. it offers random access iff all ranges offer 4389 random access, and also offers mutation and swapping if all ranges offer 4390 it. Due to this, `Zip` is extremely powerful because it allows manipulating 4391 several ranges in lockstep. 4392 Throws: 4393 An `Exception` if all of the ranges are not the same length and 4394 `sp` is set to `StoppingPolicy.requireSameLength`. 4395 4396 Limitations: The `@nogc` and `nothrow` attributes cannot be inferred for 4397 the `Zip` struct because $(LREF StoppingPolicy) can vary at runtime. This 4398 limitation is not shared by the anonymous range returned by the `zip` 4399 function when not given an explicit `StoppingPolicy` as an argument. 4400*/ 4401struct Zip(Ranges...) 4402if (Ranges.length && allSatisfy!(isInputRange, Ranges)) 4403{ 4404 import std.format : format; //for generic mixins 4405 import std.typecons : Tuple; 4406 4407 alias R = Ranges; 4408 private R ranges; 4409 alias ElementType = Tuple!(staticMap!(.ElementType, R)); 4410 private StoppingPolicy stoppingPolicy = StoppingPolicy.shortest; 4411 4412/** 4413 Builds an object. Usually this is invoked indirectly by using the 4414 $(LREF zip) function. 4415 */ 4416 this(R rs, StoppingPolicy s = StoppingPolicy.shortest) 4417 { 4418 ranges[] = rs[]; 4419 stoppingPolicy = s; 4420 } 4421 4422/** 4423 Returns `true` if the range is at end. The test depends on the 4424 stopping policy. 4425*/ 4426 static if (allSatisfy!(isInfinite, R)) 4427 { 4428 // BUG: Doesn't propagate infiniteness if only some ranges are infinite 4429 // and s == StoppingPolicy.longest. This isn't fixable in the 4430 // current design since StoppingPolicy is known only at runtime. 4431 enum bool empty = false; 4432 } 4433 else 4434 { 4435 /// 4436 @property bool empty() 4437 { 4438 import std.exception : enforce; 4439 import std.meta : anySatisfy; 4440 4441 final switch (stoppingPolicy) 4442 { 4443 case StoppingPolicy.shortest: 4444 foreach (i, Unused; R) 4445 { 4446 if (ranges[i].empty) return true; 4447 } 4448 return false; 4449 case StoppingPolicy.longest: 4450 static if (anySatisfy!(isInfinite, R)) 4451 { 4452 return false; 4453 } 4454 else 4455 { 4456 foreach (i, Unused; R) 4457 { 4458 if (!ranges[i].empty) return false; 4459 } 4460 return true; 4461 } 4462 case StoppingPolicy.requireSameLength: 4463 foreach (i, Unused; R[1 .. $]) 4464 { 4465 enforce(ranges[0].empty == 4466 ranges[i + 1].empty, 4467 "Inequal-length ranges passed to Zip"); 4468 } 4469 return ranges[0].empty; 4470 } 4471 assert(false); 4472 } 4473 } 4474 4475 static if (allSatisfy!(isForwardRange, R)) 4476 { 4477 /// 4478 @property Zip save() 4479 { 4480 //Zip(ranges[0].save, ranges[1].save, ..., stoppingPolicy) 4481 return mixin (q{Zip(%(ranges[%s].save%|, %), stoppingPolicy)}.format(iota(0, R.length))); 4482 } 4483 } 4484 4485 private .ElementType!(R[i]) tryGetInit(size_t i)() 4486 { 4487 alias E = .ElementType!(R[i]); 4488 static if (!is(typeof({static E i;}))) 4489 throw new Exception("Range with non-default constructable elements exhausted."); 4490 else 4491 return E.init; 4492 } 4493 4494/** 4495 Returns the current iterated element. 4496*/ 4497 @property ElementType front() 4498 { 4499 @property tryGetFront(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].front;} 4500 //ElementType(tryGetFront!0, tryGetFront!1, ...) 4501 return mixin(q{ElementType(%(tryGetFront!%s, %))}.format(iota(0, R.length))); 4502 } 4503 4504/** 4505 Sets the front of all iterated ranges. 4506*/ 4507 static if (allSatisfy!(hasAssignableElements, R)) 4508 { 4509 @property void front(ElementType v) 4510 { 4511 foreach (i, Unused; R) 4512 { 4513 if (!ranges[i].empty) 4514 { 4515 ranges[i].front = v[i]; 4516 } 4517 } 4518 } 4519 } 4520 4521/** 4522 Moves out the front. 4523*/ 4524 static if (allSatisfy!(hasMobileElements, R)) 4525 { 4526 ElementType moveFront() 4527 { 4528 @property tryMoveFront(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].moveFront();} 4529 //ElementType(tryMoveFront!0, tryMoveFront!1, ...) 4530 return mixin(q{ElementType(%(tryMoveFront!%s, %))}.format(iota(0, R.length))); 4531 } 4532 } 4533 4534/** 4535 Returns the rightmost element. 4536*/ 4537 static if (allSatisfy!(isBidirectionalRange, R)) 4538 { 4539 @property ElementType back() 4540 { 4541 //TODO: Fixme! BackElement != back of all ranges in case of jagged-ness 4542 4543 @property tryGetBack(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].back;} 4544 //ElementType(tryGetBack!0, tryGetBack!1, ...) 4545 return mixin(q{ElementType(%(tryGetBack!%s, %))}.format(iota(0, R.length))); 4546 } 4547 4548/** 4549 Moves out the back. 4550*/ 4551 static if (allSatisfy!(hasMobileElements, R)) 4552 { 4553 ElementType moveBack() 4554 { 4555 //TODO: Fixme! BackElement != back of all ranges in case of jagged-ness 4556 4557 @property tryMoveBack(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].moveBack();} 4558 //ElementType(tryMoveBack!0, tryMoveBack!1, ...) 4559 return mixin(q{ElementType(%(tryMoveBack!%s, %))}.format(iota(0, R.length))); 4560 } 4561 } 4562 4563/** 4564 Returns the current iterated element. 4565*/ 4566 static if (allSatisfy!(hasAssignableElements, R)) 4567 { 4568 @property void back(ElementType v) 4569 { 4570 //TODO: Fixme! BackElement != back of all ranges in case of jagged-ness. 4571 //Not sure the call is even legal for StoppingPolicy.longest 4572 4573 foreach (i, Unused; R) 4574 { 4575 if (!ranges[i].empty) 4576 { 4577 ranges[i].back = v[i]; 4578 } 4579 } 4580 } 4581 } 4582 } 4583 4584/** 4585 Advances to the next element in all controlled ranges. 4586*/ 4587 void popFront() 4588 { 4589 import std.exception : enforce; 4590 4591 final switch (stoppingPolicy) 4592 { 4593 case StoppingPolicy.shortest: 4594 foreach (i, Unused; R) 4595 { 4596 assert(!ranges[i].empty); 4597 ranges[i].popFront(); 4598 } 4599 break; 4600 case StoppingPolicy.longest: 4601 foreach (i, Unused; R) 4602 { 4603 if (!ranges[i].empty) ranges[i].popFront(); 4604 } 4605 break; 4606 case StoppingPolicy.requireSameLength: 4607 foreach (i, Unused; R) 4608 { 4609 enforce(!ranges[i].empty, "Invalid Zip object"); 4610 ranges[i].popFront(); 4611 } 4612 break; 4613 } 4614 } 4615 4616/** 4617 Calls `popBack` for all controlled ranges. 4618*/ 4619 static if (allSatisfy!(isBidirectionalRange, R)) 4620 { 4621 void popBack() 4622 { 4623 //TODO: Fixme! In case of jaggedness, this is wrong. 4624 import std.exception : enforce; 4625 4626 final switch (stoppingPolicy) 4627 { 4628 case StoppingPolicy.shortest: 4629 foreach (i, Unused; R) 4630 { 4631 assert(!ranges[i].empty); 4632 ranges[i].popBack(); 4633 } 4634 break; 4635 case StoppingPolicy.longest: 4636 foreach (i, Unused; R) 4637 { 4638 if (!ranges[i].empty) ranges[i].popBack(); 4639 } 4640 break; 4641 case StoppingPolicy.requireSameLength: 4642 foreach (i, Unused; R) 4643 { 4644 enforce(!ranges[i].empty, "Invalid Zip object"); 4645 ranges[i].popBack(); 4646 } 4647 break; 4648 } 4649 } 4650 } 4651 4652/** 4653 Returns the length of this range. Defined only if all ranges define 4654 `length`. 4655*/ 4656 static if (allSatisfy!(hasLength, R)) 4657 { 4658 @property auto length() 4659 { 4660 static if (Ranges.length == 1) 4661 return ranges[0].length; 4662 else 4663 { 4664 if (stoppingPolicy == StoppingPolicy.requireSameLength) 4665 return ranges[0].length; 4666 4667 //[min|max](ranges[0].length, ranges[1].length, ...) 4668 import std.algorithm.comparison : min, max; 4669 if (stoppingPolicy == StoppingPolicy.shortest) 4670 return mixin(q{min(%(ranges[%s].length%|, %))}.format(iota(0, R.length))); 4671 else 4672 return mixin(q{max(%(ranges[%s].length%|, %))}.format(iota(0, R.length))); 4673 } 4674 } 4675 4676 alias opDollar = length; 4677 } 4678 4679/** 4680 Returns a slice of the range. Defined only if all range define 4681 slicing. 4682*/ 4683 static if (allSatisfy!(hasSlicing, R)) 4684 { 4685 auto opSlice(size_t from, size_t to) 4686 { 4687 //Slicing an infinite range yields the type Take!R 4688 //For finite ranges, the type Take!R aliases to R 4689 alias ZipResult = Zip!(staticMap!(Take, R)); 4690 4691 //ZipResult(ranges[0][from .. to], ranges[1][from .. to], ..., stoppingPolicy) 4692 return mixin (q{ZipResult(%(ranges[%s][from .. to]%|, %), stoppingPolicy)}.format(iota(0, R.length))); 4693 } 4694 } 4695 4696/** 4697 Returns the `n`th element in the composite range. Defined if all 4698 ranges offer random access. 4699*/ 4700 static if (allSatisfy!(isRandomAccessRange, R)) 4701 { 4702 ElementType opIndex(size_t n) 4703 { 4704 //TODO: Fixme! This may create an out of bounds access 4705 //for StoppingPolicy.longest 4706 4707 //ElementType(ranges[0][n], ranges[1][n], ...) 4708 return mixin (q{ElementType(%(ranges[%s][n]%|, %))}.format(iota(0, R.length))); 4709 } 4710 4711/** 4712 Assigns to the `n`th element in the composite range. Defined if 4713 all ranges offer random access. 4714*/ 4715 static if (allSatisfy!(hasAssignableElements, R)) 4716 { 4717 void opIndexAssign(ElementType v, size_t n) 4718 { 4719 //TODO: Fixme! Not sure the call is even legal for StoppingPolicy.longest 4720 foreach (i, Range; R) 4721 { 4722 ranges[i][n] = v[i]; 4723 } 4724 } 4725 } 4726 4727/** 4728 Destructively reads the `n`th element in the composite 4729 range. Defined if all ranges offer random access. 4730*/ 4731 static if (allSatisfy!(hasMobileElements, R)) 4732 { 4733 ElementType moveAt(size_t n) 4734 { 4735 //TODO: Fixme! This may create an out of bounds access 4736 //for StoppingPolicy.longest 4737 4738 //ElementType(ranges[0].moveAt(n), ranges[1].moveAt(n), ..., ) 4739 return mixin (q{ElementType(%(ranges[%s].moveAt(n)%|, %))}.format(iota(0, R.length))); 4740 } 4741 } 4742 } 4743} 4744 4745/// Ditto 4746auto zip(Ranges...)(Ranges ranges) 4747if (Ranges.length && allSatisfy!(isInputRange, Ranges)) 4748{ 4749 import std.meta : anySatisfy, templateOr; 4750 static if (allSatisfy!(isInfinite, Ranges) || Ranges.length == 1) 4751 { 4752 return ZipShortest!(Ranges)(ranges); 4753 } 4754 else static if (allSatisfy!(isBidirectionalRange, Ranges)) 4755 { 4756 static if (allSatisfy!(templateOr!(isInfinite, hasLength), Ranges) 4757 && allSatisfy!(templateOr!(isInfinite, hasSlicing), Ranges) 4758 && allSatisfy!(isBidirectionalRange, staticMap!(Take, Ranges))) 4759 { 4760 // If all the ranges are bidirectional, if possible slice them to 4761 // the same length to simplify the implementation. 4762 static assert(anySatisfy!(hasLength, Ranges)); 4763 static foreach (i, Range; Ranges) 4764 static if (hasLength!Range) 4765 { 4766 static if (!is(typeof(minLen) == size_t)) 4767 size_t minLen = ranges[i].length; 4768 else 4769 {{ 4770 const x = ranges[i].length; 4771 if (x < minLen) minLen = x; 4772 }} 4773 } 4774 import std.format : format; 4775 static if (!anySatisfy!(isInfinite, Ranges)) 4776 return mixin(`ZipShortest!(Yes.allKnownSameLength, staticMap!(Take, Ranges))`~ 4777 `(%(ranges[%s][0 .. minLen]%|, %))`.format(iota(0, Ranges.length))); 4778 else 4779 return mixin(`ZipShortest!(Yes.allKnownSameLength, staticMap!(Take, Ranges))`~ 4780 `(%(take(ranges[%s], minLen)%|, %))`.format(iota(0, Ranges.length))); 4781 } 4782 else static if (allSatisfy!(isRandomAccessRange, Ranges)) 4783 { 4784 // We can't slice but we can still use random access to ensure 4785 // "back" is retrieving the same index for each range. 4786 return ZipShortest!(Ranges)(ranges); 4787 } 4788 else 4789 { 4790 // If bidirectional range operations would not be supported by 4791 // ZipShortest that might have actually been a bug since Zip 4792 // supported `back` without verifying that each range had the 4793 // same length, but for the sake of backwards compatibility 4794 // use the old Zip to continue supporting them. 4795 return Zip!Ranges(ranges); 4796 } 4797 } 4798 else 4799 { 4800 return ZipShortest!(Ranges)(ranges); 4801 } 4802} 4803 4804/// 4805@nogc nothrow pure @safe unittest 4806{ 4807 import std.algorithm.comparison : equal; 4808 import std.algorithm.iteration : map; 4809 4810 // pairwise sum 4811 auto arr = only(0, 1, 2); 4812 auto part1 = zip(arr, arr.dropOne).map!"a[0] + a[1]"; 4813 assert(part1.equal(only(1, 3))); 4814} 4815 4816/// 4817nothrow pure @safe unittest 4818{ 4819 import std.conv : to; 4820 4821 int[] a = [ 1, 2, 3 ]; 4822 string[] b = [ "a", "b", "c" ]; 4823 string[] result; 4824 4825 foreach (tup; zip(a, b)) 4826 { 4827 result ~= tup[0].to!string ~ tup[1]; 4828 } 4829 4830 assert(result == [ "1a", "2b", "3c" ]); 4831 4832 size_t idx = 0; 4833 // unpacking tuple elements with foreach 4834 foreach (e1, e2; zip(a, b)) 4835 { 4836 assert(e1 == a[idx]); 4837 assert(e2 == b[idx]); 4838 ++idx; 4839 } 4840} 4841 4842/// `zip` is powerful - the following code sorts two arrays in parallel: 4843nothrow pure @safe unittest 4844{ 4845 import std.algorithm.sorting : sort; 4846 4847 int[] a = [ 1, 2, 3 ]; 4848 string[] b = [ "a", "c", "b" ]; 4849 zip(a, b).sort!((t1, t2) => t1[0] > t2[0]); 4850 4851 assert(a == [ 3, 2, 1 ]); 4852 // b is sorted according to a's sorting 4853 assert(b == [ "b", "c", "a" ]); 4854} 4855 4856/// Ditto 4857auto zip(Ranges...)(StoppingPolicy sp, Ranges ranges) 4858if (Ranges.length && allSatisfy!(isInputRange, Ranges)) 4859{ 4860 return Zip!Ranges(ranges, sp); 4861} 4862 4863/** 4864 Dictates how iteration in a $(LREF zip) and $(LREF lockstep) should stop. 4865 By default stop at the end of the shortest of all ranges. 4866*/ 4867enum StoppingPolicy 4868{ 4869 /// Stop when the shortest range is exhausted 4870 shortest, 4871 /// Stop when the longest range is exhausted 4872 longest, 4873 /// Require that all ranges are equal 4874 requireSameLength, 4875} 4876 4877/// 4878pure @safe unittest 4879{ 4880 import std.algorithm.comparison : equal; 4881 import std.exception : assertThrown; 4882 import std.range.primitives; 4883 import std.typecons : tuple; 4884 4885 auto a = [1, 2, 3]; 4886 auto b = [4, 5, 6, 7]; 4887 4888 auto shortest = zip(StoppingPolicy.shortest, a, b); 4889 assert(shortest.equal([ 4890 tuple(1, 4), 4891 tuple(2, 5), 4892 tuple(3, 6) 4893 ])); 4894 4895 auto longest = zip(StoppingPolicy.longest, a, b); 4896 assert(longest.equal([ 4897 tuple(1, 4), 4898 tuple(2, 5), 4899 tuple(3, 6), 4900 tuple(0, 7) 4901 ])); 4902 4903 auto same = zip(StoppingPolicy.requireSameLength, a, b); 4904 same.popFrontN(3); 4905 assertThrown!Exception(same.popFront); 4906} 4907 4908/+ 4909Non-public. Like $(LREF Zip) with `StoppingPolicy.shortest` 4910except it properly implements `back` and `popBack` in the 4911case of uneven ranges or disables those operations when 4912it is not possible to guarantee they are correct. 4913+/ 4914package template ZipShortest(Ranges...) 4915if (Ranges.length && __traits(compiles, 4916 { 4917 static assert(allSatisfy!(isInputRange, Ranges)); 4918 })) 4919{ 4920 alias ZipShortest = .ZipShortest!( 4921 Ranges.length == 1 || allSatisfy!(isInfinite, Ranges) 4922 ? Yes.allKnownSameLength 4923 : No.allKnownSameLength, 4924 Ranges); 4925} 4926/+ non-public, ditto +/ 4927package struct ZipShortest(Flag!"allKnownSameLength" allKnownSameLength, Ranges...) 4928if (Ranges.length && allSatisfy!(isInputRange, Ranges)) 4929{ 4930 import std.format : format; //for generic mixins 4931 import std.meta : anySatisfy, templateOr; 4932 import std.typecons : Tuple; 4933 4934 deprecated("Use of an undocumented alias R.") 4935 alias R = Ranges; // Unused here but defined in case library users rely on it. 4936 private Ranges ranges; 4937 alias ElementType = Tuple!(staticMap!(.ElementType, Ranges)); 4938 4939 /+ 4940 Builds an object. Usually this is invoked indirectly by using the 4941 $(LREF zip) function. 4942 +/ 4943 this(Ranges rs) 4944 { 4945 ranges[] = rs[]; 4946 } 4947 4948 /+ 4949 Returns `true` if the range is at end. 4950 +/ 4951 static if (allKnownSameLength ? anySatisfy!(isInfinite, Ranges) 4952 : allSatisfy!(isInfinite, Ranges)) 4953 { 4954 enum bool empty = false; 4955 } 4956 else 4957 { 4958 @property bool empty() 4959 { 4960 static if (allKnownSameLength) 4961 { 4962 return ranges[0].empty; 4963 } 4964 else 4965 { 4966 static foreach (i; 0 .. Ranges.length) 4967 { 4968 if (ranges[i].empty) 4969 return true; 4970 } 4971 return false; 4972 } 4973 } 4974 } 4975 4976 /+ 4977 Forward range primitive. Only present if each constituent range is a 4978 forward range. 4979 +/ 4980 static if (allSatisfy!(isForwardRange, Ranges)) 4981 @property typeof(this) save() 4982 { 4983 return mixin(`typeof(return)(%(ranges[%s].save%|, %))`.format(iota(0, Ranges.length))); 4984 } 4985 4986 /+ 4987 Returns the current iterated element. 4988 +/ 4989 @property ElementType front() 4990 { 4991 return mixin(`typeof(return)(%(ranges[%s].front%|, %))`.format(iota(0, Ranges.length))); 4992 } 4993 4994 /+ 4995 Sets the front of all iterated ranges. Only present if each constituent 4996 range has assignable elements. 4997 +/ 4998 static if (allSatisfy!(hasAssignableElements, Ranges)) 4999 @property void front()(ElementType v) 5000 { 5001 static foreach (i; 0 .. Ranges.length) 5002 ranges[i].front = v[i]; 5003 } 5004 5005 /+ 5006 Moves out the front. Present if each constituent range has mobile elements. 5007 +/ 5008 static if (allSatisfy!(hasMobileElements, Ranges)) 5009 ElementType moveFront()() 5010 { 5011 return mixin(`typeof(return)(%(ranges[%s].moveFront()%|, %))`.format(iota(0, Ranges.length))); 5012 } 5013 5014 private enum bool isBackWellDefined = allSatisfy!(isBidirectionalRange, Ranges) 5015 && (allKnownSameLength 5016 || allSatisfy!(isRandomAccessRange, Ranges) 5017 // Could also add the case where there is one non-infinite bidirectional 5018 // range that defines `length` and all others are infinite random access 5019 // ranges. Adding this would require appropriate branches in 5020 // back/moveBack/popBack. 5021 ); 5022 5023 /+ 5024 Returns the rightmost element. Present if all constituent ranges are 5025 bidirectional and either there is a compile-time guarantee that all 5026 ranges have the same length (in `allKnownSameLength`) or all ranges 5027 provide random access to elements. 5028 +/ 5029 static if (isBackWellDefined) 5030 @property ElementType back() 5031 { 5032 static if (allKnownSameLength) 5033 { 5034 return mixin(`typeof(return)(%(ranges[%s].back()%|, %))`.format(iota(0, Ranges.length))); 5035 } 5036 else 5037 { 5038 const backIndex = length - 1; 5039 return mixin(`typeof(return)(%(ranges[%s][backIndex]%|, %))`.format(iota(0, Ranges.length))); 5040 } 5041 } 5042 5043 /+ 5044 Moves out the back. Present if `back` is defined and 5045 each constituent range has mobile elements. 5046 +/ 5047 static if (isBackWellDefined && allSatisfy!(hasMobileElements, Ranges)) 5048 ElementType moveBack()() 5049 { 5050 static if (allKnownSameLength) 5051 { 5052 return mixin(`typeof(return)(%(ranges[%s].moveBack()%|, %))`.format(iota(0, Ranges.length))); 5053 } 5054 else 5055 { 5056 const backIndex = length - 1; 5057 return mixin(`typeof(return)(%(ranges[%s].moveAt(backIndex)%|, %))`.format(iota(0, Ranges.length))); 5058 } 5059 } 5060 5061 /+ 5062 Sets the rightmost element. Only present if `back` is defined and 5063 each constituent range has assignable elements. 5064 +/ 5065 static if (isBackWellDefined && allSatisfy!(hasAssignableElements, Ranges)) 5066 @property void back()(ElementType v) 5067 { 5068 static if (allKnownSameLength) 5069 { 5070 static foreach (i; 0 .. Ranges.length) 5071 ranges[i].back = v[i]; 5072 } 5073 else 5074 { 5075 const backIndex = length - 1; 5076 static foreach (i; 0 .. Ranges.length) 5077 ranges[i][backIndex] = v[i]; 5078 } 5079 } 5080 5081 /+ 5082 Calls `popFront` on each constituent range. 5083 +/ 5084 void popFront() 5085 { 5086 static foreach (i; 0 .. Ranges.length) 5087 ranges[i].popFront(); 5088 } 5089 5090 /+ 5091 Pops the rightmost element. Present if `back` is defined. 5092 +/ 5093 static if (isBackWellDefined) 5094 void popBack() 5095 { 5096 static if (allKnownSameLength) 5097 { 5098 static foreach (i; 0 .. Ranges.length) 5099 ranges[i].popBack; 5100 } 5101 else 5102 { 5103 const len = length; 5104 static foreach (i; 0 .. Ranges.length) 5105 static if (!isInfinite!(Ranges[i])) 5106 if (ranges[i].length == len) 5107 ranges[i].popBack(); 5108 } 5109 } 5110 5111 /+ 5112 Returns the length of this range. Defined if at least one 5113 constituent range defines `length` and the other ranges all also 5114 define `length` or are infinite, or if at least one constituent 5115 range defines `length` and there is a compile-time guarantee that 5116 all ranges have the same length (in `allKnownSameLength`). 5117 +/ 5118 static if (allKnownSameLength 5119 ? anySatisfy!(hasLength, Ranges) 5120 : (anySatisfy!(hasLength, Ranges) 5121 && allSatisfy!(templateOr!(isInfinite, hasLength), Ranges))) 5122 { 5123 @property size_t length() 5124 { 5125 static foreach (i, Range; Ranges) 5126 { 5127 static if (hasLength!Range) 5128 { 5129 static if (!is(typeof(minLen) == size_t)) 5130 size_t minLen = ranges[i].length; 5131 else static if (!allKnownSameLength) 5132 {{ 5133 const x = ranges[i].length; 5134 if (x < minLen) minLen = x; 5135 }} 5136 } 5137 } 5138 return minLen; 5139 } 5140 5141 alias opDollar = length; 5142 } 5143 5144 /+ 5145 Returns a slice of the range. Defined if all constituent ranges 5146 support slicing. 5147 +/ 5148 static if (allSatisfy!(hasSlicing, Ranges)) 5149 { 5150 // Note: we will know that all elements of the resultant range 5151 // will have the same length but we cannot change `allKnownSameLength` 5152 // because the `hasSlicing` predicate tests that the result returned 5153 // by `opSlice` has the same type as the receiver. 5154 auto opSlice()(size_t from, size_t to) 5155 { 5156 //(ranges[0][from .. to], ranges[1][from .. to], ...) 5157 enum sliceArgs = `(%(ranges[%s][from .. to]%|, %))`.format(iota(0, Ranges.length)); 5158 static if (__traits(compiles, mixin(`typeof(this)`~sliceArgs))) 5159 return mixin(`typeof(this)`~sliceArgs); 5160 else 5161 // The type is different anyway so we might as well 5162 // explicitly set allKnownSameLength. 5163 return mixin(`ZipShortest!(Yes.allKnownSameLength, staticMap!(Take, Ranges))` 5164 ~sliceArgs); 5165 } 5166 } 5167 5168 /+ 5169 Returns the `n`th element in the composite range. Defined if all 5170 constituent ranges offer random access. 5171 +/ 5172 static if (allSatisfy!(isRandomAccessRange, Ranges)) 5173 ElementType opIndex()(size_t n) 5174 { 5175 return mixin(`typeof(return)(%(ranges[%s][n]%|, %))`.format(iota(0, Ranges.length))); 5176 } 5177 5178 /+ 5179 Sets the `n`th element in the composite range. Defined if all 5180 constituent ranges offer random access and have assignable elements. 5181 +/ 5182 static if (allSatisfy!(isRandomAccessRange, Ranges) 5183 && allSatisfy!(hasAssignableElements, Ranges)) 5184 void opIndexAssign()(ElementType v, size_t n) 5185 { 5186 static foreach (i; 0 .. Ranges.length) 5187 ranges[i][n] = v[i]; 5188 } 5189 5190 /+ 5191 Destructively reads the `n`th element in the composite 5192 range. Defined if all constituent ranges offer random 5193 access and have mobile elements. 5194 +/ 5195 static if (allSatisfy!(isRandomAccessRange, Ranges) 5196 && allSatisfy!(hasMobileElements, Ranges)) 5197 ElementType moveAt()(size_t n) 5198 { 5199 return mixin(`typeof(return)(%(ranges[%s].moveAt(n)%|, %))`.format(iota(0, Ranges.length))); 5200 } 5201} 5202 5203pure @system unittest 5204{ 5205 import std.algorithm.comparison : equal; 5206 import std.algorithm.iteration : filter, map; 5207 import std.algorithm.mutation : swap; 5208 import std.algorithm.sorting : sort; 5209 5210 import std.exception : assertThrown, assertNotThrown; 5211 import std.typecons : tuple; 5212 5213 int[] a = [ 1, 2, 3 ]; 5214 float[] b = [ 1.0, 2.0, 3.0 ]; 5215 foreach (e; zip(a, b)) 5216 { 5217 assert(e[0] == e[1]); 5218 } 5219 5220 swap(a[0], a[1]); 5221 { 5222 auto z = zip(a, b); 5223 } 5224 //swap(z.front(), z.back()); 5225 sort!("a[0] < b[0]")(zip(a, b)); 5226 assert(a == [1, 2, 3]); 5227 assert(b == [2.0, 1.0, 3.0]); 5228 5229 auto z = zip(StoppingPolicy.requireSameLength, a, b); 5230 assertNotThrown(z.popBack()); 5231 assertNotThrown(z.popBack()); 5232 assertNotThrown(z.popBack()); 5233 assert(z.empty); 5234 assertThrown(z.popBack()); 5235 5236 a = [ 1, 2, 3 ]; 5237 b = [ 1.0, 2.0, 3.0 ]; 5238 sort!("a[0] > b[0]")(zip(StoppingPolicy.requireSameLength, a, b)); 5239 assert(a == [3, 2, 1]); 5240 assert(b == [3.0, 2.0, 1.0]); 5241 5242 a = []; 5243 b = []; 5244 assert(zip(StoppingPolicy.requireSameLength, a, b).empty); 5245 5246 // Test infiniteness propagation. 5247 static assert(isInfinite!(typeof(zip(repeat(1), repeat(1))))); 5248 5249 // Test stopping policies with both value and reference. 5250 auto a1 = [1, 2]; 5251 auto a2 = [1, 2, 3]; 5252 auto stuff = tuple(tuple(a1, a2), 5253 tuple(filter!"a"(a1), filter!"a"(a2))); 5254 5255 alias FOO = Zip!(immutable(int)[], immutable(float)[]); 5256 5257 foreach (t; stuff.expand) 5258 { 5259 auto arr1 = t[0]; 5260 auto arr2 = t[1]; 5261 auto zShortest = zip(arr1, arr2); 5262 assert(equal(map!"a[0]"(zShortest), [1, 2])); 5263 assert(equal(map!"a[1]"(zShortest), [1, 2])); 5264 5265 try { 5266 auto zSame = zip(StoppingPolicy.requireSameLength, arr1, arr2); 5267 foreach (elem; zSame) {} 5268 assert(0); 5269 } catch (Throwable) { /* It's supposed to throw.*/ } 5270 5271 auto zLongest = zip(StoppingPolicy.longest, arr1, arr2); 5272 assert(!zLongest.ranges[0].empty); 5273 assert(!zLongest.ranges[1].empty); 5274 5275 zLongest.popFront(); 5276 zLongest.popFront(); 5277 assert(!zLongest.empty); 5278 assert(zLongest.ranges[0].empty); 5279 assert(!zLongest.ranges[1].empty); 5280 5281 zLongest.popFront(); 5282 assert(zLongest.empty); 5283 } 5284 5285 // https://issues.dlang.org/show_bug.cgi?id=8900 5286 assert(zip([1, 2], repeat('a')).array == [tuple(1, 'a'), tuple(2, 'a')]); 5287 assert(zip(repeat('a'), [1, 2]).array == [tuple('a', 1), tuple('a', 2)]); 5288 5289 // https://issues.dlang.org/show_bug.cgi?id=18524 5290 // moveBack instead performs moveFront 5291 { 5292 auto r = zip([1,2,3]); 5293 assert(r.moveBack()[0] == 3); 5294 assert(r.moveFront()[0] == 1); 5295 } 5296 5297 // Doesn't work yet. Issues w/ emplace. 5298 // static assert(is(Zip!(immutable int[], immutable float[]))); 5299 5300 5301 // These unittests pass, but make the compiler consume an absurd amount 5302 // of RAM and time. Therefore, they should only be run if explicitly 5303 // uncommented when making changes to Zip. Also, running them using 5304 // make -fwin32.mak unittest makes the compiler completely run out of RAM. 5305 // You need to test just this module. 5306 /+ 5307 foreach (DummyType1; AllDummyRanges) 5308 { 5309 DummyType1 d1; 5310 foreach (DummyType2; AllDummyRanges) 5311 { 5312 DummyType2 d2; 5313 auto r = zip(d1, d2); 5314 assert(equal(map!"a[0]"(r), [1,2,3,4,5,6,7,8,9,10])); 5315 assert(equal(map!"a[1]"(r), [1,2,3,4,5,6,7,8,9,10])); 5316 5317 static if (isForwardRange!DummyType1 && isForwardRange!DummyType2) 5318 { 5319 static assert(isForwardRange!(typeof(r))); 5320 } 5321 5322 static if (isBidirectionalRange!DummyType1 && 5323 isBidirectionalRange!DummyType2) { 5324 static assert(isBidirectionalRange!(typeof(r))); 5325 } 5326 static if (isRandomAccessRange!DummyType1 && 5327 isRandomAccessRange!DummyType2) { 5328 static assert(isRandomAccessRange!(typeof(r))); 5329 } 5330 } 5331 } 5332 +/ 5333} 5334 5335nothrow pure @safe unittest 5336{ 5337 import std.algorithm.sorting : sort; 5338 5339 auto a = [5,4,3,2,1]; 5340 auto b = [3,1,2,5,6]; 5341 auto z = zip(a, b); 5342 5343 sort!"a[0] < b[0]"(z); 5344 5345 assert(a == [1, 2, 3, 4, 5]); 5346 assert(b == [6, 5, 2, 1, 3]); 5347} 5348 5349nothrow pure @safe unittest 5350{ 5351 import std.algorithm.comparison : equal; 5352 import std.typecons : tuple; 5353 5354 auto LL = iota(1L, 1000L); 5355 auto z = zip(LL, [4]); 5356 5357 assert(equal(z, [tuple(1L,4)])); 5358 5359 auto LL2 = iota(0L, 500L); 5360 auto z2 = zip([7], LL2); 5361 assert(equal(z2, [tuple(7, 0L)])); 5362} 5363 5364// Test for https://issues.dlang.org/show_bug.cgi?id=11196 5365@safe pure unittest 5366{ 5367 import std.exception : assertThrown; 5368 5369 static struct S { @disable this(); } 5370 assert(zip((S[5]).init[]).length == 5); 5371 assert(zip(StoppingPolicy.longest, cast(S[]) null, new int[1]).length == 1); 5372 assertThrown(zip(StoppingPolicy.longest, cast(S[]) null, new int[1]).front); 5373} 5374 5375// https://issues.dlang.org/show_bug.cgi?id=12007 5376@nogc nothrow @safe pure unittest 5377{ 5378 static struct R 5379 { 5380 enum empty = false; 5381 void popFront(){} 5382 int front(){return 1;} @property 5383 R save(){return this;} @property 5384 void opAssign(R) @disable; 5385 } 5386 R r; 5387 auto z = zip(r, r); 5388 assert(z.save == z); 5389} 5390 5391nothrow pure @system unittest 5392{ 5393 import std.typecons : tuple; 5394 5395 auto r1 = [0,1,2]; 5396 auto r2 = [1,2,3]; 5397 auto z1 = zip(refRange(&r1), refRange(&r2)); 5398 auto z2 = z1.save; 5399 z1.popFront(); 5400 assert(z1.front == tuple(1,2)); 5401 assert(z2.front == tuple(0,1)); 5402} 5403 5404@nogc nothrow pure @safe unittest 5405{ 5406 // Test zip's `back` and `length` with non-equal ranges. 5407 static struct NonSliceableRandomAccess 5408 { 5409 private int[] a; 5410 @property ref front() 5411 { 5412 return a.front; 5413 } 5414 @property ref back() 5415 { 5416 return a.back; 5417 } 5418 ref opIndex(size_t i) 5419 { 5420 return a[i]; 5421 } 5422 void popFront() 5423 { 5424 a.popFront(); 5425 } 5426 void popBack() 5427 { 5428 a.popBack(); 5429 } 5430 auto moveFront() 5431 { 5432 return a.moveFront(); 5433 } 5434 auto moveBack() 5435 { 5436 return a.moveBack(); 5437 } 5438 auto moveAt(size_t i) 5439 { 5440 return a.moveAt(i); 5441 } 5442 bool empty() const 5443 { 5444 return a.empty; 5445 } 5446 size_t length() const 5447 { 5448 return a.length; 5449 } 5450 typeof(this) save() 5451 { 5452 return this; 5453 } 5454 } 5455 static assert(isRandomAccessRange!NonSliceableRandomAccess); 5456 static assert(!hasSlicing!NonSliceableRandomAccess); 5457 static foreach (iteration; 0 .. 2) 5458 {{ 5459 int[5] data = [101, 102, 103, 201, 202]; 5460 static if (iteration == 0) 5461 { 5462 auto r1 = NonSliceableRandomAccess(data[0 .. 3]); 5463 auto r2 = NonSliceableRandomAccess(data[3 .. 5]); 5464 } 5465 else 5466 { 5467 auto r1 = data[0 .. 3]; 5468 auto r2 = data[3 .. 5]; 5469 } 5470 auto z = zip(r1, r2); 5471 static assert(isRandomAccessRange!(typeof(z))); 5472 assert(z.length == 2); 5473 assert(z.back[0] == 102 && z.back[1] == 202); 5474 z.back = typeof(z.back)(-102, -202);// Assign to back. 5475 assert(z.back[0] == -102 && z.back[1] == -202); 5476 z.popBack(); 5477 assert(z.length == 1); 5478 assert(z.back[0] == 101 && z.back[1] == 201); 5479 z.front = typeof(z.front)(-101, -201); 5480 assert(z.moveBack() == typeof(z.back)(-101, -201)); 5481 z.popBack(); 5482 assert(z.empty); 5483 }} 5484} 5485 5486@nogc nothrow pure @safe unittest 5487{ 5488 // Test opSlice on infinite `zip`. 5489 auto z = zip(repeat(1), repeat(2)); 5490 assert(hasSlicing!(typeof(z))); 5491 auto slice = z[10 .. 20]; 5492 assert(slice.length == 10); 5493 static assert(!is(typeof(z) == typeof(slice))); 5494} 5495 5496/* 5497 Generate lockstep's opApply function as a mixin string. 5498 If withIndex is true prepend a size_t index to the delegate. 5499*/ 5500private string lockstepMixin(Ranges...)(bool withIndex, bool reverse) 5501{ 5502 import std.format : format; 5503 5504 string[] params; 5505 string[] emptyChecks; 5506 string[] dgArgs; 5507 string[] popFronts; 5508 string indexDef; 5509 string indexInc; 5510 5511 if (withIndex) 5512 { 5513 params ~= "size_t"; 5514 dgArgs ~= "index"; 5515 if (reverse) 5516 { 5517 indexDef = q{ 5518 size_t index = ranges[0].length-1; 5519 enforce(_stoppingPolicy == StoppingPolicy.requireSameLength, 5520 "lockstep can only be used with foreach_reverse when stoppingPolicy == requireSameLength"); 5521 5522 foreach (range; ranges[1..$]) 5523 enforce(range.length == ranges[0].length); 5524 }; 5525 indexInc = "--index;"; 5526 } 5527 else 5528 { 5529 indexDef = "size_t index = 0;"; 5530 indexInc = "++index;"; 5531 } 5532 } 5533 5534 foreach (idx, Range; Ranges) 5535 { 5536 params ~= format("%sElementType!(Ranges[%s])", hasLvalueElements!Range ? "ref " : "", idx); 5537 emptyChecks ~= format("!ranges[%s].empty", idx); 5538 if (reverse) 5539 { 5540 dgArgs ~= format("ranges[%s].back", idx); 5541 popFronts ~= format("ranges[%s].popBack();", idx); 5542 } 5543 else 5544 { 5545 dgArgs ~= format("ranges[%s].front", idx); 5546 popFronts ~= format("ranges[%s].popFront();", idx); 5547 } 5548 } 5549 5550 string name = reverse ? "opApplyReverse" : "opApply"; 5551 5552 return format( 5553 q{ 5554 int %s(scope int delegate(%s) dg) 5555 { 5556 import std.exception : enforce; 5557 5558 auto ranges = _ranges; 5559 int res; 5560 %s 5561 5562 while (%s) 5563 { 5564 res = dg(%s); 5565 if (res) break; 5566 %s 5567 %s 5568 } 5569 5570 if (_stoppingPolicy == StoppingPolicy.requireSameLength) 5571 { 5572 foreach (range; ranges) 5573 enforce(range.empty); 5574 } 5575 return res; 5576 } 5577 }, name, params.join(", "), indexDef, 5578 emptyChecks.join(" && "), dgArgs.join(", "), 5579 popFronts.join("\n "), 5580 indexInc); 5581} 5582 5583/** 5584 Iterate multiple ranges in lockstep using a `foreach` loop. In contrast to 5585 $(LREF zip) it allows reference access to its elements. If only a single 5586 range is passed in, the `Lockstep` aliases itself away. If the 5587 ranges are of different lengths and `s` == `StoppingPolicy.shortest` 5588 stop after the shortest range is empty. If the ranges are of different 5589 lengths and `s` == `StoppingPolicy.requireSameLength`, throw an 5590 exception. `s` may not be `StoppingPolicy.longest`, and passing this 5591 will throw an exception. 5592 5593 Iterating over `Lockstep` in reverse and with an index is only possible 5594 when `s` == `StoppingPolicy.requireSameLength`, in order to preserve 5595 indexes. If an attempt is made at iterating in reverse when `s` == 5596 `StoppingPolicy.shortest`, an exception will be thrown. 5597 5598 By default `StoppingPolicy` is set to `StoppingPolicy.shortest`. 5599 5600 Limitations: The `pure`, `@safe`, `@nogc`, or `nothrow` attributes cannot be 5601 inferred for `lockstep` iteration. $(LREF zip) can infer the first two due to 5602 a different implementation. 5603 5604 See_Also: $(LREF zip) 5605 5606 `lockstep` is similar to $(LREF zip), but `zip` bundles its 5607 elements and returns a range. 5608 `lockstep` also supports reference access. 5609 Use `zip` if you want to pass the result to a range function. 5610*/ 5611struct Lockstep(Ranges...) 5612if (Ranges.length > 1 && allSatisfy!(isInputRange, Ranges)) 5613{ 5614 /// 5615 this(R ranges, StoppingPolicy sp = StoppingPolicy.shortest) 5616 { 5617 import std.exception : enforce; 5618 5619 _ranges = ranges; 5620 enforce(sp != StoppingPolicy.longest, 5621 "Can't use StoppingPolicy.Longest on Lockstep."); 5622 _stoppingPolicy = sp; 5623 } 5624 5625 mixin(lockstepMixin!Ranges(false, false)); 5626 mixin(lockstepMixin!Ranges(true, false)); 5627 static if (allSatisfy!(isBidirectionalRange, Ranges)) 5628 { 5629 mixin(lockstepMixin!Ranges(false, true)); 5630 static if (allSatisfy!(hasLength, Ranges)) 5631 { 5632 mixin(lockstepMixin!Ranges(true, true)); 5633 } 5634 else 5635 { 5636 mixin(lockstepReverseFailMixin!Ranges(true)); 5637 } 5638 } 5639 else 5640 { 5641 mixin(lockstepReverseFailMixin!Ranges(false)); 5642 mixin(lockstepReverseFailMixin!Ranges(true)); 5643 } 5644 5645private: 5646 alias R = Ranges; 5647 R _ranges; 5648 StoppingPolicy _stoppingPolicy; 5649} 5650 5651/// Ditto 5652Lockstep!(Ranges) lockstep(Ranges...)(Ranges ranges) 5653if (allSatisfy!(isInputRange, Ranges)) 5654{ 5655 return Lockstep!(Ranges)(ranges); 5656} 5657/// Ditto 5658Lockstep!(Ranges) lockstep(Ranges...)(Ranges ranges, StoppingPolicy s) 5659if (allSatisfy!(isInputRange, Ranges)) 5660{ 5661 static if (Ranges.length > 1) 5662 return Lockstep!Ranges(ranges, s); 5663 else 5664 return ranges[0]; 5665} 5666 5667/// 5668@system unittest 5669{ 5670 auto arr1 = [1,2,3,4,5,100]; 5671 auto arr2 = [6,7,8,9,10]; 5672 5673 foreach (ref a, b; lockstep(arr1, arr2)) 5674 { 5675 a += b; 5676 } 5677 5678 assert(arr1 == [7,9,11,13,15,100]); 5679 5680 /// Lockstep also supports iterating with an index variable: 5681 foreach (index, a, b; lockstep(arr1, arr2)) 5682 { 5683 assert(arr1[index] == a); 5684 assert(arr2[index] == b); 5685 } 5686} 5687 5688// https://issues.dlang.org/show_bug.cgi?id=15860: foreach_reverse on lockstep 5689@system unittest 5690{ 5691 auto arr1 = [0, 1, 2, 3]; 5692 auto arr2 = [4, 5, 6, 7]; 5693 5694 size_t n = arr1.length -1; 5695 foreach_reverse (index, a, b; lockstep(arr1, arr2, StoppingPolicy.requireSameLength)) 5696 { 5697 assert(n == index); 5698 assert(index == a); 5699 assert(arr1[index] == a); 5700 assert(arr2[index] == b); 5701 n--; 5702 } 5703 5704 auto arr3 = [4, 5]; 5705 n = 1; 5706 foreach_reverse (a, b; lockstep(arr1, arr3)) 5707 { 5708 assert(a == arr1[$-n] && b == arr3[$-n]); 5709 n++; 5710 } 5711} 5712 5713@system unittest 5714{ 5715 import std.algorithm.iteration : filter; 5716 import std.conv : to; 5717 5718 // The filters are to make these the lowest common forward denominator ranges, 5719 // i.e. w/o ref return, random access, length, etc. 5720 auto foo = filter!"a"([1,2,3,4,5]); 5721 immutable bar = [6f,7f,8f,9f,10f].idup; 5722 auto l = lockstep(foo, bar); 5723 5724 // Should work twice. These are forward ranges with implicit save. 5725 foreach (i; 0 .. 2) 5726 { 5727 uint[] res1; 5728 float[] res2; 5729 5730 foreach (a, ref b; l) 5731 { 5732 res1 ~= a; 5733 res2 ~= b; 5734 } 5735 5736 assert(res1 == [1,2,3,4,5]); 5737 assert(res2 == [6,7,8,9,10]); 5738 assert(bar == [6f,7f,8f,9f,10f]); 5739 } 5740 5741 // Doc example. 5742 auto arr1 = [1,2,3,4,5]; 5743 auto arr2 = [6,7,8,9,10]; 5744 5745 foreach (ref a, ref b; lockstep(arr1, arr2)) 5746 { 5747 a += b; 5748 } 5749 5750 assert(arr1 == [7,9,11,13,15]); 5751 5752 // Make sure StoppingPolicy.requireSameLength doesn't throw. 5753 auto ls = lockstep(arr1, arr2, StoppingPolicy.requireSameLength); 5754 5755 int k = 1; 5756 foreach (a, b; ls) 5757 { 5758 assert(a - b == k); 5759 ++k; 5760 } 5761 5762 // Make sure StoppingPolicy.requireSameLength throws. 5763 arr2.popBack(); 5764 ls = lockstep(arr1, arr2, StoppingPolicy.requireSameLength); 5765 5766 try { 5767 foreach (a, b; ls) {} 5768 assert(0); 5769 } catch (Exception) {} 5770 5771 // Just make sure 1-range case instantiates. This hangs the compiler 5772 // when no explicit stopping policy is specified due to 5773 // https://issues.dlang.org/show_bug.cgi?id=4652 5774 auto stuff = lockstep([1,2,3,4,5], StoppingPolicy.shortest); 5775 foreach (i, a; stuff) 5776 { 5777 assert(stuff[i] == a); 5778 } 5779 5780 // Test with indexing. 5781 uint[] res1; 5782 float[] res2; 5783 size_t[] indices; 5784 foreach (i, a, b; lockstep(foo, bar)) 5785 { 5786 indices ~= i; 5787 res1 ~= a; 5788 res2 ~= b; 5789 } 5790 5791 assert(indices == to!(size_t[])([0, 1, 2, 3, 4])); 5792 assert(res1 == [1,2,3,4,5]); 5793 assert(res2 == [6f,7f,8f,9f,10f]); 5794 5795 // Make sure we've worked around the relevant compiler bugs and this at least 5796 // compiles w/ >2 ranges. 5797 lockstep(foo, foo, foo); 5798 5799 // Make sure it works with const. 5800 const(int[])[] foo2 = [[1, 2, 3]]; 5801 const(int[])[] bar2 = [[4, 5, 6]]; 5802 auto c = chain(foo2, bar2); 5803 5804 foreach (f, b; lockstep(c, c)) {} 5805 5806 // Regression 10468 5807 foreach (x, y; lockstep(iota(0, 10), iota(0, 10))) { } 5808} 5809 5810@system unittest 5811{ 5812 struct RvalueRange 5813 { 5814 int[] impl; 5815 @property bool empty() { return impl.empty; } 5816 @property int front() { return impl[0]; } // N.B. non-ref 5817 void popFront() { impl.popFront(); } 5818 } 5819 auto data1 = [ 1, 2, 3, 4 ]; 5820 auto data2 = [ 5, 6, 7, 8 ]; 5821 auto r1 = RvalueRange(data1); 5822 auto r2 = data2; 5823 foreach (a, ref b; lockstep(r1, r2)) 5824 { 5825 a++; 5826 b++; 5827 } 5828 assert(data1 == [ 1, 2, 3, 4 ]); // changes to a do not propagate to data 5829 assert(data2 == [ 6, 7, 8, 9 ]); // but changes to b do. 5830 5831 // Since r1 is by-value only, the compiler should reject attempts to 5832 // foreach over it with ref. 5833 static assert(!__traits(compiles, { 5834 foreach (ref a, ref b; lockstep(r1, r2)) { a++; } 5835 })); 5836} 5837 5838private string lockstepReverseFailMixin(Ranges...)(bool withIndex) 5839{ 5840 import std.format : format; 5841 string[] params; 5842 string message; 5843 5844 if (withIndex) 5845 { 5846 message = "Indexed reverse iteration with lockstep is only supported" 5847 ~"if all ranges are bidirectional and have a length.\n"; 5848 } 5849 else 5850 { 5851 message = "Reverse iteration with lockstep is only supported if all ranges are bidirectional.\n"; 5852 } 5853 5854 if (withIndex) 5855 { 5856 params ~= "size_t"; 5857 } 5858 5859 foreach (idx, Range; Ranges) 5860 { 5861 params ~= format("%sElementType!(Ranges[%s])", hasLvalueElements!Range ? "ref " : "", idx); 5862 } 5863 5864 return format( 5865 q{ 5866 int opApplyReverse()(scope int delegate(%s) dg) 5867 { 5868 static assert(false, "%s"); 5869 } 5870 }, params.join(", "), message); 5871} 5872 5873// For generic programming, make sure Lockstep!(Range) is well defined for a 5874// single range. 5875template Lockstep(Range) 5876{ 5877 alias Lockstep = Range; 5878} 5879 5880/** 5881Creates a mathematical sequence given the initial values and a 5882recurrence function that computes the next value from the existing 5883values. The sequence comes in the form of an infinite forward 5884range. The type `Recurrence` itself is seldom used directly; most 5885often, recurrences are obtained by calling the function $(D 5886recurrence). 5887 5888When calling `recurrence`, the function that computes the next 5889value is specified as a template argument, and the initial values in 5890the recurrence are passed as regular arguments. For example, in a 5891Fibonacci sequence, there are two initial values (and therefore a 5892state size of 2) because computing the next Fibonacci value needs the 5893past two values. 5894 5895The signature of this function should be: 5896---- 5897auto fun(R)(R state, size_t n) 5898---- 5899where `n` will be the index of the current value, and `state` will be an 5900opaque state vector that can be indexed with array-indexing notation 5901`state[i]`, where valid values of `i` range from $(D (n - 1)) to 5902$(D (n - State.length)). 5903 5904If the function is passed in string form, the state has name `"a"` 5905and the zero-based index in the recurrence has name `"n"`. The 5906given string must return the desired value for `a[n]` given 5907`a[n - 1]`, `a[n - 2]`, `a[n - 3]`,..., `a[n - stateSize]`. The 5908state size is dictated by the number of arguments passed to the call 5909to `recurrence`. The `Recurrence` struct itself takes care of 5910managing the recurrence's state and shifting it appropriately. 5911 */ 5912struct Recurrence(alias fun, StateType, size_t stateSize) 5913{ 5914 import std.functional : binaryFun; 5915 5916 StateType[stateSize] _state; 5917 size_t _n; 5918 5919 this(StateType[stateSize] initial) { _state = initial; } 5920 5921 void popFront() 5922 { 5923 static auto trustedCycle(ref typeof(_state) s) @trusted 5924 { 5925 return cycle(s); 5926 } 5927 // The cast here is reasonable because fun may cause integer 5928 // promotion, but needs to return a StateType to make its operation 5929 // closed. Therefore, we have no other choice. 5930 _state[_n % stateSize] = cast(StateType) binaryFun!(fun, "a", "n")( 5931 trustedCycle(_state), _n + stateSize); 5932 ++_n; 5933 } 5934 5935 @property StateType front() 5936 { 5937 return _state[_n % stateSize]; 5938 } 5939 5940 @property typeof(this) save() 5941 { 5942 return this; 5943 } 5944 5945 enum bool empty = false; 5946} 5947 5948/// 5949pure @safe nothrow unittest 5950{ 5951 import std.algorithm.comparison : equal; 5952 5953 // The Fibonacci numbers, using function in string form: 5954 // a[0] = 1, a[1] = 1, and compute a[n+1] = a[n-1] + a[n] 5955 auto fib = recurrence!("a[n-1] + a[n-2]")(1, 1); 5956 assert(fib.take(10).equal([1, 1, 2, 3, 5, 8, 13, 21, 34, 55])); 5957 5958 // The factorials, using function in lambda form: 5959 auto fac = recurrence!((a,n) => a[n-1] * n)(1); 5960 assert(take(fac, 10).equal([ 5961 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880 5962 ])); 5963 5964 // The triangular numbers, using function in explicit form: 5965 static size_t genTriangular(R)(R state, size_t n) 5966 { 5967 return state[n-1] + n; 5968 } 5969 auto tri = recurrence!genTriangular(0); 5970 assert(take(tri, 10).equal([0, 1, 3, 6, 10, 15, 21, 28, 36, 45])); 5971} 5972 5973/// Ditto 5974Recurrence!(fun, CommonType!(State), State.length) 5975recurrence(alias fun, State...)(State initial) 5976{ 5977 CommonType!(State)[State.length] state; 5978 foreach (i, Unused; State) 5979 { 5980 state[i] = initial[i]; 5981 } 5982 return typeof(return)(state); 5983} 5984 5985pure @safe nothrow unittest 5986{ 5987 import std.algorithm.comparison : equal; 5988 5989 auto fib = recurrence!("a[n-1] + a[n-2]")(1, 1); 5990 static assert(isForwardRange!(typeof(fib))); 5991 5992 int[] witness = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55 ]; 5993 assert(equal(take(fib, 10), witness)); 5994 foreach (e; take(fib, 10)) {} 5995 auto fact = recurrence!("n * a[n-1]")(1); 5996 assert( equal(take(fact, 10), [1, 1, 2, 2*3, 2*3*4, 2*3*4*5, 2*3*4*5*6, 5997 2*3*4*5*6*7, 2*3*4*5*6*7*8, 2*3*4*5*6*7*8*9][]) ); 5998 auto piapprox = recurrence!("a[n] + (n & 1 ? 4.0 : -4.0) / (2 * n + 3)")(4.0); 5999 foreach (e; take(piapprox, 20)) {} 6000 // Thanks to yebblies for this test and the associated fix 6001 auto r = recurrence!"a[n-2]"(1, 2); 6002 witness = [1, 2, 1, 2, 1]; 6003 assert(equal(take(r, 5), witness)); 6004} 6005 6006/** 6007 `Sequence` is similar to `Recurrence` except that iteration is 6008 presented in the so-called $(HTTP en.wikipedia.org/wiki/Closed_form, 6009 closed form). This means that the `n`th element in the series is 6010 computable directly from the initial values and `n` itself. This 6011 implies that the interface offered by `Sequence` is a random-access 6012 range, as opposed to the regular `Recurrence`, which only offers 6013 forward iteration. 6014 6015 The state of the sequence is stored as a `Tuple` so it can be 6016 heterogeneous. 6017*/ 6018struct Sequence(alias fun, State) 6019{ 6020private: 6021 import std.functional : binaryFun; 6022 6023 alias compute = binaryFun!(fun, "a", "n"); 6024 alias ElementType = typeof(compute(State.init, cast(size_t) 1)); 6025 State _state; 6026 size_t _n; 6027 6028 static struct DollarToken{} 6029 6030public: 6031 this(State initial, size_t n = 0) 6032 { 6033 _state = initial; 6034 _n = n; 6035 } 6036 6037 @property ElementType front() 6038 { 6039 return compute(_state, _n); 6040 } 6041 6042 void popFront() 6043 { 6044 ++_n; 6045 } 6046 6047 enum opDollar = DollarToken(); 6048 6049 auto opSlice(size_t lower, size_t upper) 6050 in 6051 { 6052 assert( 6053 upper >= lower, 6054 "Attempting to slice a Sequence with a larger first argument than the second." 6055 ); 6056 } 6057 do 6058 { 6059 return typeof(this)(_state, _n + lower).take(upper - lower); 6060 } 6061 6062 auto opSlice(size_t lower, DollarToken) 6063 { 6064 return typeof(this)(_state, _n + lower); 6065 } 6066 6067 ElementType opIndex(size_t n) 6068 { 6069 return compute(_state, n + _n); 6070 } 6071 6072 enum bool empty = false; 6073 6074 @property Sequence save() { return this; } 6075} 6076 6077/// Ditto 6078auto sequence(alias fun, State...)(State args) 6079{ 6080 import std.typecons : Tuple, tuple; 6081 alias Return = Sequence!(fun, Tuple!State); 6082 return Return(tuple(args)); 6083} 6084 6085/// Odd numbers, using function in string form: 6086pure @safe nothrow @nogc unittest 6087{ 6088 auto odds = sequence!("a[0] + n * a[1]")(1, 2); 6089 assert(odds.front == 1); 6090 odds.popFront(); 6091 assert(odds.front == 3); 6092 odds.popFront(); 6093 assert(odds.front == 5); 6094} 6095 6096/// Triangular numbers, using function in lambda form: 6097pure @safe nothrow @nogc unittest 6098{ 6099 auto tri = sequence!((a,n) => n*(n+1)/2)(); 6100 6101 // Note random access 6102 assert(tri[0] == 0); 6103 assert(tri[3] == 6); 6104 assert(tri[1] == 1); 6105 assert(tri[4] == 10); 6106 assert(tri[2] == 3); 6107} 6108 6109/// Fibonacci numbers, using function in explicit form: 6110@safe nothrow @nogc unittest 6111{ 6112 import std.math.exponential : pow; 6113 import std.math.rounding : round; 6114 import std.math.algebraic : sqrt; 6115 static ulong computeFib(S)(S state, size_t n) 6116 { 6117 // Binet's formula 6118 return cast(ulong)(round((pow(state[0], n+1) - pow(state[1], n+1)) / 6119 state[2])); 6120 } 6121 auto fib = sequence!computeFib( 6122 (1.0 + sqrt(5.0)) / 2.0, // Golden Ratio 6123 (1.0 - sqrt(5.0)) / 2.0, // Conjugate of Golden Ratio 6124 sqrt(5.0)); 6125 6126 // Note random access with [] operator 6127 assert(fib[1] == 1); 6128 assert(fib[4] == 5); 6129 assert(fib[3] == 3); 6130 assert(fib[2] == 2); 6131 assert(fib[9] == 55); 6132} 6133 6134pure @safe nothrow @nogc unittest 6135{ 6136 import std.typecons : Tuple, tuple; 6137 auto y = Sequence!("a[0] + n * a[1]", Tuple!(int, int))(tuple(0, 4)); 6138 static assert(isForwardRange!(typeof(y))); 6139 6140 //@@BUG 6141 //auto y = sequence!("a[0] + n * a[1]")(0, 4); 6142 //foreach (e; take(y, 15)) 6143 {} //writeln(e); 6144 6145 auto odds = Sequence!("a[0] + n * a[1]", Tuple!(int, int))( 6146 tuple(1, 2)); 6147 for (int currentOdd = 1; currentOdd <= 21; currentOdd += 2) 6148 { 6149 assert(odds.front == odds[0]); 6150 assert(odds[0] == currentOdd); 6151 odds.popFront(); 6152 } 6153} 6154 6155pure @safe nothrow @nogc unittest 6156{ 6157 import std.algorithm.comparison : equal; 6158 6159 auto odds = sequence!("a[0] + n * a[1]")(1, 2); 6160 static assert(hasSlicing!(typeof(odds))); 6161 6162 //Note: don't use drop or take as the target of an equal, 6163 //since they'll both just forward to opSlice, making the tests irrelevant 6164 6165 // static slicing tests 6166 assert(equal(odds[0 .. 5], only(1, 3, 5, 7, 9))); 6167 assert(equal(odds[3 .. 7], only(7, 9, 11, 13))); 6168 6169 // relative slicing test, testing slicing is NOT agnostic of state 6170 auto odds_less5 = odds.drop(5); //this should actually call odds[5 .. $] 6171 assert(equal(odds_less5[0 .. 3], only(11, 13, 15))); 6172 assert(equal(odds_less5[0 .. 10], odds[5 .. 15])); 6173 6174 //Infinite slicing tests 6175 odds = odds[10 .. $]; 6176 assert(equal(odds.take(3), only(21, 23, 25))); 6177} 6178 6179// https://issues.dlang.org/show_bug.cgi?id=5036 6180pure @safe nothrow unittest 6181{ 6182 auto s = sequence!((a, n) => new int)(0); 6183 assert(s.front != s.front); // no caching 6184} 6185 6186// iota 6187/** 6188 Creates a range of values that span the given starting and stopping 6189 values. 6190 6191 Params: 6192 begin = The starting value. 6193 end = The value that serves as the stopping criterion. This value is not 6194 included in the range. 6195 step = The value to add to the current value at each iteration. 6196 6197 Returns: 6198 A range that goes through the numbers `begin`, $(D begin + step), 6199 $(D begin + 2 * step), `...`, up to and excluding `end`. 6200 6201 The two-argument overloads have $(D step = 1). If $(D begin < end && step < 6202 0) or $(D begin > end && step > 0) or $(D begin == end), then an empty range 6203 is returned. If $(D step == 0) then $(D begin == end) is an error. 6204 6205 For built-in types, the range returned is a random access range. For 6206 user-defined types that support `++`, the range is an input 6207 range. 6208 6209 An integral iota also supports `in` operator from the right. It takes 6210 the stepping into account, the integral won't be considered 6211 contained if it falls between two consecutive values of the range. 6212 `contains` does the same as in, but from lefthand side. 6213 6214 Example: 6215 --- 6216 void main() 6217 { 6218 import std.stdio; 6219 6220 // The following groups all produce the same output of: 6221 // 0 1 2 3 4 6222 6223 foreach (i; 0 .. 5) 6224 writef("%s ", i); 6225 writeln(); 6226 6227 import std.range : iota; 6228 foreach (i; iota(0, 5)) 6229 writef("%s ", i); 6230 writeln(); 6231 6232 writefln("%(%s %|%)", iota(0, 5)); 6233 6234 import std.algorithm.iteration : map; 6235 import std.algorithm.mutation : copy; 6236 import std.format; 6237 iota(0, 5).map!(i => format("%s ", i)).copy(stdout.lockingTextWriter()); 6238 writeln(); 6239 } 6240 --- 6241*/ 6242auto iota(B, E, S)(B begin, E end, S step) 6243if ((isIntegral!(CommonType!(B, E)) || isPointer!(CommonType!(B, E))) 6244 && isIntegral!S) 6245{ 6246 import std.conv : unsigned; 6247 6248 alias Value = CommonType!(Unqual!B, Unqual!E); 6249 alias StepType = Unqual!S; 6250 6251 assert(step != 0 || begin == end); 6252 6253 static struct Result 6254 { 6255 private Value current, last; 6256 private StepType step; // by convention, 0 if range is empty 6257 6258 this(Value current, Value pastLast, StepType step) 6259 { 6260 if (current < pastLast && step > 0) 6261 { 6262 // Iterating upward 6263 assert(unsigned((pastLast - current) / step) <= size_t.max); 6264 // Cast below can't fail because current < pastLast 6265 this.last = cast(Value) (pastLast - 1); 6266 this.last -= unsigned(this.last - current) % step; 6267 } 6268 else if (current > pastLast && step < 0) 6269 { 6270 // Iterating downward 6271 assert(unsigned((current - pastLast) / (0 - step)) <= size_t.max); 6272 // Cast below can't fail because current > pastLast 6273 this.last = cast(Value) (pastLast + 1); 6274 this.last += unsigned(current - this.last) % (0 - step); 6275 } 6276 else 6277 { 6278 // Initialize an empty range 6279 this.step = 0; 6280 return; 6281 } 6282 this.step = step; 6283 this.current = current; 6284 } 6285 6286 @property bool empty() const { return step == 0; } 6287 @property inout(Value) front() inout { assert(!empty); return current; } 6288 void popFront() 6289 { 6290 assert(!empty); 6291 if (current == last) step = 0; 6292 else current += step; 6293 } 6294 6295 @property inout(Value) back() inout 6296 { 6297 assert(!empty); 6298 return last; 6299 } 6300 void popBack() 6301 { 6302 assert(!empty); 6303 if (current == last) step = 0; 6304 else last -= step; 6305 } 6306 6307 @property auto save() { return this; } 6308 6309 inout(Value) opIndex(ulong n) inout 6310 { 6311 assert(n < this.length); 6312 6313 // Just cast to Value here because doing so gives overflow behavior 6314 // consistent with calling popFront() n times. 6315 return cast(inout Value) (current + step * n); 6316 } 6317 auto opBinaryRight(string op)(Value val) const 6318 if (op == "in") 6319 { 6320 if (empty) return false; 6321 //cast to avoid becoming unsigned 6322 auto supposedIndex = cast(StepType)(val - current) / step; 6323 return supposedIndex < length && supposedIndex * step + current == val; 6324 } 6325 auto contains(Value x){return x in this;} 6326 inout(Result) opSlice() inout { return this; } 6327 inout(Result) opSlice(ulong lower, ulong upper) inout 6328 { 6329 assert(upper >= lower && upper <= this.length); 6330 6331 return cast(inout Result) Result( 6332 cast(Value)(current + lower * step), 6333 cast(Value)(current + upper * step), 6334 step); 6335 } 6336 @property size_t length() const 6337 { 6338 if (step > 0) 6339 return 1 + cast(size_t) (unsigned(last - current) / step); 6340 if (step < 0) 6341 return 1 + cast(size_t) (unsigned(current - last) / (0 - step)); 6342 return 0; 6343 } 6344 6345 alias opDollar = length; 6346 } 6347 6348 return Result(begin, end, step); 6349} 6350 6351/// Ditto 6352auto iota(B, E)(B begin, E end) 6353if (isFloatingPoint!(CommonType!(B, E))) 6354{ 6355 return iota(begin, end, CommonType!(B, E)(1)); 6356} 6357 6358/// Ditto 6359auto iota(B, E)(B begin, E end) 6360if (isIntegral!(CommonType!(B, E)) || isPointer!(CommonType!(B, E))) 6361{ 6362 import std.conv : unsigned; 6363 6364 alias Value = CommonType!(Unqual!B, Unqual!E); 6365 6366 static struct Result 6367 { 6368 private Value current, pastLast; 6369 6370 this(Value current, Value pastLast) 6371 { 6372 if (current < pastLast) 6373 { 6374 assert(unsigned(pastLast - current) <= size_t.max, 6375 "`iota` range is too long"); 6376 6377 this.current = current; 6378 this.pastLast = pastLast; 6379 } 6380 else 6381 { 6382 // Initialize an empty range 6383 this.current = this.pastLast = current; 6384 } 6385 } 6386 6387 @property bool empty() const { return current == pastLast; } 6388 @property inout(Value) front() inout 6389 { 6390 assert(!empty, "Attempt to access `front` of empty `iota` range"); 6391 return current; 6392 } 6393 void popFront() 6394 { 6395 assert(!empty, "Attempt to `popFront` of empty `iota` range"); 6396 ++current; 6397 } 6398 6399 @property inout(Value) back() inout 6400 { 6401 assert(!empty, "Attempt to access `back` of empty `iota` range"); 6402 return cast(inout(Value))(pastLast - 1); 6403 } 6404 void popBack() 6405 { 6406 assert(!empty, "Attempt to `popBack` of empty `iota` range"); 6407 --pastLast; 6408 } 6409 6410 @property auto save() { return this; } 6411 6412 inout(Value) opIndex(size_t n) inout 6413 { 6414 assert(n < this.length, 6415 "Attempt to read out-of-bounds index of `iota` range"); 6416 6417 // Just cast to Value here because doing so gives overflow behavior 6418 // consistent with calling popFront() n times. 6419 return cast(inout Value) (current + n); 6420 } 6421 auto opBinaryRight(string op)(Value val) const 6422 if (op == "in") 6423 { 6424 return current <= val && val < pastLast; 6425 } 6426 auto contains(Value x){return x in this;} 6427 inout(Result) opSlice() inout { return this; } 6428 inout(Result) opSlice(ulong lower, ulong upper) inout 6429 { 6430 assert(upper >= lower && upper <= this.length, 6431 "Attempt to get out-of-bounds slice of `iota` range"); 6432 6433 return cast(inout Result) Result(cast(Value)(current + lower), 6434 cast(Value)(pastLast - (length - upper))); 6435 } 6436 @property size_t length() const 6437 { 6438 return cast(size_t)(pastLast - current); 6439 } 6440 6441 alias opDollar = length; 6442 } 6443 6444 return Result(begin, end); 6445} 6446 6447/// Ditto 6448auto iota(E)(E end) 6449if (is(typeof(iota(E(0), end)))) 6450{ 6451 E begin = E(0); 6452 return iota(begin, end); 6453} 6454 6455/// Ditto 6456// Specialization for floating-point types 6457auto iota(B, E, S)(B begin, E end, S step) 6458if (isFloatingPoint!(CommonType!(B, E, S))) 6459in 6460{ 6461 assert(step != 0, "iota: step must not be 0"); 6462 assert((end - begin) / step >= 0, "iota: incorrect startup parameters"); 6463} 6464do 6465{ 6466 alias Value = Unqual!(CommonType!(B, E, S)); 6467 static struct Result 6468 { 6469 private Value start, step; 6470 private size_t index, count; 6471 6472 this(Value start, Value end, Value step) 6473 { 6474 import std.conv : to; 6475 6476 this.start = start; 6477 this.step = step; 6478 immutable fcount = (end - start) / step; 6479 count = to!size_t(fcount); 6480 auto pastEnd = start + count * step; 6481 if (step > 0) 6482 { 6483 if (pastEnd < end) ++count; 6484 assert(start + count * step >= end); 6485 } 6486 else 6487 { 6488 if (pastEnd > end) ++count; 6489 assert(start + count * step <= end); 6490 } 6491 } 6492 6493 @property bool empty() const { return index == count; } 6494 @property Value front() const { assert(!empty); return start + step * index; } 6495 void popFront() 6496 { 6497 assert(!empty); 6498 ++index; 6499 } 6500 @property Value back() const 6501 { 6502 assert(!empty); 6503 return start + step * (count - 1); 6504 } 6505 void popBack() 6506 { 6507 assert(!empty); 6508 --count; 6509 } 6510 6511 @property auto save() { return this; } 6512 6513 Value opIndex(size_t n) const 6514 { 6515 assert(n < count); 6516 return start + step * (n + index); 6517 } 6518 inout(Result) opSlice() inout 6519 { 6520 return this; 6521 } 6522 inout(Result) opSlice(size_t lower, size_t upper) inout 6523 { 6524 assert(upper >= lower && upper <= count); 6525 6526 Result ret = this; 6527 ret.index += lower; 6528 ret.count = upper - lower + ret.index; 6529 return cast(inout Result) ret; 6530 } 6531 @property size_t length() const 6532 { 6533 return count - index; 6534 } 6535 6536 alias opDollar = length; 6537 } 6538 6539 return Result(begin, end, step); 6540} 6541 6542/// 6543pure @safe unittest 6544{ 6545 import std.algorithm.comparison : equal; 6546 import std.math.operations : isClose; 6547 6548 auto r = iota(0, 10, 1); 6549 assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])); 6550 assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])); 6551 assert(3 in r); 6552 assert(r.contains(3)); //Same as above 6553 assert(!(10 in r)); 6554 assert(!(-8 in r)); 6555 r = iota(0, 11, 3); 6556 assert(equal(r, [0, 3, 6, 9])); 6557 assert(r[2] == 6); 6558 assert(!(2 in r)); 6559 auto rf = iota(0.0, 0.5, 0.1); 6560 assert(isClose(rf, [0.0, 0.1, 0.2, 0.3, 0.4])); 6561} 6562 6563pure nothrow @nogc @safe unittest 6564{ 6565 import std.traits : Signed; 6566 //float overloads use std.conv.to so can't be @nogc or nothrow 6567 alias ssize_t = Signed!size_t; 6568 assert(iota(ssize_t.max, 0, -1).length == ssize_t.max); 6569 assert(iota(ssize_t.max, ssize_t.min, -1).length == size_t.max); 6570 assert(iota(ssize_t.max, ssize_t.min, -2).length == 1 + size_t.max / 2); 6571 assert(iota(ssize_t.min, ssize_t.max, 2).length == 1 + size_t.max / 2); 6572 assert(iota(ssize_t.max, ssize_t.min, -3).length == size_t.max / 3); 6573} 6574 6575debug @system unittest 6576{//check the contracts 6577 import core.exception : AssertError; 6578 import std.exception : assertThrown; 6579 assertThrown!AssertError(iota(1,2,0)); 6580 assertThrown!AssertError(iota(0f,1f,0f)); 6581 assertThrown!AssertError(iota(1f,0f,0.1f)); 6582 assertThrown!AssertError(iota(0f,1f,-0.1f)); 6583} 6584 6585pure @system nothrow unittest 6586{ 6587 int[] a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; 6588 auto r1 = iota(a.ptr, a.ptr + a.length, 1); 6589 assert(r1.front == a.ptr); 6590 assert(r1.back == a.ptr + a.length - 1); 6591 assert(&a[4] in r1); 6592} 6593 6594pure @safe nothrow @nogc unittest 6595{ 6596 assert(iota(1UL, 0UL).length == 0); 6597 assert(iota(1UL, 0UL, 1).length == 0); 6598 assert(iota(0, 1, 1).length == 1); 6599 assert(iota(1, 0, -1).length == 1); 6600 assert(iota(0, 1, -1).length == 0); 6601 assert(iota(ulong.max, 0).length == 0); 6602} 6603 6604pure @safe unittest 6605{ 6606 import std.algorithm.comparison : equal; 6607 import std.algorithm.searching : count; 6608 import std.math.operations : isClose, nextUp, nextDown; 6609 import std.meta : AliasSeq; 6610 6611 static assert(is(ElementType!(typeof(iota(0f))) == float)); 6612 6613 static assert(hasLength!(typeof(iota(0, 2)))); 6614 auto r = iota(0, 10, 1); 6615 assert(r[$ - 1] == 9); 6616 assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][])); 6617 6618 auto rSlice = r[2 .. 8]; 6619 assert(equal(rSlice, [2, 3, 4, 5, 6, 7])); 6620 6621 rSlice.popFront(); 6622 assert(rSlice[0] == rSlice.front); 6623 assert(rSlice.front == 3); 6624 6625 rSlice.popBack(); 6626 assert(rSlice[rSlice.length - 1] == rSlice.back); 6627 assert(rSlice.back == 6); 6628 6629 rSlice = r[0 .. 4]; 6630 assert(equal(rSlice, [0, 1, 2, 3])); 6631 assert(3 in rSlice); 6632 assert(!(4 in rSlice)); 6633 6634 auto rr = iota(10); 6635 assert(equal(rr, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][])); 6636 6637 r = iota(0, -10, -1); 6638 assert(equal(r, [0, -1, -2, -3, -4, -5, -6, -7, -8, -9][])); 6639 rSlice = r[3 .. 9]; 6640 assert(equal(rSlice, [-3, -4, -5, -6, -7, -8])); 6641 6642 r = iota(0, -6, -3); 6643 assert(equal(r, [0, -3][])); 6644 rSlice = r[1 .. 2]; 6645 assert(equal(rSlice, [-3])); 6646 6647 r = iota(0, -7, -3); 6648 assert(equal(r, [0, -3, -6][])); 6649 assert(0 in r); 6650 assert(-6 in r); 6651 rSlice = r[1 .. 3]; 6652 assert(equal(rSlice, [-3, -6])); 6653 assert(!(0 in rSlice)); 6654 assert(!(-2 in rSlice)); 6655 assert(!(-5 in rSlice)); 6656 assert(!(3 in rSlice)); 6657 assert(!(-9 in rSlice)); 6658 6659 r = iota(0, 11, 3); 6660 assert(equal(r, [0, 3, 6, 9][])); 6661 assert(r[2] == 6); 6662 rSlice = r[1 .. 3]; 6663 assert(equal(rSlice, [3, 6])); 6664 6665 auto rf = iota(0.0, 0.5, 0.1); 6666 assert(isClose(rf, [0.0, 0.1, 0.2, 0.3, 0.4][])); 6667 assert(rf.length == 5); 6668 6669 rf.popFront(); 6670 assert(rf.length == 4); 6671 6672 auto rfSlice = rf[1 .. 4]; 6673 assert(rfSlice.length == 3); 6674 assert(isClose(rfSlice, [0.2, 0.3, 0.4])); 6675 6676 rfSlice.popFront(); 6677 assert(isClose(rfSlice[0], 0.3)); 6678 6679 rf.popFront(); 6680 assert(rf.length == 3); 6681 6682 rfSlice = rf[1 .. 3]; 6683 assert(rfSlice.length == 2); 6684 assert(isClose(rfSlice, [0.3, 0.4])); 6685 assert(isClose(rfSlice[0], 0.3)); 6686 6687 // With something just above 0.5 6688 rf = iota(0.0, nextUp(0.5), 0.1); 6689 assert(isClose(rf, [0.0, 0.1, 0.2, 0.3, 0.4, 0.5][])); 6690 rf.popBack(); 6691 assert(rf[rf.length - 1] == rf.back); 6692 assert(isClose(rf.back, 0.4)); 6693 assert(rf.length == 5); 6694 6695 // going down 6696 rf = iota(0.0, -0.5, -0.1); 6697 assert(isClose(rf, [0.0, -0.1, -0.2, -0.3, -0.4][])); 6698 rfSlice = rf[2 .. 5]; 6699 assert(isClose(rfSlice, [-0.2, -0.3, -0.4])); 6700 6701 rf = iota(0.0, nextDown(-0.5), -0.1); 6702 assert(isClose(rf, [0.0, -0.1, -0.2, -0.3, -0.4, -0.5][])); 6703 6704 // iota of longs 6705 auto rl = iota(5_000_000L); 6706 assert(rl.length == 5_000_000L); 6707 assert(0 in rl); 6708 assert(4_000_000L in rl); 6709 assert(!(-4_000_000L in rl)); 6710 assert(!(5_000_000L in rl)); 6711 6712 // iota of longs with steps 6713 auto iota_of_longs_with_steps = iota(50L, 101L, 10); 6714 assert(iota_of_longs_with_steps.length == 6); 6715 assert(equal(iota_of_longs_with_steps, [50L, 60L, 70L, 80L, 90L, 100L])); 6716 6717 // iota of unsigned zero length (https://issues.dlang.org/show_bug.cgi?id=6222) 6718 // Actually trying to consume it is the only way to find something is wrong 6719 // because the public properties are all correct. 6720 auto iota_zero_unsigned = iota(0, 0u, 3); 6721 assert(count(iota_zero_unsigned) == 0); 6722 6723 // https://issues.dlang.org/show_bug.cgi?id=7982 6724 // unsigned reverse iota can be buggy if `.length` doesn't 6725 // take them into account 6726 assert(iota(10u, 0u, -1).length == 10); 6727 assert(iota(10u, 0u, -2).length == 5); 6728 assert(iota(uint.max, uint.max-10, -1).length == 10); 6729 assert(iota(uint.max, uint.max-10, -2).length == 5); 6730 assert(iota(uint.max, 0u, -1).length == uint.max); 6731 6732 assert(20 in iota(20u, 10u, -2)); 6733 assert(16 in iota(20u, 10u, -2)); 6734 assert(!(15 in iota(20u, 10u, -2))); 6735 assert(!(10 in iota(20u, 10u, -2))); 6736 assert(!(uint.max in iota(20u, 10u, -1))); 6737 assert(!(int.min in iota(20u, 10u, -1))); 6738 assert(!(int.max in iota(20u, 10u, -1))); 6739 6740 6741 // https://issues.dlang.org/show_bug.cgi?id=8920 6742 static foreach (Type; AliasSeq!(byte, ubyte, short, ushort, 6743 int, uint, long, ulong)) 6744 {{ 6745 Type val; 6746 foreach (i; iota(cast(Type) 0, cast(Type) 10)) { val++; } 6747 assert(val == 10); 6748 }} 6749} 6750 6751pure @safe nothrow unittest 6752{ 6753 import std.algorithm.mutation : copy; 6754 auto idx = new size_t[100]; 6755 copy(iota(0, idx.length), idx); 6756} 6757 6758@safe unittest 6759{ 6760 import std.meta : AliasSeq; 6761 static foreach (range; AliasSeq!(iota(2, 27, 4), 6762 iota(3, 9), 6763 iota(2.7, 12.3, .1), 6764 iota(3.2, 9.7))) 6765 {{ 6766 const cRange = range; 6767 const e = cRange.empty; 6768 const f = cRange.front; 6769 const b = cRange.back; 6770 const i = cRange[2]; 6771 const s1 = cRange[]; 6772 const s2 = cRange[0 .. 3]; 6773 const l = cRange.length; 6774 }} 6775} 6776 6777@system unittest 6778{ 6779 //The ptr stuff can't be done at compile time, so we unfortunately end 6780 //up with some code duplication here. 6781 auto arr = [0, 5, 3, 5, 5, 7, 9, 2, 0, 42, 7, 6]; 6782 6783 { 6784 const cRange = iota(arr.ptr, arr.ptr + arr.length, 3); 6785 const e = cRange.empty; 6786 const f = cRange.front; 6787 const b = cRange.back; 6788 const i = cRange[2]; 6789 const s1 = cRange[]; 6790 const s2 = cRange[0 .. 3]; 6791 const l = cRange.length; 6792 } 6793 6794 { 6795 const cRange = iota(arr.ptr, arr.ptr + arr.length); 6796 const e = cRange.empty; 6797 const f = cRange.front; 6798 const b = cRange.back; 6799 const i = cRange[2]; 6800 const s1 = cRange[]; 6801 const s2 = cRange[0 .. 3]; 6802 const l = cRange.length; 6803 } 6804} 6805 6806@nogc nothrow pure @safe unittest 6807{ 6808 { 6809 ushort start = 0, end = 10, step = 2; 6810 foreach (i; iota(start, end, step)) 6811 static assert(is(typeof(i) == ushort)); 6812 } 6813 { 6814 ubyte start = 0, end = 255, step = 128; 6815 uint x; 6816 foreach (i; iota(start, end, step)) 6817 { 6818 static assert(is(typeof(i) == ubyte)); 6819 ++x; 6820 } 6821 assert(x == 2); 6822 } 6823} 6824 6825/* Generic overload that handles arbitrary types that support arithmetic 6826 * operations. 6827 * 6828 * User-defined types such as $(REF BigInt, std,bigint) are also supported, as long 6829 * as they can be incremented with `++` and compared with `<` or `==`. 6830 */ 6831/// ditto 6832auto iota(B, E)(B begin, E end) 6833if (!isIntegral!(CommonType!(B, E)) && 6834 !isFloatingPoint!(CommonType!(B, E)) && 6835 !isPointer!(CommonType!(B, E)) && 6836 is(typeof((ref B b) { ++b; })) && 6837 (is(typeof(B.init < E.init)) || is(typeof(B.init == E.init))) ) 6838{ 6839 static struct Result 6840 { 6841 B current; 6842 E end; 6843 6844 @property bool empty() 6845 { 6846 static if (is(typeof(B.init < E.init))) 6847 return !(current < end); 6848 else static if (is(typeof(B.init != E.init))) 6849 return current == end; 6850 else 6851 static assert(0); 6852 } 6853 @property auto front() { return current; } 6854 void popFront() 6855 { 6856 assert(!empty); 6857 ++current; 6858 } 6859 } 6860 return Result(begin, end); 6861} 6862 6863@safe unittest 6864{ 6865 import std.algorithm.comparison : equal; 6866 6867 // Test iota() for a type that only supports ++ and != but does not have 6868 // '<'-ordering. 6869 struct Cyclic(int wrapAround) 6870 { 6871 int current; 6872 6873 this(int start) { current = start % wrapAround; } 6874 6875 bool opEquals(Cyclic c) const { return current == c.current; } 6876 bool opEquals(int i) const { return current == i; } 6877 void opUnary(string op)() if (op == "++") 6878 { 6879 current = (current + 1) % wrapAround; 6880 } 6881 } 6882 alias Cycle5 = Cyclic!5; 6883 6884 // Easy case 6885 auto i1 = iota(Cycle5(1), Cycle5(4)); 6886 assert(i1.equal([1, 2, 3])); 6887 6888 // Wraparound case 6889 auto i2 = iota(Cycle5(3), Cycle5(2)); 6890 assert(i2.equal([3, 4, 0, 1 ])); 6891} 6892 6893/** 6894 Options for the $(LREF FrontTransversal) and $(LREF Transversal) ranges 6895 (below). 6896*/ 6897enum TransverseOptions 6898{ 6899/** 6900 When transversed, the elements of a range of ranges are assumed to 6901 have different lengths (e.g. a jagged array). 6902*/ 6903 assumeJagged, //default 6904 /** 6905 The transversal enforces that the elements of a range of ranges have 6906 all the same length (e.g. an array of arrays, all having the same 6907 length). Checking is done once upon construction of the transversal 6908 range. 6909 */ 6910 enforceNotJagged, 6911 /** 6912 The transversal assumes, without verifying, that the elements of a 6913 range of ranges have all the same length. This option is useful if 6914 checking was already done from the outside of the range. 6915 */ 6916 assumeNotJagged, 6917} 6918 6919/// 6920@safe pure unittest 6921{ 6922 import std.algorithm.comparison : equal; 6923 import std.exception : assertThrown; 6924 6925 auto arr = [[1, 2], [3, 4, 5]]; 6926 6927 auto r1 = arr.frontTransversal!(TransverseOptions.assumeJagged); 6928 assert(r1.equal([1, 3])); 6929 6930 // throws on construction 6931 assertThrown!Exception(arr.frontTransversal!(TransverseOptions.enforceNotJagged)); 6932 6933 auto r2 = arr.frontTransversal!(TransverseOptions.assumeNotJagged); 6934 assert(r2.equal([1, 3])); 6935 6936 // either assuming or checking for equal lengths makes 6937 // the result a random access range 6938 assert(r2[0] == 1); 6939 static assert(!__traits(compiles, r1[0])); 6940} 6941 6942/** 6943 Given a range of ranges, iterate transversally through the first 6944 elements of each of the enclosed ranges. 6945*/ 6946struct FrontTransversal(Ror, 6947 TransverseOptions opt = TransverseOptions.assumeJagged) 6948{ 6949 alias RangeOfRanges = Unqual!(Ror); 6950 alias RangeType = .ElementType!RangeOfRanges; 6951 alias ElementType = .ElementType!RangeType; 6952 6953 private void prime() 6954 { 6955 static if (opt == TransverseOptions.assumeJagged) 6956 { 6957 while (!_input.empty && _input.front.empty) 6958 { 6959 _input.popFront(); 6960 } 6961 static if (isBidirectionalRange!RangeOfRanges) 6962 { 6963 while (!_input.empty && _input.back.empty) 6964 { 6965 _input.popBack(); 6966 } 6967 } 6968 } 6969 } 6970 6971/** 6972 Construction from an input. 6973*/ 6974 this(RangeOfRanges input) 6975 { 6976 _input = input; 6977 prime(); 6978 static if (opt == TransverseOptions.enforceNotJagged) 6979 // (isRandomAccessRange!RangeOfRanges 6980 // && hasLength!RangeType) 6981 { 6982 import std.exception : enforce; 6983 6984 if (empty) return; 6985 immutable commonLength = _input.front.length; 6986 foreach (e; _input) 6987 { 6988 enforce(e.length == commonLength); 6989 } 6990 } 6991 } 6992 6993/** 6994 Forward range primitives. 6995*/ 6996 static if (isInfinite!RangeOfRanges) 6997 { 6998 enum bool empty = false; 6999 } 7000 else 7001 { 7002 @property bool empty() 7003 { 7004 static if (opt != TransverseOptions.assumeJagged) 7005 { 7006 if (!_input.empty) 7007 return _input.front.empty; 7008 } 7009 7010 return _input.empty; 7011 } 7012 } 7013 7014 /// Ditto 7015 @property auto ref front() 7016 { 7017 assert(!empty, "Attempting to fetch the front of an empty FrontTransversal"); 7018 return _input.front.front; 7019 } 7020 7021 /// Ditto 7022 static if (hasMobileElements!RangeType) 7023 { 7024 ElementType moveFront() 7025 { 7026 return _input.front.moveFront(); 7027 } 7028 } 7029 7030 static if (hasAssignableElements!RangeType) 7031 { 7032 @property void front(ElementType val) 7033 { 7034 _input.front.front = val; 7035 } 7036 } 7037 7038 /// Ditto 7039 void popFront() 7040 { 7041 assert(!empty, "Attempting to popFront an empty FrontTransversal"); 7042 _input.popFront(); 7043 prime(); 7044 } 7045 7046/** 7047 Duplicates this `frontTransversal`. Note that only the encapsulating 7048 range of range will be duplicated. Underlying ranges will not be 7049 duplicated. 7050*/ 7051 static if (isForwardRange!RangeOfRanges) 7052 { 7053 @property FrontTransversal save() 7054 { 7055 return FrontTransversal(_input.save); 7056 } 7057 } 7058 7059 static if (isBidirectionalRange!RangeOfRanges) 7060 { 7061/** 7062 Bidirectional primitives. They are offered if $(D 7063 isBidirectionalRange!RangeOfRanges). 7064*/ 7065 @property auto ref back() 7066 { 7067 assert(!empty, "Attempting to fetch the back of an empty FrontTransversal"); 7068 return _input.back.front; 7069 } 7070 /// Ditto 7071 void popBack() 7072 { 7073 assert(!empty, "Attempting to popBack an empty FrontTransversal"); 7074 _input.popBack(); 7075 prime(); 7076 } 7077 7078 /// Ditto 7079 static if (hasMobileElements!RangeType) 7080 { 7081 ElementType moveBack() 7082 { 7083 return _input.back.moveFront(); 7084 } 7085 } 7086 7087 static if (hasAssignableElements!RangeType) 7088 { 7089 @property void back(ElementType val) 7090 { 7091 _input.back.front = val; 7092 } 7093 } 7094 } 7095 7096 static if (isRandomAccessRange!RangeOfRanges && 7097 (opt == TransverseOptions.assumeNotJagged || 7098 opt == TransverseOptions.enforceNotJagged)) 7099 { 7100/** 7101 Random-access primitive. It is offered if $(D 7102 isRandomAccessRange!RangeOfRanges && (opt == 7103 TransverseOptions.assumeNotJagged || opt == 7104 TransverseOptions.enforceNotJagged)). 7105*/ 7106 auto ref opIndex(size_t n) 7107 { 7108 return _input[n].front; 7109 } 7110 7111 /// Ditto 7112 static if (hasMobileElements!RangeType) 7113 { 7114 ElementType moveAt(size_t n) 7115 { 7116 return _input[n].moveFront(); 7117 } 7118 } 7119 /// Ditto 7120 static if (hasAssignableElements!RangeType) 7121 { 7122 void opIndexAssign(ElementType val, size_t n) 7123 { 7124 _input[n].front = val; 7125 } 7126 } 7127 mixin ImplementLength!_input; 7128 7129/** 7130 Slicing if offered if `RangeOfRanges` supports slicing and all the 7131 conditions for supporting indexing are met. 7132*/ 7133 static if (hasSlicing!RangeOfRanges) 7134 { 7135 typeof(this) opSlice(size_t lower, size_t upper) 7136 { 7137 return typeof(this)(_input[lower .. upper]); 7138 } 7139 } 7140 } 7141 7142 auto opSlice() { return this; } 7143 7144private: 7145 RangeOfRanges _input; 7146} 7147 7148/// Ditto 7149FrontTransversal!(RangeOfRanges, opt) frontTransversal( 7150 TransverseOptions opt = TransverseOptions.assumeJagged, 7151 RangeOfRanges) 7152(RangeOfRanges rr) 7153{ 7154 return typeof(return)(rr); 7155} 7156 7157/// 7158pure @safe nothrow unittest 7159{ 7160 import std.algorithm.comparison : equal; 7161 int[][] x = new int[][2]; 7162 x[0] = [1, 2]; 7163 x[1] = [3, 4]; 7164 auto ror = frontTransversal(x); 7165 assert(equal(ror, [ 1, 3 ][])); 7166} 7167 7168@safe unittest 7169{ 7170 import std.algorithm.comparison : equal; 7171 import std.internal.test.dummyrange : AllDummyRanges, DummyRange, ReturnBy; 7172 7173 static assert(is(FrontTransversal!(immutable int[][]))); 7174 7175 foreach (DummyType; AllDummyRanges) 7176 { 7177 auto dummies = 7178 [DummyType.init, DummyType.init, DummyType.init, DummyType.init]; 7179 7180 foreach (i, ref elem; dummies) 7181 { 7182 // Just violate the DummyRange abstraction to get what I want. 7183 elem.arr = elem.arr[i..$ - (3 - i)]; 7184 } 7185 7186 auto ft = frontTransversal!(TransverseOptions.assumeNotJagged)(dummies); 7187 static if (isForwardRange!DummyType) 7188 { 7189 static assert(isForwardRange!(typeof(ft))); 7190 } 7191 7192 assert(equal(ft, [1, 2, 3, 4])); 7193 7194 // Test slicing. 7195 assert(equal(ft[0 .. 2], [1, 2])); 7196 assert(equal(ft[1 .. 3], [2, 3])); 7197 7198 assert(ft.front == ft.moveFront()); 7199 assert(ft.back == ft.moveBack()); 7200 assert(ft.moveAt(1) == ft[1]); 7201 7202 7203 // Test infiniteness propagation. 7204 static assert(isInfinite!(typeof(frontTransversal(repeat("foo"))))); 7205 7206 static if (DummyType.r == ReturnBy.Reference) 7207 { 7208 { 7209 ft.front++; 7210 scope(exit) ft.front--; 7211 assert(dummies.front.front == 2); 7212 } 7213 7214 { 7215 ft.front = 5; 7216 scope(exit) ft.front = 1; 7217 assert(dummies[0].front == 5); 7218 } 7219 7220 { 7221 ft.back = 88; 7222 scope(exit) ft.back = 4; 7223 assert(dummies.back.front == 88); 7224 } 7225 7226 { 7227 ft[1] = 99; 7228 scope(exit) ft[1] = 2; 7229 assert(dummies[1].front == 99); 7230 } 7231 } 7232 } 7233} 7234 7235// https://issues.dlang.org/show_bug.cgi?id=16363 7236pure @safe nothrow unittest 7237{ 7238 import std.algorithm.comparison : equal; 7239 7240 int[][] darr = [[0, 1], [4, 5]]; 7241 auto ft = frontTransversal!(TransverseOptions.assumeNotJagged)(darr); 7242 7243 assert(equal(ft, [0, 4])); 7244 static assert(isRandomAccessRange!(typeof(ft))); 7245} 7246 7247// https://issues.dlang.org/show_bug.cgi?id=16442 7248pure @safe nothrow unittest 7249{ 7250 int[][] arr = [[], []]; 7251 7252 auto ft = frontTransversal!(TransverseOptions.assumeNotJagged)(arr); 7253 assert(ft.empty); 7254} 7255 7256// ditto 7257pure @safe unittest 7258{ 7259 int[][] arr = [[], []]; 7260 7261 auto ft = frontTransversal!(TransverseOptions.enforceNotJagged)(arr); 7262 assert(ft.empty); 7263} 7264 7265/** 7266 Given a range of ranges, iterate transversally through the 7267 `n`th element of each of the enclosed ranges. This function 7268 is similar to `unzip` in other languages. 7269 7270 Params: 7271 opt = Controls the assumptions the function makes about the lengths 7272 of the ranges 7273 rr = An input range of random access ranges 7274 Returns: 7275 At minimum, an input range. Range primitives such as bidirectionality 7276 and random access are given if the element type of `rr` provides them. 7277*/ 7278struct Transversal(Ror, 7279 TransverseOptions opt = TransverseOptions.assumeJagged) 7280{ 7281 private alias RangeOfRanges = Unqual!Ror; 7282 private alias InnerRange = ElementType!RangeOfRanges; 7283 private alias E = ElementType!InnerRange; 7284 7285 private void prime() 7286 { 7287 static if (opt == TransverseOptions.assumeJagged) 7288 { 7289 while (!_input.empty && _input.front.length <= _n) 7290 { 7291 _input.popFront(); 7292 } 7293 static if (isBidirectionalRange!RangeOfRanges) 7294 { 7295 while (!_input.empty && _input.back.length <= _n) 7296 { 7297 _input.popBack(); 7298 } 7299 } 7300 } 7301 } 7302 7303/** 7304 Construction from an input and an index. 7305*/ 7306 this(RangeOfRanges input, size_t n) 7307 { 7308 _input = input; 7309 _n = n; 7310 prime(); 7311 static if (opt == TransverseOptions.enforceNotJagged) 7312 { 7313 import std.exception : enforce; 7314 7315 if (empty) return; 7316 immutable commonLength = _input.front.length; 7317 foreach (e; _input) 7318 { 7319 enforce(e.length == commonLength); 7320 } 7321 } 7322 } 7323 7324/** 7325 Forward range primitives. 7326*/ 7327 static if (isInfinite!(RangeOfRanges)) 7328 { 7329 enum bool empty = false; 7330 } 7331 else 7332 { 7333 @property bool empty() 7334 { 7335 return _input.empty; 7336 } 7337 } 7338 7339 /// Ditto 7340 @property auto ref front() 7341 { 7342 assert(!empty, "Attempting to fetch the front of an empty Transversal"); 7343 return _input.front[_n]; 7344 } 7345 7346 /// Ditto 7347 static if (hasMobileElements!InnerRange) 7348 { 7349 E moveFront() 7350 { 7351 return _input.front.moveAt(_n); 7352 } 7353 } 7354 7355 /// Ditto 7356 static if (hasAssignableElements!InnerRange) 7357 { 7358 @property void front(E val) 7359 { 7360 _input.front[_n] = val; 7361 } 7362 } 7363 7364 7365 /// Ditto 7366 void popFront() 7367 { 7368 assert(!empty, "Attempting to popFront an empty Transversal"); 7369 _input.popFront(); 7370 prime(); 7371 } 7372 7373 /// Ditto 7374 static if (isForwardRange!RangeOfRanges) 7375 { 7376 @property typeof(this) save() 7377 { 7378 auto ret = this; 7379 ret._input = _input.save; 7380 return ret; 7381 } 7382 } 7383 7384 static if (isBidirectionalRange!RangeOfRanges) 7385 { 7386/** 7387 Bidirectional primitives. They are offered if $(D 7388 isBidirectionalRange!RangeOfRanges). 7389*/ 7390 @property auto ref back() 7391 { 7392 assert(!empty, "Attempting to fetch the back of an empty Transversal"); 7393 return _input.back[_n]; 7394 } 7395 7396 /// Ditto 7397 void popBack() 7398 { 7399 assert(!empty, "Attempting to popBack an empty Transversal"); 7400 _input.popBack(); 7401 prime(); 7402 } 7403 7404 /// Ditto 7405 static if (hasMobileElements!InnerRange) 7406 { 7407 E moveBack() 7408 { 7409 return _input.back.moveAt(_n); 7410 } 7411 } 7412 7413 /// Ditto 7414 static if (hasAssignableElements!InnerRange) 7415 { 7416 @property void back(E val) 7417 { 7418 _input.back[_n] = val; 7419 } 7420 } 7421 7422 } 7423 7424 static if (isRandomAccessRange!RangeOfRanges && 7425 (opt == TransverseOptions.assumeNotJagged || 7426 opt == TransverseOptions.enforceNotJagged)) 7427 { 7428/** 7429 Random-access primitive. It is offered if $(D 7430 isRandomAccessRange!RangeOfRanges && (opt == 7431 TransverseOptions.assumeNotJagged || opt == 7432 TransverseOptions.enforceNotJagged)). 7433*/ 7434 auto ref opIndex(size_t n) 7435 { 7436 return _input[n][_n]; 7437 } 7438 7439 /// Ditto 7440 static if (hasMobileElements!InnerRange) 7441 { 7442 E moveAt(size_t n) 7443 { 7444 return _input[n].moveAt(_n); 7445 } 7446 } 7447 7448 /// Ditto 7449 static if (hasAssignableElements!InnerRange) 7450 { 7451 void opIndexAssign(E val, size_t n) 7452 { 7453 _input[n][_n] = val; 7454 } 7455 } 7456 7457 mixin ImplementLength!_input; 7458 7459/** 7460 Slicing if offered if `RangeOfRanges` supports slicing and all the 7461 conditions for supporting indexing are met. 7462*/ 7463 static if (hasSlicing!RangeOfRanges) 7464 { 7465 typeof(this) opSlice(size_t lower, size_t upper) 7466 { 7467 return typeof(this)(_input[lower .. upper], _n); 7468 } 7469 } 7470 } 7471 7472 auto opSlice() { return this; } 7473 7474private: 7475 RangeOfRanges _input; 7476 size_t _n; 7477} 7478 7479/// Ditto 7480Transversal!(RangeOfRanges, opt) transversal 7481(TransverseOptions opt = TransverseOptions.assumeJagged, RangeOfRanges) 7482(RangeOfRanges rr, size_t n) 7483{ 7484 return typeof(return)(rr, n); 7485} 7486 7487/// 7488@safe unittest 7489{ 7490 import std.algorithm.comparison : equal; 7491 int[][] x = new int[][2]; 7492 x[0] = [1, 2]; 7493 x[1] = [3, 4]; 7494 auto ror = transversal(x, 1); 7495 assert(equal(ror, [ 2, 4 ])); 7496} 7497 7498/// The following code does a full unzip 7499@safe unittest 7500{ 7501 import std.algorithm.comparison : equal; 7502 import std.algorithm.iteration : map; 7503 int[][] y = [[1, 2, 3], [4, 5, 6]]; 7504 auto z = y.front.walkLength.iota.map!(i => transversal(y, i)); 7505 assert(equal!equal(z, [[1, 4], [2, 5], [3, 6]])); 7506} 7507 7508@safe unittest 7509{ 7510 import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy; 7511 7512 int[][] x = new int[][2]; 7513 x[0] = [ 1, 2 ]; 7514 x[1] = [3, 4]; 7515 auto ror = transversal!(TransverseOptions.assumeNotJagged)(x, 1); 7516 auto witness = [ 2, 4 ]; 7517 uint i; 7518 foreach (e; ror) assert(e == witness[i++]); 7519 assert(i == 2); 7520 assert(ror.length == 2); 7521 7522 static assert(is(Transversal!(immutable int[][]))); 7523 7524 // Make sure ref, assign is being propagated. 7525 { 7526 ror.front++; 7527 scope(exit) ror.front--; 7528 assert(x[0][1] == 3); 7529 } 7530 { 7531 ror.front = 5; 7532 scope(exit) ror.front = 2; 7533 assert(x[0][1] == 5); 7534 assert(ror.moveFront() == 5); 7535 } 7536 { 7537 ror.back = 999; 7538 scope(exit) ror.back = 4; 7539 assert(x[1][1] == 999); 7540 assert(ror.moveBack() == 999); 7541 } 7542 { 7543 ror[0] = 999; 7544 scope(exit) ror[0] = 2; 7545 assert(x[0][1] == 999); 7546 assert(ror.moveAt(0) == 999); 7547 } 7548 7549 // Test w/o ref return. 7550 alias D = DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random); 7551 auto drs = [D.init, D.init]; 7552 foreach (num; 0 .. 10) 7553 { 7554 auto t = transversal!(TransverseOptions.enforceNotJagged)(drs, num); 7555 assert(t[0] == t[1]); 7556 assert(t[1] == num + 1); 7557 } 7558 7559 static assert(isInfinite!(typeof(transversal(repeat([1,2,3]), 1)))); 7560 7561 // Test slicing. 7562 auto mat = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]; 7563 auto mat1 = transversal!(TransverseOptions.assumeNotJagged)(mat, 1)[1 .. 3]; 7564 assert(mat1[0] == 6); 7565 assert(mat1[1] == 10); 7566} 7567 7568struct Transposed(RangeOfRanges, 7569 TransverseOptions opt = TransverseOptions.assumeJagged) 7570if (isForwardRange!RangeOfRanges && 7571 isInputRange!(ElementType!RangeOfRanges) && 7572 hasAssignableElements!RangeOfRanges) 7573{ 7574 this(RangeOfRanges input) 7575 { 7576 this._input = input; 7577 static if (opt == TransverseOptions.enforceNotJagged) 7578 { 7579 import std.exception : enforce; 7580 7581 if (empty) return; 7582 immutable commonLength = _input.front.length; 7583 foreach (e; _input) 7584 { 7585 enforce(e.length == commonLength); 7586 } 7587 } 7588 } 7589 7590 @property auto front() 7591 { 7592 import std.algorithm.iteration : filter, map; 7593 return _input.save 7594 .filter!(a => !a.empty) 7595 .map!(a => a.front); 7596 } 7597 7598 void popFront() 7599 { 7600 // Advance the position of each subrange. 7601 auto r = _input.save; 7602 while (!r.empty) 7603 { 7604 auto e = r.front; 7605 if (!e.empty) 7606 { 7607 e.popFront(); 7608 r.front = e; 7609 } 7610 7611 r.popFront(); 7612 } 7613 } 7614 7615 static if (isRandomAccessRange!(ElementType!RangeOfRanges)) 7616 { 7617 auto ref opIndex(size_t n) 7618 { 7619 return transversal!opt(_input, n); 7620 } 7621 } 7622 7623 @property bool empty() 7624 { 7625 if (_input.empty) return true; 7626 foreach (e; _input.save) 7627 { 7628 if (!e.empty) return false; 7629 } 7630 return true; 7631 } 7632 7633 auto opSlice() { return this; } 7634 7635private: 7636 RangeOfRanges _input; 7637} 7638 7639@safe unittest 7640{ 7641 // Boundary case: transpose of empty range should be empty 7642 int[][] ror = []; 7643 assert(transposed(ror).empty); 7644} 7645 7646// https://issues.dlang.org/show_bug.cgi?id=9507 7647@safe unittest 7648{ 7649 import std.algorithm.comparison : equal; 7650 7651 auto r = [[1,2], [3], [4,5], [], [6]]; 7652 assert(r.transposed.equal!equal([ 7653 [1, 3, 4, 6], 7654 [2, 5] 7655 ])); 7656} 7657 7658// https://issues.dlang.org/show_bug.cgi?id=17742 7659@safe unittest 7660{ 7661 import std.algorithm.iteration : map; 7662 import std.algorithm.comparison : equal; 7663 auto ror = 5.iota.map!(y => 5.iota.map!(x => x * y).array).array; 7664 assert(ror[3][2] == 6); 7665 auto result = transposed!(TransverseOptions.assumeNotJagged)(ror); 7666 assert(result[2][3] == 6); 7667 7668 auto x = [[1,2,3],[4,5,6]]; 7669 auto y = transposed!(TransverseOptions.assumeNotJagged)(x); 7670 assert(y.front.equal([1,4])); 7671 assert(y[0].equal([1,4])); 7672 assert(y[0][0] == 1); 7673 assert(y[1].equal([2,5])); 7674 assert(y[1][1] == 5); 7675 7676 auto yy = transposed!(TransverseOptions.enforceNotJagged)(x); 7677 assert(yy.front.equal([1,4])); 7678 assert(yy[0].equal([1,4])); 7679 assert(yy[0][0] == 1); 7680 assert(yy[1].equal([2,5])); 7681 assert(yy[1][1] == 5); 7682 7683 auto z = x.transposed; // assumeJagged 7684 assert(z.front.equal([1,4])); 7685 assert(z[0].equal([1,4])); 7686 assert(!is(typeof(z[0][0]))); 7687} 7688 7689@safe unittest 7690{ 7691 import std.exception : assertThrown; 7692 7693 auto r = [[1,2], [3], [4,5], [], [6]]; 7694 assertThrown(r.transposed!(TransverseOptions.enforceNotJagged)); 7695} 7696 7697/** 7698Given a range of ranges, returns a range of ranges where the $(I i)'th subrange 7699contains the $(I i)'th elements of the original subranges. 7700 7701Params: 7702 opt = Controls the assumptions the function makes about the lengths of the ranges (i.e. jagged or not) 7703 rr = Range of ranges 7704 */ 7705Transposed!(RangeOfRanges, opt) transposed 7706(TransverseOptions opt = TransverseOptions.assumeJagged, RangeOfRanges) 7707(RangeOfRanges rr) 7708if (isForwardRange!RangeOfRanges && 7709 isInputRange!(ElementType!RangeOfRanges) && 7710 hasAssignableElements!RangeOfRanges) 7711{ 7712 return Transposed!(RangeOfRanges, opt)(rr); 7713} 7714 7715/// 7716@safe unittest 7717{ 7718 import std.algorithm.comparison : equal; 7719 int[][] ror = [ 7720 [1, 2, 3], 7721 [4, 5, 6] 7722 ]; 7723 auto xp = transposed(ror); 7724 assert(equal!"a.equal(b)"(xp, [ 7725 [1, 4], 7726 [2, 5], 7727 [3, 6] 7728 ])); 7729} 7730 7731/// 7732@safe unittest 7733{ 7734 int[][] x = new int[][2]; 7735 x[0] = [1, 2]; 7736 x[1] = [3, 4]; 7737 auto tr = transposed(x); 7738 int[][] witness = [ [ 1, 3 ], [ 2, 4 ] ]; 7739 uint i; 7740 7741 foreach (e; tr) 7742 { 7743 assert(array(e) == witness[i++]); 7744 } 7745} 7746 7747// https://issues.dlang.org/show_bug.cgi?id=8764 7748@safe unittest 7749{ 7750 import std.algorithm.comparison : equal; 7751 ulong[] t0 = [ 123 ]; 7752 7753 assert(!hasAssignableElements!(typeof(t0[].chunks(1)))); 7754 assert(!is(typeof(transposed(t0[].chunks(1))))); 7755 assert(is(typeof(transposed(t0[].chunks(1).array())))); 7756 7757 auto t1 = transposed(t0[].chunks(1).array()); 7758 assert(equal!"a.equal(b)"(t1, [[123]])); 7759} 7760 7761/** 7762This struct takes two ranges, `source` and `indices`, and creates a view 7763of `source` as if its elements were reordered according to `indices`. 7764`indices` may include only a subset of the elements of `source` and 7765may also repeat elements. 7766 7767`Source` must be a random access range. The returned range will be 7768bidirectional or random-access if `Indices` is bidirectional or 7769random-access, respectively. 7770*/ 7771struct Indexed(Source, Indices) 7772if (isRandomAccessRange!Source && isInputRange!Indices && 7773 is(typeof(Source.init[ElementType!(Indices).init]))) 7774{ 7775 this(Source source, Indices indices) 7776 { 7777 this._source = source; 7778 this._indices = indices; 7779 } 7780 7781 /// Range primitives 7782 @property auto ref front() 7783 { 7784 assert(!empty, "Attempting to fetch the front of an empty Indexed"); 7785 return _source[_indices.front]; 7786 } 7787 7788 /// Ditto 7789 void popFront() 7790 { 7791 assert(!empty, "Attempting to popFront an empty Indexed"); 7792 _indices.popFront(); 7793 } 7794 7795 static if (isInfinite!Indices) 7796 { 7797 enum bool empty = false; 7798 } 7799 else 7800 { 7801 /// Ditto 7802 @property bool empty() 7803 { 7804 return _indices.empty; 7805 } 7806 } 7807 7808 static if (isForwardRange!Indices) 7809 { 7810 /// Ditto 7811 @property typeof(this) save() 7812 { 7813 // Don't need to save _source because it's never consumed. 7814 return typeof(this)(_source, _indices.save); 7815 } 7816 } 7817 7818 /// Ditto 7819 static if (hasAssignableElements!Source) 7820 { 7821 @property auto ref front(ElementType!Source newVal) 7822 { 7823 assert(!empty); 7824 return _source[_indices.front] = newVal; 7825 } 7826 } 7827 7828 7829 static if (hasMobileElements!Source) 7830 { 7831 /// Ditto 7832 auto moveFront() 7833 { 7834 assert(!empty); 7835 return _source.moveAt(_indices.front); 7836 } 7837 } 7838 7839 static if (isBidirectionalRange!Indices) 7840 { 7841 /// Ditto 7842 @property auto ref back() 7843 { 7844 assert(!empty, "Attempting to fetch the back of an empty Indexed"); 7845 return _source[_indices.back]; 7846 } 7847 7848 /// Ditto 7849 void popBack() 7850 { 7851 assert(!empty, "Attempting to popBack an empty Indexed"); 7852 _indices.popBack(); 7853 } 7854 7855 /// Ditto 7856 static if (hasAssignableElements!Source) 7857 { 7858 @property auto ref back(ElementType!Source newVal) 7859 { 7860 assert(!empty); 7861 return _source[_indices.back] = newVal; 7862 } 7863 } 7864 7865 7866 static if (hasMobileElements!Source) 7867 { 7868 /// Ditto 7869 auto moveBack() 7870 { 7871 assert(!empty); 7872 return _source.moveAt(_indices.back); 7873 } 7874 } 7875 } 7876 7877 mixin ImplementLength!_indices; 7878 7879 static if (isRandomAccessRange!Indices) 7880 { 7881 /// Ditto 7882 auto ref opIndex(size_t index) 7883 { 7884 return _source[_indices[index]]; 7885 } 7886 7887 static if (hasSlicing!Indices) 7888 { 7889 /// Ditto 7890 typeof(this) opSlice(size_t a, size_t b) 7891 { 7892 return typeof(this)(_source, _indices[a .. b]); 7893 } 7894 } 7895 7896 7897 static if (hasAssignableElements!Source) 7898 { 7899 /// Ditto 7900 auto opIndexAssign(ElementType!Source newVal, size_t index) 7901 { 7902 return _source[_indices[index]] = newVal; 7903 } 7904 } 7905 7906 7907 static if (hasMobileElements!Source) 7908 { 7909 /// Ditto 7910 auto moveAt(size_t index) 7911 { 7912 return _source.moveAt(_indices[index]); 7913 } 7914 } 7915 } 7916 7917 // All this stuff is useful if someone wants to index an Indexed 7918 // without adding a layer of indirection. 7919 7920 /** 7921 Returns the source range. 7922 */ 7923 @property Source source() 7924 { 7925 return _source; 7926 } 7927 7928 /** 7929 Returns the indices range. 7930 */ 7931 @property Indices indices() 7932 { 7933 return _indices; 7934 } 7935 7936 static if (isRandomAccessRange!Indices) 7937 { 7938 /** 7939 Returns the physical index into the source range corresponding to a 7940 given logical index. This is useful, for example, when indexing 7941 an `Indexed` without adding another layer of indirection. 7942 */ 7943 size_t physicalIndex(size_t logicalIndex) 7944 { 7945 return _indices[logicalIndex]; 7946 } 7947 7948 /// 7949 @safe unittest 7950 { 7951 auto ind = indexed([1, 2, 3, 4, 5], [1, 3, 4]); 7952 assert(ind.physicalIndex(0) == 1); 7953 } 7954 } 7955 7956private: 7957 Source _source; 7958 Indices _indices; 7959 7960} 7961 7962/// Ditto 7963Indexed!(Source, Indices) indexed(Source, Indices)(Source source, Indices indices) 7964{ 7965 return typeof(return)(source, indices); 7966} 7967 7968/// 7969@safe unittest 7970{ 7971 import std.algorithm.comparison : equal; 7972 auto source = [1, 2, 3, 4, 5]; 7973 auto indices = [4, 3, 1, 2, 0, 4]; 7974 auto ind = indexed(source, indices); 7975 assert(equal(ind, [5, 4, 2, 3, 1, 5])); 7976 assert(equal(retro(ind), [5, 1, 3, 2, 4, 5])); 7977} 7978 7979@safe unittest 7980{ 7981 { 7982 auto ind = indexed([1, 2, 3, 4, 5], [1, 3, 4]); 7983 assert(ind.physicalIndex(0) == 1); 7984 } 7985 7986 auto source = [1, 2, 3, 4, 5]; 7987 auto indices = [4, 3, 1, 2, 0, 4]; 7988 auto ind = indexed(source, indices); 7989 7990 // When elements of indices are duplicated and Source has lvalue elements, 7991 // these are aliased in ind. 7992 ind[0]++; 7993 assert(ind[0] == 6); 7994 assert(ind[5] == 6); 7995} 7996 7997@safe unittest 7998{ 7999 import std.internal.test.dummyrange : AllDummyRanges, propagatesLength, 8000 propagatesRangeType, RangeType; 8001 8002 foreach (DummyType; AllDummyRanges) 8003 { 8004 auto d = DummyType.init; 8005 auto r = indexed([1, 2, 3, 4, 5], d); 8006 static assert(propagatesRangeType!(DummyType, typeof(r))); 8007 static assert(propagatesLength!(DummyType, typeof(r))); 8008 } 8009} 8010 8011/** 8012This range iterates over fixed-sized chunks of size `chunkSize` of a 8013`source` range. `Source` must be an $(REF_ALTTEXT input range, isInputRange, std,range,primitives). 8014`chunkSize` must be greater than zero. 8015 8016If `!isInfinite!Source` and `source.walkLength` is not evenly 8017divisible by `chunkSize`, the back element of this range will contain 8018fewer than `chunkSize` elements. 8019 8020If `Source` is a forward range, the resulting range will be forward ranges as 8021well. Otherwise, the resulting chunks will be input ranges consuming the same 8022input: iterating over `front` will shrink the chunk such that subsequent 8023invocations of `front` will no longer return the full chunk, and calling 8024`popFront` on the outer range will invalidate any lingering references to 8025previous values of `front`. 8026 8027Params: 8028 source = Range from which the chunks will be selected 8029 chunkSize = Chunk size 8030 8031See_Also: $(LREF slide) 8032 8033Returns: Range of chunks. 8034*/ 8035struct Chunks(Source) 8036if (isInputRange!Source) 8037{ 8038 static if (isForwardRange!Source) 8039 { 8040 /// Standard constructor 8041 this(Source source, size_t chunkSize) 8042 { 8043 assert(chunkSize != 0, "Cannot create a Chunk with an empty chunkSize"); 8044 _source = source; 8045 _chunkSize = chunkSize; 8046 } 8047 8048 /// Input range primitives. Always present. 8049 @property auto front() 8050 { 8051 assert(!empty, "Attempting to fetch the front of an empty Chunks"); 8052 return _source.save.take(_chunkSize); 8053 } 8054 8055 /// Ditto 8056 void popFront() 8057 { 8058 assert(!empty, "Attempting to popFront and empty Chunks"); 8059 _source.popFrontN(_chunkSize); 8060 } 8061 8062 static if (!isInfinite!Source) 8063 /// Ditto 8064 @property bool empty() 8065 { 8066 return _source.empty; 8067 } 8068 else 8069 // undocumented 8070 enum empty = false; 8071 8072 /// Forward range primitives. Only present if `Source` is a forward range. 8073 @property typeof(this) save() 8074 { 8075 return typeof(this)(_source.save, _chunkSize); 8076 } 8077 8078 static if (hasLength!Source) 8079 { 8080 /// Length. Only if `hasLength!Source` is `true` 8081 @property size_t length() 8082 { 8083 // Note: _source.length + _chunkSize may actually overflow. 8084 // We cast to ulong to mitigate the problem on x86 machines. 8085 // For x64 machines, we just suppose we'll never overflow. 8086 // The "safe" code would require either an extra branch, or a 8087 // modulo operation, which is too expensive for such a rare case 8088 return cast(size_t)((cast(ulong)(_source.length) + _chunkSize - 1) / _chunkSize); 8089 } 8090 //Note: No point in defining opDollar here without slicing. 8091 //opDollar is defined below in the hasSlicing!Source section 8092 } 8093 8094 static if (hasSlicing!Source) 8095 { 8096 //Used for various purposes 8097 private enum hasSliceToEnd = is(typeof(Source.init[_chunkSize .. $]) == Source); 8098 8099 /** 8100 Indexing and slicing operations. Provided only if 8101 `hasSlicing!Source` is `true`. 8102 */ 8103 auto opIndex(size_t index) 8104 { 8105 immutable start = index * _chunkSize; 8106 immutable end = start + _chunkSize; 8107 8108 static if (isInfinite!Source) 8109 return _source[start .. end]; 8110 else 8111 { 8112 import std.algorithm.comparison : min; 8113 immutable len = _source.length; 8114 assert(start < len, "chunks index out of bounds"); 8115 return _source[start .. min(end, len)]; 8116 } 8117 } 8118 8119 /// Ditto 8120 static if (hasLength!Source) 8121 typeof(this) opSlice(size_t lower, size_t upper) 8122 { 8123 import std.algorithm.comparison : min; 8124 assert(lower <= upper && upper <= length, "chunks slicing index out of bounds"); 8125 immutable len = _source.length; 8126 return chunks(_source[min(lower * _chunkSize, len) .. min(upper * _chunkSize, len)], _chunkSize); 8127 } 8128 else static if (hasSliceToEnd) 8129 //For slicing an infinite chunk, we need to slice the source to the end. 8130 typeof(takeExactly(this, 0)) opSlice(size_t lower, size_t upper) 8131 { 8132 assert(lower <= upper, "chunks slicing index out of bounds"); 8133 return chunks(_source[lower * _chunkSize .. $], _chunkSize).takeExactly(upper - lower); 8134 } 8135 8136 static if (isInfinite!Source) 8137 { 8138 static if (hasSliceToEnd) 8139 { 8140 private static struct DollarToken{} 8141 DollarToken opDollar() 8142 { 8143 return DollarToken(); 8144 } 8145 //Slice to dollar 8146 typeof(this) opSlice(size_t lower, DollarToken) 8147 { 8148 return typeof(this)(_source[lower * _chunkSize .. $], _chunkSize); 8149 } 8150 } 8151 } 8152 else 8153 { 8154 //Dollar token carries a static type, with no extra information. 8155 //It can lazily transform into _source.length on algorithmic 8156 //operations such as : chunks[$/2, $-1]; 8157 private static struct DollarToken 8158 { 8159 Chunks!Source* mom; 8160 @property size_t momLength() 8161 { 8162 return mom.length; 8163 } 8164 alias momLength this; 8165 } 8166 DollarToken opDollar() 8167 { 8168 return DollarToken(&this); 8169 } 8170 8171 //Slice overloads optimized for using dollar. Without this, to slice to end, we would... 8172 //1. Evaluate chunks.length 8173 //2. Multiply by _chunksSize 8174 //3. To finally just compare it (with min) to the original length of source (!) 8175 //These overloads avoid that. 8176 typeof(this) opSlice(DollarToken, DollarToken) 8177 { 8178 static if (hasSliceToEnd) 8179 return chunks(_source[$ .. $], _chunkSize); 8180 else 8181 { 8182 immutable len = _source.length; 8183 return chunks(_source[len .. len], _chunkSize); 8184 } 8185 } 8186 typeof(this) opSlice(size_t lower, DollarToken) 8187 { 8188 import std.algorithm.comparison : min; 8189 assert(lower <= length, "chunks slicing index out of bounds"); 8190 static if (hasSliceToEnd) 8191 return chunks(_source[min(lower * _chunkSize, _source.length) .. $], _chunkSize); 8192 else 8193 { 8194 immutable len = _source.length; 8195 return chunks(_source[min(lower * _chunkSize, len) .. len], _chunkSize); 8196 } 8197 } 8198 typeof(this) opSlice(DollarToken, size_t upper) 8199 { 8200 assert(upper == length, "chunks slicing index out of bounds"); 8201 return this[$ .. $]; 8202 } 8203 } 8204 } 8205 8206 //Bidirectional range primitives 8207 static if (hasSlicing!Source && hasLength!Source) 8208 { 8209 /** 8210 Bidirectional range primitives. Provided only if both 8211 `hasSlicing!Source` and `hasLength!Source` are `true`. 8212 */ 8213 @property auto back() 8214 { 8215 assert(!empty, "back called on empty chunks"); 8216 immutable len = _source.length; 8217 immutable start = (len - 1) / _chunkSize * _chunkSize; 8218 return _source[start .. len]; 8219 } 8220 8221 /// Ditto 8222 void popBack() 8223 { 8224 assert(!empty, "popBack() called on empty chunks"); 8225 immutable end = (_source.length - 1) / _chunkSize * _chunkSize; 8226 _source = _source[0 .. end]; 8227 } 8228 } 8229 8230 private: 8231 Source _source; 8232 size_t _chunkSize; 8233 } 8234 else // is input range only 8235 { 8236 import std.typecons : RefCounted; 8237 8238 static struct Chunk 8239 { 8240 private RefCounted!Impl impl; 8241 8242 @property bool empty() { return impl.curSizeLeft == 0 || impl.r.empty; } 8243 @property auto front() { return impl.r.front; } 8244 void popFront() 8245 { 8246 assert(impl.curSizeLeft > 0 && !impl.r.empty); 8247 impl.curSizeLeft--; 8248 impl.r.popFront(); 8249 } 8250 } 8251 8252 static struct Impl 8253 { 8254 private Source r; 8255 private size_t chunkSize; 8256 private size_t curSizeLeft; 8257 } 8258 8259 private RefCounted!Impl impl; 8260 8261 private this(Source r, size_t chunkSize) 8262 { 8263 impl = RefCounted!Impl(r, r.empty ? 0 : chunkSize, chunkSize); 8264 } 8265 8266 @property bool empty() { return impl.chunkSize == 0; } 8267 @property Chunk front() return { return Chunk(impl); } 8268 8269 void popFront() 8270 { 8271 impl.curSizeLeft -= impl.r.popFrontN(impl.curSizeLeft); 8272 if (!impl.r.empty) 8273 impl.curSizeLeft = impl.chunkSize; 8274 else 8275 impl.chunkSize = 0; 8276 } 8277 8278 static assert(isInputRange!(typeof(this))); 8279 } 8280} 8281 8282/// Ditto 8283Chunks!Source chunks(Source)(Source source, size_t chunkSize) 8284if (isInputRange!Source) 8285{ 8286 return typeof(return)(source, chunkSize); 8287} 8288 8289/// 8290@safe unittest 8291{ 8292 import std.algorithm.comparison : equal; 8293 auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 8294 auto chunks = chunks(source, 4); 8295 assert(chunks[0] == [1, 2, 3, 4]); 8296 assert(chunks[1] == [5, 6, 7, 8]); 8297 assert(chunks[2] == [9, 10]); 8298 assert(chunks.back == chunks[2]); 8299 assert(chunks.front == chunks[0]); 8300 assert(chunks.length == 3); 8301 assert(equal(retro(array(chunks)), array(retro(chunks)))); 8302} 8303 8304/// Non-forward input ranges are supported, but with limited semantics. 8305@system /*@safe*/ unittest // FIXME: can't be @safe because RefCounted isn't. 8306{ 8307 import std.algorithm.comparison : equal; 8308 8309 int i; 8310 8311 // The generator doesn't save state, so it cannot be a forward range. 8312 auto inputRange = generate!(() => ++i).take(10); 8313 8314 // We can still process it in chunks, but it will be single-pass only. 8315 auto chunked = inputRange.chunks(2); 8316 8317 assert(chunked.front.equal([1, 2])); 8318 assert(chunked.front.empty); // Iterating the chunk has consumed it 8319 chunked.popFront; 8320 assert(chunked.front.equal([3, 4])); 8321} 8322 8323@system /*@safe*/ unittest 8324{ 8325 import std.algorithm.comparison : equal; 8326 import std.internal.test.dummyrange : ReferenceInputRange; 8327 8328 auto data = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; 8329 auto r = new ReferenceInputRange!int(data).chunks(3); 8330 assert(r.equal!equal([ 8331 [ 1, 2, 3 ], 8332 [ 4, 5, 6 ], 8333 [ 7, 8, 9 ], 8334 [ 10 ] 8335 ])); 8336 8337 auto data2 = [ 1, 2, 3, 4, 5, 6 ]; 8338 auto r2 = new ReferenceInputRange!int(data2).chunks(3); 8339 assert(r2.equal!equal([ 8340 [ 1, 2, 3 ], 8341 [ 4, 5, 6 ] 8342 ])); 8343 8344 auto data3 = [ 1, 2, 3, 4, 5 ]; 8345 auto r3 = new ReferenceInputRange!int(data3).chunks(2); 8346 assert(r3.front.equal([1, 2])); 8347 r3.popFront(); 8348 assert(!r3.empty); 8349 r3.popFront(); 8350 assert(r3.front.equal([5])); 8351} 8352 8353@safe unittest 8354{ 8355 auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 8356 auto chunks = chunks(source, 4); 8357 auto chunks2 = chunks.save; 8358 chunks.popFront(); 8359 assert(chunks[0] == [5, 6, 7, 8]); 8360 assert(chunks[1] == [9, 10]); 8361 chunks2.popBack(); 8362 assert(chunks2[1] == [5, 6, 7, 8]); 8363 assert(chunks2.length == 2); 8364 8365 static assert(isRandomAccessRange!(typeof(chunks))); 8366} 8367 8368@safe unittest 8369{ 8370 import std.algorithm.comparison : equal; 8371 8372 //Extra toying with slicing and indexing. 8373 auto chunks1 = [0, 0, 1, 1, 2, 2, 3, 3, 4].chunks(2); 8374 auto chunks2 = [0, 0, 1, 1, 2, 2, 3, 3, 4, 4].chunks(2); 8375 8376 assert(chunks1.length == 5); 8377 assert(chunks2.length == 5); 8378 assert(chunks1[4] == [4]); 8379 assert(chunks2[4] == [4, 4]); 8380 assert(chunks1.back == [4]); 8381 assert(chunks2.back == [4, 4]); 8382 8383 assert(chunks1[0 .. 1].equal([[0, 0]])); 8384 assert(chunks1[0 .. 2].equal([[0, 0], [1, 1]])); 8385 assert(chunks1[4 .. 5].equal([[4]])); 8386 assert(chunks2[4 .. 5].equal([[4, 4]])); 8387 8388 assert(chunks1[0 .. 0].equal((int[][]).init)); 8389 assert(chunks1[5 .. 5].equal((int[][]).init)); 8390 assert(chunks2[5 .. 5].equal((int[][]).init)); 8391 8392 //Fun with opDollar 8393 assert(chunks1[$ .. $].equal((int[][]).init)); //Quick 8394 assert(chunks2[$ .. $].equal((int[][]).init)); //Quick 8395 assert(chunks1[$ - 1 .. $].equal([[4]])); //Semiquick 8396 assert(chunks2[$ - 1 .. $].equal([[4, 4]])); //Semiquick 8397 assert(chunks1[$ .. 5].equal((int[][]).init)); //Semiquick 8398 assert(chunks2[$ .. 5].equal((int[][]).init)); //Semiquick 8399 8400 assert(chunks1[$ / 2 .. $ - 1].equal([[2, 2], [3, 3]])); //Slow 8401} 8402 8403@safe unittest 8404{ 8405 import std.algorithm.comparison : equal; 8406 import std.algorithm.iteration : filter; 8407 8408 //ForwardRange 8409 auto r = filter!"true"([1, 2, 3, 4, 5]).chunks(2); 8410 assert(equal!"equal(a, b)"(r, [[1, 2], [3, 4], [5]])); 8411 8412 //InfiniteRange w/o RA 8413 auto fibsByPairs = recurrence!"a[n-1] + a[n-2]"(1, 1).chunks(2); 8414 assert(equal!`equal(a, b)`(fibsByPairs.take(2), [[ 1, 1], [ 2, 3]])); 8415 8416 //InfiniteRange w/ RA and slicing 8417 auto odds = sequence!("a[0] + n * a[1]")(1, 2); 8418 auto oddsByPairs = odds.chunks(2); 8419 assert(equal!`equal(a, b)`(oddsByPairs.take(2), [[ 1, 3], [ 5, 7]])); 8420 8421 //Requires phobos#991 for Sequence to have slice to end 8422 static assert(hasSlicing!(typeof(odds))); 8423 assert(equal!`equal(a, b)`(oddsByPairs[3 .. 5], [[13, 15], [17, 19]])); 8424 assert(equal!`equal(a, b)`(oddsByPairs[3 .. $].take(2), [[13, 15], [17, 19]])); 8425} 8426 8427 8428 8429/** 8430This range splits a `source` range into `chunkCount` chunks of 8431approximately equal length. `Source` must be a forward range with 8432known length. 8433 8434Unlike $(LREF chunks), `evenChunks` takes a chunk count (not size). 8435The returned range will contain zero or more $(D source.length / 8436chunkCount + 1) elements followed by $(D source.length / chunkCount) 8437elements. If $(D source.length < chunkCount), some chunks will be empty. 8438 8439`chunkCount` must not be zero, unless `source` is also empty. 8440*/ 8441struct EvenChunks(Source) 8442if (isForwardRange!Source && hasLength!Source) 8443{ 8444 /// Standard constructor 8445 this(Source source, size_t chunkCount) 8446 { 8447 assert(chunkCount != 0 || source.empty, "Cannot create EvenChunks with a zero chunkCount"); 8448 _source = source; 8449 _chunkCount = chunkCount; 8450 } 8451 8452 /// Forward range primitives. Always present. 8453 @property auto front() 8454 { 8455 assert(!empty, "Attempting to fetch the front of an empty evenChunks"); 8456 return _source.save.take(_chunkPos(1)); 8457 } 8458 8459 /// Ditto 8460 void popFront() 8461 { 8462 assert(!empty, "Attempting to popFront an empty evenChunks"); 8463 _source.popFrontN(_chunkPos(1)); 8464 _chunkCount--; 8465 } 8466 8467 /// Ditto 8468 @property bool empty() 8469 { 8470 return _chunkCount == 0; 8471 } 8472 8473 /// Ditto 8474 @property typeof(this) save() 8475 { 8476 return typeof(this)(_source.save, _chunkCount); 8477 } 8478 8479 /// Length 8480 @property size_t length() const 8481 { 8482 return _chunkCount; 8483 } 8484 //Note: No point in defining opDollar here without slicing. 8485 //opDollar is defined below in the hasSlicing!Source section 8486 8487 static if (hasSlicing!Source) 8488 { 8489 /** 8490 Indexing, slicing and bidirectional operations and range primitives. 8491 Provided only if `hasSlicing!Source` is `true`. 8492 */ 8493 auto opIndex(size_t index) 8494 { 8495 assert(index < _chunkCount, "evenChunks index out of bounds"); 8496 return _source[_chunkPos(index) .. _chunkPos(index+1)]; 8497 } 8498 8499 /// Ditto 8500 typeof(this) opSlice(size_t lower, size_t upper) 8501 { 8502 assert(lower <= upper && upper <= length, "evenChunks slicing index out of bounds"); 8503 return evenChunks(_source[_chunkPos(lower) .. _chunkPos(upper)], upper - lower); 8504 } 8505 8506 /// Ditto 8507 @property auto back() 8508 { 8509 assert(!empty, "back called on empty evenChunks"); 8510 return _source[_chunkPos(_chunkCount - 1) .. _source.length]; 8511 } 8512 8513 /// Ditto 8514 void popBack() 8515 { 8516 assert(!empty, "popBack() called on empty evenChunks"); 8517 _source = _source[0 .. _chunkPos(_chunkCount - 1)]; 8518 _chunkCount--; 8519 } 8520 } 8521 8522private: 8523 Source _source; 8524 size_t _chunkCount; 8525 8526 size_t _chunkPos(size_t i) 8527 { 8528 /* 8529 _chunkCount = 5, _source.length = 13: 8530 8531 chunk0 8532 | chunk3 8533 | | 8534 v v 8535 +-+-+-+-+-+ ^ 8536 |0|3|.| | | | 8537 +-+-+-+-+-+ | div 8538 |1|4|.| | | | 8539 +-+-+-+-+-+ v 8540 |2|5|.| 8541 +-+-+-+ 8542 8543 <-----> 8544 mod 8545 8546 <---------> 8547 _chunkCount 8548 8549 One column is one chunk. 8550 popFront and popBack pop the left-most 8551 and right-most column, respectively. 8552 */ 8553 8554 auto div = _source.length / _chunkCount; 8555 auto mod = _source.length % _chunkCount; 8556 auto pos = i <= mod 8557 ? i * (div+1) 8558 : mod * (div+1) + (i-mod) * div 8559 ; 8560 //auto len = i < mod 8561 // ? div+1 8562 // : div 8563 //; 8564 return pos; 8565 } 8566} 8567 8568/// Ditto 8569EvenChunks!Source evenChunks(Source)(Source source, size_t chunkCount) 8570if (isForwardRange!Source && hasLength!Source) 8571{ 8572 return typeof(return)(source, chunkCount); 8573} 8574 8575/// 8576@safe unittest 8577{ 8578 import std.algorithm.comparison : equal; 8579 auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 8580 auto chunks = evenChunks(source, 3); 8581 assert(chunks[0] == [1, 2, 3, 4]); 8582 assert(chunks[1] == [5, 6, 7]); 8583 assert(chunks[2] == [8, 9, 10]); 8584} 8585 8586@safe unittest 8587{ 8588 import std.algorithm.comparison : equal; 8589 8590 auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 8591 auto chunks = evenChunks(source, 3); 8592 assert(chunks.back == chunks[2]); 8593 assert(chunks.front == chunks[0]); 8594 assert(chunks.length == 3); 8595 assert(equal(retro(array(chunks)), array(retro(chunks)))); 8596 8597 auto chunks2 = chunks.save; 8598 chunks.popFront(); 8599 assert(chunks[0] == [5, 6, 7]); 8600 assert(chunks[1] == [8, 9, 10]); 8601 chunks2.popBack(); 8602 assert(chunks2[1] == [5, 6, 7]); 8603 assert(chunks2.length == 2); 8604 8605 static assert(isRandomAccessRange!(typeof(chunks))); 8606} 8607 8608@safe unittest 8609{ 8610 import std.algorithm.comparison : equal; 8611 8612 int[] source = []; 8613 auto chunks = source.evenChunks(0); 8614 assert(chunks.length == 0); 8615 chunks = source.evenChunks(3); 8616 assert(equal(chunks, [[], [], []])); 8617 chunks = [1, 2, 3].evenChunks(5); 8618 assert(equal(chunks, [[1], [2], [3], [], []])); 8619} 8620 8621/** 8622A fixed-sized sliding window iteration 8623of size `windowSize` over a `source` range by a custom `stepSize`. 8624 8625The `Source` range must be at least a $(REF_ALTTEXT ForwardRange, isForwardRange, std,range,primitives) 8626and the `windowSize` must be greater than zero. 8627 8628For `windowSize = 1` it splits the range into single element groups (aka `unflatten`) 8629For `windowSize = 2` it is similar to `zip(source, source.save.dropOne)`. 8630 8631Params: 8632 f = Whether the last element has fewer elements than `windowSize` 8633 it should be be ignored (`No.withPartial`) or added (`Yes.withPartial`) 8634 source = Range from which the slide will be selected 8635 windowSize = Sliding window size 8636 stepSize = Steps between the windows (by default 1) 8637 8638Returns: Range of all sliding windows with propagated bi-directionality, 8639 forwarding, random access, and slicing. 8640 8641Note: To avoid performance overhead, $(REF_ALTTEXT bi-directionality, isBidirectionalRange, std,range,primitives) 8642 is only available when $(REF hasSlicing, std,range,primitives) 8643 and $(REF hasLength, std,range,primitives) are true. 8644 8645See_Also: $(LREF chunks) 8646*/ 8647auto slide(Flag!"withPartial" f = Yes.withPartial, 8648 Source)(Source source, size_t windowSize, size_t stepSize = 1) 8649if (isForwardRange!Source) 8650{ 8651 return Slides!(f, Source)(source, windowSize, stepSize); 8652} 8653 8654/// Iterate over ranges with windows 8655@safe pure nothrow unittest 8656{ 8657 import std.algorithm.comparison : equal; 8658 8659 assert([0, 1, 2, 3].slide(2).equal!equal( 8660 [[0, 1], [1, 2], [2, 3]] 8661 )); 8662 8663 assert(5.iota.slide(3).equal!equal( 8664 [[0, 1, 2], [1, 2, 3], [2, 3, 4]] 8665 )); 8666} 8667 8668/// set a custom stepsize (default 1) 8669@safe pure nothrow unittest 8670{ 8671 import std.algorithm.comparison : equal; 8672 8673 assert(6.iota.slide(1, 2).equal!equal( 8674 [[0], [2], [4]] 8675 )); 8676 8677 assert(6.iota.slide(2, 4).equal!equal( 8678 [[0, 1], [4, 5]] 8679 )); 8680 8681 assert(iota(7).slide(2, 2).equal!equal( 8682 [[0, 1], [2, 3], [4, 5], [6]] 8683 )); 8684 8685 assert(iota(12).slide(2, 4).equal!equal( 8686 [[0, 1], [4, 5], [8, 9]] 8687 )); 8688} 8689 8690/// Allow the last slide to have fewer elements than windowSize 8691@safe pure nothrow unittest 8692{ 8693 import std.algorithm.comparison : equal; 8694 8695 assert(3.iota.slide!(No.withPartial)(4).empty); 8696 assert(3.iota.slide!(Yes.withPartial)(4).equal!equal( 8697 [[0, 1, 2]] 8698 )); 8699} 8700 8701/// Count all the possible substrings of length 2 8702@safe pure nothrow unittest 8703{ 8704 import std.algorithm.iteration : each; 8705 8706 int[dstring] d; 8707 "AGAGA"d.slide!(Yes.withPartial)(2).each!(a => d[a]++); 8708 assert(d == ["AG"d: 2, "GA"d: 2]); 8709} 8710 8711/// withPartial only has an effect if last element in the range doesn't have the full size 8712@safe pure nothrow unittest 8713{ 8714 import std.algorithm.comparison : equal; 8715 8716 assert(5.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4]])); 8717 assert(6.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5]])); 8718 assert(7.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5, 6]])); 8719 8720 assert(5.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2]])); 8721 assert(6.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2]])); 8722 assert(7.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5, 6]])); 8723} 8724 8725private struct Slides(Flag!"withPartial" withPartial = Yes.withPartial, Source) 8726if (isForwardRange!Source) 8727{ 8728private: 8729 Source source; 8730 size_t windowSize; 8731 size_t stepSize; 8732 8733 static if (hasLength!Source) 8734 { 8735 enum needsEndTracker = false; 8736 } 8737 else 8738 { 8739 // If there's no information about the length, track needs to be kept manually 8740 Source nextSource; 8741 enum needsEndTracker = true; 8742 } 8743 8744 bool _empty; 8745 8746 static if (hasSlicing!Source) 8747 enum hasSliceToEnd = hasSlicing!Source && is(typeof(Source.init[0 .. $]) == Source); 8748 8749 static if (withPartial) 8750 bool hasShownPartialBefore; 8751 8752public: 8753 /// Standard constructor 8754 this(Source source, size_t windowSize, size_t stepSize) 8755 { 8756 assert(windowSize > 0, "windowSize must be greater than zero"); 8757 assert(stepSize > 0, "stepSize must be greater than zero"); 8758 this.source = source; 8759 this.windowSize = windowSize; 8760 this.stepSize = stepSize; 8761 8762 static if (needsEndTracker) 8763 { 8764 // `nextSource` is used to "look one step into the future" and check for the end 8765 // this means `nextSource` is advanced by `stepSize` on every `popFront` 8766 nextSource = source.save.drop(windowSize); 8767 } 8768 8769 if (source.empty) 8770 { 8771 _empty = true; 8772 return; 8773 } 8774 8775 static if (withPartial) 8776 { 8777 static if (needsEndTracker) 8778 { 8779 if (nextSource.empty) 8780 hasShownPartialBefore = true; 8781 } 8782 else 8783 { 8784 if (source.length <= windowSize) 8785 hasShownPartialBefore = true; 8786 } 8787 8788 } 8789 else 8790 { 8791 // empty source range is needed, s.t. length, slicing etc. works properly 8792 static if (needsEndTracker) 8793 { 8794 if (nextSource.empty) 8795 _empty = true; 8796 } 8797 else 8798 { 8799 if (source.length < windowSize) 8800 _empty = true; 8801 } 8802 } 8803 } 8804 8805 /// Forward range primitives. Always present. 8806 @property auto front() 8807 { 8808 assert(!empty, "Attempting to access front on an empty slide."); 8809 static if (hasSlicing!Source && hasLength!Source) 8810 { 8811 static if (withPartial) 8812 { 8813 import std.algorithm.comparison : min; 8814 return source[0 .. min(windowSize, source.length)]; 8815 } 8816 else 8817 { 8818 assert(windowSize <= source.length, "The last element is smaller than the current windowSize."); 8819 return source[0 .. windowSize]; 8820 } 8821 } 8822 else 8823 { 8824 static if (withPartial) 8825 return source.save.take(windowSize); 8826 else 8827 return source.save.takeExactly(windowSize); 8828 } 8829 } 8830 8831 /// Ditto 8832 void popFront() 8833 { 8834 assert(!empty, "Attempting to call popFront() on an empty slide."); 8835 source.popFrontN(stepSize); 8836 8837 if (source.empty) 8838 { 8839 _empty = true; 8840 return; 8841 } 8842 8843 static if (withPartial) 8844 { 8845 if (hasShownPartialBefore) 8846 _empty = true; 8847 } 8848 8849 static if (needsEndTracker) 8850 { 8851 // Check the upcoming slide 8852 auto poppedElements = nextSource.popFrontN(stepSize); 8853 static if (withPartial) 8854 { 8855 if (poppedElements < stepSize || nextSource.empty) 8856 hasShownPartialBefore = true; 8857 } 8858 else 8859 { 8860 if (poppedElements < stepSize) 8861 _empty = true; 8862 } 8863 } 8864 else 8865 { 8866 static if (withPartial) 8867 { 8868 if (source.length <= windowSize) 8869 hasShownPartialBefore = true; 8870 } 8871 else 8872 { 8873 if (source.length < windowSize) 8874 _empty = true; 8875 } 8876 } 8877 } 8878 8879 static if (!isInfinite!Source) 8880 { 8881 /// Ditto 8882 @property bool empty() const 8883 { 8884 return _empty; 8885 } 8886 } 8887 else 8888 { 8889 // undocumented 8890 enum empty = false; 8891 } 8892 8893 /// Ditto 8894 @property typeof(this) save() 8895 { 8896 return typeof(this)(source.save, windowSize, stepSize); 8897 } 8898 8899 static if (hasLength!Source) 8900 { 8901 // gaps between the last element and the end of the range 8902 private size_t gap() 8903 { 8904 /* 8905 * Note: 8906 * - In the following `end` is the exclusive end as used in opSlice 8907 * - For the trivial case with `stepSize = 1` `end` is at `len`: 8908 * 8909 * iota(4).slide(2) = [[0, 1], [1, 2], [2, 3]] (end = 4) 8910 * iota(4).slide(3) = [[0, 1, 2], [1, 2, 3]] (end = 4) 8911 * 8912 * - For the non-trivial cases, we need to calculate the gap 8913 * between `len` and `end` - this is the number of missing elements 8914 * from the input range: 8915 * 8916 * iota(7).slide(2, 3) = [[0, 1], [3, 4]] || <gap: 2> 6 8917 * iota(7).slide(2, 4) = [[0, 1], [4, 5]] || <gap: 1> 6 8918 * iota(7).slide(1, 5) = [[0], [5]] || <gap: 1> 6 8919 * 8920 * As it can be seen `gap` can be at most `stepSize - 1` 8921 * More generally the elements of the sliding window with 8922 * `w = windowSize` and `s = stepSize` are: 8923 * 8924 * [0, w], [s, s + w], [2 * s, 2 * s + w], ... [n * s, n * s + w] 8925 * 8926 * We can thus calculate the gap between the `end` and `len` as: 8927 * 8928 * gap = len - (n * s + w) = len - w - (n * s) 8929 * 8930 * As we aren't interested in exact value of `n`, but the best 8931 * minimal `gap` value, we can use modulo to "cut" `len - w` optimally: 8932 * 8933 * gap = len - w - (s - s ... - s) = (len - w) % s 8934 * 8935 * So for example: 8936 * 8937 * iota(7).slide(2, 3) = [[0, 1], [3, 4]] 8938 * gap: (7 - 2) % 3 = 5 % 3 = 2 8939 * end: 7 - 2 = 5 8940 * 8941 * iota(7).slide(4, 2) = [[0, 1, 2, 3], [2, 3, 4, 5]] 8942 * gap: (7 - 4) % 2 = 3 % 2 = 1 8943 * end: 7 - 1 = 6 8944 */ 8945 return (source.length - windowSize) % stepSize; 8946 } 8947 8948 private size_t numberOfFullFrames() 8949 { 8950 /** 8951 5.iota.slides(2, 1) => [0, 1], [1, 2], [2, 3], [3, 4] (4) 8952 7.iota.slides(2, 2) => [0, 1], [2, 3], [4, 5], [6] (3) 8953 7.iota.slides(2, 3) => [0, 1], [3, 4], [6] (2) 8954 6.iota.slides(3, 2) => [0, 1, 2], [2, 3, 4], [4, 5] (2) 8955 7.iota.slides(3, 3) => [0, 1, 2], [3, 4, 5], [6] (2) 8956 8957 As the last window is only added iff its complete, 8958 we don't count the last window except if it's full due to integer rounding. 8959 */ 8960 return 1 + (source.length - windowSize) / stepSize; 8961 } 8962 8963 // Whether the last slide frame size is less than windowSize 8964 private bool hasPartialElements() 8965 { 8966 static if (withPartial) 8967 return gap != 0 && source.length > numberOfFullFrames * stepSize; 8968 else 8969 return 0; 8970 } 8971 8972 /// Length. Only if `hasLength!Source` is `true` 8973 @property size_t length() 8974 { 8975 if (source.length < windowSize) 8976 { 8977 static if (withPartial) 8978 return source.length > 0; 8979 else 8980 return 0; 8981 } 8982 else 8983 { 8984 /*** 8985 We bump the pointer by stepSize for every element. 8986 If withPartial, we don't count the last element if its size 8987 isn't windowSize 8988 8989 At most: 8990 [p, p + stepSize, ..., p + stepSize * n] 8991 8992 5.iota.slides(2, 1) => [0, 1], [1, 2], [2, 3], [3, 4] (4) 8993 7.iota.slides(2, 2) => [0, 1], [2, 3], [4, 5], [6] (4) 8994 7.iota.slides(2, 3) => [0, 1], [3, 4], [6] (3) 8995 7.iota.slides(3, 2) => [0, 1, 2], [2, 3, 4], [4, 5, 6] (3) 8996 7.iota.slides(3, 3) => [0, 1, 2], [3, 4, 5], [6] (3) 8997 */ 8998 return numberOfFullFrames + hasPartialElements; 8999 } 9000 } 9001 } 9002 9003 static if (hasSlicing!Source) 9004 { 9005 /** 9006 Indexing and slicing operations. Provided only if 9007 `hasSlicing!Source` is `true`. 9008 */ 9009 auto opIndex(size_t index) 9010 { 9011 immutable start = index * stepSize; 9012 9013 static if (isInfinite!Source) 9014 { 9015 immutable end = start + windowSize; 9016 } 9017 else 9018 { 9019 import std.algorithm.comparison : min; 9020 9021 immutable len = source.length; 9022 assert(start < len, "slide index out of bounds"); 9023 immutable end = min(start + windowSize, len); 9024 } 9025 9026 return source[start .. end]; 9027 } 9028 9029 static if (!isInfinite!Source) 9030 { 9031 /// ditto 9032 typeof(this) opSlice(size_t lower, size_t upper) 9033 { 9034 import std.algorithm.comparison : min; 9035 9036 assert(upper <= length, "slide slicing index out of bounds"); 9037 assert(lower <= upper, "slide slicing index out of bounds"); 9038 9039 lower *= stepSize; 9040 upper *= stepSize; 9041 9042 immutable len = source.length; 9043 9044 static if (withPartial) 9045 { 9046 import std.algorithm.comparison : max; 9047 9048 if (lower == upper) 9049 return this[$ .. $]; 9050 9051 /* 9052 A) If `stepSize` >= `windowSize` => `rightPos = upper` 9053 9054 [0, 1, 2, 3, 4, 5, 6].slide(2, 3) -> s = [[0, 1], [3, 4], [6]] 9055 rightPos for s[0 .. 2]: (upper=2) * (stepSize=3) = 6 9056 6.iota.slide(2, 3) = [[0, 1], [3, 4]] 9057 9058 B) If `stepSize` < `windowSize` => add `windowSize - stepSize` to `upper` 9059 9060 [0, 1, 2, 3].slide(2) = [[0, 1], [1, 2], [2, 3]] 9061 rightPos for s[0 .. 1]: = (upper=1) * (stepSize=1) = 1 9062 1.iota.slide(2) = [[0]] 9063 9064 rightPos for s[0 .. 1]: = (upper=1) * (stepSize=1) + (windowSize-stepSize=1) = 2 9065 1.iota.slide(2) = [[0, 1]] 9066 9067 More complex: 9068 9069 20.iota.slide(7, 6)[0 .. 2] 9070 rightPos: (upper=2) * (stepSize=6) = 12.iota 9071 12.iota.slide(7, 6) = [[0, 1, 2, 3, 4, 5, 6], [6, 7, 8, 9, 10, 11]] 9072 9073 Now we add up for the difference between `windowSize` and `stepSize`: 9074 9075 rightPos: (upper=2) * (stepSize=6) + (windowSize-stepSize=1) = 13.iota 9076 13.iota.slide(7, 6) = [[0, 1, 2, 3, 4, 5, 6], [6, 7, 8, 9, 10, 11, 12]] 9077 */ 9078 immutable rightPos = min(len, upper + max(0, windowSize - stepSize)); 9079 } 9080 else 9081 { 9082 /* 9083 After we have normalized `lower` and `upper` by `stepSize`, 9084 we only need to look at the case of `stepSize=1`. 9085 As `leftPos`, is equal to `lower`, we will only look `rightPos`. 9086 Notice that starting from `upper`, 9087 we only need to move for `windowSize - 1` to the right: 9088 9089 - [0, 1, 2, 3].slide(2) -> s = [[0, 1], [1, 2], [2, 3]] 9090 rightPos for s[0 .. 3]: (upper=3) + (windowSize=2) - 1 = 4 9091 9092 - [0, 1, 2, 3].slide(3) -> s = [[0, 1, 2], [1, 2, 3]] 9093 rightPos for s[0 .. 2]: (upper=2) + (windowSize=3) - 1 = 4 9094 9095 - [0, 1, 2, 3, 4].slide(4) -> s = [[0, 1, 2, 3], [1, 2, 3, 4]] 9096 rightPos for s[0 .. 2]: (upper=2) + (windowSize=4) - 1 = 5 9097 */ 9098 immutable rightPos = min(upper + windowSize - 1, len); 9099 } 9100 9101 return typeof(this)(source[min(lower, len) .. rightPos], windowSize, stepSize); 9102 } 9103 } 9104 else static if (hasSliceToEnd) 9105 { 9106 // For slicing an infinite chunk, we need to slice the source to the infinite end. 9107 auto opSlice(size_t lower, size_t upper) 9108 { 9109 assert(lower <= upper, "slide slicing index out of bounds"); 9110 return typeof(this)(source[lower * stepSize .. $], windowSize, stepSize) 9111 .takeExactly(upper - lower); 9112 } 9113 } 9114 9115 static if (isInfinite!Source) 9116 { 9117 static if (hasSliceToEnd) 9118 { 9119 private static struct DollarToken{} 9120 DollarToken opDollar() 9121 { 9122 return DollarToken(); 9123 } 9124 //Slice to dollar 9125 typeof(this) opSlice(size_t lower, DollarToken) 9126 { 9127 return typeof(this)(source[lower * stepSize .. $], windowSize, stepSize); 9128 } 9129 } 9130 } 9131 else 9132 { 9133 // Dollar token carries a static type, with no extra information. 9134 // It can lazily transform into source.length on algorithmic 9135 // operations such as : slide[$/2, $-1]; 9136 private static struct DollarToken 9137 { 9138 private size_t _length; 9139 alias _length this; 9140 } 9141 9142 DollarToken opDollar() 9143 { 9144 return DollarToken(this.length); 9145 } 9146 9147 // Optimized slice overloads optimized for using dollar. 9148 typeof(this) opSlice(DollarToken, DollarToken) 9149 { 9150 static if (hasSliceToEnd) 9151 { 9152 return typeof(this)(source[$ .. $], windowSize, stepSize); 9153 } 9154 else 9155 { 9156 immutable len = source.length; 9157 return typeof(this)(source[len .. len], windowSize, stepSize); 9158 } 9159 } 9160 9161 // Optimized slice overloads optimized for using dollar. 9162 typeof(this) opSlice(size_t lower, DollarToken) 9163 { 9164 import std.algorithm.comparison : min; 9165 assert(lower <= length, "slide slicing index out of bounds"); 9166 lower *= stepSize; 9167 static if (hasSliceToEnd) 9168 { 9169 return typeof(this)(source[min(lower, source.length) .. $], windowSize, stepSize); 9170 } 9171 else 9172 { 9173 immutable len = source.length; 9174 return typeof(this)(source[min(lower, len) .. len], windowSize, stepSize); 9175 } 9176 } 9177 9178 // Optimized slice overloads optimized for using dollar. 9179 typeof(this) opSlice(DollarToken, size_t upper) 9180 { 9181 assert(upper == length, "slide slicing index out of bounds"); 9182 return this[$ .. $]; 9183 } 9184 } 9185 9186 // Bidirectional range primitives 9187 static if (!isInfinite!Source) 9188 { 9189 /** 9190 Bidirectional range primitives. Provided only if both 9191 `hasSlicing!Source` and `!isInfinite!Source` are `true`. 9192 */ 9193 @property auto back() 9194 { 9195 import std.algorithm.comparison : max; 9196 9197 assert(!empty, "Attempting to access front on an empty slide"); 9198 9199 immutable len = source.length; 9200 9201 static if (withPartial) 9202 { 9203 if (source.length <= windowSize) 9204 return source[0 .. source.length]; 9205 9206 if (hasPartialElements) 9207 return source[numberOfFullFrames * stepSize .. len]; 9208 } 9209 9210 // check for underflow 9211 immutable start = (len > windowSize + gap) ? len - windowSize - gap : 0; 9212 return source[start .. len - gap]; 9213 } 9214 9215 /// Ditto 9216 void popBack() 9217 { 9218 assert(!empty, "Attempting to call popBack() on an empty slide"); 9219 9220 // Move by stepSize 9221 immutable end = source.length > stepSize ? source.length - stepSize : 0; 9222 9223 static if (withPartial) 9224 { 9225 if (hasShownPartialBefore || source.empty) 9226 { 9227 _empty = true; 9228 return; 9229 } 9230 9231 // pop by stepSize, except for the partial frame at the end 9232 if (hasPartialElements) 9233 source = source[0 .. source.length - gap]; 9234 else 9235 source = source[0 .. end]; 9236 } 9237 else 9238 { 9239 source = source[0 .. end]; 9240 } 9241 9242 if (source.length < windowSize) 9243 _empty = true; 9244 } 9245 } 9246 } 9247} 9248 9249// test @nogc 9250@safe pure nothrow @nogc unittest 9251{ 9252 import std.algorithm.comparison : equal; 9253 9254 static immutable res1 = [[0], [1], [2], [3]]; 9255 assert(4.iota.slide!(Yes.withPartial)(1).equal!equal(res1)); 9256 9257 static immutable res2 = [[0, 1], [1, 2], [2, 3]]; 9258 assert(4.iota.slide!(Yes.withPartial)(2).equal!equal(res2)); 9259} 9260 9261// test different window sizes 9262@safe pure nothrow unittest 9263{ 9264 import std.array : array; 9265 import std.algorithm.comparison : equal; 9266 9267 assert([0, 1, 2, 3].slide!(Yes.withPartial)(1).array == [[0], [1], [2], [3]]); 9268 assert([0, 1, 2, 3].slide!(Yes.withPartial)(2).array == [[0, 1], [1, 2], [2, 3]]); 9269 assert([0, 1, 2, 3].slide!(Yes.withPartial)(3).array == [[0, 1, 2], [1, 2, 3]]); 9270 assert([0, 1, 2, 3].slide!(Yes.withPartial)(4).array == [[0, 1, 2, 3]]); 9271 assert([0, 1, 2, 3].slide!(No.withPartial)(5).walkLength == 0); 9272 assert([0, 1, 2, 3].slide!(Yes.withPartial)(5).array == [[0, 1, 2, 3]]); 9273 9274 assert(iota(2).slide!(Yes.withPartial)(2).front.equal([0, 1])); 9275 assert(iota(3).slide!(Yes.withPartial)(2).equal!equal([[0, 1],[1, 2]])); 9276 assert(iota(3).slide!(Yes.withPartial)(3).equal!equal([[0, 1, 2]])); 9277 assert(iota(3).slide!(No.withPartial)(4).walkLength == 0); 9278 assert(iota(3).slide!(Yes.withPartial)(4).equal!equal([[0, 1, 2]])); 9279 assert(iota(1, 4).slide!(Yes.withPartial)(1).equal!equal([[1], [2], [3]])); 9280 assert(iota(1, 4).slide!(Yes.withPartial)(3).equal!equal([[1, 2, 3]])); 9281} 9282 9283// test combinations 9284@safe pure nothrow unittest 9285{ 9286 import std.algorithm.comparison : equal; 9287 import std.typecons : tuple; 9288 9289 alias t = tuple; 9290 auto list = [ 9291 t(t(1, 1), [[0], [1], [2], [3], [4], [5]]), 9292 t(t(1, 2), [[0], [2], [4]]), 9293 t(t(1, 3), [[0], [3]]), 9294 t(t(1, 4), [[0], [4]]), 9295 t(t(1, 5), [[0], [5]]), 9296 t(t(2, 1), [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5]]), 9297 t(t(2, 2), [[0, 1], [2, 3], [4, 5]]), 9298 t(t(2, 3), [[0, 1], [3, 4]]), 9299 t(t(2, 4), [[0, 1], [4, 5]]), 9300 t(t(3, 1), [[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5]]), 9301 t(t(3, 3), [[0, 1, 2], [3, 4, 5]]), 9302 t(t(4, 1), [[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]), 9303 t(t(4, 2), [[0, 1, 2, 3], [2, 3, 4, 5]]), 9304 t(t(5, 1), [[0, 1, 2, 3, 4], [1, 2, 3, 4, 5]]), 9305 ]; 9306 9307 static foreach (Partial; [Yes.withPartial, No.withPartial]) 9308 foreach (e; list) 9309 assert(6.iota.slide!Partial(e[0].expand).equal!equal(e[1])); 9310 9311 auto listSpecial = [ 9312 t(t(2, 5), [[0, 1], [5]]), 9313 t(t(3, 2), [[0, 1, 2], [2, 3, 4], [4, 5]]), 9314 t(t(3, 4), [[0, 1, 2], [4, 5]]), 9315 t(t(4, 3), [[0, 1, 2, 3], [3, 4, 5]]), 9316 t(t(5, 2), [[0, 1, 2, 3, 4], [2, 3, 4, 5]]), 9317 t(t(5, 3), [[0, 1, 2, 3, 4], [3, 4, 5]]), 9318 ]; 9319 foreach (e; listSpecial) 9320 { 9321 assert(6.iota.slide!(Yes.withPartial)(e[0].expand).equal!equal(e[1])); 9322 assert(6.iota.slide!(No.withPartial)(e[0].expand).equal!equal(e[1].dropBackOne)); 9323 } 9324} 9325 9326// test emptiness and copyability 9327@safe pure nothrow unittest 9328{ 9329 import std.algorithm.comparison : equal; 9330 import std.algorithm.iteration : map; 9331 9332 // check with empty input 9333 int[] d; 9334 assert(d.slide!(Yes.withPartial)(2).empty); 9335 assert(d.slide!(Yes.withPartial)(2, 2).empty); 9336 9337 // is copyable? 9338 auto e = iota(5).slide!(Yes.withPartial)(2); 9339 e.popFront; 9340 assert(e.save.equal!equal([[1, 2], [2, 3], [3, 4]])); 9341 assert(e.save.equal!equal([[1, 2], [2, 3], [3, 4]])); 9342 assert(e.map!"a.array".array == [[1, 2], [2, 3], [3, 4]]); 9343} 9344 9345// test with strings 9346@safe pure nothrow unittest 9347{ 9348 import std.algorithm.iteration : each; 9349 9350 int[dstring] f; 9351 "AGAGA"d.slide!(Yes.withPartial)(3).each!(a => f[a]++); 9352 assert(f == ["AGA"d: 2, "GAG"d: 1]); 9353 9354 int[dstring] g; 9355 "ABCDEFG"d.slide!(Yes.withPartial)(3, 3).each!(a => g[a]++); 9356 assert(g == ["ABC"d:1, "DEF"d:1, "G": 1]); 9357 g = null; 9358 "ABCDEFG"d.slide!(No.withPartial)(3, 3).each!(a => g[a]++); 9359 assert(g == ["ABC"d:1, "DEF"d:1]); 9360} 9361 9362// test with utf8 strings 9363@safe unittest 9364{ 9365 import std.stdio; 9366 import std.algorithm.comparison : equal; 9367 9368 assert("��.��.��.".slide!(Yes.withPartial)(3, 2).equal!equal(["��.��", "��.��", "��."])); 9369 assert("��.��.��.".slide!(No.withPartial)(3, 2).equal!equal(["��.��", "��.��"])); 9370 9371 "����������������������������������������".slide!(Yes.withPartial)(2, 4).equal!equal(["��������", "��������", "��������"]); 9372 "����������������������������������������".slide!(No.withPartial)(2, 4).equal!equal(["��������", "��������", "��������"]); 9373 "����������������������������������������".slide!(Yes.withPartial)(3, 3).equal!equal(["������������", "������������", "������������", "����"]); 9374 "����������������������������������������".slide!(No.withPartial)(3, 3).equal!equal(["������������", "������������", "������������"]); 9375} 9376 9377// test length 9378@safe pure nothrow unittest 9379{ 9380 // Slides with fewer elements are empty or 1 for Yes.withPartial 9381 static foreach (expectedLength, Partial; [No.withPartial, Yes.withPartial]) 9382 {{ 9383 assert(3.iota.slide!(Partial)(4, 2).walkLength == expectedLength); 9384 assert(3.iota.slide!(Partial)(4).walkLength == expectedLength); 9385 assert(3.iota.slide!(Partial)(4, 3).walkLength == expectedLength); 9386 }} 9387 9388 static immutable list = [ 9389 // iota slide expected 9390 [4, 2, 1, 3, 3], 9391 [5, 3, 1, 3, 3], 9392 [7, 2, 2, 4, 3], 9393 [12, 2, 4, 3, 3], 9394 [6, 1, 2, 3, 3], 9395 [6, 2, 4, 2, 2], 9396 [3, 2, 4, 1, 1], 9397 [5, 2, 1, 4, 4], 9398 [7, 2, 2, 4, 3], 9399 [7, 2, 3, 3, 2], 9400 [7, 3, 2, 3, 3], 9401 [7, 3, 3, 3, 2], 9402 ]; 9403 foreach (e; list) 9404 { 9405 assert(e[0].iota.slide!(Yes.withPartial)(e[1], e[2]).length == e[3]); 9406 assert(e[0].iota.slide!(No.withPartial)(e[1], e[2]).length == e[4]); 9407 } 9408} 9409 9410// test index and slicing 9411@safe pure nothrow unittest 9412{ 9413 import std.algorithm.comparison : equal; 9414 import std.array : array; 9415 9416 static foreach (Partial; [Yes.withPartial, No.withPartial]) 9417 { 9418 foreach (s; [5, 7, 10, 15, 20]) 9419 foreach (windowSize; 1 .. 10) 9420 foreach (stepSize; 1 .. 10) 9421 { 9422 auto r = s.iota.slide!Partial(windowSize, stepSize); 9423 auto arr = r.array; 9424 assert(r.length == arr.length); 9425 9426 // test indexing 9427 foreach (i; 0 .. arr.length) 9428 assert(r[i] == arr[i]); 9429 9430 // test slicing 9431 foreach (i; 0 .. arr.length) 9432 { 9433 foreach (j; i .. arr.length) 9434 assert(r[i .. j].equal(arr[i .. j])); 9435 9436 assert(r[i .. $].equal(arr[i .. $])); 9437 } 9438 9439 // test opDollar slicing 9440 assert(r[$/2 .. $].equal(arr[$/2 .. $])); 9441 assert(r[$ .. $].empty); 9442 if (arr.empty) 9443 { 9444 assert(r[$ .. 0].empty); 9445 assert(r[$/2 .. $].empty); 9446 9447 } 9448 } 9449 } 9450} 9451 9452// test with infinite ranges 9453@safe pure nothrow unittest 9454{ 9455 import std.algorithm.comparison : equal; 9456 9457 static foreach (Partial; [Yes.withPartial, No.withPartial]) 9458 {{ 9459 // InfiniteRange without RandomAccess 9460 auto fibs = recurrence!"a[n-1] + a[n-2]"(1, 1); 9461 assert(fibs.slide!Partial(2).take(2).equal!equal([[1, 1], [1, 2]])); 9462 assert(fibs.slide!Partial(2, 3).take(2).equal!equal([[1, 1], [3, 5]])); 9463 9464 // InfiniteRange with RandomAccess and slicing 9465 auto odds = sequence!("a[0] + n * a[1]")(1, 2); 9466 auto oddsByPairs = odds.slide!Partial(2); 9467 assert(oddsByPairs.take(2).equal!equal([[ 1, 3], [ 3, 5]])); 9468 assert(oddsByPairs[1].equal([3, 5])); 9469 assert(oddsByPairs[4].equal([9, 11])); 9470 9471 static assert(hasSlicing!(typeof(odds))); 9472 assert(oddsByPairs[3 .. 5].equal!equal([[7, 9], [9, 11]])); 9473 assert(oddsByPairs[3 .. $].take(2).equal!equal([[7, 9], [9, 11]])); 9474 9475 auto oddsWithGaps = odds.slide!Partial(2, 4); 9476 assert(oddsWithGaps.take(3).equal!equal([[1, 3], [9, 11], [17, 19]])); 9477 assert(oddsWithGaps[2].equal([17, 19])); 9478 assert(oddsWithGaps[1 .. 3].equal!equal([[9, 11], [17, 19]])); 9479 assert(oddsWithGaps[1 .. $].take(2).equal!equal([[9, 11], [17, 19]])); 9480 }} 9481} 9482 9483// test reverse 9484@safe pure nothrow unittest 9485{ 9486 import std.algorithm.comparison : equal; 9487 9488 static foreach (Partial; [Yes.withPartial, No.withPartial]) 9489 {{ 9490 foreach (windowSize; 1 .. 15) 9491 foreach (stepSize; 1 .. 15) 9492 { 9493 auto r = 20.iota.slide!Partial(windowSize, stepSize); 9494 auto rArr = r.array.retro; 9495 auto rRetro = r.retro; 9496 9497 assert(rRetro.length == rArr.length); 9498 assert(rRetro.equal(rArr)); 9499 assert(rRetro.array.retro.equal(r)); 9500 } 9501 }} 9502} 9503 9504// test with dummy ranges 9505@safe pure nothrow unittest 9506{ 9507 import std.algorithm.comparison : equal; 9508 import std.internal.test.dummyrange : AllDummyRanges; 9509 import std.meta : Filter; 9510 9511 static foreach (Range; Filter!(isForwardRange, AllDummyRanges)) 9512 {{ 9513 Range r; 9514 9515 static foreach (Partial; [Yes.withPartial, No.withPartial]) 9516 { 9517 assert(r.slide!Partial(1).equal!equal( 9518 [[1], [2], [3], [4], [5], [6], [7], [8], [9], [10]] 9519 )); 9520 assert(r.slide!Partial(2).equal!equal( 9521 [[1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9], [9, 10]] 9522 )); 9523 assert(r.slide!Partial(3).equal!equal( 9524 [[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6], 9525 [5, 6, 7], [6, 7, 8], [7, 8, 9], [8, 9, 10]] 9526 )); 9527 assert(r.slide!Partial(6).equal!equal( 9528 [[1, 2, 3, 4, 5, 6], [2, 3, 4, 5, 6, 7], [3, 4, 5, 6, 7, 8], 9529 [4, 5, 6, 7, 8, 9], [5, 6, 7, 8, 9, 10]] 9530 )); 9531 } 9532 9533 // special cases 9534 assert(r.slide!(Yes.withPartial)(15).equal!equal(iota(1, 11).only)); 9535 assert(r.slide!(Yes.withPartial)(15).walkLength == 1); 9536 assert(r.slide!(No.withPartial)(15).empty); 9537 assert(r.slide!(No.withPartial)(15).walkLength == 0); 9538 }} 9539} 9540 9541// test with dummy ranges 9542@safe pure nothrow unittest 9543{ 9544 import std.algorithm.comparison : equal; 9545 import std.internal.test.dummyrange : AllDummyRanges; 9546 import std.meta : Filter; 9547 import std.typecons : tuple; 9548 9549 alias t = tuple; 9550 static immutable list = [ 9551 // iota slide expected 9552 t(6, t(4, 2), [[1, 2, 3, 4], [3, 4, 5, 6]]), 9553 t(6, t(4, 6), [[1, 2, 3, 4]]), 9554 t(6, t(4, 1), [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6]]), 9555 t(7, t(4, 1), [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 6, 7]]), 9556 t(7, t(4, 3), [[1, 2, 3, 4], [4, 5, 6, 7]]), 9557 t(8, t(4, 2), [[1, 2, 3, 4], [3, 4, 5, 6], [5, 6, 7, 8]]), 9558 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]]), 9559 t(8, t(3, 4), [[1, 2, 3], [5, 6, 7]]), 9560 t(10, t(3, 7), [[1, 2, 3], [8, 9, 10]]), 9561 ]; 9562 9563 static foreach (Range; Filter!(isForwardRange, AllDummyRanges)) 9564 static foreach (Partial; [Yes.withPartial, No.withPartial]) 9565 foreach (e; list) 9566 assert(Range().take(e[0]).slide!Partial(e[1].expand).equal!equal(e[2])); 9567 9568 static immutable listSpecial = [ 9569 // iota slide expected 9570 t(6, t(4, 3), [[1, 2, 3, 4], [4, 5, 6]]), 9571 t(7, t(4, 5), [[1, 2, 3, 4], [6, 7]]), 9572 t(7, t(4, 4), [[1, 2, 3, 4], [5, 6, 7]]), 9573 t(7, t(4, 2), [[1, 2, 3, 4], [3, 4, 5, 6], [5, 6, 7]]), 9574 t(8, t(4, 3), [[1, 2, 3, 4], [4, 5, 6, 7], [7, 8]]), 9575 t(8, t(3, 3), [[1, 2, 3], [4, 5, 6], [7, 8]]), 9576 t(8, t(3, 6), [[1, 2, 3], [7, 8]]), 9577 t(10, t(7, 6), [[1, 2, 3, 4, 5, 6, 7], [7, 8, 9, 10]]), 9578 t(10, t(3, 8), [[1, 2, 3], [9, 10]]), 9579 ]; 9580 static foreach (Range; Filter!(isForwardRange, AllDummyRanges)) 9581 static foreach (Partial; [Yes.withPartial, No.withPartial]) 9582 foreach (e; listSpecial) 9583 { 9584 Range r; 9585 assert(r.take(e[0]).slide!(Yes.withPartial)(e[1].expand).equal!equal(e[2])); 9586 assert(r.take(e[0]).slide!(No.withPartial)(e[1].expand).equal!equal(e[2].dropBackOne)); 9587 } 9588} 9589 9590// test reverse with dummy ranges 9591@safe pure nothrow unittest 9592{ 9593 import std.algorithm.comparison : equal; 9594 import std.internal.test.dummyrange : AllDummyRanges; 9595 import std.meta : Filter, templateAnd; 9596 import std.typecons : tuple; 9597 alias t = tuple; 9598 9599 static immutable list = [ 9600 // slide expected 9601 t(1, 1, [[10], [9], [8], [7], [6], [5], [4], [3], [2], [1]]), 9602 t(2, 1, [[9, 10], [8, 9], [7, 8], [6, 7], [5, 6], [4, 5], [3, 4], [2, 3], [1, 2]]), 9603 t(5, 1, [[6, 7, 8, 9, 10], [5, 6, 7, 8, 9], [4, 5, 6, 7, 8], 9604 [3, 4, 5, 6, 7], [2, 3, 4, 5, 6], [1, 2, 3, 4, 5]]), 9605 t(2, 2, [[9, 10], [7, 8], [5, 6], [3, 4], [1, 2]]), 9606 t(2, 4, [[9, 10], [5, 6], [1, 2]]), 9607 ]; 9608 9609 static foreach (Range; Filter!(templateAnd!(hasSlicing, hasLength, isBidirectionalRange), AllDummyRanges)) 9610 {{ 9611 Range r; 9612 static foreach (Partial; [Yes.withPartial, No.withPartial]) 9613 { 9614 foreach (e; list) 9615 assert(r.slide!Partial(e[0], e[1]).retro.equal!equal(e[2])); 9616 9617 // front = back 9618 foreach (windowSize; 1 .. 10) 9619 foreach (stepSize; 1 .. 10) 9620 { 9621 auto slider = r.slide!Partial(windowSize, stepSize); 9622 auto sliderRetro = slider.retro.array; 9623 assert(slider.length == sliderRetro.length); 9624 assert(sliderRetro.retro.equal!equal(slider)); 9625 } 9626 } 9627 9628 // special cases 9629 assert(r.slide!(No.withPartial)(15).retro.walkLength == 0); 9630 assert(r.slide!(Yes.withPartial)(15).retro.equal!equal(iota(1, 11).only)); 9631 }} 9632} 9633 9634// test different sliceable ranges 9635@safe pure nothrow unittest 9636{ 9637 import std.algorithm.comparison : equal; 9638 import std.internal.test.dummyrange : AllDummyRanges; 9639 import std.meta : AliasSeq; 9640 9641 struct SliceableRange(Range, Flag!"withOpDollar" withOpDollar = No.withOpDollar, 9642 Flag!"withInfiniteness" withInfiniteness = No.withInfiniteness) 9643 { 9644 Range arr = 10.iota.array; // similar to DummyRange 9645 @property auto save() { return typeof(this)(arr); } 9646 @property auto front() { return arr[0]; } 9647 void popFront() { arr.popFront(); } 9648 auto opSlice(size_t i, size_t j) 9649 { 9650 // subslices can't be infinite 9651 return SliceableRange!(Range, withOpDollar, No.withInfiniteness)(arr[i .. j]); 9652 } 9653 9654 static if (withInfiniteness) 9655 { 9656 enum empty = false; 9657 } 9658 else 9659 { 9660 @property bool empty() { return arr.empty; } 9661 @property auto length() { return arr.length; } 9662 } 9663 9664 static if (withOpDollar) 9665 { 9666 static if (withInfiniteness) 9667 { 9668 struct Dollar {} 9669 Dollar opDollar() const { return Dollar.init; } 9670 9671 // Slice to dollar 9672 typeof(this) opSlice(size_t lower, Dollar) 9673 { 9674 return typeof(this)(arr[lower .. $]); 9675 } 9676 9677 } 9678 else 9679 { 9680 alias opDollar = length; 9681 } 9682 } 9683 } 9684 9685 import std.meta : Filter, templateNot; 9686 alias SliceableDummyRanges = Filter!(hasSlicing, AllDummyRanges); 9687 9688 static foreach (Partial; [Yes.withPartial, No.withPartial]) 9689 {{ 9690 static foreach (Range; SliceableDummyRanges) 9691 {{ 9692 Range r; 9693 r.reinit; 9694 r.arr[] -= 1; // use a 0-based array (for clarity) 9695 9696 assert(r.slide!Partial(2)[0].equal([0, 1])); 9697 assert(r.slide!Partial(2)[1].equal([1, 2])); 9698 9699 // saveable 9700 auto s = r.slide!Partial(2); 9701 assert(s[0 .. 2].equal!equal([[0, 1], [1, 2]])); 9702 s.save.popFront; 9703 assert(s[0 .. 2].equal!equal([[0, 1], [1, 2]])); 9704 9705 assert(r.slide!Partial(3)[1 .. 3].equal!equal([[1, 2, 3], [2, 3, 4]])); 9706 }} 9707 9708 static foreach (Range; Filter!(templateNot!isInfinite, SliceableDummyRanges)) 9709 {{ 9710 Range r; 9711 r.reinit; 9712 r.arr[] -= 1; // use a 0-based array (for clarity) 9713 9714 assert(r.slide!(No.withPartial)(6).equal!equal( 9715 [[0, 1, 2, 3, 4, 5], [1, 2, 3, 4, 5, 6], [2, 3, 4, 5, 6, 7], 9716 [3, 4, 5, 6, 7, 8], [4, 5, 6, 7, 8, 9]] 9717 )); 9718 assert(r.slide!(No.withPartial)(16).empty); 9719 9720 assert(r.slide!Partial(4)[0 .. $].equal(r.slide!Partial(4))); 9721 assert(r.slide!Partial(2)[$/2 .. $].equal!equal([[4, 5], [5, 6], [6, 7], [7, 8], [8, 9]])); 9722 assert(r.slide!Partial(2)[$ .. $].empty); 9723 9724 assert(r.slide!Partial(3).retro.equal!equal( 9725 [[7, 8, 9], [6, 7, 8], [5, 6, 7], [4, 5, 6], [3, 4, 5], [2, 3, 4], [1, 2, 3], [0, 1, 2]] 9726 )); 9727 }} 9728 9729 alias T = int[]; 9730 9731 // separate checks for infinity 9732 auto infIndex = SliceableRange!(T, No.withOpDollar, Yes.withInfiniteness)([0, 1, 2, 3]); 9733 assert(infIndex.slide!Partial(2)[0].equal([0, 1])); 9734 assert(infIndex.slide!Partial(2)[1].equal([1, 2])); 9735 9736 auto infDollar = SliceableRange!(T, Yes.withOpDollar, Yes.withInfiniteness)(); 9737 assert(infDollar.slide!Partial(2)[1 .. $].front.equal([1, 2])); 9738 assert(infDollar.slide!Partial(4)[0 .. $].front.equal([0, 1, 2, 3])); 9739 assert(infDollar.slide!Partial(4)[2 .. $].front.equal([2, 3, 4, 5])); 9740 }} 9741} 9742 9743// https://issues.dlang.org/show_bug.cgi?id=19082 9744@safe unittest 9745{ 9746 import std.algorithm.comparison : equal; 9747 import std.algorithm.iteration : map; 9748 assert([1].map!(x => x).slide(2).equal!equal([[1]])); 9749} 9750 9751private struct OnlyResult(Values...) 9752if (Values.length > 1) 9753{ 9754 private enum arity = Values.length; 9755 9756 private alias UnqualValues = staticMap!(Unqual, Values); 9757 9758 private this(return scope ref Values values) 9759 { 9760 ref @trusted unqual(T)(ref T x){return cast() x;} 9761 9762 // TODO: this calls any possible copy constructors without qualifiers. 9763 // Find a way to initialize values using qualified copy constructors. 9764 static foreach (i; 0 .. Values.length) 9765 { 9766 this.values[i] = unqual(values[i]); 9767 } 9768 this.backIndex = arity; 9769 } 9770 9771 bool empty() @property 9772 { 9773 return frontIndex >= backIndex; 9774 } 9775 9776 CommonType!Values front() @property 9777 { 9778 assert(!empty, "Attempting to fetch the front of an empty Only range"); 9779 return this[0]; 9780 } 9781 9782 void popFront() 9783 { 9784 assert(!empty, "Attempting to popFront an empty Only range"); 9785 ++frontIndex; 9786 } 9787 9788 CommonType!Values back() @property 9789 { 9790 assert(!empty, "Attempting to fetch the back of an empty Only range"); 9791 return this[$ - 1]; 9792 } 9793 9794 void popBack() 9795 { 9796 assert(!empty, "Attempting to popBack an empty Only range"); 9797 --backIndex; 9798 } 9799 9800 OnlyResult save() @property 9801 { 9802 return this; 9803 } 9804 9805 size_t length() const @property 9806 { 9807 return backIndex - frontIndex; 9808 } 9809 9810 alias opDollar = length; 9811 9812 @trusted CommonType!Values opIndex(size_t idx) 9813 { 9814 // when i + idx points to elements popped 9815 // with popBack 9816 assert(idx < length, "Attempting to fetch an out of bounds index from an Only range"); 9817 final switch (frontIndex + idx) 9818 static foreach (i, T; Values) 9819 case i: 9820 return cast(T) values[i]; 9821 } 9822 9823 OnlyResult opSlice() 9824 { 9825 return this; 9826 } 9827 9828 OnlyResult opSlice(size_t from, size_t to) 9829 { 9830 OnlyResult result = this; 9831 result.frontIndex += from; 9832 result.backIndex = this.frontIndex + to; 9833 assert( 9834 from <= to, 9835 "Attempting to slice an Only range with a larger first argument than the second." 9836 ); 9837 assert( 9838 to <= length, 9839 "Attempting to slice using an out of bounds index on an Only range" 9840 ); 9841 return result; 9842 } 9843 9844 private size_t frontIndex = 0; 9845 private size_t backIndex = 0; 9846 9847 // https://issues.dlang.org/show_bug.cgi?id=10643 9848 version (none) 9849 { 9850 import std.traits : hasElaborateAssign; 9851 static if (hasElaborateAssign!T) 9852 private UnqualValues values; 9853 else 9854 private UnqualValues values = void; 9855 } 9856 else 9857 // These may alias to shared or immutable data. Do not let the user 9858 // to access these directly, and do not allow mutation without checking 9859 // the qualifier. 9860 private UnqualValues values; 9861} 9862 9863// Specialize for single-element results 9864private struct OnlyResult(T) 9865{ 9866 @property T front() 9867 { 9868 assert(!empty, "Attempting to fetch the front of an empty Only range"); 9869 return fetchFront(); 9870 } 9871 @property T back() 9872 { 9873 assert(!empty, "Attempting to fetch the back of an empty Only range"); 9874 return fetchFront(); 9875 } 9876 @property bool empty() const { return _empty; } 9877 @property size_t length() const { return !_empty; } 9878 @property auto save() { return this; } 9879 void popFront() 9880 { 9881 assert(!_empty, "Attempting to popFront an empty Only range"); 9882 _empty = true; 9883 } 9884 void popBack() 9885 { 9886 assert(!_empty, "Attempting to popBack an empty Only range"); 9887 _empty = true; 9888 } 9889 alias opDollar = length; 9890 9891 private this()(return scope auto ref T value) 9892 { 9893 ref @trusted unqual(ref T x){return cast() x;} 9894 // TODO: this calls the possible copy constructor without qualifiers. 9895 // Find a way to initialize value using a qualified copy constructor. 9896 this._value = unqual(value); 9897 this._empty = false; 9898 } 9899 9900 T opIndex(size_t i) 9901 { 9902 assert(!_empty && i == 0, "Attempting to fetch an out of bounds index from an Only range"); 9903 return fetchFront(); 9904 } 9905 9906 OnlyResult opSlice() 9907 { 9908 return this; 9909 } 9910 9911 OnlyResult opSlice(size_t from, size_t to) 9912 { 9913 assert( 9914 from <= to, 9915 "Attempting to slice an Only range with a larger first argument than the second." 9916 ); 9917 assert( 9918 to <= length, 9919 "Attempting to slice using an out of bounds index on an Only range" 9920 ); 9921 OnlyResult copy = this; 9922 copy._empty = _empty || from == to; 9923 return copy; 9924 } 9925 9926 // This may alias to shared or immutable data. Do not let the user 9927 // to access this directly, and do not allow mutation without checking 9928 // the qualifier. 9929 private Unqual!T _value; 9930 private bool _empty = true; 9931 private @trusted T fetchFront() 9932 { 9933 return *cast(T*)&_value; 9934 } 9935} 9936 9937/** 9938Assemble `values` into a range that carries all its 9939elements in-situ. 9940 9941Useful when a single value or multiple disconnected values 9942must be passed to an algorithm expecting a range, without 9943having to perform dynamic memory allocation. 9944 9945As copying the range means copying all elements, it can be 9946safely returned from functions. For the same reason, copying 9947the returned range may be expensive for a large number of arguments. 9948 9949Params: 9950 values = the values to assemble together 9951 9952Returns: 9953 A `RandomAccessRange` of the assembled values. 9954 9955See_Also: $(LREF chain) to chain ranges 9956 */ 9957auto only(Values...)(return scope Values values) 9958if (!is(CommonType!Values == void)) 9959{ 9960 return OnlyResult!Values(values); 9961} 9962 9963/// ditto 9964auto only()() 9965{ 9966 // cannot use noreturn due to issue 22383 9967 struct EmptyElementType {} 9968 EmptyElementType[] result; 9969 return result; 9970} 9971 9972/// 9973@safe unittest 9974{ 9975 import std.algorithm.comparison : equal; 9976 import std.algorithm.iteration : filter, joiner, map; 9977 import std.algorithm.searching : findSplitBefore; 9978 import std.uni : isUpper; 9979 9980 assert(equal(only('���'), "���")); 9981 assert([1, 2, 3, 4].findSplitBefore(only(3))[0] == [1, 2]); 9982 9983 assert(only("one", "two", "three").joiner(" ").equal("one two three")); 9984 9985 string title = "The D Programming Language"; 9986 assert(title 9987 .filter!isUpper // take the upper case letters 9988 .map!only // make each letter its own range 9989 .joiner(".") // join the ranges together lazily 9990 .equal("T.D.P.L")); 9991} 9992 9993// https://issues.dlang.org/show_bug.cgi?id=20314 9994@safe unittest 9995{ 9996 import std.algorithm.iteration : joiner; 9997 9998 const string s = "foo", t = "bar"; 9999 10000 assert([only(s, t), only(t, s)].joiner(only(", ")).join == "foobar, barfoo"); 10001} 10002 10003// Tests the zero-element result 10004@safe unittest 10005{ 10006 import std.algorithm.comparison : equal; 10007 10008 auto emptyRange = only(); 10009 10010 alias EmptyRange = typeof(emptyRange); 10011 static assert(isInputRange!EmptyRange); 10012 static assert(isForwardRange!EmptyRange); 10013 static assert(isBidirectionalRange!EmptyRange); 10014 static assert(isRandomAccessRange!EmptyRange); 10015 static assert(hasLength!EmptyRange); 10016 static assert(hasSlicing!EmptyRange); 10017 10018 assert(emptyRange.empty); 10019 assert(emptyRange.length == 0); 10020 assert(emptyRange.equal(emptyRange[])); 10021 assert(emptyRange.equal(emptyRange.save)); 10022 assert(emptyRange[0 .. 0].equal(emptyRange)); 10023} 10024 10025// Tests the single-element result 10026@safe unittest 10027{ 10028 import std.algorithm.comparison : equal; 10029 import std.typecons : tuple; 10030 foreach (x; tuple(1, '1', 1.0, "1", [1])) 10031 { 10032 auto a = only(x); 10033 typeof(x)[] e = []; 10034 assert(a.front == x); 10035 assert(a.back == x); 10036 assert(!a.empty); 10037 assert(a.length == 1); 10038 assert(equal(a, a[])); 10039 assert(equal(a, a[0 .. 1])); 10040 assert(equal(a[0 .. 0], e)); 10041 assert(equal(a[1 .. 1], e)); 10042 assert(a[0] == x); 10043 10044 auto b = a.save; 10045 assert(equal(a, b)); 10046 a.popFront(); 10047 assert(a.empty && a.length == 0 && a[].empty); 10048 b.popBack(); 10049 assert(b.empty && b.length == 0 && b[].empty); 10050 10051 alias A = typeof(a); 10052 static assert(isInputRange!A); 10053 static assert(isForwardRange!A); 10054 static assert(isBidirectionalRange!A); 10055 static assert(isRandomAccessRange!A); 10056 static assert(hasLength!A); 10057 static assert(hasSlicing!A); 10058 } 10059 10060 auto imm = only!(immutable int)(1); 10061 immutable int[] imme = []; 10062 assert(imm.front == 1); 10063 assert(imm.back == 1); 10064 assert(!imm.empty); 10065 assert(imm.init.empty); // https://issues.dlang.org/show_bug.cgi?id=13441 10066 assert(imm.length == 1); 10067 assert(equal(imm, imm[])); 10068 assert(equal(imm, imm[0 .. 1])); 10069 assert(equal(imm[0 .. 0], imme)); 10070 assert(equal(imm[1 .. 1], imme)); 10071 assert(imm[0] == 1); 10072} 10073 10074// Tests multiple-element results 10075@safe unittest 10076{ 10077 import std.algorithm.comparison : equal; 10078 import std.algorithm.iteration : joiner; 10079 import std.meta : AliasSeq; 10080 static assert(!__traits(compiles, only(1, "1"))); 10081 10082 auto nums = only!(byte, uint, long)(1, 2, 3); 10083 static assert(is(ElementType!(typeof(nums)) == long)); 10084 assert(nums.length == 3); 10085 10086 foreach (i; 0 .. 3) 10087 assert(nums[i] == i + 1); 10088 10089 auto saved = nums.save; 10090 10091 foreach (i; 1 .. 4) 10092 { 10093 assert(nums.front == nums[0]); 10094 assert(nums.front == i); 10095 nums.popFront(); 10096 assert(nums.length == 3 - i); 10097 } 10098 10099 assert(nums.empty); 10100 10101 assert(saved.equal(only(1, 2, 3))); 10102 assert(saved.equal(saved[])); 10103 assert(saved[0 .. 1].equal(only(1))); 10104 assert(saved[0 .. 2].equal(only(1, 2))); 10105 assert(saved[0 .. 3].equal(saved)); 10106 assert(saved[1 .. 3].equal(only(2, 3))); 10107 assert(saved[2 .. 3].equal(only(3))); 10108 assert(saved[0 .. 0].empty); 10109 assert(saved[3 .. 3].empty); 10110 10111 alias data = AliasSeq!("one", "two", "three", "four"); 10112 static joined = 10113 ["one two", "one two three", "one two three four"]; 10114 string[] joinedRange = joined; 10115 10116 static foreach (argCount; 2 .. 5) 10117 {{ 10118 auto values = only(data[0 .. argCount]); 10119 alias Values = typeof(values); 10120 static assert(is(ElementType!Values == string)); 10121 static assert(isInputRange!Values); 10122 static assert(isForwardRange!Values); 10123 static assert(isBidirectionalRange!Values); 10124 static assert(isRandomAccessRange!Values); 10125 static assert(hasSlicing!Values); 10126 static assert(hasLength!Values); 10127 10128 assert(values.length == argCount); 10129 assert(values[0 .. $].equal(values[0 .. values.length])); 10130 assert(values.joiner(" ").equal(joinedRange.front)); 10131 joinedRange.popFront(); 10132 }} 10133 10134 assert(saved.retro.equal(only(3, 2, 1))); 10135 assert(saved.length == 3); 10136 10137 assert(saved.back == 3); 10138 saved.popBack(); 10139 assert(saved.length == 2); 10140 assert(saved.back == 2); 10141 10142 assert(saved.front == 1); 10143 saved.popFront(); 10144 assert(saved.length == 1); 10145 assert(saved.front == 2); 10146 10147 saved.popBack(); 10148 assert(saved.empty); 10149 10150 auto imm = only!(immutable int, immutable int)(42, 24); 10151 alias Imm = typeof(imm); 10152 static assert(is(ElementType!Imm == immutable(int))); 10153 assert(!imm.empty); 10154 assert(imm.init.empty); // https://issues.dlang.org/show_bug.cgi?id=13441 10155 assert(imm.front == 42); 10156 imm.popFront(); 10157 assert(imm.front == 24); 10158 imm.popFront(); 10159 assert(imm.empty); 10160 10161 static struct Test { int* a; } 10162 immutable(Test) test; 10163 cast(void) only(test, test); // Works with mutable indirection 10164} 10165 10166// https://issues.dlang.org/show_bug.cgi?id=21129 10167@safe unittest 10168{ 10169 auto range = () @safe { 10170 const(char)[5] staticStr = "Hello"; 10171 10172 // `only` must store a char[5] - not a char[]! 10173 return only(staticStr, " World"); 10174 } (); 10175 10176 assert(range.join == "Hello World"); 10177} 10178 10179// https://issues.dlang.org/show_bug.cgi?id=21129 10180@safe unittest 10181{ 10182 struct AliasedString 10183 { 10184 const(char)[5] staticStr = "Hello"; 10185 10186 @property const(char)[] slice() const 10187 { 10188 return staticStr[]; 10189 } 10190 alias slice this; 10191 } 10192 10193 auto range = () @safe { 10194 auto hello = AliasedString(); 10195 10196 // a copy of AliasedString is stored in the range. 10197 return only(hello, " World"); 10198 } (); 10199 10200 assert(range.join == "Hello World"); 10201} 10202 10203// https://issues.dlang.org/show_bug.cgi?id=21022 10204@safe pure nothrow unittest 10205{ 10206 struct S 10207 { 10208 int* mem; 10209 } 10210 10211 immutable S x; 10212 immutable(S)[] arr; 10213 auto r1 = arr.chain(x.only, only(x, x)); 10214} 10215 10216/** 10217Iterate over `range` with an attached index variable. 10218 10219Each element is a $(REF Tuple, std,typecons) containing the index 10220and the element, in that order, where the index member is named `index` 10221and the element member is named `value`. 10222 10223The index starts at `start` and is incremented by one on every iteration. 10224 10225Overflow: 10226 If `range` has length, then it is an error to pass a value for `start` 10227 so that `start + range.length` is bigger than `Enumerator.max`, thus 10228 it is ensured that overflow cannot happen. 10229 10230 If `range` does not have length, and `popFront` is called when 10231 `front.index == Enumerator.max`, the index will overflow and 10232 continue from `Enumerator.min`. 10233 10234Params: 10235 range = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to attach indexes to 10236 start = the number to start the index counter from 10237 10238Returns: 10239 At minimum, an input range. All other range primitives are given in the 10240 resulting range if `range` has them. The exceptions are the bidirectional 10241 primitives, which are propagated only if `range` has length. 10242 10243Example: 10244Useful for using `foreach` with an index loop variable: 10245---- 10246 import std.stdio : stdin, stdout; 10247 import std.range : enumerate; 10248 10249 foreach (lineNum, line; stdin.byLine().enumerate(1)) 10250 stdout.writefln("line #%s: %s", lineNum, line); 10251---- 10252*/ 10253auto enumerate(Enumerator = size_t, Range)(Range range, Enumerator start = 0) 10254if (isIntegral!Enumerator && isInputRange!Range) 10255in 10256{ 10257 static if (hasLength!Range) 10258 { 10259 // TODO: core.checkedint supports mixed signedness yet? 10260 import core.checkedint : adds, addu; 10261 import std.conv : ConvException, to; 10262 import std.traits : isSigned, Largest, Signed; 10263 10264 alias LengthType = typeof(range.length); 10265 bool overflow; 10266 static if (isSigned!Enumerator && isSigned!LengthType) 10267 auto result = adds(start, range.length, overflow); 10268 else static if (isSigned!Enumerator) 10269 { 10270 alias signed_t = Largest!(Enumerator, Signed!LengthType); 10271 signed_t signedLength; 10272 //This is to trick the compiler because if length is enum 10273 //the compiler complains about unreachable code. 10274 auto getLength() 10275 { 10276 return range.length; 10277 } 10278 //Can length fit in the signed type 10279 assert(getLength() < signed_t.max, 10280 "a signed length type is required but the range's length() is too great"); 10281 signedLength = range.length; 10282 auto result = adds(start, signedLength, overflow); 10283 } 10284 else 10285 { 10286 static if (isSigned!LengthType) 10287 assert(range.length >= 0); 10288 auto result = addu(start, range.length, overflow); 10289 } 10290 10291 assert(!overflow && result <= Enumerator.max); 10292 } 10293} 10294do 10295{ 10296 // TODO: Relax isIntegral!Enumerator to allow user-defined integral types 10297 static struct Result 10298 { 10299 import std.typecons : Tuple; 10300 10301 private: 10302 alias ElemType = Tuple!(Enumerator, "index", ElementType!Range, "value"); 10303 Range range; 10304 Unqual!Enumerator index; 10305 10306 public: 10307 ElemType front() @property 10308 { 10309 assert(!range.empty, "Attempting to fetch the front of an empty enumerate"); 10310 return typeof(return)(index, range.front); 10311 } 10312 10313 static if (isInfinite!Range) 10314 enum bool empty = false; 10315 else 10316 { 10317 bool empty() @property 10318 { 10319 return range.empty; 10320 } 10321 } 10322 10323 void popFront() 10324 { 10325 assert(!range.empty, "Attempting to popFront an empty enumerate"); 10326 range.popFront(); 10327 ++index; // When !hasLength!Range, overflow is expected 10328 } 10329 10330 static if (isForwardRange!Range) 10331 { 10332 Result save() @property 10333 { 10334 return typeof(return)(range.save, index); 10335 } 10336 } 10337 10338 static if (hasLength!Range) 10339 { 10340 mixin ImplementLength!range; 10341 10342 static if (isBidirectionalRange!Range) 10343 { 10344 ElemType back() @property 10345 { 10346 assert(!range.empty, "Attempting to fetch the back of an empty enumerate"); 10347 return typeof(return)(cast(Enumerator)(index + range.length - 1), range.back); 10348 } 10349 10350 void popBack() 10351 { 10352 assert(!range.empty, "Attempting to popBack an empty enumerate"); 10353 range.popBack(); 10354 } 10355 } 10356 } 10357 10358 static if (isRandomAccessRange!Range) 10359 { 10360 ElemType opIndex(size_t i) 10361 { 10362 return typeof(return)(cast(Enumerator)(index + i), range[i]); 10363 } 10364 } 10365 10366 static if (hasSlicing!Range) 10367 { 10368 static if (hasLength!Range) 10369 { 10370 Result opSlice(size_t i, size_t j) 10371 { 10372 return typeof(return)(range[i .. j], cast(Enumerator)(index + i)); 10373 } 10374 } 10375 else 10376 { 10377 static struct DollarToken {} 10378 enum opDollar = DollarToken.init; 10379 10380 Result opSlice(size_t i, DollarToken) 10381 { 10382 return typeof(return)(range[i .. $], cast(Enumerator)(index + i)); 10383 } 10384 10385 auto opSlice(size_t i, size_t j) 10386 { 10387 return this[i .. $].takeExactly(j - 1); 10388 } 10389 } 10390 } 10391 } 10392 10393 return Result(range, start); 10394} 10395 10396/// Can start enumeration from a negative position: 10397pure @safe nothrow unittest 10398{ 10399 import std.array : assocArray; 10400 import std.range : enumerate; 10401 10402 bool[int] aa = true.repeat(3).enumerate(-1).assocArray(); 10403 assert(aa[-1]); 10404 assert(aa[0]); 10405 assert(aa[1]); 10406} 10407 10408// Make sure passing qualified types works 10409pure @safe nothrow unittest 10410{ 10411 char[4] v; 10412 immutable start = 2; 10413 v[2 .. $].enumerate(start); 10414} 10415 10416pure @safe nothrow unittest 10417{ 10418 import std.internal.test.dummyrange : AllDummyRanges; 10419 import std.meta : AliasSeq; 10420 import std.typecons : tuple; 10421 10422 static struct HasSlicing 10423 { 10424 typeof(this) front() @property { return typeof(this).init; } 10425 bool empty() @property { return true; } 10426 void popFront() {} 10427 10428 typeof(this) opSlice(size_t, size_t) 10429 { 10430 return typeof(this)(); 10431 } 10432 } 10433 10434 static foreach (DummyType; AliasSeq!(AllDummyRanges, HasSlicing)) 10435 {{ 10436 alias R = typeof(enumerate(DummyType.init)); 10437 static assert(isInputRange!R); 10438 static assert(isForwardRange!R == isForwardRange!DummyType); 10439 static assert(isRandomAccessRange!R == isRandomAccessRange!DummyType); 10440 static assert(!hasAssignableElements!R); 10441 10442 static if (hasLength!DummyType) 10443 { 10444 static assert(hasLength!R); 10445 static assert(isBidirectionalRange!R == 10446 isBidirectionalRange!DummyType); 10447 } 10448 10449 static assert(hasSlicing!R == hasSlicing!DummyType); 10450 }} 10451 10452 static immutable values = ["zero", "one", "two", "three"]; 10453 auto enumerated = values[].enumerate(); 10454 assert(!enumerated.empty); 10455 assert(enumerated.front == tuple(0, "zero")); 10456 assert(enumerated.back == tuple(3, "three")); 10457 10458 typeof(enumerated) saved = enumerated.save; 10459 saved.popFront(); 10460 assert(enumerated.front == tuple(0, "zero")); 10461 assert(saved.front == tuple(1, "one")); 10462 assert(saved.length == enumerated.length - 1); 10463 saved.popBack(); 10464 assert(enumerated.back == tuple(3, "three")); 10465 assert(saved.back == tuple(2, "two")); 10466 saved.popFront(); 10467 assert(saved.front == tuple(2, "two")); 10468 assert(saved.back == tuple(2, "two")); 10469 saved.popFront(); 10470 assert(saved.empty); 10471 10472 size_t control = 0; 10473 foreach (i, v; enumerated) 10474 { 10475 static assert(is(typeof(i) == size_t)); 10476 static assert(is(typeof(v) == typeof(values[0]))); 10477 assert(i == control); 10478 assert(v == values[i]); 10479 assert(tuple(i, v) == enumerated[i]); 10480 ++control; 10481 } 10482 10483 assert(enumerated[0 .. $].front == tuple(0, "zero")); 10484 assert(enumerated[$ - 1 .. $].front == tuple(3, "three")); 10485 10486 foreach (i; 0 .. 10) 10487 { 10488 auto shifted = values[0 .. 2].enumerate(i); 10489 assert(shifted.front == tuple(i, "zero")); 10490 assert(shifted[0] == shifted.front); 10491 10492 auto next = tuple(i + 1, "one"); 10493 assert(shifted[1] == next); 10494 shifted.popFront(); 10495 assert(shifted.front == next); 10496 shifted.popFront(); 10497 assert(shifted.empty); 10498 } 10499 10500 static foreach (T; AliasSeq!(ubyte, byte, uint, int)) 10501 {{ 10502 auto inf = 42.repeat().enumerate(T.max); 10503 alias Inf = typeof(inf); 10504 static assert(isInfinite!Inf); 10505 static assert(hasSlicing!Inf); 10506 10507 // test overflow 10508 assert(inf.front == tuple(T.max, 42)); 10509 inf.popFront(); 10510 assert(inf.front == tuple(T.min, 42)); 10511 10512 // test slicing 10513 inf = inf[42 .. $]; 10514 assert(inf.front == tuple(T.min + 42, 42)); 10515 auto window = inf[0 .. 2]; 10516 assert(window.length == 1); 10517 assert(window.front == inf.front); 10518 window.popFront(); 10519 assert(window.empty); 10520 }} 10521} 10522 10523pure @safe unittest 10524{ 10525 import std.algorithm.comparison : equal; 10526 import std.meta : AliasSeq; 10527 static immutable int[] values = [0, 1, 2, 3, 4]; 10528 static foreach (T; AliasSeq!(ubyte, ushort, uint, ulong)) 10529 {{ 10530 auto enumerated = values.enumerate!T(); 10531 static assert(is(typeof(enumerated.front.index) == T)); 10532 assert(enumerated.equal(values[].zip(values))); 10533 10534 foreach (T i; 0 .. 5) 10535 { 10536 auto subset = values[cast(size_t) i .. $]; 10537 auto offsetEnumerated = subset.enumerate(i); 10538 static assert(is(typeof(enumerated.front.index) == T)); 10539 assert(offsetEnumerated.equal(subset.zip(subset))); 10540 } 10541 }} 10542} 10543@nogc @safe unittest 10544{ 10545 const val = iota(1, 100).enumerate(1); 10546} 10547@nogc @safe unittest 10548{ 10549 import core.exception : AssertError; 10550 import std.exception : assertThrown; 10551 struct RangePayload { 10552 enum length = size_t.max; 10553 void popFront() {} 10554 int front() { return 0; } 10555 bool empty() { return true; } 10556 } 10557 RangePayload thePayload; 10558 //Assertion won't happen when contracts are disabled for -release. 10559 debug assertThrown!AssertError(enumerate(thePayload, -10)); 10560} 10561// https://issues.dlang.org/show_bug.cgi?id=10939 10562version (none) 10563{ 10564 // Re-enable (or remove) if 10939 is resolved. 10565 /+pure+/ @safe unittest // Impure because of std.conv.to 10566 { 10567 import core.exception : RangeError; 10568 import std.exception : assertNotThrown, assertThrown; 10569 import std.meta : AliasSeq; 10570 10571 static immutable values = [42]; 10572 10573 static struct SignedLengthRange 10574 { 10575 immutable(int)[] _values = values; 10576 10577 int front() @property { assert(false); } 10578 bool empty() @property { assert(false); } 10579 void popFront() { assert(false); } 10580 10581 int length() @property 10582 { 10583 return cast(int)_values.length; 10584 } 10585 } 10586 10587 SignedLengthRange svalues; 10588 static foreach (Enumerator; AliasSeq!(ubyte, byte, ushort, short, uint, int, ulong, long)) 10589 { 10590 assertThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max)); 10591 assertNotThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max - values.length)); 10592 assertThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max - values.length + 1)); 10593 10594 assertThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max)); 10595 assertNotThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max - values.length)); 10596 assertThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max - values.length + 1)); 10597 } 10598 10599 static foreach (Enumerator; AliasSeq!(byte, short, int)) 10600 { 10601 assertThrown!RangeError(repeat(0, uint.max).enumerate!Enumerator()); 10602 } 10603 10604 assertNotThrown!RangeError(repeat(0, uint.max).enumerate!long()); 10605 } 10606} 10607 10608/** 10609 Returns true if `fn` accepts variables of type T1 and T2 in any order. 10610 The following code should compile: 10611 --- 10612 (ref T1 a, ref T2 b) 10613 { 10614 fn(a, b); 10615 fn(b, a); 10616 } 10617 --- 10618*/ 10619template isTwoWayCompatible(alias fn, T1, T2) 10620{ 10621 enum isTwoWayCompatible = is(typeof((ref T1 a, ref T2 b) 10622 { 10623 cast(void) fn(a, b); 10624 cast(void) fn(b, a); 10625 } 10626 )); 10627} 10628 10629/// 10630@safe unittest 10631{ 10632 void func1(int a, int b); 10633 void func2(int a, float b); 10634 10635 static assert(isTwoWayCompatible!(func1, int, int)); 10636 static assert(isTwoWayCompatible!(func1, short, int)); 10637 static assert(!isTwoWayCompatible!(func2, int, float)); 10638 10639 void func3(ref int a, ref int b); 10640 static assert( isTwoWayCompatible!(func3, int, int)); 10641 static assert(!isTwoWayCompatible!(func3, short, int)); 10642} 10643 10644 10645/** 10646 Policy used with the searching primitives `lowerBound`, $(D 10647 upperBound), and `equalRange` of $(LREF SortedRange) below. 10648 */ 10649enum SearchPolicy 10650{ 10651 /** 10652 Searches in a linear fashion. 10653 */ 10654 linear, 10655 10656 /** 10657 Searches with a step that is grows linearly (1, 2, 3,...) 10658 leading to a quadratic search schedule (indexes tried are 0, 1, 10659 3, 6, 10, 15, 21, 28,...) Once the search overshoots its target, 10660 the remaining interval is searched using binary search. The 10661 search is completed in $(BIGOH sqrt(n)) time. Use it when you 10662 are reasonably confident that the value is around the beginning 10663 of the range. 10664 */ 10665 trot, 10666 10667 /** 10668 Performs a $(LINK2 https://en.wikipedia.org/wiki/Exponential_search, 10669 galloping search algorithm), i.e. searches 10670 with a step that doubles every time, (1, 2, 4, 8, ...) leading 10671 to an exponential search schedule (indexes tried are 0, 1, 3, 10672 7, 15, 31, 63,...) Once the search overshoots its target, the 10673 remaining interval is searched using binary search. A value is 10674 found in $(BIGOH log(n)) time. 10675 */ 10676 gallop, 10677 10678 /** 10679 Searches using a classic interval halving policy. The search 10680 starts in the middle of the range, and each search step cuts 10681 the range in half. This policy finds a value in $(BIGOH log(n)) 10682 time but is less cache friendly than `gallop` for large 10683 ranges. The `binarySearch` policy is used as the last step 10684 of `trot`, `gallop`, `trotBackwards`, and $(D 10685 gallopBackwards) strategies. 10686 */ 10687 binarySearch, 10688 10689 /** 10690 Similar to `trot` but starts backwards. Use it when 10691 confident that the value is around the end of the range. 10692 */ 10693 trotBackwards, 10694 10695 /** 10696 Similar to `gallop` but starts backwards. Use it when 10697 confident that the value is around the end of the range. 10698 */ 10699 gallopBackwards 10700} 10701 10702/// 10703@safe unittest 10704{ 10705 import std.algorithm.comparison : equal; 10706 10707 auto a = assumeSorted([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); 10708 auto p1 = a.upperBound!(SearchPolicy.binarySearch)(3); 10709 assert(p1.equal([4, 5, 6, 7, 8, 9])); 10710 10711 auto p2 = a.lowerBound!(SearchPolicy.gallop)(4); 10712 assert(p2.equal([0, 1, 2, 3])); 10713} 10714 10715/** 10716 Options for $(LREF SortedRange) ranges (below). 10717*/ 10718enum SortedRangeOptions 10719{ 10720 /** 10721 Assume, that the range is sorted without checking. 10722 */ 10723 assumeSorted, 10724 10725 /** 10726 All elements of the range are checked to be sorted. 10727 The check is performed in O(n) time. 10728 */ 10729 checkStrictly, 10730 10731 /** 10732 Some elements of the range are checked to be sorted. 10733 For ranges with random order, this will almost surely 10734 detect, that it is not sorted. For almost sorted ranges 10735 it's more likely to fail. The checked elements are choosen 10736 in a deterministic manner, which makes this check reproducable. 10737 The check is performed in O(log(n)) time. 10738 */ 10739 checkRoughly, 10740} 10741 10742/// 10743@safe pure unittest 10744{ 10745 // create a SortedRange, that's checked strictly 10746 SortedRange!(int[],"a < b", SortedRangeOptions.checkStrictly)([ 1, 3, 5, 7, 9 ]); 10747} 10748 10749/** 10750 Represents a sorted range. In addition to the regular range 10751 primitives, supports additional operations that take advantage of the 10752 ordering, such as merge and binary search. To obtain a $(D 10753 SortedRange) from an unsorted range `r`, use 10754 $(REF sort, std,algorithm,sorting) which sorts `r` in place and returns the 10755 corresponding `SortedRange`. To construct a `SortedRange` from a range 10756 `r` that is known to be already sorted, use $(LREF assumeSorted). 10757 10758 Params: 10759 pred: The predicate used to define the sortedness 10760 opt: Controls how strongly the range is checked for sortedness. 10761 Will only be used for `RandomAccessRanges`. 10762 Will not be used in CTFE. 10763*/ 10764struct SortedRange(Range, alias pred = "a < b", 10765 SortedRangeOptions opt = SortedRangeOptions.assumeSorted) 10766if (isInputRange!Range && !isInstanceOf!(SortedRange, Range)) 10767{ 10768 import std.functional : binaryFun; 10769 10770 private alias predFun = binaryFun!pred; 10771 private bool geq(L, R)(L lhs, R rhs) 10772 { 10773 return !predFun(lhs, rhs); 10774 } 10775 private bool gt(L, R)(L lhs, R rhs) 10776 { 10777 return predFun(rhs, lhs); 10778 } 10779 private Range _input; 10780 10781 // Undocummented because a clearer way to invoke is by calling 10782 // assumeSorted. 10783 this(Range input) 10784 { 10785 static if (opt == SortedRangeOptions.checkRoughly) 10786 { 10787 roughlyVerifySorted(input); 10788 } 10789 static if (opt == SortedRangeOptions.checkStrictly) 10790 { 10791 strictlyVerifySorted(input); 10792 } 10793 this._input = input; 10794 } 10795 10796 // Assertion only. 10797 static if (opt == SortedRangeOptions.checkRoughly) 10798 private void roughlyVerifySorted(Range r) 10799 { 10800 if (!__ctfe) 10801 { 10802 static if (isRandomAccessRange!Range && hasLength!Range) 10803 { 10804 import core.bitop : bsr; 10805 import std.algorithm.sorting : isSorted; 10806 import std.exception : enforce; 10807 10808 // Check the sortedness of the input 10809 if (r.length < 2) return; 10810 10811 immutable size_t msb = bsr(r.length) + 1; 10812 assert(msb > 0 && msb <= r.length); 10813 immutable step = r.length / msb; 10814 auto st = stride(r, step); 10815 10816 enforce(isSorted!pred(st), "Range is not sorted"); 10817 } 10818 } 10819 } 10820 10821 // Assertion only. 10822 static if (opt == SortedRangeOptions.checkStrictly) 10823 private void strictlyVerifySorted(Range r) 10824 { 10825 if (!__ctfe) 10826 { 10827 static if (isRandomAccessRange!Range && hasLength!Range) 10828 { 10829 import std.algorithm.sorting : isSorted; 10830 import std.exception : enforce; 10831 10832 enforce(isSorted!pred(r), "Range is not sorted"); 10833 } 10834 } 10835 } 10836 10837 /// Range primitives. 10838 @property bool empty() //const 10839 { 10840 return this._input.empty; 10841 } 10842 10843 /// Ditto 10844 static if (isForwardRange!Range) 10845 @property auto save() 10846 { 10847 // Avoid the constructor 10848 typeof(this) result = this; 10849 result._input = _input.save; 10850 return result; 10851 } 10852 10853 /// Ditto 10854 @property auto ref front() 10855 { 10856 return _input.front; 10857 } 10858 10859 /// Ditto 10860 void popFront() 10861 { 10862 _input.popFront(); 10863 } 10864 10865 /// Ditto 10866 static if (isBidirectionalRange!Range) 10867 { 10868 @property auto ref back() 10869 { 10870 return _input.back; 10871 } 10872 10873 /// Ditto 10874 void popBack() 10875 { 10876 _input.popBack(); 10877 } 10878 } 10879 10880 /// Ditto 10881 static if (isRandomAccessRange!Range) 10882 auto ref opIndex(size_t i) 10883 { 10884 return _input[i]; 10885 } 10886 10887 /// Ditto 10888 static if (hasSlicing!Range) 10889 auto opSlice(size_t a, size_t b) return scope 10890 { 10891 assert( 10892 a <= b, 10893 "Attempting to slice a SortedRange with a larger first argument than the second." 10894 ); 10895 typeof(this) result = this; 10896 result._input = _input[a .. b];// skip checking 10897 return result; 10898 } 10899 10900 mixin ImplementLength!_input; 10901 10902/** 10903 Releases the controlled range and returns it. 10904 10905 This does the opposite of $(LREF assumeSorted): instead of turning a range 10906 into a `SortedRange`, it extracts the original range back out of the `SortedRange` 10907 using $(REF, move, std,algorithm,mutation). 10908*/ 10909 auto release() return scope 10910 { 10911 import std.algorithm.mutation : move; 10912 return move(_input); 10913 } 10914 10915 /// 10916 static if (is(Range : int[])) 10917 @safe unittest 10918 { 10919 import std.algorithm.sorting : sort; 10920 int[3] data = [ 1, 2, 3 ]; 10921 auto a = assumeSorted(data[]); 10922 assert(a == sort!"a < b"(data[])); 10923 int[] p = a.release(); 10924 assert(p == [ 1, 2, 3 ]); 10925 } 10926 10927 // Assuming a predicate "test" that returns 0 for a left portion 10928 // of the range and then 1 for the rest, returns the index at 10929 // which the first 1 appears. Used internally by the search routines. 10930 private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v) 10931 if (sp == SearchPolicy.binarySearch && isRandomAccessRange!Range && hasLength!Range) 10932 { 10933 size_t first = 0, count = _input.length; 10934 while (count > 0) 10935 { 10936 immutable step = count / 2, it = first + step; 10937 if (!test(_input[it], v)) 10938 { 10939 first = it + 1; 10940 count -= step + 1; 10941 } 10942 else 10943 { 10944 count = step; 10945 } 10946 } 10947 return first; 10948 } 10949 10950 // Specialization for trot and gallop 10951 private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v) 10952 if ((sp == SearchPolicy.trot || sp == SearchPolicy.gallop) 10953 && isRandomAccessRange!Range) 10954 { 10955 if (empty || test(front, v)) return 0; 10956 immutable count = length; 10957 if (count == 1) return 1; 10958 size_t below = 0, above = 1, step = 2; 10959 while (!test(_input[above], v)) 10960 { 10961 // Still too small, update below and increase gait 10962 below = above; 10963 immutable next = above + step; 10964 if (next >= count) 10965 { 10966 // Overshot - the next step took us beyond the end. So 10967 // now adjust next and simply exit the loop to do the 10968 // binary search thingie. 10969 above = count; 10970 break; 10971 } 10972 // Still in business, increase step and continue 10973 above = next; 10974 static if (sp == SearchPolicy.trot) 10975 ++step; 10976 else 10977 step <<= 1; 10978 } 10979 return below + this[below .. above].getTransitionIndex!( 10980 SearchPolicy.binarySearch, test, V)(v); 10981 } 10982 10983 // Specialization for trotBackwards and gallopBackwards 10984 private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v) 10985 if ((sp == SearchPolicy.trotBackwards || sp == SearchPolicy.gallopBackwards) 10986 && isRandomAccessRange!Range) 10987 { 10988 immutable count = length; 10989 if (empty || !test(back, v)) return count; 10990 if (count == 1) return 0; 10991 size_t below = count - 2, above = count - 1, step = 2; 10992 while (test(_input[below], v)) 10993 { 10994 // Still too large, update above and increase gait 10995 above = below; 10996 if (below < step) 10997 { 10998 // Overshot - the next step took us beyond the end. So 10999 // now adjust next and simply fall through to do the 11000 // binary search thingie. 11001 below = 0; 11002 break; 11003 } 11004 // Still in business, increase step and continue 11005 below -= step; 11006 static if (sp == SearchPolicy.trot) 11007 ++step; 11008 else 11009 step <<= 1; 11010 } 11011 return below + this[below .. above].getTransitionIndex!( 11012 SearchPolicy.binarySearch, test, V)(v); 11013 } 11014 11015// lowerBound 11016/** 11017 This function uses a search with policy `sp` to find the 11018 largest left subrange on which $(D pred(x, value)) is `true` for 11019 all `x` (e.g., if `pred` is "less than", returns the portion of 11020 the range with elements strictly smaller than `value`). The search 11021 schedule and its complexity are documented in 11022 $(LREF SearchPolicy). 11023*/ 11024 auto lowerBound(SearchPolicy sp = SearchPolicy.binarySearch, V)(V value) 11025 if (isTwoWayCompatible!(predFun, ElementType!Range, V) 11026 && hasSlicing!Range) 11027 { 11028 return this[0 .. getTransitionIndex!(sp, geq)(value)]; 11029 } 11030 11031 /// 11032 static if (is(Range : int[])) 11033 @safe unittest 11034 { 11035 import std.algorithm.comparison : equal; 11036 auto a = assumeSorted([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]); 11037 auto p = a.lowerBound(4); 11038 assert(equal(p, [ 0, 1, 2, 3 ])); 11039 } 11040 11041// upperBound 11042/** 11043This function searches with policy `sp` to find the largest right 11044subrange on which $(D pred(value, x)) is `true` for all `x` 11045(e.g., if `pred` is "less than", returns the portion of the range 11046with elements strictly greater than `value`). The search schedule 11047and its complexity are documented in $(LREF SearchPolicy). 11048 11049For ranges that do not offer random access, `SearchPolicy.linear` 11050is the only policy allowed (and it must be specified explicitly lest it exposes 11051user code to unexpected inefficiencies). For random-access searches, all 11052policies are allowed, and `SearchPolicy.binarySearch` is the default. 11053*/ 11054 auto upperBound(SearchPolicy sp = SearchPolicy.binarySearch, V)(V value) 11055 if (isTwoWayCompatible!(predFun, ElementType!Range, V)) 11056 { 11057 static assert(hasSlicing!Range || sp == SearchPolicy.linear, 11058 "Specify SearchPolicy.linear explicitly for " 11059 ~ typeof(this).stringof); 11060 static if (sp == SearchPolicy.linear) 11061 { 11062 for (; !_input.empty && !predFun(value, _input.front); 11063 _input.popFront()) 11064 { 11065 } 11066 return this; 11067 } 11068 else 11069 { 11070 return this[getTransitionIndex!(sp, gt)(value) .. length]; 11071 } 11072 } 11073 11074 /// 11075 static if (is(Range : int[])) 11076 @safe unittest 11077 { 11078 import std.algorithm.comparison : equal; 11079 auto a = assumeSorted([ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]); 11080 auto p = a.upperBound(3); 11081 assert(equal(p, [4, 4, 5, 6])); 11082 } 11083 11084 11085// equalRange 11086/** 11087 Returns the subrange containing all elements `e` for which both $(D 11088 pred(e, value)) and $(D pred(value, e)) evaluate to `false` (e.g., 11089 if `pred` is "less than", returns the portion of the range with 11090 elements equal to `value`). Uses a classic binary search with 11091 interval halving until it finds a value that satisfies the condition, 11092 then uses `SearchPolicy.gallopBackwards` to find the left boundary 11093 and `SearchPolicy.gallop` to find the right boundary. These 11094 policies are justified by the fact that the two boundaries are likely 11095 to be near the first found value (i.e., equal ranges are relatively 11096 small). Completes the entire search in $(BIGOH log(n)) time. 11097*/ 11098 auto equalRange(V)(V value) 11099 if (isTwoWayCompatible!(predFun, ElementType!Range, V) 11100 && isRandomAccessRange!Range) 11101 { 11102 size_t first = 0, count = _input.length; 11103 while (count > 0) 11104 { 11105 immutable step = count / 2; 11106 auto it = first + step; 11107 if (predFun(_input[it], value)) 11108 { 11109 // Less than value, bump left bound up 11110 first = it + 1; 11111 count -= step + 1; 11112 } 11113 else if (predFun(value, _input[it])) 11114 { 11115 // Greater than value, chop count 11116 count = step; 11117 } 11118 else 11119 { 11120 // Equal to value, do binary searches in the 11121 // leftover portions 11122 // Gallop towards the left end as it's likely nearby 11123 immutable left = first 11124 + this[first .. it] 11125 .lowerBound!(SearchPolicy.gallopBackwards)(value).length; 11126 first += count; 11127 // Gallop towards the right end as it's likely nearby 11128 immutable right = first 11129 - this[it + 1 .. first] 11130 .upperBound!(SearchPolicy.gallop)(value).length; 11131 return this[left .. right]; 11132 } 11133 } 11134 return this.init; 11135 } 11136 11137 /// 11138 static if (is(Range : int[])) 11139 @safe unittest 11140 { 11141 import std.algorithm.comparison : equal; 11142 auto a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]; 11143 auto r = a.assumeSorted.equalRange(3); 11144 assert(equal(r, [ 3, 3, 3 ])); 11145 } 11146 11147// trisect 11148/** 11149Returns a tuple `r` such that `r[0]` is the same as the result 11150of `lowerBound(value)`, `r[1]` is the same as the result of $(D 11151equalRange(value)), and `r[2]` is the same as the result of $(D 11152upperBound(value)). The call is faster than computing all three 11153separately. Uses a search schedule similar to $(D 11154equalRange). Completes the entire search in $(BIGOH log(n)) time. 11155*/ 11156 auto trisect(V)(V value) 11157 if (isTwoWayCompatible!(predFun, ElementType!Range, V) 11158 && isRandomAccessRange!Range && hasLength!Range) 11159 { 11160 import std.typecons : tuple; 11161 size_t first = 0, count = _input.length; 11162 while (count > 0) 11163 { 11164 immutable step = count / 2; 11165 auto it = first + step; 11166 if (predFun(_input[it], value)) 11167 { 11168 // Less than value, bump left bound up 11169 first = it + 1; 11170 count -= step + 1; 11171 } 11172 else if (predFun(value, _input[it])) 11173 { 11174 // Greater than value, chop count 11175 count = step; 11176 } 11177 else 11178 { 11179 // Equal to value, do binary searches in the 11180 // leftover portions 11181 // Gallop towards the left end as it's likely nearby 11182 immutable left = first 11183 + this[first .. it] 11184 .lowerBound!(SearchPolicy.gallopBackwards)(value).length; 11185 first += count; 11186 // Gallop towards the right end as it's likely nearby 11187 immutable right = first 11188 - this[it + 1 .. first] 11189 .upperBound!(SearchPolicy.gallop)(value).length; 11190 return tuple(this[0 .. left], this[left .. right], 11191 this[right .. length]); 11192 } 11193 } 11194 // No equal element was found 11195 return tuple(this[0 .. first], this.init, this[first .. length]); 11196 } 11197 11198 /// 11199 static if (is(Range : int[])) 11200 @safe unittest 11201 { 11202 import std.algorithm.comparison : equal; 11203 auto a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]; 11204 auto r = assumeSorted(a).trisect(3); 11205 assert(equal(r[0], [ 1, 2 ])); 11206 assert(equal(r[1], [ 3, 3, 3 ])); 11207 assert(equal(r[2], [ 4, 4, 5, 6 ])); 11208 } 11209 11210// contains 11211/** 11212Returns `true` if and only if `value` can be found in $(D 11213range), which is assumed to be sorted. Performs $(BIGOH log(r.length)) 11214evaluations of `pred`. 11215 */ 11216 11217 bool contains(V)(V value) 11218 if (isRandomAccessRange!Range) 11219 { 11220 if (empty) return false; 11221 immutable i = getTransitionIndex!(SearchPolicy.binarySearch, geq)(value); 11222 if (i >= length) return false; 11223 return !predFun(value, _input[i]); 11224 } 11225 11226/** 11227Like `contains`, but the value is specified before the range. 11228*/ 11229 bool opBinaryRight(string op, V)(V value) 11230 if (op == "in" && isRandomAccessRange!Range) 11231 { 11232 return contains(value); 11233 } 11234 11235// groupBy 11236/** 11237Returns a range of subranges of elements that are equivalent according to the 11238sorting relation. 11239 */ 11240 auto groupBy()() 11241 { 11242 import std.algorithm.iteration : chunkBy; 11243 return _input.chunkBy!((a, b) => !predFun(a, b) && !predFun(b, a)); 11244 } 11245} 11246 11247/// ditto 11248template SortedRange(Range, alias pred = "a < b", 11249 SortedRangeOptions opt = SortedRangeOptions.assumeSorted) 11250if (isInstanceOf!(SortedRange, Range)) 11251{ 11252 // Avoid nesting SortedRange types (see https://issues.dlang.org/show_bug.cgi?id=18933); 11253 alias SortedRange = SortedRange!(Unqual!(typeof(Range._input)), pred, opt); 11254} 11255 11256/// 11257@safe unittest 11258{ 11259 import std.algorithm.sorting : sort; 11260 auto a = [ 1, 2, 3, 42, 52, 64 ]; 11261 auto r = assumeSorted(a); 11262 assert(r.contains(3)); 11263 assert(!(32 in r)); 11264 auto r1 = sort!"a > b"(a); 11265 assert(3 in r1); 11266 assert(!r1.contains(32)); 11267 assert(r1.release() == [ 64, 52, 42, 3, 2, 1 ]); 11268} 11269 11270/** 11271`SortedRange` could accept ranges weaker than random-access, but it 11272is unable to provide interesting functionality for them. Therefore, 11273`SortedRange` is currently restricted to random-access ranges. 11274 11275No copy of the original range is ever made. If the underlying range is 11276changed concurrently with its corresponding `SortedRange` in ways 11277that break its sorted-ness, `SortedRange` will work erratically. 11278*/ 11279@safe unittest 11280{ 11281 import std.algorithm.mutation : swap; 11282 auto a = [ 1, 2, 3, 42, 52, 64 ]; 11283 auto r = assumeSorted(a); 11284 assert(r.contains(42)); 11285 swap(a[3], a[5]); // illegal to break sortedness of original range 11286 assert(!r.contains(42)); // passes although it shouldn't 11287} 11288 11289/** 11290`SortedRange` can be searched with predicates that do not take 11291two elements of the underlying range as arguments. 11292 11293This is useful, if a range of structs is sorted by a member and you 11294want to search in that range by only providing a value for that member. 11295 11296*/ 11297@safe unittest 11298{ 11299 import std.algorithm.comparison : equal; 11300 static struct S { int i; } 11301 static bool byI(A, B)(A a, B b) 11302 { 11303 static if (is(A == S)) 11304 return a.i < b; 11305 else 11306 return a < b.i; 11307 } 11308 auto r = assumeSorted!byI([S(1), S(2), S(3)]); 11309 auto lessThanTwo = r.lowerBound(2); 11310 assert(equal(lessThanTwo, [S(1)])); 11311} 11312 11313@safe unittest 11314{ 11315 import std.exception : assertThrown, assertNotThrown; 11316 11317 assertNotThrown(SortedRange!(int[])([ 1, 3, 10, 5, 7 ])); 11318 assertThrown(SortedRange!(int[],"a < b", SortedRangeOptions.checkStrictly)([ 1, 3, 10, 5, 7 ])); 11319 11320 // these two checks are implementation depended 11321 assertNotThrown(SortedRange!(int[],"a < b", SortedRangeOptions.checkRoughly)([ 1, 3, 10, 5, 12, 2 ])); 11322 assertThrown(SortedRange!(int[],"a < b", SortedRangeOptions.checkRoughly)([ 1, 3, 10, 5, 2, 12 ])); 11323} 11324 11325@safe unittest 11326{ 11327 import std.algorithm.comparison : equal; 11328 11329 auto a = [ 10, 20, 30, 30, 30, 40, 40, 50, 60 ]; 11330 auto r = assumeSorted(a).trisect(30); 11331 assert(equal(r[0], [ 10, 20 ])); 11332 assert(equal(r[1], [ 30, 30, 30 ])); 11333 assert(equal(r[2], [ 40, 40, 50, 60 ])); 11334 11335 r = assumeSorted(a).trisect(35); 11336 assert(equal(r[0], [ 10, 20, 30, 30, 30 ])); 11337 assert(r[1].empty); 11338 assert(equal(r[2], [ 40, 40, 50, 60 ])); 11339} 11340 11341@safe unittest 11342{ 11343 import std.algorithm.comparison : equal; 11344 auto a = [ "A", "AG", "B", "E", "F" ]; 11345 auto r = assumeSorted!"cmp(a,b) < 0"(a).trisect("B"w); 11346 assert(equal(r[0], [ "A", "AG" ])); 11347 assert(equal(r[1], [ "B" ])); 11348 assert(equal(r[2], [ "E", "F" ])); 11349 r = assumeSorted!"cmp(a,b) < 0"(a).trisect("A"d); 11350 assert(r[0].empty); 11351 assert(equal(r[1], [ "A" ])); 11352 assert(equal(r[2], [ "AG", "B", "E", "F" ])); 11353} 11354 11355@safe unittest 11356{ 11357 import std.algorithm.comparison : equal; 11358 static void test(SearchPolicy pol)() 11359 { 11360 auto a = [ 1, 2, 3, 42, 52, 64 ]; 11361 auto r = assumeSorted(a); 11362 assert(equal(r.lowerBound(42), [1, 2, 3])); 11363 11364 assert(equal(r.lowerBound!(pol)(42), [1, 2, 3])); 11365 assert(equal(r.lowerBound!(pol)(41), [1, 2, 3])); 11366 assert(equal(r.lowerBound!(pol)(43), [1, 2, 3, 42])); 11367 assert(equal(r.lowerBound!(pol)(51), [1, 2, 3, 42])); 11368 assert(equal(r.lowerBound!(pol)(3), [1, 2])); 11369 assert(equal(r.lowerBound!(pol)(55), [1, 2, 3, 42, 52])); 11370 assert(equal(r.lowerBound!(pol)(420), a)); 11371 assert(equal(r.lowerBound!(pol)(0), a[0 .. 0])); 11372 11373 assert(equal(r.upperBound!(pol)(42), [52, 64])); 11374 assert(equal(r.upperBound!(pol)(41), [42, 52, 64])); 11375 assert(equal(r.upperBound!(pol)(43), [52, 64])); 11376 assert(equal(r.upperBound!(pol)(51), [52, 64])); 11377 assert(equal(r.upperBound!(pol)(53), [64])); 11378 assert(equal(r.upperBound!(pol)(55), [64])); 11379 assert(equal(r.upperBound!(pol)(420), a[0 .. 0])); 11380 assert(equal(r.upperBound!(pol)(0), a)); 11381 } 11382 11383 test!(SearchPolicy.trot)(); 11384 test!(SearchPolicy.gallop)(); 11385 test!(SearchPolicy.trotBackwards)(); 11386 test!(SearchPolicy.gallopBackwards)(); 11387 test!(SearchPolicy.binarySearch)(); 11388} 11389 11390@safe unittest 11391{ 11392 // Check for small arrays 11393 int[] a; 11394 auto r = assumeSorted(a); 11395 a = [ 1 ]; 11396 r = assumeSorted(a); 11397 a = [ 1, 2 ]; 11398 r = assumeSorted(a); 11399 a = [ 1, 2, 3 ]; 11400 r = assumeSorted(a); 11401} 11402 11403@safe unittest 11404{ 11405 import std.algorithm.mutation : swap; 11406 auto a = [ 1, 2, 3, 42, 52, 64 ]; 11407 auto r = assumeSorted(a); 11408 assert(r.contains(42)); 11409 swap(a[3], a[5]); // illegal to break sortedness of original range 11410 assert(!r.contains(42)); // passes although it shouldn't 11411} 11412 11413@betterC @nogc nothrow @safe unittest 11414{ 11415 static immutable(int)[] arr = [ 1, 2, 3 ]; 11416 auto s = assumeSorted(arr); 11417} 11418 11419@system unittest 11420{ 11421 import std.algorithm.comparison : equal; 11422 int[] arr = [100, 101, 102, 200, 201, 300]; 11423 auto s = assumeSorted!((a, b) => a / 100 < b / 100)(arr); 11424 assert(s.groupBy.equal!equal([[100, 101, 102], [200, 201], [300]])); 11425} 11426 11427// Test on an input range 11428@system unittest 11429{ 11430 import std.conv : text; 11431 import std.file : exists, remove, tempDir; 11432 import std.path : buildPath; 11433 import std.stdio : File; 11434 import std.uuid : randomUUID; 11435 auto name = buildPath(tempDir(), "test.std.range.line-" ~ text(__LINE__) ~ 11436 "." ~ randomUUID().toString()); 11437 auto f = File(name, "w"); 11438 scope(exit) if (exists(name)) remove(name); 11439 // write a sorted range of lines to the file 11440 f.write("abc\ndef\nghi\njkl"); 11441 f.close(); 11442 f.open(name, "r"); 11443 auto r = assumeSorted(f.byLine()); 11444 auto r1 = r.upperBound!(SearchPolicy.linear)("def"); 11445 assert(r1.front == "ghi", r1.front); 11446 f.close(); 11447} 11448 11449// https://issues.dlang.org/show_bug.cgi?id=19337 11450@safe unittest 11451{ 11452 import std.algorithm.sorting : sort; 11453 auto a = [ 1, 2, 3, 42, 52, 64 ]; 11454 a.sort.sort!"a > b"; 11455} 11456 11457/** 11458Assumes `r` is sorted by predicate `pred` and returns the 11459corresponding $(D SortedRange!(pred, R)) having `r` as support. 11460To check for sorted-ness at 11461cost $(BIGOH n), use $(REF isSorted, std,algorithm,sorting). 11462 */ 11463auto assumeSorted(alias pred = "a < b", R)(R r) 11464if (isInputRange!(Unqual!R)) 11465{ 11466 // Avoid senseless `SortedRange!(SortedRange!(...), pred)` nesting. 11467 static if (is(R == SortedRange!(RRange, RPred), RRange, alias RPred)) 11468 { 11469 static if (isInputRange!R && __traits(isSame, pred, RPred)) 11470 // If the predicate is the same and we don't need to cast away 11471 // constness for the result to be an input range. 11472 return r; 11473 else 11474 return SortedRange!(Unqual!(typeof(r._input)), pred)(r._input); 11475 } 11476 else 11477 { 11478 return SortedRange!(Unqual!R, pred)(r); 11479 } 11480} 11481 11482/// 11483@safe unittest 11484{ 11485 import std.algorithm.comparison : equal; 11486 11487 int[] a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; 11488 auto p = assumeSorted(a); 11489 11490 assert(equal(p.lowerBound(4), [0, 1, 2, 3])); 11491 assert(equal(p.lowerBound(5), [0, 1, 2, 3, 4])); 11492 assert(equal(p.lowerBound(6), [0, 1, 2, 3, 4, 5])); 11493 assert(equal(p.lowerBound(6.9), [0, 1, 2, 3, 4, 5, 6])); 11494} 11495 11496@safe unittest 11497{ 11498 import std.algorithm.comparison : equal; 11499 static assert(isRandomAccessRange!(SortedRange!(int[]))); 11500 int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]; 11501 auto p = assumeSorted(a).upperBound(3); 11502 assert(equal(p, [4, 4, 5, 6 ])); 11503 p = assumeSorted(a).upperBound(4.2); 11504 assert(equal(p, [ 5, 6 ])); 11505 11506 // https://issues.dlang.org/show_bug.cgi?id=18933 11507 // don't create senselessly nested SortedRange types. 11508 assert(is(typeof(assumeSorted(a)) == typeof(assumeSorted(assumeSorted(a))))); 11509 assert(is(typeof(assumeSorted(a)) == typeof(assumeSorted(assumeSorted!"a > b"(a))))); 11510} 11511 11512@safe unittest 11513{ 11514 import std.algorithm.comparison : equal; 11515 import std.conv : text; 11516 11517 int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]; 11518 auto p = assumeSorted(a).equalRange(3); 11519 assert(equal(p, [ 3, 3, 3 ]), text(p)); 11520 p = assumeSorted(a).equalRange(4); 11521 assert(equal(p, [ 4, 4 ]), text(p)); 11522 p = assumeSorted(a).equalRange(2); 11523 assert(equal(p, [ 2 ])); 11524 p = assumeSorted(a).equalRange(0); 11525 assert(p.empty); 11526 p = assumeSorted(a).equalRange(7); 11527 assert(p.empty); 11528 p = assumeSorted(a).equalRange(3.0); 11529 assert(equal(p, [ 3, 3, 3])); 11530} 11531 11532@safe unittest 11533{ 11534 int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]; 11535 if (a.length) 11536 { 11537 auto b = a[a.length / 2]; 11538 //auto r = sort(a); 11539 //assert(r.contains(b)); 11540 } 11541} 11542 11543@safe unittest 11544{ 11545 auto a = [ 5, 7, 34, 345, 677 ]; 11546 auto r = assumeSorted(a); 11547 a = null; 11548 r = assumeSorted(a); 11549 a = [ 1 ]; 11550 r = assumeSorted(a); 11551} 11552 11553// https://issues.dlang.org/show_bug.cgi?id=15003 11554@nogc @safe unittest 11555{ 11556 static immutable a = [1, 2, 3, 4]; 11557 auto r = a.assumeSorted; 11558} 11559 11560/++ 11561 Wrapper which effectively makes it possible to pass a range by reference. 11562 Both the original range and the RefRange will always have the exact same 11563 elements. Any operation done on one will affect the other. So, for instance, 11564 if it's passed to a function which would implicitly copy the original range 11565 if it were passed to it, the original range is $(I not) copied but is 11566 consumed as if it were a reference type. 11567 11568 Note: 11569 `save` works as normal and operates on a new range, so if 11570 `save` is ever called on the `RefRange`, then no operations on the 11571 saved range will affect the original. 11572 11573 Params: 11574 range = the range to construct the `RefRange` from 11575 11576 Returns: 11577 A `RefRange`. If the given range is a class type 11578 (and thus is already a reference type), then the original 11579 range is returned rather than a `RefRange`. 11580 +/ 11581struct RefRange(R) 11582if (isInputRange!R) 11583{ 11584public: 11585 11586 /++ +/ 11587 this(R* range) @safe pure nothrow 11588 { 11589 _range = range; 11590 } 11591 11592 11593 /++ 11594 This does not assign the pointer of `rhs` to this `RefRange`. 11595 Rather it assigns the range pointed to by `rhs` to the range pointed 11596 to by this `RefRange`. This is because $(I any) operation on a 11597 `RefRange` is the same is if it occurred to the original range. The 11598 one exception is when a `RefRange` is assigned `null` either 11599 directly or because `rhs` is `null`. In that case, `RefRange` 11600 no longer refers to the original range but is `null`. 11601 +/ 11602 auto opAssign(RefRange rhs) 11603 { 11604 if (_range && rhs._range) 11605 *_range = *rhs._range; 11606 else 11607 _range = rhs._range; 11608 11609 return this; 11610 } 11611 11612 /++ +/ 11613 void opAssign(typeof(null) rhs) 11614 { 11615 _range = null; 11616 } 11617 11618 11619 /++ 11620 A pointer to the wrapped range. 11621 +/ 11622 @property inout(R*) ptr() @safe inout pure nothrow 11623 { 11624 return _range; 11625 } 11626 11627 11628 version (StdDdoc) 11629 { 11630 /++ +/ 11631 @property auto front() {assert(0);} 11632 /++ Ditto +/ 11633 @property auto front() const {assert(0);} 11634 /++ Ditto +/ 11635 @property auto front(ElementType!R value) {assert(0);} 11636 } 11637 else 11638 { 11639 @property auto front() 11640 { 11641 return (*_range).front; 11642 } 11643 11644 static if (is(typeof((*(cast(const R*)_range)).front))) @property auto front() const 11645 { 11646 return (*_range).front; 11647 } 11648 11649 static if (is(typeof((*_range).front = (*_range).front))) @property auto front(ElementType!R value) 11650 { 11651 return (*_range).front = value; 11652 } 11653 } 11654 11655 11656 version (StdDdoc) 11657 { 11658 @property bool empty(); /// 11659 @property bool empty() const; ///Ditto 11660 } 11661 else static if (isInfinite!R) 11662 enum empty = false; 11663 else 11664 { 11665 @property bool empty() 11666 { 11667 return (*_range).empty; 11668 } 11669 11670 static if (is(typeof((*cast(const R*)_range).empty))) @property bool empty() const 11671 { 11672 return (*_range).empty; 11673 } 11674 } 11675 11676 11677 /++ +/ 11678 void popFront() 11679 { 11680 return (*_range).popFront(); 11681 } 11682 11683 11684 version (StdDdoc) 11685 { 11686 /++ 11687 Only defined if `isForwardRange!R` is `true`. 11688 +/ 11689 @property auto save() {assert(0);} 11690 /++ Ditto +/ 11691 @property auto save() const {assert(0);} 11692 /++ Ditto +/ 11693 auto opSlice() {assert(0);} 11694 /++ Ditto +/ 11695 auto opSlice() const {assert(0);} 11696 } 11697 else static if (isForwardRange!R) 11698 { 11699 import std.traits : isSafe; 11700 private alias S = typeof((*_range).save); 11701 11702 static if (is(typeof((*cast(const R*)_range).save))) 11703 private alias CS = typeof((*cast(const R*)_range).save); 11704 11705 static if (isSafe!((R* r) => (*r).save)) 11706 { 11707 @property RefRange!S save() @trusted 11708 { 11709 mixin(_genSave()); 11710 } 11711 11712 static if (is(typeof((*cast(const R*)_range).save))) @property RefRange!CS save() @trusted const 11713 { 11714 mixin(_genSave()); 11715 } 11716 } 11717 else 11718 { 11719 @property RefRange!S save() 11720 { 11721 mixin(_genSave()); 11722 } 11723 11724 static if (is(typeof((*cast(const R*)_range).save))) @property RefRange!CS save() const 11725 { 11726 mixin(_genSave()); 11727 } 11728 } 11729 11730 auto opSlice()() 11731 { 11732 return save; 11733 } 11734 11735 auto opSlice()() const 11736 { 11737 return save; 11738 } 11739 11740 private static string _genSave() @safe pure nothrow 11741 { 11742 return `import core.lifetime : emplace;` ~ 11743 `alias S = typeof((*_range).save);` ~ 11744 `static assert(isForwardRange!S, S.stringof ~ " is not a forward range.");` ~ 11745 `auto mem = new void[S.sizeof];` ~ 11746 `emplace!S(mem, cast(S)(*_range).save);` ~ 11747 `return RefRange!S(cast(S*) mem.ptr);`; 11748 } 11749 11750 static assert(isForwardRange!RefRange); 11751 } 11752 11753 11754 version (StdDdoc) 11755 { 11756 /++ 11757 Only defined if `isBidirectionalRange!R` is `true`. 11758 +/ 11759 @property auto back() {assert(0);} 11760 /++ Ditto +/ 11761 @property auto back() const {assert(0);} 11762 /++ Ditto +/ 11763 @property auto back(ElementType!R value) {assert(0);} 11764 } 11765 else static if (isBidirectionalRange!R) 11766 { 11767 @property auto back() 11768 { 11769 return (*_range).back; 11770 } 11771 11772 static if (is(typeof((*(cast(const R*)_range)).back))) @property auto back() const 11773 { 11774 return (*_range).back; 11775 } 11776 11777 static if (is(typeof((*_range).back = (*_range).back))) @property auto back(ElementType!R value) 11778 { 11779 return (*_range).back = value; 11780 } 11781 } 11782 11783 11784 /++ Ditto +/ 11785 static if (isBidirectionalRange!R) void popBack() 11786 { 11787 return (*_range).popBack(); 11788 } 11789 11790 11791 version (StdDdoc) 11792 { 11793 /++ 11794 Only defined if `isRandomAccessRange!R` is `true`. 11795 +/ 11796 auto ref opIndex(IndexType)(IndexType index) {assert(0);} 11797 11798 /++ Ditto +/ 11799 auto ref opIndex(IndexType)(IndexType index) const {assert(0);} 11800 } 11801 else static if (isRandomAccessRange!R) 11802 { 11803 auto ref opIndex(IndexType)(IndexType index) 11804 if (is(typeof((*_range)[index]))) 11805 { 11806 return (*_range)[index]; 11807 } 11808 11809 auto ref opIndex(IndexType)(IndexType index) const 11810 if (is(typeof((*cast(const R*)_range)[index]))) 11811 { 11812 return (*_range)[index]; 11813 } 11814 } 11815 11816 11817 /++ 11818 Only defined if `hasMobileElements!R` and `isForwardRange!R` are 11819 `true`. 11820 +/ 11821 static if (hasMobileElements!R && isForwardRange!R) auto moveFront() 11822 { 11823 return (*_range).moveFront(); 11824 } 11825 11826 11827 /++ 11828 Only defined if `hasMobileElements!R` and `isBidirectionalRange!R` 11829 are `true`. 11830 +/ 11831 static if (hasMobileElements!R && isBidirectionalRange!R) auto moveBack() 11832 { 11833 return (*_range).moveBack(); 11834 } 11835 11836 11837 /++ 11838 Only defined if `hasMobileElements!R` and `isRandomAccessRange!R` 11839 are `true`. 11840 +/ 11841 static if (hasMobileElements!R && isRandomAccessRange!R) auto moveAt(size_t index) 11842 { 11843 return (*_range).moveAt(index); 11844 } 11845 11846 11847 version (StdDdoc) 11848 { 11849 /// Only defined if `hasLength!R` is `true`. 11850 @property size_t length(); 11851 /// ditto 11852 @property size_t length() const; 11853 /// Ditto 11854 alias opDollar = length; 11855 } 11856 else static if (hasLength!R) 11857 { 11858 @property auto length() 11859 { 11860 return (*_range).length; 11861 } 11862 static if (is(typeof((*cast(const R*)_range).length))) @property auto length() const 11863 { 11864 return (*_range).length; 11865 } 11866 alias opDollar = length; 11867 } 11868 11869 11870 version (StdDdoc) 11871 { 11872 /++ 11873 Only defined if `hasSlicing!R` is `true`. 11874 +/ 11875 auto opSlice(IndexType1, IndexType2) 11876 (IndexType1 begin, IndexType2 end) {assert(0);} 11877 11878 /++ Ditto +/ 11879 auto opSlice(IndexType1, IndexType2) 11880 (IndexType1 begin, IndexType2 end) const {assert(0);} 11881 } 11882 else static if (hasSlicing!R) 11883 { 11884 private alias T = typeof((*_range)[1 .. 2]); 11885 static if (is(typeof((*cast(const R*)_range)[1 .. 2]))) 11886 { 11887 private alias CT = typeof((*cast(const R*)_range)[1 .. 2]); 11888 } 11889 11890 RefRange!T opSlice(IndexType1, IndexType2) 11891 (IndexType1 begin, IndexType2 end) 11892 if (is(typeof((*_range)[begin .. end]))) 11893 { 11894 mixin(_genOpSlice()); 11895 } 11896 11897 RefRange!CT opSlice(IndexType1, IndexType2) 11898 (IndexType1 begin, IndexType2 end) const 11899 if (is(typeof((*cast(const R*)_range)[begin .. end]))) 11900 { 11901 mixin(_genOpSlice()); 11902 } 11903 11904 private static string _genOpSlice() @safe pure nothrow 11905 { 11906 return `import core.lifetime : emplace;` ~ 11907 `alias S = typeof((*_range)[begin .. end]);` ~ 11908 `static assert(hasSlicing!S, S.stringof ~ " is not sliceable.");` ~ 11909 `auto mem = new void[S.sizeof];` ~ 11910 `emplace!S(mem, cast(S)(*_range)[begin .. end]);` ~ 11911 `return RefRange!S(cast(S*) mem.ptr);`; 11912 } 11913 } 11914 11915 11916private: 11917 11918 R* _range; 11919} 11920 11921/// Basic Example 11922@system unittest 11923{ 11924 import std.algorithm.searching : find; 11925 ubyte[] buffer = [1, 9, 45, 12, 22]; 11926 auto found1 = find(buffer, 45); 11927 assert(found1 == [45, 12, 22]); 11928 assert(buffer == [1, 9, 45, 12, 22]); 11929 11930 auto wrapped1 = refRange(&buffer); 11931 auto found2 = find(wrapped1, 45); 11932 assert(*found2.ptr == [45, 12, 22]); 11933 assert(buffer == [45, 12, 22]); 11934 11935 auto found3 = find(wrapped1.save, 22); 11936 assert(*found3.ptr == [22]); 11937 assert(buffer == [45, 12, 22]); 11938 11939 string str = "hello world"; 11940 auto wrappedStr = refRange(&str); 11941 assert(str.front == 'h'); 11942 str.popFrontN(5); 11943 assert(str == " world"); 11944 assert(wrappedStr.front == ' '); 11945 assert(*wrappedStr.ptr == " world"); 11946} 11947 11948/// opAssign Example. 11949@system unittest 11950{ 11951 ubyte[] buffer1 = [1, 2, 3, 4, 5]; 11952 ubyte[] buffer2 = [6, 7, 8, 9, 10]; 11953 auto wrapped1 = refRange(&buffer1); 11954 auto wrapped2 = refRange(&buffer2); 11955 assert(wrapped1.ptr is &buffer1); 11956 assert(wrapped2.ptr is &buffer2); 11957 assert(wrapped1.ptr !is wrapped2.ptr); 11958 assert(buffer1 != buffer2); 11959 11960 wrapped1 = wrapped2; 11961 11962 //Everything points to the same stuff as before. 11963 assert(wrapped1.ptr is &buffer1); 11964 assert(wrapped2.ptr is &buffer2); 11965 assert(wrapped1.ptr !is wrapped2.ptr); 11966 11967 //But buffer1 has changed due to the assignment. 11968 assert(buffer1 == [6, 7, 8, 9, 10]); 11969 assert(buffer2 == [6, 7, 8, 9, 10]); 11970 11971 buffer2 = [11, 12, 13, 14, 15]; 11972 11973 //Everything points to the same stuff as before. 11974 assert(wrapped1.ptr is &buffer1); 11975 assert(wrapped2.ptr is &buffer2); 11976 assert(wrapped1.ptr !is wrapped2.ptr); 11977 11978 //But buffer2 has changed due to the assignment. 11979 assert(buffer1 == [6, 7, 8, 9, 10]); 11980 assert(buffer2 == [11, 12, 13, 14, 15]); 11981 11982 wrapped2 = null; 11983 11984 //The pointer changed for wrapped2 but not wrapped1. 11985 assert(wrapped1.ptr is &buffer1); 11986 assert(wrapped2.ptr is null); 11987 assert(wrapped1.ptr !is wrapped2.ptr); 11988 11989 //buffer2 is not affected by the assignment. 11990 assert(buffer1 == [6, 7, 8, 9, 10]); 11991 assert(buffer2 == [11, 12, 13, 14, 15]); 11992} 11993 11994@system unittest 11995{ 11996 import std.algorithm.iteration : filter; 11997 { 11998 ubyte[] buffer = [1, 2, 3, 4, 5]; 11999 auto wrapper = refRange(&buffer); 12000 auto p = wrapper.ptr; 12001 auto f = wrapper.front; 12002 wrapper.front = f; 12003 auto e = wrapper.empty; 12004 wrapper.popFront(); 12005 auto s = wrapper.save; 12006 auto b = wrapper.back; 12007 wrapper.back = b; 12008 wrapper.popBack(); 12009 auto i = wrapper[0]; 12010 wrapper.moveFront(); 12011 wrapper.moveBack(); 12012 wrapper.moveAt(0); 12013 auto l = wrapper.length; 12014 auto sl = wrapper[0 .. 1]; 12015 assert(wrapper[0 .. $].length == buffer[0 .. $].length); 12016 } 12017 12018 { 12019 ubyte[] buffer = [1, 2, 3, 4, 5]; 12020 const wrapper = refRange(&buffer); 12021 const p = wrapper.ptr; 12022 const f = wrapper.front; 12023 const e = wrapper.empty; 12024 const s = wrapper.save; 12025 const b = wrapper.back; 12026 const i = wrapper[0]; 12027 const l = wrapper.length; 12028 const sl = wrapper[0 .. 1]; 12029 } 12030 12031 { 12032 ubyte[] buffer = [1, 2, 3, 4, 5]; 12033 auto filtered = filter!"true"(buffer); 12034 auto wrapper = refRange(&filtered); 12035 auto p = wrapper.ptr; 12036 auto f = wrapper.front; 12037 wrapper.front = f; 12038 auto e = wrapper.empty; 12039 wrapper.popFront(); 12040 auto s = wrapper.save; 12041 wrapper.moveFront(); 12042 } 12043 12044 { 12045 ubyte[] buffer = [1, 2, 3, 4, 5]; 12046 auto filtered = filter!"true"(buffer); 12047 const wrapper = refRange(&filtered); 12048 const p = wrapper.ptr; 12049 12050 //Cannot currently be const. filter needs to be updated to handle const. 12051 /+ 12052 const f = wrapper.front; 12053 const e = wrapper.empty; 12054 const s = wrapper.save; 12055 +/ 12056 } 12057 12058 { 12059 string str = "hello world"; 12060 auto wrapper = refRange(&str); 12061 auto p = wrapper.ptr; 12062 auto f = wrapper.front; 12063 auto e = wrapper.empty; 12064 wrapper.popFront(); 12065 auto s = wrapper.save; 12066 auto b = wrapper.back; 12067 wrapper.popBack(); 12068 } 12069 12070 { 12071 // https://issues.dlang.org/show_bug.cgi?id=16534 12072 // opDollar should be defined if the wrapped range defines length. 12073 auto range = 10.iota.takeExactly(5); 12074 auto wrapper = refRange(&range); 12075 assert(wrapper.length == 5); 12076 assert(wrapper[0 .. $ - 1].length == 4); 12077 } 12078} 12079 12080//Test assignment. 12081@system unittest 12082{ 12083 ubyte[] buffer1 = [1, 2, 3, 4, 5]; 12084 ubyte[] buffer2 = [6, 7, 8, 9, 10]; 12085 RefRange!(ubyte[]) wrapper1; 12086 RefRange!(ubyte[]) wrapper2 = refRange(&buffer2); 12087 assert(wrapper1.ptr is null); 12088 assert(wrapper2.ptr is &buffer2); 12089 12090 wrapper1 = refRange(&buffer1); 12091 assert(wrapper1.ptr is &buffer1); 12092 12093 wrapper1 = wrapper2; 12094 assert(wrapper1.ptr is &buffer1); 12095 assert(buffer1 == buffer2); 12096 12097 wrapper1 = RefRange!(ubyte[]).init; 12098 assert(wrapper1.ptr is null); 12099 assert(wrapper2.ptr is &buffer2); 12100 assert(buffer1 == buffer2); 12101 assert(buffer1 == [6, 7, 8, 9, 10]); 12102 12103 wrapper2 = null; 12104 assert(wrapper2.ptr is null); 12105 assert(buffer2 == [6, 7, 8, 9, 10]); 12106} 12107 12108@system unittest 12109{ 12110 import std.algorithm.comparison : equal; 12111 import std.algorithm.mutation : bringToFront; 12112 import std.algorithm.searching : commonPrefix, find, until; 12113 import std.algorithm.sorting : sort; 12114 12115 //Test that ranges are properly consumed. 12116 { 12117 int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9]; 12118 auto wrapper = refRange(&arr); 12119 12120 assert(*find(wrapper, 41).ptr == [41, 3, 40, 4, 42, 9]); 12121 assert(arr == [41, 3, 40, 4, 42, 9]); 12122 12123 assert(*drop(wrapper, 2).ptr == [40, 4, 42, 9]); 12124 assert(arr == [40, 4, 42, 9]); 12125 12126 assert(equal(until(wrapper, 42), [40, 4])); 12127 assert(arr == [42, 9]); 12128 12129 assert(find(wrapper, 12).empty); 12130 assert(arr.empty); 12131 } 12132 12133 { 12134 string str = "Hello, world-like object."; 12135 auto wrapper = refRange(&str); 12136 12137 assert(*find(wrapper, "l").ptr == "llo, world-like object."); 12138 assert(str == "llo, world-like object."); 12139 12140 assert(equal(take(wrapper, 5), "llo, ")); 12141 assert(str == "world-like object."); 12142 } 12143 12144 //Test that operating on saved ranges does not consume the original. 12145 { 12146 int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9]; 12147 auto wrapper = refRange(&arr); 12148 auto saved = wrapper.save; 12149 saved.popFrontN(3); 12150 assert(*saved.ptr == [41, 3, 40, 4, 42, 9]); 12151 assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]); 12152 } 12153 12154 { 12155 string str = "Hello, world-like object."; 12156 auto wrapper = refRange(&str); 12157 auto saved = wrapper.save; 12158 saved.popFrontN(13); 12159 assert(*saved.ptr == "like object."); 12160 assert(str == "Hello, world-like object."); 12161 } 12162 12163 //Test that functions which use save work properly. 12164 { 12165 int[] arr = [1, 42]; 12166 auto wrapper = refRange(&arr); 12167 assert(equal(commonPrefix(wrapper, [1, 27]), [1])); 12168 } 12169 12170 { 12171 int[] arr = [4, 5, 6, 7, 1, 2, 3]; 12172 auto wrapper = refRange(&arr); 12173 assert(bringToFront(wrapper[0 .. 4], wrapper[4 .. arr.length]) == 3); 12174 assert(arr == [1, 2, 3, 4, 5, 6, 7]); 12175 } 12176 12177 //Test bidirectional functions. 12178 { 12179 int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9]; 12180 auto wrapper = refRange(&arr); 12181 12182 assert(wrapper.back == 9); 12183 assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]); 12184 12185 wrapper.popBack(); 12186 assert(arr == [1, 42, 2, 41, 3, 40, 4, 42]); 12187 } 12188 12189 { 12190 string str = "Hello, world-like object."; 12191 auto wrapper = refRange(&str); 12192 12193 assert(wrapper.back == '.'); 12194 assert(str == "Hello, world-like object."); 12195 12196 wrapper.popBack(); 12197 assert(str == "Hello, world-like object"); 12198 } 12199 12200 //Test random access functions. 12201 { 12202 int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9]; 12203 auto wrapper = refRange(&arr); 12204 12205 assert(wrapper[2] == 2); 12206 assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]); 12207 12208 assert(*wrapper[3 .. 6].ptr != null, [41, 3, 40]); 12209 assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]); 12210 } 12211 12212 //Test move functions. 12213 { 12214 int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9]; 12215 auto wrapper = refRange(&arr); 12216 12217 auto t1 = wrapper.moveFront(); 12218 auto t2 = wrapper.moveBack(); 12219 wrapper.front = t2; 12220 wrapper.back = t1; 12221 assert(arr == [9, 42, 2, 41, 3, 40, 4, 42, 1]); 12222 12223 sort(wrapper.save); 12224 assert(arr == [1, 2, 3, 4, 9, 40, 41, 42, 42]); 12225 } 12226} 12227 12228@system unittest 12229{ 12230 struct S 12231 { 12232 @property int front() @safe const pure nothrow { return 0; } 12233 enum bool empty = false; 12234 void popFront() @safe pure nothrow { } 12235 @property auto save() @safe pure nothrow return scope { return this; } 12236 } 12237 12238 S s; 12239 auto wrapper = refRange(&s); 12240 static assert(isInfinite!(typeof(wrapper))); 12241} 12242 12243@system unittest 12244{ 12245 class C 12246 { 12247 @property int front() @safe const pure nothrow { return 0; } 12248 @property bool empty() @safe const pure nothrow { return false; } 12249 void popFront() @safe pure nothrow { } 12250 @property auto save() @safe pure nothrow return scope { return this; } 12251 } 12252 static assert(isForwardRange!C); 12253 12254 auto c = new C; 12255 auto cWrapper = refRange(&c); 12256 static assert(is(typeof(cWrapper) == C)); 12257 assert(cWrapper is c); 12258} 12259 12260// https://issues.dlang.org/show_bug.cgi?id=14373 12261@system unittest 12262{ 12263 static struct R 12264 { 12265 @property int front() {return 0;} 12266 void popFront() {empty = true;} 12267 bool empty = false; 12268 } 12269 R r; 12270 refRange(&r).popFront(); 12271 assert(r.empty); 12272} 12273 12274// https://issues.dlang.org/show_bug.cgi?id=14575 12275@system unittest 12276{ 12277 struct R 12278 { 12279 Object front; 12280 alias back = front; 12281 bool empty = false; 12282 void popFront() {empty = true;} 12283 alias popBack = popFront; 12284 @property R save() {return this;} 12285 } 12286 static assert(isBidirectionalRange!R); 12287 R r; 12288 auto rr = refRange(&r); 12289 12290 struct R2 12291 { 12292 @property Object front() {return null;} 12293 @property const(Object) front() const {return null;} 12294 alias back = front; 12295 bool empty = false; 12296 void popFront() {empty = true;} 12297 alias popBack = popFront; 12298 @property R2 save() {return this;} 12299 } 12300 static assert(isBidirectionalRange!R2); 12301 R2 r2; 12302 auto rr2 = refRange(&r2); 12303} 12304 12305/// ditto 12306auto refRange(R)(R* range) 12307if (isInputRange!R) 12308{ 12309 static if (!is(R == class)) 12310 return RefRange!R(range); 12311 else 12312 return *range; 12313} 12314 12315// https://issues.dlang.org/show_bug.cgi?id=9060 12316@safe unittest 12317{ 12318 import std.algorithm.iteration : map, joiner, group; 12319 import std.algorithm.searching : until; 12320 // fix for std.algorithm 12321 auto r = map!(x => 0)([1]); 12322 chain(r, r); 12323 zip(r, r); 12324 roundRobin(r, r); 12325 12326 struct NRAR { 12327 typeof(r) input; 12328 @property empty() { return input.empty; } 12329 @property front() { return input.front; } 12330 void popFront() { input.popFront(); } 12331 @property save() { return NRAR(input.save); } 12332 } 12333 auto n1 = NRAR(r); 12334 cycle(n1); // non random access range version 12335 12336 assumeSorted(r); 12337 12338 // fix for std.range 12339 joiner([r], [9]); 12340 12341 struct NRAR2 { 12342 NRAR input; 12343 @property empty() { return true; } 12344 @property front() { return input; } 12345 void popFront() { } 12346 @property save() { return NRAR2(input.save); } 12347 } 12348 auto n2 = NRAR2(n1); 12349 joiner(n2); 12350 12351 group(r); 12352 12353 until(r, 7); 12354 static void foo(R)(R r) { until!(x => x > 7)(r); } 12355 foo(r); 12356} 12357 12358private struct Bitwise(R) 12359if (isInputRange!R && isIntegral!(ElementType!R)) 12360{ 12361 import std.traits : Unsigned; 12362private: 12363 alias ElemType = ElementType!R; 12364 alias UnsignedElemType = Unsigned!ElemType; 12365 12366 R parent; 12367 enum bitsNum = ElemType.sizeof * 8; 12368 size_t maskPos = 1; 12369 12370 static if (isBidirectionalRange!R) 12371 { 12372 size_t backMaskPos = bitsNum; 12373 } 12374 12375public: 12376 this()(auto ref R range) 12377 { 12378 parent = range; 12379 } 12380 12381 static if (isInfinite!R) 12382 { 12383 enum empty = false; 12384 } 12385 else 12386 { 12387 /** 12388 * Check if the range is empty 12389 * 12390 * Returns: a boolean true or false 12391 */ 12392 bool empty() 12393 { 12394 static if (hasLength!R) 12395 { 12396 return length == 0; 12397 } 12398 else static if (isBidirectionalRange!R) 12399 { 12400 if (parent.empty) 12401 { 12402 return true; 12403 } 12404 else 12405 { 12406 /* 12407 If we have consumed the last element of the range both from 12408 the front and the back, then the masks positions will overlap 12409 */ 12410 return parent.save.dropOne.empty && (maskPos > backMaskPos); 12411 } 12412 } 12413 else 12414 { 12415 /* 12416 If we consumed the last element of the range, but not all the 12417 bits in the last element 12418 */ 12419 return parent.empty; 12420 } 12421 } 12422 } 12423 12424 bool front() 12425 { 12426 assert(!empty); 12427 return (parent.front & mask(maskPos)) != 0; 12428 } 12429 12430 void popFront() 12431 { 12432 assert(!empty); 12433 ++maskPos; 12434 if (maskPos > bitsNum) 12435 { 12436 parent.popFront; 12437 maskPos = 1; 12438 } 12439 } 12440 12441 static if (hasLength!R) 12442 { 12443 size_t length() 12444 { 12445 auto len = parent.length * bitsNum - (maskPos - 1); 12446 static if (isBidirectionalRange!R) 12447 { 12448 len -= bitsNum - backMaskPos; 12449 } 12450 return len; 12451 } 12452 12453 alias opDollar = length; 12454 } 12455 12456 static if (isForwardRange!R) 12457 { 12458 typeof(this) save() 12459 { 12460 auto result = this; 12461 result.parent = parent.save; 12462 return result; 12463 } 12464 } 12465 12466 static if (isBidirectionalRange!R) 12467 { 12468 bool back() 12469 { 12470 assert(!empty); 12471 return (parent.back & mask(backMaskPos)) != 0; 12472 } 12473 12474 void popBack() 12475 { 12476 assert(!empty); 12477 --backMaskPos; 12478 if (backMaskPos == 0) 12479 { 12480 parent.popBack; 12481 backMaskPos = bitsNum; 12482 } 12483 } 12484 } 12485 12486 static if (isRandomAccessRange!R) 12487 { 12488 /** 12489 Return the `n`th bit within the range 12490 */ 12491 bool opIndex(size_t n) 12492 in 12493 { 12494 /* 12495 If it does not have the length property, it means that R is 12496 an infinite range 12497 */ 12498 static if (hasLength!R) 12499 { 12500 assert(n < length, "Index out of bounds"); 12501 } 12502 } 12503 do 12504 { 12505 immutable size_t remainingBits = bitsNum - maskPos + 1; 12506 // If n >= maskPos, then the bit sign will be 1, otherwise 0 12507 immutable ptrdiff_t sign = (remainingBits - n - 1) >> (ptrdiff_t.sizeof * 8 - 1); 12508 /* 12509 By truncating n with remainingBits bits we have skipped the 12510 remaining bits in parent[0], so we need to add 1 to elemIndex. 12511 12512 Because bitsNum is a power of 2, n / bitsNum == n >> bitsNum.bsf 12513 */ 12514 import core.bitop : bsf; 12515 immutable size_t elemIndex = sign * (((n - remainingBits) >> bitsNum.bsf) + 1); 12516 12517 /* 12518 Since the indexing is from LSB to MSB, we need to index at the 12519 remainder of (n - remainingBits). 12520 12521 Because bitsNum is a power of 2, n % bitsNum == n & (bitsNum - 1) 12522 */ 12523 immutable size_t elemMaskPos = (sign ^ 1) * (maskPos + n) 12524 + sign * (1 + ((n - remainingBits) & (bitsNum - 1))); 12525 12526 return (parent[elemIndex] & mask(elemMaskPos)) != 0; 12527 } 12528 12529 static if (hasAssignableElements!R) 12530 { 12531 /** 12532 Assigns `flag` to the `n`th bit within the range 12533 */ 12534 void opIndexAssign(bool flag, size_t n) 12535 in 12536 { 12537 static if (hasLength!R) 12538 { 12539 assert(n < length, "Index out of bounds"); 12540 } 12541 } 12542 do 12543 { 12544 import core.bitop : bsf; 12545 12546 immutable size_t remainingBits = bitsNum - maskPos + 1; 12547 immutable ptrdiff_t sign = (remainingBits - n - 1) >> (ptrdiff_t.sizeof * 8 - 1); 12548 immutable size_t elemIndex = sign * (((n - remainingBits) >> bitsNum.bsf) + 1); 12549 immutable size_t elemMaskPos = (sign ^ 1) * (maskPos + n) 12550 + sign * (1 + ((n - remainingBits) & (bitsNum - 1))); 12551 12552 auto elem = parent[elemIndex]; 12553 auto elemMask = mask(elemMaskPos); 12554 parent[elemIndex] = cast(UnsignedElemType)(flag * (elem | elemMask) 12555 + (flag ^ 1) * (elem & ~elemMask)); 12556 } 12557 } 12558 12559 Bitwise!R opSlice() 12560 { 12561 return this.save; 12562 } 12563 12564 Bitwise!R opSlice(size_t start, size_t end) 12565 in 12566 { 12567 assert(start < end, "Invalid bounds: end <= start"); 12568 } 12569 do 12570 { 12571 import core.bitop : bsf; 12572 12573 size_t remainingBits = bitsNum - maskPos + 1; 12574 ptrdiff_t sign = (remainingBits - start - 1) >> (ptrdiff_t.sizeof * 8 - 1); 12575 immutable size_t startElemIndex = sign * (((start - remainingBits) >> bitsNum.bsf) + 1); 12576 immutable size_t startElemMaskPos = (sign ^ 1) * (maskPos + start) 12577 + sign * (1 + ((start - remainingBits) & (bitsNum - 1))); 12578 12579 immutable size_t sliceLen = end - start - 1; 12580 remainingBits = bitsNum - startElemMaskPos + 1; 12581 sign = (remainingBits - sliceLen - 1) >> (ptrdiff_t.sizeof * 8 - 1); 12582 immutable size_t endElemIndex = startElemIndex 12583 + sign * (((sliceLen - remainingBits) >> bitsNum.bsf) + 1); 12584 immutable size_t endElemMaskPos = (sign ^ 1) * (startElemMaskPos + sliceLen) 12585 + sign * (1 + ((sliceLen - remainingBits) & (bitsNum - 1))); 12586 12587 typeof(return) result; 12588 // Get the slice to be returned from the parent 12589 result.parent = (parent[startElemIndex .. endElemIndex + 1]).save; 12590 result.maskPos = startElemMaskPos; 12591 static if (isBidirectionalRange!R) 12592 { 12593 result.backMaskPos = endElemMaskPos; 12594 } 12595 return result; 12596 } 12597 } 12598 12599private: 12600 auto mask(size_t maskPos) 12601 { 12602 return (1UL << (maskPos - 1UL)); 12603 } 12604} 12605 12606/** 12607Bitwise adapter over an integral type range. Consumes the range elements bit by 12608bit, from the least significant bit to the most significant bit. 12609 12610Params: 12611 R = an integral $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to iterate over 12612 range = range to consume bit by by 12613 12614Returns: 12615 A `Bitwise` input range with propagated forward, bidirectional 12616 and random access capabilities 12617*/ 12618auto bitwise(R)(auto ref R range) 12619if (isInputRange!R && isIntegral!(ElementType!R)) 12620{ 12621 return Bitwise!R(range); 12622} 12623 12624/// 12625@safe pure unittest 12626{ 12627 import std.algorithm.comparison : equal; 12628 import std.format : format; 12629 12630 // 00000011 00001001 12631 ubyte[] arr = [3, 9]; 12632 auto r = arr.bitwise; 12633 12634 // iterate through it as with any other range 12635 assert(format("%(%d%)", r) == "1100000010010000"); 12636 assert(format("%(%d%)", r.retro).equal("1100000010010000".retro)); 12637 12638 auto r2 = r[5 .. $]; 12639 // set a bit 12640 r[2] = 1; 12641 assert(arr[0] == 7); 12642 assert(r[5] == r2[0]); 12643} 12644 12645/// You can use bitwise to implement an uniform bool generator 12646@safe unittest 12647{ 12648 import std.algorithm.comparison : equal; 12649 import std.random : rndGen; 12650 12651 auto rb = rndGen.bitwise; 12652 static assert(isInfinite!(typeof(rb))); 12653 12654 auto rb2 = rndGen.bitwise; 12655 // Don't forget that structs are passed by value 12656 assert(rb.take(10).equal(rb2.take(10))); 12657} 12658 12659// Test nogc inference 12660@safe @nogc unittest 12661{ 12662 static ubyte[] arr = [3, 9]; 12663 auto bw = arr.bitwise; 12664 auto bw2 = bw[]; 12665 auto bw3 = bw[8 .. $]; 12666 bw3[2] = true; 12667 12668 assert(arr[1] == 13); 12669 assert(bw[$ - 6]); 12670 assert(bw[$ - 6] == bw2[$ - 6]); 12671 assert(bw[$ - 6] == bw3[$ - 6]); 12672} 12673 12674// Test all range types over all integral types 12675@safe pure nothrow unittest 12676{ 12677 import std.meta : AliasSeq; 12678 import std.internal.test.dummyrange; 12679 12680 alias IntegralTypes = AliasSeq!(byte, ubyte, short, ushort, int, uint, 12681 long, ulong); 12682 foreach (IntegralType; IntegralTypes) 12683 { 12684 foreach (T; AllDummyRangesType!(IntegralType[])) 12685 { 12686 T a; 12687 auto bw = Bitwise!T(a); 12688 12689 static if (isForwardRange!T) 12690 { 12691 auto bwFwdSave = bw.save; 12692 } 12693 12694 static if (isBidirectionalRange!T) 12695 { 12696 auto bwBack = bw.save; 12697 auto bwBackSave = bw.save; 12698 } 12699 12700 static if (hasLength!T) 12701 { 12702 auto bwLength = bw.length; 12703 assert(bw.length == (IntegralType.sizeof * 8 * a.length)); 12704 static if (isForwardRange!T) 12705 { 12706 assert(bw.length == bwFwdSave.length); 12707 } 12708 } 12709 12710 // Make sure front and back are not the mechanisms that modify the range 12711 long numCalls = 42; 12712 bool initialFrontValue; 12713 12714 if (!bw.empty) 12715 { 12716 initialFrontValue = bw.front; 12717 } 12718 12719 while (!bw.empty && (--numCalls)) 12720 { 12721 bw.front; 12722 assert(bw.front == initialFrontValue); 12723 } 12724 12725 /* 12726 Check that empty works properly and that popFront does not get called 12727 more times than it should 12728 */ 12729 numCalls = 0; 12730 while (!bw.empty) 12731 { 12732 ++numCalls; 12733 12734 static if (hasLength!T) 12735 { 12736 assert(bw.length == bwLength); 12737 --bwLength; 12738 } 12739 12740 static if (isForwardRange!T) 12741 { 12742 assert(bw.front == bwFwdSave.front); 12743 bwFwdSave.popFront(); 12744 } 12745 12746 static if (isBidirectionalRange!T) 12747 { 12748 assert(bwBack.front == bwBackSave.front); 12749 bwBack.popBack(); 12750 bwBackSave.popBack(); 12751 } 12752 bw.popFront(); 12753 } 12754 12755 auto rangeLen = numCalls / (IntegralType.sizeof * 8); 12756 assert(numCalls == (IntegralType.sizeof * 8 * rangeLen)); 12757 assert(bw.empty); 12758 static if (isForwardRange!T) 12759 { 12760 assert(bwFwdSave.empty); 12761 } 12762 12763 static if (isBidirectionalRange!T) 12764 { 12765 assert(bwBack.empty); 12766 } 12767 } 12768 } 12769} 12770 12771// Test opIndex and opSlice 12772@system unittest 12773{ 12774 import std.meta : AliasSeq; 12775 alias IntegralTypes = AliasSeq!(byte, ubyte, short, ushort, int, uint, 12776 long, ulong); 12777 foreach (IntegralType; IntegralTypes) 12778 { 12779 size_t bitsNum = IntegralType.sizeof * 8; 12780 12781 auto first = cast(IntegralType)(1); 12782 12783 // 2 ^ (bitsNum - 1) 12784 auto second = cast(IntegralType)(cast(IntegralType)(1) << (bitsNum - 2)); 12785 12786 IntegralType[] a = [first, second]; 12787 auto bw = Bitwise!(IntegralType[])(a); 12788 12789 // Check against lsb of a[0] 12790 assert(bw[0] == true); 12791 // Check against msb - 1 of a[1] 12792 assert(bw[2 * bitsNum - 2] == true); 12793 12794 bw.popFront(); 12795 assert(bw[2 * bitsNum - 3] == true); 12796 12797 import std.exception : assertThrown; 12798 12799 version (D_NoBoundsChecks) {} 12800 else 12801 { 12802 // Check out of bounds error 12803 assertThrown!Error(bw[2 * bitsNum - 1]); 12804 } 12805 12806 bw[2] = true; 12807 assert(bw[2] == true); 12808 bw.popFront(); 12809 assert(bw[1] == true); 12810 12811 auto bw2 = bw[0 .. $ - 5]; 12812 auto bw3 = bw2[]; 12813 assert(bw2.length == (bw.length - 5)); 12814 assert(bw2.length == bw3.length); 12815 bw2.popFront(); 12816 assert(bw2.length != bw3.length); 12817 } 12818} 12819 12820/********************************* 12821 * An OutputRange that discards the data it receives. 12822 */ 12823struct NullSink 12824{ 12825 void put(E)(scope const E) pure @safe @nogc nothrow {} 12826} 12827 12828/// ditto 12829auto ref nullSink() 12830{ 12831 static NullSink sink; 12832 return sink; 12833} 12834 12835/// 12836@safe nothrow unittest 12837{ 12838 import std.algorithm.iteration : map; 12839 import std.algorithm.mutation : copy; 12840 [4, 5, 6].map!(x => x * 2).copy(nullSink); // data is discarded 12841} 12842 12843/// 12844@safe unittest 12845{ 12846 import std.csv : csvNextToken; 12847 12848 string line = "a,b,c"; 12849 12850 // ignore the first column 12851 line.csvNextToken(nullSink, ',', '"'); 12852 line.popFront; 12853 12854 // look at the second column 12855 Appender!string app; 12856 line.csvNextToken(app, ',', '"'); 12857 assert(app.data == "b"); 12858} 12859 12860@safe unittest 12861{ 12862 auto r = 10.iota 12863 .tee(nullSink) 12864 .dropOne; 12865 12866 assert(r.front == 1); 12867} 12868 12869/++ 12870 12871 Implements a "tee" style pipe, wrapping an input range so that elements of the 12872 range can be passed to a provided function or $(LREF OutputRange) as they are 12873 iterated over. This is useful for printing out intermediate values in a long 12874 chain of range code, performing some operation with side-effects on each call 12875 to `front` or `popFront`, or diverting the elements of a range into an 12876 auxiliary $(LREF OutputRange). 12877 12878 It is important to note that as the resultant range is evaluated lazily, 12879 in the case of the version of `tee` that takes a function, the function 12880 will not actually be executed until the range is "walked" using functions 12881 that evaluate ranges, such as $(REF array, std,array) or 12882 $(REF fold, std,algorithm,iteration). 12883 12884 Params: 12885 pipeOnPop = If `Yes.pipeOnPop`, simply iterating the range without ever 12886 calling `front` is enough to have `tee` mirror elements to `outputRange` (or, 12887 respectively, `fun`). Note that each `popFront()` call will mirror the 12888 old `front` value, not the new one. This means that the last value will 12889 not be forwarded if the range isn't iterated until empty. If 12890 `No.pipeOnPop`, only elements for which `front` does get called will be 12891 also sent to `outputRange`/`fun`. If `front` is called twice for the same 12892 element, it will still be sent only once. If this caching is undesired, 12893 consider using $(REF map, std,algorithm,iteration) instead. 12894 inputRange = The input range being passed through. 12895 outputRange = This range will receive elements of `inputRange` progressively 12896 as iteration proceeds. 12897 fun = This function will be called with elements of `inputRange` 12898 progressively as iteration proceeds. 12899 12900 Returns: 12901 An input range that offers the elements of `inputRange`. Regardless of 12902 whether `inputRange` is a more powerful range (forward, bidirectional etc), 12903 the result is always an input range. Reading this causes `inputRange` to be 12904 iterated and returns its elements in turn. In addition, the same elements 12905 will be passed to `outputRange` or `fun` as well. 12906 12907 See_Also: $(REF each, std,algorithm,iteration) 12908+/ 12909auto tee(Flag!"pipeOnPop" pipeOnPop = Yes.pipeOnPop, R1, R2)(R1 inputRange, R2 outputRange) 12910if (isInputRange!R1 && isOutputRange!(R2, ElementType!R1)) 12911{ 12912 static struct Result 12913 { 12914 private R1 _input; 12915 private R2 _output; 12916 static if (!pipeOnPop) 12917 { 12918 private bool _frontAccessed; 12919 } 12920 12921 mixin ImplementLength!_input; 12922 12923 static if (isInfinite!R1) 12924 { 12925 enum bool empty = false; 12926 } 12927 else 12928 { 12929 @property bool empty() { return _input.empty; } 12930 } 12931 12932 void popFront() 12933 { 12934 assert(!_input.empty, "Attempting to popFront an empty tee"); 12935 static if (pipeOnPop) 12936 { 12937 put(_output, _input.front); 12938 } 12939 else 12940 { 12941 _frontAccessed = false; 12942 } 12943 _input.popFront(); 12944 } 12945 12946 @property auto ref front() 12947 { 12948 assert(!_input.empty, "Attempting to fetch the front of an empty tee"); 12949 static if (!pipeOnPop) 12950 { 12951 if (!_frontAccessed) 12952 { 12953 _frontAccessed = true; 12954 put(_output, _input.front); 12955 } 12956 } 12957 return _input.front; 12958 } 12959 } 12960 12961 return Result(inputRange, outputRange); 12962} 12963 12964/// Ditto 12965auto tee(alias fun, Flag!"pipeOnPop" pipeOnPop = Yes.pipeOnPop, R1)(R1 inputRange) 12966if (is(typeof(fun) == void) || isSomeFunction!fun) 12967{ 12968 import std.traits : isDelegate, isFunctionPointer; 12969 /* 12970 Distinguish between function literals and template lambdas 12971 when using either as an $(LREF OutputRange). Since a template 12972 has no type, typeof(template) will always return void. 12973 If it's a template lambda, it's first necessary to instantiate 12974 it with `ElementType!R1`. 12975 */ 12976 static if (is(typeof(fun) == void)) 12977 alias _fun = fun!(ElementType!R1); 12978 else 12979 alias _fun = fun; 12980 12981 static if (isFunctionPointer!_fun || isDelegate!_fun) 12982 { 12983 return tee!pipeOnPop(inputRange, _fun); 12984 } 12985 else 12986 { 12987 return tee!pipeOnPop(inputRange, &_fun); 12988 } 12989} 12990 12991/// 12992@safe unittest 12993{ 12994 import std.algorithm.comparison : equal; 12995 import std.algorithm.iteration : filter, map; 12996 12997 // Sum values while copying 12998 int[] values = [1, 4, 9, 16, 25]; 12999 int sum = 0; 13000 auto newValues = values.tee!(a => sum += a).array; 13001 assert(equal(newValues, values)); 13002 assert(sum == 1 + 4 + 9 + 16 + 25); 13003 13004 // Count values that pass the first filter 13005 int count = 0; 13006 auto newValues4 = values.filter!(a => a < 10) 13007 .tee!(a => count++) 13008 .map!(a => a + 1) 13009 .filter!(a => a < 10); 13010 13011 //Fine, equal also evaluates any lazy ranges passed to it. 13012 //count is not 3 until equal evaluates newValues4 13013 assert(equal(newValues4, [2, 5])); 13014 assert(count == 3); 13015} 13016 13017// 13018@safe unittest 13019{ 13020 import std.algorithm.comparison : equal; 13021 import std.algorithm.iteration : filter, map; 13022 13023 int[] values = [1, 4, 9, 16, 25]; 13024 13025 int count = 0; 13026 auto newValues = values.filter!(a => a < 10) 13027 .tee!(a => count++, No.pipeOnPop) 13028 .map!(a => a + 1) 13029 .filter!(a => a < 10); 13030 13031 auto val = newValues.front; 13032 assert(count == 1); 13033 //front is only evaluated once per element 13034 val = newValues.front; 13035 assert(count == 1); 13036 13037 //popFront() called, fun will be called 13038 //again on the next access to front 13039 newValues.popFront(); 13040 newValues.front; 13041 assert(count == 2); 13042 13043 int[] preMap = new int[](3), postMap = []; 13044 auto mappedValues = values.filter!(a => a < 10) 13045 //Note the two different ways of using tee 13046 .tee(preMap) 13047 .map!(a => a + 1) 13048 .tee!(a => postMap ~= a) 13049 .filter!(a => a < 10); 13050 assert(equal(mappedValues, [2, 5])); 13051 assert(equal(preMap, [1, 4, 9])); 13052 assert(equal(postMap, [2, 5, 10])); 13053} 13054 13055// 13056@safe unittest 13057{ 13058 import std.algorithm.comparison : equal; 13059 import std.algorithm.iteration : filter, map; 13060 13061 char[] txt = "Line one, Line 2".dup; 13062 13063 bool isVowel(dchar c) 13064 { 13065 import std.string : indexOf; 13066 return "AaEeIiOoUu".indexOf(c) != -1; 13067 } 13068 13069 int vowelCount = 0; 13070 int shiftedCount = 0; 13071 auto removeVowels = txt.tee!(c => isVowel(c) ? vowelCount++ : 0) 13072 .filter!(c => !isVowel(c)) 13073 .map!(c => (c == ' ') ? c : c + 1) 13074 .tee!(c => isVowel(c) ? shiftedCount++ : 0); 13075 assert(equal(removeVowels, "Mo o- Mo 3")); 13076 assert(vowelCount == 6); 13077 assert(shiftedCount == 3); 13078} 13079 13080@safe unittest 13081{ 13082 // Manually stride to test different pipe behavior. 13083 void testRange(Range)(Range r) 13084 { 13085 const int strideLen = 3; 13086 int i = 0; 13087 ElementType!Range elem1; 13088 ElementType!Range elem2; 13089 while (!r.empty) 13090 { 13091 if (i % strideLen == 0) 13092 { 13093 //Make sure front is only 13094 //evaluated once per item 13095 elem1 = r.front; 13096 elem2 = r.front; 13097 assert(elem1 == elem2); 13098 } 13099 r.popFront(); 13100 i++; 13101 } 13102 } 13103 13104 string txt = "abcdefghijklmnopqrstuvwxyz"; 13105 13106 int popCount = 0; 13107 auto pipeOnPop = txt.tee!(a => popCount++); 13108 testRange(pipeOnPop); 13109 assert(popCount == 26); 13110 13111 int frontCount = 0; 13112 auto pipeOnFront = txt.tee!(a => frontCount++, No.pipeOnPop); 13113 testRange(pipeOnFront); 13114 assert(frontCount == 9); 13115} 13116 13117@safe unittest 13118{ 13119 import std.algorithm.comparison : equal; 13120 import std.meta : AliasSeq; 13121 13122 //Test diverting elements to an OutputRange 13123 string txt = "abcdefghijklmnopqrstuvwxyz"; 13124 13125 dchar[] asink1 = []; 13126 auto fsink = (dchar c) { asink1 ~= c; }; 13127 auto result1 = txt.tee(fsink).array; 13128 assert(equal(txt, result1) && (equal(result1, asink1))); 13129 13130 dchar[] _asink1 = []; 13131 auto _result1 = txt.tee!((dchar c) { _asink1 ~= c; })().array; 13132 assert(equal(txt, _result1) && (equal(_result1, _asink1))); 13133 13134 dchar[] asink2 = new dchar[](txt.length); 13135 void fsink2(dchar c) { static int i = 0; asink2[i] = c; i++; } 13136 auto result2 = txt.tee(&fsink2).array; 13137 assert(equal(txt, result2) && equal(result2, asink2)); 13138 13139 dchar[] asink3 = new dchar[](txt.length); 13140 auto result3 = txt.tee(asink3).array; 13141 assert(equal(txt, result3) && equal(result3, asink3)); 13142 13143 static foreach (CharType; AliasSeq!(char, wchar, dchar)) 13144 {{ 13145 auto appSink = appender!(CharType[])(); 13146 auto appResult = txt.tee(appSink).array; 13147 assert(equal(txt, appResult) && equal(appResult, appSink.data)); 13148 }} 13149 13150 static foreach (StringType; AliasSeq!(string, wstring, dstring)) 13151 {{ 13152 auto appSink = appender!StringType(); 13153 auto appResult = txt.tee(appSink).array; 13154 assert(equal(txt, appResult) && equal(appResult, appSink.data)); 13155 }} 13156} 13157 13158// https://issues.dlang.org/show_bug.cgi?id=13483 13159@safe unittest 13160{ 13161 static void func1(T)(T x) {} 13162 void func2(int x) {} 13163 13164 auto r = [1, 2, 3, 4].tee!func1.tee!func2; 13165} 13166 13167/** 13168Extends the length of the input range `r` by padding out the start of the 13169range with the element `e`. The element `e` must be of a common type with 13170the element type of the range `r` as defined by $(REF CommonType, std, traits). 13171If `n` is less than the length of of `r`, then `r` is returned unmodified. 13172 13173If `r` is a string with Unicode characters in it, `padLeft` follows D's rules 13174about length for strings, which is not the number of characters, or 13175graphemes, but instead the number of encoding units. If you want to treat each 13176grapheme as only one encoding unit long, then call 13177$(REF byGrapheme, std, uni) before calling this function. 13178 13179If `r` has a length, then this is $(BIGOH 1). Otherwise, it's $(BIGOH r.length). 13180 13181Params: 13182 r = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives) with a length, or a forward range 13183 e = element to pad the range with 13184 n = the length to pad to 13185 13186Returns: 13187 A range containing the elements of the original range with the extra padding 13188 13189See Also: 13190 $(REF leftJustifier, std, string) 13191*/ 13192auto padLeft(R, E)(R r, E e, size_t n) 13193if ( 13194 ((isInputRange!R && hasLength!R) || isForwardRange!R) && 13195 !is(CommonType!(ElementType!R, E) == void) 13196) 13197{ 13198 static if (hasLength!R) 13199 auto dataLength = r.length; 13200 else 13201 auto dataLength = r.save.walkLength(n); 13202 13203 return e.repeat(n > dataLength ? n - dataLength : 0).chain(r); 13204} 13205 13206/// 13207@safe pure unittest 13208{ 13209 import std.algorithm.comparison : equal; 13210 13211 assert([1, 2, 3, 4].padLeft(0, 6).equal([0, 0, 1, 2, 3, 4])); 13212 assert([1, 2, 3, 4].padLeft(0, 3).equal([1, 2, 3, 4])); 13213 13214 assert("abc".padLeft('_', 6).equal("___abc")); 13215} 13216 13217@safe pure nothrow unittest 13218{ 13219 import std.algorithm.comparison : equal; 13220 import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy; 13221 import std.meta : AliasSeq; 13222 13223 alias DummyRanges = AliasSeq!( 13224 DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Input), 13225 DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Forward), 13226 DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Bidirectional), 13227 DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random), 13228 DummyRange!(ReturnBy.Reference, Length.No, RangeType.Forward), 13229 DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Input), 13230 DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Forward), 13231 DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Bidirectional), 13232 DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random), 13233 DummyRange!(ReturnBy.Value, Length.No, RangeType.Forward) 13234 ); 13235 13236 foreach (Range; DummyRanges) 13237 { 13238 Range r; 13239 assert(r 13240 .padLeft(0, 12) 13241 .equal([0, 0, 1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U]) 13242 ); 13243 } 13244} 13245 13246// Test nogc inference 13247@safe @nogc pure unittest 13248{ 13249 import std.algorithm.comparison : equal; 13250 13251 static immutable r1 = [1, 2, 3, 4]; 13252 static immutable r2 = [0, 0, 1, 2, 3, 4]; 13253 assert(r1.padLeft(0, 6).equal(r2)); 13254} 13255 13256/** 13257Extend the length of the input range `r` by padding out the end of the range 13258with the element `e`. The element `e` must be of a common type with the 13259element type of the range `r` as defined by $(REF CommonType, std, traits). 13260If `n` is less than the length of of `r`, then the contents of `r` are 13261returned. 13262 13263The range primitives that the resulting range provides depends whether or not `r` 13264provides them. Except the functions `back` and `popBack`, which also require 13265the range to have a length as well as `back` and `popBack` 13266 13267Params: 13268 r = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives) with a length 13269 e = element to pad the range with 13270 n = the length to pad to 13271 13272Returns: 13273 A range containing the elements of the original range with the extra padding 13274 13275See Also: 13276 $(REF rightJustifier, std, string) 13277*/ 13278auto padRight(R, E)(R r, E e, size_t n) 13279if ( 13280 isInputRange!R && 13281 !isInfinite!R && 13282 !is(CommonType!(ElementType!R, E) == void)) 13283{ 13284 static struct Result 13285 { 13286 private: 13287 R data; 13288 E element; 13289 static if (hasLength!R) 13290 { 13291 size_t padLength; 13292 } 13293 else 13294 { 13295 size_t minLength; 13296 size_t consumed; 13297 } 13298 13299 public: 13300 bool empty() @property 13301 { 13302 static if (hasLength!R) 13303 { 13304 return data.empty && padLength == 0; 13305 } 13306 else 13307 { 13308 return data.empty && consumed >= minLength; 13309 } 13310 } 13311 13312 auto front() @property 13313 { 13314 assert(!empty, "Attempting to fetch the front of an empty padRight"); 13315 return data.empty ? element : data.front; 13316 } 13317 13318 void popFront() 13319 { 13320 assert(!empty, "Attempting to popFront an empty padRight"); 13321 13322 static if (hasLength!R) 13323 { 13324 if (!data.empty) 13325 { 13326 data.popFront; 13327 } 13328 else 13329 { 13330 --padLength; 13331 } 13332 } 13333 else 13334 { 13335 ++consumed; 13336 if (!data.empty) 13337 { 13338 data.popFront; 13339 } 13340 } 13341 } 13342 13343 static if (hasLength!R) 13344 { 13345 size_t length() @property 13346 { 13347 return data.length + padLength; 13348 } 13349 } 13350 13351 static if (isForwardRange!R) 13352 { 13353 auto save() @property 13354 { 13355 typeof(this) result = this; 13356 data = data.save; 13357 return result; 13358 } 13359 } 13360 13361 static if (isBidirectionalRange!R && hasLength!R) 13362 { 13363 auto back() @property 13364 { 13365 assert(!empty, "Attempting to fetch the back of an empty padRight"); 13366 return padLength > 0 ? element : data.back; 13367 } 13368 13369 void popBack() 13370 { 13371 assert(!empty, "Attempting to popBack an empty padRight"); 13372 if (padLength > 0) 13373 { 13374 --padLength; 13375 } 13376 else 13377 { 13378 data.popBack; 13379 } 13380 } 13381 } 13382 13383 static if (isRandomAccessRange!R && hasLength!R) 13384 { 13385 E opIndex(size_t index) 13386 { 13387 assert(index <= this.length, "Index out of bounds"); 13388 return index >= data.length ? element : data[index]; 13389 } 13390 } 13391 13392 static if (hasSlicing!R && hasLength!R) 13393 { 13394 auto opSlice(size_t a, size_t b) 13395 { 13396 assert( 13397 a <= b, 13398 "Attempting to slice a padRight with a larger first argument than the second." 13399 ); 13400 assert( 13401 b <= length, 13402 "Attempting to slice using an out of bounds index on a padRight" 13403 ); 13404 return Result( 13405 a >= data.length ? data[0 .. 0] : b <= data.length ? data[a .. b] : data[a .. data.length], 13406 element, b - a); 13407 } 13408 13409 alias opDollar = length; 13410 } 13411 13412 this(R r, E e, size_t n) 13413 { 13414 data = r; 13415 element = e; 13416 static if (hasLength!R) 13417 { 13418 padLength = n > data.length ? n - data.length : 0; 13419 } 13420 else 13421 { 13422 minLength = n; 13423 } 13424 } 13425 13426 @disable this(); 13427 } 13428 13429 return Result(r, e, n); 13430} 13431 13432/// 13433@safe pure unittest 13434{ 13435 import std.algorithm.comparison : equal; 13436 13437 assert([1, 2, 3, 4].padRight(0, 6).equal([1, 2, 3, 4, 0, 0])); 13438 assert([1, 2, 3, 4].padRight(0, 4).equal([1, 2, 3, 4])); 13439 13440 assert("abc".padRight('_', 6).equal("abc___")); 13441} 13442 13443pure @safe unittest 13444{ 13445 import std.algorithm.comparison : equal; 13446 import std.internal.test.dummyrange : AllDummyRanges, ReferenceInputRange; 13447 import std.meta : AliasSeq; 13448 13449 auto string_input_range = new ReferenceInputRange!dchar(['a', 'b', 'c']); 13450 dchar padding = '_'; 13451 assert(string_input_range.padRight(padding, 6).equal("abc___")); 13452 13453 foreach (RangeType; AllDummyRanges) 13454 { 13455 RangeType r1; 13456 assert(r1 13457 .padRight(0, 12) 13458 .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0, 0]) 13459 ); 13460 13461 // test if Result properly uses random access ranges 13462 static if (isRandomAccessRange!RangeType) 13463 { 13464 RangeType r3; 13465 assert(r3.padRight(0, 12)[0] == 1); 13466 assert(r3.padRight(0, 12)[2] == 3); 13467 assert(r3.padRight(0, 12)[9] == 10); 13468 assert(r3.padRight(0, 12)[10] == 0); 13469 assert(r3.padRight(0, 12)[11] == 0); 13470 } 13471 13472 // test if Result properly uses slicing and opDollar 13473 static if (hasSlicing!RangeType) 13474 { 13475 RangeType r4; 13476 assert(r4 13477 .padRight(0, 12)[0 .. 3] 13478 .equal([1, 2, 3]) 13479 ); 13480 assert(r4 13481 .padRight(0, 12)[0 .. 10] 13482 .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U]) 13483 ); 13484 assert(r4 13485 .padRight(0, 12)[0 .. 11] 13486 .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0]) 13487 ); 13488 assert(r4 13489 .padRight(0, 12)[2 .. $] 13490 .equal([3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0, 0]) 13491 ); 13492 assert(r4 13493 .padRight(0, 12)[0 .. $] 13494 .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0, 0]) 13495 ); 13496 } 13497 13498 // drop & dropBack test opslice ranges when available, popFront/popBack otherwise 13499 RangeType r5; 13500 foreach (i; 1 .. 13) assert(r5.padRight(0, 12).drop(i).walkLength == 12 - i); 13501 } 13502} 13503 13504// Test nogc inference 13505@safe @nogc pure unittest 13506{ 13507 import std.algorithm.comparison : equal; 13508 13509 static immutable r1 = [1, 2, 3, 4]; 13510 static immutable r2 = [1, 2, 3, 4, 0, 0]; 13511 assert(r1.padRight(0, 6).equal(r2)); 13512} 13513 13514// Test back, popBack, and save 13515@safe pure unittest 13516{ 13517 import std.algorithm.comparison : equal; 13518 13519 auto r1 = [1, 2, 3, 4].padRight(0, 6); 13520 assert(r1.back == 0); 13521 13522 r1.popBack; 13523 auto r2 = r1.save; 13524 assert(r1.equal([1, 2, 3, 4, 0])); 13525 assert(r2.equal([1, 2, 3, 4, 0])); 13526 13527 r1.popBackN(2); 13528 assert(r1.back == 3); 13529 assert(r1.length == 3); 13530 assert(r2.length == 5); 13531 assert(r2.equal([1, 2, 3, 4, 0])); 13532 13533 r2.popFront; 13534 assert(r2.length == 4); 13535 assert(r2[0] == 2); 13536 assert(r2[1] == 3); 13537 assert(r2[2] == 4); 13538 assert(r2[3] == 0); 13539 assert(r2.equal([2, 3, 4, 0])); 13540 13541 r2.popBack; 13542 assert(r2.equal([2, 3, 4])); 13543 13544 auto r3 = [1, 2, 3, 4].padRight(0, 6); 13545 size_t len = 0; 13546 while (!r3.empty) 13547 { 13548 ++len; 13549 r3.popBack; 13550 } 13551 assert(len == 6); 13552} 13553 13554// https://issues.dlang.org/show_bug.cgi?id=19042 13555@safe pure unittest 13556{ 13557 import std.algorithm.comparison : equal; 13558 13559 assert([2, 5, 13].padRight(42, 10).chunks(5) 13560 .equal!equal([[2, 5, 13, 42, 42], [42, 42, 42, 42, 42]])); 13561 13562 assert([1, 2, 3, 4].padRight(0, 10)[7 .. 9].equal([0, 0])); 13563} 13564 13565/** 13566This simplifies a commonly used idiom in phobos for accepting any kind of string 13567parameter. The type `R` can for example be a simple string, chained string using 13568$(REF chain, std,range), $(REF chainPath, std,path) or any other input range of 13569characters. 13570 13571Only finite length character ranges are allowed with this constraint. 13572 13573This template is equivalent to: 13574--- 13575isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) 13576--- 13577 13578See_Also: 13579$(REF isInputRange, std,range,primitives), 13580$(REF isInfinite, std,range,primitives), 13581$(LREF isSomeChar), 13582$(REF ElementEncodingType, std,range,primitives) 13583*/ 13584template isSomeFiniteCharInputRange(R) 13585{ 13586 import std.traits : isSomeChar; 13587 13588 enum isSomeFiniteCharInputRange = isInputRange!R && !isInfinite!R 13589 && isSomeChar!(ElementEncodingType!R); 13590} 13591 13592/// 13593@safe unittest 13594{ 13595 import std.path : chainPath; 13596 import std.range : chain; 13597 13598 void someLibraryMethod(R)(R argument) 13599 if (isSomeFiniteCharInputRange!R) 13600 { 13601 // implementation detail, would iterate over each character of argument 13602 } 13603 13604 someLibraryMethod("simple strings work"); 13605 someLibraryMethod(chain("chained", " ", "strings", " ", "work")); 13606 someLibraryMethod(chainPath("chained", "paths", "work")); 13607 // you can also use custom structs implementing a char range 13608} 13609 13610