@@ -1765,7 +1765,7 @@ struct s_MergeState {
17651765 the input (nothing is lost or duplicated).
17661766*/
17671767static int
1768- binarysort (MergeState * ms , const sortslice * ss , Py_ssize_t n , Py_ssize_t ok )
1768+ binarysort (MergeState * ms , const sortslice * ss , Py_ssize_t n , Py_ssize_t ok , float adapt )
17691769{
17701770 Py_ssize_t k ; /* for IFLT macro expansion */
17711771 PyObject * * const a = ss -> keys ;
@@ -1778,6 +1778,120 @@ binarysort(MergeState *ms, const sortslice *ss, Py_ssize_t n, Py_ssize_t ok)
17781778 /* assert a[:ok] is sorted */
17791779 if (! ok )
17801780 ++ ok ;
1781+
1782+ Py_ssize_t L , R ;
1783+ /* Adaptive step */
1784+ if (adapt ) {
1785+ Py_ssize_t diff = ok ; // jump (jump out on 1st loop to not kick in)
1786+ Py_ssize_t last = ok >> 1 ; // mid point (simple binary on 1st loop)
1787+ float ns = 5.0f ; // number of successes (a bit of head start)
1788+ float seen = 0.0f ; // number of loops done
1789+ // const float adapt = 1.3; // adaptivity strength
1790+ for (; ok < n && ns * adapt >= seen ; ++ ok ) {
1791+ pivot = a [ok ];
1792+
1793+ IFLT (pivot , a [last ]) {
1794+ L = 0 ;
1795+ R = last ;
1796+ if (L < R ) {
1797+ if (diff == 0 )
1798+ diff = 1 ;
1799+ M = R - diff ;
1800+ if (M < L )
1801+ M = L ;
1802+ IFLT (pivot , a [M ]) {
1803+ R = M ;
1804+ if (L < R ) {
1805+ diff += 1 ;
1806+ M = R - diff ;
1807+ if (M < L )
1808+ M = L ;
1809+ IFLT (pivot , a [M ])
1810+ R = M ;
1811+ else
1812+ L = M + 1 ;
1813+ ns += (float )(R - L ) * 8 < ok ;
1814+ }
1815+ else {
1816+ ns += 2.0f ;
1817+ }
1818+ }
1819+ else {
1820+ L = M + 1 ;
1821+ ns += (float )(R - L ) * 4 < ok ;
1822+ }
1823+ }
1824+ else {
1825+ ns += 2.0f ;
1826+ }
1827+ }
1828+ else {
1829+ L = last + 1 ;
1830+ R = ok ;
1831+ if (L < R ) {
1832+ M = L + diff ;
1833+ if (M >= R )
1834+ M = R - 1 ;
1835+ IFLT (pivot , a [M ]) {
1836+ R = M ;
1837+ ns += (float )(R - L ) * 4 < ok ;
1838+ }
1839+ else {
1840+ L = M + 1 ;
1841+ if (L < R ) {
1842+ diff += 1 ;
1843+ M = L + diff ;
1844+ if (M >= R )
1845+ M = R - 1 ;
1846+ IFLT (pivot , a [M ])
1847+ R = M ;
1848+ else
1849+ L = M + 1 ;
1850+ ns += (float )(R - L ) * 8 < ok ;
1851+ }
1852+ else {
1853+ ns += 2.0f ;
1854+ }
1855+ }
1856+ }
1857+ else {
1858+ ns += 2.0f ;
1859+ }
1860+ }
1861+
1862+ // Binary Insertion
1863+ while (L < R ) {
1864+ M = (L + R ) >> 1 ;
1865+ IFLT (pivot , a [M ])
1866+ R = M ;
1867+ else
1868+ L = M + 1 ;
1869+ }
1870+
1871+ for (M = ok ; M > L ; -- M )
1872+ a [M ] = a [M - 1 ];
1873+ a [L ] = pivot ;
1874+ if (has_values ) {
1875+ pivot = v [ok ];
1876+ for (M = ok ; M > L ; -- M )
1877+ v [M ] = v [M - 1 ];
1878+ v [L ] = pivot ;
1879+ }
1880+
1881+ // Update Adaptive runvars
1882+ diff = L - last ;
1883+ if (diff < 0 )
1884+ diff = - diff ;
1885+ last = L ;
1886+ seen += 1.0f ;
1887+ }
1888+ if (ok >= n ) {
1889+ // Successfully ran fully adaptive
1890+ // Else go to simple binary sort
1891+ return 1 ;
1892+ }
1893+ }
1894+
17811895 /* Regular insertion sort has average- and worst-case O(n**2) cost
17821896 for both # of comparisons and number of bytes moved. But its branches
17831897 are highly predictable, and it loves sorted input (n-1 compares and no
@@ -1828,7 +1942,7 @@ binarysort(MergeState *ms, const sortslice *ss, Py_ssize_t n, Py_ssize_t ok)
18281942 v [M + 1 ] = vpivot ;
18291943 }
18301944#else // binary insertion sort
1831- Py_ssize_t L , R ;
1945+
18321946 for (; ok < n ; ++ ok ) {
18331947 /* set L to where a[ok] belongs */
18341948 L = 0 ;
@@ -3074,6 +3188,9 @@ list_sort_impl(PyListObject *self, PyObject *keyfunc, int reverse)
30743188 /* March over the array once, left to right, finding natural runs,
30753189 * and extending short natural runs to minrun elements.
30763190 */
3191+ int bres ;
3192+ Py_ssize_t cs = 0 ;
3193+ Py_ssize_t cd = 1 ;
30773194 do {
30783195 Py_ssize_t n ;
30793196
@@ -3086,8 +3203,24 @@ list_sort_impl(PyListObject *self, PyObject *keyfunc, int reverse)
30863203 if (n < minrun ) {
30873204 const Py_ssize_t force = nremaining <= minrun ?
30883205 nremaining : minrun ;
3089- if (binarysort (& ms , & lo , force , n ) < 0 )
3090- goto fail ;
3206+ if (cs ) {
3207+ if (binarysort (& ms , & lo , force , n , 0.0 ) < 0 )
3208+ goto fail ;
3209+ cs -= 1 ;
3210+ }
3211+ else {
3212+ bres = binarysort (& ms , & lo , force , n , 1.3 );
3213+ if (bres < 0 )
3214+ goto fail ;
3215+ if (bres ) {
3216+ cd = 1 ;
3217+ } else {
3218+ cd += 2 ;
3219+ if (cd > 11 )
3220+ cd = 11 ;
3221+ cs = cd ;
3222+ }
3223+ }
30913224 n = force ;
30923225 }
30933226 /* Maybe merge pending runs. */
0 commit comments