From 211c6258294bf683935bff73a61ce3dd84070988 Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Sun, 1 Feb 2009 10:28:51 +0000 Subject: Issue #1717, stage 2: remove uses of tp_compare in Modules and most Objects. --- Lib/test/test_descr.py | 2 +- Lib/test/test_funcattrs.py | 33 ++++++++++- Lib/test/test_parser.py | 70 +++++++++++++++++++++++ Modules/_csv.c | 6 +- Modules/_elementtree.c | 9 +-- Modules/_localemodule.c | 4 +- Modules/_pickle.c | 2 +- Modules/_tkinter.c | 134 ++++++++++++++++++++++++++++++--------------- Modules/parsermodule.c | 72 +++++++++++++++++++----- Modules/pyexpat.c | 2 +- Objects/cellobject.c | 62 +++++++++++++++++---- Objects/descrobject.c | 76 ++++++++++++++++++++----- Objects/rangeobject.c | 11 ++-- Objects/setobject.c | 11 +--- PC/winreg.c | 4 +- 15 files changed, 385 insertions(+), 113 deletions(-) diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 9cedf44..8d43d7a 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -3885,7 +3885,7 @@ order (MRO) for bases """ # Testing method-wrapper objects... # did not support any reflection before 2.5 - return # XXX should methods really support __eq__? + # XXX should methods really support __eq__? l = [] self.assertEqual(l.__add__, l.__add__) diff --git a/Lib/test/test_funcattrs.py b/Lib/test/test_funcattrs.py index 5e9f7d3..7aab8b8 100644 --- a/Lib/test/test_funcattrs.py +++ b/Lib/test/test_funcattrs.py @@ -224,10 +224,41 @@ class FunctionDocstringTest(FuncAttrsTest): del self.b.__doc__ self.assertEqual(self.b.__doc__, None) +def cell(value): + """Create a cell containing the given value.""" + def f(): + print(a) + a = value + return f.__closure__[0] + +def empty_cell(empty=True): + """Create an empty cell.""" + def f(): + print(a) + # the intent of the following line is simply "if False:"; it's + # spelt this way to avoid the danger that a future optimization + # might simply remove an "if False:" code block. + if not empty: + a = 1729 + return f.__closure__[0] + +class CellTest(unittest.TestCase): + def test_comparison(self): + # These tests are here simply to exercise the comparison code; + # their presence should not be interpreted as providing any + # guarantees about the semantics (or even existence) of cell + # comparisons in future versions of CPython. + self.assert_(cell(2) < cell(3)) + self.assert_(empty_cell() < cell('saturday')) + self.assert_(empty_cell() == empty_cell()) + self.assert_(cell(-36) == cell(-36.0)) + self.assert_(cell(True) > empty_cell()) + + def test_main(): support.run_unittest(FunctionPropertiesTest, ImplicitReferencesTest, ArbitraryFunctionAttrTest, FunctionDictsTest, - FunctionDocstringTest) + FunctionDocstringTest, CellTest) if __name__ == "__main__": test_main() diff --git a/Lib/test/test_parser.py b/Lib/test/test_parser.py index 2f1310b..86ede3e 100644 --- a/Lib/test/test_parser.py +++ b/Lib/test/test_parser.py @@ -2,6 +2,7 @@ import parser import os import unittest import sys +import operator from test import support # @@ -496,12 +497,81 @@ class ParserStackLimitTestCase(unittest.TestCase): file=sys.stderr) self.assertRaises(MemoryError, parser.expr, e) +class STObjectTestCase(unittest.TestCase): + """Test operations on ST objects themselves""" + + def test_comparisons(self): + # ST objects should support order and equality comparisons + st1 = parser.expr('2 + 3') + st2 = parser.suite('x = 2; y = x + 3') + st3 = parser.expr('list(x**3 for x in range(20))') + st1_copy = parser.expr('2 + 3') + st2_copy = parser.suite('x = 2; y = x + 3') + st3_copy = parser.expr('list(x**3 for x in range(20))') + + # exercise fast path for object identity + self.assertEquals(st1 == st1, True) + self.assertEquals(st2 == st2, True) + self.assertEquals(st3 == st3, True) + # slow path equality + self.assertEqual(st1, st1_copy) + self.assertEqual(st2, st2_copy) + self.assertEqual(st3, st3_copy) + self.assertEquals(st1 == st2, False) + self.assertEquals(st1 == st3, False) + self.assertEquals(st2 == st3, False) + self.assertEquals(st1 != st1, False) + self.assertEquals(st2 != st2, False) + self.assertEquals(st3 != st3, False) + self.assertEquals(st1 != st1_copy, False) + self.assertEquals(st2 != st2_copy, False) + self.assertEquals(st3 != st3_copy, False) + self.assertEquals(st2 != st1, True) + self.assertEquals(st1 != st3, True) + self.assertEquals(st3 != st2, True) + # we don't particularly care what the ordering is; just that + # it's usable and self-consistent + self.assertEquals(st1 < st2, not (st2 <= st1)) + self.assertEquals(st1 < st3, not (st3 <= st1)) + self.assertEquals(st2 < st3, not (st3 <= st2)) + self.assertEquals(st1 < st2, st2 > st1) + self.assertEquals(st1 < st3, st3 > st1) + self.assertEquals(st2 < st3, st3 > st2) + self.assertEquals(st1 <= st2, st2 >= st1) + self.assertEquals(st3 <= st1, st1 >= st3) + self.assertEquals(st2 <= st3, st3 >= st2) + # transitivity + bottom = min(st1, st2, st3) + top = max(st1, st2, st3) + mid = sorted([st1, st2, st3])[1] + self.assert_(bottom < mid) + self.assert_(bottom < top) + self.assert_(mid < top) + self.assert_(bottom <= mid) + self.assert_(bottom <= top) + self.assert_(mid <= top) + self.assert_(bottom <= bottom) + self.assert_(mid <= mid) + self.assert_(top <= top) + # interaction with other types + self.assertEquals(st1 == 1588.602459, False) + self.assertEquals('spanish armada' != st2, True) + self.assertRaises(TypeError, operator.ge, st3, None) + self.assertRaises(TypeError, operator.le, False, st1) + self.assertRaises(TypeError, operator.lt, st1, 1815) + self.assertRaises(TypeError, operator.gt, b'waterloo', st2) + + + # XXX tests for pickling and unpickling of ST objects should go here + + def test_main(): support.run_unittest( RoundtripLegalSyntaxTestCase, IllegalSyntaxTestCase, CompileTestCase, ParserStackLimitTestCase, + STObjectTestCase, ) diff --git a/Modules/_csv.c b/Modules/_csv.c index 430ccdc..5175e71 100644 --- a/Modules/_csv.c +++ b/Modules/_csv.c @@ -443,7 +443,7 @@ static PyTypeObject Dialect_Type = { (printfunc)0, /* tp_print */ (getattrfunc)0, /* tp_getattr */ (setattrfunc)0, /* tp_setattr */ - (cmpfunc)0, /* tp_compare */ + 0, /* tp_compare */ (reprfunc)0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ @@ -864,7 +864,7 @@ static PyTypeObject Reader_Type = { (printfunc)0, /*tp_print*/ (getattrfunc)0, /*tp_getattr*/ (setattrfunc)0, /*tp_setattr*/ - (cmpfunc)0, /*tp_compare*/ + 0, /*tp_compare*/ (reprfunc)0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ @@ -1286,7 +1286,7 @@ static PyTypeObject Writer_Type = { (printfunc)0, /*tp_print*/ (getattrfunc)0, /*tp_getattr*/ (setattrfunc)0, /*tp_setattr*/ - (cmpfunc)0, /*tp_compare*/ + 0, /*tp_compare*/ (reprfunc)0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c index 767c6ee..46c19eb 100644 --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -761,7 +761,7 @@ element_find(ElementObject* self, PyObject* args) for (i = 0; i < self->extra->length; i++) { PyObject* item = self->extra->children[i]; if (Element_CheckExact(item) && - PyObject_Compare(((ElementObject*)item)->tag, tag) == 0) { + PyObject_RichCompareBool(((ElementObject*)item)->tag, tag, Py_EQ) == 1) { Py_INCREF(item); return item; } @@ -792,7 +792,8 @@ element_findtext(ElementObject* self, PyObject* args) for (i = 0; i < self->extra->length; i++) { ElementObject* item = (ElementObject*) self->extra->children[i]; - if (Element_CheckExact(item) && !PyObject_Compare(item->tag, tag)) { + if (Element_CheckExact(item) && (PyObject_RichCompareBool(item->tag, tag, Py_EQ) == 1)) { + PyObject* text = element_get_text(item); if (text == Py_None) return PyBytes_FromString(""); @@ -830,7 +831,7 @@ element_findall(ElementObject* self, PyObject* args) for (i = 0; i < self->extra->length; i++) { PyObject* item = self->extra->children[i]; if (Element_CheckExact(item) && - PyObject_Compare(((ElementObject*)item)->tag, tag) == 0) { + PyObject_RichCompareBool(((ElementObject*)item)->tag, tag, Py_EQ) == 1) { if (PyList_Append(out, item) < 0) { Py_DECREF(out); return NULL; @@ -1102,7 +1103,7 @@ element_remove(ElementObject* self, PyObject* args) for (i = 0; i < self->extra->length; i++) { if (self->extra->children[i] == element) break; - if (PyObject_Compare(self->extra->children[i], element) == 0) + if (PyObject_RichCompareBool(self->extra->children[i], element, Py_EQ) == 1) break; } diff --git a/Modules/_localemodule.c b/Modules/_localemodule.c index fb2837e..432df36 100644 --- a/Modules/_localemodule.c +++ b/Modules/_localemodule.c @@ -272,7 +272,9 @@ PyLocale_strcoll(PyObject* self, PyObject* args) #ifdef HAVE_WCSXFRM PyDoc_STRVAR(strxfrm__doc__, -"string -> string. Returns a string that behaves for cmp locale-aware."); +"strxfrm(string) -> string.\n\ +\n\ +Return a string that can be used as a key for locale-aware comparisons."); static PyObject* PyLocale_strxfrm(PyObject* self, PyObject* args) diff --git a/Modules/_pickle.c b/Modules/_pickle.c index 5813fd4..1036367 100644 --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -715,7 +715,7 @@ whichmodule(PyObject *global, PyObject *global_name) i = 0; module_name = NULL; while ((j = PyDict_Next(modules_dict, &i, &module_name, &module))) { - if (PyObject_Compare(module_name, main_str) == 0) + if (PyObject_RichCompareBool(module_name, main_str, Py_EQ) == 1) continue; obj = PyObject_GetAttr(module, global_name); diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index 6e595cc..01d1069 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -788,15 +788,59 @@ PyTclObject_repr(PyTclObject *self) self->value->typePtr->name, self->value); } -static int -PyTclObject_cmp(PyTclObject *self, PyTclObject *other) +#define TEST_COND(cond) ((cond) ? Py_True : Py_False) + +static PyObject * +PyTclObject_richcompare(PyObject *self, PyObject *other, int op) { - int res; - res = strcmp(Tcl_GetString(self->value), - Tcl_GetString(other->value)); - if (res < 0) return -1; - if (res > 0) return 1; - return 0; + int result; + PyObject *v; + + /* neither argument should be NULL, unless something's gone wrong */ + if (self == NULL || other == NULL) { + PyErr_BadInternalCall(); + return NULL; + } + + /* both arguments should be instances of PyTclObject */ + if (!PyTclObject_Check(self) || !PyTclObject_Check(other)) { + v = Py_NotImplemented; + goto finished; + } + + if (self == other) + /* fast path when self and other are identical */ + result = 0; + else + result = strcmp(Tcl_GetString(((PyTclObject *)self)->value), + Tcl_GetString(((PyTclObject *)other)->value)); + /* Convert return value to a Boolean */ + switch (op) { + case Py_EQ: + v = TEST_COND(result == 0); + break; + case Py_NE: + v = TEST_COND(result != 0); + break; + case Py_LE: + v = TEST_COND(result <= 0); + break; + case Py_GE: + v = TEST_COND(result >= 0); + break; + case Py_LT: + v = TEST_COND(result < 0); + break; + case Py_GT: + v = TEST_COND(result > 0); + break; + default: + PyErr_BadArgument(); + return NULL; + } + finished: + Py_INCREF(v); + return v; } PyDoc_STRVAR(get_typename__doc__, "name of the Tcl type"); @@ -818,45 +862,45 @@ static PyGetSetDef PyTclObject_getsetlist[] = { static PyTypeObject PyTclObject_Type = { PyVarObject_HEAD_INIT(NULL, 0) "_tkinter.Tcl_Obj", /*tp_name*/ - sizeof(PyTclObject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ + sizeof(PyTclObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ /* methods */ - (destructor)PyTclObject_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - (cmpfunc)PyTclObject_cmp, /*tp_compare*/ + (destructor)PyTclObject_dealloc,/*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ (reprfunc)PyTclObject_repr, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash*/ - 0, /*tp_call*/ - (reprfunc)PyTclObject_str, /*tp_str*/ - PyObject_GenericGetAttr,/*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - 0, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - 0, /*tp_methods*/ - 0, /*tp_members*/ - PyTclObject_getsetlist, /*tp_getset*/ - 0, /*tp_base*/ - 0, /*tp_dict*/ - 0, /*tp_descr_get*/ - 0, /*tp_descr_set*/ - 0, /*tp_dictoffset*/ - 0, /*tp_init*/ - 0, /*tp_alloc*/ - 0, /*tp_new*/ - 0, /*tp_free*/ - 0, /*tp_is_gc*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + (reprfunc)PyTclObject_str, /*tp_str*/ + PyObject_GenericGetAttr, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + PyTclObject_richcompare, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + 0, /*tp_methods*/ + 0, /*tp_members*/ + PyTclObject_getsetlist, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + 0, /*tp_init*/ + 0, /*tp_alloc*/ + 0, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ }; static Tcl_Obj* diff --git a/Modules/parsermodule.c b/Modules/parsermodule.c index 6778fb4..32de6bc 100644 --- a/Modules/parsermodule.c +++ b/Modules/parsermodule.c @@ -169,7 +169,7 @@ typedef struct { static void parser_free(PyST_Object *st); -static int parser_compare(PyST_Object *left, PyST_Object *right); +static PyObject* parser_richcompare(PyObject *left, PyObject *right, int op); static PyObject* parser_compilest(PyST_Object *, PyObject *, PyObject *); static PyObject* parser_isexpr(PyST_Object *, PyObject *, PyObject *); static PyObject* parser_issuite(PyST_Object *, PyObject *, PyObject *); @@ -203,7 +203,7 @@ PyTypeObject PyST_Type = { 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ - (cmpfunc)parser_compare, /* tp_compare */ + 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ @@ -223,7 +223,7 @@ PyTypeObject PyST_Type = { "Intermediate representation of a Python parse tree.", 0, /* tp_traverse */ 0, /* tp_clear */ - 0, /* tp_richcompare */ + parser_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ @@ -231,6 +231,9 @@ PyTypeObject PyST_Type = { }; /* PyST_Type */ +/* PyST_Type isn't subclassable, so just check ob_type */ +#define PyST_Object_Check(v) ((v)->ob_type == &PyST_Type) + static int parser_compare_nodes(node *left, node *right) { @@ -260,26 +263,69 @@ parser_compare_nodes(node *left, node *right) return (0); } - -/* int parser_compare(PyST_Object* left, PyST_Object* right) +/* parser_richcompare(PyObject* left, PyObject* right, int op) * * Comparison function used by the Python operators ==, !=, <, >, <=, >= * This really just wraps a call to parser_compare_nodes() with some easy * checks and protection code. * */ -static int -parser_compare(PyST_Object *left, PyST_Object *right) + +#define TEST_COND(cond) ((cond) ? Py_True : Py_False) + +static PyObject * +parser_richcompare(PyObject *left, PyObject *right, int op) { - if (left == right) - return (0); + int result; + PyObject *v; - if ((left == 0) || (right == 0)) - return (-1); + /* neither argument should be NULL, unless something's gone wrong */ + if (left == NULL || right == NULL) { + PyErr_BadInternalCall(); + return NULL; + } - return (parser_compare_nodes(left->st_node, right->st_node)); -} + /* both arguments should be instances of PyST_Object */ + if (!PyST_Object_Check(left) || !PyST_Object_Check(right)) { + v = Py_NotImplemented; + goto finished; + } + if (left == right) + /* if arguments are identical, they're equal */ + result = 0; + else + result = parser_compare_nodes(((PyST_Object *)left)->st_node, + ((PyST_Object *)right)->st_node); + + /* Convert return value to a Boolean */ + switch (op) { + case Py_EQ: + v = TEST_COND(result == 0); + break; + case Py_NE: + v = TEST_COND(result != 0); + break; + case Py_LE: + v = TEST_COND(result <= 0); + break; + case Py_GE: + v = TEST_COND(result >= 0); + break; + case Py_LT: + v = TEST_COND(result < 0); + break; + case Py_GT: + v = TEST_COND(result > 0); + break; + default: + PyErr_BadArgument(); + return NULL; + } + finished: + Py_INCREF(v); + return v; +} /* parser_newstobject(node* st) * diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c index df37589..ce72885 100644 --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -1622,7 +1622,7 @@ static PyTypeObject Xmlparsetype = { (printfunc)0, /*tp_print*/ 0, /*tp_getattr*/ (setattrfunc)xmlparse_setattr, /*tp_setattr*/ - (cmpfunc)0, /*tp_compare*/ + 0, /*tp_compare*/ (reprfunc)0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ diff --git a/Objects/cellobject.c b/Objects/cellobject.c index 50a3897..c2194b7 100644 --- a/Objects/cellobject.c +++ b/Objects/cellobject.c @@ -51,16 +51,56 @@ cell_dealloc(PyCellObject *op) PyObject_GC_Del(op); } -static int -cell_compare(PyCellObject *a, PyCellObject *b) +#define TEST_COND(cond) ((cond) ? Py_True : Py_False) + +static PyObject * +cell_richcompare(PyObject *a, PyObject *b, int op) { - 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); + int result; + PyObject *v; + + /* neither argument should be NULL, unless something's gone wrong */ + assert(a != NULL && b != NULL); + + /* both arguments should be instances of PyCellObject */ + if (!PyCell_Check(a) || !PyCell_Check(b)) { + v = Py_NotImplemented; + Py_INCREF(v); + return v; + } + + /* compare cells by contents; empty cells come before anything else */ + a = ((PyCellObject *)a)->ob_ref; + b = ((PyCellObject *)b)->ob_ref; + if (a != NULL && b != NULL) + return PyObject_RichCompare(a, b, op); + + result = (b == NULL) - (a == NULL); + switch (op) { + case Py_EQ: + v = TEST_COND(result == 0); + break; + case Py_NE: + v = TEST_COND(result != 0); + break; + case Py_LE: + v = TEST_COND(result <= 0); + break; + case Py_GE: + v = TEST_COND(result >= 0); + break; + case Py_LT: + v = TEST_COND(result < 0); + break; + case Py_GT: + v = TEST_COND(result > 0); + break; + default: + PyErr_BadArgument(); + return NULL; + } + Py_INCREF(v); + return v; } static PyObject * @@ -114,7 +154,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 */ @@ -129,7 +169,7 @@ PyTypeObject PyCell_Type = { 0, /* tp_doc */ (traverseproc)cell_traverse, /* tp_traverse */ (inquiry)cell_clear, /* tp_clear */ - 0, /* tp_richcompare */ + cell_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ diff --git a/Objects/descrobject.c b/Objects/descrobject.c index 9f4c2a6..a623925 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -774,12 +774,6 @@ proxy_traverse(PyObject *self, visitproc visit, void *arg) return 0; } -static int -proxy_compare(proxyobject *v, PyObject *w) -{ - return PyObject_Compare(v->dict, w); -} - static PyObject * proxy_richcompare(proxyobject *v, PyObject *w, int op) { @@ -796,7 +790,7 @@ PyTypeObject PyDictProxy_Type = { 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ - (cmpfunc)proxy_compare, /* tp_compare */ + 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ &proxy_as_sequence, /* tp_as_sequence */ @@ -844,12 +838,17 @@ PyDictProxy_New(PyObject *dict) /* This has no reason to be in this file except that adding new files is a bit of a pain */ +/* forward */ +static PyTypeObject wrappertype; + typedef struct { PyObject_HEAD PyWrapperDescrObject *descr; PyObject *self; } wrapperobject; +#define Wrapper_Check(v) (Py_TYPE(v) == &wrappertype) + static void wrapper_dealloc(wrapperobject *wp) { @@ -861,13 +860,60 @@ wrapper_dealloc(wrapperobject *wp) Py_TRASHCAN_SAFE_END(wp) } -static int -wrapper_compare(wrapperobject *a, wrapperobject *b) +#define TEST_COND(cond) ((cond) ? Py_True : Py_False) + +static PyObject * +wrapper_richcompare(PyObject *a, PyObject *b, int op) { - if (a->descr == b->descr) - return PyObject_Compare(a->self, b->self); - else - return (a->descr < b->descr) ? -1 : 1; + int result; + PyObject *v; + PyWrapperDescrObject *a_descr, *b_descr; + + assert(a != NULL && b != NULL); + + /* both arguments should be wrapperobjects */ + if (!Wrapper_Check(a) || !Wrapper_Check(b)) { + v = Py_NotImplemented; + Py_INCREF(v); + return v; + } + + /* compare by descriptor address; if the descriptors are the same, + compare by the objects they're bound to */ + a_descr = ((wrapperobject *)a)->descr; + b_descr = ((wrapperobject *)b)->descr; + if (a_descr == b_descr) { + a = ((wrapperobject *)a)->self; + b = ((wrapperobject *)b)->self; + return PyObject_RichCompare(a, b, op); + } + + result = a_descr - b_descr; + switch (op) { + case Py_EQ: + v = TEST_COND(result == 0); + break; + case Py_NE: + v = TEST_COND(result != 0); + break; + case Py_LE: + v = TEST_COND(result <= 0); + break; + case Py_GE: + v = TEST_COND(result >= 0); + break; + case Py_LT: + v = TEST_COND(result < 0); + break; + case Py_GT: + v = TEST_COND(result > 0); + break; + default: + PyErr_BadArgument(); + return NULL; + } + Py_INCREF(v); + return v; } static long @@ -977,7 +1023,7 @@ static PyTypeObject wrappertype = { 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ - (cmpfunc)wrapper_compare, /* tp_compare */ + 0, /* tp_compare */ (reprfunc)wrapper_repr, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ @@ -992,7 +1038,7 @@ static PyTypeObject wrappertype = { 0, /* tp_doc */ wrapper_traverse, /* tp_traverse */ 0, /* tp_clear */ - 0, /* tp_richcompare */ + wrapper_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c index f9a9cc9..68f06a4 100644 --- a/Objects/rangeobject.c +++ b/Objects/rangeobject.c @@ -123,7 +123,7 @@ range_length_obj(rangeobject *r) Algorithm is equal to that of get_len_of_range(), but it operates on PyObjects (which are assumed to be PyLong or PyInt objects). ---------------------------------------------------------------*/ - int cmp_result, cmp_call; + int cmp_result; PyObject *lo, *hi; PyObject *step = NULL; PyObject *diff = NULL; @@ -134,13 +134,12 @@ range_length_obj(rangeobject *r) PyObject *zero = PyLong_FromLong(0); if (zero == NULL) return NULL; - cmp_call = PyObject_Cmp(r->step, zero, &cmp_result); + cmp_result = PyObject_RichCompareBool(r->step, zero, Py_GT); Py_DECREF(zero); - if (cmp_call == -1) + if (cmp_result == -1) return NULL; - assert(cmp_result != 0); - if (cmp_result > 0) { + if (cmp_result == 1) { lo = r->start; hi = r->stop; step = r->step; @@ -154,7 +153,7 @@ range_length_obj(rangeobject *r) } /* if (lo >= hi), return length of 0. */ - if (PyObject_Compare(lo, hi) >= 0) { + if (PyObject_RichCompareBool(lo, hi, Py_GE) == 1) { Py_XDECREF(step); return PyLong_FromLong(0); } diff --git a/Objects/setobject.c b/Objects/setobject.c index d5d96ca..3dc396c 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -1824,13 +1824,6 @@ set_richcompare(PySetObject *v, PyObject *w, int op) return Py_NotImplemented; } -static int -set_nocmp(PyObject *self, PyObject *other) -{ - PyErr_SetString(PyExc_TypeError, "cannot compare sets using cmp()"); - return -1; -} - static PyObject * set_add(PySetObject *so, PyObject *key) { @@ -2111,7 +2104,7 @@ PyTypeObject PySet_Type = { 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ - set_nocmp, /* tp_compare */ + 0, /* tp_compare */ (reprfunc)set_repr, /* tp_repr */ &set_as_number, /* tp_as_number */ &set_as_sequence, /* tp_as_sequence */ @@ -2208,7 +2201,7 @@ PyTypeObject PyFrozenSet_Type = { 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ - set_nocmp, /* tp_compare */ + 0, /* tp_compare */ (reprfunc)set_repr, /* tp_repr */ &frozenset_as_number, /* tp_as_number */ &set_as_sequence, /* tp_as_sequence */ diff --git a/PC/winreg.c b/PC/winreg.c index 3abefa8..8a4a215 100644 --- a/PC/winreg.c +++ b/PC/winreg.c @@ -326,7 +326,7 @@ PyDoc_STRVAR(PyHKEY_doc, "Operations:\n" "__bool__ - Handles with an open object return true, otherwise false.\n" "__int__ - Converting a handle to an integer returns the Win32 handle.\n" -"__cmp__ - Handle objects are compared using the handle value."); +"rich comparison - Handle objects are compared using the handle value."); PyDoc_STRVAR(PyHKEY_Close_doc, @@ -485,7 +485,7 @@ PyTypeObject PyHKEY_Type = 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ - PyHKEY_compareFunc, /* tp_compare */ + 0, /* tp_compare */ 0, /* tp_repr */ &PyHKEY_NumberMethods, /* tp_as_number */ 0, /* tp_as_sequence */ -- cgit v0.12