diff options
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/object.c | 69 | ||||
-rw-r--r-- | Objects/typeobject.c | 14 |
2 files changed, 61 insertions, 22 deletions
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*/ |