summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Objects/object.c257
1 files changed, 139 insertions, 118 deletions
diff --git a/Objects/object.c b/Objects/object.c
index 6f22c53..b11df72 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -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