1 // Written in the D programming language.
2 /**
3 This is a submodule of $(MREF std, algorithm).
4 It contains generic searching algorithms.
5 
6 $(SCRIPT inhibitQuickIndex = 1;)
7 $(BOOKTABLE Cheat Sheet,
8 $(TR $(TH Function Name) $(TH Description))
9 $(T2 all,
10         `all!"a > 0"([1, 2, 3, 4])` returns `true` because all elements
11         are positive)
12 $(T2 any,
13         `any!"a > 0"([1, 2, -3, -4])` returns `true` because at least one
14         element is positive)
15 $(T2 balancedParens,
16         `balancedParens("((1 + 1) / 2)", '(', ')')` returns `true` because the
17         string has balanced parentheses.)
18 $(T2 boyerMooreFinder,
19         `find("hello world", boyerMooreFinder("or"))` returns `"orld"`
20         using the $(LINK2 https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_string_search_algorithm,
21         Boyer-Moore _algorithm).)
22 $(T2 canFind,
23         `canFind("hello world", "or")` returns `true`.)
24 $(T2 count,
25         Counts all elements or elements matching a predicate, specific element or sub-range.$(BR)
26         `count([1, 2, 1])` returns `3`,
27         `count([1, 2, 1], 1)` returns `2` and
28         `count!"a < 0"([1, -3, 0])` returns `1`.)
29 $(T2 countUntil,
30         `countUntil(a, b)` returns the number of steps taken in `a` to
31         reach `b`; for example, `countUntil("hello!", "o")` returns
32         `4`.)
33 $(T2 commonPrefix,
34         `commonPrefix("parakeet", "parachute")` returns `"para"`.)
35 $(T2 endsWith,
36         `endsWith("rocks", "ks")` returns `true`.)
37 $(T2 extrema, `extrema([2, 1, 3, 5, 4])` returns `[1, 5]`.)
38 $(T2 find,
39         `find("hello world", "or")` returns `"orld"` using linear search.
40         (For binary search refer to $(REF SortedRange, std,range).))
41 $(T2 findAdjacent,
42         `findAdjacent([1, 2, 3, 3, 4])` returns the subrange starting with
43         two equal adjacent elements, i.e. `[3, 3, 4]`.)
44 $(T2 findAmong,
45         `findAmong("abcd", "qcx")` returns `"cd"` because `'c'` is
46         among `"qcx"`.)
47 $(T2 findSkip,
48         If `a = "abcde"`, then `findSkip(a, "x")` returns `false` and
49         leaves `a` unchanged, whereas `findSkip(a, "c")` advances `a`
50         to `"de"` and returns `true`.)
51 $(T2 findSplit,
52         `findSplit("abcdefg", "de")` returns a tuple of three ranges `"abc"`,
53         `"de"`, and `"fg"`.)
54 $(T2 findSplitAfter,
55 `findSplitAfter("abcdefg", "de")` returns a tuple of two ranges `"abcde"`
56         and `"fg"`.)
57 $(T2 findSplitBefore,
58         `findSplitBefore("abcdefg", "de")` returns a tuple of two ranges `"abc"`
59         and `"defg"`.)
60 $(T2 minCount,
61         `minCount([2, 1, 1, 4, 1])` returns `tuple(1, 3)`.)
62 $(T2 maxCount,
63         `maxCount([2, 4, 1, 4, 1])` returns `tuple(4, 2)`.)
64 $(T2 minElement,
65         Selects the minimal element of a range.
66         `minElement([3, 4, 1, 2])` returns `1`.)
67 $(T2 maxElement,
68         Selects the maximal element of a range.
69         `maxElement([3, 4, 1, 2])` returns `4`.)
70 $(T2 minIndex,
71         Index of the minimal element of a range.
72         `minIndex([3, 4, 1, 2])` returns `2`.)
73 $(T2 maxIndex,
74         Index of the maximal element of a range.
75         `maxIndex([3, 4, 1, 2])` returns `1`.)
76 $(T2 minPos,
77         `minPos([2, 3, 1, 3, 4, 1])` returns the subrange `[1, 3, 4, 1]`,
78         i.e., positions the range at the first occurrence of its minimal
79         element.)
80 $(T2 maxPos,
81         `maxPos([2, 3, 1, 3, 4, 1])` returns the subrange `[4, 1]`,
82         i.e., positions the range at the first occurrence of its maximal
83         element.)
84 $(T2 skipOver,
85         Assume `a = "blah"`. Then `skipOver(a, "bi")` leaves `a`
86         unchanged and returns `false`, whereas `skipOver(a, "bl")`
87         advances `a` to refer to `"ah"` and returns `true`.)
88 $(T2 startsWith,
89         `startsWith("hello, world", "hello")` returns `true`.)
90 $(T2 until,
91         Lazily iterates a range until a specific value is found.)
92 )
93 
94 Copyright: Andrei Alexandrescu 2008-.
95 
96 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
97 
98 Authors: $(HTTP erdani.com, Andrei Alexandrescu)
99 
100 Source: $(PHOBOSSRC std/algorithm/searching.d)
101 
102 Macros:
103 T2=$(TR $(TDNW $(LREF $1)) $(TD $+))
104  */
105 module std.algorithm.searching;
106 
107 import std.functional : unaryFun, binaryFun;
108 import std.meta : allSatisfy;
109 import std.range.primitives;
110 import std.traits;
111 import std.typecons : Tuple, Flag, Yes, No, tuple;
112 
113 /++
114 Checks if $(I _all) of the elements satisfy `pred`.
115  +/
116 template all(alias pred = "a")
117 {
118     /++
119     Returns `true` if and only if the input range `range` is empty
120     or $(I _all) values found in `range` satisfy the predicate `pred`.
121     Performs (at most) $(BIGOH range.length) evaluations of `pred`.
122      +/
123     bool all(Range)(Range range)
124     if (isInputRange!Range &&
125         (__traits(isTemplate, pred) || is(typeof(unaryFun!pred(range.front)))))
126     {
127         import std.functional : not;
128 
129         return find!(not!(unaryFun!pred))(range).empty;
130     }
131 }
132 
133 ///
134 @safe unittest
135 {
136     assert( all!"a & 1"([1, 3, 5, 7, 9]));
137     assert(!all!"a & 1"([1, 2, 3, 5, 7, 9]));
138 }
139 
140 /++
141 `all` can also be used without a predicate, if its items can be
142 evaluated to true or false in a conditional statement. This can be a
143 convenient way to quickly evaluate that $(I _all) of the elements of a range
144 are true.
145  +/
146 @safe unittest
147 {
148     int[3] vals = [5, 3, 18];
149     assert( all(vals[]));
150 }
151 
152 @safe unittest
153 {
154     int x = 1;
155     assert(all!(a => a > x)([2, 3]));
156     assert(all!"a == 0x00c9"("\xc3\x89")); // Test that `all` auto-decodes.
157 }
158 
159 /++
160 Checks if $(I _any) of the elements satisfies `pred`.
161 `!any` can be used to verify that $(I none) of the elements satisfy
162 `pred`.
163 This is sometimes called `exists` in other languages.
164  +/
165 template any(alias pred = "a")
166 {
167     /++
168     Returns `true` if and only if the input range `range` is non-empty
169     and $(I _any) value found in `range` satisfies the predicate
170     `pred`.
171     Performs (at most) $(BIGOH range.length) evaluations of `pred`.
172      +/
173     bool any(Range)(Range range)
174     if (isInputRange!Range &&
175         (__traits(isTemplate, pred) || is(typeof(unaryFun!pred(range.front)))))
176     {
177         return !find!pred(range).empty;
178     }
179 }
180 
181 ///
182 @safe unittest
183 {
184     import std.ascii : isWhite;
185     assert( all!(any!isWhite)(["a a", "b b"]));
186     assert(!any!(all!isWhite)(["a a", "b b"]));
187 }
188 
189 /++
190 `any` can also be used without a predicate, if its items can be
191 evaluated to true or false in a conditional statement. `!any` can be a
192 convenient way to quickly test that $(I none) of the elements of a range
193 evaluate to true.
194  +/
195 @safe unittest
196 {
197     int[3] vals1 = [0, 0, 0];
198     assert(!any(vals1[])); //none of vals1 evaluate to true
199 
200     int[3] vals2 = [2, 0, 2];
201     assert( any(vals2[]));
202     assert(!all(vals2[]));
203 
204     int[3] vals3 = [3, 3, 3];
205     assert( any(vals3[]));
206     assert( all(vals3[]));
207 }
208 
209 @safe unittest
210 {
211     auto a = [ 1, 2, 0, 4 ];
212     assert(any!"a == 2"(a));
213     assert(any!"a == 0x3000"("\xe3\x80\x80")); // Test that `any` auto-decodes.
214 }
215 
216 // balancedParens
217 /**
218 Checks whether `r` has "balanced parentheses", i.e. all instances
219 of `lPar` are closed by corresponding instances of `rPar`. The
220 parameter `maxNestingLevel` controls the nesting level allowed. The
221 most common uses are the default or `0`. In the latter case, no
222 nesting is allowed.
223 
224 Params:
225     r = The range to check.
226     lPar = The element corresponding with a left (opening) parenthesis.
227     rPar = The element corresponding with a right (closing) parenthesis.
228     maxNestingLevel = The maximum allowed nesting level.
229 
230 Returns:
231     true if the given range has balanced parenthesis within the given maximum
232     nesting level; false otherwise.
233 */
234 bool balancedParens(Range, E)(Range r, E lPar, E rPar,
235         size_t maxNestingLevel = size_t.max)
236 if (isInputRange!(Range) && is(typeof(r.front == lPar)))
237 {
238     size_t count;
239 
240     static if (is(immutable ElementEncodingType!Range == immutable E) && isNarrowString!Range)
241     {
242         import std.utf : byCodeUnit;
243         auto rn = r.byCodeUnit;
244     }
245     else
246     {
247         alias rn = r;
248     }
249 
250     for (; !rn.empty; rn.popFront())
251     {
252         if (rn.front == lPar)
253         {
254             if (count > maxNestingLevel) return false;
255             ++count;
256         }
257         else if (rn.front == rPar)
258         {
259             if (!count) return false;
260             --count;
261         }
262     }
263     return count == 0;
264 }
265 
266 ///
267 @safe pure unittest
268 {
269     auto s = "1 + (2 * (3 + 1 / 2)";
270     assert(!balancedParens(s, '(', ')'));
271     s = "1 + (2 * (3 + 1) / 2)";
272     assert(balancedParens(s, '(', ')'));
273     s = "1 + (2 * (3 + 1) / 2)";
274     assert(!balancedParens(s, '(', ')', 0));
275     s = "1 + (2 * 3 + 1) / (2 - 5)";
276     assert(balancedParens(s, '(', ')', 0));
277     s = "f(x) = ⌈x⌉";
278     assert(balancedParens(s, '⌈', '⌉'));
279 }
280 
281 /**
282  * Sets up Boyer-Moore matching for use with `find` below.
283  * By default, elements are compared for equality.
284  *
285  * `BoyerMooreFinder` allocates GC memory.
286  *
287  * Params:
288  * pred = Predicate used to compare elements.
289  * needle = A random-access range with length and slicing.
290  *
291  * Returns:
292  * An instance of `BoyerMooreFinder` that can be used with `find()` to
293  * invoke the Boyer-Moore matching algorithm for finding of `needle` in a
294  * given haystack.
295  */
296 struct BoyerMooreFinder(alias pred, Range)
297 {
298 private:
299     size_t[] skip;                              // GC allocated
300     ptrdiff_t[ElementType!(Range)] occ;         // GC allocated
301     Range needle;
302 
303     ptrdiff_t occurrence(ElementType!(Range) c) scope
304     {
305         auto p = c in occ;
306         return p ? *p : -1;
307     }
308 
309 /*
310 This helper function checks whether the last "portion" bytes of
311 "needle" (which is "nlen" bytes long) exist within the "needle" at
312 offset "offset" (counted from the end of the string), and whether the
313 character preceding "offset" is not a match.  Notice that the range
314 being checked may reach beyond the beginning of the string. Such range
315 is ignored.
316  */
317     static bool needlematch(R)(R needle,
318                               size_t portion, size_t offset)
319     {
320         import std.algorithm.comparison : equal;
321         ptrdiff_t virtual_begin = needle.length - offset - portion;
322         ptrdiff_t ignore = 0;
323         if (virtual_begin < 0)
324         {
325             ignore = -virtual_begin;
326             virtual_begin = 0;
327         }
328         if (virtual_begin > 0
329             && needle[virtual_begin - 1] == needle[$ - portion - 1])
330             return 0;
331 
332         immutable delta = portion - ignore;
333         return equal(needle[needle.length - delta .. needle.length],
334                 needle[virtual_begin .. virtual_begin + delta]);
335     }
336 
337 public:
338     ///
339     this(Range needle)
340     {
341         if (!needle.length) return;
342         this.needle = needle;
343         /* Populate table with the analysis of the needle */
344         /* But ignoring the last letter */
345         foreach (i, n ; needle[0 .. $ - 1])
346         {
347             this.occ[n] = i;
348         }
349         /* Preprocess #2: init skip[] */
350         /* Note: This step could be made a lot faster.
351          * A simple implementation is shown here. */
352         this.skip = new size_t[needle.length];
353         foreach (a; 0 .. needle.length)
354         {
355             size_t value = 0;
356             while (value < needle.length
357                    && !needlematch(needle, a, value))
358             {
359                 ++value;
360             }
361             this.skip[needle.length - a - 1] = value;
362         }
363     }
364 
365     ///
366     Range beFound(Range haystack) scope
367     {
368         import std.algorithm.comparison : max;
369 
370         if (!needle.length) return haystack;
371         if (needle.length > haystack.length) return haystack[$ .. $];
372         /* Search: */
373         immutable limit = haystack.length - needle.length;
374         for (size_t hpos = 0; hpos <= limit; )
375         {
376             size_t npos = needle.length - 1;
377             while (pred(needle[npos], haystack[npos+hpos]))
378             {
379                 if (npos == 0) return haystack[hpos .. $];
380                 --npos;
381             }
382             hpos += max(skip[npos], cast(ptrdiff_t) npos - occurrence(haystack[npos+hpos]));
383         }
384         return haystack[$ .. $];
385     }
386 
387     ///
388     @property size_t length()
389     {
390         return needle.length;
391     }
392 
393     ///
394     alias opDollar = length;
395 }
396 
397 /// Ditto
398 BoyerMooreFinder!(binaryFun!(pred), Range) boyerMooreFinder
399 (alias pred = "a == b", Range)
400 (Range needle)
401 if ((isRandomAccessRange!(Range) && hasSlicing!Range) || isSomeString!Range)
402 {
403     return typeof(return)(needle);
404 }
405 
406 ///
407 @safe pure nothrow unittest
408 {
409     auto bmFinder = boyerMooreFinder("TG");
410 
411     string r = "TAGTGCCTGA";
412     // search for the first match in the haystack r
413     r = bmFinder.beFound(r);
414     assert(r == "TGCCTGA");
415 
416     // continue search in haystack
417     r = bmFinder.beFound(r[2 .. $]);
418     assert(r == "TGA");
419 }
420 
421 /**
422 Returns the common prefix of two ranges.
423 
424 Params:
425     pred = The predicate to use in comparing elements for commonality. Defaults
426         to equality `"a == b"`.
427 
428     r1 = A $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) of
429         elements.
430 
431     r2 = An $(REF_ALTTEXT input range, isInputRange, std,range,primitives) of
432         elements.
433 
434 Returns:
435 A slice of `r1` which contains the characters that both ranges start with,
436 if the first argument is a string; otherwise, the same as the result of
437 `takeExactly(r1, n)`, where `n` is the number of elements in the common
438 prefix of both ranges.
439 
440 See_Also:
441     $(REF takeExactly, std,range)
442  */
443 auto commonPrefix(alias pred = "a == b", R1, R2)(R1 r1, R2 r2)
444 if (isForwardRange!R1 && isInputRange!R2 &&
445     !isNarrowString!R1 &&
446     is(typeof(binaryFun!pred(r1.front, r2.front))))
447 {
448     import std.algorithm.comparison : min;
449     static if (isRandomAccessRange!R1 && isRandomAccessRange!R2 &&
450                hasLength!R1 && hasLength!R2 &&
451                hasSlicing!R1)
452     {
453         immutable limit = min(r1.length, r2.length);
454         foreach (i; 0 .. limit)
455         {
456             if (!binaryFun!pred(r1[i], r2[i]))
457             {
458                 return r1[0 .. i];
459             }
460         }
461         return r1[0 .. limit];
462     }
463     else
464     {
465         import std.range : takeExactly;
466         auto result = r1.save;
467         size_t i = 0;
468         for (;
469              !r1.empty && !r2.empty && binaryFun!pred(r1.front, r2.front);
470              ++i, r1.popFront(), r2.popFront())
471         {}
472         return takeExactly(result, i);
473     }
474 }
475 
476 ///
477 @safe unittest
478 {
479     assert(commonPrefix("hello, world", "hello, there") == "hello, ");
480 }
481 
482 /// ditto
483 auto commonPrefix(alias pred, R1, R2)(R1 r1, R2 r2)
484 if (isNarrowString!R1 && isInputRange!R2 &&
485     is(typeof(binaryFun!pred(r1.front, r2.front))))
486 {
487     import std.utf : decode;
488 
489     auto result = r1.save;
490     immutable len = r1.length;
491     size_t i = 0;
492 
493     for (size_t j = 0; i < len && !r2.empty; r2.popFront(), i = j)
494     {
495         immutable f = decode(r1, j);
496         if (!binaryFun!pred(f, r2.front))
497             break;
498     }
499 
500     return result[0 .. i];
501 }
502 
503 /// ditto
504 auto commonPrefix(R1, R2)(R1 r1, R2 r2)
505 if (isNarrowString!R1 && isInputRange!R2 && !isNarrowString!R2 &&
506     is(typeof(r1.front == r2.front)))
507 {
508     return commonPrefix!"a == b"(r1, r2);
509 }
510 
511 /// ditto
512 auto commonPrefix(R1, R2)(R1 r1, R2 r2)
513 if (isNarrowString!R1 && isNarrowString!R2)
514 {
515     import std.algorithm.comparison : min;
516 
517     static if (ElementEncodingType!R1.sizeof == ElementEncodingType!R2.sizeof)
518     {
519         import std.utf : stride, UTFException;
520 
521         immutable limit = min(r1.length, r2.length);
522         for (size_t i = 0; i < limit;)
523         {
524             immutable codeLen = stride(r1, i);
525             size_t j = 0;
526 
527             for (; j < codeLen && i < limit; ++i, ++j)
528             {
529                 if (r1[i] != r2[i])
530                     return r1[0 .. i - j];
531             }
532 
533             if (i == limit && j < codeLen)
534                 throw new UTFException("Invalid UTF-8 sequence", i);
535         }
536         return r1[0 .. limit];
537     }
538     else
539         return commonPrefix!"a == b"(r1, r2);
540 }
541 
542 @safe unittest
543 {
544     import std.algorithm.comparison : equal;
545     import std.algorithm.iteration : filter;
546     import std.conv : to;
547     import std.exception : assertThrown;
548     import std.meta : AliasSeq;
549     import std.range;
550     import std.utf : UTFException;
551 
552     assert(commonPrefix([1, 2, 3], [1, 2, 3, 4, 5]) == [1, 2, 3]);
553     assert(commonPrefix([1, 2, 3, 4, 5], [1, 2, 3]) == [1, 2, 3]);
554     assert(commonPrefix([1, 2, 3, 4], [1, 2, 3, 4]) == [1, 2, 3, 4]);
555     assert(commonPrefix([1, 2, 3], [7, 2, 3, 4, 5]).empty);
556     assert(commonPrefix([7, 2, 3, 4, 5], [1, 2, 3]).empty);
557     assert(commonPrefix([1, 2, 3], cast(int[]) null).empty);
558     assert(commonPrefix(cast(int[]) null, [1, 2, 3]).empty);
559     assert(commonPrefix(cast(int[]) null, cast(int[]) null).empty);
560 
561     static foreach (S; AliasSeq!(char[], const(char)[], string,
562                           wchar[], const(wchar)[], wstring,
563                           dchar[], const(dchar)[], dstring))
564     {
565         static foreach (T; AliasSeq!(string, wstring, dstring))
566         {
567             assert(commonPrefix(to!S(""), to!T("")).empty);
568             assert(commonPrefix(to!S(""), to!T("hello")).empty);
569             assert(commonPrefix(to!S("hello"), to!T("")).empty);
570             assert(commonPrefix(to!S("hello, world"), to!T("hello, there")) == to!S("hello, "));
571             assert(commonPrefix(to!S("hello, there"), to!T("hello, world")) == to!S("hello, "));
572             assert(commonPrefix(to!S("hello, "), to!T("hello, world")) == to!S("hello, "));
573             assert(commonPrefix(to!S("hello, world"), to!T("hello, ")) == to!S("hello, "));
574             assert(commonPrefix(to!S("hello, world"), to!T("hello, world")) == to!S("hello, world"));
575 
576             // https://issues.dlang.org/show_bug.cgi?id=8890
577             assert(commonPrefix(to!S("Пиво"), to!T("Пони"))== to!S("П"));
578             assert(commonPrefix(to!S("Пони"), to!T("Пиво"))== to!S("П"));
579             assert(commonPrefix(to!S("Пиво"), to!T("Пиво"))== to!S("Пиво"));
580             assert(commonPrefix(to!S("\U0010FFFF\U0010FFFB\U0010FFFE"),
581                                 to!T("\U0010FFFF\U0010FFFB\U0010FFFC")) == to!S("\U0010FFFF\U0010FFFB"));
582             assert(commonPrefix(to!S("\U0010FFFF\U0010FFFB\U0010FFFC"),
583                                 to!T("\U0010FFFF\U0010FFFB\U0010FFFE")) == to!S("\U0010FFFF\U0010FFFB"));
584             assert(commonPrefix!"a != b"(to!S("Пиво"), to!T("онво")) == to!S("Пи"));
585             assert(commonPrefix!"a != b"(to!S("онво"), to!T("Пиво")) == to!S("он"));
586         }
587 
588         static assert(is(typeof(commonPrefix(to!S("Пиво"), filter!"true"("Пони"))) == S));
589         assert(equal(commonPrefix(to!S("Пиво"), filter!"true"("Пони")), to!S("П")));
590 
591         static assert(is(typeof(commonPrefix(filter!"true"("Пиво"), to!S("Пони"))) ==
592                       typeof(takeExactly(filter!"true"("П"), 1))));
593         assert(equal(commonPrefix(filter!"true"("Пиво"), to!S("Пони")), takeExactly(filter!"true"("П"), 1)));
594     }
595 
596     assertThrown!UTFException(commonPrefix("\U0010FFFF\U0010FFFB", "\U0010FFFF\U0010FFFB"[0 .. $ - 1]));
597 
598     assert(commonPrefix("12345"d, [49, 50, 51, 60, 60]) == "123"d);
599     assert(commonPrefix([49, 50, 51, 60, 60], "12345" ) == [49, 50, 51]);
600     assert(commonPrefix([49, 50, 51, 60, 60], "12345"d) == [49, 50, 51]);
601 
602     assert(commonPrefix!"a == ('0' + b)"("12345" , [1, 2, 3, 9, 9]) == "123");
603     assert(commonPrefix!"a == ('0' + b)"("12345"d, [1, 2, 3, 9, 9]) == "123"d);
604     assert(commonPrefix!"('0' + a) == b"([1, 2, 3, 9, 9], "12345" ) == [1, 2, 3]);
605     assert(commonPrefix!"('0' + a) == b"([1, 2, 3, 9, 9], "12345"d) == [1, 2, 3]);
606 }
607 
608 // count
609 /**
610 Counts matches of `needle` in `haystack`.
611 
612 The first overload counts each element `e` in `haystack` for
613 which `pred(e, needle)` is `true`. `pred` defaults to
614 equality. Performs $(BIGOH haystack.length) evaluations of `pred`.
615 
616 The second overload counts the number of times `needle` was matched in
617 `haystack`. `pred` compares elements in each range.
618 Throws an exception if `needle.empty` is `true`, as the _count
619 of the empty range in any range would be infinite. Overlapped counts
620 are *not* considered, for example `count("aaa", "aa")` is `1`, not
621 `2`.
622 
623 Note: Regardless of the overload, `count` will not accept
624 infinite ranges for `haystack`.
625 
626 Params:
627     pred = The predicate to compare elements.
628     haystack = The range to _count.
629     needle = The element or sub-range to _count in `haystack`.
630 
631 Returns:
632     The number of matches in `haystack`.
633 */
634 size_t count(alias pred = "a == b", Range, E)(Range haystack, E needle)
635 if (isInputRange!Range && !isInfinite!Range &&
636     is(typeof(binaryFun!pred(haystack.front, needle))))
637 {
638     bool pred2(ElementType!Range a) { return binaryFun!pred(a, needle); }
639     return count!pred2(haystack);
640 }
641 
642 ///
643 @safe unittest
644 {
645     // count elements in range
646     int[] a = [ 1, 2, 4, 3, 2, 5, 3, 2, 4 ];
647     assert(count(a, 2) == 3);
648     assert(count!("a > b")(a, 2) == 5);
649 }
650 
651 ///
652 @safe unittest
653 {
654     import std.uni : toLower;
655     // count range in range
656     assert(count("abcadfabf", "ab") == 2);
657     assert(count("ababab", "abab") == 1);
658     assert(count("ababab", "abx") == 0);
659     // fuzzy count range in range
660     assert(count!((a, b) => toLower(a) == toLower(b))("AbcAdFaBf", "ab") == 2);
661 }
662 
663 @safe unittest
664 {
665     import std.conv : text;
666 
667     int[] a = [ 1, 2, 4, 3, 2, 5, 3, 2, 4 ];
668     assert(count(a, 2) == 3, text(count(a, 2)));
669     assert(count!("a > b")(a, 2) == 5, text(count!("a > b")(a, 2)));
670 
671     // check strings
672     assert(count("日本語")  == 3);
673     assert(count("日本語"w) == 3);
674     assert(count("日本語"d) == 3);
675 
676     assert(count!("a == '日'")("日本語")  == 1);
677     assert(count!("a == '本'")("日本語"w) == 1);
678     assert(count!("a == '語'")("日本語"d) == 1);
679 }
680 
681 @safe unittest
682 {
683     string s = "This is a fofofof list";
684     string sub = "fof";
685     assert(count(s, sub) == 2);
686 }
687 
688 /// Ditto
689 size_t count(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle)
690 if (isForwardRange!R1 && !isInfinite!R1 &&
691     isForwardRange!R2 &&
692     is(typeof(binaryFun!pred(haystack.front, needle.front))))
693 {
694     assert(!needle.empty, "Cannot count occurrences of an empty range");
695 
696     static if (isInfinite!R2)
697     {
698         //Note: This is the special case of looking for an infinite inside a finite...
699         //"How many instances of the Fibonacci sequence can you count in [1, 2, 3]?" - "None."
700         return 0;
701     }
702     else
703     {
704         size_t result;
705         //Note: haystack is not saved, because findskip is designed to modify it
706         for ( ; findSkip!pred(haystack, needle.save) ; ++result)
707         {}
708         return result;
709     }
710 }
711 
712 /**
713 Counts all elements or elements satisfying a predicate in `haystack`.
714 
715 The first overload counts each element `e` in `haystack` for which `pred(e)` is $(D
716 true). Performs $(BIGOH haystack.length) evaluations of `pred`.
717 
718 The second overload counts the number of elements in a range.
719 If the given range has the `length` property,
720 that is returned right away, otherwise
721 performs $(BIGOH haystack.length) to walk the range.
722 
723 Params:
724     pred = Optional predicate to find elements.
725     haystack = The range to _count.
726 
727 Returns:
728     The number of elements in `haystack` (for which `pred` returned true).
729 */
730 size_t count(alias pred, R)(R haystack)
731 if (isInputRange!R && !isInfinite!R &&
732     is(typeof(unaryFun!pred(haystack.front))))
733 {
734     size_t result;
735     alias T = ElementType!R; //For narrow strings forces dchar iteration
736     foreach (T elem; haystack)
737         if (unaryFun!pred(elem)) ++result;
738     return result;
739 }
740 
741 ///
742 @safe unittest
743 {
744     // count elements in range
745     int[] a = [ 1, 2, 4, 3, 2, 5, 3, 2, 4 ];
746     assert(count(a) == 9);
747     // count predicate in range
748     assert(count!("a > 2")(a) == 5);
749 }
750 
751 /// Ditto
752 size_t count(R)(R haystack)
753 if (isInputRange!R && !isInfinite!R)
754 {
755     return walkLength(haystack);
756 }
757 
758 @safe unittest
759 {
760     int[] a = [ 1, 2, 4, 3, 2, 5, 3, 2, 4 ];
761     assert(count!("a == 3")(a) == 2);
762     assert(count("日本語") == 3);
763 }
764 
765 // https://issues.dlang.org/show_bug.cgi?id=11253
766 @safe nothrow unittest
767 {
768     assert([1, 2, 3].count([2, 3]) == 1);
769 }
770 
771 // https://issues.dlang.org/show_bug.cgi?id=22582
772 @safe unittest
773 {
774     assert([1, 2, 3].count!"a & 1" == 2);
775 }
776 
777 /++
778     Counts elements in the given
779     $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
780     until the given predicate is true for one of the given `needles` or `needle`.
781 
782     Params:
783         pred = Binary predicate for determining when to stop counting,
784             which will be passed each element of `haystack` and a needle.
785         haystack = The
786             $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to be
787             counted. Must be a
788             $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) to
789             use multiple needles.
790         needles = A sequence of values or
791             $(REF_ALTTEXT forward ranges, isForwardRange, std,range,primitives)
792             of values, to be evaluated in turn by calling `pred(element, needle)`
793             with each element of `haystack`.
794         needle = A value passed as the 2nd argument to `pred`.
795 
796     Returns:
797   - The number of elements which must be popped from the front of
798     `haystack` before reaching an element for which
799     $(LREF startsWith)`!pred(haystack, needles)` is `true`.
800   - If
801     `startsWith!pred(haystack, needles)` is not `true` for any element in
802     `haystack`, then `-1` is returned.
803   - If more than one needle is provided,
804     `countUntil` will wrap the result in a pseudo-tuple similar to
805     `Tuple!(ptrdiff_t, "steps", ptrdiff_t, "needle")`.
806     - `steps` is the count value, which can be implicitly tested for equality.
807     - `needle` is the index into `needles` which matched.
808     - Both are `-1` if there was no match.
809 
810     See_Also: $(REF indexOf, std,string)
811   +/
812 auto countUntil(alias pred = "a == b", R, Rs...)(R haystack, Rs needles)
813 if (isForwardRange!R
814     && Rs.length > 0
815     && isForwardRange!(Rs[0]) == isInputRange!(Rs[0])
816     && allSatisfy!(canTestStartsWith!(pred, R), Rs))
817 {
818     static if (needles.length == 1)
819     {
820         static if (hasLength!R) //Note: Narrow strings don't have length.
821         {
822             //We delegate to find because find is very efficient.
823             //We store the length of the haystack so we don't have to save it.
824             auto len = haystack.length;
825             auto r2 = find!pred(haystack, needles[0]);
826             if (!r2.empty)
827                 return ptrdiff_t(len - r2.length);
828         }
829         else
830         {
831             import std.range : dropOne;
832 
833             if (needles[0].empty)
834                 return ptrdiff_t(0);
835 
836             ptrdiff_t result;
837 
838             //Default case, slower route doing startsWith iteration
839             for ( ; !haystack.empty ; ++result )
840             {
841                 //We compare the first elements of the ranges here before
842                 //forwarding to startsWith. This avoids making useless saves to
843                 //haystack/needle if they aren't even going to be mutated anyways.
844                 //It also cuts down on the amount of pops on haystack.
845                 if (binaryFun!pred(haystack.front, needles[0].front))
846                 {
847                     //Here, we need to save the needle before popping it.
848                     //haystack we pop in all paths, so we do that, and then save.
849                     haystack.popFront();
850                     if (startsWith!pred(haystack.save, needles[0].save.dropOne()))
851                         return result;
852                 }
853                 else
854                 {
855                     haystack.popFront();
856                 }
857             }
858         }
859         return ptrdiff_t(-1);
860     }
861     else
862     {
863         static struct Result
864         {
865             ptrdiff_t steps, needle; // both -1 when nothing was found
866             alias steps this; // compatible with previous ptrdiff_t return type
867             ptrdiff_t opIndex(size_t idx) // faking a tuple
868             {
869                 assert(idx < 2, "Type has only two members: pos and needle");
870                 return idx == 0 ? steps : needle;
871             }
872         }
873         Result result;
874 
875         foreach (i, Ri; Rs)
876         {
877             static if (isForwardRange!Ri)
878             {
879                 if (needles[i].empty)
880                 {
881                     result.needle = i;
882                     return result;
883                 }
884             }
885         }
886         Tuple!Rs t;
887         foreach (i, Ri; Rs)
888         {
889             static if (!isForwardRange!Ri)
890             {
891                 t[i] = needles[i];
892             }
893         }
894         for (; !haystack.empty ; ++result.steps, haystack.popFront())
895         {
896             foreach (i, Ri; Rs)
897             {
898                 static if (isForwardRange!Ri)
899                 {
900                     t[i] = needles[i].save;
901                 }
902             }
903             if (auto needle = startsWith!pred(haystack.save, t.expand))
904             {
905                 result.needle = needle - 1;
906                 return result;
907             }
908         }
909 
910         // no match was found
911         result.needle = -1;
912         result.steps = -1;
913         return result;
914     }
915 }
916 
917 /// ditto
918 ptrdiff_t countUntil(alias pred = "a == b", R, N)(R haystack, N needle)
919 if (isInputRange!R &&
920     is(typeof(binaryFun!pred(haystack.front, needle)) : bool))
921 {
922     bool pred2(ElementType!R a) { return binaryFun!pred(a, needle); }
923     return countUntil!pred2(haystack);
924 }
925 
926 ///
927 @safe unittest
928 {
929     assert(countUntil("hello world", "world") == 6);
930     assert(countUntil("hello world", 'r') == 8);
931     assert(countUntil("hello world", "programming") == -1);
932     assert(countUntil("日本語", "本語") == 1);
933     assert(countUntil("日本語", '語')   == 2);
934     assert(countUntil("日本語", "五") == -1);
935     assert(countUntil("日本語", '五') == -1);
936 
937     const arr = [0, 7, 12, 22, 9];
938     assert(countUntil(arr, [12, 22]) == 2);
939     assert(countUntil(arr, 9) == 4);
940     assert(countUntil!"a > b"(arr, 20) == 3);
941 }
942 
943 /// Multiple needles
944 @safe unittest
945 {
946     auto res = "...hello".countUntil("ha", "he");
947     assert(res.steps == 3);
948     assert(res.needle == 1); // the 2nd needle matched
949 
950     // returns -1 if no needle was found
951     res = "hello".countUntil("ha", "hu");
952     assert(res.steps == -1);
953     assert(res.needle == -1);
954 
955     // `steps` can also be implicitly compared
956     const arr = [0, 7, 12, 22, 9];
957     assert(countUntil(arr, 22, 12) == 2); // `12` found after 2 elements
958     assert(countUntil(arr, 5, 6) == -1);
959 }
960 
961 @safe unittest
962 {
963     import std.algorithm.iteration : filter;
964     import std.internal.test.dummyrange;
965 
966     assert(countUntil("日本語", "") == 0);
967     assert(countUntil("日本語"d, "") == 0);
968 
969     assert(countUntil("", "") == 0);
970     assert(countUntil("".filter!"true"(), "") == 0);
971 
972     auto rf = [0, 20, 12, 22, 9].filter!"true"();
973     assert(rf.countUntil!"a > b"((int[]).init) == 0);
974     assert(rf.countUntil!"a > b"(20) == 3);
975     assert(rf.countUntil!"a > b"([20, 8]) == 3);
976     assert(rf.countUntil!"a > b"([20, 10]) == -1);
977     assert(rf.countUntil!"a > b"([20, 8, 0]) == -1);
978 
979     auto r = new ReferenceForwardRange!int([0, 1, 2, 3, 4, 5, 6]);
980     auto r2 = new ReferenceForwardRange!int([3, 4]);
981     auto r3 = new ReferenceForwardRange!int([3, 5]);
982     assert(r.save.countUntil(3)  == 3);
983     assert(r.save.countUntil(r2) == 3);
984     assert(r.save.countUntil(7)  == -1);
985     assert(r.save.countUntil(r3) == -1);
986 }
987 
988 @safe unittest
989 {
990     assert(countUntil("hello world", "world", "asd") == 6);
991     assert(countUntil("hello world", "world", "ello") == 1);
992     assert(countUntil("hello world", "world", "") == 0);
993     assert(countUntil("hello world", "world", 'l') == 2);
994 }
995 
996 @safe unittest
997 {
998     auto res = "...hello".countUntil("hella", "hello");
999     assert(res == 3);
1000     assert(res.steps == 3);
1001     assert(res.needle == 1);
1002     // test tuple emulation
1003     assert(res[0] == 3);
1004     assert(res[1] == 1);
1005 
1006     // the first matching needle is chosen
1007     res = "...hello".countUntil("hell", "hello");
1008     assert(res == 3);
1009     assert(res.needle == 0);
1010 
1011     // no match
1012     auto noMatch = "hello world".countUntil("ha", "hu");
1013     assert(noMatch == -1);
1014     assert(noMatch.steps == -1);
1015     assert(noMatch.needle  == -1);
1016     // test tuple emulation
1017     assert(noMatch[0] == -1);
1018     assert(noMatch[1] == -1);
1019 }
1020 
1021 // test infinite ranges
1022 @safe unittest
1023 {
1024     import std.algorithm.iteration : joiner;
1025     import std.range : iota, repeat;
1026     import std.stdio;
1027     assert(10.iota.repeat.joiner.countUntil(9) == 9);
1028     assert(10.iota.repeat.joiner.countUntil(1, 2) == 1);
1029     assert(10.iota.repeat.joiner.countUntil!(a => a >= 9) == 9);
1030 }
1031 
1032 /++
1033     Counts elements in the given
1034     $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
1035     until the given predicate is true for one of the elements of `haystack`.
1036 
1037     Params:
1038         pred = Unary predicate for determining when to stop counting.
1039         haystack = The
1040             $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to be
1041             counted.
1042 
1043     Returns:
1044   - The number of elements which must be popped from the front of
1045     `haystack` before reaching an element for which
1046     $(LREF startsWith)`!pred(haystack)` is `true`.
1047   - If `startsWith!pred(haystack)` is not `true` for any element in
1048     `haystack`, then `-1` is returned.
1049   +/
1050 ptrdiff_t countUntil(alias pred, R)(R haystack)
1051 if (isInputRange!R &&
1052     is(typeof(unaryFun!pred(haystack.front)) : bool))
1053 {
1054     typeof(return) i;
1055     static if (isRandomAccessRange!R)
1056     {
1057         //Optimized RA implementation. Since we want to count *and* iterate at
1058         //the same time, it is more efficient this way.
1059         static if (hasLength!R)
1060         {
1061             immutable len = cast(typeof(return)) haystack.length;
1062             for ( ; i < len ; ++i )
1063                 if (unaryFun!pred(haystack[i])) return i;
1064         }
1065         else //if (isInfinite!R)
1066         {
1067             for ( ;  ; ++i )
1068                 if (unaryFun!pred(haystack[i])) return i;
1069         }
1070     }
1071     else static if (hasLength!R)
1072     {
1073         //For those odd ranges that have a length, but aren't RA.
1074         //It is faster to quick find, and then compare the lengths
1075         auto r2 = find!pred(haystack.save);
1076         if (!r2.empty) return cast(typeof(return)) (haystack.length - r2.length);
1077     }
1078     else //Everything else
1079     {
1080         alias T = ElementType!R; //For narrow strings forces dchar iteration
1081         foreach (T elem; haystack)
1082         {
1083             if (unaryFun!pred(elem)) return i;
1084             ++i;
1085         }
1086     }
1087 
1088     // Because of https://issues.dlang.org/show_bug.cgi?id=8804
1089     // Avoids both "unreachable code" or "no return statement"
1090     static if (isInfinite!R) assert(false, R.stringof ~ " must not be an"
1091             ~ " inifite range");
1092     else return -1;
1093 }
1094 
1095 ///
1096 @safe unittest
1097 {
1098     import std.ascii : isDigit;
1099     import std.uni : isWhite;
1100 
1101     assert(countUntil!(isWhite)("hello world") == 5);
1102     assert(countUntil!(isDigit)("hello world") == -1);
1103     assert(countUntil!"a > 20"([0, 7, 12, 22, 9]) == 3);
1104 }
1105 
1106 @safe unittest
1107 {
1108     import std.internal.test.dummyrange;
1109 
1110     // References
1111     {
1112         // input
1113         ReferenceInputRange!int r;
1114         r = new ReferenceInputRange!int([0, 1, 2, 3, 4, 5, 6]);
1115         assert(r.countUntil(3) == 3);
1116         r = new ReferenceInputRange!int([0, 1, 2, 3, 4, 5, 6]);
1117         assert(r.countUntil(7) == -1);
1118     }
1119     {
1120         // forward
1121         auto r = new ReferenceForwardRange!int([0, 1, 2, 3, 4, 5, 6]);
1122         assert(r.save.countUntil([3, 4]) == 3);
1123         assert(r.save.countUntil(3) == 3);
1124         assert(r.save.countUntil([3, 7]) == -1);
1125         assert(r.save.countUntil(7) == -1);
1126     }
1127     {
1128         // infinite forward
1129         auto r = new ReferenceInfiniteForwardRange!int(0);
1130         assert(r.save.countUntil([3, 4]) == 3);
1131         assert(r.save.countUntil(3) == 3);
1132     }
1133 }
1134 
1135 /**
1136 Checks if the given range ends with (one of) the given needle(s).
1137 The reciprocal of `startsWith`.
1138 
1139 Params:
1140     pred = The predicate to use for comparing elements between the range and
1141         the needle(s).
1142 
1143     doesThisEnd = The
1144         $(REF_ALTTEXT bidirectional range, isBidirectionalRange, std,range,primitives)
1145         to check.
1146 
1147     withOneOfThese = The needles to check against, which may be single
1148         elements, or bidirectional ranges of elements.
1149 
1150     withThis = The single element to check.
1151 
1152 Returns:
1153 0 if the needle(s) do not occur at the end of the given range;
1154 otherwise the position of the matching needle, that is, 1 if the range ends
1155 with `withOneOfThese[0]`, 2 if it ends with `withOneOfThese[1]`, and so
1156 on.
1157 
1158 In the case when no needle parameters are given, return `true` iff back of
1159 `doesThisStart` fulfils predicate `pred`.
1160 */
1161 uint endsWith(alias pred = "a == b", Range, Needles...)(Range doesThisEnd, Needles withOneOfThese)
1162 if (isBidirectionalRange!Range && Needles.length > 1 &&
1163     allSatisfy!(canTestStartsWith!(pred, Range), Needles))
1164 {
1165     alias haystack = doesThisEnd;
1166     alias needles  = withOneOfThese;
1167 
1168     // Make one pass looking for empty ranges in needles
1169     foreach (i, Unused; Needles)
1170     {
1171         // Empty range matches everything
1172         static if (!is(typeof(binaryFun!pred(haystack.back, needles[i])) : bool))
1173         {
1174             if (needles[i].empty) return i + 1;
1175         }
1176     }
1177 
1178     for (; !haystack.empty; haystack.popBack())
1179     {
1180         foreach (i, Unused; Needles)
1181         {
1182             static if (is(typeof(binaryFun!pred(haystack.back, needles[i])) : bool))
1183             {
1184                 // Single-element
1185                 if (binaryFun!pred(haystack.back, needles[i]))
1186                 {
1187                     // found, but continue to account for one-element
1188                     // range matches (consider endsWith("ab", "b",
1189                     // 'b') should return 1, not 2).
1190                     continue;
1191                 }
1192             }
1193             else
1194             {
1195                 if (binaryFun!pred(haystack.back, needles[i].back))
1196                     continue;
1197             }
1198 
1199             // This code executed on failure to match
1200             // Out with this guy, check for the others
1201             uint result = endsWith!pred(haystack, needles[0 .. i], needles[i + 1 .. $]);
1202             if (result > i) ++result;
1203             return result;
1204         }
1205 
1206         // If execution reaches this point, then the back matches for all
1207         // needles ranges. What we need to do now is to lop off the back of
1208         // all ranges involved and recurse.
1209         foreach (i, Unused; Needles)
1210         {
1211             static if (is(typeof(binaryFun!pred(haystack.back, needles[i])) : bool))
1212             {
1213                 // Test has passed in the previous loop
1214                 return i + 1;
1215             }
1216             else
1217             {
1218                 needles[i].popBack();
1219                 if (needles[i].empty) return i + 1;
1220             }
1221         }
1222     }
1223     return 0;
1224 }
1225 
1226 /// Ditto
1227 bool endsWith(alias pred = "a == b", R1, R2)(R1 doesThisEnd, R2 withThis)
1228 if (isBidirectionalRange!R1 &&
1229     isBidirectionalRange!R2 &&
1230     is(typeof(binaryFun!pred(doesThisEnd.back, withThis.back)) : bool))
1231 {
1232     alias haystack = doesThisEnd;
1233     alias needle   = withThis;
1234 
1235     static if (is(typeof(pred) : string))
1236         enum isDefaultPred = pred == "a == b";
1237     else
1238         enum isDefaultPred = false;
1239 
1240     static if (isDefaultPred && isArray!R1 && isArray!R2 &&
1241                is(immutable ElementEncodingType!R1 == immutable ElementEncodingType!R2))
1242     {
1243         if (haystack.length < needle.length) return false;
1244 
1245         return haystack[$ - needle.length .. $] == needle;
1246     }
1247     else
1248     {
1249         import std.range : retro;
1250         return startsWith!pred(retro(doesThisEnd), retro(withThis));
1251     }
1252 }
1253 
1254 /// Ditto
1255 bool endsWith(alias pred = "a == b", R, E)(R doesThisEnd, E withThis)
1256 if (isBidirectionalRange!R &&
1257     is(typeof(binaryFun!pred(doesThisEnd.back, withThis)) : bool))
1258 {
1259     if (doesThisEnd.empty)
1260         return false;
1261 
1262     static if (is(typeof(pred) : string))
1263         enum isDefaultPred = pred == "a == b";
1264     else
1265         enum isDefaultPred = false;
1266 
1267     alias predFunc = binaryFun!pred;
1268 
1269     // auto-decoding special case
1270     static if (isNarrowString!R)
1271     {
1272         // statically determine decoding is unnecessary to evaluate pred
1273         static if (isDefaultPred && isSomeChar!E && E.sizeof <= ElementEncodingType!R.sizeof)
1274             return doesThisEnd[$ - 1] == withThis;
1275         // specialize for ASCII as to not change previous behavior
1276         else
1277         {
1278             if (withThis <= 0x7F)
1279                 return predFunc(doesThisEnd[$ - 1], withThis);
1280             else
1281                 return predFunc(doesThisEnd.back, withThis);
1282         }
1283     }
1284     else
1285     {
1286         return predFunc(doesThisEnd.back, withThis);
1287     }
1288 }
1289 
1290 /// Ditto
1291 bool endsWith(alias pred, R)(R doesThisEnd)
1292 if (isInputRange!R &&
1293     ifTestable!(typeof(doesThisEnd.front), unaryFun!pred))
1294 {
1295     return !doesThisEnd.empty && unaryFun!pred(doesThisEnd.back);
1296 }
1297 
1298 ///
1299 @safe unittest
1300 {
1301     import std.ascii : isAlpha;
1302     assert("abc".endsWith!(a => a.isAlpha));
1303     assert("abc".endsWith!isAlpha);
1304 
1305     assert(!"ab1".endsWith!(a => a.isAlpha));
1306 
1307     assert(!"ab1".endsWith!isAlpha);
1308     assert(!"".endsWith!(a => a.isAlpha));
1309 
1310     import std.algorithm.comparison : among;
1311     assert("abc".endsWith!(a => a.among('c', 'd') != 0));
1312     assert(!"abc".endsWith!(a => a.among('a', 'b') != 0));
1313 
1314     assert(endsWith("abc", ""));
1315     assert(!endsWith("abc", "b"));
1316     assert(endsWith("abc", "a", 'c') == 2);
1317     assert(endsWith("abc", "c", "a") == 1);
1318     assert(endsWith("abc", "c", "c") == 1);
1319     assert(endsWith("abc", "bc", "c") == 2);
1320     assert(endsWith("abc", "x", "c", "b") == 2);
1321     assert(endsWith("abc", "x", "aa", "bc") == 3);
1322     assert(endsWith("abc", "x", "aaa", "sab") == 0);
1323     assert(endsWith("abc", "x", "aaa", 'c', "sab") == 3);
1324 }
1325 
1326 @safe unittest
1327 {
1328     import std.algorithm.iteration : filterBidirectional;
1329     import std.conv : to;
1330     import std.meta : AliasSeq;
1331 
1332     static foreach (S; AliasSeq!(char[], wchar[], dchar[], string, wstring, dstring))
1333     (){ // workaround slow optimizations for large functions
1334         // https://issues.dlang.org/show_bug.cgi?id=2396
1335         assert(!endsWith(to!S("abc"), 'a'));
1336         assert(endsWith(to!S("abc"), 'a', 'c') == 2);
1337         assert(!endsWith(to!S("abc"), 'x', 'n', 'b'));
1338         assert(endsWith(to!S("abc"), 'x', 'n', 'c') == 3);
1339         assert(endsWith(to!S("abc\uFF28"), 'a', '\uFF28', 'c') == 2);
1340 
1341         static foreach (T; AliasSeq!(char[], wchar[], dchar[], string, wstring, dstring))
1342         {
1343             //Lots of strings
1344             assert(endsWith(to!S("abc"), to!T("")));
1345             assert(!endsWith(to!S("abc"), to!T("a")));
1346             assert(!endsWith(to!S("abc"), to!T("b")));
1347             assert(endsWith(to!S("abc"), to!T("bc"), 'c') == 2);
1348             assert(endsWith(to!S("abc"), to!T("a"), "c") == 2);
1349             assert(endsWith(to!S("abc"), to!T("c"), "a") == 1);
1350             assert(endsWith(to!S("abc"), to!T("c"), "c") == 1);
1351             assert(endsWith(to!S("abc"), to!T("x"), 'c', "b") == 2);
1352             assert(endsWith(to!S("abc"), 'x', to!T("aa"), "bc") == 3);
1353             assert(endsWith(to!S("abc"), to!T("x"), "aaa", "sab") == 0);
1354             assert(endsWith(to!S("abc"), to!T("x"), "aaa", "c", "sab") == 3);
1355             assert(endsWith(to!S("\uFF28el\uFF4co"), to!T("l\uFF4co")));
1356             assert(endsWith(to!S("\uFF28el\uFF4co"), to!T("lo"), to!T("l\uFF4co")) == 2);
1357 
1358             //Unicode
1359             assert(endsWith(to!S("\uFF28el\uFF4co"), to!T("l\uFF4co")));
1360             assert(endsWith(to!S("\uFF28el\uFF4co"), to!T("lo"), to!T("l\uFF4co")) == 2);
1361             assert(endsWith(to!S("日本語"), to!T("本語")));
1362             assert(endsWith(to!S("日本語"), to!T("日本語")));
1363             assert(!endsWith(to!S("本語"), to!T("日本語")));
1364 
1365             //Empty
1366             assert(endsWith(to!S(""),  T.init));
1367             assert(!endsWith(to!S(""), 'a'));
1368             assert(endsWith(to!S("a"), T.init));
1369             assert(endsWith(to!S("a"), T.init, "") == 1);
1370             assert(endsWith(to!S("a"), T.init, 'a') == 1);
1371             assert(endsWith(to!S("a"), 'a', T.init) == 2);
1372         }
1373     }();
1374 
1375     static foreach (T; AliasSeq!(int, short))
1376     {{
1377         immutable arr = cast(T[])[0, 1, 2, 3, 4, 5];
1378 
1379         //RA range
1380         assert(endsWith(arr, cast(int[]) null));
1381         assert(!endsWith(arr, 0));
1382         assert(!endsWith(arr, 4));
1383         assert(endsWith(arr, 5));
1384         assert(endsWith(arr, 0, 4, 5) == 3);
1385         assert(endsWith(arr, [5]));
1386         assert(endsWith(arr, [4, 5]));
1387         assert(endsWith(arr, [4, 5], 7) == 1);
1388         assert(!endsWith(arr, [2, 4, 5]));
1389         assert(endsWith(arr, [2, 4, 5], [3, 4, 5]) == 2);
1390 
1391         //Normal input range
1392         assert(!endsWith(filterBidirectional!"true"(arr), 4));
1393         assert(endsWith(filterBidirectional!"true"(arr), 5));
1394         assert(endsWith(filterBidirectional!"true"(arr), [5]));
1395         assert(endsWith(filterBidirectional!"true"(arr), [4, 5]));
1396         assert(endsWith(filterBidirectional!"true"(arr), [4, 5], 7) == 1);
1397         assert(!endsWith(filterBidirectional!"true"(arr), [2, 4, 5]));
1398         assert(endsWith(filterBidirectional!"true"(arr), [2, 4, 5], [3, 4, 5]) == 2);
1399         assert(endsWith(arr, filterBidirectional!"true"([4, 5])));
1400         assert(endsWith(arr, filterBidirectional!"true"([4, 5]), 7) == 1);
1401         assert(!endsWith(arr, filterBidirectional!"true"([2, 4, 5])));
1402         assert(endsWith(arr, [2, 4, 5], filterBidirectional!"true"([3, 4, 5])) == 2);
1403 
1404         //Non-default pred
1405         assert(endsWith!("a%10 == b%10")(arr, [14, 15]));
1406         assert(!endsWith!("a%10 == b%10")(arr, [15, 14]));
1407     }}
1408 }
1409 
1410 @safe pure unittest
1411 {
1412     //example from https://issues.dlang.org/show_bug.cgi?id=19727
1413     import std.path : asRelativePath;
1414     string[] ext = ["abc", "def", "ghi"];
1415     string path = "/foo/file.def";
1416     assert(ext.any!(e => path.asRelativePath("/foo").endsWith(e)) == true);
1417     assert(ext.any!(e => path.asRelativePath("/foo").startsWith(e)) == false);
1418 }
1419 
1420 private enum bool hasConstEmptyMember(T) = is(typeof(((const T* a) => (*a).empty)(null)) : bool);
1421 
1422 /**
1423 Iterates the passed range and selects the extreme element with `less`.
1424 If the extreme element occurs multiple time, the first occurrence will be
1425 returned.
1426 
1427 Params:
1428     map = custom accessor for the comparison key
1429     selector = custom mapping for the extrema selection
1430     r = Range from which the extreme value will be selected
1431     seedElement = custom seed to use as initial element
1432 
1433 Returns:
1434     The extreme value according to `map` and `selector` of the passed-in values.
1435 */
1436 private auto extremum(alias map, alias selector = "a < b", Range)(Range r)
1437 if (isInputRange!Range && !isInfinite!Range &&
1438     is(typeof(unaryFun!map(ElementType!(Range).init))))
1439 in
1440 {
1441     assert(!r.empty, "r is an empty range");
1442 }
1443 do
1444 {
1445     import std.typecons : Rebindable2;
1446 
1447     alias Element = ElementType!Range;
1448     auto seed = Rebindable2!Element(r.front);
1449     r.popFront();
1450     return extremum!(map, selector)(r, seed.get);
1451 }
1452 
1453 private auto extremum(alias map, alias selector = "a < b", Range,
1454                       RangeElementType = ElementType!Range)
1455                      (Range r, RangeElementType seedElement)
1456 if (isInputRange!Range && !isInfinite!Range &&
1457     !is(CommonType!(ElementType!Range, RangeElementType) == void) &&
1458      is(typeof(unaryFun!map(ElementType!(Range).init))))
1459 {
1460     import std.typecons : Rebindable2;
1461 
1462     alias mapFun = unaryFun!map;
1463     alias selectorFun = binaryFun!selector;
1464 
1465     alias Element = ElementType!Range;
1466     alias CommonElement = CommonType!(Element, RangeElementType);
1467     auto extremeElement = Rebindable2!CommonElement(seedElement);
1468 
1469     // if we only have one statement in the loop, it can be optimized a lot better
1470     static if (__traits(isSame, map, a => a))
1471     {
1472         // direct access via a random access range is faster
1473         static if (isRandomAccessRange!Range)
1474         {
1475             foreach (const i; 0 .. r.length)
1476             {
1477                 if (selectorFun(r[i], extremeElement.get))
1478                 {
1479                     extremeElement = r[i];
1480                 }
1481             }
1482         }
1483         else
1484         {
1485             while (!r.empty)
1486             {
1487                 if (selectorFun(r.front, extremeElement.get))
1488                 {
1489                     extremeElement = r.front;
1490                 }
1491                 r.popFront();
1492             }
1493         }
1494     }
1495     else
1496     {
1497         alias MapType = Unqual!(typeof(mapFun(CommonElement.init)));
1498         MapType extremeElementMapped = mapFun(extremeElement.get);
1499 
1500         // direct access via a random access range is faster
1501         static if (isRandomAccessRange!Range)
1502         {
1503             foreach (const i; 0 .. r.length)
1504             {
1505                 MapType mapElement = mapFun(r[i]);
1506                 if (selectorFun(mapElement, extremeElementMapped))
1507                 {
1508                     extremeElement = r[i];
1509                     extremeElementMapped = mapElement;
1510                 }
1511             }
1512         }
1513         else
1514         {
1515             while (!r.empty)
1516             {
1517                 MapType mapElement = mapFun(r.front);
1518                 if (selectorFun(mapElement, extremeElementMapped))
1519                 {
1520                     extremeElement = r.front;
1521                     extremeElementMapped = mapElement;
1522                 }
1523                 r.popFront();
1524             }
1525         }
1526     }
1527     return extremeElement.get;
1528 }
1529 
1530 private auto extremum(alias selector = "a < b", Range)(Range r)
1531 if (isInputRange!Range && !isInfinite!Range &&
1532     !is(typeof(unaryFun!selector(ElementType!(Range).init))))
1533 {
1534     return extremum!(a => a, selector)(r);
1535 }
1536 
1537 // if we only have one statement in the loop it can be optimized a lot better
1538 private auto extremum(alias selector = "a < b", Range,
1539                       RangeElementType = ElementType!Range)
1540                      (Range r, RangeElementType seedElement)
1541 if (isInputRange!Range && !isInfinite!Range &&
1542     !is(CommonType!(ElementType!Range, RangeElementType) == void) &&
1543     !is(typeof(unaryFun!selector(ElementType!(Range).init))))
1544 {
1545     return extremum!(a => a, selector)(r, seedElement);
1546 }
1547 
1548 @safe pure unittest
1549 {
1550     // allows a custom map to select the extremum
1551     assert([[0, 4], [1, 2]].extremum!"a[0]" == [0, 4]);
1552     assert([[0, 4], [1, 2]].extremum!"a[1]" == [1, 2]);
1553 
1554     // allows a custom selector for comparison
1555     assert([[0, 4], [1, 2]].extremum!("a[0]", "a > b") == [1, 2]);
1556     assert([[0, 4], [1, 2]].extremum!("a[1]", "a > b") == [0, 4]);
1557 
1558     // use a custom comparator
1559     import std.math.operations : cmp;
1560     assert([-2., 0, 5].extremum!cmp == 5.0);
1561     assert([-2., 0, 2].extremum!`cmp(a, b) < 0` == -2.0);
1562 
1563     // combine with map
1564     import std.range : enumerate;
1565     assert([-3., 0, 5].enumerate.extremum!(`a.value`, cmp) == tuple(2, 5.0));
1566     assert([-2., 0, 2].enumerate.extremum!(`a.value`, `cmp(a, b) < 0`) == tuple(0, -2.0));
1567 
1568     // seed with a custom value
1569     int[] arr;
1570     assert(arr.extremum(1) == 1);
1571 }
1572 
1573 @safe pure nothrow unittest
1574 {
1575     // 2d seeds
1576     int[][] arr2d;
1577     assert(arr2d.extremum([1]) == [1]);
1578 
1579     // allow seeds of different types (implicit casting)
1580     assert(extremum([2, 3, 4], 1.5) == 1.5);
1581 }
1582 
1583 @safe pure unittest
1584 {
1585     import std.range : enumerate, iota;
1586 
1587     // forward ranges
1588     assert(iota(1, 5).extremum() == 1);
1589     assert(iota(2, 5).enumerate.extremum!"a.value" == tuple(0, 2));
1590 
1591     // should work with const
1592     const(int)[] immArr = [2, 1, 3];
1593     assert(immArr.extremum == 1);
1594 
1595     // should work with immutable
1596     immutable(int)[] immArr2 = [2, 1, 3];
1597     assert(immArr2.extremum == 1);
1598 
1599     // with strings
1600     assert(["b", "a", "c"].extremum == "a");
1601 
1602     // with all dummy ranges
1603     import std.internal.test.dummyrange;
1604     foreach (DummyType; AllDummyRanges)
1605     {
1606         DummyType d;
1607         assert(d.extremum == 1);
1608         assert(d.extremum!(a => a)  == 1);
1609         assert(d.extremum!`a > b` == 10);
1610         assert(d.extremum!(a => a, `a > b`) == 10);
1611     }
1612 
1613     // compiletime
1614     enum ctExtremum = iota(1, 5).extremum;
1615     assert(ctExtremum == 1);
1616 }
1617 
1618 @nogc @safe nothrow pure unittest
1619 {
1620     static immutable arr = [7, 3, 4, 2, 1, 8];
1621     assert(arr.extremum == 1);
1622 
1623     static immutable arr2d = [[1, 9], [3, 1], [4, 2]];
1624     assert(arr2d.extremum!"a[1]" == arr2d[1]);
1625 }
1626 
1627 // https://issues.dlang.org/show_bug.cgi?id=17982
1628 @safe unittest
1629 {
1630     class B
1631     {
1632         int val;
1633         this(int val){ this.val = val; }
1634     }
1635 
1636     const(B) doStuff(const(B)[] v)
1637     {
1638         return v.extremum!"a.val";
1639     }
1640     assert(doStuff([new B(1), new B(0), new B(2)]).val == 0);
1641 
1642     const(B)[] arr = [new B(0), new B(1)];
1643     // can't compare directly - https://issues.dlang.org/show_bug.cgi?id=1824
1644     assert(arr.extremum!"a.val".val == 0);
1645 }
1646 
1647 // https://issues.dlang.org/show_bug.cgi?id=22786
1648 @nogc @safe nothrow pure unittest
1649 {
1650     struct S
1651     {
1652         immutable int value;
1653     }
1654 
1655     assert([S(5), S(6)].extremum!"a.value" == S(5));
1656 }
1657 
1658 // https://issues.dlang.org/show_bug.cgi?id=24027
1659 @safe nothrow unittest
1660 {
1661     class A
1662     {
1663         int a;
1664         this(int a)
1665         {
1666             this.a = a;
1667         }
1668     }
1669 
1670     auto test = new A(5);
1671     A[] arr = [test];
1672     assert(maxElement!"a.a"(arr) is test);
1673 }
1674 
1675 // find
1676 /**
1677 Finds an element `e` of an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
1678 where `pred(e)` is `true`.
1679 $(P
1680 $(PANEL
1681 $(UL
1682 $(LI `find` behaves similarly to `dropWhile` in other languages.)
1683 $(LI To _find the *last* matching element in a
1684 $(REF_ALTTEXT bidirectional, isBidirectionalRange, std,range,primitives) `haystack`,
1685 call `find!pred(retro(haystack))`. See $(REF retro, std,range).)
1686 )))
1687 
1688 Complexity:
1689     `find` performs $(BIGOH walkLength(haystack)) evaluations of `pred`.
1690 
1691 Params:
1692 
1693     pred = The predicate to match an element.
1694     haystack = The $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
1695                searched in.
1696 
1697 Returns:
1698     `haystack` advanced such that the front element satisfies `pred`.
1699     If no such element exists, returns an empty `haystack`.
1700 */
1701 InputRange find(alias pred, InputRange)(InputRange haystack)
1702 if (isInputRange!InputRange)
1703 {
1704     alias R = InputRange;
1705     alias predFun = unaryFun!pred;
1706     static if (isNarrowString!R)
1707     {
1708         import std.utf : decode;
1709 
1710         immutable len = haystack.length;
1711         size_t i = 0, next = 0;
1712         while (next < len)
1713         {
1714             if (predFun(decode(haystack, next)))
1715                 return haystack[i .. $];
1716             i = next;
1717         }
1718         return haystack[$ .. $];
1719     }
1720     else
1721     {
1722         //standard range
1723         for ( ; !haystack.empty; haystack.popFront() )
1724         {
1725             if (predFun(haystack.front))
1726                 break;
1727         }
1728         return haystack;
1729     }
1730 }
1731 
1732 ///
1733 @safe unittest
1734 {
1735     auto arr = [ 1, 2, 3, 4, 1 ];
1736     assert(find!("a > 2")(arr) == [ 3, 4, 1 ]);
1737 
1738     // with predicate alias
1739     bool pred(int e) => e + 1 > 1.5;
1740     assert(find!(pred)(arr) == arr);
1741 }
1742 
1743 @safe pure unittest
1744 {
1745     int[] r = [ 1, 2, 3 ];
1746     assert(find!(a=>a > 2)(r) == [3]);
1747     bool pred(int x) { return x + 1 > 1.5; }
1748     assert(find!(pred)(r) == r);
1749 
1750     assert(find!(a=>a > 'v')("hello world") == "world");
1751     assert(find!(a=>a%4 == 0)("日本語") == "本語");
1752 }
1753 
1754 /**
1755 Finds an individual element in an $(REF_ALTTEXT input range, isInputRange, std,range,primitives).
1756 Elements of `haystack` are compared with `needle` by using predicate
1757 `pred` with `pred(haystack.front, needle)`.
1758 The predicate is passed to $(REF binaryFun, std, functional), and can either accept a
1759 string, or any callable that can be executed via `pred(element, element)`.
1760 
1761 If `haystack` is a $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives),
1762 `needle` can be a $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) too.
1763 In this case `startsWith!pred(haystack, needle)` is evaluated on each evaluation.
1764 
1765 $(NOTE To find the first element $(I not) matching the needle, use predicate `"a != b"`.)
1766 
1767 Complexity:
1768     `find` performs $(BIGOH walkLength(haystack)) evaluations of `pred`.
1769     There are specializations that improve performance by taking
1770     advantage of $(REF_ALTTEXT bidirectional, isBidirectionalRange, std,range,primitives)
1771     or $(REF_ALTTEXT random access, isRandomAccessRange, std,range,primitives)
1772     ranges (where possible).
1773 
1774 Params:
1775 
1776     pred = The predicate for comparing each element with the needle, defaulting to equality `"a == b"`.
1777     haystack = The $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
1778                searched in.
1779     needle = The element searched for.
1780 
1781 Returns:
1782     `haystack` advanced such that the front element is the one searched for;
1783     that is, until `binaryFun!pred(haystack.front, needle)` is `true`. If no
1784     such position exists, returns an empty `haystack`.
1785 
1786 See_Also: $(LREF findAdjacent), $(LREF findAmong), $(LREF findSkip), $(LREF findSplit), $(LREF startsWith)
1787 */
1788 InputRange find(alias pred = "a == b", InputRange, Element)(InputRange haystack, scope Element needle)
1789 if (isInputRange!InputRange &&
1790     is (typeof(binaryFun!pred(haystack.front, needle)) : bool) &&
1791    !is (typeof(binaryFun!pred(haystack.front, needle.front)) : bool))
1792 {
1793     alias R = InputRange;
1794     alias E = Element;
1795     alias predFun = binaryFun!pred;
1796     static if (is(typeof(pred == "a == b")))
1797         enum isDefaultPred = pred == "a == b";
1798     else
1799         enum isDefaultPred = false;
1800     enum  isIntegralNeedle = isSomeChar!E || isIntegral!E || isBoolean!E;
1801 
1802     alias EType  = ElementType!R;
1803 
1804     // If the haystack is a SortedRange we can use binary search to find the needle.
1805     // Works only for the default find predicate and any SortedRange predicate.
1806     // https://issues.dlang.org/show_bug.cgi?id=8829
1807     import std.range : SortedRange;
1808     static if (is(InputRange : SortedRange!TT, TT) && isDefaultPred)
1809     {
1810         auto lb = haystack.lowerBound(needle);
1811         if (lb.length == haystack.length || haystack[lb.length] != needle)
1812             return haystack[$ .. $];
1813 
1814         return haystack[lb.length .. $];
1815     }
1816     else static if (isNarrowString!R)
1817     {
1818         alias EEType = ElementEncodingType!R;
1819         alias UEEType = Unqual!EEType;
1820 
1821         //These are two special cases which can search without decoding the UTF stream.
1822         static if (isDefaultPred && isIntegralNeedle)
1823         {
1824             import std.utf : canSearchInCodeUnits;
1825 
1826             //This special case deals with UTF8 search, when the needle
1827             //is represented by a single code point.
1828             //Note: "needle <= 0x7F" properly handles sign via unsigned promotion
1829             static if (is(UEEType == char))
1830             {
1831                 if (!__ctfe && canSearchInCodeUnits!char(needle))
1832                 {
1833                     static inout(R) trustedMemchr(ref return scope inout(R) haystack,
1834                                                   ref const scope E needle) @trusted nothrow pure
1835                     {
1836                         import core.stdc.string : memchr;
1837                         auto ptr = memchr(haystack.ptr, needle, haystack.length);
1838                         return ptr ?
1839                              haystack[cast(char*) ptr - haystack.ptr .. $] :
1840                              haystack[$ .. $];
1841                     }
1842                     return trustedMemchr(haystack, needle);
1843                 }
1844             }
1845 
1846             //Ditto, but for UTF16
1847             static if (is(UEEType == wchar))
1848             {
1849                 if (canSearchInCodeUnits!wchar(needle))
1850                 {
1851                     foreach (i, ref EEType e; haystack)
1852                     {
1853                         if (e == needle)
1854                             return haystack[i .. $];
1855                     }
1856                     return haystack[$ .. $];
1857                 }
1858             }
1859         }
1860 
1861         //Previous conditional optimizations did not succeed. Fallback to
1862         //unconditional implementations
1863         static if (isDefaultPred)
1864         {
1865             import std.utf : encode;
1866 
1867             //In case of default pred, it is faster to do string/string search.
1868             UEEType[is(UEEType == char) ? 4 : 2] buf;
1869 
1870             size_t len = encode(buf, needle);
1871             return find(haystack, buf[0 .. len]);
1872         }
1873         else
1874         {
1875             import std.utf : decode;
1876 
1877             //Explicit pred: we must test each character by the book.
1878             //We choose a manual decoding approach, because it is faster than
1879             //the built-in foreach, or doing a front/popFront for-loop.
1880             immutable len = haystack.length;
1881             size_t i = 0, next = 0;
1882             while (next < len)
1883             {
1884                 if (predFun(decode(haystack, next), needle))
1885                     return haystack[i .. $];
1886                 i = next;
1887             }
1888             return haystack[$ .. $];
1889         }
1890     }
1891     else static if (isArray!R)
1892     {
1893         // https://issues.dlang.org/show_bug.cgi?id=10403 optimization
1894         static if (isDefaultPred && isIntegral!EType && EType.sizeof == 1 && isIntegralNeedle)
1895         {
1896             import std.algorithm.comparison : max, min;
1897 
1898             R findHelper(return scope ref R haystack, ref E needle) @trusted nothrow pure
1899             {
1900                 import core.stdc.string : memchr;
1901 
1902                 EType* ptr = null;
1903                 //Note: we use "min/max" to handle sign mismatch.
1904                 if (min(EType.min, needle) == EType.min &&
1905                     max(EType.max, needle) == EType.max)
1906                 {
1907                     ptr = cast(EType*) memchr(haystack.ptr, needle,
1908                         haystack.length);
1909                 }
1910 
1911                 return ptr ?
1912                     haystack[ptr - haystack.ptr .. $] :
1913                     haystack[$ .. $];
1914             }
1915 
1916             if (!__ctfe)
1917                 return findHelper(haystack, needle);
1918         }
1919 
1920         //Default implementation.
1921         foreach (i, ref e; haystack)
1922             if (predFun(e, needle))
1923                 return haystack[i .. $];
1924         return haystack[$ .. $];
1925     }
1926     else
1927     {
1928         //Everything else. Walk.
1929         for ( ; !haystack.empty; haystack.popFront() )
1930         {
1931             if (predFun(haystack.front, needle))
1932                 break;
1933         }
1934         return haystack;
1935     }
1936 }
1937 
1938 ///
1939 @safe unittest
1940 {
1941     import std.range.primitives;
1942 
1943     auto arr = [1, 2, 4, 4, 4, 4, 5, 6, 9];
1944     assert(arr.find(4) == [4, 4, 4, 4, 5, 6, 9]);
1945     assert(arr.find(1) == arr);
1946     assert(arr.find(9) == [9]);
1947     assert(arr.find!((e, n) => e > n)(4) == [5, 6, 9]);
1948     assert(arr.find!((e, n) => e < n)(4) == arr);
1949     assert(arr.find(0).empty);
1950     assert(arr.find(10).empty);
1951     assert(arr.find(8).empty);
1952 
1953     assert(find("hello, world", ',') == ", world");
1954 }
1955 
1956 /// Case-insensitive find of a string
1957 @safe unittest
1958 {
1959     import std.range.primitives;
1960     import std.uni : toLower;
1961 
1962     string[] s = ["Hello", "world", "!"];
1963     assert(s.find!((e, n) => toLower(e) == n)("hello") == s);
1964 }
1965 
1966 @safe unittest
1967 {
1968     import std.algorithm.comparison : equal;
1969     import std.container : SList;
1970 
1971     auto lst = SList!int(1, 2, 5, 7, 3);
1972     assert(lst.front == 1);
1973     auto r = find(lst[], 5);
1974     assert(equal(r, SList!int(5, 7, 3)[]));
1975     assert(find([1, 2, 3, 5], 4).empty);
1976     assert(equal(find!"a > b"("hello", 'k'), "llo"));
1977 }
1978 
1979 @safe pure nothrow unittest
1980 {
1981     assert(!find              ([1, 2, 3], 2).empty);
1982     assert(!find!((a,b)=>a == b)([1, 2, 3], 2).empty);
1983     assert(!find              ([1, 2, 3], 2).empty);
1984     assert(!find!((a,b)=>a == b)([1, 2, 3], 2).empty);
1985 }
1986 
1987 @safe pure unittest
1988 {
1989     import std.meta : AliasSeq;
1990     static foreach (R; AliasSeq!(string, wstring, dstring))
1991     {
1992         static foreach (E; AliasSeq!(char, wchar, dchar))
1993         {
1994             assert(find              ("hello world", 'w') == "world");
1995             assert(find!((a,b)=>a == b)("hello world", 'w') == "world");
1996             assert(find              ("日c語", 'c') == "c語");
1997             assert(find!((a,b)=>a == b)("日c語", 'c') == "c語");
1998             assert(find              ("0123456789", 'A').empty);
1999             static if (E.sizeof >= 2)
2000             {
2001                 assert(find              ("日本語", '本') == "本語");
2002                 assert(find!((a,b)=>a == b)("日本語", '本') == "本語");
2003             }
2004         }
2005     }
2006 }
2007 
2008 @safe unittest
2009 {
2010     //CTFE
2011     static assert(find("abc", 'b') == "bc");
2012     static assert(find("日b語", 'b') == "b語");
2013     static assert(find("日本語", '本') == "本語");
2014     static assert(find([1, 2, 3], 2)  == [2, 3]);
2015 
2016     static assert(find              ([1, 2, 3], 2));
2017     static assert(find!((a,b)=>a == b)([1, 2, 3], 2));
2018     static assert(find              ([1, 2, 3], 2));
2019     static assert(find!((a,b)=>a == b)([1, 2, 3], 2));
2020 }
2021 
2022 @safe unittest
2023 {
2024     import std.exception : assertCTFEable;
2025     import std.meta : AliasSeq;
2026 
2027     void dg() @safe pure nothrow
2028     {
2029         byte[]  sarr = [1, 2, 3, 4];
2030         ubyte[] uarr = [1, 2, 3, 4];
2031         static foreach (arr; AliasSeq!(sarr, uarr))
2032         {
2033             static foreach (T; AliasSeq!(byte, ubyte, int, uint))
2034             {
2035                 assert(find(arr, cast(T) 3) == arr[2 .. $]);
2036                 assert(find(arr, cast(T) 9) == arr[$ .. $]);
2037             }
2038             assert(find(arr, 256) == arr[$ .. $]);
2039         }
2040     }
2041     dg();
2042     assertCTFEable!dg;
2043 }
2044 
2045 // https://issues.dlang.org/show_bug.cgi?id=11603
2046 @safe unittest
2047 {
2048     enum Foo : ubyte { A }
2049     assert([Foo.A].find(Foo.A).empty == false);
2050 
2051     ubyte x = 0;
2052     assert([x].find(x).empty == false);
2053 }
2054 
2055 /// ditto
2056 R1 find(alias pred = "a == b", R1, R2)(R1 haystack, scope R2 needle)
2057 if (isForwardRange!R1 && isForwardRange!R2
2058         && is(typeof(binaryFun!pred(haystack.front, needle.front)) : bool))
2059 {
2060     static if (!isRandomAccessRange!R1)
2061     {
2062         static if (is(typeof(pred == "a == b")) && pred == "a == b" && isSomeString!R1 && isSomeString!R2
2063                 && haystack[0].sizeof == needle[0].sizeof)
2064         {
2065             // return cast(R1) find(representation(haystack), representation(needle));
2066             // Specialization for simple string search
2067             alias Representation =
2068                 Select!(haystack[0].sizeof == 1, ubyte[],
2069                     Select!(haystack[0].sizeof == 2, ushort[], uint[]));
2070             // Will use the array specialization
2071             static TO force(TO, T)(inout T r) @trusted { return cast(TO) r; }
2072             return force!R1(.find!(pred, Representation, Representation)
2073                 (force!Representation(haystack), force!Representation(needle)));
2074         }
2075         else
2076         {
2077             return simpleMindedFind!pred(haystack, needle);
2078         }
2079     }
2080     else static if (!isBidirectionalRange!R2 || !hasSlicing!R1)
2081     {
2082         static if (!is(ElementType!R1 == ElementType!R2))
2083         {
2084             return simpleMindedFind!pred(haystack, needle);
2085         }
2086         else
2087         {
2088             // Prepare the search with needle's first element
2089             if (needle.empty)
2090                 return haystack;
2091 
2092             haystack = .find!pred(haystack, needle.front);
2093 
2094             static if (hasLength!R1 && hasLength!R2 && is(typeof(takeNone(haystack)) == R1))
2095             {
2096                 if (needle.length > haystack.length)
2097                     return takeNone(haystack);
2098             }
2099             else
2100             {
2101                 if (haystack.empty)
2102                     return haystack;
2103             }
2104 
2105             needle.popFront();
2106             size_t matchLen = 1;
2107 
2108             // Loop invariant: haystack[0 .. matchLen] matches everything in
2109             // the initial needle that was popped out of needle.
2110             for (;;)
2111             {
2112                 // Extend matchLength as much as possible
2113                 for (;;)
2114                 {
2115                     import std.range : takeNone;
2116 
2117                     if (needle.empty || haystack.empty)
2118                         return haystack;
2119 
2120                     static if (hasLength!R1 && is(typeof(takeNone(haystack)) == R1))
2121                     {
2122                         if (matchLen == haystack.length)
2123                             return takeNone(haystack);
2124                     }
2125 
2126                     if (!binaryFun!pred(haystack[matchLen], needle.front))
2127                         break;
2128 
2129                     ++matchLen;
2130                     needle.popFront();
2131                 }
2132 
2133                 auto bestMatch = haystack[0 .. matchLen];
2134                 haystack.popFront();
2135                 haystack = .find!pred(haystack, bestMatch);
2136             }
2137         }
2138     }
2139     else // static if (hasSlicing!R1 && isBidirectionalRange!R2)
2140     {
2141         if (needle.empty) return haystack;
2142 
2143         static if (hasLength!R2)
2144         {
2145             immutable needleLength = needle.length;
2146         }
2147         else
2148         {
2149             immutable needleLength = walkLength(needle.save);
2150         }
2151         if (needleLength > haystack.length)
2152         {
2153             return haystack[haystack.length .. haystack.length];
2154         }
2155         // Optimization in case the ranges are both SortedRanges.
2156         // Binary search can be used to find the first occurence
2157         // of the first element of the needle in haystack.
2158         // When it is found O(walklength(needle)) steps are performed.
2159         // https://issues.dlang.org/show_bug.cgi?id=8829 enhancement
2160         import std.algorithm.comparison : mismatch;
2161         import std.range : SortedRange;
2162         static if (is(R1 == R2)
2163                 && is(R1 : SortedRange!TT, TT)
2164                 && pred == "a == b")
2165         {
2166             auto needleFirstElem = needle[0];
2167             auto partitions      = haystack.trisect(needleFirstElem);
2168             auto firstElemLen    = partitions[1].length;
2169             size_t count         = 0;
2170 
2171             if (firstElemLen == 0)
2172                 return haystack[$ .. $];
2173 
2174             while (needle.front() == needleFirstElem)
2175             {
2176                 needle.popFront();
2177                 ++count;
2178 
2179                 if (count > firstElemLen)
2180                     return haystack[$ .. $];
2181             }
2182 
2183             auto m = mismatch(partitions[2], needle);
2184 
2185             if (m[1].empty)
2186                 return haystack[partitions[0].length + partitions[1].length - count .. $];
2187         }
2188         else static if (isRandomAccessRange!R2)
2189         {
2190             immutable lastIndex = needleLength - 1;
2191             auto last = needle[lastIndex];
2192             size_t j = lastIndex, skip = 0;
2193             for (; j < haystack.length;)
2194             {
2195                 if (!binaryFun!pred(haystack[j], last))
2196                 {
2197                     ++j;
2198                     continue;
2199                 }
2200                 immutable k = j - lastIndex;
2201                 // last elements match
2202                 for (size_t i = 0;; ++i)
2203                 {
2204                     if (i == lastIndex)
2205                         return haystack[k .. haystack.length];
2206                     if (!binaryFun!pred(haystack[k + i], needle[i]))
2207                         break;
2208                 }
2209                 if (skip == 0)
2210                 {
2211                     skip = 1;
2212                     while (skip < needleLength && needle[needleLength - 1 - skip] != needle[needleLength - 1])
2213                     {
2214                         ++skip;
2215                     }
2216                 }
2217                 j += skip;
2218             }
2219         }
2220         else
2221         {
2222             // @@@BUG@@@
2223             // auto needleBack = moveBack(needle);
2224             // Stage 1: find the step
2225             size_t step = 1;
2226             auto needleBack = needle.back;
2227             needle.popBack();
2228             for (auto i = needle.save; !i.empty && i.back != needleBack;
2229                     i.popBack(), ++step)
2230             {
2231             }
2232             // Stage 2: linear find
2233             size_t scout = needleLength - 1;
2234             for (;;)
2235             {
2236                 if (scout >= haystack.length)
2237                     break;
2238                 if (!binaryFun!pred(haystack[scout], needleBack))
2239                 {
2240                     ++scout;
2241                     continue;
2242                 }
2243                 // Found a match with the last element in the needle
2244                 auto cand = haystack[scout + 1 - needleLength .. haystack.length];
2245                 if (startsWith!pred(cand, needle))
2246                 {
2247                     // found
2248                     return cand;
2249                 }
2250                 scout += step;
2251             }
2252         }
2253         return haystack[haystack.length .. haystack.length];
2254     }
2255 }
2256 
2257 ///
2258 @safe unittest
2259 {
2260     import std.container : SList;
2261     import std.range.primitives : empty;
2262     import std.typecons : Tuple;
2263 
2264     assert(find("hello, world", "World").empty);
2265     assert(find("hello, world", "wo") == "world");
2266     assert([1, 2, 3, 4].find(SList!int(2, 3)[]) == [2, 3, 4]);
2267     alias C = Tuple!(int, "x", int, "y");
2268     auto a = [C(1,0), C(2,0), C(3,1), C(4,0)];
2269     assert(a.find!"a.x == b"([2, 3]) == [C(2,0), C(3,1), C(4,0)]);
2270     assert(a[1 .. $].find!"a.x == b"([2, 3]) == [C(2,0), C(3,1), C(4,0)]);
2271 }
2272 
2273 @safe unittest
2274 {
2275     import std.container : SList;
2276     alias C = Tuple!(int, "x", int, "y");
2277     assert([C(1,0), C(2,0), C(3,1), C(4,0)].find!"a.x == b"(SList!int(2, 3)[]) == [C(2,0), C(3,1), C(4,0)]);
2278 }
2279 
2280 // https://issues.dlang.org/show_bug.cgi?id=12470
2281 @safe unittest
2282 {
2283     import std.array : replace;
2284     inout(char)[] sanitize(inout(char)[] p)
2285     {
2286         return p.replace("\0", " ");
2287     }
2288     assert(sanitize("O\x00o") == "O o");
2289 }
2290 
2291 @safe unittest
2292 {
2293     import std.algorithm.comparison : equal;
2294     import std.container : SList;
2295 
2296     auto lst = SList!int(1, 2, 5, 7, 3);
2297     static assert(isForwardRange!(int[]));
2298     static assert(isForwardRange!(typeof(lst[])));
2299     auto r = find(lst[], [2, 5]);
2300     assert(equal(r, SList!int(2, 5, 7, 3)[]));
2301 }
2302 
2303 @safe unittest
2304 {
2305     import std.range : assumeSorted;
2306 
2307     auto r1 = assumeSorted([1, 2, 3, 3, 3, 4, 5, 6, 7, 8, 8, 8, 10]);
2308     auto r2 = assumeSorted([3, 3, 4, 5, 6, 7, 8, 8]);
2309     auto r3 = assumeSorted([3, 4, 5, 6, 7, 8]);
2310     auto r4 = assumeSorted([4, 5, 6]);
2311     auto r5 = assumeSorted([12, 13]);
2312     auto r6 = assumeSorted([8, 8, 10, 11]);
2313     auto r7 = assumeSorted([3, 3, 3, 3, 3, 3, 3]);
2314 
2315     assert(find(r1, r2) == assumeSorted([3, 3, 4, 5, 6, 7, 8, 8, 8, 10]));
2316     assert(find(r1, r3) == assumeSorted([3, 4, 5, 6, 7, 8, 8, 8, 10]));
2317     assert(find(r1, r4) == assumeSorted([4, 5, 6, 7, 8, 8, 8, 10]));
2318     assert(find(r1, r5).empty());
2319     assert(find(r1, r6).empty());
2320     assert(find(r1, r7).empty());
2321 }
2322 
2323 @safe unittest
2324 {
2325     import std.algorithm.comparison : equal;
2326     // @@@BUG@@@ removing static below makes unittest fail
2327     static struct BiRange
2328     {
2329         int[] payload;
2330         @property bool empty() { return payload.empty; }
2331         @property BiRange save() { return this; }
2332         @property ref int front() { return payload[0]; }
2333         @property ref int back() { return payload[$ - 1]; }
2334         void popFront() { return payload.popFront(); }
2335         void popBack() { return payload.popBack(); }
2336     }
2337     auto r = BiRange([1, 2, 3, 10, 11, 4]);
2338     assert(equal(find(r, [10, 11]), [10, 11, 4]));
2339 }
2340 
2341 @safe unittest
2342 {
2343     import std.container : SList;
2344 
2345     assert(find([ 1, 2, 3 ], SList!int(2, 3)[]) == [ 2, 3 ]);
2346     assert(find([ 1, 2, 1, 2, 3, 3 ], SList!int(2, 3)[]) == [ 2, 3, 3 ]);
2347 }
2348 
2349 // https://issues.dlang.org/show_bug.cgi?id=8334
2350 @safe unittest
2351 {
2352     import std.algorithm.iteration : filter;
2353     import std.range;
2354 
2355     auto haystack = [1, 2, 3, 4, 1, 9, 12, 42];
2356     auto needle = [12, 42, 27];
2357 
2358     //different overload of find, but it's the base case.
2359     assert(find(haystack, needle).empty);
2360 
2361     assert(find(haystack, takeExactly(filter!"true"(needle), 3)).empty);
2362     assert(find(haystack, filter!"true"(needle)).empty);
2363 }
2364 
2365 // https://issues.dlang.org/show_bug.cgi?id=11013
2366 @safe unittest
2367 {
2368     assert(find!"a == a"("abc","abc") == "abc");
2369 }
2370 
2371 // Internally used by some find() overloads above
2372 private R1 simpleMindedFind(alias pred, R1, R2)(R1 haystack, scope R2 needle)
2373 {
2374     enum estimateNeedleLength = hasLength!R1 && !hasLength!R2;
2375 
2376     static if (hasLength!R1)
2377     {
2378         static if (!hasLength!R2)
2379             size_t estimatedNeedleLength = 0;
2380         else
2381             immutable size_t estimatedNeedleLength = needle.length;
2382     }
2383 
2384     bool haystackTooShort()
2385     {
2386         static if (estimateNeedleLength)
2387         {
2388             return haystack.length < estimatedNeedleLength;
2389         }
2390         else
2391         {
2392             return haystack.empty;
2393         }
2394     }
2395 
2396   searching:
2397     for (;; haystack.popFront())
2398     {
2399         if (haystackTooShort())
2400         {
2401             // Failed search
2402             static if (hasLength!R1)
2403             {
2404                 static if (is(typeof(haystack[haystack.length ..
2405                                                 haystack.length]) : R1))
2406                     return haystack[haystack.length .. haystack.length];
2407                 else
2408                     return R1.init;
2409             }
2410             else
2411             {
2412                 assert(haystack.empty, "Haystack must be empty by now");
2413                 return haystack;
2414             }
2415         }
2416         static if (estimateNeedleLength)
2417             size_t matchLength = 0;
2418         for (auto h = haystack.save, n = needle.save;
2419              !n.empty;
2420              h.popFront(), n.popFront())
2421         {
2422             if (h.empty || !binaryFun!pred(h.front, n.front))
2423             {
2424                 // Failed searching n in h
2425                 static if (estimateNeedleLength)
2426                 {
2427                     if (estimatedNeedleLength < matchLength)
2428                         estimatedNeedleLength = matchLength;
2429                 }
2430                 continue searching;
2431             }
2432             static if (estimateNeedleLength)
2433                 ++matchLength;
2434         }
2435         break;
2436     }
2437     return haystack;
2438 }
2439 
2440 @safe unittest
2441 {
2442     // Test simpleMindedFind for the case where both haystack and needle have
2443     // length.
2444     struct CustomString
2445     {
2446     @safe:
2447         string _impl;
2448 
2449         // This is what triggers https://issues.dlang.org/show_bug.cgi?id=7992.
2450         @property size_t length() const { return _impl.length; }
2451         @property void length(size_t len) { _impl.length = len; }
2452 
2453         // This is for conformance to the forward range API (we deliberately
2454         // make it non-random access so that we will end up in
2455         // simpleMindedFind).
2456         @property bool empty() const { return _impl.empty; }
2457         @property dchar front() const { return _impl.front; }
2458         void popFront() { _impl.popFront(); }
2459         @property CustomString save() { return this; }
2460     }
2461 
2462     // If https://issues.dlang.org/show_bug.cgi?id=7992 occurs, this will throw an exception from calling
2463     // popFront() on an empty range.
2464     auto r = find(CustomString("a"), CustomString("b"));
2465     assert(r.empty);
2466 }
2467 
2468 /**
2469 Finds two or more `needles` into a `haystack`. The predicate $(D
2470 pred) is used throughout to compare elements. By default, elements are
2471 compared for equality.
2472 
2473 Params:
2474 
2475 pred = The predicate to use for comparing elements.
2476 
2477 haystack = The target of the search. Must be an input range.
2478 If any of `needles` is a range with elements comparable to
2479 elements in `haystack`, then `haystack` must be a
2480 $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives)
2481 such that the search can backtrack.
2482 
2483 needles = One or more items to search for. Each of `needles` must
2484 be either comparable to one element in `haystack`, or be itself a
2485 forward range with elements comparable with elements in
2486 `haystack`.
2487 
2488 Returns:
2489 
2490 A tuple containing `haystack` positioned to match one of the
2491 needles and also the 1-based index of the matching element in $(D
2492 needles) (0 if none of `needles` matched, 1 if `needles[0]`
2493 matched, 2 if `needles[1]` matched...). The first needle to be found
2494 will be the one that matches. If multiple needles are found at the
2495 same spot in the range, then the shortest one is the one which matches
2496 (if multiple needles of the same length are found at the same spot (e.g
2497 `"a"` and `'a'`), then the left-most of them in the argument list
2498 matches).
2499 
2500 The relationship between `haystack` and `needles` simply means
2501 that one can e.g. search for individual `int`s or arrays of $(D
2502 int)s in an array of `int`s. In addition, if elements are
2503 individually comparable, searches of heterogeneous types are allowed
2504 as well: a `double[]` can be searched for an `int` or a $(D
2505 short[]), and conversely a `long` can be searched for a `float`
2506 or a `double[]`. This makes for efficient searches without the need
2507 to coerce one side of the comparison into the other's side type.
2508 
2509 The complexity of the search is $(BIGOH haystack.length *
2510 max(needles.length)). (For needles that are individual items, length
2511 is considered to be 1.) The strategy used in searching several
2512 subranges at once maximizes cache usage by moving in `haystack` as
2513 few times as possible.
2514  */
2515 Tuple!(Range, size_t) find(alias pred = "a == b", Range, Needles...)
2516 (Range haystack, Needles needles)
2517 if (Needles.length > 1 && is(typeof(startsWith!pred(haystack, needles))))
2518 {
2519     for (;; haystack.popFront())
2520     {
2521         size_t r = startsWith!pred(haystack, needles);
2522         if (r || haystack.empty)
2523         {
2524             return tuple(haystack, r);
2525         }
2526     }
2527 }
2528 
2529 ///
2530 @safe unittest
2531 {
2532     import std.typecons : tuple;
2533     int[] a = [ 1, 4, 2, 3 ];
2534     assert(find(a, 4) == [ 4, 2, 3 ]);
2535     assert(find(a, [ 1, 4 ]) == [ 1, 4, 2, 3 ]);
2536     assert(find(a, [ 1, 3 ], 4) == tuple([ 4, 2, 3 ], 2));
2537     // Mixed types allowed if comparable
2538     assert(find(a, 5, [ 1.2, 3.5 ], 2.0) == tuple([ 2, 3 ], 3));
2539 }
2540 
2541 @safe unittest
2542 {
2543     auto s1 = "Mary has a little lamb";
2544     assert(find(s1, "has a", "has an") == tuple("has a little lamb", 1));
2545     assert(find(s1, 't', "has a", "has an") == tuple("has a little lamb", 2));
2546     assert(find(s1, 't', "has a", 'y', "has an") == tuple("y has a little lamb", 3));
2547     assert(find("abc", "bc").length == 2);
2548 }
2549 
2550 @safe unittest
2551 {
2552     import std.algorithm.internal : rndstuff;
2553     import std.meta : AliasSeq;
2554     import std.uni : toUpper;
2555 
2556     int[] a = [ 1, 2, 3 ];
2557     assert(find(a, 5).empty);
2558     assert(find(a, 2) == [2, 3]);
2559 
2560     foreach (T; AliasSeq!(int, double))
2561     {
2562         auto b = rndstuff!(T)();
2563         if (!b.length) continue;
2564         b[$ / 2] = 200;
2565         b[$ / 4] = 200;
2566         assert(find(b, 200).length == b.length - b.length / 4);
2567     }
2568 
2569     // Case-insensitive find of a string
2570     string[] s = [ "Hello", "world", "!" ];
2571     assert(find!("toUpper(a) == toUpper(b)")(s, "hello").length == 3);
2572 
2573     static bool f(string a, string b) { return toUpper(a) == toUpper(b); }
2574     assert(find!(f)(s, "hello").length == 3);
2575 }
2576 
2577 @safe unittest
2578 {
2579     import std.algorithm.comparison : equal;
2580     import std.algorithm.internal : rndstuff;
2581     import std.meta : AliasSeq;
2582     import std.range : retro;
2583 
2584     int[] a = [ 1, 2, 3, 2, 6 ];
2585     assert(find(retro(a), 5).empty);
2586     assert(equal(find(retro(a), 2), [ 2, 3, 2, 1 ][]));
2587 
2588     foreach (T; AliasSeq!(int, double))
2589     {
2590         auto b = rndstuff!(T)();
2591         if (!b.length) continue;
2592         b[$ / 2] = 200;
2593         b[$ / 4] = 200;
2594         assert(find(retro(b), 200).length ==
2595                 b.length - (b.length - 1) / 2);
2596     }
2597 }
2598 
2599 @safe unittest
2600 {
2601     import std.algorithm.comparison : equal;
2602     import std.internal.test.dummyrange;
2603 
2604     int[] a = [ -1, 0, 1, 2, 3, 4, 5 ];
2605     int[] b = [ 1, 2, 3 ];
2606     assert(find(a, b) == [ 1, 2, 3, 4, 5 ]);
2607     assert(find(b, a).empty);
2608 
2609     foreach (DummyType; AllDummyRanges)
2610     {
2611         DummyType d;
2612         auto findRes = find(d, 5);
2613         assert(equal(findRes, [5,6,7,8,9,10]));
2614     }
2615 }
2616 
2617 /**
2618  * Finds `needle` in `haystack` efficiently using the
2619  * $(LINK2 https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_string_search_algorithm,
2620  * Boyer-Moore) method.
2621  *
2622  * Params:
2623  * haystack = A random-access range with length and slicing.
2624  * needle = A $(LREF BoyerMooreFinder).
2625  *
2626  * Returns:
2627  * `haystack` advanced such that `needle` is a prefix of it (if no
2628  * such position exists, returns `haystack` advanced to termination).
2629  */
2630 RandomAccessRange find(RandomAccessRange, alias pred, InputRange)(
2631     RandomAccessRange haystack, scope BoyerMooreFinder!(pred, InputRange) needle)
2632 {
2633     return needle.beFound(haystack);
2634 }
2635 
2636 @safe unittest
2637 {
2638     string h = "/homes/aalexand/d/dmd/bin/../lib/libphobos.a(dmain2.o)"~
2639         "(.gnu.linkonce.tmain+0x74): In function `main' undefined reference"~
2640         " to `_Dmain':";
2641     string[] ns = ["libphobos", "function", " undefined", "`", ":"];
2642     foreach (n ; ns)
2643     {
2644         auto p = find(h, boyerMooreFinder(n));
2645         assert(!p.empty);
2646     }
2647 }
2648 
2649 ///
2650 @safe unittest
2651 {
2652     import std.range.primitives : empty;
2653     int[] a = [ -1, 0, 1, 2, 3, 4, 5 ];
2654     int[] b = [ 1, 2, 3 ];
2655 
2656     assert(find(a, boyerMooreFinder(b)) == [ 1, 2, 3, 4, 5 ]);
2657     assert(find(b, boyerMooreFinder(a)).empty);
2658 }
2659 
2660 @safe unittest
2661 {
2662     auto bm = boyerMooreFinder("for");
2663     auto match = find("Moor", bm);
2664     assert(match.empty);
2665 }
2666 
2667 // canFind
2668 /++
2669 Convenience function. Like find, but only returns whether or not the search
2670 was successful.
2671 
2672 For more information about `pred` see $(LREF find).
2673 
2674 See_Also:
2675 $(REF among, std,algorithm,comparison) for checking a value against multiple arguments.
2676  +/
2677 template canFind(alias pred="a == b")
2678 {
2679     /++
2680     Returns `true` if and only if `pred(e)` is true for any value `e` in the
2681     input range `range`.
2682     Performs (at most) $(BIGOH haystack.length) evaluations of `pred`.
2683      +/
2684     bool canFind(Range)(Range haystack)
2685     if (is(typeof(find!pred(haystack))))
2686     {
2687         return any!pred(haystack);
2688     }
2689 
2690     /++
2691     Returns `true` if and only if `needle` can be found in $(D
2692     range). Performs $(BIGOH haystack.length) evaluations of `pred`.
2693      +/
2694     bool canFind(Range, Element)(Range haystack, scope Element needle)
2695     if (is(typeof(find!pred(haystack, needle))))
2696     {
2697         return !find!pred(haystack, needle).empty;
2698     }
2699 
2700     /++
2701     Returns the 1-based index of the first needle found in `haystack`. If no
2702     needle is found, then `0` is returned.
2703 
2704     So, if used directly in the condition of an `if` statement or loop, the result
2705     will be `true` if one of the needles is found and `false` if none are
2706     found, whereas if the result is used elsewhere, it can either be cast to
2707     `bool` for the same effect or used to get which needle was found first
2708     without having to deal with the tuple that $(LREF find) returns for the
2709     same operation.
2710      +/
2711     size_t canFind(Range, Needles...)(Range haystack, scope Needles needles)
2712     if (Needles.length > 1 &&
2713         is(typeof(find!pred(haystack, needles))))
2714     {
2715         return find!pred(haystack, needles)[1];
2716     }
2717 }
2718 
2719 ///
2720 @safe unittest
2721 {
2722     const arr = [0, 1, 2, 3];
2723     assert(canFind(arr, 2));
2724     assert(!canFind(arr, 4));
2725 
2726     // find one of several needles
2727     assert(arr.canFind(3, 2));
2728     assert(arr.canFind(3, 2) == 2); // second needle found
2729     assert(arr.canFind([1, 3], 2) == 2);
2730 
2731     assert(canFind(arr, [1, 2], [2, 3]));
2732     assert(canFind(arr, [1, 2], [2, 3]) == 1);
2733     assert(canFind(arr, [1, 7], [2, 3]));
2734     assert(canFind(arr, [1, 7], [2, 3]) == 2);
2735     assert(!canFind(arr, [1, 3], [2, 4]));
2736     assert(canFind(arr, [1, 3], [2, 4]) == 0);
2737 }
2738 
2739 /**
2740  * Example using a custom predicate.
2741  * Note that the needle appears as the second argument of the predicate.
2742  */
2743 @safe unittest
2744 {
2745     auto words = [
2746         "apple",
2747         "beeswax",
2748         "cardboard"
2749     ];
2750     assert(!canFind(words, "bees"));
2751     assert( canFind!((string elem, string needle) => elem.startsWith(needle))(words, "bees"));
2752 }
2753 
2754 /// Search for multiple items in an array of items (search for needles in an array of haystacks)
2755 @safe unittest
2756 {
2757     string s1 = "aaa111aaa";
2758     string s2 = "aaa222aaa";
2759     string s3 = "aaa333aaa";
2760     string s4 = "aaa444aaa";
2761     const hay = [s1, s2, s3, s4];
2762     assert(hay.canFind!(e => e.canFind("111", "222")));
2763 }
2764 
2765 @safe unittest
2766 {
2767     import std.algorithm.internal : rndstuff;
2768 
2769     auto a = rndstuff!(int)();
2770     if (a.length)
2771     {
2772         auto b = a[a.length / 2];
2773         assert(canFind(a, b));
2774     }
2775 }
2776 
2777 @safe unittest
2778 {
2779     import std.algorithm.comparison : equal;
2780     assert(equal!(canFind!"a < b")([[1, 2, 3], [7, 8, 9]], [2, 8]));
2781 }
2782 
2783 // findAdjacent
2784 /**
2785 Advances `r` until it finds the first two adjacent elements `a`,
2786 `b` that satisfy `pred(a, b)`. Performs $(BIGOH r.length)
2787 evaluations of `pred`.
2788 
2789 For more information about `pred` see $(LREF find).
2790 
2791 Params:
2792     pred = The predicate to satisfy.
2793     r = A $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) to
2794         search in.
2795 
2796 Returns:
2797 `r` advanced to the first occurrence of two adjacent elements that satisfy
2798 the given predicate. If there are no such two elements, returns `r` advanced
2799 until empty.
2800 
2801 See_Also:
2802      $(LINK2 http://en.cppreference.com/w/cpp/algorithm/adjacent_find, STL's `adjacent_find`)
2803 */
2804 Range findAdjacent(alias pred = "a == b", Range)(Range r)
2805 if (isForwardRange!(Range))
2806 {
2807     auto ahead = r.save;
2808     if (!ahead.empty)
2809     {
2810         for (ahead.popFront(); !ahead.empty; r.popFront(), ahead.popFront())
2811         {
2812             if (binaryFun!(pred)(r.front, ahead.front)) return r;
2813         }
2814     }
2815     static if (!isInfinite!Range)
2816         return ahead;
2817     assert(0);
2818 }
2819 
2820 ///
2821 @safe unittest
2822 {
2823     int[] a = [ 11, 10, 10, 9, 8, 8, 7, 8, 9 ];
2824     auto r = findAdjacent(a);
2825     assert(r == [ 10, 10, 9, 8, 8, 7, 8, 9 ]);
2826     auto p = findAdjacent!("a < b")(a);
2827     assert(p == [ 7, 8, 9 ]);
2828 
2829 }
2830 
2831 @safe unittest
2832 {
2833     import std.algorithm.comparison : equal;
2834     import std.internal.test.dummyrange;
2835     import std.range;
2836 
2837     int[] a = [ 11, 10, 10, 9, 8, 8, 7, 8, 9 ];
2838     auto p = findAdjacent(a);
2839     assert(p == [10, 10, 9, 8, 8, 7, 8, 9 ]);
2840     p = findAdjacent!("a < b")(a);
2841     assert(p == [7, 8, 9]);
2842     // empty
2843     a = [];
2844     p = findAdjacent(a);
2845     assert(p.empty);
2846     // not found
2847     a = [ 1, 2, 3, 4, 5 ];
2848     p = findAdjacent(a);
2849     assert(p.empty);
2850     p = findAdjacent!"a > b"(a);
2851     assert(p.empty);
2852     ReferenceForwardRange!int rfr = new ReferenceForwardRange!int([1, 2, 3, 2, 2, 3]);
2853     assert(equal(findAdjacent(rfr), [2, 2, 3]));
2854 
2855     // https://issues.dlang.org/show_bug.cgi?id=9350
2856     assert(!repeat(1).findAdjacent().empty);
2857 }
2858 
2859 // findAmong
2860 /**
2861 Searches the given range for an element that matches one of the given choices.
2862 
2863 Advances `seq` by calling `seq.popFront` until either
2864 `find!(pred)(choices, seq.front)` is `true`, or `seq` becomes empty.
2865 Performs $(BIGOH seq.length * choices.length) evaluations of `pred`.
2866 
2867 For more information about `pred` see $(LREF find).
2868 
2869 Params:
2870     pred = The predicate to use for determining a match.
2871     seq = The $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to
2872         search.
2873     choices = A $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives)
2874         of possible choices.
2875 
2876 Returns:
2877 `seq` advanced to the first matching element, or until empty if there are no
2878 matching elements.
2879 
2880 See_Also: $(LREF find), $(REF among, std,algorithm,comparison)
2881 */
2882 InputRange findAmong(alias pred = "a == b", InputRange, ForwardRange)(
2883     InputRange seq, ForwardRange choices)
2884 if (isInputRange!InputRange && isForwardRange!ForwardRange)
2885 {
2886     for (; !seq.empty && find!pred(choices.save, seq.front).empty; seq.popFront())
2887     {
2888     }
2889     return seq;
2890 }
2891 
2892 ///
2893 @safe unittest
2894 {
2895     int[] a = [ -1, 0, 1, 2, 3, 4, 5 ];
2896     int[] b = [ 3, 1, 2 ];
2897     assert(findAmong(a, b) == a[2 .. $]);
2898 }
2899 
2900 @safe unittest
2901 {
2902     int[] a = [ -1, 0, 2, 1, 2, 3, 4, 5 ];
2903     int[] b = [ 1, 2, 3 ];
2904     assert(findAmong(a, b) == [2, 1, 2, 3, 4, 5 ]);
2905     assert(findAmong(b, [ 4, 6, 7 ][]).empty);
2906     assert(findAmong!("a == b")(a, b).length == a.length - 2);
2907     assert(findAmong!("a == b")(b, [ 4, 6, 7 ][]).empty);
2908 }
2909 
2910 // https://issues.dlang.org/show_bug.cgi?id=19765
2911 @system unittest
2912 {
2913     import std.range.interfaces : inputRangeObject;
2914     auto choices = inputRangeObject("b");
2915     auto f = "foobar".findAmong(choices);
2916     assert(f == "bar");
2917 }
2918 
2919 // findSkip
2920 /**
2921  * Finds `needle` in `haystack` and positions `haystack`
2922  * right after the first occurrence of `needle`.
2923  *
2924  * If no needle is provided, the `haystack` is advanced as long as `pred`
2925  * evaluates to `true`.
2926  * Similarly, the haystack is positioned so as `pred` evaluates to `false` for
2927  * `haystack.front`.
2928  *
2929  * For more information about `pred` see $(LREF find).
2930 
2931  * Params:
2932  *  haystack = The
2933  *   $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) to search
2934  *   in.
2935  *  needle = The
2936  *   $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) to search
2937  *   for.
2938  *  pred = Custom predicate for comparison of haystack and needle
2939  *
2940  * Returns: `true` if the needle was found, in which case `haystack` is
2941  * positioned after the end of the first occurrence of `needle`; otherwise
2942  * `false`, leaving `haystack` untouched. If no needle is provided, it returns
2943  *  the number of times `pred(haystack.front)` returned true.
2944  *
2945  * See_Also: $(LREF find)
2946  */
2947 bool findSkip(alias pred = "a == b", R1, R2)(ref R1 haystack, R2 needle)
2948 if (isForwardRange!R1 && isForwardRange!R2
2949         && is(typeof(binaryFun!pred(haystack.front, needle.front))))
2950 {
2951     auto parts = findSplit!pred(haystack, needle);
2952     if (parts[1].empty) return false;
2953     // found
2954     haystack = parts[2];
2955     return true;
2956 }
2957 
2958 ///
2959 @safe unittest
2960 {
2961     import std.range.primitives : empty;
2962     // Needle is found; s is replaced by the substring following the first
2963     // occurrence of the needle.
2964     string s = "abcdef";
2965     assert(findSkip(s, "cd") && s == "ef");
2966 
2967     // Needle is not found; s is left untouched.
2968     s = "abcdef";
2969     assert(!findSkip(s, "cxd") && s == "abcdef");
2970 
2971     // If the needle occurs at the end of the range, the range is left empty.
2972     s = "abcdef";
2973     assert(findSkip(s, "def") && s.empty);
2974 }
2975 
2976 // https://issues.dlang.org/show_bug.cgi?id=19020
2977 @safe unittest
2978 {
2979     static struct WrapperRange
2980     {
2981         string _r;
2982         @property auto empty() { return _r.empty(); }
2983         @property auto front() { return _r.front(); }
2984         auto popFront() { return _r.popFront(); }
2985         @property auto save() { return WrapperRange(_r.save); }
2986     }
2987     auto tmp = WrapperRange("there is a bug here: *");
2988     assert(!tmp.findSkip("*/"));
2989     assert(tmp._r == "there is a bug here: *");
2990 }
2991 
2992 /// ditto
2993 size_t findSkip(alias pred, R1)(ref R1 haystack)
2994 if (isForwardRange!R1 && ifTestable!(typeof(haystack.front), unaryFun!pred))
2995 {
2996     size_t result;
2997     while (!haystack.empty && unaryFun!pred(haystack.front))
2998     {
2999         result++;
3000         haystack.popFront;
3001     }
3002     return result;
3003 }
3004 
3005 ///
3006 @safe unittest
3007 {
3008     import std.ascii : isWhite;
3009     string s = "    abc";
3010     assert(findSkip!isWhite(s) && s == "abc");
3011     assert(!findSkip!isWhite(s) && s == "abc");
3012 
3013     s = "  ";
3014     assert(findSkip!isWhite(s) == 2);
3015 }
3016 
3017 @safe unittest
3018 {
3019     import std.ascii : isWhite;
3020 
3021     auto s = "  ";
3022     assert(findSkip!isWhite(s) == 2);
3023 }
3024 
3025 private struct FindSplitResult(ubyte emptyRangeIndex, Types...)
3026 {
3027     this(Types vals)
3028     {
3029         asTuple = typeof(asTuple)(vals);
3030     }
3031     void opAssign(typeof(asTuple) rhs)
3032     {
3033         asTuple = rhs;
3034     }
3035     Tuple!Types asTuple;
3036     alias asTuple this;
3037 
3038     static if (hasConstEmptyMember!(typeof(asTuple[emptyRangeIndex])))
3039     {
3040         bool opCast(T : bool)() const => !asTuple[emptyRangeIndex].empty;
3041     }
3042     else
3043     {
3044         bool opCast(T : bool)() => !asTuple[emptyRangeIndex].empty;
3045     }
3046 }
3047 
3048 /**
3049 These functions find the first occurrence of `needle` in `haystack` and then
3050 split `haystack` as follows.
3051 
3052 $(PANEL
3053 `findSplit` returns a tuple `result` containing $(I three) ranges.
3054 $(UL
3055 $(LI `result[0]` is the portion of `haystack` before `needle`)
3056 $(LI `result[1]` is the portion of
3057 `haystack` that matches `needle`)
3058 $(LI `result[2]` is the portion of `haystack`
3059 after the match.)
3060 )
3061 If `needle` was not found, `result[0]` comprehends `haystack`
3062 entirely and `result[1]` and `result[2]` are empty.
3063 
3064 `findSplitBefore` returns a tuple `result` containing two ranges.
3065 $(UL
3066 $(LI `result[0]` is the portion of `haystack` before `needle`)
3067 $(LI `result[1]` is the balance of `haystack` starting with the match.)
3068 )
3069 If `needle` was not found, `result[0]`
3070 comprehends `haystack` entirely and `result[1]` is empty.
3071 
3072 `findSplitAfter` returns a tuple `result` containing two ranges.
3073 $(UL
3074 $(LI `result[0]` is the portion of `haystack` up to and including the
3075 match)
3076 $(LI `result[1]` is the balance of `haystack` starting
3077 after the match.)
3078 )
3079 If `needle` was not found, `result[0]` is empty
3080 and `result[1]` is `haystack`.
3081 )
3082 $(P
3083 In all cases, the concatenation of the returned ranges spans the
3084 entire `haystack`.
3085 
3086 If `haystack` is a random-access range, all three components of the tuple have
3087 the same type as `haystack`. Otherwise, `haystack` must be a
3088 $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) and
3089 the type of `result[0]` (and `result[1]` for `findSplit`) is the same as
3090 the result of $(REF takeExactly, std,range).
3091 
3092 For more information about `pred` see $(LREF find).
3093 )
3094 Params:
3095     pred = Predicate to compare 2 elements.
3096     haystack = The forward range to search.
3097     needle = The forward range to look for.
3098 
3099 Returns:
3100 
3101 A sub-type of $(REF Tuple, std, typecons) of the split portions of `haystack` (see above for
3102 details). This sub-type of `Tuple` defines `opCast!bool`, which
3103 returns `true` when the separating `needle` was found and `false` otherwise.
3104 
3105 See_Also: $(LREF find)
3106  */
3107 auto findSplit(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle)
3108 if (isForwardRange!R1 && isForwardRange!R2)
3109 {
3110     static if (isSomeString!R1 && isSomeString!R2
3111             || (isRandomAccessRange!R1 && hasSlicing!R1 && hasLength!R1 && hasLength!R2))
3112     {
3113         auto balance = find!pred(haystack, needle);
3114         immutable pos1 = haystack.length - balance.length;
3115         immutable pos2 = balance.empty ? pos1 : pos1 + needle.length;
3116         alias Slice = typeof(haystack[0 .. pos1]);
3117         return FindSplitResult!(1, Slice, Slice, Slice)(
3118             haystack[0 .. pos1], haystack[pos1 .. pos2], haystack[pos2 .. haystack.length]);
3119     }
3120     else
3121     {
3122         import std.range : takeExactly;
3123         auto original = haystack.save;
3124         auto h = haystack.save;
3125         auto n = needle.save;
3126         size_t pos1, pos2;
3127         while (!n.empty && !h.empty)
3128         {
3129             if (binaryFun!pred(h.front, n.front))
3130             {
3131                 h.popFront();
3132                 n.popFront();
3133                 ++pos2;
3134             }
3135             else
3136             {
3137                 haystack.popFront();
3138                 n = needle.save;
3139                 h = haystack.save;
3140                 pos2 = ++pos1;
3141             }
3142         }
3143         if (!n.empty) // incomplete match at the end of haystack
3144         {
3145             pos1 = pos2;
3146         }
3147         return FindSplitResult!(1,
3148             typeof(takeExactly(original, pos1)),
3149             typeof(takeExactly(original, pos1)), typeof(h))(
3150             takeExactly(original, pos1),
3151             takeExactly(haystack, pos2 - pos1), h);
3152     }
3153 }
3154 
3155 /// Ditto
3156 auto findSplitBefore(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle)
3157 if (isForwardRange!R1 && isForwardRange!R2)
3158 {
3159     static if (isSomeString!R1 && isSomeString!R2
3160             || (isRandomAccessRange!R1 && hasLength!R1 && hasSlicing!R1 && hasLength!R2))
3161     {
3162         auto balance = find!pred(haystack, needle);
3163         immutable pos = haystack.length - balance.length;
3164         return FindSplitResult!(1,
3165             typeof(haystack[0 .. pos]), typeof(haystack[0 .. pos]))(
3166             haystack[0 .. pos], haystack[pos .. haystack.length]);
3167     }
3168     else
3169     {
3170         import std.range : takeExactly;
3171         auto original = haystack.save;
3172         auto h = haystack.save;
3173         auto n = needle.save;
3174         size_t pos1, pos2;
3175         while (!n.empty && !h.empty)
3176         {
3177             if (binaryFun!pred(h.front, n.front))
3178             {
3179                 h.popFront();
3180                 n.popFront();
3181                 ++pos2;
3182             }
3183             else
3184             {
3185                 haystack.popFront();
3186                 n = needle.save;
3187                 h = haystack.save;
3188                 pos2 = ++pos1;
3189             }
3190         }
3191         if (!n.empty) // incomplete match at the end of haystack
3192         {
3193             pos1 = pos2;
3194             haystack = h;
3195         }
3196         return FindSplitResult!(1,
3197             typeof(takeExactly(original, pos1)), typeof(haystack))(
3198             takeExactly(original, pos1), haystack);
3199     }
3200 }
3201 
3202 /// Ditto
3203 auto findSplitAfter(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle)
3204 if (isForwardRange!R1 && isForwardRange!R2)
3205 {
3206     static if (isSomeString!R1 && isSomeString!R2
3207             || isRandomAccessRange!R1 && hasLength!R1 && hasSlicing!R1 && hasLength!R2)
3208     {
3209         auto balance = find!pred(haystack, needle);
3210         immutable pos = balance.empty ? 0 : haystack.length - balance.length + needle.length;
3211         return FindSplitResult!(0,
3212             typeof(haystack[0 .. pos]), typeof(haystack[0 .. pos]))(
3213             haystack[0 .. pos], haystack[pos .. haystack.length]);
3214     }
3215     else
3216     {
3217         import std.range : takeExactly;
3218         alias Res = FindSplitResult!(0, typeof(takeExactly(haystack, 0)), typeof(haystack));
3219         auto original = haystack.save;
3220         auto h = haystack.save;
3221         auto n = needle.save;
3222         size_t pos1, pos2;
3223         while (!n.empty)
3224         {
3225             if (h.empty)
3226             {
3227                 // Failed search
3228                 return Res(takeExactly(original, 0), original);
3229             }
3230             if (binaryFun!pred(h.front, n.front))
3231             {
3232                 h.popFront();
3233                 n.popFront();
3234                 ++pos2;
3235             }
3236             else
3237             {
3238                 haystack.popFront();
3239                 n = needle.save;
3240                 h = haystack.save;
3241                 pos2 = ++pos1;
3242             }
3243         }
3244         return Res(takeExactly(original, pos2), h);
3245     }
3246 }
3247 
3248 /// Returning a subtype of $(REF Tuple, std,typecons) enables
3249 /// the following convenient idiom:
3250 @safe pure nothrow unittest
3251 {
3252     // findSplit returns a triplet
3253     if (auto split = "dlang-rocks".findSplit("-"))
3254     {
3255         assert(split[0] == "dlang");
3256         assert(split[1] == "-");
3257         assert(split[2] == "rocks");
3258     }
3259     else assert(0);
3260 
3261     // findSplitBefore returns 2 ranges
3262     if (const split = [2, 3, 2, 3, 4, 1].findSplitBefore!"a > b"([2, 2]))
3263     {
3264         assert(split[0] == [2, 3, 2]);
3265         // [3, 4] each greater than [2, 2]
3266         assert(split[1] == [3, 4, 1]);
3267     }
3268     else assert(0);
3269 }
3270 
3271 ///
3272 @safe pure nothrow unittest
3273 {
3274     import std.range.primitives : empty;
3275 
3276     auto a = "Carl Sagan Memorial Station";
3277     auto r = findSplit(a, "Velikovsky");
3278     import std.typecons : isTuple;
3279     static assert(isTuple!(typeof(r.asTuple)));
3280     static assert(isTuple!(typeof(r)));
3281     assert(!r);
3282     assert(r[0] == a);
3283     assert(r[1].empty);
3284     assert(r[2].empty);
3285     r = findSplit(a, " ");
3286     assert(r[0] == "Carl");
3287     assert(r[1] == " ");
3288     assert(r[2] == "Sagan Memorial Station");
3289     if (const r1 = findSplitBefore(a, "Sagan"))
3290     {
3291         assert(r1);
3292         assert(r1[0] == "Carl ");
3293         assert(r1[1] == "Sagan Memorial Station");
3294     }
3295     if (const r2 = findSplitAfter(a, "Sagan"))
3296     {
3297         assert(r2);
3298         assert(r2[0] == "Carl Sagan");
3299         assert(r2[1] == " Memorial Station");
3300     }
3301 }
3302 
3303 /// Use $(REF only, std,range) to find single elements:
3304 @safe pure nothrow unittest
3305 {
3306     import std.range : only;
3307     assert([1, 2, 3, 4].findSplitBefore(only(3))[0] == [1, 2]);
3308 }
3309 
3310 @safe pure nothrow unittest
3311 {
3312     import std.range.primitives : empty;
3313 
3314     immutable a = [ 1, 2, 3, 4, 5, 6, 7, 8 ];
3315     auto r = findSplit(a, [9, 1]);
3316     assert(!r);
3317     assert(r[0] == a);
3318     assert(r[1].empty);
3319     assert(r[2].empty);
3320     r = findSplit(a, [3]);
3321     assert(r);
3322     assert(r[0] == a[0 .. 2]);
3323     assert(r[1] == a[2 .. 3]);
3324     assert(r[2] == a[3 .. $]);
3325 
3326     {
3327         const r1 = findSplitBefore(a, [9, 1]);
3328         assert(!r1);
3329         assert(r1[0] == a);
3330         assert(r1[1].empty);
3331     }
3332 
3333     if (immutable r1 = findSplitBefore(a, [3, 4]))
3334     {
3335         assert(r1);
3336         assert(r1[0] == a[0 .. 2]);
3337         assert(r1[1] == a[2 .. $]);
3338     }
3339     else assert(0);
3340 
3341     {
3342         const r2 = findSplitAfter(a, [9, 1]);
3343         assert(!r2);
3344         assert(r2[0].empty);
3345         assert(r2[1] == a);
3346     }
3347 
3348     if (immutable r3 = findSplitAfter(a, [3, 4]))
3349     {
3350         assert(r3);
3351         assert(r3[0] == a[0 .. 4]);
3352         assert(r3[1] == a[4 .. $]);
3353     }
3354     else assert(0);
3355 }
3356 
3357 @safe pure nothrow unittest
3358 {
3359     import std.algorithm.comparison : equal;
3360     import std.algorithm.iteration : filter;
3361 
3362     auto a = [ 1, 2, 3, 4, 5, 6, 7, 8 ];
3363     auto fwd = filter!"a > 0"(a);
3364     auto r = findSplit(fwd, [9, 1]);
3365     assert(!r);
3366     assert(equal(r[0], a));
3367     assert(r[1].empty);
3368     assert(r[2].empty);
3369     r = findSplit(fwd, [3]);
3370     assert(r);
3371     assert(equal(r[0],  a[0 .. 2]));
3372     assert(equal(r[1], a[2 .. 3]));
3373     assert(equal(r[2], a[3 .. $]));
3374     r = findSplit(fwd, [8, 9]);
3375     assert(!r);
3376     assert(equal(r[0], a));
3377     assert(r[1].empty);
3378     assert(r[2].empty);
3379 
3380     // auto variable `r2` cannot be `const` because `fwd.front` is mutable
3381     {
3382         auto r1 = findSplitBefore(fwd, [9, 1]);
3383         assert(!r1);
3384         assert(equal(r1[0], a));
3385         assert(r1[1].empty);
3386     }
3387 
3388     if (auto r1 = findSplitBefore(fwd, [3, 4]))
3389     {
3390         assert(r1);
3391         assert(equal(r1[0], a[0 .. 2]));
3392         assert(equal(r1[1], a[2 .. $]));
3393     }
3394     else assert(0);
3395 
3396     {
3397         auto r1 = findSplitBefore(fwd, [8, 9]);
3398         assert(!r1);
3399         assert(equal(r1[0], a));
3400         assert(r1[1].empty);
3401     }
3402 
3403     {
3404         auto r2 = findSplitAfter(fwd, [9, 1]);
3405         assert(!r2);
3406         assert(r2[0].empty);
3407         assert(equal(r2[1], a));
3408     }
3409 
3410     if (auto r2 = findSplitAfter(fwd, [3, 4]))
3411     {
3412         assert(r2);
3413         assert(equal(r2[0], a[0 .. 4]));
3414         assert(equal(r2[1], a[4 .. $]));
3415     }
3416     else assert(0);
3417 
3418     {
3419         auto r2 = findSplitAfter(fwd, [8, 9]);
3420         assert(!r2);
3421         assert(r2[0].empty);
3422         assert(equal(r2[1], a));
3423     }
3424 }
3425 
3426 @safe pure nothrow @nogc unittest
3427 {
3428     auto str = "sep,one,sep,two";
3429 
3430     auto split = str.findSplitAfter(",");
3431     assert(split[0] == "sep,");
3432 
3433     split = split[1].findSplitAfter(",");
3434     assert(split[0] == "one,");
3435 
3436     split = split[1].findSplitBefore(",");
3437     assert(split[0] == "sep");
3438 }
3439 
3440 @safe pure nothrow @nogc unittest
3441 {
3442     auto str = "sep,one,sep,two";
3443 
3444     auto split = str.findSplitBefore(",two");
3445     assert(split[0] == "sep,one,sep");
3446     assert(split[1] == ",two");
3447 
3448     split = split[0].findSplitBefore(",sep");
3449     assert(split[0] == "sep,one");
3450     assert(split[1] == ",sep");
3451 
3452     split = split[0].findSplitAfter(",");
3453     assert(split[0] == "sep,");
3454     assert(split[1] == "one");
3455 }
3456 
3457 // https://issues.dlang.org/show_bug.cgi?id=11013
3458 @safe pure unittest
3459 {
3460     auto var = "abc";
3461     auto split = var.findSplitBefore!q{a == a}(var);
3462     assert(split[0] == "");
3463     assert(split[1] == "abc");
3464 }
3465 
3466 // minCount
3467 /**
3468 
3469 Computes the minimum (respectively maximum) of `range` along with its number of
3470 occurrences. Formally, the minimum is a value `x` in `range` such that $(D
3471 pred(a, x)) is `false` for all values `a` in `range`. Conversely, the maximum is
3472 a value `x` in `range` such that `pred(x, a)` is `false` for all values `a`
3473 in `range` (note the swapped arguments to `pred`).
3474 
3475 These functions may be used for computing arbitrary extrema by choosing `pred`
3476 appropriately. For corrrect functioning, `pred` must be a strict partial order,
3477 i.e. transitive (if `pred(a, b) && pred(b, c)` then `pred(a, c)`) and
3478 irreflexive (`pred(a, a)` is `false`). The $(LUCKY trichotomy property of
3479 inequality) is not required: these algorithms consider elements `a` and `b` equal
3480 (for the purpose of counting) if `pred` puts them in the same equivalence class,
3481 i.e. `!pred(a, b) && !pred(b, a)`.
3482 
3483 Params:
3484     pred = The ordering predicate to use to determine the extremum (minimum
3485         or maximum).
3486     range = The $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to count.
3487 
3488 Returns: The minimum, respectively maximum element of a range together with the
3489 number it occurs in the range.
3490 
3491 Limitations: If at least one of the arguments is NaN, the result is
3492 an unspecified value. See $(REF maxElement, std,algorithm,searching)
3493 for examples on how to cope with NaNs.
3494 
3495 Throws: `Exception` if `range.empty`.
3496 
3497 See_Also: $(REF min, std,algorithm,comparison), $(LREF minIndex), $(LREF minElement), $(LREF minPos)
3498  */
3499 Tuple!(ElementType!Range, size_t)
3500 minCount(alias pred = "a < b", Range)(Range range)
3501 if (isInputRange!Range && !isInfinite!Range &&
3502     is(typeof(binaryFun!pred(range.front, range.front))))
3503 {
3504     import std.algorithm.internal : algoFormat;
3505     import std.exception : enforce;
3506 
3507     alias T  = ElementType!Range;
3508     alias UT = Unqual!T;
3509     alias RetType = Tuple!(T, size_t);
3510 
3511     static assert(is(typeof(RetType(range.front, 1))),
3512         algoFormat("Error: Cannot call minCount on a %s, because it is not possible "~
3513                "to copy the result value (a %s) into a Tuple.", Range.stringof, T.stringof));
3514 
3515     enforce(!range.empty, "Can't count elements from an empty range");
3516     size_t occurrences = 1;
3517 
3518     static if (isForwardRange!Range)
3519     {
3520         Range least = range.save;
3521         for (range.popFront(); !range.empty; range.popFront())
3522         {
3523             if (binaryFun!pred(least.front, range.front))
3524             {
3525                 assert(!binaryFun!pred(range.front, least.front),
3526                     "min/maxPos: predicate must be a strict partial order.");
3527                 continue;
3528             }
3529             if (binaryFun!pred(range.front, least.front))
3530             {
3531                 // change the min
3532                 least = range.save;
3533                 occurrences = 1;
3534             }
3535             else
3536                 ++occurrences;
3537         }
3538         return RetType(least.front, occurrences);
3539     }
3540     else static if (isAssignable!(UT, T) || (!hasElaborateAssign!UT && isAssignable!UT))
3541     {
3542         UT v = UT.init;
3543         static if (isAssignable!(UT, T)) v = range.front;
3544         else                             v = cast(UT) range.front;
3545 
3546         for (range.popFront(); !range.empty; range.popFront())
3547         {
3548             if (binaryFun!pred(*cast(T*)&v, range.front)) continue;
3549             if (binaryFun!pred(range.front, *cast(T*)&v))
3550             {
3551                 // change the min
3552                 static if (isAssignable!(UT, T)) v = range.front;
3553                 else                             v = cast(UT) range.front; //Safe because !hasElaborateAssign!UT
3554                 occurrences = 1;
3555             }
3556             else
3557                 ++occurrences;
3558         }
3559         return RetType(*cast(T*)&v, occurrences);
3560     }
3561     else static if (hasLvalueElements!Range)
3562     {
3563         import std.algorithm.internal : addressOf;
3564         T* p = addressOf(range.front);
3565         for (range.popFront(); !range.empty; range.popFront())
3566         {
3567             if (binaryFun!pred(*p, range.front)) continue;
3568             if (binaryFun!pred(range.front, *p))
3569             {
3570                 // change the min
3571                 p = addressOf(range.front);
3572                 occurrences = 1;
3573             }
3574             else
3575                 ++occurrences;
3576         }
3577         return RetType(*p, occurrences);
3578     }
3579     else
3580         static assert(false,
3581             algoFormat("Sorry, can't find the minCount of a %s: Don't know how "~
3582                    "to keep track of the smallest %s element.", Range.stringof, T.stringof));
3583 }
3584 
3585 /// Ditto
3586 Tuple!(ElementType!Range, size_t)
3587 maxCount(alias pred = "a < b", Range)(Range range)
3588 if (isInputRange!Range && !isInfinite!Range &&
3589     is(typeof(binaryFun!pred(range.front, range.front))))
3590 {
3591     return range.minCount!((a, b) => binaryFun!pred(b, a));
3592 }
3593 
3594 ///
3595 @safe unittest
3596 {
3597     import std.conv : text;
3598     import std.typecons : tuple;
3599 
3600     int[] a = [ 2, 3, 4, 1, 2, 4, 1, 1, 2 ];
3601     // Minimum is 1 and occurs 3 times
3602     assert(a.minCount == tuple(1, 3));
3603     // Maximum is 4 and occurs 2 times
3604     assert(a.maxCount == tuple(4, 2));
3605 }
3606 
3607 @system unittest
3608 {
3609     import std.conv : text;
3610     import std.exception : assertThrown;
3611     import std.internal.test.dummyrange;
3612 
3613     int[][] b = [ [4], [2, 4], [4], [4] ];
3614     auto c = minCount!("a[0] < b[0]")(b);
3615     assert(c == tuple([2, 4], 1), text(c[0]));
3616 
3617     //Test empty range
3618     assertThrown(minCount(b[$..$]));
3619 
3620     //test with reference ranges. Test both input and forward.
3621     assert(minCount(new ReferenceInputRange!int([1, 2, 1, 0, 2, 0])) == tuple(0, 2));
3622     assert(minCount(new ReferenceForwardRange!int([1, 2, 1, 0, 2, 0])) == tuple(0, 2));
3623 }
3624 
3625 @system unittest
3626 {
3627     import std.conv : text;
3628     import std.meta : AliasSeq;
3629 
3630     static struct R(T) //input range
3631     {
3632         T[] arr;
3633         alias arr this;
3634     }
3635 
3636     immutable         a = [ 2, 3, 4, 1, 2, 4, 1, 1, 2 ];
3637     R!(immutable int) b = R!(immutable int)(a);
3638 
3639     assert(minCount(a) == tuple(1, 3));
3640     assert(minCount(b) == tuple(1, 3));
3641     assert(minCount!((ref immutable int a, ref immutable int b) => (a > b))(a) == tuple(4, 2));
3642     assert(minCount!((ref immutable int a, ref immutable int b) => (a > b))(b) == tuple(4, 2));
3643 
3644     immutable(int[])[] c = [ [4], [2, 4], [4], [4] ];
3645     assert(minCount!("a[0] < b[0]")(c) == tuple([2, 4], 1), text(c[0]));
3646 
3647     static struct S1
3648     {
3649         int i;
3650     }
3651     alias IS1 = immutable(S1);
3652     static assert( isAssignable!S1);
3653     static assert( isAssignable!(S1, IS1));
3654 
3655     static struct S2
3656     {
3657         int* p;
3658         this(ref immutable int i) immutable {p = &i;}
3659         this(ref int i) {p = &i;}
3660         @property ref inout(int) i() inout {return *p;}
3661         bool opEquals(const S2 other) const {return i == other.i;}
3662     }
3663     alias IS2 = immutable(S2);
3664     static assert( isAssignable!S2);
3665     static assert(!isAssignable!(S2, IS2));
3666     static assert(!hasElaborateAssign!S2);
3667 
3668     static struct S3
3669     {
3670         int i;
3671         void opAssign(ref S3 other) @disable;
3672     }
3673     static assert(!isAssignable!S3);
3674 
3675     static foreach (Type; AliasSeq!(S1, IS1, S2, IS2, S3))
3676     {{
3677         static if (is(Type == immutable)) alias V = immutable int;
3678         else                              alias V = int;
3679         V one = 1, two = 2;
3680         auto r1 = [Type(two), Type(one), Type(one)];
3681         auto r2 = R!Type(r1);
3682         assert(minCount!"a.i < b.i"(r1) == tuple(Type(one), 2));
3683         assert(minCount!"a.i < b.i"(r2) == tuple(Type(one), 2));
3684         assert(one == 1 && two == 2);
3685     }}
3686 }
3687 
3688 /**
3689 Iterates the passed range and returns the minimal element.
3690 A custom mapping function can be passed to `map`.
3691 In other languages this is sometimes called `argmin`.
3692 
3693 Complexity: O(n)
3694     Exactly `n - 1` comparisons are needed.
3695 
3696 Params:
3697     map = custom accessor for the comparison key
3698     r = range from which the minimal element will be selected
3699     seed = custom seed to use as initial element
3700 
3701 Precondition: If a seed is not given, `r` must not be empty.
3702 
3703 Returns: The minimal element of the passed-in range.
3704 
3705 Note:
3706     If at least one of the arguments is NaN, the result is an unspecified value.
3707 
3708     If you want to ignore NaNs, you can use $(REF filter, std,algorithm,iteration)
3709     and $(REF isNaN, std,math) to remove them, before applying minElement.
3710     Add a suitable seed, to avoid error messages if all elements are NaNs:
3711 
3712     ---
3713     <range>.filter!(a=>!a.isNaN).minElement(<seed>);
3714     ---
3715 
3716     If you want to get NaN as a result if a NaN is present in the range,
3717     you can use $(REF fold, std,algorithm,iteration) and $(REF isNaN, std,math):
3718 
3719     ---
3720     <range>.fold!((a,b)=>a.isNaN || b.isNaN ? real.nan : a < b ? a : b);
3721     ---
3722 
3723 See_Also:
3724 
3725     $(LREF extrema), $(LREF maxElement), $(REF min, std,algorithm,comparison), $(LREF minCount),
3726     $(LREF minIndex), $(LREF minPos)
3727 */
3728 auto minElement(alias map = (a => a), Range)(Range r)
3729 if (isInputRange!Range && !isInfinite!Range)
3730 {
3731     return extremum!map(r);
3732 }
3733 
3734 /// ditto
3735 auto minElement(alias map = (a => a), Range, RangeElementType = ElementType!Range)
3736                (Range r, RangeElementType seed)
3737 if (isInputRange!Range && !isInfinite!Range &&
3738     !is(CommonType!(ElementType!Range, RangeElementType) == void))
3739 {
3740     return extremum!map(r, seed);
3741 }
3742 
3743 ///
3744 @safe pure unittest
3745 {
3746     import std.range : enumerate;
3747     import std.typecons : tuple;
3748 
3749     assert([2, 7, 1, 3].minElement == 1);
3750 
3751     // allows to get the index of an element too
3752     assert([5, 3, 7, 9].enumerate.minElement!"a.value" == tuple(1, 3));
3753 
3754     // any custom accessor can be passed
3755     assert([[0, 4], [1, 2]].minElement!"a[1]" == [1, 2]);
3756 
3757     // can be seeded
3758     int[] arr;
3759     assert(arr.minElement(1) == 1);
3760 }
3761 
3762 @safe pure unittest
3763 {
3764     import std.range : enumerate, iota;
3765     // supports mapping
3766     assert([3, 4, 5, 1, 2].enumerate.minElement!"a.value" == tuple(3, 1));
3767     assert([5, 2, 4].enumerate.minElement!"a.value" == tuple(1, 2));
3768 
3769     // forward ranges
3770     assert(iota(1, 5).minElement() == 1);
3771     assert(iota(2, 5).enumerate.minElement!"a.value" == tuple(0, 2));
3772 
3773     // should work with const
3774     const(int)[] immArr = [2, 1, 3];
3775     assert(immArr.minElement == 1);
3776 
3777     // should work with immutable
3778     immutable(int)[] immArr2 = [2, 1, 3];
3779     assert(immArr2.minElement == 1);
3780 
3781     // with strings
3782     assert(["b", "a", "c"].minElement == "a");
3783 
3784     // with all dummy ranges
3785     import std.internal.test.dummyrange;
3786     foreach (DummyType; AllDummyRanges)
3787     {
3788         DummyType d;
3789         assert(d.minElement == 1);
3790         assert(d.minElement!(a => a) == 1);
3791         assert(d.minElement!(a => -a) == 10);
3792     }
3793 
3794     // with empty, but seeded ranges
3795     int[] arr;
3796     assert(arr.minElement(42) == 42);
3797     assert(arr.minElement!(a => a)(42) == 42);
3798 }
3799 
3800 @nogc @safe nothrow pure unittest
3801 {
3802     static immutable arr = [7, 3, 4, 2, 1, 8];
3803     assert(arr.minElement == 1);
3804 
3805     static immutable arr2d = [[1, 9], [3, 1], [4, 2]];
3806     assert(arr2d.minElement!"a[1]" == arr2d[1]);
3807 }
3808 
3809 // https://issues.dlang.org/show_bug.cgi?id=17982
3810 @safe unittest
3811 {
3812     struct A
3813     {
3814       int val;
3815     }
3816 
3817     const(A)[] v = [A(0)];
3818     assert(v.minElement!"a.val" == A(0));
3819 }
3820 
3821 // https://issues.dlang.org/show_bug.cgi?id=17982
3822 @safe unittest
3823 {
3824     class B
3825     {
3826         int val;
3827         this(int val){ this.val = val; }
3828     }
3829 
3830     const(B) doStuff(const(B)[] v)
3831     {
3832         return v.minElement!"a.val";
3833     }
3834     assert(doStuff([new B(1), new B(0), new B(2)]).val == 0);
3835 
3836     const(B)[] arr = [new B(0), new B(1)];
3837     // can't compare directly - https://issues.dlang.org/show_bug.cgi?id=1824
3838     assert(arr.minElement!"a.val".val == 0);
3839 }
3840 
3841 // https://issues.dlang.org/show_bug.cgi?id=24827
3842 @safe unittest
3843 {
3844     static struct S
3845     {
3846         int i;
3847         bool destroyed;
3848 
3849         this(int i) @safe
3850         {
3851             this.i = i;
3852         }
3853 
3854         ~this() @safe
3855         {
3856             destroyed = true;
3857         }
3858 
3859         bool opEquals()(auto ref S rhs)
3860         {
3861             return this.i == rhs.i;
3862         }
3863 
3864         int opCmp()(auto ref S rhs)
3865         {
3866             if (this.i < rhs.i)
3867                 return -1;
3868 
3869             return this.i == rhs.i ? 0 : 1;
3870         }
3871 
3872         @safe invariant
3873         {
3874             assert(!destroyed);
3875         }
3876     }
3877 
3878     auto arr = [S(19), S(2), S(145), S(7)];
3879     assert(minElement(arr) == S(2));
3880 }
3881 
3882 /**
3883 Iterates the passed range and returns the maximal element.
3884 A custom mapping function can be passed to `map`.
3885 In other languages this is sometimes called `argmax`.
3886 
3887 Complexity: O(n)
3888     Exactly `n - 1` comparisons are needed.
3889 
3890 Params:
3891     map = custom accessor for the comparison key
3892     r = range from which the maximum element will be selected
3893     seed = custom seed to use as initial element
3894 
3895 Precondition: If a seed is not given, `r` must not be empty.
3896 
3897 Returns: The maximal element of the passed-in range.
3898 
3899 Note:
3900     If at least one of the arguments is NaN, the result is an unspecified value.
3901     See $(REF minElement, std,algorithm,searching) for examples on how to cope
3902     with NaNs.
3903 
3904 See_Also:
3905 
3906     $(LREF extrema), $(LREF minElement), $(REF max, std,algorithm,comparison), $(LREF maxCount),
3907     $(LREF maxIndex), $(LREF maxPos)
3908 */
3909 auto maxElement(alias map = (a => a), Range)(Range r)
3910 if (isInputRange!Range && !isInfinite!Range)
3911 {
3912     return extremum!(map, "a > b")(r);
3913 }
3914 
3915 /// ditto
3916 auto maxElement(alias map = (a => a), Range, RangeElementType = ElementType!Range)
3917                (Range r, RangeElementType seed)
3918 if (isInputRange!Range && !isInfinite!Range &&
3919     !is(CommonType!(ElementType!Range, RangeElementType) == void))
3920 {
3921     return extremum!(map, "a > b")(r, seed);
3922 }
3923 
3924 ///
3925 @safe pure unittest
3926 {
3927     import std.range : enumerate;
3928     import std.typecons : tuple;
3929     assert([2, 1, 4, 3].maxElement == 4);
3930 
3931     // allows to get the index of an element too
3932     assert([2, 1, 4, 3].enumerate.maxElement!"a.value" == tuple(2, 4));
3933 
3934     // any custom accessor can be passed
3935     assert([[0, 4], [1, 2]].maxElement!"a[1]" == [0, 4]);
3936 
3937     // can be seeded
3938     int[] arr;
3939     assert(arr.minElement(1) == 1);
3940 }
3941 
3942 @safe pure unittest
3943 {
3944     import std.range : enumerate, iota;
3945 
3946     // supports mapping
3947     assert([3, 4, 5, 1, 2].enumerate.maxElement!"a.value" == tuple(2, 5));
3948     assert([5, 2, 4].enumerate.maxElement!"a.value" == tuple(0, 5));
3949 
3950     // forward ranges
3951     assert(iota(1, 5).maxElement() == 4);
3952     assert(iota(2, 5).enumerate.maxElement!"a.value" == tuple(2, 4));
3953     assert(iota(4, 14).enumerate.maxElement!"a.value" == tuple(9, 13));
3954 
3955     // should work with const
3956     const(int)[] immArr = [2, 3, 1];
3957     assert(immArr.maxElement == 3);
3958 
3959     // should work with immutable
3960     immutable(int)[] immArr2 = [2, 3, 1];
3961     assert(immArr2.maxElement == 3);
3962 
3963     // with strings
3964     assert(["a", "c", "b"].maxElement == "c");
3965 
3966     // with all dummy ranges
3967     import std.internal.test.dummyrange;
3968     foreach (DummyType; AllDummyRanges)
3969     {
3970         DummyType d;
3971         assert(d.maxElement == 10);
3972         assert(d.maxElement!(a => a) == 10);
3973         assert(d.maxElement!(a => -a) == 1);
3974     }
3975 
3976     // with empty, but seeded ranges
3977     int[] arr;
3978     assert(arr.maxElement(42) == 42);
3979     assert(arr.maxElement!(a => a)(42) == 42);
3980 
3981 }
3982 
3983 @nogc @safe nothrow pure unittest
3984 {
3985     static immutable arr = [7, 3, 8, 2, 1, 4];
3986     assert(arr.maxElement == 8);
3987 
3988     static immutable arr2d = [[1, 3], [3, 9], [4, 2]];
3989     assert(arr2d.maxElement!"a[1]" == arr2d[1]);
3990 }
3991 
3992 // https://issues.dlang.org/show_bug.cgi?id=17982
3993 @safe unittest
3994 {
3995     class B
3996     {
3997         int val;
3998         this(int val){ this.val = val; }
3999     }
4000 
4001     const(B) doStuff(const(B)[] v)
4002     {
4003         return v.maxElement!"a.val";
4004     }
4005     assert(doStuff([new B(1), new B(0), new B(2)]).val == 2);
4006 
4007     const(B)[] arr = [new B(0), new B(1)];
4008     // can't compare directly - https://issues.dlang.org/show_bug.cgi?id=1824
4009     assert(arr.maxElement!"a.val".val == 1);
4010 }
4011 
4012 // https://issues.dlang.org/show_bug.cgi?id=23993
4013 @safe unittest
4014 {
4015     import std.bigint : BigInt;
4016 
4017     assert([BigInt(2), BigInt(3)].maxElement == BigInt(3));
4018 }
4019 
4020 // https://issues.dlang.org/show_bug.cgi?id=24596
4021 @safe unittest
4022 {
4023     static class A {
4024         int i;
4025         int getI() @safe => i;
4026         this(int i) @safe { this.i = i; }
4027     }
4028     auto arr = [new A(2), new A(3)];
4029 
4030     arr.maxElement!(a => a.getI);
4031 
4032     assert(arr[0].getI == 2);
4033 }
4034 
4035 // https://issues.dlang.org/show_bug.cgi?id=24827
4036 @safe unittest
4037 {
4038     static struct S
4039     {
4040         int i;
4041         bool destroyed;
4042 
4043         this(int i) @safe
4044         {
4045             this.i = i;
4046         }
4047 
4048         ~this() @safe
4049         {
4050             destroyed = true;
4051         }
4052 
4053         bool opEquals()(auto ref S rhs)
4054         {
4055             return this.i == rhs.i;
4056         }
4057 
4058         int opCmp()(auto ref S rhs)
4059         {
4060             if (this.i < rhs.i)
4061                 return -1;
4062 
4063             return this.i == rhs.i ? 0 : 1;
4064         }
4065 
4066         @safe invariant
4067         {
4068             assert(!destroyed);
4069         }
4070     }
4071 
4072     auto arr = [S(19), S(2), S(145), S(7)];
4073     assert(maxElement(arr) == S(145));
4074 }
4075 
4076 /** Returns an array of the minimum and maximum element in `r`.
4077  * Performs `< 3n/2` comparisons, unlike the naive `< 2n`.
4078  * Params:
4079  *  r = The range to traverse.
4080  */
4081 // TODO alias map = a => a
4082 ElementType!Range[2] extrema(Range)(Range r)
4083 if (isInputRange!Range && !isInfinite!Range)
4084 in (!r.empty)
4085 {
4086     static if (isRandomAccessRange!Range && hasLength!Range)
4087     {
4088         if (r.length == 1)
4089             return [r[0], r[0]];
4090 
4091         typeof(return) result;
4092         size_t i;
4093         if (r.length & 1) // odd
4094         {
4095             result = [r[0], r[0]];
4096             i = 1;
4097         }
4098         else
4099         {
4100             result = (r[0] < r[1]) ? [r[0], r[1]] : [r[1], r[0]];
4101             i = 2;
4102         }
4103         // iterate pairs
4104         const imax = r.length;
4105         for (; i != imax; i += 2)
4106         {
4107             // save work
4108             if (r[i] < r[i+1])
4109             {
4110                 if (r[i] < result[0])
4111                     result[0] = r[i];
4112                 if (r[i+1] > result[1])
4113                     result[1] = r[i+1];
4114             }
4115             else
4116             {
4117                 if (r[i+1] < result[0])
4118                     result[0] = r[i+1];
4119                 if (r[i] > result[1])
4120                     result[1] = r[i];
4121             }
4122         }
4123         return result;
4124     }
4125     else
4126     {
4127         auto first = r.front;
4128         r.popFront;
4129         if (r.empty)
4130             return [first, first];
4131 
4132         typeof(return) result = (first < r.front) ? [first, r.front] : [r.front, first];
4133         // iterate pairs
4134         while (true)
4135         {
4136             r.popFront;
4137             if (r.empty)
4138                 return result;
4139             first = r.front;
4140             r.popFront;
4141             if (r.empty)
4142             {
4143                 if (first < result[0])
4144                     result[0] = first;
4145                 else if (first > result[1])
4146                     result[1] = first;
4147                 return result;
4148             }
4149             // save work
4150             if (first < r.front)
4151             {
4152                 if (first < result[0])
4153                     result[0] = first;
4154                 if (r.front > result[1])
4155                     result[1] = r.front;
4156             }
4157             else
4158             {
4159                 if (r.front < result[0])
4160                     result[0] = r.front;
4161                 if (first > result[1])
4162                     result[1] = first;
4163             }
4164         }
4165     }
4166 }
4167 
4168 ///
4169 @safe unittest
4170 {
4171     assert(extrema([5,2,9,4,1]) == [1, 9]);
4172 }
4173 
4174 @safe unittest
4175 {
4176     assert(extrema([8,3,7,4,9]) == [3, 9]);
4177     assert(extrema([1,5,3,2]) == [1, 5]);
4178     assert(extrema([2,3,3,2]) == [2, 3]);
4179 
4180     import std.range;
4181     assert(iota(2, 5).extrema == [2, 4]);
4182     assert(iota(3, 7).retro.extrema == [3, 6]);
4183 
4184     import std.internal.test.dummyrange;
4185     foreach (DummyType; AllDummyRanges)
4186     {
4187         DummyType d;
4188         assert(d.extrema == [1, 10]);
4189     }
4190 
4191     version (StdRandomTests)
4192     foreach (i; 0 .. 1000)
4193     {
4194         import std.random;
4195         auto arr = generate!(() => uniform(0, 100)).takeExactly(uniform(1, 10)).array;
4196         auto result = arr.extrema;
4197         assert(result[0] == arr.minElement);
4198         assert(result[1] == arr.maxElement);
4199     }
4200 }
4201 
4202 // minPos
4203 /**
4204 Computes a subrange of `range` starting at the first occurrence of `range`'s
4205 minimum (respectively maximum) and with the same ending as `range`, or the
4206 empty range if `range` itself is empty.
4207 
4208 Formally, the minimum is a value `x` in `range` such that `pred(a, x)` is
4209 `false` for all values `a` in `range`. Conversely, the maximum is a value `x` in
4210 `range` such that `pred(x, a)` is `false` for all values `a` in `range` (note
4211 the swapped arguments to `pred`).
4212 
4213 These functions may be used for computing arbitrary extrema by choosing `pred`
4214 appropriately. For corrrect functioning, `pred` must be a strict partial order,
4215 i.e. transitive (if `pred(a, b) && pred(b, c)` then `pred(a, c)`) and
4216 irreflexive (`pred(a, a)` is `false`).
4217 
4218 Params:
4219     pred = The ordering predicate to use to determine the extremum (minimum or
4220         maximum) element.
4221     range = The $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) to search.
4222 
4223 Returns: The position of the minimum (respectively maximum) element of forward
4224 range `range`, i.e. a subrange of `range` starting at the position of  its
4225 smallest (respectively largest) element and with the same ending as `range`.
4226 
4227 Limitations: If at least one of the arguments is NaN, the result is
4228 an unspecified value. See $(REF maxElement, std,algorithm,searching)
4229 for examples on how to cope with NaNs.
4230 
4231 See_Also:
4232     $(REF max, std,algorithm,comparison), $(LREF minCount), $(LREF minIndex), $(LREF minElement)
4233 */
4234 Range minPos(alias pred = "a < b", Range)(Range range)
4235 if (isForwardRange!Range && !isInfinite!Range &&
4236     is(typeof(binaryFun!pred(range.front, range.front))))
4237 {
4238     static if (hasSlicing!Range && isRandomAccessRange!Range && hasLength!Range)
4239     {
4240         // Prefer index-based access
4241         size_t pos = 0;
4242         foreach (i; 1 .. range.length)
4243         {
4244             if (binaryFun!pred(range[i], range[pos]))
4245             {
4246                 pos = i;
4247             }
4248         }
4249         return range[pos .. range.length];
4250     }
4251     else
4252     {
4253         auto result = range.save;
4254         if (range.empty) return result;
4255         for (range.popFront(); !range.empty; range.popFront())
4256         {
4257             // Note: Unlike minCount, we do not care to find equivalence, so a
4258             // single pred call is enough.
4259             if (binaryFun!pred(range.front, result.front))
4260             {
4261                 // change the min
4262                 result = range.save;
4263             }
4264         }
4265         return result;
4266     }
4267 }
4268 
4269 /// Ditto
4270 Range maxPos(alias pred = "a < b", Range)(Range range)
4271 if (isForwardRange!Range && !isInfinite!Range &&
4272     is(typeof(binaryFun!pred(range.front, range.front))))
4273 {
4274     return range.minPos!((a, b) => binaryFun!pred(b, a));
4275 }
4276 
4277 ///
4278 @safe unittest
4279 {
4280     int[] a = [ 2, 3, 4, 1, 2, 4, 1, 1, 2 ];
4281     // Minimum is 1 and first occurs in position 3
4282     assert(a.minPos == [ 1, 2, 4, 1, 1, 2 ]);
4283     // Maximum is 4 and first occurs in position 2
4284     assert(a.maxPos == [ 4, 1, 2, 4, 1, 1, 2 ]);
4285 }
4286 
4287 @safe unittest
4288 {
4289     import std.algorithm.comparison : equal;
4290     import std.internal.test.dummyrange;
4291 
4292     int[] a = [ 2, 3, 4, 1, 2, 4, 1, 1, 2 ];
4293     //Test that an empty range works
4294     int[] b = a[$..$];
4295     assert(equal(minPos(b), b));
4296 
4297     //test with reference range.
4298     assert( equal( minPos(new ReferenceForwardRange!int([1, 2, 1, 0, 2, 0])), [0, 2, 0] ) );
4299 }
4300 
4301 @system unittest
4302 {
4303     //Rvalue range
4304     import std.algorithm.comparison : equal;
4305     import std.container : Array;
4306 
4307     assert(Array!int(2, 3, 4, 1, 2, 4, 1, 1, 2)
4308                []
4309                .minPos()
4310                .equal([ 1, 2, 4, 1, 1, 2 ]));
4311 }
4312 
4313 @safe unittest
4314 {
4315     //BUG 9299
4316     immutable a = [ 2, 3, 4, 1, 2, 4, 1, 1, 2 ];
4317     // Minimum is 1 and first occurs in position 3
4318     assert(minPos(a) == [ 1, 2, 4, 1, 1, 2 ]);
4319     // Maximum is 4 and first occurs in position 5
4320     assert(minPos!("a > b")(a) == [ 4, 1, 2, 4, 1, 1, 2 ]);
4321 
4322     immutable(int[])[] b = [ [4], [2, 4], [4], [4] ];
4323     assert(minPos!("a[0] < b[0]")(b) == [ [2, 4], [4], [4] ]);
4324 }
4325 
4326 /**
4327 Computes the index of the first occurrence of `range`'s minimum element.
4328 
4329 Params:
4330     pred = The ordering predicate to use to determine the minimum element.
4331     range = The $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
4332     to search.
4333 
4334 Complexity: $(BIGOH range.length)
4335     Exactly `range.length - 1` comparisons are needed.
4336 
4337 Returns:
4338     The index of the first encounter of the minimum element in `range`. If the
4339     `range` is empty, -1 is returned.
4340 
4341 Limitations:
4342     If at least one of the arguments is NaN, the result is
4343     an unspecified value. See $(REF maxElement, std,algorithm,searching)
4344     for examples on how to cope with NaNs.
4345 
4346 See_Also:
4347     $(LREF maxIndex), $(REF min, std,algorithm,comparison), $(LREF minCount), $(LREF minElement), $(LREF minPos)
4348  */
4349 ptrdiff_t minIndex(alias pred = "a < b", Range)(Range range)
4350 if (isInputRange!Range && !isInfinite!Range &&
4351     is(typeof(binaryFun!pred(range.front, range.front))))
4352 {
4353     if (range.empty) return -1;
4354 
4355     ptrdiff_t minPos = 0;
4356 
4357     static if (isRandomAccessRange!Range && hasLength!Range)
4358     {
4359         foreach (i; 1 .. range.length)
4360         {
4361             if (binaryFun!pred(range[i], range[minPos]))
4362             {
4363                 minPos = i;
4364             }
4365         }
4366     }
4367     else
4368     {
4369         ptrdiff_t curPos = 0;
4370         Unqual!(typeof(range.front)) min = range.front;
4371         for (range.popFront(); !range.empty; range.popFront())
4372         {
4373             ++curPos;
4374             if (binaryFun!pred(range.front, min))
4375             {
4376                 min = range.front;
4377                 minPos = curPos;
4378             }
4379         }
4380     }
4381     return minPos;
4382 }
4383 
4384 ///
4385 @safe pure nothrow unittest
4386 {
4387     int[] a = [2, 3, 4, 1, 2, 4, 1, 1, 2];
4388 
4389     // Minimum is 1 and first occurs in position 3
4390     assert(a.minIndex == 3);
4391     // Get maximum index with minIndex
4392     assert(a.minIndex!"a > b" == 2);
4393 
4394     // Range is empty, so return value is -1
4395     int[] b;
4396     assert(b.minIndex == -1);
4397 
4398     // Works with more custom types
4399     struct Dog { int age; }
4400     Dog[] dogs = [Dog(10), Dog(5), Dog(15)];
4401     assert(dogs.minIndex!"a.age < b.age" == 1);
4402 }
4403 
4404 @safe pure unittest
4405 {
4406     // should work with const
4407     const(int)[] immArr = [2, 1, 3];
4408     assert(immArr.minIndex == 1);
4409 
4410     // Works for const ranges too
4411     const int[] c = [2, 5, 4, 1, 2, 3];
4412     assert(c.minIndex == 3);
4413 
4414     // should work with immutable
4415     immutable(int)[] immArr2 = [2, 1, 3];
4416     assert(immArr2.minIndex == 1);
4417 
4418     // with strings
4419     assert(["b", "a", "c"].minIndex == 1);
4420 
4421     // infinite range
4422     import std.range : cycle;
4423     static assert(!__traits(compiles, cycle([1]).minIndex));
4424 
4425     // with all dummy ranges
4426     import std.internal.test.dummyrange : AllDummyRanges;
4427     foreach (DummyType; AllDummyRanges)
4428     {
4429         static if (isForwardRange!DummyType && !isInfinite!DummyType)
4430         {
4431             DummyType d;
4432             d.arr = [5, 3, 7, 2, 1, 4];
4433             assert(d.minIndex == 4);
4434 
4435             d.arr = [];
4436             assert(d.minIndex == -1);
4437         }
4438     }
4439 }
4440 
4441 @nogc @safe nothrow pure unittest
4442 {
4443     static immutable arr = [7, 3, 8, 2, 1, 4];
4444     assert(arr.minIndex == 4);
4445 
4446     static immutable arr2d = [[1, 3], [3, 9], [4, 2]];
4447     assert(arr2d.minIndex!"a[1] < b[1]" == 2);
4448 }
4449 
4450 @safe nothrow pure unittest
4451 {
4452     // InputRange test
4453 
4454     static struct InRange
4455     {
4456         @property int front()
4457         {
4458             return arr[index];
4459         }
4460 
4461         bool empty() const
4462         {
4463             return arr.length == index;
4464         }
4465 
4466         void popFront()
4467         {
4468             index++;
4469         }
4470 
4471         int[] arr;
4472         size_t index = 0;
4473     }
4474 
4475     static assert(isInputRange!InRange);
4476 
4477     auto arr1 = InRange([5, 2, 3, 4, 5, 3, 6]);
4478     auto arr2 = InRange([7, 3, 8, 2, 1, 4]);
4479 
4480     assert(arr1.minIndex == 1);
4481     assert(arr2.minIndex == 4);
4482 }
4483 
4484 /**
4485 Computes the index of the first occurrence of `range`'s maximum element.
4486 
4487 Complexity: $(BIGOH range)
4488     Exactly `range.length - 1` comparisons are needed.
4489 
4490 Params:
4491     pred = The ordering predicate to use to determine the maximum element.
4492     range = The $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to search.
4493 
4494 Returns:
4495     The index of the first encounter of the maximum in `range`. If the
4496     `range` is empty, -1 is returned.
4497 
4498 Limitations:
4499     If at least one of the arguments is NaN, the result is
4500     an unspecified value. See $(REF maxElement, std,algorithm,searching)
4501     for examples on how to cope with NaNs.
4502 
4503 See_Also:
4504     $(LREF minIndex), $(REF max, std,algorithm,comparison), $(LREF maxCount), $(LREF maxElement), $(LREF maxPos)
4505  */
4506 ptrdiff_t maxIndex(alias pred = "a < b", Range)(Range range)
4507 if (isInputRange!Range && !isInfinite!Range &&
4508     is(typeof(binaryFun!pred(range.front, range.front))))
4509 {
4510     return range.minIndex!((a, b) => binaryFun!pred(b, a));
4511 }
4512 
4513 ///
4514 @safe pure nothrow unittest
4515 {
4516     // Maximum is 4 and first occurs in position 2
4517     int[] a = [2, 3, 4, 1, 2, 4, 1, 1, 2];
4518     assert(a.maxIndex == 2);
4519 
4520     // Empty range
4521     int[] b;
4522     assert(b.maxIndex == -1);
4523 
4524     // Works with more custom types
4525     struct Dog { int age; }
4526     Dog[] dogs = [Dog(10), Dog(15), Dog(5)];
4527     assert(dogs.maxIndex!"a.age < b.age" == 1);
4528 }
4529 
4530 @safe pure unittest
4531 {
4532     // should work with const
4533     const(int)[] immArr = [5, 1, 3];
4534     assert(immArr.maxIndex == 0);
4535 
4536     // Works for const ranges too
4537     const int[] c = [2, 5, 4, 1, 2, 3];
4538     assert(c.maxIndex == 1);
4539 
4540 
4541     // should work with immutable
4542     immutable(int)[] immArr2 = [2, 1, 3];
4543     assert(immArr2.maxIndex == 2);
4544 
4545     // with strings
4546     assert(["b", "a", "c"].maxIndex == 2);
4547 
4548     // infinite range
4549     import std.range : cycle;
4550     static assert(!__traits(compiles, cycle([1]).maxIndex));
4551 
4552     // with all dummy ranges
4553     import std.internal.test.dummyrange : AllDummyRanges;
4554     foreach (DummyType; AllDummyRanges)
4555     {
4556         static if (isForwardRange!DummyType && !isInfinite!DummyType)
4557         {
4558             DummyType d;
4559 
4560             d.arr = [5, 3, 7, 2, 1, 4];
4561             assert(d.maxIndex == 2);
4562 
4563             d.arr = [];
4564             assert(d.maxIndex == -1);
4565         }
4566     }
4567 }
4568 
4569 @nogc @safe nothrow pure unittest
4570 {
4571     static immutable arr = [7, 3, 8, 2, 1, 4];
4572     assert(arr.maxIndex == 2);
4573 
4574     static immutable arr2d = [[1, 3], [3, 9], [4, 2]];
4575     assert(arr2d.maxIndex!"a[1] < b[1]" == 1);
4576 }
4577 
4578 /**
4579 Skip over the initial portion of the first given range (`haystack`) that matches
4580 any of the additionally given ranges (`needles`) fully, or
4581 if no second range is given skip over the elements that fulfill pred.
4582 Do nothing if there is no match.
4583 
4584 Params:
4585     pred = The predicate that determines whether elements from each respective
4586         range match. Defaults to equality `"a == b"`.
4587 */
4588 template skipOver(alias pred = (a, b) => a == b)
4589 {
4590     enum bool isPredComparable(T) = ifTestable!(T, binaryFun!pred);
4591 
4592     /**
4593     Params:
4594         haystack = The $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) to
4595                    move forward.
4596         needles = The $(REF_ALTTEXT input ranges, isInputRange, std,range,primitives)
4597                   representing the prefix of `r1` to skip over.
4598         es = The element to match.
4599 
4600     Returns:
4601         `true` if the prefix of `haystack` matches any range of `needles` fully
4602         or `pred` evaluates to true, and `haystack` has been advanced to the point past this segment;
4603         otherwise false, and `haystack` is left in its original position.
4604 
4605     Note:
4606         By definition, empty ranges are matched fully and if `needles` contains an empty range,
4607         `skipOver` will return `true`.
4608     */
4609     bool skipOver(Haystack, Needles...)(ref Haystack haystack, Needles needles)
4610     if (is(typeof(binaryFun!pred(haystack.front, needles[0].front))) &&
4611         isForwardRange!Haystack &&
4612         allSatisfy!(isInputRange, Needles) &&
4613         !is(CommonType!(staticMap!(ElementType, staticMap!(Unqual, Needles))) == void))
4614     {
4615         static if (__traits(isSame, pred, (a, b) => a == b)
4616                 && is(typeof(haystack[0 .. $] == needles[0]) : bool)
4617                 && is(typeof(haystack = haystack[0 .. $]))
4618                 && hasLength!Haystack && allSatisfy!(hasLength, Needles))
4619         {
4620             ptrdiff_t longestMatch = -1;
4621             static foreach (r2; needles)
4622             {
4623                 if (r2.length <= haystack.length && longestMatch < ptrdiff_t(r2.length)
4624                         && (haystack[0 .. r2.length] == r2 || r2.length == 0))
4625                     longestMatch = r2.length;
4626             }
4627             if (longestMatch >= 0)
4628             {
4629                 if (longestMatch > 0)
4630                     haystack = haystack[longestMatch .. $];
4631 
4632                 return true;
4633             }
4634             return false;
4635         }
4636         else
4637         {
4638             import std.algorithm.comparison : min;
4639             auto r = haystack.save;
4640 
4641             static if (hasLength!Haystack && allSatisfy!(hasLength, Needles))
4642             {
4643                 import std.algorithm.iteration : map;
4644                 import std.algorithm.searching : minElement;
4645                 import std.range : only;
4646                 // Shortcut opportunity!
4647                 if (needles.only.map!(a => a.length).minElement > haystack.length)
4648                     return false;
4649             }
4650 
4651             // compatibility: return true if any range was empty
4652             bool hasEmptyRanges;
4653             static foreach (i, r2; needles)
4654             {
4655                 if (r2.empty)
4656                     hasEmptyRanges = true;
4657             }
4658 
4659             bool hasNeedleMatch;
4660             size_t inactiveNeedlesLen;
4661             bool[Needles.length] inactiveNeedles;
4662             for (; !r.empty; r.popFront)
4663             {
4664                 static foreach (i, r2; needles)
4665                 {
4666                     if (!r2.empty && !inactiveNeedles[i])
4667                     {
4668                         if (binaryFun!pred(r.front, r2.front))
4669                         {
4670                             r2.popFront;
4671                             if (r2.empty)
4672                             {
4673                                 // we skipped over a new match
4674                                 hasNeedleMatch = true;
4675                                 inactiveNeedlesLen++;
4676                                 // skip over haystack
4677                                 haystack = r;
4678                             }
4679                         }
4680                         else
4681                         {
4682                             inactiveNeedles[i] = true;
4683                             inactiveNeedlesLen++;
4684                         }
4685                     }
4686                 }
4687 
4688                 // are we done?
4689                 if (inactiveNeedlesLen == needles.length)
4690                     break;
4691             }
4692 
4693             if (hasNeedleMatch)
4694                 haystack.popFront;
4695 
4696             return hasNeedleMatch || hasEmptyRanges;
4697         }
4698     }
4699 
4700     /// Ditto
4701     bool skipOver(R)(ref R r1)
4702     if (isForwardRange!R &&
4703         ifTestable!(typeof(r1.front), unaryFun!pred))
4704     {
4705         if (r1.empty || !unaryFun!pred(r1.front))
4706             return false;
4707 
4708         do
4709             r1.popFront();
4710         while (!r1.empty && unaryFun!pred(r1.front));
4711         return true;
4712     }
4713 
4714     /// Ditto
4715     bool skipOver(R, Es...)(ref R r, Es es)
4716     if (isInputRange!R && is(typeof(binaryFun!pred(r.front, es[0]))))
4717     {
4718         if (r.empty)
4719             return false;
4720 
4721         static foreach (e; es)
4722         {
4723             if (binaryFun!pred(r.front, e))
4724             {
4725                 r.popFront();
4726                 return true;
4727             }
4728         }
4729         return false;
4730     }
4731 }
4732 
4733 ///
4734 @safe unittest
4735 {
4736     import std.algorithm.comparison : equal;
4737 
4738     auto s1 = "Hello world";
4739     assert(!skipOver(s1, "Ha"));
4740     assert(s1 == "Hello world");
4741     assert(skipOver(s1, "Hell") && s1 == "o world", s1);
4742 
4743     string[]  r1 = ["abc", "def", "hij"];
4744     dstring[] r2 = ["abc"d];
4745     assert(!skipOver!((a, b) => a.equal(b))(r1, ["def"d]), r1[0]);
4746     assert(r1 == ["abc", "def", "hij"]);
4747     assert(skipOver!((a, b) => a.equal(b))(r1, r2));
4748     assert(r1 == ["def", "hij"]);
4749 }
4750 
4751 ///
4752 @safe unittest
4753 {
4754     import std.ascii : isWhite;
4755     import std.range.primitives : empty;
4756 
4757     auto s2 = "\t\tvalue";
4758     auto s3 = "";
4759     auto s4 = "\t\t\t";
4760     assert(s2.skipOver!isWhite && s2 == "value");
4761     assert(!s3.skipOver!isWhite);
4762     assert(s4.skipOver!isWhite && s3.empty);
4763 }
4764 
4765 /// Variadic skipOver
4766 @safe unittest
4767 {
4768     auto s = "Hello world";
4769     assert(!skipOver(s, "hello", "HellO"));
4770     assert(s == "Hello world");
4771 
4772     // the range is skipped over the longest matching needle is skipped
4773     assert(skipOver(s, "foo", "hell", "Hello "));
4774     assert(s == "world");
4775 }
4776 
4777 ///
4778 @safe unittest
4779 {
4780     import std.algorithm.comparison : equal;
4781 
4782     auto s1 = "Hello world";
4783     assert(!skipOver(s1, 'a'));
4784     assert(s1 == "Hello world");
4785     assert(skipOver(s1, 'H') && s1 == "ello world");
4786 
4787     string[] r = ["abc", "def", "hij"];
4788     dstring e = "abc"d;
4789     assert(!skipOver!((a, b) => a.equal(b))(r, "def"d));
4790     assert(r == ["abc", "def", "hij"]);
4791     assert(skipOver!((a, b) => a.equal(b))(r, e));
4792     assert(r == ["def", "hij"]);
4793 
4794     auto s2 = "";
4795     assert(!s2.skipOver('a'));
4796 }
4797 
4798 /// Partial instantiation
4799 @safe unittest
4800 {
4801     import std.ascii : isWhite;
4802     import std.range.primitives : empty;
4803 
4804     alias whitespaceSkiper = skipOver!isWhite;
4805 
4806     auto s2 = "\t\tvalue";
4807     auto s3 = "";
4808     auto s4 = "\t\t\t";
4809     assert(whitespaceSkiper(s2) && s2 == "value");
4810     assert(!whitespaceSkiper(s2));
4811     assert(whitespaceSkiper(s4) && s3.empty);
4812 }
4813 
4814 // variadic skipOver
4815 @safe unittest
4816 {
4817     auto s = "DLang.rocks";
4818     assert(!s.skipOver("dlang", "DLF", "DLang "));
4819     assert(s == "DLang.rocks");
4820 
4821     assert(s.skipOver("dlang", "DLANG", "DLF", "D", "DL", "DLanpp"));
4822     assert(s == "ang.rocks");
4823     s = "DLang.rocks";
4824 
4825     assert(s.skipOver("DLang", "DLANG", "DLF", "D", "DL", "DLang "));
4826     assert(s == ".rocks");
4827     s = "DLang.rocks";
4828 
4829     assert(s.skipOver("dlang", "DLANG", "DLF", "D", "DL", "DLang."));
4830     assert(s == "rocks");
4831 }
4832 
4833 // variadic with custom pred
4834 @safe unittest
4835 {
4836     import std.ascii : toLower;
4837 
4838     auto s = "DLang.rocks";
4839     assert(!s.skipOver("dlang", "DLF", "DLang "));
4840     assert(s == "DLang.rocks");
4841 
4842     assert(s.skipOver!((a, b) => a.toLower == b.toLower)("dlang", "DLF", "DLang "));
4843     assert(s == ".rocks");
4844 }
4845 
4846 // variadic skipOver with mixed needles
4847 @safe unittest
4848 {
4849     auto s = "DLang.rocks";
4850     assert(!s.skipOver("dlang"d, "DLF", "DLang "w));
4851     assert(s == "DLang.rocks");
4852 
4853     assert(s.skipOver("dlang", "DLANG"d, "DLF"w, "D"d, "DL", "DLanp"));
4854     assert(s == "ang.rocks");
4855     s = "DLang.rocks";
4856 
4857     assert(s.skipOver("DLang", "DLANG"w, "DLF"d, "D"d, "DL", "DLang "));
4858     assert(s == ".rocks");
4859     s = "DLang.rocks";
4860 
4861     assert(s.skipOver("dlang", "DLANG"w, "DLF", "D"d, "DL"w, "DLang."d));
4862     assert(s == "rocks");
4863 
4864     import std.algorithm.iteration : filter;
4865     s = "DLang.rocks";
4866     assert(s.skipOver("dlang", "DLang".filter!(a => true)));
4867     assert(s == ".rocks");
4868 }
4869 
4870 // variadic skipOver with auto-decoding
4871 @safe unittest
4872 {
4873     auto s = "☢☣☠.☺";
4874     assert(s.skipOver("a", "☢", "☢☣☠"));
4875     assert(s == ".☺");
4876 }
4877 
4878 // skipOver with @nogc
4879 @safe @nogc pure nothrow unittest
4880 {
4881     static immutable s = [0, 1, 2];
4882     immutable(int)[] s2 = s[];
4883 
4884     static immutable skip1 = [0, 2];
4885     static immutable skip2 = [0, 1];
4886     assert(s2.skipOver(skip1, skip2));
4887     assert(s2 == s[2 .. $]);
4888 }
4889 
4890 // variadic skipOver with single elements
4891 @safe unittest
4892 {
4893     auto s = "DLang.rocks";
4894     assert(!s.skipOver('a', 'd', 'e'));
4895     assert(s == "DLang.rocks");
4896 
4897     assert(s.skipOver('a', 'D', 'd', 'D'));
4898     assert(s == "Lang.rocks");
4899     s = "DLang.rocks";
4900 
4901     assert(s.skipOver(wchar('a'), dchar('D'), 'd'));
4902     assert(s == "Lang.rocks");
4903 
4904     dstring dstr = "+Foo";
4905     assert(!dstr.skipOver('.', '-'));
4906     assert(dstr == "+Foo");
4907 
4908     assert(dstr.skipOver('+', '-'));
4909     assert(dstr == "Foo");
4910 }
4911 
4912 // skipOver with empty ranges must return true (compatibility)
4913 @safe unittest
4914 {
4915     auto s = "DLang.rocks";
4916     assert(s.skipOver(""));
4917     assert(s.skipOver("", ""));
4918     assert(s.skipOver("", "foo"));
4919 
4920     auto s2 = "DLang.rocks"d;
4921     assert(s2.skipOver(""));
4922     assert(s2.skipOver("", ""));
4923     assert(s2.skipOver("", "foo"));
4924 }
4925 
4926 // dxml regression
4927 @safe unittest
4928 {
4929     import std.utf : byCodeUnit;
4930     import std.algorithm.comparison : equal;
4931 
4932     bool stripStartsWith(Text)(ref Text text, string needle)
4933     {
4934         return text.skipOver(needle.byCodeUnit());
4935     }
4936     auto text = "<xml></xml>"d.byCodeUnit;
4937     assert(stripStartsWith(text, "<xml>"));
4938     assert(text.equal("</xml>"));
4939 }
4940 
4941 /**
4942 Checks whether the given
4943 $(REF_ALTTEXT input range, isInputRange, std,range,primitives) starts with (one
4944 of) the given needle(s) or, if no needles are given,
4945 if its front element fulfils predicate `pred`.
4946 
4947 For more information about `pred` see $(LREF find).
4948 
4949 Params:
4950 
4951     pred = Predicate to use in comparing the elements of the haystack and the
4952         needle(s). Mandatory if no needles are given.
4953 
4954     doesThisStart = The input range to check.
4955 
4956     withOneOfThese = The needles against which the range is to be checked,
4957         which may be individual elements or input ranges of elements.
4958 
4959     withThis = The single needle to check, which may be either a single element
4960         or an input range of elements.
4961 
4962 Returns:
4963 
4964 0 if the needle(s) do not occur at the beginning of the given range;
4965 otherwise the position of the matching needle, that is, 1 if the range starts
4966 with `withOneOfThese[0]`, 2 if it starts with `withOneOfThese[1]`, and so
4967 on.
4968 
4969 In the case where `doesThisStart` starts with multiple of the ranges or
4970 elements in `withOneOfThese`, then the shortest one matches (if there are
4971 two which match which are of the same length (e.g. `"a"` and `'a'`), then
4972 the left-most of them in the argument
4973 list matches).
4974 
4975 In the case when no needle parameters are given, return `true` iff front of
4976 `doesThisStart` fulfils predicate `pred`.
4977  */
4978 uint startsWith(alias pred = (a, b) => a == b, Range, Needles...)(Range doesThisStart, Needles withOneOfThese)
4979 if (isInputRange!Range && Needles.length > 1 &&
4980     allSatisfy!(canTestStartsWith!(pred, Range), Needles))
4981 {
4982     template checkType(T)
4983     {
4984         enum checkType = is(immutable ElementEncodingType!Range == immutable T);
4985     }
4986 
4987     // auto-decoding special case
4988     static if (__traits(isSame, binaryFun!pred, (a, b) => a == b) &&
4989         isNarrowString!Range && allSatisfy!(checkType, Needles))
4990     {
4991         import std.utf : byCodeUnit;
4992         auto haystack = doesThisStart.byCodeUnit;
4993     }
4994     else
4995     {
4996         alias haystack = doesThisStart;
4997     }
4998     alias needles  = withOneOfThese;
4999 
5000     // Make one pass looking for empty ranges in needles
5001     foreach (i, Unused; Needles)
5002     {
5003         // Empty range matches everything
5004         static if (!is(typeof(binaryFun!pred(haystack.front, needles[i])) : bool))
5005         {
5006             if (needles[i].empty) return i + 1;
5007         }
5008     }
5009 
5010     for (; !haystack.empty; haystack.popFront())
5011     {
5012         foreach (i, Unused; Needles)
5013         {
5014             static if (is(typeof(binaryFun!pred(haystack.front, needles[i])) : bool))
5015             {
5016                 // Single-element
5017                 if (binaryFun!pred(haystack.front, needles[i]))
5018                 {
5019                     // found, but instead of returning, we just stop searching.
5020                     // This is to account for one-element
5021                     // range matches (consider startsWith("ab", "a",
5022                     // 'a') should return 1, not 2).
5023                     break;
5024                 }
5025             }
5026             else
5027             {
5028                 if (binaryFun!pred(haystack.front, needles[i].front))
5029                 {
5030                     continue;
5031                 }
5032             }
5033 
5034             // This code executed on failure to match
5035             // Out with this guy, check for the others
5036             uint result = startsWith!pred(haystack, needles[0 .. i], needles[i + 1 .. $]);
5037             if (result > i) ++result;
5038             return result;
5039         }
5040 
5041         // If execution reaches this point, then the front matches for all
5042         // needle ranges, or a needle element has been matched.
5043         // What we need to do now is iterate, lopping off the front of
5044         // the range and checking if the result is empty, or finding an
5045         // element needle and returning.
5046         // If neither happens, we drop to the end and loop.
5047         foreach (i, Unused; Needles)
5048         {
5049             static if (is(typeof(binaryFun!pred(haystack.front, needles[i])) : bool))
5050             {
5051                 // Test has passed in the previous loop
5052                 return i + 1;
5053             }
5054             else
5055             {
5056                 needles[i].popFront();
5057                 if (needles[i].empty) return i + 1;
5058             }
5059         }
5060     }
5061     return 0;
5062 }
5063 
5064 /// Ditto
5065 bool startsWith(alias pred = "a == b", R1, R2)(R1 doesThisStart, R2 withThis)
5066 if (isInputRange!R1 &&
5067     isInputRange!R2 &&
5068     is(typeof(binaryFun!pred(doesThisStart.front, withThis.front)) : bool))
5069 {
5070     alias haystack = doesThisStart;
5071     alias needle   = withThis;
5072 
5073     static if (is(typeof(pred) : string))
5074         enum isDefaultPred = pred == "a == b";
5075     else
5076         enum isDefaultPred = false;
5077 
5078     // Note: Although narrow strings don't have a "true" length, for a narrow string to start with another
5079     // narrow string, it must have *at least* as many code units.
5080     static if ((hasLength!R1 && hasLength!R2) ||
5081         ((hasLength!R1 || isNarrowString!R1) && (hasLength!R2 || isNarrowString!R2)
5082             && (ElementEncodingType!R1.sizeof <= ElementEncodingType!R2.sizeof)))
5083     {
5084         if (haystack.length < needle.length)
5085             return false;
5086     }
5087 
5088     static if (isDefaultPred && isArray!R1 && isArray!R2 &&
5089                is(immutable ElementEncodingType!R1 == immutable ElementEncodingType!R2))
5090     {
5091         //Array slice comparison mode
5092         return haystack[0 .. needle.length] == needle;
5093     }
5094     else static if (isRandomAccessRange!R1 && isRandomAccessRange!R2 && hasLength!R2)
5095     {
5096         //RA dual indexing mode
5097         foreach (j; 0 .. needle.length)
5098         {
5099             if (!binaryFun!pred(haystack[j], needle[j]))
5100                 // not found
5101                 return false;
5102         }
5103         // found!
5104         return true;
5105     }
5106     else
5107     {
5108         //Standard input range mode
5109         if (needle.empty) return true;
5110         static if (hasLength!R1 && hasLength!R2)
5111         {
5112             //We have previously checked that haystack.length > needle.length,
5113             //So no need to check haystack.empty during iteration
5114             for ( ; ; haystack.popFront() )
5115             {
5116                 if (!binaryFun!pred(haystack.front, needle.front)) break;
5117                 needle.popFront();
5118                 if (needle.empty) return true;
5119             }
5120         }
5121         else
5122         {
5123             for ( ; !haystack.empty ; haystack.popFront() )
5124             {
5125                 if (!binaryFun!pred(haystack.front, needle.front)) break;
5126                 needle.popFront();
5127                 if (needle.empty) return true;
5128             }
5129         }
5130         return false;
5131     }
5132 }
5133 
5134 /// Ditto
5135 bool startsWith(alias pred = "a == b", R, E)(R doesThisStart, E withThis)
5136 if (isInputRange!R &&
5137     is(typeof(binaryFun!pred(doesThisStart.front, withThis)) : bool))
5138 {
5139     if (doesThisStart.empty)
5140         return false;
5141 
5142     static if (is(typeof(pred) : string))
5143         enum isDefaultPred = pred == "a == b";
5144     else
5145         enum isDefaultPred = false;
5146 
5147     alias predFunc = binaryFun!pred;
5148 
5149     // auto-decoding special case
5150     static if (isNarrowString!R)
5151     {
5152         // statically determine decoding is unnecessary to evaluate pred
5153         static if (isDefaultPred && isSomeChar!E && E.sizeof <= ElementEncodingType!R.sizeof)
5154             return doesThisStart[0] == withThis;
5155         // specialize for ASCII as to not change previous behavior
5156         else
5157         {
5158             if (withThis <= 0x7F)
5159                 return predFunc(doesThisStart[0], withThis);
5160             else
5161                 return predFunc(doesThisStart.front, withThis);
5162         }
5163     }
5164     else
5165     {
5166         return predFunc(doesThisStart.front, withThis);
5167     }
5168 }
5169 
5170 /// Ditto
5171 bool startsWith(alias pred, R)(R doesThisStart)
5172 if (isInputRange!R &&
5173     ifTestable!(typeof(doesThisStart.front), unaryFun!pred))
5174 {
5175     return !doesThisStart.empty && unaryFun!pred(doesThisStart.front);
5176 }
5177 
5178 ///
5179 @safe unittest
5180 {
5181     import std.ascii : isAlpha;
5182 
5183     assert("abc".startsWith!(a => a.isAlpha));
5184     assert("abc".startsWith!isAlpha);
5185     assert(!"1ab".startsWith!(a => a.isAlpha));
5186     assert(!"".startsWith!(a => a.isAlpha));
5187 
5188     import std.algorithm.comparison : among;
5189     assert("abc".startsWith!(a => a.among('a', 'b') != 0));
5190     assert(!"abc".startsWith!(a => a.among('b', 'c') != 0));
5191 
5192     assert(startsWith("abc", ""));
5193     assert(startsWith("abc", "a"));
5194     assert(!startsWith("abc", "b"));
5195     assert(startsWith("abc", 'a', "b") == 1);
5196     assert(startsWith("abc", "b", "a") == 2);
5197     assert(startsWith("abc", "a", "a") == 1);
5198     assert(startsWith("abc", "ab", "a") == 2);
5199     assert(startsWith("abc", "x", "a", "b") == 2);
5200     assert(startsWith("abc", "x", "aa", "ab") == 3);
5201     assert(startsWith("abc", "x", "aaa", "sab") == 0);
5202     assert(startsWith("abc", "x", "aaa", "a", "sab") == 3);
5203 
5204     import std.typecons : Tuple;
5205     alias C = Tuple!(int, "x", int, "y");
5206     assert(startsWith!"a.x == b"([ C(1,1), C(1,2), C(2,2) ], [1, 1]));
5207     assert(startsWith!"a.x == b"([ C(1,1), C(2,1), C(2,2) ], [1, 1], [1, 2], [1, 3]) == 2);
5208 }
5209 
5210 @safe unittest
5211 {
5212     import std.algorithm.iteration : filter;
5213     import std.conv : to;
5214     import std.meta : AliasSeq;
5215     import std.range;
5216 
5217     static foreach (S; AliasSeq!(char[], wchar[], dchar[], string, wstring, dstring))
5218     (){ // workaround slow optimizations for large functions
5219         // https://issues.dlang.org/show_bug.cgi?id=2396
5220         assert(!startsWith(to!S("abc"), 'c'));
5221         assert(startsWith(to!S("abc"), 'a', 'c') == 1);
5222         assert(!startsWith(to!S("abc"), 'x', 'n', 'b'));
5223         assert(startsWith(to!S("abc"), 'x', 'n', 'a') == 3);
5224         assert(startsWith(to!S("\uFF28abc"), 'a', '\uFF28', 'c') == 2);
5225 
5226         static foreach (T; AliasSeq!(char[], wchar[], dchar[], string, wstring, dstring))
5227         {
5228             //Lots of strings
5229             assert(startsWith(to!S("abc"), to!T("")));
5230             assert(startsWith(to!S("ab"), to!T("a")));
5231             assert(startsWith(to!S("abc"), to!T("a")));
5232             assert(!startsWith(to!S("abc"), to!T("b")));
5233             assert(!startsWith(to!S("abc"), to!T("b"), "bc", "abcd", "xyz"));
5234             assert(startsWith(to!S("abc"), to!T("ab"), 'a') == 2);
5235             assert(startsWith(to!S("abc"), to!T("a"), "b") == 1);
5236             assert(startsWith(to!S("abc"), to!T("b"), "a") == 2);
5237             assert(startsWith(to!S("abc"), to!T("a"), 'a') == 1);
5238             assert(startsWith(to!S("abc"), 'a', to!T("a")) == 1);
5239             assert(startsWith(to!S("abc"), to!T("x"), "a", "b") == 2);
5240             assert(startsWith(to!S("abc"), to!T("x"), "aa", "ab") == 3);
5241             assert(startsWith(to!S("abc"), to!T("x"), "aaa", "sab") == 0);
5242             assert(startsWith(to!S("abc"), 'a'));
5243             assert(!startsWith(to!S("abc"), to!T("sab")));
5244             assert(startsWith(to!S("abc"), 'x', to!T("aaa"), 'a', "sab") == 3);
5245 
5246             //Unicode
5247             assert(startsWith(to!S("\uFF28el\uFF4co"), to!T("\uFF28el")));
5248             assert(startsWith(to!S("\uFF28el\uFF4co"), to!T("Hel"), to!T("\uFF28el")) == 2);
5249             assert(startsWith(to!S("日本語"), to!T("日本")));
5250             assert(startsWith(to!S("日本語"), to!T("日本語")));
5251             assert(!startsWith(to!S("日本"), to!T("日本語")));
5252 
5253             //Empty
5254             assert(startsWith(to!S(""),  T.init));
5255             assert(!startsWith(to!S(""), 'a'));
5256             assert(startsWith(to!S("a"), T.init));
5257             assert(startsWith(to!S("a"), T.init, "") == 1);
5258             assert(startsWith(to!S("a"), T.init, 'a') == 1);
5259             assert(startsWith(to!S("a"), 'a', T.init) == 2);
5260         }
5261     }();
5262 
5263     //Length but no RA
5264     assert(!startsWith("abc".takeExactly(3), "abcd".takeExactly(4)));
5265     assert(startsWith("abc".takeExactly(3), "abcd".takeExactly(3)));
5266     assert(startsWith("abc".takeExactly(3), "abcd".takeExactly(1)));
5267 
5268     static foreach (T; AliasSeq!(int, short))
5269     {{
5270         immutable arr = cast(T[])[0, 1, 2, 3, 4, 5];
5271 
5272         //RA range
5273         assert(startsWith(arr, cast(int[]) null));
5274         assert(!startsWith(arr, 5));
5275         assert(!startsWith(arr, 1));
5276         assert(startsWith(arr, 0));
5277         assert(startsWith(arr, 5, 0, 1) == 2);
5278         assert(startsWith(arr, [0]));
5279         assert(startsWith(arr, [0, 1]));
5280         assert(startsWith(arr, [0, 1], 7) == 1);
5281         assert(!startsWith(arr, [0, 1, 7]));
5282         assert(startsWith(arr, [0, 1, 7], [0, 1, 2]) == 2);
5283 
5284         //Normal input range
5285         assert(!startsWith(filter!"true"(arr), 1));
5286         assert(startsWith(filter!"true"(arr), 0));
5287         assert(startsWith(filter!"true"(arr), [0]));
5288         assert(startsWith(filter!"true"(arr), [0, 1]));
5289         assert(startsWith(filter!"true"(arr), [0, 1], 7) == 1);
5290         assert(!startsWith(filter!"true"(arr), [0, 1, 7]));
5291         assert(startsWith(filter!"true"(arr), [0, 1, 7], [0, 1, 2]) == 2);
5292         assert(startsWith(arr, filter!"true"([0, 1])));
5293         assert(startsWith(arr, filter!"true"([0, 1]), 7) == 1);
5294         assert(!startsWith(arr, filter!"true"([0, 1, 7])));
5295         assert(startsWith(arr, [0, 1, 7], filter!"true"([0, 1, 2])) == 2);
5296 
5297         //Non-default pred
5298         assert(startsWith!("a%10 == b%10")(arr, [10, 11]));
5299         assert(!startsWith!("a%10 == b%10")(arr, [10, 12]));
5300     }}
5301 }
5302 
5303 private template canTestStartsWith(alias pred, Haystack)
5304 {
5305     enum bool canTestStartsWith(Needle) = is(typeof(
5306         (ref Haystack h, ref Needle n) => startsWith!pred(h, n)));
5307 }
5308 
5309 /* (Not yet documented.)
5310 Consume all elements from `r` that are equal to one of the elements
5311 `es`.
5312  */
5313 private void skipAll(alias pred = "a == b", R, Es...)(ref R r, Es es)
5314 //if (is(typeof(binaryFun!pred(r1.front, es[0]))))
5315 {
5316   loop:
5317     for (; !r.empty; r.popFront())
5318     {
5319         foreach (i, E; Es)
5320         {
5321             if (binaryFun!pred(r.front, es[i]))
5322             {
5323                 continue loop;
5324             }
5325         }
5326         break;
5327     }
5328 }
5329 
5330 @safe unittest
5331 {
5332     auto s1 = "Hello world";
5333     skipAll(s1, 'H', 'e');
5334     assert(s1 == "llo world");
5335 }
5336 
5337 /**
5338 Interval option specifier for `until` (below) and others.
5339 
5340 If set to `OpenRight.yes`, then the interval is open to the right
5341 (last element is not included).
5342 
5343 Otherwise if set to `OpenRight.no`, then the interval is closed to the right
5344 including the entire sentinel.
5345  */
5346 alias OpenRight = Flag!"openRight";
5347 
5348 /**
5349 Lazily iterates `range` _until the element `e` for which
5350 `pred(e, sentinel)` is true.
5351 
5352 This is similar to `takeWhile` in other languages.
5353 
5354 Params:
5355     pred = Predicate to determine when to stop.
5356     range = The $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
5357     to iterate over.
5358     sentinel = The element to stop at.
5359     openRight = Determines whether the element for which the given predicate is
5360         true should be included in the resulting range (`No.openRight`), or
5361         not (`Yes.openRight`).
5362 
5363 Returns:
5364     An $(REF_ALTTEXT input range, isInputRange, std,range,primitives) that
5365     iterates over the original range's elements, but ends when the specified
5366     predicate becomes true. If the original range is a
5367     $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) or
5368     higher, this range will be a forward range.
5369  */
5370 Until!(pred, Range, Sentinel)
5371 until(alias pred = "a == b", Range, Sentinel)
5372 (Range range, Sentinel sentinel, OpenRight openRight = Yes.openRight)
5373 if (!is(Sentinel == OpenRight))
5374 {
5375     return typeof(return)(range, sentinel, openRight);
5376 }
5377 
5378 /// Ditto
5379 Until!(pred, Range, void)
5380 until(alias pred, Range)
5381 (Range range, OpenRight openRight = Yes.openRight)
5382 {
5383     return typeof(return)(range, openRight);
5384 }
5385 
5386 /// ditto
5387 struct Until(alias pred, Range, Sentinel)
5388 if (isInputRange!Range)
5389 {
5390     private Range _input;
5391     static if (!is(Sentinel == void))
5392         private Sentinel _sentinel;
5393     private OpenRight _openRight;
5394     private bool _matchStarted;
5395     private bool _done;
5396 
5397     static if (!is(Sentinel == void))
5398     {
5399         ///
5400         this(Range input, Sentinel sentinel,
5401                 OpenRight openRight = Yes.openRight)
5402         {
5403             _input = input;
5404             _sentinel = sentinel;
5405             _openRight = openRight;
5406             static if (isInputRange!Sentinel
5407                 && is(immutable ElementEncodingType!Sentinel == immutable ElementEncodingType!Range))
5408             {
5409                 _matchStarted = predSatisfied();
5410                 _done = _input.empty || _sentinel.empty || openRight && _matchStarted;
5411                 if (_matchStarted && !_done && !openRight)
5412                 {
5413                     _sentinel.popFront;
5414                 }
5415             }
5416             else
5417             {
5418                 _done = _input.empty || openRight && predSatisfied();
5419             }
5420         }
5421         private this(Range input, Sentinel sentinel, OpenRight openRight,
5422             bool done)
5423         {
5424             _input = input;
5425             _sentinel = sentinel;
5426             _openRight = openRight;
5427             _done = done;
5428         }
5429     }
5430     else
5431     {
5432         ///
5433         this(Range input, OpenRight openRight = Yes.openRight)
5434         {
5435             _input = input;
5436             _openRight = openRight;
5437             _done = _input.empty || openRight && predSatisfied();
5438         }
5439         private this(Range input, OpenRight openRight, bool done)
5440         {
5441             _input = input;
5442             _openRight = openRight;
5443             _done = done;
5444         }
5445     }
5446 
5447     ///
5448     @property bool empty()
5449     {
5450         return _done;
5451     }
5452 
5453     ///
5454     @property auto ref front()
5455     {
5456         assert(!empty, "Can not get the front of an empty Until");
5457         return _input.front;
5458     }
5459 
5460     private bool predSatisfied()
5461     {
5462         static if (is(Sentinel == void))
5463             return cast(bool) unaryFun!pred(_input.front);
5464         else
5465             return cast(bool) startsWith!pred(_input, _sentinel);
5466     }
5467 
5468     ///
5469     void popFront()
5470     {
5471         assert(!empty, "Can not popFront of an empty Until");
5472         if (!_openRight)
5473         {
5474             static if (isInputRange!Sentinel
5475                 && is(immutable ElementEncodingType!Sentinel == immutable ElementEncodingType!Range))
5476             {
5477                 _input.popFront();
5478                 _done = _input.empty || _sentinel.empty;
5479                 if (!_done)
5480                 {
5481                     if (_matchStarted)
5482                     {
5483                         _sentinel.popFront;
5484                     }
5485                     else
5486                     {
5487                         _matchStarted = predSatisfied();
5488                         if (_matchStarted)
5489                         {
5490                             _sentinel.popFront;
5491                         }
5492                     }
5493                 }
5494             }
5495             else
5496             {
5497                 _done = predSatisfied();
5498                 _input.popFront();
5499                 _done = _done || _input.empty;
5500             }
5501         }
5502         else
5503         {
5504             _input.popFront();
5505             _done = _input.empty || predSatisfied();
5506         }
5507     }
5508 
5509     static if (isForwardRange!Range)
5510     {
5511         ///
5512         @property Until save()
5513         {
5514             static if (is(Sentinel == void))
5515                 return Until(_input.save, _openRight, _done);
5516             else
5517                 return Until(_input.save, _sentinel, _openRight, _done);
5518         }
5519     }
5520 }
5521 
5522 ///
5523 @safe unittest
5524 {
5525     import std.algorithm.comparison : equal;
5526     import std.typecons : No;
5527     int[] a = [ 1, 2, 4, 7, 7, 2, 4, 7, 3, 5];
5528     assert(equal(a.until(7), [1, 2, 4]));
5529     assert(equal(a.until(7, No.openRight), [1, 2, 4, 7]));
5530 }
5531 
5532 @safe unittest
5533 {
5534     import std.algorithm.comparison : equal;
5535     int[] a = [ 1, 2, 4, 7, 7, 2, 4, 7, 3, 5];
5536 
5537     static assert(isForwardRange!(typeof(a.until(7))));
5538     static assert(isForwardRange!(typeof(until!"a == 2"(a, No.openRight))));
5539 
5540     assert(equal(a.until(7), [1, 2, 4]));
5541     assert(equal(a.until([7, 2]), [1, 2, 4, 7]));
5542     assert(equal(a.until(7, No.openRight), [1, 2, 4, 7]));
5543     assert(equal(until!"a == 2"(a, No.openRight), [1, 2]));
5544 }
5545 
5546 // https://issues.dlang.org/show_bug.cgi?id=13171
5547 @system unittest
5548 {
5549     import std.algorithm.comparison : equal;
5550     import std.range;
5551     auto a = [1, 2, 3, 4];
5552     assert(equal(refRange(&a).until(3, No.openRight), [1, 2, 3]));
5553     assert(a == [4]);
5554 }
5555 
5556 // https://issues.dlang.org/show_bug.cgi?id=10460
5557 @safe unittest
5558 {
5559     import std.algorithm.comparison : equal;
5560     auto a = [1, 2, 3, 4];
5561     foreach (ref e; a.until(3))
5562         e = 0;
5563     assert(equal(a, [0, 0, 3, 4]));
5564 }
5565 
5566 // https://issues.dlang.org/show_bug.cgi?id=13124
5567 @safe unittest
5568 {
5569     import std.algorithm.comparison : among, equal;
5570     auto s = "hello how\nare you";
5571     assert(equal(s.until!(c => c.among!('\n', '\r')), "hello how"));
5572 }
5573 
5574 // https://issues.dlang.org/show_bug.cgi?id=18657
5575 pure @safe unittest
5576 {
5577     import std.algorithm.comparison : equal;
5578     import std.range : refRange;
5579     {
5580         string s = "foobar";
5581         auto r = refRange(&s).until("bar");
5582         assert(equal(r.save, "foo"));
5583         assert(equal(r.save, "foo"));
5584     }
5585     {
5586         string s = "foobar";
5587         auto r = refRange(&s).until!(e => e == 'b');
5588         assert(equal(r.save, "foo"));
5589         assert(equal(r.save, "foo"));
5590     }
5591 }
5592 
5593 // https://issues.dlang.org/show_bug.cgi?id=14543
5594 pure @safe unittest
5595 {
5596     import std.algorithm.comparison : equal;
5597     import std.uni : toUpper;
5598     assert("one two three".until("two").equal("one "));
5599     assert("one two three".until("two", OpenRight.no).equal("one two"));
5600 
5601     assert("one two three".until("two", No.openRight).equal("one two"));
5602     assert("one two three".until("two", Yes.openRight).equal("one "));
5603 
5604     assert("one two three".until('t', Yes.openRight).equal("one "));
5605     assert("one two three".until("", Yes.openRight).equal(""));
5606     assert("one two three".until("", No.openRight).equal(""));
5607 
5608     assert("one two three".until("three", No.openRight).equal("one two three"));
5609     assert("one two three".until("three", Yes.openRight).equal("one two "));
5610 
5611     assert("one two three".until("one", No.openRight).equal("one"));
5612     assert("one two three".until("one", Yes.openRight).equal(""));
5613 
5614     assert("one two three".until("o", No.openRight).equal("o"));
5615     assert("one two three".until("o", Yes.openRight).equal(""));
5616 
5617     assert("one two three".until("", No.openRight).equal(""));
5618     assert("one two three".until("", Yes.openRight).equal(""));
5619 
5620     assert("one two three".until!((a,b)=>a.toUpper == b)("TWO", No.openRight).equal("one two"));
5621 }
5622 
5623 // https://issues.dlang.org/show_bug.cgi?id=24342
5624 pure @safe unittest
5625 {
5626     import std.algorithm.comparison : equal;
5627     assert(["A", "BC", "D"].until("BC", No.openRight).equal(["A", "BC"]));
5628     assert([[1], [2, 3], [4]].until([2, 3], No.openRight).equal([[1], [2, 3]]));
5629 }