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