]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Patch #424475: Speed-up tp_compare usage, by special-casing the common
authorMartin v. Löwis <martin@v.loewis.de>
Sat, 9 Jun 2001 07:34:05 +0000 (07:34 +0000)
committerMartin v. Löwis <martin@v.loewis.de>
Sat, 9 Jun 2001 07:34:05 +0000 (07:34 +0000)
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.

Lib/UserList.py
Objects/object.c
Objects/typeobject.c

index ee2658939ff11e57f2a6ba6a8609c3341924280f..69f683e09d8af0c233a5d656c338b5c0f38667fb 100644 (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]
index 846297170c036ba5688c3fceae122a1e96721e17..680a7d49012ab9dbf06d99cf226564f71def6a8d 100644 (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)
index c96c0aa729974d794f3764ea11a8883960223494..795714d8b52f38cdefe8d3fda5c85616a82ff0af 100644 (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*/