mirror of https://github.com/python/cpython
Rehabilitated the fast-path richcmp code, and sped it up. It wasn't
helping for types that defined tp_richcmp but not tp_compare, although that's when it's most valuable, and strings moved into that category since the fast path was first introduced. Now it helps for same-type non-Instance objects that define rich or 3-way compares. For all the edits here, the rest just amounts to moving the fast path from do_richcmp into PyObject_RichCompare, saving a layer of function call (measurable on my box!). This loses when NESTING_LIMIT is exceeded, but I don't care about that (fast-paths are for normal cases, not pathologies). Also added a tasteful <wink> label to get out of PyObject_RichCompare, as the if/else nesting in this routine was getting incomprehensible.
This commit is contained in:
parent
9930061ce2
commit
67754e993e
|
@ -825,32 +825,6 @@ static PyObject *
|
||||||
do_richcmp(PyObject *v, PyObject *w, int op)
|
do_richcmp(PyObject *v, PyObject *w, int op)
|
||||||
{
|
{
|
||||||
PyObject *res;
|
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);
|
res = try_rich_compare(v, w, op);
|
||||||
if (res != Py_NotImplemented)
|
if (res != Py_NotImplemented)
|
||||||
|
@ -862,8 +836,6 @@ do_richcmp(PyObject *v, PyObject *w, int op)
|
||||||
|
|
||||||
/* Return:
|
/* Return:
|
||||||
NULL for exception;
|
NULL for exception;
|
||||||
NotImplemented if this particular rich comparison is not implemented or
|
|
||||||
undefined;
|
|
||||||
some object not equal to NotImplemented if it is implemented
|
some object not equal to NotImplemented if it is implemented
|
||||||
(this latter object may not be a Boolean).
|
(this latter object may not be a Boolean).
|
||||||
*/
|
*/
|
||||||
|
@ -880,11 +852,12 @@ PyObject_RichCompare(PyObject *v, PyObject *w, int op)
|
||||||
|| (v->ob_type->tp_as_sequence
|
|| (v->ob_type->tp_as_sequence
|
||||||
&& !PyString_Check(v)
|
&& !PyString_Check(v)
|
||||||
&& !PyTuple_Check(v)))) {
|
&& !PyTuple_Check(v)))) {
|
||||||
|
|
||||||
/* try to detect circular data structures */
|
/* try to detect circular data structures */
|
||||||
PyObject *token = check_recursion(v, w, op);
|
PyObject *token = check_recursion(v, w, op);
|
||||||
|
|
||||||
if (token == NULL) {
|
if (token == NULL) {
|
||||||
res = NULL;
|
res = NULL;
|
||||||
|
goto Done;
|
||||||
}
|
}
|
||||||
else if (token == Py_None) {
|
else if (token == Py_None) {
|
||||||
/* already comparing these objects with this operator.
|
/* already comparing these objects with this operator.
|
||||||
|
@ -904,10 +877,41 @@ PyObject_RichCompare(PyObject *v, PyObject *w, int op)
|
||||||
res = do_richcmp(v, w, op);
|
res = do_richcmp(v, w, op);
|
||||||
delete_token(token);
|
delete_token(token);
|
||||||
}
|
}
|
||||||
|
goto Done;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
res = do_richcmp(v, w, op);
|
/* No nesting extremism.
|
||||||
|
If the types are equal, and not old-style instances, try to
|
||||||
|
get out cheap (don't bother with coercions etc.). */
|
||||||
|
if (v->ob_type == w->ob_type && !PyInstance_Check(v)) {
|
||||||
|
cmpfunc fcmp;
|
||||||
|
richcmpfunc frich = RICHCOMPARE(v->ob_type);
|
||||||
|
/* If the type has richcmp, try it first. try_rich_compare
|
||||||
|
tries it two-sided, which is not needed since we've a
|
||||||
|
single type only. */
|
||||||
|
if (frich != NULL) {
|
||||||
|
res = (*frich)(v, w, op);
|
||||||
|
if (res != Py_NotImplemented)
|
||||||
|
goto Done;
|
||||||
|
Py_DECREF(res);
|
||||||
|
}
|
||||||
|
/* No richcmp, or this particular richmp not implemented.
|
||||||
|
Try 3-way cmp. */
|
||||||
|
fcmp = v->ob_type->tp_compare;
|
||||||
|
if (fcmp != NULL) {
|
||||||
|
int c = (*fcmp)(v, w);
|
||||||
|
if (c < 0 && PyErr_Occurred()) {
|
||||||
|
res = NULL;
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
res = convert_3way_to_object(op, c);
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Fast path not taken, or couldn't deliver a useful result. */
|
||||||
|
res = do_richcmp(v, w, op);
|
||||||
|
Done:
|
||||||
compare_nesting--;
|
compare_nesting--;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue