summaryrefslogtreecommitdiffstats
path: root/Objects/object.c
diff options
context:
space:
mode:
Diffstat (limited to 'Objects/object.c')
-rw-r--r--Objects/object.c69
1 files changed, 49 insertions, 20 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)