diff options
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/bufferobject.c | 74 | ||||
-rw-r--r-- | Objects/cellobject.c | 14 | ||||
-rw-r--r-- | Objects/classobject.c | 100 | ||||
-rw-r--r-- | Objects/codeobject.c | 15 | ||||
-rw-r--r-- | Objects/dictobject.c | 166 | ||||
-rw-r--r-- | Objects/intobject.c | 15 | ||||
-rw-r--r-- | Objects/listobject.c | 22 | ||||
-rw-r--r-- | Objects/longobject.c | 14 | ||||
-rw-r--r-- | Objects/methodobject.c | 36 | ||||
-rw-r--r-- | Objects/object.c | 552 | ||||
-rw-r--r-- | Objects/sliceobject.c | 70 | ||||
-rw-r--r-- | Objects/typeobject.c | 40 | ||||
-rw-r--r-- | Objects/weakrefobject.c | 22 |
13 files changed, 498 insertions, 642 deletions
diff --git a/Objects/bufferobject.c b/Objects/bufferobject.c index 3a0e3d5..ddef868 100644 --- a/Objects/bufferobject.c +++ b/Objects/bufferobject.c @@ -252,23 +252,65 @@ buffer_dealloc(PyBufferObject *self) } static int -buffer_compare(PyBufferObject *self, PyBufferObject *other) +get_bufx(PyObject *obj, void **ptr, Py_ssize_t *size) { - void *p1, *p2; - Py_ssize_t len_self, len_other, min_len; - int cmp; + PyBufferProcs *bp; - if (!get_buf(self, &p1, &len_self, ANY_BUFFER)) - return -1; - if (!get_buf(other, &p2, &len_other, ANY_BUFFER)) - return -1; - min_len = (len_self < len_other) ? len_self : len_other; - if (min_len > 0) { - cmp = memcmp(p1, p2, min_len); - if (cmp != 0) - return cmp < 0 ? -1 : 1; + if (PyBuffer_Check(obj)) { + if (!get_buf((PyBufferObject *)obj, ptr, size, ANY_BUFFER)) { + PyErr_Clear(); + return 0; + } + else + return 1; + } + bp = obj->ob_type->tp_as_buffer; + if (bp == NULL || + bp->bf_getreadbuffer == NULL || + bp->bf_getsegcount == NULL) + return 0; + if ((*bp->bf_getsegcount)(obj, NULL) != 1) + return 0; + *size = (*bp->bf_getreadbuffer)(obj, 0, ptr); + if (*size < 0) { + PyErr_Clear(); + return 0; + } + return 1; +} + +static PyObject * +buffer_richcompare(PyObject *self, PyObject *other, int op) +{ + void *p1, *p2; + Py_ssize_t len1, len2, min_len; + int cmp, ok; + + ok = 1; + if (!get_bufx(self, &p1, &len1)) + ok = 0; + if (!get_bufx(other, &p2, &len2)) + ok = 0; + if (!ok) { + /* If we can't get the buffers, + == and != are still defined + (and the objects are unequal) */ + PyObject *result; + if (op == Py_EQ) + result = Py_False; + else if (op == Py_NE) + result = Py_True; + else + result = Py_NotImplemented; + Py_INCREF(result); + return result; } - return (len_self < len_other) ? -1 : (len_self > len_other) ? 1 : 0; + min_len = (len1 < len2) ? len1 : len2; + cmp = memcmp(p1, p2, min_len); + if (cmp == 0) + cmp = (len1 < len2) ? -1 : + (len1 > len2) ? 1 : 0; + return Py_CmpToRich(op, cmp); } static PyObject * @@ -667,7 +709,7 @@ PyTypeObject PyBuffer_Type = { 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ - (cmpfunc)buffer_compare, /* tp_compare */ + 0, /* tp_compare */ (reprfunc)buffer_repr, /* tp_repr */ 0, /* tp_as_number */ &buffer_as_sequence, /* tp_as_sequence */ @@ -682,7 +724,7 @@ PyTypeObject PyBuffer_Type = { buffer_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ - 0, /* tp_richcompare */ + buffer_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ diff --git a/Objects/cellobject.c b/Objects/cellobject.c index 65a29aa..74fa247 100644 --- a/Objects/cellobject.c +++ b/Objects/cellobject.c @@ -49,18 +49,6 @@ cell_dealloc(PyCellObject *op) PyObject_GC_Del(op); } -static int -cell_compare(PyCellObject *a, PyCellObject *b) -{ - if (a->ob_ref == NULL) { - if (b->ob_ref == NULL) - return 0; - return -1; - } else if (b->ob_ref == NULL) - return 1; - return PyObject_Compare(a->ob_ref, b->ob_ref); -} - static PyObject * cell_repr(PyCellObject *op) { @@ -108,7 +96,7 @@ PyTypeObject PyCell_Type = { 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ - (cmpfunc)cell_compare, /* tp_compare */ + 0, /* tp_compare */ (reprfunc)cell_repr, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ diff --git a/Objects/classobject.c b/Objects/classobject.c index cc09960..1107977 100644 --- a/Objects/classobject.c +++ b/Objects/classobject.c @@ -80,7 +80,7 @@ PyMethod_New(PyObject *func, PyObject *self, PyObject *klass) #define OFF(x) offsetof(PyMethodObject, x) -static PyMemberDef instancemethod_memberlist[] = { +static PyMemberDef method_memberlist[] = { {"im_class", T_OBJECT, OFF(im_class), READONLY|RESTRICTED, "the class associated with a method"}, {"im_func", T_OBJECT, OFF(im_func), READONLY|RESTRICTED, @@ -96,7 +96,7 @@ static PyMemberDef instancemethod_memberlist[] = { should only be used for the class, not for instances */ static PyObject * -instancemethod_get_doc(PyMethodObject *im, void *context) +method_get_doc(PyMethodObject *im, void *context) { static PyObject *docstr; if (docstr == NULL) { @@ -107,13 +107,13 @@ instancemethod_get_doc(PyMethodObject *im, void *context) return PyObject_GetAttr(im->im_func, docstr); } -static PyGetSetDef instancemethod_getset[] = { - {"__doc__", (getter)instancemethod_get_doc, NULL, NULL}, +static PyGetSetDef method_getset[] = { + {"__doc__", (getter)method_get_doc, NULL, NULL}, {0} }; static PyObject * -instancemethod_getattro(PyObject *obj, PyObject *name) +method_getattro(PyObject *obj, PyObject *name) { PyMethodObject *im = (PyMethodObject *)obj; PyTypeObject *tp = obj->ob_type; @@ -140,19 +140,19 @@ instancemethod_getattro(PyObject *obj, PyObject *name) return PyObject_GetAttr(im->im_func, name); } -PyDoc_STRVAR(instancemethod_doc, -"instancemethod(function, instance, class)\n\ +PyDoc_STRVAR(method_doc, +"method(function, instance, class)\n\ \n\ Create an instance method object."); static PyObject * -instancemethod_new(PyTypeObject* type, PyObject* args, PyObject *kw) +method_new(PyTypeObject* type, PyObject* args, PyObject *kw) { PyObject *func; PyObject *self; PyObject *classObj = NULL; - if (!PyArg_UnpackTuple(args, "instancemethod", 2, 3, + if (!PyArg_UnpackTuple(args, "method", 2, 3, &func, &self, &classObj)) return NULL; if (!PyCallable_Check(func)) { @@ -172,7 +172,7 @@ instancemethod_new(PyTypeObject* type, PyObject* args, PyObject *kw) } static void -instancemethod_dealloc(register PyMethodObject *im) +method_dealloc(register PyMethodObject *im) { _PyObject_GC_UNTRACK(im); if (im->im_weakreflist != NULL) @@ -184,24 +184,42 @@ instancemethod_dealloc(register PyMethodObject *im) free_list = im; } -static int -instancemethod_compare(PyMethodObject *a, PyMethodObject *b) +static PyObject * +method_richcompare(PyObject *self, PyObject *other, int op) { - int cmp; - cmp = PyObject_Compare(a->im_func, b->im_func); - if (cmp) - return cmp; - - if (a->im_self == b->im_self) - return 0; - if (a->im_self == NULL || b->im_self == NULL) - return (a->im_self < b->im_self) ? -1 : 1; + PyMethodObject *a, *b; + PyObject *res; + int eq; + + if ((op != Py_EQ && op != Py_NE) || + !PyMethod_Check(self) || + !PyMethod_Check(other)) + { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + a = (PyMethodObject *)self; + b = (PyMethodObject *)other; + eq = PyObject_RichCompareBool(a->im_func, b->im_func, Py_EQ); + if (eq == 1) { + if (a->im_self == NULL || b->im_self == NULL) + eq = a->im_self == b->im_self; + else + eq = PyObject_RichCompareBool(a->im_self, b->im_self, + Py_EQ); + } + if (eq < 0) + return NULL; + if (op == Py_EQ) + res = eq ? Py_True : Py_False; else - return PyObject_Compare(a->im_self, b->im_self); + res = eq ? Py_False : Py_True; + Py_INCREF(res); + return res; } static PyObject * -instancemethod_repr(PyMethodObject *a) +method_repr(PyMethodObject *a) { PyObject *self = a->im_self; PyObject *func = a->im_func; @@ -261,7 +279,7 @@ instancemethod_repr(PyMethodObject *a) } static long -instancemethod_hash(PyMethodObject *a) +method_hash(PyMethodObject *a) { long x, y; if (a->im_self == NULL) @@ -280,7 +298,7 @@ instancemethod_hash(PyMethodObject *a) } static int -instancemethod_traverse(PyMethodObject *im, visitproc visit, void *arg) +method_traverse(PyMethodObject *im, visitproc visit, void *arg) { Py_VISIT(im->im_func); Py_VISIT(im->im_self); @@ -333,7 +351,7 @@ getinstclassname(PyObject *inst, char *buf, int bufsize) } static PyObject * -instancemethod_call(PyObject *func, PyObject *arg, PyObject *kw) +method_call(PyObject *func, PyObject *arg, PyObject *kw) { PyObject *self = PyMethod_GET_SELF(func); PyObject *klass = PyMethod_GET_CLASS(func); @@ -392,7 +410,7 @@ instancemethod_call(PyObject *func, PyObject *arg, PyObject *kw) } static PyObject * -instancemethod_descr_get(PyObject *meth, PyObject *obj, PyObject *cls) +method_descr_get(PyObject *meth, PyObject *obj, PyObject *cls) { /* Don't rebind an already bound method, or an unbound method of a class that's not a base class of cls. */ @@ -420,43 +438,43 @@ instancemethod_descr_get(PyObject *meth, PyObject *obj, PyObject *cls) PyTypeObject PyMethod_Type = { PyObject_HEAD_INIT(&PyType_Type) 0, - "instancemethod", + "method", sizeof(PyMethodObject), 0, - (destructor)instancemethod_dealloc, /* tp_dealloc */ + (destructor)method_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ - (cmpfunc)instancemethod_compare, /* tp_compare */ - (reprfunc)instancemethod_repr, /* tp_repr */ + 0, /* tp_compare */ + (reprfunc)method_repr, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ - (hashfunc)instancemethod_hash, /* tp_hash */ - instancemethod_call, /* tp_call */ + (hashfunc)method_hash, /* tp_hash */ + method_call, /* tp_call */ 0, /* tp_str */ - instancemethod_getattro, /* tp_getattro */ + method_getattro, /* tp_getattro */ PyObject_GenericSetAttr, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - instancemethod_doc, /* tp_doc */ - (traverseproc)instancemethod_traverse, /* tp_traverse */ + method_doc, /* tp_doc */ + (traverseproc)method_traverse, /* tp_traverse */ 0, /* tp_clear */ - 0, /* tp_richcompare */ + method_richcompare, /* tp_richcompare */ offsetof(PyMethodObject, im_weakreflist), /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ 0, /* tp_methods */ - instancemethod_memberlist, /* tp_members */ - instancemethod_getset, /* tp_getset */ + method_memberlist, /* tp_members */ + method_getset, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ - instancemethod_descr_get, /* tp_descr_get */ + method_descr_get, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ - instancemethod_new, /* tp_new */ + method_new, /* tp_new */ }; /* Clear out the free list */ diff --git a/Objects/codeobject.c b/Objects/codeobject.c index 89871d6..19dcc47 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -291,9 +291,15 @@ code_repr(PyCodeObject *co) return PyString_FromString(buf); } -static int -code_compare(PyCodeObject *co, PyCodeObject *cp) +static PyObject * +code_richcompare(PyObject *self, PyObject *other, int op) { + /* Temporarily make this unsupported */ + _Py_Break(); + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + +#if 0 int cmp; cmp = PyObject_Compare(co->co_name, cp->co_name); if (cmp) return cmp; @@ -325,6 +331,7 @@ code_compare(PyCodeObject *co, PyCodeObject *cp) return -1; else return 0; +#endif } static long @@ -363,12 +370,12 @@ PyTypeObject PyCode_Type = { 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ - (cmpfunc)code_compare, /* tp_compare */ + 0, /* tp_compare */ (reprfunc)code_repr, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ - (hashfunc)code_hash, /* tp_hash */ + 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ diff --git a/Objects/dictobject.c b/Objects/dictobject.c index b3fdbf1..320befb 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -582,6 +582,36 @@ PyDict_GetItem(PyObject *op, PyObject *key) return ep->me_value; } +/* Variant of PyDict_GetItem() that doesn't suppress exceptions. + This returns NULL *with* an exception set if an exception occurred. + It returns NULL *without* an exception set if the key wasn't present. +*/ +PyObject * +PyDict_GetItemWithError(PyObject *op, PyObject *key) +{ + long hash; + dictobject *mp = (dictobject *)op; + dictentry *ep; + + if (!PyDict_Check(op)) { + PyErr_BadInternalCall(); + return NULL; + } + if (!PyString_CheckExact(key) || + (hash = ((PyStringObject *) key)->ob_shash) == -1) + { + hash = PyObject_Hash(key); + if (hash == -1) { + return NULL; + } + } + + ep = (mp->ma_lookup)(mp, key, hash); + if (ep == NULL) + return NULL; + return ep->me_value; +} + /* CAUTION: PyDict_SetItem() must guarantee that it won't resize the * dictionary if it's merely replacing the value for an existing key. * This means that it's safe to loop over a dictionary with PyDict_Next() @@ -1432,136 +1462,6 @@ PyDict_Items(PyObject *mp) return dict_items((dictobject *)mp); } -/* Subroutine which returns the smallest key in a for which b's value - is different or absent. The value is returned too, through the - pval argument. Both are NULL if no key in a is found for which b's status - differs. The refcounts on (and only on) non-NULL *pval and function return - values must be decremented by the caller (characterize() increments them - to ensure that mutating comparison and PyDict_GetItem calls can't delete - them before the caller is done looking at them). */ - -static PyObject * -characterize(dictobject *a, dictobject *b, PyObject **pval) -{ - PyObject *akey = NULL; /* smallest key in a s.t. a[akey] != b[akey] */ - PyObject *aval = NULL; /* a[akey] */ - Py_ssize_t i; - int cmp; - - for (i = 0; i <= a->ma_mask; i++) { - PyObject *thiskey, *thisaval, *thisbval; - if (a->ma_table[i].me_value == NULL) - continue; - thiskey = a->ma_table[i].me_key; - Py_INCREF(thiskey); /* keep alive across compares */ - if (akey != NULL) { - cmp = PyObject_RichCompareBool(akey, thiskey, Py_LT); - if (cmp < 0) { - Py_DECREF(thiskey); - goto Fail; - } - if (cmp > 0 || - i > a->ma_mask || - a->ma_table[i].me_value == NULL) - { - /* Not the *smallest* a key; or maybe it is - * but the compare shrunk the dict so we can't - * find its associated value anymore; or - * maybe it is but the compare deleted the - * a[thiskey] entry. - */ - Py_DECREF(thiskey); - continue; - } - } - - /* Compare a[thiskey] to b[thiskey]; cmp <- true iff equal. */ - thisaval = a->ma_table[i].me_value; - assert(thisaval); - Py_INCREF(thisaval); /* keep alive */ - thisbval = PyDict_GetItem((PyObject *)b, thiskey); - if (thisbval == NULL) - cmp = 0; - else { - /* both dicts have thiskey: same values? */ - cmp = PyObject_RichCompareBool( - thisaval, thisbval, Py_EQ); - if (cmp < 0) { - Py_DECREF(thiskey); - Py_DECREF(thisaval); - goto Fail; - } - } - if (cmp == 0) { - /* New winner. */ - Py_XDECREF(akey); - Py_XDECREF(aval); - akey = thiskey; - aval = thisaval; - } - else { - Py_DECREF(thiskey); - Py_DECREF(thisaval); - } - } - *pval = aval; - return akey; - -Fail: - Py_XDECREF(akey); - Py_XDECREF(aval); - *pval = NULL; - return NULL; -} - -static int -dict_compare(dictobject *a, dictobject *b) -{ - PyObject *adiff, *bdiff, *aval, *bval; - int res; - - /* Compare lengths first */ - if (a->ma_used < b->ma_used) - return -1; /* a is shorter */ - else if (a->ma_used > b->ma_used) - return 1; /* b is shorter */ - - /* Same length -- check all keys */ - bdiff = bval = NULL; - adiff = characterize(a, b, &aval); - if (adiff == NULL) { - assert(!aval); - /* Either an error, or a is a subset with the same length so - * must be equal. - */ - res = PyErr_Occurred() ? -1 : 0; - goto Finished; - } - bdiff = characterize(b, a, &bval); - if (bdiff == NULL && PyErr_Occurred()) { - assert(!bval); - res = -1; - goto Finished; - } - res = 0; - if (bdiff) { - /* bdiff == NULL "should be" impossible now, but perhaps - * the last comparison done by the characterize() on a had - * the side effect of making the dicts equal! - */ - res = PyObject_Compare(adiff, bdiff); - } - if (res == 0 && bval != NULL) - res = PyObject_Compare(aval, bval); - -Finished: - Py_XDECREF(adiff); - Py_XDECREF(bdiff); - Py_XDECREF(aval); - Py_XDECREF(bval); - return res; -} - /* Return 1 if dicts equal, 0 if not, -1 if error. * Gets out as soon as any difference is detected. * Uses only Py_EQ comparison. @@ -1585,9 +1485,11 @@ dict_equal(dictobject *a, dictobject *b) /* temporarily bump aval's refcount to ensure it stays alive until we're done with it */ Py_INCREF(aval); - bval = PyDict_GetItem((PyObject *)b, key); + bval = PyDict_GetItemWithError((PyObject *)b, key); if (bval == NULL) { Py_DECREF(aval); + if (PyErr_Occurred()) + return -1; return 0; } cmp = PyObject_RichCompareBool(aval, bval, Py_EQ); @@ -2028,7 +1930,7 @@ PyTypeObject PyDict_Type = { (printfunc)dict_print, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ - (cmpfunc)dict_compare, /* tp_compare */ + 0, /* tp_compare */ (reprfunc)dict_repr, /* tp_repr */ 0, /* tp_as_number */ &dict_as_sequence, /* tp_as_sequence */ diff --git a/Objects/intobject.c b/Objects/intobject.c index 0ff2321..e64d0b1 100644 --- a/Objects/intobject.c +++ b/Objects/intobject.c @@ -446,6 +446,17 @@ int_compare(PyIntObject *v, PyIntObject *w) return (i < j) ? -1 : (i > j) ? 1 : 0; } +static PyObject * +int_richcompare(PyObject *self, PyObject *other, int op) +{ + if (!PyInt_Check(self) || !PyInt_Check(other)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + return Py_CmpToRich(op, int_compare((PyIntObject *)self, + (PyIntObject *)other)); +} + static long int_hash(PyIntObject *v) { @@ -1063,7 +1074,7 @@ PyTypeObject PyInt_Type = { (printfunc)int_print, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ - (cmpfunc)int_compare, /* tp_compare */ + 0, /* tp_compare */ (reprfunc)int_repr, /* tp_repr */ &int_as_number, /* tp_as_number */ 0, /* tp_as_sequence */ @@ -1078,7 +1089,7 @@ PyTypeObject PyInt_Type = { int_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ - 0, /* tp_richcompare */ + int_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ diff --git a/Objects/listobject.c b/Objects/listobject.c index ab408e9..3d81656 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -1971,6 +1971,26 @@ build_cmpwrapper(PyObject *cmpfunc) return (PyObject *)co; } +static int +is_default_cmp(PyObject *cmpfunc) +{ + PyCFunctionObject *f; + if (cmpfunc == NULL || cmpfunc == Py_None) + return 1; + if (!PyCFunction_Check(cmpfunc)) + return 0; + f = (PyCFunction *)cmpfunc; + if (f->m_self != NULL) + return 0; + if (!PyString_Check(f->m_module)) + return 0; + if (strcmp(PyString_AS_STRING(f->m_module), "__builtin__") != 0) + return 0; + if (strcmp(f->m_ml->ml_name, "cmp") != 0) + return 0; + return 1; +} + /* An adaptive, stable, natural mergesort. See listsort.txt. * Returns Py_None on success, NULL on error. Even in case of error, the * list will be some permutation of its input state (nothing is lost or @@ -2001,7 +2021,7 @@ listsort(PyListObject *self, PyObject *args, PyObject *kwds) kwlist, &compare, &keyfunc, &reverse)) return NULL; } - if (compare == Py_None) + if (is_default_cmp(compare)) compare = NULL; if (keyfunc == Py_None) keyfunc = NULL; diff --git a/Objects/longobject.c b/Objects/longobject.c index 16c7043..ab8a8d7 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -1,5 +1,3 @@ - - /* Long (arbitrary precision) integer object implementation */ /* XXX The functional organization of this file is terrible */ @@ -1882,6 +1880,14 @@ long_compare(PyLongObject *a, PyLongObject *b) return sign < 0 ? -1 : sign > 0 ? 1 : 0; } +static PyObject * +long_richcompare(PyObject *self, PyObject *other, int op) +{ + PyLongObject *a, *b; + CONVERT_BINOP((PyObject *)self, (PyObject *)other, &a, &b); + return Py_CmpToRich(op, long_compare(a, b)); +} + static long long_hash(PyLongObject *v) { @@ -3357,7 +3363,7 @@ PyTypeObject PyLong_Type = { 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ - (cmpfunc)long_compare, /* tp_compare */ + 0, /* tp_compare */ long_repr, /* tp_repr */ &long_as_number, /* tp_as_number */ 0, /* tp_as_sequence */ @@ -3372,7 +3378,7 @@ PyTypeObject PyLong_Type = { long_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ - 0, /* tp_richcompare */ + long_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ diff --git a/Objects/methodobject.c b/Objects/methodobject.c index ecc9a0a..862acd1 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -196,17 +196,31 @@ meth_repr(PyCFunctionObject *m) m->m_self); } -static int -meth_compare(PyCFunctionObject *a, PyCFunctionObject *b) +static PyObject * +meth_richcompare(PyObject *self, PyObject *other, int op) { - if (a->m_self != b->m_self) - return (a->m_self < b->m_self) ? -1 : 1; - if (a->m_ml->ml_meth == b->m_ml->ml_meth) - return 0; - if (strcmp(a->m_ml->ml_name, b->m_ml->ml_name) < 0) - return -1; + PyCFunctionObject *a, *b; + PyObject *res; + int eq; + + if ((op != Py_EQ && op != Py_NE) || + !PyCFunction_Check(self) || + !PyCFunction_Check(other)) + { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + a = (PyCFunctionObject *)self; + b = (PyCFunctionObject *)other; + eq = a->m_self == b->m_self; + if (eq) + eq = a->m_ml->ml_meth == b->m_ml->ml_meth; + if (op == Py_EQ) + res = eq ? Py_True : Py_False; else - return 1; + res = eq ? Py_False : Py_True; + Py_INCREF(res); + return res; } static long @@ -240,7 +254,7 @@ PyTypeObject PyCFunction_Type = { 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ - (cmpfunc)meth_compare, /* tp_compare */ + 0, /* tp_compare */ (reprfunc)meth_repr, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ @@ -255,7 +269,7 @@ PyTypeObject PyCFunction_Type = { 0, /* tp_doc */ (traverseproc)meth_traverse, /* tp_traverse */ 0, /* tp_clear */ - 0, /* tp_richcompare */ + meth_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ diff --git a/Objects/object.c b/Objects/object.c index 80111b4..9bcf08b 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -252,14 +252,6 @@ _PyObject_NewVar(PyTypeObject *tp, Py_ssize_t nitems) return PyObject_INIT_VAR(op, tp, nitems); } -/* for binary compatibility with 2.2 */ -#undef _PyObject_Del -void -_PyObject_Del(PyObject *op) -{ - PyObject_FREE(op); -} - /* Implementation of PyObject_Print with recursion checking */ static int internal_print(PyObject *op, FILE *fp, int flags, int nesting) @@ -513,431 +505,200 @@ PyObject_Unicode(PyObject *v) #endif -/* Helper to warn about deprecated tp_compare return values. Return: - -2 for an exception; - -1 if v < w; - 0 if v == w; - 1 if v > w. - (This function cannot return 2.) -*/ -static int -adjust_tp_compare(int c) -{ - if (PyErr_Occurred()) { - if (c != -1 && c != -2) { - PyObject *t, *v, *tb; - PyErr_Fetch(&t, &v, &tb); - if (PyErr_Warn(PyExc_RuntimeWarning, - "tp_compare didn't return -1 or -2 " - "for exception") < 0) { - Py_XDECREF(t); - Py_XDECREF(v); - Py_XDECREF(tb); - } - else - PyErr_Restore(t, v, tb); - } - return -2; - } - else if (c < -1 || c > 1) { - if (PyErr_Warn(PyExc_RuntimeWarning, - "tp_compare didn't return -1, 0 or 1") < 0) - return -2; - else - return c < -1 ? -1 : 1; - } - else { - assert(c >= -1 && c <= 1); - return c; - } -} +/* The new comparison philosophy is: we completely separate three-way + comparison from rich comparison. That is, PyObject_Compare() and + PyObject_Cmp() *just* use the tp_compare slot. And PyObject_RichCompare() + and PyObject_RichCompareBool() *just* use the tp_richcompare slot. + + See (*) below for practical amendments. + IOW, only cmp() uses tp_compare; the comparison operators (==, !=, <=, <, + >=, >) only use tp_richcompare. Note that list.sort() only uses <. -/* Macro to get the tp_richcompare field of a type if defined */ -#define RICHCOMPARE(t) ((t)->tp_richcompare) + (And yes, eventually we'll rip out cmp() and tp_compare.) -/* Map rich comparison operators to their swapped version, e.g. LT --> GT */ -int _Py_SwappedOp[] = {Py_GT, Py_GE, Py_EQ, Py_NE, Py_LT, Py_LE}; + The calling conventions are different: tp_compare only gets called with two + objects of the appropriate type; tp_richcompare gets called with a first + argument of the appropriate type and a second object of an arbitrary type. + We never do any kind of coercion. -/* Try a genuine rich comparison, returning an object. Return: - NULL for exception; - NotImplemented if this particular rich comparison is not implemented or - undefined; - some object not equal to NotImplemented if it is implemented - (this latter object may not be a Boolean). -*/ -static PyObject * -try_rich_compare(PyObject *v, PyObject *w, int op) -{ - richcmpfunc f; - PyObject *res; + The return conventions are also different. - if (v->ob_type != w->ob_type && - PyType_IsSubtype(w->ob_type, v->ob_type) && - (f = RICHCOMPARE(w->ob_type)) != NULL) { - res = (*f)(w, v, _Py_SwappedOp[op]); - if (res != Py_NotImplemented) - return res; - Py_DECREF(res); - } - if ((f = RICHCOMPARE(v->ob_type)) != NULL) { - res = (*f)(v, w, op); - if (res != Py_NotImplemented) - return res; - Py_DECREF(res); - } - if ((f = RICHCOMPARE(w->ob_type)) != NULL) { - return (*f)(w, v, _Py_SwappedOp[op]); - } - res = Py_NotImplemented; - Py_INCREF(res); - return res; -} + The tp_compare slot should return a C int, as follows: -/* Try a genuine rich comparison, returning an int. Return: - -1 for exception (including the case where try_rich_compare() returns an - object that's not a Boolean); - 0 if the outcome is false; - 1 if the outcome is true; - 2 if this particular rich comparison is not implemented or undefined. -*/ -static int -try_rich_compare_bool(PyObject *v, PyObject *w, int op) -{ - PyObject *res; - int ok; + -1 if a < b or if an exception occurred + 0 if a == b + +1 if a > b - if (RICHCOMPARE(v->ob_type) == NULL && RICHCOMPARE(w->ob_type) == NULL) - return 2; /* Shortcut, avoid INCREF+DECREF */ - res = try_rich_compare(v, w, op); - if (res == NULL) - return -1; - if (res == Py_NotImplemented) { - Py_DECREF(res); - return 2; - } - ok = PyObject_IsTrue(res); - Py_DECREF(res); - return ok; -} + No other return values are allowed. PyObject_Compare() has the same + calling convention. -/* Try rich comparisons to determine a 3-way comparison. Return: - -2 for an exception; - -1 if v < w; - 0 if v == w; - 1 if v > w; - 2 if this particular rich comparison is not implemented or undefined. -*/ -static int -try_rich_to_3way_compare(PyObject *v, PyObject *w) -{ - static struct { int op; int outcome; } tries[3] = { - /* Try this operator, and if it is true, use this outcome: */ - {Py_EQ, 0}, - {Py_LT, -1}, - {Py_GT, 1}, - }; - int i; - - if (RICHCOMPARE(v->ob_type) == NULL && RICHCOMPARE(w->ob_type) == NULL) - return 2; /* Shortcut */ - - for (i = 0; i < 3; i++) { - switch (try_rich_compare_bool(v, w, tries[i].op)) { - case -1: - return -2; - case 1: - return tries[i].outcome; - } - } + The tp_richcompare slot should return an object, as follows: - return 2; -} + NULL if an exception occurred + NotImplemented if the requested comparison is not implemented + any other false value if the requested comparison is false + any other true value if the requested comparison is true -/* Try a 3-way comparison, returning an int. Return: - -2 for an exception; - -1 if v < w; - 0 if v == w; - 1 if v > w; - 2 if this particular 3-way comparison is not implemented or undefined. -*/ -static int -try_3way_compare(PyObject *v, PyObject *w) -{ - int c; - cmpfunc f; + The PyObject_RichCompare[Bool]() wrappers raise TypeError when they get + NotImplemented. - /* Comparisons involving instances are given to instance_compare, - which has the same return conventions as this function. */ - - f = v->ob_type->tp_compare; - - /* If both have the same (non-NULL) tp_compare, use it. */ - if (f != NULL && f == w->ob_type->tp_compare) { - c = (*f)(v, w); - return adjust_tp_compare(c); - } - - /* If either tp_compare is _PyObject_SlotCompare, that's safe. */ - if (f == _PyObject_SlotCompare || - w->ob_type->tp_compare == _PyObject_SlotCompare) - return _PyObject_SlotCompare(v, w); - - /* If we're here, v and w, - a) are not instances; - b) have different types or a type without tp_compare; and - c) don't have a user-defined tp_compare. - tp_compare implementations in C assume that both arguments - have their type, so we give up if the coercion fails. - */ - c = PyNumber_CoerceEx(&v, &w); - if (c < 0) - return -2; - if (c > 0) - return 2; - f = v->ob_type->tp_compare; - if (f != NULL && f == w->ob_type->tp_compare) { - c = (*f)(v, w); - Py_DECREF(v); - Py_DECREF(w); - return adjust_tp_compare(c); - } + (*) Practical amendments: - /* No comparison defined */ - Py_DECREF(v); - Py_DECREF(w); - return 2; -} + - If rich comparison returns NotImplemented, == and != are decided by + comparing the object pointer (i.e. falling back to the base object + implementation). + + - If three-way comparison is not implemented, it falls back on rich + comparison (but not the other way around!). -/* Final fallback 3-way comparison, returning an int. Return: - -2 if an error occurred; - -1 if v < w; - 0 if v == w; - 1 if v > w. */ -static int -default_3way_compare(PyObject *v, PyObject *w) -{ - int c; - const char *vname, *wname; - if (v->ob_type == w->ob_type) { - /* When comparing these pointers, they must be cast to - * integer types (i.e. Py_uintptr_t, our spelling of C9X's - * uintptr_t). ANSI specifies that pointer compares other - * than == and != to non-related structures are undefined. - */ - Py_uintptr_t vv = (Py_uintptr_t)v; - Py_uintptr_t ww = (Py_uintptr_t)w; - return (vv < ww) ? -1 : (vv > ww) ? 1 : 0; - } +/* Forward */ +static PyObject *do_richcompare(PyObject *v, PyObject *w, int op); - /* None is smaller than anything */ - if (v == Py_None) - return -1; - if (w == Py_None) - return 1; - - /* different type: compare type names; numbers are smaller */ - if (PyNumber_Check(v)) - vname = ""; - else - vname = v->ob_type->tp_name; - if (PyNumber_Check(w)) - wname = ""; - else - wname = w->ob_type->tp_name; - c = strcmp(vname, wname); - if (c < 0) - return -1; - if (c > 0) - return 1; - /* Same type name, or (more likely) incomparable numeric types */ - return ((Py_uintptr_t)(v->ob_type) < ( - Py_uintptr_t)(w->ob_type)) ? -1 : 1; -} - -/* Do a 3-way comparison, by hook or by crook. Return: - -2 for an exception (but see below); - -1 if v < w; - 0 if v == w; - 1 if v > w; - BUT: if the object implements a tp_compare function, it returns - whatever this function returns (whether with an exception or not). -*/ +/* Perform a three-way comparison, raising TypeError if three-way comparison + is not supported. */ static int -do_cmp(PyObject *v, PyObject *w) +do_compare(PyObject *v, PyObject *w) { - int c; cmpfunc f; + int ok; - if (v->ob_type == w->ob_type - && (f = v->ob_type->tp_compare) != NULL) { - c = (*f)(v, w); - return adjust_tp_compare(c); - } - /* We only get here if one of the following is true: - a) v and w have different types - b) v and w have the same type, which doesn't have tp_compare - c) v and w are instances, and either __cmp__ is not defined or - __cmp__ returns NotImplemented - */ - c = try_rich_to_3way_compare(v, w); - if (c < 2) - return c; - c = try_3way_compare(v, w); - if (c < 2) - return c; - return default_3way_compare(v, w); -} - -/* Compare v to w. Return - -1 if v < w or exception (PyErr_Occurred() true in latter case). - 0 if v == w. - 1 if v > w. - XXX The docs (C API manual) say the return value is undefined in case - XXX of error. -*/ + if (v->ob_type == w->ob_type && + (f = v->ob_type->tp_compare) != NULL) { + return (*f)(v, w); + } + + /* Now try three-way compare before giving up. This is intentionally + elaborate; if you have a it will raise TypeError if it detects two + objects that aren't ordered with respect to each other. */ + ok = PyObject_RichCompareBool(v, w, Py_LT); + if (ok < 0) + return -1; /* Error */ + if (ok) + return -1; /* Less than */ + ok = PyObject_RichCompareBool(v, w, Py_GT); + if (ok < 0) + return -1; /* Error */ + if (ok) + return 1; /* Greater than */ + ok = PyObject_RichCompareBool(v, w, Py_EQ); + if (ok < 0) + return -1; /* Error */ + if (ok) + return 0; /* Equal */ + + /* Give up */ + PyErr_Format(PyExc_TypeError, + "unorderable types: '%.100s' <> '%.100s'", + v->ob_type->tp_name, + w->ob_type->tp_name); + return -1; +} + +/* Perform a three-way comparison. This wraps do_compare() with a check for + NULL arguments and a recursion check. */ int PyObject_Compare(PyObject *v, PyObject *w) { - int result; + int res; if (v == NULL || w == NULL) { - PyErr_BadInternalCall(); + if (!PyErr_Occurred()) + PyErr_BadInternalCall(); return -1; } - if (v == w) - return 0; if (Py_EnterRecursiveCall(" in cmp")) return -1; - result = do_cmp(v, w); + res = do_compare(v, w); Py_LeaveRecursiveCall(); - return result < 0 ? -1 : result; + return res < 0 ? -1 : res; } -/* Return (new reference to) Py_True or Py_False. */ -static PyObject * -convert_3way_to_object(int op, int c) -{ - PyObject *result; - switch (op) { - case Py_LT: c = c < 0; break; - case Py_LE: c = c <= 0; break; - case Py_EQ: c = c == 0; break; - case Py_NE: c = c != 0; break; - case Py_GT: c = c > 0; break; - case Py_GE: c = c >= 0; break; - } - result = c ? Py_True : Py_False; - Py_INCREF(result); - return result; -} - -/* We want a rich comparison but don't have one. Try a 3-way cmp instead. - Return - NULL if error - Py_True if v op w - Py_False if not (v op w) -*/ -static PyObject * -try_3way_to_rich_compare(PyObject *v, PyObject *w, int op) -{ - int c; +/* Map rich comparison operators to their swapped version, e.g. LT <--> GT */ +int _Py_SwappedOp[] = {Py_GT, Py_GE, Py_EQ, Py_NE, Py_LT, Py_LE}; - 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 char *opstrings[] = {">", ">=", "==", "!=", "<", "<="}; -/* Do rich comparison on v and w. Return - NULL if error - Else a new reference to an object other than Py_NotImplemented, usually(?): - Py_True if v op w - Py_False if not (v op w) -*/ +/* Perform a rich comparison, raising TypeError when the requested comparison + operator is not supported. */ static PyObject * -do_richcmp(PyObject *v, PyObject *w, int op) +do_richcompare(PyObject *v, PyObject *w, int op) { + richcmpfunc f; PyObject *res; - res = try_rich_compare(v, w, op); - if (res != Py_NotImplemented) - return res; - Py_DECREF(res); - - return try_3way_to_rich_compare(v, w, op); + if (v->ob_type != w->ob_type && + PyType_IsSubtype(w->ob_type, v->ob_type) && + (f = w->ob_type->tp_richcompare) != NULL) { + res = (*f)(w, v, _Py_SwappedOp[op]); + if (res != Py_NotImplemented) + return res; + Py_DECREF(res); + } + if ((f = v->ob_type->tp_richcompare) != NULL) { + res = (*f)(v, w, op); + if (res != Py_NotImplemented) + return res; + Py_DECREF(res); + } + if ((f = w->ob_type->tp_richcompare) != NULL) { + res = (*f)(w, v, _Py_SwappedOp[op]); + if (res != Py_NotImplemented) + return res; + Py_DECREF(res); + } + /* If neither object implements it, provide a sensible default + for == and !=, but raise an exception for ordering. */ + switch (op) { + case Py_EQ: + res = (v == w) ? Py_True : Py_False; + break; + case Py_NE: + res = (v != w) ? Py_True : Py_False; + break; + default: + PyErr_Format(PyExc_TypeError, + "unorderable types: %.100s() %s %.100s()", + v->ob_type->tp_name, + opstrings[op], + w->ob_type->tp_name); + return NULL; + } + Py_INCREF(res); + return res; } -/* Return: - NULL for exception; - some object not equal to NotImplemented if it is implemented - (this latter object may not be a Boolean). -*/ +/* Perform a rich comparison with object result. This wraps do_richcompare() + with a check for NULL arguments and a recursion check. */ + PyObject * PyObject_RichCompare(PyObject *v, PyObject *w, int op) { PyObject *res; assert(Py_LT <= op && op <= Py_GE); - if (Py_EnterRecursiveCall(" in cmp")) + if (v == NULL || w == NULL) { + if (!PyErr_Occurred()) + PyErr_BadInternalCall(); return NULL; - - /* If the types are equal, and not old-style instances, try to - get out cheap (don't bother with coercions etc.). */ - if (v->ob_type == w->ob_type) { - cmpfunc fcmp; - richcmpfunc frich = RICHCOMPARE(v->ob_type); - /* If the type has richcmp, try it first. try_rich_compare - tries it two-sided, which is not needed since we've a - single type only. */ - if (frich != NULL) { - res = (*frich)(v, w, op); - if (res != Py_NotImplemented) - goto Done; - Py_DECREF(res); - } - /* No richcmp, or this particular richmp not implemented. - Try 3-way cmp. */ - fcmp = v->ob_type->tp_compare; - if (fcmp != NULL) { - int c = (*fcmp)(v, w); - c = adjust_tp_compare(c); - if (c == -2) { - res = NULL; - goto Done; - } - res = convert_3way_to_object(op, c); - goto Done; - } } - - /* Fast path not taken, or couldn't deliver a useful result. */ - res = do_richcmp(v, w, op); -Done: + if (Py_EnterRecursiveCall(" in cmp")) + return NULL; + res = do_richcompare(v, w, op); Py_LeaveRecursiveCall(); return res; } -/* Return -1 if error; 1 if v op w; 0 if not (v op w). */ +/* Perform a rich comparison with integer result. This wraps + PyObject_RichCompare(), returning -1 for error, 0 for false, 1 for true. */ int PyObject_RichCompareBool(PyObject *v, PyObject *w, int op) { PyObject *res; int ok; - /* Quick result when objects are the same. - Guarantees that identity implies equality. */ - if (v == w) { - if (op == Py_EQ) - return 1; - else if (op == Py_NE) - return 0; - } - res = PyObject_RichCompare(v, w, op); if (res == NULL) return -1; @@ -949,6 +710,44 @@ PyObject_RichCompareBool(PyObject *v, PyObject *w, int op) return ok; } +/* Turn the result of a three-way comparison into the result expected by a + rich comparison. */ +PyObject * +Py_CmpToRich(int op, int cmp) +{ + PyObject *res; + int ok; + + if (PyErr_Occurred()) + return NULL; + switch (op) { + case Py_LT: + ok = cmp < 0; + break; + case Py_LE: + ok = cmp <= 0; + break; + case Py_EQ: + ok = cmp == 0; + break; + case Py_NE: + ok = cmp != 0; + break; + case Py_GT: + ok = cmp > 0; + break; + case Py_GE: + ok = cmp >= 0; + break; + default: + PyErr_BadArgument(); + return NULL; + } + res = ok ? Py_True : Py_False; + Py_INCREF(res); + return res; +} + /* Set of hash utility functions to help maintaining the invariant that if a==b then hash(a)==hash(b) @@ -1832,6 +1631,9 @@ _Py_ReadyTypes(void) if (PyType_Ready(&PyNotImplemented_Type) < 0) Py_FatalError("Can't initialize type(NotImplemented)"); + + if (PyType_Ready(&PyCode_Type) < 0) + Py_FatalError("Can't initialize 'code'"); } diff --git a/Objects/sliceobject.c b/Objects/sliceobject.c index d8a2465..0075a4e 100644 --- a/Objects/sliceobject.c +++ b/Objects/sliceobject.c @@ -280,25 +280,55 @@ static PyMethodDef slice_methods[] = { {NULL, NULL} }; -static int -slice_compare(PySliceObject *v, PySliceObject *w) +static PyObject * +slice_richcompare(PyObject *v, PyObject *w, int op) { - int result = 0; - - if (v == w) - return 0; - - if (PyObject_Cmp(v->start, w->start, &result) < 0) - return -2; - if (result != 0) - return result; - if (PyObject_Cmp(v->stop, w->stop, &result) < 0) - return -2; - if (result != 0) - return result; - if (PyObject_Cmp(v->step, w->step, &result) < 0) - return -2; - return result; + PyObject *t1; + PyObject *t2; + PyObject *res; + + if (v == w) { + /* XXX Do we really need this shortcut? + There's a unit test for it, but is that fair? */ + switch (op) { + case Py_EQ: + case Py_LE: + case Py_GE: + res = Py_True; + break; + default: + res = Py_False; + break; + } + Py_INCREF(res); + return res; + } + + t1 = PyTuple_New(3); + t2 = PyTuple_New(3); + if (t1 == NULL || t2 == NULL) + return NULL; + + PyTuple_SET_ITEM(t1, 0, ((PySliceObject *)v)->start); + PyTuple_SET_ITEM(t1, 1, ((PySliceObject *)v)->stop); + PyTuple_SET_ITEM(t1, 2, ((PySliceObject *)v)->step); + PyTuple_SET_ITEM(t2, 0, ((PySliceObject *)w)->start); + PyTuple_SET_ITEM(t2, 1, ((PySliceObject *)w)->stop); + PyTuple_SET_ITEM(t2, 2, ((PySliceObject *)w)->step); + + res = PyObject_RichCompare(t1, t2, op); + + PyTuple_SET_ITEM(t1, 0, NULL); + PyTuple_SET_ITEM(t1, 1, NULL); + PyTuple_SET_ITEM(t1, 2, NULL); + PyTuple_SET_ITEM(t2, 0, NULL); + PyTuple_SET_ITEM(t2, 1, NULL); + PyTuple_SET_ITEM(t2, 2, NULL); + + Py_DECREF(t1); + Py_DECREF(t2); + + return res; } static long @@ -318,7 +348,7 @@ PyTypeObject PySlice_Type = { 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ - (cmpfunc)slice_compare, /* tp_compare */ + 0, /* tp_compare */ (reprfunc)slice_repr, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ @@ -333,7 +363,7 @@ PyTypeObject PySlice_Type = { slice_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ - 0, /* tp_richcompare */ + slice_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ diff --git a/Objects/typeobject.c b/Objects/typeobject.c index d19801f..d16c6b4 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -361,16 +361,6 @@ static PyGetSetDef type_getsets[] = { {0} }; -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 *type) { @@ -2192,12 +2182,12 @@ PyTypeObject PyType_Type = { 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ - type_compare, /* tp_compare */ + 0, /* tp_compare */ (reprfunc)type_repr, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ - (hashfunc)_Py_HashPointer, /* tp_hash */ + 0, /* tp_hash */ (ternaryfunc)type_call, /* tp_call */ 0, /* tp_str */ (getattrofunc)type_getattro, /* tp_getattro */ @@ -2302,6 +2292,30 @@ object_str(PyObject *self) } static PyObject * +object_richcompare(PyObject *self, PyObject *other, int op) +{ + PyObject *res; + + switch (op) { + + case Py_EQ: + res = (self == other) ? Py_True : Py_False; + break; + + case Py_NE: + res = (self != other) ? Py_True : Py_False; + break; + + default: + res = Py_NotImplemented; + break; + } + + Py_INCREF(res); + return res; +} + +static PyObject * object_get_class(PyObject *self, void *closure) { Py_INCREF(self->ob_type); @@ -2703,7 +2717,7 @@ PyTypeObject PyBaseObject_Type = { PyDoc_STR("The most base type"), /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ - 0, /* tp_richcompare */ + object_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ diff --git a/Objects/weakrefobject.c b/Objects/weakrefobject.c index f814306..206a455 100644 --- a/Objects/weakrefobject.c +++ b/Objects/weakrefobject.c @@ -184,7 +184,9 @@ weakref_repr(PyWeakReference *self) static PyObject * weakref_richcompare(PyWeakReference* self, PyWeakReference* other, int op) { - if (op != Py_EQ || self->ob_type != other->ob_type) { + if ((op != Py_EQ && op != Py_NE) || + !PyWeakref_Check(self) || + !PyWeakref_Check(other)) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } @@ -458,12 +460,12 @@ proxy_setattr(PyWeakReference *proxy, PyObject *name, PyObject *value) return PyObject_SetAttr(PyWeakref_GET_OBJECT(proxy), name, value); } -static int -proxy_compare(PyObject *proxy, PyObject *v) +static PyObject * +proxy_richcompare(PyObject *proxy, PyObject *v, int op) { - UNWRAP_I(proxy); - UNWRAP_I(v); - return PyObject_Compare(proxy, v); + UNWRAP(proxy); + UNWRAP(v); + return PyObject_RichCompare(proxy, v, op); } /* number slots */ @@ -649,7 +651,7 @@ _PyWeakref_ProxyType = { 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ - proxy_compare, /* tp_compare */ + 0, /* tp_compare */ (reprfunc)proxy_repr, /* tp_repr */ &proxy_as_number, /* tp_as_number */ &proxy_as_sequence, /* tp_as_sequence */ @@ -664,7 +666,7 @@ _PyWeakref_ProxyType = { 0, /* tp_doc */ (traverseproc)gc_traverse, /* tp_traverse */ (inquiry)gc_clear, /* tp_clear */ - 0, /* tp_richcompare */ + proxy_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ (getiterfunc)proxy_iter, /* tp_iter */ (iternextfunc)proxy_iternext, /* tp_iternext */ @@ -683,7 +685,7 @@ _PyWeakref_CallableProxyType = { 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ - proxy_compare, /* tp_compare */ + 0, /* tp_compare */ (unaryfunc)proxy_repr, /* tp_repr */ &proxy_as_number, /* tp_as_number */ &proxy_as_sequence, /* tp_as_sequence */ @@ -698,7 +700,7 @@ _PyWeakref_CallableProxyType = { 0, /* tp_doc */ (traverseproc)gc_traverse, /* tp_traverse */ (inquiry)gc_clear, /* tp_clear */ - 0, /* tp_richcompare */ + proxy_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ (getiterfunc)proxy_iter, /* tp_iter */ (iternextfunc)proxy_iternext, /* tp_iternext */ |