@@ -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