mirror of
https://github.com/python/cpython.git
synced 2025-11-25 04:34:37 +00:00
Patch #424475: Speed-up tp_compare usage, by special-casing the common
case of objects with equal types which support tp_compare. Give type objects a tp_compare function. Also add c<0 tests before a few PyErr_Occurred tests.
This commit is contained in:
parent
7bc50714fe
commit
0163d6d6ef
3 changed files with 62 additions and 23 deletions
|
|
@ -477,16 +477,6 @@ try_3way_compare(PyObject *v, PyObject *w)
|
|||
if (PyInstance_Check(w))
|
||||
return (*w->ob_type->tp_compare)(v, w);
|
||||
|
||||
/* If the types are equal, don't bother with coercions etc. */
|
||||
if (v->ob_type == w->ob_type) {
|
||||
if ((f = v->ob_type->tp_compare) == NULL)
|
||||
return 2;
|
||||
c = (*f)(v, w);
|
||||
if (PyErr_Occurred())
|
||||
return -2;
|
||||
return c < 0 ? -1 : c > 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
/* Try coercion; if it fails, give up */
|
||||
c = PyNumber_CoerceEx(&v, &w);
|
||||
if (c < 0)
|
||||
|
|
@ -499,7 +489,7 @@ try_3way_compare(PyObject *v, PyObject *w)
|
|||
c = (*f)(v, w);
|
||||
Py_DECREF(v);
|
||||
Py_DECREF(w);
|
||||
if (PyErr_Occurred())
|
||||
if (c < 0 && PyErr_Occurred())
|
||||
return -2;
|
||||
return c < 0 ? -1 : c > 0 ? 1 : 0;
|
||||
}
|
||||
|
|
@ -509,7 +499,7 @@ try_3way_compare(PyObject *v, PyObject *w)
|
|||
c = (*f)(w, v); /* swapped! */
|
||||
Py_DECREF(v);
|
||||
Py_DECREF(w);
|
||||
if (PyErr_Occurred())
|
||||
if (c < 0 && PyErr_Occurred())
|
||||
return -2;
|
||||
return c < 0 ? 1 : c > 0 ? -1 : 0; /* negated! */
|
||||
}
|
||||
|
|
@ -590,12 +580,18 @@ default_3way_compare(PyObject *v, PyObject *w)
|
|||
-1 if v < w;
|
||||
0 if v == w;
|
||||
1 if v > w;
|
||||
If the object implements a tp_compare function, it returns
|
||||
whatever this function returns (whether with an exception or not).
|
||||
*/
|
||||
static int
|
||||
do_cmp(PyObject *v, PyObject *w)
|
||||
{
|
||||
int c;
|
||||
cmpfunc f;
|
||||
|
||||
if (v->ob_type == w->ob_type
|
||||
&& (f = v->ob_type->tp_compare) != NULL)
|
||||
return (*f)(v, w);
|
||||
c = try_rich_to_3way_compare(v, w);
|
||||
if (c < 2)
|
||||
return c;
|
||||
|
|
@ -760,16 +756,9 @@ PyObject_Compare(PyObject *v, PyObject *w)
|
|||
}
|
||||
|
||||
static PyObject *
|
||||
try_3way_to_rich_compare(PyObject *v, PyObject *w, int op)
|
||||
convert_3way_to_object(int op, int c)
|
||||
{
|
||||
int c;
|
||||
PyObject *result;
|
||||
|
||||
c = try_3way_compare(v, w);
|
||||
if (c >= 2)
|
||||
c = default_3way_compare(v, w);
|
||||
if (c <= -2)
|
||||
return NULL;
|
||||
switch (op) {
|
||||
case Py_LT: c = c < 0; break;
|
||||
case Py_LE: c = c <= 0; break;
|
||||
|
|
@ -782,11 +771,51 @@ try_3way_to_rich_compare(PyObject *v, PyObject *w, int op)
|
|||
Py_INCREF(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
try_3way_to_rich_compare(PyObject *v, PyObject *w, int op)
|
||||
{
|
||||
int c;
|
||||
|
||||
c = try_3way_compare(v, w);
|
||||
if (c >= 2)
|
||||
c = default_3way_compare(v, w);
|
||||
if (c <= -2)
|
||||
return NULL;
|
||||
return convert_3way_to_object(op, c);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
do_richcmp(PyObject *v, PyObject *w, int op)
|
||||
{
|
||||
PyObject *res;
|
||||
cmpfunc f;
|
||||
|
||||
/* If the types are equal, don't bother with coercions etc.
|
||||
Instances are special-cased in try_3way_compare, since
|
||||
a result of 2 does *not* mean one value being greater
|
||||
than the other. */
|
||||
if (v->ob_type == w->ob_type
|
||||
&& (f = v->ob_type->tp_compare) != NULL
|
||||
&& !PyInstance_Check(v)) {
|
||||
int c;
|
||||
richcmpfunc f1;
|
||||
if ((f1 = RICHCOMPARE(v->ob_type)) != NULL) {
|
||||
/* If the type has richcmp, try it first.
|
||||
try_rich_compare would try it two-sided,
|
||||
which is not needed since we've a single
|
||||
type only. */
|
||||
res = (*f1)(v, w, op);
|
||||
if (res != Py_NotImplemented)
|
||||
return res;
|
||||
Py_DECREF(res);
|
||||
}
|
||||
c = (*f)(v, w);
|
||||
if (c < 0 && PyErr_Occurred())
|
||||
return NULL;
|
||||
return convert_3way_to_object(op, c);
|
||||
}
|
||||
|
||||
res = try_rich_compare(v, w, op);
|
||||
if (res != Py_NotImplemented)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue