mirror of https://github.com/python/cpython
712 lines
20 KiB
C
712 lines
20 KiB
C
/* Range object implementation */
|
|
|
|
#include "Python.h"
|
|
|
|
/* Support objects whose length is > PY_SSIZE_T_MAX.
|
|
|
|
This could be sped up for small PyLongs if they fit in an Py_ssize_t.
|
|
This only matters on Win64. Though we could use PY_LONG_LONG which
|
|
would presumably help perf.
|
|
*/
|
|
|
|
typedef struct {
|
|
PyObject_HEAD
|
|
PyObject *start;
|
|
PyObject *stop;
|
|
PyObject *step;
|
|
} rangeobject;
|
|
|
|
/* Helper function for validating step. Always returns a new reference or
|
|
NULL on error.
|
|
*/
|
|
static PyObject *
|
|
validate_step(PyObject *step)
|
|
{
|
|
/* No step specified, use a step of 1. */
|
|
if (!step)
|
|
return PyInt_FromLong(1);
|
|
|
|
step = PyNumber_Index(step);
|
|
if (step) {
|
|
Py_ssize_t istep = PyNumber_AsSsize_t(step, NULL);
|
|
if (istep == -1 && PyErr_Occurred()) {
|
|
/* Ignore OverflowError, we know the value isn't 0. */
|
|
PyErr_Clear();
|
|
}
|
|
else if (istep == 0) {
|
|
PyErr_SetString(PyExc_ValueError,
|
|
"range() arg 3 must not be zero");
|
|
Py_CLEAR(step);
|
|
}
|
|
}
|
|
|
|
return step;
|
|
}
|
|
|
|
/* XXX(nnorwitz): should we error check if the user passes any empty ranges?
|
|
range(-10)
|
|
range(0, -5)
|
|
range(0, 5, -1)
|
|
*/
|
|
static PyObject *
|
|
range_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
|
{
|
|
rangeobject *obj = NULL;
|
|
PyObject *start = NULL, *stop = NULL, *step = NULL;
|
|
|
|
if (!_PyArg_NoKeywords("range()", kw))
|
|
return NULL;
|
|
|
|
if (PyTuple_Size(args) <= 1) {
|
|
if (!PyArg_UnpackTuple(args, "range", 1, 1, &stop))
|
|
goto Fail;
|
|
stop = PyNumber_Index(stop);
|
|
if (!stop)
|
|
goto Fail;
|
|
start = PyInt_FromLong(0);
|
|
step = PyInt_FromLong(1);
|
|
if (!start || !step)
|
|
goto Fail;
|
|
}
|
|
else {
|
|
if (!PyArg_UnpackTuple(args, "range", 2, 3,
|
|
&start, &stop, &step))
|
|
goto Fail;
|
|
|
|
/* Convert borrowed refs to owned refs */
|
|
start = PyNumber_Index(start);
|
|
stop = PyNumber_Index(stop);
|
|
step = validate_step(step);
|
|
if (!start || !stop || !step)
|
|
goto Fail;
|
|
}
|
|
|
|
obj = PyObject_New(rangeobject, &PyRange_Type);
|
|
if (obj == NULL)
|
|
goto Fail;
|
|
obj->start = start;
|
|
obj->stop = stop;
|
|
obj->step = step;
|
|
return (PyObject *) obj;
|
|
|
|
Fail:
|
|
Py_XDECREF(start);
|
|
Py_XDECREF(stop);
|
|
Py_XDECREF(step);
|
|
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.");
|
|
|
|
static void
|
|
range_dealloc(rangeobject *r)
|
|
{
|
|
Py_DECREF(r->start);
|
|
Py_DECREF(r->stop);
|
|
Py_DECREF(r->step);
|
|
}
|
|
|
|
/* 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 PyInt_Check() or
|
|
* PyLong_Check(). Return -1 when there is an error.
|
|
*/
|
|
static PyObject*
|
|
range_length_obj(rangeobject *r)
|
|
{
|
|
/* -------------------------------------------------------------
|
|
Algorithm is equal to that of get_len_of_range(), but it operates
|
|
on PyObjects (which are assumed to be PyLong or PyInt objects).
|
|
---------------------------------------------------------------*/
|
|
int cmp_result, cmp_call;
|
|
PyObject *lo, *hi;
|
|
PyObject *step = NULL;
|
|
PyObject *diff = NULL;
|
|
PyObject *one = NULL;
|
|
PyObject *tmp1 = NULL, *tmp2 = NULL, *result;
|
|
/* holds sub-expression evaluations */
|
|
|
|
PyObject *zero = PyLong_FromLong(0);
|
|
if (zero == NULL)
|
|
return NULL;
|
|
cmp_call = PyObject_Cmp(r->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;
|
|
Py_INCREF(step);
|
|
} else {
|
|
lo = r->stop;
|
|
hi = r->start;
|
|
step = PyNumber_Negative(r->step);
|
|
if (!step)
|
|
return NULL;
|
|
}
|
|
|
|
/* if (lo >= hi), return length of 0. */
|
|
if (PyObject_Compare(lo, hi) >= 0) {
|
|
Py_XDECREF(step);
|
|
return PyLong_FromLong(0);
|
|
}
|
|
|
|
if ((one = PyLong_FromLong(1L)) == NULL)
|
|
goto Fail;
|
|
|
|
if ((tmp1 = PyNumber_Subtract(hi, lo)) == NULL)
|
|
goto Fail;
|
|
|
|
if ((diff = PyNumber_Subtract(tmp1, one)) == NULL)
|
|
goto Fail;
|
|
|
|
if ((tmp2 = PyNumber_FloorDivide(diff, step)) == NULL)
|
|
goto Fail;
|
|
|
|
if ((result = PyNumber_Add(tmp2, one)) == NULL)
|
|
goto Fail;
|
|
|
|
Py_DECREF(tmp2);
|
|
Py_DECREF(diff);
|
|
Py_DECREF(step);
|
|
Py_DECREF(tmp1);
|
|
Py_DECREF(one);
|
|
return result;
|
|
|
|
Fail:
|
|
Py_XDECREF(tmp2);
|
|
Py_XDECREF(diff);
|
|
Py_XDECREF(step);
|
|
Py_XDECREF(tmp1);
|
|
Py_XDECREF(one);
|
|
return NULL;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
/* 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,
|
|
"xrange object index out of range");
|
|
return NULL;
|
|
}
|
|
|
|
/* XXX(nnorwitz): optimize for short ints. */
|
|
rem = PyLong_FromSsize_t(i % len);
|
|
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)
|
|
{
|
|
PyObject *start_str = NULL, *stop_str = NULL, *step_str = NULL;
|
|
PyObject *result = NULL;
|
|
Py_ssize_t istart, istep;
|
|
|
|
/* We always need the stop value. */
|
|
stop_str = PyObject_Str(r->stop);
|
|
if (!stop_str)
|
|
return NULL;
|
|
|
|
/* XXX(nnorwitz): should we use PyObject_Repr instead of str? */
|
|
|
|
/* Check for special case values for printing. We don't always
|
|
need the start or step values. We don't care about errors
|
|
(it means overflow), so clear the errors. */
|
|
istart = PyNumber_AsSsize_t(r->start, NULL);
|
|
if (istart != 0 || (istart == -1 && PyErr_Occurred())) {
|
|
PyErr_Clear();
|
|
start_str = PyObject_Str(r->start);
|
|
}
|
|
|
|
istep = PyNumber_AsSsize_t(r->step, NULL);
|
|
if (istep != 1 || (istep == -1 && PyErr_Occurred())) {
|
|
PyErr_Clear();
|
|
step_str = PyObject_Str(r->step);
|
|
}
|
|
|
|
if (istart == 0 && istep == 1)
|
|
result = PyUnicode_FromFormat("range(%s)",
|
|
PyString_AS_STRING(stop_str));
|
|
else if (istep == 1) {
|
|
if (start_str)
|
|
result = PyUnicode_FromFormat("range(%s, %s)",
|
|
PyString_AS_STRING(start_str),
|
|
PyString_AS_STRING(stop_str));
|
|
}
|
|
else if (start_str && step_str)
|
|
result = PyUnicode_FromFormat("range(%s, %s, %s)",
|
|
PyString_AS_STRING(start_str),
|
|
PyString_AS_STRING(stop_str),
|
|
PyString_AS_STRING(step_str));
|
|
/* else result is NULL and an error should already be set. */
|
|
|
|
Py_XDECREF(start_str);
|
|
Py_XDECREF(stop_str);
|
|
Py_XDECREF(step_str);
|
|
return result;
|
|
}
|
|
|
|
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_iter(PyObject *seq);
|
|
static PyObject * range_reverse(PyObject *seq);
|
|
|
|
PyDoc_STRVAR(reverse_doc,
|
|
"Returns a reverse iterator.");
|
|
|
|
static PyMethodDef range_methods[] = {
|
|
{"__reversed__", (PyCFunction)range_reverse, METH_NOARGS,
|
|
reverse_doc},
|
|
{NULL, NULL} /* sentinel */
|
|
};
|
|
|
|
PyTypeObject PyRange_Type = {
|
|
PyObject_HEAD_INIT(&PyType_Type)
|
|
0, /* Number of items for varobject */
|
|
"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 */
|
|
};
|
|
|
|
/*********************** Xrange Iterator **************************/
|
|
|
|
/* There are 2 types of iterators, one for C longs, the other for
|
|
Python longs (ie, PyObjects). This should make iteration fast
|
|
in the normal case, but possible for any numeric value.
|
|
*/
|
|
|
|
typedef struct {
|
|
PyObject_HEAD
|
|
long index;
|
|
long start;
|
|
long step;
|
|
long len;
|
|
} rangeiterobject;
|
|
|
|
static PyObject *
|
|
rangeiter_next(rangeiterobject *r)
|
|
{
|
|
if (r->index < r->len)
|
|
return PyInt_FromLong(r->start + (r->index++) * r->step);
|
|
return NULL;
|
|
}
|
|
|
|
static PyObject *
|
|
rangeiter_len(rangeiterobject *r)
|
|
{
|
|
return PyInt_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)).");
|
|
|
|
static PyMethodDef rangeiter_methods[] = {
|
|
{"__length_hint__", (PyCFunction)rangeiter_len, METH_NOARGS,
|
|
length_hint_doc},
|
|
{NULL, NULL} /* sentinel */
|
|
};
|
|
|
|
PyTypeObject Pyrangeiter_Type = {
|
|
PyObject_HEAD_INIT(&PyType_Type)
|
|
0, /* ob_size */
|
|
"rangeiterator", /* tp_name */
|
|
sizeof(rangeiterobject), /* tp_basicsize */
|
|
0, /* tp_itemsize */
|
|
/* methods */
|
|
(destructor)PyObject_Del, /* tp_dealloc */
|
|
0, /* tp_print */
|
|
0, /* tp_getattr */
|
|
0, /* tp_setattr */
|
|
0, /* tp_compare */
|
|
0, /* tp_repr */
|
|
0, /* tp_as_number */
|
|
0, /* 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 */
|
|
0, /* tp_doc */
|
|
0, /* tp_traverse */
|
|
0, /* tp_clear */
|
|
0, /* tp_richcompare */
|
|
0, /* tp_weaklistoffset */
|
|
PyObject_SelfIter, /* tp_iter */
|
|
(iternextfunc)rangeiter_next, /* tp_iternext */
|
|
rangeiter_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 */
|
|
rangeiter_new, /* tp_new */
|
|
};
|
|
|
|
/* Return number of items in range/xrange (lo, hi, step). step > 0
|
|
* required. Return a value < 0 if & only if the true value is too
|
|
* large to fit in a signed long.
|
|
*/
|
|
static long
|
|
get_len_of_range(long lo, long hi, long step)
|
|
{
|
|
/* -------------------------------------------------------------
|
|
If lo >= hi, the range is empty.
|
|
Else if n values are in the range, the last one is
|
|
lo + (n-1)*step, which must be <= hi-1. Rearranging,
|
|
n <= (hi - lo - 1)/step + 1, so taking the floor of the RHS gives
|
|
the proper value. Since lo < hi in this case, hi-lo-1 >= 0, so
|
|
the RHS is non-negative and so truncation is the same as the
|
|
floor. Letting M be the largest positive long, the worst case
|
|
for the RHS numerator is hi=M, lo=-M-1, and then
|
|
hi-lo-1 = M-(-M-1)-1 = 2*M. Therefore unsigned long has enough
|
|
precision to compute the RHS exactly.
|
|
---------------------------------------------------------------*/
|
|
long n = 0;
|
|
if (lo < hi) {
|
|
unsigned long uhi = (unsigned long)hi;
|
|
unsigned long ulo = (unsigned long)lo;
|
|
unsigned long diff = uhi - ulo - 1;
|
|
n = (long)(diff / (unsigned long)step + 1);
|
|
}
|
|
return n;
|
|
}
|
|
|
|
static PyObject *
|
|
int_range_iter(long start, long stop, long step)
|
|
{
|
|
rangeiterobject *it = PyObject_New(rangeiterobject, &Pyrangeiter_Type);
|
|
if (it == NULL)
|
|
return NULL;
|
|
it->start = start;
|
|
it->step = step;
|
|
if (step > 0)
|
|
it->len = get_len_of_range(start, stop, step);
|
|
else
|
|
it->len = get_len_of_range(stop, start, -step);
|
|
it->index = 0;
|
|
return (PyObject *)it;
|
|
}
|
|
|
|
static PyObject *
|
|
rangeiter_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
|
{
|
|
long start, stop, step;
|
|
|
|
if (!_PyArg_NoKeywords("rangeiter()", kw))
|
|
return NULL;
|
|
|
|
if (!PyArg_ParseTuple(args, "lll;rangeiter() requires 3 int arguments",
|
|
&start, &stop, &step))
|
|
return NULL;
|
|
|
|
return int_range_iter(start, stop, step);
|
|
}
|
|
|
|
static PyMethodDef longrangeiter_methods[] = {
|
|
{"__length_hint__", (PyCFunction)longrangeiter_len, METH_NOARGS,
|
|
length_hint_doc},
|
|
{NULL, NULL} /* sentinel */
|
|
};
|
|
|
|
static void
|
|
longrangeiter_dealloc(longrangeiterobject *r)
|
|
{
|
|
Py_XDECREF(r->index);
|
|
Py_XDECREF(r->start);
|
|
Py_XDECREF(r->step);
|
|
Py_XDECREF(r->len);
|
|
}
|
|
|
|
static PyObject *
|
|
longrangeiter_next(longrangeiterobject *r)
|
|
{
|
|
PyObject *one, *product, *new_index, *result;
|
|
if (PyObject_RichCompareBool(r->index, r->len, Py_LT) != 1)
|
|
return NULL;
|
|
|
|
one = PyLong_FromLong(1);
|
|
if (!one)
|
|
return NULL;
|
|
|
|
product = PyNumber_Multiply(r->index, r->step);
|
|
if (!product) {
|
|
Py_DECREF(one);
|
|
return NULL;
|
|
}
|
|
|
|
new_index = PyNumber_Add(r->index, one);
|
|
Py_DECREF(one);
|
|
if (!new_index) {
|
|
Py_DECREF(product);
|
|
return NULL;
|
|
}
|
|
|
|
result = PyNumber_Add(r->start, product);
|
|
Py_DECREF(product);
|
|
if (result) {
|
|
Py_DECREF(r->index);
|
|
r->index = new_index;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static PyTypeObject Pylongrangeiter_Type = {
|
|
PyObject_HEAD_INIT(&PyType_Type)
|
|
0, /* ob_size */
|
|
"rangeiterator", /* tp_name */
|
|
sizeof(longrangeiterobject), /* tp_basicsize */
|
|
0, /* tp_itemsize */
|
|
/* methods */
|
|
(destructor)longrangeiter_dealloc, /* tp_dealloc */
|
|
0, /* tp_print */
|
|
0, /* tp_getattr */
|
|
0, /* tp_setattr */
|
|
0, /* tp_compare */
|
|
0, /* tp_repr */
|
|
0, /* tp_as_number */
|
|
0, /* 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 */
|
|
0, /* tp_doc */
|
|
0, /* tp_traverse */
|
|
0, /* tp_clear */
|
|
0, /* tp_richcompare */
|
|
0, /* tp_weaklistoffset */
|
|
PyObject_SelfIter, /* tp_iter */
|
|
(iternextfunc)longrangeiter_next, /* tp_iternext */
|
|
longrangeiter_methods, /* tp_methods */
|
|
0,
|
|
};
|
|
|
|
static PyObject *
|
|
range_iter(PyObject *seq)
|
|
{
|
|
rangeobject *r = (rangeobject *)seq;
|
|
longrangeiterobject *it;
|
|
PyObject *tmp, *len;
|
|
|
|
assert(PyRange_Check(seq));
|
|
if (_PyLong_FitsInLong(r->start) &&
|
|
_PyLong_FitsInLong(r->stop) &&
|
|
_PyLong_FitsInLong(r->step))
|
|
return int_range_iter(PyLong_AsLong(r->start),
|
|
PyLong_AsLong(r->stop),
|
|
PyLong_AsLong(r->step));
|
|
|
|
it = PyObject_New(longrangeiterobject, &Pylongrangeiter_Type);
|
|
if (it == NULL)
|
|
return NULL;
|
|
|
|
/* Do all initialization here, so we can DECREF on failure. */
|
|
it->start = r->start;
|
|
it->step = r->step;
|
|
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;
|
|
it->index = PyLong_FromLong(0);
|
|
if (!it->index)
|
|
goto create_failure;
|
|
|
|
return (PyObject *)it;
|
|
|
|
create_failure:
|
|
Py_DECREF(it);
|
|
return NULL;
|
|
}
|
|
|
|
static PyObject *
|
|
range_reverse(PyObject *seq)
|
|
{
|
|
rangeobject *range = (rangeobject*) seq;
|
|
longrangeiterobject *it;
|
|
PyObject *one, *sum, *diff, *len = NULL, *product;
|
|
|
|
/* XXX(nnorwitz): do the calc for the new start/stop first,
|
|
then if they fit, call the proper iter()?
|
|
*/
|
|
assert(PyRange_Check(seq));
|
|
if (_PyLong_FitsInLong(range->start) &&
|
|
_PyLong_FitsInLong(range->stop) &&
|
|
_PyLong_FitsInLong(range->step)) {
|
|
long start = PyLong_AsLong(range->start);
|
|
long step = PyLong_AsLong(range->step);
|
|
long stop = PyLong_AsLong(range->stop);
|
|
/* XXX(nnorwitz): need to check for overflow and simplify. */
|
|
long len = get_len_of_range(start, stop, step);
|
|
long new_start = start + (len - 1) * step;
|
|
long new_stop = start;
|
|
if (step > 0)
|
|
new_stop -= 1;
|
|
else
|
|
new_stop += 1;
|
|
return int_range_iter(new_start, new_stop, -step);
|
|
}
|
|
|
|
it = PyObject_New(longrangeiterobject, &Pylongrangeiter_Type);
|
|
if (it == NULL)
|
|
return NULL;
|
|
|
|
/* start + (len - 1) * step */
|
|
len = range_length_obj(range);
|
|
if (!len)
|
|
goto create_failure;
|
|
|
|
one = PyLong_FromLong(1);
|
|
if (!one)
|
|
goto create_failure;
|
|
|
|
diff = PyNumber_Subtract(len, one);
|
|
Py_DECREF(one);
|
|
if (!diff)
|
|
goto create_failure;
|
|
|
|
product = PyNumber_Multiply(len, range->step);
|
|
if (!product)
|
|
goto create_failure;
|
|
|
|
sum = PyNumber_Add(range->start, product);
|
|
Py_DECREF(product);
|
|
it->start = sum;
|
|
if (!it->start)
|
|
goto create_failure;
|
|
it->step = PyNumber_Negative(range->step);
|
|
if (!it->step) {
|
|
Py_DECREF(it->start);
|
|
PyObject_Del(it);
|
|
return NULL;
|
|
}
|
|
|
|
/* Steal reference to len. */
|
|
it->len = len;
|
|
|
|
it->index = PyLong_FromLong(0);
|
|
if (!it->index) {
|
|
Py_DECREF(it);
|
|
return NULL;
|
|
}
|
|
|
|
return (PyObject *)it;
|
|
|
|
create_failure:
|
|
Py_XDECREF(len);
|
|
PyObject_Del(it);
|
|
return NULL;
|
|
}
|