Skip to content

Commit 0341e01

Browse files
committed
init
1 parent 5c4bb9b commit 0341e01

File tree

1 file changed

+137
-4
lines changed

1 file changed

+137
-4
lines changed

Objects/listobject.c

Lines changed: 137 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1765,7 +1765,7 @@ struct s_MergeState {
17651765
the input (nothing is lost or duplicated).
17661766
*/
17671767
static 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

Comments
 (0)