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:
Martin v. Löwis 2001-06-09 07:34:05 +00:00
parent 7bc50714fe
commit 0163d6d6ef
3 changed files with 62 additions and 23 deletions

View File

@ -22,7 +22,7 @@ class UserList:
if isinstance(other, UserList): return other.data
else: return other
def __cmp__(self, other):
raise RuntimeError, "UserList.__cmp__() is obsolete"
return cmp(self.data, self.__cast(other))
def __contains__(self, item): return item in self.data
def __len__(self): return len(self.data)
def __getitem__(self, i): return self.data[i]

View File

@ -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)

View File

@ -23,6 +23,16 @@ type_getattr(PyTypeObject *t, char *name)
return NULL;
}
static int
type_compare(PyObject *v, PyObject *w)
{
/* This is called with type objects only. So we
can just compare the addresses. */
Py_uintptr_t vv = (Py_uintptr_t)v;
Py_uintptr_t ww = (Py_uintptr_t)w;
return (vv < ww) ? -1 : (vv > ww) ? 1 : 0;
}
static PyObject *
type_repr(PyTypeObject *v)
{
@ -41,12 +51,12 @@ PyTypeObject PyType_Type = {
0, /*tp_print*/
(getattrfunc)type_getattr, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
type_compare, /*tp_compare*/
(reprfunc)type_repr, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash*/
_Py_HashPointer, /*tp_hash*/
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_xxx1*/