Skip to main content

Objects/listobject.c (part 8)

Source:

cpython 3.14 @ ab2d84fe1023/Objects/listobject.c

This annotation covers the Timsort implementation. See objects_listobject7_detail for list.append, list.extend, list.insert, and list.pop.

Map

LinesSymbolRole
1-80list_sort entryTop-level sort dispatch
81-180Run detectionFind ascending/descending runs
181-280Insertion sortSort small runs
281-380MergeMerge two adjacent sorted runs
381-500Galloping modeAccelerate merge when one run dominates

Reading

Run detection

// CPython: Objects/listobject.c:1120 count_run
static Py_ssize_t
count_run(MergeState *ms, PyObject **lo, PyObject **hi, int *descending)
{
/* Find the longest initial run, either ascending or descending.
Reverse descending runs to make them ascending. */
*descending = 0;
if (lo + 1 == hi) return 1; /* Single element is a run */
if (ISLT(*lo + 1, *lo, compare)) {
*descending = 1;
while (++lo + 1 < hi && ISLT(*lo + 1, *lo, compare)) ;
reverse_slice(lo0, lo);
} else {
while (++lo + 1 < hi && !ISLT(*lo + 1, *lo, compare)) ;
}
return lo - lo0;
}

Timsort exploits existing order in the input. Descending runs are reversed in-place. The minimum run length minrun is chosen so that the total number of runs is close to a power of 2.

Galloping mode

// CPython: Objects/listobject.c:1280 gallop_left
static Py_ssize_t
gallop_left(MergeState *ms, PyObject *key, PyObject **a, Py_ssize_t n, Py_ssize_t hint)
{
/* Find the position where key would be inserted in a[0:n].
hint is an initial guess for the position.
Uses exponential search then binary search. */
Py_ssize_t ofs = 1;
while (ofs < n && ISLT(a[hint + ofs], key, ms->compare)) {
ofs <<= 1; /* Double the step */
}
/* Binary search in a[hint + ofs/2 : hint + ofs] */
return bisect_left(ms, key, a + (hint + ofs/2), n - hint - ofs/2);
}

Galloping mode activates when one run consistently provides more than MIN_GALLOP consecutive winners. It switches from O(n) linear comparisons to O(log n) comparisons for each winner. When the advantage ends, it switches back to linear merge.

gopy notes

list.sort is objects.ListSort in objects/list.go. Go's sort.SliceStable is used for the general case; for pure-Python objects the comparison function wraps objects.RichCompare. The full Timsort implementation is not replicated: Go's stable sort provides the same stability guarantee.