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                 if (__ctfe) temp.length = newSize;
2629                 else temp = () @trusted { return uninitializedArray!(T[])(newSize); }();
2630             }
2631             else
2632             {
2633                 temp = () @trusted { return uninitializedArray!(T[])(newSize); }();
2634             }
2635         }
2636         return temp;
2637     }
2638 
2639     // Merge front to back. Returns new value of minGallop.
2640     // temp must be large enough to store range[0 .. mid]
2641     size_t mergeLo()(R range, immutable size_t mid, size_t minGallop, T[] temp)
2642     out
2643     {
2644         if (!__ctfe) assert(isSorted!pred(range), "the range must be sorted");
2645     }
2646     do
2647     {
2648         import std.algorithm.mutation : copy;
2649 
2650         assert(mid <= range.length, "mid must be less than the length of the"
2651             ~ " range");
2652         assert(temp.length >= mid, "temp.length must be greater or equal to mid");
2653 
2654         // Copy run into temporary memory
2655         temp = temp[0 .. mid];
2656         copy(range[0 .. mid], temp);
2657 
2658         // Move first element into place
2659         moveEntry(range, mid, range, 0);
2660 
2661         size_t i = 1, lef = 0, rig = mid + 1;
2662         size_t count_lef, count_rig;
2663         immutable lef_end = temp.length - 1;
2664 
2665         if (lef < lef_end && rig < range.length)
2666         outer: while (true)
2667         {
2668             count_lef = 0;
2669             count_rig = 0;
2670 
2671             // Linear merge
2672             while ((count_lef | count_rig) < minGallop)
2673             {
2674                 if (lessEqual(temp[lef], range[rig]))
2675                 {
2676                     moveEntry(temp, lef++, range, i++);
2677                     if (lef >= lef_end) break outer;
2678                     ++count_lef;
2679                     count_rig = 0;
2680                 }
2681                 else
2682                 {
2683                     moveEntry(range, rig++, range, i++);
2684                     if (rig >= range.length) break outer;
2685                     count_lef = 0;
2686                     ++count_rig;
2687                 }
2688             }
2689 
2690             // Gallop merge
2691             do
2692             {
2693                 count_lef = gallopForwardUpper(temp[lef .. $], range[rig]);
2694                 foreach (j; 0 .. count_lef) moveEntry(temp, lef++, range, i++);
2695                 if (lef >= temp.length) break outer;
2696 
2697                 count_rig = gallopForwardLower(range[rig .. range.length], temp[lef]);
2698                 foreach (j; 0 .. count_rig) moveEntry(range, rig++, range, i++);
2699                 if (rig >= range.length) while (true)
2700                 {
2701                     moveEntry(temp, lef++, range, i++);
2702                     if (lef >= temp.length) break outer;
2703                 }
2704 
2705                 if (minGallop > 0) --minGallop;
2706             }
2707             while (count_lef >= minimalGallop || count_rig >= minimalGallop);
2708 
2709             minGallop += 2;
2710         }
2711 
2712         // Move remaining elements from right
2713         while (rig < range.length)
2714             moveEntry(range, rig++, range, i++);
2715 
2716         // Move remaining elements from left
2717         while (lef < temp.length)
2718             moveEntry(temp, lef++, range, i++);
2719 
2720         return minGallop > 0 ? minGallop : 1;
2721     }
2722 
2723     // Merge back to front. Returns new value of minGallop.
2724     // temp must be large enough to store range[mid .. range.length]
2725     size_t mergeHi()(R range, immutable size_t mid, size_t minGallop, T[] temp)
2726     out
2727     {
2728         if (!__ctfe) assert(isSorted!pred(range), "the range must be sorted");
2729     }
2730     do
2731     {
2732         import std.algorithm.mutation : copy;
2733         import std.format : format;
2734 
2735         assert(mid <= range.length, "mid must be less or equal to range.length");
2736         assert(temp.length >= range.length - mid, format!
2737             "temp.length %s >= range.length %s - mid %s"(temp.length,
2738             range.length, mid));
2739 
2740         // Copy run into temporary memory
2741         temp = temp[0 .. range.length - mid];
2742         copy(range[mid .. range.length], temp);
2743 
2744         // Move first element into place
2745         moveEntry(range, mid - 1, range, range.length - 1);
2746 
2747         size_t i = range.length - 2, lef = mid - 2, rig = temp.length - 1;
2748         size_t count_lef, count_rig;
2749 
2750         outer:
2751         while (true)
2752         {
2753             count_lef = 0;
2754             count_rig = 0;
2755 
2756             // Linear merge
2757             while ((count_lef | count_rig) < minGallop)
2758             {
2759                 if (greaterEqual(temp[rig], range[lef]))
2760                 {
2761                     moveEntry(temp, rig, range, i--);
2762                     if (rig == 1)
2763                     {
2764                         // Move remaining elements from left
2765                         while (true)
2766                         {
2767                             moveEntry(range, lef, range, i--);
2768                             if (lef == 0) break;
2769                             --lef;
2770                         }
2771 
2772                         // Move last element into place
2773                         moveEntry(temp, 0, range, i);
2774 
2775                         break outer;
2776                     }
2777                     --rig;
2778                     count_lef = 0;
2779                     ++count_rig;
2780                 }
2781                 else
2782                 {
2783                     moveEntry(range, lef, range, i--);
2784                     if (lef == 0) while (true)
2785                     {
2786                         moveEntry(temp, rig, range, i--);
2787                         if (rig == 0) break outer;
2788                         --rig;
2789                     }
2790                     --lef;
2791                     ++count_lef;
2792                     count_rig = 0;
2793                 }
2794             }
2795 
2796             // Gallop merge
2797             do
2798             {
2799                 count_rig = rig - gallopReverseLower(temp[0 .. rig], range[lef]);
2800                 foreach (j; 0 .. count_rig)
2801                 {
2802                     moveEntry(temp, rig, range, i--);
2803                     if (rig == 0) break outer;
2804                     --rig;
2805                 }
2806 
2807                 count_lef = lef - gallopReverseUpper(range[0 .. lef], temp[rig]);
2808                 foreach (j; 0 .. count_lef)
2809                 {
2810                     moveEntry(range, lef, range, i--);
2811                     if (lef == 0) while (true)
2812                     {
2813                         moveEntry(temp, rig, range, i--);
2814                         if (rig == 0) break outer;
2815                         --rig;
2816                     }
2817                     --lef;
2818                 }
2819 
2820                 if (minGallop > 0) --minGallop;
2821             }
2822             while (count_lef >= minimalGallop || count_rig >= minimalGallop);
2823 
2824             minGallop += 2;
2825         }
2826 
2827         return minGallop > 0 ? minGallop : 1;
2828     }
2829 
2830     // false = forward / lower, true = reverse / upper
2831     template gallopSearch(bool forwardReverse, bool lowerUpper)
2832     {
2833         // Gallop search on range according to attributes forwardReverse and lowerUpper
2834         size_t gallopSearch(R)(R range, T value)
2835         out(ret)
2836         {
2837             assert(ret <= range.length, "ret must be less or equal to"
2838                 ~ " range.length");
2839         }
2840         do
2841         {
2842             size_t lower = 0, center = 1, upper = range.length;
2843             alias gap = center;
2844 
2845             static if (forwardReverse)
2846             {
2847                 static if (!lowerUpper) alias comp = lessEqual; // reverse lower
2848                 static if (lowerUpper)  alias comp = less;      // reverse upper
2849 
2850                 // Gallop Search Reverse
2851                 while (gap <= upper)
2852                 {
2853                     if (comp(value, range[upper - gap]))
2854                     {
2855                         upper -= gap;
2856                         gap *= 2;
2857                     }
2858                     else
2859                     {
2860                         lower = upper - gap;
2861                         break;
2862                     }
2863                 }
2864 
2865                 // Binary Search Reverse
2866                 while (upper != lower)
2867                 {
2868                     center = lower + (upper - lower) / 2;
2869                     if (comp(value, range[center])) upper = center;
2870                     else lower = center + 1;
2871                 }
2872             }
2873             else
2874             {
2875                 static if (!lowerUpper) alias comp = greater;      // forward lower
2876                 static if (lowerUpper)  alias comp = greaterEqual; // forward upper
2877 
2878                 // Gallop Search Forward
2879                 while (lower + gap < upper)
2880                 {
2881                     if (comp(value, range[lower + gap]))
2882                     {
2883                         lower += gap;
2884                         gap *= 2;
2885                     }
2886                     else
2887                     {
2888                         upper = lower + gap;
2889                         break;
2890                     }
2891                 }
2892 
2893                 // Binary Search Forward
2894                 while (lower != upper)
2895                 {
2896                     center = lower + (upper - lower) / 2;
2897                     if (comp(value, range[center])) lower = center + 1;
2898                     else upper = center;
2899                 }
2900             }
2901 
2902             return lower;
2903         }
2904     }
2905 
2906     alias gallopForwardLower = gallopSearch!(false, false);
2907     alias gallopForwardUpper = gallopSearch!(false,  true);
2908     alias gallopReverseLower = gallopSearch!( true, false);
2909     alias gallopReverseUpper = gallopSearch!( true,  true);
2910 
2911     /// Helper method that moves from[fIdx] into to[tIdx] if both are lvalues and
2912     /// uses a plain assignment if not (necessary for backwards compatibility)
2913     void moveEntry(X, Y)(ref X from, const size_t fIdx, ref Y to, const size_t tIdx)
2914     {
2915         // This template is instantiated with different combinations of range (R) and temp (T[]).
2916         // T[] obviously has lvalue-elements, so checking R should be enough here
2917         static if (hasLvalueElements!R)
2918         {
2919             import core.lifetime : move;
2920             move(from[fIdx], to[tIdx]);
2921         }
2922         else
2923             to[tIdx] = from[fIdx];
2924     }
2925 }
2926 
2927 @safe unittest
2928 {
2929     import std.random : Random, uniform, randomShuffle;
2930 
2931     // Element type with two fields
2932     static struct E
2933     {
2934         size_t value, index;
2935     }
2936 
2937     // Generates data especially for testing sorting with Timsort
2938     static E[] genSampleData(uint seed) @safe
2939     {
2940         import std.algorithm.mutation : swap, swapRanges;
2941 
2942         auto rnd = Random(seed);
2943 
2944         E[] arr;
2945         arr.length = 64 * 64;
2946 
2947         // We want duplicate values for testing stability
2948         foreach (i, ref v; arr) v.value = i / 64;
2949 
2950         // Swap ranges at random middle point (test large merge operation)
2951         immutable mid = uniform(arr.length / 4, arr.length / 4 * 3, rnd);
2952         swapRanges(arr[0 .. mid], arr[mid .. $]);
2953 
2954         // Shuffle last 1/8 of the array (test insertion sort and linear merge)
2955         randomShuffle(arr[$ / 8 * 7 .. $], rnd);
2956 
2957         // Swap few random elements (test galloping mode)
2958         foreach (i; 0 .. arr.length / 64)
2959         {
2960             immutable a = uniform(0, arr.length, rnd), b = uniform(0, arr.length, rnd);
2961             swap(arr[a], arr[b]);
2962         }
2963 
2964         // Now that our test array is prepped, store original index value
2965         // This will allow us to confirm the array was sorted stably
2966         foreach (i, ref v; arr) v.index = i;
2967 
2968         return arr;
2969     }
2970 
2971     // Tests the Timsort function for correctness and stability
2972     static bool testSort(uint seed)
2973     {
2974         import std.format : format;
2975         auto arr = genSampleData(seed);
2976 
2977         // Now sort the array!
2978         static bool comp(E a, E b)
2979         {
2980             return a.value < b.value;
2981         }
2982 
2983         sort!(comp, SwapStrategy.stable)(arr);
2984 
2985         // Test that the array was sorted correctly
2986         assert(isSorted!comp(arr), "arr must be sorted");
2987 
2988         // Test that the array was sorted stably
2989         foreach (i; 0 .. arr.length - 1)
2990         {
2991             if (arr[i].value == arr[i + 1].value)
2992                 assert(arr[i].index < arr[i + 1].index, format!
2993                     "arr[i %s].index %s < arr[i + 1].index %s"(
2994                     i, arr[i].index, arr[i + 1].index));
2995         }
2996 
2997         return true;
2998     }
2999 
3000     enum seed = 310614065;
3001     testSort(seed);
3002 
3003     enum result = testSort(seed);
3004     assert(result == true, "invalid result");
3005 }
3006 
3007 // https://issues.dlang.org/show_bug.cgi?id=4584
3008 @safe unittest
3009 {
3010     assert(isSorted!"a < b"(sort!("a < b", SwapStrategy.stable)(
3011        [83, 42, 85, 86, 87, 22, 89, 30, 91, 46, 93, 94, 95, 6,
3012          97, 14, 33, 10, 101, 102, 103, 26, 105, 106, 107, 6]
3013     )));
3014 
3015 }
3016 
3017 @safe unittest
3018 {
3019     //test stable sort + zip
3020     import std.range;
3021     auto x = [10, 50, 60, 60, 20];
3022     dchar[] y = "abcde"d.dup;
3023 
3024     sort!("a[0] < b[0]", SwapStrategy.stable)(zip(x, y));
3025     assert(x == [10, 20, 50, 60, 60]);
3026     assert(y == "aebcd"d);
3027 }
3028 
3029 // https://issues.dlang.org/show_bug.cgi?id=14223
3030 @safe unittest
3031 {
3032     import std.array, std.range;
3033     auto arr = chain(iota(0, 384), iota(0, 256), iota(0, 80), iota(0, 64), iota(0, 96)).array;
3034     sort!("a < b", SwapStrategy.stable)(arr);
3035 }
3036 
3037 @safe unittest
3038 {
3039     static struct NoCopy
3040     {
3041         pure nothrow @nogc @safe:
3042 
3043         int key;
3044         this(scope const ref NoCopy)
3045         {
3046             assert(false, "Tried to copy struct!");
3047         }
3048         ref opAssign()(scope const auto ref NoCopy other)
3049         {
3050             assert(false, "Tried to copy struct!");
3051         }
3052         this(this) {}
3053     }
3054 
3055     static NoCopy[] makeArray(const size_t size)
3056     {
3057         NoCopy[] array = new NoCopy[](size);
3058         foreach (const i, ref t; array[0..$/2]) t.key = cast(int) (size - i);
3059         foreach (const i, ref t; array[$/2..$]) t.key = cast(int) i;
3060         return array;
3061     }
3062 
3063     alias cmp = (ref NoCopy a, ref NoCopy b) => a.key < b.key;
3064     enum minMerge = TimSortImpl!(cmp, NoCopy[]).minimalMerge;
3065 
3066     sort!(cmp, SwapStrategy.unstable)(makeArray(20));
3067     sort!(cmp, SwapStrategy.stable)(makeArray(minMerge - 5));
3068     sort!(cmp, SwapStrategy.stable)(makeArray(minMerge + 5));
3069 }
3070 
3071 // https://issues.dlang.org/show_bug.cgi?id=23668
3072 @safe unittest
3073 {
3074     static struct S
3075     {
3076         int opCmp(const S) const { return 1; }
3077         @disable this();
3078     }
3079     S[] array;
3080     array.sort!("a < b", SwapStrategy.stable);
3081 }
3082 
3083 // https://issues.dlang.org/show_bug.cgi?id=24773
3084 @safe unittest
3085 {
3086     static struct S
3087     {
3088         int i = 42;
3089         ~this() { assert(i == 42); }
3090     }
3091 
3092     auto array = new S[](400);
3093     array.sort!((a, b) => false, SwapStrategy.stable);
3094 }
3095 
3096 
3097 // schwartzSort
3098 /**
3099 Alternative sorting method that should be used when comparing keys involves an
3100 expensive computation.
3101 
3102 Instead of using `less(a, b)` for comparing elements,
3103 `schwartzSort` uses `less(transform(a), transform(b))`. The values of the
3104 `transform` function are precomputed in a temporary array, thus saving on
3105 repeatedly computing it. Conversely, if the cost of `transform` is small
3106 compared to the cost of allocating and filling the precomputed array, `sort`
3107 may be faster and therefore preferable.
3108 
3109 This approach to sorting is akin to the $(HTTP
3110 wikipedia.org/wiki/Schwartzian_transform, Schwartzian transform), also known as
3111 the decorate-sort-undecorate pattern in Python and Lisp. The complexity is the
3112 same as that of the corresponding `sort`, but `schwartzSort` evaluates
3113 `transform` only `r.length` times (less than half when compared to regular
3114 sorting). The usage can be best illustrated with an example.
3115 
3116 Example:
3117 ----
3118 uint hashFun(string) { ... expensive computation ... }
3119 string[] array = ...;
3120 // Sort strings by hash, slow
3121 sort!((a, b) => hashFun(a) < hashFun(b))(array);
3122 // Sort strings by hash, fast (only computes arr.length hashes):
3123 schwartzSort!(hashFun, "a < b")(array);
3124 ----
3125 
3126 The `schwartzSort` function might require less temporary data and
3127 be faster than the Perl idiom or the decorate-sort-undecorate idiom
3128 present in Python and Lisp. This is because sorting is done in-place
3129 and only minimal extra data (one array of transformed elements) is
3130 created.
3131 
3132 To check whether an array was sorted and benefit of the speedup of
3133 Schwartz sorting, a function `schwartzIsSorted` is not provided
3134 because the effect can be achieved by calling $(D
3135 isSorted!less(map!transform(r))).
3136 
3137 Params:
3138     transform = The transformation to apply. Either a unary function
3139                 (`unaryFun!transform(element)`), or a binary function
3140                 (`binaryFun!transform(element, index)`).
3141     less = The predicate to sort the transformed elements by.
3142     ss = The swapping strategy to use.
3143     r = The range to sort.
3144 
3145 Returns: The initial range wrapped as a `SortedRange` with the
3146 predicate `(a, b) => binaryFun!less(transform(a), transform(b))`.
3147  */
3148 SortedRange!(R, ((a, b) => binaryFun!less(unaryFun!transform(a),
3149                                           unaryFun!transform(b))))
3150 schwartzSort(alias transform, alias less = "a < b",
3151         SwapStrategy ss = SwapStrategy.unstable, R)(R r)
3152 if (isRandomAccessRange!R && hasLength!R && hasSwappableElements!R &&
3153     !is(typeof(binaryFun!less) == SwapStrategy))
3154 {
3155     import core.lifetime : emplace;
3156     import std.range : zip, SortedRange;
3157     import std.string : representation;
3158 
3159     static if (is(typeof(unaryFun!transform(r.front))))
3160     {
3161         alias transformFun = unaryFun!transform;
3162         alias TB = typeof(transformFun(r.front));
3163         enum isBinary = false;
3164     }
3165     else static if (is(typeof(binaryFun!transform(r.front, 0))))
3166     {
3167         alias transformFun = binaryFun!transform;
3168         alias TB = typeof(transformFun(r.front, 0));
3169         enum isBinary = true;
3170     }
3171     else
3172         static assert(false, "unsupported `transform` alias");
3173 
3174     // The `transform` function might return a qualified type, e.g. const(int).
3175     // Strip qualifiers if possible s.t. the temporary array is sortable.
3176     static if (is(TB : Unqual!TB))
3177         alias T = Unqual!TB;
3178     else
3179         static assert(false, "`transform` returns an unsortable qualified type: " ~ TB.stringof);
3180 
3181     static trustedMalloc()(size_t len) @trusted
3182     {
3183         import core.checkedint : mulu;
3184         import core.memory : pureMalloc;
3185         bool overflow;
3186         const nbytes = mulu(len, T.sizeof, overflow);
3187         if (overflow) assert(false, "multiplication overflowed");
3188         T[] result = (cast(T*) pureMalloc(nbytes))[0 .. len];
3189         static if (hasIndirections!T)
3190         {
3191             import core.memory : GC;
3192             GC.addRange(result.ptr, nbytes);
3193         }
3194         return result;
3195     }
3196     auto xform1 = trustedMalloc(r.length);
3197 
3198     size_t length;
3199     scope(exit)
3200     {
3201         static if (hasElaborateDestructor!T)
3202         {
3203             foreach (i; 0 .. length) collectException(destroy(xform1[i]));
3204         }
3205         static void trustedFree()(T[] p) @trusted
3206         {
3207             import core.memory : pureFree;
3208             static if (hasIndirections!T)
3209             {
3210                 import core.memory : GC;
3211                 GC.removeRange(p.ptr);
3212             }
3213             pureFree(p.ptr);
3214         }
3215         trustedFree(xform1);
3216     }
3217     for (; length != r.length; ++length)
3218     {
3219         static if (isBinary)
3220             emplace(&xform1[length], transformFun(r[length], length));
3221         else
3222             emplace(&xform1[length], transformFun(r[length]));
3223     }
3224     // Make sure we use ubyte[] and ushort[], not char[] and wchar[]
3225     // for the intermediate array, lest zip gets confused.
3226     static if (isNarrowString!(typeof(xform1)))
3227     {
3228         auto xform = xform1.representation();
3229     }
3230     else
3231     {
3232         alias xform = xform1;
3233     }
3234     zip(xform, r).sort!((a, b) => binaryFun!less(a[0], b[0]), ss)();
3235     return typeof(return)(r);
3236 }
3237 
3238 /// ditto
3239 auto schwartzSort(alias transform, SwapStrategy ss, R)(R r)
3240 if (isRandomAccessRange!R && hasLength!R && hasSwappableElements!R)
3241 {
3242     return schwartzSort!(transform, "a < b", ss, R)(r);
3243 }
3244 
3245 ///
3246 @safe pure unittest
3247 {
3248     import std.algorithm.iteration : map;
3249     import std.numeric : entropy;
3250 
3251     auto lowEnt = [ 1.0, 0, 0 ],
3252          midEnt = [ 0.1, 0.1, 0.8 ],
3253         highEnt = [ 0.31, 0.29, 0.4 ];
3254     auto arr = new double[][3];
3255     arr[0] = midEnt;
3256     arr[1] = lowEnt;
3257     arr[2] = highEnt;
3258 
3259     schwartzSort!(entropy, "a > b")(arr);
3260 
3261     assert(arr[0] == highEnt);
3262     assert(arr[1] == midEnt);
3263     assert(arr[2] == lowEnt);
3264     assert(isSorted!("a > b")(map!(entropy)(arr)));
3265 }
3266 
3267 @safe pure unittest
3268 {
3269     import std.algorithm.iteration : map;
3270     import std.numeric : entropy;
3271 
3272     auto lowEnt = [ 1.0, 0, 0 ],
3273         midEnt = [ 0.1, 0.1, 0.8 ],
3274         highEnt = [ 0.31, 0.29, 0.4 ];
3275     auto arr = new double[][3];
3276     arr[0] = midEnt;
3277     arr[1] = lowEnt;
3278     arr[2] = highEnt;
3279 
3280     schwartzSort!(entropy, "a < b")(arr);
3281 
3282     assert(arr[0] == lowEnt);
3283     assert(arr[1] == midEnt);
3284     assert(arr[2] == highEnt);
3285     assert(isSorted!("a < b")(map!(entropy)(arr)));
3286 }
3287 
3288 @safe pure unittest
3289 {
3290     // binary transform function
3291     string[] strings = [ "one", "two", "three" ];
3292     schwartzSort!((element, index) => size_t.max - index)(strings);
3293     assert(strings == [ "three", "two", "one" ]);
3294 }
3295 
3296 // https://issues.dlang.org/show_bug.cgi?id=4909
3297 @safe pure unittest
3298 {
3299     import std.typecons : Tuple;
3300     Tuple!(char)[] chars;
3301     schwartzSort!"a[0]"(chars);
3302 }
3303 
3304 // https://issues.dlang.org/show_bug.cgi?id=5924
3305 @safe pure unittest
3306 {
3307     import std.typecons : Tuple;
3308     Tuple!(char)[] chars;
3309     schwartzSort!((Tuple!(char) c){ return c[0]; })(chars);
3310 }
3311 
3312 // https://issues.dlang.org/show_bug.cgi?id=13965
3313 @safe pure unittest
3314 {
3315     import std.typecons : Tuple;
3316     Tuple!(char)[] chars;
3317     schwartzSort!("a[0]", SwapStrategy.stable)(chars);
3318 }
3319 
3320 // https://issues.dlang.org/show_bug.cgi?id=13965
3321 @safe pure unittest
3322 {
3323     import std.algorithm.iteration : map;
3324     import std.numeric : entropy;
3325 
3326     auto lowEnt = [ 1.0, 0, 0 ],
3327         midEnt = [ 0.1, 0.1, 0.8 ],
3328         highEnt = [ 0.31, 0.29, 0.4 ];
3329     auto arr = new double[][3];
3330     arr[0] = midEnt;
3331     arr[1] = lowEnt;
3332     arr[2] = highEnt;
3333 
3334     schwartzSort!(entropy, SwapStrategy.stable)(arr);
3335 
3336     assert(arr[0] == lowEnt);
3337     assert(arr[1] == midEnt);
3338     assert(arr[2] == highEnt);
3339     assert(isSorted!("a < b")(map!(entropy)(arr)));
3340 }
3341 
3342 // https://issues.dlang.org/show_bug.cgi?id=20799
3343 @safe unittest
3344 {
3345     import std.range : iota, retro;
3346     import std.array : array;
3347 
3348     auto arr = 1_000_000.iota.retro.array;
3349     arr.schwartzSort!(
3350         n => new int(n),
3351         (a, b) => *a < *b
3352     );
3353     assert(arr.isSorted());
3354 }
3355 
3356 // https://issues.dlang.org/show_bug.cgi?id=21183
3357 @safe unittest
3358 {
3359     static T get(T)(int) { return T.init; }
3360 
3361     // There's no need to actually sort, just checking type interference
3362     if (false)
3363     {
3364         int[] arr;
3365 
3366         // Fine because there are no indirections
3367         arr.schwartzSort!(get!(const int));
3368 
3369         // Fine because it decays to immutable(int)*
3370         arr.schwartzSort!(get!(immutable int*));
3371 
3372         // Disallowed because it would require a non-const reference
3373         static assert(!__traits(compiles, arr.schwartzSort!(get!(const Object))));
3374 
3375         static struct Wrapper
3376         {
3377             int* ptr;
3378         }
3379 
3380         // Disallowed because Wrapper.ptr would become mutable
3381         static assert(!__traits(compiles, arr.schwartzSort!(get!(const Wrapper))));
3382     }
3383 }
3384 
3385 // partialSort
3386 /**
3387 Reorders the random-access range `r` such that the range `r[0 .. mid]`
3388 is the same as if the entire `r` were sorted, and leaves
3389 the range `r[mid .. r.length]` in no particular order.
3390 
3391 Performs $(BIGOH r.length * log(mid)) evaluations of `pred`. The
3392 implementation simply calls `topN!(less, ss)(r, n)` and then $(D
3393 sort!(less, ss)(r[0 .. n])).
3394 
3395 Params:
3396     less = The predicate to sort by.
3397     ss = The swapping strategy to use.
3398     r = The random-access range to reorder.
3399     n = The length of the initial segment of `r` to sort.
3400 */
3401 void partialSort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable,
3402     Range)(Range r, size_t n)
3403 if (isRandomAccessRange!(Range) && hasLength!(Range) && hasSlicing!(Range))
3404 {
3405     partialSort!(less, ss)(r[0 .. n], r[n .. $]);
3406 }
3407 
3408 ///
3409 @system unittest
3410 {
3411     int[] a = [ 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 ];
3412     partialSort(a, 5);
3413     assert(a[0 .. 5] == [ 0, 1, 2, 3, 4 ]);
3414 }
3415 
3416 /**
3417 Stores the smallest elements of the two ranges in the left-hand range in sorted order.
3418 
3419 Params:
3420     less = The predicate to sort by.
3421     ss = The swapping strategy to use.
3422     r1 = The first range.
3423     r2 = The second range.
3424  */
3425 
3426 void partialSort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable,
3427     Range1, Range2)(Range1 r1, Range2 r2)
3428 if (isRandomAccessRange!(Range1) && hasLength!Range1 &&
3429     isInputRange!Range2 && is(ElementType!Range1 == ElementType!Range2) &&
3430     hasLvalueElements!Range1 && hasLvalueElements!Range2)
3431 {
3432     topN!(less, ss)(r1, r2);
3433     sort!(less, ss)(r1);
3434 }
3435 ///
3436 @system unittest
3437 {
3438     int[] a = [5, 7, 2, 6, 7];
3439     int[] b = [2, 1, 5, 6, 7, 3, 0];
3440 
3441     partialSort(a, b);
3442     assert(a == [0, 1, 2, 2, 3]);
3443 }
3444 
3445 // topN
3446 /**
3447 Reorders the range `r` using $(REF_ALTTEXT swap, swap, std,algorithm,mutation)
3448 such that `r[nth]` refers to the element that would fall there if the range
3449 were fully sorted.
3450 
3451 It is akin to $(LINK2 https://en.wikipedia.org/wiki/Quickselect, Quickselect),
3452 and partitions `r` such that all elements
3453 `e1` from `r[0]` to `r[nth]` satisfy `!less(r[nth], e1)`,
3454 and all elements `e2` from `r[nth]` to `r[r.length]` satisfy
3455 `!less(e2, r[nth])`. Effectively, it finds the `nth + 1` smallest
3456 (according to `less`) elements in `r`. Performs an expected
3457 $(BIGOH r.length) (if unstable) or $(BIGOH r.length * log(r.length))
3458 (if stable) evaluations of `less` and $(REF_ALTTEXT swap, swap, std,algorithm,mutation).
3459 
3460 If `n >= r.length`, the algorithm has no effect and returns
3461 `r[0 .. r.length]`.
3462 
3463 Params:
3464     less = The predicate to sort by.
3465     ss = The swapping strategy to use.
3466     r = The random-access range to reorder.
3467     nth = The index of the element that should be in sorted position after the
3468         function is done.
3469 
3470 Returns: a slice from `r[0]` to `r[nth]`, excluding `r[nth]` itself.
3471 
3472 See_Also:
3473     $(LREF topNIndex),
3474 
3475 BUGS:
3476 
3477 Stable topN has not been implemented yet.
3478 */
3479 auto topN(alias less = "a < b",
3480         SwapStrategy ss = SwapStrategy.unstable,
3481         Range)(Range r, size_t nth)
3482 if (isRandomAccessRange!(Range) && hasLength!Range &&
3483     hasSlicing!Range && hasAssignableElements!Range)
3484 {
3485     static assert(ss == SwapStrategy.unstable,
3486             "Stable topN not yet implemented");
3487     if (nth >= r.length) return r[0 .. r.length];
3488     auto ret = r[0 .. nth];
3489     if (false)
3490     {
3491         // Workaround for https://issues.dlang.org/show_bug.cgi?id=16528
3492         // Safety checks: enumerate all potentially unsafe generic primitives
3493         // then use a @trusted implementation.
3494         cast(void) binaryFun!less(r[0], r[r.length - 1]);
3495         import std.algorithm.mutation : swapAt;
3496         r.swapAt(size_t(0), size_t(0));
3497         static assert(is(typeof(r.length) == size_t),
3498             typeof(r.length).stringof ~ " must be of type size_t");
3499         pivotPartition!less(r, 0);
3500     }
3501     bool useSampling = true;
3502     topNImpl!(binaryFun!less)(r, nth, useSampling);
3503     return ret;
3504 }
3505 
3506 ///
3507 @safe unittest
3508 {
3509     int[] v = [ 25, 7, 9, 2, 0, 5, 21 ];
3510     topN!"a < b"(v, 100);
3511     assert(v == [ 25, 7, 9, 2, 0, 5, 21 ]);
3512     auto n = 4;
3513     topN!((a, b) => a < b)(v, n);
3514     assert(v[n] == 9);
3515 }
3516 
3517 // https://issues.dlang.org/show_bug.cgi?id=8341
3518 @safe unittest
3519 {
3520     import std.algorithm.comparison : equal;
3521     import std.range : zip;
3522     import std.typecons : tuple;
3523     auto a = [10, 30, 20];
3524     auto b = ["c", "b", "a"];
3525     assert(topN!"a[0] > b[0]"(zip(a, b), 2).equal([tuple(20, "a"), tuple(30, "b")]));
3526 }
3527 
3528 private @trusted
3529 void topNImpl(alias less, R)(R r, size_t n, ref bool useSampling)
3530 {
3531     for (;;)
3532     {
3533         import std.algorithm.mutation : swapAt;
3534         assert(n < r.length);
3535         size_t pivot = void;
3536 
3537         // Decide strategy for partitioning
3538         if (n == 0)
3539         {
3540             pivot = 0;
3541             foreach (i; 1 .. r.length)
3542                 if (less(r[i], r[pivot])) pivot = i;
3543             r.swapAt(n, pivot);
3544             return;
3545         }
3546         if (n + 1 == r.length)
3547         {
3548             pivot = 0;
3549             foreach (i; 1 .. r.length)
3550                 if (less(r[pivot], r[i])) pivot = i;
3551             r.swapAt(n, pivot);
3552             return;
3553         }
3554         if (r.length <= 12)
3555         {
3556             pivot = pivotPartition!less(r, r.length / 2);
3557         }
3558         else if (n * 16 <= (r.length - 1) * 7)
3559         {
3560             pivot = topNPartitionOffMedian!(less, No.leanRight)
3561                 (r, n, useSampling);
3562             // Quality check
3563             if (useSampling)
3564             {
3565                 if (pivot < n)
3566                 {
3567                     if (pivot * 4 < r.length)
3568                     {
3569                         useSampling = false;
3570                     }
3571                 }
3572                 else if ((r.length - pivot) * 8 < r.length * 3)
3573                 {
3574                     useSampling = false;
3575                 }
3576             }
3577         }
3578         else if (n * 16 >= (r.length - 1) * 9)
3579         {
3580             pivot = topNPartitionOffMedian!(less, Yes.leanRight)
3581                 (r, n, useSampling);
3582             // Quality check
3583             if (useSampling)
3584             {
3585                 if (pivot < n)
3586                 {
3587                     if (pivot * 8 < r.length * 3)
3588                     {
3589                         useSampling = false;
3590                     }
3591                 }
3592                 else if ((r.length - pivot) * 4 < r.length)
3593                 {
3594                     useSampling = false;
3595                 }
3596             }
3597         }
3598         else
3599         {
3600             pivot = topNPartition!less(r, n, useSampling);
3601             // Quality check
3602             if (useSampling &&
3603                 (pivot * 9 < r.length * 2 || pivot * 9 > r.length * 7))
3604             {
3605                 // Failed - abort sampling going forward
3606                 useSampling = false;
3607             }
3608         }
3609 
3610         assert(pivot != size_t.max, "pivot must be not equal to size_t.max");
3611         // See how the pivot fares
3612         if (pivot == n)
3613         {
3614             return;
3615         }
3616         if (pivot > n)
3617         {
3618             r = r[0 .. pivot];
3619         }
3620         else
3621         {
3622             n -= pivot + 1;
3623             r = r[pivot + 1 .. r.length];
3624         }
3625     }
3626 }
3627 
3628 private size_t topNPartition(alias lp, R)(R r, size_t n, bool useSampling)
3629 {
3630     import std.format : format;
3631     assert(r.length >= 9 && n < r.length, "length must be longer than 8"
3632         ~ " and n must be less than r.length");
3633     immutable ninth = r.length / 9;
3634     auto pivot = ninth / 2;
3635     // Position subrange r[lo .. hi] to have length equal to ninth and its upper
3636     // median r[lo .. hi][$ / 2] in exactly the same place as the upper median
3637     // of the entire range r[$ / 2]. This is to improve behavior for searching
3638     // the median in already sorted ranges.
3639     immutable lo = r.length / 2 - pivot, hi = lo + ninth;
3640     // We have either one straggler on the left, one on the right, or none.
3641     assert(lo - (r.length - hi) <= 1 || (r.length - hi) - lo <= 1,
3642         format!"straggler check failed lo %s, r.length %s, hi %s"(lo, r.length, hi));
3643     assert(lo >= ninth * 4, format!"lo %s >= ninth * 4 %s"(lo, ninth * 4));
3644     assert(r.length - hi >= ninth * 4,
3645         format!"r.length %s - hi %s >= ninth * 4 %s"(r.length, hi, ninth * 4));
3646 
3647     // Partition in groups of 3, and the mid tertile again in groups of 3
3648     if (!useSampling)
3649         p3!lp(r, lo - ninth, hi + ninth);
3650     p3!lp(r, lo, hi);
3651 
3652     // Get the median of medians of medians
3653     // Map the full interval of n to the full interval of the ninth
3654     pivot = (n * (ninth - 1)) / (r.length - 1);
3655     topNImpl!lp(r[lo .. hi], pivot, useSampling);
3656     return expandPartition!lp(r, lo, pivot + lo, hi);
3657 }
3658 
3659 private void p3(alias less, Range)(Range r, size_t lo, immutable size_t hi)
3660 {
3661     import std.format : format;
3662     assert(lo <= hi && hi < r.length,
3663         format!"lo %s <= hi %s && hi < r.length %s"(lo, hi, r.length));
3664     immutable ln = hi - lo;
3665     for (; lo < hi; ++lo)
3666     {
3667         assert(lo >= ln, format!"lo %s >= ln %s"(lo, ln));
3668         assert(lo + ln < r.length, format!"lo %s + ln %s < r.length %s"(
3669             lo, ln, r.length));
3670         medianOf!less(r, lo - ln, lo, lo + ln);
3671     }
3672 }
3673 
3674 private void p4(alias less, Flag!"leanRight" f, Range)
3675     (Range r, size_t lo, immutable size_t hi)
3676 {
3677     import std.format : format;
3678     assert(lo <= hi && hi < r.length, format!"lo %s <= hi %s && hi < r.length %s"(
3679         lo, hi, r.length));
3680     immutable ln = hi - lo, _2ln = ln * 2;
3681     for (; lo < hi; ++lo)
3682     {
3683         assert(lo >= ln, format!"lo %s >= ln %s"(lo, ln));
3684         assert(lo + ln < r.length, format!"lo %s + ln %s < r.length %s"(
3685             lo, ln, r.length));
3686         static if (f == Yes.leanRight)
3687             medianOf!(less, f)(r, lo - _2ln, lo - ln, lo, lo + ln);
3688         else
3689             medianOf!(less, f)(r, lo - ln, lo, lo + ln, lo + _2ln);
3690     }
3691 }
3692 
3693 private size_t topNPartitionOffMedian(alias lp, Flag!"leanRight" f, R)
3694     (R r, size_t n, bool useSampling)
3695 {
3696     assert(r.length >= 12, "The length of r must be greater than 11");
3697     assert(n < r.length, "n must be less than the length of r");
3698     immutable _4 = r.length / 4;
3699     static if (f == Yes.leanRight)
3700         immutable leftLimit = 2 * _4;
3701     else
3702         immutable leftLimit = _4;
3703     // Partition in groups of 4, and the left quartile again in groups of 3
3704     if (!useSampling)
3705     {
3706         p4!(lp, f)(r, leftLimit, leftLimit + _4);
3707     }
3708     immutable _12 = _4 / 3;
3709     immutable lo = leftLimit + _12, hi = lo + _12;
3710     p3!lp(r, lo, hi);
3711 
3712     // Get the median of medians of medians
3713     // Map the full interval of n to the full interval of the ninth
3714     immutable pivot = (n * (_12 - 1)) / (r.length - 1);
3715     topNImpl!lp(r[lo .. hi], pivot, useSampling);
3716     return expandPartition!lp(r, lo, pivot + lo, hi);
3717 }
3718 
3719 /*
3720 Params:
3721 less = predicate
3722 r = range to partition
3723 pivot = pivot to partition around
3724 lo = value such that r[lo .. pivot] already less than r[pivot]
3725 hi = value such that r[pivot .. hi] already greater than r[pivot]
3726 
3727 Returns: new position of pivot
3728 */
3729 private
3730 size_t expandPartition(alias lp, R)(R r, size_t lo, size_t pivot, size_t hi)
3731 in
3732 {
3733     import std.algorithm.searching : all;
3734     assert(lo <= pivot, "lo must be less than or equal pivot");
3735     assert(pivot < hi, "pivot must be less than hi");
3736     assert(hi <= r.length, "hi must be less than or equal to the length of r");
3737     assert(r[lo .. pivot + 1].all!(x => !lp(r[pivot], x)),
3738         "r[lo .. pivot + 1] failed less than test");
3739     assert(r[pivot + 1 .. hi].all!(x => !lp(x, r[pivot])),
3740         "r[pivot + 1 .. hi] failed less than test");
3741     }
3742 out
3743 {
3744     import std.algorithm.searching : all;
3745     assert(r[0 .. pivot + 1].all!(x => !lp(r[pivot], x)),
3746         "r[0 .. pivot + 1] failed less than test");
3747     assert(r[pivot + 1 .. r.length].all!(x => !lp(x, r[pivot])),
3748         "r[pivot + 1 .. r.length] failed less than test");
3749 }
3750 do
3751 {
3752     import std.algorithm.mutation : swapAt;
3753     import std.algorithm.searching : all;
3754     // We work with closed intervals!
3755     --hi;
3756 
3757     size_t left = 0, rite = r.length - 1;
3758     loop: for (;; ++left, --rite)
3759     {
3760         for (;; ++left)
3761         {
3762             if (left == lo) break loop;
3763             if (!lp(r[left], r[pivot])) break;
3764         }
3765         for (;; --rite)
3766         {
3767             if (rite == hi) break loop;
3768             if (!lp(r[pivot], r[rite])) break;
3769         }
3770         r.swapAt(left, rite);
3771     }
3772 
3773     assert(r[lo .. pivot + 1].all!(x => !lp(r[pivot], x)),
3774         "r[lo .. pivot + 1] failed less than test");
3775     assert(r[pivot + 1 .. hi + 1].all!(x => !lp(x, r[pivot])),
3776         "r[pivot + 1 .. hi + 1] failed less than test");
3777     assert(r[0 .. left].all!(x => !lp(r[pivot], x)),
3778         "r[0 .. left] failed less than test");
3779     assert(r[rite + 1 .. r.length].all!(x => !lp(x, r[pivot])),
3780         "r[rite + 1 .. r.length] failed less than test");
3781 
3782     immutable oldPivot = pivot;
3783 
3784     if (left < lo)
3785     {
3786         // First loop: spend r[lo .. pivot]
3787         for (; lo < pivot; ++left)
3788         {
3789             if (left == lo) goto done;
3790             if (!lp(r[oldPivot], r[left])) continue;
3791             --pivot;
3792             assert(!lp(r[oldPivot], r[pivot]), "less check failed");
3793             r.swapAt(left, pivot);
3794         }
3795         // Second loop: make left and pivot meet
3796         for (;; ++left)
3797         {
3798             if (left == pivot) goto done;
3799             if (!lp(r[oldPivot], r[left])) continue;
3800             for (;;)
3801             {
3802                 if (left == pivot) goto done;
3803                 --pivot;
3804                 if (lp(r[pivot], r[oldPivot]))
3805                 {
3806                     r.swapAt(left, pivot);
3807                     break;
3808                 }
3809             }
3810         }
3811     }
3812 
3813     // First loop: spend r[lo .. pivot]
3814     for (; hi != pivot; --rite)
3815     {
3816         if (rite == hi) goto done;
3817         if (!lp(r[rite], r[oldPivot])) continue;
3818         ++pivot;
3819         assert(!lp(r[pivot], r[oldPivot]), "less check failed");
3820         r.swapAt(rite, pivot);
3821     }
3822     // Second loop: make left and pivot meet
3823     for (; rite > pivot; --rite)
3824     {
3825         if (!lp(r[rite], r[oldPivot])) continue;
3826         while (rite > pivot)
3827         {
3828             ++pivot;
3829             if (lp(r[oldPivot], r[pivot]))
3830             {
3831                 r.swapAt(rite, pivot);
3832                 break;
3833             }
3834         }
3835     }
3836 
3837 done:
3838     r.swapAt(oldPivot, pivot);
3839     return pivot;
3840 }
3841 
3842 @safe unittest
3843 {
3844     auto a = [ 10, 5, 3, 4, 8,  11,  13, 3, 9, 4, 10 ];
3845     assert(expandPartition!((a, b) => a < b)(a, 4, 5, 6) == 9);
3846 
3847     import std.algorithm.iteration : map;
3848     import std.array : array;
3849     import std.random : uniform;
3850     import std.range : iota;
3851     auto size = uniform(1, 1000);
3852     a = iota(0, size).map!(_ => uniform(0, 1000)).array;
3853     if (a.length == 0) return;
3854     expandPartition!((a, b) => a < b)(a, a.length / 2, a.length / 2,
3855         a.length / 2 + 1);
3856 }
3857 
3858 @safe unittest
3859 {
3860     import std.algorithm.comparison : max, min;
3861     import std.algorithm.iteration : reduce;
3862 
3863     int[] v = [ 7, 6, 5, 4, 3, 2, 1, 0 ];
3864     ptrdiff_t n = 3;
3865     topN!("a < b")(v, n);
3866     assert(reduce!max(v[0 .. n]) <= v[n]);
3867     assert(reduce!min(v[n + 1 .. $]) >= v[n]);
3868     //
3869     v = [3, 4, 5, 6, 7, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5];
3870     n = 3;
3871     topN(v, n);
3872     assert(reduce!max(v[0 .. n]) <= v[n]);
3873     assert(reduce!min(v[n + 1 .. $]) >= v[n]);
3874     //
3875     v = [3, 4, 5, 6, 7, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5];
3876     n = 1;
3877     topN(v, n);
3878     assert(reduce!max(v[0 .. n]) <= v[n]);
3879     assert(reduce!min(v[n + 1 .. $]) >= v[n]);
3880     //
3881     v = [3, 4, 5, 6, 7, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5];
3882     n = v.length - 1;
3883     topN(v, n);
3884     assert(v[n] == 7);
3885     //
3886     v = [3, 4, 5, 6, 7, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5];
3887     n = 0;
3888     topN(v, n);
3889     assert(v[n] == 1);
3890 
3891     double[][] v1 = [[-10, -5], [-10, -3], [-10, -5], [-10, -4],
3892             [-10, -5], [-9, -5], [-9, -3], [-9, -5],];
3893 
3894     // double[][] v1 = [ [-10, -5], [-10, -4], [-9, -5], [-9, -5],
3895     //         [-10, -5], [-10, -3], [-10, -5], [-9, -3],];
3896     double[]*[] idx = [ &v1[0], &v1[1], &v1[2], &v1[3], &v1[4], &v1[5], &v1[6],
3897             &v1[7], ];
3898 
3899     auto mid = v1.length / 2;
3900     topN!((a, b){ return (*a)[1] < (*b)[1]; })(idx, mid);
3901     foreach (e; idx[0 .. mid]) assert((*e)[1] <= (*idx[mid])[1]);
3902     foreach (e; idx[mid .. $]) assert((*e)[1] >= (*idx[mid])[1]);
3903 }
3904 
3905 @safe unittest
3906 {
3907     import std.algorithm.comparison : max, min;
3908     import std.algorithm.iteration : reduce;
3909     import std.random : Random = Xorshift, uniform;
3910 
3911     immutable uint[] seeds = [90027751, 2709791795, 1374631933, 995751648, 3541495258, 984840953];
3912     foreach (s; seeds)
3913     {
3914         auto r = Random(s);
3915 
3916         int[] a = new int[uniform(1, 10000, r)];
3917         foreach (ref e; a) e = uniform(-1000, 1000, r);
3918 
3919         auto k = uniform(0, a.length, r);
3920         topN(a, k);
3921         if (k > 0)
3922         {
3923             auto left = reduce!max(a[0 .. k]);
3924             assert(left <= a[k]);
3925         }
3926         if (k + 1 < a.length)
3927         {
3928             auto right = reduce!min(a[k + 1 .. $]);
3929             assert(right >= a[k]);
3930         }
3931     }
3932 }
3933 
3934 // https://issues.dlang.org/show_bug.cgi?id=12987
3935 @safe unittest
3936 {
3937     int[] a = [ 25, 7, 9, 2, 0, 5, 21 ];
3938     auto n = 4;
3939     auto t = topN(a, n);
3940     sort(t);
3941     assert(t == [0, 2, 5, 7]);
3942 }
3943 
3944 /**
3945 Stores the smallest elements of the two ranges in the left-hand range.
3946 
3947 Params:
3948     less = The predicate to sort by.
3949     ss = The swapping strategy to use.
3950     r1 = The first range.
3951     r2 = The second range.
3952  */
3953 auto topN(alias less = "a < b",
3954         SwapStrategy ss = SwapStrategy.unstable,
3955         Range1, Range2)(Range1 r1, Range2 r2)
3956 if (isRandomAccessRange!(Range1) && hasLength!Range1 &&
3957     isInputRange!Range2 && is(ElementType!Range1 == ElementType!Range2) &&
3958     hasLvalueElements!Range1 && hasLvalueElements!Range2)
3959 {
3960     import std.container : BinaryHeap;
3961 
3962     static assert(ss == SwapStrategy.unstable,
3963             "Stable topN not yet implemented");
3964 
3965     auto heap = BinaryHeap!(Range1, less)(r1);
3966     foreach (ref e; r2)
3967     {
3968         heap.conditionalSwap(e);
3969     }
3970 
3971     return r1;
3972 }
3973 
3974 ///
3975 @system unittest
3976 {
3977     int[] a = [ 5, 7, 2, 6, 7 ];
3978     int[] b = [ 2, 1, 5, 6, 7, 3, 0 ];
3979     topN(a, b);
3980     sort(a);
3981     assert(a == [0, 1, 2, 2, 3]);
3982 }
3983 
3984 // https://issues.dlang.org/show_bug.cgi?id=15421
3985 @system unittest
3986 {
3987     import std.algorithm.comparison : equal;
3988     import std.internal.test.dummyrange;
3989     import std.meta : AliasSeq;
3990 
3991     alias RandomRanges = AliasSeq!(
3992         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random)
3993     );
3994 
3995     alias ReferenceRanges = AliasSeq!(
3996         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Forward),
3997         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Bidirectional),
3998         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random),
3999         DummyRange!(ReturnBy.Reference, Length.No, RangeType.Forward),
4000         DummyRange!(ReturnBy.Reference, Length.No, RangeType.Bidirectional));
4001 
4002     foreach (T1; RandomRanges)
4003     {
4004         foreach (T2; ReferenceRanges)
4005         {
4006             import std.array : array;
4007 
4008             T1 A;
4009             T2 B;
4010 
4011             A.reinit();
4012             B.reinit();
4013 
4014             topN(A, B);
4015 
4016             // BUG(?): sort doesn't accept DummyRanges (needs Slicing and Length)
4017             auto a = array(A);
4018             auto b = array(B);
4019             sort(a);
4020             sort(b);
4021 
4022             assert(equal(a, [ 1, 1, 2, 2, 3, 3, 4, 4, 5, 5 ]));
4023             assert(equal(b, [ 6, 6, 7, 7, 8, 8, 9, 9, 10, 10 ]));
4024         }
4025     }
4026 }
4027 
4028 // https://issues.dlang.org/show_bug.cgi?id=15421
4029 @system unittest
4030 {
4031     auto a = [ 9, 8, 0, 3, 5, 25, 43, 4, 2, 0, 7 ];
4032     auto b = [ 9, 8, 0, 3, 5, 25, 43, 4, 2, 0, 7 ];
4033 
4034     topN(a, 4);
4035     topN(b[0 .. 4], b[4 .. $]);
4036 
4037     sort(a[0 .. 4]);
4038     sort(a[4 .. $]);
4039     sort(b[0 .. 4]);
4040     sort(b[4 .. $]);
4041 
4042     assert(a[0 .. 4] == b[0 .. 4]);
4043     assert(a[4 .. $] == b[4 .. $]);
4044     assert(a == b);
4045 }
4046 
4047 // https://issues.dlang.org/show_bug.cgi?id=12987
4048 @system unittest
4049 {
4050     int[] a = [ 5, 7, 2, 6, 7 ];
4051     int[] b = [ 2, 1, 5, 6, 7, 3, 0 ];
4052     auto t = topN(a, b);
4053     sort(t);
4054     assert(t == [ 0, 1, 2, 2, 3 ]);
4055 }
4056 
4057 // https://issues.dlang.org/show_bug.cgi?id=15420
4058 @system unittest
4059 {
4060     int[] a = [ 5, 7, 2, 6, 7 ];
4061     int[] b = [ 2, 1, 5, 6, 7, 3, 0 ];
4062     topN!"a > b"(a, b);
4063     sort!"a > b"(a);
4064     assert(a == [ 7, 7, 7, 6, 6 ]);
4065 }
4066 
4067 /**
4068 Copies the top `n` elements of the
4069 $(REF_ALTTEXT input range, isInputRange, std,range,primitives) `source` into the
4070 random-access range `target`, where `n = target.length`.
4071 
4072 Elements of `source` are not touched. If $(D
4073 sorted) is `true`, the target is sorted. Otherwise, the target
4074 respects the $(HTTP en.wikipedia.org/wiki/Binary_heap, heap property).
4075 
4076 Params:
4077     less = The predicate to sort by.
4078     source = The source range.
4079     target = The target range.
4080     sorted = Whether to sort the elements copied into `target`.
4081 
4082 Returns: The slice of `target` containing the copied elements.
4083  */
4084 TRange topNCopy(alias less = "a < b", SRange, TRange)
4085     (SRange source, TRange target, SortOutput sorted = No.sortOutput)
4086 if (isInputRange!(SRange) && isRandomAccessRange!(TRange)
4087     && hasLength!(TRange) && hasSlicing!(TRange))
4088 {
4089     import std.container : BinaryHeap;
4090 
4091     if (target.empty) return target;
4092     auto heap = BinaryHeap!(TRange, less)(target, 0);
4093     foreach (e; source) heap.conditionalInsert(e);
4094     auto result = target[0 .. heap.length];
4095     if (sorted == Yes.sortOutput)
4096     {
4097         while (!heap.empty) heap.removeFront();
4098     }
4099     return result;
4100 }
4101 
4102 ///
4103 @system unittest
4104 {
4105     import std.typecons : Yes;
4106 
4107     int[] a = [ 10, 16, 2, 3, 1, 5, 0 ];
4108     int[] b = new int[3];
4109     topNCopy(a, b, Yes.sortOutput);
4110     assert(b == [ 0, 1, 2 ]);
4111 }
4112 
4113 @system unittest
4114 {
4115     import std.random : Random = Xorshift, uniform, randomShuffle;
4116     import std.typecons : Yes;
4117 
4118     auto r = Random(123_456_789);
4119     ptrdiff_t[] a = new ptrdiff_t[uniform(1, 1000, r)];
4120     foreach (i, ref e; a) e = i;
4121     randomShuffle(a, r);
4122     auto n = uniform(0, a.length, r);
4123     ptrdiff_t[] b = new ptrdiff_t[n];
4124     topNCopy!(binaryFun!("a < b"))(a, b, Yes.sortOutput);
4125     assert(isSorted!(binaryFun!("a < b"))(b));
4126 }
4127 
4128 /**
4129 Given a range of elements, constructs an index of its top $(I n) elements
4130 (i.e., the first $(I n) elements if the range were sorted).
4131 
4132 Similar to $(LREF topN), except that the range is not modified.
4133 
4134 Params:
4135     less = A binary predicate that defines the ordering of range elements.
4136         Defaults to `a < b`.
4137     ss = $(RED (Not implemented yet.)) Specify the swapping strategy.
4138     r = A
4139         $(REF_ALTTEXT random-access range, isRandomAccessRange, std,range,primitives)
4140         of elements to make an index for.
4141     index = A
4142         $(REF_ALTTEXT random-access range, isRandomAccessRange, std,range,primitives)
4143         with assignable elements to build the index in. The length of this range
4144         determines how many top elements to index in `r`.
4145 
4146         This index range can either have integral elements, in which case the
4147         constructed index will consist of zero-based numerical indices into
4148         `r`; or it can have pointers to the element type of `r`, in which
4149         case the constructed index will be pointers to the top elements in
4150         `r`.
4151     sorted = Determines whether to sort the index by the elements they refer
4152         to.
4153 
4154 See_also: $(LREF topN), $(LREF topNCopy).
4155 
4156 BUGS:
4157 The swapping strategy parameter is not implemented yet; currently it is
4158 ignored.
4159 */
4160 void topNIndex(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable,
4161                Range, RangeIndex)
4162               (Range r, RangeIndex index, SortOutput sorted = No.sortOutput)
4163 if (isRandomAccessRange!Range &&
4164     isRandomAccessRange!RangeIndex &&
4165     hasAssignableElements!RangeIndex)
4166 {
4167     static assert(ss == SwapStrategy.unstable,
4168                   "Stable swap strategy not implemented yet.");
4169 
4170     import std.container.binaryheap : BinaryHeap;
4171     if (index.empty) return;
4172 
4173     static if (isIntegral!(ElementType!(RangeIndex)))
4174     {
4175         import std.exception : enforce;
4176 
4177         enforce(ElementType!(RangeIndex).max >= index.length,
4178                 "Index type too small");
4179         bool indirectLess(ElementType!(RangeIndex) a, ElementType!(RangeIndex) b)
4180         {
4181             return binaryFun!(less)(r[a], r[b]);
4182         }
4183         auto heap = BinaryHeap!(RangeIndex, indirectLess)(index, 0);
4184         foreach (i; 0 .. r.length)
4185         {
4186             heap.conditionalInsert(cast(ElementType!RangeIndex) i);
4187         }
4188 
4189     }
4190     else static if (is(ElementType!(RangeIndex) == ElementType!(Range)*))
4191     {
4192         static bool indirectLess(const ElementType!(RangeIndex) a,
4193                                  const ElementType!(RangeIndex) b)
4194         {
4195             return binaryFun!less(*a, *b);
4196         }
4197         auto heap = BinaryHeap!(RangeIndex, indirectLess)(index, 0);
4198         foreach (i; 0 .. r.length)
4199         {
4200             heap.conditionalInsert(&r[i]);
4201         }
4202     }
4203     else static assert(0, "Invalid ElementType");
4204 
4205     if (sorted == Yes.sortOutput)
4206     {
4207         while (!heap.empty) heap.removeFront();
4208     }
4209 }
4210 
4211 ///
4212 @system unittest
4213 {
4214     import std.typecons : Yes;
4215 
4216     // Construct index to top 3 elements using numerical indices:
4217     int[] a = [ 10, 2, 7, 5, 8, 1 ];
4218     int[] index = new int[3];
4219     topNIndex(a, index, Yes.sortOutput);
4220     assert(index == [5, 1, 3]); // because a[5]==1, a[1]==2, a[3]==5
4221 
4222     // Construct index to top 3 elements using pointer indices:
4223     int*[] ptrIndex = new int*[3];
4224     topNIndex(a, ptrIndex, Yes.sortOutput);
4225     assert(ptrIndex == [ &a[5], &a[1], &a[3] ]);
4226 }
4227 
4228 @system unittest
4229 {
4230     import std.conv : text;
4231 
4232     {
4233         int[] a = [ 10, 8, 9, 2, 4, 6, 7, 1, 3, 5 ];
4234         int*[] b = new int*[5];
4235         topNIndex!("a > b")(a, b, Yes.sortOutput);
4236         assert(b == [ &a[0], &a[2], &a[1], &a[6], &a[5]]);
4237     }
4238     {
4239         int[] a = [ 10, 8, 9, 2, 4, 6, 7, 1, 3, 5 ];
4240         auto b = new ubyte[5];
4241         topNIndex!("a > b")(a, b, Yes.sortOutput);
4242         assert(b == [ cast(ubyte) 0, cast(ubyte) 2, cast(ubyte) 1, cast(ubyte) 6, cast(ubyte) 5], text(b));
4243     }
4244 }
4245 
4246 // medianOf
4247 /*
4248 Private for the time being.
4249 
4250 Computes the median of 2 to 5 arbitrary indexes in random-access range `r`
4251 using hand-written specialized algorithms. The indexes must be distinct (if not,
4252 behavior is implementation-defined). The function also partitions the elements
4253 involved around the median, e.g. `medianOf(r, a, b, c)` not only fills `r[b]`
4254 with the median of `r[a]`, `r[b]`, and `r[c]`, but also puts the minimum in
4255 `r[a]` and the maximum in `r[c]`.
4256 
4257 Params:
4258 less = The comparison predicate used, modeled as a
4259     $(LINK2 https://en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings, strict weak ordering)
4260     (irreflexive, antisymmetric, transitive, and implying a transitive equivalence).
4261 flag = Used only for even values of `T.length`. If `No.leanRight`, the median
4262 "leans left", meaning `medianOf(r, a, b, c, d)` puts the lower median of the
4263 four in `r[b]`, the minimum in `r[a]`, and the two others in `r[c]` and `r[d]`.
4264 Conversely, `median!("a < b", Yes.leanRight)(r, a, b, c, d)` puts the upper
4265 median of the four in `r[c]`, the maximum in `r[d]`, and the two others in
4266 `r[a]` and `r[b]`.
4267 r = The range containing the indexes.
4268 i = Two to five indexes inside `r`.
4269 */
4270 private void medianOf(
4271         alias less = "a < b",
4272         Flag!"leanRight" flag = No.leanRight,
4273         Range,
4274         Indexes...)
4275     (Range r, Indexes i)
4276 if (isRandomAccessRange!Range && hasLength!Range &&
4277     Indexes.length >= 2 && Indexes.length <= 5 &&
4278     allSatisfy!(isUnsigned, Indexes))
4279 {
4280     assert(r.length >= Indexes.length, "r.length must be greater than or"
4281         ~ " equal to Indexes.length");
4282     import std.functional : binaryFun;
4283     alias lt = binaryFun!less;
4284     enum k = Indexes.length;
4285     import std.algorithm.mutation : swapAt;
4286     import std.format : format;
4287 
4288     alias a = i[0];
4289     static assert(is(typeof(a) == size_t), typeof(a).stringof ~ " must be"
4290         ~ " of type size_t");
4291     static if (k >= 2)
4292     {
4293         alias b = i[1];
4294         static assert(is(typeof(b) == size_t), typeof(b).stringof ~ " must be"
4295         ~ " of type size_t");
4296         assert(a != b, "a != b ");
4297     }
4298     static if (k >= 3)
4299     {
4300         alias c = i[2];
4301         static assert(is(typeof(c) == size_t), typeof(c).stringof ~ " must be"
4302         ~ " of type size_t");
4303         assert(a != c && b != c, "a != c && b != c");
4304     }
4305     static if (k >= 4)
4306     {
4307         alias d = i[3];
4308         static assert(is(typeof(d) == size_t), typeof(d).stringof ~ " must be"
4309         ~ " of type size_t");
4310         assert(a != d && b != d && c != d, "a != d && b != d && c != d failed");
4311     }
4312     static if (k >= 5)
4313     {
4314         alias e = i[4];
4315         static assert(is(typeof(e) == size_t), typeof(e).stringof ~ " must be"
4316         ~ " of type size_t");
4317         assert(a != e && b != e && c != e && d != e,
4318             "a != e && b != e && c != e && d != e failed");
4319     }
4320 
4321     static if (k == 2)
4322     {
4323         if (lt(r[b], r[a])) r.swapAt(a, b);
4324     }
4325     else static if (k == 3)
4326     {
4327         if (lt(r[c], r[a])) // c < a
4328         {
4329             if (lt(r[a], r[b])) // c < a < b
4330             {
4331                 r.swapAt(a, b);
4332                 r.swapAt(a, c);
4333             }
4334             else // c < a, b <= a
4335             {
4336                 r.swapAt(a, c);
4337                 if (lt(r[b], r[a])) r.swapAt(a, b);
4338             }
4339         }
4340         else // a <= c
4341         {
4342             if (lt(r[b], r[a])) // b < a <= c
4343             {
4344                 r.swapAt(a, b);
4345             }
4346             else // a <= c, a <= b
4347             {
4348                 if (lt(r[c], r[b])) r.swapAt(b, c);
4349             }
4350         }
4351         assert(!lt(r[b], r[a]), "less than check failed");
4352         assert(!lt(r[c], r[b]), "less than check failed");
4353     }
4354     else static if (k == 4)
4355     {
4356         static if (flag == No.leanRight)
4357         {
4358             // Eliminate the rightmost from the competition
4359             if (lt(r[d], r[c])) r.swapAt(c, d); // c <= d
4360             if (lt(r[d], r[b])) r.swapAt(b, d); // b <= d
4361             medianOf!lt(r, a, b, c);
4362         }
4363         else
4364         {
4365             // Eliminate the leftmost from the competition
4366             if (lt(r[b], r[a])) r.swapAt(a, b); // a <= b
4367             if (lt(r[c], r[a])) r.swapAt(a, c); // a <= c
4368             medianOf!lt(r, b, c, d);
4369         }
4370     }
4371     else static if (k == 5)
4372     {
4373         // Credit: Teppo Niinimäki
4374         version (StdUnittest) scope(success)
4375         {
4376             assert(!lt(r[c], r[a]), "less than check failed");
4377             assert(!lt(r[c], r[b]), "less than check failed");
4378             assert(!lt(r[d], r[c]), "less than check failed");
4379             assert(!lt(r[e], r[c]), "less than check failed");
4380         }
4381 
4382         if (lt(r[c], r[a])) r.swapAt(a, c);
4383         if (lt(r[d], r[b])) r.swapAt(b, d);
4384         if (lt(r[d], r[c]))
4385         {
4386             r.swapAt(c, d);
4387             r.swapAt(a, b);
4388         }
4389         if (lt(r[e], r[b])) r.swapAt(b, e);
4390         if (lt(r[e], r[c]))
4391         {
4392             r.swapAt(c, e);
4393             if (lt(r[c], r[a])) r.swapAt(a, c);
4394         }
4395         else
4396         {
4397             if (lt(r[c], r[b])) r.swapAt(b, c);
4398         }
4399     }
4400 }
4401 
4402 @safe unittest
4403 {
4404     // Verify medianOf for all permutations of [1, 2, 2, 3, 4].
4405     int[5] data = [1, 2, 2, 3, 4];
4406     do
4407     {
4408         int[5] a = data;
4409         medianOf(a[], size_t(0), size_t(1));
4410         assert(a[0] <= a[1]);
4411 
4412         a[] = data[];
4413         medianOf(a[], size_t(0), size_t(1), size_t(2));
4414         assert(ordered(a[0], a[1], a[2]));
4415 
4416         a[] = data[];
4417         medianOf(a[], size_t(0), size_t(1), size_t(2), size_t(3));
4418         assert(a[0] <= a[1] && a[1] <= a[2] && a[1] <= a[3]);
4419 
4420         a[] = data[];
4421         medianOf!("a < b", Yes.leanRight)(a[], size_t(0), size_t(1),
4422             size_t(2), size_t(3));
4423         assert(a[0] <= a[2] && a[1] <= a[2] && a[2] <= a[3]);
4424 
4425         a[] = data[];
4426         medianOf(a[], size_t(0), size_t(1), size_t(2), size_t(3), size_t(4));
4427         assert(a[0] <= a[2] && a[1] <= a[2] && a[2] <= a[3] && a[2] <= a[4]);
4428     }
4429     while (nextPermutation(data[]));
4430 }
4431 
4432 // nextPermutation
4433 /**
4434  * Permutes `range` in-place to the next lexicographically greater
4435  * permutation.
4436  *
4437  * The predicate `less` defines the lexicographical ordering to be used on
4438  * the range.
4439  *
4440  * If the range is currently the lexicographically greatest permutation, it is
4441  * permuted back to the least permutation and false is returned.  Otherwise,
4442  * true is returned. One can thus generate all permutations of a range by
4443  * sorting it according to `less`, which produces the lexicographically
4444  * least permutation, and then calling nextPermutation until it returns false.
4445  * This is guaranteed to generate all distinct permutations of the range
4446  * exactly once.  If there are $(I N) elements in the range and all of them are
4447  * unique, then $(I N)! permutations will be generated. Otherwise, if there are
4448  * some duplicated elements, fewer permutations will be produced.
4449 ----
4450 // Enumerate all permutations
4451 int[] a = [1,2,3,4,5];
4452 do
4453 {
4454     // use the current permutation and
4455     // proceed to the next permutation of the array.
4456 } while (nextPermutation(a));
4457 ----
4458  * Params:
4459  *  less = The ordering to be used to determine lexicographical ordering of the
4460  *      permutations.
4461  *  range = The range to permute.
4462  *
4463  * Returns: false if the range was lexicographically the greatest, in which
4464  * case the range is reversed back to the lexicographically smallest
4465  * permutation; otherwise returns true.
4466  * See_Also:
4467  * $(REF permutations, std,algorithm,iteration).
4468  */
4469 bool nextPermutation(alias less="a < b", BidirectionalRange)
4470                     (BidirectionalRange range)
4471 if (isBidirectionalRange!BidirectionalRange &&
4472     hasSwappableElements!BidirectionalRange)
4473 {
4474     import std.algorithm.mutation : reverse, swap;
4475     import std.algorithm.searching : find;
4476     import std.range : retro, takeExactly;
4477     // Ranges of 0 or 1 element have no distinct permutations.
4478     if (range.empty) return false;
4479 
4480     auto i = retro(range);
4481     auto last = i.save;
4482 
4483     // Find last occurring increasing pair of elements
4484     size_t n = 1;
4485     for (i.popFront(); !i.empty; i.popFront(), last.popFront(), n++)
4486     {
4487         if (binaryFun!less(i.front, last.front))
4488             break;
4489     }
4490 
4491     if (i.empty)
4492     {
4493         // Entire range is decreasing: it's lexicographically the greatest. So
4494         // wrap it around.
4495         range.reverse();
4496         return false;
4497     }
4498 
4499     // Find last element greater than i.front.
4500     auto j = find!((a) => binaryFun!less(i.front, a))(
4501                    takeExactly(retro(range), n));
4502 
4503     assert(!j.empty, "j must not be empty");   // shouldn't happen since i.front < last.front
4504     swap(i.front, j.front);
4505     reverse(takeExactly(retro(range), n));
4506 
4507     return true;
4508 }
4509 
4510 ///
4511 @safe unittest
4512 {
4513     // Step through all permutations of a sorted array in lexicographic order
4514     int[] a = [1,2,3];
4515     assert(nextPermutation(a) == true);
4516     assert(a == [1,3,2]);
4517     assert(nextPermutation(a) == true);
4518     assert(a == [2,1,3]);
4519     assert(nextPermutation(a) == true);
4520     assert(a == [2,3,1]);
4521     assert(nextPermutation(a) == true);
4522     assert(a == [3,1,2]);
4523     assert(nextPermutation(a) == true);
4524     assert(a == [3,2,1]);
4525     assert(nextPermutation(a) == false);
4526     assert(a == [1,2,3]);
4527 }
4528 
4529 ///
4530 @safe unittest
4531 {
4532     // Step through permutations of an array containing duplicate elements:
4533     int[] a = [1,1,2];
4534     assert(nextPermutation(a) == true);
4535     assert(a == [1,2,1]);
4536     assert(nextPermutation(a) == true);
4537     assert(a == [2,1,1]);
4538     assert(nextPermutation(a) == false);
4539     assert(a == [1,1,2]);
4540 }
4541 
4542 @safe unittest
4543 {
4544     // Boundary cases: arrays of 0 or 1 element.
4545     int[] a1 = [];
4546     assert(!nextPermutation(a1));
4547     assert(a1 == []);
4548 
4549     int[] a2 = [1];
4550     assert(!nextPermutation(a2));
4551     assert(a2 == [1]);
4552 }
4553 
4554 @safe unittest
4555 {
4556     import std.algorithm.comparison : equal;
4557 
4558     auto a1 = [1, 2, 3, 4];
4559 
4560     assert(nextPermutation(a1));
4561     assert(equal(a1, [1, 2, 4, 3]));
4562 
4563     assert(nextPermutation(a1));
4564     assert(equal(a1, [1, 3, 2, 4]));
4565 
4566     assert(nextPermutation(a1));
4567     assert(equal(a1, [1, 3, 4, 2]));
4568 
4569     assert(nextPermutation(a1));
4570     assert(equal(a1, [1, 4, 2, 3]));
4571 
4572     assert(nextPermutation(a1));
4573     assert(equal(a1, [1, 4, 3, 2]));
4574 
4575     assert(nextPermutation(a1));
4576     assert(equal(a1, [2, 1, 3, 4]));
4577 
4578     assert(nextPermutation(a1));
4579     assert(equal(a1, [2, 1, 4, 3]));
4580 
4581     assert(nextPermutation(a1));
4582     assert(equal(a1, [2, 3, 1, 4]));
4583 
4584     assert(nextPermutation(a1));
4585     assert(equal(a1, [2, 3, 4, 1]));
4586 
4587     assert(nextPermutation(a1));
4588     assert(equal(a1, [2, 4, 1, 3]));
4589 
4590     assert(nextPermutation(a1));
4591     assert(equal(a1, [2, 4, 3, 1]));
4592 
4593     assert(nextPermutation(a1));
4594     assert(equal(a1, [3, 1, 2, 4]));
4595 
4596     assert(nextPermutation(a1));
4597     assert(equal(a1, [3, 1, 4, 2]));
4598 
4599     assert(nextPermutation(a1));
4600     assert(equal(a1, [3, 2, 1, 4]));
4601 
4602     assert(nextPermutation(a1));
4603     assert(equal(a1, [3, 2, 4, 1]));
4604 
4605     assert(nextPermutation(a1));
4606     assert(equal(a1, [3, 4, 1, 2]));
4607 
4608     assert(nextPermutation(a1));
4609     assert(equal(a1, [3, 4, 2, 1]));
4610 
4611     assert(nextPermutation(a1));
4612     assert(equal(a1, [4, 1, 2, 3]));
4613 
4614     assert(nextPermutation(a1));
4615     assert(equal(a1, [4, 1, 3, 2]));
4616 
4617     assert(nextPermutation(a1));
4618     assert(equal(a1, [4, 2, 1, 3]));
4619 
4620     assert(nextPermutation(a1));
4621     assert(equal(a1, [4, 2, 3, 1]));
4622 
4623     assert(nextPermutation(a1));
4624     assert(equal(a1, [4, 3, 1, 2]));
4625 
4626     assert(nextPermutation(a1));
4627     assert(equal(a1, [4, 3, 2, 1]));
4628 
4629     assert(!nextPermutation(a1));
4630     assert(equal(a1, [1, 2, 3, 4]));
4631 }
4632 
4633 @safe unittest
4634 {
4635     // Test with non-default sorting order
4636     int[] a = [3,2,1];
4637     assert(nextPermutation!"a > b"(a) == true);
4638     assert(a == [3,1,2]);
4639     assert(nextPermutation!"a > b"(a) == true);
4640     assert(a == [2,3,1]);
4641     assert(nextPermutation!"a > b"(a) == true);
4642     assert(a == [2,1,3]);
4643     assert(nextPermutation!"a > b"(a) == true);
4644     assert(a == [1,3,2]);
4645     assert(nextPermutation!"a > b"(a) == true);
4646     assert(a == [1,2,3]);
4647     assert(nextPermutation!"a > b"(a) == false);
4648     assert(a == [3,2,1]);
4649 }
4650 
4651 // https://issues.dlang.org/show_bug.cgi?id=13594
4652 @safe unittest
4653 {
4654     int[3] a = [1,2,3];
4655     assert(nextPermutation(a[]));
4656     assert(a == [1,3,2]);
4657 }
4658 
4659 // nextEvenPermutation
4660 /**
4661  * Permutes `range` in-place to the next lexicographically greater $(I even)
4662  * permutation.
4663  *
4664  * The predicate `less` defines the lexicographical ordering to be used on
4665  * the range.
4666  *
4667  * An even permutation is one which is produced by swapping an even number of
4668  * pairs of elements in the original range. The set of $(I even) permutations
4669  * is distinct from the set of $(I all) permutations only when there are no
4670  * duplicate elements in the range. If the range has $(I N) unique elements,
4671  * then there are exactly $(I N)!/2 even permutations.
4672  *
4673  * If the range is already the lexicographically greatest even permutation, it
4674  * is permuted back to the least even permutation and false is returned.
4675  * Otherwise, true is returned, and the range is modified in-place to be the
4676  * lexicographically next even permutation.
4677  *
4678  * One can thus generate the even permutations of a range with unique elements
4679  * by starting with the lexicographically smallest permutation, and repeatedly
4680  * calling nextEvenPermutation until it returns false.
4681 ----
4682 // Enumerate even permutations
4683 int[] a = [1,2,3,4,5];
4684 do
4685 {
4686     // use the current permutation and
4687     // proceed to the next even permutation of the array.
4688 } while (nextEvenPermutation(a));
4689 ----
4690  * One can also generate the $(I odd) permutations of a range by noting that
4691  * permutations obey the rule that even + even = even, and odd + even = odd.
4692  * Thus, by swapping the last two elements of a lexicographically least range,
4693  * it is turned into the first odd permutation. Then calling
4694  * nextEvenPermutation on this first odd permutation will generate the next
4695  * even permutation relative to this odd permutation, which is actually the
4696  * next odd permutation of the original range. Thus, by repeatedly calling
4697  * nextEvenPermutation until it returns false, one enumerates the odd
4698  * permutations of the original range.
4699 ----
4700 // Enumerate odd permutations
4701 int[] a = [1,2,3,4,5];
4702 swap(a[$-2], a[$-1]);    // a is now the first odd permutation of [1,2,3,4,5]
4703 do
4704 {
4705     // use the current permutation and
4706     // proceed to the next odd permutation of the original array
4707     // (which is an even permutation of the first odd permutation).
4708 } while (nextEvenPermutation(a));
4709 ----
4710  *
4711  * Warning: Since even permutations are only distinct from all permutations
4712  * when the range elements are unique, this function assumes that there are no
4713  * duplicate elements under the specified ordering. If this is not _true, some
4714  * permutations may fail to be generated. When the range has non-unique
4715  * elements, you should use $(MYREF nextPermutation) instead.
4716  *
4717  * Params:
4718  *  less = The ordering to be used to determine lexicographical ordering of the
4719  *      permutations.
4720  *  range = The range to permute.
4721  *
4722  * Returns: false if the range was lexicographically the greatest, in which
4723  * case the range is reversed back to the lexicographically smallest
4724  * permutation; otherwise returns true.
4725  */
4726 bool nextEvenPermutation(alias less="a < b", BidirectionalRange)
4727                         (BidirectionalRange range)
4728 if (isBidirectionalRange!BidirectionalRange &&
4729     hasSwappableElements!BidirectionalRange)
4730 {
4731     import std.algorithm.mutation : reverse, swap;
4732     import std.algorithm.searching : find;
4733     import std.range : retro, takeExactly;
4734     // Ranges of 0 or 1 element have no distinct permutations.
4735     if (range.empty) return false;
4736 
4737     bool oddParity = false;
4738     bool ret = true;
4739     do
4740     {
4741         auto i = retro(range);
4742         auto last = i.save;
4743 
4744         // Find last occurring increasing pair of elements
4745         size_t n = 1;
4746         for (i.popFront(); !i.empty;
4747             i.popFront(), last.popFront(), n++)
4748         {
4749             if (binaryFun!less(i.front, last.front))
4750                 break;
4751         }
4752 
4753         if (!i.empty)
4754         {
4755             // Find last element greater than i.front.
4756             auto j = find!((a) => binaryFun!less(i.front, a))(
4757                            takeExactly(retro(range), n));
4758 
4759             // shouldn't happen since i.front < last.front
4760             assert(!j.empty, "j must not be empty");
4761 
4762             swap(i.front, j.front);
4763             oddParity = !oddParity;
4764         }
4765         else
4766         {
4767             // Entire range is decreasing: it's lexicographically
4768             // the greatest.
4769             ret = false;
4770         }
4771 
4772         reverse(takeExactly(retro(range), n));
4773         if ((n / 2) % 2 == 1)
4774             oddParity = !oddParity;
4775     } while (oddParity);
4776 
4777     return ret;
4778 }
4779 
4780 ///
4781 @safe unittest
4782 {
4783     // Step through even permutations of a sorted array in lexicographic order
4784     int[] a = [1,2,3];
4785     assert(nextEvenPermutation(a) == true);
4786     assert(a == [2,3,1]);
4787     assert(nextEvenPermutation(a) == true);
4788     assert(a == [3,1,2]);
4789     assert(nextEvenPermutation(a) == false);
4790     assert(a == [1,2,3]);
4791 }
4792 
4793 @safe unittest
4794 {
4795     auto a3 = [ 1, 2, 3, 4 ];
4796     int count = 1;
4797     while (nextEvenPermutation(a3)) count++;
4798     assert(count == 12);
4799 }
4800 
4801 @safe unittest
4802 {
4803     // Test with non-default sorting order
4804     auto a = [ 3, 2, 1 ];
4805 
4806     assert(nextEvenPermutation!"a > b"(a) == true);
4807     assert(a == [ 2, 1, 3 ]);
4808     assert(nextEvenPermutation!"a > b"(a) == true);
4809     assert(a == [ 1, 3, 2 ]);
4810     assert(nextEvenPermutation!"a > b"(a) == false);
4811     assert(a == [ 3, 2, 1 ]);
4812 }
4813 
4814 @safe unittest
4815 {
4816     // Test various cases of rollover
4817     auto a = [ 3, 1, 2 ];
4818     assert(nextEvenPermutation(a) == false);
4819     assert(a == [ 1, 2, 3 ]);
4820 
4821     auto b = [ 3, 2, 1 ];
4822     assert(nextEvenPermutation(b) == false);
4823     assert(b == [ 1, 3, 2 ]);
4824 }
4825 
4826 // https://issues.dlang.org/show_bug.cgi?id=13594
4827 @safe unittest
4828 {
4829     int[3] a = [1,2,3];
4830     assert(nextEvenPermutation(a[]));
4831     assert(a == [2,3,1]);
4832 }
4833 
4834 /**
4835 Even permutations are useful for generating coordinates of certain geometric
4836 shapes. Here's a non-trivial example:
4837 */
4838 @safe unittest
4839 {
4840     import std.math.algebraic : sqrt;
4841 
4842     // Print the 60 vertices of a uniform truncated icosahedron (soccer ball)
4843     enum real Phi = (1.0 + sqrt(5.0)) / 2.0;    // Golden ratio
4844     real[][] seeds = [
4845         [0.0, 1.0, 3.0*Phi],
4846         [1.0, 2.0+Phi, 2.0*Phi],
4847         [Phi, 2.0, Phi^^3]
4848     ];
4849     size_t n;
4850     foreach (seed; seeds)
4851     {
4852         // Loop over even permutations of each seed
4853         do
4854         {
4855             // Loop over all sign changes of each permutation
4856             size_t i;
4857             do
4858             {
4859                 // Generate all possible sign changes
4860                 for (i=0; i < seed.length; i++)
4861                 {
4862                     if (seed[i] != 0.0)
4863                     {
4864                         seed[i] = -seed[i];
4865                         if (seed[i] < 0.0)
4866                             break;
4867                     }
4868                 }
4869                 n++;
4870             } while (i < seed.length);
4871         } while (nextEvenPermutation(seed));
4872     }
4873     assert(n == 60);
4874 }
4875 
4876 /**
4877 Permutes `range` into the `perm` permutation.
4878 
4879 The algorithm has a constant runtime complexity with respect to the number of
4880 permutations created.
4881 Due to the number of unique values of `ulong` only the first 21 elements of
4882 `range` can be permuted. The rest of the range will therefore not be
4883 permuted.
4884 This algorithm uses the $(HTTP en.wikipedia.org/wiki/Lehmer_code, Lehmer
4885 Code).
4886 
4887 The algorithm works as follows:
4888 $(D_CODE
4889     auto pem = [4,0,4,1,0,0,0]; // permutation 2982 in factorial
4890     auto src = [0,1,2,3,4,5,6]; // the range to permutate
4891 
4892     auto i = 0;                    // range index
4893     // range index iterates pem and src in sync
4894     // pem[i] + i is used as index into src
4895     // first src[pem[i] + i] is stored in t
4896     auto t = 4;                    // tmp value
4897     src = [0,1,2,3,n,5,6];
4898 
4899     // then the values between i and pem[i] + i are moved one
4900     // to the right
4901     src = [n,0,1,2,3,5,6];
4902     // at last t is inserted into position i
4903     src = [4,0,1,2,3,5,6];
4904     // finally i is incremented
4905     ++i;
4906 
4907     // this process is repeated while i < pem.length
4908 
4909     t = 0;
4910     src = [4,n,1,2,3,5,6];
4911     src = [4,0,1,2,3,5,6];
4912     ++i;
4913     t = 6;
4914     src = [4,0,1,2,3,5,n];
4915     src = [4,0,n,1,2,3,5];
4916     src = [4,0,6,1,2,3,5];
4917 )
4918 
4919 Returns:
4920     The permuted range.
4921 
4922 Params:
4923     range = The Range to permute. The original ordering will be lost.
4924     perm = The permutation to permutate `range` to.
4925 */
4926 auto ref Range nthPermutation(Range)
4927                              (auto ref Range range, const ulong perm)
4928 if (isRandomAccessRange!Range && hasLength!Range)
4929 {
4930     if (!nthPermutationImpl(range, perm))
4931     {
4932         throw new Exception(
4933             "The range to permutate must not have less"
4934             ~ " elements than the factorial number has digits");
4935     }
4936 
4937     return range;
4938 }
4939 
4940 ///
4941 pure @safe unittest
4942 {
4943     auto src = [0, 1, 2, 3, 4, 5, 6];
4944     auto rslt = [4, 0, 6, 2, 1, 3, 5];
4945 
4946     src = nthPermutation(src, 2982);
4947     assert(src == rslt);
4948 }
4949 
4950 /**
4951 Returns: `true` in case the permutation worked, `false` in case `perm` had
4952     more digits in the factorial number system than range had elements.
4953     This case must not occur as this would lead to out of range accesses.
4954 */
4955 bool nthPermutationImpl(Range)
4956                        (auto ref Range range, ulong perm)
4957 if (isRandomAccessRange!Range && hasLength!Range)
4958 {
4959     import std.range.primitives : ElementType;
4960     import std.numeric : decimalToFactorial;
4961 
4962     // ulong.max has 21 digits in the factorial number system
4963     ubyte[21] fac;
4964     size_t idx = decimalToFactorial(perm, fac);
4965 
4966     if (idx > range.length)
4967     {
4968         return false;
4969     }
4970 
4971     ElementType!Range tmp;
4972     size_t i = 0;
4973 
4974     for (; i < idx; ++i)
4975     {
4976         size_t re = fac[i];
4977         tmp = range[re + i];
4978         for (size_t j = re + i; j > i; --j)
4979         {
4980             range[j] = range[j - 1];
4981         }
4982         range[i] = tmp;
4983     }
4984 
4985     return true;
4986 }
4987 
4988 ///
4989 pure @safe unittest
4990 {
4991     auto src = [0, 1, 2, 3, 4, 5, 6];
4992     auto rslt = [4, 0, 6, 2, 1, 3, 5];
4993 
4994     bool worked = nthPermutationImpl(src, 2982);
4995     assert(worked);
4996     assert(src == rslt);
4997 }
4998 
4999 pure @safe unittest
5000 {
5001     auto rslt = [4, 0, 6, 2, 1, 3, 5];
5002 
5003     auto src = nthPermutation([0, 1, 2, 3, 4, 5, 6], 2982);
5004     assert(src == rslt);
5005 }
5006 
5007 pure @safe unittest
5008 {
5009     auto src = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
5010     auto rslt = [4, 0, 6, 2, 1, 3, 5, 7, 8, 9, 10];
5011 
5012     src = nthPermutation(src, 2982);
5013     assert(src == rslt);
5014 }
5015 
5016 pure @safe unittest
5017 {
5018     import std.exception : assertThrown;
5019 
5020     auto src = [0, 1, 2, 3];
5021 
5022     assertThrown(nthPermutation(src, 2982));
5023 }
5024 
5025 pure @safe unittest
5026 {
5027     import std.internal.test.dummyrange;
5028     import std.meta : AliasSeq;
5029 
5030     auto src = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
5031     auto rsl = [4, 0, 6, 2, 1, 3, 5, 7, 8, 9, 10];
5032 
5033     foreach (T; AliasSeq!(
5034             DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random, int[]),
5035             DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random, int[])))
5036     {
5037         static assert(isRandomAccessRange!(T));
5038         static assert(hasLength!(T));
5039         auto dr = T(src.dup);
5040         dr = nthPermutation(dr, 2982);
5041 
5042         int idx;
5043         foreach (it; dr)
5044         {
5045             assert(it == rsl[idx++]);
5046         }
5047     }
5048 }