summaryrefslogtreecommitdiffstats
path: root/Objects/rangeobject.c
diff options
context:
space:
mode:
Diffstat (limited to 'Objects/rangeobject.c')
-rw-r--r--Objects/rangeobject.c626
1 files changed, 537 insertions, 89 deletions
diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c
index 33a4d9d..cff2ce4 100644
--- a/Objects/rangeobject.c
+++ b/Objects/rangeobject.c
@@ -14,6 +14,7 @@ typedef struct {
PyObject *start;
PyObject *stop;
PyObject *step;
+ PyObject *length;
} rangeobject;
/* Helper function for validating step. Always returns a new reference or
@@ -43,6 +44,31 @@ validate_step(PyObject *step)
return step;
}
+static PyObject *
+compute_range_length(PyObject *start, PyObject *stop, PyObject *step);
+
+static rangeobject *
+make_range_object(PyTypeObject *type, PyObject *start,
+ PyObject *stop, PyObject *step)
+{
+ rangeobject *obj = NULL;
+ PyObject *length;
+ length = compute_range_length(start, stop, step);
+ if (length == NULL) {
+ return NULL;
+ }
+ obj = PyObject_New(rangeobject, type);
+ if (obj == NULL) {
+ Py_DECREF(length);
+ return NULL;
+ }
+ obj->start = start;
+ obj->stop = stop;
+ obj->step = step;
+ obj->length = length;
+ return obj;
+}
+
/* XXX(nnorwitz): should we error check if the user passes any empty ranges?
range(-10)
range(0, -5)
@@ -51,7 +77,7 @@ validate_step(PyObject *step)
static PyObject *
range_new(PyTypeObject *type, PyObject *args, PyObject *kw)
{
- rangeobject *obj = NULL;
+ rangeobject *obj;
PyObject *start = NULL, *stop = NULL, *step = NULL;
if (!_PyArg_NoKeywords("range()", kw))
@@ -97,15 +123,11 @@ range_new(PyTypeObject *type, PyObject *args, PyObject *kw)
}
}
- obj = PyObject_New(rangeobject, &PyRange_Type);
- if (obj == NULL)
- goto Fail;
- obj->start = start;
- obj->stop = stop;
- obj->step = step;
- return (PyObject *) obj;
+ obj = make_range_object(type, start, stop, step);
+ if (obj != NULL)
+ return (PyObject *) obj;
-Fail:
+ /* Failed to create object, release attributes */
Py_XDECREF(start);
Py_XDECREF(stop);
Py_XDECREF(step);
@@ -115,7 +137,7 @@ Fail:
PyDoc_STRVAR(range_doc,
"range([start,] stop[, step]) -> range object\n\
\n\
-Returns an iterator that generates the numbers in the range on demand.");
+Returns a virtual sequence of numbers from start to stop by step.");
static void
range_dealloc(rangeobject *r)
@@ -123,6 +145,7 @@ range_dealloc(rangeobject *r)
Py_DECREF(r->start);
Py_DECREF(r->stop);
Py_DECREF(r->step);
+ Py_DECREF(r->length);
PyObject_Del(r);
}
@@ -131,7 +154,7 @@ range_dealloc(rangeobject *r)
* PyLong_Check(). Return NULL when there is an error.
*/
static PyObject*
-range_length_obj(rangeobject *r)
+compute_range_length(PyObject *start, PyObject *stop, PyObject *step)
{
/* -------------------------------------------------------------
Algorithm is equal to that of get_len_of_range(), but it operates
@@ -139,7 +162,6 @@ range_length_obj(rangeobject *r)
---------------------------------------------------------------*/
int cmp_result;
PyObject *lo, *hi;
- PyObject *step = NULL;
PyObject *diff = NULL;
PyObject *one = NULL;
PyObject *tmp1 = NULL, *tmp2 = NULL, *result;
@@ -148,20 +170,19 @@ range_length_obj(rangeobject *r)
PyObject *zero = PyLong_FromLong(0);
if (zero == NULL)
return NULL;
- cmp_result = PyObject_RichCompareBool(r->step, zero, Py_GT);
+ cmp_result = PyObject_RichCompareBool(step, zero, Py_GT);
Py_DECREF(zero);
if (cmp_result == -1)
return NULL;
if (cmp_result == 1) {
- 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;
}
@@ -206,45 +227,451 @@ range_length_obj(rangeobject *r)
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 *
+compute_item(rangeobject *r, PyObject *i)
+{
+ PyObject *incr, *result;
+ /* PyLong equivalent to:
+ * return r->start + (i * r->step)
+ */
+ incr = PyNumber_Multiply(i, r->step);
+ if (!incr)
+ return NULL;
+ result = PyNumber_Add(r->start, incr);
+ Py_DECREF(incr);
+ return result;
+}
static PyObject *
-range_item(rangeobject *r, Py_ssize_t i)
+compute_range_item(rangeobject *r, PyObject *arg)
{
- 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");
+ int cmp_result;
+ PyObject *i, *result;
+
+ PyObject *zero = PyLong_FromLong(0);
+ if (zero == NULL)
return NULL;
+
+ /* PyLong equivalent to:
+ * if (arg < 0) {
+ * i = r->length + arg
+ * } else {
+ * i = arg
+ * }
+ */
+ cmp_result = PyObject_RichCompareBool(arg, zero, Py_LT);
+ if (cmp_result == -1) {
+ Py_DECREF(zero);
+ return NULL;
+ }
+ if (cmp_result == 1) {
+ i = PyNumber_Add(r->length, arg);
+ if (!i) {
+ Py_DECREF(zero);
+ return NULL;
+ }
+ } else {
+ i = arg;
+ Py_INCREF(i);
}
- /* XXX(nnorwitz): optimize for short ints. */
- rem = PyLong_FromSsize_t(i);
- if (!rem)
+ /* PyLong equivalent to:
+ * if (i < 0 || i >= r->length) {
+ * <report index out of bounds>
+ * }
+ */
+ cmp_result = PyObject_RichCompareBool(i, zero, Py_LT);
+ Py_DECREF(zero);
+ if (cmp_result == 0) {
+ cmp_result = PyObject_RichCompareBool(i, r->length, Py_GE);
+ }
+ if (cmp_result == -1) {
+ Py_DECREF(i);
+ return NULL;
+ }
+ if (cmp_result == 1) {
+ Py_DECREF(i);
+ PyErr_SetString(PyExc_IndexError,
+ "range object index out of range");
return NULL;
- incr = PyNumber_Multiply(rem, r->step);
- Py_DECREF(rem);
- if (!incr)
+ }
+
+ result = compute_item(r, i);
+ Py_DECREF(i);
+ return result;
+}
+
+static PyObject *
+range_item(rangeobject *r, Py_ssize_t i)
+{
+ PyObject *res, *arg = PyLong_FromLong(i);
+ if (!arg) {
return NULL;
- result = PyNumber_Add(r->start, incr);
- Py_DECREF(incr);
+ }
+ res = compute_range_item(r, arg);
+ Py_DECREF(arg);
+ return res;
+}
+
+/* Additional helpers, since the standard slice helpers
+ * all clip to PY_SSIZE_T_MAX
+ */
+
+/* Replace _PyEval_SliceIndex */
+static PyObject *
+compute_slice_element(PyObject *obj)
+{
+ PyObject *result = NULL;
+ if (obj != NULL) {
+ if (PyIndex_Check(obj)) {
+ result = PyNumber_Index(obj);
+ }
+ }
+ if (result == NULL) {
+ PyErr_SetString(PyExc_TypeError,
+ "slice indices must be integers or "
+ "None or have an __index__ method");
+ }
return result;
}
+/* Replace PySlice_GetIndicesEx
+ * Result indicates whether or not the slice is empty
+ * (-1 = error, 0 = empty slice, 1 = slice contains elements)
+ */
+static int
+compute_slice_indices(rangeobject *r, PySliceObject *slice,
+ PyObject **start, PyObject **stop, PyObject **step)
+{
+ int cmp_result, has_elements;
+ Py_ssize_t clamped_step = 0;
+ PyObject *zero = NULL, *one = NULL, *neg_one = NULL, *candidate = NULL;
+ PyObject *tmp_start = NULL, *tmp_stop = NULL, *tmp_step = NULL;
+ zero = PyLong_FromLong(0);
+ if (zero == NULL) goto Fail;
+ one = PyLong_FromLong(1);
+ if (one == NULL) goto Fail;
+ neg_one = PyLong_FromLong(-1);
+ if (neg_one == NULL) goto Fail;
+
+ /* Calculate step value */
+ if (slice->step == Py_None) {
+ clamped_step = 1;
+ tmp_step = one;
+ Py_INCREF(tmp_step);
+ } else {
+ if (!_PyEval_SliceIndex(slice->step, &clamped_step)) goto Fail;
+ if (clamped_step == 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "slice step cannot be zero");
+ goto Fail;
+ }
+ tmp_step = compute_slice_element(slice->step);
+ if (tmp_step == NULL) goto Fail;
+ }
+
+ /* Calculate start value */
+ if (slice->start == Py_None) {
+ if (clamped_step < 0) {
+ tmp_start = PyNumber_Subtract(r->length, one);
+ if (tmp_start == NULL) goto Fail;
+ } else {
+ tmp_start = zero;
+ Py_INCREF(tmp_start);
+ }
+ } else {
+ candidate = compute_slice_element(slice->start);
+ if (candidate == NULL) goto Fail;
+ cmp_result = PyObject_RichCompareBool(candidate, zero, Py_LT);
+ if (cmp_result == -1) goto Fail;
+ if (cmp_result) {
+ /* candidate < 0 */
+ tmp_start = PyNumber_Add(r->length, candidate);
+ if (tmp_start == NULL) goto Fail;
+ Py_CLEAR(candidate);
+ } else {
+ /* candidate >= 0 */
+ tmp_start = candidate;
+ candidate = NULL;
+ }
+ cmp_result = PyObject_RichCompareBool(tmp_start, zero, Py_LT);
+ if (cmp_result == -1) goto Fail;
+ if (cmp_result) {
+ /* tmp_start < 0 */
+ Py_CLEAR(tmp_start);
+ if (clamped_step < 0) {
+ tmp_start = neg_one;
+ } else {
+ tmp_start = zero;
+ }
+ Py_INCREF(tmp_start);
+ } else {
+ /* tmp_start >= 0 */
+ cmp_result = PyObject_RichCompareBool(tmp_start, r->length, Py_GE);
+ if (cmp_result == -1) goto Fail;
+ if (cmp_result) {
+ /* tmp_start >= r->length */
+ Py_CLEAR(tmp_start);
+ if (clamped_step < 0) {
+ tmp_start = PyNumber_Subtract(r->length, one);
+ if (tmp_start == NULL) goto Fail;
+ } else {
+ tmp_start = r->length;
+ Py_INCREF(tmp_start);
+ }
+ }
+ }
+ }
+
+ /* Calculate stop value */
+ if (slice->stop == Py_None) {
+ if (clamped_step < 0) {
+ tmp_stop = neg_one;
+ } else {
+ tmp_stop = r->length;
+ }
+ Py_INCREF(tmp_stop);
+ } else {
+ candidate = compute_slice_element(slice->stop);
+ if (candidate == NULL) goto Fail;
+ cmp_result = PyObject_RichCompareBool(candidate, zero, Py_LT);
+ if (cmp_result == -1) goto Fail;
+ if (cmp_result) {
+ /* candidate < 0 */
+ tmp_stop = PyNumber_Add(r->length, candidate);
+ if (tmp_stop == NULL) goto Fail;
+ Py_CLEAR(candidate);
+ } else {
+ /* candidate >= 0 */
+ tmp_stop = candidate;
+ candidate = NULL;
+ }
+ cmp_result = PyObject_RichCompareBool(tmp_stop, zero, Py_LT);
+ if (cmp_result == -1) goto Fail;
+ if (cmp_result) {
+ /* tmp_stop < 0 */
+ Py_CLEAR(tmp_stop);
+ if (clamped_step < 0) {
+ tmp_stop = neg_one;
+ } else {
+ tmp_stop = zero;
+ }
+ Py_INCREF(tmp_stop);
+ } else {
+ /* tmp_stop >= 0 */
+ cmp_result = PyObject_RichCompareBool(tmp_stop, r->length, Py_GE);
+ if (cmp_result == -1) goto Fail;
+ if (cmp_result) {
+ /* tmp_stop >= r->length */
+ Py_CLEAR(tmp_stop);
+ if (clamped_step < 0) {
+ tmp_stop = PyNumber_Subtract(r->length, one);
+ if (tmp_stop == NULL) goto Fail;
+ } else {
+ tmp_stop = r->length;
+ Py_INCREF(tmp_start);
+ }
+ }
+ }
+ }
+
+ /* Check if the slice is empty or not */
+ if (clamped_step < 0) {
+ has_elements = PyObject_RichCompareBool(tmp_start, tmp_stop, Py_GT);
+ } else {
+ has_elements = PyObject_RichCompareBool(tmp_start, tmp_stop, Py_LT);
+ }
+ if (has_elements == -1) goto Fail;
+
+ *start = tmp_start;
+ *stop = tmp_stop;
+ *step = tmp_step;
+ Py_DECREF(neg_one);
+ Py_DECREF(one);
+ Py_DECREF(zero);
+ return has_elements;
+
+ Fail:
+ Py_XDECREF(tmp_start);
+ Py_XDECREF(tmp_stop);
+ Py_XDECREF(tmp_step);
+ Py_XDECREF(candidate);
+ Py_XDECREF(neg_one);
+ Py_XDECREF(one);
+ Py_XDECREF(zero);
+ return -1;
+}
+
+static PyObject *
+compute_slice(rangeobject *r, PyObject *_slice)
+{
+ PySliceObject *slice = (PySliceObject *) _slice;
+ rangeobject *result;
+ PyObject *start = NULL, *stop = NULL, *step = NULL;
+ PyObject *substart = NULL, *substop = NULL, *substep = NULL;
+ int has_elements;
+
+ has_elements = compute_slice_indices(r, slice, &start, &stop, &step);
+ if (has_elements == -1) return NULL;
+
+ substep = PyNumber_Multiply(r->step, step);
+ if (substep == NULL) goto fail;
+ Py_CLEAR(step);
+
+ substart = compute_item(r, start);
+ if (substart == NULL) goto fail;
+ Py_CLEAR(start);
+
+ if (has_elements) {
+ substop = compute_item(r, stop);
+ if (substop == NULL) goto fail;
+ } else {
+ substop = substart;
+ Py_INCREF(substop);
+ }
+ Py_CLEAR(stop);
+
+ result = make_range_object(Py_TYPE(r), substart, substop, substep);
+ if (result != NULL) {
+ return (PyObject *) result;
+ }
+fail:
+ Py_XDECREF(start);
+ Py_XDECREF(stop);
+ Py_XDECREF(step);
+ Py_XDECREF(substart);
+ Py_XDECREF(substop);
+ Py_XDECREF(substep);
+ return NULL;
+}
+
+/* Assumes (PyLong_CheckExact(ob) || PyBool_Check(ob)) */
+static int
+range_contains_long(rangeobject *r, PyObject *ob)
+{
+ int cmp1, cmp2, cmp3;
+ PyObject *tmp1 = NULL;
+ PyObject *tmp2 = NULL;
+ PyObject *zero = NULL;
+ int result = -1;
+
+ zero = PyLong_FromLong(0);
+ if (zero == NULL) /* MemoryError in int(0) */
+ goto end;
+
+ /* Check if the value can possibly be in the range. */
+
+ cmp1 = PyObject_RichCompareBool(r->step, zero, Py_GT);
+ if (cmp1 == -1)
+ goto end;
+ if (cmp1 == 1) { /* positive steps: start <= ob < stop */
+ cmp2 = PyObject_RichCompareBool(r->start, ob, Py_LE);
+ cmp3 = PyObject_RichCompareBool(ob, r->stop, Py_LT);
+ }
+ else { /* negative steps: stop < ob <= start */
+ cmp2 = PyObject_RichCompareBool(ob, r->start, Py_LE);
+ cmp3 = PyObject_RichCompareBool(r->stop, ob, Py_LT);
+ }
+
+ if (cmp2 == -1 || cmp3 == -1) /* TypeError */
+ goto end;
+ if (cmp2 == 0 || cmp3 == 0) { /* ob outside of range */
+ result = 0;
+ goto end;
+ }
+
+ /* Check that the stride does not invalidate ob's membership. */
+ tmp1 = PyNumber_Subtract(ob, r->start);
+ if (tmp1 == NULL)
+ goto end;
+ tmp2 = PyNumber_Remainder(tmp1, r->step);
+ if (tmp2 == NULL)
+ goto end;
+ /* result = (int(ob) - start % step) == 0 */
+ result = PyObject_RichCompareBool(tmp2, zero, Py_EQ);
+ end:
+ Py_XDECREF(tmp1);
+ Py_XDECREF(tmp2);
+ Py_XDECREF(zero);
+ return result;
+}
+
+static int
+range_contains(rangeobject *r, PyObject *ob)
+{
+ if (PyLong_CheckExact(ob) || PyBool_Check(ob))
+ return range_contains_long(r, ob);
+
+ return (int)_PySequence_IterSearch((PyObject*)r, ob,
+ PY_ITERSEARCH_CONTAINS);
+}
+
+static PyObject *
+range_count(rangeobject *r, PyObject *ob)
+{
+ if (PyLong_CheckExact(ob) || PyBool_Check(ob)) {
+ int result = range_contains_long(r, ob);
+ if (result == -1)
+ return NULL;
+ else if (result)
+ return PyLong_FromLong(1);
+ else
+ return PyLong_FromLong(0);
+ } else {
+ Py_ssize_t count;
+ count = _PySequence_IterSearch((PyObject*)r, ob, PY_ITERSEARCH_COUNT);
+ if (count == -1)
+ return NULL;
+ return PyLong_FromSsize_t(count);
+ }
+}
+
+static PyObject *
+range_index(rangeobject *r, PyObject *ob)
+{
+ int contains;
+
+ if (!PyLong_CheckExact(ob) && !PyBool_Check(ob)) {
+ Py_ssize_t index;
+ index = _PySequence_IterSearch((PyObject*)r, ob, PY_ITERSEARCH_INDEX);
+ if (index == -1)
+ return NULL;
+ return PyLong_FromSsize_t(index);
+ }
+
+ contains = range_contains_long(r, ob);
+ if (contains == -1)
+ return NULL;
+
+ if (contains) {
+ PyObject *idx, *tmp = PyNumber_Subtract(ob, r->start);
+ if (tmp == NULL)
+ return NULL;
+ /* idx = (ob - r.start) // r.step */
+ idx = PyNumber_FloorDivide(tmp, r->step);
+ Py_DECREF(tmp);
+ return idx;
+ }
+
+ /* object is not in the range */
+ PyErr_Format(PyExc_ValueError, "%R is not in range", ob);
+ return NULL;
+}
+
+static PySequenceMethods range_as_sequence = {
+ (lenfunc)range_length, /* sq_length */
+ 0, /* sq_concat */
+ 0, /* sq_repeat */
+ (ssizeargfunc)range_item, /* sq_item */
+ 0, /* sq_slice */
+ 0, /* sq_ass_item */
+ 0, /* sq_ass_slice */
+ (objobjproc)range_contains, /* sq_contains */
+};
+
static PyObject *
range_repr(rangeobject *r)
{
@@ -269,16 +696,36 @@ range_repr(rangeobject *r)
static PyObject *
range_reduce(rangeobject *r, PyObject *args)
{
- return Py_BuildValue("(O(OOO))", Py_TYPE(r),
+ return Py_BuildValue("(O(OOO))", Py_TYPE(r),
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 PyObject *
+range_subscript(rangeobject* self, PyObject* item)
+{
+ if (PyIndex_Check(item)) {
+ PyObject *i, *result;
+ i = PyNumber_Index(item);
+ if (!i)
+ return NULL;
+ result = compute_range_item(self, i);
+ Py_DECREF(i);
+ return result;
+ }
+ if (PySlice_Check(item)) {
+ return compute_slice(self, item);
+ }
+ PyErr_Format(PyExc_TypeError,
+ "range indices must be integers or slices, not %.200s",
+ item->ob_type->tp_name);
+ return NULL;
+}
+
+
+static PyMappingMethods range_as_mapping = {
+ (lenfunc)range_length, /* mp_length */
+ (binaryfunc)range_subscript, /* mp_subscript */
+ (objobjargproc)0, /* mp_ass_subscript */
};
static PyObject * range_iter(PyObject *seq);
@@ -287,10 +734,18 @@ static PyObject * range_reverse(PyObject *seq);
PyDoc_STRVAR(reverse_doc,
"Returns a reverse iterator.");
+PyDoc_STRVAR(count_doc,
+"rangeobject.count(value) -> integer -- return number of occurrences of value");
+
+PyDoc_STRVAR(index_doc,
+"rangeobject.index(value, [start, [stop]]) -> integer -- return index of value.\n"
+"Raises ValueError if the value is not present.");
+
static PyMethodDef range_methods[] = {
- {"__reversed__", (PyCFunction)range_reverse, METH_NOARGS,
- reverse_doc},
- {"__reduce__", (PyCFunction)range_reduce, METH_VARARGS},
+ {"__reversed__", (PyCFunction)range_reverse, METH_NOARGS, reverse_doc},
+ {"__reduce__", (PyCFunction)range_reduce, METH_VARARGS},
+ {"count", (PyCFunction)range_count, METH_O, count_doc},
+ {"index", (PyCFunction)range_index, METH_O, index_doc},
{NULL, NULL} /* sentinel */
};
@@ -307,7 +762,7 @@ PyTypeObject PyRange_Type = {
(reprfunc)range_repr, /* tp_repr */
0, /* tp_as_number */
&range_as_sequence, /* tp_as_sequence */
- 0, /* tp_as_mapping */
+ &range_as_mapping, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
@@ -367,22 +822,6 @@ rangeiter_len(rangeiterobject *r)
return PyLong_FromLong(r->len - r->index);
}
-typedef struct {
- PyObject_HEAD
- PyObject *index;
- PyObject *start;
- PyObject *step;
- PyObject *len;
-} longrangeiterobject;
-
-static PyObject *
-longrangeiter_len(longrangeiterobject *r, PyObject *no_args)
-{
- return PyNumber_Subtract(r->len, r->index);
-}
-
-static PyObject *rangeiter_new(PyTypeObject *, PyObject *args, PyObject *kw);
-
PyDoc_STRVAR(length_hint_doc,
"Private method returning an estimate of len(list(it)).");
@@ -392,6 +831,8 @@ static PyMethodDef rangeiter_methods[] = {
{NULL, NULL} /* sentinel */
};
+static PyObject *rangeiter_new(PyTypeObject *, PyObject *args, PyObject *kw);
+
PyTypeObject PyRangeIter_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"range_iterator", /* tp_name */
@@ -466,7 +907,7 @@ get_len_of_range(long lo, long hi, long step)
is not representable as a C long, OverflowError is raised. */
static PyObject *
-int_range_iter(long start, long stop, long step)
+fast_range_iter(long start, long stop, long step)
{
rangeiterobject *it = PyObject_New(rangeiterobject, &PyRangeIter_Type);
unsigned long ulen;
@@ -498,7 +939,21 @@ rangeiter_new(PyTypeObject *type, PyObject *args, PyObject *kw)
&start, &stop, &step))
return NULL;
- return int_range_iter(start, stop, step);
+ return fast_range_iter(start, stop, step);
+}
+
+typedef struct {
+ PyObject_HEAD
+ PyObject *index;
+ PyObject *start;
+ PyObject *step;
+ PyObject *len;
+} longrangeiterobject;
+
+static PyObject *
+longrangeiter_len(longrangeiterobject *r, PyObject *no_args)
+{
+ return PyNumber_Subtract(r->len, r->index);
}
static PyMethodDef longrangeiter_methods[] = {
@@ -612,7 +1067,7 @@ range_iter(PyObject *seq)
PyErr_Clear();
goto long_range;
}
- int_it = int_range_iter(lstart, lstop, lstep);
+ int_it = fast_range_iter(lstart, lstop, lstep);
if (int_it == NULL && PyErr_ExceptionMatches(PyExc_OverflowError)) {
PyErr_Clear();
goto long_range;
@@ -627,14 +1082,11 @@ range_iter(PyObject *seq)
/* Do all initialization here, so we can DECREF on failure. */
it->start = r->start;
it->step = r->step;
+ it->len = r->length;
Py_INCREF(it->start);
Py_INCREF(it->step);
+ Py_INCREF(it->len);
- it->len = it->index = NULL;
-
- it->len = range_length_obj(r);
- if (!it->len)
- goto create_failure;
it->index = PyLong_FromLong(0);
if (!it->index)
goto create_failure;
@@ -651,7 +1103,7 @@ range_reverse(PyObject *seq)
{
rangeobject *range = (rangeobject*) seq;
longrangeiterobject *it;
- PyObject *one, *sum, *diff, *len = NULL, *product;
+ PyObject *one, *sum, *diff, *product;
long lstart, lstop, lstep, new_start, new_stop;
unsigned long ulen;
@@ -714,7 +1166,7 @@ range_reverse(PyObject *seq)
new_stop = lstart - lstep;
new_start = (long)(new_stop + ulen * lstep);
- return int_range_iter(new_start, new_stop, -lstep);
+ return fast_range_iter(new_start, new_stop, -lstep);
long_range:
it = PyObject_New(longrangeiterobject, &PyLongRangeIter_Type);
@@ -722,18 +1174,14 @@ long_range:
return NULL;
/* start + (len - 1) * step */
- len = range_length_obj(range);
- if (!len)
- goto create_failure;
-
- /* Steal reference to len. */
- it->len = len;
+ it->len = range->length;
+ Py_INCREF(it->len);
one = PyLong_FromLong(1);
if (!one)
goto create_failure;
- diff = PyNumber_Subtract(len, one);
+ diff = PyNumber_Subtract(it->len, one);
Py_DECREF(one);
if (!diff)
goto create_failure;