]> granicus.if.org Git - python/commitdiff
Changes for PEP 208. PyObject_Compare has been rewritten. Instances no
authorNeil Schemenauer <nascheme@enme.ucalgary.ca>
Thu, 4 Jan 2001 01:48:10 +0000 (01:48 +0000)
committerNeil Schemenauer <nascheme@enme.ucalgary.ca>
Thu, 4 Jan 2001 01:48:10 +0000 (01:48 +0000)
longer get special treatment.  The Py_NotImplemented type is here as well.

Objects/object.c

index 6f22c53769135174192ebb0247cc7ed794bc7261..b11df72193018ec21d4bc54cdc1cf8abf7325a39 100644 (file)
@@ -308,20 +308,96 @@ PyObject_Str(PyObject *v)
        return res;
 }
 
-static PyObject *
+#define NEW_STYLE_NUMBER(o) PyType_HasFeature((o)->ob_type, \
+                               Py_TPFLAGS_NEWSTYLENUMBER)
+
+static int
+cmp_to_int(PyObject *result)
+{
+       int c;
+       if (result == NULL)
+               return -1;
+       if (!PyInt_Check(result)) {
+           PyErr_SetString(PyExc_TypeError,
+                       "comparison did not return an int");
+           return -1;
+       }
+       c = PyInt_AS_LONG(result);
+       Py_DECREF(result);
+       return (c < 0) ? -1 : (c > 0) ? 1 : 0;  
+}
+
+static int
 do_cmp(PyObject *v, PyObject *w)
 {
-       long c;
-       /* __rcmp__ actually won't be called unless __cmp__ isn't defined,
-          because the check in cmpobject() reverses the objects first.
-          This is intentional -- it makes no sense to define cmp(x,y)
-          different than -cmp(y,x). */
-       if (PyInstance_Check(v) || PyInstance_Check(w))
-               return PyInstance_DoBinOp(v, w, "__cmp__", "__rcmp__", do_cmp);
-       c = PyObject_Compare(v, w);
-       if (c && PyErr_Occurred())
-               return NULL;
-       return PyInt_FromLong(c);
+       PyNumberMethods *mv, *mw;
+       PyObject *x;
+       int c;
+
+       /* new style nb_cmp gets priority */
+       mv = v->ob_type->tp_as_number;
+       if (mv != NULL && NEW_STYLE_NUMBER(v) && mv->nb_cmp) {
+               x = (*mv->nb_cmp)(v, w);
+               if (x != Py_NotImplemented)
+                       return cmp_to_int(x);
+               Py_DECREF(x);
+       }
+       mw = w->ob_type->tp_as_number;
+       if (mw != NULL && NEW_STYLE_NUMBER(w) && mw->nb_cmp) {
+               x = (*mw->nb_cmp)(v, w);
+               if (x != Py_NotImplemented)
+                       return cmp_to_int(x);
+               Py_DECREF(x);
+       }
+       /* fall back to tp_compare */
+       if (v->ob_type == w->ob_type) {
+               if (v->ob_type->tp_compare != NULL) {
+                       return (*v->ob_type->tp_compare)(v, w);
+               }
+               else {
+                       Py_uintptr_t iv = (Py_uintptr_t)v;
+                       Py_uintptr_t iw = (Py_uintptr_t)w;
+                       return (iv < iw) ? -1 : (iv > iw) ? 1 : 0;
+               }
+       }
+       if (PyUnicode_Check(v) || PyUnicode_Check(w)) {
+           c = PyUnicode_Compare(v, w);
+           if (c == -1 &&
+               PyErr_Occurred() &&
+               PyErr_ExceptionMatches(PyExc_TypeError))
+               /* TypeErrors are ignored: if Unicode coercion
+               fails due to one of the arguments not having
+               the right type, we continue as defined by the
+               coercion protocol (see above). Luckily,
+               decoding errors are reported as ValueErrors and
+               are not masked by this technique. */
+               PyErr_Clear();
+           else
+               return c;
+       }
+       /* fall back to coercion */
+       if (mv && mw && (!NEW_STYLE_NUMBER(v) || !NEW_STYLE_NUMBER(w))) {
+               /* old style operand, both operations numeric, coerce  */
+               int err = PyNumber_CoerceEx(&v, &w);
+               if (err < 0)
+                       return -1;
+               if (err == 0) {
+                       if (v->ob_type->tp_compare) {
+                               c = (*v->ob_type->tp_compare)(v, w);
+                       }
+                       else {
+                               Py_uintptr_t iv = (Py_uintptr_t)v;
+                               Py_uintptr_t iw = (Py_uintptr_t)w;
+                               c = (iv < iw) ? -1 : (iv > iw) ? 1 : 0;
+                       }
+                       Py_DECREF(v);
+                       Py_DECREF(w);
+                       return c;
+               }
+       }
+       /* last resort, use type names */
+       c = strcmp(v->ob_type->tp_name, w->ob_type->tp_name);
+       return (c < 0) ? -1: (c > 0) ? 1 : 0;
 }
 
 PyObject *_PyCompareState_Key;
@@ -401,128 +477,42 @@ PyObject_Compare(PyObject *v, PyObject *w)
        }
        if (v == w)
                return 0;
-       if (PyInstance_Check(v) || PyInstance_Check(w)) {
-               PyObject *res;
-               int c;
-               if (!PyInstance_Check(v))
-                       return -PyObject_Compare(w, v);
-               _PyCompareState_nesting++;
-               if (_PyCompareState_nesting > NESTING_LIMIT) {
-                       PyObject *inprogress, *pair;
-
-                       inprogress = get_inprogress_dict();
-                       if (inprogress == NULL) {
-                               _PyCompareState_nesting--;
-                               return -1;
-                       }
-                       pair = make_pair(v, w);
-                       if (PyDict_GetItem(inprogress, pair)) {
-                               /* already comparing these objects.  assume
-                                  they're equal until shown otherwise */
-                               Py_DECREF(pair);
-                               _PyCompareState_nesting--;
-                               return 0;
-                       }
-                       if (PyDict_SetItem(inprogress, pair, pair) == -1) {
-                               _PyCompareState_nesting--;
-                               return -1;
-                       }
-                       res = do_cmp(v, w);
-                       /* XXX DelItem shouldn't fail */
-                       PyDict_DelItem(inprogress, pair);
-                       Py_DECREF(pair);
-               } else {
-                       res = do_cmp(v, w);
-               }
-               _PyCompareState_nesting--;
-               if (res == NULL)
-                       return -1;
-               if (!PyInt_Check(res)) {
-                       Py_DECREF(res);
-                       PyErr_SetString(PyExc_TypeError,
-                                       "comparison did not return an int");
-                       return -1;
-               }
-               c = PyInt_AsLong(res);
-               Py_DECREF(res);
-               return (c < 0) ? -1 : (c > 0) ? 1 : 0;  
-       }
-       if ((vtp = v->ob_type) != (wtp = w->ob_type)) {
-               char *vname = vtp->tp_name;
-               char *wname = wtp->tp_name;
-               if (vtp->tp_as_number != NULL && wtp->tp_as_number != NULL) {
-                       int err;
-                       err = PyNumber_CoerceEx(&v, &w);
-                       if (err < 0)
-                               return -1;
-                       else if (err == 0) {
-                               int cmp;
-                               vtp = v->ob_type;
-                               if (vtp->tp_compare == NULL)
-                                       cmp = (v < w) ? -1 : 1;
-                               else
-                                       cmp = (*vtp->tp_compare)(v, w);
-                               Py_DECREF(v);
-                               Py_DECREF(w);
-                               return cmp;
-                       }
-               }
-               else if (PyUnicode_Check(v) || PyUnicode_Check(w)) {
-                       int result = PyUnicode_Compare(v, w);
-                       if (result == -1 && PyErr_Occurred() && 
-                           PyErr_ExceptionMatches(PyExc_TypeError))
-                               /* TypeErrors are ignored: if Unicode coercion
-                               fails due to one of the arguments not
-                               having the right type, we continue as
-                               defined by the coercion protocol (see
-                               above). Luckily, decoding errors are
-                               reported as ValueErrors and are not masked
-                               by this technique. */
-                               PyErr_Clear();
-                       else
-                               return result;
-               }
-               else if (vtp->tp_as_number != NULL)
-                       vname = "";
-               else if (wtp->tp_as_number != NULL)
-                       wname = "";
-               /* Numerical types compare smaller than all other types */
-               return strcmp(vname, wname);
-       }
-       if (vtp->tp_compare == NULL) {
-               Py_uintptr_t iv = (Py_uintptr_t)v;
-               Py_uintptr_t iw = (Py_uintptr_t)w;
-               return (iv < iw) ? -1 : 1;
-       }
+       vtp = v->ob_type;
+       wtp = w->ob_type;
        _PyCompareState_nesting++;
-       if (_PyCompareState_nesting > NESTING_LIMIT
-           && (vtp->tp_as_mapping 
-               || (vtp->tp_as_sequence && !PyString_Check(v)))) {
+       if (_PyCompareState_nesting > NESTING_LIMIT &&
+               (vtp->tp_as_mapping
+                || PyInstance_Check(v)
+                || (vtp->tp_as_sequence && !PyString_Check(v)))) {
+               /* try to detect circular data structures */
                PyObject *inprogress, *pair;
 
                inprogress = get_inprogress_dict();
                if (inprogress == NULL) {
-                       _PyCompareState_nesting--;
-                       return -1;
+                        result = -1;
+                        goto exit_cmp;
                }
                pair = make_pair(v, w);
                if (PyDict_GetItem(inprogress, pair)) {
                        /* already comparing these objects.  assume
                           they're equal until shown otherwise */
                        Py_DECREF(pair);
-                       _PyCompareState_nesting--;
-                       return 0;
+                        result = 0;
+                        goto exit_cmp;
                }
                if (PyDict_SetItem(inprogress, pair, pair) == -1) {
-                       _PyCompareState_nesting--;
-                       return -1;
+                        result = -1;
+                        goto exit_cmp;
                }
-               result = (*vtp->tp_compare)(v, w);
-               PyDict_DelItem(inprogress, pair); /* XXX shouldn't fail */
+               result = do_cmp(v, w);
+               /* XXX DelItem shouldn't fail */
+               PyDict_DelItem(inprogress, pair);
                Py_DECREF(pair);
-       } else {
-               result = (*vtp->tp_compare)(v, w);
        }
+       else {
+               result = do_cmp(v, w);
+       }
+exit_cmp:
        _PyCompareState_nesting--;
        return result;
 }
@@ -917,6 +907,37 @@ PyObject _Py_NoneStruct = {
        PyObject_HEAD_INIT(&PyNothing_Type)
 };
 
+/* NotImplemented is an object that can be used to signal that an
+   operation is not implemented for the given type combination. */
+
+static PyObject *
+NotImplemented_repr(PyObject *op)
+{
+       return PyString_FromString("NotImplemented");
+}
+
+static PyTypeObject PyNotImplemented_Type = {
+       PyObject_HEAD_INIT(&PyType_Type)
+       0,
+       "NotImplemented",
+       0,
+       0,
+       0,              /*tp_dealloc*/ /*never called*/
+       0,              /*tp_print*/
+       0,              /*tp_getattr*/
+       0,              /*tp_setattr*/
+       0,              /*tp_compare*/
+       (reprfunc)NotImplemented_repr, /*tp_repr*/
+       0,              /*tp_as_number*/
+       0,              /*tp_as_sequence*/
+       0,              /*tp_as_mapping*/
+       0,              /*tp_hash */
+};
+
+PyObject _Py_NotImplementedStruct = {
+       PyObject_HEAD_INIT(&PyNotImplemented_Type)
+};
+
 
 #ifdef Py_TRACE_REFS