tree-optimization/118653 - ICE in vectorizable_live_operation
[gcc.git] / libphobos / src / std / range / package.d
blob3a135ebba5108925b10ec9364c4f9d26a02ba8d2
1 // Written in the D programming language.
3 /**
4 This module defines the notion of a range. Ranges generalize the concept of
5 arrays, lists, or anything that involves sequential access. This abstraction
6 enables the same set of algorithms (see $(MREF std, algorithm)) to be used
7 with a vast variety of different concrete types. For example,
8 a linear search algorithm such as $(REF find, std, algorithm, searching)
9 works not just for arrays, but for linked-lists, input files,
10 incoming network data, etc.
12 Guides:
14 There are many articles available that can bolster understanding ranges:
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
32 Submodules:
34 This module has two submodules:
36 The $(MREF std, range, primitives) submodule
37 provides basic range functionality. It defines several templates for testing
38 whether a given object is a range, what kind of range it is, and provides
39 some common range operations.
41 The $(MREF std, range, interfaces) submodule
42 provides object-based interfaces for working with ranges via runtime
43 polymorphism.
45 The remainder of this module provides a rich set of range creation and
46 composition templates that let you construct new ranges out of existing ranges:
49 $(SCRIPT inhibitQuickIndex = 1;)
50 $(DIVC quickindex,
51 $(BOOKTABLE ,
52 $(TR $(TD $(LREF chain))
53 $(TD Concatenates several ranges into a single range.
55 $(TR $(TD $(LREF choose))
56 $(TD Chooses one of two ranges at runtime based on a boolean condition.
58 $(TR $(TD $(LREF chooseAmong))
59 $(TD Chooses one of several ranges at runtime based on an index.
61 $(TR $(TD $(LREF chunks))
62 $(TD Creates a range that returns fixed-size chunks of the original
63 range.
65 $(TR $(TD $(LREF cycle))
66 $(TD Creates an infinite range that repeats the given forward range
67 indefinitely. Good for implementing circular buffers.
69 $(TR $(TD $(LREF drop))
70 $(TD Creates the range that results from discarding the first $(I n)
71 elements from the given range.
73 $(TR $(TD $(LREF dropBack))
74 $(TD Creates the range that results from discarding the last $(I n)
75 elements from the given range.
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.
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.
85 $(TR $(TD $(LREF dropOne))
86 $(TD Creates the range that results from discarding
87 the first element from the given range.
89 $(TR $(TD $(D $(LREF dropBackOne)))
90 $(TD Creates the range that results from discarding
91 the last element from the given range.
93 $(TR $(TD $(LREF enumerate))
94 $(TD Iterates a range with an attached index variable.
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.
100 $(TR $(TD $(LREF frontTransversal))
101 $(TD Creates a range that iterates over the first elements of the
102 given ranges.
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.
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.
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.
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.
121 $(TR $(TD $(LREF nullSink))
122 $(TD An output range that discards the data it receives.
124 $(TR $(TD $(LREF only))
125 $(TD Creates a range that iterates over the given arguments.
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.
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.
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.
140 $(TR $(TD $(LREF recurrence))
141 $(TD Creates a forward range whose values are defined by a
142 mathematical recurrence relation.
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.
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.
153 $(TR $(TD $(LREF retro))
154 $(TD Iterates a bidirectional range backwards.
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.
161 $(TR $(TD $(LREF sequence))
162 $(TD Similar to `recurrence`, except that a random-access range is
163 created.
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.
171 $(TR $(TD $(LREF stride))
172 $(TD Iterates a range with stride $(I n).
174 $(TR $(TD $(LREF tail))
175 $(TD Return a range advanced to within `n` elements of the end of
176 the given range.
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.
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.
186 $(TR $(TD $(LREF takeNone))
187 $(TD Creates a random-access range consisting of zero elements of the
188 given range.
190 $(TR $(TD $(LREF takeOne))
191 $(TD Creates a random-access range consisting of exactly the first
192 element of the given range.
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.
198 $(TR $(TD $(LREF transposed))
199 $(TD Transposes a range of ranges.
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.
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.
212 Sortedness:
214 Ranges whose elements are sorted afford better efficiency with certain
215 operations. For this, the $(LREF assumeSorted) function can be used to
216 construct a $(LREF SortedRange) from a pre-sorted range. The $(REF
217 sort, std, algorithm, sorting) function also conveniently
218 returns a $(LREF SortedRange). $(LREF SortedRange) objects provide some additional
219 range operations that take advantage of the fact that the range is sorted.
221 Source: $(PHOBOSSRC std/range/package.d)
223 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
225 Authors: $(HTTP erdani.com, Andrei Alexandrescu), David Simcha,
226 $(HTTP jmdavisprog.com, Jonathan M Davis), and Jack Stouffer. Credit
227 for some of the ideas in building this module goes to
228 $(HTTP fantascienza.net/leonardo/so/, Leonardo Maffi).
230 module std.range;
232 public import std.array;
233 public import std.range.interfaces;
234 public import std.range.primitives;
235 public import std.typecons : Flag, Yes, No, Rebindable, rebindable;
237 import std.internal.attributes : betterC;
238 import std.meta : aliasSeqOf, allSatisfy, anySatisfy, staticMap;
239 import std.traits : CommonType, isCallable, isFloatingPoint, isIntegral,
240 isPointer, isSomeFunction, isStaticArray, Unqual, isInstanceOf;
244 Iterates a bidirectional range backwards. The original range can be
245 accessed by using the `source` property. Applying retro twice to
246 the same range yields the original range.
248 Params:
249 r = the bidirectional range to iterate backwards
251 Returns:
252 A bidirectional range with length if `r` also provides a length. Or,
253 if `r` is a random access range, then the return value will be random
254 access as well.
255 See_Also:
256 $(REF reverse, std,algorithm,mutation) for mutating the source range directly.
258 auto retro(Range)(Range r)
259 if (isBidirectionalRange!(Unqual!Range))
261 // Check for retro(retro(r)) and just return r in that case
262 static if (is(typeof(retro(r.source)) == Range))
264 return r.source;
266 else
268 static struct Result()
270 private alias R = Unqual!Range;
272 // User code can get and set source, too
273 R source;
275 static if (hasLength!R)
277 size_t retroIndex(size_t n)
279 return source.length - n - 1;
283 public:
284 alias Source = R;
286 @property bool empty() { return source.empty; }
287 @property auto save()
289 return Result(source.save);
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(); }
296 static if (is(typeof(source.moveBack())))
298 ElementType!R moveFront()
300 return source.moveBack();
304 static if (is(typeof(source.moveFront())))
306 ElementType!R moveBack()
308 return source.moveFront();
312 static if (hasAssignableElements!R)
314 @property void front(ElementType!R val)
316 import core.lifetime : forward;
318 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
319 source.back = __ctfe ? val : forward!val;
322 @property void back(ElementType!R val)
324 import core.lifetime : forward;
326 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
327 source.front = __ctfe ? val : forward!val;
331 static if (isRandomAccessRange!(R) && hasLength!(R))
333 auto ref opIndex(size_t n) { return source[retroIndex(n)]; }
335 static if (hasAssignableElements!R)
337 void opIndexAssign(ElementType!R val, size_t n)
339 import core.lifetime : forward;
341 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
342 source[retroIndex(n)] = __ctfe ? val : forward!val;
346 static if (is(typeof(source.moveAt(0))))
348 ElementType!R moveAt(size_t index)
350 return source.moveAt(retroIndex(index));
354 static if (hasSlicing!R)
355 typeof(this) opSlice(size_t a, size_t b)
357 return typeof(this)(source[source.length - b .. source.length - a]);
361 mixin ImplementLength!source;
364 return Result!()(r);
370 pure @safe nothrow @nogc unittest
372 import std.algorithm.comparison : equal;
373 int[5] a = [ 1, 2, 3, 4, 5 ];
374 int[5] b = [ 5, 4, 3, 2, 1 ];
375 assert(equal(retro(a[]), b[]));
376 assert(retro(a[]).source is a[]);
377 assert(retro(retro(a[])) is a[]);
380 pure @safe nothrow unittest
382 import std.algorithm.comparison : equal;
383 static assert(isBidirectionalRange!(typeof(retro("hello"))));
384 int[] a;
385 static assert(is(typeof(a) == typeof(retro(retro(a)))));
386 assert(retro(retro(a)) is a);
387 static assert(isRandomAccessRange!(typeof(retro([1, 2, 3]))));
388 void test(int[] input, int[] witness)
390 auto r = retro(input);
391 assert(r.front == witness.front);
392 assert(r.back == witness.back);
393 assert(equal(r, witness));
395 test([ 1 ], [ 1 ]);
396 test([ 1, 2 ], [ 2, 1 ]);
397 test([ 1, 2, 3 ], [ 3, 2, 1 ]);
398 test([ 1, 2, 3, 4 ], [ 4, 3, 2, 1 ]);
399 test([ 1, 2, 3, 4, 5 ], [ 5, 4, 3, 2, 1 ]);
400 test([ 1, 2, 3, 4, 5, 6 ], [ 6, 5, 4, 3, 2, 1 ]);
402 immutable foo = [1,2,3].idup;
403 auto r = retro(foo);
404 assert(equal(r, [3, 2, 1]));
407 pure @safe nothrow unittest
409 import std.internal.test.dummyrange : AllDummyRanges, propagatesRangeType,
410 ReturnBy;
412 foreach (DummyType; AllDummyRanges)
414 static if (!isBidirectionalRange!DummyType)
416 static assert(!__traits(compiles, Retro!DummyType));
418 else
420 DummyType dummyRange;
421 dummyRange.reinit();
423 auto myRetro = retro(dummyRange);
424 static assert(propagatesRangeType!(typeof(myRetro), DummyType));
425 assert(myRetro.front == 10);
426 assert(myRetro.back == 1);
427 assert(myRetro.moveFront() == 10);
428 assert(myRetro.moveBack() == 1);
430 static if (isRandomAccessRange!DummyType && hasLength!DummyType)
432 assert(myRetro[0] == myRetro.front);
433 assert(myRetro.moveAt(2) == 8);
435 static if (DummyType.r == ReturnBy.Reference)
438 myRetro[9]++;
439 scope(exit) myRetro[9]--;
440 assert(dummyRange[0] == 2);
441 myRetro.front++;
442 scope(exit) myRetro.front--;
443 assert(myRetro.front == 11);
444 myRetro.back++;
445 scope(exit) myRetro.back--;
446 assert(myRetro.back == 3);
450 myRetro.front = 0xFF;
451 scope(exit) myRetro.front = 10;
452 assert(dummyRange.back == 0xFF);
454 myRetro.back = 0xBB;
455 scope(exit) myRetro.back = 1;
456 assert(dummyRange.front == 0xBB);
458 myRetro[1] = 11;
459 scope(exit) myRetro[1] = 8;
460 assert(dummyRange[8] == 11);
468 pure @safe nothrow @nogc unittest
470 import std.algorithm.comparison : equal;
471 auto LL = iota(1L, 4L);
472 auto r = retro(LL);
473 long[3] excepted = [3, 2, 1];
474 assert(equal(r, excepted[]));
477 // https://issues.dlang.org/show_bug.cgi?id=12662
478 pure @safe nothrow @nogc unittest
480 int[3] src = [1,2,3];
481 int[] data = src[];
482 foreach_reverse (x; data) {}
483 foreach (x; data.retro) {}
486 pure @safe nothrow unittest
488 import std.algorithm.comparison : equal;
490 static struct S {
491 int v;
492 @disable this(this);
495 immutable foo = [S(1), S(2), S(3)];
496 auto r = retro(foo);
497 assert(equal(r, [S(3), S(2), S(1)]));
500 // https://issues.dlang.org/show_bug.cgi?id=24481
501 @safe unittest
503 bool called;
504 struct Handle
506 int entry;
507 void opAssign()(auto ref const(typeof(this)) that) const { called = true; }
510 const(Handle)[5] arr = [Handle(0), Handle(1), Handle(2), Handle(3), Handle(4)];
511 auto range = arr[].retro();
513 called = false;
514 range.front = Handle(42);
515 assert(called);
517 called = false;
518 range.back = Handle(42);
519 assert(called);
521 called = false;
522 range[2] = Handle(42);
523 assert(called);
527 Iterates range `r` with stride `n`. If the range is a
528 random-access range, moves by indexing into the range; otherwise,
529 moves by successive calls to `popFront`. Applying stride twice to
530 the same range results in a stride with a step that is the
531 product of the two applications. It is an error for `n` to be 0.
533 Params:
534 r = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to stride over
535 n = the number of elements to skip over
537 Returns:
538 At minimum, an input range. The resulting range will adopt the
539 range primitives of the underlying range as long as
540 $(REF hasLength, std,range,primitives) is `true`.
542 auto stride(Range)(Range r, size_t n)
543 if (isInputRange!(Unqual!Range))
546 assert(n != 0, "stride cannot have step zero.");
550 import std.algorithm.comparison : min;
552 static if (is(typeof(stride(r.source, n)) == Range))
554 // stride(stride(r, n1), n2) is stride(r, n1 * n2)
555 return stride(r.source, r._n * n);
557 else
559 static struct Result
561 private alias R = Unqual!Range;
562 public R source;
563 private size_t _n;
565 // Chop off the slack elements at the end
566 static if (hasLength!R &&
567 (isRandomAccessRange!R && hasSlicing!R
568 || isBidirectionalRange!R))
569 private void eliminateSlackElements()
571 auto slack = source.length % _n;
573 if (slack)
575 slack--;
577 else if (!source.empty)
579 slack = min(_n, source.length) - 1;
581 else
583 slack = 0;
585 if (!slack) return;
586 static if (isRandomAccessRange!R && hasLength!R && hasSlicing!R)
588 source = source[0 .. source.length - slack];
590 else static if (isBidirectionalRange!R)
592 foreach (i; 0 .. slack)
594 source.popBack();
599 static if (isForwardRange!R)
601 @property auto save()
603 return Result(source.save, _n);
607 static if (isInfinite!R)
609 enum bool empty = false;
611 else
613 @property bool empty()
615 return source.empty;
619 @property auto ref front()
621 return source.front;
624 static if (is(typeof(.moveFront(source))))
626 ElementType!R moveFront()
628 return source.moveFront();
632 static if (hasAssignableElements!R)
634 @property void front(ElementType!R val)
636 import core.lifetime : forward;
638 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
639 source.front = __ctfe ? val : forward!val;
643 void popFront()
645 source.popFrontN(_n);
648 static if (isBidirectionalRange!R && hasLength!R)
650 void popBack()
652 popBackN(source, _n);
655 @property auto ref back()
657 eliminateSlackElements();
658 return source.back;
661 static if (is(typeof(.moveBack(source))))
663 ElementType!R moveBack()
665 eliminateSlackElements();
666 return source.moveBack();
670 static if (hasAssignableElements!R)
672 @property void back(ElementType!R val)
674 eliminateSlackElements();
675 source.back = val;
680 static if (isRandomAccessRange!R && hasLength!R)
682 auto ref opIndex(size_t n)
684 return source[_n * n];
688 Forwards to $(D moveAt(source, n)).
690 static if (is(typeof(source.moveAt(0))))
692 ElementType!R moveAt(size_t n)
694 return source.moveAt(_n * n);
698 static if (hasAssignableElements!R)
700 void opIndexAssign(ElementType!R val, size_t n)
702 source[_n * n] = val;
707 static if (hasSlicing!R && hasLength!R)
708 typeof(this) opSlice(size_t lower, size_t upper)
710 assert(upper >= lower && upper <= length,
711 "Attempt to get out-of-bounds slice of `stride` range");
712 immutable translatedUpper = (upper == 0) ? 0 :
713 (upper * _n - (_n - 1));
714 immutable translatedLower = min(lower * _n, translatedUpper);
716 assert(translatedLower <= translatedUpper,
717 "Overflow when calculating slice of `stride` range");
719 return typeof(this)(source[translatedLower .. translatedUpper], _n);
722 static if (hasLength!R)
724 @property auto length()
726 return (source.length + _n - 1) / _n;
729 alias opDollar = length;
732 return Result(r, n);
737 pure @safe nothrow unittest
739 import std.algorithm.comparison : equal;
741 int[] a = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ];
742 assert(equal(stride(a, 3), [ 1, 4, 7, 10 ][]));
743 assert(stride(stride(a, 2), 3) == stride(a, 6));
746 pure @safe nothrow @nogc unittest
748 import std.algorithm.comparison : equal;
750 int[4] testArr = [1,2,3,4];
751 static immutable result = [1, 3];
752 assert(equal(testArr[].stride(2), result));
755 debug pure nothrow @system unittest
756 {//check the contract
757 int[4] testArr = [1,2,3,4];
758 bool passed = false;
759 scope (success) assert(passed);
760 import core.exception : AssertError;
761 //std.exception.assertThrown won't do because it can't infer nothrow
762 // https://issues.dlang.org/show_bug.cgi?id=12647
765 auto unused = testArr[].stride(0);
767 catch (AssertError unused)
769 passed = true;
773 pure @safe nothrow unittest
775 import std.algorithm.comparison : equal;
776 import std.internal.test.dummyrange : AllDummyRanges, propagatesRangeType,
777 ReturnBy;
779 static assert(isRandomAccessRange!(typeof(stride([1, 2, 3], 2))));
780 void test(size_t n, int[] input, int[] witness)
782 assert(equal(stride(input, n), witness));
784 test(1, [], []);
785 int[] arr = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
786 assert(stride(stride(arr, 2), 3) is stride(arr, 6));
787 test(1, arr, arr);
788 test(2, arr, [1, 3, 5, 7, 9]);
789 test(3, arr, [1, 4, 7, 10]);
790 test(4, arr, [1, 5, 9]);
792 // Test slicing.
793 auto s1 = stride(arr, 1);
794 assert(equal(s1[1 .. 4], [2, 3, 4]));
795 assert(s1[1 .. 4].length == 3);
796 assert(equal(s1[1 .. 5], [2, 3, 4, 5]));
797 assert(s1[1 .. 5].length == 4);
798 assert(s1[0 .. 0].empty);
799 assert(s1[3 .. 3].empty);
800 // assert(s1[$ .. $].empty);
801 assert(s1[s1.opDollar .. s1.opDollar].empty);
803 auto s2 = stride(arr, 2);
804 assert(equal(s2[0 .. 2], [1,3]));
805 assert(s2[0 .. 2].length == 2);
806 assert(equal(s2[1 .. 5], [3, 5, 7, 9]));
807 assert(s2[1 .. 5].length == 4);
808 assert(s2[0 .. 0].empty);
809 assert(s2[3 .. 3].empty);
810 // assert(s2[$ .. $].empty);
811 assert(s2[s2.opDollar .. s2.opDollar].empty);
813 // Test fix for https://issues.dlang.org/show_bug.cgi?id=5035
814 auto m = [1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]; // 3 rows, 4 columns
815 auto col = stride(m, 4);
816 assert(equal(col, [1, 1, 1]));
817 assert(equal(retro(col), [1, 1, 1]));
819 immutable int[] immi = [ 1, 2, 3 ];
820 static assert(isRandomAccessRange!(typeof(stride(immi, 1))));
822 // Check for infiniteness propagation.
823 static assert(isInfinite!(typeof(stride(repeat(1), 3))));
825 foreach (DummyType; AllDummyRanges)
827 DummyType dummyRange;
828 dummyRange.reinit();
830 auto myStride = stride(dummyRange, 4);
832 // Should fail if no length and bidirectional b/c there's no way
833 // to know how much slack we have.
834 static if (hasLength!DummyType || !isBidirectionalRange!DummyType)
836 static assert(propagatesRangeType!(typeof(myStride), DummyType));
838 assert(myStride.front == 1);
839 assert(myStride.moveFront() == 1);
840 assert(equal(myStride, [1, 5, 9]));
842 static if (hasLength!DummyType)
844 assert(myStride.length == 3);
847 static if (isBidirectionalRange!DummyType && hasLength!DummyType)
849 assert(myStride.back == 9);
850 assert(myStride.moveBack() == 9);
853 static if (isRandomAccessRange!DummyType && hasLength!DummyType)
855 assert(myStride[0] == 1);
856 assert(myStride[1] == 5);
857 assert(myStride.moveAt(1) == 5);
858 assert(myStride[2] == 9);
860 static assert(hasSlicing!(typeof(myStride)));
863 static if (DummyType.r == ReturnBy.Reference)
865 // Make sure reference is propagated.
868 myStride.front++;
869 scope(exit) myStride.front--;
870 assert(dummyRange.front == 2);
873 myStride.front = 4;
874 scope(exit) myStride.front = 1;
875 assert(dummyRange.front == 4);
878 static if (isBidirectionalRange!DummyType && hasLength!DummyType)
881 myStride.back++;
882 scope(exit) myStride.back--;
883 assert(myStride.back == 10);
886 myStride.back = 111;
887 scope(exit) myStride.back = 9;
888 assert(myStride.back == 111);
891 static if (isRandomAccessRange!DummyType)
894 myStride[1]++;
895 scope(exit) myStride[1]--;
896 assert(dummyRange[4] == 6);
899 myStride[1] = 55;
900 scope(exit) myStride[1] = 5;
901 assert(dummyRange[4] == 55);
909 pure @safe nothrow unittest
911 import std.algorithm.comparison : equal;
913 auto LL = iota(1L, 10L);
914 auto s = stride(LL, 3);
915 assert(equal(s, [1L, 4L, 7L]));
918 pure @safe nothrow unittest
920 import std.algorithm.comparison : equal;
922 static struct S {
923 int v;
924 @disable this(this);
927 immutable foo = [S(1), S(2), S(3), S(4), S(5)];
928 auto r = stride(foo, 3);
929 assert(equal(r, [S(1), S(4)]));
932 // https://issues.dlang.org/show_bug.cgi?id=24481
933 @safe unittest
935 bool called;
936 struct Handle
938 int entry;
939 void opAssign()(auto ref const(typeof(this)) that) const { called = true; }
942 const(Handle)[5] arr = [Handle(0), Handle(1), Handle(2), Handle(3), Handle(4)];
943 auto range = arr[].stride(2);
945 called = false;
946 range.front = Handle(42);
947 assert(called);
951 Spans multiple ranges in sequence. The function `chain` takes any
952 number of ranges and returns a $(D Chain!(R1, R2,...)) object. The
953 ranges may be different, but they must have the same element type. The
954 result is a range that offers the `front`, `popFront`, and $(D
955 empty) primitives. If all input ranges offer random access and $(D
956 length), `Chain` offers them as well.
958 Note that repeated random access of the resulting range is likely
959 to perform somewhat badly since lengths of the ranges in the chain have to be
960 added up for each random access operation. Random access to elements of
961 the first remaining range is still efficient.
963 If only one range is offered to `Chain` or `chain`, the $(D
964 Chain) type exits the picture by aliasing itself directly to that
965 range's type.
967 Params:
968 rs = the $(REF_ALTTEXT input ranges, isInputRange, std,range,primitives) to chain together
970 Returns:
971 An input range at minimum. If all of the ranges in `rs` provide
972 a range primitive, the returned range will also provide that range
973 primitive.
975 See_Also: $(LREF only) to chain values to a range
977 auto chain(Ranges...)(Ranges rs)
978 if (Ranges.length > 0 &&
979 allSatisfy!(isInputRange, staticMap!(Unqual, Ranges)) &&
980 !is(CommonType!(staticMap!(ElementType, staticMap!(Unqual, Ranges))) == void))
982 static if (Ranges.length == 1)
984 return rs[0];
986 else
988 static struct Result
990 private:
991 alias R = staticMap!(Unqual, Ranges);
992 alias RvalueElementType = CommonType!(staticMap!(.ElementType, R));
993 template sameET(A)
995 enum sameET = is(.ElementType!A == RvalueElementType);
998 enum bool allSameType = allSatisfy!(sameET, R),
999 bidirectional = allSatisfy!(isBidirectionalRange, R),
1000 mobileElements = allSatisfy!(hasMobileElements, R),
1001 assignableElements = allSameType
1002 && allSatisfy!(hasAssignableElements, R);
1004 alias ElementType = RvalueElementType;
1006 static if (allSameType && allSatisfy!(hasLvalueElements, R))
1008 static ref RvalueElementType fixRef(ref RvalueElementType val)
1010 return val;
1013 else
1015 static RvalueElementType fixRef(RvalueElementType val)
1017 return val;
1021 R source;
1022 size_t frontIndex;
1023 // Always points to index one past the last non-empty range,
1024 // because otherwise decrementing while pointing to first range
1025 // would overflow to size_t.max.
1026 static if (bidirectional) size_t backIndex;
1027 else enum backIndex = source.length;
1029 this(typeof(Result.tupleof) fields)
1031 this.tupleof = fields;
1034 public:
1035 this(R input)
1037 frontIndex = source.length;
1038 static if (bidirectional) backIndex = 0;
1040 foreach (i, ref v; input) source[i] = v;
1042 // We do this separately to avoid invoking `empty` needlessly.
1043 // While not recommended, a range may depend on side effects of
1044 // `empty` call.
1045 foreach (i, ref v; input) if (!v.empty)
1047 frontIndex = i;
1048 static if (bidirectional) backIndex = i+1;
1049 break;
1052 // backIndex is already set in the first loop to
1053 // as frontIndex+1, so we'll use that if we don't find a
1054 // non-empty range here.
1055 static if (bidirectional)
1056 static foreach_reverse (i; 1 .. R.length + 1)
1058 if (i <= frontIndex + 1) return;
1059 if (!input[i-1].empty)
1061 backIndex = i;
1062 return;
1067 import std.meta : anySatisfy;
1069 static if (anySatisfy!(isInfinite, R))
1071 // Propagate infiniteness.
1072 enum bool empty = false;
1074 else
1076 @property bool empty()
1078 if (frontIndex == 0)
1080 // special handling: we might be in Range.init state!
1081 // For instance, `format!"%s"` uses Range.init to ensure
1082 // that formatting is possible.
1083 // In that case, we must still behave in an internally consistent way.
1084 return source[0].empty;
1086 return frontIndex >= backIndex;
1090 static if (allSatisfy!(isForwardRange, R))
1092 @property auto save()
1094 auto saveI(size_t i)() => source[i].save;
1096 // TODO: this has the constructor needlessly refind
1097 // frontIndex and backIndex. It'd be better to just copy
1098 // those from `.this`.
1099 auto saveResult =
1100 Result(staticMap!(saveI, aliasSeqOf!(R.length.iota)));
1102 return saveResult;
1106 void popFront()
1108 sw1: switch (frontIndex)
1110 static foreach (i; 0 .. R.length)
1112 case i:
1113 source[i].popFront();
1114 break sw1;
1117 case R.length:
1118 assert(0, "Attempt to `popFront` of empty `chain` range");
1120 default:
1121 assert(0, "Internal library error. Please report it.");
1124 sw2: switch (frontIndex)
1126 static foreach (i; 0 .. R.length)
1128 case i:
1129 if (source[i].empty)
1131 frontIndex++;
1132 goto case;
1134 else break sw2;
1137 // Only possible to reach from goto of previous case.
1138 case R.length:
1139 break;
1141 default:
1142 assert(0, "Internal library error. Please report it.");
1146 @property auto ref front()
1148 switch (frontIndex)
1150 static foreach (i; 0 .. R.length)
1152 case i:
1153 return fixRef(source[i].front);
1156 case R.length:
1157 assert(0, "Attempt to get `front` of empty `chain` range");
1159 default:
1160 assert(0, "Internal library error. Please report it.");
1164 static if (assignableElements)
1166 // @@@BUG@@@
1167 //@property void front(T)(T v) if (is(T : RvalueElementType))
1169 @property void front(RvalueElementType v)
1171 import core.lifetime : forward;
1173 sw: switch (frontIndex)
1175 static foreach (i; 0 .. R.length)
1177 case i:
1178 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
1179 source[i].front = __ctfe ? v : forward!v;
1180 break sw;
1183 case R.length:
1184 assert(0, "Attempt to set `front` of empty `chain` range");
1186 default:
1187 assert(0, "Internal library error. Please report it.");
1192 static if (mobileElements)
1194 RvalueElementType moveFront()
1196 switch (frontIndex)
1198 static foreach (i; 0 .. R.length)
1200 case i:
1201 return source[i].moveFront();
1204 case R.length:
1205 assert(0, "Attempt to `moveFront` of empty `chain` range");
1207 default:
1208 assert(0, "Internal library error. Please report it.");
1213 static if (bidirectional)
1215 @property auto ref back()
1217 switch (backIndex)
1219 static foreach_reverse (i; 1 .. R.length + 1)
1221 case i:
1222 return fixRef(source[i-1].back);
1225 case 0:
1226 assert(0, "Attempt to get `back` of empty `chain` range");
1228 default:
1229 assert(0, "Internal library error. Please report it.");
1233 void popBack()
1235 sw1: switch (backIndex)
1237 static foreach_reverse (i; 1 .. R.length + 1)
1239 case i:
1240 source[i-1].popBack();
1241 break sw1;
1244 case 0:
1245 assert(0, "Attempt to `popFront` of empty `chain` range");
1247 default:
1248 assert(0, "Internal library error. Please report it.");
1251 sw2: switch (backIndex)
1253 static foreach_reverse (i; 1 .. R.length + 1)
1255 case i:
1256 if (source[i-1].empty)
1258 backIndex--;
1259 goto case;
1261 else break sw2;
1264 // Only possible to reach from goto of previous case.
1265 case 0:
1266 break;
1268 default:
1269 assert(0, "Internal library error. Please report it.");
1273 static if (mobileElements)
1275 RvalueElementType moveBack()
1277 switch (backIndex)
1279 static foreach_reverse (i; 1 .. R.length + 1)
1281 case i:
1282 return source[i-1].moveBack();
1285 case 0:
1286 assert(0, "Attempt to `moveBack` of empty `chain` range");
1288 default:
1289 assert(0, "Internal library error. Please report it.");
1294 static if (allSameType && allSatisfy!(hasAssignableElements, R))
1296 @property void back(RvalueElementType v)
1298 import core.lifetime : forward;
1300 sw: switch (backIndex)
1302 static foreach_reverse (i; 1 .. R.length + 1)
1304 case i:
1305 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
1306 source[i - 1].back = __ctfe ? v : forward!v;
1307 break sw;
1310 case 0:
1311 assert(0, "Attempt to set `back` of empty `chain` range");
1313 default:
1314 assert(0, "Internal library error. Please report it.");
1320 static if (allSatisfy!(hasLength, R))
1322 @property size_t length()
1324 size_t result = 0;
1325 sw: switch (frontIndex)
1327 static foreach (i; 0 .. R.length)
1329 case i:
1330 result += source[i].length;
1331 if (backIndex == i+1) break sw;
1332 else goto case;
1335 case R.length:
1336 break;
1338 default:
1339 assert(0, "Internal library error. Please report it.");
1342 return result;
1345 alias opDollar = length;
1348 static if (allSatisfy!(isRandomAccessRange, R))
1350 auto ref opIndex(size_t index)
1352 switch (frontIndex)
1354 static foreach (i; 0 .. R.length)
1356 case i:
1357 static if (!isInfinite!(R[i]))
1359 immutable length = source[i].length;
1360 if (index >= length)
1362 index -= length;
1363 goto case;
1367 return fixRef(source[i][index]);
1370 case R.length:
1371 assert(0, "Attempt to access out-of-bounds index of `chain` range");
1373 default:
1374 assert(0, "Internal library error. Please report it.");
1378 static if (mobileElements)
1380 RvalueElementType moveAt(size_t index)
1382 switch (frontIndex)
1384 static foreach (i; 0 .. R.length)
1386 case i:
1387 static if (!isInfinite!(R[i]))
1389 immutable length = source[i].length;
1390 if (index >= length)
1392 index -= length;
1393 goto case;
1397 return source[i].moveAt(index);
1400 case R.length:
1401 assert(0, "Attempt to move out-of-bounds index of `chain` range");
1403 default:
1404 assert(0, "Internal library error. Please report it.");
1409 static if (allSameType && allSatisfy!(hasAssignableElements, R))
1410 void opIndexAssign(ElementType v, size_t index)
1412 import core.lifetime : forward;
1414 sw: switch (frontIndex)
1416 static foreach (i; 0 .. R.length)
1418 case i:
1419 static if (!isInfinite!(R[i]))
1421 immutable length = source[i].length;
1422 if (index >= length)
1424 index -= length;
1425 goto case;
1429 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
1430 source[i][index] = __ctfe ? v : forward!v;
1431 break sw;
1434 case R.length:
1435 assert(0, "Attempt to write out-of-bounds index of `chain` range");
1437 default:
1438 assert(0, "Internal library error. Please report it.");
1443 static if (allSatisfy!(hasLength, R) && allSatisfy!(hasSlicing, R))
1444 auto opSlice(size_t begin, size_t end) return scope
1446 // force staticMap type conversion to Rebindable
1447 static struct ResultRanges
1449 staticMap!(Rebindable, typeof(source)) fields;
1451 auto sourceI(size_t i)() => rebindable(this.source[i]);
1452 auto resultRanges = ResultRanges(staticMap!(sourceI, aliasSeqOf!(R.length.iota))).fields;
1453 size_t resultFrontIndex = this.frontIndex;
1454 static if (bidirectional)
1455 size_t resultBackIndex = this.backIndex;
1457 sw: switch (frontIndex)
1459 static foreach (i; 0 .. R.length)
1461 case i:
1462 immutable len = resultRanges[i].length;
1463 if (len <= begin)
1465 resultRanges[i] = resultRanges[i]
1466 [len .. len];
1467 begin -= len;
1468 resultFrontIndex++;
1469 goto case;
1471 else
1473 resultRanges[i] = resultRanges[i]
1474 [begin .. len];
1475 break sw;
1479 case R.length:
1480 assert(begin == 0,
1481 "Attempt to access out-of-bounds slice of `chain` range");
1482 break;
1484 default:
1485 assert(0, "Internal library error. Please report it.");
1488 // Overflow intentional if end index too big.
1489 // This will trigger the bounds check failure below.
1490 auto cut = length - end;
1492 sw2: switch (backIndex)
1494 static foreach_reverse (i; 1 .. R.length + 1)
1496 case i:
1497 immutable len = resultRanges[i-1].length;
1498 if (len <= cut)
1500 resultRanges[i-1] = resultRanges[i-1]
1501 [0 .. 0];
1502 cut -= len;
1503 resultBackIndex--;
1504 goto case;
1506 else
1508 resultRanges[i-1] = resultRanges[i-1]
1509 [0 .. len - cut];
1510 break sw2;
1514 case 0:
1515 assert(cut == 0, end > length?
1516 "Attempt to access out-of-bounds slice of `chain` range":
1517 "Attempt to access negative length slice of `chain` range");
1518 break sw2;
1520 default:
1521 assert(0, "Internal library error. Please report it.");
1524 static if (bidirectional)
1525 return Result(resultRanges, resultFrontIndex, resultBackIndex);
1526 else
1527 return Result(resultRanges, resultFrontIndex);
1530 return Result(rs);
1535 pure @safe nothrow unittest
1537 import std.algorithm.comparison : equal;
1539 int[] arr1 = [ 1, 2, 3, 4 ];
1540 int[] arr2 = [ 5, 6 ];
1541 int[] arr3 = [ 7 ];
1542 auto s = chain(arr1, arr2, arr3);
1543 assert(s.length == 7);
1544 assert(s[5] == 6);
1545 assert(equal(s, [1, 2, 3, 4, 5, 6, 7][]));
1549 * Range primitives are carried over to the returned range if
1550 * all of the ranges provide them
1552 pure @safe nothrow unittest
1554 import std.algorithm.comparison : equal;
1555 import std.algorithm.sorting : sort;
1557 int[] arr1 = [5, 2, 8];
1558 int[] arr2 = [3, 7, 9];
1559 int[] arr3 = [1, 4, 6];
1561 // in-place sorting across all of the arrays
1562 auto s = arr1.chain(arr2, arr3).sort;
1564 assert(s.equal([1, 2, 3, 4, 5, 6, 7, 8, 9]));
1565 assert(arr1.equal([1, 2, 3]));
1566 assert(arr2.equal([4, 5, 6]));
1567 assert(arr3.equal([7, 8, 9]));
1571 Due to safe type promotion in D, chaining together different
1572 character ranges results in a `uint` range.
1574 Use $(REF_ALTTEXT byChar, byChar,std,utf), $(REF_ALTTEXT byWchar, byWchar,std,utf),
1575 and $(REF_ALTTEXT byDchar, byDchar,std,utf) on the ranges
1576 to get the type you need.
1578 pure @safe nothrow unittest
1580 import std.utf : byChar, byCodeUnit;
1582 auto s1 = "string one";
1583 auto s2 = "string two";
1584 // s1 and s2 front is dchar because of auto-decoding
1585 static assert(is(typeof(s1.front) == dchar) && is(typeof(s2.front) == dchar));
1587 auto r1 = s1.chain(s2);
1588 // chains of ranges of the same character type give that same type
1589 static assert(is(typeof(r1.front) == dchar));
1591 auto s3 = "string three".byCodeUnit;
1592 static assert(is(typeof(s3.front) == immutable char));
1593 auto r2 = s1.chain(s3);
1594 // chaining ranges of mixed character types gives `dchar`
1595 static assert(is(typeof(r2.front) == dchar));
1597 // use byChar on character ranges to correctly convert them to UTF-8
1598 auto r3 = s1.byChar.chain(s3);
1599 static assert(is(typeof(r3.front) == immutable char));
1602 pure @safe nothrow unittest
1604 import std.algorithm.comparison : equal;
1605 import std.internal.test.dummyrange : AllDummyRanges, dummyLength,
1606 propagatesRangeType;
1609 int[] arr1 = [ 1, 2, 3, 4 ];
1610 int[] arr2 = [ 5, 6 ];
1611 int[] arr3 = [ 7 ];
1612 int[] witness = [ 1, 2, 3, 4, 5, 6, 7 ];
1613 auto s1 = chain(arr1);
1614 static assert(isRandomAccessRange!(typeof(s1)));
1615 auto s2 = chain(arr1, arr2);
1616 static assert(isBidirectionalRange!(typeof(s2)));
1617 static assert(isRandomAccessRange!(typeof(s2)));
1618 s2.front = 1;
1619 auto s = chain(arr1, arr2, arr3);
1620 assert(s[5] == 6);
1621 assert(equal(s, witness));
1622 assert(s[4 .. 6].equal(arr2));
1623 assert(s[2 .. 5].equal([3, 4, 5]));
1624 assert(s[0 .. 0].empty);
1625 assert(s[7 .. $].empty);
1626 assert(s[5] == 6);
1629 int[] arr1 = [ 1, 2, 3, 4 ];
1630 int[] witness = [ 1, 2, 3, 4 ];
1631 assert(equal(chain(arr1), witness));
1634 uint[] foo = [1,2,3,4,5];
1635 uint[] bar = [1,2,3,4,5];
1636 auto c = chain(foo, bar);
1637 c[3] = 42;
1638 assert(c[3] == 42);
1639 assert(c.moveFront() == 1);
1640 assert(c.moveBack() == 5);
1641 assert(c.moveAt(4) == 5);
1642 assert(c.moveAt(5) == 1);
1646 // Make sure https://issues.dlang.org/show_bug.cgi?id=3311 is fixed.
1647 // elements are mutable.
1648 assert(equal(chain(iota(0, 3), iota(0, 3)), [0, 1, 2, 0, 1, 2]));
1650 // Test the case where infinite ranges are present.
1651 auto inf = chain([0,1,2][], cycle([4,5,6][]), [7,8,9][]); // infinite range
1652 assert(inf[0] == 0);
1653 assert(inf[3] == 4);
1654 assert(inf[6] == 4);
1655 assert(inf[7] == 5);
1656 static assert(isInfinite!(typeof(inf)));
1658 immutable int[] immi = [ 1, 2, 3 ];
1659 immutable float[] immf = [ 1, 2, 3 ];
1660 static assert(is(typeof(chain(immi, immf))));
1662 // Check that chain at least instantiates and compiles with every possible
1663 // pair of DummyRange types, in either order.
1665 foreach (DummyType1; AllDummyRanges)
1666 (){ // workaround slow optimizations for large functions
1667 // https://issues.dlang.org/show_bug.cgi?id=2396
1668 DummyType1 dummy1;
1669 foreach (DummyType2; AllDummyRanges)
1671 DummyType2 dummy2;
1672 auto myChain = chain(dummy1, dummy2);
1674 static assert(
1675 propagatesRangeType!(typeof(myChain), DummyType1, DummyType2)
1678 assert(myChain.front == 1);
1679 foreach (i; 0 .. dummyLength)
1681 myChain.popFront();
1683 assert(myChain.front == 1);
1685 static if (isBidirectionalRange!DummyType1 &&
1686 isBidirectionalRange!DummyType2) {
1687 assert(myChain.back == 10);
1690 static if (isRandomAccessRange!DummyType1 &&
1691 isRandomAccessRange!DummyType2) {
1692 assert(myChain[0] == 1);
1695 static if (hasLvalueElements!DummyType1 && hasLvalueElements!DummyType2)
1697 static assert(hasLvalueElements!(typeof(myChain)));
1699 else
1701 static assert(!hasLvalueElements!(typeof(myChain)));
1704 }();
1707 pure @safe nothrow @nogc unittest
1709 class Foo{}
1710 immutable(Foo)[] a;
1711 immutable(Foo)[] b;
1712 assert(chain(a, b).empty);
1715 // https://issues.dlang.org/show_bug.cgi?id=18657
1716 pure @safe unittest
1718 import std.algorithm.comparison : equal;
1719 string s = "foo";
1720 auto r = refRange(&s).chain("bar");
1721 assert(equal(r.save, "foobar"));
1722 assert(equal(r, "foobar"));
1725 // https://issues.dlang.org/show_bug.cgi?id=23844
1726 pure @safe unittest
1728 struct S
1730 immutable int value;
1733 auto range = chain(only(S(5)), only(S(6)));
1734 assert(range.array == [S(5), S(6)]);
1737 // https://issues.dlang.org/show_bug.cgi?id=24064
1738 pure @safe nothrow unittest
1740 import std.algorithm.comparison : equal;
1741 import std.typecons : Nullable;
1743 immutable Nullable!string foo = "b";
1744 string[] bar = ["a"];
1745 assert(chain(bar, foo).equal(["a", "b"]));
1748 pure @safe nothrow @nogc unittest
1750 // support non-copyable items
1752 static struct S {
1753 int v;
1754 @disable this(this);
1757 S[2] s0, s1;
1758 foreach (ref el; chain(s0[], s1[]))
1760 int n = el.v;
1763 S[] s2, s3;
1764 foreach (ref el; chain(s2, s3))
1766 int n = el.v;
1770 // https://issues.dlang.org/show_bug.cgi?id=24243
1771 pure @safe nothrow unittest
1773 import std.algorithm.iteration : filter;
1775 auto range = chain([2], [3].filter!"a");
1777 // This might happen in format!"%s"(range), for instance.
1778 assert(typeof(range).init.empty);
1781 // https://issues.dlang.org/show_bug.cgi?id=24481
1782 @safe unittest
1784 bool called;
1785 struct Handle
1787 int entry;
1788 void opAssign()(auto ref const(typeof(this)) that) const { called = true; }
1791 const(Handle)[5] arr = [Handle(0), Handle(1), Handle(2), Handle(3), Handle(4)];
1792 auto range = arr[0 .. 2].chain(arr[4 .. 5]);
1794 called = false;
1795 range.front = Handle(42);
1796 assert(called);
1798 called = false;
1799 range.back = Handle(42);
1800 assert(called);
1802 called = false;
1803 range[2] = Handle(42);
1804 assert(called);
1808 Choose one of two ranges at runtime depending on a Boolean condition.
1810 The ranges may be different, but they must have compatible element types (i.e.
1811 `CommonType` must exist for the two element types). The result is a range
1812 that offers the weakest capabilities of the two (e.g. `ForwardRange` if $(D
1813 R1) is a random-access range and `R2` is a forward range).
1815 Params:
1816 condition = which range to choose: `r1` if `true`, `r2` otherwise
1817 r1 = the "true" range
1818 r2 = the "false" range
1820 Returns:
1821 A range type dependent on `R1` and `R2`.
1823 auto choose(R1, R2)(bool condition, return scope R1 r1, return scope R2 r2)
1824 if (isInputRange!(Unqual!R1) && isInputRange!(Unqual!R2) &&
1825 !is(CommonType!(ElementType!(Unqual!R1), ElementType!(Unqual!R2)) == void))
1827 size_t choice = condition? 0: 1;
1828 return ChooseResult!(R1, R2)(choice, r1, r2);
1832 @safe nothrow pure @nogc unittest
1834 import std.algorithm.comparison : equal;
1835 import std.algorithm.iteration : filter, map;
1837 auto data1 = only(1, 2, 3, 4).filter!(a => a != 3);
1838 auto data2 = only(5, 6, 7, 8).map!(a => a + 1);
1840 // choose() is primarily useful when you need to select one of two ranges
1841 // with different types at runtime.
1842 static assert(!is(typeof(data1) == typeof(data2)));
1844 auto chooseRange(bool pickFirst)
1846 // The returned range is a common wrapper type that can be used for
1847 // returning or storing either range without running into a type error.
1848 return choose(pickFirst, data1, data2);
1850 // Simply returning the chosen range without using choose() does not
1851 // work, because map() and filter() return different types.
1852 //return pickFirst ? data1 : data2; // does not compile
1855 auto result = chooseRange(true);
1856 assert(result.equal(only(1, 2, 4)));
1858 result = chooseRange(false);
1859 assert(result.equal(only(6, 7, 8, 9)));
1863 private struct ChooseResult(Ranges...)
1865 import std.meta : aliasSeqOf, ApplyLeft;
1866 import std.traits : hasElaborateCopyConstructor, hasElaborateDestructor,
1867 lvalueOf;
1869 private union
1871 Ranges rs;
1873 private size_t chosenI;
1875 private static auto ref actOnChosen(alias foo, ExtraArgs ...)
1876 (ref ChooseResult r, auto ref ExtraArgs extraArgs)
1878 ref getI(size_t i)(return ref ChooseResult r) @trusted { return r.rs[i]; }
1880 switch (r.chosenI)
1882 static foreach (candI; 0 .. rs.length)
1884 case candI: return foo(getI!candI(r), extraArgs);
1887 default: assert(false);
1891 // @trusted because of assignment of r which overlap each other
1892 this(size_t chosen, return scope Ranges rs) @trusted
1894 import core.lifetime : emplace;
1896 // This should be the only place chosenI is ever assigned
1897 // independently
1898 this.chosenI = chosen;
1900 // Otherwise the compiler will complain about skipping these fields
1901 static foreach (i; 0 .. rs.length)
1903 this.rs[i] = Ranges[i].init;
1906 // The relevant field needs to be initialized last so it will overwrite
1907 // the other initializations and not the other way around.
1908 sw: switch (chosenI)
1910 static foreach (i; 0 .. rs.length)
1912 case i:
1913 emplace(&this.rs[i], rs[i]);
1914 break sw;
1917 default: assert(false);
1921 // Some legacy code may still call this with typeof(choose(/*...*/))(/*...*/)
1922 // without this overload the regular constructor would invert the meaning of
1923 // the boolean
1924 static if (rs.length == 2)
1925 pragma(inline, true)
1926 deprecated("Call with size_t (0 = first), or use the choose function")
1927 this(bool firstChosen, Ranges rs)
1929 import core.lifetime : move;
1930 this(cast(size_t)(firstChosen? 0: 1), rs[0].move, rs[1].move);
1933 void opAssign(ChooseResult r)
1935 ref getI(size_t i)(return ref ChooseResult r) @trusted { return r.rs[i]; }
1937 static if (anySatisfy!(hasElaborateDestructor, Ranges))
1938 if (chosenI != r.chosenI)
1940 // destroy the current item
1941 actOnChosen!((ref r) => destroy(r))(this);
1943 chosenI = r.chosenI;
1945 sw: switch (chosenI)
1947 static foreach (candI; 0 .. rs.length)
1949 case candI: getI!candI(this) = getI!candI(r);
1950 break sw;
1953 default: assert(false);
1957 // Carefully defined postblit to postblit the appropriate range
1958 static if (anySatisfy!(hasElaborateCopyConstructor, Ranges))
1959 this(this)
1961 actOnChosen!((ref r) {
1962 static if (hasElaborateCopyConstructor!(typeof(r))) r.__xpostblit();
1963 })(this);
1966 static if (anySatisfy!(hasElaborateDestructor, Ranges))
1967 ~this()
1969 actOnChosen!((ref r) => destroy(r))(this);
1972 // Propagate infiniteness.
1973 static if (allSatisfy!(isInfinite, Ranges)) enum bool empty = false;
1974 else @property bool empty()
1976 return actOnChosen!(r => r.empty)(this);
1979 @property auto ref front()
1981 static auto ref getFront(R)(ref R r) { return r.front; }
1982 return actOnChosen!getFront(this);
1985 void popFront()
1987 return actOnChosen!((ref r) { r.popFront; })(this);
1990 static if (allSatisfy!(isForwardRange, Ranges))
1991 @property auto save() // return scope inferred
1993 auto saveOrInit(size_t i)()
1995 ref getI() @trusted { return rs[i]; }
1996 if (i == chosenI) return getI().save;
1997 else return Ranges[i].init;
2000 return typeof(this)(chosenI, staticMap!(saveOrInit,
2001 aliasSeqOf!(rs.length.iota)));
2004 template front(T)
2006 private enum overloadValidFor(alias r) = is(typeof(r.front = T.init));
2008 static if (allSatisfy!(overloadValidFor, rs))
2009 void front(T v)
2011 actOnChosen!((ref r, T v) { r.front = v; })(this, v);
2015 static if (allSatisfy!(hasMobileElements, Ranges))
2016 auto moveFront()
2018 return actOnChosen!((ref r) => r.moveFront)(this);
2021 static if (allSatisfy!(isBidirectionalRange, Ranges))
2023 @property auto ref back()
2025 static auto ref getBack(R)(ref R r) { return r.back; }
2026 return actOnChosen!getBack(this);
2029 void popBack()
2031 actOnChosen!((ref r) { r.popBack; })(this);
2034 static if (allSatisfy!(hasMobileElements, Ranges))
2035 auto moveBack()
2037 return actOnChosen!((ref r) => r.moveBack)(this);
2040 template back(T)
2042 private enum overloadValidFor(alias r) = is(typeof(r.back = T.init));
2044 static if (allSatisfy!(overloadValidFor, rs))
2045 void back(T v)
2047 actOnChosen!((ref r, T v) { r.back = v; })(this, v);
2052 static if (allSatisfy!(hasLength, Ranges))
2054 @property size_t length()
2056 return actOnChosen!(r => r.length)(this);
2058 alias opDollar = length;
2061 static if (allSatisfy!(isRandomAccessRange, Ranges))
2063 auto ref opIndex(size_t index)
2065 static auto ref get(R)(ref R r, size_t index) { return r[index]; }
2066 return actOnChosen!get(this, index);
2069 static if (allSatisfy!(hasMobileElements, Ranges))
2070 auto moveAt(size_t index)
2072 return actOnChosen!((ref r, size_t index) => r.moveAt(index))
2073 (this, index);
2076 private enum indexAssignable(T, R) = is(typeof(lvalueOf!R[1] = T.init));
2078 template opIndexAssign(T)
2079 if (allSatisfy!(ApplyLeft!(indexAssignable, T), Ranges))
2081 void opIndexAssign(T v, size_t index)
2083 return actOnChosen!((ref r, size_t index, T v) { r[index] = v; })
2084 (this, index, v);
2089 static if (allSatisfy!(hasSlicing, Ranges))
2090 auto opSlice(size_t begin, size_t end)
2092 alias Slice(R) = typeof(R.init[0 .. 1]);
2093 alias Slices = staticMap!(Slice, Ranges);
2095 auto sliceOrInit(size_t i)()
2097 ref getI() @trusted { return rs[i]; }
2098 return i == chosenI? getI()[begin .. end]: Slices[i].init;
2101 return chooseAmong(chosenI, staticMap!(sliceOrInit,
2102 aliasSeqOf!(rs.length.iota)));
2106 // https://issues.dlang.org/show_bug.cgi?id=18657
2107 pure @safe unittest
2109 import std.algorithm.comparison : equal;
2110 string s = "foo";
2111 auto r = choose(true, refRange(&s), "bar");
2112 assert(equal(r.save, "foo"));
2113 assert(equal(r, "foo"));
2116 @safe unittest
2118 static void* p;
2119 static struct R
2121 void* q;
2122 int front;
2123 bool empty;
2124 void popFront() {}
2125 // `p = q;` is only there to prevent inference of `scope return`.
2126 @property @safe R save() { p = q; return this; }
2129 R r;
2130 choose(true, r, r).save;
2133 // Make sure ChooseResult.save doesn't trust @system user code.
2134 @system unittest // copy is @system
2136 static struct R
2138 int front;
2139 bool empty;
2140 void popFront() {}
2141 this(this) @system {}
2142 @property R save() { return R(front, empty); }
2144 choose(true, R(), R()).save;
2145 choose(true, [0], R()).save;
2146 choose(true, R(), [0]).save;
2149 @safe unittest // copy is @system
2151 static struct R
2153 int front;
2154 bool empty;
2155 void popFront() {}
2156 this(this) @system {}
2157 @property R save() { return R(front, empty); }
2159 static assert(!__traits(compiles, choose(true, R(), R()).save));
2160 static assert(!__traits(compiles, choose(true, [0], R()).save));
2161 static assert(!__traits(compiles, choose(true, R(), [0]).save));
2164 @system unittest // .save is @system
2166 static struct R
2168 int front;
2169 bool empty;
2170 void popFront() {}
2171 @property R save() @system { return this; }
2173 choose(true, R(), R()).save;
2174 choose(true, [0], R()).save;
2175 choose(true, R(), [0]).save;
2178 @safe unittest // .save is @system
2180 static struct R
2182 int front;
2183 bool empty;
2184 void popFront() {}
2185 @property R save() @system { return this; }
2187 static assert(!__traits(compiles, choose(true, R(), R()).save));
2188 static assert(!__traits(compiles, choose(true, [0], R()).save));
2189 static assert(!__traits(compiles, choose(true, R(), [0]).save));
2192 //https://issues.dlang.org/show_bug.cgi?id=19738
2193 @safe nothrow pure @nogc unittest
2195 static struct EvilRange
2197 enum empty = true;
2198 int front;
2199 void popFront() @safe {}
2200 auto opAssign(const ref EvilRange other)
2202 *(cast(uint*) 0xcafebabe) = 0xdeadbeef;
2203 return this;
2207 static assert(!__traits(compiles, () @safe
2209 auto c1 = choose(true, EvilRange(), EvilRange());
2210 auto c2 = c1;
2211 c1 = c2;
2212 }));
2216 // https://issues.dlang.org/show_bug.cgi?id=20495
2217 @safe unittest
2219 static struct KillableRange
2221 int *item;
2222 ref int front() { return *item; }
2223 bool empty() { return *item > 10; }
2224 void popFront() { ++(*item); }
2225 this(this)
2227 assert(item is null || cast(size_t) item > 1000);
2228 item = new int(*item);
2230 KillableRange save() { return this; }
2233 auto kr = KillableRange(new int(1));
2234 int[] x = [1,2,3,4,5]; // length is first
2236 auto chosen = choose(true, x, kr);
2237 auto chosen2 = chosen.save;
2240 pure @safe nothrow unittest
2242 static struct S {
2243 int v;
2244 @disable this(this);
2247 auto a = [S(1), S(2), S(3)];
2248 auto b = [S(4), S(5), S(6)];
2250 auto chosen = choose(true, a, b);
2251 assert(chosen.front.v == 1);
2253 auto chosen2 = choose(false, a, b);
2254 assert(chosen2.front.v == 4);
2257 // https://issues.dlang.org/show_bug.cgi?id=15708
2258 @safe unittest
2260 static struct HasPostblit
2262 this(this) {}
2265 static struct Range
2267 bool empty;
2268 int front;
2269 void popFront() {}
2270 HasPostblit member;
2273 Range range;
2274 int[] arr;
2276 auto chosen = choose(true, range, arr);
2277 auto copy = chosen;
2281 Choose one of multiple ranges at runtime.
2283 The ranges may be different, but they must have compatible element types. The
2284 result is a range that offers the weakest capabilities of all `Ranges`.
2286 Params:
2287 index = which range to choose, must be less than the number of ranges
2288 rs = two or more ranges
2290 Returns:
2291 The indexed range. If rs consists of only one range, the return type is an
2292 alias of that range's type.
2294 auto chooseAmong(Ranges...)(size_t index, return scope Ranges rs)
2295 if (Ranges.length >= 2
2296 && allSatisfy!(isInputRange, staticMap!(Unqual, Ranges))
2297 && !is(CommonType!(staticMap!(ElementType, Ranges)) == void))
2299 return ChooseResult!Ranges(index, rs);
2303 @safe nothrow pure @nogc unittest
2305 auto test()
2307 import std.algorithm.comparison : equal;
2309 int[4] sarr1 = [1, 2, 3, 4];
2310 int[2] sarr2 = [5, 6];
2311 int[1] sarr3 = [7];
2312 auto arr1 = sarr1[];
2313 auto arr2 = sarr2[];
2314 auto arr3 = sarr3[];
2317 auto s = chooseAmong(0, arr1, arr2, arr3);
2318 auto t = s.save;
2319 assert(s.length == 4);
2320 assert(s[2] == 3);
2321 s.popFront();
2322 assert(equal(t, only(1, 2, 3, 4)));
2325 auto s = chooseAmong(1, arr1, arr2, arr3);
2326 assert(s.length == 2);
2327 s.front = 8;
2328 assert(equal(s, only(8, 6)));
2331 auto s = chooseAmong(1, arr1, arr2, arr3);
2332 assert(s.length == 2);
2333 s[1] = 9;
2334 assert(equal(s, only(8, 9)));
2337 auto s = chooseAmong(1, arr2, arr1, arr3)[1 .. 3];
2338 assert(s.length == 2);
2339 assert(equal(s, only(2, 3)));
2342 auto s = chooseAmong(0, arr1, arr2, arr3);
2343 assert(s.length == 4);
2344 assert(s.back == 4);
2345 s.popBack();
2346 s.back = 5;
2347 assert(equal(s, only(1, 2, 5)));
2348 s.back = 3;
2349 assert(equal(s, only(1, 2, 3)));
2352 uint[5] foo = [1, 2, 3, 4, 5];
2353 uint[5] bar = [6, 7, 8, 9, 10];
2354 auto c = chooseAmong(1, foo[], bar[]);
2355 assert(c[3] == 9);
2356 c[3] = 42;
2357 assert(c[3] == 42);
2358 assert(c.moveFront() == 6);
2359 assert(c.moveBack() == 10);
2360 assert(c.moveAt(4) == 10);
2363 import std.range : cycle;
2364 auto s = chooseAmong(0, cycle(arr2), cycle(arr3));
2365 assert(isInfinite!(typeof(s)));
2366 assert(!s.empty);
2367 assert(s[100] == 8);
2368 assert(s[101] == 9);
2369 assert(s[0 .. 3].equal(only(8, 9, 8)));
2371 return 0;
2373 // works at runtime
2374 auto a = test();
2375 // and at compile time
2376 static b = test();
2379 @safe nothrow pure @nogc unittest
2381 int[3] a = [1, 2, 3];
2382 long[3] b = [4, 5, 6];
2383 auto c = chooseAmong(0, a[], b[]);
2384 c[0] = 42;
2385 assert(c[0] == 42);
2388 @safe nothrow pure @nogc unittest
2390 static struct RefAccessRange
2392 int[] r;
2393 ref front() @property { return r[0]; }
2394 ref back() @property { return r[$ - 1]; }
2395 void popFront() { r = r[1 .. $]; }
2396 void popBack() { r = r[0 .. $ - 1]; }
2397 auto empty() @property { return r.empty; }
2398 ref opIndex(size_t i) { return r[i]; }
2399 auto length() @property { return r.length; }
2400 alias opDollar = length;
2401 auto save() { return this; }
2403 static assert(isRandomAccessRange!RefAccessRange);
2404 static assert(isRandomAccessRange!RefAccessRange);
2405 int[4] a = [4, 3, 2, 1];
2406 int[2] b = [6, 5];
2407 auto c = chooseAmong(0, RefAccessRange(a[]), RefAccessRange(b[]));
2409 void refFunc(ref int a, int target) { assert(a == target); }
2411 refFunc(c[2], 2);
2412 refFunc(c.front, 4);
2413 refFunc(c.back, 1);
2418 $(D roundRobin(r1, r2, r3)) yields `r1.front`, then `r2.front`,
2419 then `r3.front`, after which it pops off one element from each and
2420 continues again from `r1`. For example, if two ranges are involved,
2421 it alternately yields elements off the two ranges. `roundRobin`
2422 stops after it has consumed all ranges (skipping over the ones that
2423 finish early).
2425 auto roundRobin(Rs...)(Rs rs)
2426 if (Rs.length > 1 && allSatisfy!(isInputRange, staticMap!(Unqual, Rs)))
2428 struct Result
2430 import std.conv : to;
2432 public Rs source;
2433 private size_t _current = size_t.max;
2435 @property bool empty()
2437 foreach (i, Unused; Rs)
2439 if (!source[i].empty) return false;
2441 return true;
2444 @property auto ref front()
2446 final switch (_current)
2448 foreach (i, R; Rs)
2450 case i:
2451 assert(
2452 !source[i].empty,
2453 "Attempting to fetch the front of an empty roundRobin"
2455 return source[i].front;
2458 assert(0);
2461 void popFront()
2463 final switch (_current)
2465 foreach (i, R; Rs)
2467 case i:
2468 source[i].popFront();
2469 break;
2473 auto next = _current == (Rs.length - 1) ? 0 : (_current + 1);
2474 final switch (next)
2476 foreach (i, R; Rs)
2478 case i:
2479 if (!source[i].empty)
2481 _current = i;
2482 return;
2484 if (i == _current)
2486 _current = _current.max;
2487 return;
2489 goto case (i + 1) % Rs.length;
2494 static if (allSatisfy!(isForwardRange, staticMap!(Unqual, Rs)))
2495 @property auto save()
2497 auto saveSource(size_t len)()
2499 import std.typecons : tuple;
2500 static assert(len > 0);
2501 static if (len == 1)
2503 return tuple(source[0].save);
2505 else
2507 return saveSource!(len - 1)() ~
2508 tuple(source[len - 1].save);
2511 return Result(saveSource!(Rs.length).expand, _current);
2514 static if (allSatisfy!(hasLength, Rs))
2516 @property size_t length()
2518 size_t result;
2519 foreach (i, R; Rs)
2521 result += source[i].length;
2523 return result;
2526 alias opDollar = length;
2530 size_t firstNonEmpty = size_t.max;
2531 static foreach (i; 0 .. Rs.length)
2533 if (firstNonEmpty == size_t.max && !rs[i].empty)
2534 firstNonEmpty = i;
2537 return Result(rs, firstNonEmpty);
2541 @safe unittest
2543 import std.algorithm.comparison : equal;
2545 int[] a = [ 1, 2, 3 ];
2546 int[] b = [ 10, 20, 30, 40 ];
2547 auto r = roundRobin(a, b);
2548 assert(equal(r, [ 1, 10, 2, 20, 3, 30, 40 ]));
2552 * roundRobin can be used to create "interleave" functionality which inserts
2553 * an element between each element in a range.
2555 @safe unittest
2557 import std.algorithm.comparison : equal;
2559 auto interleave(R, E)(R range, E element)
2560 if ((isInputRange!R && hasLength!R) || isForwardRange!R)
2562 static if (hasLength!R)
2563 immutable len = range.length;
2564 else
2565 immutable len = range.save.walkLength;
2567 return roundRobin(
2568 range,
2569 element.repeat(len - 1)
2573 assert(interleave([1, 2, 3], 0).equal([1, 0, 2, 0, 3]));
2576 pure @safe unittest
2578 import std.algorithm.comparison : equal;
2579 string f = "foo", b = "bar";
2580 auto r = roundRobin(refRange(&f), refRange(&b));
2581 assert(equal(r.save, "fboaor"));
2582 assert(equal(r.save, "fboaor"));
2584 pure @safe nothrow unittest
2586 import std.algorithm.comparison : equal;
2588 static struct S {
2589 int v;
2590 @disable this(this);
2593 S[] a = [ S(1), S(2) ];
2594 S[] b = [ S(10), S(20) ];
2595 auto r = roundRobin(a, b);
2596 assert(equal(r, [ S(1), S(10), S(2), S(20) ]));
2599 // https://issues.dlang.org/show_bug.cgi?id=24384
2600 @safe unittest
2602 auto r = roundRobin("", "a");
2603 assert(!r.empty);
2604 auto e = r.front;
2608 Iterates a random-access range starting from a given point and
2609 progressively extending left and right from that point. If no initial
2610 point is given, iteration starts from the middle of the
2611 range. Iteration spans the entire range.
2613 When `startingIndex` is 0 the range will be fully iterated in order
2614 and in reverse order when `r.length` is given.
2616 Params:
2617 r = a random access range with length and slicing
2618 startingIndex = the index to begin iteration from
2620 Returns:
2621 A forward range with length
2623 auto radial(Range, I)(Range r, I startingIndex)
2624 if (isRandomAccessRange!(Unqual!Range) && hasLength!(Unqual!Range) && hasSlicing!(Unqual!Range) && isIntegral!I)
2626 if (startingIndex != r.length) ++startingIndex;
2627 return roundRobin(retro(r[0 .. startingIndex]), r[startingIndex .. r.length]);
2630 /// Ditto
2631 auto radial(R)(R r)
2632 if (isRandomAccessRange!(Unqual!R) && hasLength!(Unqual!R) && hasSlicing!(Unqual!R))
2634 return .radial(r, (r.length - !r.empty) / 2);
2638 @safe unittest
2640 import std.algorithm.comparison : equal;
2641 int[] a = [ 1, 2, 3, 4, 5 ];
2642 assert(equal(radial(a), [ 3, 4, 2, 5, 1 ]));
2643 a = [ 1, 2, 3, 4 ];
2644 assert(equal(radial(a), [ 2, 3, 1, 4 ]));
2646 // If the left end is reached first, the remaining elements on the right
2647 // are concatenated in order:
2648 a = [ 0, 1, 2, 3, 4, 5 ];
2649 assert(equal(radial(a, 1), [ 1, 2, 0, 3, 4, 5 ]));
2651 // If the right end is reached first, the remaining elements on the left
2652 // are concatenated in reverse order:
2653 assert(equal(radial(a, 4), [ 4, 5, 3, 2, 1, 0 ]));
2656 @safe unittest
2658 import std.algorithm.comparison : equal;
2659 import std.conv : text;
2660 import std.exception : enforce;
2661 import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy;
2663 void test(int[] input, int[] witness)
2665 enforce(equal(radial(input), witness),
2666 text(radial(input), " vs. ", witness));
2668 test([], []);
2669 test([ 1 ], [ 1 ]);
2670 test([ 1, 2 ], [ 1, 2 ]);
2671 test([ 1, 2, 3 ], [ 2, 3, 1 ]);
2672 test([ 1, 2, 3, 4 ], [ 2, 3, 1, 4 ]);
2673 test([ 1, 2, 3, 4, 5 ], [ 3, 4, 2, 5, 1 ]);
2674 test([ 1, 2, 3, 4, 5, 6 ], [ 3, 4, 2, 5, 1, 6 ]);
2676 int[] a = [ 1, 2, 3, 4, 5 ];
2677 assert(equal(radial(a, 1), [ 2, 3, 1, 4, 5 ]));
2678 assert(equal(radial(a, 0), [ 1, 2, 3, 4, 5 ])); // only right subrange
2679 assert(equal(radial(a, a.length), [ 5, 4, 3, 2, 1 ])); // only left subrange
2680 static assert(isForwardRange!(typeof(radial(a, 1))));
2682 auto r = radial([1,2,3,4,5]);
2683 for (auto rr = r.save; !rr.empty; rr.popFront())
2685 assert(rr.front == moveFront(rr));
2687 r.front = 5;
2688 assert(r.front == 5);
2690 // Test instantiation without lvalue elements.
2691 DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random) dummy;
2692 assert(equal(radial(dummy, 4), [5, 6, 4, 7, 3, 8, 2, 9, 1, 10]));
2694 // immutable int[] immi = [ 1, 2 ];
2695 // static assert(is(typeof(radial(immi))));
2698 @safe unittest
2700 import std.algorithm.comparison : equal;
2702 auto LL = iota(1L, 6L);
2703 auto r = radial(LL);
2704 assert(equal(r, [3L, 4L, 2L, 5L, 1L]));
2708 Lazily takes only up to `n` elements of a range. This is
2709 particularly useful when using with infinite ranges.
2711 Unlike $(LREF takeExactly), `take` does not require that there
2712 are `n` or more elements in `input`. As a consequence, length
2713 information is not applied to the result unless `input` also has
2714 length information.
2716 Params:
2717 input = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
2718 to iterate over up to `n` times
2719 n = the number of elements to take
2721 Returns:
2722 At minimum, an input range. If the range offers random access
2723 and `length`, `take` offers them as well.
2725 Take!R take(R)(R input, size_t n)
2726 if (isInputRange!(Unqual!R))
2728 alias U = Unqual!R;
2729 static if (is(R T == Take!T))
2731 import std.algorithm.comparison : min;
2732 return R(input.source, min(n, input._maxAvailable));
2734 else static if (!isInfinite!U && hasSlicing!U)
2736 import std.algorithm.comparison : min;
2737 return input[0 .. min(n, input.length)];
2739 else
2741 return Take!R(input, n);
2745 /// ditto
2746 struct Take(Range)
2747 if (isInputRange!(Unqual!Range) &&
2748 //take _cannot_ test hasSlicing on infinite ranges, because hasSlicing uses
2749 //take for slicing infinite ranges.
2750 !((!isInfinite!(Unqual!Range) && hasSlicing!(Unqual!Range)) || is(Range T == Take!T)))
2752 private alias R = Unqual!Range;
2754 /// User accessible in read and write
2755 public R source;
2757 private size_t _maxAvailable;
2759 alias Source = R;
2761 /// Range primitives
2762 @property bool empty()
2764 return _maxAvailable == 0 || source.empty;
2767 /// ditto
2768 @property auto ref front()
2770 assert(!empty,
2771 "Attempting to fetch the front of an empty "
2772 ~ Take.stringof);
2773 return source.front;
2776 /// ditto
2777 void popFront()
2779 assert(!empty,
2780 "Attempting to popFront() past the end of a "
2781 ~ Take.stringof);
2782 source.popFront();
2783 --_maxAvailable;
2786 static if (isForwardRange!R)
2787 /// ditto
2788 @property Take save()
2790 return Take(source.save, _maxAvailable);
2793 static if (hasAssignableElements!R)
2794 /// ditto
2795 @property void front(ElementType!R v)
2797 import core.lifetime : forward;
2799 assert(!empty,
2800 "Attempting to assign to the front of an empty "
2801 ~ Take.stringof);
2803 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
2804 source.front = __ctfe ? v : forward!v;
2807 static if (hasMobileElements!R)
2809 /// ditto
2810 auto moveFront()
2812 assert(!empty,
2813 "Attempting to move the front of an empty "
2814 ~ Take.stringof);
2815 return source.moveFront();
2819 static if (isInfinite!R)
2821 /// ditto
2822 @property size_t length() const
2824 return _maxAvailable;
2827 /// ditto
2828 alias opDollar = length;
2830 //Note: Due to Take/hasSlicing circular dependency,
2831 //This needs to be a restrained template.
2832 /// ditto
2833 auto opSlice()(size_t i, size_t j)
2834 if (hasSlicing!R)
2836 assert(i <= j, "Invalid slice bounds");
2837 assert(j <= length, "Attempting to slice past the end of a "
2838 ~ Take.stringof);
2839 return source[i .. j];
2842 else static if (hasLength!R)
2844 /// ditto
2845 @property size_t length()
2847 import std.algorithm.comparison : min;
2848 return min(_maxAvailable, source.length);
2851 alias opDollar = length;
2854 static if (isRandomAccessRange!R)
2856 /// ditto
2857 void popBack()
2859 assert(!empty,
2860 "Attempting to popBack() past the beginning of a "
2861 ~ Take.stringof);
2862 --_maxAvailable;
2865 /// ditto
2866 @property auto ref back()
2868 assert(!empty,
2869 "Attempting to fetch the back of an empty "
2870 ~ Take.stringof);
2871 return source[this.length - 1];
2874 /// ditto
2875 auto ref opIndex(size_t index)
2877 assert(index < length,
2878 "Attempting to index out of the bounds of a "
2879 ~ Take.stringof);
2880 return source[index];
2883 static if (hasAssignableElements!R)
2885 /// ditto
2886 @property void back(ElementType!R v)
2888 // This has to return auto instead of void because of
2889 // https://issues.dlang.org/show_bug.cgi?id=4706
2890 assert(!empty,
2891 "Attempting to assign to the back of an empty "
2892 ~ Take.stringof);
2893 source[this.length - 1] = v;
2896 /// ditto
2897 void opIndexAssign(ElementType!R v, size_t index)
2899 assert(index < length,
2900 "Attempting to index out of the bounds of a "
2901 ~ Take.stringof);
2902 source[index] = v;
2906 static if (hasMobileElements!R)
2908 /// ditto
2909 auto moveBack()
2911 assert(!empty,
2912 "Attempting to move the back of an empty "
2913 ~ Take.stringof);
2914 return source.moveAt(this.length - 1);
2917 /// ditto
2918 auto moveAt(size_t index)
2920 assert(index < length,
2921 "Attempting to index out of the bounds of a "
2922 ~ Take.stringof);
2923 return source.moveAt(index);
2929 Access to maximal length of the range.
2930 Note: the actual length of the range depends on the underlying range.
2931 If it has fewer elements, it will stop before maxLength is reached.
2933 @property size_t maxLength() const
2935 return _maxAvailable;
2939 /// ditto
2940 template Take(R)
2941 if (isInputRange!(Unqual!R) &&
2942 ((!isInfinite!(Unqual!R) && hasSlicing!(Unqual!R)) || is(R T == Take!T)))
2944 alias Take = R;
2948 pure @safe nothrow unittest
2950 import std.algorithm.comparison : equal;
2952 int[] arr1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
2953 auto s = take(arr1, 5);
2954 assert(s.length == 5);
2955 assert(s[4] == 5);
2956 assert(equal(s, [ 1, 2, 3, 4, 5 ][]));
2960 * If the range runs out before `n` elements, `take` simply returns the entire
2961 * range (unlike $(LREF takeExactly), which will cause an assertion failure if
2962 * the range ends prematurely):
2964 pure @safe nothrow unittest
2966 import std.algorithm.comparison : equal;
2968 int[] arr2 = [ 1, 2, 3 ];
2969 auto t = take(arr2, 5);
2970 assert(t.length == 3);
2971 assert(equal(t, [ 1, 2, 3 ]));
2974 pure @safe nothrow unittest
2976 import std.algorithm.comparison : equal;
2977 import std.internal.test.dummyrange : AllDummyRanges;
2979 int[] arr1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
2980 auto s = take(arr1, 5);
2981 assert(s.length == 5);
2982 assert(s[4] == 5);
2983 assert(equal(s, [ 1, 2, 3, 4, 5 ][]));
2984 assert(equal(retro(s), [ 5, 4, 3, 2, 1 ][]));
2986 // Test fix for bug 4464.
2987 static assert(is(typeof(s) == Take!(int[])));
2988 static assert(is(typeof(s) == int[]));
2990 // Test using narrow strings.
2991 import std.exception : assumeWontThrow;
2993 auto myStr = "This is a string.";
2994 auto takeMyStr = take(myStr, 7);
2995 assert(assumeWontThrow(equal(takeMyStr, "This is")));
2996 // Test fix for bug 5052.
2997 auto takeMyStrAgain = take(takeMyStr, 4);
2998 assert(assumeWontThrow(equal(takeMyStrAgain, "This")));
2999 static assert(is (typeof(takeMyStrAgain) == typeof(takeMyStr)));
3000 takeMyStrAgain = take(takeMyStr, 10);
3001 assert(assumeWontThrow(equal(takeMyStrAgain, "This is")));
3003 foreach (DummyType; AllDummyRanges)
3005 DummyType dummy;
3006 auto t = take(dummy, 5);
3007 alias T = typeof(t);
3009 static if (isRandomAccessRange!DummyType)
3011 static assert(isRandomAccessRange!T);
3012 assert(t[4] == 5);
3014 assert(moveAt(t, 1) == t[1]);
3015 assert(t.back == moveBack(t));
3017 else static if (isForwardRange!DummyType)
3019 static assert(isForwardRange!T);
3022 for (auto tt = t; !tt.empty; tt.popFront())
3024 assert(tt.front == moveFront(tt));
3027 // Bidirectional ranges can't be propagated properly if they don't
3028 // also have random access.
3030 assert(equal(t, [1,2,3,4,5]));
3032 //Test that take doesn't wrap the result of take.
3033 assert(take(t, 4) == take(dummy, 4));
3036 immutable myRepeat = repeat(1);
3037 static assert(is(Take!(typeof(myRepeat))));
3040 pure @safe nothrow @nogc unittest
3042 //check for correct slicing of Take on an infinite range
3043 import std.algorithm.comparison : equal;
3044 foreach (start; 0 .. 4)
3045 foreach (stop; start .. 4)
3046 assert(iota(4).cycle.take(4)[start .. stop]
3047 .equal(iota(start, stop)));
3050 pure @safe nothrow @nogc unittest
3052 // Check that one can declare variables of all Take types,
3053 // and that they match the return type of the corresponding
3054 // take().
3055 // See https://issues.dlang.org/show_bug.cgi?id=4464
3056 int[] r1;
3057 Take!(int[]) t1;
3058 t1 = take(r1, 1);
3059 assert(t1.empty);
3061 string r2;
3062 Take!string t2;
3063 t2 = take(r2, 1);
3064 assert(t2.empty);
3066 Take!(Take!string) t3;
3067 t3 = take(t2, 1);
3068 assert(t3.empty);
3071 pure @safe nothrow @nogc unittest
3073 alias R1 = typeof(repeat(1));
3074 alias R2 = typeof(cycle([1]));
3075 alias TR1 = Take!R1;
3076 alias TR2 = Take!R2;
3077 static assert(isBidirectionalRange!TR1);
3078 static assert(isBidirectionalRange!TR2);
3081 // https://issues.dlang.org/show_bug.cgi?id=12731
3082 pure @safe nothrow @nogc unittest
3084 auto a = repeat(1);
3085 auto s = a[1 .. 5];
3086 s = s[1 .. 3];
3087 assert(s.length == 2);
3088 assert(s[0] == 1);
3089 assert(s[1] == 1);
3092 // https://issues.dlang.org/show_bug.cgi?id=13151
3093 pure @safe nothrow @nogc unittest
3095 import std.algorithm.comparison : equal;
3097 auto r = take(repeat(1, 4), 3);
3098 assert(r.take(2).equal(repeat(1, 2)));
3101 // https://issues.dlang.org/show_bug.cgi?id=24481
3102 @safe unittest
3104 import std.algorithm.iteration : filter;
3106 bool called;
3107 struct Handle
3109 int entry;
3110 void opAssign()(auto ref const(typeof(this)) that) const { called = true; }
3113 const(Handle)[5] arr = [Handle(0), Handle(1), Handle(2), Handle(3), Handle(4)];
3114 auto range = arr[].filter!(a => true)().take(3);
3116 called = false;
3117 range.front = Handle(42);
3118 assert(called);
3122 Similar to $(LREF take), but assumes that `range` has at least $(D
3123 n) elements. Consequently, the result of $(D takeExactly(range, n))
3124 always defines the `length` property (and initializes it to `n`)
3125 even when `range` itself does not define `length`.
3127 The result of `takeExactly` is identical to that of $(LREF take) in
3128 cases where the original range defines `length` or is infinite.
3130 Unlike $(LREF take), however, it is illegal to pass a range with less than
3131 `n` elements to `takeExactly`; this will cause an assertion failure.
3133 auto takeExactly(R)(R range, size_t n)
3134 if (isInputRange!R)
3136 static if (is(typeof(takeExactly(range._input, n)) == R))
3138 assert(n <= range._n,
3139 "Attempted to take more than the length of the range with takeExactly.");
3140 // takeExactly(takeExactly(r, n1), n2) has the same type as
3141 // takeExactly(r, n1) and simply returns takeExactly(r, n2)
3142 range._n = n;
3143 return range;
3145 //Also covers hasSlicing!R for finite ranges.
3146 else static if (hasLength!R)
3148 assert(n <= range.length,
3149 "Attempted to take more than the length of the range with takeExactly.");
3150 return take(range, n);
3152 else static if (isInfinite!R)
3153 return Take!R(range, n);
3154 else
3156 static struct Result
3158 R _input;
3159 private size_t _n;
3161 @property bool empty() const { return !_n; }
3162 @property auto ref front()
3164 assert(_n > 0, "front() on an empty " ~ Result.stringof);
3165 return _input.front;
3167 void popFront() { _input.popFront(); --_n; }
3168 @property size_t length() const { return _n; }
3169 alias opDollar = length;
3171 @property auto _takeExactly_Result_asTake()
3173 return take(_input, _n);
3176 alias _takeExactly_Result_asTake this;
3178 static if (isForwardRange!R)
3179 @property auto save()
3181 return Result(_input.save, _n);
3184 static if (hasMobileElements!R)
3186 auto moveFront()
3188 assert(!empty,
3189 "Attempting to move the front of an empty "
3190 ~ typeof(this).stringof);
3191 return _input.moveFront();
3195 static if (hasAssignableElements!R)
3197 @property auto ref front(ElementType!R v)
3199 import core.lifetime : forward;
3201 assert(!empty,
3202 "Attempting to assign to the front of an empty "
3203 ~ typeof(this).stringof);
3205 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
3206 return _input.front = __ctfe ? v : forward!v;
3211 return Result(range, n);
3216 pure @safe nothrow unittest
3218 import std.algorithm.comparison : equal;
3220 auto a = [ 1, 2, 3, 4, 5 ];
3222 auto b = takeExactly(a, 3);
3223 assert(equal(b, [1, 2, 3]));
3224 static assert(is(typeof(b.length) == size_t));
3225 assert(b.length == 3);
3226 assert(b.front == 1);
3227 assert(b.back == 3);
3230 pure @safe nothrow unittest
3232 import std.algorithm.comparison : equal;
3233 import std.algorithm.iteration : filter;
3235 auto a = [ 1, 2, 3, 4, 5 ];
3236 auto b = takeExactly(a, 3);
3237 assert(equal(b, [1, 2, 3]));
3238 auto c = takeExactly(b, 2);
3239 assert(equal(c, [1, 2]));
3243 auto d = filter!"a > 2"(a);
3244 auto e = takeExactly(d, 3);
3245 assert(equal(e, [3, 4, 5]));
3246 static assert(is(typeof(e.length) == size_t));
3247 assert(e.length == 3);
3248 assert(e.front == 3);
3250 assert(equal(takeExactly(e, 3), [3, 4, 5]));
3253 pure @safe nothrow unittest
3255 import std.algorithm.comparison : equal;
3256 import std.internal.test.dummyrange : AllDummyRanges;
3258 auto a = [ 1, 2, 3, 4, 5 ];
3259 //Test that take and takeExactly are the same for ranges which define length
3260 //but aren't sliceable.
3261 struct L
3263 @property auto front() { return _arr[0]; }
3264 @property bool empty() { return _arr.empty; }
3265 void popFront() { _arr.popFront(); }
3266 @property size_t length() { return _arr.length; }
3267 int[] _arr;
3269 static assert(is(typeof(take(L(a), 3)) == typeof(takeExactly(L(a), 3))));
3270 assert(take(L(a), 3) == takeExactly(L(a), 3));
3272 //Test that take and takeExactly are the same for ranges which are sliceable.
3273 static assert(is(typeof(take(a, 3)) == typeof(takeExactly(a, 3))));
3274 assert(take(a, 3) == takeExactly(a, 3));
3276 //Test that take and takeExactly are the same for infinite ranges.
3277 auto inf = repeat(1);
3278 static assert(is(typeof(take(inf, 5)) == Take!(typeof(inf))));
3279 assert(take(inf, 5) == takeExactly(inf, 5));
3281 //Test that take and takeExactly are _not_ the same for ranges which don't
3282 //define length.
3283 static assert(!is(typeof(take(filter!"true"(a), 3)) == typeof(takeExactly(filter!"true"(a), 3))));
3285 foreach (DummyType; AllDummyRanges)
3288 DummyType dummy;
3289 auto t = takeExactly(dummy, 5);
3291 //Test that takeExactly doesn't wrap the result of takeExactly.
3292 assert(takeExactly(t, 4) == takeExactly(dummy, 4));
3295 static if (hasMobileElements!DummyType)
3298 auto t = takeExactly(DummyType.init, 4);
3299 assert(t.moveFront() == 1);
3300 assert(equal(t, [1, 2, 3, 4]));
3304 static if (hasAssignableElements!DummyType)
3307 auto t = takeExactly(DummyType.init, 4);
3308 t.front = 9;
3309 assert(equal(t, [9, 2, 3, 4]));
3315 pure @safe nothrow unittest
3317 import std.algorithm.comparison : equal;
3318 import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy;
3320 alias DummyType = DummyRange!(ReturnBy.Value, Length.No, RangeType.Forward);
3321 auto te = takeExactly(DummyType(), 5);
3322 Take!DummyType t = te;
3323 assert(equal(t, [1, 2, 3, 4, 5]));
3324 assert(equal(t, te));
3327 // https://issues.dlang.org/show_bug.cgi?id=18092
3328 // can't combine take and takeExactly
3329 @safe unittest
3331 import std.algorithm.comparison : equal;
3332 import std.internal.test.dummyrange : AllDummyRanges;
3334 static foreach (Range; AllDummyRanges)
3336 Range r;
3337 assert(r.take(6).takeExactly(2).equal([1, 2]));
3338 assert(r.takeExactly(6).takeExactly(2).equal([1, 2]));
3339 assert(r.takeExactly(6).take(2).equal([1, 2]));
3343 // https://issues.dlang.org/show_bug.cgi?id=24481
3344 @safe unittest
3346 import std.algorithm.iteration : filter;
3348 bool called;
3349 struct Handle
3351 int entry;
3352 void opAssign()(auto ref const(typeof(this)) that) const { called = true; }
3355 const(Handle)[5] arr = [Handle(0), Handle(1), Handle(2), Handle(3), Handle(4)];
3356 auto range = arr[].filter!(a => true)().takeExactly(3);
3358 called = false;
3359 range.front = Handle(42);
3360 assert(called);
3364 Returns a range with at most one element; for example, $(D
3365 takeOne([42, 43, 44])) returns a range consisting of the integer $(D
3366 42). Calling `popFront()` off that range renders it empty.
3368 In effect `takeOne(r)` is somewhat equivalent to $(D take(r, 1)) but in
3369 certain interfaces it is important to know statically that the range may only
3370 have at most one element.
3372 The type returned by `takeOne` is a random-access range with length
3373 regardless of `R`'s capabilities, as long as it is a forward range.
3374 (another feature that distinguishes `takeOne` from `take`). If
3375 (D R) is an input range but not a forward range, return type is an input
3376 range with all random-access capabilities except save.
3378 auto takeOne(R)(R source)
3379 if (isInputRange!R)
3381 static if (hasSlicing!R)
3383 return source[0 .. !source.empty];
3385 else
3387 static struct Result
3389 private R _source;
3390 private bool _empty = true;
3391 @property bool empty() const { return _empty; }
3392 @property auto ref front()
3394 assert(!empty, "Attempting to fetch the front of an empty takeOne");
3395 return _source.front;
3397 void popFront()
3399 assert(!empty, "Attempting to popFront an empty takeOne");
3400 _source.popFront();
3401 _empty = true;
3403 void popBack()
3405 assert(!empty, "Attempting to popBack an empty takeOne");
3406 _source.popFront();
3407 _empty = true;
3409 static if (isForwardRange!(Unqual!R))
3411 @property auto save() { return Result(_source.save, empty); }
3413 @property auto ref back()
3415 assert(!empty, "Attempting to fetch the back of an empty takeOne");
3416 return _source.front;
3418 @property size_t length() const { return !empty; }
3419 alias opDollar = length;
3420 auto ref opIndex(size_t n)
3422 assert(n < length, "Attempting to index a takeOne out of bounds");
3423 return _source.front;
3425 auto opSlice(size_t m, size_t n)
3427 assert(
3428 m <= n,
3429 "Attempting to slice a takeOne range with a larger first argument than the second."
3431 assert(
3432 n <= length,
3433 "Attempting to slice using an out of bounds index on a takeOne range."
3435 return n > m ? this : Result(_source, true);
3437 // Non-standard property
3438 @property R source() { return _source; }
3441 return Result(source, source.empty);
3446 pure @safe nothrow unittest
3448 auto s = takeOne([42, 43, 44]);
3449 static assert(isRandomAccessRange!(typeof(s)));
3450 assert(s.length == 1);
3451 assert(!s.empty);
3452 assert(s.front == 42);
3453 s.front = 43;
3454 assert(s.front == 43);
3455 assert(s.back == 43);
3456 assert(s[0] == 43);
3457 s.popFront();
3458 assert(s.length == 0);
3459 assert(s.empty);
3462 pure @safe nothrow @nogc unittest
3464 struct NonForwardRange
3466 enum empty = false;
3467 int front() { return 42; }
3468 void popFront() {}
3471 static assert(!isForwardRange!NonForwardRange);
3473 auto s = takeOne(NonForwardRange());
3474 assert(s.length == 1);
3475 assert(!s.empty);
3476 assert(s.front == 42);
3477 assert(s.back == 42);
3478 assert(s[0] == 42);
3480 auto t = s[0 .. 0];
3481 assert(t.empty);
3482 assert(t.length == 0);
3484 auto u = s[1 .. 1];
3485 assert(u.empty);
3486 assert(u.length == 0);
3488 auto v = s[0 .. 1];
3489 s.popFront();
3490 assert(s.length == 0);
3491 assert(s.empty);
3492 assert(!v.empty);
3493 assert(v.front == 42);
3494 v.popBack();
3495 assert(v.empty);
3496 assert(v.length == 0);
3499 pure @safe nothrow @nogc unittest
3501 struct NonSlicingForwardRange
3503 enum empty = false;
3504 int front() { return 42; }
3505 void popFront() {}
3506 @property auto save() { return this; }
3509 static assert(isForwardRange!NonSlicingForwardRange);
3510 static assert(!hasSlicing!NonSlicingForwardRange);
3512 auto s = takeOne(NonSlicingForwardRange());
3513 assert(s.length == 1);
3514 assert(!s.empty);
3515 assert(s.front == 42);
3516 assert(s.back == 42);
3517 assert(s[0] == 42);
3518 auto t = s.save;
3519 s.popFront();
3520 assert(s.length == 0);
3521 assert(s.empty);
3522 assert(!t.empty);
3523 assert(t.front == 42);
3524 t.popBack();
3525 assert(t.empty);
3526 assert(t.length == 0);
3529 // Test that asserts trigger correctly
3530 @system unittest
3532 import std.exception : assertThrown;
3533 import core.exception : AssertError;
3535 struct NonForwardRange
3537 enum empty = false;
3538 int front() { return 42; }
3539 void popFront() {}
3542 auto s = takeOne(NonForwardRange());
3544 assertThrown!AssertError(s[1]);
3545 assertThrown!AssertError(s[0 .. 2]);
3547 size_t one = 1; // Avoid style warnings triggered by literals
3548 size_t zero = 0;
3549 assertThrown!AssertError(s[one .. zero]);
3551 s.popFront;
3552 assert(s.empty);
3553 assertThrown!AssertError(s.front);
3554 assertThrown!AssertError(s.back);
3555 assertThrown!AssertError(s.popFront);
3556 assertThrown!AssertError(s.popBack);
3559 // https://issues.dlang.org/show_bug.cgi?id=16999
3560 pure @safe unittest
3562 auto myIota = new class
3564 int front = 0;
3565 @safe void popFront(){front++;}
3566 enum empty = false;
3568 auto iotaPart = myIota.takeOne;
3569 int sum;
3570 foreach (var; chain(iotaPart, iotaPart, iotaPart))
3572 sum += var;
3574 assert(sum == 3);
3575 assert(iotaPart.front == 3);
3579 Returns an empty range which is statically known to be empty and is
3580 guaranteed to have `length` and be random access regardless of `R`'s
3581 capabilities.
3583 auto takeNone(R)()
3584 if (isInputRange!R)
3586 return typeof(takeOne(R.init)).init;
3590 pure @safe nothrow @nogc unittest
3592 auto range = takeNone!(int[])();
3593 assert(range.length == 0);
3594 assert(range.empty);
3597 pure @safe nothrow @nogc unittest
3599 enum ctfe = takeNone!(int[])();
3600 static assert(ctfe.length == 0);
3601 static assert(ctfe.empty);
3606 Creates an empty range from the given range in $(BIGOH 1). If it can, it
3607 will return the same range type. If not, it will return
3608 $(D takeExactly(range, 0)).
3610 auto takeNone(R)(R range)
3611 if (isInputRange!R)
3613 import std.traits : isDynamicArray;
3614 //Makes it so that calls to takeNone which don't use UFCS still work with a
3615 //member version if it's defined.
3616 static if (is(typeof(R.takeNone)))
3617 auto retval = range.takeNone();
3618 // https://issues.dlang.org/show_bug.cgi?id=8339
3619 else static if (isDynamicArray!R)/+ ||
3620 (is(R == struct) && __traits(compiles, {auto r = R.init;}) && R.init.empty))+/
3622 auto retval = R.init;
3624 //An infinite range sliced at [0 .. 0] would likely still not be empty...
3625 else static if (hasSlicing!R && !isInfinite!R)
3626 auto retval = range[0 .. 0];
3627 else
3628 auto retval = takeExactly(range, 0);
3630 // https://issues.dlang.org/show_bug.cgi?id=7892 prevents this from being
3631 // done in an out block.
3632 assert(retval.empty);
3633 return retval;
3637 pure @safe nothrow unittest
3639 import std.algorithm.iteration : filter;
3640 assert(takeNone([42, 27, 19]).empty);
3641 assert(takeNone("dlang.org").empty);
3642 assert(takeNone(filter!"true"([42, 27, 19])).empty);
3645 @safe unittest
3647 import std.algorithm.iteration : filter;
3648 import std.meta : AliasSeq;
3650 struct Dummy
3652 mixin template genInput()
3654 @safe:
3655 @property bool empty() { return _arr.empty; }
3656 @property auto front() { return _arr.front; }
3657 void popFront() { _arr.popFront(); }
3658 static assert(isInputRange!(typeof(this)));
3661 alias genInput = Dummy.genInput;
3663 static struct NormalStruct
3665 //Disabled to make sure that the takeExactly version is used.
3666 @disable this();
3667 this(int[] arr) { _arr = arr; }
3668 mixin genInput;
3669 int[] _arr;
3672 static struct SliceStruct
3674 @disable this();
3675 this(int[] arr) { _arr = arr; }
3676 mixin genInput;
3677 @property auto save() { return this; }
3678 auto opSlice(size_t i, size_t j) { return typeof(this)(_arr[i .. j]); }
3679 @property size_t length() { return _arr.length; }
3680 int[] _arr;
3683 static struct InitStruct
3685 mixin genInput;
3686 int[] _arr;
3689 static struct TakeNoneStruct
3691 this(int[] arr) { _arr = arr; }
3692 @disable this();
3693 mixin genInput;
3694 auto takeNone() { return typeof(this)(null); }
3695 int[] _arr;
3698 static class NormalClass
3700 this(int[] arr) {_arr = arr;}
3701 mixin genInput;
3702 int[] _arr;
3705 static class SliceClass
3707 @safe:
3708 this(int[] arr) { _arr = arr; }
3709 mixin genInput;
3710 @property auto save() { return new typeof(this)(_arr); }
3711 auto opSlice(size_t i, size_t j) { return new typeof(this)(_arr[i .. j]); }
3712 @property size_t length() { return _arr.length; }
3713 int[] _arr;
3716 static class TakeNoneClass
3718 @safe:
3719 this(int[] arr) { _arr = arr; }
3720 mixin genInput;
3721 auto takeNone() { return new typeof(this)(null); }
3722 int[] _arr;
3725 import std.format : format;
3727 static foreach (range; AliasSeq!([1, 2, 3, 4, 5],
3728 "hello world",
3729 "hello world"w,
3730 "hello world"d,
3731 SliceStruct([1, 2, 3]),
3732 // https://issues.dlang.org/show_bug.cgi?id=8339
3733 // forces this to be takeExactly `InitStruct([1, 2, 3]),
3734 TakeNoneStruct([1, 2, 3])))
3736 static assert(takeNone(range).empty, typeof(range).stringof);
3737 assert(takeNone(range).empty);
3738 static assert(is(typeof(range) == typeof(takeNone(range))), typeof(range).stringof);
3741 static foreach (range; AliasSeq!(NormalStruct([1, 2, 3]),
3742 InitStruct([1, 2, 3])))
3744 static assert(takeNone(range).empty, typeof(range).stringof);
3745 assert(takeNone(range).empty);
3746 static assert(is(typeof(takeExactly(range, 0)) == typeof(takeNone(range))), typeof(range).stringof);
3749 //Don't work in CTFE.
3750 auto normal = new NormalClass([1, 2, 3]);
3751 assert(takeNone(normal).empty);
3752 static assert(is(typeof(takeExactly(normal, 0)) == typeof(takeNone(normal))), typeof(normal).stringof);
3754 auto slice = new SliceClass([1, 2, 3]);
3755 assert(takeNone(slice).empty);
3756 static assert(is(SliceClass == typeof(takeNone(slice))), typeof(slice).stringof);
3758 auto taken = new TakeNoneClass([1, 2, 3]);
3759 assert(takeNone(taken).empty);
3760 static assert(is(TakeNoneClass == typeof(takeNone(taken))), typeof(taken).stringof);
3762 auto filtered = filter!"true"([1, 2, 3, 4, 5]);
3763 assert(takeNone(filtered).empty);
3764 // https://issues.dlang.org/show_bug.cgi?id=8339 and
3765 // https://issues.dlang.org/show_bug.cgi?id=5941 force this to be takeExactly
3766 //static assert(is(typeof(filtered) == typeof(takeNone(filtered))), typeof(filtered).stringof);
3770 + Return a range advanced to within `_n` elements of the end of
3771 + `range`.
3773 + Intended as the range equivalent of the Unix
3774 + $(HTTP en.wikipedia.org/wiki/Tail_%28Unix%29, _tail) utility. When the length
3775 + of `range` is less than or equal to `_n`, `range` is returned
3776 + as-is.
3778 + Completes in $(BIGOH 1) steps for ranges that support slicing and have
3779 + length. Completes in $(BIGOH range.length) time for all other ranges.
3781 + Params:
3782 + range = range to get _tail of
3783 + n = maximum number of elements to include in _tail
3785 + Returns:
3786 + Returns the _tail of `range` augmented with length information
3788 auto tail(Range)(Range range, size_t n)
3789 if (isInputRange!Range && !isInfinite!Range &&
3790 (hasLength!Range || isForwardRange!Range))
3792 static if (hasLength!Range)
3794 immutable length = range.length;
3795 if (n >= length)
3796 return range.takeExactly(length);
3797 else
3798 return range.drop(length - n).takeExactly(n);
3800 else
3802 Range scout = range.save;
3803 foreach (immutable i; 0 .. n)
3805 if (scout.empty)
3806 return range.takeExactly(i);
3807 scout.popFront();
3810 auto tail = range.save;
3811 while (!scout.empty)
3813 assert(!tail.empty);
3814 scout.popFront();
3815 tail.popFront();
3818 return tail.takeExactly(n);
3823 pure @safe nothrow unittest
3825 // tail -c n
3826 assert([1, 2, 3].tail(1) == [3]);
3827 assert([1, 2, 3].tail(2) == [2, 3]);
3828 assert([1, 2, 3].tail(3) == [1, 2, 3]);
3829 assert([1, 2, 3].tail(4) == [1, 2, 3]);
3830 assert([1, 2, 3].tail(0).length == 0);
3832 // tail --lines=n
3833 import std.algorithm.comparison : equal;
3834 import std.algorithm.iteration : joiner;
3835 import std.exception : assumeWontThrow;
3836 import std.string : lineSplitter;
3837 assert("one\ntwo\nthree"
3838 .lineSplitter
3839 .tail(2)
3840 .joiner("\n")
3841 .equal("two\nthree")
3842 .assumeWontThrow);
3845 // @nogc prevented by https://issues.dlang.org/show_bug.cgi?id=15408
3846 pure nothrow @safe /+@nogc+/ unittest
3848 import std.algorithm.comparison : equal;
3849 import std.internal.test.dummyrange : AllDummyRanges, DummyRange, Length,
3850 RangeType, ReturnBy;
3852 static immutable cheatsheet = [6, 7, 8, 9, 10];
3854 foreach (R; AllDummyRanges)
3856 static if (isInputRange!R && !isInfinite!R &&
3857 (hasLength!R || isForwardRange!R))
3859 assert(R.init.tail(5).equal(cheatsheet));
3860 static assert(R.init.tail(5).equal(cheatsheet));
3862 assert(R.init.tail(0).length == 0);
3863 assert(R.init.tail(10).equal(R.init));
3864 assert(R.init.tail(11).equal(R.init));
3868 // Infinite ranges are not supported
3869 static assert(!__traits(compiles, repeat(0).tail(0)));
3871 // Neither are non-forward ranges without length
3872 static assert(!__traits(compiles, DummyRange!(ReturnBy.Value, Length.No,
3873 RangeType.Input).init.tail(5)));
3876 pure @safe nothrow @nogc unittest
3878 static immutable input = [1, 2, 3];
3879 static immutable expectedOutput = [2, 3];
3880 assert(input.tail(2) == expectedOutput);
3884 Convenience function which calls
3885 $(REF popFrontN, std, range, primitives)`(range, n)` and returns `range`.
3886 `drop` makes it easier to pop elements from a range
3887 and then pass it to another function within a single expression,
3888 whereas `popFrontN` would require multiple statements.
3890 `dropBack` provides the same functionality but instead calls
3891 $(REF popBackN, std, range, primitives)`(range, n)`
3893 Note: `drop` and `dropBack` will only pop $(I up to)
3894 `n` elements but will stop if the range is empty first.
3895 In other languages this is sometimes called `skip`.
3897 Params:
3898 range = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to drop from
3899 n = the number of elements to drop
3901 Returns:
3902 `range` with up to `n` elements dropped
3904 See_Also:
3905 $(REF popFront, std, range, primitives), $(REF popBackN, std, range, primitives)
3907 R drop(R)(R range, size_t n)
3908 if (isInputRange!R)
3910 range.popFrontN(n);
3911 return range;
3915 @safe unittest
3917 import std.algorithm.comparison : equal;
3919 assert([0, 2, 1, 5, 0, 3].drop(3) == [5, 0, 3]);
3920 assert("hello world".drop(6) == "world");
3921 assert("hello world".drop(50).empty);
3922 assert("hello world".take(6).drop(3).equal("lo "));
3925 /// ditto
3926 R dropBack(R)(R range, size_t n)
3927 if (isBidirectionalRange!R)
3929 range.popBackN(n);
3930 return range;
3934 @safe unittest
3936 import std.algorithm.comparison : equal;
3938 assert([0, 2, 1, 5, 0, 3].dropBack(3) == [0, 2, 1]);
3939 assert("hello world".dropBack(6) == "hello");
3940 assert("hello world".dropBack(50).empty);
3941 assert("hello world".drop(4).dropBack(4).equal("o w"));
3944 @safe unittest
3946 import std.algorithm.comparison : equal;
3947 import std.container.dlist : DList;
3949 //Remove all but the first two elements
3950 auto a = DList!int(0, 1, 9, 9, 9, 9);
3951 a.remove(a[].drop(2));
3952 assert(a[].equal(a[].take(2)));
3955 @safe unittest
3957 import std.algorithm.comparison : equal;
3958 import std.algorithm.iteration : filter;
3960 assert(drop("", 5).empty);
3961 assert(equal(drop(filter!"true"([0, 2, 1, 5, 0, 3]), 3), [5, 0, 3]));
3964 @safe unittest
3966 import std.algorithm.comparison : equal;
3967 import std.container.dlist : DList;
3969 //insert before the last two elements
3970 auto a = DList!int(0, 1, 2, 5, 6);
3971 a.insertAfter(a[].dropBack(2), [3, 4]);
3972 assert(a[].equal(iota(0, 7)));
3976 Similar to $(LREF drop) and `dropBack` but they call
3977 $(D range.$(LREF popFrontExactly)(n)) and `range.popBackExactly(n)`
3978 instead.
3980 Note: Unlike `drop`, `dropExactly` will assume that the
3981 range holds at least `n` elements. This makes `dropExactly`
3982 faster than `drop`, but it also means that if `range` does
3983 not contain at least `n` elements, it will attempt to call `popFront`
3984 on an empty range, which is undefined behavior. So, only use
3985 `popFrontExactly` when it is guaranteed that `range` holds at least
3986 `n` elements.
3988 Params:
3989 range = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to drop from
3990 n = the number of elements to drop
3992 Returns:
3993 `range` with `n` elements dropped
3995 See_Also:
3996 $(REF popFrontExcatly, std, range, primitives),
3997 $(REF popBackExcatly, std, range, primitives)
3999 R dropExactly(R)(R range, size_t n)
4000 if (isInputRange!R)
4002 popFrontExactly(range, n);
4003 return range;
4005 /// ditto
4006 R dropBackExactly(R)(R range, size_t n)
4007 if (isBidirectionalRange!R)
4009 popBackExactly(range, n);
4010 return range;
4014 @safe unittest
4016 import std.algorithm.comparison : equal;
4017 import std.algorithm.iteration : filterBidirectional;
4019 auto a = [1, 2, 3];
4020 assert(a.dropExactly(2) == [3]);
4021 assert(a.dropBackExactly(2) == [1]);
4023 string s = "日本語";
4024 assert(s.dropExactly(2) == "語");
4025 assert(s.dropBackExactly(2) == "æ—¥");
4027 auto bd = filterBidirectional!"true"([1, 2, 3]);
4028 assert(bd.dropExactly(2).equal([3]));
4029 assert(bd.dropBackExactly(2).equal([1]));
4033 Convenience function which calls
4034 `range.popFront()` and returns `range`. `dropOne`
4035 makes it easier to pop an element from a range
4036 and then pass it to another function within a single expression,
4037 whereas `popFront` would require multiple statements.
4039 `dropBackOne` provides the same functionality but instead calls
4040 `range.popBack()`.
4042 R dropOne(R)(R range)
4043 if (isInputRange!R)
4045 range.popFront();
4046 return range;
4048 /// ditto
4049 R dropBackOne(R)(R range)
4050 if (isBidirectionalRange!R)
4052 range.popBack();
4053 return range;
4057 pure @safe nothrow unittest
4059 import std.algorithm.comparison : equal;
4060 import std.algorithm.iteration : filterBidirectional;
4061 import std.container.dlist : DList;
4063 auto dl = DList!int(9, 1, 2, 3, 9);
4064 assert(dl[].dropOne().dropBackOne().equal([1, 2, 3]));
4066 auto a = [1, 2, 3];
4067 assert(a.dropOne() == [2, 3]);
4068 assert(a.dropBackOne() == [1, 2]);
4070 string s = "日本語";
4071 import std.exception : assumeWontThrow;
4072 assert(assumeWontThrow(s.dropOne() == "本語"));
4073 assert(assumeWontThrow(s.dropBackOne() == "日本"));
4075 auto bd = filterBidirectional!"true"([1, 2, 3]);
4076 assert(bd.dropOne().equal([2, 3]));
4077 assert(bd.dropBackOne().equal([1, 2]));
4081 Create a range which repeats one value.
4083 Params:
4084 value = the _value to repeat
4085 n = the number of times to repeat `value`
4087 Returns:
4088 If `n` is not defined, an infinite random access range
4089 with slicing.
4091 If `n` is defined, a random access range with slicing.
4093 struct Repeat(T)
4095 private:
4096 import std.typecons : Rebindable2;
4098 // Store a rebindable T to make Repeat assignable.
4099 Rebindable2!T _value;
4101 public:
4102 /// Range primitives
4103 @property inout(T) front() inout { return _value.get; }
4105 /// ditto
4106 @property inout(T) back() inout { return _value.get; }
4108 /// ditto
4109 enum bool empty = false;
4111 /// ditto
4112 void popFront() {}
4114 /// ditto
4115 void popBack() {}
4117 /// ditto
4118 @property auto save() inout { return this; }
4120 /// ditto
4121 inout(T) opIndex(size_t) inout { return _value.get; }
4123 /// ditto
4124 auto opSlice(size_t i, size_t j)
4127 assert(
4128 i <= j,
4129 "Attempting to slice a Repeat with a larger first argument than the second."
4134 return this.takeExactly(j - i);
4136 private static struct DollarToken {}
4138 /// ditto
4139 enum opDollar = DollarToken.init;
4141 /// ditto
4142 auto opSlice(size_t, DollarToken) inout { return this; }
4145 /// Ditto
4146 Repeat!T repeat(T)(T value)
4148 import std.typecons : Rebindable2;
4150 return Repeat!T(Rebindable2!T(value));
4154 pure @safe nothrow unittest
4156 import std.algorithm.comparison : equal;
4158 assert(5.repeat().take(4).equal([5, 5, 5, 5]));
4161 pure @safe nothrow unittest
4163 import std.algorithm.comparison : equal;
4165 auto r = repeat(5);
4166 alias R = typeof(r);
4167 static assert(isBidirectionalRange!R);
4168 static assert(isForwardRange!R);
4169 static assert(isInfinite!R);
4170 static assert(hasSlicing!R);
4172 assert(r.back == 5);
4173 assert(r.front == 5);
4174 assert(r.take(4).equal([ 5, 5, 5, 5 ]));
4175 assert(r[0 .. 4].equal([ 5, 5, 5, 5 ]));
4177 R r2 = r[5 .. $];
4178 assert(r2.back == 5);
4179 assert(r2.front == 5);
4182 /// ditto
4183 Take!(Repeat!T) repeat(T)(T value, size_t n)
4185 return take(repeat(value), n);
4189 pure @safe nothrow unittest
4191 import std.algorithm.comparison : equal;
4193 assert(5.repeat(4).equal([5, 5, 5, 5]));
4196 // https://issues.dlang.org/show_bug.cgi?id=12007
4197 pure @safe nothrow unittest
4199 static class C{}
4200 Repeat!(immutable int) ri;
4201 ri = ri.save;
4202 Repeat!(immutable C) rc;
4203 rc = rc.save;
4205 import std.algorithm.setops : cartesianProduct;
4206 import std.algorithm.comparison : equal;
4207 import std.typecons : tuple;
4208 immutable int[] A = [1,2,3];
4209 immutable int[] B = [4,5,6];
4211 assert(equal(cartesianProduct(A,B),
4213 tuple(1, 4), tuple(1, 5), tuple(1, 6),
4214 tuple(2, 4), tuple(2, 5), tuple(2, 6),
4215 tuple(3, 4), tuple(3, 5), tuple(3, 6),
4216 ]));
4220 Given callable ($(REF isCallable, std,traits)) `fun`, create as a range
4221 whose front is defined by successive calls to `fun()`.
4222 This is especially useful to call function with global side effects (random
4223 functions), or to create ranges expressed as a single delegate, rather than
4224 an entire `front`/`popFront`/`empty` structure.
4225 `fun` maybe be passed either a template alias parameter (existing
4226 function, delegate, struct type defining `static opCall`) or
4227 a run-time value argument (delegate, function object).
4228 The result range models an InputRange
4229 ($(REF isInputRange, std,range,primitives)).
4230 The resulting range will call `fun()` on construction, and every call to
4231 `popFront`, and the cached value will be returned when `front` is called.
4233 Returns: an `inputRange` where each element represents another call to fun.
4235 auto generate(Fun)(Fun fun)
4236 if (isCallable!fun)
4238 auto gen = Generator!(Fun)(fun);
4239 gen.popFront(); // prime the first element
4240 return gen;
4243 /// ditto
4244 auto generate(alias fun)()
4245 if (isCallable!fun)
4247 auto gen = Generator!(fun)();
4248 gen.popFront(); // prime the first element
4249 return gen;
4253 @safe pure nothrow unittest
4255 import std.algorithm.comparison : equal;
4256 import std.algorithm.iteration : map;
4258 int i = 1;
4259 auto powersOfTwo = generate!(() => i *= 2)().take(10);
4260 assert(equal(powersOfTwo, iota(1, 11).map!"2^^a"()));
4264 @safe pure nothrow unittest
4266 import std.algorithm.comparison : equal;
4268 //Returns a run-time delegate
4269 auto infiniteIota(T)(T low, T high)
4271 T i = high;
4272 return (){if (i == high) i = low; return i++;};
4274 //adapted as a range.
4275 assert(equal(generate(infiniteIota(1, 4)).take(10), [1, 2, 3, 1, 2, 3, 1, 2, 3, 1]));
4279 @safe unittest
4281 import std.format : format;
4282 import std.random : uniform;
4284 auto r = generate!(() => uniform(0, 6)).take(10);
4285 format("%(%s %)", r);
4288 private struct Generator(Fun...)
4290 static assert(Fun.length == 1);
4291 static assert(isInputRange!Generator);
4292 import std.traits : FunctionAttribute, functionAttributes, ReturnType;
4294 private:
4295 static if (is(Fun[0]))
4296 Fun[0] fun;
4297 else
4298 alias fun = Fun[0];
4300 enum returnByRef_ = (functionAttributes!fun & FunctionAttribute.ref_) ? true : false;
4302 import std.traits : hasIndirections;
4303 static if (!hasIndirections!(ReturnType!fun))
4304 alias RetType = Unqual!(ReturnType!fun);
4305 else
4306 alias RetType = ReturnType!fun;
4308 static if (returnByRef_)
4309 RetType *elem_;
4310 else
4311 RetType elem_;
4312 public:
4313 /// Range primitives
4314 enum empty = false;
4316 static if (returnByRef_)
4318 /// ditto
4319 ref front() @property
4321 return *elem_;
4323 /// ditto
4324 void popFront()
4326 elem_ = &fun();
4329 else
4331 /// ditto
4332 auto front() @property
4334 return elem_;
4336 /// ditto
4337 void popFront()
4339 elem_ = fun();
4344 @safe nothrow unittest
4346 import std.algorithm.comparison : equal;
4348 struct StaticOpCall
4350 static ubyte opCall() { return 5 ; }
4353 assert(equal(generate!StaticOpCall().take(10), repeat(5).take(10)));
4356 @safe pure unittest
4358 import std.algorithm.comparison : equal;
4360 struct OpCall
4362 ubyte opCall() @safe pure { return 5 ; }
4365 OpCall op;
4366 assert(equal(generate(op).take(10), repeat(5).take(10)));
4369 // verify ref mechanism works
4370 @system nothrow unittest
4372 int[10] arr;
4373 int idx;
4375 ref int fun() {
4376 auto x = idx++;
4377 idx %= arr.length;
4378 return arr[x];
4380 int y = 1;
4381 foreach (ref x; generate!(fun).take(20))
4383 x += y++;
4385 import std.algorithm.comparison : equal;
4386 assert(equal(arr[], iota(12, 32, 2)));
4389 // assure front isn't the mechanism to make generate go to the next element.
4390 @safe unittest
4392 int i;
4393 auto g = generate!(() => ++i);
4394 auto f = g.front;
4395 assert(f == g.front);
4396 g = g.drop(5); // reassign because generate caches
4397 assert(g.front == f + 5);
4400 // https://issues.dlang.org/show_bug.cgi?id=23319
4401 @safe pure nothrow unittest
4403 auto b = generate!(() => const(int)(42));
4404 assert(b.front == 42);
4408 Repeats the given forward range ad infinitum. If the original range is
4409 infinite (fact that would make `Cycle` the identity application),
4410 `Cycle` detects that and aliases itself to the range type
4411 itself. That works for non-forward ranges too.
4412 If the original range has random access, `Cycle` offers
4413 random access and also offers a constructor taking an initial position
4414 `index`. `Cycle` works with static arrays in addition to ranges,
4415 mostly for performance reasons.
4417 Note: The input range must not be empty.
4419 Tip: This is a great way to implement simple circular buffers.
4421 struct Cycle(R)
4422 if (isForwardRange!R && !isInfinite!R)
4424 static if (isRandomAccessRange!R && hasLength!R)
4426 private R _original;
4427 private size_t _index;
4429 /// Range primitives
4430 this(R input, size_t index = 0)
4432 _original = input;
4433 _index = index % _original.length;
4436 /// ditto
4437 @property auto ref front()
4439 return _original[_index];
4442 static if (is(typeof((cast(const R)_original)[_index])))
4444 /// ditto
4445 @property auto ref front() const
4447 return _original[_index];
4451 static if (hasAssignableElements!R)
4453 /// ditto
4454 @property void front(ElementType!R val)
4456 import core.lifetime : forward;
4458 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
4459 _original[_index] = __ctfe ? val : forward!val;
4463 /// ditto
4464 enum bool empty = false;
4466 /// ditto
4467 void popFront()
4469 ++_index;
4470 if (_index >= _original.length)
4471 _index = 0;
4474 /// ditto
4475 auto ref opIndex(size_t n)
4477 return _original[(n + _index) % _original.length];
4480 static if (is(typeof((cast(const R)_original)[_index])) &&
4481 is(typeof((cast(const R)_original).length)))
4483 /// ditto
4484 auto ref opIndex(size_t n) const
4486 return _original[(n + _index) % _original.length];
4490 static if (hasAssignableElements!R)
4492 /// ditto
4493 void opIndexAssign(ElementType!R val, size_t n)
4495 _original[(n + _index) % _original.length] = val;
4499 /// ditto
4500 @property Cycle save()
4502 //No need to call _original.save, because Cycle never actually modifies _original
4503 return Cycle(_original, _index);
4506 private static struct DollarToken {}
4508 /// ditto
4509 enum opDollar = DollarToken.init;
4511 static if (hasSlicing!R)
4513 /// ditto
4514 auto opSlice(size_t i, size_t j)
4517 assert(i <= j);
4521 return this[i .. $].takeExactly(j - i);
4524 /// ditto
4525 auto opSlice(size_t i, DollarToken)
4527 return typeof(this)(_original, _index + i);
4531 else
4533 private R _original;
4534 private R _current;
4536 /// ditto
4537 this(R input)
4539 _original = input;
4540 _current = input.save;
4543 private this(R original, R current)
4545 _original = original;
4546 _current = current;
4549 /// ditto
4550 @property auto ref front()
4552 return _current.front;
4555 static if (is(typeof((cast(const R)_current).front)))
4557 /// ditto
4558 @property auto ref front() const
4560 return _current.front;
4564 static if (hasAssignableElements!R)
4566 /// ditto
4567 @property auto front(ElementType!R val)
4569 import core.lifetime : forward;
4571 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
4572 return _current.front = __ctfe ? val : forward!val;
4576 /// ditto
4577 enum bool empty = false;
4579 /// ditto
4580 void popFront()
4582 _current.popFront();
4583 if (_current.empty)
4584 _current = _original.save;
4587 /// ditto
4588 @property Cycle save()
4590 //No need to call _original.save, because Cycle never actually modifies _original
4591 return Cycle(_original, _current.save);
4596 /// ditto
4597 template Cycle(R)
4598 if (isInfinite!R)
4600 alias Cycle = R;
4603 /// ditto
4604 struct Cycle(R)
4605 if (isStaticArray!R)
4607 private alias ElementType = typeof(R.init[0]);
4608 private ElementType* _ptr;
4609 private size_t _index;
4611 nothrow:
4613 /// Range primitives
4614 this(ref R input, size_t index = 0) @system
4616 _ptr = input.ptr;
4617 _index = index % R.length;
4620 /// ditto
4621 @property ref inout(ElementType) front() inout @safe
4623 static ref auto trustedPtrIdx(typeof(_ptr) p, size_t idx) @trusted
4625 return p[idx];
4627 return trustedPtrIdx(_ptr, _index);
4630 /// ditto
4631 enum bool empty = false;
4633 /// ditto
4634 void popFront() @safe
4636 ++_index;
4637 if (_index >= R.length)
4638 _index = 0;
4641 /// ditto
4642 ref inout(ElementType) opIndex(size_t n) inout @safe
4644 static ref auto trustedPtrIdx(typeof(_ptr) p, size_t idx) @trusted
4646 return p[idx % R.length];
4648 return trustedPtrIdx(_ptr, n + _index);
4651 /// ditto
4652 @property inout(Cycle) save() inout @safe
4654 return this;
4657 private static struct DollarToken {}
4658 /// ditto
4659 enum opDollar = DollarToken.init;
4661 /// ditto
4662 auto opSlice(size_t i, size_t j) @safe
4665 assert(
4666 i <= j,
4667 "Attempting to slice a Repeat with a larger first argument than the second."
4672 return this[i .. $].takeExactly(j - i);
4675 /// ditto
4676 inout(typeof(this)) opSlice(size_t i, DollarToken) inout @safe
4678 static auto trustedCtor(typeof(_ptr) p, size_t idx) @trusted
4680 return cast(inout) Cycle(*cast(R*)(p), idx);
4682 return trustedCtor(_ptr, _index + i);
4686 /// Ditto
4687 auto cycle(R)(R input)
4688 if (isInputRange!R)
4690 static assert(isForwardRange!R || isInfinite!R,
4691 "Cycle requires a forward range argument unless it's statically known"
4692 ~ " to be infinite");
4693 assert(!input.empty, "Attempting to pass an empty input to cycle");
4694 static if (isInfinite!R) return input;
4695 else return Cycle!R(input);
4699 @safe unittest
4701 import std.algorithm.comparison : equal;
4702 import std.range : cycle, take;
4704 // Here we create an infinitive cyclic sequence from [1, 2]
4705 // (i.e. get here [1, 2, 1, 2, 1, 2 and so on]) then
4706 // take 5 elements of this sequence (so we have [1, 2, 1, 2, 1])
4707 // and compare them with the expected values for equality.
4708 assert(cycle([1, 2]).take(5).equal([ 1, 2, 1, 2, 1 ]));
4711 /// Ditto
4712 Cycle!R cycle(R)(R input, size_t index = 0)
4713 if (isRandomAccessRange!R && !isInfinite!R)
4715 assert(!input.empty, "Attempting to pass an empty input to cycle");
4716 return Cycle!R(input, index);
4719 /// Ditto
4720 Cycle!R cycle(R)(ref R input, size_t index = 0) @system
4721 if (isStaticArray!R)
4723 return Cycle!R(input, index);
4726 @safe nothrow unittest
4728 import std.algorithm.comparison : equal;
4729 import std.internal.test.dummyrange : AllDummyRanges;
4731 static assert(isForwardRange!(Cycle!(uint[])));
4733 // Make sure ref is getting propagated properly.
4734 int[] nums = [1,2,3];
4735 auto c2 = cycle(nums);
4736 c2[3]++;
4737 assert(nums[0] == 2);
4739 immutable int[] immarr = [1, 2, 3];
4741 foreach (DummyType; AllDummyRanges)
4743 static if (isForwardRange!DummyType)
4745 DummyType dummy;
4746 auto cy = cycle(dummy);
4747 static assert(isForwardRange!(typeof(cy)));
4748 auto t = take(cy, 20);
4749 assert(equal(t, [1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10]));
4751 const cRange = cy;
4752 assert(cRange.front == 1);
4754 static if (hasAssignableElements!DummyType)
4757 cy.front = 66;
4758 scope(exit) cy.front = 1;
4759 assert(dummy.front == 66);
4762 static if (isRandomAccessRange!DummyType)
4765 cy[10] = 66;
4766 scope(exit) cy[10] = 1;
4767 assert(dummy.front == 66);
4770 assert(cRange[10] == 1);
4774 static if (hasSlicing!DummyType)
4776 auto slice = cy[5 .. 15];
4777 assert(equal(slice, [6, 7, 8, 9, 10, 1, 2, 3, 4, 5]));
4778 static assert(is(typeof(slice) == typeof(takeExactly(cy, 5))));
4780 auto infSlice = cy[7 .. $];
4781 assert(equal(take(infSlice, 5), [8, 9, 10, 1, 2]));
4782 static assert(isInfinite!(typeof(infSlice)));
4788 @system nothrow unittest // For static arrays.
4790 import std.algorithm.comparison : equal;
4792 int[3] a = [ 1, 2, 3 ];
4793 static assert(isStaticArray!(typeof(a)));
4794 auto c = cycle(a);
4795 assert(a.ptr == c._ptr);
4796 assert(equal(take(cycle(a), 5), [ 1, 2, 3, 1, 2 ][]));
4797 static assert(isForwardRange!(typeof(c)));
4799 // Test qualifiers on slicing.
4800 alias C = typeof(c);
4801 static assert(is(typeof(c[1 .. $]) == C));
4802 const cConst = c;
4803 static assert(is(typeof(cConst[1 .. $]) == const(C)));
4806 @safe nothrow unittest // For infinite ranges
4808 struct InfRange
4810 void popFront() { }
4811 @property int front() { return 0; }
4812 enum empty = false;
4813 auto save() { return this; }
4815 struct NonForwardInfRange
4817 void popFront() { }
4818 @property int front() { return 0; }
4819 enum empty = false;
4822 InfRange i;
4823 NonForwardInfRange j;
4824 auto c = cycle(i);
4825 assert(c == i);
4826 //make sure it can alias out even non-forward infinite ranges
4827 static assert(is(typeof(j.cycle) == typeof(j)));
4830 @safe unittest
4832 import std.algorithm.comparison : equal;
4834 int[5] arr = [0, 1, 2, 3, 4];
4835 auto cleD = cycle(arr[]); //Dynamic
4836 assert(equal(cleD[5 .. 10], arr[]));
4838 //n is a multiple of 5 worth about 3/4 of size_t.max
4839 auto n = size_t.max/4 + size_t.max/2;
4840 n -= n % 5;
4842 //Test index overflow
4843 foreach (_ ; 0 .. 10)
4845 cleD = cleD[n .. $];
4846 assert(equal(cleD[5 .. 10], arr[]));
4850 @system @nogc nothrow unittest
4852 import std.algorithm.comparison : equal;
4854 int[5] arr = [0, 1, 2, 3, 4];
4855 auto cleS = cycle(arr); //Static
4856 assert(equal(cleS[5 .. 10], arr[]));
4858 //n is a multiple of 5 worth about 3/4 of size_t.max
4859 auto n = size_t.max/4 + size_t.max/2;
4860 n -= n % 5;
4862 //Test index overflow
4863 foreach (_ ; 0 .. 10)
4865 cleS = cleS[n .. $];
4866 assert(equal(cleS[5 .. 10], arr[]));
4870 @system unittest
4872 import std.algorithm.comparison : equal;
4874 int[1] arr = [0];
4875 auto cleS = cycle(arr);
4876 cleS = cleS[10 .. $];
4877 assert(equal(cleS[5 .. 10], 0.repeat(5)));
4878 assert(cleS.front == 0);
4881 // https://issues.dlang.org/show_bug.cgi?id=10845
4882 @system unittest
4884 import std.algorithm.comparison : equal;
4885 import std.algorithm.iteration : filter;
4887 auto a = inputRangeObject(iota(3).filter!"true");
4888 assert(equal(cycle(a).take(10), [0, 1, 2, 0, 1, 2, 0, 1, 2, 0]));
4891 // https://issues.dlang.org/show_bug.cgi?id=12177
4892 @safe unittest
4894 static assert(__traits(compiles, recurrence!q{a[n - 1] ~ a[n - 2]}("1", "0")));
4897 // https://issues.dlang.org/show_bug.cgi?id=13390
4898 @system unittest
4900 import core.exception : AssertError;
4901 import std.exception : assertThrown;
4902 assertThrown!AssertError(cycle([0, 1, 2][0 .. 0]));
4905 // https://issues.dlang.org/show_bug.cgi?id=18657
4906 pure @safe unittest
4908 import std.algorithm.comparison : equal;
4909 string s = "foo";
4910 auto r = refRange(&s).cycle.take(4);
4911 assert(equal(r.save, "foof"));
4912 assert(equal(r.save, "foof"));
4915 // https://issues.dlang.org/show_bug.cgi?id=24481
4916 @safe unittest
4918 import std.algorithm.iteration : filter;
4920 bool called;
4921 struct Handle
4923 int entry;
4924 void opAssign()(auto ref const(typeof(this)) that) const { called = true; }
4927 const(Handle)[3] arr = [Handle(0), Handle(1), Handle(2)];
4929 auto range = arr[].cycle().take(5);
4931 called = false;
4932 range.front = Handle(42);
4933 assert(called);
4936 auto range = arr[].filter!(a => true)().cycle().take(5);
4938 called = false;
4939 range.front = Handle(42);
4940 assert(called);
4944 private alias lengthType(R) = typeof(R.init.length.init);
4947 Iterate several ranges in lockstep. The element type is a proxy tuple
4948 that allows accessing the current element in the `n`th range by
4949 using `e[n]`.
4951 `zip` is similar to $(LREF lockstep), but `lockstep` doesn't
4952 bundle its elements and uses the `opApply` protocol.
4953 `lockstep` allows reference access to the elements in
4954 `foreach` iterations.
4956 Params:
4957 sp = controls what `zip` will do if the ranges are different lengths
4958 ranges = the ranges to zip together
4959 Returns:
4960 At minimum, an input range. `Zip` offers the lowest range facilities
4961 of all components, e.g. it offers random access iff all ranges offer
4962 random access, and also offers mutation and swapping if all ranges offer
4963 it. Due to this, `Zip` is extremely powerful because it allows manipulating
4964 several ranges in lockstep.
4965 Throws:
4966 An `Exception` if all of the ranges are not the same length and
4967 `sp` is set to `StoppingPolicy.requireSameLength`.
4969 Limitations: The `@nogc` and `nothrow` attributes cannot be inferred for
4970 the `Zip` struct because $(LREF StoppingPolicy) can vary at runtime. This
4971 limitation is not shared by the anonymous range returned by the `zip`
4972 function when not given an explicit `StoppingPolicy` as an argument.
4974 struct Zip(Ranges...)
4975 if (Ranges.length && allSatisfy!(isInputRange, Ranges))
4977 import std.format : format; //for generic mixins
4978 import std.typecons : Tuple;
4980 alias R = Ranges;
4981 private R ranges;
4982 alias ElementType = Tuple!(staticMap!(.ElementType, R));
4983 private StoppingPolicy stoppingPolicy = StoppingPolicy.shortest;
4986 Builds an object. Usually this is invoked indirectly by using the
4987 $(LREF zip) function.
4989 this(R rs, StoppingPolicy s = StoppingPolicy.shortest)
4991 ranges[] = rs[];
4992 stoppingPolicy = s;
4996 Returns `true` if the range is at end. The test depends on the
4997 stopping policy.
4999 static if (allSatisfy!(isInfinite, R))
5001 // BUG: Doesn't propagate infiniteness if only some ranges are infinite
5002 // and s == StoppingPolicy.longest. This isn't fixable in the
5003 // current design since StoppingPolicy is known only at runtime.
5004 enum bool empty = false;
5006 else
5009 @property bool empty()
5011 import std.exception : enforce;
5012 import std.meta : anySatisfy;
5014 final switch (stoppingPolicy)
5016 case StoppingPolicy.shortest:
5017 foreach (i, Unused; R)
5019 if (ranges[i].empty) return true;
5021 return false;
5022 case StoppingPolicy.longest:
5023 static if (anySatisfy!(isInfinite, R))
5025 return false;
5027 else
5029 foreach (i, Unused; R)
5031 if (!ranges[i].empty) return false;
5033 return true;
5035 case StoppingPolicy.requireSameLength:
5036 foreach (i, Unused; R[1 .. $])
5038 enforce(ranges[0].empty ==
5039 ranges[i + 1].empty,
5040 "Inequal-length ranges passed to Zip");
5042 return ranges[0].empty;
5044 assert(false);
5048 static if (allSatisfy!(isForwardRange, R))
5051 @property Zip save()
5053 //Zip(ranges[0].save, ranges[1].save, ..., stoppingPolicy)
5054 return mixin (q{Zip(%(ranges[%s].save%|, %), stoppingPolicy)}.format(iota(0, R.length)));
5058 private .ElementType!(R[i]) tryGetInit(size_t i)()
5060 alias E = .ElementType!(R[i]);
5061 static if (!is(typeof({static E i;})))
5062 throw new Exception("Range with non-default constructable elements exhausted.");
5063 else
5064 return E.init;
5068 Returns the current iterated element.
5070 @property ElementType front()
5072 @property tryGetFront(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].front;}
5073 //ElementType(tryGetFront!0, tryGetFront!1, ...)
5074 return mixin(q{ElementType(%(tryGetFront!%s, %))}.format(iota(0, R.length)));
5078 Sets the front of all iterated ranges.
5080 static if (allSatisfy!(hasAssignableElements, R))
5082 @property void front(ElementType v)
5084 foreach (i, Unused; R)
5086 if (!ranges[i].empty)
5088 ranges[i].front = v[i];
5095 Moves out the front.
5097 static if (allSatisfy!(hasMobileElements, R))
5099 ElementType moveFront()
5101 @property tryMoveFront(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].moveFront();}
5102 //ElementType(tryMoveFront!0, tryMoveFront!1, ...)
5103 return mixin(q{ElementType(%(tryMoveFront!%s, %))}.format(iota(0, R.length)));
5108 Returns the rightmost element.
5110 static if (allSatisfy!(isBidirectionalRange, R))
5112 @property ElementType back()
5114 //TODO: Fixme! BackElement != back of all ranges in case of jagged-ness
5116 @property tryGetBack(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].back;}
5117 //ElementType(tryGetBack!0, tryGetBack!1, ...)
5118 return mixin(q{ElementType(%(tryGetBack!%s, %))}.format(iota(0, R.length)));
5122 Moves out the back.
5124 static if (allSatisfy!(hasMobileElements, R))
5126 ElementType moveBack()
5128 //TODO: Fixme! BackElement != back of all ranges in case of jagged-ness
5130 @property tryMoveBack(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].moveBack();}
5131 //ElementType(tryMoveBack!0, tryMoveBack!1, ...)
5132 return mixin(q{ElementType(%(tryMoveBack!%s, %))}.format(iota(0, R.length)));
5137 Returns the current iterated element.
5139 static if (allSatisfy!(hasAssignableElements, R))
5141 @property void back(ElementType v)
5143 //TODO: Fixme! BackElement != back of all ranges in case of jagged-ness.
5144 //Not sure the call is even legal for StoppingPolicy.longest
5146 foreach (i, Unused; R)
5148 if (!ranges[i].empty)
5150 ranges[i].back = v[i];
5158 Advances to the next element in all controlled ranges.
5160 void popFront()
5162 import std.exception : enforce;
5164 final switch (stoppingPolicy)
5166 case StoppingPolicy.shortest:
5167 foreach (i, Unused; R)
5169 assert(!ranges[i].empty);
5170 ranges[i].popFront();
5172 break;
5173 case StoppingPolicy.longest:
5174 foreach (i, Unused; R)
5176 if (!ranges[i].empty) ranges[i].popFront();
5178 break;
5179 case StoppingPolicy.requireSameLength:
5180 foreach (i, Unused; R)
5182 enforce(!ranges[i].empty, "Invalid Zip object");
5183 ranges[i].popFront();
5185 break;
5190 Calls `popBack` for all controlled ranges.
5192 static if (allSatisfy!(isBidirectionalRange, R))
5194 void popBack()
5196 //TODO: Fixme! In case of jaggedness, this is wrong.
5197 import std.exception : enforce;
5199 final switch (stoppingPolicy)
5201 case StoppingPolicy.shortest:
5202 foreach (i, Unused; R)
5204 assert(!ranges[i].empty);
5205 ranges[i].popBack();
5207 break;
5208 case StoppingPolicy.longest:
5209 foreach (i, Unused; R)
5211 if (!ranges[i].empty) ranges[i].popBack();
5213 break;
5214 case StoppingPolicy.requireSameLength:
5215 foreach (i, Unused; R)
5217 enforce(!ranges[i].empty, "Invalid Zip object");
5218 ranges[i].popBack();
5220 break;
5226 Returns the length of this range. Defined only if all ranges define
5227 `length`.
5229 static if (allSatisfy!(hasLength, R))
5231 @property auto length()
5233 static if (Ranges.length == 1)
5234 return ranges[0].length;
5235 else
5237 if (stoppingPolicy == StoppingPolicy.requireSameLength)
5238 return ranges[0].length;
5240 //[min|max](ranges[0].length, ranges[1].length, ...)
5241 import std.algorithm.comparison : min, max;
5242 if (stoppingPolicy == StoppingPolicy.shortest)
5243 return mixin(q{min(%(ranges[%s].length%|, %))}.format(iota(0, R.length)));
5244 else
5245 return mixin(q{max(%(ranges[%s].length%|, %))}.format(iota(0, R.length)));
5249 alias opDollar = length;
5253 Returns a slice of the range. Defined only if all range define
5254 slicing.
5256 static if (allSatisfy!(hasSlicing, R))
5258 auto opSlice(size_t from, size_t to)
5260 //Slicing an infinite range yields the type Take!R
5261 //For finite ranges, the type Take!R aliases to R
5262 alias ZipResult = Zip!(staticMap!(Take, R));
5264 //ZipResult(ranges[0][from .. to], ranges[1][from .. to], ..., stoppingPolicy)
5265 return mixin (q{ZipResult(%(ranges[%s][from .. to]%|, %), stoppingPolicy)}.format(iota(0, R.length)));
5270 Returns the `n`th element in the composite range. Defined if all
5271 ranges offer random access.
5273 static if (allSatisfy!(isRandomAccessRange, R))
5275 ElementType opIndex(size_t n)
5277 //TODO: Fixme! This may create an out of bounds access
5278 //for StoppingPolicy.longest
5280 //ElementType(ranges[0][n], ranges[1][n], ...)
5281 return mixin (q{ElementType(%(ranges[%s][n]%|, %))}.format(iota(0, R.length)));
5285 Assigns to the `n`th element in the composite range. Defined if
5286 all ranges offer random access.
5288 static if (allSatisfy!(hasAssignableElements, R))
5290 void opIndexAssign(ElementType v, size_t n)
5292 //TODO: Fixme! Not sure the call is even legal for StoppingPolicy.longest
5293 foreach (i, Range; R)
5295 ranges[i][n] = v[i];
5301 Destructively reads the `n`th element in the composite
5302 range. Defined if all ranges offer random access.
5304 static if (allSatisfy!(hasMobileElements, R))
5306 ElementType moveAt(size_t n)
5308 //TODO: Fixme! This may create an out of bounds access
5309 //for StoppingPolicy.longest
5311 //ElementType(ranges[0].moveAt(n), ranges[1].moveAt(n), ..., )
5312 return mixin (q{ElementType(%(ranges[%s].moveAt(n)%|, %))}.format(iota(0, R.length)));
5318 /// Ditto
5319 auto zip(Ranges...)(Ranges ranges)
5320 if (Ranges.length && allSatisfy!(isInputRange, Ranges))
5322 import std.meta : anySatisfy, templateOr;
5323 static if (allSatisfy!(isInfinite, Ranges) || Ranges.length == 1)
5325 return ZipShortest!(Ranges)(ranges);
5327 else static if (allSatisfy!(isBidirectionalRange, Ranges))
5329 static if (allSatisfy!(templateOr!(isInfinite, hasLength), Ranges)
5330 && allSatisfy!(templateOr!(isInfinite, hasSlicing), Ranges)
5331 && allSatisfy!(isBidirectionalRange, staticMap!(Take, Ranges)))
5333 // If all the ranges are bidirectional, if possible slice them to
5334 // the same length to simplify the implementation.
5335 static assert(anySatisfy!(hasLength, Ranges));
5336 static foreach (i, Range; Ranges)
5337 static if (hasLength!Range)
5339 static if (!is(typeof(minLen) == size_t))
5340 size_t minLen = ranges[i].length;
5341 else
5343 const x = ranges[i].length;
5344 if (x < minLen) minLen = x;
5347 import std.format : format;
5348 static if (!anySatisfy!(isInfinite, Ranges))
5349 return mixin(`ZipShortest!(Yes.allKnownSameLength, staticMap!(Take, Ranges))`~
5350 `(%(ranges[%s][0 .. minLen]%|, %))`.format(iota(0, Ranges.length)));
5351 else
5352 return mixin(`ZipShortest!(Yes.allKnownSameLength, staticMap!(Take, Ranges))`~
5353 `(%(take(ranges[%s], minLen)%|, %))`.format(iota(0, Ranges.length)));
5355 else static if (allSatisfy!(isRandomAccessRange, Ranges))
5357 // We can't slice but we can still use random access to ensure
5358 // "back" is retrieving the same index for each range.
5359 return ZipShortest!(Ranges)(ranges);
5361 else
5363 // If bidirectional range operations would not be supported by
5364 // ZipShortest that might have actually been a bug since Zip
5365 // supported `back` without verifying that each range had the
5366 // same length, but for the sake of backwards compatibility
5367 // use the old Zip to continue supporting them.
5368 return Zip!Ranges(ranges);
5371 else
5373 return ZipShortest!(Ranges)(ranges);
5378 @nogc nothrow pure @safe unittest
5380 import std.algorithm.comparison : equal;
5381 import std.algorithm.iteration : map;
5383 // pairwise sum
5384 auto arr = only(0, 1, 2);
5385 auto part1 = zip(arr, arr.dropOne).map!"a[0] + a[1]";
5386 assert(part1.equal(only(1, 3)));
5390 nothrow pure @safe unittest
5392 import std.conv : to;
5394 int[] a = [ 1, 2, 3 ];
5395 string[] b = [ "a", "b", "c" ];
5396 string[] result;
5398 foreach (tup; zip(a, b))
5400 result ~= tup[0].to!string ~ tup[1];
5403 assert(result == [ "1a", "2b", "3c" ]);
5405 size_t idx = 0;
5406 // unpacking tuple elements with foreach
5407 foreach (e1, e2; zip(a, b))
5409 assert(e1 == a[idx]);
5410 assert(e2 == b[idx]);
5411 ++idx;
5415 /// `zip` is powerful - the following code sorts two arrays in parallel:
5416 nothrow pure @safe unittest
5418 import std.algorithm.sorting : sort;
5420 int[] a = [ 1, 2, 3 ];
5421 string[] b = [ "a", "c", "b" ];
5422 zip(a, b).sort!((t1, t2) => t1[0] > t2[0]);
5424 assert(a == [ 3, 2, 1 ]);
5425 // b is sorted according to a's sorting
5426 assert(b == [ "b", "c", "a" ]);
5429 /// Ditto
5430 auto zip(Ranges...)(StoppingPolicy sp, Ranges ranges)
5431 if (Ranges.length && allSatisfy!(isInputRange, Ranges))
5433 return Zip!Ranges(ranges, sp);
5437 Dictates how iteration in a $(LREF zip) and $(LREF lockstep) should stop.
5438 By default stop at the end of the shortest of all ranges.
5440 enum StoppingPolicy
5442 /// Stop when the shortest range is exhausted
5443 shortest,
5444 /// Stop when the longest range is exhausted
5445 longest,
5446 /// Require that all ranges are equal
5447 requireSameLength,
5451 pure @safe unittest
5453 import std.algorithm.comparison : equal;
5454 import std.exception : assertThrown;
5455 import std.range.primitives;
5456 import std.typecons : tuple;
5458 auto a = [1, 2, 3];
5459 auto b = [4, 5, 6, 7];
5461 auto shortest = zip(StoppingPolicy.shortest, a, b);
5462 assert(shortest.equal([
5463 tuple(1, 4),
5464 tuple(2, 5),
5465 tuple(3, 6)
5466 ]));
5468 auto longest = zip(StoppingPolicy.longest, a, b);
5469 assert(longest.equal([
5470 tuple(1, 4),
5471 tuple(2, 5),
5472 tuple(3, 6),
5473 tuple(0, 7)
5474 ]));
5476 auto same = zip(StoppingPolicy.requireSameLength, a, b);
5477 same.popFrontN(3);
5478 assertThrown!Exception(same.popFront);
5482 Non-public. Like $(LREF Zip) with `StoppingPolicy.shortest`
5483 except it properly implements `back` and `popBack` in the
5484 case of uneven ranges or disables those operations when
5485 it is not possible to guarantee they are correct.
5487 package template ZipShortest(Ranges...)
5488 if (Ranges.length && __traits(compiles,
5490 static assert(allSatisfy!(isInputRange, Ranges));
5493 alias ZipShortest = .ZipShortest!(
5494 Ranges.length == 1 || allSatisfy!(isInfinite, Ranges)
5495 ? Yes.allKnownSameLength
5496 : No.allKnownSameLength,
5497 Ranges);
5499 /+ non-public, ditto +/
5500 package struct ZipShortest(Flag!"allKnownSameLength" allKnownSameLength, Ranges...)
5501 if (Ranges.length && allSatisfy!(isInputRange, Ranges))
5503 import std.format : format; //for generic mixins
5504 import std.meta : anySatisfy, templateOr;
5505 import std.typecons : Tuple;
5507 deprecated("Use of an undocumented alias R.")
5508 alias R = Ranges; // Unused here but defined in case library users rely on it.
5509 private Ranges ranges;
5510 alias ElementType = Tuple!(staticMap!(.ElementType, Ranges));
5513 Builds an object. Usually this is invoked indirectly by using the
5514 $(LREF zip) function.
5516 this(Ranges rs)
5518 ranges[] = rs[];
5522 Returns `true` if the range is at end.
5524 static if (allKnownSameLength ? anySatisfy!(isInfinite, Ranges)
5525 : allSatisfy!(isInfinite, Ranges))
5527 enum bool empty = false;
5529 else
5531 @property bool empty()
5533 static if (allKnownSameLength)
5535 return ranges[0].empty;
5537 else
5539 static foreach (i; 0 .. Ranges.length)
5541 if (ranges[i].empty)
5542 return true;
5544 return false;
5550 Forward range primitive. Only present if each constituent range is a
5551 forward range.
5553 static if (allSatisfy!(isForwardRange, Ranges))
5554 @property typeof(this) save()
5556 return mixin(`typeof(return)(%(ranges[%s].save%|, %))`.format(iota(0, Ranges.length)));
5560 Returns the current iterated element.
5562 @property ElementType front()
5564 return mixin(`typeof(return)(%(ranges[%s].front%|, %))`.format(iota(0, Ranges.length)));
5568 Sets the front of all iterated ranges. Only present if each constituent
5569 range has assignable elements.
5571 static if (allSatisfy!(hasAssignableElements, Ranges))
5572 @property void front()(ElementType v)
5574 static foreach (i; 0 .. Ranges.length)
5575 ranges[i].front = v[i];
5579 Moves out the front. Present if each constituent range has mobile elements.
5581 static if (allSatisfy!(hasMobileElements, Ranges))
5582 ElementType moveFront()()
5584 return mixin(`typeof(return)(%(ranges[%s].moveFront()%|, %))`.format(iota(0, Ranges.length)));
5587 private enum bool isBackWellDefined = allSatisfy!(isBidirectionalRange, Ranges)
5588 && (allKnownSameLength
5589 || allSatisfy!(isRandomAccessRange, Ranges)
5590 // Could also add the case where there is one non-infinite bidirectional
5591 // range that defines `length` and all others are infinite random access
5592 // ranges. Adding this would require appropriate branches in
5593 // back/moveBack/popBack.
5597 Returns the rightmost element. Present if all constituent ranges are
5598 bidirectional and either there is a compile-time guarantee that all
5599 ranges have the same length (in `allKnownSameLength`) or all ranges
5600 provide random access to elements.
5602 static if (isBackWellDefined)
5603 @property ElementType back()
5605 static if (allKnownSameLength)
5607 return mixin(`typeof(return)(%(ranges[%s].back()%|, %))`.format(iota(0, Ranges.length)));
5609 else
5611 const backIndex = length - 1;
5612 return mixin(`typeof(return)(%(ranges[%s][backIndex]%|, %))`.format(iota(0, Ranges.length)));
5617 Moves out the back. Present if `back` is defined and
5618 each constituent range has mobile elements.
5620 static if (isBackWellDefined && allSatisfy!(hasMobileElements, Ranges))
5621 ElementType moveBack()()
5623 static if (allKnownSameLength)
5625 return mixin(`typeof(return)(%(ranges[%s].moveBack()%|, %))`.format(iota(0, Ranges.length)));
5627 else
5629 const backIndex = length - 1;
5630 return mixin(`typeof(return)(%(ranges[%s].moveAt(backIndex)%|, %))`.format(iota(0, Ranges.length)));
5635 Sets the rightmost element. Only present if `back` is defined and
5636 each constituent range has assignable elements.
5638 static if (isBackWellDefined && allSatisfy!(hasAssignableElements, Ranges))
5639 @property void back()(ElementType v)
5641 static if (allKnownSameLength)
5643 static foreach (i; 0 .. Ranges.length)
5644 ranges[i].back = v[i];
5646 else
5648 const backIndex = length - 1;
5649 static foreach (i; 0 .. Ranges.length)
5650 ranges[i][backIndex] = v[i];
5655 Calls `popFront` on each constituent range.
5657 void popFront()
5659 static foreach (i; 0 .. Ranges.length)
5660 ranges[i].popFront();
5664 Pops the rightmost element. Present if `back` is defined.
5666 static if (isBackWellDefined)
5667 void popBack()
5669 static if (allKnownSameLength)
5671 static foreach (i; 0 .. Ranges.length)
5672 ranges[i].popBack;
5674 else
5676 const len = length;
5677 static foreach (i; 0 .. Ranges.length)
5678 static if (!isInfinite!(Ranges[i]))
5679 if (ranges[i].length == len)
5680 ranges[i].popBack();
5685 Returns the length of this range. Defined if at least one
5686 constituent range defines `length` and the other ranges all also
5687 define `length` or are infinite, or if at least one constituent
5688 range defines `length` and there is a compile-time guarantee that
5689 all ranges have the same length (in `allKnownSameLength`).
5691 static if (allKnownSameLength
5692 ? anySatisfy!(hasLength, Ranges)
5693 : (anySatisfy!(hasLength, Ranges)
5694 && allSatisfy!(templateOr!(isInfinite, hasLength), Ranges)))
5696 @property size_t length()
5698 static foreach (i, Range; Ranges)
5700 static if (hasLength!Range)
5702 static if (!is(typeof(minLen) == size_t))
5703 size_t minLen = ranges[i].length;
5704 else static if (!allKnownSameLength)
5706 const x = ranges[i].length;
5707 if (x < minLen) minLen = x;
5711 return minLen;
5714 alias opDollar = length;
5718 Returns a slice of the range. Defined if all constituent ranges
5719 support slicing.
5721 static if (allSatisfy!(hasSlicing, Ranges))
5723 // Note: we will know that all elements of the resultant range
5724 // will have the same length but we cannot change `allKnownSameLength`
5725 // because the `hasSlicing` predicate tests that the result returned
5726 // by `opSlice` has the same type as the receiver.
5727 auto opSlice()(size_t from, size_t to)
5729 //(ranges[0][from .. to], ranges[1][from .. to], ...)
5730 enum sliceArgs = `(%(ranges[%s][from .. to]%|, %))`.format(iota(0, Ranges.length));
5731 static if (__traits(compiles, mixin(`typeof(this)`~sliceArgs)))
5732 return mixin(`typeof(this)`~sliceArgs);
5733 else
5734 // The type is different anyway so we might as well
5735 // explicitly set allKnownSameLength.
5736 return mixin(`ZipShortest!(Yes.allKnownSameLength, staticMap!(Take, Ranges))`
5737 ~sliceArgs);
5742 Returns the `n`th element in the composite range. Defined if all
5743 constituent ranges offer random access.
5745 static if (allSatisfy!(isRandomAccessRange, Ranges))
5746 ElementType opIndex()(size_t n)
5748 return mixin(`typeof(return)(%(ranges[%s][n]%|, %))`.format(iota(0, Ranges.length)));
5752 Sets the `n`th element in the composite range. Defined if all
5753 constituent ranges offer random access and have assignable elements.
5755 static if (allSatisfy!(isRandomAccessRange, Ranges)
5756 && allSatisfy!(hasAssignableElements, Ranges))
5757 void opIndexAssign()(ElementType v, size_t n)
5759 static foreach (i; 0 .. Ranges.length)
5760 ranges[i][n] = v[i];
5764 Destructively reads the `n`th element in the composite
5765 range. Defined if all constituent ranges offer random
5766 access and have mobile elements.
5768 static if (allSatisfy!(isRandomAccessRange, Ranges)
5769 && allSatisfy!(hasMobileElements, Ranges))
5770 ElementType moveAt()(size_t n)
5772 return mixin(`typeof(return)(%(ranges[%s].moveAt(n)%|, %))`.format(iota(0, Ranges.length)));
5776 pure @system unittest
5778 import std.algorithm.comparison : equal;
5779 import std.algorithm.iteration : filter, map;
5780 import std.algorithm.mutation : swap;
5781 import std.algorithm.sorting : sort;
5783 import std.exception : assertThrown, assertNotThrown;
5784 import std.typecons : tuple;
5786 int[] a = [ 1, 2, 3 ];
5787 float[] b = [ 1.0, 2.0, 3.0 ];
5788 foreach (e; zip(a, b))
5790 assert(e[0] == e[1]);
5793 swap(a[0], a[1]);
5795 auto z = zip(a, b);
5797 //swap(z.front(), z.back());
5798 sort!("a[0] < b[0]")(zip(a, b));
5799 assert(a == [1, 2, 3]);
5800 assert(b == [2.0, 1.0, 3.0]);
5802 auto z = zip(StoppingPolicy.requireSameLength, a, b);
5803 assertNotThrown(z.popBack());
5804 assertNotThrown(z.popBack());
5805 assertNotThrown(z.popBack());
5806 assert(z.empty);
5807 assertThrown(z.popBack());
5809 a = [ 1, 2, 3 ];
5810 b = [ 1.0, 2.0, 3.0 ];
5811 sort!("a[0] > b[0]")(zip(StoppingPolicy.requireSameLength, a, b));
5812 assert(a == [3, 2, 1]);
5813 assert(b == [3.0, 2.0, 1.0]);
5815 a = [];
5816 b = [];
5817 assert(zip(StoppingPolicy.requireSameLength, a, b).empty);
5819 // Test infiniteness propagation.
5820 static assert(isInfinite!(typeof(zip(repeat(1), repeat(1)))));
5822 // Test stopping policies with both value and reference.
5823 auto a1 = [1, 2];
5824 auto a2 = [1, 2, 3];
5825 auto stuff = tuple(tuple(a1, a2),
5826 tuple(filter!"a"(a1), filter!"a"(a2)));
5828 alias FOO = Zip!(immutable(int)[], immutable(float)[]);
5830 foreach (t; stuff.expand)
5832 auto arr1 = t[0];
5833 auto arr2 = t[1];
5834 auto zShortest = zip(arr1, arr2);
5835 assert(equal(map!"a[0]"(zShortest), [1, 2]));
5836 assert(equal(map!"a[1]"(zShortest), [1, 2]));
5838 try {
5839 auto zSame = zip(StoppingPolicy.requireSameLength, arr1, arr2);
5840 foreach (elem; zSame) {}
5841 assert(0);
5842 } catch (Throwable) { /* It's supposed to throw.*/ }
5844 auto zLongest = zip(StoppingPolicy.longest, arr1, arr2);
5845 assert(!zLongest.ranges[0].empty);
5846 assert(!zLongest.ranges[1].empty);
5848 zLongest.popFront();
5849 zLongest.popFront();
5850 assert(!zLongest.empty);
5851 assert(zLongest.ranges[0].empty);
5852 assert(!zLongest.ranges[1].empty);
5854 zLongest.popFront();
5855 assert(zLongest.empty);
5858 // https://issues.dlang.org/show_bug.cgi?id=8900
5859 assert(zip([1, 2], repeat('a')).array == [tuple(1, 'a'), tuple(2, 'a')]);
5860 assert(zip(repeat('a'), [1, 2]).array == [tuple('a', 1), tuple('a', 2)]);
5862 // https://issues.dlang.org/show_bug.cgi?id=18524
5863 // moveBack instead performs moveFront
5865 auto r = zip([1,2,3]);
5866 assert(r.moveBack()[0] == 3);
5867 assert(r.moveFront()[0] == 1);
5870 // Doesn't work yet. Issues w/ emplace.
5871 // static assert(is(Zip!(immutable int[], immutable float[])));
5874 // These unittests pass, but make the compiler consume an absurd amount
5875 // of RAM and time. Therefore, they should only be run if explicitly
5876 // uncommented when making changes to Zip. Also, running them using
5877 // make -fwin32.mak unittest makes the compiler completely run out of RAM.
5878 // You need to test just this module.
5880 foreach (DummyType1; AllDummyRanges)
5882 DummyType1 d1;
5883 foreach (DummyType2; AllDummyRanges)
5885 DummyType2 d2;
5886 auto r = zip(d1, d2);
5887 assert(equal(map!"a[0]"(r), [1,2,3,4,5,6,7,8,9,10]));
5888 assert(equal(map!"a[1]"(r), [1,2,3,4,5,6,7,8,9,10]));
5890 static if (isForwardRange!DummyType1 && isForwardRange!DummyType2)
5892 static assert(isForwardRange!(typeof(r)));
5895 static if (isBidirectionalRange!DummyType1 &&
5896 isBidirectionalRange!DummyType2) {
5897 static assert(isBidirectionalRange!(typeof(r)));
5899 static if (isRandomAccessRange!DummyType1 &&
5900 isRandomAccessRange!DummyType2) {
5901 static assert(isRandomAccessRange!(typeof(r)));
5908 nothrow pure @safe unittest
5910 import std.algorithm.sorting : sort;
5912 auto a = [5,4,3,2,1];
5913 auto b = [3,1,2,5,6];
5914 auto z = zip(a, b);
5916 sort!"a[0] < b[0]"(z);
5918 assert(a == [1, 2, 3, 4, 5]);
5919 assert(b == [6, 5, 2, 1, 3]);
5922 nothrow pure @safe unittest
5924 import std.algorithm.comparison : equal;
5925 import std.typecons : tuple;
5927 auto LL = iota(1L, 1000L);
5928 auto z = zip(LL, [4]);
5930 assert(equal(z, [tuple(1L,4)]));
5932 auto LL2 = iota(0L, 500L);
5933 auto z2 = zip([7], LL2);
5934 assert(equal(z2, [tuple(7, 0L)]));
5937 // Test for https://issues.dlang.org/show_bug.cgi?id=11196
5938 @safe pure unittest
5940 import std.exception : assertThrown;
5942 static struct S { @disable this(); }
5943 assert(zip((S[5]).init[]).length == 5);
5944 assert(zip(StoppingPolicy.longest, cast(S[]) null, new int[1]).length == 1);
5945 assertThrown(zip(StoppingPolicy.longest, cast(S[]) null, new int[1]).front);
5948 // https://issues.dlang.org/show_bug.cgi?id=12007
5949 @nogc nothrow @safe pure unittest
5951 static struct R
5953 enum empty = false;
5954 void popFront(){}
5955 int front(){return 1;} @property
5956 R save(){return this;} @property
5957 void opAssign(R) @disable;
5959 R r;
5960 auto z = zip(r, r);
5961 assert(z.save == z);
5964 nothrow pure @system unittest
5966 import std.typecons : tuple;
5968 auto r1 = [0,1,2];
5969 auto r2 = [1,2,3];
5970 auto z1 = zip(refRange(&r1), refRange(&r2));
5971 auto z2 = z1.save;
5972 z1.popFront();
5973 assert(z1.front == tuple(1,2));
5974 assert(z2.front == tuple(0,1));
5977 @nogc nothrow pure @safe unittest
5979 // Test zip's `back` and `length` with non-equal ranges.
5980 static struct NonSliceableRandomAccess
5982 private int[] a;
5983 @property ref front()
5985 return a.front;
5987 @property ref back()
5989 return a.back;
5991 ref opIndex(size_t i)
5993 return a[i];
5995 void popFront()
5997 a.popFront();
5999 void popBack()
6001 a.popBack();
6003 auto moveFront()
6005 return a.moveFront();
6007 auto moveBack()
6009 return a.moveBack();
6011 auto moveAt(size_t i)
6013 return a.moveAt(i);
6015 bool empty() const
6017 return a.empty;
6019 size_t length() const
6021 return a.length;
6023 typeof(this) save()
6025 return this;
6028 static assert(isRandomAccessRange!NonSliceableRandomAccess);
6029 static assert(!hasSlicing!NonSliceableRandomAccess);
6030 static foreach (iteration; 0 .. 2)
6032 int[5] data = [101, 102, 103, 201, 202];
6033 static if (iteration == 0)
6035 auto r1 = NonSliceableRandomAccess(data[0 .. 3]);
6036 auto r2 = NonSliceableRandomAccess(data[3 .. 5]);
6038 else
6040 auto r1 = data[0 .. 3];
6041 auto r2 = data[3 .. 5];
6043 auto z = zip(r1, r2);
6044 static assert(isRandomAccessRange!(typeof(z)));
6045 assert(z.length == 2);
6046 assert(z.back[0] == 102 && z.back[1] == 202);
6047 z.back = typeof(z.back)(-102, -202);// Assign to back.
6048 assert(z.back[0] == -102 && z.back[1] == -202);
6049 z.popBack();
6050 assert(z.length == 1);
6051 assert(z.back[0] == 101 && z.back[1] == 201);
6052 z.front = typeof(z.front)(-101, -201);
6053 assert(z.moveBack() == typeof(z.back)(-101, -201));
6054 z.popBack();
6055 assert(z.empty);
6059 @nogc nothrow pure @safe unittest
6061 // Test opSlice on infinite `zip`.
6062 auto z = zip(repeat(1), repeat(2));
6063 assert(hasSlicing!(typeof(z)));
6064 auto slice = z[10 .. 20];
6065 assert(slice.length == 10);
6066 static assert(!is(typeof(z) == typeof(slice)));
6070 Generate lockstep's opApply function as a mixin string.
6071 If withIndex is true prepend a size_t index to the delegate.
6073 private struct LockstepMixin(Ranges...)
6075 import std.conv : text;
6076 import std.format : format;
6078 string name;
6079 string implName;
6080 string[] params;
6081 string[] emptyChecks;
6082 string[] dgArgs;
6083 string[] popFronts;
6084 string indexDef;
6085 string indexInc;
6087 @safe pure:
6088 this(bool withIndex, bool reverse)
6090 if (withIndex)
6092 params ~= "size_t";
6093 dgArgs ~= "index";
6094 if (reverse)
6096 indexDef = q{
6097 size_t index = ranges[0].length - 1;
6098 enforce(
6099 this.stoppingPolicy == StoppingPolicy.requireSameLength,
6100 "Indexed lockstep can only be used with foreach_reverse when " ~
6101 "stoppingPolicy == requireSameLength");
6103 foreach (range; ranges[1 .. $])
6104 enforce(range.length == ranges[0].length);
6106 indexInc = "--index;";
6108 else
6110 indexDef = "size_t index = 0;";
6111 indexInc = "++index;";
6115 foreach (idx, Range; Ranges)
6117 params ~= format("%sElementType!(Ranges[%s])", hasLvalueElements!Range ? "ref " : "", idx);
6118 emptyChecks ~= format("!ranges[%s].empty", idx);
6119 if (reverse)
6121 dgArgs ~= format("ranges[%s].back", idx);
6122 popFronts ~= format("ranges[%s].popBack();", idx);
6124 else
6126 dgArgs ~= format("ranges[%s].front", idx);
6127 popFronts ~= format("ranges[%s].popFront();", idx);
6131 if (reverse)
6133 name = "opApplyReverse";
6134 if (withIndex) implName = "opApplyReverseIdxImpl";
6135 else implName = "opApplyReverseImpl";
6137 else
6139 name = "opApply";
6140 if (withIndex) implName = "opApplyIdxImpl";
6141 else implName = "opApplyImpl";
6145 const:
6146 string getAlias()
6148 return format(q{
6149 alias %s = %s!(int delegate(%-(%s%|, %)));
6151 name, implName, params
6155 string getImpl()
6157 return format(q{
6158 int %s(DG)(scope DG dg) scope
6160 import std.exception : enforce;
6162 auto ranges = this.ranges;
6165 while (%-(%s%| && %))
6167 if (int result = dg(%-(%s%|, %))) return result;
6168 %-(%s%|
6173 if (this.stoppingPolicy == StoppingPolicy.requireSameLength)
6175 foreach (range; ranges)
6176 enforce(range.empty);
6178 return 0;
6181 implName, indexDef, emptyChecks, dgArgs, popFronts, indexInc
6187 Iterate multiple ranges in lockstep using a `foreach` loop. In contrast to
6188 $(LREF zip) it allows reference access to its elements. If only a single
6189 range is passed in, the `Lockstep` aliases itself away. If the
6190 ranges are of different lengths and `s` == `StoppingPolicy.shortest`
6191 stop after the shortest range is empty. If the ranges are of different
6192 lengths and `s` == `StoppingPolicy.requireSameLength`, throw an
6193 exception. `s` may not be `StoppingPolicy.longest`, and passing this
6194 will throw an exception.
6196 Iterating over `Lockstep` in reverse and with an index is only possible
6197 when `s` == `StoppingPolicy.requireSameLength`, in order to preserve
6198 indexes. If an attempt is made at iterating in reverse when `s` ==
6199 `StoppingPolicy.shortest`, an exception will be thrown.
6201 By default `StoppingPolicy` is set to `StoppingPolicy.shortest`.
6203 See_Also: $(LREF zip)
6205 `lockstep` is similar to $(LREF zip), but `zip` bundles its
6206 elements and returns a range.
6207 `lockstep` also supports reference access.
6208 Use `zip` if you want to pass the result to a range function.
6210 struct Lockstep(Ranges...)
6211 if (Ranges.length > 1 && allSatisfy!(isInputRange, Ranges))
6213 private Ranges ranges;
6214 private StoppingPolicy stoppingPolicy;
6217 this(Ranges ranges, StoppingPolicy sp = StoppingPolicy.shortest)
6219 import std.exception : enforce;
6221 this.ranges = ranges;
6222 enforce(sp != StoppingPolicy.longest,
6223 "Can't use StoppingPolicy.Longest on Lockstep.");
6224 this.stoppingPolicy = sp;
6227 private enum lockstepMixinFF = LockstepMixin!Ranges(withIndex: false, reverse: false);
6228 mixin(lockstepMixinFF.getImpl);
6230 private enum lockstepMixinTF = LockstepMixin!Ranges(withIndex: true, reverse: false);
6231 mixin(lockstepMixinTF.getImpl);
6233 mixin(lockstepMixinFF.getAlias);
6234 mixin(lockstepMixinTF.getAlias);
6236 static if (allSatisfy!(isBidirectionalRange, Ranges))
6238 private enum lockstepMixinFT = LockstepMixin!Ranges(withIndex: false, reverse: true);
6239 mixin(lockstepMixinFT.getImpl);
6240 static if (allSatisfy!(hasLength, Ranges))
6242 private enum lockstepMixinTT = LockstepMixin!Ranges(withIndex: true, reverse: true);
6243 mixin(lockstepMixinTT.getImpl);
6244 mixin(lockstepMixinTT.getAlias);
6246 else
6248 mixin(lockstepReverseFailMixin!Ranges(withIndex: true));
6249 alias opApplyReverse = opApplyReverseIdxFail;
6251 mixin(lockstepMixinFT.getAlias);
6253 else
6255 mixin(lockstepReverseFailMixin!Ranges(withIndex: false));
6256 mixin(lockstepReverseFailMixin!Ranges(withIndex: true));
6257 alias opApplyReverse = opApplyReverseFail;
6258 alias opApplyReverse = opApplyReverseIdxFail;
6262 /// Ditto
6263 Lockstep!(Ranges) lockstep(Ranges...)(Ranges ranges)
6264 if (allSatisfy!(isInputRange, Ranges))
6266 return Lockstep!(Ranges)(ranges);
6268 /// Ditto
6269 Lockstep!(Ranges) lockstep(Ranges...)(Ranges ranges, StoppingPolicy s)
6270 if (allSatisfy!(isInputRange, Ranges))
6272 static if (Ranges.length > 1)
6273 return Lockstep!Ranges(ranges, s);
6274 else
6275 return ranges[0];
6279 pure @safe unittest
6281 int[6] arr1 = [1,2,3,4,5,100];
6282 int[5] arr2 = [6,7,8,9,10];
6284 foreach (ref a, b; lockstep(arr1[], arr2[]))
6286 a += b;
6289 assert(arr1 == [7,9,11,13,15,100]);
6292 /// Lockstep also supports iterating with an index variable:
6293 pure @safe unittest
6295 int[3] arr1 = [1,2,3];
6296 int[3] arr2 = [4,5,6];
6298 foreach (index, a, b; lockstep(arr1[], arr2[]))
6300 assert(arr1[index] == a);
6301 assert(arr2[index] == b);
6305 // https://issues.dlang.org/show_bug.cgi?id=15860: foreach_reverse on lockstep
6306 pure @safe unittest
6308 auto arr1 = [0, 1, 2, 3];
6309 auto arr2 = [4, 5, 6, 7];
6311 size_t n = arr1.length - 1;
6312 foreach_reverse (index, a, b; lockstep(arr1, arr2, StoppingPolicy.requireSameLength))
6314 assert(n == index);
6315 assert(index == a);
6316 assert(arr1[index] == a);
6317 assert(arr2[index] == b);
6318 n--;
6321 auto arr3 = [4, 5];
6322 n = 1;
6323 foreach_reverse (a, b; lockstep(arr1, arr3))
6325 assert(a == arr1[$-n] && b == arr3[$-n]);
6326 n++;
6330 pure @safe unittest
6332 import std.algorithm.iteration : filter;
6333 import std.conv : to;
6335 // The filters are to make these the lowest common forward denominator ranges,
6336 // i.e. w/o ref return, random access, length, etc.
6337 auto foo = filter!"a"([1,2,3,4,5]);
6338 immutable bar = [6f,7f,8f,9f,10f].idup;
6339 auto l = lockstep(foo, bar);
6341 // Should work twice. These are forward ranges with implicit save.
6342 foreach (i; 0 .. 2)
6344 uint[] res1;
6345 float[] res2;
6347 foreach (a, ref b; l)
6349 res1 ~= a;
6350 res2 ~= b;
6353 assert(res1 == [1,2,3,4,5]);
6354 assert(res2 == [6,7,8,9,10]);
6355 assert(bar == [6f,7f,8f,9f,10f]);
6358 // Doc example.
6359 auto arr1 = [1,2,3,4,5];
6360 auto arr2 = [6,7,8,9,10];
6362 foreach (ref a, ref b; lockstep(arr1, arr2))
6364 a += b;
6367 assert(arr1 == [7,9,11,13,15]);
6369 // Make sure StoppingPolicy.requireSameLength doesn't throw.
6370 auto ls = lockstep(arr1, arr2, StoppingPolicy.requireSameLength);
6372 int k = 1;
6373 foreach (a, b; ls)
6375 assert(a - b == k);
6376 ++k;
6379 // Make sure StoppingPolicy.requireSameLength throws.
6380 arr2.popBack();
6381 ls = lockstep(arr1, arr2, StoppingPolicy.requireSameLength);
6383 try {
6384 foreach (a, b; ls) {}
6385 assert(0);
6386 } catch (Exception) {}
6388 // Just make sure 1-range case instantiates. This hangs the compiler
6389 // when no explicit stopping policy is specified due to
6390 // https://issues.dlang.org/show_bug.cgi?id=4652
6391 auto stuff = lockstep([1,2,3,4,5], StoppingPolicy.shortest);
6392 foreach (i, a; stuff)
6394 assert(stuff[i] == a);
6397 // Test with indexing.
6398 uint[] res1;
6399 float[] res2;
6400 size_t[] indices;
6401 foreach (i, a, b; lockstep(foo, bar))
6403 indices ~= i;
6404 res1 ~= a;
6405 res2 ~= b;
6408 assert(indices == to!(size_t[])([0, 1, 2, 3, 4]));
6409 assert(res1 == [1,2,3,4,5]);
6410 assert(res2 == [6f,7f,8f,9f,10f]);
6412 // Make sure we've worked around the relevant compiler bugs and this at least
6413 // compiles w/ >2 ranges.
6414 lockstep(foo, foo, foo);
6416 // Make sure it works with const.
6417 const(int[])[] foo2 = [[1, 2, 3]];
6418 const(int[])[] bar2 = [[4, 5, 6]];
6419 auto c = chain(foo2, bar2);
6421 foreach (f, b; lockstep(c, c)) {}
6423 // Regression 10468
6424 foreach (x, y; lockstep(iota(0, 10), iota(0, 10))) { }
6427 pure @safe unittest
6429 struct RvalueRange
6431 int[] impl;
6432 @property bool empty() { return impl.empty; }
6433 @property int front() { return impl[0]; } // N.B. non-ref
6434 void popFront() { impl.popFront(); }
6436 auto data1 = [ 1, 2, 3, 4 ];
6437 auto data2 = [ 5, 6, 7, 8 ];
6438 auto r1 = RvalueRange(data1);
6439 auto r2 = data2;
6440 foreach (a, ref b; lockstep(r1, r2))
6442 a++;
6443 b++;
6445 assert(data1 == [ 1, 2, 3, 4 ]); // changes to a do not propagate to data
6446 assert(data2 == [ 6, 7, 8, 9 ]); // but changes to b do.
6448 // Since r1 is by-value only, the compiler should reject attempts to
6449 // foreach over it with ref.
6450 static assert(!__traits(compiles, {
6451 foreach (ref a, ref b; lockstep(r1, r2)) { a++; }
6452 }));
6455 private string lockstepReverseFailMixin(Ranges...)(bool withIndex)
6457 import std.format : format;
6458 string[] params;
6459 string message;
6461 if (withIndex)
6463 message = "Indexed reverse iteration with lockstep is only supported"
6464 ~"if all ranges are bidirectional and have a length.\n";
6466 else
6468 message = "Reverse iteration with lockstep is only supported if all ranges are bidirectional.\n";
6471 if (withIndex)
6473 params ~= "size_t";
6476 foreach (idx, Range; Ranges)
6478 params ~= format("%sElementType!(Ranges[%s])", hasLvalueElements!Range ? "ref " : "", idx);
6481 return format(
6483 int opApplyReverse%sFail()(scope int delegate(%s) dg)
6485 static assert(false, "%s");
6487 }, withIndex ? "Idx" : "" , params.join(", "), message);
6490 // For generic programming, make sure Lockstep!(Range) is well defined for a
6491 // single range.
6492 template Lockstep(Range)
6494 alias Lockstep = Range;
6498 Creates a mathematical sequence given the initial values and a
6499 recurrence function that computes the next value from the existing
6500 values. The sequence comes in the form of an infinite forward
6501 range. The type `Recurrence` itself is seldom used directly; most
6502 often, recurrences are obtained by calling the function $(D
6503 recurrence).
6505 When calling `recurrence`, the function that computes the next
6506 value is specified as a template argument, and the initial values in
6507 the recurrence are passed as regular arguments. For example, in a
6508 Fibonacci sequence, there are two initial values (and therefore a
6509 state size of 2) because computing the next Fibonacci value needs the
6510 past two values.
6512 The signature of this function should be:
6513 ----
6514 auto fun(R)(R state, size_t n)
6515 ----
6516 where `n` will be the index of the current value, and `state` will be an
6517 opaque state vector that can be indexed with array-indexing notation
6518 `state[i]`, where valid values of `i` range from $(D (n - 1)) to
6519 $(D (n - State.length)).
6521 If the function is passed in string form, the state has name `"a"`
6522 and the zero-based index in the recurrence has name `"n"`. The
6523 given string must return the desired value for `a[n]` given
6524 `a[n - 1]`, `a[n - 2]`, `a[n - 3]`,..., `a[n - stateSize]`. The
6525 state size is dictated by the number of arguments passed to the call
6526 to `recurrence`. The `Recurrence` struct itself takes care of
6527 managing the recurrence's state and shifting it appropriately.
6529 struct Recurrence(alias fun, StateType, size_t stateSize)
6531 import std.functional : binaryFun;
6533 StateType[stateSize] _state;
6534 size_t _n;
6536 this(StateType[stateSize] initial) { _state = initial; }
6538 void popFront()
6540 static auto trustedCycle(ref typeof(_state) s) @trusted
6542 return cycle(s);
6544 // The cast here is reasonable because fun may cause integer
6545 // promotion, but needs to return a StateType to make its operation
6546 // closed. Therefore, we have no other choice.
6547 _state[_n % stateSize] = cast(StateType) binaryFun!(fun, "a", "n")(
6548 trustedCycle(_state), _n + stateSize);
6549 ++_n;
6552 @property StateType front()
6554 return _state[_n % stateSize];
6557 @property typeof(this) save()
6559 return this;
6562 enum bool empty = false;
6566 pure @safe nothrow unittest
6568 import std.algorithm.comparison : equal;
6570 // The Fibonacci numbers, using function in string form:
6571 // a[0] = 1, a[1] = 1, and compute a[n+1] = a[n-1] + a[n]
6572 auto fib = recurrence!("a[n-1] + a[n-2]")(1, 1);
6573 assert(fib.take(10).equal([1, 1, 2, 3, 5, 8, 13, 21, 34, 55]));
6575 // The factorials, using function in lambda form:
6576 auto fac = recurrence!((a,n) => a[n-1] * n)(1);
6577 assert(take(fac, 10).equal([
6578 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880
6579 ]));
6581 // The triangular numbers, using function in explicit form:
6582 static size_t genTriangular(R)(R state, size_t n)
6584 return state[n-1] + n;
6586 auto tri = recurrence!genTriangular(0);
6587 assert(take(tri, 10).equal([0, 1, 3, 6, 10, 15, 21, 28, 36, 45]));
6590 /// Ditto
6591 Recurrence!(fun, CommonType!(State), State.length)
6592 recurrence(alias fun, State...)(State initial)
6594 CommonType!(State)[State.length] state;
6595 foreach (i, Unused; State)
6597 state[i] = initial[i];
6599 return typeof(return)(state);
6602 pure @safe nothrow unittest
6604 import std.algorithm.comparison : equal;
6606 auto fib = recurrence!("a[n-1] + a[n-2]")(1, 1);
6607 static assert(isForwardRange!(typeof(fib)));
6609 int[] witness = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55 ];
6610 assert(equal(take(fib, 10), witness));
6611 foreach (e; take(fib, 10)) {}
6612 auto fact = recurrence!("n * a[n-1]")(1);
6613 assert( equal(take(fact, 10), [1, 1, 2, 2*3, 2*3*4, 2*3*4*5, 2*3*4*5*6,
6614 2*3*4*5*6*7, 2*3*4*5*6*7*8, 2*3*4*5*6*7*8*9][]) );
6615 auto piapprox = recurrence!("a[n] + (n & 1 ? 4.0 : -4.0) / (2 * n + 3)")(4.0);
6616 foreach (e; take(piapprox, 20)) {}
6617 // Thanks to yebblies for this test and the associated fix
6618 auto r = recurrence!"a[n-2]"(1, 2);
6619 witness = [1, 2, 1, 2, 1];
6620 assert(equal(take(r, 5), witness));
6624 `Sequence` is similar to `Recurrence` except that iteration is
6625 presented in the so-called $(HTTP en.wikipedia.org/wiki/Closed_form,
6626 closed form). This means that the `n`th element in the series is
6627 computable directly from the initial values and `n` itself. This
6628 implies that the interface offered by `Sequence` is a random-access
6629 range, as opposed to the regular `Recurrence`, which only offers
6630 forward iteration.
6632 The state of the sequence is stored as a `Tuple` so it can be
6633 heterogeneous.
6635 struct Sequence(alias fun, State)
6637 private:
6638 import std.functional : binaryFun;
6640 alias compute = binaryFun!(fun, "a", "n");
6641 alias ElementType = typeof(compute(State.init, cast(size_t) 1));
6642 State _state;
6643 size_t _n;
6645 static struct DollarToken{}
6647 public:
6648 this(State initial, size_t n = 0)
6650 _state = initial;
6651 _n = n;
6654 @property ElementType front()
6656 return compute(_state, _n);
6659 void popFront()
6661 ++_n;
6664 enum opDollar = DollarToken();
6666 auto opSlice(size_t lower, size_t upper)
6669 assert(
6670 upper >= lower,
6671 "Attempting to slice a Sequence with a larger first argument than the second."
6676 return typeof(this)(_state, _n + lower).take(upper - lower);
6679 auto opSlice(size_t lower, DollarToken)
6681 return typeof(this)(_state, _n + lower);
6684 ElementType opIndex(size_t n)
6686 return compute(_state, n + _n);
6689 enum bool empty = false;
6691 @property Sequence save() { return this; }
6694 /// Ditto
6695 auto sequence(alias fun, State...)(State args)
6697 import std.typecons : Tuple, tuple;
6698 alias Return = Sequence!(fun, Tuple!State);
6699 return Return(tuple(args));
6702 /// Odd numbers, using function in string form:
6703 pure @safe nothrow @nogc unittest
6705 auto odds = sequence!("a[0] + n * a[1]")(1, 2);
6706 assert(odds.front == 1);
6707 odds.popFront();
6708 assert(odds.front == 3);
6709 odds.popFront();
6710 assert(odds.front == 5);
6713 /// Triangular numbers, using function in lambda form:
6714 pure @safe nothrow @nogc unittest
6716 auto tri = sequence!((a,n) => n*(n+1)/2)();
6718 // Note random access
6719 assert(tri[0] == 0);
6720 assert(tri[3] == 6);
6721 assert(tri[1] == 1);
6722 assert(tri[4] == 10);
6723 assert(tri[2] == 3);
6726 /// Fibonacci numbers, using function in explicit form:
6727 @safe nothrow @nogc unittest
6729 import std.math.exponential : pow;
6730 import std.math.rounding : round;
6731 import std.math.algebraic : sqrt;
6732 static ulong computeFib(S)(S state, size_t n)
6734 // Binet's formula
6735 return cast(ulong)(round((pow(state[0], n+1) - pow(state[1], n+1)) /
6736 state[2]));
6738 auto fib = sequence!computeFib(
6739 (1.0 + sqrt(5.0)) / 2.0, // Golden Ratio
6740 (1.0 - sqrt(5.0)) / 2.0, // Conjugate of Golden Ratio
6741 sqrt(5.0));
6743 // Note random access with [] operator
6744 assert(fib[1] == 1);
6745 assert(fib[4] == 5);
6746 assert(fib[3] == 3);
6747 assert(fib[2] == 2);
6748 assert(fib[9] == 55);
6751 pure @safe nothrow @nogc unittest
6753 import std.typecons : Tuple, tuple;
6754 auto y = Sequence!("a[0] + n * a[1]", Tuple!(int, int))(tuple(0, 4));
6755 static assert(isForwardRange!(typeof(y)));
6757 //@@BUG
6758 //auto y = sequence!("a[0] + n * a[1]")(0, 4);
6759 //foreach (e; take(y, 15))
6760 {} //writeln(e);
6762 auto odds = Sequence!("a[0] + n * a[1]", Tuple!(int, int))(
6763 tuple(1, 2));
6764 for (int currentOdd = 1; currentOdd <= 21; currentOdd += 2)
6766 assert(odds.front == odds[0]);
6767 assert(odds[0] == currentOdd);
6768 odds.popFront();
6772 pure @safe nothrow @nogc unittest
6774 import std.algorithm.comparison : equal;
6776 auto odds = sequence!("a[0] + n * a[1]")(1, 2);
6777 static assert(hasSlicing!(typeof(odds)));
6779 //Note: don't use drop or take as the target of an equal,
6780 //since they'll both just forward to opSlice, making the tests irrelevant
6782 // static slicing tests
6783 assert(equal(odds[0 .. 5], only(1, 3, 5, 7, 9)));
6784 assert(equal(odds[3 .. 7], only(7, 9, 11, 13)));
6786 // relative slicing test, testing slicing is NOT agnostic of state
6787 auto odds_less5 = odds.drop(5); //this should actually call odds[5 .. $]
6788 assert(equal(odds_less5[0 .. 3], only(11, 13, 15)));
6789 assert(equal(odds_less5[0 .. 10], odds[5 .. 15]));
6791 //Infinite slicing tests
6792 odds = odds[10 .. $];
6793 assert(equal(odds.take(3), only(21, 23, 25)));
6796 // https://issues.dlang.org/show_bug.cgi?id=5036
6797 pure @safe nothrow unittest
6799 auto s = sequence!((a, n) => new int)(0);
6800 assert(s.front != s.front); // no caching
6803 // iota
6805 Creates a range of values that span the given starting and stopping
6806 values.
6808 Params:
6809 begin = The starting value.
6810 end = The value that serves as the stopping criterion. This value is not
6811 included in the range.
6812 step = The value to add to the current value at each iteration.
6814 Returns:
6815 A range that goes through the numbers `begin`, $(D begin + step),
6816 $(D begin + 2 * step), `...`, up to and excluding `end`.
6818 The two-argument overloads have $(D step = 1). If $(D begin < end && step <
6819 0) or $(D begin > end && step > 0) or $(D begin == end), then an empty range
6820 is returned. If $(D step == 0) then $(D begin == end) is an error.
6822 For built-in types, the range returned is a random access range. For
6823 user-defined types that support `++`, the range is an input
6824 range.
6826 An integral iota also supports `in` operator from the right. It takes
6827 the stepping into account, the integral won't be considered
6828 contained if it falls between two consecutive values of the range.
6829 `contains` does the same as in, but from lefthand side.
6831 Example:
6833 void main()
6835 import std.stdio;
6837 // The following groups all produce the same output of:
6838 // 0 1 2 3 4
6840 foreach (i; 0 .. 5)
6841 writef("%s ", i);
6842 writeln();
6844 import std.range : iota;
6845 foreach (i; iota(0, 5))
6846 writef("%s ", i);
6847 writeln();
6849 writefln("%(%s %|%)", iota(0, 5));
6851 import std.algorithm.iteration : map;
6852 import std.algorithm.mutation : copy;
6853 import std.format;
6854 iota(0, 5).map!(i => format("%s ", i)).copy(stdout.lockingTextWriter());
6855 writeln();
6859 auto iota(B, E, S)(B begin, E end, S step)
6860 if ((isIntegral!(CommonType!(B, E)) || isPointer!(CommonType!(B, E)))
6861 && isIntegral!S)
6863 import std.conv : unsigned;
6865 alias Value = CommonType!(Unqual!B, Unqual!E);
6866 alias StepType = Unqual!S;
6868 assert(step != 0 || begin == end);
6870 static struct Result
6872 private Value current, last;
6873 private StepType step; // by convention, 0 if range is empty
6875 this(Value current, Value pastLast, StepType step)
6877 if (current < pastLast && step > 0)
6879 // Iterating upward
6880 assert(unsigned((pastLast - current) / step) <= size_t.max);
6881 // Cast below can't fail because current < pastLast
6882 this.last = cast(Value) (pastLast - 1);
6883 this.last -= unsigned(this.last - current) % step;
6885 else if (current > pastLast && step < 0)
6887 // Iterating downward
6888 assert(unsigned((current - pastLast) / (0 - step)) <= size_t.max);
6889 // Cast below can't fail because current > pastLast
6890 this.last = cast(Value) (pastLast + 1);
6891 this.last += unsigned(current - this.last) % (0 - step);
6893 else
6895 // Initialize an empty range
6896 this.step = 0;
6897 return;
6899 this.step = step;
6900 this.current = current;
6903 @property bool empty() const { return step == 0; }
6904 @property inout(Value) front() inout { assert(!empty); return current; }
6905 void popFront()
6907 assert(!empty);
6908 if (current == last) step = 0;
6909 else current += step;
6912 @property inout(Value) back() inout
6914 assert(!empty);
6915 return last;
6917 void popBack()
6919 assert(!empty);
6920 if (current == last) step = 0;
6921 else last -= step;
6924 @property auto save() { return this; }
6926 inout(Value) opIndex(ulong n) inout
6928 assert(n < this.length);
6930 // Just cast to Value here because doing so gives overflow behavior
6931 // consistent with calling popFront() n times.
6932 return cast(inout Value) (current + step * n);
6934 auto opBinaryRight(string op)(Value val) const
6935 if (op == "in")
6937 if (empty) return false;
6938 //cast to avoid becoming unsigned
6939 auto supposedIndex = cast(StepType)(val - current) / step;
6940 return supposedIndex < length && supposedIndex * step + current == val;
6942 auto contains(Value x){return x in this;}
6943 inout(Result) opSlice() inout { return this; }
6944 inout(Result) opSlice(ulong lower, ulong upper) inout
6946 assert(upper >= lower && upper <= this.length);
6948 return cast(inout Result) Result(
6949 cast(Value)(current + lower * step),
6950 cast(Value)(current + upper * step),
6951 step);
6953 @property size_t length() const
6955 if (step > 0)
6956 return 1 + cast(size_t) (unsigned(last - current) / step);
6957 if (step < 0)
6958 return 1 + cast(size_t) (unsigned(current - last) / (0 - step));
6959 return 0;
6962 alias opDollar = length;
6965 return Result(begin, end, step);
6968 /// Ditto
6969 auto iota(B, E)(B begin, E end)
6970 if (isFloatingPoint!(CommonType!(B, E)))
6972 return iota(begin, end, CommonType!(B, E)(1));
6975 /// Ditto
6976 auto iota(B, E)(B begin, E end)
6977 if (isIntegral!(CommonType!(B, E)) || isPointer!(CommonType!(B, E)))
6979 import std.conv : unsigned;
6981 alias Value = CommonType!(Unqual!B, Unqual!E);
6983 static struct Result
6985 private Value current, pastLast;
6987 this(Value current, Value pastLast)
6989 if (current < pastLast)
6991 assert(unsigned(pastLast - current) <= size_t.max,
6992 "`iota` range is too long");
6994 this.current = current;
6995 this.pastLast = pastLast;
6997 else
6999 // Initialize an empty range
7000 this.current = this.pastLast = current;
7004 @property bool empty() const { return current == pastLast; }
7005 @property inout(Value) front() inout
7007 assert(!empty, "Attempt to access `front` of empty `iota` range");
7008 return current;
7010 void popFront()
7012 assert(!empty, "Attempt to `popFront` of empty `iota` range");
7013 ++current;
7016 @property inout(Value) back() inout
7018 assert(!empty, "Attempt to access `back` of empty `iota` range");
7019 return cast(inout(Value))(pastLast - 1);
7021 void popBack()
7023 assert(!empty, "Attempt to `popBack` of empty `iota` range");
7024 --pastLast;
7027 @property auto save() { return this; }
7029 inout(Value) opIndex(size_t n) inout
7031 assert(n < this.length,
7032 "Attempt to read out-of-bounds index of `iota` range");
7034 // Just cast to Value here because doing so gives overflow behavior
7035 // consistent with calling popFront() n times.
7036 return cast(inout Value) (current + n);
7038 auto opBinaryRight(string op)(Value val) const
7039 if (op == "in")
7041 return current <= val && val < pastLast;
7043 auto contains(Value x){return x in this;}
7044 inout(Result) opSlice() inout { return this; }
7045 inout(Result) opSlice(ulong lower, ulong upper) inout
7047 assert(upper >= lower && upper <= this.length,
7048 "Attempt to get out-of-bounds slice of `iota` range");
7050 return cast(inout Result) Result(cast(Value)(current + lower),
7051 cast(Value)(pastLast - (length - upper)));
7053 @property size_t length() const
7055 return cast(size_t)(pastLast - current);
7058 alias opDollar = length;
7061 return Result(begin, end);
7064 /// Ditto
7065 auto iota(E)(E end)
7066 if (is(typeof(iota(E(0), end))))
7068 E begin = E(0);
7069 return iota(begin, end);
7072 /// Ditto
7073 // Specialization for floating-point types
7074 auto iota(B, E, S)(B begin, E end, S step)
7075 if (isFloatingPoint!(CommonType!(B, E, S)))
7078 assert(step != 0, "iota: step must not be 0");
7079 assert((end - begin) / step >= 0, "iota: incorrect startup parameters");
7083 alias Value = Unqual!(CommonType!(B, E, S));
7084 static struct Result
7086 private Value start, step;
7087 private size_t index, count;
7089 this(Value start, Value end, Value step)
7091 import std.conv : to;
7093 this.start = start;
7094 this.step = step;
7095 immutable fcount = (end - start) / step;
7096 count = to!size_t(fcount);
7097 auto pastEnd = start + count * step;
7098 if (step > 0)
7100 if (pastEnd < end) ++count;
7101 assert(start + count * step >= end);
7103 else
7105 if (pastEnd > end) ++count;
7106 assert(start + count * step <= end);
7110 @property bool empty() const { return index == count; }
7111 @property Value front() const { assert(!empty); return start + step * index; }
7112 void popFront()
7114 assert(!empty);
7115 ++index;
7117 @property Value back() const
7119 assert(!empty);
7120 return start + step * (count - 1);
7122 void popBack()
7124 assert(!empty);
7125 --count;
7128 @property auto save() { return this; }
7130 Value opIndex(size_t n) const
7132 assert(n < count);
7133 return start + step * (n + index);
7135 inout(Result) opSlice() inout
7137 return this;
7139 inout(Result) opSlice(size_t lower, size_t upper) inout
7141 assert(upper >= lower && upper <= count);
7143 Result ret = this;
7144 ret.index += lower;
7145 ret.count = upper - lower + ret.index;
7146 return cast(inout Result) ret;
7148 @property size_t length() const
7150 return count - index;
7153 alias opDollar = length;
7156 return Result(begin, end, step);
7160 pure @safe unittest
7162 import std.algorithm.comparison : equal;
7163 import std.math.operations : isClose;
7165 auto r = iota(0, 10, 1);
7166 assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
7167 assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
7168 assert(3 in r);
7169 assert(r.contains(3)); //Same as above
7170 assert(!(10 in r));
7171 assert(!(-8 in r));
7172 r = iota(0, 11, 3);
7173 assert(equal(r, [0, 3, 6, 9]));
7174 assert(r[2] == 6);
7175 assert(!(2 in r));
7176 auto rf = iota(0.0, 0.5, 0.1);
7177 assert(isClose(rf, [0.0, 0.1, 0.2, 0.3, 0.4]));
7180 pure nothrow @nogc @safe unittest
7182 import std.traits : Signed;
7183 //float overloads use std.conv.to so can't be @nogc or nothrow
7184 alias ssize_t = Signed!size_t;
7185 assert(iota(ssize_t.max, 0, -1).length == ssize_t.max);
7186 assert(iota(ssize_t.max, ssize_t.min, -1).length == size_t.max);
7187 assert(iota(ssize_t.max, ssize_t.min, -2).length == 1 + size_t.max / 2);
7188 assert(iota(ssize_t.min, ssize_t.max, 2).length == 1 + size_t.max / 2);
7189 assert(iota(ssize_t.max, ssize_t.min, -3).length == size_t.max / 3);
7192 debug @system unittest
7193 {//check the contracts
7194 import core.exception : AssertError;
7195 import std.exception : assertThrown;
7196 assertThrown!AssertError(iota(1,2,0));
7197 assertThrown!AssertError(iota(0f,1f,0f));
7198 assertThrown!AssertError(iota(1f,0f,0.1f));
7199 assertThrown!AssertError(iota(0f,1f,-0.1f));
7202 pure @system nothrow unittest
7204 int[] a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
7205 auto r1 = iota(a.ptr, a.ptr + a.length, 1);
7206 assert(r1.front == a.ptr);
7207 assert(r1.back == a.ptr + a.length - 1);
7208 assert(&a[4] in r1);
7211 pure @safe nothrow @nogc unittest
7213 assert(iota(1UL, 0UL).length == 0);
7214 assert(iota(1UL, 0UL, 1).length == 0);
7215 assert(iota(0, 1, 1).length == 1);
7216 assert(iota(1, 0, -1).length == 1);
7217 assert(iota(0, 1, -1).length == 0);
7218 assert(iota(ulong.max, 0).length == 0);
7221 pure @safe unittest
7223 import std.algorithm.comparison : equal;
7224 import std.algorithm.searching : count;
7225 import std.math.operations : isClose, nextUp, nextDown;
7226 import std.meta : AliasSeq;
7228 static assert(is(ElementType!(typeof(iota(0f))) == float));
7230 static assert(hasLength!(typeof(iota(0, 2))));
7231 auto r = iota(0, 10, 1);
7232 assert(r[$ - 1] == 9);
7233 assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][]));
7235 auto rSlice = r[2 .. 8];
7236 assert(equal(rSlice, [2, 3, 4, 5, 6, 7]));
7238 rSlice.popFront();
7239 assert(rSlice[0] == rSlice.front);
7240 assert(rSlice.front == 3);
7242 rSlice.popBack();
7243 assert(rSlice[rSlice.length - 1] == rSlice.back);
7244 assert(rSlice.back == 6);
7246 rSlice = r[0 .. 4];
7247 assert(equal(rSlice, [0, 1, 2, 3]));
7248 assert(3 in rSlice);
7249 assert(!(4 in rSlice));
7251 auto rr = iota(10);
7252 assert(equal(rr, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][]));
7254 r = iota(0, -10, -1);
7255 assert(equal(r, [0, -1, -2, -3, -4, -5, -6, -7, -8, -9][]));
7256 rSlice = r[3 .. 9];
7257 assert(equal(rSlice, [-3, -4, -5, -6, -7, -8]));
7259 r = iota(0, -6, -3);
7260 assert(equal(r, [0, -3][]));
7261 rSlice = r[1 .. 2];
7262 assert(equal(rSlice, [-3]));
7264 r = iota(0, -7, -3);
7265 assert(equal(r, [0, -3, -6][]));
7266 assert(0 in r);
7267 assert(-6 in r);
7268 rSlice = r[1 .. 3];
7269 assert(equal(rSlice, [-3, -6]));
7270 assert(!(0 in rSlice));
7271 assert(!(-2 in rSlice));
7272 assert(!(-5 in rSlice));
7273 assert(!(3 in rSlice));
7274 assert(!(-9 in rSlice));
7276 r = iota(0, 11, 3);
7277 assert(equal(r, [0, 3, 6, 9][]));
7278 assert(r[2] == 6);
7279 rSlice = r[1 .. 3];
7280 assert(equal(rSlice, [3, 6]));
7282 auto rf = iota(0.0, 0.5, 0.1);
7283 assert(isClose(rf, [0.0, 0.1, 0.2, 0.3, 0.4][]));
7284 assert(rf.length == 5);
7286 rf.popFront();
7287 assert(rf.length == 4);
7289 auto rfSlice = rf[1 .. 4];
7290 assert(rfSlice.length == 3);
7291 assert(isClose(rfSlice, [0.2, 0.3, 0.4]));
7293 rfSlice.popFront();
7294 assert(isClose(rfSlice[0], 0.3));
7296 rf.popFront();
7297 assert(rf.length == 3);
7299 rfSlice = rf[1 .. 3];
7300 assert(rfSlice.length == 2);
7301 assert(isClose(rfSlice, [0.3, 0.4]));
7302 assert(isClose(rfSlice[0], 0.3));
7304 // With something just above 0.5
7305 rf = iota(0.0, nextUp(0.5), 0.1);
7306 assert(isClose(rf, [0.0, 0.1, 0.2, 0.3, 0.4, 0.5][]));
7307 rf.popBack();
7308 assert(rf[rf.length - 1] == rf.back);
7309 assert(isClose(rf.back, 0.4));
7310 assert(rf.length == 5);
7312 // going down
7313 rf = iota(0.0, -0.5, -0.1);
7314 assert(isClose(rf, [0.0, -0.1, -0.2, -0.3, -0.4][]));
7315 rfSlice = rf[2 .. 5];
7316 assert(isClose(rfSlice, [-0.2, -0.3, -0.4]));
7318 rf = iota(0.0, nextDown(-0.5), -0.1);
7319 assert(isClose(rf, [0.0, -0.1, -0.2, -0.3, -0.4, -0.5][]));
7321 // iota of longs
7322 auto rl = iota(5_000_000L);
7323 assert(rl.length == 5_000_000L);
7324 assert(0 in rl);
7325 assert(4_000_000L in rl);
7326 assert(!(-4_000_000L in rl));
7327 assert(!(5_000_000L in rl));
7329 // iota of longs with steps
7330 auto iota_of_longs_with_steps = iota(50L, 101L, 10);
7331 assert(iota_of_longs_with_steps.length == 6);
7332 assert(equal(iota_of_longs_with_steps, [50L, 60L, 70L, 80L, 90L, 100L]));
7334 // iota of unsigned zero length (https://issues.dlang.org/show_bug.cgi?id=6222)
7335 // Actually trying to consume it is the only way to find something is wrong
7336 // because the public properties are all correct.
7337 auto iota_zero_unsigned = iota(0, 0u, 3);
7338 assert(count(iota_zero_unsigned) == 0);
7340 // https://issues.dlang.org/show_bug.cgi?id=7982
7341 // unsigned reverse iota can be buggy if `.length` doesn't
7342 // take them into account
7343 assert(iota(10u, 0u, -1).length == 10);
7344 assert(iota(10u, 0u, -2).length == 5);
7345 assert(iota(uint.max, uint.max-10, -1).length == 10);
7346 assert(iota(uint.max, uint.max-10, -2).length == 5);
7347 assert(iota(uint.max, 0u, -1).length == uint.max);
7349 assert(20 in iota(20u, 10u, -2));
7350 assert(16 in iota(20u, 10u, -2));
7351 assert(!(15 in iota(20u, 10u, -2)));
7352 assert(!(10 in iota(20u, 10u, -2)));
7353 assert(!(uint.max in iota(20u, 10u, -1)));
7354 assert(!(int.min in iota(20u, 10u, -1)));
7355 assert(!(int.max in iota(20u, 10u, -1)));
7358 // https://issues.dlang.org/show_bug.cgi?id=8920
7359 static foreach (Type; AliasSeq!(byte, ubyte, short, ushort,
7360 int, uint, long, ulong))
7362 Type val;
7363 foreach (i; iota(cast(Type) 0, cast(Type) 10)) { val++; }
7364 assert(val == 10);
7368 pure @safe nothrow unittest
7370 import std.algorithm.mutation : copy;
7371 auto idx = new size_t[100];
7372 copy(iota(0, idx.length), idx);
7375 @safe unittest
7377 import std.meta : AliasSeq;
7378 static foreach (range; AliasSeq!(iota(2, 27, 4),
7379 iota(3, 9),
7380 iota(2.7, 12.3, .1),
7381 iota(3.2, 9.7)))
7383 const cRange = range;
7384 const e = cRange.empty;
7385 const f = cRange.front;
7386 const b = cRange.back;
7387 const i = cRange[2];
7388 const s1 = cRange[];
7389 const s2 = cRange[0 .. 3];
7390 const l = cRange.length;
7394 @system unittest
7396 //The ptr stuff can't be done at compile time, so we unfortunately end
7397 //up with some code duplication here.
7398 auto arr = [0, 5, 3, 5, 5, 7, 9, 2, 0, 42, 7, 6];
7401 const cRange = iota(arr.ptr, arr.ptr + arr.length, 3);
7402 const e = cRange.empty;
7403 const f = cRange.front;
7404 const b = cRange.back;
7405 const i = cRange[2];
7406 const s1 = cRange[];
7407 const s2 = cRange[0 .. 3];
7408 const l = cRange.length;
7412 const cRange = iota(arr.ptr, arr.ptr + arr.length);
7413 const e = cRange.empty;
7414 const f = cRange.front;
7415 const b = cRange.back;
7416 const i = cRange[2];
7417 const s1 = cRange[];
7418 const s2 = cRange[0 .. 3];
7419 const l = cRange.length;
7423 @nogc nothrow pure @safe unittest
7426 ushort start = 0, end = 10, step = 2;
7427 foreach (i; iota(start, end, step))
7428 static assert(is(typeof(i) == ushort));
7431 ubyte start = 0, end = 255, step = 128;
7432 uint x;
7433 foreach (i; iota(start, end, step))
7435 static assert(is(typeof(i) == ubyte));
7436 ++x;
7438 assert(x == 2);
7442 /* Generic overload that handles arbitrary types that support arithmetic
7443 * operations.
7445 * User-defined types such as $(REF BigInt, std,bigint) are also supported, as long
7446 * as they can be incremented with `++` and compared with `<` or `==`.
7448 /// ditto
7449 auto iota(B, E)(B begin, E end)
7450 if (!isIntegral!(CommonType!(B, E)) &&
7451 !isFloatingPoint!(CommonType!(B, E)) &&
7452 !isPointer!(CommonType!(B, E)) &&
7453 is(typeof((ref B b) { ++b; })) &&
7454 (is(typeof(B.init < E.init)) || is(typeof(B.init == E.init))) )
7456 static struct Result
7458 B current;
7459 E end;
7461 @property bool empty()
7463 static if (is(typeof(B.init < E.init)))
7464 return !(current < end);
7465 else static if (is(typeof(B.init != E.init)))
7466 return current == end;
7467 else
7468 static assert(0);
7470 @property auto front() { return current; }
7471 void popFront()
7473 assert(!empty);
7474 ++current;
7476 @property auto save() { return this; }
7478 return Result(begin, end);
7481 @safe unittest
7483 import std.algorithm.comparison : equal;
7485 // Test iota() for a type that only supports ++ and != but does not have
7486 // '<'-ordering.
7487 struct Cyclic(int wrapAround)
7489 int current;
7491 this(int start) { current = start % wrapAround; }
7493 bool opEquals(Cyclic c) const { return current == c.current; }
7494 bool opEquals(int i) const { return current == i; }
7495 void opUnary(string op)()
7496 if (op == "++")
7498 current = (current + 1) % wrapAround;
7501 alias Cycle5 = Cyclic!5;
7503 // Easy case
7504 auto i1 = iota(Cycle5(1), Cycle5(4));
7505 assert(i1.equal([1, 2, 3]));
7507 // Wraparound case
7508 auto i2 = iota(Cycle5(3), Cycle5(2));
7509 assert(i2.equal([3, 4, 0, 1 ]));
7512 // https://issues.dlang.org/show_bug.cgi?id=23453
7513 @safe unittest
7515 auto r = iota('a', 'z');
7516 static assert(isForwardRange!(typeof(r)));
7520 Options for the $(LREF FrontTransversal) and $(LREF Transversal) ranges
7521 (below).
7523 enum TransverseOptions
7526 When transversed, the elements of a range of ranges are assumed to
7527 have different lengths (e.g. a jagged array).
7529 assumeJagged, //default
7531 The transversal enforces that the elements of a range of ranges have
7532 all the same length (e.g. an array of arrays, all having the same
7533 length). Checking is done once upon construction of the transversal
7534 range.
7536 enforceNotJagged,
7538 The transversal assumes, without verifying, that the elements of a
7539 range of ranges have all the same length. This option is useful if
7540 checking was already done from the outside of the range.
7542 assumeNotJagged,
7546 @safe pure unittest
7548 import std.algorithm.comparison : equal;
7549 import std.exception : assertThrown;
7551 auto arr = [[1, 2], [3, 4, 5]];
7553 auto r1 = arr.frontTransversal!(TransverseOptions.assumeJagged);
7554 assert(r1.equal([1, 3]));
7556 // throws on construction
7557 assertThrown!Exception(arr.frontTransversal!(TransverseOptions.enforceNotJagged));
7559 auto r2 = arr.frontTransversal!(TransverseOptions.assumeNotJagged);
7560 assert(r2.equal([1, 3]));
7562 // either assuming or checking for equal lengths makes
7563 // the result a random access range
7564 assert(r2[0] == 1);
7565 static assert(!__traits(compiles, r1[0]));
7569 Given a range of ranges, iterate transversally through the first
7570 elements of each of the enclosed ranges.
7572 struct FrontTransversal(Ror,
7573 TransverseOptions opt = TransverseOptions.assumeJagged)
7575 alias RangeOfRanges = Unqual!(Ror);
7576 alias RangeType = .ElementType!RangeOfRanges;
7577 alias ElementType = .ElementType!RangeType;
7579 private void prime()
7581 static if (opt == TransverseOptions.assumeJagged)
7583 while (!_input.empty && _input.front.empty)
7585 _input.popFront();
7587 static if (isBidirectionalRange!RangeOfRanges)
7589 while (!_input.empty && _input.back.empty)
7591 _input.popBack();
7598 Construction from an input.
7600 this(RangeOfRanges input)
7602 _input = input;
7603 prime();
7604 static if (opt == TransverseOptions.enforceNotJagged)
7605 // (isRandomAccessRange!RangeOfRanges
7606 // && hasLength!RangeType)
7608 import std.exception : enforce;
7610 if (empty) return;
7611 immutable commonLength = _input.front.length;
7612 foreach (e; _input)
7614 enforce(e.length == commonLength);
7620 Forward range primitives.
7622 static if (isInfinite!RangeOfRanges)
7624 enum bool empty = false;
7626 else
7628 @property bool empty()
7630 static if (opt != TransverseOptions.assumeJagged)
7632 if (!_input.empty)
7633 return _input.front.empty;
7636 return _input.empty;
7640 /// Ditto
7641 @property auto ref front()
7643 assert(!empty, "Attempting to fetch the front of an empty FrontTransversal");
7644 return _input.front.front;
7647 /// Ditto
7648 static if (hasMobileElements!RangeType)
7650 ElementType moveFront()
7652 return _input.front.moveFront();
7656 static if (hasAssignableElements!RangeType)
7658 @property void front(ElementType val)
7660 import core.lifetime : forward;
7662 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
7663 _input.front.front = __ctfe ? val : forward!val;
7667 /// Ditto
7668 void popFront()
7670 assert(!empty, "Attempting to popFront an empty FrontTransversal");
7671 _input.popFront();
7672 prime();
7676 Duplicates this `frontTransversal`. Note that only the encapsulating
7677 range of range will be duplicated. Underlying ranges will not be
7678 duplicated.
7680 static if (isForwardRange!RangeOfRanges)
7682 @property FrontTransversal save()
7684 return FrontTransversal(_input.save);
7688 static if (isBidirectionalRange!RangeOfRanges)
7691 Bidirectional primitives. They are offered if $(D
7692 isBidirectionalRange!RangeOfRanges).
7694 @property auto ref back()
7696 assert(!empty, "Attempting to fetch the back of an empty FrontTransversal");
7697 return _input.back.front;
7699 /// Ditto
7700 void popBack()
7702 assert(!empty, "Attempting to popBack an empty FrontTransversal");
7703 _input.popBack();
7704 prime();
7707 /// Ditto
7708 static if (hasMobileElements!RangeType)
7710 ElementType moveBack()
7712 return _input.back.moveFront();
7716 static if (hasAssignableElements!RangeType)
7718 @property void back(ElementType val)
7720 import core.lifetime : forward;
7722 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
7723 _input.back.front = __ctfe ? val : forward!val;
7728 static if (isRandomAccessRange!RangeOfRanges &&
7729 (opt == TransverseOptions.assumeNotJagged ||
7730 opt == TransverseOptions.enforceNotJagged))
7733 Random-access primitive. It is offered if $(D
7734 isRandomAccessRange!RangeOfRanges && (opt ==
7735 TransverseOptions.assumeNotJagged || opt ==
7736 TransverseOptions.enforceNotJagged)).
7738 auto ref opIndex(size_t n)
7740 return _input[n].front;
7743 /// Ditto
7744 static if (hasMobileElements!RangeType)
7746 ElementType moveAt(size_t n)
7748 return _input[n].moveFront();
7751 /// Ditto
7752 static if (hasAssignableElements!RangeType)
7754 void opIndexAssign(ElementType val, size_t n)
7756 import core.lifetime : forward;
7758 // __ctfe check is workaround for https://issues.dlang.org/show_bug.cgi?id=21542
7759 _input[n].front = __ctfe ? val : forward!val;
7762 mixin ImplementLength!_input;
7765 Slicing if offered if `RangeOfRanges` supports slicing and all the
7766 conditions for supporting indexing are met.
7768 static if (hasSlicing!RangeOfRanges)
7770 typeof(this) opSlice(size_t lower, size_t upper)
7772 return typeof(this)(_input[lower .. upper]);
7777 auto opSlice() { return this; }
7779 private:
7780 RangeOfRanges _input;
7783 /// Ditto
7784 FrontTransversal!(RangeOfRanges, opt) frontTransversal(
7785 TransverseOptions opt = TransverseOptions.assumeJagged,
7786 RangeOfRanges)
7787 (RangeOfRanges rr)
7789 return typeof(return)(rr);
7793 pure @safe nothrow unittest
7795 import std.algorithm.comparison : equal;
7796 int[][] x = new int[][2];
7797 x[0] = [1, 2];
7798 x[1] = [3, 4];
7799 auto ror = frontTransversal(x);
7800 assert(equal(ror, [ 1, 3 ][]));
7803 @safe unittest
7805 import std.algorithm.comparison : equal;
7806 import std.internal.test.dummyrange : AllDummyRanges, DummyRange, ReturnBy;
7808 static assert(is(FrontTransversal!(immutable int[][])));
7810 foreach (DummyType; AllDummyRanges)
7812 auto dummies =
7813 [DummyType.init, DummyType.init, DummyType.init, DummyType.init];
7815 foreach (i, ref elem; dummies)
7817 // Just violate the DummyRange abstraction to get what I want.
7818 elem.arr = elem.arr[i..$ - (3 - i)];
7821 auto ft = frontTransversal!(TransverseOptions.assumeNotJagged)(dummies);
7822 static if (isForwardRange!DummyType)
7824 static assert(isForwardRange!(typeof(ft)));
7827 assert(equal(ft, [1, 2, 3, 4]));
7829 // Test slicing.
7830 assert(equal(ft[0 .. 2], [1, 2]));
7831 assert(equal(ft[1 .. 3], [2, 3]));
7833 assert(ft.front == ft.moveFront());
7834 assert(ft.back == ft.moveBack());
7835 assert(ft.moveAt(1) == ft[1]);
7838 // Test infiniteness propagation.
7839 static assert(isInfinite!(typeof(frontTransversal(repeat("foo")))));
7841 static if (DummyType.r == ReturnBy.Reference)
7844 ft.front++;
7845 scope(exit) ft.front--;
7846 assert(dummies.front.front == 2);
7850 ft.front = 5;
7851 scope(exit) ft.front = 1;
7852 assert(dummies[0].front == 5);
7856 ft.back = 88;
7857 scope(exit) ft.back = 4;
7858 assert(dummies.back.front == 88);
7862 ft[1] = 99;
7863 scope(exit) ft[1] = 2;
7864 assert(dummies[1].front == 99);
7870 // https://issues.dlang.org/show_bug.cgi?id=16363
7871 pure @safe nothrow unittest
7873 import std.algorithm.comparison : equal;
7875 int[][] darr = [[0, 1], [4, 5]];
7876 auto ft = frontTransversal!(TransverseOptions.assumeNotJagged)(darr);
7878 assert(equal(ft, [0, 4]));
7879 static assert(isRandomAccessRange!(typeof(ft)));
7882 // https://issues.dlang.org/show_bug.cgi?id=16442
7883 pure @safe nothrow unittest
7885 int[][] arr = [[], []];
7887 auto ft = frontTransversal!(TransverseOptions.assumeNotJagged)(arr);
7888 assert(ft.empty);
7891 // ditto
7892 pure @safe unittest
7894 int[][] arr = [[], []];
7896 auto ft = frontTransversal!(TransverseOptions.enforceNotJagged)(arr);
7897 assert(ft.empty);
7900 // https://issues.dlang.org/show_bug.cgi?id=24481
7901 @safe unittest
7903 bool called;
7904 struct Handle
7906 int entry;
7907 void opAssign()(auto ref const(typeof(this)) that) const { called = true; }
7910 const(Handle)[][] arr = [[Handle(0), Handle(10)],
7911 [Handle(1), Handle(11)],
7912 [Handle(2), Handle(12)],
7913 [Handle(3), Handle(13)],
7914 [Handle(4), Handle(14)]];
7917 auto range = arr.frontTransversal();
7919 called = false;
7920 range.front = Handle(42);
7921 assert(called == true);
7923 called = false;
7924 range.back = Handle(42);
7925 assert(called == true);
7928 auto range = arr.frontTransversal!(TransverseOptions.assumeNotJagged)();
7930 called = false;
7931 range.front = Handle(42);
7932 assert(called == true);
7934 called = false;
7935 range.back = Handle(42);
7936 assert(called == true);
7938 called = false;
7939 range[0] = Handle(42);
7940 assert(called == true);
7945 Given a range of ranges, iterate transversally through the
7946 `n`th element of each of the enclosed ranges. This function
7947 is similar to `unzip` in other languages.
7949 Params:
7950 opt = Controls the assumptions the function makes about the lengths
7951 of the ranges
7952 rr = An input range of random access ranges
7953 Returns:
7954 At minimum, an input range. Range primitives such as bidirectionality
7955 and random access are given if the element type of `rr` provides them.
7957 struct Transversal(Ror,
7958 TransverseOptions opt = TransverseOptions.assumeJagged)
7960 private alias RangeOfRanges = Unqual!Ror;
7961 private alias InnerRange = ElementType!RangeOfRanges;
7962 private alias E = ElementType!InnerRange;
7964 private void prime()
7966 static if (opt == TransverseOptions.assumeJagged)
7968 while (!_input.empty && _input.front.length <= _n)
7970 _input.popFront();
7972 static if (isBidirectionalRange!RangeOfRanges)
7974 while (!_input.empty && _input.back.length <= _n)
7976 _input.popBack();
7983 Construction from an input and an index.
7985 this(RangeOfRanges input, size_t n)
7987 _input = input;
7988 _n = n;
7989 prime();
7990 static if (opt == TransverseOptions.enforceNotJagged)
7992 import std.exception : enforce;
7994 if (empty) return;
7995 immutable commonLength = _input.front.length;
7996 foreach (e; _input)
7998 enforce(e.length == commonLength);
8004 Forward range primitives.
8006 static if (isInfinite!(RangeOfRanges))
8008 enum bool empty = false;
8010 else
8012 @property bool empty()
8014 return _input.empty;
8018 /// Ditto
8019 @property auto ref front()
8021 assert(!empty, "Attempting to fetch the front of an empty Transversal");
8022 return _input.front[_n];
8025 /// Ditto
8026 static if (hasMobileElements!InnerRange)
8028 E moveFront()
8030 return _input.front.moveAt(_n);
8034 /// Ditto
8035 static if (hasAssignableElements!InnerRange)
8037 @property void front(E val)
8039 _input.front[_n] = val;
8044 /// Ditto
8045 void popFront()
8047 assert(!empty, "Attempting to popFront an empty Transversal");
8048 _input.popFront();
8049 prime();
8052 /// Ditto
8053 static if (isForwardRange!RangeOfRanges)
8055 @property typeof(this) save()
8057 auto ret = this;
8058 ret._input = _input.save;
8059 return ret;
8063 static if (isBidirectionalRange!RangeOfRanges)
8066 Bidirectional primitives. They are offered if $(D
8067 isBidirectionalRange!RangeOfRanges).
8069 @property auto ref back()
8071 assert(!empty, "Attempting to fetch the back of an empty Transversal");
8072 return _input.back[_n];
8075 /// Ditto
8076 void popBack()
8078 assert(!empty, "Attempting to popBack an empty Transversal");
8079 _input.popBack();
8080 prime();
8083 /// Ditto
8084 static if (hasMobileElements!InnerRange)
8086 E moveBack()
8088 return _input.back.moveAt(_n);
8092 /// Ditto
8093 static if (hasAssignableElements!InnerRange)
8095 @property void back(E val)
8097 _input.back[_n] = val;
8103 static if (isRandomAccessRange!RangeOfRanges &&
8104 (opt == TransverseOptions.assumeNotJagged ||
8105 opt == TransverseOptions.enforceNotJagged))
8108 Random-access primitive. It is offered if $(D
8109 isRandomAccessRange!RangeOfRanges && (opt ==
8110 TransverseOptions.assumeNotJagged || opt ==
8111 TransverseOptions.enforceNotJagged)).
8113 auto ref opIndex(size_t n)
8115 return _input[n][_n];
8118 /// Ditto
8119 static if (hasMobileElements!InnerRange)
8121 E moveAt(size_t n)
8123 return _input[n].moveAt(_n);
8127 /// Ditto
8128 static if (hasAssignableElements!InnerRange)
8130 void opIndexAssign(E val, size_t n)
8132 _input[n][_n] = val;
8136 mixin ImplementLength!_input;
8139 Slicing if offered if `RangeOfRanges` supports slicing and all the
8140 conditions for supporting indexing are met.
8142 static if (hasSlicing!RangeOfRanges)
8144 typeof(this) opSlice(size_t lower, size_t upper)
8146 return typeof(this)(_input[lower .. upper], _n);
8151 auto opSlice() { return this; }
8153 private:
8154 RangeOfRanges _input;
8155 size_t _n;
8158 /// Ditto
8159 Transversal!(RangeOfRanges, opt) transversal
8160 (TransverseOptions opt = TransverseOptions.assumeJagged, RangeOfRanges)
8161 (RangeOfRanges rr, size_t n)
8163 return typeof(return)(rr, n);
8167 @safe unittest
8169 import std.algorithm.comparison : equal;
8170 int[][] x = new int[][2];
8171 x[0] = [1, 2];
8172 x[1] = [3, 4];
8173 auto ror = transversal(x, 1);
8174 assert(equal(ror, [ 2, 4 ]));
8177 /// The following code does a full unzip
8178 @safe unittest
8180 import std.algorithm.comparison : equal;
8181 import std.algorithm.iteration : map;
8182 int[][] y = [[1, 2, 3], [4, 5, 6]];
8183 auto z = y.front.walkLength.iota.map!(i => transversal(y, i));
8184 assert(equal!equal(z, [[1, 4], [2, 5], [3, 6]]));
8187 @safe unittest
8189 import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy;
8191 int[][] x = new int[][2];
8192 x[0] = [ 1, 2 ];
8193 x[1] = [3, 4];
8194 auto ror = transversal!(TransverseOptions.assumeNotJagged)(x, 1);
8195 auto witness = [ 2, 4 ];
8196 uint i;
8197 foreach (e; ror) assert(e == witness[i++]);
8198 assert(i == 2);
8199 assert(ror.length == 2);
8201 static assert(is(Transversal!(immutable int[][])));
8203 // Make sure ref, assign is being propagated.
8205 ror.front++;
8206 scope(exit) ror.front--;
8207 assert(x[0][1] == 3);
8210 ror.front = 5;
8211 scope(exit) ror.front = 2;
8212 assert(x[0][1] == 5);
8213 assert(ror.moveFront() == 5);
8216 ror.back = 999;
8217 scope(exit) ror.back = 4;
8218 assert(x[1][1] == 999);
8219 assert(ror.moveBack() == 999);
8222 ror[0] = 999;
8223 scope(exit) ror[0] = 2;
8224 assert(x[0][1] == 999);
8225 assert(ror.moveAt(0) == 999);
8228 // Test w/o ref return.
8229 alias D = DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random);
8230 auto drs = [D.init, D.init];
8231 foreach (num; 0 .. 10)
8233 auto t = transversal!(TransverseOptions.enforceNotJagged)(drs, num);
8234 assert(t[0] == t[1]);
8235 assert(t[1] == num + 1);
8238 static assert(isInfinite!(typeof(transversal(repeat([1,2,3]), 1))));
8240 // Test slicing.
8241 auto mat = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]];
8242 auto mat1 = transversal!(TransverseOptions.assumeNotJagged)(mat, 1)[1 .. 3];
8243 assert(mat1[0] == 6);
8244 assert(mat1[1] == 10);
8247 struct Transposed(RangeOfRanges,
8248 TransverseOptions opt = TransverseOptions.assumeJagged)
8249 if (isForwardRange!RangeOfRanges &&
8250 isInputRange!(ElementType!RangeOfRanges) &&
8251 hasAssignableElements!RangeOfRanges)
8253 this(RangeOfRanges input)
8255 this._input = input;
8256 static if (opt == TransverseOptions.enforceNotJagged)
8258 import std.exception : enforce;
8260 if (empty) return;
8261 immutable commonLength = _input.front.length;
8262 foreach (e; _input)
8264 enforce(e.length == commonLength);
8269 @property auto front()
8271 import std.algorithm.iteration : filter, map;
8272 return _input.save
8273 .filter!(a => !a.empty)
8274 .map!(a => a.front);
8277 void popFront()
8279 // Advance the position of each subrange.
8280 auto r = _input.save;
8281 while (!r.empty)
8283 auto e = r.front;
8284 if (!e.empty)
8286 e.popFront();
8287 r.front = e;
8290 r.popFront();
8294 static if (isRandomAccessRange!(ElementType!RangeOfRanges))
8296 auto ref opIndex(size_t n)
8298 return transversal!opt(_input, n);
8302 @property bool empty()
8304 if (_input.empty) return true;
8305 foreach (e; _input.save)
8307 if (!e.empty) return false;
8309 return true;
8312 auto opSlice() { return this; }
8314 private:
8315 RangeOfRanges _input;
8318 @safe unittest
8320 // Boundary case: transpose of empty range should be empty
8321 int[][] ror = [];
8322 assert(transposed(ror).empty);
8325 // https://issues.dlang.org/show_bug.cgi?id=9507
8326 @safe unittest
8328 import std.algorithm.comparison : equal;
8330 auto r = [[1,2], [3], [4,5], [], [6]];
8331 assert(r.transposed.equal!equal([
8332 [1, 3, 4, 6],
8333 [2, 5]
8334 ]));
8337 // https://issues.dlang.org/show_bug.cgi?id=17742
8338 @safe unittest
8340 import std.algorithm.iteration : map;
8341 import std.algorithm.comparison : equal;
8342 auto ror = 5.iota.map!(y => 5.iota.map!(x => x * y).array).array;
8343 assert(ror[3][2] == 6);
8344 auto result = transposed!(TransverseOptions.assumeNotJagged)(ror);
8345 assert(result[2][3] == 6);
8347 auto x = [[1,2,3],[4,5,6]];
8348 auto y = transposed!(TransverseOptions.assumeNotJagged)(x);
8349 assert(y.front.equal([1,4]));
8350 assert(y[0].equal([1,4]));
8351 assert(y[0][0] == 1);
8352 assert(y[1].equal([2,5]));
8353 assert(y[1][1] == 5);
8355 auto yy = transposed!(TransverseOptions.enforceNotJagged)(x);
8356 assert(yy.front.equal([1,4]));
8357 assert(yy[0].equal([1,4]));
8358 assert(yy[0][0] == 1);
8359 assert(yy[1].equal([2,5]));
8360 assert(yy[1][1] == 5);
8362 auto z = x.transposed; // assumeJagged
8363 assert(z.front.equal([1,4]));
8364 assert(z[0].equal([1,4]));
8365 assert(!is(typeof(z[0][0])));
8368 @safe unittest
8370 import std.exception : assertThrown;
8372 auto r = [[1,2], [3], [4,5], [], [6]];
8373 assertThrown(r.transposed!(TransverseOptions.enforceNotJagged));
8377 Given a range of ranges, returns a range of ranges where the $(I i)'th subrange
8378 contains the $(I i)'th elements of the original subranges.
8380 Params:
8381 opt = Controls the assumptions the function makes about the lengths of the ranges (i.e. jagged or not)
8382 rr = Range of ranges
8384 Transposed!(RangeOfRanges, opt) transposed
8385 (TransverseOptions opt = TransverseOptions.assumeJagged, RangeOfRanges)
8386 (RangeOfRanges rr)
8387 if (isForwardRange!RangeOfRanges &&
8388 isInputRange!(ElementType!RangeOfRanges) &&
8389 hasAssignableElements!RangeOfRanges)
8391 return Transposed!(RangeOfRanges, opt)(rr);
8395 @safe unittest
8397 import std.algorithm.comparison : equal;
8398 int[][] ror = [
8399 [1, 2, 3],
8400 [4, 5, 6]
8402 auto xp = transposed(ror);
8403 assert(equal!"a.equal(b)"(xp, [
8404 [1, 4],
8405 [2, 5],
8406 [3, 6]
8407 ]));
8411 @safe unittest
8413 int[][] x = new int[][2];
8414 x[0] = [1, 2];
8415 x[1] = [3, 4];
8416 auto tr = transposed(x);
8417 int[][] witness = [ [ 1, 3 ], [ 2, 4 ] ];
8418 uint i;
8420 foreach (e; tr)
8422 assert(array(e) == witness[i++]);
8426 // https://issues.dlang.org/show_bug.cgi?id=8764
8427 @safe unittest
8429 import std.algorithm.comparison : equal;
8430 ulong[] t0 = [ 123 ];
8432 assert(!hasAssignableElements!(typeof(t0[].chunks(1))));
8433 assert(!is(typeof(transposed(t0[].chunks(1)))));
8434 assert(is(typeof(transposed(t0[].chunks(1).array()))));
8436 auto t1 = transposed(t0[].chunks(1).array());
8437 assert(equal!"a.equal(b)"(t1, [[123]]));
8441 This struct takes two ranges, `source` and `indices`, and creates a view
8442 of `source` as if its elements were reordered according to `indices`.
8443 `indices` may include only a subset of the elements of `source` and
8444 may also repeat elements.
8446 `Source` must be a random access range. The returned range will be
8447 bidirectional or random-access if `Indices` is bidirectional or
8448 random-access, respectively.
8450 struct Indexed(Source, Indices)
8451 if (isRandomAccessRange!Source && isInputRange!Indices &&
8452 is(typeof(Source.init[ElementType!(Indices).init])))
8454 this(Source source, Indices indices)
8456 this._source = source;
8457 this._indices = indices;
8460 /// Range primitives
8461 @property auto ref front()
8463 assert(!empty, "Attempting to fetch the front of an empty Indexed");
8464 return _source[_indices.front];
8467 /// Ditto
8468 void popFront()
8470 assert(!empty, "Attempting to popFront an empty Indexed");
8471 _indices.popFront();
8474 static if (isInfinite!Indices)
8476 enum bool empty = false;
8478 else
8480 /// Ditto
8481 @property bool empty()
8483 return _indices.empty;
8487 static if (isForwardRange!Indices)
8489 /// Ditto
8490 @property typeof(this) save()
8492 // Don't need to save _source because it's never consumed.
8493 return typeof(this)(_source, _indices.save);
8497 /// Ditto
8498 static if (hasAssignableElements!Source)
8500 @property auto ref front(ElementType!Source newVal)
8502 assert(!empty);
8503 return _source[_indices.front] = newVal;
8508 static if (hasMobileElements!Source)
8510 /// Ditto
8511 auto moveFront()
8513 assert(!empty);
8514 return _source.moveAt(_indices.front);
8518 static if (isBidirectionalRange!Indices)
8520 /// Ditto
8521 @property auto ref back()
8523 assert(!empty, "Attempting to fetch the back of an empty Indexed");
8524 return _source[_indices.back];
8527 /// Ditto
8528 void popBack()
8530 assert(!empty, "Attempting to popBack an empty Indexed");
8531 _indices.popBack();
8534 /// Ditto
8535 static if (hasAssignableElements!Source)
8537 @property auto ref back(ElementType!Source newVal)
8539 assert(!empty);
8540 return _source[_indices.back] = newVal;
8545 static if (hasMobileElements!Source)
8547 /// Ditto
8548 auto moveBack()
8550 assert(!empty);
8551 return _source.moveAt(_indices.back);
8556 mixin ImplementLength!_indices;
8558 static if (isRandomAccessRange!Indices)
8560 /// Ditto
8561 auto ref opIndex(size_t index)
8563 return _source[_indices[index]];
8566 static if (hasSlicing!Indices)
8568 /// Ditto
8569 typeof(this) opSlice(size_t a, size_t b)
8571 return typeof(this)(_source, _indices[a .. b]);
8576 static if (hasAssignableElements!Source)
8578 /// Ditto
8579 auto opIndexAssign(ElementType!Source newVal, size_t index)
8581 return _source[_indices[index]] = newVal;
8586 static if (hasMobileElements!Source)
8588 /// Ditto
8589 auto moveAt(size_t index)
8591 return _source.moveAt(_indices[index]);
8596 // All this stuff is useful if someone wants to index an Indexed
8597 // without adding a layer of indirection.
8600 Returns the source range.
8602 @property Source source()
8604 return _source;
8608 Returns the indices range.
8610 @property Indices indices()
8612 return _indices;
8615 static if (isRandomAccessRange!Indices)
8618 Returns the physical index into the source range corresponding to a
8619 given logical index. This is useful, for example, when indexing
8620 an `Indexed` without adding another layer of indirection.
8622 size_t physicalIndex(size_t logicalIndex)
8624 return _indices[logicalIndex];
8628 @safe unittest
8630 auto ind = indexed([1, 2, 3, 4, 5], [1, 3, 4]);
8631 assert(ind.physicalIndex(0) == 1);
8635 private:
8636 Source _source;
8637 Indices _indices;
8641 /// Ditto
8642 Indexed!(Source, Indices) indexed(Source, Indices)(Source source, Indices indices)
8644 return typeof(return)(source, indices);
8648 @safe unittest
8650 import std.algorithm.comparison : equal;
8651 auto source = [1, 2, 3, 4, 5];
8652 auto indices = [4, 3, 1, 2, 0, 4];
8653 auto ind = indexed(source, indices);
8654 assert(equal(ind, [5, 4, 2, 3, 1, 5]));
8655 assert(equal(retro(ind), [5, 1, 3, 2, 4, 5]));
8658 @safe unittest
8661 auto ind = indexed([1, 2, 3, 4, 5], [1, 3, 4]);
8662 assert(ind.physicalIndex(0) == 1);
8665 auto source = [1, 2, 3, 4, 5];
8666 auto indices = [4, 3, 1, 2, 0, 4];
8667 auto ind = indexed(source, indices);
8669 // When elements of indices are duplicated and Source has lvalue elements,
8670 // these are aliased in ind.
8671 ind[0]++;
8672 assert(ind[0] == 6);
8673 assert(ind[5] == 6);
8676 @safe unittest
8678 import std.internal.test.dummyrange : AllDummyRanges, propagatesLength,
8679 propagatesRangeType, RangeType;
8681 foreach (DummyType; AllDummyRanges)
8683 auto d = DummyType.init;
8684 auto r = indexed([1, 2, 3, 4, 5], d);
8685 static assert(propagatesRangeType!(DummyType, typeof(r)));
8686 static assert(propagatesLength!(DummyType, typeof(r)));
8691 This range iterates over fixed-sized chunks of size `chunkSize` of a
8692 `source` range. `Source` must be an $(REF_ALTTEXT input range, isInputRange, std,range,primitives).
8693 `chunkSize` must be greater than zero.
8695 If `!isInfinite!Source` and `source.walkLength` is not evenly
8696 divisible by `chunkSize`, the back element of this range will contain
8697 fewer than `chunkSize` elements.
8699 If `Source` is a forward range, the resulting range will be forward ranges as
8700 well. Otherwise, the resulting chunks will be input ranges consuming the same
8701 input: iterating over `front` will shrink the chunk such that subsequent
8702 invocations of `front` will no longer return the full chunk, and calling
8703 `popFront` on the outer range will invalidate any lingering references to
8704 previous values of `front`.
8706 Params:
8707 source = Range from which the chunks will be selected
8708 chunkSize = Chunk size
8710 See_Also: $(LREF slide)
8712 Returns: Range of chunks.
8714 struct Chunks(Source)
8715 if (isInputRange!Source)
8717 static if (isForwardRange!Source)
8719 /// Standard constructor
8720 this(Source source, size_t chunkSize)
8722 assert(chunkSize != 0, "Cannot create a Chunk with an empty chunkSize");
8723 _source = source;
8724 _chunkSize = chunkSize;
8727 /// Input range primitives. Always present.
8728 @property auto front()
8730 assert(!empty, "Attempting to fetch the front of an empty Chunks");
8731 return _source.save.take(_chunkSize);
8734 /// Ditto
8735 void popFront()
8737 assert(!empty, "Attempting to popFront and empty Chunks");
8738 _source.popFrontN(_chunkSize);
8741 static if (!isInfinite!Source)
8742 /// Ditto
8743 @property bool empty()
8745 return _source.empty;
8747 else
8748 // undocumented
8749 enum empty = false;
8751 /// Forward range primitives. Only present if `Source` is a forward range.
8752 @property typeof(this) save()
8754 return typeof(this)(_source.save, _chunkSize);
8757 static if (hasLength!Source)
8759 /// Length. Only if `hasLength!Source` is `true`
8760 @property size_t length()
8762 // Note: _source.length + _chunkSize may actually overflow.
8763 // We cast to ulong to mitigate the problem on x86 machines.
8764 // For x64 machines, we just suppose we'll never overflow.
8765 // The "safe" code would require either an extra branch, or a
8766 // modulo operation, which is too expensive for such a rare case
8767 return cast(size_t)((cast(ulong)(_source.length) + _chunkSize - 1) / _chunkSize);
8769 //Note: No point in defining opDollar here without slicing.
8770 //opDollar is defined below in the hasSlicing!Source section
8773 static if (hasSlicing!Source)
8775 //Used for various purposes
8776 private enum hasSliceToEnd = is(typeof(Source.init[_chunkSize .. $]) == Source);
8779 Indexing and slicing operations. Provided only if
8780 `hasSlicing!Source` is `true`.
8782 auto opIndex(size_t index)
8784 immutable start = index * _chunkSize;
8785 immutable end = start + _chunkSize;
8787 static if (isInfinite!Source)
8788 return _source[start .. end];
8789 else
8791 import std.algorithm.comparison : min;
8792 immutable len = _source.length;
8793 assert(start < len, "chunks index out of bounds");
8794 return _source[start .. min(end, len)];
8798 /// Ditto
8799 static if (hasLength!Source)
8800 typeof(this) opSlice(size_t lower, size_t upper)
8802 import std.algorithm.comparison : min;
8803 assert(lower <= upper && upper <= length, "chunks slicing index out of bounds");
8804 immutable len = _source.length;
8805 return chunks(_source[min(lower * _chunkSize, len) .. min(upper * _chunkSize, len)], _chunkSize);
8807 else static if (hasSliceToEnd)
8808 //For slicing an infinite chunk, we need to slice the source to the end.
8809 typeof(takeExactly(this, 0)) opSlice(size_t lower, size_t upper)
8811 assert(lower <= upper, "chunks slicing index out of bounds");
8812 return chunks(_source[lower * _chunkSize .. $], _chunkSize).takeExactly(upper - lower);
8815 static if (isInfinite!Source)
8817 static if (hasSliceToEnd)
8819 private static struct DollarToken{}
8820 DollarToken opDollar()
8822 return DollarToken();
8824 //Slice to dollar
8825 typeof(this) opSlice(size_t lower, DollarToken)
8827 return typeof(this)(_source[lower * _chunkSize .. $], _chunkSize);
8831 else
8833 //Dollar token carries a static type, with no extra information.
8834 //It can lazily transform into _source.length on algorithmic
8835 //operations such as : chunks[$/2, $-1];
8836 private static struct DollarToken
8838 Chunks!Source* mom;
8839 @property size_t momLength()
8841 return mom.length;
8843 alias momLength this;
8845 DollarToken opDollar()
8847 return DollarToken(&this);
8850 //Slice overloads optimized for using dollar. Without this, to slice to end, we would...
8851 //1. Evaluate chunks.length
8852 //2. Multiply by _chunksSize
8853 //3. To finally just compare it (with min) to the original length of source (!)
8854 //These overloads avoid that.
8855 typeof(this) opSlice(DollarToken, DollarToken)
8857 static if (hasSliceToEnd)
8858 return chunks(_source[$ .. $], _chunkSize);
8859 else
8861 immutable len = _source.length;
8862 return chunks(_source[len .. len], _chunkSize);
8865 typeof(this) opSlice(size_t lower, DollarToken)
8867 import std.algorithm.comparison : min;
8868 assert(lower <= length, "chunks slicing index out of bounds");
8869 static if (hasSliceToEnd)
8870 return chunks(_source[min(lower * _chunkSize, _source.length) .. $], _chunkSize);
8871 else
8873 immutable len = _source.length;
8874 return chunks(_source[min(lower * _chunkSize, len) .. len], _chunkSize);
8877 typeof(this) opSlice(DollarToken, size_t upper)
8879 assert(upper == length, "chunks slicing index out of bounds");
8880 return this[$ .. $];
8885 //Bidirectional range primitives
8886 static if (hasSlicing!Source && hasLength!Source)
8889 Bidirectional range primitives. Provided only if both
8890 `hasSlicing!Source` and `hasLength!Source` are `true`.
8892 @property auto back()
8894 assert(!empty, "back called on empty chunks");
8895 immutable len = _source.length;
8896 immutable start = (len - 1) / _chunkSize * _chunkSize;
8897 return _source[start .. len];
8900 /// Ditto
8901 void popBack()
8903 assert(!empty, "popBack() called on empty chunks");
8904 immutable end = (_source.length - 1) / _chunkSize * _chunkSize;
8905 _source = _source[0 .. end];
8909 private:
8910 Source _source;
8911 size_t _chunkSize;
8913 else // is input range only
8915 import std.typecons : RefCounted;
8917 static struct Chunk
8919 private RefCounted!Impl impl;
8921 @property bool empty() { return impl.curSizeLeft == 0 || impl.r.empty; }
8922 @property auto front() { return impl.r.front; }
8923 void popFront()
8925 assert(impl.curSizeLeft > 0 && !impl.r.empty);
8926 impl.curSizeLeft--;
8927 impl.r.popFront();
8931 static struct Impl
8933 private Source r;
8934 private size_t chunkSize;
8935 private size_t curSizeLeft;
8938 private RefCounted!Impl impl;
8940 private this(Source r, size_t chunkSize)
8942 impl = RefCounted!Impl(r, r.empty ? 0 : chunkSize, chunkSize);
8945 @property bool empty() { return impl.chunkSize == 0; }
8946 @property Chunk front() return { return Chunk(impl); }
8948 void popFront()
8950 impl.curSizeLeft -= impl.r.popFrontN(impl.curSizeLeft);
8951 if (!impl.r.empty)
8952 impl.curSizeLeft = impl.chunkSize;
8953 else
8954 impl.chunkSize = 0;
8957 static assert(isInputRange!(typeof(this)));
8961 /// Ditto
8962 Chunks!Source chunks(Source)(Source source, size_t chunkSize)
8963 if (isInputRange!Source)
8965 return typeof(return)(source, chunkSize);
8969 @safe unittest
8971 import std.algorithm.comparison : equal;
8972 auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
8973 auto chunks = chunks(source, 4);
8974 assert(chunks[0] == [1, 2, 3, 4]);
8975 assert(chunks[1] == [5, 6, 7, 8]);
8976 assert(chunks[2] == [9, 10]);
8977 assert(chunks.back == chunks[2]);
8978 assert(chunks.front == chunks[0]);
8979 assert(chunks.length == 3);
8980 assert(equal(retro(array(chunks)), array(retro(chunks))));
8983 /// Non-forward input ranges are supported, but with limited semantics.
8984 @system /*@safe*/ unittest // FIXME: can't be @safe because RefCounted isn't.
8986 import std.algorithm.comparison : equal;
8988 int i;
8990 // The generator doesn't save state, so it cannot be a forward range.
8991 auto inputRange = generate!(() => ++i).take(10);
8993 // We can still process it in chunks, but it will be single-pass only.
8994 auto chunked = inputRange.chunks(2);
8996 assert(chunked.front.equal([1, 2]));
8997 assert(chunked.front.empty); // Iterating the chunk has consumed it
8998 chunked.popFront;
8999 assert(chunked.front.equal([3, 4]));
9002 @system /*@safe*/ unittest
9004 import std.algorithm.comparison : equal;
9005 import std.internal.test.dummyrange : ReferenceInputRange;
9007 auto data = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
9008 auto r = new ReferenceInputRange!int(data).chunks(3);
9009 assert(r.equal!equal([
9010 [ 1, 2, 3 ],
9011 [ 4, 5, 6 ],
9012 [ 7, 8, 9 ],
9013 [ 10 ]
9014 ]));
9016 auto data2 = [ 1, 2, 3, 4, 5, 6 ];
9017 auto r2 = new ReferenceInputRange!int(data2).chunks(3);
9018 assert(r2.equal!equal([
9019 [ 1, 2, 3 ],
9020 [ 4, 5, 6 ]
9021 ]));
9023 auto data3 = [ 1, 2, 3, 4, 5 ];
9024 auto r3 = new ReferenceInputRange!int(data3).chunks(2);
9025 assert(r3.front.equal([1, 2]));
9026 r3.popFront();
9027 assert(!r3.empty);
9028 r3.popFront();
9029 assert(r3.front.equal([5]));
9032 @safe unittest
9034 auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
9035 auto chunks = chunks(source, 4);
9036 auto chunks2 = chunks.save;
9037 chunks.popFront();
9038 assert(chunks[0] == [5, 6, 7, 8]);
9039 assert(chunks[1] == [9, 10]);
9040 chunks2.popBack();
9041 assert(chunks2[1] == [5, 6, 7, 8]);
9042 assert(chunks2.length == 2);
9044 static assert(isRandomAccessRange!(typeof(chunks)));
9047 @safe unittest
9049 import std.algorithm.comparison : equal;
9051 //Extra toying with slicing and indexing.
9052 auto chunks1 = [0, 0, 1, 1, 2, 2, 3, 3, 4].chunks(2);
9053 auto chunks2 = [0, 0, 1, 1, 2, 2, 3, 3, 4, 4].chunks(2);
9055 assert(chunks1.length == 5);
9056 assert(chunks2.length == 5);
9057 assert(chunks1[4] == [4]);
9058 assert(chunks2[4] == [4, 4]);
9059 assert(chunks1.back == [4]);
9060 assert(chunks2.back == [4, 4]);
9062 assert(chunks1[0 .. 1].equal([[0, 0]]));
9063 assert(chunks1[0 .. 2].equal([[0, 0], [1, 1]]));
9064 assert(chunks1[4 .. 5].equal([[4]]));
9065 assert(chunks2[4 .. 5].equal([[4, 4]]));
9067 assert(chunks1[0 .. 0].equal((int[][]).init));
9068 assert(chunks1[5 .. 5].equal((int[][]).init));
9069 assert(chunks2[5 .. 5].equal((int[][]).init));
9071 //Fun with opDollar
9072 assert(chunks1[$ .. $].equal((int[][]).init)); //Quick
9073 assert(chunks2[$ .. $].equal((int[][]).init)); //Quick
9074 assert(chunks1[$ - 1 .. $].equal([[4]])); //Semiquick
9075 assert(chunks2[$ - 1 .. $].equal([[4, 4]])); //Semiquick
9076 assert(chunks1[$ .. 5].equal((int[][]).init)); //Semiquick
9077 assert(chunks2[$ .. 5].equal((int[][]).init)); //Semiquick
9079 assert(chunks1[$ / 2 .. $ - 1].equal([[2, 2], [3, 3]])); //Slow
9082 @safe unittest
9084 import std.algorithm.comparison : equal;
9085 import std.algorithm.iteration : filter;
9087 //ForwardRange
9088 auto r = filter!"true"([1, 2, 3, 4, 5]).chunks(2);
9089 assert(equal!"equal(a, b)"(r, [[1, 2], [3, 4], [5]]));
9091 //InfiniteRange w/o RA
9092 auto fibsByPairs = recurrence!"a[n-1] + a[n-2]"(1, 1).chunks(2);
9093 assert(equal!`equal(a, b)`(fibsByPairs.take(2), [[ 1, 1], [ 2, 3]]));
9095 //InfiniteRange w/ RA and slicing
9096 auto odds = sequence!("a[0] + n * a[1]")(1, 2);
9097 auto oddsByPairs = odds.chunks(2);
9098 assert(equal!`equal(a, b)`(oddsByPairs.take(2), [[ 1, 3], [ 5, 7]]));
9100 //Requires phobos#991 for Sequence to have slice to end
9101 static assert(hasSlicing!(typeof(odds)));
9102 assert(equal!`equal(a, b)`(oddsByPairs[3 .. 5], [[13, 15], [17, 19]]));
9103 assert(equal!`equal(a, b)`(oddsByPairs[3 .. $].take(2), [[13, 15], [17, 19]]));
9109 This range splits a `source` range into `chunkCount` chunks of
9110 approximately equal length. `Source` must be a forward range with
9111 known length.
9113 Unlike $(LREF chunks), `evenChunks` takes a chunk count (not size).
9114 The returned range will contain zero or more $(D source.length /
9115 chunkCount + 1) elements followed by $(D source.length / chunkCount)
9116 elements. If $(D source.length < chunkCount), some chunks will be empty.
9118 `chunkCount` must not be zero, unless `source` is also empty.
9120 struct EvenChunks(Source)
9121 if (isForwardRange!Source && hasLength!Source)
9123 /// Standard constructor
9124 this(Source source, size_t chunkCount)
9126 assert(chunkCount != 0 || source.empty, "Cannot create EvenChunks with a zero chunkCount");
9127 _source = source;
9128 _chunkCount = chunkCount;
9131 /// Forward range primitives. Always present.
9132 @property auto front()
9134 assert(!empty, "Attempting to fetch the front of an empty evenChunks");
9135 return _source.save.take(_chunkPos(1));
9138 /// Ditto
9139 void popFront()
9141 assert(!empty, "Attempting to popFront an empty evenChunks");
9142 _source.popFrontN(_chunkPos(1));
9143 _chunkCount--;
9146 /// Ditto
9147 @property bool empty()
9149 return _chunkCount == 0;
9152 /// Ditto
9153 @property typeof(this) save()
9155 return typeof(this)(_source.save, _chunkCount);
9158 /// Length
9159 @property size_t length() const
9161 return _chunkCount;
9163 //Note: No point in defining opDollar here without slicing.
9164 //opDollar is defined below in the hasSlicing!Source section
9166 static if (hasSlicing!Source)
9169 Indexing, slicing and bidirectional operations and range primitives.
9170 Provided only if `hasSlicing!Source` is `true`.
9172 auto opIndex(size_t index)
9174 assert(index < _chunkCount, "evenChunks index out of bounds");
9175 return _source[_chunkPos(index) .. _chunkPos(index+1)];
9178 /// Ditto
9179 typeof(this) opSlice(size_t lower, size_t upper)
9181 assert(lower <= upper && upper <= length, "evenChunks slicing index out of bounds");
9182 return evenChunks(_source[_chunkPos(lower) .. _chunkPos(upper)], upper - lower);
9185 /// Ditto
9186 @property auto back()
9188 assert(!empty, "back called on empty evenChunks");
9189 return _source[_chunkPos(_chunkCount - 1) .. _source.length];
9192 /// Ditto
9193 void popBack()
9195 assert(!empty, "popBack() called on empty evenChunks");
9196 _source = _source[0 .. _chunkPos(_chunkCount - 1)];
9197 _chunkCount--;
9201 private:
9202 Source _source;
9203 size_t _chunkCount;
9205 size_t _chunkPos(size_t i)
9208 _chunkCount = 5, _source.length = 13:
9210 chunk0
9211 | chunk3
9214 +-+-+-+-+-+ ^
9215 |0|3|.| | | |
9216 +-+-+-+-+-+ | div
9217 |1|4|.| | | |
9218 +-+-+-+-+-+ v
9219 |2|5|.|
9220 +-+-+-+
9222 <----->
9225 <--------->
9226 _chunkCount
9228 One column is one chunk.
9229 popFront and popBack pop the left-most
9230 and right-most column, respectively.
9233 auto div = _source.length / _chunkCount;
9234 auto mod = _source.length % _chunkCount;
9235 auto pos = i <= mod
9236 ? i * (div+1)
9237 : mod * (div+1) + (i-mod) * div
9239 //auto len = i < mod
9240 // ? div+1
9241 // : div
9243 return pos;
9247 /// Ditto
9248 EvenChunks!Source evenChunks(Source)(Source source, size_t chunkCount)
9249 if (isForwardRange!Source && hasLength!Source)
9251 return typeof(return)(source, chunkCount);
9255 @safe unittest
9257 import std.algorithm.comparison : equal;
9258 auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
9259 auto chunks = evenChunks(source, 3);
9260 assert(chunks[0] == [1, 2, 3, 4]);
9261 assert(chunks[1] == [5, 6, 7]);
9262 assert(chunks[2] == [8, 9, 10]);
9265 @safe unittest
9267 import std.algorithm.comparison : equal;
9269 auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
9270 auto chunks = evenChunks(source, 3);
9271 assert(chunks.back == chunks[2]);
9272 assert(chunks.front == chunks[0]);
9273 assert(chunks.length == 3);
9274 assert(equal(retro(array(chunks)), array(retro(chunks))));
9276 auto chunks2 = chunks.save;
9277 chunks.popFront();
9278 assert(chunks[0] == [5, 6, 7]);
9279 assert(chunks[1] == [8, 9, 10]);
9280 chunks2.popBack();
9281 assert(chunks2[1] == [5, 6, 7]);
9282 assert(chunks2.length == 2);
9284 static assert(isRandomAccessRange!(typeof(chunks)));
9287 @safe unittest
9289 import std.algorithm.comparison : equal;
9291 int[] source = [];
9292 auto chunks = source.evenChunks(0);
9293 assert(chunks.length == 0);
9294 chunks = source.evenChunks(3);
9295 assert(equal(chunks, [[], [], []]));
9296 chunks = [1, 2, 3].evenChunks(5);
9297 assert(equal(chunks, [[1], [2], [3], [], []]));
9301 A fixed-sized sliding window iteration
9302 of size `windowSize` over a `source` range by a custom `stepSize`.
9304 The `Source` range must be at least a $(REF_ALTTEXT ForwardRange, isForwardRange, std,range,primitives)
9305 and the `windowSize` must be greater than zero.
9307 For `windowSize = 1` it splits the range into single element groups (aka `unflatten`)
9308 For `windowSize = 2` it is similar to `zip(source, source.save.dropOne)`.
9310 Params:
9311 f = Whether the last element has fewer elements than `windowSize`
9312 it should be be ignored (`No.withPartial`) or added (`Yes.withPartial`)
9313 source = Range from which the slide will be selected
9314 windowSize = Sliding window size
9315 stepSize = Steps between the windows (by default 1)
9317 Returns: Range of all sliding windows with propagated bi-directionality,
9318 forwarding, random access, and slicing.
9320 Note: To avoid performance overhead, $(REF_ALTTEXT bi-directionality, isBidirectionalRange, std,range,primitives)
9321 is only available when $(REF hasSlicing, std,range,primitives)
9322 and $(REF hasLength, std,range,primitives) are true.
9324 See_Also: $(LREF chunks)
9326 auto slide(Flag!"withPartial" f = Yes.withPartial,
9327 Source)(Source source, size_t windowSize, size_t stepSize = 1)
9328 if (isForwardRange!Source)
9330 return Slides!(f, Source)(source, windowSize, stepSize);
9333 /// Iterate over ranges with windows
9334 @safe pure nothrow unittest
9336 import std.algorithm.comparison : equal;
9338 assert([0, 1, 2, 3].slide(2).equal!equal(
9339 [[0, 1], [1, 2], [2, 3]]
9342 assert(5.iota.slide(3).equal!equal(
9343 [[0, 1, 2], [1, 2, 3], [2, 3, 4]]
9347 /// set a custom stepsize (default 1)
9348 @safe pure nothrow unittest
9350 import std.algorithm.comparison : equal;
9352 assert(6.iota.slide(1, 2).equal!equal(
9353 [[0], [2], [4]]
9356 assert(6.iota.slide(2, 4).equal!equal(
9357 [[0, 1], [4, 5]]
9360 assert(iota(7).slide(2, 2).equal!equal(
9361 [[0, 1], [2, 3], [4, 5], [6]]
9364 assert(iota(12).slide(2, 4).equal!equal(
9365 [[0, 1], [4, 5], [8, 9]]
9369 /// Allow the last slide to have fewer elements than windowSize
9370 @safe pure nothrow unittest
9372 import std.algorithm.comparison : equal;
9374 assert(3.iota.slide!(No.withPartial)(4).empty);
9375 assert(3.iota.slide!(Yes.withPartial)(4).equal!equal(
9376 [[0, 1, 2]]
9380 /// Count all the possible substrings of length 2
9381 @safe pure nothrow unittest
9383 import std.algorithm.iteration : each;
9385 int[dstring] d;
9386 "AGAGA"d.slide!(Yes.withPartial)(2).each!(a => d[a]++);
9387 assert(d == ["AG"d: 2, "GA"d: 2]);
9390 /// withPartial only has an effect if last element in the range doesn't have the full size
9391 @safe pure nothrow unittest
9393 import std.algorithm.comparison : equal;
9395 assert(5.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4]]));
9396 assert(6.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5]]));
9397 assert(7.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5, 6]]));
9399 assert(5.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2]]));
9400 assert(6.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2]]));
9401 assert(7.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5, 6]]));
9404 private struct Slides(Flag!"withPartial" withPartial = Yes.withPartial, Source)
9405 if (isForwardRange!Source)
9407 private:
9408 Source source;
9409 size_t windowSize;
9410 size_t stepSize;
9412 static if (hasLength!Source)
9414 enum needsEndTracker = false;
9416 else
9418 // If there's no information about the length, track needs to be kept manually
9419 Source nextSource;
9420 enum needsEndTracker = true;
9423 bool _empty;
9425 static if (hasSlicing!Source)
9426 enum hasSliceToEnd = hasSlicing!Source && is(typeof(Source.init[0 .. $]) == Source);
9428 static if (withPartial)
9429 bool hasShownPartialBefore;
9431 public:
9432 /// Standard constructor
9433 this(Source source, size_t windowSize, size_t stepSize)
9435 assert(windowSize > 0, "windowSize must be greater than zero");
9436 assert(stepSize > 0, "stepSize must be greater than zero");
9437 this.source = source;
9438 this.windowSize = windowSize;
9439 this.stepSize = stepSize;
9441 static if (needsEndTracker)
9443 // `nextSource` is used to "look one step into the future" and check for the end
9444 // this means `nextSource` is advanced by `stepSize` on every `popFront`
9445 nextSource = source.save;
9446 auto poppedElems = nextSource.popFrontN(windowSize);
9449 if (source.empty)
9451 _empty = true;
9452 return;
9455 static if (withPartial)
9457 static if (needsEndTracker)
9459 if (nextSource.empty)
9460 hasShownPartialBefore = true;
9462 else
9464 if (source.length <= windowSize)
9465 hasShownPartialBefore = true;
9468 else
9470 // empty source range is needed, s.t. length, slicing etc. works properly
9471 static if (needsEndTracker)
9473 if (poppedElems < windowSize)
9474 _empty = true;
9476 else
9478 if (source.length < windowSize)
9479 _empty = true;
9484 /// Forward range primitives. Always present.
9485 @property auto front()
9487 assert(!empty, "Attempting to access front on an empty slide.");
9488 static if (hasSlicing!Source && hasLength!Source)
9490 static if (withPartial)
9492 import std.algorithm.comparison : min;
9493 return source[0 .. min(windowSize, source.length)];
9495 else
9497 assert(windowSize <= source.length, "The last element is smaller than the current windowSize.");
9498 return source[0 .. windowSize];
9501 else
9503 static if (withPartial)
9504 return source.save.take(windowSize);
9505 else
9506 return source.save.takeExactly(windowSize);
9510 /// Ditto
9511 void popFront()
9513 assert(!empty, "Attempting to call popFront() on an empty slide.");
9514 source.popFrontN(stepSize);
9516 if (source.empty)
9518 _empty = true;
9519 return;
9522 static if (withPartial)
9524 if (hasShownPartialBefore)
9525 _empty = true;
9528 static if (needsEndTracker)
9530 // Check the upcoming slide
9531 auto poppedElements = nextSource.popFrontN(stepSize);
9532 static if (withPartial)
9534 if (poppedElements < stepSize || nextSource.empty)
9535 hasShownPartialBefore = true;
9537 else
9539 if (poppedElements < stepSize)
9540 _empty = true;
9543 else
9545 static if (withPartial)
9547 if (source.length <= windowSize)
9548 hasShownPartialBefore = true;
9550 else
9552 if (source.length < windowSize)
9553 _empty = true;
9558 static if (!isInfinite!Source)
9560 /// Ditto
9561 @property bool empty() const
9563 return _empty;
9566 else
9568 // undocumented
9569 enum empty = false;
9572 /// Ditto
9573 @property typeof(this) save()
9575 return typeof(this)(source.save, windowSize, stepSize);
9578 static if (hasLength!Source)
9580 // gaps between the last element and the end of the range
9581 private size_t gap()
9584 * Note:
9585 * - In the following `end` is the exclusive end as used in opSlice
9586 * - For the trivial case with `stepSize = 1` `end` is at `len`:
9588 * iota(4).slide(2) = [[0, 1], [1, 2], [2, 3]] (end = 4)
9589 * iota(4).slide(3) = [[0, 1, 2], [1, 2, 3]] (end = 4)
9591 * - For the non-trivial cases, we need to calculate the gap
9592 * between `len` and `end` - this is the number of missing elements
9593 * from the input range:
9595 * iota(7).slide(2, 3) = [[0, 1], [3, 4]] || <gap: 2> 6
9596 * iota(7).slide(2, 4) = [[0, 1], [4, 5]] || <gap: 1> 6
9597 * iota(7).slide(1, 5) = [[0], [5]] || <gap: 1> 6
9599 * As it can be seen `gap` can be at most `stepSize - 1`
9600 * More generally the elements of the sliding window with
9601 * `w = windowSize` and `s = stepSize` are:
9603 * [0, w], [s, s + w], [2 * s, 2 * s + w], ... [n * s, n * s + w]
9605 * We can thus calculate the gap between the `end` and `len` as:
9607 * gap = len - (n * s + w) = len - w - (n * s)
9609 * As we aren't interested in exact value of `n`, but the best
9610 * minimal `gap` value, we can use modulo to "cut" `len - w` optimally:
9612 * gap = len - w - (s - s ... - s) = (len - w) % s
9614 * So for example:
9616 * iota(7).slide(2, 3) = [[0, 1], [3, 4]]
9617 * gap: (7 - 2) % 3 = 5 % 3 = 2
9618 * end: 7 - 2 = 5
9620 * iota(7).slide(4, 2) = [[0, 1, 2, 3], [2, 3, 4, 5]]
9621 * gap: (7 - 4) % 2 = 3 % 2 = 1
9622 * end: 7 - 1 = 6
9624 return (source.length - windowSize) % stepSize;
9627 private size_t numberOfFullFrames()
9630 5.iota.slides(2, 1) => [0, 1], [1, 2], [2, 3], [3, 4] (4)
9631 7.iota.slides(2, 2) => [0, 1], [2, 3], [4, 5], [6] (3)
9632 7.iota.slides(2, 3) => [0, 1], [3, 4], [6] (2)
9633 6.iota.slides(3, 2) => [0, 1, 2], [2, 3, 4], [4, 5] (2)
9634 7.iota.slides(3, 3) => [0, 1, 2], [3, 4, 5], [6] (2)
9636 As the last window is only added iff its complete,
9637 we don't count the last window except if it's full due to integer rounding.
9639 return 1 + (source.length - windowSize) / stepSize;
9642 // Whether the last slide frame size is less than windowSize
9643 private bool hasPartialElements()
9645 static if (withPartial)
9646 return gap != 0 && source.length > numberOfFullFrames * stepSize;
9647 else
9648 return 0;
9651 /// Length. Only if `hasLength!Source` is `true`
9652 @property size_t length()
9654 if (source.length < windowSize)
9656 static if (withPartial)
9657 return source.length > 0;
9658 else
9659 return 0;
9661 else
9663 /***
9664 We bump the pointer by stepSize for every element.
9665 If withPartial, we don't count the last element if its size
9666 isn't windowSize
9668 At most:
9669 [p, p + stepSize, ..., p + stepSize * n]
9671 5.iota.slides(2, 1) => [0, 1], [1, 2], [2, 3], [3, 4] (4)
9672 7.iota.slides(2, 2) => [0, 1], [2, 3], [4, 5], [6] (4)
9673 7.iota.slides(2, 3) => [0, 1], [3, 4], [6] (3)
9674 7.iota.slides(3, 2) => [0, 1, 2], [2, 3, 4], [4, 5, 6] (3)
9675 7.iota.slides(3, 3) => [0, 1, 2], [3, 4, 5], [6] (3)
9677 return numberOfFullFrames + hasPartialElements;
9682 static if (hasSlicing!Source)
9685 Indexing and slicing operations. Provided only if
9686 `hasSlicing!Source` is `true`.
9688 auto opIndex(size_t index)
9690 immutable start = index * stepSize;
9692 static if (isInfinite!Source)
9694 immutable end = start + windowSize;
9696 else
9698 import std.algorithm.comparison : min;
9700 immutable len = source.length;
9701 assert(start < len, "slide index out of bounds");
9702 immutable end = min(start + windowSize, len);
9705 return source[start .. end];
9708 static if (!isInfinite!Source)
9710 /// ditto
9711 typeof(this) opSlice(size_t lower, size_t upper)
9713 import std.algorithm.comparison : min;
9715 assert(upper <= length, "slide slicing index out of bounds");
9716 assert(lower <= upper, "slide slicing index out of bounds");
9718 lower *= stepSize;
9719 upper *= stepSize;
9721 immutable len = source.length;
9723 static if (withPartial)
9725 import std.algorithm.comparison : max;
9727 if (lower == upper)
9728 return this[$ .. $];
9731 A) If `stepSize` >= `windowSize` => `rightPos = upper`
9733 [0, 1, 2, 3, 4, 5, 6].slide(2, 3) -> s = [[0, 1], [3, 4], [6]]
9734 rightPos for s[0 .. 2]: (upper=2) * (stepSize=3) = 6
9735 6.iota.slide(2, 3) = [[0, 1], [3, 4]]
9737 B) If `stepSize` < `windowSize` => add `windowSize - stepSize` to `upper`
9739 [0, 1, 2, 3].slide(2) = [[0, 1], [1, 2], [2, 3]]
9740 rightPos for s[0 .. 1]: = (upper=1) * (stepSize=1) = 1
9741 1.iota.slide(2) = [[0]]
9743 rightPos for s[0 .. 1]: = (upper=1) * (stepSize=1) + (windowSize-stepSize=1) = 2
9744 1.iota.slide(2) = [[0, 1]]
9746 More complex:
9748 20.iota.slide(7, 6)[0 .. 2]
9749 rightPos: (upper=2) * (stepSize=6) = 12.iota
9750 12.iota.slide(7, 6) = [[0, 1, 2, 3, 4, 5, 6], [6, 7, 8, 9, 10, 11]]
9752 Now we add up for the difference between `windowSize` and `stepSize`:
9754 rightPos: (upper=2) * (stepSize=6) + (windowSize-stepSize=1) = 13.iota
9755 13.iota.slide(7, 6) = [[0, 1, 2, 3, 4, 5, 6], [6, 7, 8, 9, 10, 11, 12]]
9757 immutable rightPos = min(len, upper + max(0, windowSize - stepSize));
9759 else
9762 After we have normalized `lower` and `upper` by `stepSize`,
9763 we only need to look at the case of `stepSize=1`.
9764 As `leftPos`, is equal to `lower`, we will only look `rightPos`.
9765 Notice that starting from `upper`,
9766 we only need to move for `windowSize - 1` to the right:
9768 - [0, 1, 2, 3].slide(2) -> s = [[0, 1], [1, 2], [2, 3]]
9769 rightPos for s[0 .. 3]: (upper=3) + (windowSize=2) - 1 = 4
9771 - [0, 1, 2, 3].slide(3) -> s = [[0, 1, 2], [1, 2, 3]]
9772 rightPos for s[0 .. 2]: (upper=2) + (windowSize=3) - 1 = 4
9774 - [0, 1, 2, 3, 4].slide(4) -> s = [[0, 1, 2, 3], [1, 2, 3, 4]]
9775 rightPos for s[0 .. 2]: (upper=2) + (windowSize=4) - 1 = 5
9777 immutable rightPos = min(upper + windowSize - 1, len);
9780 return typeof(this)(source[min(lower, len) .. rightPos], windowSize, stepSize);
9783 else static if (hasSliceToEnd)
9785 // For slicing an infinite chunk, we need to slice the source to the infinite end.
9786 auto opSlice(size_t lower, size_t upper)
9788 assert(lower <= upper, "slide slicing index out of bounds");
9789 return typeof(this)(source[lower * stepSize .. $], windowSize, stepSize)
9790 .takeExactly(upper - lower);
9794 static if (isInfinite!Source)
9796 static if (hasSliceToEnd)
9798 private static struct DollarToken{}
9799 DollarToken opDollar()
9801 return DollarToken();
9803 //Slice to dollar
9804 typeof(this) opSlice(size_t lower, DollarToken)
9806 return typeof(this)(source[lower * stepSize .. $], windowSize, stepSize);
9810 else
9812 // Dollar token carries a static type, with no extra information.
9813 // It can lazily transform into source.length on algorithmic
9814 // operations such as : slide[$/2, $-1];
9815 private static struct DollarToken
9817 private size_t _length;
9818 alias _length this;
9821 DollarToken opDollar()
9823 return DollarToken(this.length);
9826 // Optimized slice overloads optimized for using dollar.
9827 typeof(this) opSlice(DollarToken, DollarToken)
9829 static if (hasSliceToEnd)
9831 return typeof(this)(source[$ .. $], windowSize, stepSize);
9833 else
9835 immutable len = source.length;
9836 return typeof(this)(source[len .. len], windowSize, stepSize);
9840 // Optimized slice overloads optimized for using dollar.
9841 typeof(this) opSlice(size_t lower, DollarToken)
9843 import std.algorithm.comparison : min;
9844 assert(lower <= length, "slide slicing index out of bounds");
9845 lower *= stepSize;
9846 static if (hasSliceToEnd)
9848 return typeof(this)(source[min(lower, source.length) .. $], windowSize, stepSize);
9850 else
9852 immutable len = source.length;
9853 return typeof(this)(source[min(lower, len) .. len], windowSize, stepSize);
9857 // Optimized slice overloads optimized for using dollar.
9858 typeof(this) opSlice(DollarToken, size_t upper)
9860 assert(upper == length, "slide slicing index out of bounds");
9861 return this[$ .. $];
9865 // Bidirectional range primitives
9866 static if (!isInfinite!Source)
9869 Bidirectional range primitives. Provided only if both
9870 `hasSlicing!Source` and `!isInfinite!Source` are `true`.
9872 @property auto back()
9874 import std.algorithm.comparison : max;
9876 assert(!empty, "Attempting to access front on an empty slide");
9878 immutable len = source.length;
9880 static if (withPartial)
9882 if (source.length <= windowSize)
9883 return source[0 .. source.length];
9885 if (hasPartialElements)
9886 return source[numberOfFullFrames * stepSize .. len];
9889 // check for underflow
9890 immutable start = (len > windowSize + gap) ? len - windowSize - gap : 0;
9891 return source[start .. len - gap];
9894 /// Ditto
9895 void popBack()
9897 assert(!empty, "Attempting to call popBack() on an empty slide");
9899 // Move by stepSize
9900 immutable end = source.length > stepSize ? source.length - stepSize : 0;
9902 static if (withPartial)
9904 if (hasShownPartialBefore || source.empty)
9906 _empty = true;
9907 return;
9910 // pop by stepSize, except for the partial frame at the end
9911 if (hasPartialElements)
9912 source = source[0 .. source.length - gap];
9913 else
9914 source = source[0 .. end];
9916 else
9918 source = source[0 .. end];
9921 if (source.length < windowSize)
9922 _empty = true;
9928 // test @nogc
9929 @safe pure nothrow @nogc unittest
9931 import std.algorithm.comparison : equal;
9933 static immutable res1 = [[0], [1], [2], [3]];
9934 assert(4.iota.slide!(Yes.withPartial)(1).equal!equal(res1));
9936 static immutable res2 = [[0, 1], [1, 2], [2, 3]];
9937 assert(4.iota.slide!(Yes.withPartial)(2).equal!equal(res2));
9940 // test different window sizes
9941 @safe pure nothrow unittest
9943 import std.array : array;
9944 import std.algorithm.comparison : equal;
9946 assert([0, 1, 2, 3].slide!(Yes.withPartial)(1).array == [[0], [1], [2], [3]]);
9947 assert([0, 1, 2, 3].slide!(Yes.withPartial)(2).array == [[0, 1], [1, 2], [2, 3]]);
9948 assert([0, 1, 2, 3].slide!(Yes.withPartial)(3).array == [[0, 1, 2], [1, 2, 3]]);
9949 assert([0, 1, 2, 3].slide!(Yes.withPartial)(4).array == [[0, 1, 2, 3]]);
9950 assert([0, 1, 2, 3].slide!(No.withPartial)(5).walkLength == 0);
9951 assert([0, 1, 2, 3].slide!(Yes.withPartial)(5).array == [[0, 1, 2, 3]]);
9953 assert(iota(2).slide!(Yes.withPartial)(2).front.equal([0, 1]));
9954 assert(iota(3).slide!(Yes.withPartial)(2).equal!equal([[0, 1],[1, 2]]));
9955 assert(iota(3).slide!(Yes.withPartial)(3).equal!equal([[0, 1, 2]]));
9956 assert(iota(3).slide!(No.withPartial)(4).walkLength == 0);
9957 assert(iota(3).slide!(Yes.withPartial)(4).equal!equal([[0, 1, 2]]));
9958 assert(iota(1, 4).slide!(Yes.withPartial)(1).equal!equal([[1], [2], [3]]));
9959 assert(iota(1, 4).slide!(Yes.withPartial)(3).equal!equal([[1, 2, 3]]));
9962 // test combinations
9963 @safe pure nothrow unittest
9965 import std.algorithm.comparison : equal;
9966 import std.typecons : tuple;
9968 alias t = tuple;
9969 auto list = [
9970 t(t(1, 1), [[0], [1], [2], [3], [4], [5]]),
9971 t(t(1, 2), [[0], [2], [4]]),
9972 t(t(1, 3), [[0], [3]]),
9973 t(t(1, 4), [[0], [4]]),
9974 t(t(1, 5), [[0], [5]]),
9975 t(t(2, 1), [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5]]),
9976 t(t(2, 2), [[0, 1], [2, 3], [4, 5]]),
9977 t(t(2, 3), [[0, 1], [3, 4]]),
9978 t(t(2, 4), [[0, 1], [4, 5]]),
9979 t(t(3, 1), [[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5]]),
9980 t(t(3, 3), [[0, 1, 2], [3, 4, 5]]),
9981 t(t(4, 1), [[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]),
9982 t(t(4, 2), [[0, 1, 2, 3], [2, 3, 4, 5]]),
9983 t(t(5, 1), [[0, 1, 2, 3, 4], [1, 2, 3, 4, 5]]),
9986 static foreach (Partial; [Yes.withPartial, No.withPartial])
9987 foreach (e; list)
9988 assert(6.iota.slide!Partial(e[0].expand).equal!equal(e[1]));
9990 auto listSpecial = [
9991 t(t(2, 5), [[0, 1], [5]]),
9992 t(t(3, 2), [[0, 1, 2], [2, 3, 4], [4, 5]]),
9993 t(t(3, 4), [[0, 1, 2], [4, 5]]),
9994 t(t(4, 3), [[0, 1, 2, 3], [3, 4, 5]]),
9995 t(t(5, 2), [[0, 1, 2, 3, 4], [2, 3, 4, 5]]),
9996 t(t(5, 3), [[0, 1, 2, 3, 4], [3, 4, 5]]),
9998 foreach (e; listSpecial)
10000 assert(6.iota.slide!(Yes.withPartial)(e[0].expand).equal!equal(e[1]));
10001 assert(6.iota.slide!(No.withPartial)(e[0].expand).equal!equal(e[1].dropBackOne));
10005 // test emptiness and copyability
10006 @safe pure nothrow unittest
10008 import std.algorithm.comparison : equal;
10009 import std.algorithm.iteration : map;
10011 // check with empty input
10012 int[] d;
10013 assert(d.slide!(Yes.withPartial)(2).empty);
10014 assert(d.slide!(Yes.withPartial)(2, 2).empty);
10016 // is copyable?
10017 auto e = iota(5).slide!(Yes.withPartial)(2);
10018 e.popFront;
10019 assert(e.save.equal!equal([[1, 2], [2, 3], [3, 4]]));
10020 assert(e.save.equal!equal([[1, 2], [2, 3], [3, 4]]));
10021 assert(e.map!"a.array".array == [[1, 2], [2, 3], [3, 4]]);
10024 // test with strings
10025 @safe pure nothrow unittest
10027 import std.algorithm.iteration : each;
10029 int[dstring] f;
10030 "AGAGA"d.slide!(Yes.withPartial)(3).each!(a => f[a]++);
10031 assert(f == ["AGA"d: 2, "GAG"d: 1]);
10033 int[dstring] g;
10034 "ABCDEFG"d.slide!(Yes.withPartial)(3, 3).each!(a => g[a]++);
10035 assert(g == ["ABC"d:1, "DEF"d:1, "G": 1]);
10036 g = null;
10037 "ABCDEFG"d.slide!(No.withPartial)(3, 3).each!(a => g[a]++);
10038 assert(g == ["ABC"d:1, "DEF"d:1]);
10041 // test with utf8 strings
10042 @safe unittest
10044 import std.stdio;
10045 import std.algorithm.comparison : equal;
10047 assert("ä.ö.ü.".slide!(Yes.withPartial)(3, 2).equal!equal(["ä.ö", "ö.ü", "ü."]));
10048 assert("ä.ö.ü.".slide!(No.withPartial)(3, 2).equal!equal(["ä.ö", "ö.ü"]));
10050 "😄😅😆😇😈😄😅😆😇😈".slide!(Yes.withPartial)(2, 4).equal!equal(["😄😅", "😈😄", "😇😈"]);
10051 "😄😅😆😇😈😄😅😆😇😈".slide!(No.withPartial)(2, 4).equal!equal(["😄😅", "😈😄", "😇😈"]);
10052 "😄😅😆😇😈😄😅😆😇😈".slide!(Yes.withPartial)(3, 3).equal!equal(["😄😅😆", "😇😈😄", "😅😆😇", "😈"]);
10053 "😄😅😆😇😈😄😅😆😇😈".slide!(No.withPartial)(3, 3).equal!equal(["😄😅😆", "😇😈😄", "😅😆😇"]);
10056 // test length
10057 @safe pure nothrow unittest
10059 // Slides with fewer elements are empty or 1 for Yes.withPartial
10060 static foreach (expectedLength, Partial; [No.withPartial, Yes.withPartial])
10062 assert(3.iota.slide!(Partial)(4, 2).walkLength == expectedLength);
10063 assert(3.iota.slide!(Partial)(4).walkLength == expectedLength);
10064 assert(3.iota.slide!(Partial)(4, 3).walkLength == expectedLength);
10067 static immutable list = [
10068 // iota slide expected
10069 [4, 2, 1, 3, 3],
10070 [5, 3, 1, 3, 3],
10071 [7, 2, 2, 4, 3],
10072 [12, 2, 4, 3, 3],
10073 [6, 1, 2, 3, 3],
10074 [6, 2, 4, 2, 2],
10075 [3, 2, 4, 1, 1],
10076 [5, 2, 1, 4, 4],
10077 [7, 2, 2, 4, 3],
10078 [7, 2, 3, 3, 2],
10079 [7, 3, 2, 3, 3],
10080 [7, 3, 3, 3, 2],
10082 foreach (e; list)
10084 assert(e[0].iota.slide!(Yes.withPartial)(e[1], e[2]).length == e[3]);
10085 assert(e[0].iota.slide!(No.withPartial)(e[1], e[2]).length == e[4]);
10089 // test index and slicing
10090 @safe pure nothrow unittest
10092 import std.algorithm.comparison : equal;
10093 import std.array : array;
10095 static foreach (Partial; [Yes.withPartial, No.withPartial])
10097 foreach (s; [5, 7, 10, 15, 20])
10098 foreach (windowSize; 1 .. 10)
10099 foreach (stepSize; 1 .. 10)
10101 auto r = s.iota.slide!Partial(windowSize, stepSize);
10102 auto arr = r.array;
10103 assert(r.length == arr.length);
10105 // test indexing
10106 foreach (i; 0 .. arr.length)
10107 assert(r[i] == arr[i]);
10109 // test slicing
10110 foreach (i; 0 .. arr.length)
10112 foreach (j; i .. arr.length)
10113 assert(r[i .. j].equal(arr[i .. j]));
10115 assert(r[i .. $].equal(arr[i .. $]));
10118 // test opDollar slicing
10119 assert(r[$/2 .. $].equal(arr[$/2 .. $]));
10120 assert(r[$ .. $].empty);
10121 if (arr.empty)
10123 assert(r[$ .. 0].empty);
10124 assert(r[$/2 .. $].empty);
10131 // test with infinite ranges
10132 @safe pure nothrow unittest
10134 import std.algorithm.comparison : equal;
10136 static foreach (Partial; [Yes.withPartial, No.withPartial])
10138 // InfiniteRange without RandomAccess
10139 auto fibs = recurrence!"a[n-1] + a[n-2]"(1, 1);
10140 assert(fibs.slide!Partial(2).take(2).equal!equal([[1, 1], [1, 2]]));
10141 assert(fibs.slide!Partial(2, 3).take(2).equal!equal([[1, 1], [3, 5]]));
10143 // InfiniteRange with RandomAccess and slicing
10144 auto odds = sequence!("a[0] + n * a[1]")(1, 2);
10145 auto oddsByPairs = odds.slide!Partial(2);
10146 assert(oddsByPairs.take(2).equal!equal([[ 1, 3], [ 3, 5]]));
10147 assert(oddsByPairs[1].equal([3, 5]));
10148 assert(oddsByPairs[4].equal([9, 11]));
10150 static assert(hasSlicing!(typeof(odds)));
10151 assert(oddsByPairs[3 .. 5].equal!equal([[7, 9], [9, 11]]));
10152 assert(oddsByPairs[3 .. $].take(2).equal!equal([[7, 9], [9, 11]]));
10154 auto oddsWithGaps = odds.slide!Partial(2, 4);
10155 assert(oddsWithGaps.take(3).equal!equal([[1, 3], [9, 11], [17, 19]]));
10156 assert(oddsWithGaps[2].equal([17, 19]));
10157 assert(oddsWithGaps[1 .. 3].equal!equal([[9, 11], [17, 19]]));
10158 assert(oddsWithGaps[1 .. $].take(2).equal!equal([[9, 11], [17, 19]]));
10162 // test reverse
10163 @safe pure nothrow unittest
10165 import std.algorithm.comparison : equal;
10167 static foreach (Partial; [Yes.withPartial, No.withPartial])
10169 foreach (windowSize; 1 .. 15)
10170 foreach (stepSize; 1 .. 15)
10172 auto r = 20.iota.slide!Partial(windowSize, stepSize);
10173 auto rArr = r.array.retro;
10174 auto rRetro = r.retro;
10176 assert(rRetro.length == rArr.length);
10177 assert(rRetro.equal(rArr));
10178 assert(rRetro.array.retro.equal(r));
10183 // test with dummy ranges
10184 @safe pure nothrow unittest
10186 import std.algorithm.comparison : equal;
10187 import std.internal.test.dummyrange : AllDummyRanges;
10188 import std.meta : Filter;
10190 static foreach (Range; Filter!(isForwardRange, AllDummyRanges))
10192 Range r;
10194 static foreach (Partial; [Yes.withPartial, No.withPartial])
10196 assert(r.slide!Partial(1).equal!equal(
10197 [[1], [2], [3], [4], [5], [6], [7], [8], [9], [10]]
10199 assert(r.slide!Partial(2).equal!equal(
10200 [[1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9], [9, 10]]
10202 assert(r.slide!Partial(3).equal!equal(
10203 [[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6],
10204 [5, 6, 7], [6, 7, 8], [7, 8, 9], [8, 9, 10]]
10206 assert(r.slide!Partial(6).equal!equal(
10207 [[1, 2, 3, 4, 5, 6], [2, 3, 4, 5, 6, 7], [3, 4, 5, 6, 7, 8],
10208 [4, 5, 6, 7, 8, 9], [5, 6, 7, 8, 9, 10]]
10212 // special cases
10213 assert(r.slide!(Yes.withPartial)(15).equal!equal(iota(1, 11).only));
10214 assert(r.slide!(Yes.withPartial)(15).walkLength == 1);
10215 assert(r.slide!(No.withPartial)(15).empty);
10216 assert(r.slide!(No.withPartial)(15).walkLength == 0);
10220 // test with dummy ranges
10221 @safe pure nothrow unittest
10223 import std.algorithm.comparison : equal;
10224 import std.internal.test.dummyrange : AllDummyRanges;
10225 import std.meta : Filter;
10226 import std.typecons : tuple;
10228 alias t = tuple;
10229 static immutable list = [
10230 // iota slide expected
10231 t(6, t(4, 2), [[1, 2, 3, 4], [3, 4, 5, 6]]),
10232 t(6, t(4, 6), [[1, 2, 3, 4]]),
10233 t(6, t(4, 1), [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6]]),
10234 t(7, t(4, 1), [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 6, 7]]),
10235 t(7, t(4, 3), [[1, 2, 3, 4], [4, 5, 6, 7]]),
10236 t(8, t(4, 2), [[1, 2, 3, 4], [3, 4, 5, 6], [5, 6, 7, 8]]),
10237 t(8, t(4, 1), [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 6, 7], [5, 6, 7, 8]]),
10238 t(8, t(3, 4), [[1, 2, 3], [5, 6, 7]]),
10239 t(10, t(3, 7), [[1, 2, 3], [8, 9, 10]]),
10242 static foreach (Range; Filter!(isForwardRange, AllDummyRanges))
10243 static foreach (Partial; [Yes.withPartial, No.withPartial])
10244 foreach (e; list)
10245 assert(Range().take(e[0]).slide!Partial(e[1].expand).equal!equal(e[2]));
10247 static immutable listSpecial = [
10248 // iota slide expected
10249 t(6, t(4, 3), [[1, 2, 3, 4], [4, 5, 6]]),
10250 t(7, t(4, 5), [[1, 2, 3, 4], [6, 7]]),
10251 t(7, t(4, 4), [[1, 2, 3, 4], [5, 6, 7]]),
10252 t(7, t(4, 2), [[1, 2, 3, 4], [3, 4, 5, 6], [5, 6, 7]]),
10253 t(8, t(4, 3), [[1, 2, 3, 4], [4, 5, 6, 7], [7, 8]]),
10254 t(8, t(3, 3), [[1, 2, 3], [4, 5, 6], [7, 8]]),
10255 t(8, t(3, 6), [[1, 2, 3], [7, 8]]),
10256 t(10, t(7, 6), [[1, 2, 3, 4, 5, 6, 7], [7, 8, 9, 10]]),
10257 t(10, t(3, 8), [[1, 2, 3], [9, 10]]),
10259 static foreach (Range; Filter!(isForwardRange, AllDummyRanges))
10260 static foreach (Partial; [Yes.withPartial, No.withPartial])
10261 foreach (e; listSpecial)
10263 Range r;
10264 assert(r.take(e[0]).slide!(Yes.withPartial)(e[1].expand).equal!equal(e[2]));
10265 assert(r.take(e[0]).slide!(No.withPartial)(e[1].expand).equal!equal(e[2].dropBackOne));
10269 // test reverse with dummy ranges
10270 @safe pure nothrow unittest
10272 import std.algorithm.comparison : equal;
10273 import std.internal.test.dummyrange : AllDummyRanges;
10274 import std.meta : Filter, templateAnd;
10275 import std.typecons : tuple;
10276 alias t = tuple;
10278 static immutable list = [
10279 // slide expected
10280 t(1, 1, [[10], [9], [8], [7], [6], [5], [4], [3], [2], [1]]),
10281 t(2, 1, [[9, 10], [8, 9], [7, 8], [6, 7], [5, 6], [4, 5], [3, 4], [2, 3], [1, 2]]),
10282 t(5, 1, [[6, 7, 8, 9, 10], [5, 6, 7, 8, 9], [4, 5, 6, 7, 8],
10283 [3, 4, 5, 6, 7], [2, 3, 4, 5, 6], [1, 2, 3, 4, 5]]),
10284 t(2, 2, [[9, 10], [7, 8], [5, 6], [3, 4], [1, 2]]),
10285 t(2, 4, [[9, 10], [5, 6], [1, 2]]),
10288 static foreach (Range; Filter!(templateAnd!(hasSlicing, hasLength, isBidirectionalRange), AllDummyRanges))
10290 Range r;
10291 static foreach (Partial; [Yes.withPartial, No.withPartial])
10293 foreach (e; list)
10294 assert(r.slide!Partial(e[0], e[1]).retro.equal!equal(e[2]));
10296 // front = back
10297 foreach (windowSize; 1 .. 10)
10298 foreach (stepSize; 1 .. 10)
10300 auto slider = r.slide!Partial(windowSize, stepSize);
10301 auto sliderRetro = slider.retro.array;
10302 assert(slider.length == sliderRetro.length);
10303 assert(sliderRetro.retro.equal!equal(slider));
10307 // special cases
10308 assert(r.slide!(No.withPartial)(15).retro.walkLength == 0);
10309 assert(r.slide!(Yes.withPartial)(15).retro.equal!equal(iota(1, 11).only));
10313 // test different sliceable ranges
10314 @safe pure nothrow unittest
10316 import std.algorithm.comparison : equal;
10317 import std.internal.test.dummyrange : AllDummyRanges;
10318 import std.meta : AliasSeq;
10320 struct SliceableRange(Range, Flag!"withOpDollar" withOpDollar = No.withOpDollar,
10321 Flag!"withInfiniteness" withInfiniteness = No.withInfiniteness)
10323 Range arr = 10.iota.array; // similar to DummyRange
10324 @property auto save() { return typeof(this)(arr); }
10325 @property auto front() { return arr[0]; }
10326 void popFront() { arr.popFront(); }
10327 auto opSlice(size_t i, size_t j)
10329 // subslices can't be infinite
10330 return SliceableRange!(Range, withOpDollar, No.withInfiniteness)(arr[i .. j]);
10333 static if (withInfiniteness)
10335 enum empty = false;
10337 else
10339 @property bool empty() { return arr.empty; }
10340 @property auto length() { return arr.length; }
10343 static if (withOpDollar)
10345 static if (withInfiniteness)
10347 struct Dollar {}
10348 Dollar opDollar() const { return Dollar.init; }
10350 // Slice to dollar
10351 typeof(this) opSlice(size_t lower, Dollar)
10353 return typeof(this)(arr[lower .. $]);
10357 else
10359 alias opDollar = length;
10364 import std.meta : Filter, templateNot;
10365 alias SliceableDummyRanges = Filter!(hasSlicing, AllDummyRanges);
10367 static foreach (Partial; [Yes.withPartial, No.withPartial])
10369 static foreach (Range; SliceableDummyRanges)
10371 Range r;
10372 r.reinit;
10373 r.arr[] -= 1; // use a 0-based array (for clarity)
10375 assert(r.slide!Partial(2)[0].equal([0, 1]));
10376 assert(r.slide!Partial(2)[1].equal([1, 2]));
10378 // saveable
10379 auto s = r.slide!Partial(2);
10380 assert(s[0 .. 2].equal!equal([[0, 1], [1, 2]]));
10381 s.save.popFront;
10382 assert(s[0 .. 2].equal!equal([[0, 1], [1, 2]]));
10384 assert(r.slide!Partial(3)[1 .. 3].equal!equal([[1, 2, 3], [2, 3, 4]]));
10387 static foreach (Range; Filter!(templateNot!isInfinite, SliceableDummyRanges))
10389 Range r;
10390 r.reinit;
10391 r.arr[] -= 1; // use a 0-based array (for clarity)
10393 assert(r.slide!(No.withPartial)(6).equal!equal(
10394 [[0, 1, 2, 3, 4, 5], [1, 2, 3, 4, 5, 6], [2, 3, 4, 5, 6, 7],
10395 [3, 4, 5, 6, 7, 8], [4, 5, 6, 7, 8, 9]]
10397 assert(r.slide!(No.withPartial)(16).empty);
10399 assert(r.slide!Partial(4)[0 .. $].equal(r.slide!Partial(4)));
10400 assert(r.slide!Partial(2)[$/2 .. $].equal!equal([[4, 5], [5, 6], [6, 7], [7, 8], [8, 9]]));
10401 assert(r.slide!Partial(2)[$ .. $].empty);
10403 assert(r.slide!Partial(3).retro.equal!equal(
10404 [[7, 8, 9], [6, 7, 8], [5, 6, 7], [4, 5, 6], [3, 4, 5], [2, 3, 4], [1, 2, 3], [0, 1, 2]]
10408 alias T = int[];
10410 // separate checks for infinity
10411 auto infIndex = SliceableRange!(T, No.withOpDollar, Yes.withInfiniteness)([0, 1, 2, 3]);
10412 assert(infIndex.slide!Partial(2)[0].equal([0, 1]));
10413 assert(infIndex.slide!Partial(2)[1].equal([1, 2]));
10415 auto infDollar = SliceableRange!(T, Yes.withOpDollar, Yes.withInfiniteness)();
10416 assert(infDollar.slide!Partial(2)[1 .. $].front.equal([1, 2]));
10417 assert(infDollar.slide!Partial(4)[0 .. $].front.equal([0, 1, 2, 3]));
10418 assert(infDollar.slide!Partial(4)[2 .. $].front.equal([2, 3, 4, 5]));
10422 // https://issues.dlang.org/show_bug.cgi?id=19082
10423 @safe unittest
10425 import std.algorithm.comparison : equal;
10426 import std.algorithm.iteration : map;
10427 assert([1].map!(x => x).slide(2).equal!equal([[1]]));
10430 // https://issues.dlang.org/show_bug.cgi?id=19642
10431 @safe unittest
10433 import std.algorithm.comparison : equal;
10434 import std.algorithm.iteration : splitter;
10436 assert("ab cd".splitter(' ').slide!(No.withPartial)(2).equal!equal([["ab", "cd"]]));
10439 // https://issues.dlang.org/show_bug.cgi?id=23976
10440 @safe unittest
10442 import std.algorithm.comparison : equal;
10443 import std.algorithm.iteration : splitter;
10445 assert("1<2".splitter('<').slide(2).equal!equal([["1", "2"]]));
10448 private struct OnlyResult(Values...)
10449 if (Values.length > 1)
10451 import std.meta : ApplyRight;
10452 import std.traits : isAssignable;
10454 private enum arity = Values.length;
10456 private alias UnqualValues = staticMap!(Unqual, Values);
10458 private enum canAssignElements = allSatisfy!(
10459 ApplyRight!(isAssignable, CommonType!Values),
10460 Values
10463 private this(return scope ref Values values)
10465 ref @trusted unqual(T)(ref T x){return cast() x;}
10467 // TODO: this calls any possible copy constructors without qualifiers.
10468 // Find a way to initialize values using qualified copy constructors.
10469 static foreach (i; 0 .. Values.length)
10471 this.values[i] = unqual(values[i]);
10473 this.backIndex = arity;
10476 bool empty() @property
10478 return frontIndex >= backIndex;
10481 CommonType!Values front() @property
10483 assert(!empty, "Attempting to fetch the front of an empty Only range");
10484 return this[0];
10487 static if (canAssignElements)
10489 void front(CommonType!Values value) @property
10491 assert(!empty, "Attempting to assign the front of an empty Only range");
10492 this[0] = value;
10496 void popFront()
10498 assert(!empty, "Attempting to popFront an empty Only range");
10499 ++frontIndex;
10502 CommonType!Values back() @property
10504 assert(!empty, "Attempting to fetch the back of an empty Only range");
10505 return this[$ - 1];
10508 static if (canAssignElements)
10510 void back(CommonType!Values value) @property
10512 assert(!empty, "Attempting to assign the back of an empty Only range");
10513 this[$ - 1] = value;
10517 void popBack()
10519 assert(!empty, "Attempting to popBack an empty Only range");
10520 --backIndex;
10523 OnlyResult save() @property
10525 return this;
10528 size_t length() const @property
10530 return backIndex - frontIndex;
10533 alias opDollar = length;
10535 @trusted CommonType!Values opIndex(size_t idx)
10537 // when i + idx points to elements popped
10538 // with popBack
10539 assert(idx < length, "Attempting to fetch an out of bounds index from an Only range");
10540 final switch (frontIndex + idx)
10541 static foreach (i, T; Values)
10542 case i:
10543 return cast(T) values[i];
10546 static if (canAssignElements)
10548 void opIndexAssign(CommonType!Values value, size_t idx)
10550 assert(idx < length, "Attempting to assign to an out of bounds index of an Only range");
10551 final switch (frontIndex + idx)
10552 static foreach (i; 0 .. Values.length)
10553 case i:
10554 values[i] = value;
10558 OnlyResult opSlice()
10560 return this;
10563 OnlyResult opSlice(size_t from, size_t to)
10565 OnlyResult result = this;
10566 result.frontIndex += from;
10567 result.backIndex = this.frontIndex + to;
10568 assert(
10569 from <= to,
10570 "Attempting to slice an Only range with a larger first argument than the second."
10572 assert(
10573 to <= length,
10574 "Attempting to slice using an out of bounds index on an Only range"
10576 return result;
10579 private size_t frontIndex = 0;
10580 private size_t backIndex = 0;
10582 // https://issues.dlang.org/show_bug.cgi?id=10643
10583 version (none)
10585 import std.traits : hasElaborateAssign;
10586 static if (hasElaborateAssign!T)
10587 private UnqualValues values;
10588 else
10589 private UnqualValues values = void;
10591 else
10592 // These may alias to shared or immutable data. Do not let the user
10593 // to access these directly, and do not allow mutation without checking
10594 // the qualifier.
10595 private UnqualValues values;
10598 // Specialize for single-element results
10599 private struct OnlyResult(T)
10601 import std.traits : isAssignable;
10603 @property T front()
10605 assert(!empty, "Attempting to fetch the front of an empty Only range");
10606 return fetchFront();
10608 static if (isAssignable!T)
10610 @property void front(T value)
10612 assert(!empty, "Attempting to assign the front of an empty Only range");
10613 assignFront(value);
10616 @property T back()
10618 assert(!empty, "Attempting to fetch the back of an empty Only range");
10619 return fetchFront();
10621 static if (isAssignable!T)
10623 @property void back(T value)
10625 assert(!empty, "Attempting to assign the front of an empty Only range");
10626 assignFront(value);
10629 @property bool empty() const { return _empty; }
10630 @property size_t length() const { return !_empty; }
10631 @property auto save() { return this; }
10632 void popFront()
10634 assert(!_empty, "Attempting to popFront an empty Only range");
10635 _empty = true;
10637 void popBack()
10639 assert(!_empty, "Attempting to popBack an empty Only range");
10640 _empty = true;
10642 alias opDollar = length;
10644 // FIXME Workaround for https://issues.dlang.org/show_bug.cgi?id=24415
10645 import std.traits : hasElaborateCopyConstructor;
10646 static if (hasElaborateCopyConstructor!T)
10648 private static struct WorkaroundBugzilla24415 {}
10649 public this()(WorkaroundBugzilla24415) {}
10652 private this()(return scope auto ref T value)
10654 ref @trusted unqual(ref T x){return cast() x;}
10655 // TODO: this calls the possible copy constructor without qualifiers.
10656 // Find a way to initialize value using a qualified copy constructor.
10657 this._value = unqual(value);
10658 this._empty = false;
10661 T opIndex(size_t i)
10663 assert(!_empty && i == 0, "Attempting to fetch an out of bounds index from an Only range");
10664 return fetchFront();
10667 static if (isAssignable!T)
10669 void opIndexAssign(T value, size_t i)
10671 assert(!_empty && i == 0, "Attempting to assign an out of bounds index of an Only range");
10672 assignFront(value);
10676 OnlyResult opSlice()
10678 return this;
10681 OnlyResult opSlice(size_t from, size_t to)
10683 assert(
10684 from <= to,
10685 "Attempting to slice an Only range with a larger first argument than the second."
10687 assert(
10688 to <= length,
10689 "Attempting to slice using an out of bounds index on an Only range"
10691 OnlyResult copy = this;
10692 copy._empty = _empty || from == to;
10693 return copy;
10696 // This may alias to shared or immutable data. Do not let the user
10697 // to access this directly, and do not allow mutation without checking
10698 // the qualifier.
10699 private Unqual!T _value;
10700 private bool _empty = true;
10701 private @trusted T fetchFront()
10703 return *cast(T*)&_value;
10705 static if (isAssignable!T)
10707 private @trusted void assignFront(T newValue)
10709 *cast(T*) &_value = newValue;
10715 Assemble `values` into a range that carries all its
10716 elements in-situ.
10718 Useful when a single value or multiple disconnected values
10719 must be passed to an algorithm expecting a range, without
10720 having to perform dynamic memory allocation.
10722 As copying the range means copying all elements, it can be
10723 safely returned from functions. For the same reason, copying
10724 the returned range may be expensive for a large number of arguments.
10726 Params:
10727 values = the values to assemble together
10729 Returns:
10730 A `RandomAccessRange` of the assembled values.
10732 The returned range can be sliced. Its elements can be assigned to if every
10733 type in `Values` supports assignment from the range's element type.
10735 See_Also: $(LREF chain) to chain ranges
10737 auto only(Values...)(return scope Values values)
10738 if (!is(CommonType!Values == void))
10740 return OnlyResult!Values(values);
10743 /// ditto
10744 auto only()()
10746 // cannot use noreturn due to https://issues.dlang.org/show_bug.cgi?id=22383
10747 struct EmptyElementType {}
10748 EmptyElementType[] result;
10749 return result;
10753 @safe unittest
10755 import std.algorithm.comparison : equal;
10756 import std.algorithm.iteration : filter, joiner, map;
10757 import std.algorithm.searching : findSplitBefore;
10758 import std.uni : isUpper;
10760 assert(equal(only('♡'), "♡"));
10761 assert([1, 2, 3, 4].findSplitBefore(only(3))[0] == [1, 2]);
10763 assert(only("one", "two", "three").joiner(" ").equal("one two three"));
10765 string title = "The D Programming Language";
10766 assert(title
10767 .filter!isUpper // take the upper case letters
10768 .map!only // make each letter its own range
10769 .joiner(".") // join the ranges together lazily
10770 .equal("T.D.P.L"));
10773 // https://issues.dlang.org/show_bug.cgi?id=20314
10774 @safe unittest
10776 import std.algorithm.iteration : joiner;
10778 const string s = "foo", t = "bar";
10780 assert([only(s, t), only(t, s)].joiner(only(", ")).join == "foobar, barfoo");
10783 // Tests the zero-element result
10784 @safe unittest
10786 import std.algorithm.comparison : equal;
10788 auto emptyRange = only();
10790 alias EmptyRange = typeof(emptyRange);
10791 static assert(isInputRange!EmptyRange);
10792 static assert(isForwardRange!EmptyRange);
10793 static assert(isBidirectionalRange!EmptyRange);
10794 static assert(isRandomAccessRange!EmptyRange);
10795 static assert(hasLength!EmptyRange);
10796 static assert(hasSlicing!EmptyRange);
10798 assert(emptyRange.empty);
10799 assert(emptyRange.length == 0);
10800 assert(emptyRange.equal(emptyRange[]));
10801 assert(emptyRange.equal(emptyRange.save));
10802 assert(emptyRange[0 .. 0].equal(emptyRange));
10805 // Tests the single-element result
10806 @safe unittest
10808 import std.algorithm.comparison : equal;
10809 import std.typecons : tuple;
10810 foreach (x; tuple(1, '1', 1.0, "1", [1]))
10812 auto a = only(x);
10813 typeof(x)[] e = [];
10814 assert(a.front == x);
10815 assert(a.back == x);
10816 assert(!a.empty);
10817 assert(a.length == 1);
10818 assert(equal(a, a[]));
10819 assert(equal(a, a[0 .. 1]));
10820 assert(equal(a[0 .. 0], e));
10821 assert(equal(a[1 .. 1], e));
10822 assert(a[0] == x);
10824 auto b = a.save;
10825 assert(equal(a, b));
10826 a.popFront();
10827 assert(a.empty && a.length == 0 && a[].empty);
10828 b.popBack();
10829 assert(b.empty && b.length == 0 && b[].empty);
10831 alias A = typeof(a);
10832 static assert(isInputRange!A);
10833 static assert(isForwardRange!A);
10834 static assert(isBidirectionalRange!A);
10835 static assert(isRandomAccessRange!A);
10836 static assert(hasLength!A);
10837 static assert(hasSlicing!A);
10840 auto imm = only!(immutable int)(1);
10841 immutable int[] imme = [];
10842 assert(imm.front == 1);
10843 assert(imm.back == 1);
10844 assert(!imm.empty);
10845 assert(imm.init.empty); // https://issues.dlang.org/show_bug.cgi?id=13441
10846 assert(imm.length == 1);
10847 assert(equal(imm, imm[]));
10848 assert(equal(imm, imm[0 .. 1]));
10849 assert(equal(imm[0 .. 0], imme));
10850 assert(equal(imm[1 .. 1], imme));
10851 assert(imm[0] == 1);
10854 // Tests multiple-element results
10855 @safe unittest
10857 import std.algorithm.comparison : equal;
10858 import std.algorithm.iteration : joiner;
10859 import std.meta : AliasSeq;
10860 static assert(!__traits(compiles, only(1, "1")));
10862 auto nums = only!(byte, uint, long)(1, 2, 3);
10863 static assert(is(ElementType!(typeof(nums)) == long));
10864 assert(nums.length == 3);
10866 foreach (i; 0 .. 3)
10867 assert(nums[i] == i + 1);
10869 auto saved = nums.save;
10871 foreach (i; 1 .. 4)
10873 assert(nums.front == nums[0]);
10874 assert(nums.front == i);
10875 nums.popFront();
10876 assert(nums.length == 3 - i);
10879 assert(nums.empty);
10881 assert(saved.equal(only(1, 2, 3)));
10882 assert(saved.equal(saved[]));
10883 assert(saved[0 .. 1].equal(only(1)));
10884 assert(saved[0 .. 2].equal(only(1, 2)));
10885 assert(saved[0 .. 3].equal(saved));
10886 assert(saved[1 .. 3].equal(only(2, 3)));
10887 assert(saved[2 .. 3].equal(only(3)));
10888 assert(saved[0 .. 0].empty);
10889 assert(saved[3 .. 3].empty);
10891 alias data = AliasSeq!("one", "two", "three", "four");
10892 static joined =
10893 ["one two", "one two three", "one two three four"];
10894 string[] joinedRange = joined;
10896 static foreach (argCount; 2 .. 5)
10898 auto values = only(data[0 .. argCount]);
10899 alias Values = typeof(values);
10900 static assert(is(ElementType!Values == string));
10901 static assert(isInputRange!Values);
10902 static assert(isForwardRange!Values);
10903 static assert(isBidirectionalRange!Values);
10904 static assert(isRandomAccessRange!Values);
10905 static assert(hasSlicing!Values);
10906 static assert(hasLength!Values);
10908 assert(values.length == argCount);
10909 assert(values[0 .. $].equal(values[0 .. values.length]));
10910 assert(values.joiner(" ").equal(joinedRange.front));
10911 joinedRange.popFront();
10914 assert(saved.retro.equal(only(3, 2, 1)));
10915 assert(saved.length == 3);
10917 assert(saved.back == 3);
10918 saved.popBack();
10919 assert(saved.length == 2);
10920 assert(saved.back == 2);
10922 assert(saved.front == 1);
10923 saved.popFront();
10924 assert(saved.length == 1);
10925 assert(saved.front == 2);
10927 saved.popBack();
10928 assert(saved.empty);
10930 auto imm = only!(immutable int, immutable int)(42, 24);
10931 alias Imm = typeof(imm);
10932 static assert(is(ElementType!Imm == immutable(int)));
10933 assert(!imm.empty);
10934 assert(imm.init.empty); // https://issues.dlang.org/show_bug.cgi?id=13441
10935 assert(imm.front == 42);
10936 imm.popFront();
10937 assert(imm.front == 24);
10938 imm.popFront();
10939 assert(imm.empty);
10941 static struct Test { int* a; }
10942 immutable(Test) test;
10943 cast(void) only(test, test); // Works with mutable indirection
10946 // https://issues.dlang.org/show_bug.cgi?id=21129
10947 @safe unittest
10949 auto range = () @safe {
10950 const(char)[5] staticStr = "Hello";
10952 // `only` must store a char[5] - not a char[]!
10953 return only(staticStr, " World");
10954 } ();
10956 assert(range.join == "Hello World");
10959 // https://issues.dlang.org/show_bug.cgi?id=21129
10960 @safe unittest
10962 struct AliasedString
10964 const(char)[5] staticStr = "Hello";
10966 @property const(char)[] slice() const
10968 return staticStr[];
10970 alias slice this;
10973 auto range = () @safe {
10974 auto hello = AliasedString();
10976 // a copy of AliasedString is stored in the range.
10977 return only(hello, " World");
10978 } ();
10980 assert(range.join == "Hello World");
10983 // https://issues.dlang.org/show_bug.cgi?id=21022
10984 @safe pure nothrow unittest
10986 struct S
10988 int* mem;
10991 immutable S x;
10992 immutable(S)[] arr;
10993 auto r1 = arr.chain(x.only, only(x, x));
10996 // https://issues.dlang.org/show_bug.cgi?id=24382
10997 @safe unittest
10999 auto r1 = only(123);
11000 r1.front = 456;
11001 r1.back = 456;
11002 r1[0] = 456;
11004 auto r2 = only(123, 456);
11005 r2.front = 789;
11006 r2.back = 789;
11007 r2[0] = 789;
11009 auto r3 = only(1.23, 456);
11010 // Can't assign double to int
11011 static assert(!__traits(compiles, r3.front = 7.89));
11012 static assert(!__traits(compiles, r3.back = 7.89));
11013 // Workaround https://issues.dlang.org/show_bug.cgi?id=24383
11014 static assert(!__traits(compiles, () { r3[0] = 7.89; }));
11015 // Can't assign type other than element type (even if compatible)
11016 static assert(!__traits(compiles, r3.front = 789));
11017 static assert(!__traits(compiles, r3.back = 789));
11018 // Workaround https://issues.dlang.org/show_bug.cgi?id=24383
11019 static assert(!__traits(compiles, () { r3[0] = 789; }));
11023 Iterate over `range` with an attached index variable.
11025 Each element is a $(REF Tuple, std,typecons) containing the index
11026 and the element, in that order, where the index member is named `index`
11027 and the element member is named `value`.
11029 The index starts at `start` and is incremented by one on every iteration.
11031 Overflow:
11032 If `range` has length, then it is an error to pass a value for `start`
11033 so that `start + range.length` is bigger than `Enumerator.max`, thus
11034 it is ensured that overflow cannot happen.
11036 If `range` does not have length, and `popFront` is called when
11037 `front.index == Enumerator.max`, the index will overflow and
11038 continue from `Enumerator.min`.
11040 Params:
11041 range = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to attach indexes to
11042 start = the number to start the index counter from
11044 Returns:
11045 At minimum, an input range. All other range primitives are given in the
11046 resulting range if `range` has them. The exceptions are the bidirectional
11047 primitives, which are propagated only if `range` has length.
11049 Example:
11050 Useful for using `foreach` with an index loop variable:
11051 ----
11052 import std.stdio : stdin, stdout;
11053 import std.range : enumerate;
11055 foreach (lineNum, line; stdin.byLine().enumerate(1))
11056 stdout.writefln("line #%s: %s", lineNum, line);
11057 ----
11059 auto enumerate(Enumerator = size_t, Range)(Range range, Enumerator start = 0)
11060 if (isIntegral!Enumerator && isInputRange!Range)
11063 static if (hasLength!Range)
11065 // TODO: core.checkedint supports mixed signedness yet?
11066 import core.checkedint : adds, addu;
11067 import std.conv : ConvException, to;
11068 import std.traits : isSigned, Largest, Signed;
11070 alias LengthType = typeof(range.length);
11071 bool overflow;
11072 static if (isSigned!Enumerator && isSigned!LengthType)
11073 auto result = adds(start, range.length, overflow);
11074 else static if (isSigned!Enumerator)
11076 alias signed_t = Largest!(Enumerator, Signed!LengthType);
11077 signed_t signedLength;
11078 //This is to trick the compiler because if length is enum
11079 //the compiler complains about unreachable code.
11080 auto getLength()
11082 return range.length;
11084 //Can length fit in the signed type
11085 assert(getLength() < signed_t.max,
11086 "a signed length type is required but the range's length() is too great");
11087 signedLength = range.length;
11088 auto result = adds(start, signedLength, overflow);
11090 else
11092 static if (isSigned!LengthType)
11093 assert(range.length >= 0);
11094 auto result = addu(start, range.length, overflow);
11097 assert(!overflow && result <= Enumerator.max);
11102 // TODO: Relax isIntegral!Enumerator to allow user-defined integral types
11103 static struct Result
11105 import std.typecons : Tuple;
11107 private:
11108 alias ElemType = Tuple!(Enumerator, "index", ElementType!Range, "value");
11109 Range range;
11110 Unqual!Enumerator index;
11112 public:
11113 ElemType front() @property
11115 assert(!range.empty, "Attempting to fetch the front of an empty enumerate");
11116 return typeof(return)(index, range.front);
11119 static if (isInfinite!Range)
11120 enum bool empty = false;
11121 else
11123 bool empty() @property
11125 return range.empty;
11129 void popFront()
11131 assert(!range.empty, "Attempting to popFront an empty enumerate");
11132 range.popFront();
11133 ++index; // When !hasLength!Range, overflow is expected
11136 static if (isForwardRange!Range)
11138 Result save() @property
11140 return typeof(return)(range.save, index);
11144 static if (hasLength!Range)
11146 mixin ImplementLength!range;
11148 static if (isBidirectionalRange!Range)
11150 ElemType back() @property
11152 assert(!range.empty, "Attempting to fetch the back of an empty enumerate");
11153 return typeof(return)(cast(Enumerator)(index + range.length - 1), range.back);
11156 void popBack()
11158 assert(!range.empty, "Attempting to popBack an empty enumerate");
11159 range.popBack();
11164 static if (isRandomAccessRange!Range)
11166 ElemType opIndex(size_t i)
11168 return typeof(return)(cast(Enumerator)(index + i), range[i]);
11172 static if (hasSlicing!Range)
11174 static if (hasLength!Range)
11176 Result opSlice(size_t i, size_t j)
11178 return typeof(return)(range[i .. j], cast(Enumerator)(index + i));
11181 else
11183 static struct DollarToken {}
11184 enum opDollar = DollarToken.init;
11186 Result opSlice(size_t i, DollarToken)
11188 return typeof(return)(range[i .. $], cast(Enumerator)(index + i));
11191 auto opSlice(size_t i, size_t j)
11193 return this[i .. $].takeExactly(j - 1);
11199 return Result(range, start);
11202 /// Can start enumeration from a negative position:
11203 pure @safe nothrow unittest
11205 import std.array : assocArray;
11206 import std.range : enumerate;
11208 bool[int] aa = true.repeat(3).enumerate(-1).assocArray();
11209 assert(aa[-1]);
11210 assert(aa[0]);
11211 assert(aa[1]);
11214 // Make sure passing qualified types works
11215 pure @safe nothrow unittest
11217 char[4] v;
11218 immutable start = 2;
11219 v[2 .. $].enumerate(start);
11222 pure @safe nothrow unittest
11224 import std.internal.test.dummyrange : AllDummyRanges;
11225 import std.meta : AliasSeq;
11226 import std.typecons : tuple;
11228 static struct HasSlicing
11230 typeof(this) front() @property { return typeof(this).init; }
11231 bool empty() @property { return true; }
11232 void popFront() {}
11234 typeof(this) opSlice(size_t, size_t)
11236 return typeof(this)();
11240 static foreach (DummyType; AliasSeq!(AllDummyRanges, HasSlicing))
11242 alias R = typeof(enumerate(DummyType.init));
11243 static assert(isInputRange!R);
11244 static assert(isForwardRange!R == isForwardRange!DummyType);
11245 static assert(isRandomAccessRange!R == isRandomAccessRange!DummyType);
11246 static assert(!hasAssignableElements!R);
11248 static if (hasLength!DummyType)
11250 static assert(hasLength!R);
11251 static assert(isBidirectionalRange!R ==
11252 isBidirectionalRange!DummyType);
11255 static assert(hasSlicing!R == hasSlicing!DummyType);
11258 static immutable values = ["zero", "one", "two", "three"];
11259 auto enumerated = values[].enumerate();
11260 assert(!enumerated.empty);
11261 assert(enumerated.front == tuple(0, "zero"));
11262 assert(enumerated.back == tuple(3, "three"));
11264 typeof(enumerated) saved = enumerated.save;
11265 saved.popFront();
11266 assert(enumerated.front == tuple(0, "zero"));
11267 assert(saved.front == tuple(1, "one"));
11268 assert(saved.length == enumerated.length - 1);
11269 saved.popBack();
11270 assert(enumerated.back == tuple(3, "three"));
11271 assert(saved.back == tuple(2, "two"));
11272 saved.popFront();
11273 assert(saved.front == tuple(2, "two"));
11274 assert(saved.back == tuple(2, "two"));
11275 saved.popFront();
11276 assert(saved.empty);
11278 size_t control = 0;
11279 foreach (i, v; enumerated)
11281 static assert(is(typeof(i) == size_t));
11282 static assert(is(typeof(v) == typeof(values[0])));
11283 assert(i == control);
11284 assert(v == values[i]);
11285 assert(tuple(i, v) == enumerated[i]);
11286 ++control;
11289 assert(enumerated[0 .. $].front == tuple(0, "zero"));
11290 assert(enumerated[$ - 1 .. $].front == tuple(3, "three"));
11292 foreach (i; 0 .. 10)
11294 auto shifted = values[0 .. 2].enumerate(i);
11295 assert(shifted.front == tuple(i, "zero"));
11296 assert(shifted[0] == shifted.front);
11298 auto next = tuple(i + 1, "one");
11299 assert(shifted[1] == next);
11300 shifted.popFront();
11301 assert(shifted.front == next);
11302 shifted.popFront();
11303 assert(shifted.empty);
11306 static foreach (T; AliasSeq!(ubyte, byte, uint, int))
11308 auto inf = 42.repeat().enumerate(T.max);
11309 alias Inf = typeof(inf);
11310 static assert(isInfinite!Inf);
11311 static assert(hasSlicing!Inf);
11313 // test overflow
11314 assert(inf.front == tuple(T.max, 42));
11315 inf.popFront();
11316 assert(inf.front == tuple(T.min, 42));
11318 // test slicing
11319 inf = inf[42 .. $];
11320 assert(inf.front == tuple(T.min + 42, 42));
11321 auto window = inf[0 .. 2];
11322 assert(window.length == 1);
11323 assert(window.front == inf.front);
11324 window.popFront();
11325 assert(window.empty);
11329 pure @safe unittest
11331 import std.algorithm.comparison : equal;
11332 import std.meta : AliasSeq;
11333 static immutable int[] values = [0, 1, 2, 3, 4];
11334 static foreach (T; AliasSeq!(ubyte, ushort, uint, ulong))
11336 auto enumerated = values.enumerate!T();
11337 static assert(is(typeof(enumerated.front.index) == T));
11338 assert(enumerated.equal(values[].zip(values)));
11340 foreach (T i; 0 .. 5)
11342 auto subset = values[cast(size_t) i .. $];
11343 auto offsetEnumerated = subset.enumerate(i);
11344 static assert(is(typeof(enumerated.front.index) == T));
11345 assert(offsetEnumerated.equal(subset.zip(subset)));
11349 @nogc @safe unittest
11351 const val = iota(1, 100).enumerate(1);
11353 @nogc @safe unittest
11355 import core.exception : AssertError;
11356 import std.exception : assertThrown;
11357 struct RangePayload {
11358 enum length = size_t.max;
11359 void popFront() {}
11360 int front() { return 0; }
11361 bool empty() { return true; }
11363 RangePayload thePayload;
11364 //Assertion won't happen when contracts are disabled for -release.
11365 debug assertThrown!AssertError(enumerate(thePayload, -10));
11367 // https://issues.dlang.org/show_bug.cgi?id=10939
11368 version (none)
11370 // Re-enable (or remove) if 10939 is resolved.
11371 /+pure+/ @safe unittest // Impure because of std.conv.to
11373 import core.exception : RangeError;
11374 import std.exception : assertNotThrown, assertThrown;
11375 import std.meta : AliasSeq;
11377 static immutable values = [42];
11379 static struct SignedLengthRange
11381 immutable(int)[] _values = values;
11383 int front() @property { assert(false); }
11384 bool empty() @property { assert(false); }
11385 void popFront() { assert(false); }
11387 int length() @property
11389 return cast(int)_values.length;
11393 SignedLengthRange svalues;
11394 static foreach (Enumerator; AliasSeq!(ubyte, byte, ushort, short, uint, int, ulong, long))
11396 assertThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max));
11397 assertNotThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max - values.length));
11398 assertThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max - values.length + 1));
11400 assertThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max));
11401 assertNotThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max - values.length));
11402 assertThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max - values.length + 1));
11405 static foreach (Enumerator; AliasSeq!(byte, short, int))
11407 assertThrown!RangeError(repeat(0, uint.max).enumerate!Enumerator());
11410 assertNotThrown!RangeError(repeat(0, uint.max).enumerate!long());
11415 Returns true if `fn` accepts variables of type T1 and T2 in any order.
11416 The following code should compile:
11418 (ref T1 a, ref T2 b)
11420 fn(a, b);
11421 fn(b, a);
11425 template isTwoWayCompatible(alias fn, T1, T2)
11427 enum isTwoWayCompatible = is(typeof((ref T1 a, ref T2 b)
11429 cast(void) fn(a, b);
11430 cast(void) fn(b, a);
11436 @safe unittest
11438 void func1(int a, int b);
11439 void func2(int a, float b);
11441 static assert(isTwoWayCompatible!(func1, int, int));
11442 static assert(isTwoWayCompatible!(func1, short, int));
11443 static assert(!isTwoWayCompatible!(func2, int, float));
11445 void func3(ref int a, ref int b);
11446 static assert( isTwoWayCompatible!(func3, int, int));
11447 static assert(!isTwoWayCompatible!(func3, short, int));
11452 Policy used with the searching primitives `lowerBound`, $(D
11453 upperBound), and `equalRange` of $(LREF SortedRange) below.
11455 enum SearchPolicy
11458 Searches in a linear fashion.
11460 linear,
11463 Searches with a step that is grows linearly (1, 2, 3,...)
11464 leading to a quadratic search schedule (indexes tried are 0, 1,
11465 3, 6, 10, 15, 21, 28,...) Once the search overshoots its target,
11466 the remaining interval is searched using binary search. The
11467 search is completed in $(BIGOH sqrt(n)) time. Use it when you
11468 are reasonably confident that the value is around the beginning
11469 of the range.
11471 trot,
11474 Performs a $(LINK2 https://en.wikipedia.org/wiki/Exponential_search,
11475 galloping search algorithm), i.e. searches
11476 with a step that doubles every time, (1, 2, 4, 8, ...) leading
11477 to an exponential search schedule (indexes tried are 0, 1, 3,
11478 7, 15, 31, 63,...) Once the search overshoots its target, the
11479 remaining interval is searched using binary search. A value is
11480 found in $(BIGOH log(n)) time.
11482 gallop,
11485 Searches using a classic interval halving policy. The search
11486 starts in the middle of the range, and each search step cuts
11487 the range in half. This policy finds a value in $(BIGOH log(n))
11488 time but is less cache friendly than `gallop` for large
11489 ranges. The `binarySearch` policy is used as the last step
11490 of `trot`, `gallop`, `trotBackwards`, and $(D
11491 gallopBackwards) strategies.
11493 binarySearch,
11496 Similar to `trot` but starts backwards. Use it when
11497 confident that the value is around the end of the range.
11499 trotBackwards,
11502 Similar to `gallop` but starts backwards. Use it when
11503 confident that the value is around the end of the range.
11505 gallopBackwards
11509 @safe unittest
11511 import std.algorithm.comparison : equal;
11513 auto a = assumeSorted([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
11514 auto p1 = a.upperBound!(SearchPolicy.binarySearch)(3);
11515 assert(p1.equal([4, 5, 6, 7, 8, 9]));
11517 auto p2 = a.lowerBound!(SearchPolicy.gallop)(4);
11518 assert(p2.equal([0, 1, 2, 3]));
11522 Options for $(LREF SortedRange) ranges (below).
11524 enum SortedRangeOptions
11527 Assume, that the range is sorted without checking.
11529 assumeSorted,
11532 All elements of the range are checked to be sorted.
11533 The check is performed in O(n) time.
11535 checkStrictly,
11538 Some elements of the range are checked to be sorted.
11539 For ranges with random order, this will almost surely
11540 detect, that it is not sorted. For almost sorted ranges
11541 it's more likely to fail. The checked elements are choosen
11542 in a deterministic manner, which makes this check reproducable.
11543 The check is performed in O(log(n)) time.
11545 checkRoughly,
11549 @safe pure unittest
11551 // create a SortedRange, that's checked strictly
11552 SortedRange!(int[],"a < b", SortedRangeOptions.checkStrictly)([ 1, 3, 5, 7, 9 ]);
11556 Represents a sorted range. In addition to the regular range
11557 primitives, supports additional operations that take advantage of the
11558 ordering, such as merge and binary search. To obtain a $(D
11559 SortedRange) from an unsorted range `r`, use
11560 $(REF sort, std,algorithm,sorting) which sorts `r` in place and returns the
11561 corresponding `SortedRange`. To construct a `SortedRange` from a range
11562 `r` that is known to be already sorted, use $(LREF assumeSorted).
11564 Params:
11565 pred: The predicate used to define the sortedness
11566 opt: Controls how strongly the range is checked for sortedness.
11567 Will only be used for `RandomAccessRanges`.
11568 Will not be used in CTFE.
11570 struct SortedRange(Range, alias pred = "a < b",
11571 SortedRangeOptions opt = SortedRangeOptions.assumeSorted)
11572 if (isInputRange!Range && !isInstanceOf!(SortedRange, Range))
11574 import std.functional : binaryFun;
11576 private alias predFun = binaryFun!pred;
11577 private bool geq(L, R)(L lhs, R rhs)
11579 return !predFun(lhs, rhs);
11581 private bool gt(L, R)(L lhs, R rhs)
11583 return predFun(rhs, lhs);
11585 private Range _input;
11587 // Undocummented because a clearer way to invoke is by calling
11588 // assumeSorted.
11589 this(Range input)
11591 static if (opt == SortedRangeOptions.checkRoughly)
11593 roughlyVerifySorted(input);
11595 static if (opt == SortedRangeOptions.checkStrictly)
11597 strictlyVerifySorted(input);
11599 this._input = input;
11602 // Assertion only.
11603 static if (opt == SortedRangeOptions.checkRoughly)
11604 private void roughlyVerifySorted(Range r)
11606 if (!__ctfe)
11608 static if (isRandomAccessRange!Range && hasLength!Range)
11610 import core.bitop : bsr;
11611 import std.algorithm.sorting : isSorted;
11612 import std.exception : enforce;
11614 // Check the sortedness of the input
11615 if (r.length < 2) return;
11617 immutable size_t msb = bsr(r.length) + 1;
11618 assert(msb > 0 && msb <= r.length);
11619 immutable step = r.length / msb;
11620 auto st = stride(r, step);
11622 enforce(isSorted!pred(st), "Range is not sorted");
11627 // Assertion only.
11628 static if (opt == SortedRangeOptions.checkStrictly)
11629 private void strictlyVerifySorted(Range r)
11631 if (!__ctfe)
11633 static if (isRandomAccessRange!Range && hasLength!Range)
11635 import std.algorithm.sorting : isSorted;
11636 import std.exception : enforce;
11638 enforce(isSorted!pred(r), "Range is not sorted");
11643 /// Range primitives.
11644 @property bool empty() //const
11646 return this._input.empty;
11649 /// Ditto
11650 static if (isForwardRange!Range)
11651 @property auto save()
11653 // Avoid the constructor
11654 typeof(this) result = this;
11655 result._input = _input.save;
11656 return result;
11659 /// Ditto
11660 @property auto ref front()
11662 return _input.front;
11665 /// Ditto
11666 void popFront()
11668 _input.popFront();
11671 /// Ditto
11672 static if (isBidirectionalRange!Range)
11674 @property auto ref back()
11676 return _input.back;
11679 /// Ditto
11680 void popBack()
11682 _input.popBack();
11686 /// Ditto
11687 static if (isRandomAccessRange!Range)
11688 auto ref opIndex(size_t i)
11690 return _input[i];
11693 /// Ditto
11694 static if (hasSlicing!Range)
11695 auto opSlice(size_t a, size_t b) return scope
11697 assert(
11698 a <= b,
11699 "Attempting to slice a SortedRange with a larger first argument than the second."
11701 typeof(this) result = this;
11702 result._input = _input[a .. b];// skip checking
11703 return result;
11706 mixin ImplementLength!_input;
11709 Releases the controlled range and returns it.
11711 This does the opposite of $(LREF assumeSorted): instead of turning a range
11712 into a `SortedRange`, it extracts the original range back out of the `SortedRange`
11713 using $(REF, move, std,algorithm,mutation).
11715 auto release() return scope
11717 import std.algorithm.mutation : move;
11718 return move(_input);
11722 static if (is(Range : int[]))
11723 @safe unittest
11725 import std.algorithm.sorting : sort;
11726 int[3] data = [ 1, 2, 3 ];
11727 auto a = assumeSorted(data[]);
11728 assert(a == sort!"a < b"(data[]));
11729 int[] p = a.release();
11730 assert(p == [ 1, 2, 3 ]);
11733 // Assuming a predicate "test" that returns 0 for a left portion
11734 // of the range and then 1 for the rest, returns the index at
11735 // which the first 1 appears. Used internally by the search routines.
11736 private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v)
11737 if (sp == SearchPolicy.binarySearch && isRandomAccessRange!Range && hasLength!Range)
11739 size_t first = 0, count = _input.length;
11740 while (count > 0)
11742 immutable step = count / 2, it = first + step;
11743 if (!test(_input[it], v))
11745 first = it + 1;
11746 count -= step + 1;
11748 else
11750 count = step;
11753 return first;
11756 // Specialization for trot and gallop
11757 private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v)
11758 if ((sp == SearchPolicy.trot || sp == SearchPolicy.gallop)
11759 && isRandomAccessRange!Range)
11761 if (empty || test(front, v)) return 0;
11762 immutable count = length;
11763 if (count == 1) return 1;
11764 size_t below = 0, above = 1, step = 2;
11765 while (!test(_input[above], v))
11767 // Still too small, update below and increase gait
11768 below = above;
11769 immutable next = above + step;
11770 if (next >= count)
11772 // Overshot - the next step took us beyond the end. So
11773 // now adjust next and simply exit the loop to do the
11774 // binary search thingie.
11775 above = count;
11776 break;
11778 // Still in business, increase step and continue
11779 above = next;
11780 static if (sp == SearchPolicy.trot)
11781 ++step;
11782 else
11783 step <<= 1;
11785 return below + this[below .. above].getTransitionIndex!(
11786 SearchPolicy.binarySearch, test, V)(v);
11789 // Specialization for trotBackwards and gallopBackwards
11790 private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v)
11791 if ((sp == SearchPolicy.trotBackwards || sp == SearchPolicy.gallopBackwards)
11792 && isRandomAccessRange!Range)
11794 immutable count = length;
11795 if (empty || !test(back, v)) return count;
11796 if (count == 1) return 0;
11797 size_t below = count - 2, above = count - 1, step = 2;
11798 while (test(_input[below], v))
11800 // Still too large, update above and increase gait
11801 above = below;
11802 if (below < step)
11804 // Overshot - the next step took us beyond the end. So
11805 // now adjust next and simply fall through to do the
11806 // binary search thingie.
11807 below = 0;
11808 break;
11810 // Still in business, increase step and continue
11811 below -= step;
11812 static if (sp == SearchPolicy.trot)
11813 ++step;
11814 else
11815 step <<= 1;
11817 return below + this[below .. above].getTransitionIndex!(
11818 SearchPolicy.binarySearch, test, V)(v);
11821 // lowerBound
11823 This function uses a search with policy `sp` to find the
11824 largest left subrange on which $(D pred(x, value)) is `true` for
11825 all `x` (e.g., if `pred` is "less than", returns the portion of
11826 the range with elements strictly smaller than `value`). The search
11827 schedule and its complexity are documented in
11828 $(LREF SearchPolicy).
11830 auto lowerBound(SearchPolicy sp = SearchPolicy.binarySearch, V)(V value)
11831 if (isTwoWayCompatible!(predFun, ElementType!Range, V)
11832 && hasSlicing!Range)
11834 return this[0 .. getTransitionIndex!(sp, geq)(value)];
11838 static if (is(Range : int[]))
11839 @safe unittest
11841 import std.algorithm.comparison : equal;
11842 auto a = assumeSorted([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]);
11843 auto p = a.lowerBound(4);
11844 assert(equal(p, [ 0, 1, 2, 3 ]));
11847 // upperBound
11849 This function searches with policy `sp` to find the largest right
11850 subrange on which $(D pred(value, x)) is `true` for all `x`
11851 (e.g., if `pred` is "less than", returns the portion of the range
11852 with elements strictly greater than `value`). The search schedule
11853 and its complexity are documented in $(LREF SearchPolicy).
11855 For ranges that do not offer random access, `SearchPolicy.linear`
11856 is the only policy allowed (and it must be specified explicitly lest it exposes
11857 user code to unexpected inefficiencies). For random-access searches, all
11858 policies are allowed, and `SearchPolicy.binarySearch` is the default.
11860 auto upperBound(SearchPolicy sp = SearchPolicy.binarySearch, V)(V value)
11861 if (isTwoWayCompatible!(predFun, ElementType!Range, V))
11863 static assert(hasSlicing!Range || sp == SearchPolicy.linear,
11864 "Specify SearchPolicy.linear explicitly for "
11865 ~ typeof(this).stringof);
11866 static if (sp == SearchPolicy.linear)
11868 for (; !_input.empty && !predFun(value, _input.front);
11869 _input.popFront())
11872 return this;
11874 else
11876 return this[getTransitionIndex!(sp, gt)(value) .. length];
11881 static if (is(Range : int[]))
11882 @safe unittest
11884 import std.algorithm.comparison : equal;
11885 auto a = assumeSorted([ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]);
11886 auto p = a.upperBound(3);
11887 assert(equal(p, [4, 4, 5, 6]));
11891 // equalRange
11893 Returns the subrange containing all elements `e` for which both $(D
11894 pred(e, value)) and $(D pred(value, e)) evaluate to `false` (e.g.,
11895 if `pred` is "less than", returns the portion of the range with
11896 elements equal to `value`). Uses a classic binary search with
11897 interval halving until it finds a value that satisfies the condition,
11898 then uses `SearchPolicy.gallopBackwards` to find the left boundary
11899 and `SearchPolicy.gallop` to find the right boundary. These
11900 policies are justified by the fact that the two boundaries are likely
11901 to be near the first found value (i.e., equal ranges are relatively
11902 small). Completes the entire search in $(BIGOH log(n)) time.
11904 auto equalRange(V)(V value)
11905 if (isTwoWayCompatible!(predFun, ElementType!Range, V)
11906 && isRandomAccessRange!Range)
11908 size_t first = 0, count = _input.length;
11909 while (count > 0)
11911 immutable step = count / 2;
11912 auto it = first + step;
11913 if (predFun(_input[it], value))
11915 // Less than value, bump left bound up
11916 first = it + 1;
11917 count -= step + 1;
11919 else if (predFun(value, _input[it]))
11921 // Greater than value, chop count
11922 count = step;
11924 else
11926 // Equal to value, do binary searches in the
11927 // leftover portions
11928 // Gallop towards the left end as it's likely nearby
11929 immutable left = first
11930 + this[first .. it]
11931 .lowerBound!(SearchPolicy.gallopBackwards)(value).length;
11932 first += count;
11933 // Gallop towards the right end as it's likely nearby
11934 immutable right = first
11935 - this[it + 1 .. first]
11936 .upperBound!(SearchPolicy.gallop)(value).length;
11937 return this[left .. right];
11940 return this.init;
11944 static if (is(Range : int[]))
11945 @safe unittest
11947 import std.algorithm.comparison : equal;
11948 auto a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
11949 auto r = a.assumeSorted.equalRange(3);
11950 assert(equal(r, [ 3, 3, 3 ]));
11953 // trisect
11955 Returns a tuple `r` such that `r[0]` is the same as the result
11956 of `lowerBound(value)`, `r[1]` is the same as the result of $(D
11957 equalRange(value)), and `r[2]` is the same as the result of $(D
11958 upperBound(value)). The call is faster than computing all three
11959 separately. Uses a search schedule similar to $(D
11960 equalRange). Completes the entire search in $(BIGOH log(n)) time.
11962 auto trisect(V)(V value)
11963 if (isTwoWayCompatible!(predFun, ElementType!Range, V)
11964 && isRandomAccessRange!Range && hasLength!Range)
11966 import std.typecons : tuple;
11967 size_t first = 0, count = _input.length;
11968 while (count > 0)
11970 immutable step = count / 2;
11971 auto it = first + step;
11972 if (predFun(_input[it], value))
11974 // Less than value, bump left bound up
11975 first = it + 1;
11976 count -= step + 1;
11978 else if (predFun(value, _input[it]))
11980 // Greater than value, chop count
11981 count = step;
11983 else
11985 // Equal to value, do binary searches in the
11986 // leftover portions
11987 // Gallop towards the left end as it's likely nearby
11988 immutable left = first
11989 + this[first .. it]
11990 .lowerBound!(SearchPolicy.gallopBackwards)(value).length;
11991 first += count;
11992 // Gallop towards the right end as it's likely nearby
11993 immutable right = first
11994 - this[it + 1 .. first]
11995 .upperBound!(SearchPolicy.gallop)(value).length;
11996 return tuple(this[0 .. left], this[left .. right],
11997 this[right .. length]);
12000 // No equal element was found
12001 return tuple(this[0 .. first], this.init, this[first .. length]);
12005 static if (is(Range : int[]))
12006 @safe unittest
12008 import std.algorithm.comparison : equal;
12009 auto a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
12010 auto r = assumeSorted(a).trisect(3);
12011 assert(equal(r[0], [ 1, 2 ]));
12012 assert(equal(r[1], [ 3, 3, 3 ]));
12013 assert(equal(r[2], [ 4, 4, 5, 6 ]));
12016 // contains
12018 Returns `true` if and only if `value` can be found in $(D
12019 range), which is assumed to be sorted. Performs $(BIGOH log(r.length))
12020 evaluations of `pred`.
12023 bool contains(V)(V value)
12024 if (isRandomAccessRange!Range)
12026 if (empty) return false;
12027 immutable i = getTransitionIndex!(SearchPolicy.binarySearch, geq)(value);
12028 if (i >= length) return false;
12029 return !predFun(value, _input[i]);
12033 Like `contains`, but the value is specified before the range.
12035 bool opBinaryRight(string op, V)(V value)
12036 if (op == "in" && isRandomAccessRange!Range)
12038 return contains(value);
12041 // groupBy
12043 Returns a range of subranges of elements that are equivalent according to the
12044 sorting relation.
12046 auto groupBy()()
12048 import std.algorithm.iteration : chunkBy;
12049 return _input.chunkBy!((a, b) => !predFun(a, b) && !predFun(b, a));
12053 /// ditto
12054 template SortedRange(Range, alias pred = "a < b",
12055 SortedRangeOptions opt = SortedRangeOptions.assumeSorted)
12056 if (isInstanceOf!(SortedRange, Range))
12058 // Avoid nesting SortedRange types (see https://issues.dlang.org/show_bug.cgi?id=18933);
12059 alias SortedRange = SortedRange!(Unqual!(typeof(Range._input)), pred, opt);
12063 @safe unittest
12065 import std.algorithm.sorting : sort;
12066 auto a = [ 1, 2, 3, 42, 52, 64 ];
12067 auto r = assumeSorted(a);
12068 assert(r.contains(3));
12069 assert(!(32 in r));
12070 auto r1 = sort!"a > b"(a);
12071 assert(3 in r1);
12072 assert(!r1.contains(32));
12073 assert(r1.release() == [ 64, 52, 42, 3, 2, 1 ]);
12077 `SortedRange` could accept ranges weaker than random-access, but it
12078 is unable to provide interesting functionality for them. Therefore,
12079 `SortedRange` is currently restricted to random-access ranges.
12081 No copy of the original range is ever made. If the underlying range is
12082 changed concurrently with its corresponding `SortedRange` in ways
12083 that break its sorted-ness, `SortedRange` will work erratically.
12085 @safe unittest
12087 import std.algorithm.mutation : swap;
12088 auto a = [ 1, 2, 3, 42, 52, 64 ];
12089 auto r = assumeSorted(a);
12090 assert(r.contains(42));
12091 swap(a[3], a[5]); // illegal to break sortedness of original range
12092 assert(!r.contains(42)); // passes although it shouldn't
12096 `SortedRange` can be searched with predicates that do not take
12097 two elements of the underlying range as arguments.
12099 This is useful, if a range of structs is sorted by a member and you
12100 want to search in that range by only providing a value for that member.
12103 @safe unittest
12105 import std.algorithm.comparison : equal;
12106 static struct S { int i; }
12107 static bool byI(A, B)(A a, B b)
12109 static if (is(A == S))
12110 return a.i < b;
12111 else
12112 return a < b.i;
12114 auto r = assumeSorted!byI([S(1), S(2), S(3)]);
12115 auto lessThanTwo = r.lowerBound(2);
12116 assert(equal(lessThanTwo, [S(1)]));
12119 @safe unittest
12121 import std.exception : assertThrown, assertNotThrown;
12123 assertNotThrown(SortedRange!(int[])([ 1, 3, 10, 5, 7 ]));
12124 assertThrown(SortedRange!(int[],"a < b", SortedRangeOptions.checkStrictly)([ 1, 3, 10, 5, 7 ]));
12126 // these two checks are implementation depended
12127 assertNotThrown(SortedRange!(int[],"a < b", SortedRangeOptions.checkRoughly)([ 1, 3, 10, 5, 12, 2 ]));
12128 assertThrown(SortedRange!(int[],"a < b", SortedRangeOptions.checkRoughly)([ 1, 3, 10, 5, 2, 12 ]));
12131 @safe unittest
12133 import std.algorithm.comparison : equal;
12135 auto a = [ 10, 20, 30, 30, 30, 40, 40, 50, 60 ];
12136 auto r = assumeSorted(a).trisect(30);
12137 assert(equal(r[0], [ 10, 20 ]));
12138 assert(equal(r[1], [ 30, 30, 30 ]));
12139 assert(equal(r[2], [ 40, 40, 50, 60 ]));
12141 r = assumeSorted(a).trisect(35);
12142 assert(equal(r[0], [ 10, 20, 30, 30, 30 ]));
12143 assert(r[1].empty);
12144 assert(equal(r[2], [ 40, 40, 50, 60 ]));
12147 @safe unittest
12149 import std.algorithm.comparison : equal;
12150 auto a = [ "A", "AG", "B", "E", "F" ];
12151 auto r = assumeSorted!"cmp(a,b) < 0"(a).trisect("B"w);
12152 assert(equal(r[0], [ "A", "AG" ]));
12153 assert(equal(r[1], [ "B" ]));
12154 assert(equal(r[2], [ "E", "F" ]));
12155 r = assumeSorted!"cmp(a,b) < 0"(a).trisect("A"d);
12156 assert(r[0].empty);
12157 assert(equal(r[1], [ "A" ]));
12158 assert(equal(r[2], [ "AG", "B", "E", "F" ]));
12161 @safe unittest
12163 import std.algorithm.comparison : equal;
12164 static void test(SearchPolicy pol)()
12166 auto a = [ 1, 2, 3, 42, 52, 64 ];
12167 auto r = assumeSorted(a);
12168 assert(equal(r.lowerBound(42), [1, 2, 3]));
12170 assert(equal(r.lowerBound!(pol)(42), [1, 2, 3]));
12171 assert(equal(r.lowerBound!(pol)(41), [1, 2, 3]));
12172 assert(equal(r.lowerBound!(pol)(43), [1, 2, 3, 42]));
12173 assert(equal(r.lowerBound!(pol)(51), [1, 2, 3, 42]));
12174 assert(equal(r.lowerBound!(pol)(3), [1, 2]));
12175 assert(equal(r.lowerBound!(pol)(55), [1, 2, 3, 42, 52]));
12176 assert(equal(r.lowerBound!(pol)(420), a));
12177 assert(equal(r.lowerBound!(pol)(0), a[0 .. 0]));
12179 assert(equal(r.upperBound!(pol)(42), [52, 64]));
12180 assert(equal(r.upperBound!(pol)(41), [42, 52, 64]));
12181 assert(equal(r.upperBound!(pol)(43), [52, 64]));
12182 assert(equal(r.upperBound!(pol)(51), [52, 64]));
12183 assert(equal(r.upperBound!(pol)(53), [64]));
12184 assert(equal(r.upperBound!(pol)(55), [64]));
12185 assert(equal(r.upperBound!(pol)(420), a[0 .. 0]));
12186 assert(equal(r.upperBound!(pol)(0), a));
12189 test!(SearchPolicy.trot)();
12190 test!(SearchPolicy.gallop)();
12191 test!(SearchPolicy.trotBackwards)();
12192 test!(SearchPolicy.gallopBackwards)();
12193 test!(SearchPolicy.binarySearch)();
12196 @safe unittest
12198 // Check for small arrays
12199 int[] a;
12200 auto r = assumeSorted(a);
12201 a = [ 1 ];
12202 r = assumeSorted(a);
12203 a = [ 1, 2 ];
12204 r = assumeSorted(a);
12205 a = [ 1, 2, 3 ];
12206 r = assumeSorted(a);
12209 @safe unittest
12211 import std.algorithm.mutation : swap;
12212 auto a = [ 1, 2, 3, 42, 52, 64 ];
12213 auto r = assumeSorted(a);
12214 assert(r.contains(42));
12215 swap(a[3], a[5]); // illegal to break sortedness of original range
12216 assert(!r.contains(42)); // passes although it shouldn't
12219 @betterC @nogc nothrow @safe unittest
12221 static immutable(int)[] arr = [ 1, 2, 3 ];
12222 auto s = assumeSorted(arr);
12225 @system unittest
12227 import std.algorithm.comparison : equal;
12228 int[] arr = [100, 101, 102, 200, 201, 300];
12229 auto s = assumeSorted!((a, b) => a / 100 < b / 100)(arr);
12230 assert(s.groupBy.equal!equal([[100, 101, 102], [200, 201], [300]]));
12233 // Test on an input range
12234 @system unittest
12236 import std.conv : text;
12237 import std.file : exists, remove, tempDir;
12238 import std.path : buildPath;
12239 import std.stdio : File;
12240 import std.uuid : randomUUID;
12241 auto name = buildPath(tempDir(), "test.std.range.line-" ~ text(__LINE__) ~
12242 "." ~ randomUUID().toString());
12243 auto f = File(name, "w");
12244 scope(exit) if (exists(name)) remove(name);
12245 // write a sorted range of lines to the file
12246 f.write("abc\ndef\nghi\njkl");
12247 f.close();
12248 f.open(name, "r");
12249 auto r = assumeSorted(f.byLine());
12250 auto r1 = r.upperBound!(SearchPolicy.linear)("def");
12251 assert(r1.front == "ghi", r1.front);
12252 f.close();
12255 // https://issues.dlang.org/show_bug.cgi?id=19337
12256 @safe unittest
12258 import std.algorithm.sorting : sort;
12259 auto a = [ 1, 2, 3, 42, 52, 64 ];
12260 a.sort.sort!"a > b";
12264 Assumes `r` is sorted by predicate `pred` and returns the
12265 corresponding $(D SortedRange!(pred, R)) having `r` as support.
12266 To check for sorted-ness at
12267 cost $(BIGOH n), use $(REF isSorted, std,algorithm,sorting).
12269 auto assumeSorted(alias pred = "a < b", R)(R r)
12270 if (isInputRange!(Unqual!R))
12272 // Avoid senseless `SortedRange!(SortedRange!(...), pred)` nesting.
12273 static if (is(R == SortedRange!(RRange, RPred), RRange, alias RPred))
12275 static if (isInputRange!R && __traits(isSame, pred, RPred))
12276 // If the predicate is the same and we don't need to cast away
12277 // constness for the result to be an input range.
12278 return r;
12279 else
12280 return SortedRange!(Unqual!(typeof(r._input)), pred)(r._input);
12282 else
12284 return SortedRange!(Unqual!R, pred)(r);
12289 @safe unittest
12291 import std.algorithm.comparison : equal;
12293 int[] a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
12294 auto p = assumeSorted(a);
12296 assert(equal(p.lowerBound(4), [0, 1, 2, 3]));
12297 assert(equal(p.lowerBound(5), [0, 1, 2, 3, 4]));
12298 assert(equal(p.lowerBound(6), [0, 1, 2, 3, 4, 5]));
12299 assert(equal(p.lowerBound(6.9), [0, 1, 2, 3, 4, 5, 6]));
12302 @safe unittest
12304 import std.algorithm.comparison : equal;
12305 static assert(isRandomAccessRange!(SortedRange!(int[])));
12306 int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
12307 auto p = assumeSorted(a).upperBound(3);
12308 assert(equal(p, [4, 4, 5, 6 ]));
12309 p = assumeSorted(a).upperBound(4.2);
12310 assert(equal(p, [ 5, 6 ]));
12312 // https://issues.dlang.org/show_bug.cgi?id=18933
12313 // don't create senselessly nested SortedRange types.
12314 assert(is(typeof(assumeSorted(a)) == typeof(assumeSorted(assumeSorted(a)))));
12315 assert(is(typeof(assumeSorted(a)) == typeof(assumeSorted(assumeSorted!"a > b"(a)))));
12318 @safe unittest
12320 import std.algorithm.comparison : equal;
12321 import std.conv : text;
12323 int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
12324 auto p = assumeSorted(a).equalRange(3);
12325 assert(equal(p, [ 3, 3, 3 ]), text(p));
12326 p = assumeSorted(a).equalRange(4);
12327 assert(equal(p, [ 4, 4 ]), text(p));
12328 p = assumeSorted(a).equalRange(2);
12329 assert(equal(p, [ 2 ]));
12330 p = assumeSorted(a).equalRange(0);
12331 assert(p.empty);
12332 p = assumeSorted(a).equalRange(7);
12333 assert(p.empty);
12334 p = assumeSorted(a).equalRange(3.0);
12335 assert(equal(p, [ 3, 3, 3]));
12338 @safe unittest
12340 int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
12341 if (a.length)
12343 auto b = a[a.length / 2];
12344 //auto r = sort(a);
12345 //assert(r.contains(b));
12349 @safe unittest
12351 auto a = [ 5, 7, 34, 345, 677 ];
12352 auto r = assumeSorted(a);
12353 a = null;
12354 r = assumeSorted(a);
12355 a = [ 1 ];
12356 r = assumeSorted(a);
12359 // https://issues.dlang.org/show_bug.cgi?id=15003
12360 @nogc @safe unittest
12362 static immutable a = [1, 2, 3, 4];
12363 auto r = a.assumeSorted;
12367 Wrapper which effectively makes it possible to pass a range by reference.
12368 Both the original range and the RefRange will always have the exact same
12369 elements. Any operation done on one will affect the other. So, for instance,
12370 if it's passed to a function which would implicitly copy the original range
12371 if it were passed to it, the original range is $(I not) copied but is
12372 consumed as if it were a reference type.
12374 Note:
12375 `save` works as normal and operates on a new range, so if
12376 `save` is ever called on the `RefRange`, then no operations on the
12377 saved range will affect the original.
12379 Params:
12380 range = the range to construct the `RefRange` from
12382 Returns:
12383 A `RefRange`. If the given range is a class type
12384 (and thus is already a reference type), then the original
12385 range is returned rather than a `RefRange`.
12387 struct RefRange(R)
12388 if (isInputRange!R)
12390 public:
12392 /++ +/
12393 this(R* range) @safe pure nothrow
12395 _range = range;
12400 This does not assign the pointer of `rhs` to this `RefRange`.
12401 Rather it assigns the range pointed to by `rhs` to the range pointed
12402 to by this `RefRange`. This is because $(I any) operation on a
12403 `RefRange` is the same is if it occurred to the original range. The
12404 one exception is when a `RefRange` is assigned `null` either
12405 directly or because `rhs` is `null`. In that case, `RefRange`
12406 no longer refers to the original range but is `null`.
12408 auto opAssign(RefRange rhs)
12410 if (_range && rhs._range)
12411 *_range = *rhs._range;
12412 else
12413 _range = rhs._range;
12415 return this;
12418 /++ +/
12419 void opAssign(typeof(null) rhs)
12421 _range = null;
12426 A pointer to the wrapped range.
12428 @property inout(R*) ptr() @safe inout pure nothrow
12430 return _range;
12434 version (StdDdoc)
12436 /++ +/
12437 @property auto front() {assert(0);}
12438 /++ Ditto +/
12439 @property auto front() const {assert(0);}
12440 /++ Ditto +/
12441 @property auto front(ElementType!R value) {assert(0);}
12443 else
12445 @property auto front()
12447 return (*_range).front;
12450 static if (is(typeof(((const R* r) => (*r).front)(null)))) @property auto front() const
12452 return (*_range).front;
12455 static if (is(typeof((*_range).front = (*_range).front))) @property auto front(ElementType!R value)
12457 return (*_range).front = value;
12462 version (StdDdoc)
12464 @property bool empty(); ///
12465 @property bool empty() const; ///Ditto
12467 else static if (isInfinite!R)
12468 enum empty = false;
12469 else
12471 @property bool empty()
12473 return (*_range).empty;
12476 static if (is(typeof(((const R* r) => (*r).empty)(null)))) @property bool empty() const
12478 return (*_range).empty;
12483 /++ +/
12484 void popFront()
12486 return (*_range).popFront();
12490 version (StdDdoc)
12493 Only defined if `isForwardRange!R` is `true`.
12495 @property auto save() {assert(0);}
12496 /++ Ditto +/
12497 @property auto save() const {assert(0);}
12498 /++ Ditto +/
12499 auto opSlice() {assert(0);}
12500 /++ Ditto +/
12501 auto opSlice() const {assert(0);}
12503 else static if (isForwardRange!R)
12505 import std.traits : isSafe;
12506 private alias S = typeof((() => (*_range).save)());
12508 static if (is(typeof(((const R* r) => (*r).save)(null))))
12509 private alias CS = typeof(((const R* r) => (*r).save)(null));
12512 static if (isSafe!((R* r) => (*r).save))
12514 @property RefRange!S save() @trusted
12516 mixin(_genSave());
12519 static if (is(typeof(((const R* r) => (*r).save)(null)))) @property RefRange!CS save() @trusted const
12521 mixin(_genSave());
12524 else
12526 @property RefRange!S save()
12528 mixin(_genSave());
12531 static if (is(typeof(((const R* r) => (*r).save)(null)))) @property RefRange!CS save() const
12533 mixin(_genSave());
12537 auto opSlice()()
12539 return save;
12542 auto opSlice()() const
12544 return save;
12547 private static string _genSave() @safe pure nothrow
12549 return `import core.lifetime : emplace;` ~
12550 `alias S = typeof((() => (*_range).save)());` ~
12551 `static assert(isForwardRange!S, S.stringof ~ " is not a forward range.");` ~
12552 `auto mem = new void[S.sizeof];` ~
12553 `emplace!S(mem, cast(S)(*_range).save);` ~
12554 `return RefRange!S(cast(S*) mem.ptr);`;
12557 static assert(isForwardRange!RefRange);
12561 version (StdDdoc)
12564 Only defined if `isBidirectionalRange!R` is `true`.
12566 @property auto back() {assert(0);}
12567 /++ Ditto +/
12568 @property auto back() const {assert(0);}
12569 /++ Ditto +/
12570 @property auto back(ElementType!R value) {assert(0);}
12572 else static if (isBidirectionalRange!R)
12574 @property auto back()
12576 return (*_range).back;
12579 static if (is(typeof(((const R* r) => (*r).back)(null)))) @property auto back() const
12581 return (*_range).back;
12584 static if (is(typeof((*_range).back = (*_range).back))) @property auto back(ElementType!R value)
12586 return (*_range).back = value;
12591 /++ Ditto +/
12592 static if (isBidirectionalRange!R) void popBack()
12594 return (*_range).popBack();
12598 version (StdDdoc)
12601 Only defined if `isRandomAccessRange!R` is `true`.
12603 auto ref opIndex(IndexType)(IndexType index) {assert(0);}
12605 /++ Ditto +/
12606 auto ref opIndex(IndexType)(IndexType index) const {assert(0);}
12608 else static if (isRandomAccessRange!R)
12610 auto ref opIndex(IndexType)(IndexType index)
12611 if (is(typeof((*_range)[index])))
12613 return (*_range)[index];
12616 auto ref opIndex(IndexType)(IndexType index) const
12617 if (is(typeof((*cast(const R*)_range)[index])))
12619 return (*_range)[index];
12625 Only defined if `hasMobileElements!R` and `isForwardRange!R` are
12626 `true`.
12628 static if (hasMobileElements!R && isForwardRange!R) auto moveFront()
12630 return (*_range).moveFront();
12635 Only defined if `hasMobileElements!R` and `isBidirectionalRange!R`
12636 are `true`.
12638 static if (hasMobileElements!R && isBidirectionalRange!R) auto moveBack()
12640 return (*_range).moveBack();
12645 Only defined if `hasMobileElements!R` and `isRandomAccessRange!R`
12646 are `true`.
12648 static if (hasMobileElements!R && isRandomAccessRange!R) auto moveAt(size_t index)
12650 return (*_range).moveAt(index);
12654 version (StdDdoc)
12656 /// Only defined if `hasLength!R` is `true`.
12657 @property size_t length();
12658 /// ditto
12659 @property size_t length() const;
12660 /// Ditto
12661 alias opDollar = length;
12663 else static if (hasLength!R)
12665 @property auto length()
12667 return (*_range).length;
12669 static if (is(typeof(((const R* r) => (*r).length)(null)))) @property auto length() const
12671 return (*_range).length;
12673 alias opDollar = length;
12677 version (StdDdoc)
12680 Only defined if `hasSlicing!R` is `true`.
12682 auto opSlice(IndexType1, IndexType2)
12683 (IndexType1 begin, IndexType2 end) {assert(0);}
12685 /++ Ditto +/
12686 auto opSlice(IndexType1, IndexType2)
12687 (IndexType1 begin, IndexType2 end) const {assert(0);}
12689 else static if (hasSlicing!R)
12691 private alias T = typeof((*_range)[1 .. 2]);
12692 static if (is(typeof((*cast(const R*)_range)[1 .. 2])))
12694 private alias CT = typeof((*cast(const R*)_range)[1 .. 2]);
12697 RefRange!T opSlice(IndexType1, IndexType2)
12698 (IndexType1 begin, IndexType2 end)
12699 if (is(typeof((*_range)[begin .. end])))
12701 mixin(_genOpSlice());
12704 RefRange!CT opSlice(IndexType1, IndexType2)
12705 (IndexType1 begin, IndexType2 end) const
12706 if (is(typeof((*cast(const R*)_range)[begin .. end])))
12708 mixin(_genOpSlice());
12711 private static string _genOpSlice() @safe pure nothrow
12713 return `import core.lifetime : emplace;` ~
12714 `alias S = typeof((*_range)[begin .. end]);` ~
12715 `static assert(hasSlicing!S, S.stringof ~ " is not sliceable.");` ~
12716 `auto mem = new void[S.sizeof];` ~
12717 `emplace!S(mem, cast(S)(*_range)[begin .. end]);` ~
12718 `return RefRange!S(cast(S*) mem.ptr);`;
12723 private:
12725 R* _range;
12728 /// Basic Example
12729 @system unittest
12731 import std.algorithm.searching : find;
12732 ubyte[] buffer = [1, 9, 45, 12, 22];
12733 auto found1 = find(buffer, 45);
12734 assert(found1 == [45, 12, 22]);
12735 assert(buffer == [1, 9, 45, 12, 22]);
12737 auto wrapped1 = refRange(&buffer);
12738 auto found2 = find(wrapped1, 45);
12739 assert(*found2.ptr == [45, 12, 22]);
12740 assert(buffer == [45, 12, 22]);
12742 auto found3 = find(wrapped1.save, 22);
12743 assert(*found3.ptr == [22]);
12744 assert(buffer == [45, 12, 22]);
12746 string str = "hello world";
12747 auto wrappedStr = refRange(&str);
12748 assert(str.front == 'h');
12749 str.popFrontN(5);
12750 assert(str == " world");
12751 assert(wrappedStr.front == ' ');
12752 assert(*wrappedStr.ptr == " world");
12755 /// opAssign Example.
12756 @system unittest
12758 ubyte[] buffer1 = [1, 2, 3, 4, 5];
12759 ubyte[] buffer2 = [6, 7, 8, 9, 10];
12760 auto wrapped1 = refRange(&buffer1);
12761 auto wrapped2 = refRange(&buffer2);
12762 assert(wrapped1.ptr is &buffer1);
12763 assert(wrapped2.ptr is &buffer2);
12764 assert(wrapped1.ptr !is wrapped2.ptr);
12765 assert(buffer1 != buffer2);
12767 wrapped1 = wrapped2;
12769 //Everything points to the same stuff as before.
12770 assert(wrapped1.ptr is &buffer1);
12771 assert(wrapped2.ptr is &buffer2);
12772 assert(wrapped1.ptr !is wrapped2.ptr);
12774 //But buffer1 has changed due to the assignment.
12775 assert(buffer1 == [6, 7, 8, 9, 10]);
12776 assert(buffer2 == [6, 7, 8, 9, 10]);
12778 buffer2 = [11, 12, 13, 14, 15];
12780 //Everything points to the same stuff as before.
12781 assert(wrapped1.ptr is &buffer1);
12782 assert(wrapped2.ptr is &buffer2);
12783 assert(wrapped1.ptr !is wrapped2.ptr);
12785 //But buffer2 has changed due to the assignment.
12786 assert(buffer1 == [6, 7, 8, 9, 10]);
12787 assert(buffer2 == [11, 12, 13, 14, 15]);
12789 wrapped2 = null;
12791 //The pointer changed for wrapped2 but not wrapped1.
12792 assert(wrapped1.ptr is &buffer1);
12793 assert(wrapped2.ptr is null);
12794 assert(wrapped1.ptr !is wrapped2.ptr);
12796 //buffer2 is not affected by the assignment.
12797 assert(buffer1 == [6, 7, 8, 9, 10]);
12798 assert(buffer2 == [11, 12, 13, 14, 15]);
12801 @system unittest
12803 import std.algorithm.iteration : filter;
12805 ubyte[] buffer = [1, 2, 3, 4, 5];
12806 auto wrapper = refRange(&buffer);
12807 auto p = wrapper.ptr;
12808 auto f = wrapper.front;
12809 wrapper.front = f;
12810 auto e = wrapper.empty;
12811 wrapper.popFront();
12812 auto s = wrapper.save;
12813 auto b = wrapper.back;
12814 wrapper.back = b;
12815 wrapper.popBack();
12816 auto i = wrapper[0];
12817 wrapper.moveFront();
12818 wrapper.moveBack();
12819 wrapper.moveAt(0);
12820 auto l = wrapper.length;
12821 auto sl = wrapper[0 .. 1];
12822 assert(wrapper[0 .. $].length == buffer[0 .. $].length);
12826 ubyte[] buffer = [1, 2, 3, 4, 5];
12827 const wrapper = refRange(&buffer);
12828 const p = wrapper.ptr;
12829 const f = wrapper.front;
12830 const e = wrapper.empty;
12831 const s = wrapper.save;
12832 const b = wrapper.back;
12833 const i = wrapper[0];
12834 const l = wrapper.length;
12835 const sl = wrapper[0 .. 1];
12839 ubyte[] buffer = [1, 2, 3, 4, 5];
12840 auto filtered = filter!"true"(buffer);
12841 auto wrapper = refRange(&filtered);
12842 auto p = wrapper.ptr;
12843 auto f = wrapper.front;
12844 wrapper.front = f;
12845 auto e = wrapper.empty;
12846 wrapper.popFront();
12847 auto s = wrapper.save;
12848 wrapper.moveFront();
12852 ubyte[] buffer = [1, 2, 3, 4, 5];
12853 auto filtered = filter!"true"(buffer);
12854 const wrapper = refRange(&filtered);
12855 const p = wrapper.ptr;
12857 //Cannot currently be const. filter needs to be updated to handle const.
12859 const f = wrapper.front;
12860 const e = wrapper.empty;
12861 const s = wrapper.save;
12866 string str = "hello world";
12867 auto wrapper = refRange(&str);
12868 auto p = wrapper.ptr;
12869 auto f = wrapper.front;
12870 auto e = wrapper.empty;
12871 wrapper.popFront();
12872 auto s = wrapper.save;
12873 auto b = wrapper.back;
12874 wrapper.popBack();
12878 // https://issues.dlang.org/show_bug.cgi?id=16534
12879 // opDollar should be defined if the wrapped range defines length.
12880 auto range = 10.iota.takeExactly(5);
12881 auto wrapper = refRange(&range);
12882 assert(wrapper.length == 5);
12883 assert(wrapper[0 .. $ - 1].length == 4);
12887 //Test assignment.
12888 @system unittest
12890 ubyte[] buffer1 = [1, 2, 3, 4, 5];
12891 ubyte[] buffer2 = [6, 7, 8, 9, 10];
12892 RefRange!(ubyte[]) wrapper1;
12893 RefRange!(ubyte[]) wrapper2 = refRange(&buffer2);
12894 assert(wrapper1.ptr is null);
12895 assert(wrapper2.ptr is &buffer2);
12897 wrapper1 = refRange(&buffer1);
12898 assert(wrapper1.ptr is &buffer1);
12900 wrapper1 = wrapper2;
12901 assert(wrapper1.ptr is &buffer1);
12902 assert(buffer1 == buffer2);
12904 wrapper1 = RefRange!(ubyte[]).init;
12905 assert(wrapper1.ptr is null);
12906 assert(wrapper2.ptr is &buffer2);
12907 assert(buffer1 == buffer2);
12908 assert(buffer1 == [6, 7, 8, 9, 10]);
12910 wrapper2 = null;
12911 assert(wrapper2.ptr is null);
12912 assert(buffer2 == [6, 7, 8, 9, 10]);
12915 @system unittest
12917 import std.algorithm.comparison : equal;
12918 import std.algorithm.mutation : bringToFront;
12919 import std.algorithm.searching : commonPrefix, find, until;
12920 import std.algorithm.sorting : sort;
12922 //Test that ranges are properly consumed.
12924 int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
12925 auto wrapper = refRange(&arr);
12927 assert(*find(wrapper, 41).ptr == [41, 3, 40, 4, 42, 9]);
12928 assert(arr == [41, 3, 40, 4, 42, 9]);
12930 assert(*drop(wrapper, 2).ptr == [40, 4, 42, 9]);
12931 assert(arr == [40, 4, 42, 9]);
12933 assert(equal(until(wrapper, 42), [40, 4]));
12934 assert(arr == [42, 9]);
12936 assert(find(wrapper, 12).empty);
12937 assert(arr.empty);
12941 string str = "Hello, world-like object.";
12942 auto wrapper = refRange(&str);
12944 assert(*find(wrapper, "l").ptr == "llo, world-like object.");
12945 assert(str == "llo, world-like object.");
12947 assert(equal(take(wrapper, 5), "llo, "));
12948 assert(str == "world-like object.");
12951 //Test that operating on saved ranges does not consume the original.
12953 int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
12954 auto wrapper = refRange(&arr);
12955 auto saved = wrapper.save;
12956 saved.popFrontN(3);
12957 assert(*saved.ptr == [41, 3, 40, 4, 42, 9]);
12958 assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]);
12962 string str = "Hello, world-like object.";
12963 auto wrapper = refRange(&str);
12964 auto saved = wrapper.save;
12965 saved.popFrontN(13);
12966 assert(*saved.ptr == "like object.");
12967 assert(str == "Hello, world-like object.");
12970 //Test that functions which use save work properly.
12972 int[] arr = [1, 42];
12973 auto wrapper = refRange(&arr);
12974 assert(equal(commonPrefix(wrapper, [1, 27]), [1]));
12978 int[] arr = [4, 5, 6, 7, 1, 2, 3];
12979 auto wrapper = refRange(&arr);
12980 assert(bringToFront(wrapper[0 .. 4], wrapper[4 .. arr.length]) == 3);
12981 assert(arr == [1, 2, 3, 4, 5, 6, 7]);
12984 //Test bidirectional functions.
12986 int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
12987 auto wrapper = refRange(&arr);
12989 assert(wrapper.back == 9);
12990 assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]);
12992 wrapper.popBack();
12993 assert(arr == [1, 42, 2, 41, 3, 40, 4, 42]);
12997 string str = "Hello, world-like object.";
12998 auto wrapper = refRange(&str);
13000 assert(wrapper.back == '.');
13001 assert(str == "Hello, world-like object.");
13003 wrapper.popBack();
13004 assert(str == "Hello, world-like object");
13007 //Test random access functions.
13009 int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
13010 auto wrapper = refRange(&arr);
13012 assert(wrapper[2] == 2);
13013 assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]);
13015 assert(*wrapper[3 .. 6].ptr != null, [41, 3, 40]);
13016 assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]);
13019 //Test move functions.
13021 int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
13022 auto wrapper = refRange(&arr);
13024 auto t1 = wrapper.moveFront();
13025 auto t2 = wrapper.moveBack();
13026 wrapper.front = t2;
13027 wrapper.back = t1;
13028 assert(arr == [9, 42, 2, 41, 3, 40, 4, 42, 1]);
13030 sort(wrapper.save);
13031 assert(arr == [1, 2, 3, 4, 9, 40, 41, 42, 42]);
13035 @system unittest
13037 struct S
13039 @property int front() @safe const pure nothrow { return 0; }
13040 enum bool empty = false;
13041 void popFront() @safe pure nothrow { }
13042 @property auto save() @safe pure nothrow return scope { return this; }
13045 S s;
13046 auto wrapper = refRange(&s);
13047 static assert(isInfinite!(typeof(wrapper)));
13050 @system unittest
13052 class C
13054 @property int front() @safe const pure nothrow { return 0; }
13055 @property bool empty() @safe const pure nothrow { return false; }
13056 void popFront() @safe pure nothrow { }
13057 @property auto save() @safe pure nothrow return scope { return this; }
13059 static assert(isForwardRange!C);
13061 auto c = new C;
13062 auto cWrapper = refRange(&c);
13063 static assert(is(typeof(cWrapper) == C));
13064 assert(cWrapper is c);
13067 // https://issues.dlang.org/show_bug.cgi?id=14373
13068 @system unittest
13070 static struct R
13072 @property int front() {return 0;}
13073 void popFront() {empty = true;}
13074 bool empty = false;
13076 R r;
13077 refRange(&r).popFront();
13078 assert(r.empty);
13081 // https://issues.dlang.org/show_bug.cgi?id=14575
13082 @system unittest
13084 struct R
13086 Object front;
13087 alias back = front;
13088 bool empty = false;
13089 void popFront() {empty = true;}
13090 alias popBack = popFront;
13091 @property R save() {return this;}
13093 static assert(isBidirectionalRange!R);
13094 R r;
13095 auto rr = refRange(&r);
13097 struct R2
13099 @property Object front() {return null;}
13100 @property const(Object) front() const {return null;}
13101 alias back = front;
13102 bool empty = false;
13103 void popFront() {empty = true;}
13104 alias popBack = popFront;
13105 @property R2 save() {return this;}
13107 static assert(isBidirectionalRange!R2);
13108 R2 r2;
13109 auto rr2 = refRange(&r2);
13112 // https://issues.dlang.org/show_bug.cgi?id=24801
13113 @safe unittest
13117 static struct R
13119 int front() => 0;
13120 void popFront() {}
13121 bool empty() => false;
13123 R range;
13124 auto r = RefRange!R(&range);
13128 static struct R
13130 size_t start, end;
13131 size_t length() => end - start;
13132 int opIndex(size_t i) => 0;
13135 int front() => this[0];
13136 int back() => this[length-1];
13137 void popFront() { start++; }
13138 void popBack() { end--; }
13139 bool empty() => length == 0;
13140 R save() const => R();
13143 R range;
13144 auto r = RefRange!R(&range);
13150 /// ditto
13151 auto refRange(R)(R* range)
13152 if (isInputRange!R)
13154 static if (!is(R == class))
13155 return RefRange!R(range);
13156 else
13157 return *range;
13160 // https://issues.dlang.org/show_bug.cgi?id=9060
13161 @safe unittest
13163 import std.algorithm.iteration : map, joiner, group;
13164 import std.algorithm.searching : until;
13165 // fix for std.algorithm
13166 auto r = map!(x => 0)([1]);
13167 chain(r, r);
13168 zip(r, r);
13169 roundRobin(r, r);
13171 struct NRAR {
13172 typeof(r) input;
13173 @property empty() { return input.empty; }
13174 @property front() { return input.front; }
13175 void popFront() { input.popFront(); }
13176 @property save() { return NRAR(input.save); }
13178 auto n1 = NRAR(r);
13179 cycle(n1); // non random access range version
13181 assumeSorted(r);
13183 // fix for std.range
13184 joiner([r], [9]);
13186 struct NRAR2 {
13187 NRAR input;
13188 @property empty() { return true; }
13189 @property front() { return input; }
13190 void popFront() { }
13191 @property save() { return NRAR2(input.save); }
13193 auto n2 = NRAR2(n1);
13194 joiner(n2);
13196 group(r);
13198 until(r, 7);
13199 static void foo(R)(R r) { until!(x => x > 7)(r); }
13200 foo(r);
13203 private struct Bitwise(R)
13204 if (isInputRange!R && isIntegral!(ElementType!R))
13206 import std.traits : Unsigned;
13207 private:
13208 alias ElemType = ElementType!R;
13209 alias UnsignedElemType = Unsigned!ElemType;
13211 R parent;
13212 enum bitsNum = ElemType.sizeof * 8;
13213 size_t maskPos = 1;
13215 static if (isBidirectionalRange!R)
13217 size_t backMaskPos = bitsNum;
13220 public:
13221 this()(auto ref R range)
13223 parent = range;
13226 static if (isInfinite!R)
13228 enum empty = false;
13230 else
13233 * Check if the range is empty
13235 * Returns: a boolean true or false
13237 bool empty()
13239 static if (hasLength!R)
13241 return length == 0;
13243 else static if (isBidirectionalRange!R)
13245 if (parent.empty)
13247 return true;
13249 else
13252 If we have consumed the last element of the range both from
13253 the front and the back, then the masks positions will overlap
13255 return parent.save.dropOne.empty && (maskPos > backMaskPos);
13258 else
13261 If we consumed the last element of the range, but not all the
13262 bits in the last element
13264 return parent.empty;
13269 bool front()
13271 assert(!empty);
13272 return (parent.front & mask(maskPos)) != 0;
13275 void popFront()
13277 assert(!empty);
13278 ++maskPos;
13279 if (maskPos > bitsNum)
13281 parent.popFront;
13282 maskPos = 1;
13286 static if (hasLength!R)
13288 size_t length()
13290 auto len = parent.length * bitsNum - (maskPos - 1);
13291 static if (isBidirectionalRange!R)
13293 len -= bitsNum - backMaskPos;
13295 return len;
13298 alias opDollar = length;
13301 static if (isForwardRange!R)
13303 typeof(this) save()
13305 auto result = this;
13306 result.parent = parent.save;
13307 return result;
13311 static if (isBidirectionalRange!R)
13313 bool back()
13315 assert(!empty);
13316 return (parent.back & mask(backMaskPos)) != 0;
13319 void popBack()
13321 assert(!empty);
13322 --backMaskPos;
13323 if (backMaskPos == 0)
13325 parent.popBack;
13326 backMaskPos = bitsNum;
13331 static if (isRandomAccessRange!R)
13334 Return the `n`th bit within the range
13336 bool opIndex(size_t n)
13340 If it does not have the length property, it means that R is
13341 an infinite range
13343 static if (hasLength!R)
13345 assert(n < length, "Index out of bounds");
13350 immutable size_t remainingBits = bitsNum - maskPos + 1;
13351 // If n >= maskPos, then the bit sign will be 1, otherwise 0
13352 immutable ptrdiff_t sign = (remainingBits - n - 1) >> (ptrdiff_t.sizeof * 8 - 1);
13354 By truncating n with remainingBits bits we have skipped the
13355 remaining bits in parent[0], so we need to add 1 to elemIndex.
13357 Because bitsNum is a power of 2, n / bitsNum == n >> bitsNum.bsf
13359 import core.bitop : bsf;
13360 immutable size_t elemIndex = sign * (((n - remainingBits) >> bitsNum.bsf) + 1);
13363 Since the indexing is from LSB to MSB, we need to index at the
13364 remainder of (n - remainingBits).
13366 Because bitsNum is a power of 2, n % bitsNum == n & (bitsNum - 1)
13368 immutable size_t elemMaskPos = (sign ^ 1) * (maskPos + n)
13369 + sign * (1 + ((n - remainingBits) & (bitsNum - 1)));
13371 return (parent[elemIndex] & mask(elemMaskPos)) != 0;
13374 static if (hasAssignableElements!R)
13377 Assigns `flag` to the `n`th bit within the range
13379 void opIndexAssign(bool flag, size_t n)
13382 static if (hasLength!R)
13384 assert(n < length, "Index out of bounds");
13389 import core.bitop : bsf;
13391 immutable size_t remainingBits = bitsNum - maskPos + 1;
13392 immutable ptrdiff_t sign = (remainingBits - n - 1) >> (ptrdiff_t.sizeof * 8 - 1);
13393 immutable size_t elemIndex = sign * (((n - remainingBits) >> bitsNum.bsf) + 1);
13394 immutable size_t elemMaskPos = (sign ^ 1) * (maskPos + n)
13395 + sign * (1 + ((n - remainingBits) & (bitsNum - 1)));
13397 auto elem = parent[elemIndex];
13398 auto elemMask = mask(elemMaskPos);
13399 parent[elemIndex] = cast(UnsignedElemType)(flag * (elem | elemMask)
13400 + (flag ^ 1) * (elem & ~elemMask));
13404 Bitwise!R opSlice()
13406 return this.save;
13409 Bitwise!R opSlice(size_t start, size_t end)
13412 assert(start < end, "Invalid bounds: end <= start");
13416 import core.bitop : bsf;
13418 size_t remainingBits = bitsNum - maskPos + 1;
13419 ptrdiff_t sign = (remainingBits - start - 1) >> (ptrdiff_t.sizeof * 8 - 1);
13420 immutable size_t startElemIndex = sign * (((start - remainingBits) >> bitsNum.bsf) + 1);
13421 immutable size_t startElemMaskPos = (sign ^ 1) * (maskPos + start)
13422 + sign * (1 + ((start - remainingBits) & (bitsNum - 1)));
13424 immutable size_t sliceLen = end - start - 1;
13425 remainingBits = bitsNum - startElemMaskPos + 1;
13426 sign = (remainingBits - sliceLen - 1) >> (ptrdiff_t.sizeof * 8 - 1);
13427 immutable size_t endElemIndex = startElemIndex
13428 + sign * (((sliceLen - remainingBits) >> bitsNum.bsf) + 1);
13429 immutable size_t endElemMaskPos = (sign ^ 1) * (startElemMaskPos + sliceLen)
13430 + sign * (1 + ((sliceLen - remainingBits) & (bitsNum - 1)));
13432 typeof(return) result;
13433 // Get the slice to be returned from the parent
13434 result.parent = (parent[startElemIndex .. endElemIndex + 1]).save;
13435 result.maskPos = startElemMaskPos;
13436 static if (isBidirectionalRange!R)
13438 result.backMaskPos = endElemMaskPos;
13440 return result;
13444 private:
13445 auto mask(size_t maskPos)
13447 return (1UL << (maskPos - 1UL));
13452 Bitwise adapter over an integral type range. Consumes the range elements bit by
13453 bit, from the least significant bit to the most significant bit.
13455 Params:
13456 R = an integral $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to iterate over
13457 range = range to consume bit by by
13459 Returns:
13460 A `Bitwise` input range with propagated forward, bidirectional
13461 and random access capabilities
13463 auto bitwise(R)(auto ref R range)
13464 if (isInputRange!R && isIntegral!(ElementType!R))
13466 return Bitwise!R(range);
13470 @safe pure unittest
13472 import std.algorithm.comparison : equal;
13473 import std.format : format;
13475 // 00000011 00001001
13476 ubyte[] arr = [3, 9];
13477 auto r = arr.bitwise;
13479 // iterate through it as with any other range
13480 assert(format("%(%d%)", r) == "1100000010010000");
13481 assert(format("%(%d%)", r.retro).equal("1100000010010000".retro));
13483 auto r2 = r[5 .. $];
13484 // set a bit
13485 r[2] = 1;
13486 assert(arr[0] == 7);
13487 assert(r[5] == r2[0]);
13490 /// You can use bitwise to implement an uniform bool generator
13491 @safe unittest
13493 import std.algorithm.comparison : equal;
13494 import std.random : rndGen;
13496 auto rb = rndGen.bitwise;
13497 static assert(isInfinite!(typeof(rb)));
13499 auto rb2 = rndGen.bitwise;
13500 // Don't forget that structs are passed by value
13501 assert(rb.take(10).equal(rb2.take(10)));
13504 // Test nogc inference
13505 @safe @nogc unittest
13507 static ubyte[] arr = [3, 9];
13508 auto bw = arr.bitwise;
13509 auto bw2 = bw[];
13510 auto bw3 = bw[8 .. $];
13511 bw3[2] = true;
13513 assert(arr[1] == 13);
13514 assert(bw[$ - 6]);
13515 assert(bw[$ - 6] == bw2[$ - 6]);
13516 assert(bw[$ - 6] == bw3[$ - 6]);
13519 // Test all range types over all integral types
13520 @safe pure nothrow unittest
13522 import std.meta : AliasSeq;
13523 import std.internal.test.dummyrange;
13525 alias IntegralTypes = AliasSeq!(byte, ubyte, short, ushort, int, uint,
13526 long, ulong);
13527 foreach (IntegralType; IntegralTypes)
13529 foreach (T; AllDummyRangesType!(IntegralType[]))
13531 T a;
13532 auto bw = Bitwise!T(a);
13534 static if (isForwardRange!T)
13536 auto bwFwdSave = bw.save;
13539 static if (isBidirectionalRange!T)
13541 auto bwBack = bw.save;
13542 auto bwBackSave = bw.save;
13545 static if (hasLength!T)
13547 auto bwLength = bw.length;
13548 assert(bw.length == (IntegralType.sizeof * 8 * a.length));
13549 static if (isForwardRange!T)
13551 assert(bw.length == bwFwdSave.length);
13555 // Make sure front and back are not the mechanisms that modify the range
13556 long numCalls = 42;
13557 bool initialFrontValue;
13559 if (!bw.empty)
13561 initialFrontValue = bw.front;
13564 while (!bw.empty && (--numCalls))
13566 bw.front;
13567 assert(bw.front == initialFrontValue);
13571 Check that empty works properly and that popFront does not get called
13572 more times than it should
13574 numCalls = 0;
13575 while (!bw.empty)
13577 ++numCalls;
13579 static if (hasLength!T)
13581 assert(bw.length == bwLength);
13582 --bwLength;
13585 static if (isForwardRange!T)
13587 assert(bw.front == bwFwdSave.front);
13588 bwFwdSave.popFront();
13591 static if (isBidirectionalRange!T)
13593 assert(bwBack.front == bwBackSave.front);
13594 bwBack.popBack();
13595 bwBackSave.popBack();
13597 bw.popFront();
13600 auto rangeLen = numCalls / (IntegralType.sizeof * 8);
13601 assert(numCalls == (IntegralType.sizeof * 8 * rangeLen));
13602 assert(bw.empty);
13603 static if (isForwardRange!T)
13605 assert(bwFwdSave.empty);
13608 static if (isBidirectionalRange!T)
13610 assert(bwBack.empty);
13616 // Test opIndex and opSlice
13617 @system unittest
13619 import std.meta : AliasSeq;
13620 alias IntegralTypes = AliasSeq!(byte, ubyte, short, ushort, int, uint,
13621 long, ulong);
13622 foreach (IntegralType; IntegralTypes)
13624 size_t bitsNum = IntegralType.sizeof * 8;
13626 auto first = IntegralType(1);
13628 // 2 ^ (bitsNum - 1)
13629 auto second = cast(IntegralType)(IntegralType(1) << (bitsNum - 2));
13631 IntegralType[] a = [first, second];
13632 auto bw = Bitwise!(IntegralType[])(a);
13634 // Check against lsb of a[0]
13635 assert(bw[0] == true);
13636 // Check against msb - 1 of a[1]
13637 assert(bw[2 * bitsNum - 2] == true);
13639 bw.popFront();
13640 assert(bw[2 * bitsNum - 3] == true);
13642 import std.exception : assertThrown;
13644 version (D_NoBoundsChecks) {}
13645 else
13647 // Check out of bounds error
13648 assertThrown!Error(bw[2 * bitsNum - 1]);
13651 bw[2] = true;
13652 assert(bw[2] == true);
13653 bw.popFront();
13654 assert(bw[1] == true);
13656 auto bw2 = bw[0 .. $ - 5];
13657 auto bw3 = bw2[];
13658 assert(bw2.length == bw.length - 5);
13659 assert(bw2.length == bw3.length);
13660 bw2.popFront();
13661 assert(bw2.length != bw3.length);
13665 /*********************************
13666 * An OutputRange that discards the data it receives.
13668 struct NullSink
13670 void put(E)(scope const E) pure @safe @nogc nothrow {}
13673 /// ditto
13674 auto ref nullSink()
13676 static NullSink sink;
13677 return sink;
13681 @safe nothrow unittest
13683 import std.algorithm.iteration : map;
13684 import std.algorithm.mutation : copy;
13685 [4, 5, 6].map!(x => x * 2).copy(nullSink); // data is discarded
13689 @safe unittest
13691 import std.csv : csvNextToken;
13693 string line = "a,b,c";
13695 // ignore the first column
13696 line.csvNextToken(nullSink, ',', '"');
13697 line.popFront;
13699 // look at the second column
13700 Appender!string app;
13701 line.csvNextToken(app, ',', '"');
13702 assert(app.data == "b");
13705 @safe unittest
13707 auto r = 10.iota
13708 .tee(nullSink)
13709 .dropOne;
13711 assert(r.front == 1);
13716 Implements a "tee" style pipe, wrapping an input range so that elements of the
13717 range can be passed to a provided function or $(LREF OutputRange) as they are
13718 iterated over. This is useful for printing out intermediate values in a long
13719 chain of range code, performing some operation with side-effects on each call
13720 to `front` or `popFront`, or diverting the elements of a range into an
13721 auxiliary $(LREF OutputRange).
13723 It is important to note that as the resultant range is evaluated lazily,
13724 in the case of the version of `tee` that takes a function, the function
13725 will not actually be executed until the range is "walked" using functions
13726 that evaluate ranges, such as $(REF array, std,array) or
13727 $(REF fold, std,algorithm,iteration).
13729 Params:
13730 pipeOnPop = If `Yes.pipeOnPop`, simply iterating the range without ever
13731 calling `front` is enough to have `tee` mirror elements to `outputRange` (or,
13732 respectively, `fun`). Note that each `popFront()` call will mirror the
13733 old `front` value, not the new one. This means that the last value will
13734 not be forwarded if the range isn't iterated until empty. If
13735 `No.pipeOnPop`, only elements for which `front` does get called will be
13736 also sent to `outputRange`/`fun`. If `front` is called twice for the same
13737 element, it will still be sent only once. If this caching is undesired,
13738 consider using $(REF map, std,algorithm,iteration) instead.
13739 inputRange = The input range being passed through.
13740 outputRange = This range will receive elements of `inputRange` progressively
13741 as iteration proceeds.
13742 fun = This function will be called with elements of `inputRange`
13743 progressively as iteration proceeds.
13745 Returns:
13746 An input range that offers the elements of `inputRange`. Regardless of
13747 whether `inputRange` is a more powerful range (forward, bidirectional etc),
13748 the result is always an input range. Reading this causes `inputRange` to be
13749 iterated and returns its elements in turn. In addition, the same elements
13750 will be passed to `outputRange` or `fun` as well.
13752 See_Also: $(REF each, std,algorithm,iteration)
13754 auto tee(Flag!"pipeOnPop" pipeOnPop = Yes.pipeOnPop, R1, R2)(R1 inputRange, R2 outputRange)
13755 if (isInputRange!R1 && isOutputRange!(R2, ElementType!R1))
13757 static struct Result
13759 private R1 _input;
13760 private R2 _output;
13761 static if (!pipeOnPop)
13763 private bool _frontAccessed;
13766 mixin ImplementLength!_input;
13768 static if (isInfinite!R1)
13770 enum bool empty = false;
13772 else
13774 @property bool empty() { return _input.empty; }
13777 void popFront()
13779 assert(!_input.empty, "Attempting to popFront an empty tee");
13780 static if (pipeOnPop)
13782 put(_output, _input.front);
13784 else
13786 _frontAccessed = false;
13788 _input.popFront();
13791 @property auto ref front()
13793 assert(!_input.empty, "Attempting to fetch the front of an empty tee");
13794 static if (!pipeOnPop)
13796 if (!_frontAccessed)
13798 _frontAccessed = true;
13799 put(_output, _input.front);
13802 return _input.front;
13806 return Result(inputRange, outputRange);
13809 /// Ditto
13810 auto tee(alias fun, Flag!"pipeOnPop" pipeOnPop = Yes.pipeOnPop, R1)(R1 inputRange)
13811 if (is(typeof(fun) == void) || isSomeFunction!fun)
13813 import std.traits : isDelegate, isFunctionPointer;
13815 Distinguish between function literals and template lambdas
13816 when using either as an $(LREF OutputRange). Since a template
13817 has no type, typeof(template) will always return void.
13818 If it's a template lambda, it's first necessary to instantiate
13819 it with `ElementType!R1`.
13821 static if (is(typeof(fun) == void))
13822 alias _fun = fun!(ElementType!R1);
13823 else
13824 alias _fun = fun;
13826 static if (isFunctionPointer!_fun || isDelegate!_fun)
13828 return tee!pipeOnPop(inputRange, _fun);
13830 else
13832 return tee!pipeOnPop(inputRange, &_fun);
13837 @safe unittest
13839 import std.algorithm.comparison : equal;
13840 import std.algorithm.iteration : filter, map;
13842 // Sum values while copying
13843 int[] values = [1, 4, 9, 16, 25];
13844 int sum = 0;
13845 auto newValues = values.tee!(a => sum += a).array;
13846 assert(equal(newValues, values));
13847 assert(sum == 1 + 4 + 9 + 16 + 25);
13849 // Count values that pass the first filter
13850 int count = 0;
13851 auto newValues4 = values.filter!(a => a < 10)
13852 .tee!(a => count++)
13853 .map!(a => a + 1)
13854 .filter!(a => a < 10);
13856 //Fine, equal also evaluates any lazy ranges passed to it.
13857 //count is not 3 until equal evaluates newValues4
13858 assert(equal(newValues4, [2, 5]));
13859 assert(count == 3);
13863 @safe unittest
13865 import std.algorithm.comparison : equal;
13866 import std.algorithm.iteration : filter, map;
13868 int[] values = [1, 4, 9, 16, 25];
13870 int count = 0;
13871 auto newValues = values.filter!(a => a < 10)
13872 .tee!(a => count++, No.pipeOnPop)
13873 .map!(a => a + 1)
13874 .filter!(a => a < 10);
13876 auto val = newValues.front;
13877 assert(count == 1);
13878 //front is only evaluated once per element
13879 val = newValues.front;
13880 assert(count == 1);
13882 //popFront() called, fun will be called
13883 //again on the next access to front
13884 newValues.popFront();
13885 newValues.front;
13886 assert(count == 2);
13888 int[] preMap = new int[](3), postMap = [];
13889 auto mappedValues = values.filter!(a => a < 10)
13890 //Note the two different ways of using tee
13891 .tee(preMap)
13892 .map!(a => a + 1)
13893 .tee!(a => postMap ~= a)
13894 .filter!(a => a < 10);
13895 assert(equal(mappedValues, [2, 5]));
13896 assert(equal(preMap, [1, 4, 9]));
13897 assert(equal(postMap, [2, 5, 10]));
13901 @safe unittest
13903 import std.algorithm.comparison : equal;
13904 import std.algorithm.iteration : filter, map;
13906 char[] txt = "Line one, Line 2".dup;
13908 bool isVowel(dchar c)
13910 import std.string : indexOf;
13911 return "AaEeIiOoUu".indexOf(c) != -1;
13914 int vowelCount = 0;
13915 int shiftedCount = 0;
13916 auto removeVowels = txt.tee!(c => isVowel(c) ? vowelCount++ : 0)
13917 .filter!(c => !isVowel(c))
13918 .map!(c => (c == ' ') ? c : c + 1)
13919 .tee!(c => isVowel(c) ? shiftedCount++ : 0);
13920 assert(equal(removeVowels, "Mo o- Mo 3"));
13921 assert(vowelCount == 6);
13922 assert(shiftedCount == 3);
13925 @safe unittest
13927 // Manually stride to test different pipe behavior.
13928 void testRange(Range)(Range r)
13930 const int strideLen = 3;
13931 int i = 0;
13932 ElementType!Range elem1;
13933 ElementType!Range elem2;
13934 while (!r.empty)
13936 if (i % strideLen == 0)
13938 //Make sure front is only
13939 //evaluated once per item
13940 elem1 = r.front;
13941 elem2 = r.front;
13942 assert(elem1 == elem2);
13944 r.popFront();
13945 i++;
13949 string txt = "abcdefghijklmnopqrstuvwxyz";
13951 int popCount = 0;
13952 auto pipeOnPop = txt.tee!(a => popCount++);
13953 testRange(pipeOnPop);
13954 assert(popCount == 26);
13956 int frontCount = 0;
13957 auto pipeOnFront = txt.tee!(a => frontCount++, No.pipeOnPop);
13958 testRange(pipeOnFront);
13959 assert(frontCount == 9);
13962 @safe unittest
13964 import std.algorithm.comparison : equal;
13965 import std.meta : AliasSeq;
13967 //Test diverting elements to an OutputRange
13968 string txt = "abcdefghijklmnopqrstuvwxyz";
13970 dchar[] asink1 = [];
13971 auto fsink = (dchar c) { asink1 ~= c; };
13972 auto result1 = txt.tee(fsink).array;
13973 assert(equal(txt, result1) && (equal(result1, asink1)));
13975 dchar[] _asink1 = [];
13976 auto _result1 = txt.tee!((dchar c) { _asink1 ~= c; })().array;
13977 assert(equal(txt, _result1) && (equal(_result1, _asink1)));
13979 dchar[] asink2 = new dchar[](txt.length);
13980 void fsink2(dchar c) { static int i = 0; asink2[i] = c; i++; }
13981 auto result2 = txt.tee(&fsink2).array;
13982 assert(equal(txt, result2) && equal(result2, asink2));
13984 dchar[] asink3 = new dchar[](txt.length);
13985 auto result3 = txt.tee(asink3).array;
13986 assert(equal(txt, result3) && equal(result3, asink3));
13988 static foreach (CharType; AliasSeq!(char, wchar, dchar))
13990 auto appSink = appender!(CharType[])();
13991 auto appResult = txt.tee(appSink).array;
13992 assert(equal(txt, appResult) && equal(appResult, appSink.data));
13995 static foreach (StringType; AliasSeq!(string, wstring, dstring))
13997 auto appSink = appender!StringType();
13998 auto appResult = txt.tee(appSink).array;
13999 assert(equal(txt, appResult) && equal(appResult, appSink.data));
14003 // https://issues.dlang.org/show_bug.cgi?id=13483
14004 @safe unittest
14006 static void func1(T)(T x) {}
14007 void func2(int x) {}
14009 auto r = [1, 2, 3, 4].tee!func1.tee!func2;
14013 Extends the length of the input range `r` by padding out the start of the
14014 range with the element `e`. The element `e` must be of a common type with
14015 the element type of the range `r` as defined by $(REF CommonType, std, traits).
14016 If `n` is less than the length of of `r`, then `r` is returned unmodified.
14018 If `r` is a string with Unicode characters in it, `padLeft` follows D's rules
14019 about length for strings, which is not the number of characters, or
14020 graphemes, but instead the number of encoding units. If you want to treat each
14021 grapheme as only one encoding unit long, then call
14022 $(REF byGrapheme, std, uni) before calling this function.
14024 If `r` has a length, then this is $(BIGOH 1). Otherwise, it's $(BIGOH r.length).
14026 Params:
14027 r = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives) with a length, or a forward range
14028 e = element to pad the range with
14029 n = the length to pad to
14031 Returns:
14032 A range containing the elements of the original range with the extra padding
14034 See Also:
14035 $(REF leftJustifier, std, string)
14037 auto padLeft(R, E)(R r, E e, size_t n)
14038 if (
14039 ((isInputRange!R && hasLength!R) || isForwardRange!R) &&
14040 !is(CommonType!(ElementType!R, E) == void)
14043 static if (hasLength!R)
14044 auto dataLength = r.length;
14045 else
14046 auto dataLength = r.save.walkLength(n);
14048 return e.repeat(n > dataLength ? n - dataLength : 0).chain(r);
14052 @safe pure unittest
14054 import std.algorithm.comparison : equal;
14056 assert([1, 2, 3, 4].padLeft(0, 6).equal([0, 0, 1, 2, 3, 4]));
14057 assert([1, 2, 3, 4].padLeft(0, 3).equal([1, 2, 3, 4]));
14059 assert("abc".padLeft('_', 6).equal("___abc"));
14062 @safe pure nothrow unittest
14064 import std.algorithm.comparison : equal;
14065 import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy;
14066 import std.meta : AliasSeq;
14068 alias DummyRanges = AliasSeq!(
14069 DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Input),
14070 DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Forward),
14071 DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Bidirectional),
14072 DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random),
14073 DummyRange!(ReturnBy.Reference, Length.No, RangeType.Forward),
14074 DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Input),
14075 DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Forward),
14076 DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Bidirectional),
14077 DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random),
14078 DummyRange!(ReturnBy.Value, Length.No, RangeType.Forward)
14081 foreach (Range; DummyRanges)
14083 Range r;
14084 assert(r
14085 .padLeft(0, 12)
14086 .equal([0, 0, 1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U])
14091 // Test nogc inference
14092 @safe @nogc pure unittest
14094 import std.algorithm.comparison : equal;
14096 static immutable r1 = [1, 2, 3, 4];
14097 static immutable r2 = [0, 0, 1, 2, 3, 4];
14098 assert(r1.padLeft(0, 6).equal(r2));
14102 Extend the length of the input range `r` by padding out the end of the range
14103 with the element `e`. The element `e` must be of a common type with the
14104 element type of the range `r` as defined by $(REF CommonType, std, traits).
14105 If `n` is less than the length of of `r`, then the contents of `r` are
14106 returned.
14108 The range primitives that the resulting range provides depends whether or not `r`
14109 provides them. Except the functions `back` and `popBack`, which also require
14110 the range to have a length as well as `back` and `popBack`
14112 Params:
14113 r = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives) with a length
14114 e = element to pad the range with
14115 n = the length to pad to
14117 Returns:
14118 A range containing the elements of the original range with the extra padding
14120 See Also:
14121 $(REF rightJustifier, std, string)
14123 auto padRight(R, E)(R r, E e, size_t n)
14124 if (
14125 isInputRange!R &&
14126 !isInfinite!R &&
14127 !is(CommonType!(ElementType!R, E) == void))
14129 static struct Result
14131 private:
14132 R data;
14133 E element;
14134 static if (hasLength!R)
14136 size_t padLength;
14138 else
14140 size_t minLength;
14141 size_t consumed;
14144 public:
14145 bool empty() @property
14147 static if (hasLength!R)
14149 return data.empty && padLength == 0;
14151 else
14153 return data.empty && consumed >= minLength;
14157 auto front() @property
14159 assert(!empty, "Attempting to fetch the front of an empty padRight");
14160 return data.empty ? element : data.front;
14163 void popFront()
14165 assert(!empty, "Attempting to popFront an empty padRight");
14167 static if (hasLength!R)
14169 if (!data.empty)
14171 data.popFront;
14173 else
14175 --padLength;
14178 else
14180 ++consumed;
14181 if (!data.empty)
14183 data.popFront;
14188 static if (hasLength!R)
14190 size_t length() @property
14192 return data.length + padLength;
14196 static if (isForwardRange!R)
14198 auto save() @property
14200 typeof(this) result = this;
14201 data = data.save;
14202 return result;
14206 static if (isBidirectionalRange!R && hasLength!R)
14208 auto back() @property
14210 assert(!empty, "Attempting to fetch the back of an empty padRight");
14211 return padLength > 0 ? element : data.back;
14214 void popBack()
14216 assert(!empty, "Attempting to popBack an empty padRight");
14217 if (padLength > 0)
14219 --padLength;
14221 else
14223 data.popBack;
14228 static if (isRandomAccessRange!R && hasLength!R)
14230 E opIndex(size_t index)
14232 assert(index <= this.length, "Index out of bounds");
14233 return index >= data.length ? element : data[index];
14237 static if (hasSlicing!R && hasLength!R)
14239 auto opSlice(size_t a, size_t b)
14241 assert(
14242 a <= b,
14243 "Attempting to slice a padRight with a larger first argument than the second."
14245 assert(
14246 b <= length,
14247 "Attempting to slice using an out of bounds index on a padRight"
14249 return Result(
14250 a >= data.length ? data[0 .. 0] : b <= data.length ? data[a .. b] : data[a .. data.length],
14251 element, b - a);
14254 alias opDollar = length;
14257 this(R r, E e, size_t n)
14259 data = r;
14260 element = e;
14261 static if (hasLength!R)
14263 padLength = n > data.length ? n - data.length : 0;
14265 else
14267 minLength = n;
14271 @disable this();
14274 return Result(r, e, n);
14278 @safe pure unittest
14280 import std.algorithm.comparison : equal;
14282 assert([1, 2, 3, 4].padRight(0, 6).equal([1, 2, 3, 4, 0, 0]));
14283 assert([1, 2, 3, 4].padRight(0, 4).equal([1, 2, 3, 4]));
14285 assert("abc".padRight('_', 6).equal("abc___"));
14288 pure @safe unittest
14290 import std.algorithm.comparison : equal;
14291 import std.internal.test.dummyrange : AllDummyRanges, ReferenceInputRange;
14292 import std.meta : AliasSeq;
14294 auto string_input_range = new ReferenceInputRange!dchar(['a', 'b', 'c']);
14295 dchar padding = '_';
14296 assert(string_input_range.padRight(padding, 6).equal("abc___"));
14298 foreach (RangeType; AllDummyRanges)
14300 RangeType r1;
14301 assert(r1
14302 .padRight(0, 12)
14303 .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0, 0])
14306 // test if Result properly uses random access ranges
14307 static if (isRandomAccessRange!RangeType)
14309 RangeType r3;
14310 assert(r3.padRight(0, 12)[0] == 1);
14311 assert(r3.padRight(0, 12)[2] == 3);
14312 assert(r3.padRight(0, 12)[9] == 10);
14313 assert(r3.padRight(0, 12)[10] == 0);
14314 assert(r3.padRight(0, 12)[11] == 0);
14317 // test if Result properly uses slicing and opDollar
14318 static if (hasSlicing!RangeType)
14320 RangeType r4;
14321 assert(r4
14322 .padRight(0, 12)[0 .. 3]
14323 .equal([1, 2, 3])
14325 assert(r4
14326 .padRight(0, 12)[0 .. 10]
14327 .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U])
14329 assert(r4
14330 .padRight(0, 12)[0 .. 11]
14331 .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0])
14333 assert(r4
14334 .padRight(0, 12)[2 .. $]
14335 .equal([3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0, 0])
14337 assert(r4
14338 .padRight(0, 12)[0 .. $]
14339 .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0, 0])
14343 // drop & dropBack test opslice ranges when available, popFront/popBack otherwise
14344 RangeType r5;
14345 foreach (i; 1 .. 13) assert(r5.padRight(0, 12).drop(i).walkLength == 12 - i);
14349 // Test nogc inference
14350 @safe @nogc pure unittest
14352 import std.algorithm.comparison : equal;
14354 static immutable r1 = [1, 2, 3, 4];
14355 static immutable r2 = [1, 2, 3, 4, 0, 0];
14356 assert(r1.padRight(0, 6).equal(r2));
14359 // Test back, popBack, and save
14360 @safe pure unittest
14362 import std.algorithm.comparison : equal;
14364 auto r1 = [1, 2, 3, 4].padRight(0, 6);
14365 assert(r1.back == 0);
14367 r1.popBack;
14368 auto r2 = r1.save;
14369 assert(r1.equal([1, 2, 3, 4, 0]));
14370 assert(r2.equal([1, 2, 3, 4, 0]));
14372 r1.popBackN(2);
14373 assert(r1.back == 3);
14374 assert(r1.length == 3);
14375 assert(r2.length == 5);
14376 assert(r2.equal([1, 2, 3, 4, 0]));
14378 r2.popFront;
14379 assert(r2.length == 4);
14380 assert(r2[0] == 2);
14381 assert(r2[1] == 3);
14382 assert(r2[2] == 4);
14383 assert(r2[3] == 0);
14384 assert(r2.equal([2, 3, 4, 0]));
14386 r2.popBack;
14387 assert(r2.equal([2, 3, 4]));
14389 auto r3 = [1, 2, 3, 4].padRight(0, 6);
14390 size_t len = 0;
14391 while (!r3.empty)
14393 ++len;
14394 r3.popBack;
14396 assert(len == 6);
14399 // https://issues.dlang.org/show_bug.cgi?id=19042
14400 @safe pure unittest
14402 import std.algorithm.comparison : equal;
14404 assert([2, 5, 13].padRight(42, 10).chunks(5)
14405 .equal!equal([[2, 5, 13, 42, 42], [42, 42, 42, 42, 42]]));
14407 assert([1, 2, 3, 4].padRight(0, 10)[7 .. 9].equal([0, 0]));
14411 This simplifies a commonly used idiom in phobos for accepting any kind of string
14412 parameter. The type `R` can for example be a simple string, chained string using
14413 $(REF chain, std,range), $(REF chainPath, std,path) or any other input range of
14414 characters.
14416 Only finite length character ranges are allowed with this constraint.
14418 This template is equivalent to:
14420 isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R)
14423 See_Also:
14424 $(REF isInputRange, std,range,primitives),
14425 $(REF isInfinite, std,range,primitives),
14426 $(LREF isSomeChar),
14427 $(REF ElementEncodingType, std,range,primitives)
14429 template isSomeFiniteCharInputRange(R)
14431 import std.traits : isSomeChar;
14433 enum isSomeFiniteCharInputRange = isInputRange!R && !isInfinite!R
14434 && isSomeChar!(ElementEncodingType!R);
14438 @safe unittest
14440 import std.path : chainPath;
14441 import std.range : chain;
14443 void someLibraryMethod(R)(R argument)
14444 if (isSomeFiniteCharInputRange!R)
14446 // implementation detail, would iterate over each character of argument
14449 someLibraryMethod("simple strings work");
14450 someLibraryMethod(chain("chained", " ", "strings", " ", "work"));
14451 someLibraryMethod(chainPath("chained", "paths", "work"));
14452 // you can also use custom structs implementing a char range