#include "Python.h"
#include "pycore_abstract.h"
#include "pycore_range.h"
#include "pycore_long.h"
#include "pycore_tuple.h"
#include "structmember.h"
typedef struct {
PyObject_HEAD
PyObject *start;
PyObject *stop;
PyObject *step;
PyObject *length;
} rangeobject;
static PyObject *
validate_step(PyObject *step)
{
if (!step)
return PyLong_FromLong(1);
step = PyNumber_Index(step);
if (step && _PyLong_IsZero((PyLongObject *)step)) {
PyErr_SetString(PyExc_ValueError,
"range() arg 3 must not be zero");
Py_CLEAR(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;
}
static PyObject *
range_from_array(PyTypeObject *type, PyObject *const *args, Py_ssize_t num_args)
{
rangeobject *obj;
PyObject *start = NULL, *stop = NULL, *step = NULL;
switch (num_args) {
case 3:
step = args[2];
case 2:
start = PyNumber_Index(args[0]);
if (!start) {
return NULL;
}
stop = PyNumber_Index(args[1]);
if (!stop) {
Py_DECREF(start);
return NULL;
}
step = validate_step(step);
if (!step) {
Py_DECREF(start);
Py_DECREF(stop);
return NULL;
}
break;
case 1:
stop = PyNumber_Index(args[0]);
if (!stop) {
return NULL;
}
start = Py_NewRef(_PyLong_GetZero());
step = Py_NewRef(_PyLong_GetOne());
break;
case 0:
PyErr_SetString(PyExc_TypeError,
"range expected at least 1 argument, got 0");
return NULL;
default:
PyErr_Format(PyExc_TypeError,
"range expected at most 3 arguments, got %zd",
num_args);
return NULL;
}
obj = make_range_object(type, start, stop, step);
if (obj != NULL) {
return (PyObject *) obj;
}
Py_DECREF(start);
Py_DECREF(stop);
Py_DECREF(step);
return NULL;
}
static PyObject *
range_new(PyTypeObject *type, PyObject *args, PyObject *kw)
{
if (!_PyArg_NoKeywords("range", kw))
return NULL;
return range_from_array(type, _PyTuple_ITEMS(args), PyTuple_GET_SIZE(args));
}
static PyObject *
range_vectorcall(PyTypeObject *type, PyObject *const *args,
size_t nargsf, PyObject *kwnames)
{
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
if (!_PyArg_NoKwnames("range", kwnames)) {
return NULL;
}
return range_from_array(type, args, nargs);
}
PyDoc_STRVAR(range_doc,
"range(stop) -> range object\n\
range(start, stop[, step]) -> range object\n\
\n\
Return an object that produces a sequence of integers from start (inclusive)\n\
to stop (exclusive) by step. range(i, j) produces i, i+1, i+2, ..., j-1.\n\
start defaults to 0, and stop is omitted! range(4) produces 0, 1, 2, 3.\n\
These are exactly the valid indices for a list of 4 elements.\n\
When step is given, it specifies the increment (or decrement).");
static void
range_dealloc(rangeobject *r)
{
Py_DECREF(r->start);
Py_DECREF(r->stop);
Py_DECREF(r->step);
Py_DECREF(r->length);
PyObject_Free(r);
}
static unsigned long
get_len_of_range(long lo, long hi, long step);
static long compute_range_length_long(PyObject *start,
PyObject *stop, PyObject *step) {
int overflow = 0;
long long_start = PyLong_AsLongAndOverflow(start, &overflow);
if (overflow) {
return -2;
}
if (long_start == -1 && PyErr_Occurred()) {
return -1;
}
long long_stop = PyLong_AsLongAndOverflow(stop, &overflow);
if (overflow) {
return -2;
}
if (long_stop == -1 && PyErr_Occurred()) {
return -1;
}
long long_step = PyLong_AsLongAndOverflow(step, &overflow);
if (overflow) {
return -2;
}
if (long_step == -1 && PyErr_Occurred()) {
return -1;
}
unsigned long ulen = get_len_of_range(long_start, long_stop, long_step);
if (ulen > (unsigned long)LONG_MAX) {
return -2;
}
else {
return (long)ulen;
}
}
static PyObject*
compute_range_length(PyObject *start, PyObject *stop, PyObject *step)
{
int cmp_result;
PyObject *lo, *hi;
PyObject *diff = NULL;
PyObject *tmp1 = NULL, *tmp2 = NULL, *result;
PyObject *zero = _PyLong_GetZero();
PyObject *one = _PyLong_GetOne();
assert(PyLong_Check(start));
assert(PyLong_Check(stop));
assert(PyLong_Check(step));
long len = compute_range_length_long(start, stop, step);
if (len >= 0) {
return PyLong_FromLong(len);
}
else if (len == -1) {
return NULL;
}
assert(len == -2);
cmp_result = PyObject_RichCompareBool(step, zero, Py_GT);
if (cmp_result == -1)
return NULL;
if (cmp_result == 1) {
lo = start;
hi = stop;
Py_INCREF(step);
} else {
lo = stop;
hi = start;
step = PyNumber_Negative(step);
if (!step)
return NULL;
}
cmp_result = PyObject_RichCompareBool(lo, hi, Py_GE);
if (cmp_result != 0) {
Py_DECREF(step);
if (cmp_result < 0)
return NULL;
result = zero;
return Py_NewRef(result);
}
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);
return result;
Fail:
Py_DECREF(step);
Py_XDECREF(tmp2);
Py_XDECREF(diff);
Py_XDECREF(tmp1);
return NULL;
}
static Py_ssize_t
range_length(rangeobject *r)
{
return PyLong_AsSsize_t(r->length);
}
static PyObject *
compute_item(rangeobject *r, PyObject *i)
{
PyObject *incr, *result;
if (r->step == _PyLong_GetOne()) {
result = PyNumber_Add(r->start, i);
}
else {
incr = PyNumber_Multiply(i, r->step);
if (!incr) {
return NULL;
}
result = PyNumber_Add(r->start, incr);
Py_DECREF(incr);
}
return result;
}
static PyObject *
compute_range_item(rangeobject *r, PyObject *arg)
{
PyObject *zero = _PyLong_GetZero();
int cmp_result;
PyObject *i, *result;
cmp_result = PyObject_RichCompareBool(arg, zero, Py_LT);
if (cmp_result == -1) {
return NULL;
}
if (cmp_result == 1) {
i = PyNumber_Add(r->length, arg);
if (!i) {
return NULL;
}
} else {
i = Py_NewRef(arg);
}
cmp_result = PyObject_RichCompareBool(i, zero, Py_LT);
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;
}
result = compute_item(r, i);
Py_DECREF(i);
return result;
}
static PyObject *
range_item(rangeobject *r, Py_ssize_t i)
{
PyObject *res, *arg = PyLong_FromSsize_t(i);
if (!arg) {
return NULL;
}
res = compute_range_item(r, arg);
Py_DECREF(arg);
return res;
}
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 error;
error = _PySlice_GetLongIndices(slice, r->length, &start, &stop, &step);
if (error == -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);
substop = compute_item(r, stop);
if (substop == NULL) goto fail;
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;
}
static int
range_contains_long(rangeobject *r, PyObject *ob)
{
PyObject *zero = _PyLong_GetZero();
int cmp1, cmp2, cmp3;
PyObject *tmp1 = NULL;
PyObject *tmp2 = NULL;
int result = -1;
cmp1 = PyObject_RichCompareBool(r->step, zero, Py_GT);
if (cmp1 == -1)
goto end;
if (cmp1 == 1) {
cmp2 = PyObject_RichCompareBool(r->start, ob, Py_LE);
cmp3 = PyObject_RichCompareBool(ob, r->stop, Py_LT);
}
else {
cmp2 = PyObject_RichCompareBool(ob, r->start, Py_LE);
cmp3 = PyObject_RichCompareBool(r->stop, ob, Py_LT);
}
if (cmp2 == -1 || cmp3 == -1)
goto end;
if (cmp2 == 0 || cmp3 == 0) {
result = 0;
goto end;
}
tmp1 = PyNumber_Subtract(ob, r->start);
if (tmp1 == NULL)
goto end;
tmp2 = PyNumber_Remainder(tmp1, r->step);
if (tmp2 == NULL)
goto end;
result = PyObject_RichCompareBool(tmp2, zero, Py_EQ);
end:
Py_XDECREF(tmp1);
Py_XDECREF(tmp2);
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 int
range_equals(rangeobject *r0, rangeobject *r1)
{
int cmp_result;
if (r0 == r1)
return 1;
cmp_result = PyObject_RichCompareBool(r0->length, r1->length, Py_EQ);
if (cmp_result != 1)
return cmp_result;
cmp_result = PyObject_Not(r0->length);
if (cmp_result != 0)
return cmp_result;
cmp_result = PyObject_RichCompareBool(r0->start, r1->start, Py_EQ);
if (cmp_result != 1)
return cmp_result;
cmp_result = PyObject_RichCompareBool(r0->length, _PyLong_GetOne(), Py_EQ);
if (cmp_result != 0)
return cmp_result;
return PyObject_RichCompareBool(r0->step, r1->step, Py_EQ);
}
static PyObject *
range_richcompare(PyObject *self, PyObject *other, int op)
{
int result;
if (!PyRange_Check(other))
Py_RETURN_NOTIMPLEMENTED;
switch (op) {
case Py_NE:
case Py_EQ:
result = range_equals((rangeobject*)self, (rangeobject*)other);
if (result == -1)
return NULL;
if (op == Py_NE)
result = !result;
if (result)
Py_RETURN_TRUE;
else
Py_RETURN_FALSE;
case Py_LE:
case Py_GE:
case Py_LT:
case Py_GT:
Py_RETURN_NOTIMPLEMENTED;
default:
PyErr_BadArgument();
return NULL;
}
}
static Py_hash_t
range_hash(rangeobject *r)
{
PyObject *t;
Py_hash_t result = -1;
int cmp_result;
t = PyTuple_New(3);
if (!t)
return -1;
PyTuple_SET_ITEM(t, 0, Py_NewRef(r->length));
cmp_result = PyObject_Not(r->length);
if (cmp_result == -1)
goto end;
if (cmp_result == 1) {
PyTuple_SET_ITEM(t, 1, Py_NewRef(Py_None));
PyTuple_SET_ITEM(t, 2, Py_NewRef(Py_None));
}
else {
PyTuple_SET_ITEM(t, 1, Py_NewRef(r->start));
cmp_result = PyObject_RichCompareBool(r->length, _PyLong_GetOne(), Py_EQ);
if (cmp_result == -1)
goto end;
if (cmp_result == 1) {
PyTuple_SET_ITEM(t, 2, Py_NewRef(Py_None));
}
else {
PyTuple_SET_ITEM(t, 2, Py_NewRef(r->step));
}
}
result = PyObject_Hash(t);
end:
Py_DECREF(t);
return result;
}
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;
return PyLong_FromLong(result);
} 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 = PyNumber_Subtract(ob, r->start);
if (idx == NULL) {
return NULL;
}
if (r->step == _PyLong_GetOne()) {
return idx;
}
PyObject *sidx = PyNumber_FloorDivide(idx, r->step);
Py_DECREF(idx);
return sidx;
}
PyErr_Format(PyExc_ValueError, "%R is not in range", ob);
return NULL;
}
static PySequenceMethods range_as_sequence = {
(lenfunc)range_length,
0,
0,
(ssizeargfunc)range_item,
0,
0,
0,
(objobjproc)range_contains,
};
static PyObject *
range_repr(rangeobject *r)
{
Py_ssize_t istep;
istep = PyNumber_AsSsize_t(r->step, NULL);
if (istep == -1 && PyErr_Occurred()) {
assert(!PyErr_ExceptionMatches(PyExc_OverflowError));
return NULL;
}
if (istep == 1)
return PyUnicode_FromFormat("range(%R, %R)", r->start, r->stop);
else
return PyUnicode_FromFormat("range(%R, %R, %R)",
r->start, r->stop, r->step);
}
static PyObject *
range_reduce(rangeobject *r, PyObject *args)
{
return Py_BuildValue("(O(OOO))", Py_TYPE(r),
r->start, r->stop, r->step);
}
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",
Py_TYPE(item)->tp_name);
return NULL;
}
static PyMappingMethods range_as_mapping = {
(lenfunc)range_length,
(binaryfunc)range_subscript,
(objobjargproc)0,
};
static int
range_bool(rangeobject* self)
{
return PyObject_IsTrue(self->length);
}
static PyNumberMethods range_as_number = {
.nb_bool = (inquiry)range_bool,
};
static PyObject * range_iter(PyObject *seq);
static PyObject * range_reverse(PyObject *seq, PyObject *Py_UNUSED(ignored));
PyDoc_STRVAR(reverse_doc,
"Return a reverse iterator.");
PyDoc_STRVAR(count_doc,
"rangeobject.count(value) -> integer -- return number of occurrences of value");
PyDoc_STRVAR(index_doc,
"rangeobject.index(value) -> integer -- return index of value.\n"
"Raise ValueError if the value is not present.");
static PyMethodDef range_methods[] = {
{"__reversed__", 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}
};
static PyMemberDef range_members[] = {
{"start", T_OBJECT_EX, offsetof(rangeobject, start), READONLY},
{"stop", T_OBJECT_EX, offsetof(rangeobject, stop), READONLY},
{"step", T_OBJECT_EX, offsetof(rangeobject, step), READONLY},
{0}
};
PyTypeObject PyRange_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"range",
sizeof(rangeobject),
0,
(destructor)range_dealloc,
0,
0,
0,
0,
(reprfunc)range_repr,
&range_as_number,
&range_as_sequence,
&range_as_mapping,
(hashfunc)range_hash,
0,
0,
PyObject_GenericGetAttr,
0,
0,
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_SEQUENCE,
range_doc,
0,
0,
range_richcompare,
0,
range_iter,
0,
range_methods,
range_members,
0,
0,
0,
0,
0,
0,
0,
0,
range_new,
.tp_vectorcall = (vectorcallfunc)range_vectorcall
};
static PyObject *
rangeiter_next(_PyRangeIterObject *r)
{
if (r->len > 0) {
long result = r->start;
r->start = result + r->step;
r->len--;
return PyLong_FromLong(result);
}
return NULL;
}
static PyObject *
rangeiter_len(_PyRangeIterObject *r, PyObject *Py_UNUSED(ignored))
{
return PyLong_FromLong(r->len);
}
PyDoc_STRVAR(length_hint_doc,
"Private method returning an estimate of len(list(it)).");
static PyObject *
rangeiter_reduce(_PyRangeIterObject *r, PyObject *Py_UNUSED(ignored))
{
PyObject *start=NULL, *stop=NULL, *step=NULL;
PyObject *range;
start = PyLong_FromLong(r->start);
if (start == NULL)
goto err;
stop = PyLong_FromLong(r->start + r->len * r->step);
if (stop == NULL)
goto err;
step = PyLong_FromLong(r->step);
if (step == NULL)
goto err;
range = (PyObject*)make_range_object(&PyRange_Type,
start, stop, step);
if (range == NULL)
goto err;
return Py_BuildValue("N(N)O", _PyEval_GetBuiltin(&_Py_ID(iter)),
range, Py_None);
err:
Py_XDECREF(start);
Py_XDECREF(stop);
Py_XDECREF(step);
return NULL;
}
static PyObject *
rangeiter_setstate(_PyRangeIterObject *r, PyObject *state)
{
long index = PyLong_AsLong(state);
if (index == -1 && PyErr_Occurred())
return NULL;
if (index < 0)
index = 0;
else if (index > r->len)
index = r->len;
r->start += index * r->step;
r->len -= index;
Py_RETURN_NONE;
}
PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
PyDoc_STRVAR(setstate_doc, "Set state information for unpickling.");
static PyMethodDef rangeiter_methods[] = {
{"__length_hint__", (PyCFunction)rangeiter_len, METH_NOARGS,
length_hint_doc},
{"__reduce__", (PyCFunction)rangeiter_reduce, METH_NOARGS,
reduce_doc},
{"__setstate__", (PyCFunction)rangeiter_setstate, METH_O,
setstate_doc},
{NULL, NULL}
};
PyTypeObject PyRangeIter_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"range_iterator",
sizeof(_PyRangeIterObject),
0,
(destructor)PyObject_Del,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
PyObject_GenericGetAttr,
0,
0,
Py_TPFLAGS_DEFAULT,
0,
0,
0,
0,
0,
PyObject_SelfIter,
(iternextfunc)rangeiter_next,
rangeiter_methods,
0,
};
static unsigned long
get_len_of_range(long lo, long hi, long step)
{
assert(step != 0);
if (step > 0 && lo < hi)
return 1UL + (hi - 1UL - lo) / step;
else if (step < 0 && lo > hi)
return 1UL + (lo - 1UL - hi) / (0UL - step);
else
return 0UL;
}
static PyObject *
fast_range_iter(long start, long stop, long step, long len)
{
_PyRangeIterObject *it = PyObject_New(_PyRangeIterObject, &PyRangeIter_Type);
if (it == NULL)
return NULL;
it->start = start;
it->step = step;
it->len = len;
return (PyObject *)it;
}
typedef struct {
PyObject_HEAD
PyObject *start;
PyObject *step;
PyObject *len;
} longrangeiterobject;
static PyObject *
longrangeiter_len(longrangeiterobject *r, PyObject *no_args)
{
Py_INCREF(r->len);
return r->len;
}
static PyObject *
longrangeiter_reduce(longrangeiterobject *r, PyObject *Py_UNUSED(ignored))
{
PyObject *product, *stop=NULL;
PyObject *range;
product = PyNumber_Multiply(r->len, r->step);
if (product == NULL)
return NULL;
stop = PyNumber_Add(r->start, product);
Py_DECREF(product);
if (stop == NULL)
return NULL;
range = (PyObject*)make_range_object(&PyRange_Type,
Py_NewRef(r->start), stop, Py_NewRef(r->step));
if (range == NULL) {
Py_DECREF(r->start);
Py_DECREF(stop);
Py_DECREF(r->step);
return NULL;
}
return Py_BuildValue("N(N)O", _PyEval_GetBuiltin(&_Py_ID(iter)),
range, Py_None);
}
static PyObject *
longrangeiter_setstate(longrangeiterobject *r, PyObject *state)
{
PyObject *zero = _PyLong_GetZero();
int cmp;
cmp = PyObject_RichCompareBool(state, zero, Py_LT);
if (cmp < 0)
return NULL;
if (cmp > 0) {
state = zero;
}
else {
cmp = PyObject_RichCompareBool(r->len, state, Py_LT);
if (cmp < 0)
return NULL;
if (cmp > 0)
state = r->len;
}
PyObject *product = PyNumber_Multiply(state, r->step);
if (product == NULL)
return NULL;
PyObject *new_start = PyNumber_Add(r->start, product);
Py_DECREF(product);
if (new_start == NULL)
return NULL;
PyObject *new_len = PyNumber_Subtract(r->len, state);
if (new_len == NULL) {
Py_DECREF(new_start);
return NULL;
}
PyObject *tmp = r->start;
r->start = new_start;
Py_SETREF(r->len, new_len);
Py_DECREF(tmp);
Py_RETURN_NONE;
}
static PyMethodDef longrangeiter_methods[] = {
{"__length_hint__", (PyCFunction)longrangeiter_len, METH_NOARGS,
length_hint_doc},
{"__reduce__", (PyCFunction)longrangeiter_reduce, METH_NOARGS,
reduce_doc},
{"__setstate__", (PyCFunction)longrangeiter_setstate, METH_O,
setstate_doc},
{NULL, NULL}
};
static void
longrangeiter_dealloc(longrangeiterobject *r)
{
Py_XDECREF(r->start);
Py_XDECREF(r->step);
Py_XDECREF(r->len);
PyObject_Free(r);
}
static PyObject *
longrangeiter_next(longrangeiterobject *r)
{
if (PyObject_RichCompareBool(r->len, _PyLong_GetZero(), Py_GT) != 1)
return NULL;
PyObject *new_start = PyNumber_Add(r->start, r->step);
if (new_start == NULL) {
return NULL;
}
PyObject *new_len = PyNumber_Subtract(r->len, _PyLong_GetOne());
if (new_len == NULL) {
Py_DECREF(new_start);
return NULL;
}
PyObject *result = r->start;
r->start = new_start;
Py_SETREF(r->len, new_len);
return result;
}
PyTypeObject PyLongRangeIter_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"longrange_iterator",
sizeof(longrangeiterobject),
0,
(destructor)longrangeiter_dealloc,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
PyObject_GenericGetAttr,
0,
0,
Py_TPFLAGS_DEFAULT,
0,
0,
0,
0,
0,
PyObject_SelfIter,
(iternextfunc)longrangeiter_next,
longrangeiter_methods,
0,
};
static PyObject *
range_iter(PyObject *seq)
{
rangeobject *r = (rangeobject *)seq;
longrangeiterobject *it;
long lstart, lstop, lstep;
unsigned long ulen;
assert(PyRange_Check(seq));
lstart = PyLong_AsLong(r->start);
if (lstart == -1 && PyErr_Occurred()) {
PyErr_Clear();
goto long_range;
}
lstop = PyLong_AsLong(r->stop);
if (lstop == -1 && PyErr_Occurred()) {
PyErr_Clear();
goto long_range;
}
lstep = PyLong_AsLong(r->step);
if (lstep == -1 && PyErr_Occurred()) {
PyErr_Clear();
goto long_range;
}
ulen = get_len_of_range(lstart, lstop, lstep);
if (ulen > (unsigned long)LONG_MAX) {
goto long_range;
}
if (ulen) {
if (lstep > 0) {
if (lstop > LONG_MAX - (lstep - 1))
goto long_range;
}
else {
if (lstop < LONG_MIN + (-1 - lstep))
goto long_range;
}
}
return fast_range_iter(lstart, lstop, lstep, (long)ulen);
long_range:
it = PyObject_New(longrangeiterobject, &PyLongRangeIter_Type);
if (it == NULL)
return NULL;
it->start = Py_NewRef(r->start);
it->step = Py_NewRef(r->step);
it->len = Py_NewRef(r->length);
return (PyObject *)it;
}
static PyObject *
range_reverse(PyObject *seq, PyObject *Py_UNUSED(ignored))
{
rangeobject *range = (rangeobject*) seq;
longrangeiterobject *it;
PyObject *sum, *diff, *product;
long lstart, lstop, lstep, new_start, new_stop;
unsigned long ulen;
assert(PyRange_Check(seq));
lstart = PyLong_AsLong(range->start);
if (lstart == -1 && PyErr_Occurred()) {
PyErr_Clear();
goto long_range;
}
lstop = PyLong_AsLong(range->stop);
if (lstop == -1 && PyErr_Occurred()) {
PyErr_Clear();
goto long_range;
}
lstep = PyLong_AsLong(range->step);
if (lstep == -1 && PyErr_Occurred()) {
PyErr_Clear();
goto long_range;
}
if (lstep == LONG_MIN)
goto long_range;
if (lstep > 0) {
if ((unsigned long)lstart - LONG_MIN < (unsigned long)lstep)
goto long_range;
}
else {
if (LONG_MAX - (unsigned long)lstart < 0UL - lstep)
goto long_range;
}
ulen = get_len_of_range(lstart, lstop, lstep);
if (ulen > (unsigned long)LONG_MAX)
goto long_range;
new_stop = lstart - lstep;
new_start = (long)(new_stop + ulen * lstep);
return fast_range_iter(new_start, new_stop, -lstep, (long)ulen);
long_range:
it = PyObject_New(longrangeiterobject, &PyLongRangeIter_Type);
if (it == NULL)
return NULL;
it->start = it->step = NULL;
it->len = Py_NewRef(range->length);
diff = PyNumber_Subtract(it->len, _PyLong_GetOne());
if (!diff)
goto create_failure;
product = PyNumber_Multiply(diff, range->step);
Py_DECREF(diff);
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)
goto create_failure;
return (PyObject *)it;
create_failure:
Py_DECREF(it);
return NULL;
}