summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorRaymond Hettinger <python@rcn.com>2008-01-30 20:15:17 (GMT)
committerRaymond Hettinger <python@rcn.com>2008-01-30 20:15:17 (GMT)
commit70b64fce96e894dfa8af5afd1f8b3fe863ba16e0 (patch)
tree15d549753edea1f11c0a3990ea0419426220c445 /Objects
parent4f066126d616d35aa8c0911a915ad64a09aaf16e (diff)
downloadcpython-70b64fce96e894dfa8af5afd1f8b3fe863ba16e0.zip
cpython-70b64fce96e894dfa8af5afd1f8b3fe863ba16e0.tar.gz
cpython-70b64fce96e894dfa8af5afd1f8b3fe863ba16e0.tar.bz2
Issue #1771: Remove cmp parameter from list.sort() and builtin.sorted().
Diffstat (limited to 'Objects')
-rw-r--r--Objects/listobject.c219
1 files changed, 29 insertions, 190 deletions
diff --git a/Objects/listobject.c b/Objects/listobject.c
index 4bc5ca9..a36a29e 100644
--- a/Objects/listobject.c
+++ b/Objects/listobject.c
@@ -888,64 +888,17 @@ 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).
+/* Comparison function: PyObject_RichCompareBool with Py_LT.
* Returns -1 on error, 1 if x < y, 0 if x >= y.
*/
-static int
-islt(PyObject *x, PyObject *y, PyObject *compare)
-{
- PyObject *res;
- PyObject *args;
- Py_ssize_t i;
- 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 (!PyLong_CheckExact(res)) {
- PyErr_Format(PyExc_TypeError,
- "comparison function must return int, not %.200s",
- res->ob_type->tp_name);
- Py_DECREF(res);
- return -1;
- }
- i = PyLong_AsLong(res);
- Py_DECREF(res);
- if (i == -1 && PyErr_Occurred()) {
- /* Overflow in long conversion. */
- return -1;
- }
- return i < 0;
-}
-
-/* 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.
- * 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
@@ -960,8 +913,7 @@ 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(PyObject **lo, PyObject **hi, PyObject **start)
{
register Py_ssize_t k;
register PyObject **l, **p, **r;
@@ -1026,7 +978,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;
@@ -1081,7 +1033,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;
@@ -1172,7 +1124,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;
@@ -1273,9 +1225,6 @@ struct s_slice {
};
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.
@@ -1306,10 +1255,9 @@ typedef struct s_MergeState {
/* Conceptually a MergeState's constructor. */
static void
-merge_init(MergeState *ms, PyObject *compare)
+merge_init(MergeState *ms)
{
assert(ms != NULL);
- ms->compare = compare;
ms->a = ms->temparray;
ms->alloced = MERGESTATE_TEMP_SIZE;
ms->n = 0;
@@ -1366,7 +1314,6 @@ merge_lo(MergeState *ms, PyObject **pa, Py_ssize_t na,
PyObject **pb, Py_ssize_t nb)
{
Py_ssize_t k;
- PyObject *compare;
PyObject **dest;
int result = -1; /* guilty until proved innocent */
Py_ssize_t min_gallop;
@@ -1386,7 +1333,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 */
@@ -1396,7 +1342,7 @@ merge_lo(MergeState *ms, PyObject **pa, Py_ssize_t na,
*/
for (;;) {
assert(na > 1 && nb > 0);
- k = ISLT(*pb, *pa, compare);
+ k = ISLT(*pb, *pa);
if (k) {
if (k < 0)
goto Fail;
@@ -1431,7 +1377,7 @@ 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(*pb, pa, na, 0);
acount = k;
if (k) {
if (k < 0)
@@ -1454,7 +1400,7 @@ merge_lo(MergeState *ms, PyObject **pa, Py_ssize_t na,
if (nb == 0)
goto Succeed;
- k = gallop_left(*pa, pb, nb, 0, compare);
+ k = gallop_left(*pa, pb, nb, 0);
bcount = k;
if (k) {
if (k < 0)
@@ -1498,7 +1444,6 @@ static Py_ssize_t
merge_hi(MergeState *ms, PyObject **pa, Py_ssize_t na, PyObject **pb, Py_ssize_t nb)
{
Py_ssize_t k;
- PyObject *compare;
PyObject **dest;
int result = -1; /* guilty until proved innocent */
PyObject **basea;
@@ -1523,7 +1468,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 */
@@ -1533,7 +1477,7 @@ 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(*pb, *pa);
if (k) {
if (k < 0)
goto Fail;
@@ -1568,7 +1512,7 @@ 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(*pb, basea, na, na-1);
if (k < 0)
goto Fail;
k = na - k;
@@ -1586,7 +1530,7 @@ merge_hi(MergeState *ms, PyObject **pa, Py_ssize_t na, PyObject **pb, Py_ssize_t
if (nb == 1)
goto CopyA;
- k = gallop_left(*pa, baseb, nb, nb-1, compare);
+ k = gallop_left(*pa, baseb, nb, nb-1);
if (k < 0)
goto Fail;
k = nb - k;
@@ -1638,7 +1582,6 @@ merge_at(MergeState *ms, Py_ssize_t i)
PyObject **pa, **pb;
Py_ssize_t na, nb;
Py_ssize_t k;
- PyObject *compare;
assert(ms != NULL);
assert(ms->n >= 2);
@@ -1664,8 +1607,7 @@ 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(*pb, pa, na, 0);
if (k < 0)
return -1;
pa += k;
@@ -1676,7 +1618,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(pa[na-1], pb, nb, nb-1);
if (nb <= 0)
return nb;
@@ -1771,8 +1713,8 @@ merge_compute_minrun(Py_ssize_t n)
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. */
+ unchanged. Also, the comparison function will only see the key instead of
+ a full record. */
typedef struct {
PyObject_HEAD
@@ -1866,104 +1808,6 @@ sortwrapper_getvalue(PyObject *so)
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, &PySortWrapper_Type) ||
- !PyObject_TypeCheck(y, &PySortWrapper_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.");
-
-PyTypeObject PyCmpWrapper_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)
-{
- cmpwrapperobject *co;
-
- co = PyObject_New(cmpwrapperobject, &PyCmpWrapper_Type);
- if (co == NULL)
- return NULL;
- Py_INCREF(cmpfunc);
- co->func = cmpfunc;
- return (PyObject *)co;
-}
-
-static int
-is_default_cmp(PyObject *cmpfunc)
-{
- PyCFunctionObject *f;
- const char *module;
- if (cmpfunc == NULL || cmpfunc == Py_None)
- return 1;
- if (!PyCFunction_Check(cmpfunc))
- return 0;
- f = (PyCFunctionObject *)cmpfunc;
- if (f->m_self != NULL)
- return 0;
- if (!PyUnicode_Check(f->m_module))
- return 0;
- module = PyUnicode_AsString(f->m_module);
- if (module == NULL)
- return 0;
- if (strcmp(module, "builtins") != 0)
- return 0;
- if (strcmp(f->m_ml->ml_name, "cmp") != 0)
- return 0;
- return 1;
-}
-
/* An adaptive, stable, natural mergesort. See listsort.txt.
* Returns Py_None on success, NULL on error. Even in case of error, the
* list will be some permutation of its input state (nothing is lost or
@@ -1979,31 +1823,27 @@ listsort(PyListObject *self, PyObject *args, PyObject *kwds)
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};
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 (is_default_cmp(compare))
- compare = 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
@@ -2043,7 +1883,7 @@ listsort(PyListObject *self, PyObject *args, PyObject *kwds)
if (reverse && saved_ob_size > 1)
reverse_slice(saved_ob_item, saved_ob_item + saved_ob_size);
- merge_init(&ms, compare);
+ merge_init(&ms);
nremaining = saved_ob_size;
if (nremaining < 2)
@@ -2060,7 +1900,7 @@ listsort(PyListObject *self, PyObject *args, PyObject *kwds)
Py_ssize_t n;
/* Identify next run. */
- n = count_run(lo, hi, compare, &descending);
+ n = count_run(lo, hi, &descending);
if (n < 0)
goto fail;
if (descending)
@@ -2069,7 +1909,7 @@ listsort(PyListObject *self, PyObject *args, PyObject *kwds)
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 + force, lo + n) < 0)
goto fail;
n = force;
}
@@ -2131,7 +1971,6 @@ dsu_fail:
}
PyMem_FREE(final_ob_item);
}
- Py_XDECREF(compare);
Py_XINCREF(result);
return result;
}