xref: /netbsd-src/external/gpl3/gcc/dist/libphobos/src/std/algorithm/sorting.d (revision b1e838363e3c6fc78a55519254d99869742dd33c)
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 {
foreach(i,_;T[0..$-1])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 {
foreach(i,_;T[0..$-1])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;
even(int a)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
fun(int a)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;
even(int a)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
version(StdUnittest)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 {
test(alias less)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";
myLess(int a,int 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];
foreach(s;seeds)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 
thisMerge1110     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     {
emptyMerge1122         @property bool empty()
1123         {
1124             return _lastFrontIndex == size_t.max;
1125         }
1126     }
1127 
frontMerge1128     @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 
frontIndexMerge1141     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 
popFrontMerge1158     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     {
backMerge1186         @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 
backIndexMerge1203         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 
popBackMerge1220         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     {
saveMerge1257         @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     {
lengthMerge1270         @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];
foreach(DummyType;AllDummyRanges)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 
validPredicates(E,less...)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  */
multiSort(less...)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 
multiSortPredFun(Range,funs...)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 
multiSortImpl(Range,SwapStrategy ss,funs...)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 
byX(const ref A lhs,const ref A rhs)1614     static bool byX(const ref A lhs, const ref A rhs)
1615     {
1616         return lhs.x < rhs.x;
1617     }
1618 
byY(const ref A lhs,const ref A rhs)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 @safe unittest
1646 {
lt(int a,int b)1647     bool lt(int a, int b) { return a < b; } static @system
1648     auto a = [2, 1];
1649     a.multiSort!(lt, lt);
1650     assert(a == [1, 2]);
1651 }
1652 
getPivot(alias less,Range)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 */
shortSort(alias less,Range)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
trustedMoveEmplace(T)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)];
foreach(ref e;a)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 */
sort5(alias lt,Range)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,
1926         Range)(Range r)
1927 if (((ss == SwapStrategy.unstable && (hasSwappableElements!Range ||
1928     hasAssignableElements!Range)) ||
1929     (ss != SwapStrategy.unstable && hasAssignableElements!Range)) &&
1930     isRandomAccessRange!Range &&
1931     hasSlicing!Range &&
1932     hasLength!Range)
1933     /+ Unstable sorting uses the quicksort algorithm, which uses swapAt,
1934        which either uses swap(...), requiring swappable elements, or just
1935        swaps using assignment.
1936        Stable sorting uses TimSort, which needs to copy elements into a buffer,
1937        requiring assignable elements. +/
1938 {
1939     import std.range : assumeSorted;
1940     alias lessFun = binaryFun!(less);
1941     alias LessRet = typeof(lessFun(r.front, r.front));    // instantiate lessFun
1942     static if (is(LessRet == bool))
1943     {
1944         static if (ss == SwapStrategy.unstable)
1945             quickSortImpl!(lessFun)(r, r.length);
1946         else //use Tim Sort for semistable & stable
1947             TimSortImpl!(lessFun, Range).sort(r, null);
1948 
1949         assert(isSorted!lessFun(r), "Failed to sort range of type " ~ Range.stringof);
1950     }
1951     else
1952     {
1953         static assert(false, "Invalid predicate passed to sort: " ~ less.stringof);
1954     }
1955     return assumeSorted!less(r);
1956 }
1957 
1958 ///
1959 @safe pure nothrow unittest
1960 {
1961     int[] array = [ 1, 2, 3, 4 ];
1962 
1963     // sort in descending order
1964     array.sort!("a > b");
1965     assert(array == [ 4, 3, 2, 1 ]);
1966 
1967     // sort in ascending order
1968     array.sort();
1969     assert(array == [ 1, 2, 3, 4 ]);
1970 
1971     // sort with reusable comparator and chain
1972     alias myComp = (x, y) => x > y;
1973     assert(array.sort!(myComp).release == [ 4, 3, 2, 1 ]);
1974 }
1975 
1976 ///
1977 @safe unittest
1978 {
1979     // Showcase stable sorting
1980     import std.algorithm.mutation : SwapStrategy;
1981     string[] words = [ "aBc", "a", "abc", "b", "ABC", "c" ];
1982     sort!("toUpper(a) < toUpper(b)", SwapStrategy.stable)(words);
1983     assert(words == [ "a", "aBc", "abc", "ABC", "b", "c" ]);
1984 }
1985 
1986 ///
1987 @safe unittest
1988 {
1989     // Sorting floating-point numbers in presence of NaN
1990     double[] numbers = [-0.0, 3.0, -2.0, double.nan, 0.0, -double.nan];
1991 
1992     import std.algorithm.comparison : equal;
1993     import std.math.operations : cmp;
1994     import std.math.traits : isIdentical;
1995 
1996     sort!((a, b) => cmp(a, b) < 0)(numbers);
1997 
1998     double[] sorted = [-double.nan, -2.0, -0.0, 0.0, 3.0, double.nan];
1999     assert(numbers.equal!isIdentical(sorted));
2000 }
2001 
2002 @safe unittest
2003 {
2004     // Simple regression benchmark
2005     import std.algorithm.iteration, std.algorithm.mutation;
2006     import std.array : array;
2007     import std.random : Random, uniform;
2008     import std.range : iota;
2009     Random rng;
2010     int[] a = iota(20148).map!(_ => uniform(-1000, 1000, rng)).array;
2011     static uint comps;
less(int a,int b)2012     static bool less(int a, int b) { ++comps; return a < b; }
2013     sort!less(a); // random numbers
2014     sort!less(a); // sorted ascending
2015     a.reverse();
2016     sort!less(a); // sorted descending
2017     a[] = 0;
2018     sort!less(a); // all equal
2019 
2020     // This should get smaller with time. On occasion it may go larger, but only
2021     // if there's thorough justification.
2022     debug enum uint watermark = 1676220;
2023     else enum uint watermark = 1676220;
2024 
2025     import std.conv;
2026     assert(comps <= watermark, text("You seem to have pessimized sort! ",
2027         watermark, " < ", comps));
2028     assert(comps >= watermark, text("You seem to have improved sort!",
2029         " Please update watermark from ", watermark, " to ", comps));
2030 }
2031 
2032 @safe unittest
2033 {
2034     import std.algorithm.internal : rndstuff;
2035     import std.algorithm.mutation : swapRanges;
2036     import std.random : Random = Xorshift, uniform;
2037     import std.uni : toUpper;
2038 
2039     // sort using delegate
2040     auto a = new int[100];
2041     auto rnd = Random(123_456_789);
foreach(ref e;a)2042     foreach (ref e; a)
2043     {
2044         e = uniform(-100, 100, rnd);
2045     }
2046 
2047     int i = 0;
greater2(int a,int b)2048     bool greater2(int a, int b) @safe { return a + i > b + i; }
2049     auto greater = &greater2;
2050     sort!(greater)(a);
2051     assert(isSorted!(greater)(a));
2052 
2053     // sort using string
2054     sort!("a < b")(a);
2055     assert(isSorted!("a < b")(a));
2056 
2057     // sort using function; all elements equal
foreach(ref e;a)2058     foreach (ref e; a)
2059     {
2060         e = 5;
2061     }
less(int a,int b)2062     static bool less(int a, int b) { return a < b; }
2063     sort!(less)(a);
2064     assert(isSorted!(less)(a));
2065 
2066     string[] words = [ "aBc", "a", "abc", "b", "ABC", "c" ];
lessi(string a,string b)2067     bool lessi(string a, string b) { return toUpper(a) < toUpper(b); }
2068     sort!(lessi, SwapStrategy.stable)(words);
2069     assert(words == [ "a", "aBc", "abc", "ABC", "b", "c" ]);
2070 
2071     // sort using ternary predicate
2072     //sort!("b - a")(a);
2073     //assert(isSorted!(less)(a));
2074 
2075     a = rndstuff!(int)();
2076     sort(a);
2077     assert(isSorted(a));
2078     auto b = rndstuff!(string)();
2079     sort!("toLower(a) < toLower(b)")(b);
2080     assert(isSorted!("toUpper(a) < toUpper(b)")(b));
2081 
2082     {
2083         // https://issues.dlang.org/show_bug.cgi?id=10317
2084         enum E_10317 { a, b }
2085         auto a_10317 = new E_10317[10];
2086         sort(a_10317);
2087     }
2088 
2089     {
2090         // https://issues.dlang.org/show_bug.cgi?id=7767
2091         // Unstable sort should complete without an excessive number of predicate calls
2092         // This would suggest it's running in quadratic time
2093 
2094         // Compilation error if predicate is not static, i.e. a nested function
2095         static uint comp;
pred(size_t a,size_t b)2096         static bool pred(size_t a, size_t b)
2097         {
2098             ++comp;
2099             return a < b;
2100         }
2101 
2102         size_t[] arr;
2103         arr.length = 1024;
2104 
2105         foreach (k; 0 .. arr.length) arr[k] = k;
2106         swapRanges(arr[0..$/2], arr[$/2..$]);
2107 
2108         sort!(pred, SwapStrategy.unstable)(arr);
2109         assert(comp < 25_000);
2110     }
2111 
2112     {
2113         import std.algorithm.mutation : swap;
2114 
2115         bool proxySwapCalled;
2116         struct S
2117         {
2118             int i;
2119             alias i this;
proxySwapS2120             void proxySwap(ref S other) { swap(i, other.i); proxySwapCalled = true; }
2121             @disable void opAssign(S value);
2122         }
2123 
2124         alias R = S[];
2125         R r = [S(3), S(2), S(1)];
2126         static assert(hasSwappableElements!R);
2127         static assert(!hasAssignableElements!R);
2128         r.sort();
2129         assert(proxySwapCalled);
2130     }
2131 
2132     // https://issues.dlang.org/show_bug.cgi?id=20751
2133     {
refPred(ref int a,ref int b)2134         static bool refPred(ref int a, ref int b)
2135         {
2136             return a < b;
2137         }
2138 
2139         auto sortedArr = [5,4,3,2,1].sort!refPred;
2140         sortedArr.equalRange(3);
2141     }
2142 }
2143 
quickSortImpl(alias less,Range)2144 private void quickSortImpl(alias less, Range)(Range r, size_t depth)
2145 {
2146     import std.algorithm.comparison : min, max;
2147     import std.algorithm.mutation : swap, swapAt;
2148     import std.conv : to;
2149 
2150     alias Elem = ElementType!(Range);
2151     enum size_t shortSortGetsBetter = max(32, 1024 / Elem.sizeof);
2152     static assert(shortSortGetsBetter >= 1, Elem.stringof ~ " "
2153         ~ to!string(Elem.sizeof));
2154 
2155     // partition
2156     while (r.length > shortSortGetsBetter)
2157     {
2158         if (depth == 0)
2159         {
2160             HeapOps!(less, Range).heapSort(r);
2161             return;
2162         }
2163         depth = depth >= depth.max / 2 ? (depth / 3) * 2 : (depth * 2) / 3;
2164 
2165         const pivotIdx = getPivot!(less)(r);
2166         auto pivot = r[pivotIdx];
2167 
2168         // partition
2169         r.swapAt(pivotIdx, r.length - 1);
2170         size_t lessI = size_t.max, greaterI = r.length - 1;
2171 
2172         outer: for (;;)
2173         {
2174             alias pred = binaryFun!less;
2175             while (pred(r[++lessI], pivot)) {}
2176             assert(lessI <= greaterI, "sort: invalid comparison function.");
2177             for (;;)
2178             {
2179                 if (greaterI == lessI) break outer;
2180                 if (!pred(pivot, r[--greaterI])) break;
2181             }
2182             assert(lessI <= greaterI, "sort: invalid comparison function.");
2183             if (lessI == greaterI) break;
2184             r.swapAt(lessI, greaterI);
2185         }
2186 
2187         r.swapAt(r.length - 1, lessI);
2188         auto left = r[0 .. lessI], right = r[lessI + 1 .. r.length];
2189         if (right.length > left.length)
2190         {
2191             swap(left, right);
2192         }
2193         .quickSortImpl!(less, Range)(right, depth);
2194         r = left;
2195     }
2196     // residual sort
2197     static if (shortSortGetsBetter > 1)
2198     {
2199         shortSort!(less, Range)(r);
2200     }
2201 }
2202 
2203 // Heap operations for random-access ranges
package(std)2204 package(std) template HeapOps(alias less, Range)
2205 {
2206     import std.algorithm.mutation : swapAt;
2207 
2208     static assert(isRandomAccessRange!Range, Range.stringof ~ " must be a"
2209         ~ " RandomAccessRange");
2210     static assert(hasLength!Range, Range.stringof ~ " must have length");
2211     static assert(hasSwappableElements!Range || hasAssignableElements!Range,
2212         Range.stringof ~ " must have swappable or assignable Elements");
2213 
2214     alias lessFun = binaryFun!less;
2215 
2216     //template because of https://issues.dlang.org/show_bug.cgi?id=12410
2217     void heapSort()(Range r)
2218     {
2219         // If true, there is nothing to do
2220         if (r.length < 2) return;
2221         // Build Heap
2222         buildHeap(r);
2223         // Sort
2224         for (size_t i = r.length - 1; i > 0; --i)
2225         {
2226             r.swapAt(0, i);
2227             percolate(r, 0, i);
2228         }
2229     }
2230 
2231     //template because of https://issues.dlang.org/show_bug.cgi?id=12410
2232     void buildHeap()(Range r)
2233     {
2234         immutable n = r.length;
2235         for (size_t i = n / 2; i-- > 0; )
2236         {
2237             siftDown(r, i, n);
2238         }
2239         assert(isHeap(r), "r is not a heap");
2240     }
2241 
2242     bool isHeap()(Range r)
2243     {
2244         size_t parent = 0;
2245         foreach (child; 1 .. r.length)
2246         {
2247             if (lessFun(r[parent], r[child])) return false;
2248             // Increment parent every other pass
2249             parent += !(child & 1);
2250         }
2251         return true;
2252     }
2253 
2254     // Sifts down r[parent] (which is initially assumed to be messed up) so the
2255     // heap property is restored for r[parent .. end].
2256     // template because of https://issues.dlang.org/show_bug.cgi?id=12410
2257     void siftDown()(Range r, size_t parent, immutable size_t end)
2258     {
2259         for (;;)
2260         {
2261             auto child = (parent + 1) * 2;
2262             if (child >= end)
2263             {
2264                 // Leftover left child?
2265                 if (child == end && lessFun(r[parent], r[--child]))
2266                     r.swapAt(parent, child);
2267                 break;
2268             }
2269             auto leftChild = child - 1;
2270             if (lessFun(r[child], r[leftChild])) child = leftChild;
2271             if (!lessFun(r[parent], r[child])) break;
2272             r.swapAt(parent, child);
2273             parent = child;
2274         }
2275     }
2276 
2277     // Alternate version of siftDown that performs fewer comparisons, see
2278     // https://en.wikipedia.org/wiki/Heapsort#Bottom-up_heapsort. The percolate
2279     // process first sifts the parent all the way down (without comparing it
2280     // against the leaves), and then a bit up until the heap property is
2281     // restored. So there are more swaps but fewer comparisons. Gains are made
2282     // when the final position is likely to end toward the bottom of the heap,
2283     // so not a lot of sifts back are performed.
2284     //template because of https://issues.dlang.org/show_bug.cgi?id=12410
2285     void percolate()(Range r, size_t parent, immutable size_t end)
2286     {
2287         immutable root = parent;
2288 
2289         // Sift down
2290         for (;;)
2291         {
2292             auto child = (parent + 1) * 2;
2293 
2294             if (child >= end)
2295             {
2296                 if (child == end)
2297                 {
2298                     // Leftover left node.
2299                     --child;
2300                     r.swapAt(parent, child);
2301                     parent = child;
2302                 }
2303                 break;
2304             }
2305 
2306             auto leftChild = child - 1;
2307             if (lessFun(r[child], r[leftChild])) child = leftChild;
2308             r.swapAt(parent, child);
2309             parent = child;
2310         }
2311 
2312         // Sift up
2313         for (auto child = parent; child > root; child = parent)
2314         {
2315             parent = (child - 1) / 2;
2316             if (!lessFun(r[parent], r[child])) break;
2317             r.swapAt(parent, child);
2318         }
2319     }
2320 }
2321 
2322 // Tim Sort implementation
TimSortImpl(alias pred,R)2323 private template TimSortImpl(alias pred, R)
2324 {
2325     import core.bitop : bsr;
2326     import std.array : uninitializedArray;
2327 
2328     static assert(isRandomAccessRange!R, R.stringof ~ " must be a"
2329         ~ " RandomAccessRange");
2330     static assert(hasLength!R, R.stringof ~ " must have a length");
2331     static assert(hasSlicing!R, R.stringof ~ " must support slicing");
2332     static assert(hasAssignableElements!R, R.stringof ~ " must have"
2333         ~ " assignable elements");
2334 
2335     alias T = ElementType!R;
2336 
2337     alias less = binaryFun!pred;
2338     bool greater()(auto ref T a, auto ref T b) { return less(b, a); }
2339     bool greaterEqual()(auto ref T a, auto ref T b) { return !less(a, b); }
2340     bool lessEqual()(auto ref T a, auto ref T b) { return !less(b, a); }
2341 
2342     enum minimalMerge = 128;
2343     enum minimalGallop = 7;
2344     enum minimalStorage = 256;
2345     enum stackSize = 40;
2346 
2347     struct Slice{ size_t base, length; }
2348 
2349     // Entry point for tim sort
2350     void sort()(R range, T[] temp)
2351     {
2352         import std.algorithm.comparison : min;
2353         import std.format : format;
2354 
2355         // Do insertion sort on small range
2356         if (range.length <= minimalMerge)
2357         {
2358             binaryInsertionSort(range);
2359             return;
2360         }
2361 
2362         immutable minRun = minRunLength(range.length);
2363         immutable minTemp = min(range.length / 2, minimalStorage);
2364         size_t minGallop = minimalGallop;
2365         Slice[stackSize] stack = void;
2366         size_t stackLen = 0;
2367 
2368         // Allocate temporary memory if not provided by user
2369         if (temp.length < minTemp) temp = () @trusted { return uninitializedArray!(T[])(minTemp); }();
2370 
2371         for (size_t i = 0; i < range.length; )
2372         {
2373             // Find length of first run in list
2374             size_t runLen = firstRun(range[i .. range.length]);
2375 
2376             // If run has less than minRun elements, extend using insertion sort
2377             if (runLen < minRun)
2378             {
2379                 // Do not run farther than the length of the range
2380                 immutable force = range.length - i > minRun ? minRun : range.length - i;
2381                 binaryInsertionSort(range[i .. i + force], runLen);
2382                 runLen = force;
2383             }
2384 
2385             // Push run onto stack
2386             stack[stackLen++] = Slice(i, runLen);
2387             i += runLen;
2388 
2389             // Collapse stack so that (e1 > e2 + e3 && e2 > e3)
2390             // STACK is | ... e1 e2 e3 >
2391             while (stackLen > 1)
2392             {
2393                 immutable run4 = stackLen - 1;
2394                 immutable run3 = stackLen - 2;
2395                 immutable run2 = stackLen - 3;
2396                 immutable run1 = stackLen - 4;
2397 
2398                 if ( (stackLen > 2 && stack[run2].length <= stack[run3].length + stack[run4].length) ||
2399                      (stackLen > 3 && stack[run1].length <= stack[run3].length + stack[run2].length) )
2400                 {
2401                     immutable at = stack[run2].length < stack[run4].length ? run2 : run3;
2402                     mergeAt(range, stack[0 .. stackLen], at, minGallop, temp);
2403                 }
2404                 else if (stack[run3].length > stack[run4].length) break;
2405                 else mergeAt(range, stack[0 .. stackLen], run3, minGallop, temp);
2406 
2407                 stackLen -= 1;
2408             }
2409 
2410             // Assert that the code above established the invariant correctly
2411             version (StdUnittest)
2412             {
2413                 if (stackLen == 2)
2414                 {
2415                     assert(stack[0].length > stack[1].length, format!
2416                         "stack[0].length %s > stack[1].length %s"(
2417                             stack[0].length, stack[1].length
2418                         ));
2419                 }
2420                 else if (stackLen > 2)
2421                 {
2422                     foreach (k; 2 .. stackLen)
2423                     {
2424                         assert(stack[k - 2].length > stack[k - 1].length + stack[k].length,
2425                             format!"stack[k - 2].length %s > stack[k - 1].length %s + stack[k].length %s"(
2426                                 stack[k - 2].length, stack[k - 1].length, stack[k].length
2427                             ));
2428                         assert(stack[k - 1].length > stack[k].length,
2429                             format!"stack[k - 1].length %s > stack[k].length %s"(
2430                                 stack[k - 1].length, stack[k].length
2431                             ));
2432                     }
2433                 }
2434             }
2435         }
2436 
2437         // Force collapse stack until there is only one run left
2438         while (stackLen > 1)
2439         {
2440             immutable run3 = stackLen - 1;
2441             immutable run2 = stackLen - 2;
2442             immutable run1 = stackLen - 3;
2443             immutable at = stackLen >= 3 && stack[run1].length <= stack[run3].length
2444                 ? run1 : run2;
2445             mergeAt(range, stack[0 .. stackLen], at, minGallop, temp);
2446             --stackLen;
2447         }
2448     }
2449 
2450     // Calculates optimal value for minRun:
2451     // take first 6 bits of n and add 1 if any lower bits are set
2452     size_t minRunLength()(size_t n)
2453     {
2454         immutable shift = bsr(n)-5;
2455         auto result = (n >> shift) + !!(n & ~((1 << shift)-1));
2456         return result;
2457     }
2458 
2459     // Returns length of first run in range
2460     size_t firstRun()(R range)
2461     out(ret)
2462     {
2463         assert(ret <= range.length, "ret must be less or equal than"
2464             ~ " range.length");
2465     }
2466     do
2467     {
2468         import std.algorithm.mutation : reverse;
2469 
2470         if (range.length < 2) return range.length;
2471 
2472         size_t i = 2;
2473         if (lessEqual(range[0], range[1]))
2474         {
2475             while (i < range.length && lessEqual(range[i-1], range[i])) ++i;
2476         }
2477         else
2478         {
2479             while (i < range.length && greater(range[i-1], range[i])) ++i;
2480             reverse(range[0 .. i]);
2481         }
2482         return i;
2483     }
2484 
2485     // A binary insertion sort for building runs up to minRun length
2486     void binaryInsertionSort()(R range, size_t sortedLen = 1)
2487     out
2488     {
2489         if (!__ctfe) assert(isSorted!pred(range), "range must be sorted");
2490     }
2491     do
2492     {
2493         import std.algorithm.mutation : move;
2494 
2495         for (; sortedLen < range.length; ++sortedLen)
2496         {
2497             T item = range.moveAt(sortedLen);
2498             size_t lower = 0;
2499             size_t upper = sortedLen;
2500             while (upper != lower)
2501             {
2502                 size_t center = (lower + upper) / 2;
2503                 if (less(item, range[center])) upper = center;
2504                 else lower = center + 1;
2505             }
2506             //Currently (DMD 2.061) moveAll+retro is slightly less
2507             //efficient then stright 'for' loop
2508             //11 instructions vs 7 in the innermost loop [checked on Win32]
2509             //moveAll(retro(range[lower .. sortedLen]),
2510             //            retro(range[lower+1 .. sortedLen+1]));
2511             for (upper=sortedLen; upper > lower; upper--)
2512             {
2513                 static if (hasLvalueElements!R)
2514                     move(range[upper -1], range[upper]);
2515                 else
2516                     range[upper] = range.moveAt(upper - 1);
2517             }
2518 
2519             static if (hasLvalueElements!R)
2520                 move(item, range[lower]);
2521             else
2522                 range[lower] = move(item);
2523         }
2524     }
2525 
2526     // Merge two runs in stack (at, at + 1)
2527     void mergeAt()(R range, Slice[] stack, immutable size_t at, ref size_t minGallop, ref T[] temp)
2528     in
2529     {
2530         import std.format : format;
2531         assert(stack.length >= 2, "stack be be greater than 1");
2532         assert(stack.length - at == 2 || stack.length - at == 3,
2533             format!"stack.length - at %s must be 2 or 3"(stack.length - at));
2534     }
2535     do
2536     {
2537         immutable base = stack[at].base;
2538         immutable mid  = stack[at].length;
2539         immutable len  = stack[at + 1].length + mid;
2540 
2541         // Pop run from stack
2542         stack[at] = Slice(base, len);
2543         if (stack.length - at == 3) stack[$ - 2] = stack[$ - 1];
2544 
2545         // Merge runs (at, at + 1)
2546         return merge(range[base .. base + len], mid, minGallop, temp);
2547     }
2548 
2549     // Merge two runs in a range. Mid is the starting index of the second run.
2550     // minGallop and temp are references; The calling function must receive the updated values.
2551     void merge()(R range, size_t mid, ref size_t minGallop, ref T[] temp)
2552     in
2553     {
2554         if (!__ctfe)
2555         {
2556             assert(isSorted!pred(range[0 .. mid]), "range[0 .. mid] must be"
2557                 ~ " sorted");
2558             assert(isSorted!pred(range[mid .. range.length]), "range[mid .."
2559                 ~ " range.length] must be sorted");
2560         }
2561     }
2562     do
2563     {
2564         assert(mid < range.length, "mid must be less than the length of the"
2565             ~ " range");
2566 
2567         // Reduce range of elements
2568         immutable firstElement = gallopForwardUpper(range[0 .. mid], range[mid]);
2569         immutable lastElement  = gallopReverseLower(range[mid .. range.length], range[mid - 1]) + mid;
2570         range = range[firstElement .. lastElement];
2571         mid -= firstElement;
2572 
2573         if (mid == 0 || mid == range.length) return;
2574 
2575         // Call function which will copy smaller run into temporary memory
2576         if (mid <= range.length / 2)
2577         {
2578             temp = ensureCapacity(mid, temp);
2579             minGallop = mergeLo(range, mid, minGallop, temp);
2580         }
2581         else
2582         {
2583             temp = ensureCapacity(range.length - mid, temp);
2584             minGallop = mergeHi(range, mid, minGallop, temp);
2585         }
2586     }
2587 
2588     // Enlarge size of temporary memory if needed
2589     T[] ensureCapacity()(size_t minCapacity, T[] temp)
2590     out(ret)
2591     {
2592         assert(ret.length >= minCapacity, "ensuring the capacity failed");
2593     }
2594     do
2595     {
2596         if (temp.length < minCapacity)
2597         {
2598             size_t newSize = 1<<(bsr(minCapacity)+1);
2599             //Test for overflow
2600             if (newSize < minCapacity) newSize = minCapacity;
2601 
2602             if (__ctfe) temp.length = newSize;
2603             else temp = () @trusted { return uninitializedArray!(T[])(newSize); }();
2604         }
2605         return temp;
2606     }
2607 
2608     // Merge front to back. Returns new value of minGallop.
2609     // temp must be large enough to store range[0 .. mid]
2610     size_t mergeLo()(R range, immutable size_t mid, size_t minGallop, T[] temp)
2611     out
2612     {
2613         if (!__ctfe) assert(isSorted!pred(range), "the range must be sorted");
2614     }
2615     do
2616     {
2617         import std.algorithm.mutation : copy;
2618 
2619         assert(mid <= range.length, "mid must be less than the length of the"
2620             ~ " range");
2621         assert(temp.length >= mid, "temp.length must be greater or equal to mid");
2622 
2623         // Copy run into temporary memory
2624         temp = temp[0 .. mid];
2625         copy(range[0 .. mid], temp);
2626 
2627         // Move first element into place
2628         moveEntry(range, mid, range, 0);
2629 
2630         size_t i = 1, lef = 0, rig = mid + 1;
2631         size_t count_lef, count_rig;
2632         immutable lef_end = temp.length - 1;
2633 
2634         if (lef < lef_end && rig < range.length)
2635         outer: while (true)
2636         {
2637             count_lef = 0;
2638             count_rig = 0;
2639 
2640             // Linear merge
2641             while ((count_lef | count_rig) < minGallop)
2642             {
2643                 if (lessEqual(temp[lef], range[rig]))
2644                 {
2645                     moveEntry(temp, lef++, range, i++);
2646                     if (lef >= lef_end) break outer;
2647                     ++count_lef;
2648                     count_rig = 0;
2649                 }
2650                 else
2651                 {
2652                     moveEntry(range, rig++, range, i++);
2653                     if (rig >= range.length) break outer;
2654                     count_lef = 0;
2655                     ++count_rig;
2656                 }
2657             }
2658 
2659             // Gallop merge
2660             do
2661             {
2662                 count_lef = gallopForwardUpper(temp[lef .. $], range[rig]);
2663                 foreach (j; 0 .. count_lef) moveEntry(temp, lef++, range, i++);
2664                 if (lef >= temp.length) break outer;
2665 
2666                 count_rig = gallopForwardLower(range[rig .. range.length], temp[lef]);
2667                 foreach (j; 0 .. count_rig) moveEntry(range, rig++, range, i++);
2668                 if (rig >= range.length) while (true)
2669                 {
2670                     moveEntry(temp, lef++, range, i++);
2671                     if (lef >= temp.length) break outer;
2672                 }
2673 
2674                 if (minGallop > 0) --minGallop;
2675             }
2676             while (count_lef >= minimalGallop || count_rig >= minimalGallop);
2677 
2678             minGallop += 2;
2679         }
2680 
2681         // Move remaining elements from right
2682         while (rig < range.length)
2683             moveEntry(range, rig++, range, i++);
2684 
2685         // Move remaining elements from left
2686         while (lef < temp.length)
2687             moveEntry(temp, lef++, range, i++);
2688 
2689         return minGallop > 0 ? minGallop : 1;
2690     }
2691 
2692     // Merge back to front. Returns new value of minGallop.
2693     // temp must be large enough to store range[mid .. range.length]
2694     size_t mergeHi()(R range, immutable size_t mid, size_t minGallop, T[] temp)
2695     out
2696     {
2697         if (!__ctfe) assert(isSorted!pred(range), "the range must be sorted");
2698     }
2699     do
2700     {
2701         import std.algorithm.mutation : copy;
2702         import std.format : format;
2703 
2704         assert(mid <= range.length, "mid must be less or equal to range.length");
2705         assert(temp.length >= range.length - mid, format!
2706             "temp.length %s >= range.length %s - mid %s"(temp.length,
2707             range.length, mid));
2708 
2709         // Copy run into temporary memory
2710         temp = temp[0 .. range.length - mid];
2711         copy(range[mid .. range.length], temp);
2712 
2713         // Move first element into place
2714         moveEntry(range, mid - 1, range, range.length - 1);
2715 
2716         size_t i = range.length - 2, lef = mid - 2, rig = temp.length - 1;
2717         size_t count_lef, count_rig;
2718 
2719         outer:
2720         while (true)
2721         {
2722             count_lef = 0;
2723             count_rig = 0;
2724 
2725             // Linear merge
2726             while ((count_lef | count_rig) < minGallop)
2727             {
2728                 if (greaterEqual(temp[rig], range[lef]))
2729                 {
2730                     moveEntry(temp, rig, range, i--);
2731                     if (rig == 1)
2732                     {
2733                         // Move remaining elements from left
2734                         while (true)
2735                         {
2736                             moveEntry(range, lef, range, i--);
2737                             if (lef == 0) break;
2738                             --lef;
2739                         }
2740 
2741                         // Move last element into place
2742                         moveEntry(temp, 0, range, i);
2743 
2744                         break outer;
2745                     }
2746                     --rig;
2747                     count_lef = 0;
2748                     ++count_rig;
2749                 }
2750                 else
2751                 {
2752                     moveEntry(range, lef, range, i--);
2753                     if (lef == 0) while (true)
2754                     {
2755                         moveEntry(temp, rig, range, i--);
2756                         if (rig == 0) break outer;
2757                         --rig;
2758                     }
2759                     --lef;
2760                     ++count_lef;
2761                     count_rig = 0;
2762                 }
2763             }
2764 
2765             // Gallop merge
2766             do
2767             {
2768                 count_rig = rig - gallopReverseLower(temp[0 .. rig], range[lef]);
2769                 foreach (j; 0 .. count_rig)
2770                 {
2771                     moveEntry(temp, rig, range, i--);
2772                     if (rig == 0) break outer;
2773                     --rig;
2774                 }
2775 
2776                 count_lef = lef - gallopReverseUpper(range[0 .. lef], temp[rig]);
2777                 foreach (j; 0 .. count_lef)
2778                 {
2779                     moveEntry(range, lef, range, i--);
2780                     if (lef == 0) while (true)
2781                     {
2782                         moveEntry(temp, rig, range, i--);
2783                         if (rig == 0) break outer;
2784                         --rig;
2785                     }
2786                     --lef;
2787                 }
2788 
2789                 if (minGallop > 0) --minGallop;
2790             }
2791             while (count_lef >= minimalGallop || count_rig >= minimalGallop);
2792 
2793             minGallop += 2;
2794         }
2795 
2796         return minGallop > 0 ? minGallop : 1;
2797     }
2798 
2799     // false = forward / lower, true = reverse / upper
2800     template gallopSearch(bool forwardReverse, bool lowerUpper)
2801     {
2802         // Gallop search on range according to attributes forwardReverse and lowerUpper
2803         size_t gallopSearch(R)(R range, T value)
2804         out(ret)
2805         {
2806             assert(ret <= range.length, "ret must be less or equal to"
2807                 ~ " range.length");
2808         }
2809         do
2810         {
2811             size_t lower = 0, center = 1, upper = range.length;
2812             alias gap = center;
2813 
2814             static if (forwardReverse)
2815             {
2816                 static if (!lowerUpper) alias comp = lessEqual; // reverse lower
2817                 static if (lowerUpper)  alias comp = less;      // reverse upper
2818 
2819                 // Gallop Search Reverse
2820                 while (gap <= upper)
2821                 {
2822                     if (comp(value, range[upper - gap]))
2823                     {
2824                         upper -= gap;
2825                         gap *= 2;
2826                     }
2827                     else
2828                     {
2829                         lower = upper - gap;
2830                         break;
2831                     }
2832                 }
2833 
2834                 // Binary Search Reverse
2835                 while (upper != lower)
2836                 {
2837                     center = lower + (upper - lower) / 2;
2838                     if (comp(value, range[center])) upper = center;
2839                     else lower = center + 1;
2840                 }
2841             }
2842             else
2843             {
2844                 static if (!lowerUpper) alias comp = greater;      // forward lower
2845                 static if (lowerUpper)  alias comp = greaterEqual; // forward upper
2846 
2847                 // Gallop Search Forward
2848                 while (lower + gap < upper)
2849                 {
2850                     if (comp(value, range[lower + gap]))
2851                     {
2852                         lower += gap;
2853                         gap *= 2;
2854                     }
2855                     else
2856                     {
2857                         upper = lower + gap;
2858                         break;
2859                     }
2860                 }
2861 
2862                 // Binary Search Forward
2863                 while (lower != upper)
2864                 {
2865                     center = lower + (upper - lower) / 2;
2866                     if (comp(value, range[center])) lower = center + 1;
2867                     else upper = center;
2868                 }
2869             }
2870 
2871             return lower;
2872         }
2873     }
2874 
2875     alias gallopForwardLower = gallopSearch!(false, false);
2876     alias gallopForwardUpper = gallopSearch!(false,  true);
2877     alias gallopReverseLower = gallopSearch!( true, false);
2878     alias gallopReverseUpper = gallopSearch!( true,  true);
2879 
2880     /// Helper method that moves from[fIdx] into to[tIdx] if both are lvalues and
2881     /// uses a plain assignment if not (necessary for backwards compatibility)
2882     void moveEntry(X, Y)(ref X from, const size_t fIdx, ref Y to, const size_t tIdx)
2883     {
2884         // This template is instantiated with different combinations of range (R) and temp (T[]).
2885         // T[] obviously has lvalue-elements, so checking R should be enough here
2886         static if (hasLvalueElements!R)
2887         {
2888             import core.lifetime : move;
2889             move(from[fIdx], to[tIdx]);
2890         }
2891         else
2892             to[tIdx] = from[fIdx];
2893     }
2894 }
2895 
2896 @safe unittest
2897 {
2898     import std.random : Random, uniform, randomShuffle;
2899 
2900     // Element type with two fields
2901     static struct E
2902     {
2903         size_t value, index;
2904     }
2905 
2906     // Generates data especially for testing sorting with Timsort
genSampleData(uint seed)2907     static E[] genSampleData(uint seed) @safe
2908     {
2909         import std.algorithm.mutation : swap, swapRanges;
2910 
2911         auto rnd = Random(seed);
2912 
2913         E[] arr;
2914         arr.length = 64 * 64;
2915 
2916         // We want duplicate values for testing stability
2917         foreach (i, ref v; arr) v.value = i / 64;
2918 
2919         // Swap ranges at random middle point (test large merge operation)
2920         immutable mid = uniform(arr.length / 4, arr.length / 4 * 3, rnd);
2921         swapRanges(arr[0 .. mid], arr[mid .. $]);
2922 
2923         // Shuffle last 1/8 of the array (test insertion sort and linear merge)
2924         randomShuffle(arr[$ / 8 * 7 .. $], rnd);
2925 
2926         // Swap few random elements (test galloping mode)
2927         foreach (i; 0 .. arr.length / 64)
2928         {
2929             immutable a = uniform(0, arr.length, rnd), b = uniform(0, arr.length, rnd);
2930             swap(arr[a], arr[b]);
2931         }
2932 
2933         // Now that our test array is prepped, store original index value
2934         // This will allow us to confirm the array was sorted stably
2935         foreach (i, ref v; arr) v.index = i;
2936 
2937         return arr;
2938     }
2939 
2940     // Tests the Timsort function for correctness and stability
testSort(uint seed)2941     static bool testSort(uint seed)
2942     {
2943         import std.format : format;
2944         auto arr = genSampleData(seed);
2945 
2946         // Now sort the array!
2947         static bool comp(E a, E b)
2948         {
2949             return a.value < b.value;
2950         }
2951 
2952         sort!(comp, SwapStrategy.stable)(arr);
2953 
2954         // Test that the array was sorted correctly
2955         assert(isSorted!comp(arr), "arr must be sorted");
2956 
2957         // Test that the array was sorted stably
2958         foreach (i; 0 .. arr.length - 1)
2959         {
2960             if (arr[i].value == arr[i + 1].value)
2961                 assert(arr[i].index < arr[i + 1].index, format!
2962                     "arr[i %s].index %s < arr[i + 1].index %s"(
2963                     i, arr[i].index, arr[i + 1].index));
2964         }
2965 
2966         return true;
2967     }
2968 
2969     enum seed = 310614065;
2970     testSort(seed);
2971 
2972     enum result = testSort(seed);
2973     assert(result == true, "invalid result");
2974 }
2975 
2976 // https://issues.dlang.org/show_bug.cgi?id=4584
2977 @safe unittest
2978 {
2979     assert(isSorted!"a < b"(sort!("a < b", SwapStrategy.stable)(
2980        [83, 42, 85, 86, 87, 22, 89, 30, 91, 46, 93, 94, 95, 6,
2981          97, 14, 33, 10, 101, 102, 103, 26, 105, 106, 107, 6]
2982     )));
2983 
2984 }
2985 
2986 @safe unittest
2987 {
2988     //test stable sort + zip
2989     import std.range;
2990     auto x = [10, 50, 60, 60, 20];
2991     dchar[] y = "abcde"d.dup;
2992 
2993     sort!("a[0] < b[0]", SwapStrategy.stable)(zip(x, y));
2994     assert(x == [10, 20, 50, 60, 60]);
2995     assert(y == "aebcd"d);
2996 }
2997 
2998 // https://issues.dlang.org/show_bug.cgi?id=14223
2999 @safe unittest
3000 {
3001     import std.array, std.range;
3002     auto arr = chain(iota(0, 384), iota(0, 256), iota(0, 80), iota(0, 64), iota(0, 96)).array;
3003     sort!("a < b", SwapStrategy.stable)(arr);
3004 }
3005 
3006 @safe unittest
3007 {
3008     static struct NoCopy
3009     {
3010         pure nothrow @nogc @safe:
3011 
3012         int key;
thisNoCopy3013         this(scope const ref NoCopy)
3014         {
3015             assert(false, "Tried to copy struct!");
3016         }
opAssignNoCopy3017         ref opAssign()(scope const auto ref NoCopy other)
3018         {
3019             assert(false, "Tried to copy struct!");
3020         }
thisNoCopy3021         this(this) {}
3022     }
3023 
makeArray(const size_t size)3024     static NoCopy[] makeArray(const size_t size)
3025     {
3026         NoCopy[] array = new NoCopy[](size);
3027         foreach (const i, ref t; array[0..$/2]) t.key = cast(int) (size - i);
3028         foreach (const i, ref t; array[$/2..$]) t.key = cast(int) i;
3029         return array;
3030     }
3031 
3032     alias cmp = (ref NoCopy a, ref NoCopy b) => a.key < b.key;
3033     enum minMerge = TimSortImpl!(cmp, NoCopy[]).minimalMerge;
3034 
3035     sort!(cmp, SwapStrategy.unstable)(makeArray(20));
3036     sort!(cmp, SwapStrategy.stable)(makeArray(minMerge - 5));
3037     sort!(cmp, SwapStrategy.stable)(makeArray(minMerge + 5));
3038 }
3039 
3040 // schwartzSort
3041 /**
3042 Alternative sorting method that should be used when comparing keys involves an
3043 expensive computation.
3044 
3045 Instead of using `less(a, b)` for comparing elements,
3046 `schwartzSort` uses `less(transform(a), transform(b))`. The values of the
3047 `transform` function are precomputed in a temporary array, thus saving on
3048 repeatedly computing it. Conversely, if the cost of `transform` is small
3049 compared to the cost of allocating and filling the precomputed array, `sort`
3050 may be faster and therefore preferable.
3051 
3052 This approach to sorting is akin to the $(HTTP
3053 wikipedia.org/wiki/Schwartzian_transform, Schwartzian transform), also known as
3054 the decorate-sort-undecorate pattern in Python and Lisp. The complexity is the
3055 same as that of the corresponding `sort`, but `schwartzSort` evaluates
3056 `transform` only `r.length` times (less than half when compared to regular
3057 sorting). The usage can be best illustrated with an example.
3058 
3059 Example:
3060 ----
3061 uint hashFun(string) { ... expensive computation ... }
3062 string[] array = ...;
3063 // Sort strings by hash, slow
3064 sort!((a, b) => hashFun(a) < hashFun(b))(array);
3065 // Sort strings by hash, fast (only computes arr.length hashes):
3066 schwartzSort!(hashFun, "a < b")(array);
3067 ----
3068 
3069 The `schwartzSort` function might require less temporary data and
3070 be faster than the Perl idiom or the decorate-sort-undecorate idiom
3071 present in Python and Lisp. This is because sorting is done in-place
3072 and only minimal extra data (one array of transformed elements) is
3073 created.
3074 
3075 To check whether an array was sorted and benefit of the speedup of
3076 Schwartz sorting, a function `schwartzIsSorted` is not provided
3077 because the effect can be achieved by calling $(D
3078 isSorted!less(map!transform(r))).
3079 
3080 Params:
3081     transform = The transformation to apply. Either a unary function
3082                 (`unaryFun!transform(element)`), or a binary function
3083                 (`binaryFun!transform(element, index)`).
3084     less = The predicate to sort the transformed elements by.
3085     ss = The swapping strategy to use.
3086     r = The range to sort.
3087 
3088 Returns: The initial range wrapped as a `SortedRange` with the
3089 predicate `(a, b) => binaryFun!less(transform(a), transform(b))`.
3090  */
3091 SortedRange!(R, ((a, b) => binaryFun!less(unaryFun!transform(a),
3092                                           unaryFun!transform(b))))
3093 schwartzSort(alias transform, alias less = "a < b",
3094         SwapStrategy ss = SwapStrategy.unstable, R)(R r)
3095 if (isRandomAccessRange!R && hasLength!R && hasSwappableElements!R &&
3096     !is(typeof(binaryFun!less) == SwapStrategy))
3097 {
3098     import core.lifetime : emplace;
3099     import std.range : zip, SortedRange;
3100     import std.string : representation;
3101 
3102     static if (is(typeof(unaryFun!transform(r.front))))
3103     {
3104         alias transformFun = unaryFun!transform;
3105         alias TB = typeof(transformFun(r.front));
3106         enum isBinary = false;
3107     }
3108     else static if (is(typeof(binaryFun!transform(r.front, 0))))
3109     {
3110         alias transformFun = binaryFun!transform;
3111         alias TB = typeof(transformFun(r.front, 0));
3112         enum isBinary = true;
3113     }
3114     else
3115         static assert(false, "unsupported `transform` alias");
3116 
3117     // The `transform` function might return a qualified type, e.g. const(int).
3118     // Strip qualifiers if possible s.t. the temporary array is sortable.
3119     static if (is(TB : Unqual!TB))
3120         alias T = Unqual!TB;
3121     else
3122         static assert(false, "`transform` returns an unsortable qualified type: " ~ TB.stringof);
3123 
trustedMalloc()3124     static trustedMalloc()(size_t len) @trusted
3125     {
3126         import core.checkedint : mulu;
3127         import core.memory : pureMalloc;
3128         bool overflow;
3129         const nbytes = mulu(len, T.sizeof, overflow);
3130         if (overflow) assert(false, "multiplication overflowed");
3131         T[] result = (cast(T*) pureMalloc(nbytes))[0 .. len];
3132         static if (hasIndirections!T)
3133         {
3134             import core.memory : GC;
3135             GC.addRange(result.ptr, nbytes);
3136         }
3137         return result;
3138     }
3139     auto xform1 = trustedMalloc(r.length);
3140 
3141     size_t length;
scope(exit)3142     scope(exit)
3143     {
3144         static if (hasElaborateDestructor!T)
3145         {
3146             foreach (i; 0 .. length) collectException(destroy(xform1[i]));
3147         }
3148         static void trustedFree()(T[] p) @trusted
3149         {
3150             import core.memory : pureFree;
3151             static if (hasIndirections!T)
3152             {
3153                 import core.memory : GC;
3154                 GC.removeRange(p.ptr);
3155             }
3156             pureFree(p.ptr);
3157         }
3158         trustedFree(xform1);
3159     }
3160     for (; length != r.length; ++length)
3161     {
3162         static if (isBinary)
3163             emplace(&xform1[length], transformFun(r[length], length));
3164         else
3165             emplace(&xform1[length], transformFun(r[length]));
3166     }
3167     // Make sure we use ubyte[] and ushort[], not char[] and wchar[]
3168     // for the intermediate array, lest zip gets confused.
3169     static if (isNarrowString!(typeof(xform1)))
3170     {
3171         auto xform = xform1.representation();
3172     }
3173     else
3174     {
3175         alias xform = xform1;
3176     }
3177     zip(xform, r).sort!((a, b) => binaryFun!less(a[0], b[0]), ss)();
3178     return typeof(return)(r);
3179 }
3180 
3181 /// ditto
3182 auto schwartzSort(alias transform, SwapStrategy ss, R)(R r)
3183 if (isRandomAccessRange!R && hasLength!R && hasSwappableElements!R)
3184 {
3185     return schwartzSort!(transform, "a < b", ss, R)(r);
3186 }
3187 
3188 ///
3189 @safe pure unittest
3190 {
3191     import std.algorithm.iteration : map;
3192     import std.numeric : entropy;
3193 
3194     auto lowEnt = [ 1.0, 0, 0 ],
3195          midEnt = [ 0.1, 0.1, 0.8 ],
3196         highEnt = [ 0.31, 0.29, 0.4 ];
3197     auto arr = new double[][3];
3198     arr[0] = midEnt;
3199     arr[1] = lowEnt;
3200     arr[2] = highEnt;
3201 
3202     schwartzSort!(entropy, "a > b")(arr);
3203 
3204     assert(arr[0] == highEnt);
3205     assert(arr[1] == midEnt);
3206     assert(arr[2] == lowEnt);
3207     assert(isSorted!("a > b")(map!(entropy)(arr)));
3208 }
3209 
3210 @safe pure unittest
3211 {
3212     import std.algorithm.iteration : map;
3213     import std.numeric : entropy;
3214 
3215     auto lowEnt = [ 1.0, 0, 0 ],
3216         midEnt = [ 0.1, 0.1, 0.8 ],
3217         highEnt = [ 0.31, 0.29, 0.4 ];
3218     auto arr = new double[][3];
3219     arr[0] = midEnt;
3220     arr[1] = lowEnt;
3221     arr[2] = highEnt;
3222 
3223     schwartzSort!(entropy, "a < b")(arr);
3224 
3225     assert(arr[0] == lowEnt);
3226     assert(arr[1] == midEnt);
3227     assert(arr[2] == highEnt);
3228     assert(isSorted!("a < b")(map!(entropy)(arr)));
3229 }
3230 
3231 @safe pure unittest
3232 {
3233     // binary transform function
3234     string[] strings = [ "one", "two", "three" ];
3235     schwartzSort!((element, index) => size_t.max - index)(strings);
3236     assert(strings == [ "three", "two", "one" ]);
3237 }
3238 
3239 // https://issues.dlang.org/show_bug.cgi?id=4909
3240 @safe pure unittest
3241 {
3242     import std.typecons : Tuple;
3243     Tuple!(char)[] chars;
3244     schwartzSort!"a[0]"(chars);
3245 }
3246 
3247 // https://issues.dlang.org/show_bug.cgi?id=5924
3248 @safe pure unittest
3249 {
3250     import std.typecons : Tuple;
3251     Tuple!(char)[] chars;
3252     schwartzSort!((Tuple!(char) c){ return c[0]; })(chars);
3253 }
3254 
3255 // https://issues.dlang.org/show_bug.cgi?id=13965
3256 @safe pure unittest
3257 {
3258     import std.typecons : Tuple;
3259     Tuple!(char)[] chars;
3260     schwartzSort!("a[0]", SwapStrategy.stable)(chars);
3261 }
3262 
3263 // https://issues.dlang.org/show_bug.cgi?id=13965
3264 @safe pure unittest
3265 {
3266     import std.algorithm.iteration : map;
3267     import std.numeric : entropy;
3268 
3269     auto lowEnt = [ 1.0, 0, 0 ],
3270         midEnt = [ 0.1, 0.1, 0.8 ],
3271         highEnt = [ 0.31, 0.29, 0.4 ];
3272     auto arr = new double[][3];
3273     arr[0] = midEnt;
3274     arr[1] = lowEnt;
3275     arr[2] = highEnt;
3276 
3277     schwartzSort!(entropy, SwapStrategy.stable)(arr);
3278 
3279     assert(arr[0] == lowEnt);
3280     assert(arr[1] == midEnt);
3281     assert(arr[2] == highEnt);
3282     assert(isSorted!("a < b")(map!(entropy)(arr)));
3283 }
3284 
3285 // https://issues.dlang.org/show_bug.cgi?id=20799
3286 @safe unittest
3287 {
3288     import std.range : iota, retro;
3289     import std.array : array;
3290 
3291     auto arr = 1_000_000.iota.retro.array;
3292     arr.schwartzSort!(
3293         n => new int(n),
3294         (a, b) => *a < *b
3295     );
3296     assert(arr.isSorted());
3297 }
3298 
3299 // https://issues.dlang.org/show_bug.cgi?id=21183
3300 @safe unittest
3301 {
get(T)3302     static T get(T)(int) { return T.init; }
3303 
3304     // There's no need to actually sort, just checking type interference
3305     if (false)
3306     {
3307         int[] arr;
3308 
3309         // Fine because there are no indirections
3310         arr.schwartzSort!(get!(const int));
3311 
3312         // Fine because it decays to immutable(int)*
3313         arr.schwartzSort!(get!(immutable int*));
3314 
3315         // Disallowed because it would require a non-const reference
3316         static assert(!__traits(compiles, arr.schwartzSort!(get!(const Object))));
3317 
3318         static struct Wrapper
3319         {
3320             int* ptr;
3321         }
3322 
3323         // Disallowed because Wrapper.ptr would become mutable
3324         static assert(!__traits(compiles, arr.schwartzSort!(get!(const Wrapper))));
3325     }
3326 }
3327 
3328 // partialSort
3329 /**
3330 Reorders the random-access range `r` such that the range `r[0 .. mid]`
3331 is the same as if the entire `r` were sorted, and leaves
3332 the range `r[mid .. r.length]` in no particular order.
3333 
3334 Performs $(BIGOH r.length * log(mid)) evaluations of `pred`. The
3335 implementation simply calls `topN!(less, ss)(r, n)` and then $(D
3336 sort!(less, ss)(r[0 .. n])).
3337 
3338 Params:
3339     less = The predicate to sort by.
3340     ss = The swapping strategy to use.
3341     r = The random-access range to reorder.
3342     n = The length of the initial segment of `r` to sort.
3343 */
3344 void partialSort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable,
3345     Range)(Range r, size_t n)
3346 if (isRandomAccessRange!(Range) && hasLength!(Range) && hasSlicing!(Range))
3347 {
3348     partialSort!(less, ss)(r[0 .. n], r[n .. $]);
3349 }
3350 
3351 ///
3352 @system unittest
3353 {
3354     int[] a = [ 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 ];
3355     partialSort(a, 5);
3356     assert(a[0 .. 5] == [ 0, 1, 2, 3, 4 ]);
3357 }
3358 
3359 /**
3360 Stores the smallest elements of the two ranges in the left-hand range in sorted order.
3361 
3362 Params:
3363     less = The predicate to sort by.
3364     ss = The swapping strategy to use.
3365     r1 = The first range.
3366     r2 = The second range.
3367  */
3368 
3369 void partialSort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable,
3370     Range1, Range2)(Range1 r1, Range2 r2)
3371 if (isRandomAccessRange!(Range1) && hasLength!Range1 &&
3372     isInputRange!Range2 && is(ElementType!Range1 == ElementType!Range2) &&
3373     hasLvalueElements!Range1 && hasLvalueElements!Range2)
3374 {
3375     topN!(less, ss)(r1, r2);
3376     sort!(less, ss)(r1);
3377 }
3378 ///
3379 @system unittest
3380 {
3381     int[] a = [5, 7, 2, 6, 7];
3382     int[] b = [2, 1, 5, 6, 7, 3, 0];
3383 
3384     partialSort(a, b);
3385     assert(a == [0, 1, 2, 2, 3]);
3386 }
3387 
3388 // topN
3389 /**
3390 Reorders the range `r` using $(REF_ALTTEXT swap, swap, std,algorithm,mutation)
3391 such that `r[nth]` refers to the element that would fall there if the range
3392 were fully sorted.
3393 
3394 It is akin to $(LINK2 https://en.wikipedia.org/wiki/Quickselect, Quickselect),
3395 and partitions `r` such that all elements
3396 `e1` from `r[0]` to `r[nth]` satisfy `!less(r[nth], e1)`,
3397 and all elements `e2` from `r[nth]` to `r[r.length]` satisfy
3398 `!less(e2, r[nth])`. Effectively, it finds the `nth + 1` smallest
3399 (according to `less`) elements in `r`. Performs an expected
3400 $(BIGOH r.length) (if unstable) or $(BIGOH r.length * log(r.length))
3401 (if stable) evaluations of `less` and $(REF_ALTTEXT swap, swap, std,algorithm,mutation).
3402 
3403 If `n >= r.length`, the algorithm has no effect and returns
3404 `r[0 .. r.length]`.
3405 
3406 Params:
3407     less = The predicate to sort by.
3408     ss = The swapping strategy to use.
3409     r = The random-access range to reorder.
3410     nth = The index of the element that should be in sorted position after the
3411         function is done.
3412 
3413 Returns: a slice from `r[0]` to `r[nth]`, excluding `r[nth]` itself.
3414 
3415 See_Also:
3416     $(LREF topNIndex),
3417 
3418 BUGS:
3419 
3420 Stable topN has not been implemented yet.
3421 */
3422 auto topN(alias less = "a < b",
3423         SwapStrategy ss = SwapStrategy.unstable,
3424         Range)(Range r, size_t nth)
3425 if (isRandomAccessRange!(Range) && hasLength!Range &&
3426     hasSlicing!Range && hasAssignableElements!Range)
3427 {
3428     static assert(ss == SwapStrategy.unstable,
3429             "Stable topN not yet implemented");
3430     if (nth >= r.length) return r[0 .. r.length];
3431     auto ret = r[0 .. nth];
3432     if (false)
3433     {
3434         // Workaround for https://issues.dlang.org/show_bug.cgi?id=16528
3435         // Safety checks: enumerate all potentially unsafe generic primitives
3436         // then use a @trusted implementation.
3437         cast(void) binaryFun!less(r[0], r[r.length - 1]);
3438         import std.algorithm.mutation : swapAt;
3439         r.swapAt(size_t(0), size_t(0));
3440         static assert(is(typeof(r.length) == size_t),
3441             typeof(r.length).stringof ~ " must be of type size_t");
3442         pivotPartition!less(r, 0);
3443     }
3444     bool useSampling = true;
3445     topNImpl!(binaryFun!less)(r, nth, useSampling);
3446     return ret;
3447 }
3448 
3449 ///
3450 @safe unittest
3451 {
3452     int[] v = [ 25, 7, 9, 2, 0, 5, 21 ];
3453     topN!"a < b"(v, 100);
3454     assert(v == [ 25, 7, 9, 2, 0, 5, 21 ]);
3455     auto n = 4;
3456     topN!((a, b) => a < b)(v, n);
3457     assert(v[n] == 9);
3458 }
3459 
3460 // https://issues.dlang.org/show_bug.cgi?id=8341
3461 @safe unittest
3462 {
3463     import std.algorithm.comparison : equal;
3464     import std.range : zip;
3465     import std.typecons : tuple;
3466     auto a = [10, 30, 20];
3467     auto b = ["c", "b", "a"];
3468     assert(topN!"a[0] > b[0]"(zip(a, b), 2).equal([tuple(20, "a"), tuple(30, "b")]));
3469 }
3470 
3471 private @trusted
topNImpl(alias less,R)3472 void topNImpl(alias less, R)(R r, size_t n, ref bool useSampling)
3473 {
3474     for (;;)
3475     {
3476         import std.algorithm.mutation : swapAt;
3477         assert(n < r.length);
3478         size_t pivot = void;
3479 
3480         // Decide strategy for partitioning
3481         if (n == 0)
3482         {
3483             pivot = 0;
3484             foreach (i; 1 .. r.length)
3485                 if (less(r[i], r[pivot])) pivot = i;
3486             r.swapAt(n, pivot);
3487             return;
3488         }
3489         if (n + 1 == r.length)
3490         {
3491             pivot = 0;
3492             foreach (i; 1 .. r.length)
3493                 if (less(r[pivot], r[i])) pivot = i;
3494             r.swapAt(n, pivot);
3495             return;
3496         }
3497         if (r.length <= 12)
3498         {
3499             pivot = pivotPartition!less(r, r.length / 2);
3500         }
3501         else if (n * 16 <= (r.length - 1) * 7)
3502         {
3503             pivot = topNPartitionOffMedian!(less, No.leanRight)
3504                 (r, n, useSampling);
3505             // Quality check
3506             if (useSampling)
3507             {
3508                 if (pivot < n)
3509                 {
3510                     if (pivot * 4 < r.length)
3511                     {
3512                         useSampling = false;
3513                     }
3514                 }
3515                 else if ((r.length - pivot) * 8 < r.length * 3)
3516                 {
3517                     useSampling = false;
3518                 }
3519             }
3520         }
3521         else if (n * 16 >= (r.length - 1) * 9)
3522         {
3523             pivot = topNPartitionOffMedian!(less, Yes.leanRight)
3524                 (r, n, useSampling);
3525             // Quality check
3526             if (useSampling)
3527             {
3528                 if (pivot < n)
3529                 {
3530                     if (pivot * 8 < r.length * 3)
3531                     {
3532                         useSampling = false;
3533                     }
3534                 }
3535                 else if ((r.length - pivot) * 4 < r.length)
3536                 {
3537                     useSampling = false;
3538                 }
3539             }
3540         }
3541         else
3542         {
3543             pivot = topNPartition!less(r, n, useSampling);
3544             // Quality check
3545             if (useSampling &&
3546                 (pivot * 9 < r.length * 2 || pivot * 9 > r.length * 7))
3547             {
3548                 // Failed - abort sampling going forward
3549                 useSampling = false;
3550             }
3551         }
3552 
3553         assert(pivot != size_t.max, "pivot must be not equal to size_t.max");
3554         // See how the pivot fares
3555         if (pivot == n)
3556         {
3557             return;
3558         }
3559         if (pivot > n)
3560         {
3561             r = r[0 .. pivot];
3562         }
3563         else
3564         {
3565             n -= pivot + 1;
3566             r = r[pivot + 1 .. r.length];
3567         }
3568     }
3569 }
3570 
topNPartition(alias lp,R)3571 private size_t topNPartition(alias lp, R)(R r, size_t n, bool useSampling)
3572 {
3573     import std.format : format;
3574     assert(r.length >= 9 && n < r.length, "length must be longer than 8"
3575         ~ " and n must be less than r.length");
3576     immutable ninth = r.length / 9;
3577     auto pivot = ninth / 2;
3578     // Position subrange r[lo .. hi] to have length equal to ninth and its upper
3579     // median r[lo .. hi][$ / 2] in exactly the same place as the upper median
3580     // of the entire range r[$ / 2]. This is to improve behavior for searching
3581     // the median in already sorted ranges.
3582     immutable lo = r.length / 2 - pivot, hi = lo + ninth;
3583     // We have either one straggler on the left, one on the right, or none.
3584     assert(lo - (r.length - hi) <= 1 || (r.length - hi) - lo <= 1,
3585         format!"straggler check failed lo %s, r.length %s, hi %s"(lo, r.length, hi));
3586     assert(lo >= ninth * 4, format!"lo %s >= ninth * 4 %s"(lo, ninth * 4));
3587     assert(r.length - hi >= ninth * 4,
3588         format!"r.length %s - hi %s >= ninth * 4 %s"(r.length, hi, ninth * 4));
3589 
3590     // Partition in groups of 3, and the mid tertile again in groups of 3
3591     if (!useSampling)
3592         p3!lp(r, lo - ninth, hi + ninth);
3593     p3!lp(r, lo, hi);
3594 
3595     // Get the median of medians of medians
3596     // Map the full interval of n to the full interval of the ninth
3597     pivot = (n * (ninth - 1)) / (r.length - 1);
3598     topNImpl!lp(r[lo .. hi], pivot, useSampling);
3599     return expandPartition!lp(r, lo, pivot + lo, hi);
3600 }
3601 
p3(alias less,Range)3602 private void p3(alias less, Range)(Range r, size_t lo, immutable size_t hi)
3603 {
3604     import std.format : format;
3605     assert(lo <= hi && hi < r.length,
3606         format!"lo %s <= hi %s && hi < r.length %s"(lo, hi, r.length));
3607     immutable ln = hi - lo;
3608     for (; lo < hi; ++lo)
3609     {
3610         assert(lo >= ln, format!"lo %s >= ln %s"(lo, ln));
3611         assert(lo + ln < r.length, format!"lo %s + ln %s < r.length %s"(
3612             lo, ln, r.length));
3613         medianOf!less(r, lo - ln, lo, lo + ln);
3614     }
3615 }
3616 
3617 private void p4(alias less, Flag!"leanRight" f, Range)
3618     (Range r, size_t lo, immutable size_t hi)
3619 {
3620     import std.format : format;
3621     assert(lo <= hi && hi < r.length, format!"lo %s <= hi %s && hi < r.length %s"(
3622         lo, hi, r.length));
3623     immutable ln = hi - lo, _2ln = ln * 2;
3624     for (; lo < hi; ++lo)
3625     {
3626         assert(lo >= ln, format!"lo %s >= ln %s"(lo, ln));
3627         assert(lo + ln < r.length, format!"lo %s + ln %s < r.length %s"(
3628             lo, ln, r.length));
3629         static if (f == Yes.leanRight)
3630             medianOf!(less, f)(r, lo - _2ln, lo - ln, lo, lo + ln);
3631         else
3632             medianOf!(less, f)(r, lo - ln, lo, lo + ln, lo + _2ln);
3633     }
3634 }
3635 
3636 private size_t topNPartitionOffMedian(alias lp, Flag!"leanRight" f, R)
3637     (R r, size_t n, bool useSampling)
3638 {
3639     assert(r.length >= 12, "The length of r must be greater than 11");
3640     assert(n < r.length, "n must be less than the length of r");
3641     immutable _4 = r.length / 4;
3642     static if (f == Yes.leanRight)
3643         immutable leftLimit = 2 * _4;
3644     else
3645         immutable leftLimit = _4;
3646     // Partition in groups of 4, and the left quartile again in groups of 3
3647     if (!useSampling)
3648     {
3649         p4!(lp, f)(r, leftLimit, leftLimit + _4);
3650     }
3651     immutable _12 = _4 / 3;
3652     immutable lo = leftLimit + _12, hi = lo + _12;
3653     p3!lp(r, lo, hi);
3654 
3655     // Get the median of medians of medians
3656     // Map the full interval of n to the full interval of the ninth
3657     immutable pivot = (n * (_12 - 1)) / (r.length - 1);
3658     topNImpl!lp(r[lo .. hi], pivot, useSampling);
3659     return expandPartition!lp(r, lo, pivot + lo, hi);
3660 }
3661 
3662 /*
3663 Params:
3664 less = predicate
3665 r = range to partition
3666 pivot = pivot to partition around
3667 lo = value such that r[lo .. pivot] already less than r[pivot]
3668 hi = value such that r[pivot .. hi] already greater than r[pivot]
3669 
3670 Returns: new position of pivot
3671 */
3672 private
expandPartition(alias lp,R)3673 size_t expandPartition(alias lp, R)(R r, size_t lo, size_t pivot, size_t hi)
3674 in
3675 {
3676     import std.algorithm.searching : all;
3677     assert(lo <= pivot, "lo must be less than or equal pivot");
3678     assert(pivot < hi, "pivot must be less than hi");
3679     assert(hi <= r.length, "hi must be less than or equal to the length of r");
3680     assert(r[lo .. pivot + 1].all!(x => !lp(r[pivot], x)),
3681         "r[lo .. pivot + 1] failed less than test");
3682     assert(r[pivot + 1 .. hi].all!(x => !lp(x, r[pivot])),
3683         "r[pivot + 1 .. hi] failed less than test");
3684     }
3685 out
3686 {
3687     import std.algorithm.searching : all;
3688     assert(r[0 .. pivot + 1].all!(x => !lp(r[pivot], x)),
3689         "r[0 .. pivot + 1] failed less than test");
3690     assert(r[pivot + 1 .. r.length].all!(x => !lp(x, r[pivot])),
3691         "r[pivot + 1 .. r.length] failed less than test");
3692 }
3693 do
3694 {
3695     import std.algorithm.mutation : swapAt;
3696     import std.algorithm.searching : all;
3697     // We work with closed intervals!
3698     --hi;
3699 
3700     size_t left = 0, rite = r.length - 1;
3701     loop: for (;; ++left, --rite)
3702     {
3703         for (;; ++left)
3704         {
3705             if (left == lo) break loop;
3706             if (!lp(r[left], r[pivot])) break;
3707         }
3708         for (;; --rite)
3709         {
3710             if (rite == hi) break loop;
3711             if (!lp(r[pivot], r[rite])) break;
3712         }
3713         r.swapAt(left, rite);
3714     }
3715 
3716     assert(r[lo .. pivot + 1].all!(x => !lp(r[pivot], x)),
3717         "r[lo .. pivot + 1] failed less than test");
3718     assert(r[pivot + 1 .. hi + 1].all!(x => !lp(x, r[pivot])),
3719         "r[pivot + 1 .. hi + 1] failed less than test");
3720     assert(r[0 .. left].all!(x => !lp(r[pivot], x)),
3721         "r[0 .. left] failed less than test");
3722     assert(r[rite + 1 .. r.length].all!(x => !lp(x, r[pivot])),
3723         "r[rite + 1 .. r.length] failed less than test");
3724 
3725     immutable oldPivot = pivot;
3726 
3727     if (left < lo)
3728     {
3729         // First loop: spend r[lo .. pivot]
3730         for (; lo < pivot; ++left)
3731         {
3732             if (left == lo) goto done;
3733             if (!lp(r[oldPivot], r[left])) continue;
3734             --pivot;
3735             assert(!lp(r[oldPivot], r[pivot]), "less check failed");
3736             r.swapAt(left, pivot);
3737         }
3738         // Second loop: make left and pivot meet
3739         for (;; ++left)
3740         {
3741             if (left == pivot) goto done;
3742             if (!lp(r[oldPivot], r[left])) continue;
3743             for (;;)
3744             {
3745                 if (left == pivot) goto done;
3746                 --pivot;
3747                 if (lp(r[pivot], r[oldPivot]))
3748                 {
3749                     r.swapAt(left, pivot);
3750                     break;
3751                 }
3752             }
3753         }
3754     }
3755 
3756     // First loop: spend r[lo .. pivot]
3757     for (; hi != pivot; --rite)
3758     {
3759         if (rite == hi) goto done;
3760         if (!lp(r[rite], r[oldPivot])) continue;
3761         ++pivot;
3762         assert(!lp(r[pivot], r[oldPivot]), "less check failed");
3763         r.swapAt(rite, pivot);
3764     }
3765     // Second loop: make left and pivot meet
3766     for (; rite > pivot; --rite)
3767     {
3768         if (!lp(r[rite], r[oldPivot])) continue;
3769         while (rite > pivot)
3770         {
3771             ++pivot;
3772             if (lp(r[oldPivot], r[pivot]))
3773             {
3774                 r.swapAt(rite, pivot);
3775                 break;
3776             }
3777         }
3778     }
3779 
3780 done:
3781     r.swapAt(oldPivot, pivot);
3782     return pivot;
3783 }
3784 
3785 @safe unittest
3786 {
3787     auto a = [ 10, 5, 3, 4, 8,  11,  13, 3, 9, 4, 10 ];
3788     assert(expandPartition!((a, b) => a < b)(a, 4, 5, 6) == 9);
3789 
3790     import std.algorithm.iteration : map;
3791     import std.array : array;
3792     import std.random : uniform;
3793     import std.range : iota;
3794     auto size = uniform(1, 1000);
3795     a = iota(0, size).map!(_ => uniform(0, 1000)).array;
3796     if (a.length == 0) return;
3797     expandPartition!((a, b) => a < b)(a, a.length / 2, a.length / 2,
3798         a.length / 2 + 1);
3799 }
3800 
3801 @safe unittest
3802 {
3803     import std.algorithm.comparison : max, min;
3804     import std.algorithm.iteration : reduce;
3805 
3806     int[] v = [ 7, 6, 5, 4, 3, 2, 1, 0 ];
3807     ptrdiff_t n = 3;
3808     topN!("a < b")(v, n);
3809     assert(reduce!max(v[0 .. n]) <= v[n]);
3810     assert(reduce!min(v[n + 1 .. $]) >= v[n]);
3811     //
3812     v = [3, 4, 5, 6, 7, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5];
3813     n = 3;
3814     topN(v, n);
3815     assert(reduce!max(v[0 .. n]) <= v[n]);
3816     assert(reduce!min(v[n + 1 .. $]) >= v[n]);
3817     //
3818     v = [3, 4, 5, 6, 7, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5];
3819     n = 1;
3820     topN(v, n);
3821     assert(reduce!max(v[0 .. n]) <= v[n]);
3822     assert(reduce!min(v[n + 1 .. $]) >= v[n]);
3823     //
3824     v = [3, 4, 5, 6, 7, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5];
3825     n = v.length - 1;
3826     topN(v, n);
3827     assert(v[n] == 7);
3828     //
3829     v = [3, 4, 5, 6, 7, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5];
3830     n = 0;
3831     topN(v, n);
3832     assert(v[n] == 1);
3833 
3834     double[][] v1 = [[-10, -5], [-10, -3], [-10, -5], [-10, -4],
3835             [-10, -5], [-9, -5], [-9, -3], [-9, -5],];
3836 
3837     // double[][] v1 = [ [-10, -5], [-10, -4], [-9, -5], [-9, -5],
3838     //         [-10, -5], [-10, -3], [-10, -5], [-9, -3],];
3839     double[]*[] idx = [ &v1[0], &v1[1], &v1[2], &v1[3], &v1[4], &v1[5], &v1[6],
3840             &v1[7], ];
3841 
3842     auto mid = v1.length / 2;
3843     topN!((a, b){ return (*a)[1] < (*b)[1]; })(idx, mid);
3844     foreach (e; idx[0 .. mid]) assert((*e)[1] <= (*idx[mid])[1]);
3845     foreach (e; idx[mid .. $]) assert((*e)[1] >= (*idx[mid])[1]);
3846 }
3847 
3848 @safe unittest
3849 {
3850     import std.algorithm.comparison : max, min;
3851     import std.algorithm.iteration : reduce;
3852     import std.random : Random = Xorshift, uniform;
3853 
3854     immutable uint[] seeds = [90027751, 2709791795, 1374631933, 995751648, 3541495258, 984840953];
foreach(s;seeds)3855     foreach (s; seeds)
3856     {
3857         auto r = Random(s);
3858 
3859         int[] a = new int[uniform(1, 10000, r)];
3860         foreach (ref e; a) e = uniform(-1000, 1000, r);
3861 
3862         auto k = uniform(0, a.length, r);
3863         topN(a, k);
3864         if (k > 0)
3865         {
3866             auto left = reduce!max(a[0 .. k]);
3867             assert(left <= a[k]);
3868         }
3869         if (k + 1 < a.length)
3870         {
3871             auto right = reduce!min(a[k + 1 .. $]);
3872             assert(right >= a[k]);
3873         }
3874     }
3875 }
3876 
3877 // https://issues.dlang.org/show_bug.cgi?id=12987
3878 @safe unittest
3879 {
3880     int[] a = [ 25, 7, 9, 2, 0, 5, 21 ];
3881     auto n = 4;
3882     auto t = topN(a, n);
3883     sort(t);
3884     assert(t == [0, 2, 5, 7]);
3885 }
3886 
3887 /**
3888 Stores the smallest elements of the two ranges in the left-hand range.
3889 
3890 Params:
3891     less = The predicate to sort by.
3892     ss = The swapping strategy to use.
3893     r1 = The first range.
3894     r2 = The second range.
3895  */
3896 auto topN(alias less = "a < b",
3897         SwapStrategy ss = SwapStrategy.unstable,
3898         Range1, Range2)(Range1 r1, Range2 r2)
3899 if (isRandomAccessRange!(Range1) && hasLength!Range1 &&
3900     isInputRange!Range2 && is(ElementType!Range1 == ElementType!Range2) &&
3901     hasLvalueElements!Range1 && hasLvalueElements!Range2)
3902 {
3903     import std.container : BinaryHeap;
3904 
3905     static assert(ss == SwapStrategy.unstable,
3906             "Stable topN not yet implemented");
3907 
3908     auto heap = BinaryHeap!(Range1, less)(r1);
foreach(ref e;r2)3909     foreach (ref e; r2)
3910     {
3911         heap.conditionalSwap(e);
3912     }
3913 
3914     return r1;
3915 }
3916 
3917 ///
3918 @system unittest
3919 {
3920     int[] a = [ 5, 7, 2, 6, 7 ];
3921     int[] b = [ 2, 1, 5, 6, 7, 3, 0 ];
3922     topN(a, b);
3923     sort(a);
3924     assert(a == [0, 1, 2, 2, 3]);
3925 }
3926 
3927 // https://issues.dlang.org/show_bug.cgi?id=15421
3928 @system unittest
3929 {
3930     import std.algorithm.comparison : equal;
3931     import std.internal.test.dummyrange;
3932     import std.meta : AliasSeq;
3933 
3934     alias RandomRanges = AliasSeq!(
3935         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random)
3936     );
3937 
3938     alias ReferenceRanges = AliasSeq!(
3939         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Forward),
3940         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Bidirectional),
3941         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random),
3942         DummyRange!(ReturnBy.Reference, Length.No, RangeType.Forward),
3943         DummyRange!(ReturnBy.Reference, Length.No, RangeType.Bidirectional));
3944 
foreach(T1;RandomRanges)3945     foreach (T1; RandomRanges)
3946     {
3947         foreach (T2; ReferenceRanges)
3948         {
3949             import std.array;
3950 
3951             T1 A;
3952             T2 B;
3953 
3954             A.reinit();
3955             B.reinit();
3956 
3957             topN(A, B);
3958 
3959             // BUG(?): sort doesn't accept DummyRanges (needs Slicing and Length)
3960             auto a = array(A);
3961             auto b = array(B);
3962             sort(a);
3963             sort(b);
3964 
3965             assert(equal(a, [ 1, 1, 2, 2, 3, 3, 4, 4, 5, 5 ]));
3966             assert(equal(b, [ 6, 6, 7, 7, 8, 8, 9, 9, 10, 10 ]));
3967         }
3968     }
3969 }
3970 
3971 // https://issues.dlang.org/show_bug.cgi?id=15421
3972 @system unittest
3973 {
3974     auto a = [ 9, 8, 0, 3, 5, 25, 43, 4, 2, 0, 7 ];
3975     auto b = [ 9, 8, 0, 3, 5, 25, 43, 4, 2, 0, 7 ];
3976 
3977     topN(a, 4);
3978     topN(b[0 .. 4], b[4 .. $]);
3979 
3980     sort(a[0 .. 4]);
3981     sort(a[4 .. $]);
3982     sort(b[0 .. 4]);
3983     sort(b[4 .. $]);
3984 
3985     assert(a[0 .. 4] == b[0 .. 4]);
3986     assert(a[4 .. $] == b[4 .. $]);
3987     assert(a == b);
3988 }
3989 
3990 // https://issues.dlang.org/show_bug.cgi?id=12987
3991 @system unittest
3992 {
3993     int[] a = [ 5, 7, 2, 6, 7 ];
3994     int[] b = [ 2, 1, 5, 6, 7, 3, 0 ];
3995     auto t = topN(a, b);
3996     sort(t);
3997     assert(t == [ 0, 1, 2, 2, 3 ]);
3998 }
3999 
4000 // https://issues.dlang.org/show_bug.cgi?id=15420
4001 @system unittest
4002 {
4003     int[] a = [ 5, 7, 2, 6, 7 ];
4004     int[] b = [ 2, 1, 5, 6, 7, 3, 0 ];
4005     topN!"a > b"(a, b);
4006     sort!"a > b"(a);
4007     assert(a == [ 7, 7, 7, 6, 6 ]);
4008 }
4009 
4010 /**
4011 Copies the top `n` elements of the
4012 $(REF_ALTTEXT input range, isInputRange, std,range,primitives) `source` into the
4013 random-access range `target`, where `n = target.length`.
4014 
4015 Elements of `source` are not touched. If $(D
4016 sorted) is `true`, the target is sorted. Otherwise, the target
4017 respects the $(HTTP en.wikipedia.org/wiki/Binary_heap, heap property).
4018 
4019 Params:
4020     less = The predicate to sort by.
4021     source = The source range.
4022     target = The target range.
4023     sorted = Whether to sort the elements copied into `target`.
4024 
4025 Returns: The slice of `target` containing the copied elements.
4026  */
4027 TRange topNCopy(alias less = "a < b", SRange, TRange)
4028     (SRange source, TRange target, SortOutput sorted = No.sortOutput)
4029 if (isInputRange!(SRange) && isRandomAccessRange!(TRange)
4030     && hasLength!(TRange) && hasSlicing!(TRange))
4031 {
4032     import std.container : BinaryHeap;
4033 
4034     if (target.empty) return target;
4035     auto heap = BinaryHeap!(TRange, less)(target, 0);
4036     foreach (e; source) heap.conditionalInsert(e);
4037     auto result = target[0 .. heap.length];
4038     if (sorted == Yes.sortOutput)
4039     {
4040         while (!heap.empty) heap.removeFront();
4041     }
4042     return result;
4043 }
4044 
4045 ///
4046 @system unittest
4047 {
4048     import std.typecons : Yes;
4049 
4050     int[] a = [ 10, 16, 2, 3, 1, 5, 0 ];
4051     int[] b = new int[3];
4052     topNCopy(a, b, Yes.sortOutput);
4053     assert(b == [ 0, 1, 2 ]);
4054 }
4055 
4056 @system unittest
4057 {
4058     import std.random : Random = Xorshift, uniform, randomShuffle;
4059     import std.typecons : Yes;
4060 
4061     auto r = Random(123_456_789);
4062     ptrdiff_t[] a = new ptrdiff_t[uniform(1, 1000, r)];
4063     foreach (i, ref e; a) e = i;
4064     randomShuffle(a, r);
4065     auto n = uniform(0, a.length, r);
4066     ptrdiff_t[] b = new ptrdiff_t[n];
4067     topNCopy!(binaryFun!("a < b"))(a, b, Yes.sortOutput);
4068     assert(isSorted!(binaryFun!("a < b"))(b));
4069 }
4070 
4071 /**
4072 Given a range of elements, constructs an index of its top $(I n) elements
4073 (i.e., the first $(I n) elements if the range were sorted).
4074 
4075 Similar to $(LREF topN), except that the range is not modified.
4076 
4077 Params:
4078     less = A binary predicate that defines the ordering of range elements.
4079         Defaults to `a < b`.
4080     ss = $(RED (Not implemented yet.)) Specify the swapping strategy.
4081     r = A
4082         $(REF_ALTTEXT random-access range, isRandomAccessRange, std,range,primitives)
4083         of elements to make an index for.
4084     index = A
4085         $(REF_ALTTEXT random-access range, isRandomAccessRange, std,range,primitives)
4086         with assignable elements to build the index in. The length of this range
4087         determines how many top elements to index in `r`.
4088 
4089         This index range can either have integral elements, in which case the
4090         constructed index will consist of zero-based numerical indices into
4091         `r`; or it can have pointers to the element type of `r`, in which
4092         case the constructed index will be pointers to the top elements in
4093         `r`.
4094     sorted = Determines whether to sort the index by the elements they refer
4095         to.
4096 
4097 See_also: $(LREF topN), $(LREF topNCopy).
4098 
4099 BUGS:
4100 The swapping strategy parameter is not implemented yet; currently it is
4101 ignored.
4102 */
4103 void topNIndex(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable,
4104                Range, RangeIndex)
4105               (Range r, RangeIndex index, SortOutput sorted = No.sortOutput)
4106 if (isRandomAccessRange!Range &&
4107     isRandomAccessRange!RangeIndex &&
4108     hasAssignableElements!RangeIndex)
4109 {
4110     static assert(ss == SwapStrategy.unstable,
4111                   "Stable swap strategy not implemented yet.");
4112 
4113     import std.container.binaryheap : BinaryHeap;
4114     if (index.empty) return;
4115 
4116     static if (isIntegral!(ElementType!(RangeIndex)))
4117     {
4118         import std.exception : enforce;
4119 
4120         enforce(ElementType!(RangeIndex).max >= index.length,
4121                 "Index type too small");
4122         bool indirectLess(ElementType!(RangeIndex) a, ElementType!(RangeIndex) b)
4123         {
4124             return binaryFun!(less)(r[a], r[b]);
4125         }
4126         auto heap = BinaryHeap!(RangeIndex, indirectLess)(index, 0);
4127         foreach (i; 0 .. r.length)
4128         {
4129             heap.conditionalInsert(cast(ElementType!RangeIndex) i);
4130         }
4131 
4132     }
4133     else static if (is(ElementType!(RangeIndex) == ElementType!(Range)*))
4134     {
4135         static bool indirectLess(const ElementType!(RangeIndex) a,
4136                                  const ElementType!(RangeIndex) b)
4137         {
4138             return binaryFun!less(*a, *b);
4139         }
4140         auto heap = BinaryHeap!(RangeIndex, indirectLess)(index, 0);
4141         foreach (i; 0 .. r.length)
4142         {
4143             heap.conditionalInsert(&r[i]);
4144         }
4145     }
4146     else static assert(0, "Invalid ElementType");
4147 
4148     if (sorted == Yes.sortOutput)
4149     {
4150         while (!heap.empty) heap.removeFront();
4151     }
4152 }
4153 
4154 ///
4155 @system unittest
4156 {
4157     import std.typecons : Yes;
4158 
4159     // Construct index to top 3 elements using numerical indices:
4160     int[] a = [ 10, 2, 7, 5, 8, 1 ];
4161     int[] index = new int[3];
4162     topNIndex(a, index, Yes.sortOutput);
4163     assert(index == [5, 1, 3]); // because a[5]==1, a[1]==2, a[3]==5
4164 
4165     // Construct index to top 3 elements using pointer indices:
4166     int*[] ptrIndex = new int*[3];
4167     topNIndex(a, ptrIndex, Yes.sortOutput);
4168     assert(ptrIndex == [ &a[5], &a[1], &a[3] ]);
4169 }
4170 
4171 @system unittest
4172 {
4173     import std.conv : text;
4174 
4175     {
4176         int[] a = [ 10, 8, 9, 2, 4, 6, 7, 1, 3, 5 ];
4177         int*[] b = new int*[5];
4178         topNIndex!("a > b")(a, b, Yes.sortOutput);
4179         assert(b == [ &a[0], &a[2], &a[1], &a[6], &a[5]]);
4180     }
4181     {
4182         int[] a = [ 10, 8, 9, 2, 4, 6, 7, 1, 3, 5 ];
4183         auto b = new ubyte[5];
4184         topNIndex!("a > b")(a, b, Yes.sortOutput);
4185         assert(b == [ cast(ubyte) 0, cast(ubyte) 2, cast(ubyte) 1, cast(ubyte) 6, cast(ubyte) 5], text(b));
4186     }
4187 }
4188 
4189 // medianOf
4190 /*
4191 Private for the time being.
4192 
4193 Computes the median of 2 to 5 arbitrary indexes in random-access range `r`
4194 using hand-written specialized algorithms. The indexes must be distinct (if not,
4195 behavior is implementation-defined). The function also partitions the elements
4196 involved around the median, e.g. `medianOf(r, a, b, c)` not only fills `r[b]`
4197 with the median of `r[a]`, `r[b]`, and `r[c]`, but also puts the minimum in
4198 `r[a]` and the maximum in `r[c]`.
4199 
4200 Params:
4201 less = The comparison predicate used, modeled as a
4202     $(LINK2 https://en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings, strict weak ordering)
4203     (irreflexive, antisymmetric, transitive, and implying a transitive equivalence).
4204 flag = Used only for even values of `T.length`. If `No.leanRight`, the median
4205 "leans left", meaning `medianOf(r, a, b, c, d)` puts the lower median of the
4206 four in `r[b]`, the minimum in `r[a]`, and the two others in `r[c]` and `r[d]`.
4207 Conversely, `median!("a < b", Yes.leanRight)(r, a, b, c, d)` puts the upper
4208 median of the four in `r[c]`, the maximum in `r[d]`, and the two others in
4209 `r[a]` and `r[b]`.
4210 r = The range containing the indexes.
4211 i = Two to five indexes inside `r`.
4212 */
4213 private void medianOf(
4214         alias less = "a < b",
4215         Flag!"leanRight" flag = No.leanRight,
4216         Range,
4217         Indexes...)
4218     (Range r, Indexes i)
4219 if (isRandomAccessRange!Range && hasLength!Range &&
4220     Indexes.length >= 2 && Indexes.length <= 5 &&
4221     allSatisfy!(isUnsigned, Indexes))
4222 {
4223     assert(r.length >= Indexes.length, "r.length must be greater than or"
4224         ~ " equal to Indexes.length");
4225     import std.functional : binaryFun;
4226     alias lt = binaryFun!less;
4227     enum k = Indexes.length;
4228     import std.algorithm.mutation : swapAt;
4229     import std.format : format;
4230 
4231     alias a = i[0];
4232     static assert(is(typeof(a) == size_t), typeof(a).stringof ~ " must be"
4233         ~ " of type size_t");
4234     static if (k >= 2)
4235     {
4236         alias b = i[1];
4237         static assert(is(typeof(b) == size_t), typeof(b).stringof ~ " must be"
4238         ~ " of type size_t");
4239         assert(a != b, "a != b ");
4240     }
4241     static if (k >= 3)
4242     {
4243         alias c = i[2];
4244         static assert(is(typeof(c) == size_t), typeof(c).stringof ~ " must be"
4245         ~ " of type size_t");
4246         assert(a != c && b != c, "a != c && b != c");
4247     }
4248     static if (k >= 4)
4249     {
4250         alias d = i[3];
4251         static assert(is(typeof(d) == size_t), typeof(d).stringof ~ " must be"
4252         ~ " of type size_t");
4253         assert(a != d && b != d && c != d, "a != d && b != d && c != d failed");
4254     }
4255     static if (k >= 5)
4256     {
4257         alias e = i[4];
4258         static assert(is(typeof(e) == size_t), typeof(e).stringof ~ " must be"
4259         ~ " of type size_t");
4260         assert(a != e && b != e && c != e && d != e,
4261             "a != e && b != e && c != e && d != e failed");
4262     }
4263 
4264     static if (k == 2)
4265     {
4266         if (lt(r[b], r[a])) r.swapAt(a, b);
4267     }
4268     else static if (k == 3)
4269     {
4270         if (lt(r[c], r[a])) // c < a
4271         {
4272             if (lt(r[a], r[b])) // c < a < b
4273             {
4274                 r.swapAt(a, b);
4275                 r.swapAt(a, c);
4276             }
4277             else // c < a, b <= a
4278             {
4279                 r.swapAt(a, c);
4280                 if (lt(r[b], r[a])) r.swapAt(a, b);
4281             }
4282         }
4283         else // a <= c
4284         {
4285             if (lt(r[b], r[a])) // b < a <= c
4286             {
4287                 r.swapAt(a, b);
4288             }
4289             else // a <= c, a <= b
4290             {
4291                 if (lt(r[c], r[b])) r.swapAt(b, c);
4292             }
4293         }
4294         assert(!lt(r[b], r[a]), "less than check failed");
4295         assert(!lt(r[c], r[b]), "less than check failed");
4296     }
4297     else static if (k == 4)
4298     {
4299         static if (flag == No.leanRight)
4300         {
4301             // Eliminate the rightmost from the competition
4302             if (lt(r[d], r[c])) r.swapAt(c, d); // c <= d
4303             if (lt(r[d], r[b])) r.swapAt(b, d); // b <= d
4304             medianOf!lt(r, a, b, c);
4305         }
4306         else
4307         {
4308             // Eliminate the leftmost from the competition
4309             if (lt(r[b], r[a])) r.swapAt(a, b); // a <= b
4310             if (lt(r[c], r[a])) r.swapAt(a, c); // a <= c
4311             medianOf!lt(r, b, c, d);
4312         }
4313     }
4314     else static if (k == 5)
4315     {
4316         // Credit: Teppo Niinimäki
scope(success)4317         version (StdUnittest) scope(success)
4318         {
4319             assert(!lt(r[c], r[a]), "less than check failed");
4320             assert(!lt(r[c], r[b]), "less than check failed");
4321             assert(!lt(r[d], r[c]), "less than check failed");
4322             assert(!lt(r[e], r[c]), "less than check failed");
4323         }
4324 
4325         if (lt(r[c], r[a])) r.swapAt(a, c);
4326         if (lt(r[d], r[b])) r.swapAt(b, d);
4327         if (lt(r[d], r[c]))
4328         {
4329             r.swapAt(c, d);
4330             r.swapAt(a, b);
4331         }
4332         if (lt(r[e], r[b])) r.swapAt(b, e);
4333         if (lt(r[e], r[c]))
4334         {
4335             r.swapAt(c, e);
4336             if (lt(r[c], r[a])) r.swapAt(a, c);
4337         }
4338         else
4339         {
4340             if (lt(r[c], r[b])) r.swapAt(b, c);
4341         }
4342     }
4343 }
4344 
4345 @safe unittest
4346 {
4347     // Verify medianOf for all permutations of [1, 2, 2, 3, 4].
4348     int[5] data = [1, 2, 2, 3, 4];
4349     do
4350     {
4351         int[5] a = data;
4352         medianOf(a[], size_t(0), size_t(1));
4353         assert(a[0] <= a[1]);
4354 
4355         a[] = data[];
4356         medianOf(a[], size_t(0), size_t(1), size_t(2));
4357         assert(ordered(a[0], a[1], a[2]));
4358 
4359         a[] = data[];
4360         medianOf(a[], size_t(0), size_t(1), size_t(2), size_t(3));
4361         assert(a[0] <= a[1] && a[1] <= a[2] && a[1] <= a[3]);
4362 
4363         a[] = data[];
4364         medianOf!("a < b", Yes.leanRight)(a[], size_t(0), size_t(1),
4365             size_t(2), size_t(3));
4366         assert(a[0] <= a[2] && a[1] <= a[2] && a[2] <= a[3]);
4367 
4368         a[] = data[];
4369         medianOf(a[], size_t(0), size_t(1), size_t(2), size_t(3), size_t(4));
4370         assert(a[0] <= a[2] && a[1] <= a[2] && a[2] <= a[3] && a[2] <= a[4]);
4371     }
4372     while (nextPermutation(data[]));
4373 }
4374 
4375 // nextPermutation
4376 /**
4377  * Permutes `range` in-place to the next lexicographically greater
4378  * permutation.
4379  *
4380  * The predicate `less` defines the lexicographical ordering to be used on
4381  * the range.
4382  *
4383  * If the range is currently the lexicographically greatest permutation, it is
4384  * permuted back to the least permutation and false is returned.  Otherwise,
4385  * true is returned. One can thus generate all permutations of a range by
4386  * sorting it according to `less`, which produces the lexicographically
4387  * least permutation, and then calling nextPermutation until it returns false.
4388  * This is guaranteed to generate all distinct permutations of the range
4389  * exactly once.  If there are $(I N) elements in the range and all of them are
4390  * unique, then $(I N)! permutations will be generated. Otherwise, if there are
4391  * some duplicated elements, fewer permutations will be produced.
4392 ----
4393 // Enumerate all permutations
4394 int[] a = [1,2,3,4,5];
4395 do
4396 {
4397     // use the current permutation and
4398     // proceed to the next permutation of the array.
4399 } while (nextPermutation(a));
4400 ----
4401  * Params:
4402  *  less = The ordering to be used to determine lexicographical ordering of the
4403  *      permutations.
4404  *  range = The range to permute.
4405  *
4406  * Returns: false if the range was lexicographically the greatest, in which
4407  * case the range is reversed back to the lexicographically smallest
4408  * permutation; otherwise returns true.
4409  * See_Also:
4410  * $(REF permutations, std,algorithm,iteration).
4411  */
4412 bool nextPermutation(alias less="a < b", BidirectionalRange)
4413                     (BidirectionalRange range)
4414 if (isBidirectionalRange!BidirectionalRange &&
4415     hasSwappableElements!BidirectionalRange)
4416 {
4417     import std.algorithm.mutation : reverse, swap;
4418     import std.algorithm.searching : find;
4419     import std.range : retro, takeExactly;
4420     // Ranges of 0 or 1 element have no distinct permutations.
4421     if (range.empty) return false;
4422 
4423     auto i = retro(range);
4424     auto last = i.save;
4425 
4426     // Find last occurring increasing pair of elements
4427     size_t n = 1;
4428     for (i.popFront(); !i.empty; i.popFront(), last.popFront(), n++)
4429     {
4430         if (binaryFun!less(i.front, last.front))
4431             break;
4432     }
4433 
4434     if (i.empty)
4435     {
4436         // Entire range is decreasing: it's lexicographically the greatest. So
4437         // wrap it around.
4438         range.reverse();
4439         return false;
4440     }
4441 
4442     // Find last element greater than i.front.
4443     auto j = find!((a) => binaryFun!less(i.front, a))(
4444                    takeExactly(retro(range), n));
4445 
4446     assert(!j.empty, "j must not be empty");   // shouldn't happen since i.front < last.front
4447     swap(i.front, j.front);
4448     reverse(takeExactly(retro(range), n));
4449 
4450     return true;
4451 }
4452 
4453 ///
4454 @safe unittest
4455 {
4456     // Step through all permutations of a sorted array in lexicographic order
4457     int[] a = [1,2,3];
4458     assert(nextPermutation(a) == true);
4459     assert(a == [1,3,2]);
4460     assert(nextPermutation(a) == true);
4461     assert(a == [2,1,3]);
4462     assert(nextPermutation(a) == true);
4463     assert(a == [2,3,1]);
4464     assert(nextPermutation(a) == true);
4465     assert(a == [3,1,2]);
4466     assert(nextPermutation(a) == true);
4467     assert(a == [3,2,1]);
4468     assert(nextPermutation(a) == false);
4469     assert(a == [1,2,3]);
4470 }
4471 
4472 ///
4473 @safe unittest
4474 {
4475     // Step through permutations of an array containing duplicate elements:
4476     int[] a = [1,1,2];
4477     assert(nextPermutation(a) == true);
4478     assert(a == [1,2,1]);
4479     assert(nextPermutation(a) == true);
4480     assert(a == [2,1,1]);
4481     assert(nextPermutation(a) == false);
4482     assert(a == [1,1,2]);
4483 }
4484 
4485 @safe unittest
4486 {
4487     // Boundary cases: arrays of 0 or 1 element.
4488     int[] a1 = [];
4489     assert(!nextPermutation(a1));
4490     assert(a1 == []);
4491 
4492     int[] a2 = [1];
4493     assert(!nextPermutation(a2));
4494     assert(a2 == [1]);
4495 }
4496 
4497 @safe unittest
4498 {
4499     import std.algorithm.comparison : equal;
4500 
4501     auto a1 = [1, 2, 3, 4];
4502 
4503     assert(nextPermutation(a1));
4504     assert(equal(a1, [1, 2, 4, 3]));
4505 
4506     assert(nextPermutation(a1));
4507     assert(equal(a1, [1, 3, 2, 4]));
4508 
4509     assert(nextPermutation(a1));
4510     assert(equal(a1, [1, 3, 4, 2]));
4511 
4512     assert(nextPermutation(a1));
4513     assert(equal(a1, [1, 4, 2, 3]));
4514 
4515     assert(nextPermutation(a1));
4516     assert(equal(a1, [1, 4, 3, 2]));
4517 
4518     assert(nextPermutation(a1));
4519     assert(equal(a1, [2, 1, 3, 4]));
4520 
4521     assert(nextPermutation(a1));
4522     assert(equal(a1, [2, 1, 4, 3]));
4523 
4524     assert(nextPermutation(a1));
4525     assert(equal(a1, [2, 3, 1, 4]));
4526 
4527     assert(nextPermutation(a1));
4528     assert(equal(a1, [2, 3, 4, 1]));
4529 
4530     assert(nextPermutation(a1));
4531     assert(equal(a1, [2, 4, 1, 3]));
4532 
4533     assert(nextPermutation(a1));
4534     assert(equal(a1, [2, 4, 3, 1]));
4535 
4536     assert(nextPermutation(a1));
4537     assert(equal(a1, [3, 1, 2, 4]));
4538 
4539     assert(nextPermutation(a1));
4540     assert(equal(a1, [3, 1, 4, 2]));
4541 
4542     assert(nextPermutation(a1));
4543     assert(equal(a1, [3, 2, 1, 4]));
4544 
4545     assert(nextPermutation(a1));
4546     assert(equal(a1, [3, 2, 4, 1]));
4547 
4548     assert(nextPermutation(a1));
4549     assert(equal(a1, [3, 4, 1, 2]));
4550 
4551     assert(nextPermutation(a1));
4552     assert(equal(a1, [3, 4, 2, 1]));
4553 
4554     assert(nextPermutation(a1));
4555     assert(equal(a1, [4, 1, 2, 3]));
4556 
4557     assert(nextPermutation(a1));
4558     assert(equal(a1, [4, 1, 3, 2]));
4559 
4560     assert(nextPermutation(a1));
4561     assert(equal(a1, [4, 2, 1, 3]));
4562 
4563     assert(nextPermutation(a1));
4564     assert(equal(a1, [4, 2, 3, 1]));
4565 
4566     assert(nextPermutation(a1));
4567     assert(equal(a1, [4, 3, 1, 2]));
4568 
4569     assert(nextPermutation(a1));
4570     assert(equal(a1, [4, 3, 2, 1]));
4571 
4572     assert(!nextPermutation(a1));
4573     assert(equal(a1, [1, 2, 3, 4]));
4574 }
4575 
4576 @safe unittest
4577 {
4578     // Test with non-default sorting order
4579     int[] a = [3,2,1];
4580     assert(nextPermutation!"a > b"(a) == true);
4581     assert(a == [3,1,2]);
4582     assert(nextPermutation!"a > b"(a) == true);
4583     assert(a == [2,3,1]);
4584     assert(nextPermutation!"a > b"(a) == true);
4585     assert(a == [2,1,3]);
4586     assert(nextPermutation!"a > b"(a) == true);
4587     assert(a == [1,3,2]);
4588     assert(nextPermutation!"a > b"(a) == true);
4589     assert(a == [1,2,3]);
4590     assert(nextPermutation!"a > b"(a) == false);
4591     assert(a == [3,2,1]);
4592 }
4593 
4594 // https://issues.dlang.org/show_bug.cgi?id=13594
4595 @safe unittest
4596 {
4597     int[3] a = [1,2,3];
4598     assert(nextPermutation(a[]));
4599     assert(a == [1,3,2]);
4600 }
4601 
4602 // nextEvenPermutation
4603 /**
4604  * Permutes `range` in-place to the next lexicographically greater $(I even)
4605  * permutation.
4606  *
4607  * The predicate `less` defines the lexicographical ordering to be used on
4608  * the range.
4609  *
4610  * An even permutation is one which is produced by swapping an even number of
4611  * pairs of elements in the original range. The set of $(I even) permutations
4612  * is distinct from the set of $(I all) permutations only when there are no
4613  * duplicate elements in the range. If the range has $(I N) unique elements,
4614  * then there are exactly $(I N)!/2 even permutations.
4615  *
4616  * If the range is already the lexicographically greatest even permutation, it
4617  * is permuted back to the least even permutation and false is returned.
4618  * Otherwise, true is returned, and the range is modified in-place to be the
4619  * lexicographically next even permutation.
4620  *
4621  * One can thus generate the even permutations of a range with unique elements
4622  * by starting with the lexicographically smallest permutation, and repeatedly
4623  * calling nextEvenPermutation until it returns false.
4624 ----
4625 // Enumerate even permutations
4626 int[] a = [1,2,3,4,5];
4627 do
4628 {
4629     // use the current permutation and
4630     // proceed to the next even permutation of the array.
4631 } while (nextEvenPermutation(a));
4632 ----
4633  * One can also generate the $(I odd) permutations of a range by noting that
4634  * permutations obey the rule that even + even = even, and odd + even = odd.
4635  * Thus, by swapping the last two elements of a lexicographically least range,
4636  * it is turned into the first odd permutation. Then calling
4637  * nextEvenPermutation on this first odd permutation will generate the next
4638  * even permutation relative to this odd permutation, which is actually the
4639  * next odd permutation of the original range. Thus, by repeatedly calling
4640  * nextEvenPermutation until it returns false, one enumerates the odd
4641  * permutations of the original range.
4642 ----
4643 // Enumerate odd permutations
4644 int[] a = [1,2,3,4,5];
4645 swap(a[$-2], a[$-1]);    // a is now the first odd permutation of [1,2,3,4,5]
4646 do
4647 {
4648     // use the current permutation and
4649     // proceed to the next odd permutation of the original array
4650     // (which is an even permutation of the first odd permutation).
4651 } while (nextEvenPermutation(a));
4652 ----
4653  *
4654  * Warning: Since even permutations are only distinct from all permutations
4655  * when the range elements are unique, this function assumes that there are no
4656  * duplicate elements under the specified ordering. If this is not _true, some
4657  * permutations may fail to be generated. When the range has non-unique
4658  * elements, you should use $(MYREF nextPermutation) instead.
4659  *
4660  * Params:
4661  *  less = The ordering to be used to determine lexicographical ordering of the
4662  *      permutations.
4663  *  range = The range to permute.
4664  *
4665  * Returns: false if the range was lexicographically the greatest, in which
4666  * case the range is reversed back to the lexicographically smallest
4667  * permutation; otherwise returns true.
4668  */
4669 bool nextEvenPermutation(alias less="a < b", BidirectionalRange)
4670                         (BidirectionalRange range)
4671 if (isBidirectionalRange!BidirectionalRange &&
4672     hasSwappableElements!BidirectionalRange)
4673 {
4674     import std.algorithm.mutation : reverse, swap;
4675     import std.algorithm.searching : find;
4676     import std.range : retro, takeExactly;
4677     // Ranges of 0 or 1 element have no distinct permutations.
4678     if (range.empty) return false;
4679 
4680     bool oddParity = false;
4681     bool ret = true;
4682     do
4683     {
4684         auto i = retro(range);
4685         auto last = i.save;
4686 
4687         // Find last occurring increasing pair of elements
4688         size_t n = 1;
4689         for (i.popFront(); !i.empty;
4690             i.popFront(), last.popFront(), n++)
4691         {
4692             if (binaryFun!less(i.front, last.front))
4693                 break;
4694         }
4695 
4696         if (!i.empty)
4697         {
4698             // Find last element greater than i.front.
4699             auto j = find!((a) => binaryFun!less(i.front, a))(
4700                            takeExactly(retro(range), n));
4701 
4702             // shouldn't happen since i.front < last.front
4703             assert(!j.empty, "j must not be empty");
4704 
4705             swap(i.front, j.front);
4706             oddParity = !oddParity;
4707         }
4708         else
4709         {
4710             // Entire range is decreasing: it's lexicographically
4711             // the greatest.
4712             ret = false;
4713         }
4714 
4715         reverse(takeExactly(retro(range), n));
4716         if ((n / 2) % 2 == 1)
4717             oddParity = !oddParity;
4718     } while (oddParity);
4719 
4720     return ret;
4721 }
4722 
4723 ///
4724 @safe unittest
4725 {
4726     // Step through even permutations of a sorted array in lexicographic order
4727     int[] a = [1,2,3];
4728     assert(nextEvenPermutation(a) == true);
4729     assert(a == [2,3,1]);
4730     assert(nextEvenPermutation(a) == true);
4731     assert(a == [3,1,2]);
4732     assert(nextEvenPermutation(a) == false);
4733     assert(a == [1,2,3]);
4734 }
4735 
4736 @safe unittest
4737 {
4738     auto a3 = [ 1, 2, 3, 4 ];
4739     int count = 1;
4740     while (nextEvenPermutation(a3)) count++;
4741     assert(count == 12);
4742 }
4743 
4744 @safe unittest
4745 {
4746     // Test with non-default sorting order
4747     auto a = [ 3, 2, 1 ];
4748 
4749     assert(nextEvenPermutation!"a > b"(a) == true);
4750     assert(a == [ 2, 1, 3 ]);
4751     assert(nextEvenPermutation!"a > b"(a) == true);
4752     assert(a == [ 1, 3, 2 ]);
4753     assert(nextEvenPermutation!"a > b"(a) == false);
4754     assert(a == [ 3, 2, 1 ]);
4755 }
4756 
4757 @safe unittest
4758 {
4759     // Test various cases of rollover
4760     auto a = [ 3, 1, 2 ];
4761     assert(nextEvenPermutation(a) == false);
4762     assert(a == [ 1, 2, 3 ]);
4763 
4764     auto b = [ 3, 2, 1 ];
4765     assert(nextEvenPermutation(b) == false);
4766     assert(b == [ 1, 3, 2 ]);
4767 }
4768 
4769 // https://issues.dlang.org/show_bug.cgi?id=13594
4770 @safe unittest
4771 {
4772     int[3] a = [1,2,3];
4773     assert(nextEvenPermutation(a[]));
4774     assert(a == [2,3,1]);
4775 }
4776 
4777 /**
4778 Even permutations are useful for generating coordinates of certain geometric
4779 shapes. Here's a non-trivial example:
4780 */
4781 @safe unittest
4782 {
4783     import std.math.algebraic : sqrt;
4784 
4785     // Print the 60 vertices of a uniform truncated icosahedron (soccer ball)
4786     enum real Phi = (1.0 + sqrt(5.0)) / 2.0;    // Golden ratio
4787     real[][] seeds = [
4788         [0.0, 1.0, 3.0*Phi],
4789         [1.0, 2.0+Phi, 2.0*Phi],
4790         [Phi, 2.0, Phi^^3]
4791     ];
4792     size_t n;
foreach(seed;seeds)4793     foreach (seed; seeds)
4794     {
4795         // Loop over even permutations of each seed
4796         do
4797         {
4798             // Loop over all sign changes of each permutation
4799             size_t i;
4800             do
4801             {
4802                 // Generate all possible sign changes
4803                 for (i=0; i < seed.length; i++)
4804                 {
4805                     if (seed[i] != 0.0)
4806                     {
4807                         seed[i] = -seed[i];
4808                         if (seed[i] < 0.0)
4809                             break;
4810                     }
4811                 }
4812                 n++;
4813             } while (i < seed.length);
4814         } while (nextEvenPermutation(seed));
4815     }
4816     assert(n == 60);
4817 }
4818 
4819 /**
4820 Permutes `range` into the `perm` permutation.
4821 
4822 The algorithm has a constant runtime complexity with respect to the number of
4823 permutations created.
4824 Due to the number of unique values of `ulong` only the first 21 elements of
4825 `range` can be permuted. The rest of the range will therefore not be
4826 permuted.
4827 This algorithm uses the $(HTTP en.wikipedia.org/wiki/Lehmer_code, Lehmer
4828 Code).
4829 
4830 The algorithm works as follows:
4831 $(D_CODE
4832     auto pem = [4,0,4,1,0,0,0]; // permutation 2982 in factorial
4833     auto src = [0,1,2,3,4,5,6]; // the range to permutate
4834 
4835     auto i = 0;                    // range index
4836     // range index iterates pem and src in sync
4837     // pem[i] + i is used as index into src
4838     // first src[pem[i] + i] is stored in t
4839     auto t = 4;                    // tmp value
4840     src = [0,1,2,3,n,5,6];
4841 
4842     // then the values between i and pem[i] + i are moved one
4843     // to the right
4844     src = [n,0,1,2,3,5,6];
4845     // at last t is inserted into position i
4846     src = [4,0,1,2,3,5,6];
4847     // finally i is incremented
4848     ++i;
4849 
4850     // this process is repeated while i < pem.length
4851 
4852     t = 0;
4853     src = [4,n,1,2,3,5,6];
4854     src = [4,0,1,2,3,5,6];
4855     ++i;
4856     t = 6;
4857     src = [4,0,1,2,3,5,n];
4858     src = [4,0,n,1,2,3,5];
4859     src = [4,0,6,1,2,3,5];
4860 )
4861 
4862 Returns:
4863     The permuted range.
4864 
4865 Params:
4866     range = The Range to permute. The original ordering will be lost.
4867     perm = The permutation to permutate `range` to.
4868 */
4869 auto ref Range nthPermutation(Range)
4870                              (auto ref Range range, const ulong perm)
4871 if (isRandomAccessRange!Range && hasLength!Range)
4872 {
4873     if (!nthPermutationImpl(range, perm))
4874     {
4875         throw new Exception(
4876             "The range to permutate must not have less"
4877             ~ " elements than the factorial number has digits");
4878     }
4879 
4880     return range;
4881 }
4882 
4883 ///
4884 pure @safe unittest
4885 {
4886     auto src = [0, 1, 2, 3, 4, 5, 6];
4887     auto rslt = [4, 0, 6, 2, 1, 3, 5];
4888 
4889     src = nthPermutation(src, 2982);
4890     assert(src == rslt);
4891 }
4892 
4893 /**
4894 Returns: `true` in case the permutation worked, `false` in case `perm` had
4895     more digits in the factorial number system than range had elements.
4896     This case must not occur as this would lead to out of range accesses.
4897 */
4898 bool nthPermutationImpl(Range)
4899                        (auto ref Range range, ulong perm)
4900 if (isRandomAccessRange!Range && hasLength!Range)
4901 {
4902     import std.range.primitives : ElementType;
4903     import std.numeric : decimalToFactorial;
4904 
4905     // ulong.max has 21 digits in the factorial number system
4906     ubyte[21] fac;
4907     size_t idx = decimalToFactorial(perm, fac);
4908 
4909     if (idx > range.length)
4910     {
4911         return false;
4912     }
4913 
4914     ElementType!Range tmp;
4915     size_t i = 0;
4916 
4917     for (; i < idx; ++i)
4918     {
4919         size_t re = fac[i];
4920         tmp = range[re + i];
4921         for (size_t j = re + i; j > i; --j)
4922         {
4923             range[j] = range[j - 1];
4924         }
4925         range[i] = tmp;
4926     }
4927 
4928     return true;
4929 }
4930 
4931 ///
4932 pure @safe unittest
4933 {
4934     auto src = [0, 1, 2, 3, 4, 5, 6];
4935     auto rslt = [4, 0, 6, 2, 1, 3, 5];
4936 
4937     bool worked = nthPermutationImpl(src, 2982);
4938     assert(worked);
4939     assert(src == rslt);
4940 }
4941 
4942 pure @safe unittest
4943 {
4944     auto rslt = [4, 0, 6, 2, 1, 3, 5];
4945 
4946     auto src = nthPermutation([0, 1, 2, 3, 4, 5, 6], 2982);
4947     assert(src == rslt);
4948 }
4949 
4950 pure @safe unittest
4951 {
4952     auto src = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
4953     auto rslt = [4, 0, 6, 2, 1, 3, 5, 7, 8, 9, 10];
4954 
4955     src = nthPermutation(src, 2982);
4956     assert(src == rslt);
4957 }
4958 
4959 pure @safe unittest
4960 {
4961     import std.exception : assertThrown;
4962 
4963     auto src = [0, 1, 2, 3];
4964 
4965     assertThrown(nthPermutation(src, 2982));
4966 }
4967 
4968 pure @safe unittest
4969 {
4970     import std.internal.test.dummyrange;
4971     import std.meta : AliasSeq;
4972 
4973     auto src = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
4974     auto rsl = [4, 0, 6, 2, 1, 3, 5, 7, 8, 9, 10];
4975 
4976     foreach (T; AliasSeq!(
4977             DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random, int[]),
4978             DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random, int[])))
4979     {
4980         static assert(isRandomAccessRange!(T));
4981         static assert(hasLength!(T));
4982         auto dr = T(src.dup);
4983         dr = nthPermutation(dr, 2982);
4984 
4985         int idx;
foreach(it;dr)4986         foreach (it; dr)
4987         {
4988             assert(it == rsl[idx++]);
4989         }
4990     }
4991 }
4992