diff options
Diffstat (limited to 'Objects/listobject.c')
| -rw-r--r-- | Objects/listobject.c | 805 |
1 files changed, 318 insertions, 487 deletions
diff --git a/Objects/listobject.c b/Objects/listobject.c index f753643..b9ef0d0 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -1,6 +1,7 @@ /* List object implementation */ #include "Python.h" +#include "accu.h" #ifdef STDC_HEADERS #include <stddef.h> @@ -184,7 +185,7 @@ PyList_GetItem(PyObject *op, Py_ssize_t i) } if (i < 0 || i >= Py_SIZE(op)) { if (indexerr == NULL) { - indexerr = PyString_FromString( + indexerr = PyUnicode_FromString( "list index out of range"); if (indexerr == NULL) return NULL; @@ -317,115 +318,63 @@ list_dealloc(PyListObject *op) Py_TRASHCAN_SAFE_END(op) } -static int -list_print(PyListObject *op, FILE *fp, int flags) +static PyObject * +list_repr(PyListObject *v) { - int rc; Py_ssize_t i; - PyObject *item; + PyObject *s = NULL; + _PyAccu acc; + static PyObject *sep = NULL; - rc = Py_ReprEnter((PyObject*)op); - if (rc != 0) { - if (rc < 0) - return rc; - Py_BEGIN_ALLOW_THREADS - fprintf(fp, "[...]"); - Py_END_ALLOW_THREADS - return 0; - } - Py_BEGIN_ALLOW_THREADS - fprintf(fp, "["); - Py_END_ALLOW_THREADS - for (i = 0; i < Py_SIZE(op); i++) { - item = op->ob_item[i]; - Py_INCREF(item); - if (i > 0) { - Py_BEGIN_ALLOW_THREADS - fprintf(fp, ", "); - Py_END_ALLOW_THREADS - } - if (PyObject_Print(item, fp, 0) != 0) { - Py_DECREF(item); - Py_ReprLeave((PyObject *)op); - return -1; - } - Py_DECREF(item); + if (Py_SIZE(v) == 0) { + return PyUnicode_FromString("[]"); } - Py_BEGIN_ALLOW_THREADS - fprintf(fp, "]"); - Py_END_ALLOW_THREADS - Py_ReprLeave((PyObject *)op); - return 0; -} -static PyObject * -list_repr(PyListObject *v) -{ - Py_ssize_t i; - PyObject *s, *temp; - PyObject *pieces = NULL, *result = NULL; + if (sep == NULL) { + sep = PyUnicode_FromString(", "); + if (sep == NULL) + return NULL; + } i = Py_ReprEnter((PyObject*)v); if (i != 0) { - return i > 0 ? PyString_FromString("[...]") : NULL; + return i > 0 ? PyUnicode_FromString("[...]") : NULL; } - if (Py_SIZE(v) == 0) { - result = PyString_FromString("[]"); - goto Done; - } + if (_PyAccu_Init(&acc)) + goto error; - pieces = PyList_New(0); - if (pieces == NULL) - goto Done; + s = PyUnicode_FromString("["); + if (s == NULL || _PyAccu_Accumulate(&acc, s)) + goto error; + Py_CLEAR(s); /* Do repr() on each element. Note that this may mutate the list, so must refetch the list size on each iteration. */ for (i = 0; i < Py_SIZE(v); ++i) { - int status; if (Py_EnterRecursiveCall(" while getting the repr of a list")) - goto Done; + goto error; s = PyObject_Repr(v->ob_item[i]); Py_LeaveRecursiveCall(); - if (s == NULL) - goto Done; - status = PyList_Append(pieces, s); - Py_DECREF(s); /* append created a new ref */ - if (status < 0) - goto Done; - } - - /* Add "[]" decorations to the first and last items. */ - assert(PyList_GET_SIZE(pieces) > 0); - s = PyString_FromString("["); - if (s == NULL) - goto Done; - temp = PyList_GET_ITEM(pieces, 0); - PyString_ConcatAndDel(&s, temp); - PyList_SET_ITEM(pieces, 0, s); - if (s == NULL) - goto Done; - - s = PyString_FromString("]"); - if (s == NULL) - goto Done; - temp = PyList_GET_ITEM(pieces, PyList_GET_SIZE(pieces) - 1); - PyString_ConcatAndDel(&temp, s); - PyList_SET_ITEM(pieces, PyList_GET_SIZE(pieces) - 1, temp); - if (temp == NULL) - goto Done; - - /* Paste them all together with ", " between. */ - s = PyString_FromString(", "); - if (s == NULL) - goto Done; - result = _PyString_Join(s, pieces); - Py_DECREF(s); - -Done: - Py_XDECREF(pieces); + if (i > 0 && _PyAccu_Accumulate(&acc, sep)) + goto error; + if (s == NULL || _PyAccu_Accumulate(&acc, s)) + goto error; + Py_CLEAR(s); + } + s = PyUnicode_FromString("]"); + if (s == NULL || _PyAccu_Accumulate(&acc, s)) + goto error; + Py_CLEAR(s); + Py_ReprLeave((PyObject *)v); - return result; + return _PyAccu_Finish(&acc); + +error: + _PyAccu_Destroy(&acc); + Py_XDECREF(s); + Py_ReprLeave((PyObject *)v); + return NULL; } static Py_ssize_t @@ -451,7 +400,7 @@ list_item(PyListObject *a, Py_ssize_t i) { if (i < 0 || i >= Py_SIZE(a)) { if (indexerr == NULL) { - indexerr = PyString_FromString( + indexerr = PyUnicode_FromString( "list index out of range"); if (indexerr == NULL) return NULL; @@ -981,60 +930,82 @@ reverse_slice(PyObject **lo, PyObject **hi) * pieces to this algorithm; read listsort.txt for overviews and details. */ -/* Comparison function. Takes care of calling a user-supplied - * comparison function (any callable Python object), which must not be - * NULL (use the ISLT macro if you don't know, or call PyObject_RichCompareBool - * with Py_LT if you know it's NULL). - * Returns -1 on error, 1 if x < y, 0 if x >= y. +/* A sortslice contains a pointer to an array of keys and a pointer to + * an array of corresponding values. In other words, keys[i] + * corresponds with values[i]. If values == NULL, then the keys are + * also the values. + * + * Several convenience routines are provided here, so that keys and + * values are always moved in sync. */ -static int -islt(PyObject *x, PyObject *y, PyObject *compare) + +typedef struct { + PyObject **keys; + PyObject **values; +} sortslice; + +Py_LOCAL_INLINE(void) +sortslice_copy(sortslice *s1, Py_ssize_t i, sortslice *s2, Py_ssize_t j) { - PyObject *res; - PyObject *args; - Py_ssize_t i; + s1->keys[i] = s2->keys[j]; + if (s1->values != NULL) + s1->values[i] = s2->values[j]; +} - assert(compare != NULL); - /* Call the user's comparison function and translate the 3-way - * result into true or false (or error). - */ - args = PyTuple_New(2); - if (args == NULL) - return -1; - Py_INCREF(x); - Py_INCREF(y); - PyTuple_SET_ITEM(args, 0, x); - PyTuple_SET_ITEM(args, 1, y); - res = PyObject_Call(compare, args, NULL); - Py_DECREF(args); - if (res == NULL) - return -1; - if (!PyInt_Check(res)) { - PyErr_Format(PyExc_TypeError, - "comparison function must return int, not %.200s", - res->ob_type->tp_name); - Py_DECREF(res); - return -1; - } - i = PyInt_AsLong(res); - Py_DECREF(res); - return i < 0; +Py_LOCAL_INLINE(void) +sortslice_copy_incr(sortslice *dst, sortslice *src) +{ + *dst->keys++ = *src->keys++; + if (dst->values != NULL) + *dst->values++ = *src->values++; } -/* If COMPARE is NULL, calls PyObject_RichCompareBool with Py_LT, else calls - * islt. This avoids a layer of function call in the usual case, and - * sorting does many comparisons. +Py_LOCAL_INLINE(void) +sortslice_copy_decr(sortslice *dst, sortslice *src) +{ + *dst->keys-- = *src->keys--; + if (dst->values != NULL) + *dst->values-- = *src->values--; +} + + +Py_LOCAL_INLINE(void) +sortslice_memcpy(sortslice *s1, Py_ssize_t i, sortslice *s2, Py_ssize_t j, + Py_ssize_t n) +{ + memcpy(&s1->keys[i], &s2->keys[j], sizeof(PyObject *) * n); + if (s1->values != NULL) + memcpy(&s1->values[i], &s2->values[j], sizeof(PyObject *) * n); +} + +Py_LOCAL_INLINE(void) +sortslice_memmove(sortslice *s1, Py_ssize_t i, sortslice *s2, Py_ssize_t j, + Py_ssize_t n) +{ + memmove(&s1->keys[i], &s2->keys[j], sizeof(PyObject *) * n); + if (s1->values != NULL) + memmove(&s1->values[i], &s2->values[j], sizeof(PyObject *) * n); +} + +Py_LOCAL_INLINE(void) +sortslice_advance(sortslice *slice, Py_ssize_t n) +{ + slice->keys += n; + if (slice->values != NULL) + slice->values += n; +} + +/* Comparison function: PyObject_RichCompareBool with Py_LT. * Returns -1 on error, 1 if x < y, 0 if x >= y. */ -#define ISLT(X, Y, COMPARE) ((COMPARE) == NULL ? \ - PyObject_RichCompareBool(X, Y, Py_LT) : \ - islt(X, Y, COMPARE)) + +#define ISLT(X, Y) (PyObject_RichCompareBool(X, Y, Py_LT)) /* Compare X to Y via "<". Goto "fail" if the comparison raises an error. Else "k" is set to true iff X<Y, and an "if (k)" block is started. It makes more sense in context <wink>. X and Y are PyObject*s. */ -#define IFLT(X, Y) if ((k = ISLT(X, Y, compare)) < 0) goto fail; \ +#define IFLT(X, Y) if ((k = ISLT(X, Y)) < 0) goto fail; \ if (k) /* binarysort is the best method for sorting small arrays: it does @@ -1049,20 +1020,19 @@ islt(PyObject *x, PyObject *y, PyObject *compare) the input (nothing is lost or duplicated). */ static int -binarysort(PyObject **lo, PyObject **hi, PyObject **start, PyObject *compare) - /* compare -- comparison function object, or NULL for default */ +binarysort(sortslice lo, PyObject **hi, PyObject **start) { register Py_ssize_t k; register PyObject **l, **p, **r; register PyObject *pivot; - assert(lo <= start && start <= hi); + assert(lo.keys <= start && start <= hi); /* assert [lo, start) is sorted */ - if (lo == start) + if (lo.keys == start) ++start; for (; start < hi; ++start) { /* set l to where *start belongs */ - l = lo; + l = lo.keys; r = start; pivot = *r; /* Invariants: @@ -1089,6 +1059,15 @@ binarysort(PyObject **lo, PyObject **hi, PyObject **start, PyObject *compare) for (p = start; p > l; --p) *p = *(p-1); *l = pivot; + if (lo.values != NULL) { + Py_ssize_t offset = lo.values - lo.keys; + p = start + offset; + pivot = *p; + l += offset; + for (p = start + offset; p > l; --p) + *p = *(p-1); + *l = pivot; + } } return 0; @@ -1115,7 +1094,7 @@ elements to get out of order). Returns -1 in case of error. */ static Py_ssize_t -count_run(PyObject **lo, PyObject **hi, PyObject *compare, int *descending) +count_run(PyObject **lo, PyObject **hi, int *descending) { Py_ssize_t k; Py_ssize_t n; @@ -1170,7 +1149,7 @@ key, and the last n-k should follow key. Returns -1 on error. See listsort.txt for info on the method. */ static Py_ssize_t -gallop_left(PyObject *key, PyObject **a, Py_ssize_t n, Py_ssize_t hint, PyObject *compare) +gallop_left(PyObject *key, PyObject **a, Py_ssize_t n, Py_ssize_t hint) { Py_ssize_t ofs; Py_ssize_t lastofs; @@ -1261,7 +1240,7 @@ we're sticking to "<" comparisons that it's much harder to follow if written as one routine with yet another "left or right?" flag. */ static Py_ssize_t -gallop_right(PyObject *key, PyObject **a, Py_ssize_t n, Py_ssize_t hint, PyObject *compare) +gallop_right(PyObject *key, PyObject **a, Py_ssize_t n, Py_ssize_t hint) { Py_ssize_t ofs; Py_ssize_t lastofs; @@ -1357,14 +1336,11 @@ fail: * a convenient way to pass state around among the helper functions. */ struct s_slice { - PyObject **base; + sortslice base; Py_ssize_t len; }; typedef struct s_MergeState { - /* The user-supplied comparison function. or NULL if none given. */ - PyObject *compare; - /* This controls when we get *into* galloping mode. It's initialized * to MIN_GALLOP. merge_lo and merge_hi tend to nudge it higher for * random data, and lower for highly structured data. @@ -1374,7 +1350,7 @@ typedef struct s_MergeState { /* 'a' is temp storage to help with merges. It contains room for * alloced entries. */ - PyObject **a; /* may point to temparray below */ + sortslice a; /* may point to temparray below */ Py_ssize_t alloced; /* A stack of n pending runs yet to be merged. Run #i starts at @@ -1395,12 +1371,29 @@ typedef struct s_MergeState { /* Conceptually a MergeState's constructor. */ static void -merge_init(MergeState *ms, PyObject *compare) +merge_init(MergeState *ms, Py_ssize_t list_size, int has_keyfunc) { assert(ms != NULL); - ms->compare = compare; - ms->a = ms->temparray; - ms->alloced = MERGESTATE_TEMP_SIZE; + if (has_keyfunc) { + /* The temporary space for merging will need at most half the list + * size rounded up. Use the minimum possible space so we can use the + * rest of temparray for other things. In particular, if there is + * enough extra space, listsort() will use it to store the keys. + */ + ms->alloced = (list_size + 1) / 2; + + /* ms->alloced describes how many keys will be stored at + ms->temparray, but we also need to store the values. Hence, + ms->alloced is capped at half of MERGESTATE_TEMP_SIZE. */ + if (MERGESTATE_TEMP_SIZE / 2 < ms->alloced) + ms->alloced = MERGESTATE_TEMP_SIZE / 2; + ms->a.values = &ms->temparray[ms->alloced]; + } + else { + ms->alloced = MERGESTATE_TEMP_SIZE; + ms->a.values = NULL; + } + ms->a.keys = ms->temparray; ms->n = 0; ms->min_gallop = MIN_GALLOP; } @@ -1413,10 +1406,8 @@ static void merge_freemem(MergeState *ms) { assert(ms != NULL); - if (ms->a != ms->temparray) - PyMem_Free(ms->a); - ms->a = ms->temparray; - ms->alloced = MERGESTATE_TEMP_SIZE; + if (ms->a.keys != ms->temparray) + PyMem_Free(ms->a.keys); } /* Ensure enough temp memory for 'need' array slots is available. @@ -1425,53 +1416,60 @@ merge_freemem(MergeState *ms) static int merge_getmem(MergeState *ms, Py_ssize_t need) { + int multiplier; + assert(ms != NULL); if (need <= ms->alloced) return 0; + + multiplier = ms->a.values != NULL ? 2 : 1; + /* Don't realloc! That can cost cycles to copy the old data, but * we don't care what's in the block. */ merge_freemem(ms); - if ((size_t)need > PY_SSIZE_T_MAX / sizeof(PyObject*)) { + if ((size_t)need > PY_SSIZE_T_MAX / sizeof(PyObject*) / multiplier) { PyErr_NoMemory(); return -1; } - ms->a = (PyObject **)PyMem_Malloc(need * sizeof(PyObject*)); - if (ms->a) { + ms->a.keys = (PyObject**)PyMem_Malloc(multiplier * need + * sizeof(PyObject *)); + if (ms->a.keys != NULL) { ms->alloced = need; + if (ms->a.values != NULL) + ms->a.values = &ms->a.keys[need]; return 0; } PyErr_NoMemory(); - merge_freemem(ms); /* reset to sane state */ return -1; } #define MERGE_GETMEM(MS, NEED) ((NEED) <= (MS)->alloced ? 0 : \ merge_getmem(MS, NEED)) -/* Merge the na elements starting at pa with the nb elements starting at pb - * in a stable way, in-place. na and nb must be > 0, and pa + na == pb. - * Must also have that *pb < *pa, that pa[na-1] belongs at the end of the - * merge, and should have na <= nb. See listsort.txt for more info. - * Return 0 if successful, -1 if error. +/* Merge the na elements starting at ssa with the nb elements starting at + * ssb.keys = ssa.keys + na in a stable way, in-place. na and nb must be > 0. + * Must also have that ssa.keys[na-1] belongs at the end of the merge, and + * should have na <= nb. See listsort.txt for more info. Return 0 if + * successful, -1 if error. */ static Py_ssize_t -merge_lo(MergeState *ms, PyObject **pa, Py_ssize_t na, - PyObject **pb, Py_ssize_t nb) +merge_lo(MergeState *ms, sortslice ssa, Py_ssize_t na, + sortslice ssb, Py_ssize_t nb) { Py_ssize_t k; - PyObject *compare; - PyObject **dest; + sortslice dest; int result = -1; /* guilty until proved innocent */ Py_ssize_t min_gallop; - assert(ms && pa && pb && na > 0 && nb > 0 && pa + na == pb); + assert(ms && ssa.keys && ssb.keys && na > 0 && nb > 0); + assert(ssa.keys + na == ssb.keys); if (MERGE_GETMEM(ms, na) < 0) return -1; - memcpy(ms->a, pa, na * sizeof(PyObject*)); - dest = pa; - pa = ms->a; + sortslice_memcpy(&ms->a, 0, &ssa, 0, na); + dest = ssa; + ssa = ms->a; - *dest++ = *pb++; + sortslice_copy_incr(&dest, &ssb); --nb; if (nb == 0) goto Succeed; @@ -1479,7 +1477,6 @@ merge_lo(MergeState *ms, PyObject **pa, Py_ssize_t na, goto CopyB; min_gallop = ms->min_gallop; - compare = ms->compare; for (;;) { Py_ssize_t acount = 0; /* # of times A won in a row */ Py_ssize_t bcount = 0; /* # of times B won in a row */ @@ -1489,11 +1486,11 @@ merge_lo(MergeState *ms, PyObject **pa, Py_ssize_t na, */ for (;;) { assert(na > 1 && nb > 0); - k = ISLT(*pb, *pa, compare); + k = ISLT(ssb.keys[0], ssa.keys[0]); if (k) { if (k < 0) goto Fail; - *dest++ = *pb++; + sortslice_copy_incr(&dest, &ssb); ++bcount; acount = 0; --nb; @@ -1503,7 +1500,7 @@ merge_lo(MergeState *ms, PyObject **pa, Py_ssize_t na, break; } else { - *dest++ = *pa++; + sortslice_copy_incr(&dest, &ssa); ++acount; bcount = 0; --na; @@ -1524,14 +1521,14 @@ merge_lo(MergeState *ms, PyObject **pa, Py_ssize_t na, assert(na > 1 && nb > 0); min_gallop -= min_gallop > 1; ms->min_gallop = min_gallop; - k = gallop_right(*pb, pa, na, 0, compare); + k = gallop_right(ssb.keys[0], ssa.keys, na, 0); acount = k; if (k) { if (k < 0) goto Fail; - memcpy(dest, pa, k * sizeof(PyObject *)); - dest += k; - pa += k; + sortslice_memcpy(&dest, 0, &ssa, 0, k); + sortslice_advance(&dest, k); + sortslice_advance(&ssa, k); na -= k; if (na == 1) goto CopyB; @@ -1542,24 +1539,24 @@ merge_lo(MergeState *ms, PyObject **pa, Py_ssize_t na, if (na == 0) goto Succeed; } - *dest++ = *pb++; + sortslice_copy_incr(&dest, &ssb); --nb; if (nb == 0) goto Succeed; - k = gallop_left(*pa, pb, nb, 0, compare); + k = gallop_left(ssa.keys[0], ssb.keys, nb, 0); bcount = k; if (k) { if (k < 0) goto Fail; - memmove(dest, pb, k * sizeof(PyObject *)); - dest += k; - pb += k; + sortslice_memmove(&dest, 0, &ssb, 0, k); + sortslice_advance(&dest, k); + sortslice_advance(&ssb, k); nb -= k; if (nb == 0) goto Succeed; } - *dest++ = *pa++; + sortslice_copy_incr(&dest, &ssa); --na; if (na == 1) goto CopyB; @@ -1571,44 +1568,46 @@ Succeed: result = 0; Fail: if (na) - memcpy(dest, pa, na * sizeof(PyObject*)); + sortslice_memcpy(&dest, 0, &ssa, 0, na); return result; CopyB: assert(na == 1 && nb > 0); - /* The last element of pa belongs at the end of the merge. */ - memmove(dest, pb, nb * sizeof(PyObject *)); - dest[nb] = *pa; + /* The last element of ssa belongs at the end of the merge. */ + sortslice_memmove(&dest, 0, &ssb, 0, nb); + sortslice_copy(&dest, nb, &ssa, 0); return 0; } -/* Merge the na elements starting at pa with the nb elements starting at pb - * in a stable way, in-place. na and nb must be > 0, and pa + na == pb. - * Must also have that *pb < *pa, that pa[na-1] belongs at the end of the - * merge, and should have na >= nb. See listsort.txt for more info. - * Return 0 if successful, -1 if error. +/* Merge the na elements starting at pa with the nb elements starting at + * ssb.keys = ssa.keys + na in a stable way, in-place. na and nb must be > 0. + * Must also have that ssa.keys[na-1] belongs at the end of the merge, and + * should have na >= nb. See listsort.txt for more info. Return 0 if + * successful, -1 if error. */ static Py_ssize_t -merge_hi(MergeState *ms, PyObject **pa, Py_ssize_t na, PyObject **pb, Py_ssize_t nb) +merge_hi(MergeState *ms, sortslice ssa, Py_ssize_t na, + sortslice ssb, Py_ssize_t nb) { Py_ssize_t k; - PyObject *compare; - PyObject **dest; + sortslice dest, basea, baseb; int result = -1; /* guilty until proved innocent */ - PyObject **basea; - PyObject **baseb; Py_ssize_t min_gallop; - assert(ms && pa && pb && na > 0 && nb > 0 && pa + na == pb); + assert(ms && ssa.keys && ssb.keys && na > 0 && nb > 0); + assert(ssa.keys + na == ssb.keys); if (MERGE_GETMEM(ms, nb) < 0) return -1; - dest = pb + nb - 1; - memcpy(ms->a, pb, nb * sizeof(PyObject*)); - basea = pa; + dest = ssb; + sortslice_advance(&dest, nb-1); + sortslice_memcpy(&ms->a, 0, &ssb, 0, nb); + basea = ssa; baseb = ms->a; - pb = ms->a + nb - 1; - pa += na - 1; + ssb.keys = ms->a.keys + nb - 1; + if (ssb.values != NULL) + ssb.values = ms->a.values + nb - 1; + sortslice_advance(&ssa, na - 1); - *dest-- = *pa--; + sortslice_copy_decr(&dest, &ssa); --na; if (na == 0) goto Succeed; @@ -1616,7 +1615,6 @@ merge_hi(MergeState *ms, PyObject **pa, Py_ssize_t na, PyObject **pb, Py_ssize_t goto CopyA; min_gallop = ms->min_gallop; - compare = ms->compare; for (;;) { Py_ssize_t acount = 0; /* # of times A won in a row */ Py_ssize_t bcount = 0; /* # of times B won in a row */ @@ -1626,11 +1624,11 @@ merge_hi(MergeState *ms, PyObject **pa, Py_ssize_t na, PyObject **pb, Py_ssize_t */ for (;;) { assert(na > 0 && nb > 1); - k = ISLT(*pb, *pa, compare); + k = ISLT(ssb.keys[0], ssa.keys[0]); if (k) { if (k < 0) goto Fail; - *dest-- = *pa--; + sortslice_copy_decr(&dest, &ssa); ++acount; bcount = 0; --na; @@ -1640,7 +1638,7 @@ merge_hi(MergeState *ms, PyObject **pa, Py_ssize_t na, PyObject **pb, Py_ssize_t break; } else { - *dest-- = *pb--; + sortslice_copy_decr(&dest, &ssb); ++bcount; acount = 0; --nb; @@ -1661,33 +1659,33 @@ merge_hi(MergeState *ms, PyObject **pa, Py_ssize_t na, PyObject **pb, Py_ssize_t assert(na > 0 && nb > 1); min_gallop -= min_gallop > 1; ms->min_gallop = min_gallop; - k = gallop_right(*pb, basea, na, na-1, compare); + k = gallop_right(ssb.keys[0], basea.keys, na, na-1); if (k < 0) goto Fail; k = na - k; acount = k; if (k) { - dest -= k; - pa -= k; - memmove(dest+1, pa+1, k * sizeof(PyObject *)); + sortslice_advance(&dest, -k); + sortslice_advance(&ssa, -k); + sortslice_memmove(&dest, 1, &ssa, 1, k); na -= k; if (na == 0) goto Succeed; } - *dest-- = *pb--; + sortslice_copy_decr(&dest, &ssb); --nb; if (nb == 1) goto CopyA; - k = gallop_left(*pa, baseb, nb, nb-1, compare); + k = gallop_left(ssa.keys[0], baseb.keys, nb, nb-1); if (k < 0) goto Fail; k = nb - k; bcount = k; if (k) { - dest -= k; - pb -= k; - memcpy(dest+1, pb+1, k * sizeof(PyObject *)); + sortslice_advance(&dest, -k); + sortslice_advance(&ssb, -k); + sortslice_memcpy(&dest, 1, &ssb, 1, k); nb -= k; if (nb == 1) goto CopyA; @@ -1698,7 +1696,7 @@ merge_hi(MergeState *ms, PyObject **pa, Py_ssize_t na, PyObject **pb, Py_ssize_t if (nb == 0) goto Succeed; } - *dest-- = *pa--; + sortslice_copy_decr(&dest, &ssa); --na; if (na == 0) goto Succeed; @@ -1710,15 +1708,15 @@ Succeed: result = 0; Fail: if (nb) - memcpy(dest-(nb-1), baseb, nb * sizeof(PyObject*)); + sortslice_memcpy(&dest, -(nb-1), &baseb, 0, nb); return result; CopyA: assert(nb == 1 && na > 0); - /* The first element of pb belongs at the front of the merge. */ - dest -= na; - pa -= na; - memmove(dest+1, pa+1, na * sizeof(PyObject *)); - *dest = *pb; + /* The first element of ssb belongs at the front of the merge. */ + sortslice_memmove(&dest, 1-na, &ssa, 1-na, na); + sortslice_advance(&dest, -na); + sortslice_advance(&ssa, -na); + sortslice_copy(&dest, 0, &ssb, 0); return 0; } @@ -1728,22 +1726,21 @@ CopyA: static Py_ssize_t merge_at(MergeState *ms, Py_ssize_t i) { - PyObject **pa, **pb; + sortslice ssa, ssb; Py_ssize_t na, nb; Py_ssize_t k; - PyObject *compare; assert(ms != NULL); assert(ms->n >= 2); assert(i >= 0); assert(i == ms->n - 2 || i == ms->n - 3); - pa = ms->pending[i].base; + ssa = ms->pending[i].base; na = ms->pending[i].len; - pb = ms->pending[i+1].base; + ssb = ms->pending[i+1].base; nb = ms->pending[i+1].len; assert(na > 0 && nb > 0); - assert(pa + na == pb); + assert(ssa.keys + na == ssb.keys); /* Record the length of the combined runs; if i is the 3rd-last * run now, also slide over the last run (which isn't involved @@ -1757,11 +1754,10 @@ merge_at(MergeState *ms, Py_ssize_t i) /* Where does b start in a? Elements in a before that can be * ignored (already in place). */ - compare = ms->compare; - k = gallop_right(*pb, pa, na, 0, compare); + k = gallop_right(*ssb.keys, ssa.keys, na, 0); if (k < 0) return -1; - pa += k; + sortslice_advance(&ssa, k); na -= k; if (na == 0) return 0; @@ -1769,7 +1765,7 @@ merge_at(MergeState *ms, Py_ssize_t i) /* Where does a end in b? Elements in b after that can be * ignored (already in place). */ - nb = gallop_left(pa[na-1], pb, nb, nb-1, compare); + nb = gallop_left(ssa.keys[na-1], ssb.keys, nb, nb-1); if (nb <= 0) return nb; @@ -1777,9 +1773,9 @@ merge_at(MergeState *ms, Py_ssize_t i) * min(na, nb) elements. */ if (na <= nb) - return merge_lo(ms, pa, na, pb, nb); + return merge_lo(ms, ssa, na, ssb, nb); else - return merge_hi(ms, pa, na, pb, nb); + return merge_hi(ms, ssa, na, ssb, nb); } /* Examine the stack of runs waiting to be merged, merging adjacent runs @@ -1860,178 +1856,12 @@ merge_compute_minrun(Py_ssize_t n) return n + r; } -/* Special wrapper to support stable sorting using the decorate-sort-undecorate - pattern. Holds a key which is used for comparisons and the original record - which is returned during the undecorate phase. By exposing only the key - during comparisons, the underlying sort stability characteristics are left - unchanged. Also, if a custom comparison function is used, it will only see - the key instead of a full record. */ - -typedef struct { - PyObject_HEAD - PyObject *key; - PyObject *value; -} sortwrapperobject; - -PyDoc_STRVAR(sortwrapper_doc, "Object wrapper with a custom sort key."); -static PyObject * -sortwrapper_richcompare(sortwrapperobject *, sortwrapperobject *, int); -static void -sortwrapper_dealloc(sortwrapperobject *); - -static PyTypeObject sortwrapper_type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - "sortwrapper", /* tp_name */ - sizeof(sortwrapperobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)sortwrapper_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | - Py_TPFLAGS_HAVE_RICHCOMPARE, /* tp_flags */ - sortwrapper_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - (richcmpfunc)sortwrapper_richcompare, /* tp_richcompare */ -}; - - -static PyObject * -sortwrapper_richcompare(sortwrapperobject *a, sortwrapperobject *b, int op) -{ - if (!PyObject_TypeCheck(b, &sortwrapper_type)) { - PyErr_SetString(PyExc_TypeError, - "expected a sortwrapperobject"); - return NULL; - } - return PyObject_RichCompare(a->key, b->key, op); -} - static void -sortwrapper_dealloc(sortwrapperobject *so) -{ - Py_XDECREF(so->key); - Py_XDECREF(so->value); - PyObject_Del(so); -} - -/* Returns a new reference to a sortwrapper. - Consumes the references to the two underlying objects. */ - -static PyObject * -build_sortwrapper(PyObject *key, PyObject *value) -{ - sortwrapperobject *so; - - so = PyObject_New(sortwrapperobject, &sortwrapper_type); - if (so == NULL) - return NULL; - so->key = key; - so->value = value; - return (PyObject *)so; -} - -/* Returns a new reference to the value underlying the wrapper. */ -static PyObject * -sortwrapper_getvalue(PyObject *so) -{ - PyObject *value; - - if (!PyObject_TypeCheck(so, &sortwrapper_type)) { - PyErr_SetString(PyExc_TypeError, - "expected a sortwrapperobject"); - return NULL; - } - value = ((sortwrapperobject *)so)->value; - Py_INCREF(value); - return value; -} - -/* Wrapper for user specified cmp functions in combination with a - specified key function. Makes sure the cmp function is presented - with the actual key instead of the sortwrapper */ - -typedef struct { - PyObject_HEAD - PyObject *func; -} cmpwrapperobject; - -static void -cmpwrapper_dealloc(cmpwrapperobject *co) -{ - Py_XDECREF(co->func); - PyObject_Del(co); -} - -static PyObject * -cmpwrapper_call(cmpwrapperobject *co, PyObject *args, PyObject *kwds) -{ - PyObject *x, *y, *xx, *yy; - - if (!PyArg_UnpackTuple(args, "", 2, 2, &x, &y)) - return NULL; - if (!PyObject_TypeCheck(x, &sortwrapper_type) || - !PyObject_TypeCheck(y, &sortwrapper_type)) { - PyErr_SetString(PyExc_TypeError, - "expected a sortwrapperobject"); - return NULL; - } - xx = ((sortwrapperobject *)x)->key; - yy = ((sortwrapperobject *)y)->key; - return PyObject_CallFunctionObjArgs(co->func, xx, yy, NULL); -} - -PyDoc_STRVAR(cmpwrapper_doc, "cmp() wrapper for sort with custom keys."); - -static PyTypeObject cmpwrapper_type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - "cmpwrapper", /* tp_name */ - sizeof(cmpwrapperobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)cmpwrapper_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - (ternaryfunc)cmpwrapper_call, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - cmpwrapper_doc, /* tp_doc */ -}; - -static PyObject * -build_cmpwrapper(PyObject *cmpfunc) +reverse_sortslice(sortslice *s, Py_ssize_t n) { - cmpwrapperobject *co; - - co = PyObject_New(cmpwrapperobject, &cmpwrapper_type); - if (co == NULL) - return NULL; - Py_INCREF(cmpfunc); - co->func = cmpfunc; - return (PyObject *)co; + reverse_slice(s->keys, &s->keys[n]); + if (s->values != NULL) + reverse_slice(s->values, &s->values[n]); } /* An adaptive, stable, natural mergesort. See listsort.txt. @@ -2043,40 +1873,33 @@ static PyObject * listsort(PyListObject *self, PyObject *args, PyObject *kwds) { MergeState ms; - PyObject **lo, **hi; Py_ssize_t nremaining; Py_ssize_t minrun; + sortslice lo; Py_ssize_t saved_ob_size, saved_allocated; PyObject **saved_ob_item; PyObject **final_ob_item; - PyObject *compare = NULL; PyObject *result = NULL; /* guilty until proved innocent */ int reverse = 0; PyObject *keyfunc = NULL; Py_ssize_t i; - PyObject *key, *value, *kvpair; - static char *kwlist[] = {"cmp", "key", "reverse", 0}; + static char *kwlist[] = {"key", "reverse", 0}; + PyObject **keys; assert(self != NULL); assert (PyList_Check(self)); if (args != NULL) { - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOi:sort", - kwlist, &compare, &keyfunc, &reverse)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oi:sort", + kwlist, &keyfunc, &reverse)) return NULL; + if (Py_SIZE(args) > 0) { + PyErr_SetString(PyExc_TypeError, + "must use keyword argument for key function"); + return NULL; + } } - if (compare == Py_None) - compare = NULL; - if (compare != NULL && - PyErr_WarnPy3k("the cmp argument is not supported in 3.x", 1) < 0) - return NULL; if (keyfunc == Py_None) keyfunc = NULL; - if (compare != NULL && keyfunc != NULL) { - compare = build_cmpwrapper(compare); - if (compare == NULL) - return NULL; - } else - Py_XINCREF(compare); /* The list is temporarily made empty, so that mutations performed * by comparison functions can't affect the slice of memory we're @@ -2090,59 +1913,70 @@ listsort(PyListObject *self, PyObject *args, PyObject *kwds) self->ob_item = NULL; self->allocated = -1; /* any operation will reset it to >= 0 */ - if (keyfunc != NULL) { - for (i=0 ; i < saved_ob_size ; i++) { - value = saved_ob_item[i]; - key = PyObject_CallFunctionObjArgs(keyfunc, value, - NULL); - if (key == NULL) { - for (i=i-1 ; i>=0 ; i--) { - kvpair = saved_ob_item[i]; - value = sortwrapper_getvalue(kvpair); - saved_ob_item[i] = value; - Py_DECREF(kvpair); - } - goto dsu_fail; + if (keyfunc == NULL) { + keys = NULL; + lo.keys = saved_ob_item; + lo.values = NULL; + } + else { + if (saved_ob_size < MERGESTATE_TEMP_SIZE/2) + /* Leverage stack space we allocated but won't otherwise use */ + keys = &ms.temparray[saved_ob_size+1]; + else { + keys = PyMem_MALLOC(sizeof(PyObject *) * saved_ob_size); + if (keys == NULL) + return NULL; + } + + for (i = 0; i < saved_ob_size ; i++) { + keys[i] = PyObject_CallFunctionObjArgs(keyfunc, saved_ob_item[i], + NULL); + if (keys[i] == NULL) { + for (i=i-1 ; i>=0 ; i--) + Py_DECREF(keys[i]); + if (keys != &ms.temparray[saved_ob_size+1]) + PyMem_FREE(keys); + goto keyfunc_fail; } - kvpair = build_sortwrapper(key, value); - if (kvpair == NULL) - goto dsu_fail; - saved_ob_item[i] = kvpair; } - } - /* Reverse sort stability achieved by initially reversing the list, - applying a stable forward sort, then reversing the final result. */ - if (reverse && saved_ob_size > 1) - reverse_slice(saved_ob_item, saved_ob_item + saved_ob_size); + lo.keys = keys; + lo.values = saved_ob_item; + } - merge_init(&ms, compare); + merge_init(&ms, saved_ob_size, keys != NULL); nremaining = saved_ob_size; if (nremaining < 2) goto succeed; + /* Reverse sort stability achieved by initially reversing the list, + applying a stable forward sort, then reversing the final result. */ + if (reverse) { + if (keys != NULL) + reverse_slice(&keys[0], &keys[saved_ob_size]); + reverse_slice(&saved_ob_item[0], &saved_ob_item[saved_ob_size]); + } + /* March over the array once, left to right, finding natural runs, * and extending short natural runs to minrun elements. */ - lo = saved_ob_item; - hi = lo + nremaining; minrun = merge_compute_minrun(nremaining); do { int descending; Py_ssize_t n; /* Identify next run. */ - n = count_run(lo, hi, compare, &descending); + n = count_run(lo.keys, lo.keys + nremaining, &descending); if (n < 0) goto fail; if (descending) - reverse_slice(lo, lo + n); + reverse_sortslice(&lo, n); /* If short, extend to min(minrun, nremaining). */ if (n < minrun) { const Py_ssize_t force = nremaining <= minrun ? nremaining : minrun; - if (binarysort(lo, lo + force, lo + n, compare) < 0) + if (binarysort(lo, lo.keys + force, lo.keys + n) < 0) goto fail; n = force; } @@ -2154,27 +1988,27 @@ listsort(PyListObject *self, PyObject *args, PyObject *kwds) if (merge_collapse(&ms) < 0) goto fail; /* Advance to find next run. */ - lo += n; + sortslice_advance(&lo, n); nremaining -= n; } while (nremaining); - assert(lo == hi); if (merge_force_collapse(&ms) < 0) goto fail; assert(ms.n == 1); - assert(ms.pending[0].base == saved_ob_item); + assert(keys == NULL + ? ms.pending[0].base.keys == saved_ob_item + : ms.pending[0].base.keys == &keys[0]); assert(ms.pending[0].len == saved_ob_size); + lo = ms.pending[0].base; succeed: result = Py_None; fail: - if (keyfunc != NULL) { - for (i=0 ; i < saved_ob_size ; i++) { - kvpair = saved_ob_item[i]; - value = sortwrapper_getvalue(kvpair); - saved_ob_item[i] = value; - Py_DECREF(kvpair); - } + if (keys != NULL) { + for (i = 0; i < saved_ob_size; i++) + Py_DECREF(keys[i]); + if (keys != &ms.temparray[saved_ob_size+1]) + PyMem_FREE(keys); } if (self->allocated != -1 && result != NULL) { @@ -2190,7 +2024,7 @@ fail: merge_freemem(&ms); -dsu_fail: +keyfunc_fail: final_ob_item = self->ob_item; i = Py_SIZE(self); Py_SIZE(self) = saved_ob_size; @@ -2204,7 +2038,6 @@ dsu_fail: } PyMem_FREE(final_ob_item); } - Py_XDECREF(compare); Py_XINCREF(result); return result; } @@ -2296,19 +2129,19 @@ listindex(PyListObject *self, PyObject *args) for (i = start; i < stop && i < Py_SIZE(self); i++) { int cmp = PyObject_RichCompareBool(self->ob_item[i], v, Py_EQ); if (cmp > 0) - return PyInt_FromSsize_t(i); + return PyLong_FromSsize_t(i); else if (cmp < 0) return NULL; } if (err_format == NULL) { - err_format = PyString_FromString("%r is not in list"); + err_format = PyUnicode_FromString("%r is not in list"); if (err_format == NULL) return NULL; } format_tuple = PyTuple_Pack(1, v); if (format_tuple == NULL) return NULL; - err_string = PyString_Format(err_format, format_tuple); + err_string = PyUnicode_Format(err_format, format_tuple); Py_DECREF(format_tuple); if (err_string == NULL) return NULL; @@ -2330,7 +2163,7 @@ listcount(PyListObject *self, PyObject *v) else if (cmp < 0) return NULL; } - return PyInt_FromSsize_t(count); + return PyLong_FromSsize_t(count); } static PyObject * @@ -2469,7 +2302,7 @@ list_sizeof(PyListObject *self) Py_ssize_t res; res = sizeof(PyListObject) + self->allocated * sizeof(void*); - return PyInt_FromSsize_t(res); + return PyLong_FromSsize_t(res); } static PyObject *list_iter(PyObject *seq); @@ -2501,8 +2334,7 @@ PyDoc_STRVAR(count_doc, PyDoc_STRVAR(reverse_doc, "L.reverse() -- reverse *IN PLACE*"); PyDoc_STRVAR(sort_doc, -"L.sort(cmp=None, key=None, reverse=False) -- stable sort *IN PLACE*;\n\ -cmp(x, y) -> -1, 0, 1"); +"L.sort(key=None, reverse=False) -- stable sort *IN PLACE*"); static PyObject *list_subscript(PyListObject*, PyObject*); @@ -2527,9 +2359,9 @@ static PySequenceMethods list_as_sequence = { (binaryfunc)list_concat, /* sq_concat */ (ssizeargfunc)list_repeat, /* sq_repeat */ (ssizeargfunc)list_item, /* sq_item */ - (ssizessizeargfunc)list_slice, /* sq_slice */ + 0, /* sq_slice */ (ssizeobjargproc)list_ass_item, /* sq_ass_item */ - (ssizessizeobjargproc)list_ass_slice, /* sq_ass_slice */ + 0, /* sq_ass_slice */ (objobjproc)list_contains, /* sq_contains */ (binaryfunc)list_inplace_concat, /* sq_inplace_concat */ (ssizeargfunc)list_inplace_repeat, /* sq_inplace_repeat */ @@ -2539,7 +2371,6 @@ PyDoc_STRVAR(list_doc, "list() -> new empty list\n" "list(iterable) -> new list initialized from iterable's items"); - static PyObject * list_subscript(PyListObject* self, PyObject* item) { @@ -2558,7 +2389,7 @@ list_subscript(PyListObject* self, PyObject* item) PyObject* it; PyObject **src, **dest; - if (PySlice_GetIndicesEx((PySliceObject*)item, Py_SIZE(self), + if (PySlice_GetIndicesEx(item, Py_SIZE(self), &start, &stop, &step, &slicelength) < 0) { return NULL; } @@ -2607,7 +2438,7 @@ list_ass_subscript(PyListObject* self, PyObject* item, PyObject* value) else if (PySlice_Check(item)) { Py_ssize_t start, stop, step, slicelength; - if (PySlice_GetIndicesEx((PySliceObject*)item, Py_SIZE(self), + if (PySlice_GetIndicesEx(item, Py_SIZE(self), &start, &stop, &step, &slicelength) < 0) { return -1; } @@ -2768,15 +2599,15 @@ PyTypeObject PyList_Type = { sizeof(PyListObject), 0, (destructor)list_dealloc, /* tp_dealloc */ - (printfunc)list_print, /* tp_print */ + 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ - 0, /* tp_compare */ + 0, /* tp_reserved */ (reprfunc)list_repr, /* tp_repr */ 0, /* tp_as_number */ &list_as_sequence, /* tp_as_sequence */ &list_as_mapping, /* tp_as_mapping */ - (hashfunc)PyObject_HashNotImplemented, /* tp_hash */ + PyObject_HashNotImplemented, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ @@ -2829,7 +2660,7 @@ static PyMethodDef listiter_methods[] = { PyTypeObject PyListIter_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - "listiterator", /* tp_name */ + "list_iterator", /* tp_name */ sizeof(listiterobject), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ @@ -2837,7 +2668,7 @@ PyTypeObject PyListIter_Type = { 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ - 0, /* tp_compare */ + 0, /* tp_reserved */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ @@ -2926,9 +2757,9 @@ listiter_len(listiterobject *it) if (it->it_seq) { len = PyList_GET_SIZE(it->it_seq) - it->it_index; if (len >= 0) - return PyInt_FromSsize_t(len); + return PyLong_FromSsize_t(len); } - return PyInt_FromLong(0); + return PyLong_FromLong(0); } /*********************** List Reverse Iterator **************************/ @@ -2951,7 +2782,7 @@ static PyMethodDef listreviter_methods[] = { PyTypeObject PyListRevIter_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - "listreverseiterator", /* tp_name */ + "list_reverseiterator", /* tp_name */ sizeof(listreviterobject), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ @@ -2959,7 +2790,7 @@ PyTypeObject PyListRevIter_Type = { 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ - 0, /* tp_compare */ + 0, /* tp_reserved */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ |
