diff options
author | Mark Dickinson <mdickinson@enthought.com> | 2011-10-23 18:53:01 (GMT) |
---|---|---|
committer | Mark Dickinson <mdickinson@enthought.com> | 2011-10-23 18:53:01 (GMT) |
commit | 36645681c8ad9a30d142f1dabb44d1d6c3ed5fab (patch) | |
tree | b98250ba008c4e858e44563e12f232d5ccfb8dd9 /Objects/rangeobject.c | |
parent | a2a2e480f335b8758a159ea72ab0067127d1d303 (diff) | |
download | cpython-36645681c8ad9a30d142f1dabb44d1d6c3ed5fab.zip cpython-36645681c8ad9a30d142f1dabb44d1d6c3ed5fab.tar.gz cpython-36645681c8ad9a30d142f1dabb44d1d6c3ed5fab.tar.bz2 |
Issue #13201: equality for range objects is now based on equality of the underlying sequences. Thanks Sven Marnach for the patch.
Diffstat (limited to 'Objects/rangeobject.c')
-rw-r--r-- | Objects/rangeobject.c | 135 |
1 files changed, 133 insertions, 2 deletions
diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c index 58d373c..c1e9e54 100644 --- a/Objects/rangeobject.c +++ b/Objects/rangeobject.c @@ -609,6 +609,137 @@ range_contains(rangeobject *r, PyObject *ob) PY_ITERSEARCH_CONTAINS); } +/* Compare two range objects. Return 1 for equal, 0 for not equal + and -1 on error. The algorithm is roughly the C equivalent of + + if r0 is r1: + return True + if len(r0) != len(r1): + return False + if not len(r0): + return True + if r0.start != r1.start: + return False + if len(r0) == 1: + return True + return r0.step == r1.step +*/ +static int +range_equals(rangeobject *r0, rangeobject *r1) +{ + int cmp_result; + PyObject *one; + + if (r0 == r1) + return 1; + cmp_result = PyObject_RichCompareBool(r0->length, r1->length, Py_EQ); + /* Return False or error to the caller. */ + if (cmp_result != 1) + return cmp_result; + cmp_result = PyObject_Not(r0->length); + /* Return True or error to the caller. */ + if (cmp_result != 0) + return cmp_result; + cmp_result = PyObject_RichCompareBool(r0->start, r1->start, Py_EQ); + /* Return False or error to the caller. */ + if (cmp_result != 1) + return cmp_result; + one = PyLong_FromLong(1); + if (!one) + return -1; + cmp_result = PyObject_RichCompareBool(r0->length, one, Py_EQ); + Py_DECREF(one); + /* Return True or error to the caller. */ + if (cmp_result != 0) + return cmp_result; + return PyObject_RichCompareBool(r0->step, r1->step, Py_EQ); +} + +static PyObject * +range_richcompare(PyObject *self, PyObject *other, int op) +{ + int result; + + if (!PyRange_Check(other)) + Py_RETURN_NOTIMPLEMENTED; + switch (op) { + case Py_NE: + case Py_EQ: + result = range_equals((rangeobject*)self, (rangeobject*)other); + if (result == -1) + return NULL; + if (op == Py_NE) + result = !result; + if (result) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; + case Py_LE: + case Py_GE: + case Py_LT: + case Py_GT: + Py_RETURN_NOTIMPLEMENTED; + default: + PyErr_BadArgument(); + return NULL; + } +} + +/* Hash function for range objects. Rough C equivalent of + + if not len(r): + return hash((len(r), None, None)) + if len(r) == 1: + return hash((len(r), r.start, None)) + return hash((len(r), r.start, r.step)) +*/ +static Py_hash_t +range_hash(rangeobject *r) +{ + PyObject *t; + Py_hash_t result = -1; + int cmp_result; + + t = PyTuple_New(3); + if (!t) + return -1; + Py_INCREF(r->length); + PyTuple_SET_ITEM(t, 0, r->length); + cmp_result = PyObject_Not(r->length); + if (cmp_result == -1) + goto end; + if (cmp_result == 1) { + Py_INCREF(Py_None); + Py_INCREF(Py_None); + PyTuple_SET_ITEM(t, 1, Py_None); + PyTuple_SET_ITEM(t, 2, Py_None); + } + else { + PyObject *one; + Py_INCREF(r->start); + PyTuple_SET_ITEM(t, 1, r->start); + one = PyLong_FromLong(1); + if (!one) + goto end; + cmp_result = PyObject_RichCompareBool(r->length, one, Py_EQ); + Py_DECREF(one); + if (cmp_result == -1) + goto end; + if (cmp_result == 1) { + Py_INCREF(Py_None); + PyTuple_SET_ITEM(t, 2, Py_None); + } + else { + Py_INCREF(r->step); + PyTuple_SET_ITEM(t, 2, r->step); + } + } + result = PyObject_Hash(t); + end: + Py_DECREF(t); + return result; +} + static PyObject * range_count(rangeobject *r, PyObject *ob) { @@ -763,7 +894,7 @@ PyTypeObject PyRange_Type = { 0, /* tp_as_number */ &range_as_sequence, /* tp_as_sequence */ &range_as_mapping, /* tp_as_mapping */ - 0, /* tp_hash */ + (hashfunc)range_hash, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ @@ -773,7 +904,7 @@ PyTypeObject PyRange_Type = { range_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ - 0, /* tp_richcompare */ + range_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ range_iter, /* tp_iter */ 0, /* tp_iternext */ |