summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin v. Löwis <martin@v.loewis.de>2001-06-09 07:34:05 (GMT)
committerMartin v. Löwis <martin@v.loewis.de>2001-06-09 07:34:05 (GMT)
commit0163d6d6ef85dd0cd0ea4ea6dce4b867e39cd6b9 (patch)
tree238ba5fe594b3f5ab5a890a75a3e0bc86e5890cb
parent7bc50714febbd1a01c5c364844df6d9bd801eb24 (diff)
downloadcpython-0163d6d6ef85dd0cd0ea4ea6dce4b867e39cd6b9.zip
cpython-0163d6d6ef85dd0cd0ea4ea6dce4b867e39cd6b9.tar.gz
cpython-0163d6d6ef85dd0cd0ea4ea6dce4b867e39cd6b9.tar.bz2
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.
-rw-r--r--Lib/UserList.py2
-rw-r--r--Objects/object.c69
-rw-r--r--Objects/typeobject.c14
3 files changed, 62 insertions, 23 deletions
diff --git a/Lib/UserList.py b/Lib/UserList.py
index ee26589..69f683e 100644
--- a/Lib/UserList.py
+++ b/Lib/UserList.py
@@ -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]
diff --git a/Objects/object.c b/Objects/object.c
index 8462971..680a7d4 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -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)
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index c96c0aa..795714d 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -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*/