Index: Objects/rangeobject.c =================================================================== --- Objects/rangeobject.c (revision 62635) +++ Objects/rangeobject.c (working copy) @@ -1,6 +1,7 @@ /* Range object implementation */ #include "Python.h" +#include "structmember.h" /* Support objects whose length is > PY_SSIZE_T_MAX. @@ -14,6 +15,7 @@ PyObject *start; PyObject *stop; PyObject *step; + PyObject *length; } rangeobject; /* Helper function for validating step. Always returns a new reference or @@ -43,6 +45,9 @@ return step; } +static PyObject* range_compute_length(PyObject *start, + PyObject *stop, PyObject *step); + /* XXX(nnorwitz): should we error check if the user passes any empty ranges? range(-10) range(0, -5) @@ -52,7 +57,7 @@ range_new(PyTypeObject *type, PyObject *args, PyObject *kw) { rangeobject *obj = NULL; - PyObject *start = NULL, *stop = NULL, *step = NULL; + PyObject *start = NULL, *stop = NULL, *step = NULL, *length = NULL; if (!_PyArg_NoKeywords("range()", kw)) return NULL; @@ -81,25 +86,31 @@ goto Fail; } + length = range_compute_length(start, stop, step); + if (length == NULL) + goto Fail; obj = PyObject_New(rangeobject, &PyRange_Type); if (obj == NULL) goto Fail; obj->start = start; obj->stop = stop; obj->step = step; + obj->length = length; return (PyObject *) obj; Fail: Py_XDECREF(start); Py_XDECREF(stop); Py_XDECREF(step); + Py_XDECREF(length); return NULL; } PyDoc_STRVAR(range_doc, "range([start,] stop[, step]) -> range object\n\ \n\ -Returns an iterator that generates the numbers in the range on demand."); +Return an arithmetic progression of numbers from start " + "to stop (exclusive) by step."); static void range_dealloc(rangeobject *r) @@ -107,17 +118,12 @@ Py_DECREF(r->start); Py_DECREF(r->stop); Py_DECREF(r->step); + Py_DECREF(r->length); PyObject_Del(r); } -/* Return number of items in range (lo, hi, step), when arguments are - * PyInt or PyLong objects. step > 0 required. Return a value < 0 if - * & only if the true value is too large to fit in a signed long. - * Arguments MUST return 1 with either PyLong_Check() or - * PyLong_Check(). Return -1 when there is an error. - */ -static PyObject* -range_length_obj(rangeobject *r) +static PyObject * +range_compute_length(PyObject *start, PyObject *stop, PyObject *step) { /* ------------------------------------------------------------- Algorithm is equal to that of get_len_of_range(), but it operates @@ -125,7 +131,6 @@ ---------------------------------------------------------------*/ int cmp_result, cmp_call; PyObject *lo, *hi; - PyObject *step = NULL; PyObject *diff = NULL; PyObject *one = NULL; PyObject *tmp1 = NULL, *tmp2 = NULL, *result; @@ -134,23 +139,22 @@ PyObject *zero = PyLong_FromLong(0); if (zero == NULL) return NULL; - cmp_call = PyObject_Cmp(r->step, zero, &cmp_result); + cmp_call = PyObject_Cmp(step, zero, &cmp_result); Py_DECREF(zero); if (cmp_call == -1) return NULL; assert(cmp_result != 0); if (cmp_result > 0) { - lo = r->start; - hi = r->stop; - step = r->step; + lo = start; + hi = stop; Py_INCREF(step); } else { - lo = r->stop; - hi = r->start; - step = PyNumber_Negative(r->step); + lo = stop; + hi = start; + step = PyNumber_Negative(step); if (!step) - return NULL; + goto Fail; } /* if (lo >= hi), return length of 0. */ @@ -193,46 +197,11 @@ static Py_ssize_t range_length(rangeobject *r) { - PyObject *len = range_length_obj(r); - Py_ssize_t result = -1; - if (len) { - result = PyLong_AsSsize_t(len); - Py_DECREF(len); - } - return result; + return PyLong_AsSsize_t(r->length); } -/* range(...)[x] is necessary for: seq[:] = range(...) */ static PyObject * -range_item(rangeobject *r, Py_ssize_t i) -{ - Py_ssize_t len = range_length(r); - PyObject *rem, *incr, *result; - - /* XXX(nnorwitz): should negative indices be supported? */ - /* XXX(nnorwitz): should support range[x] where x > PY_SSIZE_T_MAX? */ - if (i < 0 || i >= len) { - if (!PyErr_Occurred()) - PyErr_SetString(PyExc_IndexError, - "range object index out of range"); - return NULL; - } - - /* XXX(nnorwitz): optimize for short ints. */ - rem = PyLong_FromSsize_t(i); - if (!rem) - return NULL; - incr = PyNumber_Multiply(rem, r->step); - Py_DECREF(rem); - if (!incr) - return NULL; - result = PyNumber_Add(r->start, incr); - Py_DECREF(incr); - return result; -} - -static PyObject * range_repr(rangeobject *r) { Py_ssize_t istep; @@ -252,12 +221,11 @@ r->start, r->stop, r->step); } -static PySequenceMethods range_as_sequence = { - (lenfunc)range_length, /* sq_length */ - 0, /* sq_concat */ - 0, /* sq_repeat */ - (ssizeargfunc)range_item, /* sq_item */ - 0, /* sq_slice */ +static PyMemberDef range_members[] = { + {"start", T_OBJECT, offsetof(rangeobject, start), READONLY}, + {"stop", T_OBJECT, offsetof(rangeobject, stop), READONLY}, + {"step", T_OBJECT, offsetof(rangeobject, step), READONLY}, + {0} }; static PyObject * range_iter(PyObject *seq); @@ -266,6 +234,19 @@ PyDoc_STRVAR(reverse_doc, "Returns a reverse iterator."); +static PySequenceMethods range_as_sequence = { + (lenfunc)range_length, /* sq_length */ + 0, /* sq_concat */ + 0, /* sq_repeat */ + 0, /* sq_item */ + 0, /* sq_slice */ + 0, /* sq_ass_item */ + 0, /* sq_ass_slice */ + 0, /* sq_contains */ + 0, /* sq_inplace_concat */ + 0, /* sq_inplace_repeat */ +}; + static PyMethodDef range_methods[] = { {"__reversed__", (PyCFunction)range_reverse, METH_NOARGS, reverse_doc}, @@ -284,8 +265,8 @@ 0, /* tp_compare */ (reprfunc)range_repr, /* tp_repr */ 0, /* tp_as_number */ - &range_as_sequence, /* tp_as_sequence */ - 0, /* tp_as_mapping */ + &range_as_sequence, /* tp_as_sequence */ + 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ @@ -301,8 +282,8 @@ range_iter, /* tp_iter */ 0, /* tp_iternext */ range_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ + range_members, /* tp_members */ + 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ @@ -347,13 +328,13 @@ PyObject *index; PyObject *start; PyObject *step; - PyObject *len; + PyObject *length; } longrangeiterobject; static PyObject * longrangeiter_len(longrangeiterobject *r, PyObject *no_args) { - return PyNumber_Subtract(r->len, r->index); + return PyNumber_Subtract(r->length, r->index); } static PyObject *rangeiter_new(PyTypeObject *, PyObject *args, PyObject *kw); @@ -481,7 +462,7 @@ Py_XDECREF(r->index); Py_XDECREF(r->start); Py_XDECREF(r->step); - Py_XDECREF(r->len); + Py_XDECREF(r->length); PyObject_Del(r); } @@ -489,7 +470,7 @@ longrangeiter_next(longrangeiterobject *r) { PyObject *one, *product, *new_index, *result; - if (PyObject_RichCompareBool(r->index, r->len, Py_LT) != 1) + if (PyObject_RichCompareBool(r->index, r->length, Py_LT) != 1) return NULL; one = PyLong_FromLong(1); @@ -557,7 +538,6 @@ { rangeobject *r = (rangeobject *)seq; longrangeiterobject *it; - PyObject *tmp, *len; long lstart, lstop, lstep; assert(PyRange_Check(seq)); @@ -586,19 +566,10 @@ Py_INCREF(it->start); Py_INCREF(it->step); - it->len = it->index = NULL; - - /* Calculate length: (r->stop - r->start) / r->step */ - tmp = PyNumber_Subtract(r->stop, r->start); - if (!tmp) - goto create_failure; - len = PyNumber_FloorDivide(tmp, r->step); - Py_DECREF(tmp); - if (!len) - goto create_failure; - it->len = len; + Py_INCREF(r->length); + it->length = r->length; it->index = PyLong_FromLong(0); - if (!it->index) + if (it->index == NULL) goto create_failure; return (PyObject *)it; @@ -647,9 +618,8 @@ return NULL; /* start + (len - 1) * step */ - len = range_length_obj(range); - if (!len) - goto create_failure; + Py_INCREF(range->length); + len = range->length; one = PyLong_FromLong(1); if (!one) @@ -677,7 +647,7 @@ } /* Steal reference to len. */ - it->len = len; + it->length = len; it->index = PyLong_FromLong(0); if (!it->index) { Index: Lib/ctypes/test/test_slicing.py =================================================================== --- Lib/ctypes/test/test_slicing.py (revision 62635) +++ Lib/ctypes/test/test_slicing.py (working copy) @@ -20,7 +20,7 @@ self.failUnlessEqual(a[:12:6], b[:12:6]) self.failUnlessEqual(a[2:6:4], b[2:6:4]) - a[0:5] = range(5, 10) + a[0:5] = list(range(5, 10)) self.failUnlessEqual(a[0:5], list(range(5, 10))) self.failUnlessEqual(a[0:5:], list(range(5, 10))) self.failUnlessEqual(a[4::-1], list(range(9, 4, -1))) @@ -31,18 +31,18 @@ a[32:47] = list(range(32, 47)) self.failUnlessEqual(a[32:47], list(range(32, 47))) - a[32:47] = range(132, 147) + a[32:47] = list(range(132, 147)) self.failUnlessEqual(a[32:47:], list(range(132, 147))) - a[46:31:-1] = range(232, 247) + a[46:31:-1] = list(range(232, 247)) self.failUnlessEqual(a[32:47:1], list(range(246, 231, -1))) - a[32:47] = range(1132, 1147) + a[32:47] = list(range(1132, 1147)) self.failUnlessEqual(a[:], b) - a[32:47:7] = range(3) - b[32:47:7] = range(3) + a[32:47:7] = list(range(3)) + b[32:47:7] = list(range(3)) self.failUnlessEqual(a[:], b) - a[33::-3] = range(12) - b[33::-3] = range(12) + a[33::-3] = list(range(12)) + b[33::-3] = list(range(12)) self.failUnlessEqual(a[:], b) from operator import setitem Index: Lib/test/test_set.py =================================================================== --- Lib/test/test_set.py (revision 62635) +++ Lib/test/test_set.py (working copy) @@ -1569,7 +1569,7 @@ def test_constructor(self): for cons in (set, frozenset): - for s in ("123", "", range(1000), ('do', 1.2), range(2000,2200,5)): + for s in ("123", "", ('do', 1.2)): for g in (G, I, Ig, S, L, R): self.assertEqual(sorted(cons(g(s)), key=repr), sorted(g(s), key=repr)) self.assertRaises(TypeError, cons , X(s)) @@ -1578,7 +1578,7 @@ def test_inline_methods(self): s = set('november') - for data in ("123", "", range(1000), ('do', 1.2), range(2000,2200,5), 'december'): + for data in ("123", "", ('do', 1.2), 'december'): for meth in (s.union, s.intersection, s.difference, s.symmetric_difference, s.isdisjoint): for g in (G, I, Ig, L, R): expected = meth(data) @@ -1592,7 +1592,7 @@ self.assertRaises(ZeroDivisionError, meth, E(s)) def test_inplace_methods(self): - for data in ("123", "", range(1000), ('do', 1.2), range(2000,2200,5), 'december'): + for data in ("123", "", ('do', 1.2), 'december'): for methname in ('update', 'intersection_update', 'difference_update', 'symmetric_difference_update'): for g in (G, I, Ig, S, L, R): Index: Lib/test/test_heapq.py =================================================================== --- Lib/test/test_heapq.py (revision 62635) +++ Lib/test/test_heapq.py (working copy) @@ -337,7 +337,7 @@ def test_iterable_args(self): for f in (self.module.nlargest, self.module.nsmallest): - for s in ("123", "", range(1000), (1, 1.2), range(2000,2200,5)): + for s in ("123", "", (1, 1.2)): for g in (G, I, Ig, L, R): self.assertEqual(list(f(2, g(s))), list(f(2,s))) self.assertEqual(list(f(2, S(s))), []) Index: Lib/test/test_operator.py =================================================================== --- Lib/test/test_operator.py (revision 62635) +++ Lib/test/test_operator.py (working copy) @@ -148,7 +148,7 @@ self.failUnless(operator.truediv(5, 2) == 2.5) def test_getitem(self): - a = range(10) + a = list(range(10)) self.failUnlessRaises(TypeError, operator.getitem) self.failUnlessRaises(TypeError, operator.getitem, a, None) self.failUnless(operator.getitem(a, 2) == 2) @@ -183,7 +183,7 @@ self.failUnlessRaises(TypeError, operator.isSequenceType) self.failUnless(operator.isSequenceType(dir())) self.failUnless(operator.isSequenceType(())) - self.failUnless(operator.isSequenceType(range(10))) + self.failUnless(operator.isSequenceType(list(range(10)))) self.failUnless(operator.isSequenceType('yeahbuddy')) self.failIf(operator.isSequenceType(3)) class Dict(dict): pass Index: Lib/test/pickletester.py =================================================================== --- Lib/test/pickletester.py (revision 62635) +++ Lib/test/pickletester.py (working copy) @@ -585,7 +585,7 @@ p = self.dumps(None, proto) self.assertEqual(p, expected) - oob = protocols[-1] + 1 # a future protocol + oob = list(protocols)[-1] + 1 # a future protocol badpickle = pickle.PROTO + bytes([oob]) + build_none try: self.loads(badpickle) Index: Lib/test/test_deque.py =================================================================== --- Lib/test/test_deque.py (revision 62635) +++ Lib/test/test_deque.py (working copy) @@ -423,7 +423,7 @@ class TestVariousIteratorArgs(unittest.TestCase): def test_constructor(self): - for s in ("123", "", range(1000), ('do', 1.2), range(2000,2200,5)): + for s in ("123", "", ('do', 1.2)): for g in (seq_tests.Sequence, seq_tests.IterFunc, seq_tests.IterGen, seq_tests.IterFuncStop, seq_tests.itermulti, seq_tests.iterfunc): Index: Lib/test/seq_tests.py =================================================================== --- Lib/test/seq_tests.py (revision 62635) +++ Lib/test/seq_tests.py (working copy) @@ -120,7 +120,7 @@ self.assertEqual(len(vv), len(s)) # Create from various iteratables - for s in ("123", "", range(1000), ('do', 1.2), range(2000,2200,5)): + for s in ("123", "", ('do', 1.2)): for g in (Sequence, IterFunc, IterGen, itermulti, iterfunc): self.assertEqual(self.type2test(g(s)), self.type2test(s)) Index: Lib/test/test_mutants.py =================================================================== --- Lib/test/test_mutants.py (revision 62635) +++ Lib/test/test_mutants.py (working copy) @@ -128,8 +128,8 @@ # Fill the dicts without mutating them. mutate = 0 - dict1keys = fill_dict(dict1, range(n), n) - dict2keys = fill_dict(dict2, range(n), n) + dict1keys = fill_dict(dict1, list(range(n)), n) + dict2keys = fill_dict(dict2, list(range(n)), n) # Enable mutation, then compare the dicts so long as they have the # same size. Index: Lib/test/test_random.py =================================================================== --- Lib/test/test_random.py (revision 62635) +++ Lib/test/test_random.py (working copy) @@ -46,7 +46,7 @@ # For the entire allowable range of 0 <= k <= N, validate that # the sample is of the correct length and contains only unique items N = 100 - population = range(N) + population = list(range(N)) for k in range(N+1): s = self.gen.sample(population, k) self.assertEqual(len(s), k) @@ -59,7 +59,7 @@ # For the entire allowable range of 0 <= k <= N, validate that # sample generates all possible permutations n = 5 - pop = range(n) + pop = list(range(n)) trials = 10000 # large num prevents false negatives without slowing normal case def factorial(n): if n == 0: @@ -78,8 +78,8 @@ def test_sample_inputs(self): # SF bug #801342 -- population can be any iterable defining __len__() self.gen.sample(set(range(20)), 2) - self.gen.sample(range(20), 2) - self.gen.sample(range(20), 2) + self.gen.sample(list(range(20)), 2) + self.gen.sample(list(range(20)), 2) self.gen.sample(str('abcdefghijklmnopqrst'), 2) self.gen.sample(tuple('abcdefghijklmnopqrst'), 2) Index: Lib/test/test_enumerate.py =================================================================== --- Lib/test/test_enumerate.py (revision 62635) +++ Lib/test/test_enumerate.py (working copy) @@ -121,7 +121,7 @@ class TestBig(EnumerateTestCase): - seq = range(10,20000,2) + seq = list(range(10,20000,2)) res = list(zip(range(20000), seq)) class TestReversed(unittest.TestCase): Index: Lib/test/test_range.py =================================================================== --- Lib/test/test_range.py (revision 62635) +++ Lib/test/test_range.py (working copy) @@ -51,16 +51,35 @@ self.assertRaises(TypeError, range, 0, "spam") self.assertRaises(TypeError, range, 0, 42, "spam") + def test_repr(self): + self.assertEqual(repr(range(1)), 'range(0, 1)') + self.assertEqual(repr(range(1, 2)), 'range(1, 2)') + self.assertEqual(repr(range(1, 2, 3)), 'range(1, 2, 3)') + + def test_attributes(self): + r = range(0, 10, 2) + self.assertEqual(r.start, 0) + self.assertEqual(r.stop, 10) + self.assertEqual(r.step, 2) + r = range(10) + self.assertEqual(r.start, 0) + self.assertEqual(r.stop, 10) + self.assertEqual(r.step, 1) + r = range(10, 0, 4) + self.assertEqual(r.start, 10) + self.assertEqual(r.stop, 0) + self.assertEqual(r.step, 4) + + def test_len(self): + self.assertEqual(len(range(10)), 10) + self.assertEqual(len(range(10, 0)), 0) + self.assertEqual(len(range(0, 10, 2)), 5) + self.assertEqual(len(range(0, sys.maxsize, sys.maxsize-1)), 2) r = range(-sys.maxsize, sys.maxsize, 2) self.assertEqual(len(r), sys.maxsize) - def test_repr(self): - self.assertEqual(repr(range(1)), 'range(0, 1)') - self.assertEqual(repr(range(1, 2)), 'range(1, 2)') - self.assertEqual(repr(range(1, 2, 3)), 'range(1, 2, 3)') - def test_main(): test.test_support.run_unittest(RangeTest) Index: Lib/test/test_trace.py =================================================================== --- Lib/test/test_trace.py (revision 62635) +++ Lib/test/test_trace.py (working copy) @@ -161,7 +161,7 @@ # Tight loop with while(1) example (SF #765624) def tightloop_example(): - items = range(0, 3) + items = list(range(0, 3)) try: i = 0 while 1: @@ -184,7 +184,7 @@ (7, 'return')] def tighterloop_example(): - items = range(1, 4) + items = list(range(1, 4)) try: i = 0 while 1: i = items[i]