Index: Objects/rangeobject.c =================================================================== --- Objects/rangeobject.c (revision 62273) +++ Objects/rangeobject.c (working copy) @@ -252,6 +252,78 @@ r->start, r->stop, r->step); } +static long +range_hash(rangeobject *v) +{ + /* reproduce tuple hash */ + register long x, y; + register Py_ssize_t len = Py_SIZE(v); + long mult = 1000003L; + x = 0x345678L; + y = PyObject_Hash(v->start); + if (y == -1) + return -1; + x = (x ^ y) * mult; + /* the cast might truncate len; that doesn't change hash stability */ + mult += (long)(82520L + len + len); + + y = PyObject_Hash(v->stop); + if (y == -1) + return -1; + x = (x ^ y) * mult; + /* the cast might truncate len; that doesn't change hash stability */ + mult += (long)(82520L + len + len); + + y = PyObject_Hash(v->step); + if (y == -1) + return -1; + x = (x ^ y) * mult; + /* the cast might truncate len; that doesn't change hash stability */ + mult += (long)(82520L + len + len); + + x += 97531L; + if (x == -1) + x = -2; + return x; + } + +static PyObject * +range_richcompare(rangeobject *v, rangeobject *w, int op) +{ + int start_same, stop_same, step_same, is_equal; + + if (!PyRange_Check(v) + || !PyRange_Check(w) + || (op != Py_EQ + && op != Py_NE)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + start_same = PyObject_RichCompareBool(v->start, w->start, Py_EQ); + if (start_same == -1) + return NULL; + stop_same = PyObject_RichCompareBool(v->stop, w->stop, Py_EQ); + if (stop_same == -1) + return NULL; + step_same = PyObject_RichCompareBool(v->step, w->step, Py_EQ); + if (step_same == -1) + return NULL; + + is_equal = ( + start_same + && stop_same + && step_same + ); + 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 */ @@ -286,7 +358,7 @@ 0, /* tp_as_number */ &range_as_sequence, /* tp_as_sequence */ 0, /* tp_as_mapping */ - 0, /* tp_hash */ + (hashfunc)range_hash, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ @@ -296,7 +368,7 @@ range_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ - 0, /* tp_richcompare */ + (richcmpfunc)range_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ range_iter, /* tp_iter */ 0, /* tp_iternext */ Index: Lib/test/test_builtin.py =================================================================== --- Lib/test/test_builtin.py (revision 62273) +++ Lib/test/test_builtin.py (working copy) @@ -1594,6 +1594,10 @@ #NEAL self.assertRaises(OverflowError, range, 0, 2*sys.maxsize) 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.assertNotEquals(range(1, 15, 3), range(1, 20, 3)) def test_input(self): self.write_testfile()