Index: Objects/rangeobject.c =================================================================== --- Objects/rangeobject.c (revision 62506) +++ Objects/rangeobject.c (working copy) @@ -252,6 +252,80 @@ r->start, r->stop, r->step); } +static long +range_hash(rangeobject *v) +{ + Py_ssize_t len, start, step; + + len = range_length(v); + if (len == -1) + return -1; + start = PyObject_Hash(v->start); + if (start == -1) + return -1; + step = PyObject_Hash(v->step); + if (step == -1) + return -1; + + return (long)(start*1000003L+len)*1630457L+step; +} + +static PyObject * +range_richcompare(rangeobject *v, rangeobject *w, int op) +{ + int is_equal, lengths_equal = 0; + PyObject *v_len, *w_len; + + if (!PyRange_Check(v) || !PyRange_Check(w) || + (op != Py_EQ && op != Py_NE)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + is_equal = PyObject_RichCompareBool(v->start, w->start, Py_EQ); + if (is_equal == -1) + return NULL; + if (!is_equal) + goto find_result; + + is_equal = PyObject_RichCompareBool(v->stop, w->stop, Py_EQ); + if (is_equal == -1) + return NULL; + if (!is_equal) { + /* account for ones like range(5, 10, 2) and range(5, 9, 2) */ + v_len = range_length_obj(v); + if (v_len == NULL) + return NULL; + w_len = range_length_obj(w); + if (w_len == NULL) { + Py_DECREF(v_len); + return NULL; + } + + lengths_equal = PyObject_RichCompareBool(v_len, w_len, Py_EQ); + if (lengths_equal == -1) + return NULL; + Py_DECREF(v_len); + Py_DECREF(w_len); + if (lengths_equal) + is_equal = 1; + else + goto find_result; + } + + is_equal = PyObject_RichCompareBool(v->step, w->step, Py_EQ); + if (is_equal == -1) + return NULL; + +find_result: + if ((is_equal && op == Py_EQ) || (!is_equal && op == Py_NE)) { + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } +} + static PySequenceMethods range_as_sequence = { (lenfunc)range_length, /* sq_length */ 0, /* sq_concat */ @@ -274,43 +348,43 @@ PyTypeObject PyRange_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - "range", /* Name of this type */ - sizeof(rangeobject), /* Basic object size */ - 0, /* Item size for varobject */ - (destructor)range_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - (reprfunc)range_repr, /* tp_repr */ - 0, /* tp_as_number */ - &range_as_sequence, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - range_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - range_iter, /* tp_iter */ - 0, /* tp_iternext */ - range_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* 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 */ - range_new, /* tp_new */ + "range", /* Name of this type */ + sizeof(rangeobject), /* Basic object size */ + 0, /* Item size for varobject */ + (destructor)range_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)range_repr, /* tp_repr */ + 0, /* tp_as_number */ + &range_as_sequence, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc)range_hash, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + range_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + (richcmpfunc)range_richcompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + range_iter, /* tp_iter */ + 0, /* tp_iternext */ + range_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* 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 */ + range_new, /* tp_new */ }; /*********************** range Iterator **************************/ Index: Lib/test/test_builtin.py =================================================================== --- Lib/test/test_builtin.py (revision 62506) +++ Lib/test/test_builtin.py (working copy) @@ -1595,6 +1595,22 @@ self.assertRaises(OverflowError, len, range(0, sys.maxsize**10)) + self.assertEquals(range(1234), range(1234)) + self.assertEquals(range(4, 3, 2), range(4, 3, 2)) + self.assertEquals(range(2222, 3333), range(2222, 3333)) + self.assertNotEquals(range(1, 15, 3), range(1, 20, 3)) + # The sequence of numbers can be the same + self.assertEquals(range(0, 9, 2), range(0, 10, 2)) + + self.assertEquals(hash(range(1234)), hash(range(1234))) + self.assertEquals(hash(range(1, 20, 3)), hash(range(1, 20, 3))) + self.assertNotEquals(hash(range(5, 10)), hash(range(6, 10))) + self.assertNotEquals(hash(range(0, 10, 2)), hash(range(0, 11, 2))) + self.assertNotEquals(hash(range(1)), hash(range(1, 2, 3))) + self.assertEquals(hash(range(0, 9, 2)), hash(range(0, 10, 2))) + # Can't hash huge ranges + self.assertRaises(OverflowError, hash, range(2**100)) + def test_input(self): self.write_testfile() fp = open(TESTFN, 'r')