@@ -1902,28 +1902,28 @@ abinarysort(MergeState *ms, const sortslice *ss, Py_ssize_t n, Py_ssize_t ok, in
19021902
19031903 Py_ssize_t M , L , R ;
19041904 Py_ssize_t nsorted = ok ;
1905- Py_ssize_t diff_new ;
1906- Py_ssize_t diff = ok ; // jump (jump out on 1st loop to not kick in)
1907- Py_ssize_t last = ok >> 1 ; // mid point (simple binary on 1st loop)
1908- Py_ssize_t ns = 0 ; // number of successes (a bit of head start)
1905+ Py_ssize_t last = ok >> 1 ;
1906+ Py_ssize_t std = ok >> 2 ;
1907+ Py_ssize_t mu = last ;
1908+ Py_ssize_t nb = 0 ; // badness of fit
19091909
19101910 if (adapt ) {
19111911 for (; ok < n ; ++ ok ) {
19121912 pivot = a [ok ];
19131913
1914- IFLT (pivot , a [last ]) {
1914+ IFLT (pivot , a [mu ]) {
19151915 L = 0 ;
1916- R = last ;
1916+ R = mu ;
19171917 if (L < R ) {
19181918 // To not affect diff for measure counting
1919- diff_new = diff + ( diff == 0 );
1920- M = R - diff_new ;
1919+ std += ( std == 0 );
1920+ M = R - std ;
19211921 if (M < L )
19221922 M = L ;
19231923 IFLT (pivot , a [M ]) {
19241924 R = M ;
19251925 if (L < R ) {
1926- M = R - diff_new ;
1926+ M = R - std ;
19271927 if (M < L )
19281928 M = L ;
19291929 IFLT (pivot , a [M ])
@@ -1938,10 +1938,10 @@ abinarysort(MergeState *ms, const sortslice *ss, Py_ssize_t n, Py_ssize_t ok, in
19381938 }
19391939 }
19401940 else {
1941- L = last + 1 ;
1941+ L = mu + 1 ;
19421942 R = ok ;
19431943 if (L < R ) {
1944- M = L + diff ;
1944+ M = L + std ;
19451945 if (M >= R )
19461946 M = R - 1 ;
19471947 IFLT (pivot , a [M ]) {
@@ -1950,7 +1950,7 @@ abinarysort(MergeState *ms, const sortslice *ss, Py_ssize_t n, Py_ssize_t ok, in
19501950 else {
19511951 L = M + 1 ;
19521952 if (L < R ) {
1953- M = L + diff ;
1953+ M = L + std ;
19541954 if (M >= R )
19551955 M = R - 1 ;
19561956 IFLT (pivot , a [M ])
@@ -1982,9 +1982,10 @@ abinarysort(MergeState *ms, const sortslice *ss, Py_ssize_t n, Py_ssize_t ok, in
19821982 }
19831983
19841984 // Update Adaptive runvars
1985- diff_new = L < last ? last - L : L - last ;
1986- ns += diff_new < diff ? diff - diff_new : diff_new - diff ;
1987- diff = diff_new ;
1985+ std = L < mu ? mu - L : L - mu ;
1986+ nb += std ;
1987+ mu = L + L - last ;
1988+ mu = mu < 0 ? 0 : mu > ok ? ok : mu ;
19881989 last = L ;
19891990 }
19901991 }
@@ -2014,15 +2015,16 @@ abinarysort(MergeState *ms, const sortslice *ss, Py_ssize_t n, Py_ssize_t ok, in
20142015 }
20152016
20162017 // Update Adaptive runvars
2017- diff_new = L < last ? last - L : L - last ;
2018- ns += diff_new < diff ? diff - diff_new : diff_new - diff ;
2019- diff = diff_new ;
2018+ std = L < mu ? mu - L : L - mu ;
2019+ nb += std ;
2020+ mu = L + L - last ;
2021+ mu = mu < 0 ? 0 : mu > ok ? ok : mu ;
20202022 last = L ;
20212023 }
20222024 }
20232025
20242026 // Return Adaptivity measure (max 1000)
2025- return ns * 2000 / ((n + 2 * nsorted - 1 ) * n );
2027+ return nb * 2000 / ((n + 2 * nsorted - 1 ) * n );
20262028
20272029 fail :
20282030 return -1 ;
@@ -3216,10 +3218,12 @@ list_sort_impl(PyListObject *self, PyObject *keyfunc, int reverse)
32163218 /* March over the array once, left to right, finding natural runs,
32173219 * and extending short natural runs to minrun elements.
32183220 */
3219- int binary_adapt = 1 ;
32203221 // NOTE: Could turn on based on minlen or comparison type
3222+ int binary_adapt = ms .listlen >= 100 ;
32213223 if (binary_adapt ) {
32223224 int adapt = 0 ; // do not run binarysort adaptivity on 1st run
3225+ Py_ssize_t cs = 0 ;
3226+ Py_ssize_t cd = 1 ;
32233227 do {
32243228 /* Identify next run. */
32253229 Py_ssize_t n ;
@@ -3231,11 +3235,27 @@ list_sort_impl(PyListObject *self, PyObject *keyfunc, int reverse)
32313235 if (n < minrun ) {
32323236 const Py_ssize_t force = nremaining <= minrun ?
32333237 nremaining : minrun ;
3234- Py_ssize_t bres ;
3235- bres = abinarysort (& ms , & lo , force , n , adapt );
3236- if (bres < 0 )
3237- goto fail ;
3238- adapt = bres < 125 ;
3238+ if (cs ) {
3239+ if (binarysort (& ms , & lo , force , n ) < 0 )
3240+ goto fail ;
3241+ cs -= 1 ;
3242+ }
3243+ else {
3244+ Py_ssize_t bres ;
3245+ bres = abinarysort (& ms , & lo , force , n , adapt );
3246+ if (bres < 0 )
3247+ goto fail ;
3248+ adapt = bres < 250 ;
3249+ if (adapt ) {
3250+ cd = 1 ;
3251+ }
3252+ else {
3253+ cd += 2 ;
3254+ if (cd > 11 )
3255+ cd = 11 ;
3256+ cs = cd ;
3257+ }
3258+ }
32393259 n = force ;
32403260 }
32413261 else {
0 commit comments