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:
Tim Peters 2001-11-04 07:29:31 +00:00
parent 9930061ce2
commit 67754e993e
1 changed files with 35 additions and 31 deletions

View File

@ -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 {
/* 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); res = do_richcmp(v, w, op);
} Done:
compare_nesting--; compare_nesting--;
return res; return res;
} }