1 // Written in the D programming language.
2 /**
3 This is a submodule of $(MREF std, algorithm).
4 It contains generic sorting algorithms.
5 
6 $(SCRIPT inhibitQuickIndex = 1;)
7 $(BOOKTABLE Cheat Sheet,
8 $(TR $(TH Function Name) $(TH Description))
9 $(T2 completeSort,
10         If `a = [10, 20, 30]` and `b = [40, 6, 15]`, then
11         `completeSort(a, b)` leaves `a = [6, 10, 15]` and `b = [20, 30, 40]`.
12         The range `a` must be sorted prior to the call, and as a result the
13         combination `$(REF chain, std,range)(a, b)` is sorted.)
14 $(T2 isPartitioned,
15         `isPartitioned!"a < 0"([-1, -2, 1, 0, 2])` returns `true` because
16         the predicate is `true` for a portion of the range and `false`
17         afterwards.)
18 $(T2 isSorted,
19         `isSorted([1, 1, 2, 3])` returns `true`.)
20 $(T2 isStrictlyMonotonic,
21         `isStrictlyMonotonic([1, 1, 2, 3])` returns `false`.)
22 $(T2 ordered,
23         `ordered(1, 1, 2, 3)` returns `true`.)
24 $(T2 strictlyOrdered,
25         `strictlyOrdered(1, 1, 2, 3)` returns `false`.)
26 $(T2 makeIndex,
27         Creates a separate index for a range.)
28 $(T2 merge,
29         Lazily merges two or more sorted ranges.)
30 $(T2 multiSort,
31         Sorts by multiple keys.)
32 $(T2 nextEvenPermutation,
33         Computes the next lexicographically greater even permutation of a range
34         in-place.)
35 $(T2 nextPermutation,
36         Computes the next lexicographically greater permutation of a range
37         in-place.)
38 $(T2 nthPermutation,
39         Computes the nth permutation of a range
40         in-place.)
41 $(T2 partialSort,
42         If `a = [5, 4, 3, 2, 1]`, then `partialSort(a, 3)` leaves
43         `a[0 .. 3] = [1, 2, 3]`.
44         The other elements of `a` are left in an unspecified order.)
45 $(T2 partition,
46         Partitions a range according to a unary predicate.)
47 $(T2 partition3,
48         Partitions a range according to a binary predicate in three parts (less
49         than, equal, greater than the given pivot). Pivot is not given as an
50         index, but instead as an element independent from the range's content.)
51 $(T2 pivotPartition,
52         Partitions a range according to a binary predicate in two parts: less
53         than or equal, and greater than or equal to the given pivot, passed as
54         an index in the range.)
55 $(T2 schwartzSort,
56         Sorts with the help of the $(LINK2 https://en.wikipedia.org/wiki/Schwartzian_transform, Schwartzian transform).)
57 $(T2 sort,
58         Sorts.)
59 $(T2 topN,
60         Separates the top elements in a range, akin to $(LINK2 https://en.wikipedia.org/wiki/Quickselect, Quickselect).)
61 $(T2 topNCopy,
62         Copies out the top elements of a range.)
63 $(T2 topNIndex,
64         Builds an index of the top elements of a range.)
65 )
66 
67 Copyright: Andrei Alexandrescu 2008-.
68 
69 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
70 
71 Authors: $(HTTP erdani.com, Andrei Alexandrescu)
72 
73 Source: $(PHOBOSSRC std/algorithm/sorting.d)
74 
75 Macros:
76 T2=$(TR $(TDNW $(LREF $1)) $(TD $+))
77  */
78 module std.algorithm.sorting;
79 
80 import std.algorithm.mutation : SwapStrategy;
81 import std.functional : unaryFun, binaryFun;
82 import std.range.primitives;
83 import std.typecons : Flag, No, Yes;
84 import std.meta : allSatisfy;
85 import std.range : SortedRange;
86 import std.traits;
87 
88 /**
89 Specifies whether the output of certain algorithm is desired in sorted
90 format.
91 
92 If set to `SortOutput.no`, the output should not be sorted.
93 
94 Otherwise if set to `SortOutput.yes`, the output should be sorted.
95  */
96 alias SortOutput = Flag!"sortOutput";
97 
98 // completeSort
99 /**
100 Sorts the random-access range `chain(lhs, rhs)` according to
101 predicate `less`.
102 
103 The left-hand side of the range `lhs` is assumed to be already sorted;
104 `rhs` is assumed to be unsorted.
105 The exact strategy chosen depends on the relative sizes of `lhs` and
106 `rhs`.  Performs $(BIGOH lhs.length + rhs.length * log(rhs.length))
107 (best case) to $(BIGOH (lhs.length + rhs.length) * log(lhs.length +
108 rhs.length)) (worst-case) evaluations of $(REF_ALTTEXT swap, swap, std,algorithm,mutation).
109 
110 Params:
111     less = The predicate to sort by.
112     ss = The swapping strategy to use.
113     lhs = The sorted, left-hand side of the random access range to be sorted.
114     rhs = The unsorted, right-hand side of the random access range to be
115         sorted.
116 */
117 void completeSort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable,
118         Lhs , Rhs)(SortedRange!(Lhs, less) lhs, Rhs rhs)
119 if (hasLength!(Rhs) && hasSlicing!(Rhs)
120         && hasSwappableElements!Lhs && hasSwappableElements!Rhs)
121 {
122     import std.algorithm.mutation : bringToFront;
123     import std.range : chain, assumeSorted;
124     // Probably this algorithm can be optimized by using in-place
125     // merge
126     auto lhsOriginal = lhs.release();
127     foreach (i; 0 .. rhs.length)
128     {
129         auto sortedSoFar = chain(lhsOriginal, rhs[0 .. i]);
130         auto ub = assumeSorted!less(sortedSoFar).upperBound(rhs[i]);
131         if (!ub.length) continue;
132         bringToFront(ub.release(), rhs[i .. i + 1]);
133     }
134 }
135 
136 ///
137 @safe unittest
138 {
139     import std.range : assumeSorted;
140     int[] a = [ 1, 2, 3 ];
141     int[] b = [ 4, 0, 6, 5 ];
142     completeSort(assumeSorted(a), b);
143     assert(a == [ 0, 1, 2 ]);
144     assert(b == [ 3, 4, 5, 6 ]);
145 }
146 
147 // isSorted
148 /**
149 Checks whether a $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives)
150 is sorted according to the comparison operation `less`. Performs $(BIGOH r.length)
151 evaluations of `less`.
152 
153 Unlike `isSorted`, `isStrictlyMonotonic` does not allow for equal values,
154 i.e. values for which both `less(a, b)` and `less(b, a)` are false.
155 
156 With either function, the predicate must be a strict ordering just like with
157 `isSorted`. For example, using `"a <= b"` instead of `"a < b"` is
158 incorrect and will cause failed assertions.
159 
160 Params:
161     less = Predicate the range should be sorted by.
162     r = Forward range to check for sortedness.
163 
164 Returns:
165     `true` if the range is sorted, false otherwise. `isSorted` allows
166     duplicates, `isStrictlyMonotonic` not.
167 */
168 bool isSorted(alias less = "a < b", Range)(Range r)
169 if (isForwardRange!(Range))
170 {
171     if (r.empty) return true;
172 
173     static if (isRandomAccessRange!Range && hasLength!Range)
174     {
175         immutable limit = r.length - 1;
176         foreach (i; 0 .. limit)
177         {
178             if (!binaryFun!less(r[i + 1], r[i])) continue;
179             assert(
180                 !binaryFun!less(r[i], r[i + 1]),
181                 "Predicate for isSorted is not antisymmetric. Both" ~
182                         " pred(a, b) and pred(b, a) are true for certain values.");
183             return false;
184         }
185     }
186     else
187     {
188         auto ahead = r.save;
189         ahead.popFront();
190         size_t i;
191 
192         for (; !ahead.empty; ahead.popFront(), r.popFront(), ++i)
193         {
194             if (!binaryFun!less(ahead.front, r.front)) continue;
195             // Check for antisymmetric predicate
196             assert(
197                 !binaryFun!less(r.front, ahead.front),
198                 "Predicate for isSorted is not antisymmetric. Both" ~
199                         " pred(a, b) and pred(b, a) are true for certain values.");
200             return false;
201         }
202     }
203     return true;
204 }
205 
206 ///
207 @safe unittest
208 {
209     assert([1, 1, 2].isSorted);
210     // strictly monotonic doesn't allow duplicates
211     assert(![1, 1, 2].isStrictlyMonotonic);
212 
213     int[] arr = [4, 3, 2, 1];
214     assert(!isSorted(arr));
215     assert(!isStrictlyMonotonic(arr));
216 
217     assert(isSorted!"a > b"(arr));
218     assert(isStrictlyMonotonic!"a > b"(arr));
219 
220     sort(arr);
221     assert(isSorted(arr));
222     assert(isStrictlyMonotonic(arr));
223 }
224 
225 @safe unittest
226 {
227     import std.conv : to;
228 
229     // https://issues.dlang.org/show_bug.cgi?id=9457
230     auto x = "abcd";
231     assert(isSorted(x));
232     auto y = "acbd";
233     assert(!isSorted(y));
234 
235     int[] a = [1, 2, 3];
236     assert(isSorted(a));
237     int[] b = [1, 3, 2];
238     assert(!isSorted(b));
239 
240     // ignores duplicates
241     int[] c = [1, 1, 2];
242     assert(isSorted(c));
243 
244     dchar[] ds = "コーヒーが好きです"d.dup;
245     sort(ds);
246     string s = to!string(ds);
247     assert(isSorted(ds));  // random-access
248     assert(isSorted(s));   // bidirectional
249 }
250 
251 @nogc @safe nothrow pure unittest
252 {
253     static immutable a = [1, 2, 3];
254     assert(a.isSorted);
255 }
256 
257 /// ditto
258 bool isStrictlyMonotonic(alias less = "a < b", Range)(Range r)
259 if (isForwardRange!Range)
260 {
261     import std.algorithm.searching : findAdjacent;
262     return findAdjacent!((a,b) => !binaryFun!less(a,b))(r).empty;
263 }
264 
265 @safe unittest
266 {
267     import std.conv : to;
268 
269     assert("abcd".isStrictlyMonotonic);
270     assert(!"aacd".isStrictlyMonotonic);
271     assert(!"acb".isStrictlyMonotonic);
272 
273     assert([1, 2, 3].isStrictlyMonotonic);
274     assert(![1, 3, 2].isStrictlyMonotonic);
275     assert(![1, 1, 2].isStrictlyMonotonic);
276 
277     // ー occurs twice -> can't be strict
278     dchar[] ds = "コーヒーが好きです"d.dup;
279     sort(ds);
280     string s = to!string(ds);
281     assert(!isStrictlyMonotonic(ds));  // random-access
282     assert(!isStrictlyMonotonic(s));   // bidirectional
283 
284     dchar[] ds2 = "コーヒが好きです"d.dup;
285     sort(ds2);
286     string s2 = to!string(ds2);
287     assert(isStrictlyMonotonic(ds2));  // random-access
288     assert(isStrictlyMonotonic(s2));   // bidirectional
289 }
290 
291 @nogc @safe nothrow pure unittest
292 {
293     static immutable a = [1, 2, 3];
294     assert(a.isStrictlyMonotonic);
295 }
296 
297 /**
298 Like `isSorted`, returns `true` if the given `values` are ordered
299 according to the comparison operation `less`. Unlike `isSorted`, takes values
300 directly instead of structured in a range.
301 
302 `ordered` allows repeated values, e.g. `ordered(1, 1, 2)` is `true`. To verify
303 that the values are ordered strictly monotonically, use `strictlyOrdered`;
304 `strictlyOrdered(1, 1, 2)` is `false`.
305 
306 With either function, the predicate must be a strict ordering. For example,
307 using `"a <= b"` instead of `"a < b"` is incorrect and will cause failed
308 assertions.
309 
310 Params:
311     values = The tested value
312     less = The comparison predicate
313 
314 Returns:
315     `true` if the values are ordered; `ordered` allows for duplicates,
316     `strictlyOrdered` does not.
317 */
318 
319 bool ordered(alias less = "a < b", T...)(T values)
320 if ((T.length == 2 && is(typeof(binaryFun!less(values[1], values[0])) : bool))
321     ||
322     (T.length > 2 && is(typeof(ordered!less(values[0 .. 1 + $ / 2])))
323         && is(typeof(ordered!less(values[$ / 2 .. $]))))
324     )
325 {
326     foreach (i, _; T[0 .. $ - 1])
327     {
328         if (binaryFun!less(values[i + 1], values[i]))
329         {
330             assert(!binaryFun!less(values[i], values[i + 1]),
331                 __FUNCTION__ ~ ": incorrect non-strict predicate.");
332             return false;
333         }
334     }
335     return true;
336 }
337 
338 /// ditto
339 bool strictlyOrdered(alias less = "a < b", T...)(T values)
340 if (is(typeof(ordered!less(values))))
341 {
342     foreach (i, _; T[0 .. $ - 1])
343     {
344         if (!binaryFun!less(values[i], values[i + 1]))
345         {
346             return false;
347         }
348         assert(!binaryFun!less(values[i + 1], values[i]),
349             __FUNCTION__ ~ ": incorrect non-strict predicate.");
350     }
351     return true;
352 }
353 
354 ///
355 @safe unittest
356 {
357     assert(ordered(42, 42, 43));
358     assert(!strictlyOrdered(43, 42, 45));
359     assert(ordered(42, 42, 43));
360     assert(!strictlyOrdered(42, 42, 43));
361     assert(!ordered(43, 42, 45));
362     // Ordered lexicographically
363     assert(ordered("Jane", "Jim", "Joe"));
364     assert(strictlyOrdered("Jane", "Jim", "Joe"));
365     // Incidentally also ordered by length decreasing
366     assert(ordered!((a, b) => a.length > b.length)("Jane", "Jim", "Joe"));
367     // ... but not strictly so: "Jim" and "Joe" have the same length
368     assert(!strictlyOrdered!((a, b) => a.length > b.length)("Jane", "Jim", "Joe"));
369 }
370 
371 // partition
372 /**
373 Partitions a range in two using the given `predicate`.
374 
375 Specifically, reorders the range `r = [left, right$(RPAREN)` using $(REF_ALTTEXT swap, swap, std,algorithm,mutation)
376 such that all elements `i` for which `predicate(i)` is `true` come
377 before all elements `j` for which `predicate(j)` returns `false`.
378 
379 Performs $(BIGOH r.length) (if unstable or semistable) or $(BIGOH
380 r.length * log(r.length)) (if stable) evaluations of `less` and $(REF_ALTTEXT swap, swap, std,algorithm,mutation).
381 The unstable version computes the minimum possible evaluations of `swap`
382 (roughly half of those performed by the semistable version).
383 
384 Params:
385     predicate = The predicate to partition by.
386     ss = The swapping strategy to employ.
387     r = The random-access range to partition.
388 
389 Returns:
390 
391 The right part of `r` after partitioning.
392 
393 If `ss == SwapStrategy.stable`, `partition` preserves the relative
394 ordering of all elements `a`, `b` in `r` for which
395 `predicate(a) == predicate(b)`.
396 If `ss == SwapStrategy.semistable`, `partition` preserves
397 the relative ordering of all elements `a`, `b` in the left part of `r`
398 for which `predicate(a) == predicate(b)`.
399 */
400 Range partition(alias predicate, SwapStrategy ss, Range)(Range r)
401 if (ss == SwapStrategy.stable && isRandomAccessRange!(Range) && hasLength!Range &&
402         hasSlicing!Range && hasSwappableElements!Range)
403 {
404     import std.algorithm.mutation : bringToFront;
405 
406     alias pred = unaryFun!(predicate);
407     if (r.empty) return r;
408 
409     if (r.length == 1)
410     {
411         if (pred(r.front)) r.popFront();
412         return r;
413     }
414     const middle = r.length / 2;
415     alias recurse = .partition!(pred, ss, Range);
416     auto lower = recurse(r[0 .. middle]);
417     auto upper = recurse(r[middle .. r.length]);
418     bringToFront(lower, r[middle .. r.length - upper.length]);
419     return r[r.length - lower.length - upper.length .. r.length];
420 }
421 
422 ///ditto
423 Range partition(alias predicate, SwapStrategy ss = SwapStrategy.unstable, Range)(Range r)
424 if (ss != SwapStrategy.stable && isInputRange!Range && hasSwappableElements!Range)
425 {
426     import std.algorithm.mutation : swap;
427     alias pred = unaryFun!(predicate);
428 
429     static if (ss == SwapStrategy.semistable)
430     {
431         if (r.empty) return r;
432 
433         for (; !r.empty; r.popFront())
434         {
435             // skip the initial portion of "correct" elements
436             if (pred(r.front)) continue;
437             // hit the first "bad" element
438             auto result = r;
439             for (r.popFront(); !r.empty; r.popFront())
440             {
441                 if (!pred(r.front)) continue;
442                 swap(result.front, r.front);
443                 result.popFront();
444             }
445             return result;
446         }
447 
448         return r;
449     }
450     else
451     {
452         // Inspired from www.stepanovpapers.com/PAM3-partition_notes.pdf,
453         // section "Bidirectional Partition Algorithm (Hoare)"
454         static if (isDynamicArray!Range)
455         {
456             import std.algorithm.mutation : swapAt;
457             // For dynamic arrays prefer index-based manipulation
458             if (!r.length) return r;
459             size_t lo = 0, hi = r.length - 1;
460             for (;;)
461             {
462                 for (;;)
463                 {
464                     if (lo > hi) return r[lo .. r.length];
465                     if (!pred(r[lo])) break;
466                     ++lo;
467                 }
468                 // found the left bound
469                 assert(lo <= hi, "lo must be <= hi");
470                 for (;;)
471                 {
472                     if (lo == hi) return r[lo .. r.length];
473                     if (pred(r[hi])) break;
474                     --hi;
475                 }
476                 // found the right bound, swap & make progress
477                 r.swapAt(lo++, hi--);
478             }
479         }
480         else
481         {
482             import std.algorithm.mutation : swap;
483             auto result = r;
484             for (;;)
485             {
486                 for (;;)
487                 {
488                     if (r.empty) return result;
489                     if (!pred(r.front)) break;
490                     r.popFront();
491                     result.popFront();
492                 }
493                 // found the left bound
494                 assert(!r.empty, "r must not be empty");
495                 for (;;)
496                 {
497                     if (pred(r.back)) break;
498                     r.popBack();
499                     if (r.empty) return result;
500                 }
501                 // found the right bound, swap & make progress
502                 static if (is(typeof(swap(r.front, r.back))))
503                 {
504                     swap(r.front, r.back);
505                 }
506                 else
507                 {
508                     auto t1 = r.moveFront(), t2 = r.moveBack();
509                     r.front = t2;
510                     r.back = t1;
511                 }
512                 r.popFront();
513                 result.popFront();
514                 r.popBack();
515             }
516         }
517     }
518 }
519 
520 ///
521 @safe unittest
522 {
523     import std.algorithm.mutation : SwapStrategy;
524     import std.algorithm.searching : count, find;
525     import std.conv : text;
526     import std.range.primitives : empty;
527 
528     auto Arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
529     auto arr = Arr.dup;
530     static bool even(int a) { return (a & 1) == 0; }
531     // Partition arr such that even numbers come first
532     auto r = partition!(even)(arr);
533     // Now arr is separated in evens and odds.
534     // Numbers may have become shuffled due to instability
535     assert(r == arr[5 .. $]);
536     assert(count!(even)(arr[0 .. 5]) == 5);
537     assert(find!(even)(r).empty);
538 
539     // Can also specify the predicate as a string.
540     // Use 'a' as the predicate argument name
541     arr[] = Arr[];
542     r = partition!(q{(a & 1) == 0})(arr);
543     assert(r == arr[5 .. $]);
544 
545     // Now for a stable partition:
546     arr[] = Arr[];
547     r = partition!(q{(a & 1) == 0}, SwapStrategy.stable)(arr);
548     // Now arr is [2 4 6 8 10 1 3 5 7 9], and r points to 1
549     assert(arr == [2, 4, 6, 8, 10, 1, 3, 5, 7, 9] && r == arr[5 .. $]);
550 
551     // In case the predicate needs to hold its own state, use a delegate:
552     arr[] = Arr[];
553     int x = 3;
554     // Put stuff greater than 3 on the left
555     bool fun(int a) { return a > x; }
556     r = partition!(fun, SwapStrategy.semistable)(arr);
557     // Now arr is [4 5 6 7 8 9 10 2 3 1] and r points to 2
558     assert(arr == [4, 5, 6, 7, 8, 9, 10, 2, 3, 1] && r == arr[7 .. $]);
559 }
560 
561 @safe unittest
562 {
563     import std.algorithm.internal : rndstuff;
564     static bool even(int a) { return (a & 1) == 0; }
565 
566     // test with random data
567     auto a = rndstuff!int();
568     partition!even(a);
569     assert(isPartitioned!even(a));
570     auto b = rndstuff!string();
571     partition!`a.length < 5`(b);
572     assert(isPartitioned!`a.length < 5`(b));
573 }
574 
575 // pivotPartition
576 /**
577 Partitions `r` around `pivot` using comparison function `less`, algorithm akin
578 to $(LINK2 https://en.wikipedia.org/wiki/Quicksort#Hoare_partition_scheme,
579 Hoare partition).
580 
581 Specifically, permutes elements of `r` and returns
582 an index `k < r.length` such that:
583 
584 $(UL
585 
586 $(LI `r[pivot]` is swapped to `r[k]`)
587 
588 $(LI All elements `e` in subrange `r[0 .. k]` satisfy `!less(r[k], e)`
589 (i.e. `r[k]` is greater than or equal to each element to its left according to
590 predicate `less`))
591 
592 $(LI All elements `e` in subrange `r[k .. $]` satisfy `!less(e, r[k])`
593 (i.e. `r[k]` is less than or equal to each element to its right
594 according to predicate `less`)))
595 
596 If `r` contains equivalent elements, multiple permutations of `r` satisfy these
597 constraints. In such cases, `pivotPartition` attempts to distribute equivalent
598 elements fairly to the left and right of `k` such that `k` stays close to  $(D
599 r.length / 2).
600 
601 Params:
602 less = The predicate used for comparison, modeled as a
603         $(LINK2 https://en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings,
604         strict weak ordering) (irreflexive, antisymmetric, transitive, and implying a transitive
605         equivalence)
606 r = The range being partitioned
607 pivot = The index of the pivot for partitioning, must be less than `r.length` or
608 `0` if `r.length` is `0`
609 
610 Returns:
611 The new position of the pivot
612 
613 See_Also:
614 $(HTTP jgrcs.info/index.php/jgrcs/article/view/142, Engineering of a Quicksort
615 Partitioning Algorithm), D. Abhyankar, Journal of Global Research in Computer
616 Science, February 2011. $(HTTPS youtube.com/watch?v=AxnotgLql0k, ACCU 2016
617 Keynote), Andrei Alexandrescu.
618 */
619 size_t pivotPartition(alias less = "a < b", Range)
620 (Range r, size_t pivot)
621 if (isRandomAccessRange!Range && hasLength!Range && hasSlicing!Range && hasAssignableElements!Range)
622 {
623     assert(pivot < r.length || r.length == 0 && pivot == 0, "pivot must be"
624         ~ " less than the length of r or r must be empty and pivot zero");
625     if (r.length <= 1) return 0;
626     import std.algorithm.mutation : swapAt, move;
627     alias lt = binaryFun!less;
628 
629     // Pivot at the front
630     r.swapAt(pivot, 0);
631 
632     // Fork implementation depending on nothrow copy, assignment, and
633     // comparison. If all of these are nothrow, use the specialized
634     // implementation discussed at https://youtube.com/watch?v=AxnotgLql0k.
635     static if (is(typeof(
636             () nothrow { auto x = r.front; x = r.front; return lt(x, x); }
637         )))
638     {
639         auto p = r[0];
640         // Plant the pivot in the end as well as a sentinel
641         size_t lo = 0, hi = r.length - 1;
642         auto save = r.moveAt(hi);
643         r[hi] = p; // Vacancy is in r[$ - 1] now
644         // Start process
645         for (;;)
646         {
647             // Loop invariant
648             version (StdUnittest)
649             {
650                 // this used to import std.algorithm.all, but we want to save
651                 // imports when unittests are enabled if possible.
652                 foreach (x; r[0 .. lo])
653                     assert(!lt(p, x), "p must not be less than x");
654                 foreach (x; r[hi+1 .. r.length])
655                     assert(!lt(x, p), "x must not be less than p");
656             }
657             do ++lo; while (lt(r[lo], p));
658             r[hi] = r[lo];
659             // Vacancy is now in r[lo]
660             do --hi; while (lt(p, r[hi]));
661             if (lo >= hi) break;
662             r[lo] = r[hi];
663             // Vacancy is not in r[hi]
664         }
665         // Fixup
666         assert(lo - hi <= 2, "Following compare not possible");
667         assert(!lt(p, r[hi]), "r[hi] must not be less than p");
668         if (lo == hi + 2)
669         {
670             assert(!lt(r[hi + 1], p), "r[hi + 1] must not be less than p");
671             r[lo] = r[hi + 1];
672             --lo;
673         }
674         r[lo] = save;
675         if (lt(p, save)) --lo;
676         assert(!lt(p, r[lo]), "r[lo] must not be less than p");
677     }
678     else
679     {
680         size_t lo = 1, hi = r.length - 1;
681         loop: for (;; lo++, hi--)
682         {
683             for (;; ++lo)
684             {
685                 if (lo > hi) break loop;
686                 if (!lt(r[lo], r[0])) break;
687             }
688             // found the left bound:  r[lo] >= r[0]
689             assert(lo <= hi, "lo must be less or equal than hi");
690             for (;; --hi)
691             {
692                 if (lo >= hi) break loop;
693                 if (!lt(r[0], r[hi])) break;
694             }
695             // found the right bound: r[hi] <= r[0], swap & make progress
696             assert(!lt(r[lo], r[hi]), "r[lo] must not be less than r[hi]");
697             r.swapAt(lo, hi);
698         }
699         --lo;
700     }
701     r.swapAt(lo, 0);
702     return lo;
703 }
704 
705 ///
706 @safe nothrow unittest
707 {
708     int[] a = [5, 3, 2, 6, 4, 1, 3, 7];
709     size_t pivot = pivotPartition(a, a.length / 2);
710     import std.algorithm.searching : all;
711     assert(a[0 .. pivot].all!(x => x <= a[pivot]));
712     assert(a[pivot .. $].all!(x => x >= a[pivot]));
713 }
714 
715 @safe unittest
716 {
717     void test(alias less)()
718     {
719         int[] a;
720         size_t pivot;
721 
722         a = [-9, -4, -2, -2, 9];
723         pivot = pivotPartition!less(a, a.length / 2);
724         import std.algorithm.searching : all;
725         assert(a[0 .. pivot].all!(x => x <= a[pivot]));
726         assert(a[pivot .. $].all!(x => x >= a[pivot]));
727 
728         a = [9, 2, 8, -5, 5, 4, -8, -4, 9];
729         pivot = pivotPartition!less(a, a.length / 2);
730         assert(a[0 .. pivot].all!(x => x <= a[pivot]));
731         assert(a[pivot .. $].all!(x => x >= a[pivot]));
732 
733         a = [ 42 ];
734         pivot = pivotPartition!less(a, a.length / 2);
735         assert(pivot == 0);
736         assert(a == [ 42 ]);
737 
738         a = [ 43, 42 ];
739         pivot = pivotPartition!less(a, 0);
740         assert(pivot == 1);
741         assert(a == [ 42, 43 ]);
742 
743         a = [ 43, 42 ];
744         pivot = pivotPartition!less(a, 1);
745         assert(pivot == 0);
746         assert(a == [ 42, 43 ]);
747 
748         a = [ 42, 42 ];
749         pivot = pivotPartition!less(a, 0);
750         assert(pivot == 0 || pivot == 1);
751         assert(a == [ 42, 42 ]);
752         pivot = pivotPartition!less(a, 1);
753         assert(pivot == 0 || pivot == 1);
754         assert(a == [ 42, 42 ]);
755 
756         import std.algorithm.iteration : map;
757         import std.array : array;
758         import std.format : format;
759         import std.random : Random, uniform, Xorshift;
760         import std.range : iota;
761         auto s = 123_456_789;
762         auto g = Xorshift(s);
763         a = iota(0, uniform(1, 1000, g))
764             .map!(_ => uniform(-1000, 1000, g))
765             .array;
766         pivot = pivotPartition!less(a, a.length / 2);
767         assert(a[0 .. pivot].all!(x => x <= a[pivot]), "RNG seed: %d".format(s));
768         assert(a[pivot .. $].all!(x => x >= a[pivot]), "RNG seed: %d".format(s));
769     }
770     test!"a < b";
771     static bool myLess(int a, int b)
772     {
773         static bool bogus;
774         if (bogus) throw new Exception(""); // just to make it no-nothrow
775         return a < b;
776     }
777     test!myLess;
778 }
779 
780 /**
781 Params:
782     pred = The predicate that the range should be partitioned by.
783     r = The range to check.
784 Returns: `true` if `r` is partitioned according to predicate `pred`.
785  */
786 bool isPartitioned(alias pred, Range)(Range r)
787 if (isForwardRange!(Range))
788 {
789     for (; !r.empty; r.popFront())
790     {
791         if (unaryFun!(pred)(r.front)) continue;
792         for (r.popFront(); !r.empty; r.popFront())
793         {
794             if (unaryFun!(pred)(r.front)) return false;
795         }
796         break;
797     }
798     return true;
799 }
800 
801 ///
802 @safe unittest
803 {
804     int[] r = [ 1, 3, 5, 7, 8, 2, 4, ];
805     assert(isPartitioned!"a & 1"(r));
806 }
807 
808 // partition3
809 /**
810 Rearranges elements in `r` in three adjacent ranges and returns
811 them.
812 
813 The first and leftmost range only contains elements in `r`
814 less than `pivot`. The second and middle range only contains
815 elements in `r` that are equal to `pivot`. Finally, the third
816 and rightmost range only contains elements in `r` that are greater
817 than `pivot`. The less-than test is defined by the binary function
818 `less`.
819 
820 Params:
821     less = The predicate to use for the rearrangement.
822     ss = The swapping strategy to use.
823     r = The random-access range to rearrange.
824     pivot = The pivot element.
825 
826 Returns:
827     A $(REF Tuple, std,typecons) of the three resulting ranges. These ranges are
828     slices of the original range.
829 
830 BUGS: stable `partition3` has not been implemented yet.
831  */
832 auto partition3(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range, E)
833 (Range r, E pivot)
834 if (ss == SwapStrategy.unstable && isRandomAccessRange!Range
835         && hasSwappableElements!Range && hasLength!Range && hasSlicing!Range
836         && is(typeof(binaryFun!less(r.front, pivot)) == bool)
837         && is(typeof(binaryFun!less(pivot, r.front)) == bool)
838         && is(typeof(binaryFun!less(r.front, r.front)) == bool))
839 {
840     // The algorithm is described in "Engineering a sort function" by
841     // Jon Bentley et al, pp 1257.
842 
843     import std.algorithm.comparison : min;
844     import std.algorithm.mutation : swap, swapAt, swapRanges;
845     import std.typecons : tuple;
846 
847     alias lessFun = binaryFun!less;
848     size_t i, j, k = r.length, l = k;
849 
850  bigloop:
851     for (;;)
852     {
853         for (;; ++j)
854         {
855             if (j == k) break bigloop;
856             assert(j < r.length, "j must be less than r.length");
857             if (lessFun(r[j], pivot)) continue;
858             if (lessFun(pivot, r[j])) break;
859             r.swapAt(i++, j);
860         }
861         assert(j < k, "j must be less than k");
862         for (;;)
863         {
864             assert(k > 0, "k must be positive");
865             if (!lessFun(pivot, r[--k]))
866             {
867                 if (lessFun(r[k], pivot)) break;
868                 r.swapAt(k, --l);
869             }
870             if (j == k) break bigloop;
871         }
872         // Here we know r[j] > pivot && r[k] < pivot
873         r.swapAt(j++, k);
874     }
875 
876     // Swap the equal ranges from the extremes into the middle
877     auto strictlyLess = j - i, strictlyGreater = l - k;
878     auto swapLen = min(i, strictlyLess);
879     swapRanges(r[0 .. swapLen], r[j - swapLen .. j]);
880     swapLen = min(r.length - l, strictlyGreater);
881     swapRanges(r[k .. k + swapLen], r[r.length - swapLen .. r.length]);
882     return tuple(r[0 .. strictlyLess],
883             r[strictlyLess .. r.length - strictlyGreater],
884             r[r.length - strictlyGreater .. r.length]);
885 }
886 
887 ///
888 @safe unittest
889 {
890     auto a = [ 8, 3, 4, 1, 4, 7, 4 ];
891     auto pieces = partition3(a, 4);
892     assert(pieces[0] == [ 1, 3 ]);
893     assert(pieces[1] == [ 4, 4, 4 ]);
894     assert(pieces[2] == [ 8, 7 ]);
895 }
896 
897 @safe unittest
898 {
899     import std.random : Random = Xorshift, uniform;
900 
901     immutable uint[] seeds = [3923355730, 1927035882];
902     foreach (s; seeds)
903     {
904         auto r = Random(s);
905         auto a = new int[](uniform(0, 100, r));
906         foreach (ref e; a)
907         {
908             e = uniform(0, 50, r);
909         }
910         auto pieces = partition3(a, 25);
911         assert(pieces[0].length + pieces[1].length + pieces[2].length == a.length);
912         foreach (e; pieces[0])
913         {
914             assert(e < 25);
915         }
916         foreach (e; pieces[1])
917         {
918             assert(e == 25);
919         }
920         foreach (e; pieces[2])
921         {
922             assert(e > 25);
923         }
924     }
925 }
926 
927 // makeIndex
928 /**
929 Computes an index for `r` based on the comparison `less`.
930 
931 The index is a sorted array of pointers or indices into the original
932 range. This technique is similar to sorting, but it is more flexible
933 because (1) it allows "sorting" of immutable collections, (2) allows
934 binary search even if the original collection does not offer random
935 access, (3) allows multiple indexes, each on a different predicate,
936 and (4) may be faster when dealing with large objects. However, using
937 an index may also be slower under certain circumstances due to the
938 extra indirection, and is always larger than a sorting-based solution
939 because it needs space for the index in addition to the original
940 collection. The complexity is the same as `sort`'s.
941 
942 The first overload of `makeIndex` writes to a range containing
943 pointers, and the second writes to a range containing offsets. The
944 first overload requires `Range` to be a
945 $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives), and the
946 latter requires it to be a random-access range.
947 
948 `makeIndex` overwrites its second argument with the result, but
949 never reallocates it.
950 
951 Params:
952     less = The comparison to use.
953     ss = The swapping strategy.
954     r = The range to index.
955     index = The resulting index.
956 
957 Returns: The pointer-based version returns a `SortedRange` wrapper
958 over index, of type
959 `SortedRange!(RangeIndex, (a, b) => binaryFun!less(*a, *b))`
960 thus reflecting the ordering of the
961 index. The index-based version returns `void` because the ordering
962 relation involves not only `index` but also `r`.
963 
964 Throws: If the second argument's length is less than that of the range
965 indexed, an exception is thrown.
966 */
967 SortedRange!(RangeIndex, (a, b) => binaryFun!less(*a, *b))
968 makeIndex(
969     alias less = "a < b",
970     SwapStrategy ss = SwapStrategy.unstable,
971     Range,
972     RangeIndex)
973 (Range r, RangeIndex index)
974 if (isForwardRange!(Range) && isRandomAccessRange!(RangeIndex)
975     && is(ElementType!(RangeIndex) : ElementType!(Range)*) && hasAssignableElements!RangeIndex)
976 {
977     import std.algorithm.internal : addressOf;
978     import std.exception : enforce;
979 
980     // assume collection already ordered
981     size_t i;
982     for (; !r.empty; r.popFront(), ++i)
983         index[i] = addressOf(r.front);
984     enforce(index.length == i);
985     // sort the index
986     sort!((a, b) => binaryFun!less(*a, *b), ss)(index);
987     return typeof(return)(index);
988 }
989 
990 /// Ditto
991 void makeIndex(
992     alias less = "a < b",
993     SwapStrategy ss = SwapStrategy.unstable,
994     Range,
995     RangeIndex)
996 (Range r, RangeIndex index)
997 if (isRandomAccessRange!Range && !isInfinite!Range &&
998     isRandomAccessRange!RangeIndex && !isInfinite!RangeIndex &&
999     isIntegral!(ElementType!RangeIndex) && hasAssignableElements!RangeIndex)
1000 {
1001     import std.conv : to;
1002     import std.exception : enforce;
1003 
1004     alias IndexType = Unqual!(ElementType!RangeIndex);
1005     enforce(r.length == index.length,
1006         "r and index must be same length for makeIndex.");
1007     static if (IndexType.sizeof < size_t.sizeof)
1008     {
1009         enforce(r.length <= size_t(1) + IndexType.max, "Cannot create an index with " ~
1010             "element type " ~ IndexType.stringof ~ " with length " ~
1011             to!string(r.length) ~ ".");
1012     }
1013 
1014     // Use size_t as loop index to avoid overflow on ++i,
1015     // e.g. when squeezing 256 elements into a ubyte index.
1016     foreach (size_t i; 0 .. r.length)
1017         index[i] = cast(IndexType) i;
1018 
1019     // sort the index
1020     sort!((a, b) => binaryFun!less(r[cast(size_t) a], r[cast(size_t) b]), ss)
1021       (index);
1022 }
1023 
1024 ///
1025 @system unittest
1026 {
1027     immutable(int[]) arr = [ 2, 3, 1, 5, 0 ];
1028     // index using pointers
1029     auto index1 = new immutable(int)*[arr.length];
1030     makeIndex!("a < b")(arr, index1);
1031     assert(isSorted!("*a < *b")(index1));
1032     // index using offsets
1033     auto index2 = new size_t[arr.length];
1034     makeIndex!("a < b")(arr, index2);
1035     assert(isSorted!
1036         ((size_t a, size_t b){ return arr[a] < arr[b];})
1037         (index2));
1038 }
1039 
1040 @system unittest
1041 {
1042     immutable(int)[] arr = [ 2, 3, 1, 5, 0 ];
1043     // index using pointers
1044     auto index1 = new immutable(int)*[arr.length];
1045     alias ImmRange = typeof(arr);
1046     alias ImmIndex = typeof(index1);
1047     static assert(isForwardRange!(ImmRange));
1048     static assert(isRandomAccessRange!(ImmIndex));
1049     static assert(!isIntegral!(ElementType!(ImmIndex)));
1050     static assert(is(ElementType!(ImmIndex) : ElementType!(ImmRange)*));
1051     makeIndex!("a < b")(arr, index1);
1052     assert(isSorted!("*a < *b")(index1));
1053 
1054     // index using offsets
1055     auto index2 = new long[arr.length];
1056     makeIndex(arr, index2);
1057     assert(isSorted!
1058             ((long a, long b){
1059                 return arr[cast(size_t) a] < arr[cast(size_t) b];
1060             })(index2));
1061 
1062     // index strings using offsets
1063     string[] arr1 = ["I", "have", "no", "chocolate"];
1064     auto index3 = new byte[arr1.length];
1065     makeIndex(arr1, index3);
1066     assert(isSorted!
1067             ((byte a, byte b){ return arr1[a] < arr1[b];})
1068             (index3));
1069 }
1070 
1071 @safe unittest
1072 {
1073     import std.algorithm.comparison : equal;
1074     import std.range : iota;
1075 
1076     ubyte[256] index = void;
1077     iota(256).makeIndex(index[]);
1078     assert(index[].equal(iota(256)));
1079     byte[128] sindex = void;
1080     iota(128).makeIndex(sindex[]);
1081     assert(sindex[].equal(iota(128)));
1082 
1083     auto index2 = new uint[10];
1084     10.iota.makeIndex(index2);
1085     assert(index2.equal(10.iota));
1086 }
1087 
1088 struct Merge(alias less = "a < b", Rs...)
1089 if (Rs.length >= 2 &&
1090     allSatisfy!(isInputRange, Rs) &&
1091     !is(CommonType!(staticMap!(ElementType, Rs)) == void))
1092 {
1093     public Rs source;
1094     private size_t _lastFrontIndex = size_t.max;
1095     static if (isBidirectional)
1096     {
1097         private size_t _lastBackIndex = size_t.max; // `size_t.max` means uninitialized,
1098     }
1099 
1100     import std.functional : binaryFun;
1101     import std.meta : anySatisfy;
1102     import std.traits : isCopyable;
1103 
1104     private alias comp = binaryFun!less;
1105     private alias ElementType = CommonType!(staticMap!(.ElementType, Rs));
1106     private enum isBidirectional = allSatisfy!(isBidirectionalRange, staticMap!(Unqual, Rs));
1107 
1108     debug private enum canCheckSortedness = isCopyable!ElementType && !hasAliasing!ElementType;
1109 
1110     this(Rs source)
1111     {
1112         this.source = source;
1113         this._lastFrontIndex = frontIndex;
1114     }
1115 
1116     static if (anySatisfy!(isInfinite, Rs))
1117     {
1118         enum bool empty = false; // propagate infiniteness
1119     }
1120     else
1121     {
1122         @property bool empty()
1123         {
1124             return _lastFrontIndex == size_t.max;
1125         }
1126     }
1127 
1128     @property auto ref front()
1129     {
1130         final switch (_lastFrontIndex)
1131         {
1132             foreach (i, _; Rs)
1133             {
1134             case i:
1135                 assert(!source[i].empty, "Can not get front of empty Merge");
1136                 return source[i].front;
1137             }
1138         }
1139     }
1140 
1141     private size_t frontIndex()
1142     {
1143         size_t bestIndex = size_t.max; // indicate undefined
1144         Unqual!ElementType bestElement;
1145         foreach (i, _; Rs)
1146         {
1147             if (source[i].empty) continue;
1148             if (bestIndex == size_t.max || // either this is the first or
1149                 comp(source[i].front, bestElement))
1150             {
1151                 bestIndex = i;
1152                 bestElement = source[i].front;
1153             }
1154         }
1155         return bestIndex;
1156     }
1157 
1158     void popFront()
1159     {
1160         sw: final switch (_lastFrontIndex)
1161         {
1162             foreach (i, R; Rs)
1163             {
1164             case i:
1165                 debug static if (canCheckSortedness)
1166                 {
1167                     ElementType previousFront = source[i].front();
1168                 }
1169                 source[i].popFront();
1170                 debug static if (canCheckSortedness)
1171                 {
1172                     if (!source[i].empty)
1173                     {
1174                         assert(!comp(source[i].front, previousFront),
1175                                "Input " ~ i.stringof ~ " is unsorted"); // @nogc
1176                     }
1177                 }
1178                 break sw;
1179             }
1180         }
1181         _lastFrontIndex = frontIndex;
1182     }
1183 
1184     static if (isBidirectional)
1185     {
1186         @property auto ref back()
1187         {
1188             if (_lastBackIndex == size_t.max)
1189             {
1190                 this._lastBackIndex = backIndex; // lazy initialization
1191             }
1192             final switch (_lastBackIndex)
1193             {
1194                 foreach (i, _; Rs)
1195                 {
1196                 case i:
1197                     assert(!source[i].empty, "Can not get back of empty Merge");
1198                     return source[i].back;
1199                 }
1200             }
1201         }
1202 
1203         private size_t backIndex()
1204         {
1205             size_t bestIndex = size_t.max; // indicate undefined
1206             Unqual!ElementType bestElement;
1207             foreach (i, _; Rs)
1208             {
1209                 if (source[i].empty) continue;
1210                 if (bestIndex == size_t.max || // either this is the first or
1211                     comp(bestElement, source[i].back))
1212                 {
1213                     bestIndex = i;
1214                     bestElement = source[i].back;
1215                 }
1216             }
1217             return bestIndex;
1218         }
1219 
1220         void popBack()
1221         {
1222             if (_lastBackIndex == size_t.max)
1223             {
1224                 this._lastBackIndex = backIndex; // lazy initialization
1225             }
1226             sw: final switch (_lastBackIndex)
1227             {
1228                 foreach (i, R; Rs)
1229                 {
1230                 case i:
1231                     debug static if (canCheckSortedness)
1232                     {
1233                         ElementType previousBack = source[i].back();
1234                     }
1235                     source[i].popBack();
1236                     debug static if (canCheckSortedness)
1237                     {
1238                         if (!source[i].empty)
1239                         {
1240                             assert(!comp(previousBack, source[i].back),
1241                                    "Input " ~ i.stringof ~ " is unsorted"); // @nogc
1242                         }
1243                     }
1244                     break sw;
1245                 }
1246             }
1247             _lastBackIndex = backIndex;
1248             if (_lastBackIndex == size_t.max) // if emptied
1249             {
1250                 _lastFrontIndex = size_t.max;
1251             }
1252         }
1253     }
1254 
1255     static if (allSatisfy!(isForwardRange, staticMap!(Unqual, Rs)))
1256     {
1257         @property auto save()
1258         {
1259             auto result = this;
1260             foreach (i, _; Rs)
1261             {
1262                 result.source[i] = result.source[i].save;
1263             }
1264             return result;
1265         }
1266     }
1267 
1268     static if (allSatisfy!(hasLength, Rs))
1269     {
1270         @property size_t length()
1271         {
1272             size_t result;
1273             foreach (i, _; Rs)
1274             {
1275                 result += source[i].length;
1276             }
1277             return result;
1278         }
1279 
1280         alias opDollar = length;
1281     }
1282 }
1283 
1284 /**
1285    Merge multiple sorted ranges `rs` with less-than predicate function `pred`
1286    into one single sorted output range containing the sorted union of the
1287    elements of inputs.
1288 
1289    Duplicates are not eliminated, meaning that the total
1290    number of elements in the output is the sum of all elements in the ranges
1291    passed to it; the `length` member is offered if all inputs also have
1292    `length`. The element types of all the inputs must have a common type
1293    `CommonType`.
1294 
1295 Params:
1296     less = Predicate the given ranges are sorted by.
1297     rs = The ranges to compute the union for.
1298 
1299 Returns:
1300     A range containing the union of the given ranges.
1301 
1302 Details:
1303 
1304 All of its inputs are assumed to be sorted. This can mean that inputs are
1305    instances of $(REF SortedRange, std,range). Use the result of $(REF sort,
1306    std,algorithm,sorting), or $(REF assumeSorted, std,range) to merge ranges
1307    known to be sorted (show in the example below). Note that there is currently
1308    no way of ensuring that two or more instances of $(REF SortedRange,
1309    std,range) are sorted using a specific comparison function `pred`. Therefore
1310    no checking is done here to assure that all inputs `rs` are instances of
1311    $(REF SortedRange, std,range).
1312 
1313    This algorithm is lazy, doing work progressively as elements are pulled off
1314    the result.
1315 
1316    Time complexity is proportional to the sum of element counts over all inputs.
1317 
1318    If all inputs have the same element type and offer it by `ref`, output
1319    becomes a range with mutable `front` (and `back` where appropriate) that
1320    reflects in the original inputs.
1321 
1322    If any of the inputs `rs` is infinite so is the result (`empty` being always
1323    `false`).
1324 
1325 See_Also: $(REF multiwayMerge, std,algorithm,setops) for an analogous function
1326    that merges a dynamic number of ranges.
1327 */
1328 Merge!(less, Rs) merge(alias less = "a < b", Rs...)(Rs rs)
1329 if (Rs.length >= 2 &&
1330     allSatisfy!(isInputRange, Rs) &&
1331     !is(CommonType!(staticMap!(ElementType, Rs)) == void))
1332 {
1333     return typeof(return)(rs);
1334 }
1335 
1336 ///
1337 @safe pure nothrow unittest
1338 {
1339     import std.algorithm.comparison : equal;
1340     import std.range : retro;
1341 
1342     int[] a = [1, 3, 5];
1343     int[] b = [2, 3, 4];
1344 
1345     assert(a.merge(b).equal([1, 2, 3, 3, 4, 5]));
1346     assert(a.merge(b).retro.equal([5, 4, 3, 3, 2, 1]));
1347 }
1348 
1349 @safe pure nothrow unittest
1350 {
1351     import std.algorithm.comparison : equal;
1352 
1353     int[] a = [ 1, 2, 4, 5, 7, 9 ];
1354     int[] b = [ 0, 1, 2, 4, 7, 8 ];
1355     double[] c = [ 10.5 ];
1356 
1357     assert(merge(a, b).length == a.length + b.length);
1358     assert(equal(merge(a, b), [0, 1, 1, 2, 2, 4, 4, 5, 7, 7, 8, 9][]));
1359     assert(equal(merge(a, c, b),
1360                     [0, 1, 1, 2, 2, 4, 4, 5, 7, 7, 8, 9, 10.5][]));
1361     auto u = merge(a, b);
1362     u.front--;
1363     assert(equal(u, [-1, 1, 1, 2, 2, 4, 4, 5, 7, 7, 8, 9][]));
1364 }
1365 
1366 @safe pure nothrow unittest
1367 {
1368     // save
1369     import std.range : dropOne;
1370     int[] a = [1, 2];
1371     int[] b = [0, 3];
1372     auto arr = a.merge(b);
1373     assert(arr.front == 0);
1374     assert(arr.save.dropOne.front == 1);
1375     assert(arr.front == 0);
1376 }
1377 
1378 @safe pure nothrow unittest
1379 {
1380     import std.algorithm.comparison : equal;
1381     import std.internal.test.dummyrange;
1382 
1383     auto dummyResult1 = [1, 1, 1.5, 2, 3, 4, 5, 5.5, 6, 7, 8, 9, 10];
1384     auto dummyResult2 = [1, 1, 2, 2, 3, 3, 4, 4, 5, 5,
1385                          6, 6, 7, 7, 8, 8, 9, 9, 10, 10];
1386     foreach (DummyType; AllDummyRanges)
1387     {
1388         DummyType d;
1389         assert(d.merge([1, 1.5, 5.5]).equal(dummyResult1));
1390         assert(d.merge(d).equal(dummyResult2));
1391     }
1392 }
1393 
1394 @nogc @safe pure nothrow unittest
1395 {
1396     import std.algorithm.comparison : equal;
1397 
1398     static immutable a = [1, 3, 5];
1399     static immutable b = [2, 3, 4];
1400     static immutable r = [1, 2, 3, 3, 4, 5];
1401     assert(a.merge(b).equal(r));
1402 }
1403 
1404 /// test bi-directional access and common type
1405 @safe pure nothrow unittest
1406 {
1407     import std.algorithm.comparison : equal;
1408     import std.range : retro;
1409     import std.traits : CommonType;
1410 
1411     alias S = short;
1412     alias I = int;
1413     alias D = double;
1414 
1415     S[] a = [1, 2, 3];
1416     I[] b = [50, 60];
1417     D[] c = [10, 20, 30, 40];
1418 
1419     auto m = merge(a, b, c);
1420 
1421     static assert(is(typeof(m.front) == CommonType!(S, I, D)));
1422 
1423     assert(equal(m, [1, 2, 3, 10, 20, 30, 40, 50, 60]));
1424     assert(equal(m.retro, [60, 50, 40, 30, 20, 10, 3, 2, 1]));
1425 
1426     m.popFront();
1427     assert(equal(m, [2, 3, 10, 20, 30, 40, 50, 60]));
1428     m.popBack();
1429     assert(equal(m, [2, 3, 10, 20, 30, 40, 50]));
1430     m.popFront();
1431     assert(equal(m, [3, 10, 20, 30, 40, 50]));
1432     m.popBack();
1433     assert(equal(m, [3, 10, 20, 30, 40]));
1434     m.popFront();
1435     assert(equal(m, [10, 20, 30, 40]));
1436     m.popBack();
1437     assert(equal(m, [10, 20, 30]));
1438     m.popFront();
1439     assert(equal(m, [20, 30]));
1440     m.popBack();
1441     assert(equal(m, [20]));
1442     m.popFront();
1443     assert(m.empty);
1444 }
1445 
1446 // Issue 21810: Check for sortedness must not use `==`
1447 @nogc @safe pure nothrow unittest
1448 {
1449     import std.algorithm.comparison : equal;
1450     import std.typecons : tuple;
1451 
1452     static immutable a = [
1453         tuple(1, 1),
1454         tuple(3, 1),
1455         tuple(3, 2),
1456         tuple(5, 1),
1457     ];
1458     static immutable b = [
1459         tuple(2, 1),
1460         tuple(3, 1),
1461         tuple(4, 1),
1462         tuple(4, 2),
1463     ];
1464     static immutable r = [
1465         tuple(1, 1),
1466         tuple(2, 1),
1467         tuple(3, 1),
1468         tuple(3, 2),
1469         tuple(3, 1),
1470         tuple(4, 1),
1471         tuple(4, 2),
1472         tuple(5, 1),
1473     ];
1474     assert(merge!"a[0] < b[0]"(a, b).equal(r));
1475 }
1476 
1477 private template validPredicates(E, less...)
1478 {
1479     static if (less.length == 0)
1480         enum validPredicates = true;
1481     else static if (less.length == 1 && is(typeof(less[0]) == SwapStrategy))
1482         enum validPredicates = true;
1483     else
1484         enum validPredicates =
1485             is(typeof((E a, E b){ bool r = binaryFun!(less[0])(a, b); }))
1486             && validPredicates!(E, less[1 .. $]);
1487 }
1488 
1489 /**
1490 Sorts a range by multiple keys.
1491 
1492 The call $(D multiSort!("a.id < b.id",
1493 "a.date > b.date")(r)) sorts the range `r` by `id` ascending,
1494 and sorts elements that have the same `id` by `date`
1495 descending. Such a call is equivalent to $(D sort!"a.id != b.id ? a.id
1496 < b.id : a.date > b.date"(r)), but `multiSort` is faster because it
1497 does fewer comparisons (in addition to being more convenient).
1498 
1499 Returns:
1500     The initial range wrapped as a `SortedRange` with its predicates
1501     converted to an equivalent single predicate.
1502  */
1503 template multiSort(less...) //if (less.length > 1)
1504 {
1505     auto multiSort(Range)(Range r)
1506     if (validPredicates!(ElementType!Range, less) && hasSwappableElements!Range)
1507     {
1508         import std.meta : AliasSeq;
1509         import std.range : assumeSorted;
1510         static if (is(typeof(less[$ - 1]) == SwapStrategy))
1511         {
1512             enum ss = less[$ - 1];
1513             alias funs = less[0 .. $ - 1];
1514         }
1515         else
1516         {
1517             enum ss = SwapStrategy.unstable;
1518             alias funs = less;
1519         }
1520 
1521         static if (funs.length == 0)
1522             static assert(false, "No sorting predicate provided for multiSort");
1523         else
1524         static if (funs.length == 1)
1525             return sort!(funs[0], ss, Range)(r);
1526         else
1527         {
1528             multiSortImpl!(Range, ss, funs)(r);
1529             return assumeSorted!(multiSortPredFun!(Range, funs))(r);
1530         }
1531     }
1532 }
1533 
1534 ///
1535 @safe unittest
1536 {
1537     import std.algorithm.mutation : SwapStrategy;
1538     static struct Point { int x, y; }
1539     auto pts1 = [ Point(0, 0), Point(5, 5), Point(0, 1), Point(0, 2) ];
1540     auto pts2 = [ Point(0, 0), Point(0, 1), Point(0, 2), Point(5, 5) ];
1541     multiSort!("a.x < b.x", "a.y < b.y", SwapStrategy.unstable)(pts1);
1542     assert(pts1 == pts2);
1543 }
1544 
1545 private bool multiSortPredFun(Range, funs...)(ElementType!Range a, ElementType!Range b)
1546 {
1547     foreach (f; funs)
1548     {
1549         alias lessFun = binaryFun!(f);
1550         if (lessFun(a, b)) return true;
1551         if (lessFun(b, a)) return false;
1552     }
1553     return false;
1554 }
1555 
1556 private void multiSortImpl(Range, SwapStrategy ss, funs...)(Range r)
1557 {
1558     alias lessFun = binaryFun!(funs[0]);
1559 
1560     static if (funs.length > 1)
1561     {
1562         while (r.length > 1)
1563         {
1564             auto p = getPivot!lessFun(r);
1565             auto t = partition3!(funs[0], ss)(r, r[p]);
1566             if (t[0].length <= t[2].length)
1567             {
1568                 multiSortImpl!(Range, ss, funs)(t[0]);
1569                 multiSortImpl!(Range, ss, funs[1 .. $])(t[1]);
1570                 r = t[2];
1571             }
1572             else
1573             {
1574                 multiSortImpl!(Range, ss, funs[1 .. $])(t[1]);
1575                 multiSortImpl!(Range, ss, funs)(t[2]);
1576                 r = t[0];
1577             }
1578         }
1579     }
1580     else
1581     {
1582         sort!(lessFun, ss)(r);
1583     }
1584 }
1585 
1586 @safe unittest
1587 {
1588     import std.algorithm.comparison : equal;
1589     import std.range;
1590 
1591     static struct Point { int x, y; }
1592     auto pts1 = [ Point(5, 6), Point(1, 0), Point(5, 7), Point(1, 1), Point(1, 2), Point(0, 1) ];
1593     auto pts2 = [ Point(0, 1), Point(1, 0), Point(1, 1), Point(1, 2), Point(5, 6), Point(5, 7) ];
1594     static assert(validPredicates!(Point, "a.x < b.x", "a.y < b.y"));
1595     multiSort!("a.x < b.x", "a.y < b.y", SwapStrategy.unstable)(pts1);
1596     assert(pts1 == pts2);
1597 
1598     auto pts3 = indexed(pts1, iota(pts1.length));
1599     assert(pts3.multiSort!("a.x < b.x", "a.y < b.y", SwapStrategy.unstable).release.equal(pts2));
1600 
1601     auto pts4 = iota(10).array;
1602     assert(pts4.multiSort!("a > b").release.equal(iota(10).retro));
1603 }
1604 
1605 //https://issues.dlang.org/show_bug.cgi?id=9160 (L-value only comparators)
1606 @safe unittest
1607 {
1608     static struct A
1609     {
1610         int x;
1611         int y;
1612     }
1613 
1614     static bool byX(const ref A lhs, const ref A rhs)
1615     {
1616         return lhs.x < rhs.x;
1617     }
1618 
1619     static bool byY(const ref A lhs, const ref A rhs)
1620     {
1621         return lhs.y < rhs.y;
1622     }
1623 
1624     auto points = [ A(4, 1), A(2, 4)];
1625     multiSort!(byX, byY)(points);
1626     assert(points[0] == A(2, 4));
1627     assert(points[1] == A(4, 1));
1628 }
1629 
1630 // cannot access frame of function
1631 // https://issues.dlang.org/show_bug.cgi?id=16179
1632 @safe unittest
1633 {
1634     auto arr = [[1, 2], [2, 0], [1, 0], [1, 1]];
1635     int c = 3;
1636 
1637     arr.multiSort!(
1638         (a, b) => a[0] < b[0],
1639         (a, b) => c*a[1] < c*b[1]
1640     );
1641     assert(arr == [[1, 0], [1, 1], [1, 2], [2, 0]]);
1642 }
1643 
1644 // https://issues.dlang.org/show_bug.cgi?id=16413 - @system comparison function
1645 @system unittest
1646 {
1647     static @system bool lt(int a, int b) { return a < b; }
1648     auto a = [2, 1];
1649     a.multiSort!(lt, lt);
1650     assert(a == [1, 2]);
1651 }
1652 
1653 private size_t getPivot(alias less, Range)(Range r)
1654 {
1655     auto mid = r.length / 2;
1656     if (r.length < 512)
1657     {
1658         if (r.length >= 32)
1659             medianOf!less(r, size_t(0), mid, r.length - 1);
1660         return mid;
1661     }
1662 
1663     // The plan here is to take the median of five by taking five elements in
1664     // the array, segregate around their median, and return the position of the
1665     // third. We choose first, mid, last, and two more in between those.
1666 
1667     auto quarter = r.length / 4;
1668     medianOf!less(r,
1669         size_t(0), mid - quarter, mid, mid + quarter, r.length - 1);
1670     return mid;
1671 }
1672 
1673 /*
1674 Sorting routine that is optimized for short ranges. Note: uses insertion sort
1675 going downward. Benchmarked a similar routine that goes upward, for some reason
1676 it's slower.
1677 */
1678 private void shortSort(alias less, Range)(Range r)
1679 {
1680     import std.algorithm.mutation : swapAt;
1681     alias pred = binaryFun!(less);
1682 
1683     switch (r.length)
1684     {
1685         case 0: case 1:
1686             return;
1687         case 2:
1688             if (pred(r[1], r[0])) r.swapAt(0, 1);
1689             return;
1690         case 3:
1691             if (pred(r[2], r[0]))
1692             {
1693                 if (pred(r[0], r[1]))
1694                 {
1695                     r.swapAt(0, 1);
1696                     r.swapAt(0, 2);
1697                 }
1698                 else
1699                 {
1700                     r.swapAt(0, 2);
1701                     if (pred(r[1], r[0])) r.swapAt(0, 1);
1702                 }
1703             }
1704             else
1705             {
1706                 if (pred(r[1], r[0]))
1707                 {
1708                     r.swapAt(0, 1);
1709                 }
1710                 else
1711                 {
1712                     if (pred(r[2], r[1])) r.swapAt(1, 2);
1713                 }
1714             }
1715             return;
1716         case 4:
1717             if (pred(r[1], r[0])) r.swapAt(0, 1);
1718             if (pred(r[3], r[2])) r.swapAt(2, 3);
1719             if (pred(r[2], r[0])) r.swapAt(0, 2);
1720             if (pred(r[3], r[1])) r.swapAt(1, 3);
1721             if (pred(r[2], r[1])) r.swapAt(1, 2);
1722             return;
1723         default:
1724             sort5!pred(r[r.length - 5 .. r.length]);
1725             if (r.length == 5) return;
1726             break;
1727     }
1728 
1729     assert(r.length >= 6, "r must have more than 5 elements");
1730     /* The last 5 elements of the range are sorted. Proceed with expanding the
1731     sorted portion downward. */
1732     immutable maxJ = r.length - 2;
1733     for (size_t i = r.length - 6; ; --i)
1734     {
1735         static if (is(typeof(() nothrow
1736             {
1737                 auto t = r[0]; if (pred(t, r[0])) r[0] = r[0];
1738             }))) // Can we afford to temporarily invalidate the array?
1739         {
1740             import core.lifetime : move;
1741 
1742             size_t j = i + 1;
1743             static if (hasLvalueElements!Range)
1744                 auto temp = move(r[i]);
1745             else
1746                 auto temp = r[i];
1747 
1748             if (pred(r[j], temp))
1749             {
1750                 do
1751                 {
1752                     static if (hasLvalueElements!Range)
1753                         trustedMoveEmplace(r[j], r[j - 1]);
1754                     else
1755                         r[j - 1] = r[j];
1756                     ++j;
1757                 }
1758                 while (j < r.length && pred(r[j], temp));
1759 
1760                 static if (hasLvalueElements!Range)
1761                     trustedMoveEmplace(temp, r[j - 1]);
1762                 else
1763                     r[j - 1] = move(temp);
1764             }
1765         }
1766         else
1767         {
1768             size_t j = i;
1769             while (pred(r[j + 1], r[j]))
1770             {
1771                 r.swapAt(j, j + 1);
1772                 if (j == maxJ) break;
1773                 ++j;
1774             }
1775         }
1776         if (i == 0) break;
1777     }
1778 }
1779 
1780 /// @trusted wrapper for moveEmplace
1781 private void trustedMoveEmplace(T)(ref T source, ref T target) @trusted
1782 {
1783     import core.lifetime : moveEmplace;
1784     moveEmplace(source, target);
1785 }
1786 
1787 @safe unittest
1788 {
1789     import std.random : Random = Xorshift, uniform;
1790 
1791     auto rnd = Random(1);
1792     auto a = new int[uniform(100, 200, rnd)];
1793     foreach (ref e; a)
1794     {
1795         e = uniform(-100, 100, rnd);
1796     }
1797 
1798     shortSort!(binaryFun!("a < b"), int[])(a);
1799     assert(isSorted(a));
1800 }
1801 
1802 /*
1803 Sorts the first 5 elements exactly of range r.
1804 */
1805 private void sort5(alias lt, Range)(Range r)
1806 {
1807     assert(r.length >= 5, "r must have more than 4 elements");
1808 
1809     import std.algorithm.mutation : swapAt;
1810 
1811     // 1. Sort first two pairs
1812     if (lt(r[1], r[0])) r.swapAt(0, 1);
1813     if (lt(r[3], r[2])) r.swapAt(2, 3);
1814 
1815     // 2. Arrange first two pairs by the largest element
1816     if (lt(r[3], r[1]))
1817     {
1818         r.swapAt(0, 2);
1819         r.swapAt(1, 3);
1820     }
1821     assert(!lt(r[1], r[0]) && !lt(r[3], r[1]) && !lt(r[3], r[2]), "unexpected"
1822         ~ " order");
1823 
1824     // 3. Insert 4 into [0, 1, 3]
1825     if (lt(r[4], r[1]))
1826     {
1827         r.swapAt(3, 4);
1828         r.swapAt(1, 3);
1829         if (lt(r[1], r[0]))
1830         {
1831             r.swapAt(0, 1);
1832         }
1833     }
1834     else if (lt(r[4], r[3]))
1835     {
1836         r.swapAt(3, 4);
1837     }
1838     assert(!lt(r[1], r[0]) && !lt(r[3], r[1]) && !lt(r[4], r[3]), "unexpected"
1839         ~ " order");
1840 
1841     // 4. Insert 2 into [0, 1, 3, 4] (note: we already know the last is greater)
1842     assert(!lt(r[4], r[2]), "unexpected order");
1843     if (lt(r[2], r[1]))
1844     {
1845         r.swapAt(1, 2);
1846         if (lt(r[1], r[0]))
1847         {
1848             r.swapAt(0, 1);
1849         }
1850     }
1851     else if (lt(r[3], r[2]))
1852     {
1853         r.swapAt(2, 3);
1854     }
1855     // 7 comparisons, 0-9 swaps
1856 }
1857 
1858 @safe unittest
1859 {
1860     import std.algorithm.iteration : permutations;
1861     import std.algorithm.mutation : copy;
1862     import std.range : iota;
1863 
1864     int[5] buf;
1865     foreach (per; iota(5).permutations)
1866     {
1867         per.copy(buf[]);
1868         sort5!((a, b) => a < b)(buf[]);
1869         assert(buf[].isSorted);
1870     }
1871 }
1872 
1873 // sort
1874 /**
1875 Sorts a random-access range according to the predicate `less`.
1876 
1877 Performs $(BIGOH r.length * log(r.length)) evaluations of `less`. If `less` involves
1878 expensive computations on the _sort key, it may be worthwhile to use
1879 $(LREF schwartzSort) instead.
1880 
1881 Stable sorting requires `hasAssignableElements!Range` to be true.
1882 
1883 `sort` returns a $(REF SortedRange, std,range) over the original range,
1884 allowing functions that can take advantage of sorted data to know that the
1885 range is sorted and adjust accordingly. The $(REF SortedRange, std,range) is a
1886 wrapper around the original range, so both it and the original range are sorted.
1887 Other functions can't know that the original range has been sorted, but
1888 they $(I can) know that $(REF SortedRange, std,range) has been sorted.
1889 
1890 Preconditions:
1891 
1892 The predicate is expected to satisfy certain rules in order for `sort` to
1893 behave as expected - otherwise, the program may fail on certain inputs (but not
1894 others) when not compiled in release mode, due to the cursory `assumeSorted`
1895 check. Specifically, `sort` expects `less(a,b) && less(b,c)` to imply
1896 `less(a,c)` (transitivity), and, conversely, `!less(a,b) && !less(b,c)` to
1897 imply `!less(a,c)`. Note that the default predicate (`"a < b"`) does not
1898 always satisfy these conditions for floating point types, because the expression
1899 will always be `false` when either `a` or `b` is NaN.
1900 Use $(REF cmp, std,math) instead.
1901 
1902 Params:
1903     less = The predicate to sort by.
1904     ss = The swapping strategy to use.
1905     r = The range to sort.
1906 
1907 Returns: The initial range wrapped as a `SortedRange` with the predicate
1908 `binaryFun!less`.
1909 
1910 Algorithms: $(HTTP en.wikipedia.org/wiki/Introsort, Introsort) is used for unstable sorting and
1911 $(HTTP en.wikipedia.org/wiki/Timsort, Timsort) is used for stable sorting.
1912 Each algorithm has benefits beyond stability. Introsort is generally faster but
1913 Timsort may achieve greater speeds on data with low entropy or if predicate calls
1914 are expensive. Introsort performs no allocations whereas Timsort will perform one
1915 or more allocations per call. Both algorithms have $(BIGOH n log n) worst-case
1916 time complexity.
1917 
1918 See_Also:
1919     $(REF assumeSorted, std,range)$(BR)
1920     $(REF SortedRange, std,range)$(BR)
1921     $(REF SwapStrategy, std,algorithm,mutation)$(BR)
1922     $(REF binaryFun, std,functional)
1923 */
1924 SortedRange!(Range, less)
1925 sort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range)
1926 (Range r)
1927     /+ Unstable sorting uses the quicksort algorithm, which uses swapAt,
1928        which either uses swap(...), requiring swappable elements, or just
1929        swaps using assignment.
1930        Stable sorting uses TimSort, which needs to copy elements into a buffer,
1931        requiring assignable elements. +/
1932 {
1933     import std.range : assumeSorted;
1934     static if (ss == SwapStrategy.unstable)
1935     {
1936         static assert(hasSwappableElements!Range || hasAssignableElements!Range,
1937                   "When using SwapStrategy.unstable, the passed Range '"
1938                 ~ Range.stringof ~ "' must"
1939                 ~ " either fulfill hasSwappableElements, or"
1940                 ~ " hasAssignableElements, both were not the case");
1941     }
1942     else
1943     {
1944         static assert(hasAssignableElements!Range, "When using a SwapStrategy"
1945                 ~ " != unstable, the"
1946                 ~ " passed Range '" ~ Range.stringof ~ "' must fulfill"
1947                 ~ " hasAssignableElements, which it did not");
1948     }
1949 
1950     static assert(isRandomAccessRange!Range, "The passed Range '"
1951             ~ Range.stringof ~ "' must be a Random AccessRange "
1952             ~ "(isRandomAccessRange)");
1953 
1954     static assert(hasSlicing!Range, "The passed Range '"
1955             ~ Range.stringof ~ "' must allow Slicing (hasSlicing)");
1956 
1957     static assert(hasLength!Range, "The passed Range '"
1958             ~ Range.stringof ~ "' must have a length (hasLength)");
1959 
1960     alias lessFun = binaryFun!(less);
1961     alias LessRet = typeof(lessFun(r.front, r.front));    // instantiate lessFun
1962 
1963     static assert(is(LessRet == bool), "The return type of the template"
1964             ~ " argument 'less' when used with the binaryFun!less template"
1965             ~ " must be a bool. This is not the case, the returned type is '"
1966             ~ LessRet.stringof ~ "'");
1967 
1968     static if (ss == SwapStrategy.unstable)
1969         quickSortImpl!(lessFun)(r, r.length);
1970     else //use Tim Sort for semistable & stable
1971         TimSortImpl!(lessFun, Range).sort(r, null);
1972 
1973     assert(isSorted!lessFun(r), "Failed to sort range of type " ~ Range.stringof);
1974     return assumeSorted!less(r);
1975 }
1976 
1977 ///
1978 @safe pure nothrow unittest
1979 {
1980     int[] array = [ 1, 2, 3, 4 ];
1981 
1982     // sort in descending order
1983     array.sort!("a > b");
1984     assert(array == [ 4, 3, 2, 1 ]);
1985 
1986     // sort in ascending order
1987     array.sort();
1988     assert(array == [ 1, 2, 3, 4 ]);
1989 
1990     // sort with reusable comparator and chain
1991     alias myComp = (x, y) => x > y;
1992     assert(array.sort!(myComp).release == [ 4, 3, 2, 1 ]);
1993 }
1994 
1995 ///
1996 @safe unittest
1997 {
1998     // Showcase stable sorting
1999     import std.algorithm.mutation : SwapStrategy;
2000     string[] words = [ "aBc", "a", "abc", "b", "ABC", "c" ];
2001     sort!("toUpper(a) < toUpper(b)", SwapStrategy.stable)(words);
2002     assert(words == [ "a", "aBc", "abc", "ABC", "b", "c" ]);
2003 }
2004 
2005 ///
2006 @safe unittest
2007 {
2008     // Sorting floating-point numbers in presence of NaN
2009     double[] numbers = [-0.0, 3.0, -2.0, double.nan, 0.0, -double.nan];
2010 
2011     import std.algorithm.comparison : equal;
2012     import std.math.operations : cmp;
2013     import std.math.traits : isIdentical;
2014 
2015     sort!((a, b) => cmp(a, b) < 0)(numbers);
2016 
2017     double[] sorted = [-double.nan, -2.0, -0.0, 0.0, 3.0, double.nan];
2018     assert(numbers.equal!isIdentical(sorted));
2019 }
2020 
2021 @safe unittest
2022 {
2023     // Simple regression benchmark
2024     import std.algorithm.iteration, std.algorithm.mutation;
2025     import std.array : array;
2026     import std.random : Random, uniform;
2027     import std.range : iota;
2028     Random rng;
2029     int[] a = iota(20148).map!(_ => uniform(-1000, 1000, rng)).array;
2030     static uint comps;
2031     static bool less(int a, int b) { ++comps; return a < b; }
2032     sort!less(a); // random numbers
2033     sort!less(a); // sorted ascending
2034     a.reverse();
2035     sort!less(a); // sorted descending
2036     a[] = 0;
2037     sort!less(a); // all equal
2038 
2039     // This should get smaller with time. On occasion it may go larger, but only
2040     // if there's thorough justification.
2041     debug enum uint watermark = 1676220;
2042     else enum uint watermark = 1676220;
2043 
2044     import std.conv;
2045     assert(comps <= watermark, text("You seem to have pessimized sort! ",
2046         watermark, " < ", comps));
2047     assert(comps >= watermark, text("You seem to have improved sort!",
2048         " Please update watermark from ", watermark, " to ", comps));
2049 }
2050 
2051 @safe unittest
2052 {
2053     import std.algorithm.internal : rndstuff;
2054     import std.algorithm.mutation : swapRanges;
2055     import std.random : Random = Xorshift, uniform;
2056     import std.uni : toUpper;
2057 
2058     // sort using delegate
2059     auto a = new int[100];
2060     auto rnd = Random(123_456_789);
2061     foreach (ref e; a)
2062     {
2063         e = uniform(-100, 100, rnd);
2064     }
2065 
2066     int i = 0;
2067     bool greater2(int a, int b) @safe { return a + i > b + i; }
2068     auto greater = &greater2;
2069     sort!(greater)(a);
2070     assert(isSorted!(greater)(a));
2071 
2072     // sort using string
2073     sort!("a < b")(a);
2074     assert(isSorted!("a < b")(a));
2075 
2076     // sort using function; all elements equal
2077     foreach (ref e; a)
2078     {
2079         e = 5;
2080     }
2081     static bool less(int a, int b) { return a < b; }
2082     sort!(less)(a);
2083     assert(isSorted!(less)(a));
2084 
2085     string[] words = [ "aBc", "a", "abc", "b", "ABC", "c" ];
2086     bool lessi(string a, string b) { return toUpper(a) < toUpper(b); }
2087     sort!(lessi, SwapStrategy.stable)(words);
2088     assert(words == [ "a", "aBc", "abc", "ABC", "b", "c" ]);
2089 
2090     // sort using ternary predicate
2091     //sort!("b - a")(a);
2092     //assert(isSorted!(less)(a));
2093 
2094     a = rndstuff!(int)();
2095     sort(a);
2096     assert(isSorted(a));
2097     auto b = rndstuff!(string)();
2098     sort!("toLower(a) < toLower(b)")(b);
2099     assert(isSorted!("toUpper(a) < toUpper(b)")(b));
2100 
2101     {
2102         // https://issues.dlang.org/show_bug.cgi?id=10317
2103         enum E_10317 { a, b }
2104         auto a_10317 = new E_10317[10];
2105         sort(a_10317);
2106     }
2107 
2108     {
2109         // https://issues.dlang.org/show_bug.cgi?id=7767
2110         // Unstable sort should complete without an excessive number of predicate calls
2111         // This would suggest it's running in quadratic time
2112 
2113         // Compilation error if predicate is not static, i.e. a nested function
2114         static uint comp;
2115         static bool pred(size_t a, size_t b)
2116         {
2117             ++comp;
2118             return a < b;
2119         }
2120 
2121         size_t[] arr;
2122         arr.length = 1024;
2123 
2124         foreach (k; 0 .. arr.length) arr[k] = k;
2125         swapRanges(arr[0..$/2], arr[$/2..$]);
2126 
2127         sort!(pred, SwapStrategy.unstable)(arr);
2128         assert(comp < 25_000);
2129     }
2130 
2131     {
2132         import std.algorithm.mutation : swap;
2133 
2134         bool proxySwapCalled;
2135         struct S
2136         {
2137             int i;
2138             alias i this;
2139             void proxySwap(ref S other) { swap(i, other.i); proxySwapCalled = true; }
2140             @disable void opAssign(S value);
2141         }
2142 
2143         alias R = S[];
2144         R r = [S(3), S(2), S(1)];
2145         static assert(hasSwappableElements!R);
2146         static assert(!hasAssignableElements!R);
2147         r.sort();
2148         assert(proxySwapCalled);
2149     }
2150 
2151     // https://issues.dlang.org/show_bug.cgi?id=20751
2152     {
2153         static bool refPred(ref int a, ref int b)
2154         {
2155             return a < b;
2156         }
2157 
2158         auto sortedArr = [5,4,3,2,1].sort!refPred;
2159         sortedArr.equalRange(3);
2160     }
2161 }
2162 
2163 private void quickSortImpl(alias less, Range)(Range r, size_t depth)
2164 {
2165     import std.algorithm.comparison : min, max;
2166     import std.algorithm.mutation : swap, swapAt;
2167 
2168     alias Elem = ElementType!(Range);
2169     enum int size = Elem.sizeof;
2170     enum size_t shortSortGetsBetter = max(32, 1024 / size);
2171     static assert(shortSortGetsBetter >= 1, Elem.stringof ~ " "
2172         ~ size.stringof);
2173 
2174     // partition
2175     while (r.length > shortSortGetsBetter)
2176     {
2177         if (depth == 0)
2178         {
2179             HeapOps!(less, Range).heapSort(r);
2180             return;
2181         }
2182         depth = depth >= depth.max / 2 ? (depth / 3) * 2 : (depth * 2) / 3;
2183 
2184         const pivotIdx = getPivot!(less)(r);
2185         auto pivot = r[pivotIdx];
2186 
2187         // partition
2188         r.swapAt(pivotIdx, r.length - 1);
2189         size_t lessI = size_t.max, greaterI = r.length - 1;
2190 
2191         outer: for (;;)
2192         {
2193             alias pred = binaryFun!less;
2194             while (pred(r[++lessI], pivot)) {}
2195             assert(lessI <= greaterI, "sort: invalid comparison function.");
2196             for (;;)
2197             {
2198                 if (greaterI == lessI) break outer;
2199                 if (!pred(pivot, r[--greaterI])) break;
2200             }
2201             assert(lessI <= greaterI, "sort: invalid comparison function.");
2202             if (lessI == greaterI) break;
2203             r.swapAt(lessI, greaterI);
2204         }
2205 
2206         r.swapAt(r.length - 1, lessI);
2207         auto left = r[0 .. lessI], right = r[lessI + 1 .. r.length];
2208         if (right.length > left.length)
2209         {
2210             swap(left, right);
2211         }
2212         .quickSortImpl!(less, Range)(right, depth);
2213         r = left;
2214     }
2215     // residual sort
2216     static if (shortSortGetsBetter > 1)
2217     {
2218         shortSort!(less, Range)(r);
2219     }
2220 }
2221 
2222 // Heap operations for random-access ranges
2223 package(std) template HeapOps(alias less, Range)
2224 {
2225     import std.algorithm.mutation : swapAt;
2226 
2227     static assert(isRandomAccessRange!Range, Range.stringof ~ " must be a"
2228         ~ " RandomAccessRange");
2229     static assert(hasLength!Range, Range.stringof ~ " must have length");
2230     static assert(hasSwappableElements!Range || hasAssignableElements!Range,
2231         Range.stringof ~ " must have swappable or assignable Elements");
2232 
2233     alias lessFun = binaryFun!less;
2234 
2235     //template because of https://issues.dlang.org/show_bug.cgi?id=12410
2236     void heapSort()(Range r)
2237     {
2238         // If true, there is nothing to do
2239         if (r.length < 2) return;
2240         // Build Heap
2241         buildHeap(r);
2242         // Sort
2243         for (size_t i = r.length - 1; i > 0; --i)
2244         {
2245             r.swapAt(0, i);
2246             percolate(r, 0, i);
2247         }
2248     }
2249 
2250     //template because of https://issues.dlang.org/show_bug.cgi?id=12410
2251     void buildHeap()(Range r)
2252     {
2253         immutable n = r.length;
2254         for (size_t i = n / 2; i-- > 0; )
2255         {
2256             siftDown(r, i, n);
2257         }
2258         assert(isHeap(r), "r is not a heap");
2259     }
2260 
2261     bool isHeap()(Range r)
2262     {
2263         size_t parent = 0;
2264         foreach (child; 1 .. r.length)
2265         {
2266             if (lessFun(r[parent], r[child])) return false;
2267             // Increment parent every other pass
2268             parent += !(child & 1);
2269         }
2270         return true;
2271     }
2272 
2273     // Sifts down r[parent] (which is initially assumed to be messed up) so the
2274     // heap property is restored for r[parent .. end].
2275     // template because of https://issues.dlang.org/show_bug.cgi?id=12410
2276     void siftDown()(Range r, size_t parent, immutable size_t end)
2277     {
2278         for (;;)
2279         {
2280             auto child = (parent + 1) * 2;
2281             if (child >= end)
2282             {
2283                 // Leftover left child?
2284                 if (child == end && lessFun(r[parent], r[--child]))
2285                     r.swapAt(parent, child);
2286                 break;
2287             }
2288             auto leftChild = child - 1;
2289             if (lessFun(r[child], r[leftChild])) child = leftChild;
2290             if (!lessFun(r[parent], r[child])) break;
2291             r.swapAt(parent, child);
2292             parent = child;
2293         }
2294     }
2295 
2296     // Alternate version of siftDown that performs fewer comparisons, see
2297     // https://en.wikipedia.org/wiki/Heapsort#Bottom-up_heapsort. The percolate
2298     // process first sifts the parent all the way down (without comparing it
2299     // against the leaves), and then a bit up until the heap property is
2300     // restored. So there are more swaps but fewer comparisons. Gains are made
2301     // when the final position is likely to end toward the bottom of the heap,
2302     // so not a lot of sifts back are performed.
2303     //template because of https://issues.dlang.org/show_bug.cgi?id=12410
2304     void percolate()(Range r, size_t parent, immutable size_t end)
2305     {
2306         immutable root = parent;
2307 
2308         // Sift down
2309         for (;;)
2310         {
2311             auto child = (parent + 1) * 2;
2312 
2313             if (child >= end)
2314             {
2315                 if (child == end)
2316                 {
2317                     // Leftover left node.
2318                     --child;
2319                     r.swapAt(parent, child);
2320                     parent = child;
2321                 }
2322                 break;
2323             }
2324 
2325             auto leftChild = child - 1;
2326             if (lessFun(r[child], r[leftChild])) child = leftChild;
2327             r.swapAt(parent, child);
2328             parent = child;
2329         }
2330 
2331         // Sift up
2332         for (auto child = parent; child > root; child = parent)
2333         {
2334             parent = (child - 1) / 2;
2335             if (!lessFun(r[parent], r[child])) break;
2336             r.swapAt(parent, child);
2337         }
2338     }
2339 }
2340 
2341 // Tim Sort implementation
2342 private template TimSortImpl(alias pred, R)
2343 {
2344     import core.bitop : bsr;
2345     import std.array : uninitializedArray;
2346 
2347     static assert(isRandomAccessRange!R, R.stringof ~ " must be a"
2348         ~ " RandomAccessRange");
2349     static assert(hasLength!R, R.stringof ~ " must have a length");
2350     static assert(hasSlicing!R, R.stringof ~ " must support slicing");
2351     static assert(hasAssignableElements!R, R.stringof ~ " must have"
2352         ~ " assignable elements");
2353 
2354     alias T = ElementType!R;
2355 
2356     alias less = binaryFun!pred;
2357     bool greater()(auto ref T a, auto ref T b) { return less(b, a); }
2358     bool greaterEqual()(auto ref T a, auto ref T b) { return !less(a, b); }
2359     bool lessEqual()(auto ref T a, auto ref T b) { return !less(b, a); }
2360 
2361     enum minimalMerge = 128;
2362     enum minimalGallop = 7;
2363     enum minimalStorage = 256;
2364     enum stackSize = 40;
2365 
2366     struct Slice{ size_t base, length; }
2367 
2368     // Entry point for tim sort
2369     void sort()(R range, T[] temp)
2370     {
2371         import std.algorithm.comparison : min;
2372         import std.format : format;
2373 
2374         // Do insertion sort on small range
2375         if (range.length <= minimalMerge)
2376         {
2377             binaryInsertionSort(range);
2378             return;
2379         }
2380 
2381         immutable minRun = minRunLength(range.length);
2382         immutable minTemp = min(range.length / 2, minimalStorage);
2383         size_t minGallop = minimalGallop;
2384         Slice[stackSize] stack = void;
2385         size_t stackLen = 0;
2386 
2387         // Allocate temporary memory if not provided by user
2388         if (temp.length < minTemp)
2389         {
2390             static if (hasElaborateAssign!T) temp = new T[](minTemp);
2391             else temp = () @trusted { return uninitializedArray!(T[])(minTemp); }();
2392         }
2393 
2394         for (size_t i = 0; i < range.length; )
2395         {
2396             // Find length of first run in list
2397             size_t runLen = firstRun(range[i .. range.length]);
2398 
2399             // If run has less than minRun elements, extend using insertion sort
2400             if (runLen < minRun)
2401             {
2402                 // Do not run farther than the length of the range
2403                 immutable force = range.length - i > minRun ? minRun : range.length - i;
2404                 binaryInsertionSort(range[i .. i + force], runLen);
2405                 runLen = force;
2406             }
2407 
2408             // Push run onto stack
2409             stack[stackLen++] = Slice(i, runLen);
2410             i += runLen;
2411 
2412             // Collapse stack so that (e1 > e2 + e3 && e2 > e3)
2413             // STACK is | ... e1 e2 e3 >
2414             while (stackLen > 1)
2415             {
2416                 immutable run4 = stackLen - 1;
2417                 immutable run3 = stackLen - 2;
2418                 immutable run2 = stackLen - 3;
2419                 immutable run1 = stackLen - 4;
2420 
2421                 if ( (stackLen > 2 && stack[run2].length <= stack[run3].length + stack[run4].length) ||
2422                      (stackLen > 3 && stack[run1].length <= stack[run3].length + stack[run2].length) )
2423                 {
2424                     immutable at = stack[run2].length < stack[run4].length ? run2 : run3;
2425                     mergeAt(range, stack[0 .. stackLen], at, minGallop, temp);
2426                 }
2427                 else if (stack[run3].length > stack[run4].length) break;
2428                 else mergeAt(range, stack[0 .. stackLen], run3, minGallop, temp);
2429 
2430                 stackLen -= 1;
2431             }
2432 
2433             // Assert that the code above established the invariant correctly
2434             version (StdUnittest)
2435             {
2436                 if (stackLen == 2)
2437                 {
2438                     assert(stack[0].length > stack[1].length, format!
2439                         "stack[0].length %s > stack[1].length %s"(
2440                             stack[0].length, stack[1].length
2441                         ));
2442                 }
2443                 else if (stackLen > 2)
2444                 {
2445                     foreach (k; 2 .. stackLen)
2446                     {
2447                         assert(stack[k - 2].length > stack[k - 1].length + stack[k].length,
2448                             format!"stack[k - 2].length %s > stack[k - 1].length %s + stack[k].length %s"(
2449                                 stack[k - 2].length, stack[k - 1].length, stack[k].length
2450                             ));
2451                         assert(stack[k - 1].length > stack[k].length,
2452                             format!"stack[k - 1].length %s > stack[k].length %s"(
2453                                 stack[k - 1].length, stack[k].length
2454                             ));
2455                     }
2456                 }
2457             }
2458         }
2459 
2460         // Force collapse stack until there is only one run left
2461         while (stackLen > 1)
2462         {
2463             immutable run3 = stackLen - 1;
2464             immutable run2 = stackLen - 2;
2465             immutable run1 = stackLen - 3;
2466             immutable at = stackLen >= 3 && stack[run1].length <= stack[run3].length
2467                 ? run1 : run2;
2468             mergeAt(range, stack[0 .. stackLen], at, minGallop, temp);
2469             --stackLen;
2470         }
2471     }
2472 
2473     // Calculates optimal value for minRun:
2474     // take first 6 bits of n and add 1 if any lower bits are set
2475     size_t minRunLength()(size_t n)
2476     {
2477         immutable shift = bsr(n)-5;
2478         auto result = (n >> shift) + !!(n & ~((1 << shift)-1));
2479         return result;
2480     }
2481 
2482     // Returns length of first run in range
2483     size_t firstRun()(R range)
2484     out(ret)
2485     {
2486         assert(ret <= range.length, "ret must be less or equal than"
2487             ~ " range.length");
2488     }
2489     do
2490     {
2491         import std.algorithm.mutation : reverse;
2492 
2493         if (range.length < 2) return range.length;
2494 
2495         size_t i = 2;
2496         if (lessEqual(range[0], range[1]))
2497         {
2498             while (i < range.length && lessEqual(range[i-1], range[i])) ++i;
2499         }
2500         else
2501         {
2502             while (i < range.length && greater(range[i-1], range[i])) ++i;
2503             reverse(range[0 .. i]);
2504         }
2505         return i;
2506     }
2507 
2508     // A binary insertion sort for building runs up to minRun length
2509     void binaryInsertionSort()(R range, size_t sortedLen = 1)
2510     out
2511     {
2512         if (!__ctfe) assert(isSorted!pred(range), "range must be sorted");
2513     }
2514     do
2515     {
2516         import std.algorithm.mutation : move;
2517 
2518         for (; sortedLen < range.length; ++sortedLen)
2519         {
2520             T item = range.moveAt(sortedLen);
2521             size_t lower = 0;
2522             size_t upper = sortedLen;
2523             while (upper != lower)
2524             {
2525                 size_t center = (lower + upper) / 2;
2526                 if (less(item, range[center])) upper = center;
2527                 else lower = center + 1;
2528             }
2529             //Currently (DMD 2.061) moveAll+retro is slightly less
2530             //efficient then stright 'for' loop
2531             //11 instructions vs 7 in the innermost loop [checked on Win32]
2532             //moveAll(retro(range[lower .. sortedLen]),
2533             //            retro(range[lower+1 .. sortedLen+1]));
2534             for (upper=sortedLen; upper > lower; upper--)
2535             {
2536                 static if (hasLvalueElements!R)
2537                     move(range[upper -1], range[upper]);
2538                 else
2539                     range[upper] = range.moveAt(upper - 1);
2540             }
2541 
2542             static if (hasLvalueElements!R)
2543                 move(item, range[lower]);
2544             else
2545                 range[lower] = move(item);
2546         }
2547     }
2548 
2549     // Merge two runs in stack (at, at + 1)
2550     void mergeAt()(R range, Slice[] stack, immutable size_t at, ref size_t minGallop, ref T[] temp)
2551     in
2552     {
2553         import std.format : format;
2554         assert(stack.length >= 2, "stack be be greater than 1");
2555         assert(stack.length - at == 2 || stack.length - at == 3,
2556             format!"stack.length - at %s must be 2 or 3"(stack.length - at));
2557     }
2558     do
2559     {
2560         immutable base = stack[at].base;
2561         immutable mid  = stack[at].length;
2562         immutable len  = stack[at + 1].length + mid;
2563 
2564         // Pop run from stack
2565         stack[at] = Slice(base, len);
2566         if (stack.length - at == 3) stack[$ - 2] = stack[$ - 1];
2567 
2568         // Merge runs (at, at + 1)
2569         return merge(range[base .. base + len], mid, minGallop, temp);
2570     }
2571 
2572     // Merge two runs in a range. Mid is the starting index of the second run.
2573     // minGallop and temp are references; The calling function must receive the updated values.
2574     void merge()(R range, size_t mid, ref size_t minGallop, ref T[] temp)
2575     in
2576     {
2577         if (!__ctfe)
2578         {
2579             assert(isSorted!pred(range[0 .. mid]), "range[0 .. mid] must be"
2580                 ~ " sorted");
2581             assert(isSorted!pred(range[mid .. range.length]), "range[mid .."
2582                 ~ " range.length] must be sorted");
2583         }
2584     }
2585     do
2586     {
2587         assert(mid < range.length, "mid must be less than the length of the"
2588             ~ " range");
2589 
2590         // Reduce range of elements
2591         immutable firstElement = gallopForwardUpper(range[0 .. mid], range[mid]);
2592         immutable lastElement  = gallopReverseLower(range[mid .. range.length], range[mid - 1]) + mid;
2593         range = range[firstElement .. lastElement];
2594         mid -= firstElement;
2595 
2596         if (mid == 0 || mid == range.length) return;
2597 
2598         // Call function which will copy smaller run into temporary memory
2599         if (mid <= range.length / 2)
2600         {
2601             temp = ensureCapacity(mid, temp);
2602             minGallop = mergeLo(range, mid, minGallop, temp);
2603         }
2604         else
2605         {
2606             temp = ensureCapacity(range.length - mid, temp);
2607             minGallop = mergeHi(range, mid, minGallop, temp);
2608         }
2609     }
2610 
2611     // Enlarge size of temporary memory if needed
2612     T[] ensureCapacity()(size_t minCapacity, T[] temp)
2613     out(ret)
2614     {
2615         assert(ret.length >= minCapacity, "ensuring the capacity failed");
2616     }
2617     do
2618     {
2619         if (temp.length < minCapacity)
2620         {
2621             size_t newSize = 1<<(bsr(minCapacity)+1);
2622             //Test for overflow
2623             if (newSize < minCapacity) newSize = minCapacity;
2624 
2625             // can't use `temp.length` if there's no default constructor
2626             static if (__traits(compiles, { T defaultConstructed; cast(void) defaultConstructed; }))
2627             {
2628 
2629                 static if (hasElaborateAssign!T)
2630                     temp.length = newSize;
2631                 else
2632                 {
2633                     if (__ctfe) temp.length = newSize;
2634                     else temp = () @trusted { return uninitializedArray!(T[])(newSize); }();
2635                 }
2636             }
2637             else
2638             {
2639                 static assert(!hasElaborateAssign!T,
2640                               "Structs which have opAssign but cannot be default-initialized " ~
2641                               "do not currently work with stable sort: " ~
2642                               "https://issues.dlang.org/show_bug.cgi?id=24810");
2643                 temp = () @trusted { return uninitializedArray!(T[])(newSize); }();
2644             }
2645         }
2646         return temp;
2647     }
2648 
2649     // Merge front to back. Returns new value of minGallop.
2650     // temp must be large enough to store range[0 .. mid]
2651     size_t mergeLo()(R range, immutable size_t mid, size_t minGallop, T[] temp)
2652     out
2653     {
2654         if (!__ctfe) assert(isSorted!pred(range), "the range must be sorted");
2655     }
2656     do
2657     {
2658         import std.algorithm.mutation : copy;
2659 
2660         assert(mid <= range.length, "mid must be less than the length of the"
2661             ~ " range");
2662         assert(temp.length >= mid, "temp.length must be greater or equal to mid");
2663 
2664         // Copy run into temporary memory
2665         temp = temp[0 .. mid];
2666         copy(range[0 .. mid], temp);
2667 
2668         // Move first element into place
2669         moveEntry(range, mid, range, 0);
2670 
2671         size_t i = 1, lef = 0, rig = mid + 1;
2672         size_t count_lef, count_rig;
2673         immutable lef_end = temp.length - 1;
2674 
2675         if (lef < lef_end && rig < range.length)
2676         outer: while (true)
2677         {
2678             count_lef = 0;
2679             count_rig = 0;
2680 
2681             // Linear merge
2682             while ((count_lef | count_rig) < minGallop)
2683             {
2684                 if (lessEqual(temp[lef], range[rig]))
2685                 {
2686                     moveEntry(temp, lef++, range, i++);
2687                     if (lef >= lef_end) break outer;
2688                     ++count_lef;
2689                     count_rig = 0;
2690                 }
2691                 else
2692                 {
2693                     moveEntry(range, rig++, range, i++);
2694                     if (rig >= range.length) break outer;
2695                     count_lef = 0;
2696                     ++count_rig;
2697                 }
2698             }
2699 
2700             // Gallop merge
2701             do
2702             {
2703                 count_lef = gallopForwardUpper(temp[lef .. $], range[rig]);
2704                 foreach (j; 0 .. count_lef) moveEntry(temp, lef++, range, i++);
2705                 if (lef >= temp.length) break outer;
2706 
2707                 count_rig = gallopForwardLower(range[rig .. range.length], temp[lef]);
2708                 foreach (j; 0 .. count_rig) moveEntry(range, rig++, range, i++);
2709                 if (rig >= range.length) while (true)
2710                 {
2711                     moveEntry(temp, lef++, range, i++);
2712                     if (lef >= temp.length) break outer;
2713                 }
2714 
2715                 if (minGallop > 0) --minGallop;
2716             }
2717             while (count_lef >= minimalGallop || count_rig >= minimalGallop);
2718 
2719             minGallop += 2;
2720         }
2721 
2722         // Move remaining elements from right
2723         while (rig < range.length)
2724             moveEntry(range, rig++, range, i++);
2725 
2726         // Move remaining elements from left
2727         while (lef < temp.length)
2728             moveEntry(temp, lef++, range, i++);
2729 
2730         return minGallop > 0 ? minGallop : 1;
2731     }
2732 
2733     // Merge back to front. Returns new value of minGallop.
2734     // temp must be large enough to store range[mid .. range.length]
2735     size_t mergeHi()(R range, immutable size_t mid, size_t minGallop, T[] temp)
2736     out
2737     {
2738         if (!__ctfe) assert(isSorted!pred(range), "the range must be sorted");
2739     }
2740     do
2741     {
2742         import std.algorithm.mutation : copy;
2743         import std.format : format;
2744 
2745         assert(mid <= range.length, "mid must be less or equal to range.length");
2746         assert(temp.length >= range.length - mid, format!
2747             "temp.length %s >= range.length %s - mid %s"(temp.length,
2748             range.length, mid));
2749 
2750         // Copy run into temporary memory
2751         temp = temp[0 .. range.length - mid];
2752         copy(range[mid .. range.length], temp);
2753 
2754         // Move first element into place
2755         moveEntry(range, mid - 1, range, range.length - 1);
2756 
2757         size_t i = range.length - 2, lef = mid - 2, rig = temp.length - 1;
2758         size_t count_lef, count_rig;
2759 
2760         outer:
2761         while (true)
2762         {
2763             count_lef = 0;
2764             count_rig = 0;
2765 
2766             // Linear merge
2767             while ((count_lef | count_rig) < minGallop)
2768             {
2769                 if (greaterEqual(temp[rig], range[lef]))
2770                 {
2771                     moveEntry(temp, rig, range, i--);
2772                     if (rig == 1)
2773                     {
2774                         // Move remaining elements from left
2775                         while (true)
2776                         {
2777                             moveEntry(range, lef, range, i--);
2778                             if (lef == 0) break;
2779                             --lef;
2780                         }
2781 
2782                         // Move last element into place
2783                         moveEntry(temp, 0, range, i);
2784 
2785                         break outer;
2786                     }
2787                     --rig;
2788                     count_lef = 0;
2789                     ++count_rig;
2790                 }
2791                 else
2792                 {
2793                     moveEntry(range, lef, range, i--);
2794                     if (lef == 0) while (true)
2795                     {
2796                         moveEntry(temp, rig, range, i--);
2797                         if (rig == 0) break outer;
2798                         --rig;
2799                     }
2800                     --lef;
2801                     ++count_lef;
2802                     count_rig = 0;
2803                 }
2804             }
2805 
2806             // Gallop merge
2807             do
2808             {
2809                 count_rig = rig - gallopReverseLower(temp[0 .. rig], range[lef]);
2810                 foreach (j; 0 .. count_rig)
2811                 {
2812                     moveEntry(temp, rig, range, i--);
2813                     if (rig == 0) break outer;
2814                     --rig;
2815                 }
2816 
2817                 count_lef = lef - gallopReverseUpper(range[0 .. lef], temp[rig]);
2818                 foreach (j; 0 .. count_lef)
2819                 {
2820                     moveEntry(range, lef, range, i--);
2821                     if (lef == 0) while (true)
2822                     {
2823                         moveEntry(temp, rig, range, i--);
2824                         if (rig == 0) break outer;
2825                         --rig;
2826                     }
2827                     --lef;
2828                 }
2829 
2830                 if (minGallop > 0) --minGallop;
2831             }
2832             while (count_lef >= minimalGallop || count_rig >= minimalGallop);
2833 
2834             minGallop += 2;
2835         }
2836 
2837         return minGallop > 0 ? minGallop : 1;
2838     }
2839 
2840     // false = forward / lower, true = reverse / upper
2841     template gallopSearch(bool forwardReverse, bool lowerUpper)
2842     {
2843         // Gallop search on range according to attributes forwardReverse and lowerUpper
2844         size_t gallopSearch(R)(R range, T value)
2845         out(ret)
2846         {
2847             assert(ret <= range.length, "ret must be less or equal to"
2848                 ~ " range.length");
2849         }
2850         do
2851         {
2852             size_t lower = 0, center = 1, upper = range.length;
2853             alias gap = center;
2854 
2855             static if (forwardReverse)
2856             {
2857                 static if (!lowerUpper) alias comp = lessEqual; // reverse lower
2858                 static if (lowerUpper)  alias comp = less;      // reverse upper
2859 
2860                 // Gallop Search Reverse
2861                 while (gap <= upper)
2862                 {
2863                     if (comp(value, range[upper - gap]))
2864                     {
2865                         upper -= gap;
2866                         gap *= 2;
2867                     }
2868                     else
2869                     {
2870                         lower = upper - gap;
2871                         break;
2872                     }
2873                 }
2874 
2875                 // Binary Search Reverse
2876                 while (upper != lower)
2877                 {
2878                     center = lower + (upper - lower) / 2;
2879                     if (comp(value, range[center])) upper = center;
2880                     else lower = center + 1;
2881                 }
2882             }
2883             else
2884             {
2885                 static if (!lowerUpper) alias comp = greater;      // forward lower
2886                 static if (lowerUpper)  alias comp = greaterEqual; // forward upper
2887 
2888                 // Gallop Search Forward
2889                 while (lower + gap < upper)
2890                 {
2891                     if (comp(value, range[lower + gap]))
2892                     {
2893                         lower += gap;
2894                         gap *= 2;
2895                     }
2896                     else
2897                     {
2898                         upper = lower + gap;
2899                         break;
2900                     }
2901                 }
2902 
2903                 // Binary Search Forward
2904                 while (lower != upper)
2905                 {
2906                     center = lower + (upper - lower) / 2;
2907                     if (comp(value, range[center])) lower = center + 1;
2908                     else upper = center;
2909                 }
2910             }
2911 
2912             return lower;
2913         }
2914     }
2915 
2916     alias gallopForwardLower = gallopSearch!(false, false);
2917     alias gallopForwardUpper = gallopSearch!(false,  true);
2918     alias gallopReverseLower = gallopSearch!( true, false);
2919     alias gallopReverseUpper = gallopSearch!( true,  true);
2920 
2921     /// Helper method that moves from[fIdx] into to[tIdx] if both are lvalues and
2922     /// uses a plain assignment if not (necessary for backwards compatibility)
2923     void moveEntry(X, Y)(ref X from, const size_t fIdx, ref Y to, const size_t tIdx)
2924     {
2925         // This template is instantiated with different combinations of range (R) and temp (T[]).
2926         // T[] obviously has lvalue-elements, so checking R should be enough here
2927         static if (hasLvalueElements!R)
2928         {
2929             import core.lifetime : move;
2930             move(from[fIdx], to[tIdx]);
2931         }
2932         else
2933             to[tIdx] = from[fIdx];
2934     }
2935 }
2936 
2937 @safe unittest
2938 {
2939     import std.random : Random, uniform, randomShuffle;
2940 
2941     // Element type with two fields
2942     static struct E
2943     {
2944         size_t value, index;
2945     }
2946 
2947     // Generates data especially for testing sorting with Timsort
2948     static E[] genSampleData(uint seed) @safe
2949     {
2950         import std.algorithm.mutation : swap, swapRanges;
2951 
2952         auto rnd = Random(seed);
2953 
2954         E[] arr;
2955         arr.length = 64 * 64;
2956 
2957         // We want duplicate values for testing stability
2958         foreach (i, ref v; arr) v.value = i / 64;
2959 
2960         // Swap ranges at random middle point (test large merge operation)
2961         immutable mid = uniform(arr.length / 4, arr.length / 4 * 3, rnd);
2962         swapRanges(arr[0 .. mid], arr[mid .. $]);
2963 
2964         // Shuffle last 1/8 of the array (test insertion sort and linear merge)
2965         randomShuffle(arr[$ / 8 * 7 .. $], rnd);
2966 
2967         // Swap few random elements (test galloping mode)
2968         foreach (i; 0 .. arr.length / 64)
2969         {
2970             immutable a = uniform(0, arr.length, rnd), b = uniform(0, arr.length, rnd);
2971             swap(arr[a], arr[b]);
2972         }
2973 
2974         // Now that our test array is prepped, store original index value
2975         // This will allow us to confirm the array was sorted stably
2976         foreach (i, ref v; arr) v.index = i;
2977 
2978         return arr;
2979     }
2980 
2981     // Tests the Timsort function for correctness and stability
2982     static bool testSort(uint seed)
2983     {
2984         import std.format : format;
2985         auto arr = genSampleData(seed);
2986 
2987         // Now sort the array!
2988         static bool comp(E a, E b)
2989         {
2990             return a.value < b.value;
2991         }
2992 
2993         sort!(comp, SwapStrategy.stable)(arr);
2994 
2995         // Test that the array was sorted correctly
2996         assert(isSorted!comp(arr), "arr must be sorted");
2997 
2998         // Test that the array was sorted stably
2999         foreach (i; 0 .. arr.length - 1)
3000         {
3001             if (arr[i].value == arr[i + 1].value)
3002                 assert(arr[i].index < arr[i + 1].index, format!
3003                     "arr[i %s].index %s < arr[i + 1].index %s"(
3004                     i, arr[i].index, arr[i + 1].index));
3005         }
3006 
3007         return true;
3008     }
3009 
3010     enum seed = 310614065;
3011     testSort(seed);
3012 
3013     enum result = testSort(seed);
3014     assert(result == true, "invalid result");
3015 }
3016 
3017 // https://issues.dlang.org/show_bug.cgi?id=4584
3018 @safe unittest
3019 {
3020     assert(isSorted!"a < b"(sort!("a < b", SwapStrategy.stable)(
3021        [83, 42, 85, 86, 87, 22, 89, 30, 91, 46, 93, 94, 95, 6,
3022          97, 14, 33, 10, 101, 102, 103, 26, 105, 106, 107, 6]
3023     )));
3024 
3025 }
3026 
3027 @safe unittest
3028 {
3029     //test stable sort + zip
3030     import std.range;
3031     auto x = [10, 50, 60, 60, 20];
3032     dchar[] y = "abcde"d.dup;
3033 
3034     sort!("a[0] < b[0]", SwapStrategy.stable)(zip(x, y));
3035     assert(x == [10, 20, 50, 60, 60]);
3036     assert(y == "aebcd"d);
3037 }
3038 
3039 // https://issues.dlang.org/show_bug.cgi?id=14223
3040 @safe unittest
3041 {
3042     import std.array, std.range;
3043     auto arr = chain(iota(0, 384), iota(0, 256), iota(0, 80), iota(0, 64), iota(0, 96)).array;
3044     sort!("a < b", SwapStrategy.stable)(arr);
3045 }
3046 
3047 @safe unittest
3048 {
3049     static struct NoCopy
3050     {
3051         pure nothrow @nogc @safe:
3052 
3053         int key;
3054         this(scope const ref NoCopy)
3055         {
3056             assert(false, "Tried to copy struct!");
3057         }
3058         ref opAssign()(scope const auto ref NoCopy other)
3059         {
3060             assert(false, "Tried to copy struct!");
3061         }
3062         this(this) {}
3063     }
3064 
3065     static NoCopy[] makeArray(const size_t size)
3066     {
3067         NoCopy[] array = new NoCopy[](size);
3068         foreach (const i, ref t; array[0..$/2]) t.key = cast(int) (size - i);
3069         foreach (const i, ref t; array[$/2..$]) t.key = cast(int) i;
3070         return array;
3071     }
3072 
3073     alias cmp = (ref NoCopy a, ref NoCopy b) => a.key < b.key;
3074     enum minMerge = TimSortImpl!(cmp, NoCopy[]).minimalMerge;
3075 
3076     sort!(cmp, SwapStrategy.unstable)(makeArray(20));
3077     sort!(cmp, SwapStrategy.stable)(makeArray(minMerge - 5));
3078     sort!(cmp, SwapStrategy.stable)(makeArray(minMerge + 5));
3079 }
3080 
3081 // https://issues.dlang.org/show_bug.cgi?id=23668
3082 @safe unittest
3083 {
3084     static struct S
3085     {
3086         int opCmp(const S) const { return 1; }
3087         @disable this();
3088     }
3089     S[] array;
3090     array.sort!("a < b", SwapStrategy.stable);
3091 }
3092 
3093 // https://issues.dlang.org/show_bug.cgi?id=24773
3094 @safe unittest
3095 {
3096     static struct S
3097     {
3098         int i = 42;
3099         ~this() { assert(i == 42); }
3100     }
3101 
3102     auto array = new S[](400);
3103     array.sort!((a, b) => false, SwapStrategy.stable);
3104 }
3105 
3106 // https://issues.dlang.org/show_bug.cgi?id=24809
3107 @safe unittest
3108 {
3109     static struct E
3110     {
3111         int value;
3112         int valid = 42;
3113 
3114         ~this()
3115         {
3116             assert(valid == 42);
3117         }
3118     }
3119 
3120     import std.array : array;
3121     import std.range : chain, only, repeat;
3122     auto arr = chain(repeat(E(41), 18),
3123                      only(E(39)),
3124                      repeat(E(41), 16),
3125                      only(E(1)),
3126                      repeat(E(42), 33),
3127                      only(E(33)),
3128                      repeat(E(42), 16),
3129                      repeat(E(43), 27),
3130                      only(E(33)),
3131                      repeat(E(43), 34),
3132                      only(E(34)),
3133                      only(E(43)),
3134                      only(E(63)),
3135                      repeat(E(44), 42),
3136                      only(E(27)),
3137                      repeat(E(44), 11),
3138                      repeat(E(45), 64),
3139                      repeat(E(46), 3),
3140                      only(E(11)),
3141                      repeat(E(46), 7),
3142                      only(E(4)),
3143                      repeat(E(46), 34),
3144                      only(E(36)),
3145                      repeat(E(46), 17),
3146                      repeat(E(47), 36),
3147                      only(E(39)),
3148                      repeat(E(47), 26),
3149                      repeat(E(48), 17),
3150                      only(E(21)),
3151                      repeat(E(48), 5),
3152                      only(E(39)),
3153                      repeat(E(48), 14),
3154                      only(E(58)),
3155                      repeat(E(48), 24),
3156                      repeat(E(49), 13),
3157                      only(E(40)),
3158                      repeat(E(49), 38),
3159                      only(E(18)),
3160                      repeat(E(49), 11),
3161                      repeat(E(50), 6)).array();
3162 
3163     arr.sort!((a, b) => a.value < b.value, SwapStrategy.stable)();
3164 }
3165 
3166 // schwartzSort
3167 /**
3168 Alternative sorting method that should be used when comparing keys involves an
3169 expensive computation.
3170 
3171 Instead of using `less(a, b)` for comparing elements,
3172 `schwartzSort` uses `less(transform(a), transform(b))`. The values of the
3173 `transform` function are precomputed in a temporary array, thus saving on
3174 repeatedly computing it. Conversely, if the cost of `transform` is small
3175 compared to the cost of allocating and filling the precomputed array, `sort`
3176 may be faster and therefore preferable.
3177 
3178 This approach to sorting is akin to the $(HTTP
3179 wikipedia.org/wiki/Schwartzian_transform, Schwartzian transform), also known as
3180 the decorate-sort-undecorate pattern in Python and Lisp. The complexity is the
3181 same as that of the corresponding `sort`, but `schwartzSort` evaluates
3182 `transform` only `r.length` times (less than half when compared to regular
3183 sorting). The usage can be best illustrated with an example.
3184 
3185 Example:
3186 ----
3187 uint hashFun(string) { ... expensive computation ... }
3188 string[] array = ...;
3189 // Sort strings by hash, slow
3190 sort!((a, b) => hashFun(a) < hashFun(b))(array);
3191 // Sort strings by hash, fast (only computes arr.length hashes):
3192 schwartzSort!(hashFun, "a < b")(array);
3193 ----
3194 
3195 The `schwartzSort` function might require less temporary data and
3196 be faster than the Perl idiom or the decorate-sort-undecorate idiom
3197 present in Python and Lisp. This is because sorting is done in-place
3198 and only minimal extra data (one array of transformed elements) is
3199 created.
3200 
3201 To check whether an array was sorted and benefit of the speedup of
3202 Schwartz sorting, a function `schwartzIsSorted` is not provided
3203 because the effect can be achieved by calling $(D
3204 isSorted!less(map!transform(r))).
3205 
3206 Params:
3207     transform = The transformation to apply. Either a unary function
3208                 (`unaryFun!transform(element)`), or a binary function
3209                 (`binaryFun!transform(element, index)`).
3210     less = The predicate to sort the transformed elements by.
3211     ss = The swapping strategy to use.
3212     r = The range to sort.
3213 
3214 Returns: The initial range wrapped as a `SortedRange` with the
3215 predicate `(a, b) => binaryFun!less(transform(a), transform(b))`.
3216  */
3217 SortedRange!(R, ((a, b) => binaryFun!less(unaryFun!transform(a),
3218                                           unaryFun!transform(b))))
3219 schwartzSort(alias transform, alias less = "a < b",
3220         SwapStrategy ss = SwapStrategy.unstable, R)(R r)
3221 if (isRandomAccessRange!R && hasLength!R && hasSwappableElements!R &&
3222     !is(typeof(binaryFun!less) == SwapStrategy))
3223 {
3224     import core.lifetime : emplace;
3225     import std.range : zip, SortedRange;
3226     import std.string : representation;
3227 
3228     static if (is(typeof(unaryFun!transform(r.front))))
3229     {
3230         alias transformFun = unaryFun!transform;
3231         alias TB = typeof(transformFun(r.front));
3232         enum isBinary = false;
3233     }
3234     else static if (is(typeof(binaryFun!transform(r.front, 0))))
3235     {
3236         alias transformFun = binaryFun!transform;
3237         alias TB = typeof(transformFun(r.front, 0));
3238         enum isBinary = true;
3239     }
3240     else
3241         static assert(false, "unsupported `transform` alias");
3242 
3243     // The `transform` function might return a qualified type, e.g. const(int).
3244     // Strip qualifiers if possible s.t. the temporary array is sortable.
3245     static if (is(TB : Unqual!TB))
3246         alias T = Unqual!TB;
3247     else
3248         static assert(false, "`transform` returns an unsortable qualified type: " ~ TB.stringof);
3249 
3250     static trustedMalloc()(size_t len) @trusted
3251     {
3252         import core.checkedint : mulu;
3253         import core.memory : pureMalloc;
3254         bool overflow;
3255         const nbytes = mulu(len, T.sizeof, overflow);
3256         if (overflow) assert(false, "multiplication overflowed");
3257         T[] result = (cast(T*) pureMalloc(nbytes))[0 .. len];
3258         static if (hasIndirections!T)
3259         {
3260             import core.memory : GC;
3261             GC.addRange(result.ptr, nbytes);
3262         }
3263         return result;
3264     }
3265     auto xform1 = trustedMalloc(r.length);
3266 
3267     size_t length;
3268     scope(exit)
3269     {
3270         static if (hasElaborateDestructor!T)
3271         {
3272             foreach (i; 0 .. length) collectException(destroy(xform1[i]));
3273         }
3274         static void trustedFree()(T[] p) @trusted
3275         {
3276             import core.memory : pureFree;
3277             static if (hasIndirections!T)
3278             {
3279                 import core.memory : GC;
3280                 GC.removeRange(p.ptr);
3281             }
3282             pureFree(p.ptr);
3283         }
3284         trustedFree(xform1);
3285     }
3286     for (; length != r.length; ++length)
3287     {
3288         static if (isBinary)
3289             emplace(&xform1[length], transformFun(r[length], length));
3290         else
3291             emplace(&xform1[length], transformFun(r[length]));
3292     }
3293     // Make sure we use ubyte[] and ushort[], not char[] and wchar[]
3294     // for the intermediate array, lest zip gets confused.
3295     static if (isNarrowString!(typeof(xform1)))
3296     {
3297         auto xform = xform1.representation();
3298     }
3299     else
3300     {
3301         alias xform = xform1;
3302     }
3303     zip(xform, r).sort!((a, b) => binaryFun!less(a[0], b[0]), ss)();
3304     return typeof(return)(r);
3305 }
3306 
3307 /// ditto
3308 auto schwartzSort(alias transform, SwapStrategy ss, R)(R r)
3309 if (isRandomAccessRange!R && hasLength!R && hasSwappableElements!R)
3310 {
3311     return schwartzSort!(transform, "a < b", ss, R)(r);
3312 }
3313 
3314 ///
3315 @safe pure unittest
3316 {
3317     import std.algorithm.iteration : map;
3318     import std.numeric : entropy;
3319 
3320     auto lowEnt = [ 1.0, 0, 0 ],
3321          midEnt = [ 0.1, 0.1, 0.8 ],
3322         highEnt = [ 0.31, 0.29, 0.4 ];
3323     auto arr = new double[][3];
3324     arr[0] = midEnt;
3325     arr[1] = lowEnt;
3326     arr[2] = highEnt;
3327 
3328     schwartzSort!(entropy, "a > b")(arr);
3329 
3330     assert(arr[0] == highEnt);
3331     assert(arr[1] == midEnt);
3332     assert(arr[2] == lowEnt);
3333     assert(isSorted!("a > b")(map!(entropy)(arr)));
3334 }
3335 
3336 @safe pure unittest
3337 {
3338     import std.algorithm.iteration : map;
3339     import std.numeric : entropy;
3340 
3341     auto lowEnt = [ 1.0, 0, 0 ],
3342         midEnt = [ 0.1, 0.1, 0.8 ],
3343         highEnt = [ 0.31, 0.29, 0.4 ];
3344     auto arr = new double[][3];
3345     arr[0] = midEnt;
3346     arr[1] = lowEnt;
3347     arr[2] = highEnt;
3348 
3349     schwartzSort!(entropy, "a < b")(arr);
3350 
3351     assert(arr[0] == lowEnt);
3352     assert(arr[1] == midEnt);
3353     assert(arr[2] == highEnt);
3354     assert(isSorted!("a < b")(map!(entropy)(arr)));
3355 }
3356 
3357 @safe pure unittest
3358 {
3359     // binary transform function
3360     string[] strings = [ "one", "two", "three" ];
3361     schwartzSort!((element, index) => size_t.max - index)(strings);
3362     assert(strings == [ "three", "two", "one" ]);
3363 }
3364 
3365 // https://issues.dlang.org/show_bug.cgi?id=4909
3366 @safe pure unittest
3367 {
3368     import std.typecons : Tuple;
3369     Tuple!(char)[] chars;
3370     schwartzSort!"a[0]"(chars);
3371 }
3372 
3373 // https://issues.dlang.org/show_bug.cgi?id=5924
3374 @safe pure unittest
3375 {
3376     import std.typecons : Tuple;
3377     Tuple!(char)[] chars;
3378     schwartzSort!((Tuple!(char) c){ return c[0]; })(chars);
3379 }
3380 
3381 // https://issues.dlang.org/show_bug.cgi?id=13965
3382 @safe pure unittest
3383 {
3384     import std.typecons : Tuple;
3385     Tuple!(char)[] chars;
3386     schwartzSort!("a[0]", SwapStrategy.stable)(chars);
3387 }
3388 
3389 // https://issues.dlang.org/show_bug.cgi?id=13965
3390 @safe pure unittest
3391 {
3392     import std.algorithm.iteration : map;
3393     import std.numeric : entropy;
3394 
3395     auto lowEnt = [ 1.0, 0, 0 ],
3396         midEnt = [ 0.1, 0.1, 0.8 ],
3397         highEnt = [ 0.31, 0.29, 0.4 ];
3398     auto arr = new double[][3];
3399     arr[0] = midEnt;
3400     arr[1] = lowEnt;
3401     arr[2] = highEnt;
3402 
3403     schwartzSort!(entropy, SwapStrategy.stable)(arr);
3404 
3405     assert(arr[0] == lowEnt);
3406     assert(arr[1] == midEnt);
3407     assert(arr[2] == highEnt);
3408     assert(isSorted!("a < b")(map!(entropy)(arr)));
3409 }
3410 
3411 // https://issues.dlang.org/show_bug.cgi?id=20799
3412 @safe unittest
3413 {
3414     import std.range : iota, retro;
3415     import std.array : array;
3416 
3417     auto arr = 1_000_000.iota.retro.array;
3418     arr.schwartzSort!(
3419         n => new int(n),
3420         (a, b) => *a < *b
3421     );
3422     assert(arr.isSorted());
3423 }
3424 
3425 // https://issues.dlang.org/show_bug.cgi?id=21183
3426 @safe unittest
3427 {
3428     static T get(T)(int) { return T.init; }
3429 
3430     // There's no need to actually sort, just checking type interference
3431     if (false)
3432     {
3433         int[] arr;
3434 
3435         // Fine because there are no indirections
3436         arr.schwartzSort!(get!(const int));
3437 
3438         // Fine because it decays to immutable(int)*
3439         arr.schwartzSort!(get!(immutable int*));
3440 
3441         // Disallowed because it would require a non-const reference
3442         static assert(!__traits(compiles, arr.schwartzSort!(get!(const Object))));
3443 
3444         static struct Wrapper
3445         {
3446             int* ptr;
3447         }
3448 
3449         // Disallowed because Wrapper.ptr would become mutable
3450         static assert(!__traits(compiles, arr.schwartzSort!(get!(const Wrapper))));
3451     }
3452 }
3453 
3454 // partialSort
3455 /**
3456 Reorders the random-access range `r` such that the range `r[0 .. mid]`
3457 is the same as if the entire `r` were sorted, and leaves
3458 the range `r[mid .. r.length]` in no particular order.
3459 
3460 Performs $(BIGOH r.length * log(mid)) evaluations of `pred`. The
3461 implementation simply calls `topN!(less, ss)(r, n)` and then $(D
3462 sort!(less, ss)(r[0 .. n])).
3463 
3464 Params:
3465     less = The predicate to sort by.
3466     ss = The swapping strategy to use.
3467     r = The random-access range to reorder.
3468     n = The length of the initial segment of `r` to sort.
3469 */
3470 void partialSort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable,
3471     Range)(Range r, size_t n)
3472 if (isRandomAccessRange!(Range) && hasLength!(Range) && hasSlicing!(Range))
3473 {
3474     partialSort!(less, ss)(r[0 .. n], r[n .. $]);
3475 }
3476 
3477 ///
3478 @system unittest
3479 {
3480     int[] a = [ 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 ];
3481     partialSort(a, 5);
3482     assert(a[0 .. 5] == [ 0, 1, 2, 3, 4 ]);
3483 }
3484 
3485 /**
3486 Stores the smallest elements of the two ranges in the left-hand range in sorted order.
3487 
3488 Params:
3489     less = The predicate to sort by.
3490     ss = The swapping strategy to use.
3491     r1 = The first range.
3492     r2 = The second range.
3493  */
3494 
3495 void partialSort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable,
3496     Range1, Range2)(Range1 r1, Range2 r2)
3497 if (isRandomAccessRange!(Range1) && hasLength!Range1 &&
3498     isInputRange!Range2 && is(ElementType!Range1 == ElementType!Range2) &&
3499     hasLvalueElements!Range1 && hasLvalueElements!Range2)
3500 {
3501     topN!(less, ss)(r1, r2);
3502     sort!(less, ss)(r1);
3503 }
3504 ///
3505 @system unittest
3506 {
3507     int[] a = [5, 7, 2, 6, 7];
3508     int[] b = [2, 1, 5, 6, 7, 3, 0];
3509 
3510     partialSort(a, b);
3511     assert(a == [0, 1, 2, 2, 3]);
3512 }
3513 
3514 // topN
3515 /**
3516 Reorders the range `r` using $(REF_ALTTEXT swap, swap, std,algorithm,mutation)
3517 such that `r[nth]` refers to the element that would fall there if the range
3518 were fully sorted.
3519 
3520 It is akin to $(LINK2 https://en.wikipedia.org/wiki/Quickselect, Quickselect),
3521 and partitions `r` such that all elements
3522 `e1` from `r[0]` to `r[nth]` satisfy `!less(r[nth], e1)`,
3523 and all elements `e2` from `r[nth]` to `r[r.length]` satisfy
3524 `!less(e2, r[nth])`. Effectively, it finds the `nth + 1` smallest
3525 (according to `less`) elements in `r`. Performs an expected
3526 $(BIGOH r.length) (if unstable) or $(BIGOH r.length * log(r.length))
3527 (if stable) evaluations of `less` and $(REF_ALTTEXT swap, swap, std,algorithm,mutation).
3528 
3529 If `n >= r.length`, the algorithm has no effect and returns
3530 `r[0 .. r.length]`.
3531 
3532 Params:
3533     less = The predicate to sort by.
3534     ss = The swapping strategy to use.
3535     r = The random-access range to reorder.
3536     nth = The index of the element that should be in sorted position after the
3537         function is done.
3538 
3539 Returns: a slice from `r[0]` to `r[nth]`, excluding `r[nth]` itself.
3540 
3541 See_Also:
3542     $(LREF topNIndex),
3543 
3544 BUGS:
3545 
3546 Stable topN has not been implemented yet.
3547 */
3548 auto topN(alias less = "a < b",
3549         SwapStrategy ss = SwapStrategy.unstable,
3550         Range)(Range r, size_t nth)
3551 if (isRandomAccessRange!(Range) && hasLength!Range &&
3552     hasSlicing!Range && hasAssignableElements!Range)
3553 {
3554     static assert(ss == SwapStrategy.unstable,
3555             "Stable topN not yet implemented");
3556     if (nth >= r.length) return r[0 .. r.length];
3557     auto ret = r[0 .. nth];
3558     if (false)
3559     {
3560         // Workaround for https://issues.dlang.org/show_bug.cgi?id=16528
3561         // Safety checks: enumerate all potentially unsafe generic primitives
3562         // then use a @trusted implementation.
3563         cast(void) binaryFun!less(r[0], r[r.length - 1]);
3564         import std.algorithm.mutation : swapAt;
3565         r.swapAt(size_t(0), size_t(0));
3566         static assert(is(typeof(r.length) == size_t),
3567             typeof(r.length).stringof ~ " must be of type size_t");
3568         pivotPartition!less(r, 0);
3569     }
3570     bool useSampling = true;
3571     topNImpl!(binaryFun!less)(r, nth, useSampling);
3572     return ret;
3573 }
3574 
3575 ///
3576 @safe unittest
3577 {
3578     int[] v = [ 25, 7, 9, 2, 0, 5, 21 ];
3579     topN!"a < b"(v, 100);
3580     assert(v == [ 25, 7, 9, 2, 0, 5, 21 ]);
3581     auto n = 4;
3582     topN!((a, b) => a < b)(v, n);
3583     assert(v[n] == 9);
3584 }
3585 
3586 // https://issues.dlang.org/show_bug.cgi?id=8341
3587 @safe unittest
3588 {
3589     import std.algorithm.comparison : equal;
3590     import std.range : zip;
3591     import std.typecons : tuple;
3592     auto a = [10, 30, 20];
3593     auto b = ["c", "b", "a"];
3594     assert(topN!"a[0] > b[0]"(zip(a, b), 2).equal([tuple(20, "a"), tuple(30, "b")]));
3595 }
3596 
3597 private @trusted
3598 void topNImpl(alias less, R)(R r, size_t n, ref bool useSampling)
3599 {
3600     for (;;)
3601     {
3602         import std.algorithm.mutation : swapAt;
3603         assert(n < r.length);
3604         size_t pivot = void;
3605 
3606         // Decide strategy for partitioning
3607         if (n == 0)
3608         {
3609             pivot = 0;
3610             foreach (i; 1 .. r.length)
3611                 if (less(r[i], r[pivot])) pivot = i;
3612             r.swapAt(n, pivot);
3613             return;
3614         }
3615         if (n + 1 == r.length)
3616         {
3617             pivot = 0;
3618             foreach (i; 1 .. r.length)
3619                 if (less(r[pivot], r[i])) pivot = i;
3620             r.swapAt(n, pivot);
3621             return;
3622         }
3623         if (r.length <= 12)
3624         {
3625             pivot = pivotPartition!less(r, r.length / 2);
3626         }
3627         else if (n * 16 <= (r.length - 1) * 7)
3628         {
3629             pivot = topNPartitionOffMedian!(less, No.leanRight)
3630                 (r, n, useSampling);
3631             // Quality check
3632             if (useSampling)
3633             {
3634                 if (pivot < n)
3635                 {
3636                     if (pivot * 4 < r.length)
3637                     {
3638                         useSampling = false;
3639                     }
3640                 }
3641                 else if ((r.length - pivot) * 8 < r.length * 3)
3642                 {
3643                     useSampling = false;
3644                 }
3645             }
3646         }
3647         else if (n * 16 >= (r.length - 1) * 9)
3648         {
3649             pivot = topNPartitionOffMedian!(less, Yes.leanRight)
3650                 (r, n, useSampling);
3651             // Quality check
3652             if (useSampling)
3653             {
3654                 if (pivot < n)
3655                 {
3656                     if (pivot * 8 < r.length * 3)
3657                     {
3658                         useSampling = false;
3659                     }
3660                 }
3661                 else if ((r.length - pivot) * 4 < r.length)
3662                 {
3663                     useSampling = false;
3664                 }
3665             }
3666         }
3667         else
3668         {
3669             pivot = topNPartition!less(r, n, useSampling);
3670             // Quality check
3671             if (useSampling &&
3672                 (pivot * 9 < r.length * 2 || pivot * 9 > r.length * 7))
3673             {
3674                 // Failed - abort sampling going forward
3675                 useSampling = false;
3676             }
3677         }
3678 
3679         assert(pivot != size_t.max, "pivot must be not equal to size_t.max");
3680         // See how the pivot fares
3681         if (pivot == n)
3682         {
3683             return;
3684         }
3685         if (pivot > n)
3686         {
3687             r = r[0 .. pivot];
3688         }
3689         else
3690         {
3691             n -= pivot + 1;
3692             r = r[pivot + 1 .. r.length];
3693         }
3694     }
3695 }
3696 
3697 private size_t topNPartition(alias lp, R)(R r, size_t n, bool useSampling)
3698 {
3699     import std.format : format;
3700     assert(r.length >= 9 && n < r.length, "length must be longer than 8"
3701         ~ " and n must be less than r.length");
3702     immutable ninth = r.length / 9;
3703     auto pivot = ninth / 2;
3704     // Position subrange r[lo .. hi] to have length equal to ninth and its upper
3705     // median r[lo .. hi][$ / 2] in exactly the same place as the upper median
3706     // of the entire range r[$ / 2]. This is to improve behavior for searching
3707     // the median in already sorted ranges.
3708     immutable lo = r.length / 2 - pivot, hi = lo + ninth;
3709     // We have either one straggler on the left, one on the right, or none.
3710     assert(lo - (r.length - hi) <= 1 || (r.length - hi) - lo <= 1,
3711         format!"straggler check failed lo %s, r.length %s, hi %s"(lo, r.length, hi));
3712     assert(lo >= ninth * 4, format!"lo %s >= ninth * 4 %s"(lo, ninth * 4));
3713     assert(r.length - hi >= ninth * 4,
3714         format!"r.length %s - hi %s >= ninth * 4 %s"(r.length, hi, ninth * 4));
3715 
3716     // Partition in groups of 3, and the mid tertile again in groups of 3
3717     if (!useSampling)
3718         p3!lp(r, lo - ninth, hi + ninth);
3719     p3!lp(r, lo, hi);
3720 
3721     // Get the median of medians of medians
3722     // Map the full interval of n to the full interval of the ninth
3723     pivot = (n * (ninth - 1)) / (r.length - 1);
3724     topNImpl!lp(r[lo .. hi], pivot, useSampling);
3725     return expandPartition!lp(r, lo, pivot + lo, hi);
3726 }
3727 
3728 private void p3(alias less, Range)(Range r, size_t lo, immutable size_t hi)
3729 {
3730     import std.format : format;
3731     assert(lo <= hi && hi < r.length,
3732         format!"lo %s <= hi %s && hi < r.length %s"(lo, hi, r.length));
3733     immutable ln = hi - lo;
3734     for (; lo < hi; ++lo)
3735     {
3736         assert(lo >= ln, format!"lo %s >= ln %s"(lo, ln));
3737         assert(lo + ln < r.length, format!"lo %s + ln %s < r.length %s"(
3738             lo, ln, r.length));
3739         medianOf!less(r, lo - ln, lo, lo + ln);
3740     }
3741 }
3742 
3743 private void p4(alias less, Flag!"leanRight" f, Range)
3744     (Range r, size_t lo, immutable size_t hi)
3745 {
3746     import std.format : format;
3747     assert(lo <= hi && hi < r.length, format!"lo %s <= hi %s && hi < r.length %s"(
3748         lo, hi, r.length));
3749     immutable ln = hi - lo, _2ln = ln * 2;
3750     for (; lo < hi; ++lo)
3751     {
3752         assert(lo >= ln, format!"lo %s >= ln %s"(lo, ln));
3753         assert(lo + ln < r.length, format!"lo %s + ln %s < r.length %s"(
3754             lo, ln, r.length));
3755         static if (f == Yes.leanRight)
3756             medianOf!(less, f)(r, lo - _2ln, lo - ln, lo, lo + ln);
3757         else
3758             medianOf!(less, f)(r, lo - ln, lo, lo + ln, lo + _2ln);
3759     }
3760 }
3761 
3762 private size_t topNPartitionOffMedian(alias lp, Flag!"leanRight" f, R)
3763     (R r, size_t n, bool useSampling)
3764 {
3765     assert(r.length >= 12, "The length of r must be greater than 11");
3766     assert(n < r.length, "n must be less than the length of r");
3767     immutable _4 = r.length / 4;
3768     static if (f == Yes.leanRight)
3769         immutable leftLimit = 2 * _4;
3770     else
3771         immutable leftLimit = _4;
3772     // Partition in groups of 4, and the left quartile again in groups of 3
3773     if (!useSampling)
3774     {
3775         p4!(lp, f)(r, leftLimit, leftLimit + _4);
3776     }
3777     immutable _12 = _4 / 3;
3778     immutable lo = leftLimit + _12, hi = lo + _12;
3779     p3!lp(r, lo, hi);
3780 
3781     // Get the median of medians of medians
3782     // Map the full interval of n to the full interval of the ninth
3783     immutable pivot = (n * (_12 - 1)) / (r.length - 1);
3784     topNImpl!lp(r[lo .. hi], pivot, useSampling);
3785     return expandPartition!lp(r, lo, pivot + lo, hi);
3786 }
3787 
3788 /*
3789 Params:
3790 less = predicate
3791 r = range to partition
3792 pivot = pivot to partition around
3793 lo = value such that r[lo .. pivot] already less than r[pivot]
3794 hi = value such that r[pivot .. hi] already greater than r[pivot]
3795 
3796 Returns: new position of pivot
3797 */
3798 private
3799 size_t expandPartition(alias lp, R)(R r, size_t lo, size_t pivot, size_t hi)
3800 in
3801 {
3802     import std.algorithm.searching : all;
3803     assert(lo <= pivot, "lo must be less than or equal pivot");
3804     assert(pivot < hi, "pivot must be less than hi");
3805     assert(hi <= r.length, "hi must be less than or equal to the length of r");
3806     assert(r[lo .. pivot + 1].all!(x => !lp(r[pivot], x)),
3807         "r[lo .. pivot + 1] failed less than test");
3808     assert(r[pivot + 1 .. hi].all!(x => !lp(x, r[pivot])),
3809         "r[pivot + 1 .. hi] failed less than test");
3810     }
3811 out
3812 {
3813     import std.algorithm.searching : all;
3814     assert(r[0 .. pivot + 1].all!(x => !lp(r[pivot], x)),
3815         "r[0 .. pivot + 1] failed less than test");
3816     assert(r[pivot + 1 .. r.length].all!(x => !lp(x, r[pivot])),
3817         "r[pivot + 1 .. r.length] failed less than test");
3818 }
3819 do
3820 {
3821     import std.algorithm.mutation : swapAt;
3822     import std.algorithm.searching : all;
3823     // We work with closed intervals!
3824     --hi;
3825 
3826     size_t left = 0, rite = r.length - 1;
3827     loop: for (;; ++left, --rite)
3828     {
3829         for (;; ++left)
3830         {
3831             if (left == lo) break loop;
3832             if (!lp(r[left], r[pivot])) break;
3833         }
3834         for (;; --rite)
3835         {
3836             if (rite == hi) break loop;
3837             if (!lp(r[pivot], r[rite])) break;
3838         }
3839         r.swapAt(left, rite);
3840     }
3841 
3842     assert(r[lo .. pivot + 1].all!(x => !lp(r[pivot], x)),
3843         "r[lo .. pivot + 1] failed less than test");
3844     assert(r[pivot + 1 .. hi + 1].all!(x => !lp(x, r[pivot])),
3845         "r[pivot + 1 .. hi + 1] failed less than test");
3846     assert(r[0 .. left].all!(x => !lp(r[pivot], x)),
3847         "r[0 .. left] failed less than test");
3848     assert(r[rite + 1 .. r.length].all!(x => !lp(x, r[pivot])),
3849         "r[rite + 1 .. r.length] failed less than test");
3850 
3851     immutable oldPivot = pivot;
3852 
3853     if (left < lo)
3854     {
3855         // First loop: spend r[lo .. pivot]
3856         for (; lo < pivot; ++left)
3857         {
3858             if (left == lo) goto done;
3859             if (!lp(r[oldPivot], r[left])) continue;
3860             --pivot;
3861             assert(!lp(r[oldPivot], r[pivot]), "less check failed");
3862             r.swapAt(left, pivot);
3863         }
3864         // Second loop: make left and pivot meet
3865         for (;; ++left)
3866         {
3867             if (left == pivot) goto done;
3868             if (!lp(r[oldPivot], r[left])) continue;
3869             for (;;)
3870             {
3871                 if (left == pivot) goto done;
3872                 --pivot;
3873                 if (lp(r[pivot], r[oldPivot]))
3874                 {
3875                     r.swapAt(left, pivot);
3876                     break;
3877                 }
3878             }
3879         }
3880     }
3881 
3882     // First loop: spend r[lo .. pivot]
3883     for (; hi != pivot; --rite)
3884     {
3885         if (rite == hi) goto done;
3886         if (!lp(r[rite], r[oldPivot])) continue;
3887         ++pivot;
3888         assert(!lp(r[pivot], r[oldPivot]), "less check failed");
3889         r.swapAt(rite, pivot);
3890     }
3891     // Second loop: make left and pivot meet
3892     for (; rite > pivot; --rite)
3893     {
3894         if (!lp(r[rite], r[oldPivot])) continue;
3895         while (rite > pivot)
3896         {
3897             ++pivot;
3898             if (lp(r[oldPivot], r[pivot]))
3899             {
3900                 r.swapAt(rite, pivot);
3901                 break;
3902             }
3903         }
3904     }
3905 
3906 done:
3907     r.swapAt(oldPivot, pivot);
3908     return pivot;
3909 }
3910 
3911 @safe unittest
3912 {
3913     auto a = [ 10, 5, 3, 4, 8,  11,  13, 3, 9, 4, 10 ];
3914     assert(expandPartition!((a, b) => a < b)(a, 4, 5, 6) == 9);
3915 
3916     import std.algorithm.iteration : map;
3917     import std.array : array;
3918     import std.random : uniform;
3919     import std.range : iota;
3920     auto size = uniform(1, 1000);
3921     a = iota(0, size).map!(_ => uniform(0, 1000)).array;
3922     if (a.length == 0) return;
3923     expandPartition!((a, b) => a < b)(a, a.length / 2, a.length / 2,
3924         a.length / 2 + 1);
3925 }
3926 
3927 @safe unittest
3928 {
3929     import std.algorithm.comparison : max, min;
3930     import std.algorithm.iteration : reduce;
3931 
3932     int[] v = [ 7, 6, 5, 4, 3, 2, 1, 0 ];
3933     ptrdiff_t n = 3;
3934     topN!("a < b")(v, n);
3935     assert(reduce!max(v[0 .. n]) <= v[n]);
3936     assert(reduce!min(v[n + 1 .. $]) >= v[n]);
3937     //
3938     v = [3, 4, 5, 6, 7, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5];
3939     n = 3;
3940     topN(v, n);
3941     assert(reduce!max(v[0 .. n]) <= v[n]);
3942     assert(reduce!min(v[n + 1 .. $]) >= v[n]);
3943     //
3944     v = [3, 4, 5, 6, 7, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5];
3945     n = 1;
3946     topN(v, n);
3947     assert(reduce!max(v[0 .. n]) <= v[n]);
3948     assert(reduce!min(v[n + 1 .. $]) >= v[n]);
3949     //
3950     v = [3, 4, 5, 6, 7, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5];
3951     n = v.length - 1;
3952     topN(v, n);
3953     assert(v[n] == 7);
3954     //
3955     v = [3, 4, 5, 6, 7, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5];
3956     n = 0;
3957     topN(v, n);
3958     assert(v[n] == 1);
3959 
3960     double[][] v1 = [[-10, -5], [-10, -3], [-10, -5], [-10, -4],
3961             [-10, -5], [-9, -5], [-9, -3], [-9, -5],];
3962 
3963     // double[][] v1 = [ [-10, -5], [-10, -4], [-9, -5], [-9, -5],
3964     //         [-10, -5], [-10, -3], [-10, -5], [-9, -3],];
3965     double[]*[] idx = [ &v1[0], &v1[1], &v1[2], &v1[3], &v1[4], &v1[5], &v1[6],
3966             &v1[7], ];
3967 
3968     auto mid = v1.length / 2;
3969     topN!((a, b){ return (*a)[1] < (*b)[1]; })(idx, mid);
3970     foreach (e; idx[0 .. mid]) assert((*e)[1] <= (*idx[mid])[1]);
3971     foreach (e; idx[mid .. $]) assert((*e)[1] >= (*idx[mid])[1]);
3972 }
3973 
3974 @safe unittest
3975 {
3976     import std.algorithm.comparison : max, min;
3977     import std.algorithm.iteration : reduce;
3978     import std.random : Random = Xorshift, uniform;
3979 
3980     immutable uint[] seeds = [90027751, 2709791795, 1374631933, 995751648, 3541495258, 984840953];
3981     foreach (s; seeds)
3982     {
3983         auto r = Random(s);
3984 
3985         int[] a = new int[uniform(1, 10000, r)];
3986         foreach (ref e; a) e = uniform(-1000, 1000, r);
3987 
3988         auto k = uniform(0, a.length, r);
3989         topN(a, k);
3990         if (k > 0)
3991         {
3992             auto left = reduce!max(a[0 .. k]);
3993             assert(left <= a[k]);
3994         }
3995         if (k + 1 < a.length)
3996         {
3997             auto right = reduce!min(a[k + 1 .. $]);
3998             assert(right >= a[k]);
3999         }
4000     }
4001 }
4002 
4003 // https://issues.dlang.org/show_bug.cgi?id=12987
4004 @safe unittest
4005 {
4006     int[] a = [ 25, 7, 9, 2, 0, 5, 21 ];
4007     auto n = 4;
4008     auto t = topN(a, n);
4009     sort(t);
4010     assert(t == [0, 2, 5, 7]);
4011 }
4012 
4013 /**
4014 Stores the smallest elements of the two ranges in the left-hand range.
4015 
4016 Params:
4017     less = The predicate to sort by.
4018     ss = The swapping strategy to use.
4019     r1 = The first range.
4020     r2 = The second range.
4021  */
4022 auto topN(alias less = "a < b",
4023         SwapStrategy ss = SwapStrategy.unstable,
4024         Range1, Range2)(Range1 r1, Range2 r2)
4025 if (isRandomAccessRange!(Range1) && hasLength!Range1 &&
4026     isInputRange!Range2 && is(ElementType!Range1 == ElementType!Range2) &&
4027     hasLvalueElements!Range1 && hasLvalueElements!Range2)
4028 {
4029     import std.container : BinaryHeap;
4030 
4031     static assert(ss == SwapStrategy.unstable,
4032             "Stable topN not yet implemented");
4033 
4034     auto heap = BinaryHeap!(Range1, less)(r1);
4035     foreach (ref e; r2)
4036     {
4037         heap.conditionalSwap(e);
4038     }
4039 
4040     return r1;
4041 }
4042 
4043 ///
4044 @system unittest
4045 {
4046     int[] a = [ 5, 7, 2, 6, 7 ];
4047     int[] b = [ 2, 1, 5, 6, 7, 3, 0 ];
4048     topN(a, b);
4049     sort(a);
4050     assert(a == [0, 1, 2, 2, 3]);
4051 }
4052 
4053 // https://issues.dlang.org/show_bug.cgi?id=15421
4054 @system unittest
4055 {
4056     import std.algorithm.comparison : equal;
4057     import std.internal.test.dummyrange;
4058     import std.meta : AliasSeq;
4059 
4060     alias RandomRanges = AliasSeq!(
4061         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random)
4062     );
4063 
4064     alias ReferenceRanges = AliasSeq!(
4065         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Forward),
4066         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Bidirectional),
4067         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random),
4068         DummyRange!(ReturnBy.Reference, Length.No, RangeType.Forward),
4069         DummyRange!(ReturnBy.Reference, Length.No, RangeType.Bidirectional));
4070 
4071     foreach (T1; RandomRanges)
4072     {
4073         foreach (T2; ReferenceRanges)
4074         {
4075             import std.array : array;
4076 
4077             T1 A;
4078             T2 B;
4079 
4080             A.reinit();
4081             B.reinit();
4082 
4083             topN(A, B);
4084 
4085             // BUG(?): sort doesn't accept DummyRanges (needs Slicing and Length)
4086             auto a = array(A);
4087             auto b = array(B);
4088             sort(a);
4089             sort(b);
4090 
4091             assert(equal(a, [ 1, 1, 2, 2, 3, 3, 4, 4, 5, 5 ]));
4092             assert(equal(b, [ 6, 6, 7, 7, 8, 8, 9, 9, 10, 10 ]));
4093         }
4094     }
4095 }
4096 
4097 // https://issues.dlang.org/show_bug.cgi?id=15421
4098 @system unittest
4099 {
4100     auto a = [ 9, 8, 0, 3, 5, 25, 43, 4, 2, 0, 7 ];
4101     auto b = [ 9, 8, 0, 3, 5, 25, 43, 4, 2, 0, 7 ];
4102 
4103     topN(a, 4);
4104     topN(b[0 .. 4], b[4 .. $]);
4105 
4106     sort(a[0 .. 4]);
4107     sort(a[4 .. $]);
4108     sort(b[0 .. 4]);
4109     sort(b[4 .. $]);
4110 
4111     assert(a[0 .. 4] == b[0 .. 4]);
4112     assert(a[4 .. $] == b[4 .. $]);
4113     assert(a == b);
4114 }
4115 
4116 // https://issues.dlang.org/show_bug.cgi?id=12987
4117 @system unittest
4118 {
4119     int[] a = [ 5, 7, 2, 6, 7 ];
4120     int[] b = [ 2, 1, 5, 6, 7, 3, 0 ];
4121     auto t = topN(a, b);
4122     sort(t);
4123     assert(t == [ 0, 1, 2, 2, 3 ]);
4124 }
4125 
4126 // https://issues.dlang.org/show_bug.cgi?id=15420
4127 @system unittest
4128 {
4129     int[] a = [ 5, 7, 2, 6, 7 ];
4130     int[] b = [ 2, 1, 5, 6, 7, 3, 0 ];
4131     topN!"a > b"(a, b);
4132     sort!"a > b"(a);
4133     assert(a == [ 7, 7, 7, 6, 6 ]);
4134 }
4135 
4136 /**
4137 Copies the top `n` elements of the
4138 $(REF_ALTTEXT input range, isInputRange, std,range,primitives) `source` into the
4139 random-access range `target`, where `n = target.length`.
4140 
4141 Elements of `source` are not touched. If $(D
4142 sorted) is `true`, the target is sorted. Otherwise, the target
4143 respects the $(HTTP en.wikipedia.org/wiki/Binary_heap, heap property).
4144 
4145 Params:
4146     less = The predicate to sort by.
4147     source = The source range.
4148     target = The target range.
4149     sorted = Whether to sort the elements copied into `target`.
4150 
4151 Returns: The slice of `target` containing the copied elements.
4152  */
4153 TRange topNCopy(alias less = "a < b", SRange, TRange)
4154     (SRange source, TRange target, SortOutput sorted = No.sortOutput)
4155 if (isInputRange!(SRange) && isRandomAccessRange!(TRange)
4156     && hasLength!(TRange) && hasSlicing!(TRange))
4157 {
4158     import std.container : BinaryHeap;
4159 
4160     if (target.empty) return target;
4161     auto heap = BinaryHeap!(TRange, less)(target, 0);
4162     foreach (e; source) heap.conditionalInsert(e);
4163     auto result = target[0 .. heap.length];
4164     if (sorted == Yes.sortOutput)
4165     {
4166         while (!heap.empty) heap.removeFront();
4167     }
4168     return result;
4169 }
4170 
4171 ///
4172 @system unittest
4173 {
4174     import std.typecons : Yes;
4175 
4176     int[] a = [ 10, 16, 2, 3, 1, 5, 0 ];
4177     int[] b = new int[3];
4178     topNCopy(a, b, Yes.sortOutput);
4179     assert(b == [ 0, 1, 2 ]);
4180 }
4181 
4182 @system unittest
4183 {
4184     import std.random : Random = Xorshift, uniform, randomShuffle;
4185     import std.typecons : Yes;
4186 
4187     auto r = Random(123_456_789);
4188     ptrdiff_t[] a = new ptrdiff_t[uniform(1, 1000, r)];
4189     foreach (i, ref e; a) e = i;
4190     randomShuffle(a, r);
4191     auto n = uniform(0, a.length, r);
4192     ptrdiff_t[] b = new ptrdiff_t[n];
4193     topNCopy!(binaryFun!("a < b"))(a, b, Yes.sortOutput);
4194     assert(isSorted!(binaryFun!("a < b"))(b));
4195 }
4196 
4197 /**
4198 Given a range of elements, constructs an index of its top $(I n) elements
4199 (i.e., the first $(I n) elements if the range were sorted).
4200 
4201 Similar to $(LREF topN), except that the range is not modified.
4202 
4203 Params:
4204     less = A binary predicate that defines the ordering of range elements.
4205         Defaults to `a < b`.
4206     ss = $(RED (Not implemented yet.)) Specify the swapping strategy.
4207     r = A
4208         $(REF_ALTTEXT random-access range, isRandomAccessRange, std,range,primitives)
4209         of elements to make an index for.
4210     index = A
4211         $(REF_ALTTEXT random-access range, isRandomAccessRange, std,range,primitives)
4212         with assignable elements to build the index in. The length of this range
4213         determines how many top elements to index in `r`.
4214 
4215         This index range can either have integral elements, in which case the
4216         constructed index will consist of zero-based numerical indices into
4217         `r`; or it can have pointers to the element type of `r`, in which
4218         case the constructed index will be pointers to the top elements in
4219         `r`.
4220     sorted = Determines whether to sort the index by the elements they refer
4221         to.
4222 
4223 See_also: $(LREF topN), $(LREF topNCopy).
4224 
4225 BUGS:
4226 The swapping strategy parameter is not implemented yet; currently it is
4227 ignored.
4228 */
4229 void topNIndex(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable,
4230                Range, RangeIndex)
4231               (Range r, RangeIndex index, SortOutput sorted = No.sortOutput)
4232 if (isRandomAccessRange!Range &&
4233     isRandomAccessRange!RangeIndex &&
4234     hasAssignableElements!RangeIndex)
4235 {
4236     static assert(ss == SwapStrategy.unstable,
4237                   "Stable swap strategy not implemented yet.");
4238 
4239     import std.container.binaryheap : BinaryHeap;
4240     if (index.empty) return;
4241 
4242     static if (isIntegral!(ElementType!(RangeIndex)))
4243     {
4244         import std.exception : enforce;
4245 
4246         enforce(ElementType!(RangeIndex).max >= index.length,
4247                 "Index type too small");
4248         bool indirectLess(ElementType!(RangeIndex) a, ElementType!(RangeIndex) b)
4249         {
4250             return binaryFun!(less)(r[a], r[b]);
4251         }
4252         auto heap = BinaryHeap!(RangeIndex, indirectLess)(index, 0);
4253         foreach (i; 0 .. r.length)
4254         {
4255             heap.conditionalInsert(cast(ElementType!RangeIndex) i);
4256         }
4257 
4258     }
4259     else static if (is(ElementType!(RangeIndex) == ElementType!(Range)*))
4260     {
4261         static bool indirectLess(const ElementType!(RangeIndex) a,
4262                                  const ElementType!(RangeIndex) b)
4263         {
4264             return binaryFun!less(*a, *b);
4265         }
4266         auto heap = BinaryHeap!(RangeIndex, indirectLess)(index, 0);
4267         foreach (i; 0 .. r.length)
4268         {
4269             heap.conditionalInsert(&r[i]);
4270         }
4271     }
4272     else static assert(0, "Invalid ElementType");
4273 
4274     if (sorted == Yes.sortOutput)
4275     {
4276         while (!heap.empty) heap.removeFront();
4277     }
4278 }
4279 
4280 ///
4281 @system unittest
4282 {
4283     import std.typecons : Yes;
4284 
4285     // Construct index to top 3 elements using numerical indices:
4286     int[] a = [ 10, 2, 7, 5, 8, 1 ];
4287     int[] index = new int[3];
4288     topNIndex(a, index, Yes.sortOutput);
4289     assert(index == [5, 1, 3]); // because a[5]==1, a[1]==2, a[3]==5
4290 
4291     // Construct index to top 3 elements using pointer indices:
4292     int*[] ptrIndex = new int*[3];
4293     topNIndex(a, ptrIndex, Yes.sortOutput);
4294     assert(ptrIndex == [ &a[5], &a[1], &a[3] ]);
4295 }
4296 
4297 @system unittest
4298 {
4299     import std.conv : text;
4300 
4301     {
4302         int[] a = [ 10, 8, 9, 2, 4, 6, 7, 1, 3, 5 ];
4303         int*[] b = new int*[5];
4304         topNIndex!("a > b")(a, b, Yes.sortOutput);
4305         assert(b == [ &a[0], &a[2], &a[1], &a[6], &a[5]]);
4306     }
4307     {
4308         int[] a = [ 10, 8, 9, 2, 4, 6, 7, 1, 3, 5 ];
4309         auto b = new ubyte[5];
4310         topNIndex!("a > b")(a, b, Yes.sortOutput);
4311         assert(b == [ cast(ubyte) 0, cast(ubyte) 2, cast(ubyte) 1, cast(ubyte) 6, cast(ubyte) 5], text(b));
4312     }
4313 }
4314 
4315 // medianOf
4316 /*
4317 Private for the time being.
4318 
4319 Computes the median of 2 to 5 arbitrary indexes in random-access range `r`
4320 using hand-written specialized algorithms. The indexes must be distinct (if not,
4321 behavior is implementation-defined). The function also partitions the elements
4322 involved around the median, e.g. `medianOf(r, a, b, c)` not only fills `r[b]`
4323 with the median of `r[a]`, `r[b]`, and `r[c]`, but also puts the minimum in
4324 `r[a]` and the maximum in `r[c]`.
4325 
4326 Params:
4327 less = The comparison predicate used, modeled as a
4328     $(LINK2 https://en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings, strict weak ordering)
4329     (irreflexive, antisymmetric, transitive, and implying a transitive equivalence).
4330 flag = Used only for even values of `T.length`. If `No.leanRight`, the median
4331 "leans left", meaning `medianOf(r, a, b, c, d)` puts the lower median of the
4332 four in `r[b]`, the minimum in `r[a]`, and the two others in `r[c]` and `r[d]`.
4333 Conversely, `median!("a < b", Yes.leanRight)(r, a, b, c, d)` puts the upper
4334 median of the four in `r[c]`, the maximum in `r[d]`, and the two others in
4335 `r[a]` and `r[b]`.
4336 r = The range containing the indexes.
4337 i = Two to five indexes inside `r`.
4338 */
4339 private void medianOf(
4340         alias less = "a < b",
4341         Flag!"leanRight" flag = No.leanRight,
4342         Range,
4343         Indexes...)
4344     (Range r, Indexes i)
4345 if (isRandomAccessRange!Range && hasLength!Range &&
4346     Indexes.length >= 2 && Indexes.length <= 5 &&
4347     allSatisfy!(isUnsigned, Indexes))
4348 {
4349     assert(r.length >= Indexes.length, "r.length must be greater than or"
4350         ~ " equal to Indexes.length");
4351     import std.functional : binaryFun;
4352     alias lt = binaryFun!less;
4353     enum k = Indexes.length;
4354     import std.algorithm.mutation : swapAt;
4355     import std.format : format;
4356 
4357     alias a = i[0];
4358     static assert(is(typeof(a) == size_t), typeof(a).stringof ~ " must be"
4359         ~ " of type size_t");
4360     static if (k >= 2)
4361     {
4362         alias b = i[1];
4363         static assert(is(typeof(b) == size_t), typeof(b).stringof ~ " must be"
4364         ~ " of type size_t");
4365         assert(a != b, "a != b ");
4366     }
4367     static if (k >= 3)
4368     {
4369         alias c = i[2];
4370         static assert(is(typeof(c) == size_t), typeof(c).stringof ~ " must be"
4371         ~ " of type size_t");
4372         assert(a != c && b != c, "a != c && b != c");
4373     }
4374     static if (k >= 4)
4375     {
4376         alias d = i[3];
4377         static assert(is(typeof(d) == size_t), typeof(d).stringof ~ " must be"
4378         ~ " of type size_t");
4379         assert(a != d && b != d && c != d, "a != d && b != d && c != d failed");
4380     }
4381     static if (k >= 5)
4382     {
4383         alias e = i[4];
4384         static assert(is(typeof(e) == size_t), typeof(e).stringof ~ " must be"
4385         ~ " of type size_t");
4386         assert(a != e && b != e && c != e && d != e,
4387             "a != e && b != e && c != e && d != e failed");
4388     }
4389 
4390     static if (k == 2)
4391     {
4392         if (lt(r[b], r[a])) r.swapAt(a, b);
4393     }
4394     else static if (k == 3)
4395     {
4396         if (lt(r[c], r[a])) // c < a
4397         {
4398             if (lt(r[a], r[b])) // c < a < b
4399             {
4400                 r.swapAt(a, b);
4401                 r.swapAt(a, c);
4402             }
4403             else // c < a, b <= a
4404             {
4405                 r.swapAt(a, c);
4406                 if (lt(r[b], r[a])) r.swapAt(a, b);
4407             }
4408         }
4409         else // a <= c
4410         {
4411             if (lt(r[b], r[a])) // b < a <= c
4412             {
4413                 r.swapAt(a, b);
4414             }
4415             else // a <= c, a <= b
4416             {
4417                 if (lt(r[c], r[b])) r.swapAt(b, c);
4418             }
4419         }
4420         assert(!lt(r[b], r[a]), "less than check failed");
4421         assert(!lt(r[c], r[b]), "less than check failed");
4422     }
4423     else static if (k == 4)
4424     {
4425         static if (flag == No.leanRight)
4426         {
4427             // Eliminate the rightmost from the competition
4428             if (lt(r[d], r[c])) r.swapAt(c, d); // c <= d
4429             if (lt(r[d], r[b])) r.swapAt(b, d); // b <= d
4430             medianOf!lt(r, a, b, c);
4431         }
4432         else
4433         {
4434             // Eliminate the leftmost from the competition
4435             if (lt(r[b], r[a])) r.swapAt(a, b); // a <= b
4436             if (lt(r[c], r[a])) r.swapAt(a, c); // a <= c
4437             medianOf!lt(r, b, c, d);
4438         }
4439     }
4440     else static if (k == 5)
4441     {
4442         // Credit: Teppo Niinimäki
4443         version (StdUnittest) scope(success)
4444         {
4445             assert(!lt(r[c], r[a]), "less than check failed");
4446             assert(!lt(r[c], r[b]), "less than check failed");
4447             assert(!lt(r[d], r[c]), "less than check failed");
4448             assert(!lt(r[e], r[c]), "less than check failed");
4449         }
4450 
4451         if (lt(r[c], r[a])) r.swapAt(a, c);
4452         if (lt(r[d], r[b])) r.swapAt(b, d);
4453         if (lt(r[d], r[c]))
4454         {
4455             r.swapAt(c, d);
4456             r.swapAt(a, b);
4457         }
4458         if (lt(r[e], r[b])) r.swapAt(b, e);
4459         if (lt(r[e], r[c]))
4460         {
4461             r.swapAt(c, e);
4462             if (lt(r[c], r[a])) r.swapAt(a, c);
4463         }
4464         else
4465         {
4466             if (lt(r[c], r[b])) r.swapAt(b, c);
4467         }
4468     }
4469 }
4470 
4471 @safe unittest
4472 {
4473     // Verify medianOf for all permutations of [1, 2, 2, 3, 4].
4474     int[5] data = [1, 2, 2, 3, 4];
4475     do
4476     {
4477         int[5] a = data;
4478         medianOf(a[], size_t(0), size_t(1));
4479         assert(a[0] <= a[1]);
4480 
4481         a[] = data[];
4482         medianOf(a[], size_t(0), size_t(1), size_t(2));
4483         assert(ordered(a[0], a[1], a[2]));
4484 
4485         a[] = data[];
4486         medianOf(a[], size_t(0), size_t(1), size_t(2), size_t(3));
4487         assert(a[0] <= a[1] && a[1] <= a[2] && a[1] <= a[3]);
4488 
4489         a[] = data[];
4490         medianOf!("a < b", Yes.leanRight)(a[], size_t(0), size_t(1),
4491             size_t(2), size_t(3));
4492         assert(a[0] <= a[2] && a[1] <= a[2] && a[2] <= a[3]);
4493 
4494         a[] = data[];
4495         medianOf(a[], size_t(0), size_t(1), size_t(2), size_t(3), size_t(4));
4496         assert(a[0] <= a[2] && a[1] <= a[2] && a[2] <= a[3] && a[2] <= a[4]);
4497     }
4498     while (nextPermutation(data[]));
4499 }
4500 
4501 // nextPermutation
4502 /**
4503  * Permutes `range` in-place to the next lexicographically greater
4504  * permutation.
4505  *
4506  * The predicate `less` defines the lexicographical ordering to be used on
4507  * the range.
4508  *
4509  * If the range is currently the lexicographically greatest permutation, it is
4510  * permuted back to the least permutation and false is returned.  Otherwise,
4511  * true is returned. One can thus generate all permutations of a range by
4512  * sorting it according to `less`, which produces the lexicographically
4513  * least permutation, and then calling nextPermutation until it returns false.
4514  * This is guaranteed to generate all distinct permutations of the range
4515  * exactly once.  If there are $(I N) elements in the range and all of them are
4516  * unique, then $(I N)! permutations will be generated. Otherwise, if there are
4517  * some duplicated elements, fewer permutations will be produced.
4518 ----
4519 // Enumerate all permutations
4520 int[] a = [1,2,3,4,5];
4521 do
4522 {
4523     // use the current permutation and
4524     // proceed to the next permutation of the array.
4525 } while (nextPermutation(a));
4526 ----
4527  * Params:
4528  *  less = The ordering to be used to determine lexicographical ordering of the
4529  *      permutations.
4530  *  range = The range to permute.
4531  *
4532  * Returns: false if the range was lexicographically the greatest, in which
4533  * case the range is reversed back to the lexicographically smallest
4534  * permutation; otherwise returns true.
4535  * See_Also:
4536  * $(REF permutations, std,algorithm,iteration).
4537  */
4538 bool nextPermutation(alias less="a < b", BidirectionalRange)
4539                     (BidirectionalRange range)
4540 if (isBidirectionalRange!BidirectionalRange &&
4541     hasSwappableElements!BidirectionalRange)
4542 {
4543     import std.algorithm.mutation : reverse, swap;
4544     import std.algorithm.searching : find;
4545     import std.range : retro, takeExactly;
4546     // Ranges of 0 or 1 element have no distinct permutations.
4547     if (range.empty) return false;
4548 
4549     auto i = retro(range);
4550     auto last = i.save;
4551 
4552     // Find last occurring increasing pair of elements
4553     size_t n = 1;
4554     for (i.popFront(); !i.empty; i.popFront(), last.popFront(), n++)
4555     {
4556         if (binaryFun!less(i.front, last.front))
4557             break;
4558     }
4559 
4560     if (i.empty)
4561     {
4562         // Entire range is decreasing: it's lexicographically the greatest. So
4563         // wrap it around.
4564         range.reverse();
4565         return false;
4566     }
4567 
4568     // Find last element greater than i.front.
4569     auto j = find!((a) => binaryFun!less(i.front, a))(
4570                    takeExactly(retro(range), n));
4571 
4572     assert(!j.empty, "j must not be empty");   // shouldn't happen since i.front < last.front
4573     swap(i.front, j.front);
4574     reverse(takeExactly(retro(range), n));
4575 
4576     return true;
4577 }
4578 
4579 ///
4580 @safe unittest
4581 {
4582     // Step through all permutations of a sorted array in lexicographic order
4583     int[] a = [1,2,3];
4584     assert(nextPermutation(a) == true);
4585     assert(a == [1,3,2]);
4586     assert(nextPermutation(a) == true);
4587     assert(a == [2,1,3]);
4588     assert(nextPermutation(a) == true);
4589     assert(a == [2,3,1]);
4590     assert(nextPermutation(a) == true);
4591     assert(a == [3,1,2]);
4592     assert(nextPermutation(a) == true);
4593     assert(a == [3,2,1]);
4594     assert(nextPermutation(a) == false);
4595     assert(a == [1,2,3]);
4596 }
4597 
4598 ///
4599 @safe unittest
4600 {
4601     // Step through permutations of an array containing duplicate elements:
4602     int[] a = [1,1,2];
4603     assert(nextPermutation(a) == true);
4604     assert(a == [1,2,1]);
4605     assert(nextPermutation(a) == true);
4606     assert(a == [2,1,1]);
4607     assert(nextPermutation(a) == false);
4608     assert(a == [1,1,2]);
4609 }
4610 
4611 @safe unittest
4612 {
4613     // Boundary cases: arrays of 0 or 1 element.
4614     int[] a1 = [];
4615     assert(!nextPermutation(a1));
4616     assert(a1 == []);
4617 
4618     int[] a2 = [1];
4619     assert(!nextPermutation(a2));
4620     assert(a2 == [1]);
4621 }
4622 
4623 @safe unittest
4624 {
4625     import std.algorithm.comparison : equal;
4626 
4627     auto a1 = [1, 2, 3, 4];
4628 
4629     assert(nextPermutation(a1));
4630     assert(equal(a1, [1, 2, 4, 3]));
4631 
4632     assert(nextPermutation(a1));
4633     assert(equal(a1, [1, 3, 2, 4]));
4634 
4635     assert(nextPermutation(a1));
4636     assert(equal(a1, [1, 3, 4, 2]));
4637 
4638     assert(nextPermutation(a1));
4639     assert(equal(a1, [1, 4, 2, 3]));
4640 
4641     assert(nextPermutation(a1));
4642     assert(equal(a1, [1, 4, 3, 2]));
4643 
4644     assert(nextPermutation(a1));
4645     assert(equal(a1, [2, 1, 3, 4]));
4646 
4647     assert(nextPermutation(a1));
4648     assert(equal(a1, [2, 1, 4, 3]));
4649 
4650     assert(nextPermutation(a1));
4651     assert(equal(a1, [2, 3, 1, 4]));
4652 
4653     assert(nextPermutation(a1));
4654     assert(equal(a1, [2, 3, 4, 1]));
4655 
4656     assert(nextPermutation(a1));
4657     assert(equal(a1, [2, 4, 1, 3]));
4658 
4659     assert(nextPermutation(a1));
4660     assert(equal(a1, [2, 4, 3, 1]));
4661 
4662     assert(nextPermutation(a1));
4663     assert(equal(a1, [3, 1, 2, 4]));
4664 
4665     assert(nextPermutation(a1));
4666     assert(equal(a1, [3, 1, 4, 2]));
4667 
4668     assert(nextPermutation(a1));
4669     assert(equal(a1, [3, 2, 1, 4]));
4670 
4671     assert(nextPermutation(a1));
4672     assert(equal(a1, [3, 2, 4, 1]));
4673 
4674     assert(nextPermutation(a1));
4675     assert(equal(a1, [3, 4, 1, 2]));
4676 
4677     assert(nextPermutation(a1));
4678     assert(equal(a1, [3, 4, 2, 1]));
4679 
4680     assert(nextPermutation(a1));
4681     assert(equal(a1, [4, 1, 2, 3]));
4682 
4683     assert(nextPermutation(a1));
4684     assert(equal(a1, [4, 1, 3, 2]));
4685 
4686     assert(nextPermutation(a1));
4687     assert(equal(a1, [4, 2, 1, 3]));
4688 
4689     assert(nextPermutation(a1));
4690     assert(equal(a1, [4, 2, 3, 1]));
4691 
4692     assert(nextPermutation(a1));
4693     assert(equal(a1, [4, 3, 1, 2]));
4694 
4695     assert(nextPermutation(a1));
4696     assert(equal(a1, [4, 3, 2, 1]));
4697 
4698     assert(!nextPermutation(a1));
4699     assert(equal(a1, [1, 2, 3, 4]));
4700 }
4701 
4702 @safe unittest
4703 {
4704     // Test with non-default sorting order
4705     int[] a = [3,2,1];
4706     assert(nextPermutation!"a > b"(a) == true);
4707     assert(a == [3,1,2]);
4708     assert(nextPermutation!"a > b"(a) == true);
4709     assert(a == [2,3,1]);
4710     assert(nextPermutation!"a > b"(a) == true);
4711     assert(a == [2,1,3]);
4712     assert(nextPermutation!"a > b"(a) == true);
4713     assert(a == [1,3,2]);
4714     assert(nextPermutation!"a > b"(a) == true);
4715     assert(a == [1,2,3]);
4716     assert(nextPermutation!"a > b"(a) == false);
4717     assert(a == [3,2,1]);
4718 }
4719 
4720 // https://issues.dlang.org/show_bug.cgi?id=13594
4721 @safe unittest
4722 {
4723     int[3] a = [1,2,3];
4724     assert(nextPermutation(a[]));
4725     assert(a == [1,3,2]);
4726 }
4727 
4728 // nextEvenPermutation
4729 /**
4730  * Permutes `range` in-place to the next lexicographically greater $(I even)
4731  * permutation.
4732  *
4733  * The predicate `less` defines the lexicographical ordering to be used on
4734  * the range.
4735  *
4736  * An even permutation is one which is produced by swapping an even number of
4737  * pairs of elements in the original range. The set of $(I even) permutations
4738  * is distinct from the set of $(I all) permutations only when there are no
4739  * duplicate elements in the range. If the range has $(I N) unique elements,
4740  * then there are exactly $(I N)!/2 even permutations.
4741  *
4742  * If the range is already the lexicographically greatest even permutation, it
4743  * is permuted back to the least even permutation and false is returned.
4744  * Otherwise, true is returned, and the range is modified in-place to be the
4745  * lexicographically next even permutation.
4746  *
4747  * One can thus generate the even permutations of a range with unique elements
4748  * by starting with the lexicographically smallest permutation, and repeatedly
4749  * calling nextEvenPermutation until it returns false.
4750 ----
4751 // Enumerate even permutations
4752 int[] a = [1,2,3,4,5];
4753 do
4754 {
4755     // use the current permutation and
4756     // proceed to the next even permutation of the array.
4757 } while (nextEvenPermutation(a));
4758 ----
4759  * One can also generate the $(I odd) permutations of a range by noting that
4760  * permutations obey the rule that even + even = even, and odd + even = odd.
4761  * Thus, by swapping the last two elements of a lexicographically least range,
4762  * it is turned into the first odd permutation. Then calling
4763  * nextEvenPermutation on this first odd permutation will generate the next
4764  * even permutation relative to this odd permutation, which is actually the
4765  * next odd permutation of the original range. Thus, by repeatedly calling
4766  * nextEvenPermutation until it returns false, one enumerates the odd
4767  * permutations of the original range.
4768 ----
4769 // Enumerate odd permutations
4770 int[] a = [1,2,3,4,5];
4771 swap(a[$-2], a[$-1]);    // a is now the first odd permutation of [1,2,3,4,5]
4772 do
4773 {
4774     // use the current permutation and
4775     // proceed to the next odd permutation of the original array
4776     // (which is an even permutation of the first odd permutation).
4777 } while (nextEvenPermutation(a));
4778 ----
4779  *
4780  * Warning: Since even permutations are only distinct from all permutations
4781  * when the range elements are unique, this function assumes that there are no
4782  * duplicate elements under the specified ordering. If this is not _true, some
4783  * permutations may fail to be generated. When the range has non-unique
4784  * elements, you should use $(MYREF nextPermutation) instead.
4785  *
4786  * Params:
4787  *  less = The ordering to be used to determine lexicographical ordering of the
4788  *      permutations.
4789  *  range = The range to permute.
4790  *
4791  * Returns: false if the range was lexicographically the greatest, in which
4792  * case the range is reversed back to the lexicographically smallest
4793  * permutation; otherwise returns true.
4794  */
4795 bool nextEvenPermutation(alias less="a < b", BidirectionalRange)
4796                         (BidirectionalRange range)
4797 if (isBidirectionalRange!BidirectionalRange &&
4798     hasSwappableElements!BidirectionalRange)
4799 {
4800     import std.algorithm.mutation : reverse, swap;
4801     import std.algorithm.searching : find;
4802     import std.range : retro, takeExactly;
4803     // Ranges of 0 or 1 element have no distinct permutations.
4804     if (range.empty) return false;
4805 
4806     bool oddParity = false;
4807     bool ret = true;
4808     do
4809     {
4810         auto i = retro(range);
4811         auto last = i.save;
4812 
4813         // Find last occurring increasing pair of elements
4814         size_t n = 1;
4815         for (i.popFront(); !i.empty;
4816             i.popFront(), last.popFront(), n++)
4817         {
4818             if (binaryFun!less(i.front, last.front))
4819                 break;
4820         }
4821 
4822         if (!i.empty)
4823         {
4824             // Find last element greater than i.front.
4825             auto j = find!((a) => binaryFun!less(i.front, a))(
4826                            takeExactly(retro(range), n));
4827 
4828             // shouldn't happen since i.front < last.front
4829             assert(!j.empty, "j must not be empty");
4830 
4831             swap(i.front, j.front);
4832             oddParity = !oddParity;
4833         }
4834         else
4835         {
4836             // Entire range is decreasing: it's lexicographically
4837             // the greatest.
4838             ret = false;
4839         }
4840 
4841         reverse(takeExactly(retro(range), n));
4842         if ((n / 2) % 2 == 1)
4843             oddParity = !oddParity;
4844     } while (oddParity);
4845 
4846     return ret;
4847 }
4848 
4849 ///
4850 @safe unittest
4851 {
4852     // Step through even permutations of a sorted array in lexicographic order
4853     int[] a = [1,2,3];
4854     assert(nextEvenPermutation(a) == true);
4855     assert(a == [2,3,1]);
4856     assert(nextEvenPermutation(a) == true);
4857     assert(a == [3,1,2]);
4858     assert(nextEvenPermutation(a) == false);
4859     assert(a == [1,2,3]);
4860 }
4861 
4862 @safe unittest
4863 {
4864     auto a3 = [ 1, 2, 3, 4 ];
4865     int count = 1;
4866     while (nextEvenPermutation(a3)) count++;
4867     assert(count == 12);
4868 }
4869 
4870 @safe unittest
4871 {
4872     // Test with non-default sorting order
4873     auto a = [ 3, 2, 1 ];
4874 
4875     assert(nextEvenPermutation!"a > b"(a) == true);
4876     assert(a == [ 2, 1, 3 ]);
4877     assert(nextEvenPermutation!"a > b"(a) == true);
4878     assert(a == [ 1, 3, 2 ]);
4879     assert(nextEvenPermutation!"a > b"(a) == false);
4880     assert(a == [ 3, 2, 1 ]);
4881 }
4882 
4883 @safe unittest
4884 {
4885     // Test various cases of rollover
4886     auto a = [ 3, 1, 2 ];
4887     assert(nextEvenPermutation(a) == false);
4888     assert(a == [ 1, 2, 3 ]);
4889 
4890     auto b = [ 3, 2, 1 ];
4891     assert(nextEvenPermutation(b) == false);
4892     assert(b == [ 1, 3, 2 ]);
4893 }
4894 
4895 // https://issues.dlang.org/show_bug.cgi?id=13594
4896 @safe unittest
4897 {
4898     int[3] a = [1,2,3];
4899     assert(nextEvenPermutation(a[]));
4900     assert(a == [2,3,1]);
4901 }
4902 
4903 /**
4904 Even permutations are useful for generating coordinates of certain geometric
4905 shapes. Here's a non-trivial example:
4906 */
4907 @safe unittest
4908 {
4909     import std.math.algebraic : sqrt;
4910 
4911     // Print the 60 vertices of a uniform truncated icosahedron (soccer ball)
4912     enum real Phi = (1.0 + sqrt(5.0)) / 2.0;    // Golden ratio
4913     real[][] seeds = [
4914         [0.0, 1.0, 3.0*Phi],
4915         [1.0, 2.0+Phi, 2.0*Phi],
4916         [Phi, 2.0, Phi^^3]
4917     ];
4918     size_t n;
4919     foreach (seed; seeds)
4920     {
4921         // Loop over even permutations of each seed
4922         do
4923         {
4924             // Loop over all sign changes of each permutation
4925             size_t i;
4926             do
4927             {
4928                 // Generate all possible sign changes
4929                 for (i=0; i < seed.length; i++)
4930                 {
4931                     if (seed[i] != 0.0)
4932                     {
4933                         seed[i] = -seed[i];
4934                         if (seed[i] < 0.0)
4935                             break;
4936                     }
4937                 }
4938                 n++;
4939             } while (i < seed.length);
4940         } while (nextEvenPermutation(seed));
4941     }
4942     assert(n == 60);
4943 }
4944 
4945 /**
4946 Permutes `range` into the `perm` permutation.
4947 
4948 The algorithm has a constant runtime complexity with respect to the number of
4949 permutations created.
4950 Due to the number of unique values of `ulong` only the first 21 elements of
4951 `range` can be permuted. The rest of the range will therefore not be
4952 permuted.
4953 This algorithm uses the $(HTTP en.wikipedia.org/wiki/Lehmer_code, Lehmer
4954 Code).
4955 
4956 The algorithm works as follows:
4957 $(D_CODE
4958     auto pem = [4,0,4,1,0,0,0]; // permutation 2982 in factorial
4959     auto src = [0,1,2,3,4,5,6]; // the range to permutate
4960 
4961     auto i = 0;                    // range index
4962     // range index iterates pem and src in sync
4963     // pem[i] + i is used as index into src
4964     // first src[pem[i] + i] is stored in t
4965     auto t = 4;                    // tmp value
4966     src = [0,1,2,3,n,5,6];
4967 
4968     // then the values between i and pem[i] + i are moved one
4969     // to the right
4970     src = [n,0,1,2,3,5,6];
4971     // at last t is inserted into position i
4972     src = [4,0,1,2,3,5,6];
4973     // finally i is incremented
4974     ++i;
4975 
4976     // this process is repeated while i < pem.length
4977 
4978     t = 0;
4979     src = [4,n,1,2,3,5,6];
4980     src = [4,0,1,2,3,5,6];
4981     ++i;
4982     t = 6;
4983     src = [4,0,1,2,3,5,n];
4984     src = [4,0,n,1,2,3,5];
4985     src = [4,0,6,1,2,3,5];
4986 )
4987 
4988 Returns:
4989     The permuted range.
4990 
4991 Params:
4992     range = The Range to permute. The original ordering will be lost.
4993     perm = The permutation to permutate `range` to.
4994 */
4995 auto ref Range nthPermutation(Range)
4996                              (auto ref Range range, const ulong perm)
4997 if (isRandomAccessRange!Range && hasLength!Range)
4998 {
4999     if (!nthPermutationImpl(range, perm))
5000     {
5001         throw new Exception(
5002             "The range to permutate must not have less"
5003             ~ " elements than the factorial number has digits");
5004     }
5005 
5006     return range;
5007 }
5008 
5009 ///
5010 pure @safe unittest
5011 {
5012     auto src = [0, 1, 2, 3, 4, 5, 6];
5013     auto rslt = [4, 0, 6, 2, 1, 3, 5];
5014 
5015     src = nthPermutation(src, 2982);
5016     assert(src == rslt);
5017 }
5018 
5019 /**
5020 Returns: `true` in case the permutation worked, `false` in case `perm` had
5021     more digits in the factorial number system than range had elements.
5022     This case must not occur as this would lead to out of range accesses.
5023 */
5024 bool nthPermutationImpl(Range)
5025                        (auto ref Range range, ulong perm)
5026 if (isRandomAccessRange!Range && hasLength!Range)
5027 {
5028     import std.range.primitives : ElementType;
5029     import std.numeric : decimalToFactorial;
5030 
5031     // ulong.max has 21 digits in the factorial number system
5032     ubyte[21] fac;
5033     size_t idx = decimalToFactorial(perm, fac);
5034 
5035     if (idx > range.length)
5036     {
5037         return false;
5038     }
5039 
5040     ElementType!Range tmp;
5041     size_t i = 0;
5042 
5043     for (; i < idx; ++i)
5044     {
5045         size_t re = fac[i];
5046         tmp = range[re + i];
5047         for (size_t j = re + i; j > i; --j)
5048         {
5049             range[j] = range[j - 1];
5050         }
5051         range[i] = tmp;
5052     }
5053 
5054     return true;
5055 }
5056 
5057 ///
5058 pure @safe unittest
5059 {
5060     auto src = [0, 1, 2, 3, 4, 5, 6];
5061     auto rslt = [4, 0, 6, 2, 1, 3, 5];
5062 
5063     bool worked = nthPermutationImpl(src, 2982);
5064     assert(worked);
5065     assert(src == rslt);
5066 }
5067 
5068 pure @safe unittest
5069 {
5070     auto rslt = [4, 0, 6, 2, 1, 3, 5];
5071 
5072     auto src = nthPermutation([0, 1, 2, 3, 4, 5, 6], 2982);
5073     assert(src == rslt);
5074 }
5075 
5076 pure @safe unittest
5077 {
5078     auto src = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
5079     auto rslt = [4, 0, 6, 2, 1, 3, 5, 7, 8, 9, 10];
5080 
5081     src = nthPermutation(src, 2982);
5082     assert(src == rslt);
5083 }
5084 
5085 pure @safe unittest
5086 {
5087     import std.exception : assertThrown;
5088 
5089     auto src = [0, 1, 2, 3];
5090 
5091     assertThrown(nthPermutation(src, 2982));
5092 }
5093 
5094 pure @safe unittest
5095 {
5096     import std.internal.test.dummyrange;
5097     import std.meta : AliasSeq;
5098 
5099     auto src = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
5100     auto rsl = [4, 0, 6, 2, 1, 3, 5, 7, 8, 9, 10];
5101 
5102     foreach (T; AliasSeq!(
5103             DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random, int[]),
5104             DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random, int[])))
5105     {
5106         static assert(isRandomAccessRange!(T));
5107         static assert(hasLength!(T));
5108         auto dr = T(src.dup);
5109         dr = nthPermutation(dr, 2982);
5110 
5111         int idx;
5112         foreach (it; dr)
5113         {
5114             assert(it == rsl[idx++]);
5115         }
5116     }
5117 }