@@ -1423,44 +1423,21 @@ unittest //Issue 16413 - @system comparison function
14231423
14241424private size_t getPivot (alias less, Range )(Range r)
14251425{
1426- import std.algorithm.mutation : swapAt;
1427-
1428- // This algorithm sorts the first, middle and last elements of r,
1429- // then returns the index of the middle element. In effect, it uses the
1430- // median-of-three heuristic.
1431-
1432- alias pred = binaryFun! (less);
1433- immutable len = r.length;
1434- immutable size_t mid = len / 2 ;
1435- immutable uint result = ((cast (uint ) (pred(r[0 ], r[mid]))) << 2 ) |
1436- ((cast (uint ) (pred(r[0 ], r[len - 1 ]))) << 1 ) |
1437- (cast (uint ) (pred(r[mid], r[len - 1 ])));
1438-
1439- switch (result)
1426+ auto mid = r.length / 2 ;
1427+ if (r.length < 512 )
14401428 {
1441- case 0b001:
1442- r.swapAt(0 , len - 1 );
1443- r.swapAt(0 , mid);
1444- break ;
1445- case 0b110:
1446- r.swapAt(mid, len - 1 );
1447- break ;
1448- case 0b011:
1449- r.swapAt(0 , mid);
1450- break ;
1451- case 0b100:
1452- r.swapAt(mid, len - 1 );
1453- r.swapAt(0 , mid);
1454- break ;
1455- case 0b000:
1456- r.swapAt(0 , len - 1 );
1457- break ;
1458- case 0b111:
1459- break ;
1460- default :
1461- assert (0 );
1429+ if (r.length >= 32 )
1430+ medianOf! less(r, size_t (0 ), mid, r.length - 1 );
1431+ return mid;
14621432 }
14631433
1434+ // The plan here is to take the median of five by taking five elements in
1435+ // the array, segregate around their median, and return the position of the
1436+ // third. We choose first, mid, last, and two more in between those.
1437+
1438+ auto quarter = r.length / 4 ;
1439+ medianOf! less(r,
1440+ size_t (0 ), mid - quarter, mid, mid + quarter, r.length - 1 );
14641441 return mid;
14651442}
14661443
@@ -1770,6 +1747,33 @@ sort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable,
17701747 assert (numbers.equal! isIdentical(sorted));
17711748}
17721749
1750+ unittest
1751+ {
1752+ // Simple regression benchmark
1753+ import std.random , std.algorithm.iteration , std.algorithm.mutation ;
1754+ Random rng;
1755+ int [] a = iota(20148 ).map! (_ => uniform(- 1000 , 1000 , rng)).array;
1756+ static uint comps;
1757+ static bool less (int a, int b) { ++ comps; return a < b; }
1758+ sort! less(a); // random numbers
1759+ sort! less(a); // sorted ascending
1760+ a.reverse();
1761+ sort! less(a); // sorted descending
1762+ a[] = 0 ;
1763+ sort! less(a); // all equal
1764+
1765+ // This should get smaller with time. On occasion it may go larger, but only
1766+ // if there's thorough justification.
1767+ debug enum uint watermark = 1676280 ;
1768+ else enum uint watermark = 1676220 ;
1769+
1770+ import std.conv ;
1771+ assert (comps <= watermark, text(" You seem to have pessimized sort! " ,
1772+ watermark, " < " , comps));
1773+ assert (comps >= watermark, text(" You seem to have improved sort!" ,
1774+ " Please update watermark from " , watermark, " to " , comps));
1775+ }
1776+
17731777@safe unittest
17741778{
17751779 import std.algorithm.internal : rndstuff;
0 commit comments