summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
Diffstat (limited to 'Objects')
-rw-r--r--Objects/bufferobject.c74
-rw-r--r--Objects/cellobject.c14
-rw-r--r--Objects/classobject.c100
-rw-r--r--Objects/codeobject.c15
-rw-r--r--Objects/dictobject.c166
-rw-r--r--Objects/intobject.c15
-rw-r--r--Objects/listobject.c22
-rw-r--r--Objects/longobject.c14
-rw-r--r--Objects/methodobject.c36
-rw-r--r--Objects/object.c552
-rw-r--r--Objects/sliceobject.c70
-rw-r--r--Objects/typeobject.c40
-rw-r--r--Objects/weakrefobject.c22
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 */