diff -r f51d11405f1d Lib/test/test_xrange.py --- a/Lib/test/test_xrange.py Mon Sep 24 20:25:24 2012 +0100 +++ b/Lib/test/test_xrange.py Tue Sep 25 08:15:11 2012 +0100 @@ -98,12 +98,33 @@ def test_pickling(self): testcases = [(13,), (0, 11), (-22, 10), (20, 3, -1), (13, 21, 3), (-2, 2, 2)] + + large_testcases = [ + (0, sys.maxint, 1), + (sys.maxint, 0, -1), + #(0, sys.maxint, sys.maxint-1), + ] + for proto in range(pickle.HIGHEST_PROTOCOL + 1): for t in testcases: r = xrange(*t) self.assertEqual(list(pickle.loads(pickle.dumps(r, proto))), list(r)) + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + for t in testcases + large_testcases: + r = xrange(*t) + r_out = pickle.loads(pickle.dumps(r, proto)) + # We can't compare the 2 xranges directly, so check that + # their lengths, first element and last element match. + self.assertEqual(len(r), len(r_out)) + if len(r) >= 1: + self.assertEqual(r[0], r_out[0]) + self.assertEqual(r[-1], r_out[-1]) + # And for good measure, we check the step too. + if len(r) >= 2: + self.assertEqual(r[1] - r[0], r_out[1] - r_out[0]) + def test_range_iterators(self): # see issue 7298 limits = [base + jiggle diff -r f51d11405f1d Objects/rangeobject.c --- a/Objects/rangeobject.c Mon Sep 24 20:25:24 2012 +0100 +++ b/Objects/rangeobject.c Tue Sep 25 08:15:11 2012 +0100 @@ -105,6 +105,29 @@ return (Py_ssize_t)(r->len); } +/* Stop value suitable for use in repr and reduce. + * + * Computes start + len * step, clipped to the range [LONG_MIN, LONG_MAX]. + */ +static long +range_stop(rangeobject *r) +{ + long last; + + if (r->len == 0) + return r->start; + + /* The tricky bit is avoiding overflow. Here we first compute the last + entry in the xrange (start + (len - 1) * step), which is guaranteed to + lie within the range of a long, and then add step to it. */ + last = (long)(r->start + (unsigned long)(r->len - 1) * r->step); + if (r->step > 0) + return last > LONG_MAX - r->step ? LONG_MAX : last + r->step; + else + return last < LONG_MIN - r->step ? LONG_MIN : last + r->step; +} + + static PyObject * range_repr(rangeobject *r) { @@ -112,17 +135,17 @@ if (r->start == 0 && r->step == 1) rtn = PyString_FromFormat("xrange(%ld)", - r->start + r->len * r->step); + range_stop(r)); else if (r->step == 1) rtn = PyString_FromFormat("xrange(%ld, %ld)", r->start, - r->start + r->len * r->step); + range_stop(r)); else rtn = PyString_FromFormat("xrange(%ld, %ld, %ld)", r->start, - r->start + r->len * r->step, + range_stop(r), r->step); return rtn; } @@ -131,9 +154,9 @@ static PyObject * range_reduce(rangeobject *r, PyObject *args) { - return Py_BuildValue("(O(iii))", Py_TYPE(r), + return Py_BuildValue("(O(lll))", Py_TYPE(r), r->start, - r->start + r->len * r->step, + range_stop(r), r->step); }