1 // Written in the D programming language.
2
3 /**
4 This module defines the notion of a range. Ranges generalize the concept of
5 arrays, lists, or anything that involves sequential access. This abstraction
6 enables the same set of algorithms (see $(MREF std, algorithm)) to be used
7 with a vast variety of different concrete types. For example,
8 a linear search algorithm such as $(REF find, std, algorithm, searching)
9 works not just for arrays, but for linked-lists, input files,
10 incoming network data, etc.
11
12 Guides:
13
14 There are many articles available that can bolster understanding ranges:
15
16 $(UL
17 $(LI Ali Çehreli's $(HTTP ddili.org/ders/d.en/ranges.html, tutorial on _ranges)
18 for the basics of working with and creating range-based code.)
19 $(LI Jonathan M. Davis $(LINK2 http://dconf.org/2015/talks/davis.html, $(I Introduction to Ranges))
20 talk at DConf 2015 a vivid introduction from its core constructs to practical advice.)
21 $(LI The DLang Tour's $(LINK2 http://tour.dlang.org/tour/en/basics/ranges, chapter on ranges)
22 for an interactive introduction.)
23 $(LI H. S. Teoh's $(LINK2 http://wiki.dlang.org/Component_programming_with_ranges, tutorial on
24 component programming with ranges) for a real-world showcase of the influence
25 of _range-based programming on complex algorithms.)
26 $(LI Andrei Alexandrescu's article
27 $(LINK2 http://www.informit.com/articles/printerfriendly.aspx?p=1407357$(AMP)rll=1,
28 $(I On Iteration)) for conceptual aspect of ranges and the motivation
29 )
30 )
31
32 Submodules:
33
34 This module has two submodules:
35
36 The $(MREF std, _range, primitives) submodule
37 provides basic _range functionality. It defines several templates for testing
38 whether a given object is a _range, what kind of _range it is, and provides
39 some common _range operations.
40
41 The $(MREF std, _range, interfaces) submodule
42 provides object-based interfaces for working with ranges via runtime
43 polymorphism.
44
45 The remainder of this module provides a rich set of _range creation and
46 composition templates that let you construct new ranges out of existing ranges:
47
48
49 $(SCRIPT inhibitQuickIndex = 1;)
50 $(BOOKTABLE ,
51 $(TR $(TD $(LREF chain))
52 $(TD Concatenates several ranges into a single _range.
53 ))
54 $(TR $(TD $(LREF choose))
55 $(TD Chooses one of two ranges at runtime based on a boolean condition.
56 ))
57 $(TR $(TD $(LREF chooseAmong))
58 $(TD Chooses one of several ranges at runtime based on an index.
59 ))
60 $(TR $(TD $(LREF chunks))
61 $(TD Creates a _range that returns fixed-size chunks of the original
62 _range.
63 ))
64 $(TR $(TD $(LREF cycle))
65 $(TD Creates an infinite _range that repeats the given forward _range
66 indefinitely. Good for implementing circular buffers.
67 ))
68 $(TR $(TD $(LREF drop))
69 $(TD Creates the _range that results from discarding the first $(I n)
70 elements from the given _range.
71 ))
72 $(TR $(TD $(LREF dropBack))
73 $(TD Creates the _range that results from discarding the last $(I n)
74 elements from the given _range.
75 ))
76 $(TR $(TD $(LREF dropExactly))
77 $(TD Creates the _range that results from discarding exactly $(I n)
78 of the first elements from the given _range.
79 ))
80 $(TR $(TD $(LREF dropBackExactly))
81 $(TD Creates the _range that results from discarding exactly $(I n)
82 of the last elements from the given _range.
83 ))
84 $(TR $(TD $(LREF dropOne))
85 $(TD Creates the _range that results from discarding
86 the first element from the given _range.
87 ))
88 $(TR $(TD $(D $(LREF dropBackOne)))
89 $(TD Creates the _range that results from discarding
90 the last element from the given _range.
91 ))
92 $(TR $(TD $(LREF enumerate))
93 $(TD Iterates a _range with an attached index variable.
94 ))
95 $(TR $(TD $(LREF evenChunks))
96 $(TD Creates a _range that returns a number of chunks of
97 approximately equal length from the original _range.
98 ))
99 $(TR $(TD $(LREF frontTransversal))
100 $(TD Creates a _range that iterates over the first elements of the
101 given ranges.
102 ))
103 $(TR $(TD $(LREF generate))
104 $(TD Creates a _range by successive calls to a given function. This
105 allows to create ranges as a single delegate.
106 ))
107 $(TR $(TD $(LREF indexed))
108 $(TD Creates a _range that offers a view of a given _range as though
109 its elements were reordered according to a given _range of indices.
110 ))
111 $(TR $(TD $(LREF iota))
112 $(TD Creates a _range consisting of numbers between a starting point
113 and ending point, spaced apart by a given interval.
114 ))
115 $(TR $(TD $(LREF lockstep))
116 $(TD Iterates $(I n) _ranges in lockstep, for use in a $(D foreach)
117 loop. Similar to $(D zip), except that $(D lockstep) is designed
118 especially for $(D foreach) loops.
119 ))
120 $(TR $(TD $(LREF NullSink))
121 $(TD An output _range that discards the data it receives.
122 ))
123 $(TR $(TD $(LREF only))
124 $(TD Creates a _range that iterates over the given arguments.
125 ))
126 $(TR $(TD $(LREF padLeft))
127 $(TD Pads a _range to a specified length by adding a given element to
128 the front of the _range. Is lazy if the _range has a known length.
129 ))
130 $(TR $(TD $(LREF padRight))
131 $(TD Lazily pads a _range to a specified length by adding a given element to
132 the back of the _range.
133 ))
134 $(TR $(TD $(LREF radial))
135 $(TD Given a random-access _range and a starting point, creates a
136 _range that alternately returns the next left and next right element to
137 the starting point.
138 ))
139 $(TR $(TD $(LREF recurrence))
140 $(TD Creates a forward _range whose values are defined by a
141 mathematical recurrence relation.
142 ))
143 $(TR $(TD $(LREF refRange))
144 $(TD Pass a _range by reference. Both the original _range and the RefRange
145 will always have the exact same elements.
146 Any operation done on one will affect the other.
147 ))
148 $(TR $(TD $(LREF repeat))
149 $(TD Creates a _range that consists of a single element repeated $(I n)
150 times, or an infinite _range repeating that element indefinitely.
151 ))
152 $(TR $(TD $(LREF retro))
153 $(TD Iterates a bidirectional _range backwards.
154 ))
155 $(TR $(TD $(LREF roundRobin))
156 $(TD Given $(I n) ranges, creates a new _range that return the $(I n)
157 first elements of each _range, in turn, then the second element of each
158 _range, and so on, in a round-robin fashion.
159 ))
160 $(TR $(TD $(LREF sequence))
161 $(TD Similar to $(D recurrence), except that a random-access _range is
162 created.
163 ))
164 $(COMMENT Explicitly undocumented to delay the release until 2.076
165 $(TR $(TD $(D $(LREF slide)))
166 $(TD Creates a _range that returns a fixed-size sliding window
167 over the original _range. Unlike chunks,
168 it advances a configurable number of items at a time,
169 not one chunk at a time.
170 ))
171 )
172 $(TR $(TD $(LREF stride))
173 $(TD Iterates a _range with stride $(I n).
174 ))
175 $(TR $(TD $(LREF tail))
176 $(TD Return a _range advanced to within $(D n) elements of the end of
177 the given _range.
178 ))
179 $(TR $(TD $(LREF take))
180 $(TD Creates a sub-_range consisting of only up to the first $(I n)
181 elements of the given _range.
182 ))
183 $(TR $(TD $(LREF takeExactly))
184 $(TD Like $(D take), but assumes the given _range actually has $(I n)
185 elements, and therefore also defines the $(D length) property.
186 ))
187 $(TR $(TD $(LREF takeNone))
188 $(TD Creates a random-access _range consisting of zero elements of the
189 given _range.
190 ))
191 $(TR $(TD $(LREF takeOne))
192 $(TD Creates a random-access _range consisting of exactly the first
193 element of the given _range.
194 ))
195 $(TR $(TD $(LREF tee))
196 $(TD Creates a _range that wraps a given _range, forwarding along
197 its elements while also calling a provided function with each element.
198 ))
199 $(TR $(TD $(LREF transposed))
200 $(TD Transposes a _range of ranges.
201 ))
202 $(TR $(TD $(LREF transversal))
203 $(TD Creates a _range that iterates over the $(I n)'th elements of the
204 given random-access ranges.
205 ))
206 $(TR $(TD $(LREF zip))
207 $(TD Given $(I n) _ranges, creates a _range that successively returns a
208 tuple of all the first elements, a tuple of all the second elements,
209 etc.
210 ))
211 )
212
213 Sortedness:
214
215 Ranges whose elements are sorted afford better efficiency with certain
216 operations. For this, the $(LREF assumeSorted) function can be used to
217 construct a $(LREF SortedRange) from a pre-sorted _range. The $(REF
218 sort, std, algorithm, sorting) function also conveniently
219 returns a $(LREF SortedRange). $(LREF SortedRange) objects provide some additional
220 _range operations that take advantage of the fact that the _range is sorted.
221
222 Source: $(PHOBOSSRC std/_range/_package.d)
223
224 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
225
226 Authors: $(HTTP erdani.com, Andrei Alexandrescu), David Simcha, Jonathan M Davis,
227 and Jack Stouffer. Credit for some of the ideas in building this module goes
228 to $(HTTP fantascienza.net/leonardo/so/, Leonardo Maffi).
229 */
230 module std.range;
231
232 public import std.array;
233 public import std.range.interfaces;
234 public import std.range.primitives;
235 public import std.typecons : Flag, Yes, No;
236
237 import std.meta; // allSatisfy, staticMap
238 import std.traits; // CommonType, isCallable, isFloatingPoint, isIntegral,
239 // isPointer, isSomeFunction, isStaticArray, Unqual
240
241
242 /**
243 Iterates a bidirectional range backwards. The original range can be
244 accessed by using the $(D source) property. Applying retro twice to
245 the same range yields the original range.
246
247 Params:
248 r = the bidirectional range to iterate backwards
249
250 Returns:
251 A bidirectional range with length if `r` also provides a length. Or,
252 if `r` is a random access range, then the return value will be random
253 access as well.
254 See_Also:
255 $(REF reverse, std,algorithm,mutation) for mutating the source range directly.
256 */
257 auto retro(Range)(Range r)
258 if (isBidirectionalRange!(Unqual!Range))
259 {
260 // Check for retro(retro(r)) and just return r in that case
261 static if (is(typeof(retro(r.source)) == Range))
262 {
263 return r.source;
264 }
265 else
266 {
Result()267 static struct Result()
268 {
269 private alias R = Unqual!Range;
270
271 // User code can get and set source, too
272 R source;
273
274 static if (hasLength!R)
275 {
276 size_t retroIndex(size_t n)
277 {
278 return source.length - n - 1;
279 }
280 }
281
282 public:
283 alias Source = R;
284
285 @property bool empty() { return source.empty; }
286 @property auto save()
287 {
288 return Result(source.save);
289 }
290 @property auto ref front() { return source.back; }
291 void popFront() { source.popBack(); }
292 @property auto ref back() { return source.front; }
293 void popBack() { source.popFront(); }
294
295 static if (is(typeof(source.moveBack())))
296 {
297 ElementType!R moveFront()
298 {
299 return source.moveBack();
300 }
301 }
302
303 static if (is(typeof(source.moveFront())))
304 {
305 ElementType!R moveBack()
306 {
307 return source.moveFront();
308 }
309 }
310
311 static if (hasAssignableElements!R)
312 {
313 @property void front(ElementType!R val)
314 {
315 source.back = val;
316 }
317
318 @property void back(ElementType!R val)
319 {
320 source.front = val;
321 }
322 }
323
324 static if (isRandomAccessRange!(R) && hasLength!(R))
325 {
326 auto ref opIndex(size_t n) { return source[retroIndex(n)]; }
327
328 static if (hasAssignableElements!R)
329 {
330 void opIndexAssign(ElementType!R val, size_t n)
331 {
332 source[retroIndex(n)] = val;
333 }
334 }
335
336 static if (is(typeof(source.moveAt(0))))
337 {
338 ElementType!R moveAt(size_t index)
339 {
340 return source.moveAt(retroIndex(index));
341 }
342 }
343
344 static if (hasSlicing!R)
345 typeof(this) opSlice(size_t a, size_t b)
346 {
347 return typeof(this)(source[source.length - b .. source.length - a]);
348 }
349 }
350
351 static if (hasLength!R)
352 {
353 @property auto length()
354 {
355 return source.length;
356 }
357
358 alias opDollar = length;
359 }
360 }
361
362 return Result!()(r);
363 }
364 }
365
366
367 ///
368 pure @safe nothrow @nogc unittest
369 {
370 import std.algorithm.comparison : equal;
371 int[5] a = [ 1, 2, 3, 4, 5 ];
372 int[5] b = [ 5, 4, 3, 2, 1 ];
373 assert(equal(retro(a[]), b[]));
374 assert(retro(a[]).source is a[]);
375 assert(retro(retro(a[])) is a[]);
376 }
377
378 pure @safe nothrow unittest
379 {
380 import std.algorithm.comparison : equal;
381 static assert(isBidirectionalRange!(typeof(retro("hello"))));
382 int[] a;
383 static assert(is(typeof(a) == typeof(retro(retro(a)))));
384 assert(retro(retro(a)) is a);
385 static assert(isRandomAccessRange!(typeof(retro([1, 2, 3]))));
test(int[]input,int[]witness)386 void test(int[] input, int[] witness)
387 {
388 auto r = retro(input);
389 assert(r.front == witness.front);
390 assert(r.back == witness.back);
391 assert(equal(r, witness));
392 }
393 test([ 1 ], [ 1 ]);
394 test([ 1, 2 ], [ 2, 1 ]);
395 test([ 1, 2, 3 ], [ 3, 2, 1 ]);
396 test([ 1, 2, 3, 4 ], [ 4, 3, 2, 1 ]);
397 test([ 1, 2, 3, 4, 5 ], [ 5, 4, 3, 2, 1 ]);
398 test([ 1, 2, 3, 4, 5, 6 ], [ 6, 5, 4, 3, 2, 1 ]);
399
400 immutable foo = [1,2,3].idup;
401 auto r = retro(foo);
402 assert(equal(r, [3, 2, 1]));
403 }
404
405 pure @safe nothrow unittest
406 {
407 import std.internal.test.dummyrange : AllDummyRanges, propagatesRangeType,
408 ReturnBy;
409
foreach(DummyType;AllDummyRanges)410 foreach (DummyType; AllDummyRanges)
411 {
412 static if (!isBidirectionalRange!DummyType)
413 {
414 static assert(!__traits(compiles, Retro!DummyType));
415 }
416 else
417 {
418 DummyType dummyRange;
419 dummyRange.reinit();
420
421 auto myRetro = retro(dummyRange);
422 static assert(propagatesRangeType!(typeof(myRetro), DummyType));
423 assert(myRetro.front == 10);
424 assert(myRetro.back == 1);
425 assert(myRetro.moveFront() == 10);
426 assert(myRetro.moveBack() == 1);
427
428 static if (isRandomAccessRange!DummyType && hasLength!DummyType)
429 {
430 assert(myRetro[0] == myRetro.front);
431 assert(myRetro.moveAt(2) == 8);
432
433 static if (DummyType.r == ReturnBy.Reference)
434 {
435 {
436 myRetro[9]++;
437 scope(exit) myRetro[9]--;
438 assert(dummyRange[0] == 2);
439 myRetro.front++;
440 scope(exit) myRetro.front--;
441 assert(myRetro.front == 11);
442 myRetro.back++;
443 scope(exit) myRetro.back--;
444 assert(myRetro.back == 3);
445 }
446
447 {
448 myRetro.front = 0xFF;
449 scope(exit) myRetro.front = 10;
450 assert(dummyRange.back == 0xFF);
451
452 myRetro.back = 0xBB;
453 scope(exit) myRetro.back = 1;
454 assert(dummyRange.front == 0xBB);
455
456 myRetro[1] = 11;
457 scope(exit) myRetro[1] = 8;
458 assert(dummyRange[8] == 11);
459 }
460 }
461 }
462 }
463 }
464 }
465
466 pure @safe nothrow @nogc unittest
467 {
468 import std.algorithm.comparison : equal;
469 auto LL = iota(1L, 4L);
470 auto r = retro(LL);
471 long[3] excepted = [3, 2, 1];
472 assert(equal(r, excepted[]));
473 }
474
475 // Issue 12662
476 pure @safe nothrow @nogc unittest
477 {
478 int[3] src = [1,2,3];
479 int[] data = src[];
foreach_reverse(x;data)480 foreach_reverse (x; data) {}
481 foreach (x; data.retro) {}
482 }
483
484
485 /**
486 Iterates range $(D r) with stride $(D n). If the range is a
487 random-access range, moves by indexing into the range; otherwise,
488 moves by successive calls to $(D popFront). Applying stride twice to
489 the same range results in a stride with a step that is the
490 product of the two applications. It is an error for $(D n) to be 0.
491
492 Params:
493 r = the input range to stride over
494 n = the number of elements to skip over
495
496 Returns:
497 At minimum, an input range. The resulting range will adopt the
498 range primitives of the underlying range as long as
499 $(REF hasLength, std,range,primitives) is `true`.
500 */
501 auto stride(Range)(Range r, size_t n)
502 if (isInputRange!(Unqual!Range))
503 in
504 {
505 assert(n != 0, "stride cannot have step zero.");
506 }
507 body
508 {
509 import std.algorithm.comparison : min;
510
511 static if (is(typeof(stride(r.source, n)) == Range))
512 {
513 // stride(stride(r, n1), n2) is stride(r, n1 * n2)
514 return stride(r.source, r._n * n);
515 }
516 else
517 {
518 static struct Result
519 {
520 private alias R = Unqual!Range;
521 public R source;
522 private size_t _n;
523
524 // Chop off the slack elements at the end
525 static if (hasLength!R &&
526 (isRandomAccessRange!R && hasSlicing!R
527 || isBidirectionalRange!R))
eliminateSlackElementsResult528 private void eliminateSlackElements()
529 {
530 auto slack = source.length % _n;
531
532 if (slack)
533 {
534 slack--;
535 }
536 else if (!source.empty)
537 {
538 slack = min(_n, source.length) - 1;
539 }
540 else
541 {
542 slack = 0;
543 }
544 if (!slack) return;
545 static if (isRandomAccessRange!R && hasLength!R && hasSlicing!R)
546 {
547 source = source[0 .. source.length - slack];
548 }
549 else static if (isBidirectionalRange!R)
550 {
551 foreach (i; 0 .. slack)
552 {
553 source.popBack();
554 }
555 }
556 }
557
558 static if (isForwardRange!R)
559 {
saveResult560 @property auto save()
561 {
562 return Result(source.save, _n);
563 }
564 }
565
566 static if (isInfinite!R)
567 {
568 enum bool empty = false;
569 }
570 else
571 {
emptyResult572 @property bool empty()
573 {
574 return source.empty;
575 }
576 }
577
frontResult578 @property auto ref front()
579 {
580 return source.front;
581 }
582
583 static if (is(typeof(.moveFront(source))))
584 {
585 ElementType!R moveFront()
586 {
587 return source.moveFront();
588 }
589 }
590
591 static if (hasAssignableElements!R)
592 {
593 @property void front(ElementType!R val)
594 {
595 source.front = val;
596 }
597 }
598
popFrontResult599 void popFront()
600 {
601 source.popFrontN(_n);
602 }
603
604 static if (isBidirectionalRange!R && hasLength!R)
605 {
popBackResult606 void popBack()
607 {
608 popBackN(source, _n);
609 }
610
backResult611 @property auto ref back()
612 {
613 eliminateSlackElements();
614 return source.back;
615 }
616
617 static if (is(typeof(.moveBack(source))))
618 {
619 ElementType!R moveBack()
620 {
621 eliminateSlackElements();
622 return source.moveBack();
623 }
624 }
625
626 static if (hasAssignableElements!R)
627 {
628 @property void back(ElementType!R val)
629 {
630 eliminateSlackElements();
631 source.back = val;
632 }
633 }
634 }
635
636 static if (isRandomAccessRange!R && hasLength!R)
637 {
opIndexResult638 auto ref opIndex(size_t n)
639 {
640 return source[_n * n];
641 }
642
643 /**
644 Forwards to $(D moveAt(source, n)).
645 */
646 static if (is(typeof(source.moveAt(0))))
647 {
648 ElementType!R moveAt(size_t n)
649 {
650 return source.moveAt(_n * n);
651 }
652 }
653
654 static if (hasAssignableElements!R)
655 {
656 void opIndexAssign(ElementType!R val, size_t n)
657 {
658 source[_n * n] = val;
659 }
660 }
661 }
662
663 static if (hasSlicing!R && hasLength!R)
opSliceResult664 typeof(this) opSlice(size_t lower, size_t upper)
665 {
666 assert(upper >= lower && upper <= length);
667 immutable translatedUpper = (upper == 0) ? 0 :
668 (upper * _n - (_n - 1));
669 immutable translatedLower = min(lower * _n, translatedUpper);
670
671 assert(translatedLower <= translatedUpper);
672
673 return typeof(this)(source[translatedLower .. translatedUpper], _n);
674 }
675
676 static if (hasLength!R)
677 {
lengthResult678 @property auto length()
679 {
680 return (source.length + _n - 1) / _n;
681 }
682
683 alias opDollar = length;
684 }
685 }
686 return Result(r, n);
687 }
688 }
689
690 ///
691 pure @safe nothrow unittest
692 {
693 import std.algorithm.comparison : equal;
694
695 int[] a = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ];
696 assert(equal(stride(a, 3), [ 1, 4, 7, 10 ][]));
697 assert(stride(stride(a, 2), 3) == stride(a, 6));
698 }
699
700 pure @safe nothrow @nogc unittest
701 {
702 import std.algorithm.comparison : equal;
703
704 int[4] testArr = [1,2,3,4];
705 static immutable result = [1, 3];
706 assert(equal(testArr[].stride(2), result));
707 }
708
709 debug pure nothrow @system unittest
710 {//check the contract
711 int[4] testArr = [1,2,3,4];
712 bool passed = false;
713 scope (success) assert(passed);
714 import core.exception : AssertError;
715 //std.exception.assertThrown won't do because it can't infer nothrow
716 // @@@BUG@@@ 12647
717 try
718 {
719 auto unused = testArr[].stride(0);
720 }
catch(AssertError unused)721 catch (AssertError unused)
722 {
723 passed = true;
724 }
725 }
726
727 pure @safe nothrow unittest
728 {
729 import std.algorithm.comparison : equal;
730 import std.internal.test.dummyrange : AllDummyRanges, propagatesRangeType,
731 ReturnBy;
732
733 static assert(isRandomAccessRange!(typeof(stride([1, 2, 3], 2))));
test(size_t n,int[]input,int[]witness)734 void test(size_t n, int[] input, int[] witness)
735 {
736 assert(equal(stride(input, n), witness));
737 }
738 test(1, [], []);
739 int[] arr = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
740 assert(stride(stride(arr, 2), 3) is stride(arr, 6));
741 test(1, arr, arr);
742 test(2, arr, [1, 3, 5, 7, 9]);
743 test(3, arr, [1, 4, 7, 10]);
744 test(4, arr, [1, 5, 9]);
745
746 // Test slicing.
747 auto s1 = stride(arr, 1);
748 assert(equal(s1[1 .. 4], [2, 3, 4]));
749 assert(s1[1 .. 4].length == 3);
750 assert(equal(s1[1 .. 5], [2, 3, 4, 5]));
751 assert(s1[1 .. 5].length == 4);
752 assert(s1[0 .. 0].empty);
753 assert(s1[3 .. 3].empty);
754 // assert(s1[$ .. $].empty);
755 assert(s1[s1.opDollar .. s1.opDollar].empty);
756
757 auto s2 = stride(arr, 2);
758 assert(equal(s2[0 .. 2], [1,3]));
759 assert(s2[0 .. 2].length == 2);
760 assert(equal(s2[1 .. 5], [3, 5, 7, 9]));
761 assert(s2[1 .. 5].length == 4);
762 assert(s2[0 .. 0].empty);
763 assert(s2[3 .. 3].empty);
764 // assert(s2[$ .. $].empty);
765 assert(s2[s2.opDollar .. s2.opDollar].empty);
766
767 // Test fix for Bug 5035
768 auto m = [1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]; // 3 rows, 4 columns
769 auto col = stride(m, 4);
770 assert(equal(col, [1, 1, 1]));
771 assert(equal(retro(col), [1, 1, 1]));
772
773 immutable int[] immi = [ 1, 2, 3 ];
774 static assert(isRandomAccessRange!(typeof(stride(immi, 1))));
775
776 // Check for infiniteness propagation.
777 static assert(isInfinite!(typeof(stride(repeat(1), 3))));
778
foreach(DummyType;AllDummyRanges)779 foreach (DummyType; AllDummyRanges)
780 {
781 DummyType dummyRange;
782 dummyRange.reinit();
783
784 auto myStride = stride(dummyRange, 4);
785
786 // Should fail if no length and bidirectional b/c there's no way
787 // to know how much slack we have.
788 static if (hasLength!DummyType || !isBidirectionalRange!DummyType)
789 {
790 static assert(propagatesRangeType!(typeof(myStride), DummyType));
791 }
792 assert(myStride.front == 1);
793 assert(myStride.moveFront() == 1);
794 assert(equal(myStride, [1, 5, 9]));
795
796 static if (hasLength!DummyType)
797 {
798 assert(myStride.length == 3);
799 }
800
801 static if (isBidirectionalRange!DummyType && hasLength!DummyType)
802 {
803 assert(myStride.back == 9);
804 assert(myStride.moveBack() == 9);
805 }
806
807 static if (isRandomAccessRange!DummyType && hasLength!DummyType)
808 {
809 assert(myStride[0] == 1);
810 assert(myStride[1] == 5);
811 assert(myStride.moveAt(1) == 5);
812 assert(myStride[2] == 9);
813
814 static assert(hasSlicing!(typeof(myStride)));
815 }
816
817 static if (DummyType.r == ReturnBy.Reference)
818 {
819 // Make sure reference is propagated.
820
821 {
822 myStride.front++;
823 scope(exit) myStride.front--;
824 assert(dummyRange.front == 2);
825 }
826 {
827 myStride.front = 4;
828 scope(exit) myStride.front = 1;
829 assert(dummyRange.front == 4);
830 }
831
832 static if (isBidirectionalRange!DummyType && hasLength!DummyType)
833 {
834 {
835 myStride.back++;
836 scope(exit) myStride.back--;
837 assert(myStride.back == 10);
838 }
839 {
840 myStride.back = 111;
841 scope(exit) myStride.back = 9;
842 assert(myStride.back == 111);
843 }
844
845 static if (isRandomAccessRange!DummyType)
846 {
847 {
848 myStride[1]++;
849 scope(exit) myStride[1]--;
850 assert(dummyRange[4] == 6);
851 }
852 {
853 myStride[1] = 55;
854 scope(exit) myStride[1] = 5;
855 assert(dummyRange[4] == 55);
856 }
857 }
858 }
859 }
860 }
861 }
862
863 pure @safe nothrow unittest
864 {
865 import std.algorithm.comparison : equal;
866
867 auto LL = iota(1L, 10L);
868 auto s = stride(LL, 3);
869 assert(equal(s, [1L, 4L, 7L]));
870 }
871
872 /**
873 Spans multiple ranges in sequence. The function $(D chain) takes any
874 number of ranges and returns a $(D Chain!(R1, R2,...)) object. The
875 ranges may be different, but they must have the same element type. The
876 result is a range that offers the $(D front), $(D popFront), and $(D
877 empty) primitives. If all input ranges offer random access and $(D
878 length), $(D Chain) offers them as well.
879
880 If only one range is offered to $(D Chain) or $(D chain), the $(D
881 Chain) type exits the picture by aliasing itself directly to that
882 range's type.
883
884 Params:
885 rs = the input ranges to chain together
886
887 Returns:
888 An input range at minimum. If all of the ranges in `rs` provide
889 a range primitive, the returned range will also provide that range
890 primitive.
891
892 See_Also: $(LREF only) to chain values to a range
893 */
894 auto chain(Ranges...)(Ranges rs)
895 if (Ranges.length > 0 &&
896 allSatisfy!(isInputRange, staticMap!(Unqual, Ranges)) &&
897 !is(CommonType!(staticMap!(ElementType, staticMap!(Unqual, Ranges))) == void))
898 {
899 static if (Ranges.length == 1)
900 {
901 return rs[0];
902 }
903 else
904 {
905 static struct Result
906 {
907 private:
908 alias R = staticMap!(Unqual, Ranges);
909 alias RvalueElementType = CommonType!(staticMap!(.ElementType, R));
sameETResult910 private template sameET(A)
911 {
912 enum sameET = is(.ElementType!A == RvalueElementType);
913 }
914
915 enum bool allSameType = allSatisfy!(sameET, R);
916
917 // This doesn't work yet
918 static if (allSameType)
919 {
920 alias ElementType = ref RvalueElementType;
921 }
922 else
923 {
924 alias ElementType = RvalueElementType;
925 }
926 static if (allSameType && allSatisfy!(hasLvalueElements, R))
927 {
fixRefResult928 static ref RvalueElementType fixRef(ref RvalueElementType val)
929 {
930 return val;
931 }
932 }
933 else
934 {
fixRefResult935 static RvalueElementType fixRef(RvalueElementType val)
936 {
937 return val;
938 }
939 }
940
941 // This is the entire state
942 R source;
943 // TODO: use a vtable (or more) instead of linear iteration
944
945 public:
thisResult946 this(R input)
947 {
948 foreach (i, v; input)
949 {
950 source[i] = v;
951 }
952 }
953
954 import std.meta : anySatisfy;
955
956 static if (anySatisfy!(isInfinite, R))
957 {
958 // Propagate infiniteness.
959 enum bool empty = false;
960 }
961 else
962 {
emptyResult963 @property bool empty()
964 {
965 foreach (i, Unused; R)
966 {
967 if (!source[i].empty) return false;
968 }
969 return true;
970 }
971 }
972
973 static if (allSatisfy!(isForwardRange, R))
saveResult974 @property auto save()
975 {
976 typeof(this) result = this;
977 foreach (i, Unused; R)
978 {
979 result.source[i] = result.source[i].save;
980 }
981 return result;
982 }
983
popFrontResult984 void popFront()
985 {
986 foreach (i, Unused; R)
987 {
988 if (source[i].empty) continue;
989 source[i].popFront();
990 return;
991 }
992 }
993
frontResult994 @property auto ref front()
995 {
996 foreach (i, Unused; R)
997 {
998 if (source[i].empty) continue;
999 return fixRef(source[i].front);
1000 }
1001 assert(false);
1002 }
1003
1004 static if (allSameType && allSatisfy!(hasAssignableElements, R))
1005 {
1006 // @@@BUG@@@
1007 //@property void front(T)(T v) if (is(T : RvalueElementType))
1008
frontResult1009 @property void front(RvalueElementType v)
1010 {
1011 foreach (i, Unused; R)
1012 {
1013 if (source[i].empty) continue;
1014 source[i].front = v;
1015 return;
1016 }
1017 assert(false);
1018 }
1019 }
1020
1021 static if (allSatisfy!(hasMobileElements, R))
1022 {
moveFrontResult1023 RvalueElementType moveFront()
1024 {
1025 foreach (i, Unused; R)
1026 {
1027 if (source[i].empty) continue;
1028 return source[i].moveFront();
1029 }
1030 assert(false);
1031 }
1032 }
1033
1034 static if (allSatisfy!(isBidirectionalRange, R))
1035 {
backResult1036 @property auto ref back()
1037 {
1038 foreach_reverse (i, Unused; R)
1039 {
1040 if (source[i].empty) continue;
1041 return fixRef(source[i].back);
1042 }
1043 assert(false);
1044 }
1045
popBackResult1046 void popBack()
1047 {
1048 foreach_reverse (i, Unused; R)
1049 {
1050 if (source[i].empty) continue;
1051 source[i].popBack();
1052 return;
1053 }
1054 }
1055
1056 static if (allSatisfy!(hasMobileElements, R))
1057 {
moveBackResult1058 RvalueElementType moveBack()
1059 {
1060 foreach_reverse (i, Unused; R)
1061 {
1062 if (source[i].empty) continue;
1063 return source[i].moveBack();
1064 }
1065 assert(false);
1066 }
1067 }
1068
1069 static if (allSameType && allSatisfy!(hasAssignableElements, R))
1070 {
backResult1071 @property void back(RvalueElementType v)
1072 {
1073 foreach_reverse (i, Unused; R)
1074 {
1075 if (source[i].empty) continue;
1076 source[i].back = v;
1077 return;
1078 }
1079 assert(false);
1080 }
1081 }
1082 }
1083
1084 static if (allSatisfy!(hasLength, R))
1085 {
lengthResult1086 @property size_t length()
1087 {
1088 size_t result;
1089 foreach (i, Unused; R)
1090 {
1091 result += source[i].length;
1092 }
1093 return result;
1094 }
1095
1096 alias opDollar = length;
1097 }
1098
1099 static if (allSatisfy!(isRandomAccessRange, R))
1100 {
opIndexResult1101 auto ref opIndex(size_t index)
1102 {
1103 foreach (i, Range; R)
1104 {
1105 static if (isInfinite!(Range))
1106 {
1107 return source[i][index];
1108 }
1109 else
1110 {
1111 immutable length = source[i].length;
1112 if (index < length) return fixRef(source[i][index]);
1113 index -= length;
1114 }
1115 }
1116 assert(false);
1117 }
1118
1119 static if (allSatisfy!(hasMobileElements, R))
1120 {
moveAtResult1121 RvalueElementType moveAt(size_t index)
1122 {
1123 foreach (i, Range; R)
1124 {
1125 static if (isInfinite!(Range))
1126 {
1127 return source[i].moveAt(index);
1128 }
1129 else
1130 {
1131 immutable length = source[i].length;
1132 if (index < length) return source[i].moveAt(index);
1133 index -= length;
1134 }
1135 }
1136 assert(false);
1137 }
1138 }
1139
1140 static if (allSameType && allSatisfy!(hasAssignableElements, R))
opIndexAssignResult1141 void opIndexAssign(ElementType v, size_t index)
1142 {
1143 foreach (i, Range; R)
1144 {
1145 static if (isInfinite!(Range))
1146 {
1147 source[i][index] = v;
1148 }
1149 else
1150 {
1151 immutable length = source[i].length;
1152 if (index < length)
1153 {
1154 source[i][index] = v;
1155 return;
1156 }
1157 index -= length;
1158 }
1159 }
1160 assert(false);
1161 }
1162 }
1163
1164 static if (allSatisfy!(hasLength, R) && allSatisfy!(hasSlicing, R))
opSliceResult1165 auto opSlice(size_t begin, size_t end)
1166 {
1167 auto result = this;
1168 foreach (i, Unused; R)
1169 {
1170 immutable len = result.source[i].length;
1171 if (len < begin)
1172 {
1173 result.source[i] = result.source[i]
1174 [len .. len];
1175 begin -= len;
1176 }
1177 else
1178 {
1179 result.source[i] = result.source[i]
1180 [begin .. len];
1181 break;
1182 }
1183 }
1184 auto cut = length;
1185 cut = cut <= end ? 0 : cut - end;
1186 foreach_reverse (i, Unused; R)
1187 {
1188 immutable len = result.source[i].length;
1189 if (cut > len)
1190 {
1191 result.source[i] = result.source[i]
1192 [0 .. 0];
1193 cut -= len;
1194 }
1195 else
1196 {
1197 result.source[i] = result.source[i]
1198 [0 .. len - cut];
1199 break;
1200 }
1201 }
1202 return result;
1203 }
1204 }
1205 return Result(rs);
1206 }
1207 }
1208
1209 ///
1210 pure @safe nothrow unittest
1211 {
1212 import std.algorithm.comparison : equal;
1213
1214 int[] arr1 = [ 1, 2, 3, 4 ];
1215 int[] arr2 = [ 5, 6 ];
1216 int[] arr3 = [ 7 ];
1217 auto s = chain(arr1, arr2, arr3);
1218 assert(s.length == 7);
1219 assert(s[5] == 6);
1220 assert(equal(s, [1, 2, 3, 4, 5, 6, 7][]));
1221 }
1222
1223 /**
1224 * Range primitives are carried over to the returned range if
1225 * all of the ranges provide them
1226 */
1227 pure @safe nothrow unittest
1228 {
1229 import std.algorithm.comparison : equal;
1230 import std.algorithm.sorting : sort;
1231
1232 int[] arr1 = [5, 2, 8];
1233 int[] arr2 = [3, 7, 9];
1234 int[] arr3 = [1, 4, 6];
1235
1236 // in-place sorting across all of the arrays
1237 auto s = arr1.chain(arr2, arr3).sort;
1238
1239 assert(s.equal([1, 2, 3, 4, 5, 6, 7, 8, 9]));
1240 assert(arr1.equal([1, 2, 3]));
1241 assert(arr2.equal([4, 5, 6]));
1242 assert(arr3.equal([7, 8, 9]));
1243 }
1244
1245 pure @safe nothrow unittest
1246 {
1247 import std.algorithm.comparison : equal;
1248 import std.internal.test.dummyrange : AllDummyRanges, dummyLength,
1249 propagatesRangeType;
1250
1251 {
1252 int[] arr1 = [ 1, 2, 3, 4 ];
1253 int[] arr2 = [ 5, 6 ];
1254 int[] arr3 = [ 7 ];
1255 int[] witness = [ 1, 2, 3, 4, 5, 6, 7 ];
1256 auto s1 = chain(arr1);
1257 static assert(isRandomAccessRange!(typeof(s1)));
1258 auto s2 = chain(arr1, arr2);
1259 static assert(isBidirectionalRange!(typeof(s2)));
1260 static assert(isRandomAccessRange!(typeof(s2)));
1261 s2.front = 1;
1262 auto s = chain(arr1, arr2, arr3);
1263 assert(s[5] == 6);
1264 assert(equal(s, witness));
1265 assert(s[5] == 6);
1266 }
1267 {
1268 int[] arr1 = [ 1, 2, 3, 4 ];
1269 int[] witness = [ 1, 2, 3, 4 ];
1270 assert(equal(chain(arr1), witness));
1271 }
1272 {
1273 uint[] foo = [1,2,3,4,5];
1274 uint[] bar = [1,2,3,4,5];
1275 auto c = chain(foo, bar);
1276 c[3] = 42;
1277 assert(c[3] == 42);
1278 assert(c.moveFront() == 1);
1279 assert(c.moveBack() == 5);
1280 assert(c.moveAt(4) == 5);
1281 assert(c.moveAt(5) == 1);
1282 }
1283
1284 // Make sure bug 3311 is fixed. ChainImpl should compile even if not all
1285 // elements are mutable.
1286 assert(equal(chain(iota(0, 3), iota(0, 3)), [0, 1, 2, 0, 1, 2]));
1287
1288 // Test the case where infinite ranges are present.
1289 auto inf = chain([0,1,2][], cycle([4,5,6][]), [7,8,9][]); // infinite range
1290 assert(inf[0] == 0);
1291 assert(inf[3] == 4);
1292 assert(inf[6] == 4);
1293 assert(inf[7] == 5);
1294 static assert(isInfinite!(typeof(inf)));
1295
1296 immutable int[] immi = [ 1, 2, 3 ];
1297 immutable float[] immf = [ 1, 2, 3 ];
1298 static assert(is(typeof(chain(immi, immf))));
1299
1300 // Check that chain at least instantiates and compiles with every possible
1301 // pair of DummyRange types, in either order.
1302
foreach(DummyType1;AllDummyRanges)1303 foreach (DummyType1; AllDummyRanges)
1304 {
1305 DummyType1 dummy1;
1306 foreach (DummyType2; AllDummyRanges)
1307 {
1308 DummyType2 dummy2;
1309 auto myChain = chain(dummy1, dummy2);
1310
1311 static assert(
1312 propagatesRangeType!(typeof(myChain), DummyType1, DummyType2)
1313 );
1314
1315 assert(myChain.front == 1);
1316 foreach (i; 0 .. dummyLength)
1317 {
1318 myChain.popFront();
1319 }
1320 assert(myChain.front == 1);
1321
1322 static if (isBidirectionalRange!DummyType1 &&
1323 isBidirectionalRange!DummyType2) {
1324 assert(myChain.back == 10);
1325 }
1326
1327 static if (isRandomAccessRange!DummyType1 &&
1328 isRandomAccessRange!DummyType2) {
1329 assert(myChain[0] == 1);
1330 }
1331
1332 static if (hasLvalueElements!DummyType1 && hasLvalueElements!DummyType2)
1333 {
1334 static assert(hasLvalueElements!(typeof(myChain)));
1335 }
1336 else
1337 {
1338 static assert(!hasLvalueElements!(typeof(myChain)));
1339 }
1340 }
1341 }
1342 }
1343
1344 pure @safe nothrow @nogc unittest
1345 {
1346 class Foo{}
1347 immutable(Foo)[] a;
1348 immutable(Foo)[] b;
1349 assert(chain(a, b).empty);
1350 }
1351
1352 /**
1353 Choose one of two ranges at runtime depending on a Boolean condition.
1354
1355 The ranges may be different, but they must have compatible element types (i.e.
1356 $(D CommonType) must exist for the two element types). The result is a range
1357 that offers the weakest capabilities of the two (e.g. $(D ForwardRange) if $(D
1358 R1) is a random-access range and $(D R2) is a forward range).
1359
1360 Params:
1361 condition = which range to choose: $(D r1) if $(D true), $(D r2) otherwise
1362 r1 = the "true" range
1363 r2 = the "false" range
1364
1365 Returns:
1366 A range type dependent on $(D R1) and $(D R2).
1367
1368 Bugs:
1369 $(BUGZILLA 14660)
1370 */
1371 auto choose(R1, R2)(bool condition, R1 r1, R2 r2)
1372 if (isInputRange!(Unqual!R1) && isInputRange!(Unqual!R2) &&
1373 !is(CommonType!(ElementType!(Unqual!R1), ElementType!(Unqual!R2)) == void))
1374 {
1375 static struct Result
1376 {
1377 import std.algorithm.comparison : max;
1378 import std.algorithm.internal : addressOf;
1379 import std.traits : hasElaborateCopyConstructor, hasElaborateDestructor;
1380
1381 private union
1382 {
1383 void[max(R1.sizeof, R2.sizeof)] buffer = void;
1384 void* forAlignmentOnly = void;
1385 }
1386 private bool condition;
r1Result1387 private @property ref R1 r1()
1388 {
1389 assert(condition);
1390 return *cast(R1*) buffer.ptr;
1391 }
r2Result1392 private @property ref R2 r2()
1393 {
1394 assert(!condition);
1395 return *cast(R2*) buffer.ptr;
1396 }
1397
thisResult1398 this(bool condition, R1 r1, R2 r2)
1399 {
1400 this.condition = condition;
1401 import std.conv : emplace;
1402 if (condition) emplace(addressOf(this.r1), r1);
1403 else emplace(addressOf(this.r2), r2);
1404 }
1405
1406 // Carefully defined postblit to postblit the appropriate range
1407 static if (hasElaborateCopyConstructor!R1
1408 || hasElaborateCopyConstructor!R2)
thisResult1409 this(this)
1410 {
1411 if (condition)
1412 {
1413 static if (hasElaborateCopyConstructor!R1) r1.__postblit();
1414 }
1415 else
1416 {
1417 static if (hasElaborateCopyConstructor!R2) r2.__postblit();
1418 }
1419 }
1420
1421 static if (hasElaborateDestructor!R1 || hasElaborateDestructor!R2)
~thisResult1422 ~this()
1423 {
1424 if (condition) destroy(r1);
1425 else destroy(r2);
1426 }
1427
1428 static if (isInfinite!R1 && isInfinite!R2)
1429 // Propagate infiniteness.
1430 enum bool empty = false;
1431 else
emptyResult1432 @property bool empty()
1433 {
1434 return condition ? r1.empty : r2.empty;
1435 }
1436
frontResult1437 @property auto ref front()
1438 {
1439 return condition ? r1.front : r2.front;
1440 }
1441
popFrontResult1442 void popFront()
1443 {
1444 return condition ? r1.popFront : r2.popFront;
1445 }
1446
1447 static if (isForwardRange!R1 && isForwardRange!R2)
saveResult1448 @property auto save()
1449 {
1450 auto result = this;
1451 if (condition) r1 = r1.save;
1452 else r2 = r2.save;
1453 return result;
1454 }
1455
1456 @property void front(T)(T v)
1457 if (is(typeof({ r1.front = v; r2.front = v; })))
1458 {
1459 if (condition) r1.front = v; else r2.front = v;
1460 }
1461
1462 static if (hasMobileElements!R1 && hasMobileElements!R2)
moveFrontResult1463 auto moveFront()
1464 {
1465 return condition ? r1.moveFront : r2.moveFront;
1466 }
1467
1468 static if (isBidirectionalRange!R1 && isBidirectionalRange!R2)
1469 {
backResult1470 @property auto ref back()
1471 {
1472 return condition ? r1.back : r2.back;
1473 }
1474
popBackResult1475 void popBack()
1476 {
1477 return condition ? r1.popBack : r2.popBack;
1478 }
1479
1480 static if (hasMobileElements!R1 && hasMobileElements!R2)
moveBackResult1481 auto moveBack()
1482 {
1483 return condition ? r1.moveBack : r2.moveBack;
1484 }
1485
1486 @property void back(T)(T v)
1487 if (is(typeof({ r1.back = v; r2.back = v; })))
1488 {
1489 if (condition) r1.back = v; else r2.back = v;
1490 }
1491 }
1492
1493 static if (hasLength!R1 && hasLength!R2)
1494 {
lengthResult1495 @property size_t length()
1496 {
1497 return condition ? r1.length : r2.length;
1498 }
1499 alias opDollar = length;
1500 }
1501
1502 static if (isRandomAccessRange!R1 && isRandomAccessRange!R2)
1503 {
opIndexResult1504 auto ref opIndex(size_t index)
1505 {
1506 return condition ? r1[index] : r2[index];
1507 }
1508
1509 static if (hasMobileElements!R1 && hasMobileElements!R2)
moveAtResult1510 auto moveAt(size_t index)
1511 {
1512 return condition ? r1.moveAt(index) : r2.moveAt(index);
1513 }
1514
1515 void opIndexAssign(T)(T v, size_t index)
1516 if (is(typeof({ r1[1] = v; r2[1] = v; })))
1517 {
1518 if (condition) r1[index] = v; else r2[index] = v;
1519 }
1520 }
1521
1522 // BUG: this should work for infinite ranges, too
1523 static if (hasSlicing!R1 && hasSlicing!R2 &&
1524 !isInfinite!R2 && !isInfinite!R2)
opSliceResult1525 auto opSlice(size_t begin, size_t end)
1526 {
1527 auto result = this;
1528 if (condition) result.r1 = result.r1[begin .. end];
1529 else result.r2 = result.r2[begin .. end];
1530 return result;
1531 }
1532 }
1533 return Result(condition, r1, r2);
1534 }
1535
1536 ///
1537 @system unittest
1538 {
1539 import std.algorithm.comparison : equal;
1540 import std.algorithm.iteration : filter, map;
1541
1542 auto data1 = [ 1, 2, 3, 4 ].filter!(a => a != 3);
1543 auto data2 = [ 5, 6, 7, 8 ].map!(a => a + 1);
1544
1545 // choose() is primarily useful when you need to select one of two ranges
1546 // with different types at runtime.
1547 static assert(!is(typeof(data1) == typeof(data2)));
1548
chooseRange(bool pickFirst)1549 auto chooseRange(bool pickFirst)
1550 {
1551 // The returned range is a common wrapper type that can be used for
1552 // returning or storing either range without running into a type error.
1553 return choose(pickFirst, data1, data2);
1554
1555 // Simply returning the chosen range without using choose() does not
1556 // work, because map() and filter() return different types.
1557 //return pickFirst ? data1 : data2; // does not compile
1558 }
1559
1560 auto result = chooseRange(true);
1561 assert(result.equal([ 1, 2, 4 ]));
1562
1563 result = chooseRange(false);
1564 assert(result.equal([ 6, 7, 8, 9 ]));
1565 }
1566
1567 /**
1568 Choose one of multiple ranges at runtime.
1569
1570 The ranges may be different, but they must have compatible element types. The
1571 result is a range that offers the weakest capabilities of all $(D Ranges).
1572
1573 Params:
1574 index = which range to choose, must be less than the number of ranges
1575 rs = two or more ranges
1576
1577 Returns:
1578 The indexed range. If rs consists of only one range, the return type is an
1579 alias of that range's type.
1580 */
1581 auto chooseAmong(Ranges...)(size_t index, Ranges rs)
1582 if (Ranges.length >= 2
1583 && allSatisfy!(isInputRange, staticMap!(Unqual, Ranges))
1584 && !is(CommonType!(staticMap!(ElementType, Ranges)) == void))
1585 {
1586 static if (Ranges.length == 2)
1587 return choose(index == 0, rs[0], rs[1]);
1588 else
1589 return choose(index == 0, rs[0], chooseAmong(index - 1, rs[1 .. $]));
1590 }
1591
1592 ///
1593 @system unittest
1594 {
1595 import std.algorithm.comparison : equal;
1596
1597 int[] arr1 = [ 1, 2, 3, 4 ];
1598 int[] arr2 = [ 5, 6 ];
1599 int[] arr3 = [ 7 ];
1600
1601 {
1602 auto s = chooseAmong(0, arr1, arr2, arr3);
1603 auto t = s.save;
1604 assert(s.length == 4);
1605 assert(s[2] == 3);
1606 s.popFront();
1607 assert(equal(t, [1, 2, 3, 4][]));
1608 }
1609 {
1610 auto s = chooseAmong(1, arr1, arr2, arr3);
1611 assert(s.length == 2);
1612 s.front = 8;
1613 assert(equal(s, [8, 6][]));
1614 }
1615 {
1616 auto s = chooseAmong(1, arr1, arr2, arr3);
1617 assert(s.length == 2);
1618 s[1] = 9;
1619 assert(equal(s, [8, 9][]));
1620 }
1621 {
1622 auto s = chooseAmong(1, arr2, arr1, arr3)[1 .. 3];
1623 assert(s.length == 2);
1624 assert(equal(s, [2, 3][]));
1625 }
1626 {
1627 auto s = chooseAmong(0, arr1, arr2, arr3);
1628 assert(s.length == 4);
1629 assert(s.back == 4);
1630 s.popBack();
1631 s.back = 5;
1632 assert(equal(s, [1, 2, 5][]));
1633 s.back = 3;
1634 assert(equal(s, [1, 2, 3][]));
1635 }
1636 {
1637 uint[] foo = [1,2,3,4,5];
1638 uint[] bar = [6,7,8,9,10];
1639 auto c = chooseAmong(1,foo, bar);
1640 assert(c[3] == 9);
1641 c[3] = 42;
1642 assert(c[3] == 42);
1643 assert(c.moveFront() == 6);
1644 assert(c.moveBack() == 10);
1645 assert(c.moveAt(4) == 10);
1646 }
1647 {
1648 import std.range : cycle;
1649 auto s = chooseAmong(1, cycle(arr2), cycle(arr3));
1650 assert(isInfinite!(typeof(s)));
1651 assert(!s.empty);
1652 assert(s[100] == 7);
1653 }
1654 }
1655
1656 @system unittest
1657 {
1658 int[] a = [1, 2, 3];
1659 long[] b = [4, 5, 6];
1660 auto c = chooseAmong(0, a, b);
1661 c[0] = 42;
1662 assert(c[0] == 42);
1663 }
1664
1665
1666 /**
1667 $(D roundRobin(r1, r2, r3)) yields $(D r1.front), then $(D r2.front),
1668 then $(D r3.front), after which it pops off one element from each and
1669 continues again from $(D r1). For example, if two ranges are involved,
1670 it alternately yields elements off the two ranges. $(D roundRobin)
1671 stops after it has consumed all ranges (skipping over the ones that
1672 finish early).
1673 */
1674 auto roundRobin(Rs...)(Rs rs)
1675 if (Rs.length > 1 && allSatisfy!(isInputRange, staticMap!(Unqual, Rs)))
1676 {
1677 struct Result
1678 {
1679 import std.conv : to;
1680
1681 public Rs source;
1682 private size_t _current = size_t.max;
1683
emptyResult1684 @property bool empty()
1685 {
1686 foreach (i, Unused; Rs)
1687 {
1688 if (!source[i].empty) return false;
1689 }
1690 return true;
1691 }
1692
frontResult1693 @property auto ref front()
1694 {
1695 final switch (_current)
1696 {
1697 foreach (i, R; Rs)
1698 {
1699 case i:
1700 assert(
1701 !source[i].empty,
1702 "Attempting to fetch the front of an empty roundRobin"
1703 );
1704 return source[i].front;
1705 }
1706 }
1707 assert(0);
1708 }
1709
popFrontResult1710 void popFront()
1711 {
1712 final switch (_current)
1713 {
1714 foreach (i, R; Rs)
1715 {
1716 case i:
1717 source[i].popFront();
1718 break;
1719 }
1720 }
1721
1722 auto next = _current == (Rs.length - 1) ? 0 : (_current + 1);
1723 final switch (next)
1724 {
1725 foreach (i, R; Rs)
1726 {
1727 case i:
1728 if (!source[i].empty)
1729 {
1730 _current = i;
1731 return;
1732 }
1733 if (i == _current)
1734 {
1735 _current = _current.max;
1736 return;
1737 }
1738 goto case (i + 1) % Rs.length;
1739 }
1740 }
1741 }
1742
1743 static if (allSatisfy!(isForwardRange, staticMap!(Unqual, Rs)))
saveResult1744 @property auto save()
1745 {
1746 Result result = this;
1747 foreach (i, Unused; Rs)
1748 {
1749 result.source[i] = result.source[i].save;
1750 }
1751 return result;
1752 }
1753
1754 static if (allSatisfy!(hasLength, Rs))
1755 {
lengthResult1756 @property size_t length()
1757 {
1758 size_t result;
1759 foreach (i, R; Rs)
1760 {
1761 result += source[i].length;
1762 }
1763 return result;
1764 }
1765
1766 alias opDollar = length;
1767 }
1768 }
1769
1770 return Result(rs, 0);
1771 }
1772
1773 ///
1774 @safe unittest
1775 {
1776 import std.algorithm.comparison : equal;
1777
1778 int[] a = [ 1, 2, 3 ];
1779 int[] b = [ 10, 20, 30, 40 ];
1780 auto r = roundRobin(a, b);
1781 assert(equal(r, [ 1, 10, 2, 20, 3, 30, 40 ]));
1782 }
1783
1784 /**
1785 * roundRobin can be used to create "interleave" functionality which inserts
1786 * an element between each element in a range.
1787 */
1788 @safe unittest
1789 {
1790 import std.algorithm.comparison : equal;
1791
1792 auto interleave(R, E)(R range, E element)
1793 if ((isInputRange!R && hasLength!R) || isForwardRange!R)
1794 {
1795 static if (hasLength!R)
1796 immutable len = range.length;
1797 else
1798 immutable len = range.save.walkLength;
1799
1800 return roundRobin(
1801 range,
1802 element.repeat(len - 1)
1803 );
1804 }
1805
1806 assert(interleave([1, 2, 3], 0).equal([1, 0, 2, 0, 3]));
1807 }
1808
1809 /**
1810 Iterates a random-access range starting from a given point and
1811 progressively extending left and right from that point. If no initial
1812 point is given, iteration starts from the middle of the
1813 range. Iteration spans the entire range.
1814
1815 When `startingIndex` is 0 the range will be fully iterated in order
1816 and in reverse order when `r.length` is given.
1817
1818 Params:
1819 r = a random access range with length and slicing
1820 startingIndex = the index to begin iteration from
1821
1822 Returns:
1823 A forward range with length
1824 */
1825 auto radial(Range, I)(Range r, I startingIndex)
1826 if (isRandomAccessRange!(Unqual!Range) && hasLength!(Unqual!Range) && hasSlicing!(Unqual!Range) && isIntegral!I)
1827 {
1828 if (startingIndex != r.length) ++startingIndex;
1829 return roundRobin(retro(r[0 .. startingIndex]), r[startingIndex .. r.length]);
1830 }
1831
1832 /// Ditto
1833 auto radial(R)(R r)
1834 if (isRandomAccessRange!(Unqual!R) && hasLength!(Unqual!R) && hasSlicing!(Unqual!R))
1835 {
1836 return .radial(r, (r.length - !r.empty) / 2);
1837 }
1838
1839 ///
1840 @safe unittest
1841 {
1842 import std.algorithm.comparison : equal;
1843 int[] a = [ 1, 2, 3, 4, 5 ];
1844 assert(equal(radial(a), [ 3, 4, 2, 5, 1 ]));
1845 a = [ 1, 2, 3, 4 ];
1846 assert(equal(radial(a), [ 2, 3, 1, 4 ]));
1847
1848 // If the left end is reached first, the remaining elements on the right
1849 // are concatenated in order:
1850 a = [ 0, 1, 2, 3, 4, 5 ];
1851 assert(equal(radial(a, 1), [ 1, 2, 0, 3, 4, 5 ]));
1852
1853 // If the right end is reached first, the remaining elements on the left
1854 // are concatenated in reverse order:
1855 assert(equal(radial(a, 4), [ 4, 5, 3, 2, 1, 0 ]));
1856 }
1857
1858 @safe unittest
1859 {
1860 import std.algorithm.comparison : equal;
1861 import std.conv : text;
1862 import std.exception : enforce;
1863 import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy;
1864
test(int[]input,int[]witness)1865 void test(int[] input, int[] witness)
1866 {
1867 enforce(equal(radial(input), witness),
1868 text(radial(input), " vs. ", witness));
1869 }
1870 test([], []);
1871 test([ 1 ], [ 1 ]);
1872 test([ 1, 2 ], [ 1, 2 ]);
1873 test([ 1, 2, 3 ], [ 2, 3, 1 ]);
1874 test([ 1, 2, 3, 4 ], [ 2, 3, 1, 4 ]);
1875 test([ 1, 2, 3, 4, 5 ], [ 3, 4, 2, 5, 1 ]);
1876 test([ 1, 2, 3, 4, 5, 6 ], [ 3, 4, 2, 5, 1, 6 ]);
1877
1878 int[] a = [ 1, 2, 3, 4, 5 ];
1879 assert(equal(radial(a, 1), [ 2, 3, 1, 4, 5 ]));
1880 assert(equal(radial(a, 0), [ 1, 2, 3, 4, 5 ])); // only right subrange
1881 assert(equal(radial(a, a.length), [ 5, 4, 3, 2, 1 ])); // only left subrange
1882 static assert(isForwardRange!(typeof(radial(a, 1))));
1883
1884 auto r = radial([1,2,3,4,5]);
1885 for (auto rr = r.save; !rr.empty; rr.popFront())
1886 {
1887 assert(rr.front == moveFront(rr));
1888 }
1889 r.front = 5;
1890 assert(r.front == 5);
1891
1892 // Test instantiation without lvalue elements.
1893 DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random) dummy;
1894 assert(equal(radial(dummy, 4), [5, 6, 4, 7, 3, 8, 2, 9, 1, 10]));
1895
1896 // immutable int[] immi = [ 1, 2 ];
1897 // static assert(is(typeof(radial(immi))));
1898 }
1899
1900 @safe unittest
1901 {
1902 import std.algorithm.comparison : equal;
1903
1904 auto LL = iota(1L, 6L);
1905 auto r = radial(LL);
1906 assert(equal(r, [3L, 4L, 2L, 5L, 1L]));
1907 }
1908
1909 /**
1910 Lazily takes only up to `n` elements of a range. This is
1911 particularly useful when using with infinite ranges.
1912
1913 Unlike $(LREF takeExactly), `take` does not require that there
1914 are `n` or more elements in `input`. As a consequence, length
1915 information is not applied to the result unless `input` also has
1916 length information.
1917
1918 Params:
1919 input = an input range to iterate over up to `n` times
1920 n = the number of elements to take
1921
1922 Returns:
1923 At minimum, an input range. If the range offers random access
1924 and `length`, `take` offers them as well.
1925 */
1926 Take!R take(R)(R input, size_t n)
1927 if (isInputRange!(Unqual!R))
1928 {
1929 alias U = Unqual!R;
1930 static if (is(R T == Take!T))
1931 {
1932 import std.algorithm.comparison : min;
1933 return R(input.source, min(n, input._maxAvailable));
1934 }
1935 else static if (!isInfinite!U && hasSlicing!U)
1936 {
1937 import std.algorithm.comparison : min;
1938 return input[0 .. min(n, input.length)];
1939 }
1940 else
1941 {
1942 return Take!R(input, n);
1943 }
1944 }
1945
1946 /// ditto
1947 struct Take(Range)
1948 if (isInputRange!(Unqual!Range) &&
1949 //take _cannot_ test hasSlicing on infinite ranges, because hasSlicing uses
1950 //take for slicing infinite ranges.
1951 !((!isInfinite!(Unqual!Range) && hasSlicing!(Unqual!Range)) || is(Range T == Take!T)))
1952 {
1953 private alias R = Unqual!Range;
1954
1955 /// User accessible in read and write
1956 public R source;
1957
1958 private size_t _maxAvailable;
1959
1960 alias Source = R;
1961
1962 /// Range primitives
empty()1963 @property bool empty()
1964 {
1965 return _maxAvailable == 0 || source.empty;
1966 }
1967
1968 /// ditto
front()1969 @property auto ref front()
1970 {
1971 assert(!empty,
1972 "Attempting to fetch the front of an empty "
1973 ~ Take.stringof);
1974 return source.front;
1975 }
1976
1977 /// ditto
popFront()1978 void popFront()
1979 {
1980 assert(!empty,
1981 "Attempting to popFront() past the end of a "
1982 ~ Take.stringof);
1983 source.popFront();
1984 --_maxAvailable;
1985 }
1986
1987 static if (isForwardRange!R)
1988 /// ditto
save()1989 @property Take save()
1990 {
1991 return Take(source.save, _maxAvailable);
1992 }
1993
1994 static if (hasAssignableElements!R)
1995 /// ditto
1996 @property void front(ElementType!R v)
1997 {
1998 assert(!empty,
1999 "Attempting to assign to the front of an empty "
2000 ~ Take.stringof);
2001 // This has to return auto instead of void because of Bug 4706.
2002 source.front = v;
2003 }
2004
2005 static if (hasMobileElements!R)
2006 {
2007 /// ditto
moveFront()2008 auto moveFront()
2009 {
2010 assert(!empty,
2011 "Attempting to move the front of an empty "
2012 ~ Take.stringof);
2013 return source.moveFront();
2014 }
2015 }
2016
2017 static if (isInfinite!R)
2018 {
2019 /// ditto
length()2020 @property size_t length() const
2021 {
2022 return _maxAvailable;
2023 }
2024
2025 /// ditto
2026 alias opDollar = length;
2027
2028 //Note: Due to Take/hasSlicing circular dependency,
2029 //This needs to be a restrained template.
2030 /// ditto
2031 auto opSlice()(size_t i, size_t j)
2032 if (hasSlicing!R)
2033 {
2034 assert(i <= j, "Invalid slice bounds");
2035 assert(j <= length, "Attempting to slice past the end of a "
2036 ~ Take.stringof);
2037 return source[i .. j];
2038 }
2039 }
2040 else static if (hasLength!R)
2041 {
2042 /// ditto
length()2043 @property size_t length()
2044 {
2045 import std.algorithm.comparison : min;
2046 return min(_maxAvailable, source.length);
2047 }
2048
2049 alias opDollar = length;
2050 }
2051
2052 static if (isRandomAccessRange!R)
2053 {
2054 /// ditto
popBack()2055 void popBack()
2056 {
2057 assert(!empty,
2058 "Attempting to popBack() past the beginning of a "
2059 ~ Take.stringof);
2060 --_maxAvailable;
2061 }
2062
2063 /// ditto
back()2064 @property auto ref back()
2065 {
2066 assert(!empty,
2067 "Attempting to fetch the back of an empty "
2068 ~ Take.stringof);
2069 return source[this.length - 1];
2070 }
2071
2072 /// ditto
opIndex(size_t index)2073 auto ref opIndex(size_t index)
2074 {
2075 assert(index < length,
2076 "Attempting to index out of the bounds of a "
2077 ~ Take.stringof);
2078 return source[index];
2079 }
2080
2081 static if (hasAssignableElements!R)
2082 {
2083 /// ditto
2084 @property void back(ElementType!R v)
2085 {
2086 // This has to return auto instead of void because of Bug 4706.
2087 assert(!empty,
2088 "Attempting to assign to the back of an empty "
2089 ~ Take.stringof);
2090 source[this.length - 1] = v;
2091 }
2092
2093 /// ditto
2094 void opIndexAssign(ElementType!R v, size_t index)
2095 {
2096 assert(index < length,
2097 "Attempting to index out of the bounds of a "
2098 ~ Take.stringof);
2099 source[index] = v;
2100 }
2101 }
2102
2103 static if (hasMobileElements!R)
2104 {
2105 /// ditto
moveBack()2106 auto moveBack()
2107 {
2108 assert(!empty,
2109 "Attempting to move the back of an empty "
2110 ~ Take.stringof);
2111 return source.moveAt(this.length - 1);
2112 }
2113
2114 /// ditto
moveAt(size_t index)2115 auto moveAt(size_t index)
2116 {
2117 assert(index < length,
2118 "Attempting to index out of the bounds of a "
2119 ~ Take.stringof);
2120 return source.moveAt(index);
2121 }
2122 }
2123 }
2124
2125 /**
2126 Access to maximal length of the range.
2127 Note: the actual length of the range depends on the underlying range.
2128 If it has fewer elements, it will stop before maxLength is reached.
2129 */
maxLength()2130 @property size_t maxLength() const
2131 {
2132 return _maxAvailable;
2133 }
2134 }
2135
2136 /**
2137 This template simply aliases itself to R and is useful for consistency in
2138 generic code.
2139 */
2140 template Take(R)
2141 if (isInputRange!(Unqual!R) &&
2142 ((!isInfinite!(Unqual!R) && hasSlicing!(Unqual!R)) || is(R T == Take!T)))
2143 {
2144 alias Take = R;
2145 }
2146
2147 ///
2148 pure @safe nothrow unittest
2149 {
2150 import std.algorithm.comparison : equal;
2151
2152 int[] arr1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
2153 auto s = take(arr1, 5);
2154 assert(s.length == 5);
2155 assert(s[4] == 5);
2156 assert(equal(s, [ 1, 2, 3, 4, 5 ][]));
2157 }
2158
2159 /**
2160 * If the range runs out before `n` elements, `take` simply returns the entire
2161 * range (unlike $(LREF takeExactly), which will cause an assertion failure if
2162 * the range ends prematurely):
2163 */
2164 pure @safe nothrow unittest
2165 {
2166 import std.algorithm.comparison : equal;
2167
2168 int[] arr2 = [ 1, 2, 3 ];
2169 auto t = take(arr2, 5);
2170 assert(t.length == 3);
2171 assert(equal(t, [ 1, 2, 3 ]));
2172 }
2173
2174 pure @safe nothrow unittest
2175 {
2176 import std.algorithm.comparison : equal;
2177 import std.internal.test.dummyrange : AllDummyRanges;
2178
2179 int[] arr1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
2180 auto s = take(arr1, 5);
2181 assert(s.length == 5);
2182 assert(s[4] == 5);
2183 assert(equal(s, [ 1, 2, 3, 4, 5 ][]));
2184 assert(equal(retro(s), [ 5, 4, 3, 2, 1 ][]));
2185
2186 // Test fix for bug 4464.
2187 static assert(is(typeof(s) == Take!(int[])));
2188 static assert(is(typeof(s) == int[]));
2189
2190 // Test using narrow strings.
2191 import std.exception : assumeWontThrow;
2192
2193 auto myStr = "This is a string.";
2194 auto takeMyStr = take(myStr, 7);
2195 assert(assumeWontThrow(equal(takeMyStr, "This is")));
2196 // Test fix for bug 5052.
2197 auto takeMyStrAgain = take(takeMyStr, 4);
2198 assert(assumeWontThrow(equal(takeMyStrAgain, "This")));
2199 static assert(is (typeof(takeMyStrAgain) == typeof(takeMyStr)));
2200 takeMyStrAgain = take(takeMyStr, 10);
2201 assert(assumeWontThrow(equal(takeMyStrAgain, "This is")));
2202
foreach(DummyType;AllDummyRanges)2203 foreach (DummyType; AllDummyRanges)
2204 {
2205 DummyType dummy;
2206 auto t = take(dummy, 5);
2207 alias T = typeof(t);
2208
2209 static if (isRandomAccessRange!DummyType)
2210 {
2211 static assert(isRandomAccessRange!T);
2212 assert(t[4] == 5);
2213
2214 assert(moveAt(t, 1) == t[1]);
2215 assert(t.back == moveBack(t));
2216 }
2217 else static if (isForwardRange!DummyType)
2218 {
2219 static assert(isForwardRange!T);
2220 }
2221
2222 for (auto tt = t; !tt.empty; tt.popFront())
2223 {
2224 assert(tt.front == moveFront(tt));
2225 }
2226
2227 // Bidirectional ranges can't be propagated properly if they don't
2228 // also have random access.
2229
2230 assert(equal(t, [1,2,3,4,5]));
2231
2232 //Test that take doesn't wrap the result of take.
2233 assert(take(t, 4) == take(dummy, 4));
2234 }
2235
2236 immutable myRepeat = repeat(1);
2237 static assert(is(Take!(typeof(myRepeat))));
2238 }
2239
2240 pure @safe nothrow @nogc unittest
2241 {
2242 //check for correct slicing of Take on an infinite range
2243 import std.algorithm.comparison : equal;
2244 foreach (start; 0 .. 4)
2245 foreach (stop; start .. 4)
2246 assert(iota(4).cycle.take(4)[start .. stop]
2247 .equal(iota(start, stop)));
2248 }
2249
2250 pure @safe nothrow @nogc unittest
2251 {
2252 // Check that one can declare variables of all Take types,
2253 // and that they match the return type of the corresponding
2254 // take(). (See issue 4464.)
2255 int[] r1;
2256 Take!(int[]) t1;
2257 t1 = take(r1, 1);
2258 assert(t1.empty);
2259
2260 string r2;
2261 Take!string t2;
2262 t2 = take(r2, 1);
2263 assert(t2.empty);
2264
2265 Take!(Take!string) t3;
2266 t3 = take(t2, 1);
2267 assert(t3.empty);
2268 }
2269
2270 pure @safe nothrow @nogc unittest
2271 {
2272 alias R1 = typeof(repeat(1));
2273 alias R2 = typeof(cycle([1]));
2274 alias TR1 = Take!R1;
2275 alias TR2 = Take!R2;
2276 static assert(isBidirectionalRange!TR1);
2277 static assert(isBidirectionalRange!TR2);
2278 }
2279
2280 pure @safe nothrow @nogc unittest //12731
2281 {
2282 auto a = repeat(1);
2283 auto s = a[1 .. 5];
2284 s = s[1 .. 3];
2285 assert(s.length == 2);
2286 assert(s[0] == 1);
2287 assert(s[1] == 1);
2288 }
2289
2290 pure @safe nothrow @nogc unittest //13151
2291 {
2292 import std.algorithm.comparison : equal;
2293
2294 auto r = take(repeat(1, 4), 3);
2295 assert(r.take(2).equal(repeat(1, 2)));
2296 }
2297
2298
2299 /**
2300 Similar to $(LREF take), but assumes that $(D range) has at least $(D
2301 n) elements. Consequently, the result of $(D takeExactly(range, n))
2302 always defines the $(D length) property (and initializes it to $(D n))
2303 even when $(D range) itself does not define $(D length).
2304
2305 The result of $(D takeExactly) is identical to that of $(LREF take) in
2306 cases where the original range defines $(D length) or is infinite.
2307
2308 Unlike $(LREF take), however, it is illegal to pass a range with less than
2309 $(D n) elements to $(D takeExactly); this will cause an assertion failure.
2310 */
2311 auto takeExactly(R)(R range, size_t n)
2312 if (isInputRange!R)
2313 {
2314 static if (is(typeof(takeExactly(range._input, n)) == R))
2315 {
2316 assert(n <= range._n,
2317 "Attempted to take more than the length of the range with takeExactly.");
2318 // takeExactly(takeExactly(r, n1), n2) has the same type as
2319 // takeExactly(r, n1) and simply returns takeExactly(r, n2)
2320 range._n = n;
2321 return range;
2322 }
2323 //Also covers hasSlicing!R for finite ranges.
2324 else static if (hasLength!R)
2325 {
2326 assert(n <= range.length,
2327 "Attempted to take more than the length of the range with takeExactly.");
2328 return take(range, n);
2329 }
2330 else static if (isInfinite!R)
2331 return Take!R(range, n);
2332 else
2333 {
2334 static struct Result
2335 {
2336 R _input;
2337 private size_t _n;
2338
emptyResult2339 @property bool empty() const { return !_n; }
frontResult2340 @property auto ref front()
2341 {
2342 assert(_n > 0, "front() on an empty " ~ Result.stringof);
2343 return _input.front;
2344 }
popFrontResult2345 void popFront() { _input.popFront(); --_n; }
lengthResult2346 @property size_t length() const { return _n; }
2347 alias opDollar = length;
2348
2349 @property Take!R _takeExactly_Result_asTake()
2350 {
2351 return typeof(return)(_input, _n);
2352 }
2353
2354 alias _takeExactly_Result_asTake this;
2355
2356 static if (isForwardRange!R)
saveResult2357 @property auto save()
2358 {
2359 return Result(_input.save, _n);
2360 }
2361
2362 static if (hasMobileElements!R)
2363 {
moveFrontResult2364 auto moveFront()
2365 {
2366 assert(!empty,
2367 "Attempting to move the front of an empty "
2368 ~ typeof(this).stringof);
2369 return _input.moveFront();
2370 }
2371 }
2372
2373 static if (hasAssignableElements!R)
2374 {
2375 @property auto ref front(ElementType!R v)
2376 {
2377 assert(!empty,
2378 "Attempting to assign to the front of an empty "
2379 ~ typeof(this).stringof);
2380 return _input.front = v;
2381 }
2382 }
2383 }
2384
2385 return Result(range, n);
2386 }
2387 }
2388
2389 ///
2390 pure @safe nothrow unittest
2391 {
2392 import std.algorithm.comparison : equal;
2393
2394 auto a = [ 1, 2, 3, 4, 5 ];
2395
2396 auto b = takeExactly(a, 3);
2397 assert(equal(b, [1, 2, 3]));
2398 static assert(is(typeof(b.length) == size_t));
2399 assert(b.length == 3);
2400 assert(b.front == 1);
2401 assert(b.back == 3);
2402 }
2403
2404 pure @safe nothrow unittest
2405 {
2406 import std.algorithm.comparison : equal;
2407 import std.algorithm.iteration : filter;
2408
2409 auto a = [ 1, 2, 3, 4, 5 ];
2410 auto b = takeExactly(a, 3);
2411 assert(equal(b, [1, 2, 3]));
2412 auto c = takeExactly(b, 2);
2413 assert(equal(c, [1, 2]));
2414
2415
2416
2417 auto d = filter!"a > 2"(a);
2418 auto e = takeExactly(d, 3);
2419 assert(equal(e, [3, 4, 5]));
2420 static assert(is(typeof(e.length) == size_t));
2421 assert(e.length == 3);
2422 assert(e.front == 3);
2423
2424 assert(equal(takeExactly(e, 3), [3, 4, 5]));
2425 }
2426
2427 pure @safe nothrow unittest
2428 {
2429 import std.algorithm.comparison : equal;
2430 import std.internal.test.dummyrange : AllDummyRanges;
2431
2432 auto a = [ 1, 2, 3, 4, 5 ];
2433 //Test that take and takeExactly are the same for ranges which define length
2434 //but aren't sliceable.
2435 struct L
2436 {
frontL2437 @property auto front() { return _arr[0]; }
emptyL2438 @property bool empty() { return _arr.empty; }
popFrontL2439 void popFront() { _arr.popFront(); }
lengthL2440 @property size_t length() { return _arr.length; }
2441 int[] _arr;
2442 }
2443 static assert(is(typeof(take(L(a), 3)) == typeof(takeExactly(L(a), 3))));
2444 assert(take(L(a), 3) == takeExactly(L(a), 3));
2445
2446 //Test that take and takeExactly are the same for ranges which are sliceable.
2447 static assert(is(typeof(take(a, 3)) == typeof(takeExactly(a, 3))));
2448 assert(take(a, 3) == takeExactly(a, 3));
2449
2450 //Test that take and takeExactly are the same for infinite ranges.
2451 auto inf = repeat(1);
2452 static assert(is(typeof(take(inf, 5)) == Take!(typeof(inf))));
2453 assert(take(inf, 5) == takeExactly(inf, 5));
2454
2455 //Test that take and takeExactly are _not_ the same for ranges which don't
2456 //define length.
2457 static assert(!is(typeof(take(filter!"true"(a), 3)) == typeof(takeExactly(filter!"true"(a), 3))));
2458
foreach(DummyType;AllDummyRanges)2459 foreach (DummyType; AllDummyRanges)
2460 {
2461 {
2462 DummyType dummy;
2463 auto t = takeExactly(dummy, 5);
2464
2465 //Test that takeExactly doesn't wrap the result of takeExactly.
2466 assert(takeExactly(t, 4) == takeExactly(dummy, 4));
2467 }
2468
2469 static if (hasMobileElements!DummyType)
2470 {
2471 {
2472 auto t = takeExactly(DummyType.init, 4);
2473 assert(t.moveFront() == 1);
2474 assert(equal(t, [1, 2, 3, 4]));
2475 }
2476 }
2477
2478 static if (hasAssignableElements!DummyType)
2479 {
2480 {
2481 auto t = takeExactly(DummyType.init, 4);
2482 t.front = 9;
2483 assert(equal(t, [9, 2, 3, 4]));
2484 }
2485 }
2486 }
2487 }
2488
2489 pure @safe nothrow unittest
2490 {
2491 import std.algorithm.comparison : equal;
2492 import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy;
2493
2494 alias DummyType = DummyRange!(ReturnBy.Value, Length.No, RangeType.Forward);
2495 auto te = takeExactly(DummyType(), 5);
2496 Take!DummyType t = te;
2497 assert(equal(t, [1, 2, 3, 4, 5]));
2498 assert(equal(t, te));
2499 }
2500
2501 /**
2502 Returns a range with at most one element; for example, $(D
2503 takeOne([42, 43, 44])) returns a range consisting of the integer $(D
2504 42). Calling $(D popFront()) off that range renders it empty.
2505
2506 In effect $(D takeOne(r)) is somewhat equivalent to $(D take(r, 1)) but in
2507 certain interfaces it is important to know statically that the range may only
2508 have at most one element.
2509
2510 The type returned by $(D takeOne) is a random-access range with length
2511 regardless of $(D R)'s capabilities, as long as it is a forward range.
2512 (another feature that distinguishes $(D takeOne) from $(D take)). If
2513 (D R) is an input range but not a forward range, return type is an input
2514 range with all random-access capabilities except save.
2515 */
2516 auto takeOne(R)(R source)
2517 if (isInputRange!R)
2518 {
2519 static if (hasSlicing!R)
2520 {
2521 return source[0 .. !source.empty];
2522 }
2523 else
2524 {
2525 static struct Result
2526 {
2527 private R _source;
2528 private bool _empty = true;
emptyResult2529 @property bool empty() const { return _empty; }
frontResult2530 @property auto ref front()
2531 {
2532 assert(!empty, "Attempting to fetch the front of an empty takeOne");
2533 return _source.front;
2534 }
popFrontResult2535 void popFront()
2536 {
2537 assert(!empty, "Attempting to popFront an empty takeOne");
2538 _source.popFront();
2539 _empty = true;
2540 }
popBackResult2541 void popBack()
2542 {
2543 assert(!empty, "Attempting to popBack an empty takeOne");
2544 _source.popFront();
2545 _empty = true;
2546 }
2547 static if (isForwardRange!(Unqual!R))
2548 {
saveResult2549 @property auto save() { return Result(_source.save, empty); }
2550 }
backResult2551 @property auto ref back()
2552 {
2553 assert(!empty, "Attempting to fetch the back of an empty takeOne");
2554 return _source.front;
2555 }
lengthResult2556 @property size_t length() const { return !empty; }
2557 alias opDollar = length;
opIndexResult2558 auto ref opIndex(size_t n)
2559 {
2560 assert(n < length, "Attempting to index a takeOne out of bounds");
2561 return _source.front;
2562 }
opSliceResult2563 auto opSlice(size_t m, size_t n)
2564 {
2565 assert(m <= n && n < length, "Attempting to index a takeOne out of bounds");
2566 return n > m ? this : Result(_source, false);
2567 }
2568 // Non-standard property
sourceResult2569 @property R source() { return _source; }
2570 }
2571
2572 return Result(source, source.empty);
2573 }
2574 }
2575
2576 ///
2577 pure @safe nothrow unittest
2578 {
2579 auto s = takeOne([42, 43, 44]);
2580 static assert(isRandomAccessRange!(typeof(s)));
2581 assert(s.length == 1);
2582 assert(!s.empty);
2583 assert(s.front == 42);
2584 s.front = 43;
2585 assert(s.front == 43);
2586 assert(s.back == 43);
2587 assert(s[0] == 43);
2588 s.popFront();
2589 assert(s.length == 0);
2590 assert(s.empty);
2591 }
2592
2593 pure @safe nothrow @nogc unittest
2594 {
2595 struct NonForwardRange
2596 {
2597 enum empty = false;
frontNonForwardRange2598 int front() { return 42; }
popFrontNonForwardRange2599 void popFront() {}
2600 }
2601
2602 static assert(!isForwardRange!NonForwardRange);
2603
2604 auto s = takeOne(NonForwardRange());
2605 assert(s.front == 42);
2606 }
2607
2608 //guards against issue 16999
2609 pure @safe unittest
2610 {
2611 auto myIota = new class
2612 {
2613 int front = 0;
popFront()2614 @safe void popFront(){front++;}
2615 enum empty = false;
2616 };
2617 auto iotaPart = myIota.takeOne;
2618 int sum;
foreach(var;chain (iotaPart,iotaPart,iotaPart))2619 foreach (var; chain(iotaPart, iotaPart, iotaPart))
2620 {
2621 sum += var;
2622 }
2623 assert(sum == 3);
2624 assert(iotaPart.front == 3);
2625 }
2626
2627 /++
2628 Returns an empty range which is statically known to be empty and is
2629 guaranteed to have $(D length) and be random access regardless of $(D R)'s
2630 capabilities.
2631 +/
2632 auto takeNone(R)()
2633 if (isInputRange!R)
2634 {
2635 return typeof(takeOne(R.init)).init;
2636 }
2637
2638 ///
2639 pure @safe nothrow @nogc unittest
2640 {
2641 auto range = takeNone!(int[])();
2642 assert(range.length == 0);
2643 assert(range.empty);
2644 }
2645
2646 pure @safe nothrow @nogc unittest
2647 {
2648 enum ctfe = takeNone!(int[])();
2649 static assert(ctfe.length == 0);
2650 static assert(ctfe.empty);
2651 }
2652
2653
2654 /++
2655 Creates an empty range from the given range in $(BIGOH 1). If it can, it
2656 will return the same range type. If not, it will return
2657 $(D takeExactly(range, 0)).
2658 +/
2659 auto takeNone(R)(R range)
2660 if (isInputRange!R)
2661 {
2662 import std.traits : isDynamicArray;
2663 //Makes it so that calls to takeNone which don't use UFCS still work with a
2664 //member version if it's defined.
2665 static if (is(typeof(R.takeNone)))
2666 auto retval = range.takeNone();
2667 //@@@BUG@@@ 8339
2668 else static if (isDynamicArray!R)/+ ||
2669 (is(R == struct) && __traits(compiles, {auto r = R.init;}) && R.init.empty))+/
2670 {
2671 auto retval = R.init;
2672 }
2673 //An infinite range sliced at [0 .. 0] would likely still not be empty...
2674 else static if (hasSlicing!R && !isInfinite!R)
2675 auto retval = range[0 .. 0];
2676 else
2677 auto retval = takeExactly(range, 0);
2678
2679 //@@@BUG@@@ 7892 prevents this from being done in an out block.
2680 assert(retval.empty);
2681 return retval;
2682 }
2683
2684 ///
2685 pure @safe nothrow unittest
2686 {
2687 import std.algorithm.iteration : filter;
2688 assert(takeNone([42, 27, 19]).empty);
2689 assert(takeNone("dlang.org").empty);
2690 assert(takeNone(filter!"true"([42, 27, 19])).empty);
2691 }
2692
2693 @safe unittest
2694 {
2695 import std.algorithm.iteration : filter;
2696 import std.meta : AliasSeq;
2697
2698 struct Dummy
2699 {
genInputDummy2700 mixin template genInput()
2701 {
2702 @safe:
2703 @property bool empty() { return _arr.empty; }
2704 @property auto front() { return _arr.front; }
2705 void popFront() { _arr.popFront(); }
2706 static assert(isInputRange!(typeof(this)));
2707 }
2708 }
2709 alias genInput = Dummy.genInput;
2710
2711 static struct NormalStruct
2712 {
2713 //Disabled to make sure that the takeExactly version is used.
2714 @disable this();
thisNormalStruct2715 this(int[] arr) { _arr = arr; }
2716 mixin genInput;
2717 int[] _arr;
2718 }
2719
2720 static struct SliceStruct
2721 {
2722 @disable this();
this(int[]arr)2723 this(int[] arr) { _arr = arr; }
2724 mixin genInput;
save()2725 @property auto save() { return this; }
opSlice(size_t i,size_t j)2726 auto opSlice(size_t i, size_t j) { return typeof(this)(_arr[i .. j]); }
length()2727 @property size_t length() { return _arr.length; }
2728 int[] _arr;
2729 }
2730
2731 static struct InitStruct
2732 {
2733 mixin genInput;
2734 int[] _arr;
2735 }
2736
2737 static struct TakeNoneStruct
2738 {
this(int[]arr)2739 this(int[] arr) { _arr = arr; }
2740 @disable this();
2741 mixin genInput;
takeNone()2742 auto takeNone() { return typeof(this)(null); }
2743 int[] _arr;
2744 }
2745
2746 static class NormalClass
2747 {
this(int[]arr)2748 this(int[] arr) {_arr = arr;}
2749 mixin genInput;
2750 int[] _arr;
2751 }
2752
2753 static class SliceClass
2754 {
2755 @safe:
this(int[]arr)2756 this(int[] arr) { _arr = arr; }
2757 mixin genInput;
save()2758 @property auto save() { return new typeof(this)(_arr); }
opSlice(size_t i,size_t j)2759 auto opSlice(size_t i, size_t j) { return new typeof(this)(_arr[i .. j]); }
length()2760 @property size_t length() { return _arr.length; }
2761 int[] _arr;
2762 }
2763
2764 static class TakeNoneClass
2765 {
2766 @safe:
this(int[]arr)2767 this(int[] arr) { _arr = arr; }
2768 mixin genInput;
takeNone()2769 auto takeNone() { return new typeof(this)(null); }
2770 int[] _arr;
2771 }
2772
2773 import std.format : format;
2774
2775 foreach (range; AliasSeq!([1, 2, 3, 4, 5],
2776 "hello world",
2777 "hello world"w,
2778 "hello world"d,
2779 SliceStruct([1, 2, 3]),
2780 //@@@BUG@@@ 8339 forces this to be takeExactly
2781 //`InitStruct([1, 2, 3]),
2782 TakeNoneStruct([1, 2, 3])))
2783 {
2784 static assert(takeNone(range).empty, typeof(range).stringof);
2785 assert(takeNone(range).empty);
2786 static assert(is(typeof(range) == typeof(takeNone(range))), typeof(range).stringof);
2787 }
2788
2789 foreach (range; AliasSeq!(NormalStruct([1, 2, 3]),
2790 InitStruct([1, 2, 3])))
2791 {
2792 static assert(takeNone(range).empty, typeof(range).stringof);
2793 assert(takeNone(range).empty);
2794 static assert(is(typeof(takeExactly(range, 0)) == typeof(takeNone(range))), typeof(range).stringof);
2795 }
2796
2797 //Don't work in CTFE.
2798 auto normal = new NormalClass([1, 2, 3]);
2799 assert(takeNone(normal).empty);
2800 static assert(is(typeof(takeExactly(normal, 0)) == typeof(takeNone(normal))), typeof(normal).stringof);
2801
2802 auto slice = new SliceClass([1, 2, 3]);
2803 assert(takeNone(slice).empty);
2804 static assert(is(SliceClass == typeof(takeNone(slice))), typeof(slice).stringof);
2805
2806 auto taken = new TakeNoneClass([1, 2, 3]);
2807 assert(takeNone(taken).empty);
2808 static assert(is(TakeNoneClass == typeof(takeNone(taken))), typeof(taken).stringof);
2809
2810 auto filtered = filter!"true"([1, 2, 3, 4, 5]);
2811 assert(takeNone(filtered).empty);
2812 //@@@BUG@@@ 8339 and 5941 force this to be takeExactly
2813 //static assert(is(typeof(filtered) == typeof(takeNone(filtered))), typeof(filtered).stringof);
2814 }
2815
2816 /++
2817 + Return a _range advanced to within $(D _n) elements of the end of
2818 + $(D _range).
2819 +
2820 + Intended as the _range equivalent of the Unix
2821 + $(HTTP en.wikipedia.org/wiki/Tail_%28Unix%29, _tail) utility. When the length
2822 + of $(D _range) is less than or equal to $(D _n), $(D _range) is returned
2823 + as-is.
2824 +
2825 + Completes in $(BIGOH 1) steps for ranges that support slicing and have
2826 + length. Completes in $(BIGOH _range.length) time for all other ranges.
2827 +
2828 + Params:
2829 + range = _range to get _tail of
2830 + n = maximum number of elements to include in _tail
2831 +
2832 + Returns:
2833 + Returns the _tail of $(D _range) augmented with length information
2834 +/
2835 auto tail(Range)(Range range, size_t n)
2836 if (isInputRange!Range && !isInfinite!Range &&
2837 (hasLength!Range || isForwardRange!Range))
2838 {
2839 static if (hasLength!Range)
2840 {
2841 immutable length = range.length;
2842 if (n >= length)
2843 return range.takeExactly(length);
2844 else
2845 return range.drop(length - n).takeExactly(n);
2846 }
2847 else
2848 {
2849 Range scout = range.save;
2850 foreach (immutable i; 0 .. n)
2851 {
2852 if (scout.empty)
2853 return range.takeExactly(i);
2854 scout.popFront();
2855 }
2856
2857 auto tail = range.save;
2858 while (!scout.empty)
2859 {
2860 assert(!tail.empty);
2861 scout.popFront();
2862 tail.popFront();
2863 }
2864
2865 return tail.takeExactly(n);
2866 }
2867 }
2868
2869 ///
2870 pure @safe nothrow unittest
2871 {
2872 // tail -c n
2873 assert([1, 2, 3].tail(1) == [3]);
2874 assert([1, 2, 3].tail(2) == [2, 3]);
2875 assert([1, 2, 3].tail(3) == [1, 2, 3]);
2876 assert([1, 2, 3].tail(4) == [1, 2, 3]);
2877 assert([1, 2, 3].tail(0).length == 0);
2878
2879 // tail --lines=n
2880 import std.algorithm.comparison : equal;
2881 import std.algorithm.iteration : joiner;
2882 import std.exception : assumeWontThrow;
2883 import std.string : lineSplitter;
2884 assert("one\ntwo\nthree"
2885 .lineSplitter
2886 .tail(2)
2887 .joiner("\n")
2888 .equal("two\nthree")
2889 .assumeWontThrow);
2890 }
2891
2892 // @nogc prevented by @@@BUG@@@ 15408
2893 pure nothrow @safe /+@nogc+/ unittest
2894 {
2895 import std.algorithm.comparison : equal;
2896 import std.internal.test.dummyrange : AllDummyRanges, DummyRange, Length,
2897 RangeType, ReturnBy;
2898
2899 static immutable cheatsheet = [6, 7, 8, 9, 10];
2900
foreach(R;AllDummyRanges)2901 foreach (R; AllDummyRanges)
2902 {
2903 static if (isInputRange!R && !isInfinite!R &&
2904 (hasLength!R || isForwardRange!R))
2905 {
2906 assert(R.init.tail(5).equal(cheatsheet));
2907 static assert(R.init.tail(5).equal(cheatsheet));
2908
2909 assert(R.init.tail(0).length == 0);
2910 assert(R.init.tail(10).equal(R.init));
2911 assert(R.init.tail(11).equal(R.init));
2912 }
2913 }
2914
2915 // Infinite ranges are not supported
2916 static assert(!__traits(compiles, repeat(0).tail(0)));
2917
2918 // Neither are non-forward ranges without length
2919 static assert(!__traits(compiles, DummyRange!(ReturnBy.Value, Length.No,
2920 RangeType.Input).init.tail(5)));
2921 }
2922
2923 pure @safe nothrow @nogc unittest
2924 {
2925 static immutable input = [1, 2, 3];
2926 static immutable expectedOutput = [2, 3];
2927 assert(input.tail(2) == expectedOutput);
2928 }
2929
2930 /++
2931 Convenience function which calls
2932 $(REF popFrontN, std, _range, primitives)`(range, n)` and returns `range`.
2933 `drop` makes it easier to pop elements from a range
2934 and then pass it to another function within a single expression,
2935 whereas `popFrontN` would require multiple statements.
2936
2937 `dropBack` provides the same functionality but instead calls
2938 $(REF popBackN, std, _range, primitives)`(range, n)`
2939
2940 Note: `drop` and `dropBack` will only pop $(I up to)
2941 `n` elements but will stop if the range is empty first.
2942 In other languages this is sometimes called `skip`.
2943
2944 Params:
2945 range = the input range to drop from
2946 n = the number of elements to drop
2947
2948 Returns:
2949 `range` with up to `n` elements dropped
2950
2951 See_Also:
2952 $(REF popFront, std, _range, primitives), $(REF popBackN, std, _range, primitives)
2953 +/
2954 R drop(R)(R range, size_t n)
2955 if (isInputRange!R)
2956 {
2957 range.popFrontN(n);
2958 return range;
2959 }
2960 /// ditto
2961 R dropBack(R)(R range, size_t n)
2962 if (isBidirectionalRange!R)
2963 {
2964 range.popBackN(n);
2965 return range;
2966 }
2967
2968 ///
2969 @safe unittest
2970 {
2971 import std.algorithm.comparison : equal;
2972
2973 assert([0, 2, 1, 5, 0, 3].drop(3) == [5, 0, 3]);
2974 assert("hello world".drop(6) == "world");
2975 assert("hello world".drop(50).empty);
2976 assert("hello world".take(6).drop(3).equal("lo "));
2977 }
2978
2979 @safe unittest
2980 {
2981 import std.algorithm.comparison : equal;
2982
2983 assert([0, 2, 1, 5, 0, 3].dropBack(3) == [0, 2, 1]);
2984 assert("hello world".dropBack(6) == "hello");
2985 assert("hello world".dropBack(50).empty);
2986 assert("hello world".drop(4).dropBack(4).equal("o w"));
2987 }
2988
2989 @safe unittest
2990 {
2991 import std.algorithm.comparison : equal;
2992 import std.container.dlist : DList;
2993
2994 //Remove all but the first two elements
2995 auto a = DList!int(0, 1, 9, 9, 9, 9);
2996 a.remove(a[].drop(2));
2997 assert(a[].equal(a[].take(2)));
2998 }
2999
3000 @safe unittest
3001 {
3002 import std.algorithm.comparison : equal;
3003 import std.algorithm.iteration : filter;
3004
3005 assert(drop("", 5).empty);
3006 assert(equal(drop(filter!"true"([0, 2, 1, 5, 0, 3]), 3), [5, 0, 3]));
3007 }
3008
3009 @safe unittest
3010 {
3011 import std.algorithm.comparison : equal;
3012 import std.container.dlist : DList;
3013
3014 //insert before the last two elements
3015 auto a = DList!int(0, 1, 2, 5, 6);
3016 a.insertAfter(a[].dropBack(2), [3, 4]);
3017 assert(a[].equal(iota(0, 7)));
3018 }
3019
3020 /++
3021 Similar to $(LREF drop) and $(D dropBack) but they call
3022 $(D range.$(LREF popFrontExactly)(n)) and $(D range.popBackExactly(n))
3023 instead.
3024
3025 Note: Unlike $(D drop), $(D dropExactly) will assume that the
3026 range holds at least $(D n) elements. This makes $(D dropExactly)
3027 faster than $(D drop), but it also means that if $(D range) does
3028 not contain at least $(D n) elements, it will attempt to call $(D popFront)
3029 on an empty range, which is undefined behavior. So, only use
3030 $(D popFrontExactly) when it is guaranteed that $(D range) holds at least
3031 $(D n) elements.
3032
3033 Params:
3034 range = the input range to drop from
3035 n = the number of elements to drop
3036
3037 Returns:
3038 `range` with `n` elements dropped
3039
3040 See_Also:
3041 $(REF popFrontExcatly, std, _range, primitives),
3042 $(REF popBackExcatly, std, _range, primitives)
3043 +/
3044 R dropExactly(R)(R range, size_t n)
3045 if (isInputRange!R)
3046 {
3047 popFrontExactly(range, n);
3048 return range;
3049 }
3050 /// ditto
3051 R dropBackExactly(R)(R range, size_t n)
3052 if (isBidirectionalRange!R)
3053 {
3054 popBackExactly(range, n);
3055 return range;
3056 }
3057
3058 ///
3059 @safe unittest
3060 {
3061 import std.algorithm.comparison : equal;
3062 import std.algorithm.iteration : filterBidirectional;
3063
3064 auto a = [1, 2, 3];
3065 assert(a.dropExactly(2) == [3]);
3066 assert(a.dropBackExactly(2) == [1]);
3067
3068 string s = "日本語";
3069 assert(s.dropExactly(2) == "語");
3070 assert(s.dropBackExactly(2) == "日");
3071
3072 auto bd = filterBidirectional!"true"([1, 2, 3]);
3073 assert(bd.dropExactly(2).equal([3]));
3074 assert(bd.dropBackExactly(2).equal([1]));
3075 }
3076
3077 /++
3078 Convenience function which calls
3079 $(D range.popFront()) and returns $(D range). $(D dropOne)
3080 makes it easier to pop an element from a range
3081 and then pass it to another function within a single expression,
3082 whereas $(D popFront) would require multiple statements.
3083
3084 $(D dropBackOne) provides the same functionality but instead calls
3085 $(D range.popBack()).
3086 +/
3087 R dropOne(R)(R range)
3088 if (isInputRange!R)
3089 {
3090 range.popFront();
3091 return range;
3092 }
3093 /// ditto
3094 R dropBackOne(R)(R range)
3095 if (isBidirectionalRange!R)
3096 {
3097 range.popBack();
3098 return range;
3099 }
3100
3101 ///
3102 pure @safe nothrow unittest
3103 {
3104 import std.algorithm.comparison : equal;
3105 import std.algorithm.iteration : filterBidirectional;
3106 import std.container.dlist : DList;
3107
3108 auto dl = DList!int(9, 1, 2, 3, 9);
3109 assert(dl[].dropOne().dropBackOne().equal([1, 2, 3]));
3110
3111 auto a = [1, 2, 3];
3112 assert(a.dropOne() == [2, 3]);
3113 assert(a.dropBackOne() == [1, 2]);
3114
3115 string s = "日本語";
3116 import std.exception : assumeWontThrow;
3117 assert(assumeWontThrow(s.dropOne() == "本語"));
3118 assert(assumeWontThrow(s.dropBackOne() == "日本"));
3119
3120 auto bd = filterBidirectional!"true"([1, 2, 3]);
3121 assert(bd.dropOne().equal([2, 3]));
3122 assert(bd.dropBackOne().equal([1, 2]));
3123 }
3124
3125 /**
3126 Create a range which repeats one value forever.
3127
3128 Params:
3129 value = the value to repeat
3130
3131 Returns:
3132 An infinite random access range with slicing.
3133 */
Repeat(T)3134 struct Repeat(T)
3135 {
3136 private:
3137 //Store a non-qualified T when possible: This is to make Repeat assignable
3138 static if ((is(T == class) || is(T == interface)) && (is(T == const) || is(T == immutable)))
3139 {
3140 import std.typecons : Rebindable;
3141 alias UT = Rebindable!T;
3142 }
3143 else static if (is(T : Unqual!T) && is(Unqual!T : T))
3144 alias UT = Unqual!T;
3145 else
3146 alias UT = T;
3147 UT _value;
3148
3149 public:
3150 /// Range primitives
3151 @property inout(T) front() inout { return _value; }
3152
3153 /// ditto
3154 @property inout(T) back() inout { return _value; }
3155
3156 /// ditto
3157 enum bool empty = false;
3158
3159 /// ditto
3160 void popFront() {}
3161
3162 /// ditto
3163 void popBack() {}
3164
3165 /// ditto
3166 @property auto save() inout { return this; }
3167
3168 /// ditto
3169 inout(T) opIndex(size_t) inout { return _value; }
3170
3171 /// ditto
3172 auto opSlice(size_t i, size_t j)
3173 in
3174 {
3175 assert(
3176 i <= j,
3177 "Attempting to slice a Repeat with a larger first argument than the second."
3178 );
3179 }
3180 body
3181 {
3182 return this.takeExactly(j - i);
3183 }
3184 private static struct DollarToken {}
3185
3186 /// ditto
3187 enum opDollar = DollarToken.init;
3188
3189 /// ditto
3190 auto opSlice(size_t, DollarToken) inout { return this; }
3191 }
3192
3193 /// Ditto
3194 Repeat!T repeat(T)(T value) { return Repeat!T(value); }
3195
3196 ///
3197 pure @safe nothrow unittest
3198 {
3199 import std.algorithm.comparison : equal;
3200
3201 assert(equal(5.repeat().take(4), [ 5, 5, 5, 5 ]));
3202 }
3203
3204 pure @safe nothrow unittest
3205 {
3206 import std.algorithm.comparison : equal;
3207
3208 auto r = repeat(5);
3209 alias R = typeof(r);
3210 static assert(isBidirectionalRange!R);
3211 static assert(isForwardRange!R);
3212 static assert(isInfinite!R);
3213 static assert(hasSlicing!R);
3214
3215 assert(r.back == 5);
3216 assert(r.front == 5);
3217 assert(r.take(4).equal([ 5, 5, 5, 5 ]));
3218 assert(r[0 .. 4].equal([ 5, 5, 5, 5 ]));
3219
3220 R r2 = r[5 .. $];
3221 assert(r2.back == 5);
3222 assert(r2.front == 5);
3223 }
3224
3225 /**
3226 Repeats $(D value) exactly $(D n) times. Equivalent to $(D
3227 take(repeat(value), n)).
3228 */
3229 Take!(Repeat!T) repeat(T)(T value, size_t n)
3230 {
3231 return take(repeat(value), n);
3232 }
3233
3234 ///
3235 pure @safe nothrow @nogc unittest
3236 {
3237 import std.algorithm.comparison : equal;
3238
3239 assert(equal(5.repeat(4), 5.repeat().take(4)));
3240 }
3241
3242 pure @safe nothrow unittest //12007
3243 {
3244 static class C{}
3245 Repeat!(immutable int) ri;
3246 ri = ri.save;
3247 Repeat!(immutable C) rc;
3248 rc = rc.save;
3249
3250 import std.algorithm.setops : cartesianProduct;
3251 import std.algorithm.comparison : equal;
3252 import std.typecons : tuple;
3253 immutable int[] A = [1,2,3];
3254 immutable int[] B = [4,5,6];
3255
3256 assert(equal(cartesianProduct(A,B),
3257 [
3258 tuple(1, 4), tuple(1, 5), tuple(1, 6),
3259 tuple(2, 4), tuple(2, 5), tuple(2, 6),
3260 tuple(3, 4), tuple(3, 5), tuple(3, 6),
3261 ]));
3262 }
3263
3264 /**
3265 Given callable ($(REF isCallable, std,traits)) `fun`, create as a range
3266 whose front is defined by successive calls to `fun()`.
3267 This is especially useful to call function with global side effects (random
3268 functions), or to create ranges expressed as a single delegate, rather than
3269 an entire `front`/`popFront`/`empty` structure.
3270 `fun` maybe be passed either a template alias parameter (existing
3271 function, delegate, struct type defining `static opCall`) or
3272 a run-time value argument (delegate, function object).
3273 The result range models an InputRange
3274 ($(REF isInputRange, std,range,primitives)).
3275 The resulting range will call `fun()` on construction, and every call to
3276 `popFront`, and the cached value will be returned when `front` is called.
3277
3278 Returns: an `inputRange` where each element represents another call to fun.
3279 */
3280 auto generate(Fun)(Fun fun)
3281 if (isCallable!fun)
3282 {
3283 auto gen = Generator!(Fun)(fun);
3284 gen.popFront(); // prime the first element
3285 return gen;
3286 }
3287
3288 /// ditto
3289 auto generate(alias fun)()
3290 if (isCallable!fun)
3291 {
3292 auto gen = Generator!(fun)();
3293 gen.popFront(); // prime the first element
3294 return gen;
3295 }
3296
3297 ///
3298 @safe pure unittest
3299 {
3300 import std.algorithm.comparison : equal;
3301 import std.algorithm.iteration : map;
3302
3303 int i = 1;
3304 auto powersOfTwo = generate!(() => i *= 2)().take(10);
3305 assert(equal(powersOfTwo, iota(1, 11).map!"2^^a"()));
3306 }
3307
3308 ///
3309 @safe pure unittest
3310 {
3311 import std.algorithm.comparison : equal;
3312
3313 //Returns a run-time delegate
infiniteIota(T)3314 auto infiniteIota(T)(T low, T high)
3315 {
3316 T i = high;
3317 return (){if (i == high) i = low; return i++;};
3318 }
3319 //adapted as a range.
3320 assert(equal(generate(infiniteIota(1, 4)).take(10), [1, 2, 3, 1, 2, 3, 1, 2, 3, 1]));
3321 }
3322
3323 ///
3324 @safe unittest
3325 {
3326 import std.format : format;
3327 import std.random : uniform;
3328
3329 auto r = generate!(() => uniform(0, 6)).take(10);
3330 format("%(%s %)", r);
3331 }
3332
Generator(Fun...)3333 private struct Generator(Fun...)
3334 {
3335 static assert(Fun.length == 1);
3336 static assert(isInputRange!Generator);
3337
3338 private:
3339 static if (is(Fun[0]))
3340 Fun[0] fun;
3341 else
3342 alias fun = Fun[0];
3343
3344 enum returnByRef_ = (functionAttributes!fun & FunctionAttribute.ref_) ? true : false;
3345 static if (returnByRef_)
3346 ReturnType!fun *elem_;
3347 else
3348 ReturnType!fun elem_;
3349 public:
3350 /// Range primitives
3351 enum empty = false;
3352
3353 static if (returnByRef_)
3354 {
3355 /// ditto
3356 ref front() @property
3357 {
3358 return *elem_;
3359 }
3360 /// ditto
3361 void popFront()
3362 {
3363 elem_ = &fun();
3364 }
3365 }
3366 else
3367 {
3368 /// ditto
3369 auto front() @property
3370 {
3371 return elem_;
3372 }
3373 /// ditto
3374 void popFront()
3375 {
3376 elem_ = fun();
3377 }
3378 }
3379 }
3380
3381 @safe unittest
3382 {
3383 import std.algorithm.comparison : equal;
3384
3385 struct StaticOpCall
3386 {
opCallStaticOpCall3387 static ubyte opCall() { return 5 ; }
3388 }
3389
3390 assert(equal(generate!StaticOpCall().take(10), repeat(5).take(10)));
3391 }
3392
3393 @safe pure unittest
3394 {
3395 import std.algorithm.comparison : equal;
3396
3397 struct OpCall
3398 {
opCallOpCall3399 ubyte opCall() @safe pure { return 5 ; }
3400 }
3401
3402 OpCall op;
3403 assert(equal(generate(op).take(10), repeat(5).take(10)));
3404 }
3405
3406 // verify ref mechanism works
3407 @system unittest
3408 {
3409 int[10] arr;
3410 int idx;
3411
fun()3412 ref int fun() {
3413 auto x = idx++;
3414 idx %= arr.length;
3415 return arr[x];
3416 }
3417 int y = 1;
3418 foreach (ref x; generate!(fun).take(20))
3419 {
3420 x += y++;
3421 }
3422 import std.algorithm.comparison : equal;
3423 assert(equal(arr[], iota(12, 32, 2)));
3424 }
3425
3426 // assure front isn't the mechanism to make generate go to the next element.
3427 @safe unittest
3428 {
3429 int i;
3430 auto g = generate!(() => ++i);
3431 auto f = g.front;
3432 assert(f == g.front);
3433 g = g.drop(5); // reassign because generate caches
3434 assert(g.front == f + 5);
3435 }
3436
3437 /**
3438 Repeats the given forward range ad infinitum. If the original range is
3439 infinite (fact that would make $(D Cycle) the identity application),
3440 $(D Cycle) detects that and aliases itself to the range type
3441 itself. That works for non-forward ranges too.
3442 If the original range has random access, $(D Cycle) offers
3443 random access and also offers a constructor taking an initial position
3444 $(D index). $(D Cycle) works with static arrays in addition to ranges,
3445 mostly for performance reasons.
3446
3447 Note: The input range must not be empty.
3448
3449 Tip: This is a great way to implement simple circular buffers.
3450 */
3451 struct Cycle(R)
3452 if (isForwardRange!R && !isInfinite!R)
3453 {
3454 static if (isRandomAccessRange!R && hasLength!R)
3455 {
3456 private R _original;
3457 private size_t _index;
3458
3459 /// Range primitives
3460 this(R input, size_t index = 0)
3461 {
3462 _original = input;
3463 _index = index % _original.length;
3464 }
3465
3466 /// ditto
front()3467 @property auto ref front()
3468 {
3469 return _original[_index];
3470 }
3471
3472 static if (is(typeof((cast(const R)_original)[_index])))
3473 {
3474 /// ditto
front()3475 @property auto ref front() const
3476 {
3477 return _original[_index];
3478 }
3479 }
3480
3481 static if (hasAssignableElements!R)
3482 {
3483 /// ditto
3484 @property void front(ElementType!R val)
3485 {
3486 _original[_index] = val;
3487 }
3488 }
3489
3490 /// ditto
3491 enum bool empty = false;
3492
3493 /// ditto
popFront()3494 void popFront()
3495 {
3496 ++_index;
3497 if (_index >= _original.length)
3498 _index = 0;
3499 }
3500
3501 /// ditto
opIndex(size_t n)3502 auto ref opIndex(size_t n)
3503 {
3504 return _original[(n + _index) % _original.length];
3505 }
3506
3507 static if (is(typeof((cast(const R)_original)[_index])) &&
3508 is(typeof((cast(const R)_original).length)))
3509 {
3510 /// ditto
opIndex(size_t n)3511 auto ref opIndex(size_t n) const
3512 {
3513 return _original[(n + _index) % _original.length];
3514 }
3515 }
3516
3517 static if (hasAssignableElements!R)
3518 {
3519 /// ditto
3520 void opIndexAssign(ElementType!R val, size_t n)
3521 {
3522 _original[(n + _index) % _original.length] = val;
3523 }
3524 }
3525
3526 /// ditto
save()3527 @property Cycle save()
3528 {
3529 //No need to call _original.save, because Cycle never actually modifies _original
3530 return Cycle(_original, _index);
3531 }
3532
3533 private static struct DollarToken {}
3534
3535 /// ditto
3536 enum opDollar = DollarToken.init;
3537
3538 static if (hasSlicing!R)
3539 {
3540 /// ditto
opSlice(size_t i,size_t j)3541 auto opSlice(size_t i, size_t j)
3542 in
3543 {
3544 assert(i <= j);
3545 }
3546 body
3547 {
3548 return this[i .. $].takeExactly(j - i);
3549 }
3550
3551 /// ditto
opSlice(size_t i,DollarToken)3552 auto opSlice(size_t i, DollarToken)
3553 {
3554 return typeof(this)(_original, _index + i);
3555 }
3556 }
3557 }
3558 else
3559 {
3560 private R _original;
3561 private R _current;
3562
3563 /// ditto
this(R input)3564 this(R input)
3565 {
3566 _original = input;
3567 _current = input.save;
3568 }
3569
3570 /// ditto
front()3571 @property auto ref front()
3572 {
3573 return _current.front;
3574 }
3575
3576 static if (is(typeof((cast(const R)_current).front)))
3577 {
3578 /// ditto
front()3579 @property auto ref front() const
3580 {
3581 return _current.front;
3582 }
3583 }
3584
3585 static if (hasAssignableElements!R)
3586 {
3587 /// ditto
3588 @property auto front(ElementType!R val)
3589 {
3590 return _current.front = val;
3591 }
3592 }
3593
3594 /// ditto
3595 enum bool empty = false;
3596
3597 /// ditto
popFront()3598 void popFront()
3599 {
3600 _current.popFront();
3601 if (_current.empty)
3602 _current = _original.save;
3603 }
3604
3605 /// ditto
save()3606 @property Cycle save()
3607 {
3608 //No need to call _original.save, because Cycle never actually modifies _original
3609 Cycle ret = this;
3610 ret._original = _original;
3611 ret._current = _current.save;
3612 return ret;
3613 }
3614 }
3615 }
3616
3617 /// ditto
3618 template Cycle(R)
3619 if (isInfinite!R)
3620 {
3621 alias Cycle = R;
3622 }
3623
3624 ///
3625 struct Cycle(R)
3626 if (isStaticArray!R)
3627 {
3628 private alias ElementType = typeof(R.init[0]);
3629 private ElementType* _ptr;
3630 private size_t _index;
3631
3632 nothrow:
3633
3634 /// Range primitives
3635 this(ref R input, size_t index = 0) @system
3636 {
3637 _ptr = input.ptr;
3638 _index = index % R.length;
3639 }
3640
3641 /// ditto
inout(ElementType)3642 @property ref inout(ElementType) front() inout @safe
3643 {
3644 static ref auto trustedPtrIdx(typeof(_ptr) p, size_t idx) @trusted
3645 {
3646 return p[idx];
3647 }
3648 return trustedPtrIdx(_ptr, _index);
3649 }
3650
3651 /// ditto
3652 enum bool empty = false;
3653
3654 /// ditto
popFront()3655 void popFront() @safe
3656 {
3657 ++_index;
3658 if (_index >= R.length)
3659 _index = 0;
3660 }
3661
3662 /// ditto
inout(ElementType)3663 ref inout(ElementType) opIndex(size_t n) inout @safe
3664 {
3665 static ref auto trustedPtrIdx(typeof(_ptr) p, size_t idx) @trusted
3666 {
3667 return p[idx % R.length];
3668 }
3669 return trustedPtrIdx(_ptr, n + _index);
3670 }
3671
3672 /// ditto
inout(Cycle)3673 @property inout(Cycle) save() inout @safe
3674 {
3675 return this;
3676 }
3677
3678 private static struct DollarToken {}
3679 /// ditto
3680 enum opDollar = DollarToken.init;
3681
3682 /// ditto
opSlice(size_t i,size_t j)3683 auto opSlice(size_t i, size_t j) @safe
3684 in
3685 {
3686 assert(
3687 i <= j,
3688 "Attempting to slice a Repeat with a larger first argument than the second."
3689 );
3690 }
3691 body
3692 {
3693 return this[i .. $].takeExactly(j - i);
3694 }
3695
3696 /// ditto
opSlice(size_t i,DollarToken)3697 inout(typeof(this)) opSlice(size_t i, DollarToken) inout @safe
3698 {
3699 static auto trustedCtor(typeof(_ptr) p, size_t idx) @trusted
3700 {
3701 return cast(inout) Cycle(*cast(R*)(p), idx);
3702 }
3703 return trustedCtor(_ptr, _index + i);
3704 }
3705 }
3706
3707 /// Ditto
3708 auto cycle(R)(R input)
3709 if (isInputRange!R)
3710 {
3711 static assert(isForwardRange!R || isInfinite!R,
3712 "Cycle requires a forward range argument unless it's statically known"
3713 ~ " to be infinite");
3714 assert(!input.empty, "Attempting to pass an empty input to cycle");
3715 static if (isInfinite!R) return input;
3716 else return Cycle!R(input);
3717 }
3718
3719 ///
3720 @safe unittest
3721 {
3722 import std.algorithm.comparison : equal;
3723 import std.range : cycle, take;
3724
3725 // Here we create an infinitive cyclic sequence from [1, 2]
3726 // (i.e. get here [1, 2, 1, 2, 1, 2 and so on]) then
3727 // take 5 elements of this sequence (so we have [1, 2, 1, 2, 1])
3728 // and compare them with the expected values for equality.
3729 assert(cycle([1, 2]).take(5).equal([ 1, 2, 1, 2, 1 ]));
3730 }
3731
3732 /// Ditto
3733 Cycle!R cycle(R)(R input, size_t index = 0)
3734 if (isRandomAccessRange!R && !isInfinite!R)
3735 {
3736 assert(!input.empty, "Attempting to pass an empty input to cycle");
3737 return Cycle!R(input, index);
3738 }
3739
3740 /// Ditto
3741 Cycle!R cycle(R)(ref R input, size_t index = 0) @system
3742 if (isStaticArray!R)
3743 {
3744 return Cycle!R(input, index);
3745 }
3746
3747 @safe unittest
3748 {
3749 import std.algorithm.comparison : equal;
3750 import std.internal.test.dummyrange : AllDummyRanges;
3751
3752 static assert(isForwardRange!(Cycle!(uint[])));
3753
3754 // Make sure ref is getting propagated properly.
3755 int[] nums = [1,2,3];
3756 auto c2 = cycle(nums);
3757 c2[3]++;
3758 assert(nums[0] == 2);
3759
3760 immutable int[] immarr = [1, 2, 3];
3761
foreach(DummyType;AllDummyRanges)3762 foreach (DummyType; AllDummyRanges)
3763 {
3764 static if (isForwardRange!DummyType)
3765 {
3766 DummyType dummy;
3767 auto cy = cycle(dummy);
3768 static assert(isForwardRange!(typeof(cy)));
3769 auto t = take(cy, 20);
3770 assert(equal(t, [1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10]));
3771
3772 const cRange = cy;
3773 assert(cRange.front == 1);
3774
3775 static if (hasAssignableElements!DummyType)
3776 {
3777 {
3778 cy.front = 66;
3779 scope(exit) cy.front = 1;
3780 assert(dummy.front == 66);
3781 }
3782
3783 static if (isRandomAccessRange!DummyType)
3784 {
3785 {
3786 cy[10] = 66;
3787 scope(exit) cy[10] = 1;
3788 assert(dummy.front == 66);
3789 }
3790
3791 assert(cRange[10] == 1);
3792 }
3793 }
3794
3795 static if (hasSlicing!DummyType)
3796 {
3797 auto slice = cy[5 .. 15];
3798 assert(equal(slice, [6, 7, 8, 9, 10, 1, 2, 3, 4, 5]));
3799 static assert(is(typeof(slice) == typeof(takeExactly(cy, 5))));
3800
3801 auto infSlice = cy[7 .. $];
3802 assert(equal(take(infSlice, 5), [8, 9, 10, 1, 2]));
3803 static assert(isInfinite!(typeof(infSlice)));
3804 }
3805 }
3806 }
3807 }
3808
3809 @system unittest // For static arrays.
3810 {
3811 import std.algorithm.comparison : equal;
3812
3813 int[3] a = [ 1, 2, 3 ];
3814 static assert(isStaticArray!(typeof(a)));
3815 auto c = cycle(a);
3816 assert(a.ptr == c._ptr);
3817 assert(equal(take(cycle(a), 5), [ 1, 2, 3, 1, 2 ][]));
3818 static assert(isForwardRange!(typeof(c)));
3819
3820 // Test qualifiers on slicing.
3821 alias C = typeof(c);
3822 static assert(is(typeof(c[1 .. $]) == C));
3823 const cConst = c;
3824 static assert(is(typeof(cConst[1 .. $]) == const(C)));
3825 }
3826
3827 @safe unittest // For infinite ranges
3828 {
3829 struct InfRange
3830 {
popFrontInfRange3831 void popFront() { }
frontInfRange3832 @property int front() { return 0; }
3833 enum empty = false;
saveInfRange3834 auto save() { return this; }
3835 }
3836 struct NonForwardInfRange
3837 {
popFront()3838 void popFront() { }
front()3839 @property int front() { return 0; }
3840 enum empty = false;
3841 }
3842
3843 InfRange i;
3844 NonForwardInfRange j;
3845 auto c = cycle(i);
3846 assert(c == i);
3847 //make sure it can alias out even non-forward infinite ranges
3848 static assert(is(typeof(j.cycle) == typeof(j)));
3849 }
3850
3851 @safe unittest
3852 {
3853 import std.algorithm.comparison : equal;
3854
3855 int[5] arr = [0, 1, 2, 3, 4];
3856 auto cleD = cycle(arr[]); //Dynamic
3857 assert(equal(cleD[5 .. 10], arr[]));
3858
3859 //n is a multiple of 5 worth about 3/4 of size_t.max
3860 auto n = size_t.max/4 + size_t.max/2;
3861 n -= n % 5;
3862
3863 //Test index overflow
3864 foreach (_ ; 0 .. 10)
3865 {
3866 cleD = cleD[n .. $];
3867 assert(equal(cleD[5 .. 10], arr[]));
3868 }
3869 }
3870
3871 @system unittest
3872 {
3873 import std.algorithm.comparison : equal;
3874
3875 int[5] arr = [0, 1, 2, 3, 4];
3876 auto cleS = cycle(arr); //Static
3877 assert(equal(cleS[5 .. 10], arr[]));
3878
3879 //n is a multiple of 5 worth about 3/4 of size_t.max
3880 auto n = size_t.max/4 + size_t.max/2;
3881 n -= n % 5;
3882
3883 //Test index overflow
3884 foreach (_ ; 0 .. 10)
3885 {
3886 cleS = cleS[n .. $];
3887 assert(equal(cleS[5 .. 10], arr[]));
3888 }
3889 }
3890
3891 @system unittest
3892 {
3893 import std.algorithm.comparison : equal;
3894
3895 int[1] arr = [0];
3896 auto cleS = cycle(arr);
3897 cleS = cleS[10 .. $];
3898 assert(equal(cleS[5 .. 10], 0.repeat(5)));
3899 assert(cleS.front == 0);
3900 }
3901
3902 @system unittest //10845
3903 {
3904 import std.algorithm.comparison : equal;
3905 import std.algorithm.iteration : filter;
3906
3907 auto a = inputRangeObject(iota(3).filter!"true");
3908 assert(equal(cycle(a).take(10), [0, 1, 2, 0, 1, 2, 0, 1, 2, 0]));
3909 }
3910
3911 @safe unittest // 12177
3912 {
3913 static assert(__traits(compiles, recurrence!q{a[n - 1] ~ a[n - 2]}("1", "0")));
3914 }
3915
3916 // Issue 13390
3917 @system unittest
3918 {
3919 import core.exception : AssertError;
3920 import std.exception : assertThrown;
3921 assertThrown!AssertError(cycle([0, 1, 2][0 .. 0]));
3922 }
3923
3924 private alias lengthType(R) = typeof(R.init.length.init);
3925
3926 /**
3927 Iterate several ranges in lockstep. The element type is a proxy tuple
3928 that allows accessing the current element in the $(D n)th range by
3929 using $(D e[n]).
3930
3931 `zip` is similar to $(LREF lockstep), but `lockstep` doesn't
3932 bundle its elements and uses the `opApply` protocol.
3933 `lockstep` allows reference access to the elements in
3934 `foreach` iterations.
3935
3936 Params:
3937 sp = controls what `zip` will do if the _ranges are different lengths
3938 ranges = the ranges to zip together
3939 Returns:
3940 At minimum, an input range. `Zip` offers the lowest range facilities
3941 of all components, e.g. it offers random access iff all ranges offer
3942 random access, and also offers mutation and swapping if all ranges offer
3943 it. Due to this, `Zip` is extremely powerful because it allows manipulating
3944 several ranges in lockstep.
3945 Throws:
3946 An `Exception` if all of the _ranges are not the same length and
3947 `sp` is set to `StoppingPolicy.requireSameLength`.
3948 */
3949 struct Zip(Ranges...)
3950 if (Ranges.length && allSatisfy!(isInputRange, Ranges))
3951 {
3952 import std.format : format; //for generic mixins
3953 import std.typecons : Tuple;
3954
3955 alias R = Ranges;
3956 private R ranges;
3957 alias ElementType = Tuple!(staticMap!(.ElementType, R));
3958 private StoppingPolicy stoppingPolicy = StoppingPolicy.shortest;
3959
3960 /**
3961 Builds an object. Usually this is invoked indirectly by using the
3962 $(LREF zip) function.
3963 */
3964 this(R rs, StoppingPolicy s = StoppingPolicy.shortest)
3965 {
3966 ranges[] = rs[];
3967 stoppingPolicy = s;
3968 }
3969
3970 /**
3971 Returns $(D true) if the range is at end. The test depends on the
3972 stopping policy.
3973 */
3974 static if (allSatisfy!(isInfinite, R))
3975 {
3976 // BUG: Doesn't propagate infiniteness if only some ranges are infinite
3977 // and s == StoppingPolicy.longest. This isn't fixable in the
3978 // current design since StoppingPolicy is known only at runtime.
3979 enum bool empty = false;
3980 }
3981 else
3982 {
3983 ///
empty()3984 @property bool empty()
3985 {
3986 import std.exception : enforce;
3987 import std.meta : anySatisfy;
3988
3989 final switch (stoppingPolicy)
3990 {
3991 case StoppingPolicy.shortest:
3992 foreach (i, Unused; R)
3993 {
3994 if (ranges[i].empty) return true;
3995 }
3996 return false;
3997 case StoppingPolicy.longest:
3998 static if (anySatisfy!(isInfinite, R))
3999 {
4000 return false;
4001 }
4002 else
4003 {
4004 foreach (i, Unused; R)
4005 {
4006 if (!ranges[i].empty) return false;
4007 }
4008 return true;
4009 }
4010 case StoppingPolicy.requireSameLength:
4011 foreach (i, Unused; R[1 .. $])
4012 {
4013 enforce(ranges[0].empty ==
4014 ranges[i + 1].empty,
4015 "Inequal-length ranges passed to Zip");
4016 }
4017 return ranges[0].empty;
4018 }
4019 assert(false);
4020 }
4021 }
4022
4023 static if (allSatisfy!(isForwardRange, R))
4024 {
4025 ///
save()4026 @property Zip save()
4027 {
4028 //Zip(ranges[0].save, ranges[1].save, ..., stoppingPolicy)
4029 return mixin (q{Zip(%(ranges[%s].save%|, %), stoppingPolicy)}.format(iota(0, R.length)));
4030 }
4031 }
4032
4033 private .ElementType!(R[i]) tryGetInit(size_t i)()
4034 {
4035 alias E = .ElementType!(R[i]);
4036 static if (!is(typeof({static E i;})))
4037 throw new Exception("Range with non-default constructable elements exhausted.");
4038 else
4039 return E.init;
4040 }
4041
4042 /**
4043 Returns the current iterated element.
4044 */
front()4045 @property ElementType front()
4046 {
4047 @property tryGetFront(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].front;}
4048 //ElementType(tryGetFront!0, tryGetFront!1, ...)
4049 return mixin(q{ElementType(%(tryGetFront!%s, %))}.format(iota(0, R.length)));
4050 }
4051
4052 /**
4053 Sets the front of all iterated ranges.
4054 */
4055 static if (allSatisfy!(hasAssignableElements, R))
4056 {
front(ElementType v)4057 @property void front(ElementType v)
4058 {
4059 foreach (i, Unused; R)
4060 {
4061 if (!ranges[i].empty)
4062 {
4063 ranges[i].front = v[i];
4064 }
4065 }
4066 }
4067 }
4068
4069 /**
4070 Moves out the front.
4071 */
4072 static if (allSatisfy!(hasMobileElements, R))
4073 {
moveFront()4074 ElementType moveFront()
4075 {
4076 @property tryMoveFront(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].moveFront();}
4077 //ElementType(tryMoveFront!0, tryMoveFront!1, ...)
4078 return mixin(q{ElementType(%(tryMoveFront!%s, %))}.format(iota(0, R.length)));
4079 }
4080 }
4081
4082 /**
4083 Returns the rightmost element.
4084 */
4085 static if (allSatisfy!(isBidirectionalRange, R))
4086 {
back()4087 @property ElementType back()
4088 {
4089 //TODO: Fixme! BackElement != back of all ranges in case of jagged-ness
4090
4091 @property tryGetBack(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].back;}
4092 //ElementType(tryGetBack!0, tryGetBack!1, ...)
4093 return mixin(q{ElementType(%(tryGetBack!%s, %))}.format(iota(0, R.length)));
4094 }
4095
4096 /**
4097 Moves out the back.
4098 */
4099 static if (allSatisfy!(hasMobileElements, R))
4100 {
moveBack()4101 ElementType moveBack()
4102 {
4103 //TODO: Fixme! BackElement != back of all ranges in case of jagged-ness
4104
4105 @property tryMoveBack(size_t i)(){return ranges[i].empty ? tryGetInit!i() : ranges[i].moveFront();}
4106 //ElementType(tryMoveBack!0, tryMoveBack!1, ...)
4107 return mixin(q{ElementType(%(tryMoveBack!%s, %))}.format(iota(0, R.length)));
4108 }
4109 }
4110
4111 /**
4112 Returns the current iterated element.
4113 */
4114 static if (allSatisfy!(hasAssignableElements, R))
4115 {
back(ElementType v)4116 @property void back(ElementType v)
4117 {
4118 //TODO: Fixme! BackElement != back of all ranges in case of jagged-ness.
4119 //Not sure the call is even legal for StoppingPolicy.longest
4120
4121 foreach (i, Unused; R)
4122 {
4123 if (!ranges[i].empty)
4124 {
4125 ranges[i].back = v[i];
4126 }
4127 }
4128 }
4129 }
4130 }
4131
4132 /**
4133 Advances to the next element in all controlled ranges.
4134 */
popFront()4135 void popFront()
4136 {
4137 import std.exception : enforce;
4138
4139 final switch (stoppingPolicy)
4140 {
4141 case StoppingPolicy.shortest:
4142 foreach (i, Unused; R)
4143 {
4144 assert(!ranges[i].empty);
4145 ranges[i].popFront();
4146 }
4147 break;
4148 case StoppingPolicy.longest:
4149 foreach (i, Unused; R)
4150 {
4151 if (!ranges[i].empty) ranges[i].popFront();
4152 }
4153 break;
4154 case StoppingPolicy.requireSameLength:
4155 foreach (i, Unused; R)
4156 {
4157 enforce(!ranges[i].empty, "Invalid Zip object");
4158 ranges[i].popFront();
4159 }
4160 break;
4161 }
4162 }
4163
4164 /**
4165 Calls $(D popBack) for all controlled ranges.
4166 */
4167 static if (allSatisfy!(isBidirectionalRange, R))
4168 {
popBack()4169 void popBack()
4170 {
4171 //TODO: Fixme! In case of jaggedness, this is wrong.
4172 import std.exception : enforce;
4173
4174 final switch (stoppingPolicy)
4175 {
4176 case StoppingPolicy.shortest:
4177 foreach (i, Unused; R)
4178 {
4179 assert(!ranges[i].empty);
4180 ranges[i].popBack();
4181 }
4182 break;
4183 case StoppingPolicy.longest:
4184 foreach (i, Unused; R)
4185 {
4186 if (!ranges[i].empty) ranges[i].popBack();
4187 }
4188 break;
4189 case StoppingPolicy.requireSameLength:
4190 foreach (i, Unused; R)
4191 {
4192 enforce(!ranges[i].empty, "Invalid Zip object");
4193 ranges[i].popBack();
4194 }
4195 break;
4196 }
4197 }
4198 }
4199
4200 /**
4201 Returns the length of this range. Defined only if all ranges define
4202 $(D length).
4203 */
4204 static if (allSatisfy!(hasLength, R))
4205 {
length()4206 @property auto length()
4207 {
4208 static if (Ranges.length == 1)
4209 return ranges[0].length;
4210 else
4211 {
4212 if (stoppingPolicy == StoppingPolicy.requireSameLength)
4213 return ranges[0].length;
4214
4215 //[min|max](ranges[0].length, ranges[1].length, ...)
4216 import std.algorithm.comparison : min, max;
4217 if (stoppingPolicy == StoppingPolicy.shortest)
4218 return mixin(q{min(%(ranges[%s].length%|, %))}.format(iota(0, R.length)));
4219 else
4220 return mixin(q{max(%(ranges[%s].length%|, %))}.format(iota(0, R.length)));
4221 }
4222 }
4223
4224 alias opDollar = length;
4225 }
4226
4227 /**
4228 Returns a slice of the range. Defined only if all range define
4229 slicing.
4230 */
4231 static if (allSatisfy!(hasSlicing, R))
4232 {
opSlice(size_t from,size_t to)4233 auto opSlice(size_t from, size_t to)
4234 {
4235 //Slicing an infinite range yields the type Take!R
4236 //For finite ranges, the type Take!R aliases to R
4237 alias ZipResult = Zip!(staticMap!(Take, R));
4238
4239 //ZipResult(ranges[0][from .. to], ranges[1][from .. to], ..., stoppingPolicy)
4240 return mixin (q{ZipResult(%(ranges[%s][from .. to]%|, %), stoppingPolicy)}.format(iota(0, R.length)));
4241 }
4242 }
4243
4244 /**
4245 Returns the $(D n)th element in the composite range. Defined if all
4246 ranges offer random access.
4247 */
4248 static if (allSatisfy!(isRandomAccessRange, R))
4249 {
opIndex(size_t n)4250 ElementType opIndex(size_t n)
4251 {
4252 //TODO: Fixme! This may create an out of bounds access
4253 //for StoppingPolicy.longest
4254
4255 //ElementType(ranges[0][n], ranges[1][n], ...)
4256 return mixin (q{ElementType(%(ranges[%s][n]%|, %))}.format(iota(0, R.length)));
4257 }
4258
4259 /**
4260 Assigns to the $(D n)th element in the composite range. Defined if
4261 all ranges offer random access.
4262 */
4263 static if (allSatisfy!(hasAssignableElements, R))
4264 {
opIndexAssign(ElementType v,size_t n)4265 void opIndexAssign(ElementType v, size_t n)
4266 {
4267 //TODO: Fixme! Not sure the call is even legal for StoppingPolicy.longest
4268 foreach (i, Range; R)
4269 {
4270 ranges[i][n] = v[i];
4271 }
4272 }
4273 }
4274
4275 /**
4276 Destructively reads the $(D n)th element in the composite
4277 range. Defined if all ranges offer random access.
4278 */
4279 static if (allSatisfy!(hasMobileElements, R))
4280 {
moveAt(size_t n)4281 ElementType moveAt(size_t n)
4282 {
4283 //TODO: Fixme! This may create an out of bounds access
4284 //for StoppingPolicy.longest
4285
4286 //ElementType(ranges[0].moveAt(n), ranges[1].moveAt(n), ..., )
4287 return mixin (q{ElementType(%(ranges[%s].moveAt(n)%|, %))}.format(iota(0, R.length)));
4288 }
4289 }
4290 }
4291 }
4292
4293 /// Ditto
4294 auto zip(Ranges...)(Ranges ranges)
4295 if (Ranges.length && allSatisfy!(isInputRange, Ranges))
4296 {
4297 return Zip!Ranges(ranges);
4298 }
4299
4300 ///
4301 pure @safe unittest
4302 {
4303 import std.algorithm.comparison : equal;
4304 import std.algorithm.iteration : map;
4305
4306 // pairwise sum
4307 auto arr = [0, 1, 2];
4308 assert(zip(arr, arr.dropOne).map!"a[0] + a[1]".equal([1, 3]));
4309 }
4310
4311 ///
4312 pure @safe unittest
4313 {
4314 import std.conv : to;
4315
4316 int[] a = [ 1, 2, 3 ];
4317 string[] b = [ "a", "b", "c" ];
4318 string[] result;
4319
foreach(tup;zip (a,b))4320 foreach (tup; zip(a, b))
4321 {
4322 result ~= tup[0].to!string ~ tup[1];
4323 }
4324
4325 assert(result == [ "1a", "2b", "3c" ]);
4326
4327 size_t idx = 0;
4328 // unpacking tuple elements with foreach
foreach(e1,e2;zip (a,b))4329 foreach (e1, e2; zip(a, b))
4330 {
4331 assert(e1 == a[idx]);
4332 assert(e2 == b[idx]);
4333 ++idx;
4334 }
4335 }
4336
4337 /// $(D zip) is powerful - the following code sorts two arrays in parallel:
4338 pure @safe unittest
4339 {
4340 import std.algorithm.sorting : sort;
4341
4342 int[] a = [ 1, 2, 3 ];
4343 string[] b = [ "a", "c", "b" ];
4344 zip(a, b).sort!((t1, t2) => t1[0] > t2[0]);
4345
4346 assert(a == [ 3, 2, 1 ]);
4347 // b is sorted according to a's sorting
4348 assert(b == [ "b", "c", "a" ]);
4349 }
4350
4351 /// Ditto
4352 auto zip(Ranges...)(StoppingPolicy sp, Ranges ranges)
4353 if (Ranges.length && allSatisfy!(isInputRange, Ranges))
4354 {
4355 return Zip!Ranges(ranges, sp);
4356 }
4357
4358 /**
4359 Dictates how iteration in a $(D Zip) should stop. By default stop at
4360 the end of the shortest of all ranges.
4361 */
4362 enum StoppingPolicy
4363 {
4364 /// Stop when the shortest range is exhausted
4365 shortest,
4366 /// Stop when the longest range is exhausted
4367 longest,
4368 /// Require that all ranges are equal
4369 requireSameLength,
4370 }
4371
4372 @system unittest
4373 {
4374 import std.algorithm.comparison : equal;
4375 import std.algorithm.iteration : filter, map;
4376 import std.algorithm.mutation : swap;
4377 import std.algorithm.sorting : sort;
4378
4379 import std.exception : assertThrown, assertNotThrown;
4380 import std.typecons : tuple;
4381
4382 int[] a = [ 1, 2, 3 ];
4383 float[] b = [ 1.0, 2.0, 3.0 ];
foreach(e;zip (a,b))4384 foreach (e; zip(a, b))
4385 {
4386 assert(e[0] == e[1]);
4387 }
4388
4389 swap(a[0], a[1]);
4390 auto z = zip(a, b);
4391 //swap(z.front(), z.back());
4392 sort!("a[0] < b[0]")(zip(a, b));
4393 assert(a == [1, 2, 3]);
4394 assert(b == [2.0, 1.0, 3.0]);
4395
4396 z = zip(StoppingPolicy.requireSameLength, a, b);
4397 assertNotThrown(z.popBack());
4398 assertNotThrown(z.popBack());
4399 assertNotThrown(z.popBack());
4400 assert(z.empty);
4401 assertThrown(z.popBack());
4402
4403 a = [ 1, 2, 3 ];
4404 b = [ 1.0, 2.0, 3.0 ];
4405 sort!("a[0] > b[0]")(zip(StoppingPolicy.requireSameLength, a, b));
4406 assert(a == [3, 2, 1]);
4407 assert(b == [3.0, 2.0, 1.0]);
4408
4409 a = [];
4410 b = [];
4411 assert(zip(StoppingPolicy.requireSameLength, a, b).empty);
4412
4413 // Test infiniteness propagation.
4414 static assert(isInfinite!(typeof(zip(repeat(1), repeat(1)))));
4415
4416 // Test stopping policies with both value and reference.
4417 auto a1 = [1, 2];
4418 auto a2 = [1, 2, 3];
4419 auto stuff = tuple(tuple(a1, a2),
4420 tuple(filter!"a"(a1), filter!"a"(a2)));
4421
4422 alias FOO = Zip!(immutable(int)[], immutable(float)[]);
4423
4424 foreach (t; stuff.expand)
4425 {
4426 auto arr1 = t[0];
4427 auto arr2 = t[1];
4428 auto zShortest = zip(arr1, arr2);
4429 assert(equal(map!"a[0]"(zShortest), [1, 2]));
4430 assert(equal(map!"a[1]"(zShortest), [1, 2]));
4431
4432 try {
4433 auto zSame = zip(StoppingPolicy.requireSameLength, arr1, arr2);
foreach(elem;zSame)4434 foreach (elem; zSame) {}
4435 assert(0);
catch(Throwable)4436 } catch (Throwable) { /* It's supposed to throw.*/ }
4437
4438 auto zLongest = zip(StoppingPolicy.longest, arr1, arr2);
4439 assert(!zLongest.ranges[0].empty);
4440 assert(!zLongest.ranges[1].empty);
4441
4442 zLongest.popFront();
4443 zLongest.popFront();
4444 assert(!zLongest.empty);
4445 assert(zLongest.ranges[0].empty);
4446 assert(!zLongest.ranges[1].empty);
4447
4448 zLongest.popFront();
4449 assert(zLongest.empty);
4450 }
4451
4452 // BUG 8900
4453 assert(zip([1, 2], repeat('a')).array == [tuple(1, 'a'), tuple(2, 'a')]);
4454 assert(zip(repeat('a'), [1, 2]).array == [tuple('a', 1), tuple('a', 2)]);
4455
4456 // Doesn't work yet. Issues w/ emplace.
4457 // static assert(is(Zip!(immutable int[], immutable float[])));
4458
4459
4460 // These unittests pass, but make the compiler consume an absurd amount
4461 // of RAM and time. Therefore, they should only be run if explicitly
4462 // uncommented when making changes to Zip. Also, running them using
4463 // make -fwin32.mak unittest makes the compiler completely run out of RAM.
4464 // You need to test just this module.
4465 /+
4466 foreach (DummyType1; AllDummyRanges)
4467 {
4468 DummyType1 d1;
4469 foreach (DummyType2; AllDummyRanges)
4470 {
4471 DummyType2 d2;
4472 auto r = zip(d1, d2);
4473 assert(equal(map!"a[0]"(r), [1,2,3,4,5,6,7,8,9,10]));
4474 assert(equal(map!"a[1]"(r), [1,2,3,4,5,6,7,8,9,10]));
4475
4476 static if (isForwardRange!DummyType1 && isForwardRange!DummyType2)
4477 {
4478 static assert(isForwardRange!(typeof(r)));
4479 }
4480
4481 static if (isBidirectionalRange!DummyType1 &&
4482 isBidirectionalRange!DummyType2) {
4483 static assert(isBidirectionalRange!(typeof(r)));
4484 }
4485 static if (isRandomAccessRange!DummyType1 &&
4486 isRandomAccessRange!DummyType2) {
4487 static assert(isRandomAccessRange!(typeof(r)));
4488 }
4489 }
4490 }
4491 +/
4492 }
4493
4494 pure @safe unittest
4495 {
4496 import std.algorithm.sorting : sort;
4497
4498 auto a = [5,4,3,2,1];
4499 auto b = [3,1,2,5,6];
4500 auto z = zip(a, b);
4501
4502 sort!"a[0] < b[0]"(z);
4503
4504 assert(a == [1, 2, 3, 4, 5]);
4505 assert(b == [6, 5, 2, 1, 3]);
4506 }
4507
4508 @safe pure unittest
4509 {
4510 import std.algorithm.comparison : equal;
4511 import std.typecons : tuple;
4512
4513 auto LL = iota(1L, 1000L);
4514 auto z = zip(LL, [4]);
4515
4516 assert(equal(z, [tuple(1L,4)]));
4517
4518 auto LL2 = iota(0L, 500L);
4519 auto z2 = zip([7], LL2);
4520 assert(equal(z2, [tuple(7, 0L)]));
4521 }
4522
4523 // Text for Issue 11196
4524 @safe pure unittest
4525 {
4526 import std.exception : assertThrown;
4527
4528 static struct S { @disable this(); }
4529 assert(zip((S[5]).init[]).length == 5);
4530 assert(zip(StoppingPolicy.longest, cast(S[]) null, new int[1]).length == 1);
4531 assertThrown(zip(StoppingPolicy.longest, cast(S[]) null, new int[1]).front);
4532 }
4533
4534 @safe pure unittest //12007
4535 {
4536 static struct R
4537 {
4538 enum empty = false;
popFrontR4539 void popFront(){}
frontR4540 int front(){return 1;} @property
saveR4541 R save(){return this;} @property
4542 void opAssign(R) @disable;
4543 }
4544 R r;
4545 auto z = zip(r, r);
4546 assert(z.save == z);
4547 }
4548
4549 pure @system unittest
4550 {
4551 import std.typecons : tuple;
4552
4553 auto r1 = [0,1,2];
4554 auto r2 = [1,2,3];
4555 auto z1 = zip(refRange(&r1), refRange(&r2));
4556 auto z2 = z1.save;
4557 z1.popFront();
4558 assert(z1.front == tuple(1,2));
4559 assert(z2.front == tuple(0,1));
4560 }
4561
4562 /*
4563 Generate lockstep's opApply function as a mixin string.
4564 If withIndex is true prepend a size_t index to the delegate.
4565 */
lockstepMixin(Ranges...)4566 private string lockstepMixin(Ranges...)(bool withIndex, bool reverse)
4567 {
4568 import std.format : format;
4569
4570 string[] params;
4571 string[] emptyChecks;
4572 string[] dgArgs;
4573 string[] popFronts;
4574 string indexDef;
4575 string indexInc;
4576
4577 if (withIndex)
4578 {
4579 params ~= "size_t";
4580 dgArgs ~= "index";
4581 if (reverse)
4582 {
4583 indexDef = q{
4584 size_t index = ranges[0].length-1;
4585 enforce(_stoppingPolicy == StoppingPolicy.requireSameLength,
4586 "lockstep can only be used with foreach_reverse when stoppingPolicy == requireSameLength");
4587
4588 foreach (range; ranges[1..$])
4589 enforce(range.length == ranges[0].length);
4590 };
4591 indexInc = "--index;";
4592 }
4593 else
4594 {
4595 indexDef = "size_t index = 0;";
4596 indexInc = "++index;";
4597 }
4598 }
4599
4600 foreach (idx, Range; Ranges)
4601 {
4602 params ~= format("%sElementType!(Ranges[%s])", hasLvalueElements!Range ? "ref " : "", idx);
4603 emptyChecks ~= format("!ranges[%s].empty", idx);
4604 if (reverse)
4605 {
4606 dgArgs ~= format("ranges[%s].back", idx);
4607 popFronts ~= format("ranges[%s].popBack();", idx);
4608 }
4609 else
4610 {
4611 dgArgs ~= format("ranges[%s].front", idx);
4612 popFronts ~= format("ranges[%s].popFront();", idx);
4613 }
4614 }
4615
4616 string name = reverse ? "opApplyReverse" : "opApply";
4617
4618 return format(
4619 q{
4620 int %s(scope int delegate(%s) dg)
4621 {
4622 import std.exception : enforce;
4623
4624 auto ranges = _ranges;
4625 int res;
4626 %s
4627
4628 while (%s)
4629 {
4630 res = dg(%s);
4631 if (res) break;
4632 %s
4633 %s
4634 }
4635
4636 if (_stoppingPolicy == StoppingPolicy.requireSameLength)
4637 {
4638 foreach (range; ranges)
4639 enforce(range.empty);
4640 }
4641 return res;
4642 }
4643 }, name, params.join(", "), indexDef,
4644 emptyChecks.join(" && "), dgArgs.join(", "),
4645 popFronts.join("\n "),
4646 indexInc);
4647 }
4648
4649 /**
4650 Iterate multiple ranges in lockstep using a $(D foreach) loop. In contrast to
4651 $(LREF zip) it allows reference access to its elements. If only a single
4652 range is passed in, the $(D Lockstep) aliases itself away. If the
4653 ranges are of different lengths and $(D s) == $(D StoppingPolicy.shortest)
4654 stop after the shortest range is empty. If the ranges are of different
4655 lengths and $(D s) == $(D StoppingPolicy.requireSameLength), throw an
4656 exception. $(D s) may not be $(D StoppingPolicy.longest), and passing this
4657 will throw an exception.
4658
4659 Iterating over $(D Lockstep) in reverse and with an index is only possible
4660 when $(D s) == $(D StoppingPolicy.requireSameLength), in order to preserve
4661 indexes. If an attempt is made at iterating in reverse when $(D s) ==
4662 $(D StoppingPolicy.shortest), an exception will be thrown.
4663
4664 By default $(D StoppingPolicy) is set to $(D StoppingPolicy.shortest).
4665
4666 See_Also: $(LREF zip)
4667
4668 `lockstep` is similar to $(LREF zip), but `zip` bundles its
4669 elements and returns a range.
4670 `lockstep` also supports reference access.
4671 Use `zip` if you want to pass the result to a range function.
4672 */
4673 struct Lockstep(Ranges...)
4674 if (Ranges.length > 1 && allSatisfy!(isInputRange, Ranges))
4675 {
4676 ///
4677 this(R ranges, StoppingPolicy sp = StoppingPolicy.shortest)
4678 {
4679 import std.exception : enforce;
4680
4681 _ranges = ranges;
4682 enforce(sp != StoppingPolicy.longest,
4683 "Can't use StoppingPolicy.Longest on Lockstep.");
4684 _stoppingPolicy = sp;
4685 }
4686
4687 mixin(lockstepMixin!Ranges(false, false));
4688 mixin(lockstepMixin!Ranges(true, false));
4689 static if (allSatisfy!(isBidirectionalRange, Ranges))
4690 {
4691 mixin(lockstepMixin!Ranges(false, true));
4692 static if (allSatisfy!(hasLength, Ranges))
4693 {
4694 mixin(lockstepMixin!Ranges(true, true));
4695 }
4696 else
4697 {
4698 mixin(lockstepReverseFailMixin!Ranges(true));
4699 }
4700 }
4701 else
4702 {
4703 mixin(lockstepReverseFailMixin!Ranges(false));
4704 mixin(lockstepReverseFailMixin!Ranges(true));
4705 }
4706
4707 private:
4708 alias R = Ranges;
4709 R _ranges;
4710 StoppingPolicy _stoppingPolicy;
4711 }
4712
lockstepReverseFailMixin(Ranges...)4713 string lockstepReverseFailMixin(Ranges...)(bool withIndex)
4714 {
4715 import std.format : format;
4716 string[] params;
4717 string message;
4718
4719 if (withIndex)
4720 {
4721 message = "Indexed reverse iteration with lockstep is only supported"
4722 ~"if all ranges are bidirectional and have a length.\n";
4723 }
4724 else
4725 {
4726 message = "Reverse iteration with lockstep is only supported if all ranges are bidirectional.\n";
4727 }
4728
4729 if (withIndex)
4730 {
4731 params ~= "size_t";
4732 }
4733
4734 foreach (idx, Range; Ranges)
4735 {
4736 params ~= format("%sElementType!(Ranges[%s])", hasLvalueElements!Range ? "ref " : "", idx);
4737 }
4738
4739 return format(
4740 q{
4741 int opApplyReverse()(scope int delegate(%s) dg)
4742 {
4743 static assert(false, "%s");
4744 }
4745 }, params.join(", "), message);
4746 }
4747
4748 // For generic programming, make sure Lockstep!(Range) is well defined for a
4749 // single range.
Lockstep(Range)4750 template Lockstep(Range)
4751 {
4752 alias Lockstep = Range;
4753 }
4754
4755 /// Ditto
4756 Lockstep!(Ranges) lockstep(Ranges...)(Ranges ranges)
4757 if (allSatisfy!(isInputRange, Ranges))
4758 {
4759 return Lockstep!(Ranges)(ranges);
4760 }
4761 /// Ditto
4762 Lockstep!(Ranges) lockstep(Ranges...)(Ranges ranges, StoppingPolicy s)
4763 if (allSatisfy!(isInputRange, Ranges))
4764 {
4765 static if (Ranges.length > 1)
4766 return Lockstep!Ranges(ranges, s);
4767 else
4768 return ranges[0];
4769 }
4770
4771 ///
4772 @system unittest
4773 {
4774 auto arr1 = [1,2,3,4,5,100];
4775 auto arr2 = [6,7,8,9,10];
4776
foreach(ref a,b;lockstep (arr1,arr2))4777 foreach (ref a, b; lockstep(arr1, arr2))
4778 {
4779 a += b;
4780 }
4781
4782 assert(arr1 == [7,9,11,13,15,100]);
4783
4784 /// Lockstep also supports iterating with an index variable:
foreach(index,a,b;lockstep (arr1,arr2))4785 foreach (index, a, b; lockstep(arr1, arr2))
4786 {
4787 assert(arr1[index] == a);
4788 assert(arr2[index] == b);
4789 }
4790 }
4791
4792 @system unittest // Bugzilla 15860: foreach_reverse on lockstep
4793 {
4794 auto arr1 = [0, 1, 2, 3];
4795 auto arr2 = [4, 5, 6, 7];
4796
4797 size_t n = arr1.length -1;
4798 foreach_reverse (index, a, b; lockstep(arr1, arr2, StoppingPolicy.requireSameLength))
4799 {
4800 assert(n == index);
4801 assert(index == a);
4802 assert(arr1[index] == a);
4803 assert(arr2[index] == b);
4804 n--;
4805 }
4806
4807 auto arr3 = [4, 5];
4808 n = 1;
foreach_reverse(a,b;lockstep (arr1,arr3))4809 foreach_reverse (a, b; lockstep(arr1, arr3))
4810 {
4811 assert(a == arr1[$-n] && b == arr3[$-n]);
4812 n++;
4813 }
4814 }
4815
4816 @system unittest
4817 {
4818 import std.algorithm.iteration : filter;
4819 import std.conv : to;
4820
4821 // The filters are to make these the lowest common forward denominator ranges,
4822 // i.e. w/o ref return, random access, length, etc.
4823 auto foo = filter!"a"([1,2,3,4,5]);
4824 immutable bar = [6f,7f,8f,9f,10f].idup;
4825 auto l = lockstep(foo, bar);
4826
4827 // Should work twice. These are forward ranges with implicit save.
4828 foreach (i; 0 .. 2)
4829 {
4830 uint[] res1;
4831 float[] res2;
4832
foreach(a,ref b;l)4833 foreach (a, ref b; l)
4834 {
4835 res1 ~= a;
4836 res2 ~= b;
4837 }
4838
4839 assert(res1 == [1,2,3,4,5]);
4840 assert(res2 == [6,7,8,9,10]);
4841 assert(bar == [6f,7f,8f,9f,10f]);
4842 }
4843
4844 // Doc example.
4845 auto arr1 = [1,2,3,4,5];
4846 auto arr2 = [6,7,8,9,10];
4847
foreach(ref a,ref b;lockstep (arr1,arr2))4848 foreach (ref a, ref b; lockstep(arr1, arr2))
4849 {
4850 a += b;
4851 }
4852
4853 assert(arr1 == [7,9,11,13,15]);
4854
4855 // Make sure StoppingPolicy.requireSameLength doesn't throw.
4856 auto ls = lockstep(arr1, arr2, StoppingPolicy.requireSameLength);
4857
4858 int k = 1;
foreach(a,b;ls)4859 foreach (a, b; ls)
4860 {
4861 assert(a - b == k);
4862 ++k;
4863 }
4864
4865 // Make sure StoppingPolicy.requireSameLength throws.
4866 arr2.popBack();
4867 ls = lockstep(arr1, arr2, StoppingPolicy.requireSameLength);
4868
4869 try {
foreach(a,b;ls)4870 foreach (a, b; ls) {}
4871 assert(0);
catch(Exception)4872 } catch (Exception) {}
4873
4874 // Just make sure 1-range case instantiates. This hangs the compiler
4875 // when no explicit stopping policy is specified due to Bug 4652.
4876 auto stuff = lockstep([1,2,3,4,5], StoppingPolicy.shortest);
foreach(i,a;stuff)4877 foreach (i, a; stuff)
4878 {
4879 assert(stuff[i] == a);
4880 }
4881
4882 // Test with indexing.
4883 uint[] res1;
4884 float[] res2;
4885 size_t[] indices;
foreach(i,a,b;lockstep (foo,bar))4886 foreach (i, a, b; lockstep(foo, bar))
4887 {
4888 indices ~= i;
4889 res1 ~= a;
4890 res2 ~= b;
4891 }
4892
4893 assert(indices == to!(size_t[])([0, 1, 2, 3, 4]));
4894 assert(res1 == [1,2,3,4,5]);
4895 assert(res2 == [6f,7f,8f,9f,10f]);
4896
4897 // Make sure we've worked around the relevant compiler bugs and this at least
4898 // compiles w/ >2 ranges.
4899 lockstep(foo, foo, foo);
4900
4901 // Make sure it works with const.
4902 const(int[])[] foo2 = [[1, 2, 3]];
4903 const(int[])[] bar2 = [[4, 5, 6]];
4904 auto c = chain(foo2, bar2);
4905
foreach(f,b;lockstep (c,c))4906 foreach (f, b; lockstep(c, c)) {}
4907
4908 // Regression 10468
4909 foreach (x, y; lockstep(iota(0, 10), iota(0, 10))) { }
4910 }
4911
4912 @system unittest
4913 {
4914 struct RvalueRange
4915 {
4916 int[] impl;
emptyRvalueRange4917 @property bool empty() { return impl.empty; }
frontRvalueRange4918 @property int front() { return impl[0]; } // N.B. non-ref
popFrontRvalueRange4919 void popFront() { impl.popFront(); }
4920 }
4921 auto data1 = [ 1, 2, 3, 4 ];
4922 auto data2 = [ 5, 6, 7, 8 ];
4923 auto r1 = RvalueRange(data1);
4924 auto r2 = data2;
foreach(a,ref b;lockstep (r1,r2))4925 foreach (a, ref b; lockstep(r1, r2))
4926 {
4927 a++;
4928 b++;
4929 }
4930 assert(data1 == [ 1, 2, 3, 4 ]); // changes to a do not propagate to data
4931 assert(data2 == [ 6, 7, 8, 9 ]); // but changes to b do.
4932
4933 // Since r1 is by-value only, the compiler should reject attempts to
4934 // foreach over it with ref.
4935 static assert(!__traits(compiles, {
4936 foreach (ref a, ref b; lockstep(r1, r2)) { a++; }
4937 }));
4938 }
4939
4940 /**
4941 Creates a mathematical sequence given the initial values and a
4942 recurrence function that computes the next value from the existing
4943 values. The sequence comes in the form of an infinite forward
4944 range. The type $(D Recurrence) itself is seldom used directly; most
4945 often, recurrences are obtained by calling the function $(D
4946 recurrence).
4947
4948 When calling $(D recurrence), the function that computes the next
4949 value is specified as a template argument, and the initial values in
4950 the recurrence are passed as regular arguments. For example, in a
4951 Fibonacci sequence, there are two initial values (and therefore a
4952 state size of 2) because computing the next Fibonacci value needs the
4953 past two values.
4954
4955 The signature of this function should be:
4956 ----
4957 auto fun(R)(R state, size_t n)
4958 ----
4959 where $(D n) will be the index of the current value, and $(D state) will be an
4960 opaque state vector that can be indexed with array-indexing notation
4961 $(D state[i]), where valid values of $(D i) range from $(D (n - 1)) to
4962 $(D (n - State.length)).
4963
4964 If the function is passed in string form, the state has name $(D "a")
4965 and the zero-based index in the recurrence has name $(D "n"). The
4966 given string must return the desired value for $(D a[n]) given $(D a[n
4967 - 1]), $(D a[n - 2]), $(D a[n - 3]),..., $(D a[n - stateSize]). The
4968 state size is dictated by the number of arguments passed to the call
4969 to $(D recurrence). The $(D Recurrence) struct itself takes care of
4970 managing the recurrence's state and shifting it appropriately.
4971 */
Recurrence(alias fun,StateType,size_t stateSize)4972 struct Recurrence(alias fun, StateType, size_t stateSize)
4973 {
4974 import std.functional : binaryFun;
4975
4976 StateType[stateSize] _state;
4977 size_t _n;
4978
4979 this(StateType[stateSize] initial) { _state = initial; }
4980
4981 void popFront()
4982 {
4983 static auto trustedCycle(ref typeof(_state) s) @trusted
4984 {
4985 return cycle(s);
4986 }
4987 // The cast here is reasonable because fun may cause integer
4988 // promotion, but needs to return a StateType to make its operation
4989 // closed. Therefore, we have no other choice.
4990 _state[_n % stateSize] = cast(StateType) binaryFun!(fun, "a", "n")(
4991 trustedCycle(_state), _n + stateSize);
4992 ++_n;
4993 }
4994
4995 @property StateType front()
4996 {
4997 return _state[_n % stateSize];
4998 }
4999
5000 @property typeof(this) save()
5001 {
5002 return this;
5003 }
5004
5005 enum bool empty = false;
5006 }
5007
5008 ///
5009 @safe unittest
5010 {
5011 import std.algorithm.comparison : equal;
5012
5013 // The Fibonacci numbers, using function in string form:
5014 // a[0] = 1, a[1] = 1, and compute a[n+1] = a[n-1] + a[n]
5015 auto fib = recurrence!("a[n-1] + a[n-2]")(1, 1);
5016 assert(fib.take(10).equal([1, 1, 2, 3, 5, 8, 13, 21, 34, 55]));
5017
5018 // The factorials, using function in lambda form:
5019 auto fac = recurrence!((a,n) => a[n-1] * n)(1);
5020 assert(take(fac, 10).equal([
5021 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880
5022 ]));
5023
5024 // The triangular numbers, using function in explicit form:
genTriangular(R)5025 static size_t genTriangular(R)(R state, size_t n)
5026 {
5027 return state[n-1] + n;
5028 }
5029 auto tri = recurrence!genTriangular(0);
5030 assert(take(tri, 10).equal([0, 1, 3, 6, 10, 15, 21, 28, 36, 45]));
5031 }
5032
5033 /// Ditto
5034 Recurrence!(fun, CommonType!(State), State.length)
5035 recurrence(alias fun, State...)(State initial)
5036 {
5037 CommonType!(State)[State.length] state;
foreach(i,Unused;State)5038 foreach (i, Unused; State)
5039 {
5040 state[i] = initial[i];
5041 }
5042 return typeof(return)(state);
5043 }
5044
5045 @safe unittest
5046 {
5047 import std.algorithm.comparison : equal;
5048
5049 auto fib = recurrence!("a[n-1] + a[n-2]")(1, 1);
5050 static assert(isForwardRange!(typeof(fib)));
5051
5052 int[] witness = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55 ];
5053 assert(equal(take(fib, 10), witness));
5054 foreach (e; take(fib, 10)) {}
5055 auto fact = recurrence!("n * a[n-1]")(1);
5056 assert( equal(take(fact, 10), [1, 1, 2, 2*3, 2*3*4, 2*3*4*5, 2*3*4*5*6,
5057 2*3*4*5*6*7, 2*3*4*5*6*7*8, 2*3*4*5*6*7*8*9][]) );
5058 auto piapprox = recurrence!("a[n] + (n & 1 ? 4.0 : -4.0) / (2 * n + 3)")(4.0);
5059 foreach (e; take(piapprox, 20)) {}
5060 // Thanks to yebblies for this test and the associated fix
5061 auto r = recurrence!"a[n-2]"(1, 2);
5062 witness = [1, 2, 1, 2, 1];
5063 assert(equal(take(r, 5), witness));
5064 }
5065
5066 /**
5067 $(D Sequence) is similar to $(D Recurrence) except that iteration is
5068 presented in the so-called $(HTTP en.wikipedia.org/wiki/Closed_form,
5069 closed form). This means that the $(D n)th element in the series is
5070 computable directly from the initial values and $(D n) itself. This
5071 implies that the interface offered by $(D Sequence) is a random-access
5072 range, as opposed to the regular $(D Recurrence), which only offers
5073 forward iteration.
5074
5075 The state of the sequence is stored as a $(D Tuple) so it can be
5076 heterogeneous.
5077 */
Sequence(alias fun,State)5078 struct Sequence(alias fun, State)
5079 {
5080 private:
5081 import std.functional : binaryFun;
5082
5083 alias compute = binaryFun!(fun, "a", "n");
5084 alias ElementType = typeof(compute(State.init, cast(size_t) 1));
5085 State _state;
5086 size_t _n;
5087
5088 static struct DollarToken{}
5089
5090 public:
5091 this(State initial, size_t n = 0)
5092 {
5093 _state = initial;
5094 _n = n;
5095 }
5096
5097 @property ElementType front()
5098 {
5099 return compute(_state, _n);
5100 }
5101
5102 void popFront()
5103 {
5104 ++_n;
5105 }
5106
5107 enum opDollar = DollarToken();
5108
5109 auto opSlice(size_t lower, size_t upper)
5110 in
5111 {
5112 assert(
5113 upper >= lower,
5114 "Attempting to slice a Sequence with a larger first argument than the second."
5115 );
5116 }
5117 body
5118 {
5119 return typeof(this)(_state, _n + lower).take(upper - lower);
5120 }
5121
5122 auto opSlice(size_t lower, DollarToken)
5123 {
5124 return typeof(this)(_state, _n + lower);
5125 }
5126
5127 ElementType opIndex(size_t n)
5128 {
5129 return compute(_state, n + _n);
5130 }
5131
5132 enum bool empty = false;
5133
5134 @property Sequence save() { return this; }
5135 }
5136
5137 /// Ditto
sequence(alias fun,State...)5138 auto sequence(alias fun, State...)(State args)
5139 {
5140 import std.typecons : Tuple, tuple;
5141 alias Return = Sequence!(fun, Tuple!State);
5142 return Return(tuple(args));
5143 }
5144
5145 /// Odd numbers, using function in string form:
5146 @safe unittest
5147 {
5148 auto odds = sequence!("a[0] + n * a[1]")(1, 2);
5149 assert(odds.front == 1);
5150 odds.popFront();
5151 assert(odds.front == 3);
5152 odds.popFront();
5153 assert(odds.front == 5);
5154 }
5155
5156 /// Triangular numbers, using function in lambda form:
5157 @safe unittest
5158 {
5159 auto tri = sequence!((a,n) => n*(n+1)/2)();
5160
5161 // Note random access
5162 assert(tri[0] == 0);
5163 assert(tri[3] == 6);
5164 assert(tri[1] == 1);
5165 assert(tri[4] == 10);
5166 assert(tri[2] == 3);
5167 }
5168
5169 /// Fibonacci numbers, using function in explicit form:
5170 @safe unittest
5171 {
5172 import std.math : pow, round, sqrt;
computeFib(S)5173 static ulong computeFib(S)(S state, size_t n)
5174 {
5175 // Binet's formula
5176 return cast(ulong)(round((pow(state[0], n+1) - pow(state[1], n+1)) /
5177 state[2]));
5178 }
5179 auto fib = sequence!computeFib(
5180 (1.0 + sqrt(5.0)) / 2.0, // Golden Ratio
5181 (1.0 - sqrt(5.0)) / 2.0, // Conjugate of Golden Ratio
5182 sqrt(5.0));
5183
5184 // Note random access with [] operator
5185 assert(fib[1] == 1);
5186 assert(fib[4] == 5);
5187 assert(fib[3] == 3);
5188 assert(fib[2] == 2);
5189 assert(fib[9] == 55);
5190 }
5191
5192 @safe unittest
5193 {
5194 import std.typecons : Tuple, tuple;
5195 auto y = Sequence!("a[0] + n * a[1]", Tuple!(int, int))(tuple(0, 4));
5196 static assert(isForwardRange!(typeof(y)));
5197
5198 //@@BUG
5199 //auto y = sequence!("a[0] + n * a[1]")(0, 4);
5200 //foreach (e; take(y, 15))
5201 {} //writeln(e);
5202
5203 auto odds = Sequence!("a[0] + n * a[1]", Tuple!(int, int))(
5204 tuple(1, 2));
5205 for (int currentOdd = 1; currentOdd <= 21; currentOdd += 2)
5206 {
5207 assert(odds.front == odds[0]);
5208 assert(odds[0] == currentOdd);
5209 odds.popFront();
5210 }
5211 }
5212
5213 @safe unittest
5214 {
5215 import std.algorithm.comparison : equal;
5216
5217 auto odds = sequence!("a[0] + n * a[1]")(1, 2);
5218 static assert(hasSlicing!(typeof(odds)));
5219
5220 //Note: don't use drop or take as the target of an equal,
5221 //since they'll both just forward to opSlice, making the tests irrelevant
5222
5223 // static slicing tests
5224 assert(equal(odds[0 .. 5], [1, 3, 5, 7, 9]));
5225 assert(equal(odds[3 .. 7], [7, 9, 11, 13]));
5226
5227 // relative slicing test, testing slicing is NOT agnostic of state
5228 auto odds_less5 = odds.drop(5); //this should actually call odds[5 .. $]
5229 assert(equal(odds_less5[0 .. 3], [11, 13, 15]));
5230 assert(equal(odds_less5[0 .. 10], odds[5 .. 15]));
5231
5232 //Infinite slicing tests
5233 odds = odds[10 .. $];
5234 assert(equal(odds.take(3), [21, 23, 25]));
5235 }
5236
5237 // Issue 5036
5238 @safe unittest
5239 {
5240 auto s = sequence!((a, n) => new int)(0);
5241 assert(s.front != s.front); // no caching
5242 }
5243
5244 // iota
5245 /**
5246 Creates a range of values that span the given starting and stopping
5247 values.
5248
5249 Params:
5250 begin = The starting value.
5251 end = The value that serves as the stopping criterion. This value is not
5252 included in the range.
5253 step = The value to add to the current value at each iteration.
5254
5255 Returns:
5256 A range that goes through the numbers $(D begin), $(D begin + step),
5257 $(D begin + 2 * step), $(D ...), up to and excluding $(D end).
5258
5259 The two-argument overloads have $(D step = 1). If $(D begin < end && step <
5260 0) or $(D begin > end && step > 0) or $(D begin == end), then an empty range
5261 is returned. If $(D step == 0) then $(D begin == end) is an error.
5262
5263 For built-in types, the range returned is a random access range. For
5264 user-defined types that support $(D ++), the range is an input
5265 range.
5266
5267 An integral iota also supports $(D in) operator from the right. It takes
5268 the stepping into account, the integral won't be considered
5269 contained if it falls between two consecutive values of the range.
5270 $(D contains) does the same as in, but from lefthand side.
5271
5272 Example:
5273 ---
5274 void main()
5275 {
5276 import std.stdio;
5277
5278 // The following groups all produce the same output of:
5279 // 0 1 2 3 4
5280
5281 foreach (i; 0 .. 5)
5282 writef("%s ", i);
5283 writeln();
5284
5285 import std.range : iota;
5286 foreach (i; iota(0, 5))
5287 writef("%s ", i);
5288 writeln();
5289
5290 writefln("%(%s %|%)", iota(0, 5));
5291
5292 import std.algorithm.iteration : map;
5293 import std.algorithm.mutation : copy;
5294 import std.format;
5295 iota(0, 5).map!(i => format("%s ", i)).copy(stdout.lockingTextWriter());
5296 writeln();
5297 }
5298 ---
5299 */
5300 auto iota(B, E, S)(B begin, E end, S step)
5301 if ((isIntegral!(CommonType!(B, E)) || isPointer!(CommonType!(B, E)))
5302 && isIntegral!S)
5303 {
5304 import std.conv : unsigned;
5305
5306 alias Value = CommonType!(Unqual!B, Unqual!E);
5307 alias StepType = Unqual!S;
5308
5309 assert(step != 0 || begin == end);
5310
5311 static struct Result
5312 {
5313 private Value current, last;
5314 private StepType step; // by convention, 0 if range is empty
5315
thisResult5316 this(Value current, Value pastLast, StepType step)
5317 {
5318 if (current < pastLast && step > 0)
5319 {
5320 // Iterating upward
5321 assert(unsigned((pastLast - current) / step) <= size_t.max);
5322 // Cast below can't fail because current < pastLast
5323 this.last = cast(Value) (pastLast - 1);
5324 this.last -= unsigned(this.last - current) % step;
5325 }
5326 else if (current > pastLast && step < 0)
5327 {
5328 // Iterating downward
5329 assert(unsigned((current - pastLast) / (0 - step)) <= size_t.max);
5330 // Cast below can't fail because current > pastLast
5331 this.last = cast(Value) (pastLast + 1);
5332 this.last += unsigned(current - this.last) % (0 - step);
5333 }
5334 else
5335 {
5336 // Initialize an empty range
5337 this.step = 0;
5338 return;
5339 }
5340 this.step = step;
5341 this.current = current;
5342 }
5343
emptyResult5344 @property bool empty() const { return step == 0; }
inoutResult5345 @property inout(Value) front() inout { assert(!empty); return current; }
popFrontResult5346 void popFront()
5347 {
5348 assert(!empty);
5349 if (current == last) step = 0;
5350 else current += step;
5351 }
5352
inoutResult5353 @property inout(Value) back() inout
5354 {
5355 assert(!empty);
5356 return last;
5357 }
popBackResult5358 void popBack()
5359 {
5360 assert(!empty);
5361 if (current == last) step = 0;
5362 else last -= step;
5363 }
5364
saveResult5365 @property auto save() { return this; }
5366
opIndexResult5367 inout(Value) opIndex(ulong n) inout
5368 {
5369 assert(n < this.length);
5370
5371 // Just cast to Value here because doing so gives overflow behavior
5372 // consistent with calling popFront() n times.
5373 return cast(inout Value) (current + step * n);
5374 }
5375 auto opBinaryRight(string op)(Value val) const
5376 if (op == "in")
5377 {
5378 if (empty) return false;
5379 //cast to avoid becoming unsigned
5380 auto supposedIndex = cast(StepType)(val - current) / step;
5381 return supposedIndex < length && supposedIndex * step + current == val;
5382 }
containsResult5383 auto contains(Value x){return x in this;}
opSliceResult5384 inout(Result) opSlice() inout { return this; }
opSliceResult5385 inout(Result) opSlice(ulong lower, ulong upper) inout
5386 {
5387 assert(upper >= lower && upper <= this.length);
5388
5389 return cast(inout Result) Result(
5390 cast(Value)(current + lower * step),
5391 cast(Value)(current + upper * step),
5392 step);
5393 }
lengthResult5394 @property size_t length() const
5395 {
5396 if (step > 0)
5397 return 1 + cast(size_t) (unsigned(last - current) / step);
5398 if (step < 0)
5399 return 1 + cast(size_t) (unsigned(current - last) / (0 - step));
5400 return 0;
5401 }
5402
5403 alias opDollar = length;
5404 }
5405
5406 return Result(begin, end, step);
5407 }
5408
5409 /// Ditto
5410 auto iota(B, E)(B begin, E end)
5411 if (isFloatingPoint!(CommonType!(B, E)))
5412 {
5413 return iota(begin, end, CommonType!(B, E)(1));
5414 }
5415
5416 /// Ditto
5417 auto iota(B, E)(B begin, E end)
5418 if (isIntegral!(CommonType!(B, E)) || isPointer!(CommonType!(B, E)))
5419 {
5420 import std.conv : unsigned;
5421
5422 alias Value = CommonType!(Unqual!B, Unqual!E);
5423
5424 static struct Result
5425 {
5426 private Value current, pastLast;
5427
thisResult5428 this(Value current, Value pastLast)
5429 {
5430 if (current < pastLast)
5431 {
5432 assert(unsigned(pastLast - current) <= size_t.max);
5433
5434 this.current = current;
5435 this.pastLast = pastLast;
5436 }
5437 else
5438 {
5439 // Initialize an empty range
5440 this.current = this.pastLast = current;
5441 }
5442 }
5443
emptyResult5444 @property bool empty() const { return current == pastLast; }
inoutResult5445 @property inout(Value) front() inout { assert(!empty); return current; }
popFrontResult5446 void popFront() { assert(!empty); ++current; }
5447
inoutResult5448 @property inout(Value) back() inout { assert(!empty); return cast(inout(Value))(pastLast - 1); }
popBackResult5449 void popBack() { assert(!empty); --pastLast; }
5450
saveResult5451 @property auto save() { return this; }
5452
opIndexResult5453 inout(Value) opIndex(size_t n) inout
5454 {
5455 assert(n < this.length);
5456
5457 // Just cast to Value here because doing so gives overflow behavior
5458 // consistent with calling popFront() n times.
5459 return cast(inout Value) (current + n);
5460 }
5461 auto opBinaryRight(string op)(Value val) const
5462 if (op == "in")
5463 {
5464 return current <= val && val < pastLast;
5465 }
containsResult5466 auto contains(Value x){return x in this;}
opSliceResult5467 inout(Result) opSlice() inout { return this; }
opSliceResult5468 inout(Result) opSlice(ulong lower, ulong upper) inout
5469 {
5470 assert(upper >= lower && upper <= this.length);
5471
5472 return cast(inout Result) Result(cast(Value)(current + lower),
5473 cast(Value)(pastLast - (length - upper)));
5474 }
lengthResult5475 @property size_t length() const
5476 {
5477 return cast(size_t)(pastLast - current);
5478 }
5479
5480 alias opDollar = length;
5481 }
5482
5483 return Result(begin, end);
5484 }
5485
5486 /// Ditto
5487 auto iota(E)(E end)
5488 if (is(typeof(iota(E(0), end))))
5489 {
5490 E begin = E(0);
5491 return iota(begin, end);
5492 }
5493
5494 /// Ditto
5495 // Specialization for floating-point types
5496 auto iota(B, E, S)(B begin, E end, S step)
5497 if (isFloatingPoint!(CommonType!(B, E, S)))
5498 in
5499 {
5500 assert(step != 0, "iota: step must not be 0");
5501 assert((end - begin) / step >= 0, "iota: incorrect startup parameters");
5502 }
5503 body
5504 {
5505 alias Value = Unqual!(CommonType!(B, E, S));
5506 static struct Result
5507 {
5508 private Value start, step;
5509 private size_t index, count;
5510
thisResult5511 this(Value start, Value end, Value step)
5512 {
5513 import std.conv : to;
5514
5515 this.start = start;
5516 this.step = step;
5517 immutable fcount = (end - start) / step;
5518 count = to!size_t(fcount);
5519 auto pastEnd = start + count * step;
5520 if (step > 0)
5521 {
5522 if (pastEnd < end) ++count;
5523 assert(start + count * step >= end);
5524 }
5525 else
5526 {
5527 if (pastEnd > end) ++count;
5528 assert(start + count * step <= end);
5529 }
5530 }
5531
emptyResult5532 @property bool empty() const { return index == count; }
frontResult5533 @property Value front() const { assert(!empty); return start + step * index; }
popFrontResult5534 void popFront()
5535 {
5536 assert(!empty);
5537 ++index;
5538 }
backResult5539 @property Value back() const
5540 {
5541 assert(!empty);
5542 return start + step * (count - 1);
5543 }
popBackResult5544 void popBack()
5545 {
5546 assert(!empty);
5547 --count;
5548 }
5549
saveResult5550 @property auto save() { return this; }
5551
opIndexResult5552 Value opIndex(size_t n) const
5553 {
5554 assert(n < count);
5555 return start + step * (n + index);
5556 }
opSliceResult5557 inout(Result) opSlice() inout
5558 {
5559 return this;
5560 }
opSliceResult5561 inout(Result) opSlice(size_t lower, size_t upper) inout
5562 {
5563 assert(upper >= lower && upper <= count);
5564
5565 Result ret = this;
5566 ret.index += lower;
5567 ret.count = upper - lower + ret.index;
5568 return cast(inout Result) ret;
5569 }
lengthResult5570 @property size_t length() const
5571 {
5572 return count - index;
5573 }
5574
5575 alias opDollar = length;
5576 }
5577
5578 return Result(begin, end, step);
5579 }
5580
5581 ///
5582 @safe unittest
5583 {
5584 import std.algorithm.comparison : equal;
5585 import std.math : approxEqual;
5586
5587 auto r = iota(0, 10, 1);
5588 assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
5589 assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
5590 assert(3 in r);
5591 assert(r.contains(3)); //Same as above
5592 assert(!(10 in r));
5593 assert(!(-8 in r));
5594 r = iota(0, 11, 3);
5595 assert(equal(r, [0, 3, 6, 9]));
5596 assert(r[2] == 6);
5597 assert(!(2 in r));
5598 auto rf = iota(0.0, 0.5, 0.1);
5599 assert(approxEqual(rf, [0.0, 0.1, 0.2, 0.3, 0.4]));
5600 }
5601
5602 nothrow @nogc @safe unittest
5603 {
5604 //float overloads use std.conv.to so can't be @nogc or nothrow
5605 alias ssize_t = Signed!size_t;
5606 assert(iota(ssize_t.max, 0, -1).length == ssize_t.max);
5607 assert(iota(ssize_t.max, ssize_t.min, -1).length == size_t.max);
5608 assert(iota(ssize_t.max, ssize_t.min, -2).length == 1 + size_t.max / 2);
5609 assert(iota(ssize_t.min, ssize_t.max, 2).length == 1 + size_t.max / 2);
5610 assert(iota(ssize_t.max, ssize_t.min, -3).length == size_t.max / 3);
5611 }
5612
5613 debug @system unittest
5614 {//check the contracts
5615 import core.exception : AssertError;
5616 import std.exception : assertThrown;
5617 assertThrown!AssertError(iota(1,2,0));
5618 assertThrown!AssertError(iota(0f,1f,0f));
5619 assertThrown!AssertError(iota(1f,0f,0.1f));
5620 assertThrown!AssertError(iota(0f,1f,-0.1f));
5621 }
5622
5623 @system unittest
5624 {
5625 int[] a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
5626 auto r1 = iota(a.ptr, a.ptr + a.length, 1);
5627 assert(r1.front == a.ptr);
5628 assert(r1.back == a.ptr + a.length - 1);
5629 assert(&a[4] in r1);
5630 }
5631
5632 @safe unittest
5633 {
5634 assert(iota(1UL, 0UL).length == 0);
5635 assert(iota(1UL, 0UL, 1).length == 0);
5636 assert(iota(0, 1, 1).length == 1);
5637 assert(iota(1, 0, -1).length == 1);
5638 assert(iota(0, 1, -1).length == 0);
5639 assert(iota(ulong.max, 0).length == 0);
5640 }
5641
5642 @safe unittest
5643 {
5644 import std.algorithm.comparison : equal;
5645 import std.algorithm.searching : count;
5646 import std.math : approxEqual, nextUp, nextDown;
5647 import std.meta : AliasSeq;
5648
5649 static assert(is(ElementType!(typeof(iota(0f))) == float));
5650
5651 static assert(hasLength!(typeof(iota(0, 2))));
5652 auto r = iota(0, 10, 1);
5653 assert(r[$ - 1] == 9);
5654 assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][]));
5655
5656 auto rSlice = r[2 .. 8];
5657 assert(equal(rSlice, [2, 3, 4, 5, 6, 7]));
5658
5659 rSlice.popFront();
5660 assert(rSlice[0] == rSlice.front);
5661 assert(rSlice.front == 3);
5662
5663 rSlice.popBack();
5664 assert(rSlice[rSlice.length - 1] == rSlice.back);
5665 assert(rSlice.back == 6);
5666
5667 rSlice = r[0 .. 4];
5668 assert(equal(rSlice, [0, 1, 2, 3]));
5669 assert(3 in rSlice);
5670 assert(!(4 in rSlice));
5671
5672 auto rr = iota(10);
5673 assert(equal(rr, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][]));
5674
5675 r = iota(0, -10, -1);
5676 assert(equal(r, [0, -1, -2, -3, -4, -5, -6, -7, -8, -9][]));
5677 rSlice = r[3 .. 9];
5678 assert(equal(rSlice, [-3, -4, -5, -6, -7, -8]));
5679
5680 r = iota(0, -6, -3);
5681 assert(equal(r, [0, -3][]));
5682 rSlice = r[1 .. 2];
5683 assert(equal(rSlice, [-3]));
5684
5685 r = iota(0, -7, -3);
5686 assert(equal(r, [0, -3, -6][]));
5687 assert(0 in r);
5688 assert(-6 in r);
5689 rSlice = r[1 .. 3];
5690 assert(equal(rSlice, [-3, -6]));
5691 assert(!(0 in rSlice));
5692 assert(!(-2 in rSlice));
5693 assert(!(-5 in rSlice));
5694 assert(!(3 in rSlice));
5695 assert(!(-9 in rSlice));
5696
5697 r = iota(0, 11, 3);
5698 assert(equal(r, [0, 3, 6, 9][]));
5699 assert(r[2] == 6);
5700 rSlice = r[1 .. 3];
5701 assert(equal(rSlice, [3, 6]));
5702
5703 auto rf = iota(0.0, 0.5, 0.1);
5704 assert(approxEqual(rf, [0.0, 0.1, 0.2, 0.3, 0.4][]));
5705 assert(rf.length == 5);
5706
5707 rf.popFront();
5708 assert(rf.length == 4);
5709
5710 auto rfSlice = rf[1 .. 4];
5711 assert(rfSlice.length == 3);
5712 assert(approxEqual(rfSlice, [0.2, 0.3, 0.4]));
5713
5714 rfSlice.popFront();
5715 assert(approxEqual(rfSlice[0], 0.3));
5716
5717 rf.popFront();
5718 assert(rf.length == 3);
5719
5720 rfSlice = rf[1 .. 3];
5721 assert(rfSlice.length == 2);
5722 assert(approxEqual(rfSlice, [0.3, 0.4]));
5723 assert(approxEqual(rfSlice[0], 0.3));
5724
5725 // With something just above 0.5
5726 rf = iota(0.0, nextUp(0.5), 0.1);
5727 assert(approxEqual(rf, [0.0, 0.1, 0.2, 0.3, 0.4, 0.5][]));
5728 rf.popBack();
5729 assert(rf[rf.length - 1] == rf.back);
5730 assert(approxEqual(rf.back, 0.4));
5731 assert(rf.length == 5);
5732
5733 // going down
5734 rf = iota(0.0, -0.5, -0.1);
5735 assert(approxEqual(rf, [0.0, -0.1, -0.2, -0.3, -0.4][]));
5736 rfSlice = rf[2 .. 5];
5737 assert(approxEqual(rfSlice, [-0.2, -0.3, -0.4]));
5738
5739 rf = iota(0.0, nextDown(-0.5), -0.1);
5740 assert(approxEqual(rf, [0.0, -0.1, -0.2, -0.3, -0.4, -0.5][]));
5741
5742 // iota of longs
5743 auto rl = iota(5_000_000L);
5744 assert(rl.length == 5_000_000L);
5745 assert(0 in rl);
5746 assert(4_000_000L in rl);
5747 assert(!(-4_000_000L in rl));
5748 assert(!(5_000_000L in rl));
5749
5750 // iota of longs with steps
5751 auto iota_of_longs_with_steps = iota(50L, 101L, 10);
5752 assert(iota_of_longs_with_steps.length == 6);
5753 assert(equal(iota_of_longs_with_steps, [50L, 60L, 70L, 80L, 90L, 100L]));
5754
5755 // iota of unsigned zero length (issue 6222, actually trying to consume it
5756 // is the only way to find something is wrong because the public
5757 // properties are all correct)
5758 auto iota_zero_unsigned = iota(0, 0u, 3);
5759 assert(count(iota_zero_unsigned) == 0);
5760
5761 // unsigned reverse iota can be buggy if .length doesn't take them into
5762 // account (issue 7982).
5763 assert(iota(10u, 0u, -1).length == 10);
5764 assert(iota(10u, 0u, -2).length == 5);
5765 assert(iota(uint.max, uint.max-10, -1).length == 10);
5766 assert(iota(uint.max, uint.max-10, -2).length == 5);
5767 assert(iota(uint.max, 0u, -1).length == uint.max);
5768
5769 assert(20 in iota(20u, 10u, -2));
5770 assert(16 in iota(20u, 10u, -2));
5771 assert(!(15 in iota(20u, 10u, -2)));
5772 assert(!(10 in iota(20u, 10u, -2)));
5773 assert(!(uint.max in iota(20u, 10u, -1)));
5774 assert(!(int.min in iota(20u, 10u, -1)));
5775 assert(!(int.max in iota(20u, 10u, -1)));
5776
5777
5778 // Issue 8920
5779 foreach (Type; AliasSeq!(byte, ubyte, short, ushort,
5780 int, uint, long, ulong))
5781 {
5782 Type val;
5783 foreach (i; iota(cast(Type) 0, cast(Type) 10)) { val++; }
5784 assert(val == 10);
5785 }
5786 }
5787
5788 @safe unittest
5789 {
5790 import std.algorithm.mutation : copy;
5791 auto idx = new size_t[100];
5792 copy(iota(0, idx.length), idx);
5793 }
5794
5795 @safe unittest
5796 {
5797 import std.meta : AliasSeq;
5798 foreach (range; AliasSeq!(iota(2, 27, 4),
5799 iota(3, 9),
5800 iota(2.7, 12.3, .1),
5801 iota(3.2, 9.7)))
5802 {
5803 const cRange = range;
5804 const e = cRange.empty;
5805 const f = cRange.front;
5806 const b = cRange.back;
5807 const i = cRange[2];
5808 const s1 = cRange[];
5809 const s2 = cRange[0 .. 3];
5810 const l = cRange.length;
5811 }
5812 }
5813
5814 @system unittest
5815 {
5816 //The ptr stuff can't be done at compile time, so we unfortunately end
5817 //up with some code duplication here.
5818 auto arr = [0, 5, 3, 5, 5, 7, 9, 2, 0, 42, 7, 6];
5819
5820 {
5821 const cRange = iota(arr.ptr, arr.ptr + arr.length, 3);
5822 const e = cRange.empty;
5823 const f = cRange.front;
5824 const b = cRange.back;
5825 const i = cRange[2];
5826 const s1 = cRange[];
5827 const s2 = cRange[0 .. 3];
5828 const l = cRange.length;
5829 }
5830
5831 {
5832 const cRange = iota(arr.ptr, arr.ptr + arr.length);
5833 const e = cRange.empty;
5834 const f = cRange.front;
5835 const b = cRange.back;
5836 const i = cRange[2];
5837 const s1 = cRange[];
5838 const s2 = cRange[0 .. 3];
5839 const l = cRange.length;
5840 }
5841 }
5842
5843 @nogc nothrow pure @safe
5844 unittest
5845 {
5846 {
5847 ushort start = 0, end = 10, step = 2;
5848 foreach (i; iota(start, end, step))
5849 static assert(is(typeof(i) == ushort));
5850 }
5851 {
5852 ubyte start = 0, end = 255, step = 128;
5853 uint x;
foreach(i;iota (start,end,step))5854 foreach (i; iota(start, end, step))
5855 {
5856 static assert(is(typeof(i) == ubyte));
5857 ++x;
5858 }
5859 assert(x == 2);
5860 }
5861 }
5862
5863 /* Generic overload that handles arbitrary types that support arithmetic
5864 * operations.
5865 *
5866 * User-defined types such as $(REF BigInt, std,bigint) are also supported, as long
5867 * as they can be incremented with $(D ++) and compared with $(D <) or $(D ==).
5868 */
5869 /// ditto
5870 auto iota(B, E)(B begin, E end)
5871 if (!isIntegral!(CommonType!(B, E)) &&
5872 !isFloatingPoint!(CommonType!(B, E)) &&
5873 !isPointer!(CommonType!(B, E)) &&
5874 is(typeof((ref B b) { ++b; })) &&
5875 (is(typeof(B.init < E.init)) || is(typeof(B.init == E.init))) )
5876 {
5877 static struct Result
5878 {
5879 B current;
5880 E end;
5881
emptyResult5882 @property bool empty()
5883 {
5884 static if (is(typeof(B.init < E.init)))
5885 return !(current < end);
5886 else static if (is(typeof(B.init != E.init)))
5887 return current == end;
5888 else
5889 static assert(0);
5890 }
frontResult5891 @property auto front() { return current; }
popFrontResult5892 void popFront()
5893 {
5894 assert(!empty);
5895 ++current;
5896 }
5897 }
5898 return Result(begin, end);
5899 }
5900
5901 @safe unittest
5902 {
5903 import std.algorithm.comparison : equal;
5904
5905 // Test iota() for a type that only supports ++ and != but does not have
5906 // '<'-ordering.
Cyclic(int wrapAround)5907 struct Cyclic(int wrapAround)
5908 {
5909 int current;
5910
5911 this(int start) { current = start % wrapAround; }
5912
5913 bool opEquals(Cyclic c) const { return current == c.current; }
5914 bool opEquals(int i) const { return current == i; }
5915 void opUnary(string op)() if (op == "++")
5916 {
5917 current = (current + 1) % wrapAround;
5918 }
5919 }
5920 alias Cycle5 = Cyclic!5;
5921
5922 // Easy case
5923 auto i1 = iota(Cycle5(1), Cycle5(4));
5924 assert(i1.equal([1, 2, 3]));
5925
5926 // Wraparound case
5927 auto i2 = iota(Cycle5(3), Cycle5(2));
5928 assert(i2.equal([3, 4, 0, 1 ]));
5929 }
5930
5931 /**
5932 Options for the $(LREF FrontTransversal) and $(LREF Transversal) ranges
5933 (below).
5934 */
5935 enum TransverseOptions
5936 {
5937 /**
5938 When transversed, the elements of a range of ranges are assumed to
5939 have different lengths (e.g. a jagged array).
5940 */
5941 assumeJagged, //default
5942 /**
5943 The transversal enforces that the elements of a range of ranges have
5944 all the same length (e.g. an array of arrays, all having the same
5945 length). Checking is done once upon construction of the transversal
5946 range.
5947 */
5948 enforceNotJagged,
5949 /**
5950 The transversal assumes, without verifying, that the elements of a
5951 range of ranges have all the same length. This option is useful if
5952 checking was already done from the outside of the range.
5953 */
5954 assumeNotJagged,
5955 }
5956
5957 /**
5958 Given a range of ranges, iterate transversally through the first
5959 elements of each of the enclosed ranges.
5960 */
5961 struct FrontTransversal(Ror,
5962 TransverseOptions opt = TransverseOptions.assumeJagged)
5963 {
5964 alias RangeOfRanges = Unqual!(Ror);
5965 alias RangeType = .ElementType!RangeOfRanges;
5966 alias ElementType = .ElementType!RangeType;
5967
prime()5968 private void prime()
5969 {
5970 static if (opt == TransverseOptions.assumeJagged)
5971 {
5972 while (!_input.empty && _input.front.empty)
5973 {
5974 _input.popFront();
5975 }
5976 static if (isBidirectionalRange!RangeOfRanges)
5977 {
5978 while (!_input.empty && _input.back.empty)
5979 {
5980 _input.popBack();
5981 }
5982 }
5983 }
5984 }
5985
5986 /**
5987 Construction from an input.
5988 */
this(RangeOfRanges input)5989 this(RangeOfRanges input)
5990 {
5991 _input = input;
5992 prime();
5993 static if (opt == TransverseOptions.enforceNotJagged)
5994 // (isRandomAccessRange!RangeOfRanges
5995 // && hasLength!RangeType)
5996 {
5997 import std.exception : enforce;
5998
5999 if (empty) return;
6000 immutable commonLength = _input.front.length;
6001 foreach (e; _input)
6002 {
6003 enforce(e.length == commonLength);
6004 }
6005 }
6006 }
6007
6008 /**
6009 Forward range primitives.
6010 */
6011 static if (isInfinite!RangeOfRanges)
6012 {
6013 enum bool empty = false;
6014 }
6015 else
6016 {
empty()6017 @property bool empty()
6018 {
6019 static if (opt != TransverseOptions.assumeJagged)
6020 {
6021 if (!_input.empty)
6022 return _input.front.empty;
6023 }
6024
6025 return _input.empty;
6026 }
6027 }
6028
6029 /// Ditto
front()6030 @property auto ref front()
6031 {
6032 assert(!empty, "Attempting to fetch the front of an empty FrontTransversal");
6033 return _input.front.front;
6034 }
6035
6036 /// Ditto
6037 static if (hasMobileElements!RangeType)
6038 {
moveFront()6039 ElementType moveFront()
6040 {
6041 return _input.front.moveFront();
6042 }
6043 }
6044
6045 static if (hasAssignableElements!RangeType)
6046 {
front(ElementType val)6047 @property void front(ElementType val)
6048 {
6049 _input.front.front = val;
6050 }
6051 }
6052
6053 /// Ditto
popFront()6054 void popFront()
6055 {
6056 assert(!empty, "Attempting to popFront an empty FrontTransversal");
6057 _input.popFront();
6058 prime();
6059 }
6060
6061 /**
6062 Duplicates this $(D frontTransversal). Note that only the encapsulating
6063 range of range will be duplicated. Underlying ranges will not be
6064 duplicated.
6065 */
6066 static if (isForwardRange!RangeOfRanges)
6067 {
save()6068 @property FrontTransversal save()
6069 {
6070 return FrontTransversal(_input.save);
6071 }
6072 }
6073
6074 static if (isBidirectionalRange!RangeOfRanges)
6075 {
6076 /**
6077 Bidirectional primitives. They are offered if $(D
6078 isBidirectionalRange!RangeOfRanges).
6079 */
back()6080 @property auto ref back()
6081 {
6082 assert(!empty, "Attempting to fetch the back of an empty FrontTransversal");
6083 return _input.back.front;
6084 }
6085 /// Ditto
popBack()6086 void popBack()
6087 {
6088 assert(!empty, "Attempting to popBack an empty FrontTransversal");
6089 _input.popBack();
6090 prime();
6091 }
6092
6093 /// Ditto
6094 static if (hasMobileElements!RangeType)
6095 {
moveBack()6096 ElementType moveBack()
6097 {
6098 return _input.back.moveFront();
6099 }
6100 }
6101
6102 static if (hasAssignableElements!RangeType)
6103 {
back(ElementType val)6104 @property void back(ElementType val)
6105 {
6106 _input.back.front = val;
6107 }
6108 }
6109 }
6110
6111 static if (isRandomAccessRange!RangeOfRanges &&
6112 (opt == TransverseOptions.assumeNotJagged ||
6113 opt == TransverseOptions.enforceNotJagged))
6114 {
6115 /**
6116 Random-access primitive. It is offered if $(D
6117 isRandomAccessRange!RangeOfRanges && (opt ==
6118 TransverseOptions.assumeNotJagged || opt ==
6119 TransverseOptions.enforceNotJagged)).
6120 */
opIndex(size_t n)6121 auto ref opIndex(size_t n)
6122 {
6123 return _input[n].front;
6124 }
6125
6126 /// Ditto
6127 static if (hasMobileElements!RangeType)
6128 {
moveAt(size_t n)6129 ElementType moveAt(size_t n)
6130 {
6131 return _input[n].moveFront();
6132 }
6133 }
6134 /// Ditto
6135 static if (hasAssignableElements!RangeType)
6136 {
opIndexAssign(ElementType val,size_t n)6137 void opIndexAssign(ElementType val, size_t n)
6138 {
6139 _input[n].front = val;
6140 }
6141 }
6142 /// Ditto
6143 static if (hasLength!RangeOfRanges)
6144 {
length()6145 @property size_t length()
6146 {
6147 return _input.length;
6148 }
6149
6150 alias opDollar = length;
6151 }
6152
6153 /**
6154 Slicing if offered if $(D RangeOfRanges) supports slicing and all the
6155 conditions for supporting indexing are met.
6156 */
6157 static if (hasSlicing!RangeOfRanges)
6158 {
opSlice(size_t lower,size_t upper)6159 typeof(this) opSlice(size_t lower, size_t upper)
6160 {
6161 return typeof(this)(_input[lower .. upper]);
6162 }
6163 }
6164 }
6165
opSlice()6166 auto opSlice() { return this; }
6167
6168 private:
6169 RangeOfRanges _input;
6170 }
6171
6172 /// Ditto
6173 FrontTransversal!(RangeOfRanges, opt) frontTransversal(
6174 TransverseOptions opt = TransverseOptions.assumeJagged,
6175 RangeOfRanges)
6176 (RangeOfRanges rr)
6177 {
6178 return typeof(return)(rr);
6179 }
6180
6181 ///
6182 @safe unittest
6183 {
6184 import std.algorithm.comparison : equal;
6185 int[][] x = new int[][2];
6186 x[0] = [1, 2];
6187 x[1] = [3, 4];
6188 auto ror = frontTransversal(x);
6189 assert(equal(ror, [ 1, 3 ][]));
6190 }
6191
6192 @safe unittest
6193 {
6194 import std.algorithm.comparison : equal;
6195 import std.internal.test.dummyrange : AllDummyRanges, DummyRange, ReturnBy;
6196
6197 static assert(is(FrontTransversal!(immutable int[][])));
6198
foreach(DummyType;AllDummyRanges)6199 foreach (DummyType; AllDummyRanges)
6200 {
6201 auto dummies =
6202 [DummyType.init, DummyType.init, DummyType.init, DummyType.init];
6203
6204 foreach (i, ref elem; dummies)
6205 {
6206 // Just violate the DummyRange abstraction to get what I want.
6207 elem.arr = elem.arr[i..$ - (3 - i)];
6208 }
6209
6210 auto ft = frontTransversal!(TransverseOptions.assumeNotJagged)(dummies);
6211 static if (isForwardRange!DummyType)
6212 {
6213 static assert(isForwardRange!(typeof(ft)));
6214 }
6215
6216 assert(equal(ft, [1, 2, 3, 4]));
6217
6218 // Test slicing.
6219 assert(equal(ft[0 .. 2], [1, 2]));
6220 assert(equal(ft[1 .. 3], [2, 3]));
6221
6222 assert(ft.front == ft.moveFront());
6223 assert(ft.back == ft.moveBack());
6224 assert(ft.moveAt(1) == ft[1]);
6225
6226
6227 // Test infiniteness propagation.
6228 static assert(isInfinite!(typeof(frontTransversal(repeat("foo")))));
6229
6230 static if (DummyType.r == ReturnBy.Reference)
6231 {
6232 {
6233 ft.front++;
6234 scope(exit) ft.front--;
6235 assert(dummies.front.front == 2);
6236 }
6237
6238 {
6239 ft.front = 5;
6240 scope(exit) ft.front = 1;
6241 assert(dummies[0].front == 5);
6242 }
6243
6244 {
6245 ft.back = 88;
6246 scope(exit) ft.back = 4;
6247 assert(dummies.back.front == 88);
6248 }
6249
6250 {
6251 ft[1] = 99;
6252 scope(exit) ft[1] = 2;
6253 assert(dummies[1].front == 99);
6254 }
6255 }
6256 }
6257 }
6258
6259 // Issue 16363
6260 @safe unittest
6261 {
6262 import std.algorithm.comparison : equal;
6263
6264 int[][] darr = [[0, 1], [4, 5]];
6265 auto ft = frontTransversal!(TransverseOptions.assumeNotJagged)(darr);
6266
6267 assert(equal(ft, [0, 4]));
6268 static assert(isRandomAccessRange!(typeof(ft)));
6269 }
6270
6271 // Bugzilla 16442
6272 @safe unittest
6273 {
6274 int[][] arr = [[], []];
6275
6276 auto ft1 = frontTransversal!(TransverseOptions.assumeNotJagged)(arr);
6277 assert(ft1.empty);
6278
6279 auto ft2 = frontTransversal!(TransverseOptions.enforceNotJagged)(arr);
6280 assert(ft2.empty);
6281 }
6282
6283 /**
6284 Given a range of ranges, iterate transversally through the
6285 `n`th element of each of the enclosed ranges.
6286
6287 Params:
6288 opt = Controls the assumptions the function makes about the lengths
6289 of the ranges
6290 rr = An input range of random access ranges
6291 Returns:
6292 At minimum, an input range. Range primitives such as bidirectionality
6293 and random access are given if the element type of `rr` provides them.
6294 */
6295 struct Transversal(Ror,
6296 TransverseOptions opt = TransverseOptions.assumeJagged)
6297 {
6298 private alias RangeOfRanges = Unqual!Ror;
6299 private alias InnerRange = ElementType!RangeOfRanges;
6300 private alias E = ElementType!InnerRange;
6301
primeTransversal6302 private void prime()
6303 {
6304 static if (opt == TransverseOptions.assumeJagged)
6305 {
6306 while (!_input.empty && _input.front.length <= _n)
6307 {
6308 _input.popFront();
6309 }
6310 static if (isBidirectionalRange!RangeOfRanges)
6311 {
6312 while (!_input.empty && _input.back.length <= _n)
6313 {
6314 _input.popBack();
6315 }
6316 }
6317 }
6318 }
6319
6320 /**
6321 Construction from an input and an index.
6322 */
thisTransversal6323 this(RangeOfRanges input, size_t n)
6324 {
6325 _input = input;
6326 _n = n;
6327 prime();
6328 static if (opt == TransverseOptions.enforceNotJagged)
6329 {
6330 import std.exception : enforce;
6331
6332 if (empty) return;
6333 immutable commonLength = _input.front.length;
6334 foreach (e; _input)
6335 {
6336 enforce(e.length == commonLength);
6337 }
6338 }
6339 }
6340
6341 /**
6342 Forward range primitives.
6343 */
6344 static if (isInfinite!(RangeOfRanges))
6345 {
6346 enum bool empty = false;
6347 }
6348 else
6349 {
emptyTransversal6350 @property bool empty()
6351 {
6352 return _input.empty;
6353 }
6354 }
6355
6356 /// Ditto
frontTransversal6357 @property auto ref front()
6358 {
6359 assert(!empty, "Attempting to fetch the front of an empty Transversal");
6360 return _input.front[_n];
6361 }
6362
6363 /// Ditto
6364 static if (hasMobileElements!InnerRange)
6365 {
moveFrontTransversal6366 E moveFront()
6367 {
6368 return _input.front.moveAt(_n);
6369 }
6370 }
6371
6372 /// Ditto
6373 static if (hasAssignableElements!InnerRange)
6374 {
frontTransversal6375 @property void front(E val)
6376 {
6377 _input.front[_n] = val;
6378 }
6379 }
6380
6381
6382 /// Ditto
popFrontTransversal6383 void popFront()
6384 {
6385 assert(!empty, "Attempting to popFront an empty Transversal");
6386 _input.popFront();
6387 prime();
6388 }
6389
6390 /// Ditto
6391 static if (isForwardRange!RangeOfRanges)
6392 {
typeofTransversal6393 @property typeof(this) save()
6394 {
6395 auto ret = this;
6396 ret._input = _input.save;
6397 return ret;
6398 }
6399 }
6400
6401 static if (isBidirectionalRange!RangeOfRanges)
6402 {
6403 /**
6404 Bidirectional primitives. They are offered if $(D
6405 isBidirectionalRange!RangeOfRanges).
6406 */
backTransversal6407 @property auto ref back()
6408 {
6409 assert(!empty, "Attempting to fetch the back of an empty Transversal");
6410 return _input.back[_n];
6411 }
6412
6413 /// Ditto
popBackTransversal6414 void popBack()
6415 {
6416 assert(!empty, "Attempting to popBack an empty Transversal");
6417 _input.popBack();
6418 prime();
6419 }
6420
6421 /// Ditto
6422 static if (hasMobileElements!InnerRange)
6423 {
moveBackTransversal6424 E moveBack()
6425 {
6426 return _input.back.moveAt(_n);
6427 }
6428 }
6429
6430 /// Ditto
6431 static if (hasAssignableElements!InnerRange)
6432 {
backTransversal6433 @property void back(E val)
6434 {
6435 _input.back[_n] = val;
6436 }
6437 }
6438
6439 }
6440
6441 static if (isRandomAccessRange!RangeOfRanges &&
6442 (opt == TransverseOptions.assumeNotJagged ||
6443 opt == TransverseOptions.enforceNotJagged))
6444 {
6445 /**
6446 Random-access primitive. It is offered if $(D
6447 isRandomAccessRange!RangeOfRanges && (opt ==
6448 TransverseOptions.assumeNotJagged || opt ==
6449 TransverseOptions.enforceNotJagged)).
6450 */
opIndexTransversal6451 auto ref opIndex(size_t n)
6452 {
6453 return _input[n][_n];
6454 }
6455
6456 /// Ditto
6457 static if (hasMobileElements!InnerRange)
6458 {
moveAtTransversal6459 E moveAt(size_t n)
6460 {
6461 return _input[n].moveAt(_n);
6462 }
6463 }
6464
6465 /// Ditto
6466 static if (hasAssignableElements!InnerRange)
6467 {
opIndexAssignTransversal6468 void opIndexAssign(E val, size_t n)
6469 {
6470 _input[n][_n] = val;
6471 }
6472 }
6473
6474 /// Ditto
6475 static if (hasLength!RangeOfRanges)
6476 {
lengthTransversal6477 @property size_t length()
6478 {
6479 return _input.length;
6480 }
6481
6482 alias opDollar = length;
6483 }
6484
6485 /**
6486 Slicing if offered if $(D RangeOfRanges) supports slicing and all the
6487 conditions for supporting indexing are met.
6488 */
6489 static if (hasSlicing!RangeOfRanges)
6490 {
opSliceTransversal6491 typeof(this) opSlice(size_t lower, size_t upper)
6492 {
6493 return typeof(this)(_input[lower .. upper], _n);
6494 }
6495 }
6496 }
6497
opSliceTransversal6498 auto opSlice() { return this; }
6499
6500 private:
6501 RangeOfRanges _input;
6502 size_t _n;
6503 }
6504
6505 /// Ditto
6506 Transversal!(RangeOfRanges, opt) transversal
6507 (TransverseOptions opt = TransverseOptions.assumeJagged, RangeOfRanges)
6508 (RangeOfRanges rr, size_t n)
6509 {
6510 return typeof(return)(rr, n);
6511 }
6512
6513 ///
6514 @safe unittest
6515 {
6516 import std.algorithm.comparison : equal;
6517 int[][] x = new int[][2];
6518 x[0] = [1, 2];
6519 x[1] = [3, 4];
6520 auto ror = transversal(x, 1);
6521 assert(equal(ror, [ 2, 4 ][]));
6522 }
6523
6524 @safe unittest
6525 {
6526 import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy;
6527
6528 int[][] x = new int[][2];
6529 x[0] = [ 1, 2 ];
6530 x[1] = [3, 4];
6531 auto ror = transversal!(TransverseOptions.assumeNotJagged)(x, 1);
6532 auto witness = [ 2, 4 ];
6533 uint i;
6534 foreach (e; ror) assert(e == witness[i++]);
6535 assert(i == 2);
6536 assert(ror.length == 2);
6537
6538 static assert(is(Transversal!(immutable int[][])));
6539
6540 // Make sure ref, assign is being propagated.
6541 {
6542 ror.front++;
6543 scope(exit) ror.front--;
6544 assert(x[0][1] == 3);
6545 }
6546 {
6547 ror.front = 5;
6548 scope(exit) ror.front = 2;
6549 assert(x[0][1] == 5);
6550 assert(ror.moveFront() == 5);
6551 }
6552 {
6553 ror.back = 999;
6554 scope(exit) ror.back = 4;
6555 assert(x[1][1] == 999);
6556 assert(ror.moveBack() == 999);
6557 }
6558 {
6559 ror[0] = 999;
6560 scope(exit) ror[0] = 2;
6561 assert(x[0][1] == 999);
6562 assert(ror.moveAt(0) == 999);
6563 }
6564
6565 // Test w/o ref return.
6566 alias D = DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random);
6567 auto drs = [D.init, D.init];
6568 foreach (num; 0 .. 10)
6569 {
6570 auto t = transversal!(TransverseOptions.enforceNotJagged)(drs, num);
6571 assert(t[0] == t[1]);
6572 assert(t[1] == num + 1);
6573 }
6574
6575 static assert(isInfinite!(typeof(transversal(repeat([1,2,3]), 1))));
6576
6577 // Test slicing.
6578 auto mat = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]];
6579 auto mat1 = transversal!(TransverseOptions.assumeNotJagged)(mat, 1)[1 .. 3];
6580 assert(mat1[0] == 6);
6581 assert(mat1[1] == 10);
6582 }
6583
6584 struct Transposed(RangeOfRanges)
6585 if (isForwardRange!RangeOfRanges &&
6586 isInputRange!(ElementType!RangeOfRanges) &&
6587 hasAssignableElements!RangeOfRanges)
6588 {
6589 //alias ElementType = typeof(map!"a.front"(RangeOfRanges.init));
6590
this(RangeOfRanges input)6591 this(RangeOfRanges input)
6592 {
6593 this._input = input;
6594 }
6595
front()6596 @property auto front()
6597 {
6598 import std.algorithm.iteration : filter, map;
6599 return _input.save
6600 .filter!(a => !a.empty)
6601 .map!(a => a.front);
6602 }
6603
popFront()6604 void popFront()
6605 {
6606 // Advance the position of each subrange.
6607 auto r = _input.save;
6608 while (!r.empty)
6609 {
6610 auto e = r.front;
6611 if (!e.empty)
6612 {
6613 e.popFront();
6614 r.front = e;
6615 }
6616
6617 r.popFront();
6618 }
6619 }
6620
6621 // ElementType opIndex(size_t n)
6622 // {
6623 // return _input[n].front;
6624 // }
6625
empty()6626 @property bool empty()
6627 {
6628 if (_input.empty) return true;
6629 foreach (e; _input.save)
6630 {
6631 if (!e.empty) return false;
6632 }
6633 return true;
6634 }
6635
save()6636 @property Transposed save()
6637 {
6638 return Transposed(_input.save);
6639 }
6640
opSlice()6641 auto opSlice() { return this; }
6642
6643 private:
6644 RangeOfRanges _input;
6645 }
6646
6647 @safe unittest
6648 {
6649 // Boundary case: transpose of empty range should be empty
6650 int[][] ror = [];
6651 assert(transposed(ror).empty);
6652 }
6653
6654 // Issue 9507
6655 @safe unittest
6656 {
6657 import std.algorithm.comparison : equal;
6658
6659 auto r = [[1,2], [3], [4,5], [], [6]];
6660 assert(r.transposed.equal!equal([
6661 [1, 3, 4, 6],
6662 [2, 5]
6663 ]));
6664 }
6665
6666 /**
6667 Given a range of ranges, returns a range of ranges where the $(I i)'th subrange
6668 contains the $(I i)'th elements of the original subranges.
6669 */
6670 Transposed!RangeOfRanges transposed(RangeOfRanges)(RangeOfRanges rr)
6671 if (isForwardRange!RangeOfRanges &&
6672 isInputRange!(ElementType!RangeOfRanges) &&
6673 hasAssignableElements!RangeOfRanges)
6674 {
6675 return Transposed!RangeOfRanges(rr);
6676 }
6677
6678 ///
6679 @safe unittest
6680 {
6681 import std.algorithm.comparison : equal;
6682 int[][] ror = [
6683 [1, 2, 3],
6684 [4, 5, 6]
6685 ];
6686 auto xp = transposed(ror);
6687 assert(equal!"a.equal(b)"(xp, [
6688 [1, 4],
6689 [2, 5],
6690 [3, 6]
6691 ]));
6692 }
6693
6694 ///
6695 @safe unittest
6696 {
6697 int[][] x = new int[][2];
6698 x[0] = [1, 2];
6699 x[1] = [3, 4];
6700 auto tr = transposed(x);
6701 int[][] witness = [ [ 1, 3 ], [ 2, 4 ] ];
6702 uint i;
6703
foreach(e;tr)6704 foreach (e; tr)
6705 {
6706 assert(array(e) == witness[i++]);
6707 }
6708 }
6709
6710 // Issue 8764
6711 @safe unittest
6712 {
6713 import std.algorithm.comparison : equal;
6714 ulong[1] t0 = [ 123 ];
6715
6716 assert(!hasAssignableElements!(typeof(t0[].chunks(1))));
6717 assert(!is(typeof(transposed(t0[].chunks(1)))));
6718 assert(is(typeof(transposed(t0[].chunks(1).array()))));
6719
6720 auto t1 = transposed(t0[].chunks(1).array());
6721 assert(equal!"a.equal(b)"(t1, [[123]]));
6722 }
6723
6724 /**
6725 This struct takes two ranges, $(D source) and $(D indices), and creates a view
6726 of $(D source) as if its elements were reordered according to $(D indices).
6727 $(D indices) may include only a subset of the elements of $(D source) and
6728 may also repeat elements.
6729
6730 $(D Source) must be a random access range. The returned range will be
6731 bidirectional or random-access if $(D Indices) is bidirectional or
6732 random-access, respectively.
6733 */
6734 struct Indexed(Source, Indices)
6735 if (isRandomAccessRange!Source && isInputRange!Indices &&
6736 is(typeof(Source.init[ElementType!(Indices).init])))
6737 {
this(Source source,Indices indices)6738 this(Source source, Indices indices)
6739 {
6740 this._source = source;
6741 this._indices = indices;
6742 }
6743
6744 /// Range primitives
front()6745 @property auto ref front()
6746 {
6747 assert(!empty, "Attempting to fetch the front of an empty Indexed");
6748 return _source[_indices.front];
6749 }
6750
6751 /// Ditto
popFront()6752 void popFront()
6753 {
6754 assert(!empty, "Attempting to popFront an empty Indexed");
6755 _indices.popFront();
6756 }
6757
6758 static if (isInfinite!Indices)
6759 {
6760 enum bool empty = false;
6761 }
6762 else
6763 {
6764 /// Ditto
empty()6765 @property bool empty()
6766 {
6767 return _indices.empty;
6768 }
6769 }
6770
6771 static if (isForwardRange!Indices)
6772 {
6773 /// Ditto
typeof(this)6774 @property typeof(this) save()
6775 {
6776 // Don't need to save _source because it's never consumed.
6777 return typeof(this)(_source, _indices.save);
6778 }
6779 }
6780
6781 /// Ditto
6782 static if (hasAssignableElements!Source)
6783 {
6784 @property auto ref front(ElementType!Source newVal)
6785 {
6786 assert(!empty);
6787 return _source[_indices.front] = newVal;
6788 }
6789 }
6790
6791
6792 static if (hasMobileElements!Source)
6793 {
6794 /// Ditto
moveFront()6795 auto moveFront()
6796 {
6797 assert(!empty);
6798 return _source.moveAt(_indices.front);
6799 }
6800 }
6801
6802 static if (isBidirectionalRange!Indices)
6803 {
6804 /// Ditto
back()6805 @property auto ref back()
6806 {
6807 assert(!empty, "Attempting to fetch the back of an empty Indexed");
6808 return _source[_indices.back];
6809 }
6810
6811 /// Ditto
popBack()6812 void popBack()
6813 {
6814 assert(!empty, "Attempting to popBack an empty Indexed");
6815 _indices.popBack();
6816 }
6817
6818 /// Ditto
6819 static if (hasAssignableElements!Source)
6820 {
6821 @property auto ref back(ElementType!Source newVal)
6822 {
6823 assert(!empty);
6824 return _source[_indices.back] = newVal;
6825 }
6826 }
6827
6828
6829 static if (hasMobileElements!Source)
6830 {
6831 /// Ditto
moveBack()6832 auto moveBack()
6833 {
6834 assert(!empty);
6835 return _source.moveAt(_indices.back);
6836 }
6837 }
6838 }
6839
6840 static if (hasLength!Indices)
6841 {
6842 /// Ditto
length()6843 @property size_t length()
6844 {
6845 return _indices.length;
6846 }
6847
6848 alias opDollar = length;
6849 }
6850
6851 static if (isRandomAccessRange!Indices)
6852 {
6853 /// Ditto
opIndex(size_t index)6854 auto ref opIndex(size_t index)
6855 {
6856 return _source[_indices[index]];
6857 }
6858
6859 static if (hasSlicing!Indices)
6860 {
6861 /// Ditto
opSlice(size_t a,size_t b)6862 typeof(this) opSlice(size_t a, size_t b)
6863 {
6864 return typeof(this)(_source, _indices[a .. b]);
6865 }
6866 }
6867
6868
6869 static if (hasAssignableElements!Source)
6870 {
6871 /// Ditto
6872 auto opIndexAssign(ElementType!Source newVal, size_t index)
6873 {
6874 return _source[_indices[index]] = newVal;
6875 }
6876 }
6877
6878
6879 static if (hasMobileElements!Source)
6880 {
6881 /// Ditto
moveAt(size_t index)6882 auto moveAt(size_t index)
6883 {
6884 return _source.moveAt(_indices[index]);
6885 }
6886 }
6887 }
6888
6889 // All this stuff is useful if someone wants to index an Indexed
6890 // without adding a layer of indirection.
6891
6892 /**
6893 Returns the source range.
6894 */
source()6895 @property Source source()
6896 {
6897 return _source;
6898 }
6899
6900 /**
6901 Returns the indices range.
6902 */
indices()6903 @property Indices indices()
6904 {
6905 return _indices;
6906 }
6907
6908 static if (isRandomAccessRange!Indices)
6909 {
6910 /**
6911 Returns the physical index into the source range corresponding to a
6912 given logical index. This is useful, for example, when indexing
6913 an $(D Indexed) without adding another layer of indirection.
6914 */
physicalIndex(size_t logicalIndex)6915 size_t physicalIndex(size_t logicalIndex)
6916 {
6917 return _indices[logicalIndex];
6918 }
6919
6920 ///
6921 @safe unittest
6922 {
6923 auto ind = indexed([1, 2, 3, 4, 5], [1, 3, 4]);
6924 assert(ind.physicalIndex(0) == 1);
6925 }
6926 }
6927
6928 private:
6929 Source _source;
6930 Indices _indices;
6931
6932 }
6933
6934 /// Ditto
6935 Indexed!(Source, Indices) indexed(Source, Indices)(Source source, Indices indices)
6936 {
6937 return typeof(return)(source, indices);
6938 }
6939
6940 ///
6941 @safe unittest
6942 {
6943 import std.algorithm.comparison : equal;
6944 auto source = [1, 2, 3, 4, 5];
6945 auto indices = [4, 3, 1, 2, 0, 4];
6946 auto ind = indexed(source, indices);
6947 assert(equal(ind, [5, 4, 2, 3, 1, 5]));
6948 assert(equal(retro(ind), [5, 1, 3, 2, 4, 5]));
6949 }
6950
6951 @safe unittest
6952 {
6953 {
6954 auto ind = indexed([1, 2, 3, 4, 5], [1, 3, 4]);
6955 assert(ind.physicalIndex(0) == 1);
6956 }
6957
6958 auto source = [1, 2, 3, 4, 5];
6959 auto indices = [4, 3, 1, 2, 0, 4];
6960 auto ind = indexed(source, indices);
6961
6962 // When elements of indices are duplicated and Source has lvalue elements,
6963 // these are aliased in ind.
6964 ind[0]++;
6965 assert(ind[0] == 6);
6966 assert(ind[5] == 6);
6967 }
6968
6969 @safe unittest
6970 {
6971 import std.internal.test.dummyrange : AllDummyRanges, propagatesLength,
6972 propagatesRangeType, RangeType;
6973
foreach(DummyType;AllDummyRanges)6974 foreach (DummyType; AllDummyRanges)
6975 {
6976 auto d = DummyType.init;
6977 auto r = indexed([1, 2, 3, 4, 5], d);
6978 static assert(propagatesRangeType!(DummyType, typeof(r)));
6979 static assert(propagatesLength!(DummyType, typeof(r)));
6980 }
6981 }
6982
6983 /**
6984 This range iterates over fixed-sized chunks of size $(D chunkSize) of a
6985 $(D source) range. $(D Source) must be an input range. $(D chunkSize) must be
6986 greater than zero.
6987
6988 If $(D !isInfinite!Source) and $(D source.walkLength) is not evenly
6989 divisible by $(D chunkSize), the back element of this range will contain
6990 fewer than $(D chunkSize) elements.
6991
6992 If `Source` is a forward range, the resulting range will be forward ranges as
6993 well. Otherwise, the resulting chunks will be input ranges consuming the same
6994 input: iterating over `front` will shrink the chunk such that subsequent
6995 invocations of `front` will no longer return the full chunk, and calling
6996 `popFront` on the outer range will invalidate any lingering references to
6997 previous values of `front`.
6998
6999 Params:
7000 source = Range from which the chunks will be selected
7001 chunkSize = Chunk size
7002
7003 See_Also: $(LREF slide)
7004
7005 Returns: Range of chunks.
7006 */
7007 struct Chunks(Source)
7008 if (isInputRange!Source)
7009 {
7010 static if (isForwardRange!Source)
7011 {
7012 /// Standard constructor
this(Source source,size_t chunkSize)7013 this(Source source, size_t chunkSize)
7014 {
7015 assert(chunkSize != 0, "Cannot create a Chunk with an empty chunkSize");
7016 _source = source;
7017 _chunkSize = chunkSize;
7018 }
7019
7020 /// Input range primitives. Always present.
front()7021 @property auto front()
7022 {
7023 assert(!empty, "Attempting to fetch the front of an empty Chunks");
7024 return _source.save.take(_chunkSize);
7025 }
7026
7027 /// Ditto
popFront()7028 void popFront()
7029 {
7030 assert(!empty, "Attempting to popFront and empty Chunks");
7031 _source.popFrontN(_chunkSize);
7032 }
7033
7034 static if (!isInfinite!Source)
7035 /// Ditto
empty()7036 @property bool empty()
7037 {
7038 return _source.empty;
7039 }
7040 else
7041 // undocumented
7042 enum empty = false;
7043
7044 /// Forward range primitives. Only present if `Source` is a forward range.
typeof(this)7045 @property typeof(this) save()
7046 {
7047 return typeof(this)(_source.save, _chunkSize);
7048 }
7049
7050 static if (hasLength!Source)
7051 {
7052 /// Length. Only if $(D hasLength!Source) is $(D true)
length()7053 @property size_t length()
7054 {
7055 // Note: _source.length + _chunkSize may actually overflow.
7056 // We cast to ulong to mitigate the problem on x86 machines.
7057 // For x64 machines, we just suppose we'll never overflow.
7058 // The "safe" code would require either an extra branch, or a
7059 // modulo operation, which is too expensive for such a rare case
7060 return cast(size_t)((cast(ulong)(_source.length) + _chunkSize - 1) / _chunkSize);
7061 }
7062 //Note: No point in defining opDollar here without slicing.
7063 //opDollar is defined below in the hasSlicing!Source section
7064 }
7065
7066 static if (hasSlicing!Source)
7067 {
7068 //Used for various purposes
7069 private enum hasSliceToEnd = is(typeof(Source.init[_chunkSize .. $]) == Source);
7070
7071 /**
7072 Indexing and slicing operations. Provided only if
7073 $(D hasSlicing!Source) is $(D true).
7074 */
opIndex(size_t index)7075 auto opIndex(size_t index)
7076 {
7077 immutable start = index * _chunkSize;
7078 immutable end = start + _chunkSize;
7079
7080 static if (isInfinite!Source)
7081 return _source[start .. end];
7082 else
7083 {
7084 import std.algorithm.comparison : min;
7085 immutable len = _source.length;
7086 assert(start < len, "chunks index out of bounds");
7087 return _source[start .. min(end, len)];
7088 }
7089 }
7090
7091 /// Ditto
7092 static if (hasLength!Source)
opSlice(size_t lower,size_t upper)7093 typeof(this) opSlice(size_t lower, size_t upper)
7094 {
7095 import std.algorithm.comparison : min;
7096 assert(lower <= upper && upper <= length, "chunks slicing index out of bounds");
7097 immutable len = _source.length;
7098 return chunks(_source[min(lower * _chunkSize, len) .. min(upper * _chunkSize, len)], _chunkSize);
7099 }
7100 else static if (hasSliceToEnd)
7101 //For slicing an infinite chunk, we need to slice the source to the end.
opSlice(size_t lower,size_t upper)7102 typeof(takeExactly(this, 0)) opSlice(size_t lower, size_t upper)
7103 {
7104 assert(lower <= upper, "chunks slicing index out of bounds");
7105 return chunks(_source[lower * _chunkSize .. $], _chunkSize).takeExactly(upper - lower);
7106 }
7107
7108 static if (isInfinite!Source)
7109 {
7110 static if (hasSliceToEnd)
7111 {
7112 private static struct DollarToken{}
opDollar()7113 DollarToken opDollar()
7114 {
7115 return DollarToken();
7116 }
7117 //Slice to dollar
opSlice(size_t lower,DollarToken)7118 typeof(this) opSlice(size_t lower, DollarToken)
7119 {
7120 return typeof(this)(_source[lower * _chunkSize .. $], _chunkSize);
7121 }
7122 }
7123 }
7124 else
7125 {
7126 //Dollar token carries a static type, with no extra information.
7127 //It can lazily transform into _source.length on algorithmic
7128 //operations such as : chunks[$/2, $-1];
7129 private static struct DollarToken
7130 {
7131 Chunks!Source* mom;
momLengthDollarToken7132 @property size_t momLength()
7133 {
7134 return mom.length;
7135 }
7136 alias momLength this;
7137 }
opDollar()7138 DollarToken opDollar()
7139 {
7140 return DollarToken(&this);
7141 }
7142
7143 //Slice overloads optimized for using dollar. Without this, to slice to end, we would...
7144 //1. Evaluate chunks.length
7145 //2. Multiply by _chunksSize
7146 //3. To finally just compare it (with min) to the original length of source (!)
7147 //These overloads avoid that.
opSlice(DollarToken,DollarToken)7148 typeof(this) opSlice(DollarToken, DollarToken)
7149 {
7150 static if (hasSliceToEnd)
7151 return chunks(_source[$ .. $], _chunkSize);
7152 else
7153 {
7154 immutable len = _source.length;
7155 return chunks(_source[len .. len], _chunkSize);
7156 }
7157 }
opSlice(size_t lower,DollarToken)7158 typeof(this) opSlice(size_t lower, DollarToken)
7159 {
7160 import std.algorithm.comparison : min;
7161 assert(lower <= length, "chunks slicing index out of bounds");
7162 static if (hasSliceToEnd)
7163 return chunks(_source[min(lower * _chunkSize, _source.length) .. $], _chunkSize);
7164 else
7165 {
7166 immutable len = _source.length;
7167 return chunks(_source[min(lower * _chunkSize, len) .. len], _chunkSize);
7168 }
7169 }
opSlice(DollarToken,size_t upper)7170 typeof(this) opSlice(DollarToken, size_t upper)
7171 {
7172 assert(upper == length, "chunks slicing index out of bounds");
7173 return this[$ .. $];
7174 }
7175 }
7176 }
7177
7178 //Bidirectional range primitives
7179 static if (hasSlicing!Source && hasLength!Source)
7180 {
7181 /**
7182 Bidirectional range primitives. Provided only if both
7183 $(D hasSlicing!Source) and $(D hasLength!Source) are $(D true).
7184 */
back()7185 @property auto back()
7186 {
7187 assert(!empty, "back called on empty chunks");
7188 immutable len = _source.length;
7189 immutable start = (len - 1) / _chunkSize * _chunkSize;
7190 return _source[start .. len];
7191 }
7192
7193 /// Ditto
popBack()7194 void popBack()
7195 {
7196 assert(!empty, "popBack() called on empty chunks");
7197 immutable end = (_source.length - 1) / _chunkSize * _chunkSize;
7198 _source = _source[0 .. end];
7199 }
7200 }
7201
7202 private:
7203 Source _source;
7204 size_t _chunkSize;
7205 }
7206 else // is input range only
7207 {
7208 import std.typecons : RefCounted;
7209
7210 static struct Chunk
7211 {
7212 private RefCounted!Impl impl;
7213
emptyChunk7214 @property bool empty() { return impl.curSizeLeft == 0 || impl.r.empty; }
frontChunk7215 @property auto front() { return impl.r.front; }
popFrontChunk7216 void popFront()
7217 {
7218 assert(impl.curSizeLeft > 0 && !impl.r.empty);
7219 impl.curSizeLeft--;
7220 impl.r.popFront();
7221 }
7222 }
7223
7224 static struct Impl
7225 {
7226 private Source r;
7227 private size_t chunkSize;
7228 private size_t curSizeLeft;
7229 }
7230
7231 private RefCounted!Impl impl;
7232
this(Source r,size_t chunkSize)7233 private this(Source r, size_t chunkSize)
7234 {
7235 impl = RefCounted!Impl(r, r.empty ? 0 : chunkSize, chunkSize);
7236 }
7237
empty()7238 @property bool empty() { return impl.chunkSize == 0; }
7239 @property Chunk front() return { return Chunk(impl); }
7240
7241 void popFront()
7242 {
7243 impl.curSizeLeft -= impl.r.popFrontN(impl.curSizeLeft);
7244 if (!impl.r.empty)
7245 impl.curSizeLeft = impl.chunkSize;
7246 else
7247 impl.chunkSize = 0;
7248 }
7249
7250 static assert(isInputRange!(typeof(this)));
7251 }
7252 }
7253
7254 /// Ditto
7255 Chunks!Source chunks(Source)(Source source, size_t chunkSize)
7256 if (isInputRange!Source)
7257 {
7258 return typeof(return)(source, chunkSize);
7259 }
7260
7261 ///
7262 @safe unittest
7263 {
7264 import std.algorithm.comparison : equal;
7265 auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
7266 auto chunks = chunks(source, 4);
7267 assert(chunks[0] == [1, 2, 3, 4]);
7268 assert(chunks[1] == [5, 6, 7, 8]);
7269 assert(chunks[2] == [9, 10]);
7270 assert(chunks.back == chunks[2]);
7271 assert(chunks.front == chunks[0]);
7272 assert(chunks.length == 3);
7273 assert(equal(retro(array(chunks)), array(retro(chunks))));
7274 }
7275
7276 /// Non-forward input ranges are supported, but with limited semantics.
7277 @system /*@safe*/ unittest // FIXME: can't be @safe because RefCounted isn't.
7278 {
7279 import std.algorithm.comparison : equal;
7280
7281 int i;
7282
7283 // The generator doesn't save state, so it cannot be a forward range.
7284 auto inputRange = generate!(() => ++i).take(10);
7285
7286 // We can still process it in chunks, but it will be single-pass only.
7287 auto chunked = inputRange.chunks(2);
7288
7289 assert(chunked.front.equal([1, 2]));
7290 assert(chunked.front.empty); // Iterating the chunk has consumed it
7291 chunked.popFront;
7292 assert(chunked.front.equal([3, 4]));
7293 }
7294
7295 @system /*@safe*/ unittest
7296 {
7297 import std.algorithm.comparison : equal;
7298 import std.internal.test.dummyrange : ReferenceInputRange;
7299
7300 auto data = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
7301 auto r = new ReferenceInputRange!int(data).chunks(3);
7302 assert(r.equal!equal([
7303 [ 1, 2, 3 ],
7304 [ 4, 5, 6 ],
7305 [ 7, 8, 9 ],
7306 [ 10 ]
7307 ]));
7308
7309 auto data2 = [ 1, 2, 3, 4, 5, 6 ];
7310 auto r2 = new ReferenceInputRange!int(data2).chunks(3);
7311 assert(r2.equal!equal([
7312 [ 1, 2, 3 ],
7313 [ 4, 5, 6 ]
7314 ]));
7315
7316 auto data3 = [ 1, 2, 3, 4, 5 ];
7317 auto r3 = new ReferenceInputRange!int(data3).chunks(2);
7318 assert(r3.front.equal([1, 2]));
7319 r3.popFront();
7320 assert(!r3.empty);
7321 r3.popFront();
7322 assert(r3.front.equal([5]));
7323 }
7324
7325 @safe unittest
7326 {
7327 auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
7328 auto chunks = chunks(source, 4);
7329 auto chunks2 = chunks.save;
7330 chunks.popFront();
7331 assert(chunks[0] == [5, 6, 7, 8]);
7332 assert(chunks[1] == [9, 10]);
7333 chunks2.popBack();
7334 assert(chunks2[1] == [5, 6, 7, 8]);
7335 assert(chunks2.length == 2);
7336
7337 static assert(isRandomAccessRange!(typeof(chunks)));
7338 }
7339
7340 @safe unittest
7341 {
7342 import std.algorithm.comparison : equal;
7343
7344 //Extra toying with slicing and indexing.
7345 auto chunks1 = [0, 0, 1, 1, 2, 2, 3, 3, 4].chunks(2);
7346 auto chunks2 = [0, 0, 1, 1, 2, 2, 3, 3, 4, 4].chunks(2);
7347
7348 assert(chunks1.length == 5);
7349 assert(chunks2.length == 5);
7350 assert(chunks1[4] == [4]);
7351 assert(chunks2[4] == [4, 4]);
7352 assert(chunks1.back == [4]);
7353 assert(chunks2.back == [4, 4]);
7354
7355 assert(chunks1[0 .. 1].equal([[0, 0]]));
7356 assert(chunks1[0 .. 2].equal([[0, 0], [1, 1]]));
7357 assert(chunks1[4 .. 5].equal([[4]]));
7358 assert(chunks2[4 .. 5].equal([[4, 4]]));
7359
7360 assert(chunks1[0 .. 0].equal((int[][]).init));
7361 assert(chunks1[5 .. 5].equal((int[][]).init));
7362 assert(chunks2[5 .. 5].equal((int[][]).init));
7363
7364 //Fun with opDollar
7365 assert(chunks1[$ .. $].equal((int[][]).init)); //Quick
7366 assert(chunks2[$ .. $].equal((int[][]).init)); //Quick
7367 assert(chunks1[$ - 1 .. $].equal([[4]])); //Semiquick
7368 assert(chunks2[$ - 1 .. $].equal([[4, 4]])); //Semiquick
7369 assert(chunks1[$ .. 5].equal((int[][]).init)); //Semiquick
7370 assert(chunks2[$ .. 5].equal((int[][]).init)); //Semiquick
7371
7372 assert(chunks1[$ / 2 .. $ - 1].equal([[2, 2], [3, 3]])); //Slow
7373 }
7374
7375 @safe unittest
7376 {
7377 import std.algorithm.comparison : equal;
7378 import std.algorithm.iteration : filter;
7379
7380 //ForwardRange
7381 auto r = filter!"true"([1, 2, 3, 4, 5]).chunks(2);
7382 assert(equal!"equal(a, b)"(r, [[1, 2], [3, 4], [5]]));
7383
7384 //InfiniteRange w/o RA
7385 auto fibsByPairs = recurrence!"a[n-1] + a[n-2]"(1, 1).chunks(2);
7386 assert(equal!`equal(a, b)`(fibsByPairs.take(2), [[ 1, 1], [ 2, 3]]));
7387
7388 //InfiniteRange w/ RA and slicing
7389 auto odds = sequence!("a[0] + n * a[1]")(1, 2);
7390 auto oddsByPairs = odds.chunks(2);
7391 assert(equal!`equal(a, b)`(oddsByPairs.take(2), [[ 1, 3], [ 5, 7]]));
7392
7393 //Requires phobos#991 for Sequence to have slice to end
7394 static assert(hasSlicing!(typeof(odds)));
7395 assert(equal!`equal(a, b)`(oddsByPairs[3 .. 5], [[13, 15], [17, 19]]));
7396 assert(equal!`equal(a, b)`(oddsByPairs[3 .. $].take(2), [[13, 15], [17, 19]]));
7397 }
7398
7399
7400
7401 /**
7402 This range splits a $(D source) range into $(D chunkCount) chunks of
7403 approximately equal length. $(D Source) must be a forward range with
7404 known length.
7405
7406 Unlike $(LREF chunks), $(D evenChunks) takes a chunk count (not size).
7407 The returned range will contain zero or more $(D source.length /
7408 chunkCount + 1) elements followed by $(D source.length / chunkCount)
7409 elements. If $(D source.length < chunkCount), some chunks will be empty.
7410
7411 $(D chunkCount) must not be zero, unless $(D source) is also empty.
7412 */
7413 struct EvenChunks(Source)
7414 if (isForwardRange!Source && hasLength!Source)
7415 {
7416 /// Standard constructor
this(Source source,size_t chunkCount)7417 this(Source source, size_t chunkCount)
7418 {
7419 assert(chunkCount != 0 || source.empty, "Cannot create EvenChunks with a zero chunkCount");
7420 _source = source;
7421 _chunkCount = chunkCount;
7422 }
7423
7424 /// Forward range primitives. Always present.
front()7425 @property auto front()
7426 {
7427 assert(!empty, "Attempting to fetch the front of an empty evenChunks");
7428 return _source.save.take(_chunkPos(1));
7429 }
7430
7431 /// Ditto
popFront()7432 void popFront()
7433 {
7434 assert(!empty, "Attempting to popFront an empty evenChunks");
7435 _source.popFrontN(_chunkPos(1));
7436 _chunkCount--;
7437 }
7438
7439 /// Ditto
empty()7440 @property bool empty()
7441 {
7442 return _source.empty;
7443 }
7444
7445 /// Ditto
typeof(this)7446 @property typeof(this) save()
7447 {
7448 return typeof(this)(_source.save, _chunkCount);
7449 }
7450
7451 /// Length
length()7452 @property size_t length() const
7453 {
7454 return _chunkCount;
7455 }
7456 //Note: No point in defining opDollar here without slicing.
7457 //opDollar is defined below in the hasSlicing!Source section
7458
7459 static if (hasSlicing!Source)
7460 {
7461 /**
7462 Indexing, slicing and bidirectional operations and range primitives.
7463 Provided only if $(D hasSlicing!Source) is $(D true).
7464 */
opIndex(size_t index)7465 auto opIndex(size_t index)
7466 {
7467 assert(index < _chunkCount, "evenChunks index out of bounds");
7468 return _source[_chunkPos(index) .. _chunkPos(index+1)];
7469 }
7470
7471 /// Ditto
opSlice(size_t lower,size_t upper)7472 typeof(this) opSlice(size_t lower, size_t upper)
7473 {
7474 assert(lower <= upper && upper <= length, "evenChunks slicing index out of bounds");
7475 return evenChunks(_source[_chunkPos(lower) .. _chunkPos(upper)], upper - lower);
7476 }
7477
7478 /// Ditto
back()7479 @property auto back()
7480 {
7481 assert(!empty, "back called on empty evenChunks");
7482 return _source[_chunkPos(_chunkCount - 1) .. _source.length];
7483 }
7484
7485 /// Ditto
popBack()7486 void popBack()
7487 {
7488 assert(!empty, "popBack() called on empty evenChunks");
7489 _source = _source[0 .. _chunkPos(_chunkCount - 1)];
7490 _chunkCount--;
7491 }
7492 }
7493
7494 private:
7495 Source _source;
7496 size_t _chunkCount;
7497
_chunkPos(size_t i)7498 size_t _chunkPos(size_t i)
7499 {
7500 /*
7501 _chunkCount = 5, _source.length = 13:
7502
7503 chunk0
7504 | chunk3
7505 | |
7506 v v
7507 +-+-+-+-+-+ ^
7508 |0|3|.| | | |
7509 +-+-+-+-+-+ | div
7510 |1|4|.| | | |
7511 +-+-+-+-+-+ v
7512 |2|5|.|
7513 +-+-+-+
7514
7515 <----->
7516 mod
7517
7518 <--------->
7519 _chunkCount
7520
7521 One column is one chunk.
7522 popFront and popBack pop the left-most
7523 and right-most column, respectively.
7524 */
7525
7526 auto div = _source.length / _chunkCount;
7527 auto mod = _source.length % _chunkCount;
7528 auto pos = i <= mod
7529 ? i * (div+1)
7530 : mod * (div+1) + (i-mod) * div
7531 ;
7532 //auto len = i < mod
7533 // ? div+1
7534 // : div
7535 //;
7536 return pos;
7537 }
7538 }
7539
7540 /// Ditto
7541 EvenChunks!Source evenChunks(Source)(Source source, size_t chunkCount)
7542 if (isForwardRange!Source && hasLength!Source)
7543 {
7544 return typeof(return)(source, chunkCount);
7545 }
7546
7547 ///
7548 @safe unittest
7549 {
7550 import std.algorithm.comparison : equal;
7551 auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
7552 auto chunks = evenChunks(source, 3);
7553 assert(chunks[0] == [1, 2, 3, 4]);
7554 assert(chunks[1] == [5, 6, 7]);
7555 assert(chunks[2] == [8, 9, 10]);
7556 }
7557
7558 @safe unittest
7559 {
7560 import std.algorithm.comparison : equal;
7561
7562 auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
7563 auto chunks = evenChunks(source, 3);
7564 assert(chunks.back == chunks[2]);
7565 assert(chunks.front == chunks[0]);
7566 assert(chunks.length == 3);
7567 assert(equal(retro(array(chunks)), array(retro(chunks))));
7568
7569 auto chunks2 = chunks.save;
7570 chunks.popFront();
7571 assert(chunks[0] == [5, 6, 7]);
7572 assert(chunks[1] == [8, 9, 10]);
7573 chunks2.popBack();
7574 assert(chunks2[1] == [5, 6, 7]);
7575 assert(chunks2.length == 2);
7576
7577 static assert(isRandomAccessRange!(typeof(chunks)));
7578 }
7579
7580 @safe unittest
7581 {
7582 import std.algorithm.comparison : equal;
7583
7584 int[] source = [];
7585 auto chunks = source.evenChunks(0);
7586 assert(chunks.length == 0);
7587 chunks = source.evenChunks(3);
7588 assert(equal(chunks, [[], [], []]));
7589 chunks = [1, 2, 3].evenChunks(5);
7590 assert(equal(chunks, [[1], [2], [3], [], []]));
7591 }
7592
7593 /*
7594 A fixed-sized sliding window iteration
7595 of size `windowSize` over a `source` range by a custom `stepSize`.
7596
7597 The `Source` range must be at least an `ForwardRange` and
7598 the `windowSize` must be greater than zero.
7599
7600 For `windowSize = 1` it splits the range into single element groups (aka `unflatten`)
7601 For `windowSize = 2` it is similar to `zip(source, source.save.dropOne)`.
7602
7603 Params:
7604 f = If `Yes.withFewerElements` slide with fewer
7605 elements than `windowSize`. This can only happen if the initial range
7606 contains less elements than `windowSize`. In this case
7607 if `No.withFewerElements` an empty range will be returned.
7608 source = Range from which the slide will be selected
7609 windowSize = Sliding window size
7610 stepSize = Steps between the windows (by default 1)
7611
7612 Returns: Range of all sliding windows with propagated bi-directionality,
7613 forwarding, conditional random access, and slicing.
7614
7615 See_Also: $(LREF chunks)
7616 */
7617 // Explicitly set to private to delay the release until 2.076
7618 private
7619 auto slide(Flag!"withFewerElements" f = Yes.withFewerElements,
7620 Source)(Source source, size_t windowSize, size_t stepSize = 1)
7621 if (isForwardRange!Source)
7622 {
7623 return Slides!(f, Source)(source, windowSize, stepSize);
7624 }
7625
7626 private struct Slides(Flag!"withFewerElements" withFewerElements = Yes.withFewerElements, Source)
7627 if (isForwardRange!Source)
7628 {
7629 private:
7630 Source _source;
7631 size_t _windowSize;
7632 size_t _stepSize;
7633
7634 static if (hasLength!Source)
7635 {
7636 enum needsEndTracker = false;
7637 }
7638 else
7639 {
7640 // if there's no information about the length, track needs to be kept manually
7641 Source _nextSource;
7642 enum needsEndTracker = true;
7643 }
7644
7645 bool _empty;
7646
7647 static if (hasSlicing!Source)
7648 {
7649 enum hasSliceToEnd = hasSlicing!Source && is(typeof(Source.init[0 .. $]) == Source);
7650 }
7651
7652 public:
7653 /// Standard constructor
thisSlides7654 this(Source source, size_t windowSize, size_t stepSize)
7655 {
7656 assert(windowSize > 0, "windowSize must be greater than zero");
7657 assert(stepSize > 0, "stepSize must be greater than zero");
7658 _source = source;
7659 _windowSize = windowSize;
7660 _stepSize = stepSize;
7661
7662 static if (needsEndTracker)
7663 {
7664 // _nextSource is used to "look into the future" and check for the end
7665 _nextSource = source.save;
7666 _nextSource.popFrontN(windowSize);
7667 }
7668
7669 static if (!withFewerElements)
7670 {
7671 // empty source range is needed, s.t. length, slicing etc. works properly
7672 static if (needsEndTracker)
7673 {
7674 if (_nextSource.empty)
7675 _source = _nextSource;
7676 }
7677 else
7678 {
7679 if (_source.length < windowSize)
7680 {
7681 static if (hasSlicing!Source)
7682 {
7683 // if possible use the faster opDollar overload
7684 static if (hasSliceToEnd)
7685 _source = _source[$ .. $];
7686 else
7687 _source = _source[_source.length .. _source.length];
7688 }
7689 else
7690 {
7691 _source.popFrontN(_source.length);
7692 }
7693 }
7694 }
7695 }
7696
7697 _empty = _source.empty;
7698 }
7699
7700 /// Forward range primitives. Always present.
frontSlides7701 @property auto front()
7702 {
7703 assert(!empty, "Attempting to access front on an empty slide");
7704 static if (hasSlicing!Source && hasLength!Source)
7705 {
7706 import std.algorithm.comparison : min;
7707 return _source[0 .. min(_windowSize, _source.length)];
7708 }
7709 else
7710 {
7711 return _source.save.take(_windowSize);
7712 }
7713 }
7714
7715 /// Ditto
popFrontSlides7716 void popFront()
7717 {
7718 assert(!empty, "Attempting to call popFront() on an empty slide");
7719 _source.popFrontN(_stepSize);
7720
7721 // if the range has less elements than its window size,
7722 // we have seen the last full window (i.e. its empty)
7723 static if (needsEndTracker)
7724 {
7725 if (_nextSource.empty)
7726 _empty = true;
7727 else
7728 _nextSource.popFrontN(_stepSize);
7729 }
7730 else
7731 {
7732 if (_source.length < _windowSize)
7733 _empty = true;
7734 }
7735 }
7736
7737 static if (!isInfinite!Source)
7738 {
7739 /// Ditto
emptySlides7740 @property bool empty() const
7741 {
7742 return _empty;
7743 }
7744 }
7745 else
7746 {
7747 // undocumented
7748 enum empty = false;
7749 }
7750
7751 /// Ditto
typeofSlides7752 @property typeof(this) save()
7753 {
7754 return typeof(this)(_source.save, _windowSize, _stepSize);
7755 }
7756
7757 static if (hasLength!Source)
7758 {
7759 /// Length. Only if $(D hasLength!Source) is $(D true)
lengthSlides7760 @property size_t length()
7761 {
7762 if (_source.length < _windowSize)
7763 {
7764 static if (withFewerElements)
7765 return 1;
7766 else
7767 return 0;
7768 }
7769 else
7770 {
7771 return (_source.length - _windowSize + _stepSize) / _stepSize;
7772 }
7773 }
7774 }
7775
7776 static if (hasSlicing!Source)
7777 {
7778 /**
7779 Indexing and slicing operations. Provided only if
7780 `hasSlicing!Source` is `true`.
7781 */
opIndexSlides7782 auto opIndex(size_t index)
7783 {
7784 immutable start = index * _stepSize;
7785
7786 static if (isInfinite!Source)
7787 {
7788 immutable end = start + _windowSize;
7789 }
7790 else
7791 {
7792 import std.algorithm.comparison : min;
7793
7794 immutable len = _source.length;
7795 assert(start < len, "slide index out of bounds");
7796 immutable end = min(start + _windowSize, len);
7797 }
7798
7799 return _source[start .. end];
7800 }
7801
7802 static if (!isInfinite!Source)
7803 {
7804 /// ditto
opSliceSlides7805 typeof(this) opSlice(size_t lower, size_t upper)
7806 {
7807 import std.algorithm.comparison : min;
7808 assert(lower <= upper && upper <= length, "slide slicing index out of bounds");
7809
7810 lower *= _stepSize;
7811 upper *= _stepSize;
7812
7813 immutable len = _source.length;
7814
7815 /*
7816 * Notice that we only need to move for windowSize - 1 to the right:
7817 * source = [0, 1, 2, 3] (length: 4)
7818 * - source.slide(2) -> s = [[0, 1], [1, 2], [2, 3]]
7819 * right pos for s[0 .. 3]: 3 (upper) + 2 (windowSize) - 1 = 4
7820 *
7821 * - source.slide(3) -> s = [[0, 1, 2], [1, 2, 3]]
7822 * right pos for s[0 .. 2]: 2 (upper) + 3 (windowSize) - 1 = 4
7823 *
7824 * source = [0, 1, 2, 3, 4] (length: 5)
7825 * - source.slide(4) -> s = [[0, 1, 2, 3], [1, 2, 3, 4]]
7826 * right pos for s[0 .. 2]: 2 (upper) + 4 (windowSize) - 1 = 5
7827 */
7828 return typeof(this)
7829 (_source[min(lower, len) .. min(upper + _windowSize - 1, len)],
7830 _windowSize, _stepSize);
7831 }
7832 }
7833 else static if (hasSliceToEnd)
7834 {
7835 //For slicing an infinite chunk, we need to slice the source to the infinite end.
opSliceSlides7836 auto opSlice(size_t lower, size_t upper)
7837 {
7838 assert(lower <= upper, "slide slicing index out of bounds");
7839 return typeof(this)(_source[lower * _stepSize .. $],
7840 _windowSize, _stepSize).takeExactly(upper - lower);
7841 }
7842 }
7843
7844 static if (isInfinite!Source)
7845 {
7846 static if (hasSliceToEnd)
7847 {
7848 private static struct DollarToken{}
opDollarSlides7849 DollarToken opDollar()
7850 {
7851 return DollarToken();
7852 }
7853 //Slice to dollar
opSliceSlides7854 typeof(this) opSlice(size_t lower, DollarToken)
7855 {
7856 return typeof(this)(_source[lower * _stepSize .. $], _windowSize, _stepSize);
7857 }
7858 }
7859 }
7860 else
7861 {
7862 //Dollar token carries a static type, with no extra information.
7863 //It can lazily transform into _source.length on algorithmic
7864 //operations such as : slide[$/2, $-1];
7865 private static struct DollarToken
7866 {
7867 private size_t _length;
7868 alias _length this;
7869 }
7870
opDollarSlides7871 DollarToken opDollar()
7872 {
7873 return DollarToken(this.length);
7874 }
7875
7876 // Optimized slice overloads optimized for using dollar.
opSliceSlides7877 typeof(this) opSlice(DollarToken, DollarToken)
7878 {
7879 static if (hasSliceToEnd)
7880 {
7881 return typeof(this)(_source[$ .. $], _windowSize, _stepSize);
7882 }
7883 else
7884 {
7885 immutable len = _source.length;
7886 return typeof(this)(_source[len .. len], _windowSize, _stepSize);
7887 }
7888 }
7889
7890 // Optimized slice overloads optimized for using dollar.
opSliceSlides7891 typeof(this) opSlice(size_t lower, DollarToken)
7892 {
7893 import std.algorithm.comparison : min;
7894 assert(lower <= length, "slide slicing index out of bounds");
7895 lower *= _stepSize;
7896 static if (hasSliceToEnd)
7897 {
7898 return typeof(this)(_source[min(lower, _source.length) .. $], _windowSize, _stepSize);
7899 }
7900 else
7901 {
7902 immutable len = _source.length;
7903 return typeof(this)(_source[min(lower, len) .. len], _windowSize, _stepSize);
7904 }
7905 }
7906
7907 // Optimized slice overloads optimized for using dollar.
opSliceSlides7908 typeof(this) opSlice(DollarToken, size_t upper)
7909 {
7910 assert(upper == length, "slide slicing index out of bounds");
7911 return this[$ .. $];
7912 }
7913 }
7914
7915 // Bidirectional range primitives
7916 static if (!isInfinite!Source)
7917 {
7918 /**
7919 Bidirectional range primitives. Provided only if both
7920 `hasSlicing!Source` and `!isInfinite!Source` are `true`.
7921 */
backSlides7922 @property auto back()
7923 {
7924 import std.algorithm.comparison : max;
7925
7926 assert(!empty, "Attempting to access front on an empty slide");
7927
7928 immutable len = _source.length;
7929 /*
7930 * Note:
7931 * - `end` in the following is the exclusive end as used in opSlice
7932 * - For the trivial case with `stepSize = 1` `end` is at `len`:
7933 *
7934 * iota(4).slide(2) = [[0, 1], [1, 2], [2, 3] (end = 4)
7935 * iota(4).slide(3) = [[0, 1, 2], [1, 2, 3]] (end = 4)
7936 *
7937 * - For the non-trivial cases, we need to calculate the gap
7938 * between `len` and `end` - this is the number of missing elements
7939 * from the input range:
7940 *
7941 * iota(7).slide(2, 3) = [[0, 1], [3, 4]] || <gap: 2> 6
7942 * iota(7).slide(2, 4) = [[0, 1], [4, 5]] || <gap: 1> 6
7943 * iota(7).slide(1, 5) = [[0], [5]] || <gap: 1> 6
7944 *
7945 * As it can be seen `gap` can be at most `stepSize - 1`
7946 * More generally the elements of the sliding window with
7947 * `w = windowSize` and `s = stepSize` are:
7948 *
7949 * [0, w], [s, s + w], [2 * s, 2 * s + w], ... [n * s, n * s + w]
7950 *
7951 * We can thus calculate the gap between the `end` and `len` as:
7952 *
7953 * gap = len - (n * s + w) = len - w - (n * s)
7954 *
7955 * As we aren't interested in exact value of `n`, but the best
7956 * minimal `gap` value, we can use modulo to "cut" `len - w` optimally:
7957 *
7958 * gap = len - w - (s - s ... - s) = (len - w) % s
7959 *
7960 * So for example:
7961 *
7962 * iota(7).slide(2, 3) = [[0, 1], [3, 4]]
7963 * gap: (7 - 2) % 3 = 5 % 3 = 2
7964 * end: 7 - 2 = 5
7965 *
7966 * iota(7).slide(4, 2) = [[0, 1, 2, 3], [2, 3, 4, 5]]
7967 * gap: (7 - 4) % 2 = 3 % 2 = 1
7968 * end: 7 - 1 = 6
7969 */
7970 size_t gap = (len - _windowSize) % _stepSize;
7971
7972 // check for underflow
7973 immutable start = (len > _windowSize + gap) ? len - _windowSize - gap : 0;
7974
7975 return _source[start .. len - gap];
7976 }
7977
7978 /// Ditto
popBackSlides7979 void popBack()
7980 {
7981 assert(!empty, "Attempting to call popBack() on an empty slide");
7982
7983 immutable end = _source.length > _stepSize ? _source.length - _stepSize : 0;
7984 _source = _source[0 .. end];
7985
7986 if (_source.length < _windowSize)
7987 _empty = true;
7988 }
7989 }
7990 }
7991 }
7992
7993 //
7994 @safe pure nothrow unittest
7995 {
7996 import std.algorithm.comparison : equal;
7997 import std.array : array;
7998
7999 assert([0, 1, 2, 3].slide(2).equal!equal(
8000 [[0, 1], [1, 2], [2, 3]]
8001 ));
8002 assert(5.iota.slide(3).equal!equal(
8003 [[0, 1, 2], [1, 2, 3], [2, 3, 4]]
8004 ));
8005
8006 assert(iota(7).slide(2, 2).equal!equal([[0, 1], [2, 3], [4, 5]]));
8007 assert(iota(12).slide(2, 4).equal!equal([[0, 1], [4, 5], [8, 9]]));
8008
8009 // set a custom stepsize (default 1)
8010 assert(6.iota.slide(1, 2).equal!equal(
8011 [[0], [2], [4]]
8012 ));
8013
8014 assert(6.iota.slide(2, 4).equal!equal(
8015 [[0, 1], [4, 5]]
8016 ));
8017
8018 // allow slide with less elements than the window size
8019 assert(3.iota.slide!(No.withFewerElements)(4).empty);
8020 assert(3.iota.slide!(Yes.withFewerElements)(4).equal!equal(
8021 [[0, 1, 2]]
8022 ));
8023 }
8024
8025 // count k-mers
8026 @safe pure nothrow unittest
8027 {
8028 import std.algorithm.comparison : equal;
8029 import std.algorithm.iteration : each;
8030
8031 int[dstring] d;
8032 "AGAGA"d.slide(2).each!(a => d[a]++);
8033 assert(d == ["AG"d: 2, "GA"d: 2]);
8034 }
8035
8036 // @nogc
8037 @safe pure nothrow @nogc unittest
8038 {
8039 import std.algorithm.comparison : equal;
8040
8041 static immutable res1 = [[0], [1], [2], [3]];
8042 assert(4.iota.slide(1).equal!equal(res1));
8043
8044 static immutable res2 = [[0, 1], [1, 2], [2, 3]];
8045 assert(4.iota.slide(2).equal!equal(res2));
8046 }
8047
8048 // different window sizes
8049 @safe pure nothrow unittest
8050 {
8051 import std.algorithm.comparison : equal;
8052 import std.array : array;
8053
8054 assert([0, 1, 2, 3].slide(1).array == [[0], [1], [2], [3]]);
8055 assert([0, 1, 2, 3].slide(2).array == [[0, 1], [1, 2], [2, 3]]);
8056 assert([0, 1, 2, 3].slide(3).array == [[0, 1, 2], [1, 2, 3]]);
8057 assert([0, 1, 2, 3].slide(4).array == [[0, 1, 2, 3]]);
8058 assert([0, 1, 2, 3].slide(5).array == [[0, 1, 2, 3]]);
8059
8060
8061 assert(iota(2).slide(2).front.equal([0, 1]));
8062 assert(iota(3).slide(2).equal!equal([[0, 1],[1, 2]]));
8063 assert(iota(3).slide(3).equal!equal([[0, 1, 2]]));
8064 assert(iota(3).slide(4).equal!equal([[0, 1, 2]]));
8065 assert(iota(1, 4).slide(1).equal!equal([[1], [2], [3]]));
8066 assert(iota(1, 4).slide(3).equal!equal([[1, 2, 3]]));
8067 }
8068
8069 @safe unittest
8070 {
8071 import std.algorithm.comparison : equal;
8072
8073 assert(6.iota.slide(1, 1).equal!equal(
8074 [[0], [1], [2], [3], [4], [5]]
8075 ));
8076 assert(6.iota.slide(1, 2).equal!equal(
8077 [[0], [2], [4]]
8078 ));
8079 assert(6.iota.slide(1, 3).equal!equal(
8080 [[0], [3]]
8081 ));
8082 assert(6.iota.slide(1, 4).equal!equal(
8083 [[0], [4]]
8084 ));
8085 assert(6.iota.slide(1, 5).equal!equal(
8086 [[0], [5]]
8087 ));
8088 assert(6.iota.slide(2, 1).equal!equal(
8089 [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5]]
8090 ));
8091 assert(6.iota.slide(2, 2).equal!equal(
8092 [[0, 1], [2, 3], [4, 5]]
8093 ));
8094 assert(6.iota.slide(2, 3).equal!equal(
8095 [[0, 1], [3, 4]]
8096 ));
8097 assert(6.iota.slide(2, 4).equal!equal(
8098 [[0, 1], [4, 5]]
8099 ));
8100 assert(6.iota.slide(2, 5).equal!equal(
8101 [[0, 1]]
8102 ));
8103 assert(6.iota.slide(3, 1).equal!equal(
8104 [[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5]]
8105 ));
8106 assert(6.iota.slide(3, 2).equal!equal(
8107 [[0, 1, 2], [2, 3, 4]]
8108 ));
8109 assert(6.iota.slide(3, 3).equal!equal(
8110 [[0, 1, 2], [3, 4, 5]]
8111 ));
8112 assert(6.iota.slide(3, 4).equal!equal(
8113 [[0, 1, 2]]
8114 ));
8115 assert(6.iota.slide(4, 1).equal!equal(
8116 [[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
8117 ));
8118 assert(6.iota.slide(4, 2).equal!equal(
8119 [[0, 1, 2, 3], [2, 3, 4, 5]]
8120 ));
8121 assert(6.iota.slide(4, 3).equal!equal(
8122 [[0, 1, 2, 3]]
8123 ));
8124 assert(6.iota.slide(5, 1).equal!equal(
8125 [[0, 1, 2, 3, 4], [1, 2, 3, 4, 5]]
8126 ));
8127 assert(6.iota.slide(5, 2).equal!equal(
8128 [[0, 1, 2, 3, 4]]
8129 ));
8130 assert(6.iota.slide(5, 3).equal!equal(
8131 [[0, 1, 2, 3, 4]]
8132 ));
8133 }
8134
8135 // emptyness, copyability, strings
8136 @safe pure nothrow unittest
8137 {
8138 import std.algorithm.comparison : equal;
8139 import std.algorithm.iteration : each, map;
8140
8141 // check with empty input
8142 int[] d;
8143 assert(d.slide(2).empty);
8144 assert(d.slide(2, 2).empty);
8145
8146 // is copyable?
8147 auto e = iota(5).slide(2);
8148 e.popFront;
8149 assert(e.save.equal!equal([[1, 2], [2, 3], [3, 4]]));
8150 assert(e.save.equal!equal([[1, 2], [2, 3], [3, 4]]));
8151 assert(e.map!"a.array".array == [[1, 2], [2, 3], [3, 4]]);
8152
8153 // test with strings
8154 int[dstring] f;
8155 "AGAGA"d.slide(3).each!(a => f[a]++);
8156 assert(f == ["AGA"d: 2, "GAG"d: 1]);
8157
8158 int[dstring] g;
8159 "ABCDEFG"d.slide(3, 3).each!(a => g[a]++);
8160 assert(g == ["ABC"d:1, "DEF"d:1]);
8161 }
8162
8163 // test slicing, length
8164 @safe pure nothrow unittest
8165 {
8166 import std.algorithm.comparison : equal;
8167 import std.array : array;
8168
8169 // test index
8170 assert(iota(3).slide(4)[0].equal([0, 1, 2]));
8171 assert(iota(5).slide(4)[1].equal([1, 2, 3, 4]));
8172 assert(iota(3).slide(4, 2)[0].equal([0, 1, 2]));
8173 assert(iota(5).slide(4, 2)[1].equal([2, 3, 4]));
8174 assert(iota(3).slide(4, 3)[0].equal([0, 1, 2]));
8175 assert(iota(5).slide(4, 3)[1].equal([3, 4,]));
8176
8177 // test slicing
8178 assert(iota(3).slide(4)[0 .. $].equal!equal([[0, 1, 2]]));
8179 assert(iota(3).slide(2)[1 .. $].equal!equal([[1, 2]]));
8180 assert(iota(1, 5).slide(2)[0 .. 1].equal!equal([[1, 2]]));
8181 assert(iota(1, 5).slide(2)[0 .. 2].equal!equal([[1, 2], [2, 3]]));
8182 assert(iota(1, 5).slide(3)[0 .. 1].equal!equal([[1, 2, 3]]));
8183 assert(iota(1, 5).slide(3)[0 .. 2].equal!equal([[1, 2, 3], [2, 3, 4]]));
8184 assert(iota(1, 6).slide(3)[2 .. 3].equal!equal([[3, 4, 5]]));
8185 assert(iota(1, 5).slide(4)[0 .. 1].equal!equal([[1, 2, 3, 4]]));
8186
8187 // length
8188 assert(iota(3).slide(1).length == 3);
8189 assert(iota(3).slide(1, 2).length == 2);
8190 assert(iota(3).slide(1, 3).length == 1);
8191 assert(iota(3).slide(1, 4).length == 1);
8192 assert(iota(3).slide(2).length == 2);
8193 assert(iota(3).slide(2, 2).length == 1);
8194 assert(iota(3).slide(2, 3).length == 1);
8195 assert(iota(3).slide(3).length == 1);
8196 assert(iota(3).slide(3, 2).length == 1);
8197
8198 // opDollar
8199 assert(iota(3).slide(4)[$/2 .. $].equal!equal([[0, 1, 2]]));
8200 assert(iota(3).slide(4)[$ .. $].empty);
8201 assert(iota(3).slide(4)[$ .. 1].empty);
8202
8203 assert(iota(5).slide(3, 1)[$/2 .. $].equal!equal([[1, 2, 3], [2, 3, 4]]));
8204 assert(iota(5).slide(3, 2)[$/2 .. $].equal!equal([[2, 3, 4]]));
8205 assert(iota(5).slide(3, 3)[$/2 .. $].equal!equal([[0, 1, 2]]));
8206 assert(iota(3).slide(4, 3)[$ .. $].empty);
8207 assert(iota(3).slide(4, 3)[$ .. 1].empty);
8208 }
8209
8210 // test No.withFewerElements
8211 @safe pure nothrow unittest
8212 {
8213 assert(iota(3).slide(4).length == 1);
8214 assert(iota(3).slide(4, 4).length == 1);
8215
8216 assert(iota(3).slide!(No.withFewerElements)(4).empty);
8217 assert(iota(3, 3).slide!(No.withFewerElements)(4).empty);
8218 assert(iota(3).slide!(No.withFewerElements)(4).length == 0);
8219 assert(iota(3).slide!(No.withFewerElements)(4, 4).length == 0);
8220
8221 assert(iota(3).slide!(No.withFewerElements)(400).empty);
8222 assert(iota(3).slide!(No.withFewerElements)(400).length == 0);
8223 assert(iota(3).slide!(No.withFewerElements)(400, 10).length == 0);
8224
8225 assert(iota(3).slide!(No.withFewerElements)(4)[0 .. $].empty);
8226 assert(iota(3).slide!(No.withFewerElements)(4)[$ .. $].empty);
8227 assert(iota(3).slide!(No.withFewerElements)(4)[$ .. 0].empty);
8228 assert(iota(3).slide!(No.withFewerElements)(4)[$/2 .. $].empty);
8229
8230 // with different step sizes
8231 assert(iota(3).slide!(No.withFewerElements)(4, 5)[0 .. $].empty);
8232 assert(iota(3).slide!(No.withFewerElements)(4, 6)[$ .. $].empty);
8233 assert(iota(3).slide!(No.withFewerElements)(4, 7)[$ .. 0].empty);
8234 assert(iota(3).slide!(No.withFewerElements)(4, 8)[$/2 .. $].empty);
8235 }
8236
8237 // test with infinite ranges
8238 @safe pure nothrow unittest
8239 {
8240 import std.algorithm.comparison : equal;
8241
8242 // InfiniteRange without RandomAccess
8243 auto fibs = recurrence!"a[n-1] + a[n-2]"(1, 1);
8244 assert(fibs.slide(2).take(2).equal!equal([[1, 1], [1, 2]]));
8245 assert(fibs.slide(2, 3).take(2).equal!equal([[1, 1], [3, 5]]));
8246
8247 // InfiniteRange with RandomAccess and slicing
8248 auto odds = sequence!("a[0] + n * a[1]")(1, 2);
8249 auto oddsByPairs = odds.slide(2);
8250 assert(oddsByPairs.take(2).equal!equal([[ 1, 3], [ 3, 5]]));
8251 assert(oddsByPairs[1].equal([3, 5]));
8252 assert(oddsByPairs[4].equal([9, 11]));
8253
8254 static assert(hasSlicing!(typeof(odds)));
8255 assert(oddsByPairs[3 .. 5].equal!equal([[7, 9], [9, 11]]));
8256 assert(oddsByPairs[3 .. $].take(2).equal!equal([[7, 9], [9, 11]]));
8257
8258 auto oddsWithGaps = odds.slide(2, 4);
8259 assert(oddsWithGaps.take(3).equal!equal([[1, 3], [9, 11], [17, 19]]));
8260 assert(oddsWithGaps[2].equal([17, 19]));
8261 assert(oddsWithGaps[1 .. 3].equal!equal([[9, 11], [17, 19]]));
8262 assert(oddsWithGaps[1 .. $].take(2).equal!equal([[9, 11], [17, 19]]));
8263 }
8264
8265 // test reverse
8266 @safe pure nothrow unittest
8267 {
8268 import std.algorithm.comparison : equal;
8269
8270 auto e = iota(3).slide(2);
8271 assert(e.retro.equal!equal([[1, 2], [0, 1]]));
8272 assert(e.retro.array.equal(e.array.retro));
8273
8274 auto e2 = iota(5).slide(3);
8275 assert(e2.retro.equal!equal([[2, 3, 4], [1, 2, 3], [0, 1, 2]]));
8276 assert(e2.retro.array.equal(e2.array.retro));
8277
8278 auto e3 = iota(3).slide(4);
8279 assert(e3.retro.equal!equal([[0, 1, 2]]));
8280 assert(e3.retro.array.equal(e3.array.retro));
8281 }
8282
8283 // test reverse with different steps
8284 @safe pure nothrow unittest
8285 {
8286 import std.algorithm.comparison : equal;
8287
8288 assert(iota(7).slide(2, 1).retro.equal!equal(
8289 [[5, 6], [4, 5], [3, 4], [2, 3], [1, 2], [0, 1]]
8290 ));
8291 assert(iota(7).slide(2, 2).retro.equal!equal(
8292 [[4, 5], [2, 3], [0, 1]]
8293 ));
8294 assert(iota(7).slide(2, 3).retro.equal!equal(
8295 [[3, 4], [0, 1]]
8296 ));
8297 assert(iota(7).slide(2, 4).retro.equal!equal(
8298 [[4, 5], [0, 1]]
8299 ));
8300 assert(iota(7).slide(2, 5).retro.equal!equal(
8301 [[5, 6], [0, 1]]
8302 ));
8303 assert(iota(7).slide(3, 1).retro.equal!equal(
8304 [[4, 5, 6], [3, 4, 5], [2, 3, 4], [1, 2, 3], [0, 1, 2]]
8305 ));
8306 assert(iota(7).slide(3, 2).retro.equal!equal(
8307 [[4, 5, 6], [2, 3, 4], [0, 1, 2]]
8308 ));
8309 assert(iota(7).slide(4, 1).retro.equal!equal(
8310 [[3, 4, 5, 6], [2, 3, 4, 5], [1, 2, 3, 4], [0, 1, 2, 3]]
8311 ));
8312 assert(iota(7).slide(4, 2).retro.equal!equal(
8313 [[2, 3, 4, 5], [0, 1, 2, 3]]
8314 ));
8315 assert(iota(7).slide(4, 3).retro.equal!equal(
8316 [[3, 4, 5, 6], [0, 1, 2, 3]]
8317 ));
8318 assert(iota(7).slide(4, 4).retro.equal!equal(
8319 [[0, 1, 2, 3]]
8320 ));
8321 assert(iota(7).slide(5, 1).retro.equal!equal(
8322 [[2, 3, 4, 5, 6], [1, 2, 3, 4, 5], [0, 1, 2, 3, 4]]
8323 ));
8324 assert(iota(7).slide(5, 2).retro.equal!equal(
8325 [[2, 3, 4, 5, 6], [0, 1, 2, 3, 4]]
8326 ));
8327 assert(iota(7).slide(5, 3).retro.equal!equal(
8328 [[0, 1, 2, 3, 4]]
8329 ));
8330 assert(iota(7).slide(5, 4).retro.equal!equal(
8331 [[0, 1, 2, 3, 4]]
8332 ));
8333 }
8334
8335 // step size
8336 @safe pure nothrow unittest
8337 {
8338 import std.algorithm.comparison : equal;
8339
8340 assert(iota(7).slide(2, 2).equal!equal([[0, 1], [2, 3], [4, 5]]));
8341 assert(iota(8).slide(2, 2).equal!equal([[0, 1], [2, 3], [4, 5], [6, 7]]));
8342 assert(iota(9).slide(2, 2).equal!equal([[0, 1], [2, 3], [4, 5], [6, 7]]));
8343 assert(iota(12).slide(2, 4).equal!equal([[0, 1], [4, 5], [8, 9]]));
8344 assert(iota(13).slide(2, 4).equal!equal([[0, 1], [4, 5], [8, 9]]));
8345 }
8346
8347 // test with dummy ranges
8348 @safe pure nothrow unittest
8349 {
8350 import std.algorithm.comparison : equal;
8351 import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy, AllDummyRanges;
8352 import std.meta : AliasSeq;
8353
8354 alias AllForwardDummyRanges = AliasSeq!(
8355 DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Forward),
8356 DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Bidirectional),
8357 DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random),
8358 DummyRange!(ReturnBy.Reference, Length.No, RangeType.Forward),
8359 DummyRange!(ReturnBy.Reference, Length.No, RangeType.Bidirectional),
8360 //DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Input),
8361 DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Forward),
8362 DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Bidirectional),
8363 DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random),
8364 //DummyRange!(ReturnBy.Value, Length.No, RangeType.Input),
8365 DummyRange!(ReturnBy.Value, Length.No, RangeType.Forward),
8366 DummyRange!(ReturnBy.Value, Length.No, RangeType.Bidirectional)
8367 );
8368
8369 foreach (Range; AliasSeq!AllForwardDummyRanges)
8370 {
8371 Range r;
8372 assert(r.slide(1).equal!equal(
8373 [[1], [2], [3], [4], [5], [6], [7], [8], [9], [10]]
8374 ));
8375 assert(r.slide(2).equal!equal(
8376 [[1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9], [9, 10]]
8377 ));
8378 assert(r.slide(3).equal!equal(
8379 [[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6],
8380 [5, 6, 7], [6, 7, 8], [7, 8, 9], [8, 9, 10]]
8381 ));
8382 assert(r.slide(6).equal!equal(
8383 [[1, 2, 3, 4, 5, 6], [2, 3, 4, 5, 6, 7], [3, 4, 5, 6, 7, 8],
8384 [4, 5, 6, 7, 8, 9], [5, 6, 7, 8, 9, 10]]
8385 ));
8386 assert(r.slide(15).equal!equal(
8387 [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]
8388 ));
8389
8390 assert(r.slide!(No.withFewerElements)(15).empty);
8391 }
8392
8393 alias BackwardsDummyRanges = AliasSeq!(
8394 DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random),
8395 DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random),
8396 );
8397
8398 foreach (Range; AliasSeq!BackwardsDummyRanges)
8399 {
8400 Range r;
8401 assert(r.slide(1).retro.equal!equal(
8402 [[10], [9], [8], [7], [6], [5], [4], [3], [2], [1]]
8403 ));
8404 assert(r.slide(2).retro.equal!equal(
8405 [[9, 10], [8, 9], [7, 8], [6, 7], [5, 6], [4, 5], [3, 4], [2, 3], [1, 2]]
8406 ));
8407 assert(r.slide(5).retro.equal!equal(
8408 [[6, 7, 8, 9, 10], [5, 6, 7, 8, 9], [4, 5, 6, 7, 8],
8409 [3, 4, 5, 6, 7], [2, 3, 4, 5, 6], [1, 2, 3, 4, 5]]
8410 ));
8411 assert(r.slide(15).retro.equal!equal(
8412 [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]
8413 ));
8414
8415 // different step sizes
8416 assert(r.slide(2, 4)[2].equal([9, 10]));
8417 assert(r.slide(2, 1).equal!equal(
8418 [[1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9], [9, 10]]
8419 ));
8420 assert(r.slide(2, 2).equal!equal(
8421 [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]
8422 ));
8423 assert(r.slide(2, 3).equal!equal(
8424 [[1, 2], [4, 5], [7, 8]]
8425 ));
8426 assert(r.slide(2, 4).equal!equal(
8427 [[1, 2], [5, 6], [9, 10]]
8428 ));
8429
8430 // front = back
8431 foreach (windowSize; 1 .. 10)
8432 foreach (stepSize; 1 .. 10)
8433 {
8434 auto slider = r.slide(windowSize, stepSize);
8435 assert(slider.retro.retro.equal!equal(slider));
8436 }
8437 }
8438
8439 assert(iota(1, 12).slide(2, 4)[0 .. 3].equal!equal([[1, 2], [5, 6], [9, 10]]));
8440 assert(iota(1, 12).slide(2, 4)[0 .. $].equal!equal([[1, 2], [5, 6], [9, 10]]));
8441 assert(iota(1, 12).slide(2, 4)[$/2 .. $].equal!equal([[5, 6], [9, 10]]));
8442
8443 // reverse
8444 assert(iota(1, 12).slide(2, 4).retro.equal!equal([[9, 10], [5, 6], [1, 2]]));
8445 }
8446
8447 // test different sliceable ranges
8448 @safe pure nothrow unittest
8449 {
8450 import std.algorithm.comparison : equal;
8451 import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy;
8452 import std.meta : AliasSeq;
8453
8454 struct SliceableRange(Range, Flag!"withOpDollar" withOpDollar = No.withOpDollar,
8455 Flag!"withInfiniteness" withInfiniteness = No.withInfiniteness)
8456 {
8457 Range arr = 10.iota.array; // similar to DummyRange
saveSliceableRange8458 @property auto save() { return typeof(this)(arr); }
frontSliceableRange8459 @property auto front() { return arr[0]; }
popFrontSliceableRange8460 void popFront() { arr.popFront(); }
opSliceSliceableRange8461 auto opSlice(size_t i, size_t j)
8462 {
8463 // subslices can't be infinite
8464 return SliceableRange!(Range, withOpDollar, No.withInfiniteness)(arr[i .. j]);
8465 }
8466
8467 static if (withInfiniteness)
8468 {
8469 enum empty = false;
8470 }
8471 else
8472 {
emptySliceableRange8473 @property bool empty() { return arr.empty; }
lengthSliceableRange8474 @property auto length() { return arr.length; }
8475 }
8476
8477 static if (withOpDollar)
8478 {
8479 static if (withInfiniteness)
8480 {
8481 struct Dollar {}
opDollarSliceableRange8482 Dollar opDollar() const { return Dollar.init; }
8483
8484 //Slice to dollar
opSliceSliceableRange8485 typeof(this) opSlice(size_t lower, Dollar)
8486 {
8487 return typeof(this)(arr[lower .. $]);
8488 }
8489
8490 }
8491 else
8492 {
8493 alias opDollar = length;
8494 }
8495 }
8496 }
8497
8498 alias T = int[];
8499
8500 alias SliceableDummyRanges = AliasSeq!(
8501 DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random, T),
8502 DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random, T),
8503 SliceableRange!(T, No.withOpDollar, No.withInfiniteness),
8504 SliceableRange!(T, Yes.withOpDollar, No.withInfiniteness),
8505 SliceableRange!(T, Yes.withOpDollar, Yes.withInfiniteness),
8506 );
8507
8508 foreach (Range; AliasSeq!SliceableDummyRanges)
8509 {
8510 Range r;
8511 r.arr = 10.iota.array; // for clarity
8512
8513 static assert(isForwardRange!Range);
8514 enum hasSliceToEnd = hasSlicing!Range && is(typeof(Range.init[0 .. $]) == Range);
8515
8516 assert(r.slide(2)[0].equal([0, 1]));
8517 assert(r.slide(2)[1].equal([1, 2]));
8518
8519 // saveable
8520 auto s = r.slide(2);
8521 assert(s[0 .. 2].equal!equal([[0, 1], [1, 2]]));
8522 s.save.popFront;
8523 assert(s[0 .. 2].equal!equal([[0, 1], [1, 2]]));
8524
8525 assert(r.slide(3)[1 .. 3].equal!equal([[1, 2, 3], [2, 3, 4]]));
8526 }
8527
8528 alias SliceableDummyRangesWithoutInfinity = AliasSeq!(
8529 DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random, T),
8530 DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random, T),
8531 SliceableRange!(T, No.withOpDollar, No.withInfiniteness),
8532 SliceableRange!(T, Yes.withOpDollar, No.withInfiniteness),
8533 );
8534
8535 foreach (Range; AliasSeq!SliceableDummyRangesWithoutInfinity)
8536 {
8537 static assert(hasSlicing!Range);
8538 static assert(hasLength!Range);
8539
8540 Range r;
8541 r.arr = 10.iota.array; // for clarity
8542
8543 assert(r.slide!(No.withFewerElements)(6).equal!equal(
8544 [[0, 1, 2, 3, 4, 5], [1, 2, 3, 4, 5, 6], [2, 3, 4, 5, 6, 7],
8545 [3, 4, 5, 6, 7, 8], [4, 5, 6, 7, 8, 9]]
8546 ));
8547 assert(r.slide!(No.withFewerElements)(16).empty);
8548
8549 assert(r.slide(4)[0 .. $].equal(r.slide(4)));
8550 assert(r.slide(2)[$/2 .. $].equal!equal([[4, 5], [5, 6], [6, 7], [7, 8], [8, 9]]));
8551 assert(r.slide(2)[$ .. $].empty);
8552
8553 assert(r.slide(3).retro.equal!equal(
8554 [[7, 8, 9], [6, 7, 8], [5, 6, 7], [4, 5, 6], [3, 4, 5], [2, 3, 4], [1, 2, 3], [0, 1, 2]]
8555 ));
8556 }
8557
8558 // separate checks for infinity
8559 auto infIndex = SliceableRange!(T, No.withOpDollar, Yes.withInfiniteness)([0, 1, 2, 3]);
8560 assert(infIndex.slide(2)[0].equal([0, 1]));
8561 assert(infIndex.slide(2)[1].equal([1, 2]));
8562
8563 auto infDollar = SliceableRange!(T, Yes.withOpDollar, Yes.withInfiniteness)();
8564 assert(infDollar.slide(2)[1 .. $].front.equal([1, 2]));
8565 assert(infDollar.slide(4)[0 .. $].front.equal([0, 1, 2, 3]));
8566 assert(infDollar.slide(4)[2 .. $].front.equal([2, 3, 4, 5]));
8567 }
8568
OnlyResult(T,size_t arity)8569 private struct OnlyResult(T, size_t arity)
8570 {
8571 private this(Values...)(auto ref Values values)
8572 {
8573 this.data = [values];
8574 this.backIndex = arity;
8575 }
8576
8577 bool empty() @property
8578 {
8579 return frontIndex >= backIndex;
8580 }
8581
8582 T front() @property
8583 {
8584 assert(!empty, "Attempting to fetch the front of an empty Only range");
8585 return data[frontIndex];
8586 }
8587
8588 void popFront()
8589 {
8590 assert(!empty, "Attempting to popFront an empty Only range");
8591 ++frontIndex;
8592 }
8593
8594 T back() @property
8595 {
8596 assert(!empty, "Attempting to fetch the back of an empty Only range");
8597 return data[backIndex - 1];
8598 }
8599
8600 void popBack()
8601 {
8602 assert(!empty, "Attempting to popBack an empty Only range");
8603 --backIndex;
8604 }
8605
8606 OnlyResult save() @property
8607 {
8608 return this;
8609 }
8610
8611 size_t length() const @property
8612 {
8613 return backIndex - frontIndex;
8614 }
8615
8616 alias opDollar = length;
8617
8618 T opIndex(size_t idx)
8619 {
8620 // when i + idx points to elements popped
8621 // with popBack
8622 assert(idx < length, "Attempting to fetch an out of bounds index from an Only range");
8623 return data[frontIndex + idx];
8624 }
8625
8626 OnlyResult opSlice()
8627 {
8628 return this;
8629 }
8630
8631 OnlyResult opSlice(size_t from, size_t to)
8632 {
8633 OnlyResult result = this;
8634 result.frontIndex += from;
8635 result.backIndex = this.frontIndex + to;
8636 assert(
8637 from <= to,
8638 "Attempting to slice an Only range with a larger first argument than the second."
8639 );
8640 assert(
8641 to <= length,
8642 "Attempting to slice using an out of bounds index on an Only range"
8643 );
8644 return result;
8645 }
8646
8647 private size_t frontIndex = 0;
8648 private size_t backIndex = 0;
8649
8650 // @@@BUG@@@ 10643
8651 version (none)
8652 {
8653 import std.traits : hasElaborateAssign;
8654 static if (hasElaborateAssign!T)
8655 private T[arity] data;
8656 else
8657 private T[arity] data = void;
8658 }
8659 else
8660 private T[arity] data;
8661 }
8662
8663 // Specialize for single-element results
8664 private struct OnlyResult(T, size_t arity : 1)
8665 {
frontOnlyResult8666 @property T front()
8667 {
8668 assert(!empty, "Attempting to fetch the front of an empty Only range");
8669 return _value;
8670 }
backOnlyResult8671 @property T back()
8672 {
8673 assert(!empty, "Attempting to fetch the back of an empty Only range");
8674 return _value;
8675 }
emptyOnlyResult8676 @property bool empty() const { return _empty; }
lengthOnlyResult8677 @property size_t length() const { return !_empty; }
saveOnlyResult8678 @property auto save() { return this; }
popFrontOnlyResult8679 void popFront()
8680 {
8681 assert(!_empty, "Attempting to popFront an empty Only range");
8682 _empty = true;
8683 }
popBackOnlyResult8684 void popBack()
8685 {
8686 assert(!_empty, "Attempting to popBack an empty Only range");
8687 _empty = true;
8688 }
8689 alias opDollar = length;
8690
thisOnlyResult8691 private this()(auto ref T value)
8692 {
8693 this._value = value;
8694 this._empty = false;
8695 }
8696
opIndexOnlyResult8697 T opIndex(size_t i)
8698 {
8699 assert(!_empty && i == 0, "Attempting to fetch an out of bounds index from an Only range");
8700 return _value;
8701 }
8702
opSliceOnlyResult8703 OnlyResult opSlice()
8704 {
8705 return this;
8706 }
8707
opSliceOnlyResult8708 OnlyResult opSlice(size_t from, size_t to)
8709 {
8710 assert(
8711 from <= to,
8712 "Attempting to slice an Only range with a larger first argument than the second."
8713 );
8714 assert(
8715 to <= length,
8716 "Attempting to slice using an out of bounds index on an Only range"
8717 );
8718 OnlyResult copy = this;
8719 copy._empty = _empty || from == to;
8720 return copy;
8721 }
8722
8723 private Unqual!T _value;
8724 private bool _empty = true;
8725 }
8726
8727 // Specialize for the empty range
8728 private struct OnlyResult(T, size_t arity : 0)
8729 {
8730 private static struct EmptyElementType {}
8731
empty()8732 bool empty() @property { return true; }
length()8733 size_t length() const @property { return 0; }
8734 alias opDollar = length;
front()8735 EmptyElementType front() @property { assert(false); }
popFront()8736 void popFront() { assert(false); }
back()8737 EmptyElementType back() @property { assert(false); }
popBack()8738 void popBack() { assert(false); }
save()8739 OnlyResult save() @property { return this; }
8740
opIndex(size_t i)8741 EmptyElementType opIndex(size_t i)
8742 {
8743 assert(false);
8744 }
8745
opSlice()8746 OnlyResult opSlice() { return this; }
8747
opSlice(size_t from,size_t to)8748 OnlyResult opSlice(size_t from, size_t to)
8749 {
8750 assert(from == 0 && to == 0);
8751 return this;
8752 }
8753 }
8754
8755 /**
8756 Assemble $(D values) into a range that carries all its
8757 elements in-situ.
8758
8759 Useful when a single value or multiple disconnected values
8760 must be passed to an algorithm expecting a range, without
8761 having to perform dynamic memory allocation.
8762
8763 As copying the range means copying all elements, it can be
8764 safely returned from functions. For the same reason, copying
8765 the returned range may be expensive for a large number of arguments.
8766
8767 Params:
8768 values = the values to assemble together
8769
8770 Returns:
8771 A `RandomAccessRange` of the assembled values.
8772
8773 See_Also: $(LREF chain) to chain ranges
8774 */
8775 auto only(Values...)(auto ref Values values)
8776 if (!is(CommonType!Values == void) || Values.length == 0)
8777 {
8778 return OnlyResult!(CommonType!Values, Values.length)(values);
8779 }
8780
8781 ///
8782 @safe unittest
8783 {
8784 import std.algorithm.comparison : equal;
8785 import std.algorithm.iteration : filter, joiner, map;
8786 import std.algorithm.searching : findSplitBefore;
8787 import std.uni : isUpper;
8788
8789 assert(equal(only('♡'), "♡"));
8790 assert([1, 2, 3, 4].findSplitBefore(only(3))[0] == [1, 2]);
8791
8792 assert(only("one", "two", "three").joiner(" ").equal("one two three"));
8793
8794 string title = "The D Programming Language";
8795 assert(title
8796 .filter!isUpper // take the upper case letters
8797 .map!only // make each letter its own range
8798 .joiner(".") // join the ranges together lazily
8799 .equal("T.D.P.L"));
8800 }
8801
8802 @safe unittest
8803 {
8804 // Verify that the same common type and same arity
8805 // results in the same template instantiation
8806 static assert(is(typeof(only(byte.init, int.init)) ==
8807 typeof(only(int.init, byte.init))));
8808
8809 static assert(is(typeof(only((const(char)[]).init, string.init)) ==
8810 typeof(only((const(char)[]).init, (const(char)[]).init))));
8811 }
8812
8813 // Tests the zero-element result
8814 @safe unittest
8815 {
8816 import std.algorithm.comparison : equal;
8817
8818 auto emptyRange = only();
8819
8820 alias EmptyRange = typeof(emptyRange);
8821 static assert(isInputRange!EmptyRange);
8822 static assert(isForwardRange!EmptyRange);
8823 static assert(isBidirectionalRange!EmptyRange);
8824 static assert(isRandomAccessRange!EmptyRange);
8825 static assert(hasLength!EmptyRange);
8826 static assert(hasSlicing!EmptyRange);
8827
8828 assert(emptyRange.empty);
8829 assert(emptyRange.length == 0);
8830 assert(emptyRange.equal(emptyRange[]));
8831 assert(emptyRange.equal(emptyRange.save));
8832 assert(emptyRange[0 .. 0].equal(emptyRange));
8833 }
8834
8835 // Tests the single-element result
8836 @safe unittest
8837 {
8838 import std.algorithm.comparison : equal;
8839 import std.typecons : tuple;
8840 foreach (x; tuple(1, '1', 1.0, "1", [1]))
8841 {
8842 auto a = only(x);
8843 typeof(x)[] e = [];
8844 assert(a.front == x);
8845 assert(a.back == x);
8846 assert(!a.empty);
8847 assert(a.length == 1);
8848 assert(equal(a, a[]));
8849 assert(equal(a, a[0 .. 1]));
8850 assert(equal(a[0 .. 0], e));
8851 assert(equal(a[1 .. 1], e));
8852 assert(a[0] == x);
8853
8854 auto b = a.save;
8855 assert(equal(a, b));
8856 a.popFront();
8857 assert(a.empty && a.length == 0 && a[].empty);
8858 b.popBack();
8859 assert(b.empty && b.length == 0 && b[].empty);
8860
8861 alias A = typeof(a);
8862 static assert(isInputRange!A);
8863 static assert(isForwardRange!A);
8864 static assert(isBidirectionalRange!A);
8865 static assert(isRandomAccessRange!A);
8866 static assert(hasLength!A);
8867 static assert(hasSlicing!A);
8868 }
8869
8870 auto imm = only!(immutable int)(1);
8871 immutable int[] imme = [];
8872 assert(imm.front == 1);
8873 assert(imm.back == 1);
8874 assert(!imm.empty);
8875 assert(imm.init.empty); // Issue 13441
8876 assert(imm.length == 1);
8877 assert(equal(imm, imm[]));
8878 assert(equal(imm, imm[0 .. 1]));
8879 assert(equal(imm[0 .. 0], imme));
8880 assert(equal(imm[1 .. 1], imme));
8881 assert(imm[0] == 1);
8882 }
8883
8884 // Tests multiple-element results
8885 @safe unittest
8886 {
8887 import std.algorithm.comparison : equal;
8888 import std.algorithm.iteration : joiner;
8889 import std.meta : AliasSeq;
8890 static assert(!__traits(compiles, only(1, "1")));
8891
8892 auto nums = only!(byte, uint, long)(1, 2, 3);
8893 static assert(is(ElementType!(typeof(nums)) == long));
8894 assert(nums.length == 3);
8895
8896 foreach (i; 0 .. 3)
8897 assert(nums[i] == i + 1);
8898
8899 auto saved = nums.save;
8900
8901 foreach (i; 1 .. 4)
8902 {
8903 assert(nums.front == nums[0]);
8904 assert(nums.front == i);
8905 nums.popFront();
8906 assert(nums.length == 3 - i);
8907 }
8908
8909 assert(nums.empty);
8910
8911 assert(saved.equal(only(1, 2, 3)));
8912 assert(saved.equal(saved[]));
8913 assert(saved[0 .. 1].equal(only(1)));
8914 assert(saved[0 .. 2].equal(only(1, 2)));
8915 assert(saved[0 .. 3].equal(saved));
8916 assert(saved[1 .. 3].equal(only(2, 3)));
8917 assert(saved[2 .. 3].equal(only(3)));
8918 assert(saved[0 .. 0].empty);
8919 assert(saved[3 .. 3].empty);
8920
8921 alias data = AliasSeq!("one", "two", "three", "four");
8922 static joined =
8923 ["one two", "one two three", "one two three four"];
8924 string[] joinedRange = joined;
8925
8926 foreach (argCount; AliasSeq!(2, 3, 4))
8927 {
8928 auto values = only(data[0 .. argCount]);
8929 alias Values = typeof(values);
8930 static assert(is(ElementType!Values == string));
8931 static assert(isInputRange!Values);
8932 static assert(isForwardRange!Values);
8933 static assert(isBidirectionalRange!Values);
8934 static assert(isRandomAccessRange!Values);
8935 static assert(hasSlicing!Values);
8936 static assert(hasLength!Values);
8937
8938 assert(values.length == argCount);
8939 assert(values[0 .. $].equal(values[0 .. values.length]));
8940 assert(values.joiner(" ").equal(joinedRange.front));
8941 joinedRange.popFront();
8942 }
8943
8944 assert(saved.retro.equal(only(3, 2, 1)));
8945 assert(saved.length == 3);
8946
8947 assert(saved.back == 3);
8948 saved.popBack();
8949 assert(saved.length == 2);
8950 assert(saved.back == 2);
8951
8952 assert(saved.front == 1);
8953 saved.popFront();
8954 assert(saved.length == 1);
8955 assert(saved.front == 2);
8956
8957 saved.popBack();
8958 assert(saved.empty);
8959
8960 auto imm = only!(immutable int, immutable int)(42, 24);
8961 alias Imm = typeof(imm);
8962 static assert(is(ElementType!Imm == immutable(int)));
8963 assert(!imm.empty);
8964 assert(imm.init.empty); // Issue 13441
8965 assert(imm.front == 42);
8966 imm.popFront();
8967 assert(imm.front == 24);
8968 imm.popFront();
8969 assert(imm.empty);
8970
8971 static struct Test { int* a; }
8972 immutable(Test) test;
8973 cast(void) only(test, test); // Works with mutable indirection
8974 }
8975
8976 /**
8977 Iterate over `range` with an attached index variable.
8978
8979 Each element is a $(REF Tuple, std,typecons) containing the index
8980 and the element, in that order, where the index member is named $(D index)
8981 and the element member is named `value`.
8982
8983 The index starts at `start` and is incremented by one on every iteration.
8984
8985 Overflow:
8986 If `range` has length, then it is an error to pass a value for `start`
8987 so that `start + range.length` is bigger than `Enumerator.max`, thus
8988 it is ensured that overflow cannot happen.
8989
8990 If `range` does not have length, and `popFront` is called when
8991 `front.index == Enumerator.max`, the index will overflow and
8992 continue from `Enumerator.min`.
8993
8994 Params:
8995 range = the input range to attach indexes to
8996 start = the number to start the index counter from
8997
8998 Returns:
8999 At minimum, an input range. All other range primitives are given in the
9000 resulting range if `range` has them. The exceptions are the bidirectional
9001 primitives, which are propagated only if `range` has length.
9002
9003 Example:
9004 Useful for using $(D foreach) with an index loop variable:
9005 ----
9006 import std.stdio : stdin, stdout;
9007 import std.range : enumerate;
9008
9009 foreach (lineNum, line; stdin.byLine().enumerate(1))
9010 stdout.writefln("line #%s: %s", lineNum, line);
9011 ----
9012 */
9013 auto enumerate(Enumerator = size_t, Range)(Range range, Enumerator start = 0)
9014 if (isIntegral!Enumerator && isInputRange!Range)
9015 in
9016 {
9017 static if (hasLength!Range)
9018 {
9019 // TODO: core.checkedint supports mixed signedness yet?
9020 import core.checkedint : adds, addu;
9021 import std.conv : ConvException, to;
9022 import std.traits : isSigned, Largest, Signed;
9023
9024 alias LengthType = typeof(range.length);
9025 bool overflow;
9026 static if (isSigned!Enumerator && isSigned!LengthType)
9027 auto result = adds(start, range.length, overflow);
9028 else static if (isSigned!Enumerator)
9029 {
9030 Largest!(Enumerator, Signed!LengthType) signedLength;
9031 try signedLength = to!(typeof(signedLength))(range.length);
9032 catch (ConvException)
9033 overflow = true;
9034 catch (Exception)
9035 assert(false);
9036
9037 auto result = adds(start, signedLength, overflow);
9038 }
9039 else
9040 {
9041 static if (isSigned!LengthType)
9042 assert(range.length >= 0);
9043 auto result = addu(start, range.length, overflow);
9044 }
9045
9046 assert(!overflow && result <= Enumerator.max);
9047 }
9048 }
9049 body
9050 {
9051 // TODO: Relax isIntegral!Enumerator to allow user-defined integral types
9052 static struct Result
9053 {
9054 import std.typecons : Tuple;
9055
9056 private:
9057 alias ElemType = Tuple!(Enumerator, "index", ElementType!Range, "value");
9058 Range range;
9059 Enumerator index;
9060
9061 public:
frontResult9062 ElemType front() @property
9063 {
9064 assert(!range.empty, "Attempting to fetch the front of an empty enumerate");
9065 return typeof(return)(index, range.front);
9066 }
9067
9068 static if (isInfinite!Range)
9069 enum bool empty = false;
9070 else
9071 {
emptyResult9072 bool empty() @property
9073 {
9074 return range.empty;
9075 }
9076 }
9077
popFrontResult9078 void popFront()
9079 {
9080 assert(!range.empty, "Attempting to popFront an empty enumerate");
9081 range.popFront();
9082 ++index; // When !hasLength!Range, overflow is expected
9083 }
9084
9085 static if (isForwardRange!Range)
9086 {
saveResult9087 Result save() @property
9088 {
9089 return typeof(return)(range.save, index);
9090 }
9091 }
9092
9093 static if (hasLength!Range)
9094 {
lengthResult9095 size_t length() @property
9096 {
9097 return range.length;
9098 }
9099
9100 alias opDollar = length;
9101
9102 static if (isBidirectionalRange!Range)
9103 {
backResult9104 ElemType back() @property
9105 {
9106 assert(!range.empty, "Attempting to fetch the back of an empty enumerate");
9107 return typeof(return)(cast(Enumerator)(index + range.length - 1), range.back);
9108 }
9109
popBackResult9110 void popBack()
9111 {
9112 assert(!range.empty, "Attempting to popBack an empty enumerate");
9113 range.popBack();
9114 }
9115 }
9116 }
9117
9118 static if (isRandomAccessRange!Range)
9119 {
opIndexResult9120 ElemType opIndex(size_t i)
9121 {
9122 return typeof(return)(cast(Enumerator)(index + i), range[i]);
9123 }
9124 }
9125
9126 static if (hasSlicing!Range)
9127 {
9128 static if (hasLength!Range)
9129 {
opSliceResult9130 Result opSlice(size_t i, size_t j)
9131 {
9132 return typeof(return)(range[i .. j], cast(Enumerator)(index + i));
9133 }
9134 }
9135 else
9136 {
9137 static struct DollarToken {}
9138 enum opDollar = DollarToken.init;
9139
opSliceResult9140 Result opSlice(size_t i, DollarToken)
9141 {
9142 return typeof(return)(range[i .. $], cast(Enumerator)(index + i));
9143 }
9144
opSliceResult9145 auto opSlice(size_t i, size_t j)
9146 {
9147 return this[i .. $].takeExactly(j - 1);
9148 }
9149 }
9150 }
9151 }
9152
9153 return Result(range, start);
9154 }
9155
9156 /// Can start enumeration from a negative position:
9157 pure @safe nothrow unittest
9158 {
9159 import std.array : assocArray;
9160 import std.range : enumerate;
9161
9162 bool[int] aa = true.repeat(3).enumerate(-1).assocArray();
9163 assert(aa[-1]);
9164 assert(aa[0]);
9165 assert(aa[1]);
9166 }
9167
9168 pure @safe nothrow unittest
9169 {
9170 import std.internal.test.dummyrange : AllDummyRanges;
9171 import std.meta : AliasSeq;
9172 import std.typecons : tuple;
9173
9174 static struct HasSlicing
9175 {
frontHasSlicing9176 typeof(this) front() @property { return typeof(this).init; }
emptyHasSlicing9177 bool empty() @property { return true; }
popFrontHasSlicing9178 void popFront() {}
9179
opSliceHasSlicing9180 typeof(this) opSlice(size_t, size_t)
9181 {
9182 return typeof(this)();
9183 }
9184 }
9185
9186 foreach (DummyType; AliasSeq!(AllDummyRanges, HasSlicing))
9187 {
9188 alias R = typeof(enumerate(DummyType.init));
9189 static assert(isInputRange!R);
9190 static assert(isForwardRange!R == isForwardRange!DummyType);
9191 static assert(isRandomAccessRange!R == isRandomAccessRange!DummyType);
9192 static assert(!hasAssignableElements!R);
9193
9194 static if (hasLength!DummyType)
9195 {
9196 static assert(hasLength!R);
9197 static assert(isBidirectionalRange!R ==
9198 isBidirectionalRange!DummyType);
9199 }
9200
9201 static assert(hasSlicing!R == hasSlicing!DummyType);
9202 }
9203
9204 static immutable values = ["zero", "one", "two", "three"];
9205 auto enumerated = values[].enumerate();
9206 assert(!enumerated.empty);
9207 assert(enumerated.front == tuple(0, "zero"));
9208 assert(enumerated.back == tuple(3, "three"));
9209
9210 typeof(enumerated) saved = enumerated.save;
9211 saved.popFront();
9212 assert(enumerated.front == tuple(0, "zero"));
9213 assert(saved.front == tuple(1, "one"));
9214 assert(saved.length == enumerated.length - 1);
9215 saved.popBack();
9216 assert(enumerated.back == tuple(3, "three"));
9217 assert(saved.back == tuple(2, "two"));
9218 saved.popFront();
9219 assert(saved.front == tuple(2, "two"));
9220 assert(saved.back == tuple(2, "two"));
9221 saved.popFront();
9222 assert(saved.empty);
9223
9224 size_t control = 0;
foreach(i,v;enumerated)9225 foreach (i, v; enumerated)
9226 {
9227 static assert(is(typeof(i) == size_t));
9228 static assert(is(typeof(v) == typeof(values[0])));
9229 assert(i == control);
9230 assert(v == values[i]);
9231 assert(tuple(i, v) == enumerated[i]);
9232 ++control;
9233 }
9234
9235 assert(enumerated[0 .. $].front == tuple(0, "zero"));
9236 assert(enumerated[$ - 1 .. $].front == tuple(3, "three"));
9237
9238 foreach (i; 0 .. 10)
9239 {
9240 auto shifted = values[0 .. 2].enumerate(i);
9241 assert(shifted.front == tuple(i, "zero"));
9242 assert(shifted[0] == shifted.front);
9243
9244 auto next = tuple(i + 1, "one");
9245 assert(shifted[1] == next);
9246 shifted.popFront();
9247 assert(shifted.front == next);
9248 shifted.popFront();
9249 assert(shifted.empty);
9250 }
9251
9252 foreach (T; AliasSeq!(ubyte, byte, uint, int))
9253 {
9254 auto inf = 42.repeat().enumerate(T.max);
9255 alias Inf = typeof(inf);
9256 static assert(isInfinite!Inf);
9257 static assert(hasSlicing!Inf);
9258
9259 // test overflow
9260 assert(inf.front == tuple(T.max, 42));
9261 inf.popFront();
9262 assert(inf.front == tuple(T.min, 42));
9263
9264 // test slicing
9265 inf = inf[42 .. $];
9266 assert(inf.front == tuple(T.min + 42, 42));
9267 auto window = inf[0 .. 2];
9268 assert(window.length == 1);
9269 assert(window.front == inf.front);
9270 window.popFront();
9271 assert(window.empty);
9272 }
9273 }
9274
9275 pure @safe unittest
9276 {
9277 import std.algorithm.comparison : equal;
9278 import std.meta : AliasSeq;
9279 static immutable int[] values = [0, 1, 2, 3, 4];
9280 foreach (T; AliasSeq!(ubyte, ushort, uint, ulong))
9281 {
9282 auto enumerated = values.enumerate!T();
9283 static assert(is(typeof(enumerated.front.index) == T));
9284 assert(enumerated.equal(values[].zip(values)));
9285
9286 foreach (T i; 0 .. 5)
9287 {
9288 auto subset = values[cast(size_t) i .. $];
9289 auto offsetEnumerated = subset.enumerate(i);
9290 static assert(is(typeof(enumerated.front.index) == T));
9291 assert(offsetEnumerated.equal(subset.zip(subset)));
9292 }
9293 }
9294 }
9295
version(none)9296 version (none) // @@@BUG@@@ 10939
9297 {
9298 // Re-enable (or remove) if 10939 is resolved.
9299 /+pure+/ @safe unittest // Impure because of std.conv.to
9300 {
9301 import core.exception : RangeError;
9302 import std.exception : assertNotThrown, assertThrown;
9303 import std.meta : AliasSeq;
9304
9305 static immutable values = [42];
9306
9307 static struct SignedLengthRange
9308 {
9309 immutable(int)[] _values = values;
9310
9311 int front() @property { assert(false); }
9312 bool empty() @property { assert(false); }
9313 void popFront() { assert(false); }
9314
9315 int length() @property
9316 {
9317 return cast(int)_values.length;
9318 }
9319 }
9320
9321 SignedLengthRange svalues;
9322 foreach (Enumerator; AliasSeq!(ubyte, byte, ushort, short, uint, int, ulong, long))
9323 {
9324 assertThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max));
9325 assertNotThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max - values.length));
9326 assertThrown!RangeError(values[].enumerate!Enumerator(Enumerator.max - values.length + 1));
9327
9328 assertThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max));
9329 assertNotThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max - values.length));
9330 assertThrown!RangeError(svalues.enumerate!Enumerator(Enumerator.max - values.length + 1));
9331 }
9332
9333 foreach (Enumerator; AliasSeq!(byte, short, int))
9334 {
9335 assertThrown!RangeError(repeat(0, uint.max).enumerate!Enumerator());
9336 }
9337
9338 assertNotThrown!RangeError(repeat(0, uint.max).enumerate!long());
9339 }
9340 }
9341
9342 /**
9343 Returns true if $(D fn) accepts variables of type T1 and T2 in any order.
9344 The following code should compile:
9345 ---
9346 T1 foo();
9347 T2 bar();
9348
9349 fn(foo(), bar());
9350 fn(bar(), foo());
9351 ---
9352 */
isTwoWayCompatible(alias fn,T1,T2)9353 template isTwoWayCompatible(alias fn, T1, T2)
9354 {
9355 enum isTwoWayCompatible = is(typeof( (){
9356 T1 foo();
9357 T2 bar();
9358
9359 fn(foo(), bar());
9360 fn(bar(), foo());
9361 }
9362 ));
9363 }
9364
9365
9366 /**
9367 Policy used with the searching primitives $(D lowerBound), $(D
9368 upperBound), and $(D equalRange) of $(LREF SortedRange) below.
9369 */
9370 enum SearchPolicy
9371 {
9372 /**
9373 Searches in a linear fashion.
9374 */
9375 linear,
9376
9377 /**
9378 Searches with a step that is grows linearly (1, 2, 3,...)
9379 leading to a quadratic search schedule (indexes tried are 0, 1,
9380 3, 6, 10, 15, 21, 28,...) Once the search overshoots its target,
9381 the remaining interval is searched using binary search. The
9382 search is completed in $(BIGOH sqrt(n)) time. Use it when you
9383 are reasonably confident that the value is around the beginning
9384 of the range.
9385 */
9386 trot,
9387
9388 /**
9389 Performs a $(LINK2 https://en.wikipedia.org/wiki/Exponential_search,
9390 galloping search algorithm), i.e. searches
9391 with a step that doubles every time, (1, 2, 4, 8, ...) leading
9392 to an exponential search schedule (indexes tried are 0, 1, 3,
9393 7, 15, 31, 63,...) Once the search overshoots its target, the
9394 remaining interval is searched using binary search. A value is
9395 found in $(BIGOH log(n)) time.
9396 */
9397 gallop,
9398
9399 /**
9400 Searches using a classic interval halving policy. The search
9401 starts in the middle of the range, and each search step cuts
9402 the range in half. This policy finds a value in $(BIGOH log(n))
9403 time but is less cache friendly than $(D gallop) for large
9404 ranges. The $(D binarySearch) policy is used as the last step
9405 of $(D trot), $(D gallop), $(D trotBackwards), and $(D
9406 gallopBackwards) strategies.
9407 */
9408 binarySearch,
9409
9410 /**
9411 Similar to $(D trot) but starts backwards. Use it when
9412 confident that the value is around the end of the range.
9413 */
9414 trotBackwards,
9415
9416 /**
9417 Similar to $(D gallop) but starts backwards. Use it when
9418 confident that the value is around the end of the range.
9419 */
9420 gallopBackwards
9421 }
9422
9423 /**
9424 Represents a sorted range. In addition to the regular range
9425 primitives, supports additional operations that take advantage of the
9426 ordering, such as merge and binary search. To obtain a $(D
9427 SortedRange) from an unsorted range $(D r), use
9428 $(REF sort, std,algorithm,sorting) which sorts $(D r) in place and returns the
9429 corresponding $(D SortedRange). To construct a $(D SortedRange) from a range
9430 $(D r) that is known to be already sorted, use $(LREF assumeSorted) described
9431 below.
9432 */
9433 struct SortedRange(Range, alias pred = "a < b")
9434 if (isInputRange!Range)
9435 {
9436 import std.functional : binaryFun;
9437
9438 private alias predFun = binaryFun!pred;
geq(L,R)9439 private bool geq(L, R)(L lhs, R rhs)
9440 {
9441 return !predFun(lhs, rhs);
9442 }
gt(L,R)9443 private bool gt(L, R)(L lhs, R rhs)
9444 {
9445 return predFun(rhs, lhs);
9446 }
9447 private Range _input;
9448
9449 // Undocummented because a clearer way to invoke is by calling
9450 // assumeSorted.
this(Range input)9451 this(Range input)
9452 out
9453 {
9454 // moved out of the body as a workaround for Issue 12661
9455 dbgVerifySorted();
9456 }
9457 body
9458 {
9459 this._input = input;
9460 }
9461
9462 // Assertion only.
dbgVerifySorted()9463 private void dbgVerifySorted()
9464 {
9465 if (!__ctfe)
9466 debug
9467 {
9468 static if (isRandomAccessRange!Range && hasLength!Range)
9469 {
9470 import core.bitop : bsr;
9471 import std.algorithm.sorting : isSorted;
9472
9473 // Check the sortedness of the input
9474 if (this._input.length < 2) return;
9475
9476 immutable size_t msb = bsr(this._input.length) + 1;
9477 assert(msb > 0 && msb <= this._input.length);
9478 immutable step = this._input.length / msb;
9479 auto st = stride(this._input, step);
9480
9481 assert(isSorted!pred(st), "Range is not sorted");
9482 }
9483 }
9484 }
9485
9486 /// Range primitives.
empty()9487 @property bool empty() //const
9488 {
9489 return this._input.empty;
9490 }
9491
9492 /// Ditto
9493 static if (isForwardRange!Range)
save()9494 @property auto save()
9495 {
9496 // Avoid the constructor
9497 typeof(this) result = this;
9498 result._input = _input.save;
9499 return result;
9500 }
9501
9502 /// Ditto
front()9503 @property auto ref front()
9504 {
9505 return _input.front;
9506 }
9507
9508 /// Ditto
popFront()9509 void popFront()
9510 {
9511 _input.popFront();
9512 }
9513
9514 /// Ditto
9515 static if (isBidirectionalRange!Range)
9516 {
back()9517 @property auto ref back()
9518 {
9519 return _input.back;
9520 }
9521
9522 /// Ditto
popBack()9523 void popBack()
9524 {
9525 _input.popBack();
9526 }
9527 }
9528
9529 /// Ditto
9530 static if (isRandomAccessRange!Range)
opIndex(size_t i)9531 auto ref opIndex(size_t i)
9532 {
9533 return _input[i];
9534 }
9535
9536 /// Ditto
9537 static if (hasSlicing!Range)
opSlice(size_t a,size_t b)9538 auto opSlice(size_t a, size_t b)
9539 {
9540 assert(
9541 a <= b,
9542 "Attempting to slice a SortedRange with a larger first argument than the second."
9543 );
9544 typeof(this) result = this;
9545 result._input = _input[a .. b];// skip checking
9546 return result;
9547 }
9548
9549 /// Ditto
9550 static if (hasLength!Range)
9551 {
length()9552 @property size_t length() //const
9553 {
9554 return _input.length;
9555 }
9556 alias opDollar = length;
9557 }
9558
9559 /**
9560 Releases the controlled range and returns it.
9561 */
release()9562 auto release()
9563 {
9564 import std.algorithm.mutation : move;
9565 return move(_input);
9566 }
9567
9568 // Assuming a predicate "test" that returns 0 for a left portion
9569 // of the range and then 1 for the rest, returns the index at
9570 // which the first 1 appears. Used internally by the search routines.
9571 private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v)
9572 if (sp == SearchPolicy.binarySearch && isRandomAccessRange!Range && hasLength!Range)
9573 {
9574 size_t first = 0, count = _input.length;
9575 while (count > 0)
9576 {
9577 immutable step = count / 2, it = first + step;
9578 if (!test(_input[it], v))
9579 {
9580 first = it + 1;
9581 count -= step + 1;
9582 }
9583 else
9584 {
9585 count = step;
9586 }
9587 }
9588 return first;
9589 }
9590
9591 // Specialization for trot and gallop
9592 private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v)
9593 if ((sp == SearchPolicy.trot || sp == SearchPolicy.gallop)
9594 && isRandomAccessRange!Range)
9595 {
9596 if (empty || test(front, v)) return 0;
9597 immutable count = length;
9598 if (count == 1) return 1;
9599 size_t below = 0, above = 1, step = 2;
9600 while (!test(_input[above], v))
9601 {
9602 // Still too small, update below and increase gait
9603 below = above;
9604 immutable next = above + step;
9605 if (next >= count)
9606 {
9607 // Overshot - the next step took us beyond the end. So
9608 // now adjust next and simply exit the loop to do the
9609 // binary search thingie.
9610 above = count;
9611 break;
9612 }
9613 // Still in business, increase step and continue
9614 above = next;
9615 static if (sp == SearchPolicy.trot)
9616 ++step;
9617 else
9618 step <<= 1;
9619 }
9620 return below + this[below .. above].getTransitionIndex!(
9621 SearchPolicy.binarySearch, test, V)(v);
9622 }
9623
9624 // Specialization for trotBackwards and gallopBackwards
9625 private size_t getTransitionIndex(SearchPolicy sp, alias test, V)(V v)
9626 if ((sp == SearchPolicy.trotBackwards || sp == SearchPolicy.gallopBackwards)
9627 && isRandomAccessRange!Range)
9628 {
9629 immutable count = length;
9630 if (empty || !test(back, v)) return count;
9631 if (count == 1) return 0;
9632 size_t below = count - 2, above = count - 1, step = 2;
9633 while (test(_input[below], v))
9634 {
9635 // Still too large, update above and increase gait
9636 above = below;
9637 if (below < step)
9638 {
9639 // Overshot - the next step took us beyond the end. So
9640 // now adjust next and simply fall through to do the
9641 // binary search thingie.
9642 below = 0;
9643 break;
9644 }
9645 // Still in business, increase step and continue
9646 below -= step;
9647 static if (sp == SearchPolicy.trot)
9648 ++step;
9649 else
9650 step <<= 1;
9651 }
9652 return below + this[below .. above].getTransitionIndex!(
9653 SearchPolicy.binarySearch, test, V)(v);
9654 }
9655
9656 // lowerBound
9657 /**
9658 This function uses a search with policy $(D sp) to find the
9659 largest left subrange on which $(D pred(x, value)) is $(D true) for
9660 all $(D x) (e.g., if $(D pred) is "less than", returns the portion of
9661 the range with elements strictly smaller than $(D value)). The search
9662 schedule and its complexity are documented in
9663 $(LREF SearchPolicy). See also STL's
9664 $(HTTP sgi.com/tech/stl/lower_bound.html, lower_bound).
9665 */
9666 auto lowerBound(SearchPolicy sp = SearchPolicy.binarySearch, V)(V value)
9667 if (isTwoWayCompatible!(predFun, ElementType!Range, V)
9668 && hasSlicing!Range)
9669 {
9670 return this[0 .. getTransitionIndex!(sp, geq)(value)];
9671 }
9672
9673 ///
9674 @safe unittest
9675 {
9676 import std.algorithm.comparison : equal;
9677 auto a = assumeSorted([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]);
9678 auto p = a.lowerBound(4);
9679 assert(equal(p, [ 0, 1, 2, 3 ]));
9680 }
9681
9682 // upperBound
9683 /**
9684 This function searches with policy $(D sp) to find the largest right
9685 subrange on which $(D pred(value, x)) is $(D true) for all $(D x)
9686 (e.g., if $(D pred) is "less than", returns the portion of the range
9687 with elements strictly greater than $(D value)). The search schedule
9688 and its complexity are documented in $(LREF SearchPolicy).
9689
9690 For ranges that do not offer random access, $(D SearchPolicy.linear)
9691 is the only policy allowed (and it must be specified explicitly lest it exposes
9692 user code to unexpected inefficiencies). For random-access searches, all
9693 policies are allowed, and $(D SearchPolicy.binarySearch) is the default.
9694
9695 See_Also: STL's $(HTTP sgi.com/tech/stl/lower_bound.html,upper_bound).
9696 */
9697 auto upperBound(SearchPolicy sp = SearchPolicy.binarySearch, V)(V value)
9698 if (isTwoWayCompatible!(predFun, ElementType!Range, V))
9699 {
9700 static assert(hasSlicing!Range || sp == SearchPolicy.linear,
9701 "Specify SearchPolicy.linear explicitly for "
9702 ~ typeof(this).stringof);
9703 static if (sp == SearchPolicy.linear)
9704 {
9705 for (; !_input.empty && !predFun(value, _input.front);
9706 _input.popFront())
9707 {
9708 }
9709 return this;
9710 }
9711 else
9712 {
9713 return this[getTransitionIndex!(sp, gt)(value) .. length];
9714 }
9715 }
9716
9717 ///
9718 @safe unittest
9719 {
9720 import std.algorithm.comparison : equal;
9721 auto a = assumeSorted([ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]);
9722 auto p = a.upperBound(3);
9723 assert(equal(p, [4, 4, 5, 6]));
9724 }
9725
9726
9727 // equalRange
9728 /**
9729 Returns the subrange containing all elements $(D e) for which both $(D
9730 pred(e, value)) and $(D pred(value, e)) evaluate to $(D false) (e.g.,
9731 if $(D pred) is "less than", returns the portion of the range with
9732 elements equal to $(D value)). Uses a classic binary search with
9733 interval halving until it finds a value that satisfies the condition,
9734 then uses $(D SearchPolicy.gallopBackwards) to find the left boundary
9735 and $(D SearchPolicy.gallop) to find the right boundary. These
9736 policies are justified by the fact that the two boundaries are likely
9737 to be near the first found value (i.e., equal ranges are relatively
9738 small). Completes the entire search in $(BIGOH log(n)) time. See also
9739 STL's $(HTTP sgi.com/tech/stl/equal_range.html, equal_range).
9740 */
9741 auto equalRange(V)(V value)
9742 if (isTwoWayCompatible!(predFun, ElementType!Range, V)
9743 && isRandomAccessRange!Range)
9744 {
9745 size_t first = 0, count = _input.length;
9746 while (count > 0)
9747 {
9748 immutable step = count / 2;
9749 auto it = first + step;
9750 if (predFun(_input[it], value))
9751 {
9752 // Less than value, bump left bound up
9753 first = it + 1;
9754 count -= step + 1;
9755 }
9756 else if (predFun(value, _input[it]))
9757 {
9758 // Greater than value, chop count
9759 count = step;
9760 }
9761 else
9762 {
9763 // Equal to value, do binary searches in the
9764 // leftover portions
9765 // Gallop towards the left end as it's likely nearby
9766 immutable left = first
9767 + this[first .. it]
9768 .lowerBound!(SearchPolicy.gallopBackwards)(value).length;
9769 first += count;
9770 // Gallop towards the right end as it's likely nearby
9771 immutable right = first
9772 - this[it + 1 .. first]
9773 .upperBound!(SearchPolicy.gallop)(value).length;
9774 return this[left .. right];
9775 }
9776 }
9777 return this.init;
9778 }
9779
9780 ///
9781 @safe unittest
9782 {
9783 import std.algorithm.comparison : equal;
9784 auto a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
9785 auto r = a.assumeSorted.equalRange(3);
9786 assert(equal(r, [ 3, 3, 3 ]));
9787 }
9788
9789 // trisect
9790 /**
9791 Returns a tuple $(D r) such that $(D r[0]) is the same as the result
9792 of $(D lowerBound(value)), $(D r[1]) is the same as the result of $(D
9793 equalRange(value)), and $(D r[2]) is the same as the result of $(D
9794 upperBound(value)). The call is faster than computing all three
9795 separately. Uses a search schedule similar to $(D
9796 equalRange). Completes the entire search in $(BIGOH log(n)) time.
9797 */
9798 auto trisect(V)(V value)
9799 if (isTwoWayCompatible!(predFun, ElementType!Range, V)
9800 && isRandomAccessRange!Range && hasLength!Range)
9801 {
9802 import std.typecons : tuple;
9803 size_t first = 0, count = _input.length;
9804 while (count > 0)
9805 {
9806 immutable step = count / 2;
9807 auto it = first + step;
9808 if (predFun(_input[it], value))
9809 {
9810 // Less than value, bump left bound up
9811 first = it + 1;
9812 count -= step + 1;
9813 }
9814 else if (predFun(value, _input[it]))
9815 {
9816 // Greater than value, chop count
9817 count = step;
9818 }
9819 else
9820 {
9821 // Equal to value, do binary searches in the
9822 // leftover portions
9823 // Gallop towards the left end as it's likely nearby
9824 immutable left = first
9825 + this[first .. it]
9826 .lowerBound!(SearchPolicy.gallopBackwards)(value).length;
9827 first += count;
9828 // Gallop towards the right end as it's likely nearby
9829 immutable right = first
9830 - this[it + 1 .. first]
9831 .upperBound!(SearchPolicy.gallop)(value).length;
9832 return tuple(this[0 .. left], this[left .. right],
9833 this[right .. length]);
9834 }
9835 }
9836 // No equal element was found
9837 return tuple(this[0 .. first], this.init, this[first .. length]);
9838 }
9839
9840 ///
9841 @safe unittest
9842 {
9843 import std.algorithm.comparison : equal;
9844 auto a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
9845 auto r = assumeSorted(a).trisect(3);
9846 assert(equal(r[0], [ 1, 2 ]));
9847 assert(equal(r[1], [ 3, 3, 3 ]));
9848 assert(equal(r[2], [ 4, 4, 5, 6 ]));
9849 }
9850
9851 // contains
9852 /**
9853 Returns $(D true) if and only if $(D value) can be found in $(D
9854 range), which is assumed to be sorted. Performs $(BIGOH log(r.length))
9855 evaluations of $(D pred). See also STL's $(HTTP
9856 sgi.com/tech/stl/binary_search.html, binary_search).
9857 */
9858
9859 bool contains(V)(V value)
9860 if (isRandomAccessRange!Range)
9861 {
9862 if (empty) return false;
9863 immutable i = getTransitionIndex!(SearchPolicy.binarySearch, geq)(value);
9864 if (i >= length) return false;
9865 return !predFun(value, _input[i]);
9866 }
9867
9868 // groupBy
9869 /**
9870 Returns a range of subranges of elements that are equivalent according to the
9871 sorting relation.
9872 */
groupBy()9873 auto groupBy()()
9874 {
9875 import std.algorithm.iteration : chunkBy;
9876 return _input.chunkBy!((a, b) => !predFun(a, b) && !predFun(b, a));
9877 }
9878 }
9879
9880 ///
9881 @safe unittest
9882 {
9883 import std.algorithm.sorting : sort;
9884 auto a = [ 1, 2, 3, 42, 52, 64 ];
9885 auto r = assumeSorted(a);
9886 assert(r.contains(3));
9887 assert(!r.contains(32));
9888 auto r1 = sort!"a > b"(a);
9889 assert(r1.contains(3));
9890 assert(!r1.contains(32));
9891 assert(r1.release() == [ 64, 52, 42, 3, 2, 1 ]);
9892 }
9893
9894 /**
9895 $(D SortedRange) could accept ranges weaker than random-access, but it
9896 is unable to provide interesting functionality for them. Therefore,
9897 $(D SortedRange) is currently restricted to random-access ranges.
9898
9899 No copy of the original range is ever made. If the underlying range is
9900 changed concurrently with its corresponding $(D SortedRange) in ways
9901 that break its sorted-ness, $(D SortedRange) will work erratically.
9902 */
9903 @safe unittest
9904 {
9905 import std.algorithm.mutation : swap;
9906 auto a = [ 1, 2, 3, 42, 52, 64 ];
9907 auto r = assumeSorted(a);
9908 assert(r.contains(42));
9909 swap(a[3], a[5]); // illegal to break sortedness of original range
9910 assert(!r.contains(42)); // passes although it shouldn't
9911 }
9912
9913 @safe unittest
9914 {
9915 import std.algorithm.comparison : equal;
9916
9917 auto a = [ 10, 20, 30, 30, 30, 40, 40, 50, 60 ];
9918 auto r = assumeSorted(a).trisect(30);
9919 assert(equal(r[0], [ 10, 20 ]));
9920 assert(equal(r[1], [ 30, 30, 30 ]));
9921 assert(equal(r[2], [ 40, 40, 50, 60 ]));
9922
9923 r = assumeSorted(a).trisect(35);
9924 assert(equal(r[0], [ 10, 20, 30, 30, 30 ]));
9925 assert(r[1].empty);
9926 assert(equal(r[2], [ 40, 40, 50, 60 ]));
9927 }
9928
9929 @safe unittest
9930 {
9931 import std.algorithm.comparison : equal;
9932 auto a = [ "A", "AG", "B", "E", "F" ];
9933 auto r = assumeSorted!"cmp(a,b) < 0"(a).trisect("B"w);
9934 assert(equal(r[0], [ "A", "AG" ]));
9935 assert(equal(r[1], [ "B" ]));
9936 assert(equal(r[2], [ "E", "F" ]));
9937 r = assumeSorted!"cmp(a,b) < 0"(a).trisect("A"d);
9938 assert(r[0].empty);
9939 assert(equal(r[1], [ "A" ]));
9940 assert(equal(r[2], [ "AG", "B", "E", "F" ]));
9941 }
9942
9943 @safe unittest
9944 {
9945 import std.algorithm.comparison : equal;
test(SearchPolicy pol)9946 static void test(SearchPolicy pol)()
9947 {
9948 auto a = [ 1, 2, 3, 42, 52, 64 ];
9949 auto r = assumeSorted(a);
9950 assert(equal(r.lowerBound(42), [1, 2, 3]));
9951
9952 assert(equal(r.lowerBound!(pol)(42), [1, 2, 3]));
9953 assert(equal(r.lowerBound!(pol)(41), [1, 2, 3]));
9954 assert(equal(r.lowerBound!(pol)(43), [1, 2, 3, 42]));
9955 assert(equal(r.lowerBound!(pol)(51), [1, 2, 3, 42]));
9956 assert(equal(r.lowerBound!(pol)(3), [1, 2]));
9957 assert(equal(r.lowerBound!(pol)(55), [1, 2, 3, 42, 52]));
9958 assert(equal(r.lowerBound!(pol)(420), a));
9959 assert(equal(r.lowerBound!(pol)(0), a[0 .. 0]));
9960
9961 assert(equal(r.upperBound!(pol)(42), [52, 64]));
9962 assert(equal(r.upperBound!(pol)(41), [42, 52, 64]));
9963 assert(equal(r.upperBound!(pol)(43), [52, 64]));
9964 assert(equal(r.upperBound!(pol)(51), [52, 64]));
9965 assert(equal(r.upperBound!(pol)(53), [64]));
9966 assert(equal(r.upperBound!(pol)(55), [64]));
9967 assert(equal(r.upperBound!(pol)(420), a[0 .. 0]));
9968 assert(equal(r.upperBound!(pol)(0), a));
9969 }
9970
9971 test!(SearchPolicy.trot)();
9972 test!(SearchPolicy.gallop)();
9973 test!(SearchPolicy.trotBackwards)();
9974 test!(SearchPolicy.gallopBackwards)();
9975 test!(SearchPolicy.binarySearch)();
9976 }
9977
9978 @safe unittest
9979 {
9980 // Check for small arrays
9981 int[] a;
9982 auto r = assumeSorted(a);
9983 a = [ 1 ];
9984 r = assumeSorted(a);
9985 a = [ 1, 2 ];
9986 r = assumeSorted(a);
9987 a = [ 1, 2, 3 ];
9988 r = assumeSorted(a);
9989 }
9990
9991 @safe unittest
9992 {
9993 import std.algorithm.mutation : swap;
9994 auto a = [ 1, 2, 3, 42, 52, 64 ];
9995 auto r = assumeSorted(a);
9996 assert(r.contains(42));
9997 swap(a[3], a[5]); // illegal to break sortedness of original range
9998 assert(!r.contains(42)); // passes although it shouldn't
9999 }
10000
10001 @safe unittest
10002 {
10003 immutable(int)[] arr = [ 1, 2, 3 ];
10004 auto s = assumeSorted(arr);
10005 }
10006
10007 @system unittest
10008 {
10009 import std.algorithm.comparison : equal;
10010 int[] arr = [100, 101, 102, 200, 201, 300];
10011 auto s = assumeSorted!((a, b) => a / 100 < b / 100)(arr);
10012 assert(s.groupBy.equal!equal([[100, 101, 102], [200, 201], [300]]));
10013 }
10014
10015 // Test on an input range
10016 @system unittest
10017 {
10018 import std.conv : text;
10019 import std.file : exists, remove, tempDir;
10020 import std.path : buildPath;
10021 import std.stdio : File;
10022 import std.uuid : randomUUID;
10023 auto name = buildPath(tempDir(), "test.std.range.line-" ~ text(__LINE__) ~
10024 "." ~ randomUUID().toString());
10025 auto f = File(name, "w");
10026 scope(exit) if (exists(name)) remove(name);
10027 // write a sorted range of lines to the file
10028 f.write("abc\ndef\nghi\njkl");
10029 f.close();
10030 f.open(name, "r");
10031 auto r = assumeSorted(f.byLine());
10032 auto r1 = r.upperBound!(SearchPolicy.linear)("def");
10033 assert(r1.front == "ghi", r1.front);
10034 f.close();
10035 }
10036
10037 /**
10038 Assumes $(D r) is sorted by predicate $(D pred) and returns the
10039 corresponding $(D SortedRange!(pred, R)) having $(D r) as support. To
10040 keep the checking costs low, the cost is $(BIGOH 1) in release mode
10041 (no checks for sorted-ness are performed). In debug mode, a few random
10042 elements of $(D r) are checked for sorted-ness. The size of the sample
10043 is proportional $(BIGOH log(r.length)). That way, checking has no
10044 effect on the complexity of subsequent operations specific to sorted
10045 ranges (such as binary search). The probability of an arbitrary
10046 unsorted range failing the test is very high (however, an
10047 almost-sorted range is likely to pass it). To check for sorted-ness at
10048 cost $(BIGOH n), use $(REF isSorted, std,algorithm,sorting).
10049 */
10050 auto assumeSorted(alias pred = "a < b", R)(R r)
10051 if (isInputRange!(Unqual!R))
10052 {
10053 return SortedRange!(Unqual!R, pred)(r);
10054 }
10055
10056 @safe unittest
10057 {
10058 import std.algorithm.comparison : equal;
10059 static assert(isRandomAccessRange!(SortedRange!(int[])));
10060 int[] a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ];
10061 auto p = assumeSorted(a).lowerBound(4);
10062 assert(equal(p, [0, 1, 2, 3]));
10063 p = assumeSorted(a).lowerBound(5);
10064 assert(equal(p, [0, 1, 2, 3, 4]));
10065 p = assumeSorted(a).lowerBound(6);
10066 assert(equal(p, [ 0, 1, 2, 3, 4, 5]));
10067 p = assumeSorted(a).lowerBound(6.9);
10068 assert(equal(p, [ 0, 1, 2, 3, 4, 5, 6]));
10069 }
10070
10071 @safe unittest
10072 {
10073 import std.algorithm.comparison : equal;
10074 int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
10075 auto p = assumeSorted(a).upperBound(3);
10076 assert(equal(p, [4, 4, 5, 6 ]));
10077 p = assumeSorted(a).upperBound(4.2);
10078 assert(equal(p, [ 5, 6 ]));
10079 }
10080
10081 @safe unittest
10082 {
10083 import std.algorithm.comparison : equal;
10084 import std.conv : text;
10085
10086 int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
10087 auto p = assumeSorted(a).equalRange(3);
10088 assert(equal(p, [ 3, 3, 3 ]), text(p));
10089 p = assumeSorted(a).equalRange(4);
10090 assert(equal(p, [ 4, 4 ]), text(p));
10091 p = assumeSorted(a).equalRange(2);
10092 assert(equal(p, [ 2 ]));
10093 p = assumeSorted(a).equalRange(0);
10094 assert(p.empty);
10095 p = assumeSorted(a).equalRange(7);
10096 assert(p.empty);
10097 p = assumeSorted(a).equalRange(3.0);
10098 assert(equal(p, [ 3, 3, 3]));
10099 }
10100
10101 @safe unittest
10102 {
10103 int[] a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
10104 if (a.length)
10105 {
10106 auto b = a[a.length / 2];
10107 //auto r = sort(a);
10108 //assert(r.contains(b));
10109 }
10110 }
10111
10112 @safe unittest
10113 {
10114 auto a = [ 5, 7, 34, 345, 677 ];
10115 auto r = assumeSorted(a);
10116 a = null;
10117 r = assumeSorted(a);
10118 a = [ 1 ];
10119 r = assumeSorted(a);
10120 }
10121
10122 @system unittest
10123 {
10124 bool ok = true;
10125 try
10126 {
10127 auto r2 = assumeSorted([ 677, 345, 34, 7, 5 ]);
10128 debug ok = false;
10129 }
catch(Throwable)10130 catch (Throwable)
10131 {
10132 }
10133 assert(ok);
10134 }
10135
10136 // issue 15003
10137 @nogc @safe unittest
10138 {
10139 static immutable a = [1, 2, 3, 4];
10140 auto r = a.assumeSorted;
10141 }
10142
10143 /++
10144 Wrapper which effectively makes it possible to pass a range by reference.
10145 Both the original range and the RefRange will always have the exact same
10146 elements. Any operation done on one will affect the other. So, for instance,
10147 if it's passed to a function which would implicitly copy the original range
10148 if it were passed to it, the original range is $(I not) copied but is
10149 consumed as if it were a reference type.
10150
10151 Note:
10152 `save` works as normal and operates on a new _range, so if
10153 `save` is ever called on the `RefRange`, then no operations on the
10154 saved _range will affect the original.
10155
10156 Params:
10157 range = the range to construct the `RefRange` from
10158
10159 Returns:
10160 A `RefRange`. If the given _range is a class type
10161 (and thus is already a reference type), then the original
10162 range is returned rather than a `RefRange`.
10163 +/
10164 struct RefRange(R)
10165 if (isInputRange!R)
10166 {
10167 public:
10168
10169 /++ +/
this(R * range)10170 this(R* range) @safe pure nothrow
10171 {
10172 _range = range;
10173 }
10174
10175
10176 /++
10177 This does not assign the pointer of $(D rhs) to this $(D RefRange).
10178 Rather it assigns the range pointed to by $(D rhs) to the range pointed
10179 to by this $(D RefRange). This is because $(I any) operation on a
10180 $(D RefRange) is the same is if it occurred to the original range. The
10181 one exception is when a $(D RefRange) is assigned $(D null) either
10182 directly or because $(D rhs) is $(D null). In that case, $(D RefRange)
10183 no longer refers to the original range but is $(D null).
10184 +/
10185 auto opAssign(RefRange rhs)
10186 {
10187 if (_range && rhs._range)
10188 *_range = *rhs._range;
10189 else
10190 _range = rhs._range;
10191
10192 return this;
10193 }
10194
10195 /++ +/
10196 void opAssign(typeof(null) rhs)
10197 {
10198 _range = null;
10199 }
10200
10201
10202 /++
10203 A pointer to the wrapped range.
10204 +/
10205 @property inout(R*) ptr() @safe inout pure nothrow
10206 {
10207 return _range;
10208 }
10209
10210
10211 version (StdDdoc)
10212 {
10213 /++ +/
10214 @property auto front() {assert(0);}
10215 /++ Ditto +/
10216 @property auto front() const {assert(0);}
10217 /++ Ditto +/
10218 @property auto front(ElementType!R value) {assert(0);}
10219 }
10220 else
10221 {
10222 @property auto front()
10223 {
10224 return (*_range).front;
10225 }
10226
10227 static if (is(typeof((*(cast(const R*)_range)).front))) @property auto front() const
10228 {
10229 return (*_range).front;
10230 }
10231
10232 static if (is(typeof((*_range).front = (*_range).front))) @property auto front(ElementType!R value)
10233 {
10234 return (*_range).front = value;
10235 }
10236 }
10237
10238
10239 version (StdDdoc)
10240 {
10241 @property bool empty(); ///
10242 @property bool empty() const; ///Ditto
10243 }
10244 else static if (isInfinite!R)
10245 enum empty = false;
10246 else
10247 {
10248 @property bool empty()
10249 {
10250 return (*_range).empty;
10251 }
10252
10253 static if (is(typeof((*cast(const R*)_range).empty))) @property bool empty() const
10254 {
10255 return (*_range).empty;
10256 }
10257 }
10258
10259
10260 /++ +/
10261 void popFront()
10262 {
10263 return (*_range).popFront();
10264 }
10265
10266
10267 version (StdDdoc)
10268 {
10269 /++
10270 Only defined if $(D isForwardRange!R) is $(D true).
10271 +/
10272 @property auto save() {assert(0);}
10273 /++ Ditto +/
10274 @property auto save() const {assert(0);}
10275 /++ Ditto +/
10276 auto opSlice() {assert(0);}
10277 /++ Ditto +/
10278 auto opSlice() const {assert(0);}
10279 }
10280 else static if (isForwardRange!R)
10281 {
10282 import std.traits : isSafe;
10283 private alias S = typeof((*_range).save);
10284
10285 static if (is(typeof((*cast(const R*)_range).save)))
10286 private alias CS = typeof((*cast(const R*)_range).save);
10287
10288 static if (isSafe!((R* r) => (*r).save))
10289 {
10290 @property RefRange!S save() @trusted
10291 {
10292 mixin(_genSave());
10293 }
10294
10295 static if (is(typeof((*cast(const R*)_range).save))) @property RefRange!CS save() @trusted const
10296 {
10297 mixin(_genSave());
10298 }
10299 }
10300 else
10301 {
10302 @property RefRange!S save()
10303 {
10304 mixin(_genSave());
10305 }
10306
10307 static if (is(typeof((*cast(const R*)_range).save))) @property RefRange!CS save() const
10308 {
10309 mixin(_genSave());
10310 }
10311 }
10312
10313 auto opSlice()()
10314 {
10315 return save;
10316 }
10317
10318 auto opSlice()() const
10319 {
10320 return save;
10321 }
10322
10323 private static string _genSave() @safe pure nothrow
10324 {
10325 return `import std.conv : emplace;` ~
10326 `alias S = typeof((*_range).save);` ~
10327 `static assert(isForwardRange!S, S.stringof ~ " is not a forward range.");` ~
10328 `auto mem = new void[S.sizeof];` ~
10329 `emplace!S(mem, cast(S)(*_range).save);` ~
10330 `return RefRange!S(cast(S*) mem.ptr);`;
10331 }
10332
10333 static assert(isForwardRange!RefRange);
10334 }
10335
10336
10337 version (StdDdoc)
10338 {
10339 /++
10340 Only defined if $(D isBidirectionalRange!R) is $(D true).
10341 +/
10342 @property auto back() {assert(0);}
10343 /++ Ditto +/
10344 @property auto back() const {assert(0);}
10345 /++ Ditto +/
10346 @property auto back(ElementType!R value) {assert(0);}
10347 }
10348 else static if (isBidirectionalRange!R)
10349 {
10350 @property auto back()
10351 {
10352 return (*_range).back;
10353 }
10354
10355 static if (is(typeof((*(cast(const R*)_range)).back))) @property auto back() const
10356 {
10357 return (*_range).back;
10358 }
10359
10360 static if (is(typeof((*_range).back = (*_range).back))) @property auto back(ElementType!R value)
10361 {
10362 return (*_range).back = value;
10363 }
10364 }
10365
10366
10367 /++ Ditto +/
10368 static if (isBidirectionalRange!R) void popBack()
10369 {
10370 return (*_range).popBack();
10371 }
10372
10373
10374 version (StdDdoc)
10375 {
10376 /++
10377 Only defined if $(D isRandomAccesRange!R) is $(D true).
10378 +/
10379 auto ref opIndex(IndexType)(IndexType index) {assert(0);}
10380
10381 /++ Ditto +/
10382 auto ref opIndex(IndexType)(IndexType index) const {assert(0);}
10383 }
10384 else static if (isRandomAccessRange!R)
10385 {
10386 auto ref opIndex(IndexType)(IndexType index)
10387 if (is(typeof((*_range)[index])))
10388 {
10389 return (*_range)[index];
10390 }
10391
10392 auto ref opIndex(IndexType)(IndexType index) const
10393 if (is(typeof((*cast(const R*)_range)[index])))
10394 {
10395 return (*_range)[index];
10396 }
10397 }
10398
10399
10400 /++
10401 Only defined if $(D hasMobileElements!R) and $(D isForwardRange!R) are
10402 $(D true).
10403 +/
10404 static if (hasMobileElements!R && isForwardRange!R) auto moveFront()
10405 {
10406 return (*_range).moveFront();
10407 }
10408
10409
10410 /++
10411 Only defined if $(D hasMobileElements!R) and $(D isBidirectionalRange!R)
10412 are $(D true).
10413 +/
10414 static if (hasMobileElements!R && isBidirectionalRange!R) auto moveBack()
10415 {
10416 return (*_range).moveBack();
10417 }
10418
10419
10420 /++
10421 Only defined if $(D hasMobileElements!R) and $(D isRandomAccessRange!R)
10422 are $(D true).
10423 +/
10424 static if (hasMobileElements!R && isRandomAccessRange!R) auto moveAt(size_t index)
10425 {
10426 return (*_range).moveAt(index);
10427 }
10428
10429
10430 version (StdDdoc)
10431 {
10432 /++
10433 Only defined if $(D hasLength!R) is $(D true).
10434 +/
10435 @property auto length() {assert(0);}
10436
10437 /++ Ditto +/
10438 @property auto length() const {assert(0);}
10439
10440 /++ Ditto +/
10441 alias opDollar = length;
10442 }
10443 else static if (hasLength!R)
10444 {
10445 @property auto length()
10446 {
10447 return (*_range).length;
10448 }
10449
10450 static if (is(typeof((*cast(const R*)_range).length))) @property auto length() const
10451 {
10452 return (*_range).length;
10453 }
10454
10455 alias opDollar = length;
10456 }
10457
10458
10459 version (StdDdoc)
10460 {
10461 /++
10462 Only defined if $(D hasSlicing!R) is $(D true).
10463 +/
10464 auto opSlice(IndexType1, IndexType2)
10465 (IndexType1 begin, IndexType2 end) {assert(0);}
10466
10467 /++ Ditto +/
10468 auto opSlice(IndexType1, IndexType2)
10469 (IndexType1 begin, IndexType2 end) const {assert(0);}
10470 }
10471 else static if (hasSlicing!R)
10472 {
10473 private alias T = typeof((*_range)[1 .. 2]);
10474 static if (is(typeof((*cast(const R*)_range)[1 .. 2])))
10475 {
10476 private alias CT = typeof((*cast(const R*)_range)[1 .. 2]);
10477 }
10478
10479 RefRange!T opSlice(IndexType1, IndexType2)
10480 (IndexType1 begin, IndexType2 end)
10481 if (is(typeof((*_range)[begin .. end])))
10482 {
10483 mixin(_genOpSlice());
10484 }
10485
10486 RefRange!CT opSlice(IndexType1, IndexType2)
10487 (IndexType1 begin, IndexType2 end) const
10488 if (is(typeof((*cast(const R*)_range)[begin .. end])))
10489 {
10490 mixin(_genOpSlice());
10491 }
10492
10493 private static string _genOpSlice() @safe pure nothrow
10494 {
10495 return `import std.conv : emplace;` ~
10496 `alias S = typeof((*_range)[begin .. end]);` ~
10497 `static assert(hasSlicing!S, S.stringof ~ " is not sliceable.");` ~
10498 `auto mem = new void[S.sizeof];` ~
10499 `emplace!S(mem, cast(S)(*_range)[begin .. end]);` ~
10500 `return RefRange!S(cast(S*) mem.ptr);`;
10501 }
10502 }
10503
10504
10505 private:
10506
10507 R* _range;
10508 }
10509
10510 /// Basic Example
10511 @system unittest
10512 {
10513 import std.algorithm.searching : find;
10514 ubyte[] buffer = [1, 9, 45, 12, 22];
10515 auto found1 = find(buffer, 45);
10516 assert(found1 == [45, 12, 22]);
10517 assert(buffer == [1, 9, 45, 12, 22]);
10518
10519 auto wrapped1 = refRange(&buffer);
10520 auto found2 = find(wrapped1, 45);
10521 assert(*found2.ptr == [45, 12, 22]);
10522 assert(buffer == [45, 12, 22]);
10523
10524 auto found3 = find(wrapped1.save, 22);
10525 assert(*found3.ptr == [22]);
10526 assert(buffer == [45, 12, 22]);
10527
10528 string str = "hello world";
10529 auto wrappedStr = refRange(&str);
10530 assert(str.front == 'h');
10531 str.popFrontN(5);
10532 assert(str == " world");
10533 assert(wrappedStr.front == ' ');
10534 assert(*wrappedStr.ptr == " world");
10535 }
10536
10537 /// opAssign Example.
10538 @system unittest
10539 {
10540 ubyte[] buffer1 = [1, 2, 3, 4, 5];
10541 ubyte[] buffer2 = [6, 7, 8, 9, 10];
10542 auto wrapped1 = refRange(&buffer1);
10543 auto wrapped2 = refRange(&buffer2);
10544 assert(wrapped1.ptr is &buffer1);
10545 assert(wrapped2.ptr is &buffer2);
10546 assert(wrapped1.ptr !is wrapped2.ptr);
10547 assert(buffer1 != buffer2);
10548
10549 wrapped1 = wrapped2;
10550
10551 //Everything points to the same stuff as before.
10552 assert(wrapped1.ptr is &buffer1);
10553 assert(wrapped2.ptr is &buffer2);
10554 assert(wrapped1.ptr !is wrapped2.ptr);
10555
10556 //But buffer1 has changed due to the assignment.
10557 assert(buffer1 == [6, 7, 8, 9, 10]);
10558 assert(buffer2 == [6, 7, 8, 9, 10]);
10559
10560 buffer2 = [11, 12, 13, 14, 15];
10561
10562 //Everything points to the same stuff as before.
10563 assert(wrapped1.ptr is &buffer1);
10564 assert(wrapped2.ptr is &buffer2);
10565 assert(wrapped1.ptr !is wrapped2.ptr);
10566
10567 //But buffer2 has changed due to the assignment.
10568 assert(buffer1 == [6, 7, 8, 9, 10]);
10569 assert(buffer2 == [11, 12, 13, 14, 15]);
10570
10571 wrapped2 = null;
10572
10573 //The pointer changed for wrapped2 but not wrapped1.
10574 assert(wrapped1.ptr is &buffer1);
10575 assert(wrapped2.ptr is null);
10576 assert(wrapped1.ptr !is wrapped2.ptr);
10577
10578 //buffer2 is not affected by the assignment.
10579 assert(buffer1 == [6, 7, 8, 9, 10]);
10580 assert(buffer2 == [11, 12, 13, 14, 15]);
10581 }
10582
10583 @system unittest
10584 {
10585 import std.algorithm.iteration : filter;
10586 {
10587 ubyte[] buffer = [1, 2, 3, 4, 5];
10588 auto wrapper = refRange(&buffer);
10589 auto p = wrapper.ptr;
10590 auto f = wrapper.front;
10591 wrapper.front = f;
10592 auto e = wrapper.empty;
10593 wrapper.popFront();
10594 auto s = wrapper.save;
10595 auto b = wrapper.back;
10596 wrapper.back = b;
10597 wrapper.popBack();
10598 auto i = wrapper[0];
10599 wrapper.moveFront();
10600 wrapper.moveBack();
10601 wrapper.moveAt(0);
10602 auto l = wrapper.length;
10603 auto sl = wrapper[0 .. 1];
10604 assert(wrapper[0 .. $].length == buffer[0 .. $].length);
10605 }
10606
10607 {
10608 ubyte[] buffer = [1, 2, 3, 4, 5];
10609 const wrapper = refRange(&buffer);
10610 const p = wrapper.ptr;
10611 const f = wrapper.front;
10612 const e = wrapper.empty;
10613 const s = wrapper.save;
10614 const b = wrapper.back;
10615 const i = wrapper[0];
10616 const l = wrapper.length;
10617 const sl = wrapper[0 .. 1];
10618 }
10619
10620 {
10621 ubyte[] buffer = [1, 2, 3, 4, 5];
10622 auto filtered = filter!"true"(buffer);
10623 auto wrapper = refRange(&filtered);
10624 auto p = wrapper.ptr;
10625 auto f = wrapper.front;
10626 wrapper.front = f;
10627 auto e = wrapper.empty;
10628 wrapper.popFront();
10629 auto s = wrapper.save;
10630 wrapper.moveFront();
10631 }
10632
10633 {
10634 ubyte[] buffer = [1, 2, 3, 4, 5];
10635 auto filtered = filter!"true"(buffer);
10636 const wrapper = refRange(&filtered);
10637 const p = wrapper.ptr;
10638
10639 //Cannot currently be const. filter needs to be updated to handle const.
10640 /+
10641 const f = wrapper.front;
10642 const e = wrapper.empty;
10643 const s = wrapper.save;
10644 +/
10645 }
10646
10647 {
10648 string str = "hello world";
10649 auto wrapper = refRange(&str);
10650 auto p = wrapper.ptr;
10651 auto f = wrapper.front;
10652 auto e = wrapper.empty;
10653 wrapper.popFront();
10654 auto s = wrapper.save;
10655 auto b = wrapper.back;
10656 wrapper.popBack();
10657 }
10658
10659 {
10660 // Issue 16534 - opDollar should be defined if the
10661 // wrapped range defines length.
10662 auto range = 10.iota.takeExactly(5);
10663 auto wrapper = refRange(&range);
10664 assert(wrapper.length == 5);
10665 assert(wrapper[0 .. $ - 1].length == 4);
10666 }
10667 }
10668
10669 //Test assignment.
10670 @system unittest
10671 {
10672 ubyte[] buffer1 = [1, 2, 3, 4, 5];
10673 ubyte[] buffer2 = [6, 7, 8, 9, 10];
10674 RefRange!(ubyte[]) wrapper1;
10675 RefRange!(ubyte[]) wrapper2 = refRange(&buffer2);
10676 assert(wrapper1.ptr is null);
10677 assert(wrapper2.ptr is &buffer2);
10678
10679 wrapper1 = refRange(&buffer1);
10680 assert(wrapper1.ptr is &buffer1);
10681
10682 wrapper1 = wrapper2;
10683 assert(wrapper1.ptr is &buffer1);
10684 assert(buffer1 == buffer2);
10685
10686 wrapper1 = RefRange!(ubyte[]).init;
10687 assert(wrapper1.ptr is null);
10688 assert(wrapper2.ptr is &buffer2);
10689 assert(buffer1 == buffer2);
10690 assert(buffer1 == [6, 7, 8, 9, 10]);
10691
10692 wrapper2 = null;
10693 assert(wrapper2.ptr is null);
10694 assert(buffer2 == [6, 7, 8, 9, 10]);
10695 }
10696
10697 @system unittest
10698 {
10699 import std.algorithm.comparison : equal;
10700 import std.algorithm.mutation : bringToFront;
10701 import std.algorithm.searching : commonPrefix, find, until;
10702 import std.algorithm.sorting : sort;
10703
10704 //Test that ranges are properly consumed.
10705 {
10706 int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
10707 auto wrapper = refRange(&arr);
10708
10709 assert(*find(wrapper, 41).ptr == [41, 3, 40, 4, 42, 9]);
10710 assert(arr == [41, 3, 40, 4, 42, 9]);
10711
10712 assert(*drop(wrapper, 2).ptr == [40, 4, 42, 9]);
10713 assert(arr == [40, 4, 42, 9]);
10714
10715 assert(equal(until(wrapper, 42), [40, 4]));
10716 assert(arr == [42, 9]);
10717
10718 assert(find(wrapper, 12).empty);
10719 assert(arr.empty);
10720 }
10721
10722 {
10723 string str = "Hello, world-like object.";
10724 auto wrapper = refRange(&str);
10725
10726 assert(*find(wrapper, "l").ptr == "llo, world-like object.");
10727 assert(str == "llo, world-like object.");
10728
10729 assert(equal(take(wrapper, 5), "llo, "));
10730 assert(str == "world-like object.");
10731 }
10732
10733 //Test that operating on saved ranges does not consume the original.
10734 {
10735 int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
10736 auto wrapper = refRange(&arr);
10737 auto saved = wrapper.save;
10738 saved.popFrontN(3);
10739 assert(*saved.ptr == [41, 3, 40, 4, 42, 9]);
10740 assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]);
10741 }
10742
10743 {
10744 string str = "Hello, world-like object.";
10745 auto wrapper = refRange(&str);
10746 auto saved = wrapper.save;
10747 saved.popFrontN(13);
10748 assert(*saved.ptr == "like object.");
10749 assert(str == "Hello, world-like object.");
10750 }
10751
10752 //Test that functions which use save work properly.
10753 {
10754 int[] arr = [1, 42];
10755 auto wrapper = refRange(&arr);
10756 assert(equal(commonPrefix(wrapper, [1, 27]), [1]));
10757 }
10758
10759 {
10760 int[] arr = [4, 5, 6, 7, 1, 2, 3];
10761 auto wrapper = refRange(&arr);
10762 assert(bringToFront(wrapper[0 .. 4], wrapper[4 .. arr.length]) == 3);
10763 assert(arr == [1, 2, 3, 4, 5, 6, 7]);
10764 }
10765
10766 //Test bidirectional functions.
10767 {
10768 int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
10769 auto wrapper = refRange(&arr);
10770
10771 assert(wrapper.back == 9);
10772 assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]);
10773
10774 wrapper.popBack();
10775 assert(arr == [1, 42, 2, 41, 3, 40, 4, 42]);
10776 }
10777
10778 {
10779 string str = "Hello, world-like object.";
10780 auto wrapper = refRange(&str);
10781
10782 assert(wrapper.back == '.');
10783 assert(str == "Hello, world-like object.");
10784
10785 wrapper.popBack();
10786 assert(str == "Hello, world-like object");
10787 }
10788
10789 //Test random access functions.
10790 {
10791 int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
10792 auto wrapper = refRange(&arr);
10793
10794 assert(wrapper[2] == 2);
10795 assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]);
10796
10797 assert(*wrapper[3 .. 6].ptr != null, [41, 3, 40]);
10798 assert(arr == [1, 42, 2, 41, 3, 40, 4, 42, 9]);
10799 }
10800
10801 //Test move functions.
10802 {
10803 int[] arr = [1, 42, 2, 41, 3, 40, 4, 42, 9];
10804 auto wrapper = refRange(&arr);
10805
10806 auto t1 = wrapper.moveFront();
10807 auto t2 = wrapper.moveBack();
10808 wrapper.front = t2;
10809 wrapper.back = t1;
10810 assert(arr == [9, 42, 2, 41, 3, 40, 4, 42, 1]);
10811
10812 sort(wrapper.save);
10813 assert(arr == [1, 2, 3, 4, 9, 40, 41, 42, 42]);
10814 }
10815 }
10816
10817 @system unittest
10818 {
10819 struct S
10820 {
10821 @property int front() @safe const pure nothrow { return 0; }
10822 enum bool empty = false;
10823 void popFront() @safe pure nothrow { }
10824 @property auto save() @safe pure nothrow { return this; }
10825 }
10826
10827 S s;
10828 auto wrapper = refRange(&s);
10829 static assert(isInfinite!(typeof(wrapper)));
10830 }
10831
10832 @system unittest
10833 {
10834 class C
10835 {
10836 @property int front() @safe const pure nothrow { return 0; }
10837 @property bool empty() @safe const pure nothrow { return false; }
10838 void popFront() @safe pure nothrow { }
10839 @property auto save() @safe pure nothrow { return this; }
10840 }
10841 static assert(isForwardRange!C);
10842
10843 auto c = new C;
10844 auto cWrapper = refRange(&c);
10845 static assert(is(typeof(cWrapper) == C));
10846 assert(cWrapper is c);
10847 }
10848
10849 @system unittest // issue 14373
10850 {
10851 static struct R
10852 {
10853 @property int front() {return 0;}
10854 void popFront() {empty = true;}
10855 bool empty = false;
10856 }
10857 R r;
10858 refRange(&r).popFront();
10859 assert(r.empty);
10860 }
10861
10862 @system unittest // issue 14575
10863 {
10864 struct R
10865 {
10866 Object front;
10867 alias back = front;
10868 bool empty = false;
10869 void popFront() {empty = true;}
10870 alias popBack = popFront;
10871 @property R save() {return this;}
10872 }
10873 static assert(isBidirectionalRange!R);
10874 R r;
10875 auto rr = refRange(&r);
10876
10877 struct R2
10878 {
10879 @property Object front() {return null;}
10880 @property const(Object) front() const {return null;}
10881 alias back = front;
10882 bool empty = false;
10883 void popFront() {empty = true;}
10884 alias popBack = popFront;
10885 @property R2 save() {return this;}
10886 }
10887 static assert(isBidirectionalRange!R2);
10888 R2 r2;
10889 auto rr2 = refRange(&r2);
10890 }
10891
10892 /// ditto
10893 auto refRange(R)(R* range)
10894 if (isInputRange!R)
10895 {
10896 static if (!is(R == class))
10897 return RefRange!R(range);
10898 else
10899 return *range;
10900 }
10901
10902 /*****************************************************************************/
10903
10904 @safe unittest // bug 9060
10905 {
10906 import std.algorithm.iteration : map, joiner, group;
10907 import std.algorithm.searching : until;
10908 // fix for std.algorithm
10909 auto r = map!(x => 0)([1]);
10910 chain(r, r);
10911 zip(r, r);
10912 roundRobin(r, r);
10913
10914 struct NRAR {
10915 typeof(r) input;
10916 @property empty() { return input.empty; }
10917 @property front() { return input.front; }
10918 void popFront() { input.popFront(); }
10919 @property save() { return NRAR(input.save); }
10920 }
10921 auto n1 = NRAR(r);
10922 cycle(n1); // non random access range version
10923
10924 assumeSorted(r);
10925
10926 // fix for std.range
10927 joiner([r], [9]);
10928
10929 struct NRAR2 {
10930 NRAR input;
10931 @property empty() { return true; }
10932 @property front() { return input; }
10933 void popFront() { }
10934 @property save() { return NRAR2(input.save); }
10935 }
10936 auto n2 = NRAR2(n1);
10937 joiner(n2);
10938
10939 group(r);
10940
10941 until(r, 7);
10942 static void foo(R)(R r) { until!(x => x > 7)(r); }
10943 foo(r);
10944 }
10945
10946 private struct Bitwise(R)
10947 if (isInputRange!R && isIntegral!(ElementType!R))
10948 {
10949 private:
10950 alias ElemType = ElementType!R;
10951 alias UnsignedElemType = Unsigned!ElemType;
10952
10953 R parent;
10954 enum bitsNum = ElemType.sizeof * 8;
10955 size_t maskPos = 1;
10956
10957 static if (isBidirectionalRange!R)
10958 {
10959 size_t backMaskPos = bitsNum;
10960 }
10961
10962 public:
10963 this()(auto ref R range)
10964 {
10965 parent = range;
10966 }
10967
10968 static if (isInfinite!R)
10969 {
10970 enum empty = false;
10971 }
10972 else
10973 {
10974 /**
10975 * Check if the range is empty
10976 *
10977 * Returns: a boolean true or false
10978 */
10979 bool empty()
10980 {
10981 static if (hasLength!R)
10982 {
10983 return length == 0;
10984 }
10985 else static if (isBidirectionalRange!R)
10986 {
10987 if (parent.empty)
10988 {
10989 return true;
10990 }
10991 else
10992 {
10993 /*
10994 If we have consumed the last element of the range both from
10995 the front and the back, then the masks positions will overlap
10996 */
10997 return parent.save.dropOne.empty && (maskPos > backMaskPos);
10998 }
10999 }
11000 else
11001 {
11002 /*
11003 If we consumed the last element of the range, but not all the
11004 bits in the last element
11005 */
11006 return parent.empty;
11007 }
11008 }
11009 }
11010
11011 bool front()
11012 {
11013 assert(!empty);
11014 return (parent.front & mask(maskPos)) != 0;
11015 }
11016
11017 void popFront()
11018 {
11019 assert(!empty);
11020 ++maskPos;
11021 if (maskPos > bitsNum)
11022 {
11023 parent.popFront;
11024 maskPos = 1;
11025 }
11026 }
11027
11028 static if (hasLength!R)
11029 {
11030 size_t length()
11031 {
11032 auto len = parent.length * bitsNum - (maskPos - 1);
11033 static if (isBidirectionalRange!R)
11034 {
11035 len -= bitsNum - backMaskPos;
11036 }
11037 return len;
11038 }
11039
11040 alias opDollar = length;
11041 }
11042
11043 static if (isForwardRange!R)
11044 {
11045 typeof(this) save()
11046 {
11047 auto result = this;
11048 result.parent = parent.save;
11049 return result;
11050 }
11051 }
11052
11053 static if (isBidirectionalRange!R)
11054 {
11055 bool back()
11056 {
11057 assert(!empty);
11058 return (parent.back & mask(backMaskPos)) != 0;
11059 }
11060
11061 void popBack()
11062 {
11063 assert(!empty);
11064 --backMaskPos;
11065 if (backMaskPos == 0)
11066 {
11067 parent.popBack;
11068 backMaskPos = bitsNum;
11069 }
11070 }
11071 }
11072
11073 static if (isRandomAccessRange!R)
11074 {
11075 /**
11076 Return the `n`th bit within the range
11077 */
11078 bool opIndex(size_t n)
11079 in
11080 {
11081 /*
11082 If it does not have the length property, it means that R is
11083 an infinite range
11084 */
11085 static if (hasLength!R)
11086 {
11087 assert(n < length, "Index out of bounds");
11088 }
11089 }
11090 body
11091 {
11092 immutable size_t remainingBits = bitsNum - maskPos + 1;
11093 // If n >= maskPos, then the bit sign will be 1, otherwise 0
11094 immutable sizediff_t sign = (remainingBits - n - 1) >> (sizediff_t.sizeof * 8 - 1);
11095 /*
11096 By truncating n with remainingBits bits we have skipped the
11097 remaining bits in parent[0], so we need to add 1 to elemIndex.
11098
11099 Because bitsNum is a power of 2, n / bitsNum == n >> bitsNum.bsf
11100 */
11101 import core.bitop : bsf;
11102 immutable size_t elemIndex = sign * (((n - remainingBits) >> bitsNum.bsf) + 1);
11103
11104 /*
11105 Since the indexing is from LSB to MSB, we need to index at the
11106 remainder of (n - remainingBits).
11107
11108 Because bitsNum is a power of 2, n % bitsNum == n & (bitsNum - 1)
11109 */
11110 immutable size_t elemMaskPos = (sign ^ 1) * (maskPos + n)
11111 + sign * (1 + ((n - remainingBits) & (bitsNum - 1)));
11112
11113 return (parent[elemIndex] & mask(elemMaskPos)) != 0;
11114 }
11115
11116 static if (hasAssignableElements!R)
11117 {
11118 /**
11119 Assigns `flag` to the `n`th bit within the range
11120 */
11121 void opIndexAssign(bool flag, size_t n)
11122 in
11123 {
11124 static if (hasLength!R)
11125 {
11126 assert(n < length, "Index out of bounds");
11127 }
11128 }
11129 body
11130 {
11131 import core.bitop : bsf;
11132
11133 immutable size_t remainingBits = bitsNum - maskPos + 1;
11134 immutable sizediff_t sign = (remainingBits - n - 1) >> (sizediff_t.sizeof * 8 - 1);
11135 immutable size_t elemIndex = sign * (((n - remainingBits) >> bitsNum.bsf) + 1);
11136 immutable size_t elemMaskPos = (sign ^ 1) * (maskPos + n)
11137 + sign * (1 + ((n - remainingBits) & (bitsNum - 1)));
11138
11139 auto elem = parent[elemIndex];
11140 auto elemMask = mask(elemMaskPos);
11141 parent[elemIndex] = cast(UnsignedElemType)(flag * (elem | elemMask)
11142 + (flag ^ 1) * (elem & ~elemMask));
11143 }
11144 }
11145
11146 Bitwise!R opSlice()
11147 {
11148 return this.save;
11149 }
11150
11151 Bitwise!R opSlice(size_t start, size_t end)
11152 in
11153 {
11154 assert(start < end, "Invalid bounds: end <= start");
11155 }
11156 body
11157 {
11158 import core.bitop : bsf;
11159
11160 size_t remainingBits = bitsNum - maskPos + 1;
11161 sizediff_t sign = (remainingBits - start - 1) >> (sizediff_t.sizeof * 8 - 1);
11162 immutable size_t startElemIndex = sign * (((start - remainingBits) >> bitsNum.bsf) + 1);
11163 immutable size_t startElemMaskPos = (sign ^ 1) * (maskPos + start)
11164 + sign * (1 + ((start - remainingBits) & (bitsNum - 1)));
11165
11166 immutable size_t sliceLen = end - start - 1;
11167 remainingBits = bitsNum - startElemMaskPos + 1;
11168 sign = (remainingBits - sliceLen - 1) >> (sizediff_t.sizeof * 8 - 1);
11169 immutable size_t endElemIndex = startElemIndex
11170 + sign * (((sliceLen - remainingBits) >> bitsNum.bsf) + 1);
11171 immutable size_t endElemMaskPos = (sign ^ 1) * (startElemMaskPos + sliceLen)
11172 + sign * (1 + ((sliceLen - remainingBits) & (bitsNum - 1)));
11173
11174 typeof(return) result;
11175 // Get the slice to be returned from the parent
11176 result.parent = (parent[startElemIndex .. endElemIndex + 1]).save;
11177 result.maskPos = startElemMaskPos;
11178 static if (isBidirectionalRange!R)
11179 {
11180 result.backMaskPos = endElemMaskPos;
11181 }
11182 return result;
11183 }
11184 }
11185
11186 private:
11187 auto mask(size_t maskPos)
11188 {
11189 return (1UL << (maskPos - 1UL));
11190 }
11191 }
11192
11193 /**
11194 Bitwise adapter over an integral type range. Consumes the range elements bit by
11195 bit, from the least significant bit to the most significant bit.
11196
11197 Params:
11198 R = an integral input range to iterate over
11199 range = range to consume bit by by
11200
11201 Returns:
11202 A `Bitwise` input range with propagated forward, bidirectional
11203 and random access capabilities
11204 */
11205 auto bitwise(R)(auto ref R range)
11206 if (isInputRange!R && isIntegral!(ElementType!R))
11207 {
11208 return Bitwise!R(range);
11209 }
11210
11211 ///
11212 @safe pure unittest
11213 {
11214 import std.algorithm.comparison : equal;
11215 import std.format : format;
11216
11217 // 00000011 00001001
11218 ubyte[] arr = [3, 9];
11219 auto r = arr.bitwise;
11220
11221 // iterate through it as with any other range
11222 assert(format("%(%d%)", r) == "1100000010010000");
11223 assert(format("%(%d%)", r.retro).equal("1100000010010000".retro));
11224
11225 auto r2 = r[5 .. $];
11226 // set a bit
11227 r[2] = 1;
11228 assert(arr[0] == 7);
11229 assert(r[5] == r2[0]);
11230 }
11231
11232 /// You can use bitwise to implement an uniform bool generator
11233 @safe unittest
11234 {
11235 import std.algorithm.comparison : equal;
11236 import std.random : rndGen;
11237
11238 auto rb = rndGen.bitwise;
11239 static assert(isInfinite!(typeof(rb)));
11240
11241 auto rb2 = rndGen.bitwise;
11242 // Don't forget that structs are passed by value
11243 assert(rb.take(10).equal(rb2.take(10)));
11244 }
11245
11246 // Test nogc inference
11247 @safe @nogc unittest
11248 {
11249 static ubyte[] arr = [3, 9];
11250 auto bw = arr.bitwise;
11251 auto bw2 = bw[];
11252 auto bw3 = bw[8 .. $];
11253 bw3[2] = true;
11254
11255 assert(arr[1] == 13);
11256 assert(bw[$ - 6]);
11257 assert(bw[$ - 6] == bw2[$ - 6]);
11258 assert(bw[$ - 6] == bw3[$ - 6]);
11259 }
11260
11261 // Test all range types over all integral types
11262 @safe pure nothrow unittest
11263 {
11264 import std.internal.test.dummyrange;
11265
11266 alias IntegralTypes = AliasSeq!(byte, ubyte, short, ushort, int, uint,
11267 long, ulong);
foreach(IntegralType;IntegralTypes)11268 foreach (IntegralType; IntegralTypes)
11269 {
11270 foreach (T; AllDummyRangesType!(IntegralType[]))
11271 {
11272 T a;
11273 auto bw = Bitwise!T(a);
11274
11275 static if (isForwardRange!T)
11276 {
11277 auto bwFwdSave = bw.save;
11278 }
11279
11280 static if (isBidirectionalRange!T)
11281 {
11282 auto bwBack = bw.save;
11283 auto bwBackSave = bw.save;
11284 }
11285
11286 static if (hasLength!T)
11287 {
11288 auto bwLength = bw.length;
11289 assert(bw.length == (IntegralType.sizeof * 8 * a.length));
11290 static if (isForwardRange!T)
11291 {
11292 assert(bw.length == bwFwdSave.length);
11293 }
11294 }
11295
11296 // Make sure front and back are not the mechanisms that modify the range
11297 long numCalls = 42;
11298 bool initialFrontValue;
11299
11300 if (!bw.empty)
11301 {
11302 initialFrontValue = bw.front;
11303 }
11304
11305 while (!bw.empty && (--numCalls))
11306 {
11307 bw.front;
11308 assert(bw.front == initialFrontValue);
11309 }
11310
11311 /*
11312 Check that empty works properly and that popFront does not get called
11313 more times than it should
11314 */
11315 numCalls = 0;
11316 while (!bw.empty)
11317 {
11318 ++numCalls;
11319
11320 static if (hasLength!T)
11321 {
11322 assert(bw.length == bwLength);
11323 --bwLength;
11324 }
11325
11326 static if (isForwardRange!T)
11327 {
11328 assert(bw.front == bwFwdSave.front);
11329 bwFwdSave.popFront();
11330 }
11331
11332 static if (isBidirectionalRange!T)
11333 {
11334 assert(bwBack.front == bwBackSave.front);
11335 bwBack.popBack();
11336 bwBackSave.popBack();
11337 }
11338 bw.popFront();
11339 }
11340
11341 auto rangeLen = numCalls / (IntegralType.sizeof * 8);
11342 assert(numCalls == (IntegralType.sizeof * 8 * rangeLen));
11343 assert(bw.empty);
11344 static if (isForwardRange!T)
11345 {
11346 assert(bwFwdSave.empty);
11347 }
11348
11349 static if (isBidirectionalRange!T)
11350 {
11351 assert(bwBack.empty);
11352 }
11353 }
11354 }
11355 }
11356
11357 // Test opIndex and opSlice
11358 @system unittest
11359 {
11360 alias IntegralTypes = AliasSeq!(byte, ubyte, short, ushort, int, uint,
11361 long, ulong);
foreach(IntegralType;IntegralTypes)11362 foreach (IntegralType; IntegralTypes)
11363 {
11364 size_t bitsNum = IntegralType.sizeof * 8;
11365
11366 auto first = cast(IntegralType)(1);
11367
11368 // 2 ^ (bitsNum - 1)
11369 auto second = cast(IntegralType)(cast(IntegralType)(1) << (bitsNum - 2));
11370
11371 IntegralType[] a = [first, second];
11372 auto bw = Bitwise!(IntegralType[])(a);
11373
11374 // Check against lsb of a[0]
11375 assert(bw[0] == true);
11376 // Check against msb - 1 of a[1]
11377 assert(bw[2 * bitsNum - 2] == true);
11378
11379 bw.popFront();
11380 assert(bw[2 * bitsNum - 3] == true);
11381
11382 import std.exception : assertThrown;
11383
11384 // Check out of bounds error
11385 assertThrown!Error(bw[2 * bitsNum - 1]);
11386
11387 bw[2] = true;
11388 assert(bw[2] == true);
11389 bw.popFront();
11390 assert(bw[1] == true);
11391
11392 auto bw2 = bw[0 .. $ - 5];
11393 auto bw3 = bw2[];
11394 assert(bw2.length == (bw.length - 5));
11395 assert(bw2.length == bw3.length);
11396 bw2.popFront();
11397 assert(bw2.length != bw3.length);
11398 }
11399 }
11400
11401 /*********************************
11402 * An OutputRange that discards the data it receives.
11403 */
11404 struct NullSink
11405 {
putNullSink11406 void put(E)(E){}
11407 }
11408
11409 ///
11410 @safe unittest
11411 {
11412 import std.algorithm.iteration : map;
11413 import std.algorithm.mutation : copy;
11414 [4, 5, 6].map!(x => x * 2).copy(NullSink()); // data is discarded
11415 }
11416
11417
11418 /++
11419
11420 Implements a "tee" style pipe, wrapping an input range so that elements of the
11421 range can be passed to a provided function or $(LREF OutputRange) as they are
11422 iterated over. This is useful for printing out intermediate values in a long
11423 chain of range code, performing some operation with side-effects on each call
11424 to $(D front) or $(D popFront), or diverting the elements of a range into an
11425 auxiliary $(LREF OutputRange).
11426
11427 It is important to note that as the resultant range is evaluated lazily,
11428 in the case of the version of $(D tee) that takes a function, the function
11429 will not actually be executed until the range is "walked" using functions
11430 that evaluate ranges, such as $(REF array, std,array) or
11431 $(REF fold, std,algorithm,iteration).
11432
11433 Params:
11434 pipeOnPop = If `Yes.pipeOnPop`, simply iterating the range without ever
11435 calling `front` is enough to have `tee` mirror elements to `outputRange` (or,
11436 respectively, `fun`). If `No.pipeOnPop`, only elements for which `front` does
11437 get called will be also sent to `outputRange`/`fun`.
11438 inputRange = The input range being passed through.
11439 outputRange = This range will receive elements of `inputRange` progressively
11440 as iteration proceeds.
11441 fun = This function will be called with elements of `inputRange`
11442 progressively as iteration proceeds.
11443
11444 Returns:
11445 An input range that offers the elements of `inputRange`. Regardless of
11446 whether `inputRange` is a more powerful range (forward, bidirectional etc),
11447 the result is always an input range. Reading this causes `inputRange` to be
11448 iterated and returns its elements in turn. In addition, the same elements
11449 will be passed to `outputRange` or `fun` as well.
11450
11451 See_Also: $(REF each, std,algorithm,iteration)
11452 +/
11453 auto tee(Flag!"pipeOnPop" pipeOnPop = Yes.pipeOnPop, R1, R2)(R1 inputRange, R2 outputRange)
11454 if (isInputRange!R1 && isOutputRange!(R2, ElementType!R1))
11455 {
11456 static struct Result
11457 {
11458 private R1 _input;
11459 private R2 _output;
11460 static if (!pipeOnPop)
11461 {
11462 private bool _frontAccessed;
11463 }
11464
11465 static if (hasLength!R1)
11466 {
lengthResult11467 @property auto length()
11468 {
11469 return _input.length;
11470 }
11471 }
11472
11473 static if (isInfinite!R1)
11474 {
11475 enum bool empty = false;
11476 }
11477 else
11478 {
emptyResult11479 @property bool empty() { return _input.empty; }
11480 }
11481
popFrontResult11482 void popFront()
11483 {
11484 assert(!_input.empty, "Attempting to popFront an empty tee");
11485 static if (pipeOnPop)
11486 {
11487 put(_output, _input.front);
11488 }
11489 else
11490 {
11491 _frontAccessed = false;
11492 }
11493 _input.popFront();
11494 }
11495
frontResult11496 @property auto ref front()
11497 {
11498 assert(!_input.empty, "Attempting to fetch the front of an empty tee");
11499 static if (!pipeOnPop)
11500 {
11501 if (!_frontAccessed)
11502 {
11503 _frontAccessed = true;
11504 put(_output, _input.front);
11505 }
11506 }
11507 return _input.front;
11508 }
11509 }
11510
11511 return Result(inputRange, outputRange);
11512 }
11513
11514 /// Ditto
11515 auto tee(alias fun, Flag!"pipeOnPop" pipeOnPop = Yes.pipeOnPop, R1)(R1 inputRange)
11516 if (is(typeof(fun) == void) || isSomeFunction!fun)
11517 {
11518 import std.traits : isDelegate, isFunctionPointer;
11519 /*
11520 Distinguish between function literals and template lambdas
11521 when using either as an $(LREF OutputRange). Since a template
11522 has no type, typeof(template) will always return void.
11523 If it's a template lambda, it's first necessary to instantiate
11524 it with $(D ElementType!R1).
11525 */
11526 static if (is(typeof(fun) == void))
11527 alias _fun = fun!(ElementType!R1);
11528 else
11529 alias _fun = fun;
11530
11531 static if (isFunctionPointer!_fun || isDelegate!_fun)
11532 {
11533 return tee!pipeOnPop(inputRange, _fun);
11534 }
11535 else
11536 {
11537 return tee!pipeOnPop(inputRange, &_fun);
11538 }
11539 }
11540
11541 ///
11542 @safe unittest
11543 {
11544 import std.algorithm.comparison : equal;
11545 import std.algorithm.iteration : filter, map;
11546
11547 // Sum values while copying
11548 int[] values = [1, 4, 9, 16, 25];
11549 int sum = 0;
11550 auto newValues = values.tee!(a => sum += a).array;
11551 assert(equal(newValues, values));
11552 assert(sum == 1 + 4 + 9 + 16 + 25);
11553
11554 // Count values that pass the first filter
11555 int count = 0;
11556 auto newValues4 = values.filter!(a => a < 10)
11557 .tee!(a => count++)
11558 .map!(a => a + 1)
11559 .filter!(a => a < 10);
11560
11561 //Fine, equal also evaluates any lazy ranges passed to it.
11562 //count is not 3 until equal evaluates newValues4
11563 assert(equal(newValues4, [2, 5]));
11564 assert(count == 3);
11565 }
11566
11567 //
11568 @safe unittest
11569 {
11570 import std.algorithm.comparison : equal;
11571 import std.algorithm.iteration : filter, map;
11572
11573 int[] values = [1, 4, 9, 16, 25];
11574
11575 int count = 0;
11576 auto newValues = values.filter!(a => a < 10)
11577 .tee!(a => count++, No.pipeOnPop)
11578 .map!(a => a + 1)
11579 .filter!(a => a < 10);
11580
11581 auto val = newValues.front;
11582 assert(count == 1);
11583 //front is only evaluated once per element
11584 val = newValues.front;
11585 assert(count == 1);
11586
11587 //popFront() called, fun will be called
11588 //again on the next access to front
11589 newValues.popFront();
11590 newValues.front;
11591 assert(count == 2);
11592
11593 int[] preMap = new int[](3), postMap = [];
11594 auto mappedValues = values.filter!(a => a < 10)
11595 //Note the two different ways of using tee
11596 .tee(preMap)
11597 .map!(a => a + 1)
11598 .tee!(a => postMap ~= a)
11599 .filter!(a => a < 10);
11600 assert(equal(mappedValues, [2, 5]));
11601 assert(equal(preMap, [1, 4, 9]));
11602 assert(equal(postMap, [2, 5, 10]));
11603 }
11604
11605 //
11606 @safe unittest
11607 {
11608 import std.algorithm.comparison : equal;
11609 import std.algorithm.iteration : filter, map;
11610
11611 char[] txt = "Line one, Line 2".dup;
11612
isVowel(dchar c)11613 bool isVowel(dchar c)
11614 {
11615 import std.string : indexOf;
11616 return "AaEeIiOoUu".indexOf(c) != -1;
11617 }
11618
11619 int vowelCount = 0;
11620 int shiftedCount = 0;
11621 auto removeVowels = txt.tee!(c => isVowel(c) ? vowelCount++ : 0)
11622 .filter!(c => !isVowel(c))
11623 .map!(c => (c == ' ') ? c : c + 1)
11624 .tee!(c => isVowel(c) ? shiftedCount++ : 0);
11625 assert(equal(removeVowels, "Mo o- Mo 3"));
11626 assert(vowelCount == 6);
11627 assert(shiftedCount == 3);
11628 }
11629
11630 @safe unittest
11631 {
11632 // Manually stride to test different pipe behavior.
testRange(Range)11633 void testRange(Range)(Range r)
11634 {
11635 const int strideLen = 3;
11636 int i = 0;
11637 ElementType!Range elem1;
11638 ElementType!Range elem2;
11639 while (!r.empty)
11640 {
11641 if (i % strideLen == 0)
11642 {
11643 //Make sure front is only
11644 //evaluated once per item
11645 elem1 = r.front;
11646 elem2 = r.front;
11647 assert(elem1 == elem2);
11648 }
11649 r.popFront();
11650 i++;
11651 }
11652 }
11653
11654 string txt = "abcdefghijklmnopqrstuvwxyz";
11655
11656 int popCount = 0;
11657 auto pipeOnPop = txt.tee!(a => popCount++);
11658 testRange(pipeOnPop);
11659 assert(popCount == 26);
11660
11661 int frontCount = 0;
11662 auto pipeOnFront = txt.tee!(a => frontCount++, No.pipeOnPop);
11663 testRange(pipeOnFront);
11664 assert(frontCount == 9);
11665 }
11666
11667 @safe unittest
11668 {
11669 import std.algorithm.comparison : equal;
11670 import std.meta : AliasSeq;
11671
11672 //Test diverting elements to an OutputRange
11673 string txt = "abcdefghijklmnopqrstuvwxyz";
11674
11675 dchar[] asink1 = [];
11676 auto fsink = (dchar c) { asink1 ~= c; };
11677 auto result1 = txt.tee(fsink).array;
11678 assert(equal(txt, result1) && (equal(result1, asink1)));
11679
11680 dchar[] _asink1 = [];
11681 auto _result1 = txt.tee!((dchar c) { _asink1 ~= c; })().array;
11682 assert(equal(txt, _result1) && (equal(_result1, _asink1)));
11683
11684 dchar[] asink2 = new dchar[](txt.length);
fsink2(dchar c)11685 void fsink2(dchar c) { static int i = 0; asink2[i] = c; i++; }
11686 auto result2 = txt.tee(&fsink2).array;
11687 assert(equal(txt, result2) && equal(result2, asink2));
11688
11689 dchar[] asink3 = new dchar[](txt.length);
11690 auto result3 = txt.tee(asink3).array;
11691 assert(equal(txt, result3) && equal(result3, asink3));
11692
11693 foreach (CharType; AliasSeq!(char, wchar, dchar))
11694 {
11695 auto appSink = appender!(CharType[])();
11696 auto appResult = txt.tee(appSink).array;
11697 assert(equal(txt, appResult) && equal(appResult, appSink.data));
11698 }
11699
11700 foreach (StringType; AliasSeq!(string, wstring, dstring))
11701 {
11702 auto appSink = appender!StringType();
11703 auto appResult = txt.tee(appSink).array;
11704 assert(equal(txt, appResult) && equal(appResult, appSink.data));
11705 }
11706 }
11707
11708 @safe unittest
11709 {
11710 // Issue 13483
func1(T)11711 static void func1(T)(T x) {}
func2(int x)11712 void func2(int x) {}
11713
11714 auto r = [1, 2, 3, 4].tee!func1.tee!func2;
11715 }
11716
11717 /**
11718 Extends the length of the input range `r` by padding out the start of the
11719 range with the element `e`. The element `e` must be of a common type with
11720 the element type of the range `r` as defined by $(REF CommonType, std, traits).
11721 If `n` is less than the length of of `r`, then `r` is returned unmodified.
11722
11723 If `r` is a string with Unicode characters in it, `padLeft` follows D's rules
11724 about length for strings, which is not the number of characters, or
11725 graphemes, but instead the number of encoding units. If you want to treat each
11726 grapheme as only one encoding unit long, then call
11727 $(REF byGrapheme, std, uni) before calling this function.
11728
11729 If `r` has a length, then this is $(BIGOH 1). Otherwise, it's $(BIGOH r.length).
11730
11731 Params:
11732 r = an input range with a length, or a forward range
11733 e = element to pad the range with
11734 n = the length to pad to
11735
11736 Returns:
11737 A range containing the elements of the original range with the extra padding
11738
11739 See Also:
11740 $(REF leftJustifier, std, string)
11741 */
11742 auto padLeft(R, E)(R r, E e, size_t n)
11743 if (
11744 ((isInputRange!R && hasLength!R) || isForwardRange!R) &&
11745 !is(CommonType!(ElementType!R, E) == void)
11746 )
11747 {
11748 static if (hasLength!R)
11749 auto dataLength = r.length;
11750 else
11751 auto dataLength = r.save.walkLength(n);
11752
11753 return e.repeat(n > dataLength ? n - dataLength : 0).chain(r);
11754 }
11755
11756 ///
11757 @safe pure unittest
11758 {
11759 import std.algorithm.comparison : equal;
11760
11761 assert([1, 2, 3, 4].padLeft(0, 6).equal([0, 0, 1, 2, 3, 4]));
11762 assert([1, 2, 3, 4].padLeft(0, 3).equal([1, 2, 3, 4]));
11763
11764 assert("abc".padLeft('_', 6).equal("___abc"));
11765 }
11766
11767 @safe pure nothrow unittest
11768 {
11769 import std.algorithm.comparison : equal;
11770 import std.internal.test.dummyrange : DummyRange, Length, RangeType, ReturnBy;
11771 import std.meta : AliasSeq;
11772
11773 alias DummyRanges = AliasSeq!(
11774 DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Input),
11775 DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Forward),
11776 DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Bidirectional),
11777 DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random),
11778 DummyRange!(ReturnBy.Reference, Length.No, RangeType.Forward),
11779 DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Input),
11780 DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Forward),
11781 DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Bidirectional),
11782 DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random),
11783 DummyRange!(ReturnBy.Value, Length.No, RangeType.Forward)
11784 );
11785
foreach(Range;DummyRanges)11786 foreach (Range; DummyRanges)
11787 {
11788 Range r;
11789 assert(r
11790 .padLeft(0, 12)
11791 .equal([0, 0, 1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U])
11792 );
11793 }
11794 }
11795
11796 // Test nogc inference
11797 @safe @nogc pure unittest
11798 {
11799 import std.algorithm.comparison : equal;
11800
11801 static immutable r1 = [1, 2, 3, 4];
11802 static immutable r2 = [0, 0, 1, 2, 3, 4];
11803 assert(r1.padLeft(0, 6).equal(r2));
11804 }
11805
11806 /**
11807 Extend the length of the input range `r` by padding out the end of the range
11808 with the element `e`. The element `e` must be of a common type with the
11809 element type of the range `r` as defined by $(REF CommonType, std, traits).
11810 If `n` is less than the length of of `r`, then the contents of `r` are
11811 returned.
11812
11813 The range primitives that the resulting range provides depends whether or not `r`
11814 provides them. Except the functions `back` and `popBack`, which also require
11815 the range to have a length as well as `back` and `popBack`
11816
11817 Params:
11818 r = an input range with a length
11819 e = element to pad the range with
11820 n = the length to pad to
11821
11822 Returns:
11823 A range containing the elements of the original range with the extra padding
11824
11825 See Also:
11826 $(REF rightJustifier, std, string)
11827 */
11828 auto padRight(R, E)(R r, E e, size_t n)
11829 if (
11830 isInputRange!R &&
11831 !isInfinite!R &&
11832 !is(CommonType!(ElementType!R, E) == void))
11833 {
11834 static struct Result
11835 {
11836 private:
11837 R data;
11838 E element;
11839 size_t counter;
11840 static if (isBidirectionalRange!R && hasLength!R) size_t backPosition;
11841 size_t maxSize;
11842
11843 public:
emptyResult11844 bool empty() @property
11845 {
11846 return data.empty && counter >= maxSize;
11847 }
11848
frontResult11849 auto front() @property
11850 {
11851 assert(!empty, "Attempting to fetch the front of an empty padRight");
11852 return data.empty ? element : data.front;
11853 }
11854
popFrontResult11855 void popFront()
11856 {
11857 assert(!empty, "Attempting to popFront an empty padRight");
11858 ++counter;
11859
11860 if (!data.empty)
11861 {
11862 data.popFront;
11863 }
11864 }
11865
11866 static if (hasLength!R)
11867 {
lengthResult11868 size_t length() @property
11869 {
11870 import std.algorithm.comparison : max;
11871 return max(data.length, maxSize);
11872 }
11873 }
11874
11875 static if (isForwardRange!R)
11876 {
saveResult11877 auto save() @property
11878 {
11879 typeof(this) result = this;
11880 data = data.save;
11881 return result;
11882 }
11883 }
11884
11885 static if (isBidirectionalRange!R && hasLength!R)
11886 {
backResult11887 auto back() @property
11888 {
11889 assert(!empty, "Attempting to fetch the back of an empty padRight");
11890 return backPosition > data.length ? element : data.back;
11891 }
11892
popBackResult11893 void popBack()
11894 {
11895 assert(!empty, "Attempting to popBack an empty padRight");
11896 if (backPosition > data.length)
11897 {
11898 --backPosition;
11899 --maxSize;
11900 }
11901 else
11902 {
11903 data.popBack;
11904 }
11905 }
11906 }
11907
11908 static if (isRandomAccessRange!R && hasLength!R)
11909 {
opIndexResult11910 E opIndex(size_t index)
11911 {
11912 assert(index <= this.length, "Index out of bounds");
11913 return (index > data.length && index <= maxSize) ? element :
11914 data[index];
11915 }
11916 }
11917
11918 static if (hasSlicing!R && hasLength!R)
11919 {
opSliceResult11920 auto opSlice(size_t a, size_t b)
11921 {
11922 assert(
11923 a <= b,
11924 "Attempting to slice a padRight with a larger first argument than the second."
11925 );
11926 assert(
11927 b <= length,
11928 "Attempting to slice using an out of bounds index on a padRight"
11929 );
11930 return Result((b <= data.length) ? data[a .. b] : data[a .. data.length],
11931 element, b - a);
11932 }
11933
11934 alias opDollar = length;
11935 }
11936
thisResult11937 this(R r, E e, size_t max)
11938 {
11939 data = r;
11940 element = e;
11941 maxSize = max;
11942 static if (isBidirectionalRange!R && hasLength!R)
11943 backPosition = max;
11944 }
11945
11946 @disable this();
11947 }
11948
11949 return Result(r, e, n);
11950 }
11951
11952 ///
11953 @safe pure unittest
11954 {
11955 import std.algorithm.comparison : equal;
11956
11957 assert([1, 2, 3, 4].padRight(0, 6).equal([1, 2, 3, 4, 0, 0]));
11958 assert([1, 2, 3, 4].padRight(0, 4).equal([1, 2, 3, 4]));
11959
11960 assert("abc".padRight('_', 6).equal("abc___"));
11961 }
11962
11963 pure @safe unittest
11964 {
11965 import std.algorithm.comparison : equal;
11966 import std.internal.test.dummyrange : AllDummyRanges, ReferenceInputRange;
11967 import std.meta : AliasSeq;
11968
11969 auto string_input_range = new ReferenceInputRange!dchar(['a', 'b', 'c']);
11970 dchar padding = '_';
11971 assert(string_input_range.padRight(padding, 6).equal("abc___"));
11972
foreach(RangeType;AllDummyRanges)11973 foreach (RangeType; AllDummyRanges)
11974 {
11975 RangeType r1;
11976 assert(r1
11977 .padRight(0, 12)
11978 .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0, 0])
11979 );
11980
11981 // test if Result properly uses random access ranges
11982 static if (isRandomAccessRange!RangeType)
11983 {
11984 RangeType r3;
11985 assert(r3.padRight(0, 12)[0] == 1);
11986 assert(r3.padRight(0, 12)[2] == 3);
11987 assert(r3.padRight(0, 12)[11] == 0);
11988 }
11989
11990 // test if Result properly uses slicing and opDollar
11991 static if (hasSlicing!RangeType)
11992 {
11993 RangeType r4;
11994 assert(r4
11995 .padRight(0, 12)[0 .. 3]
11996 .equal([1, 2, 3])
11997 );
11998 assert(r4
11999 .padRight(0, 12)[2 .. $]
12000 .equal([3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0, 0])
12001 );
12002 assert(r4
12003 .padRight(0, 12)[0 .. $]
12004 .equal([1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 0, 0])
12005 );
12006 }
12007 }
12008 }
12009
12010 // Test nogc inference
12011 @safe @nogc pure unittest
12012 {
12013 import std.algorithm.comparison : equal;
12014
12015 static immutable r1 = [1, 2, 3, 4];
12016 static immutable r2 = [1, 2, 3, 4, 0, 0];
12017 assert(r1.padRight(0, 6).equal(r2));
12018 }
12019