typedef struct {
PyObject_HEAD
long start;
long step;
long len;
} rangeobject;
/* 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;
}
if (!_PyArg_NoKeywords("xrange()", kw))
return NULL;
if (PyTuple_Size(args) <= 1) {
if (!PyArg_ParseTuple(args,
"l;xrange() requires 1-3 int arguments",
&ihigh))
return NULL;
}
else {
if (!PyArg_ParseTuple(args,
"ll|l;xrange() requires 1-3 int arguments",
&ilow, &ihigh, &istep))
return NULL;
}
if (istep == 0) {
PyErr_SetString(PyExc_ValueError, "xrange() arg 3 must not be zero");
return NULL;
}
if (istep > 0)
n = get_len_of_range(ilow, ihigh, istep);
else
n = get_len_of_range(ihigh, ilow, -istep);
if (n < 0) {
PyErr_SetString(PyExc_OverflowError,
"xrange() result has too many items");
return NULL;
}
PyDoc_STRVAR(range_doc,
"xrange([start,] stop[, step]) -> xrange object\n\
\n\
Like range(), but instead of returning a list, returns an object that\n\
generates the numbers in the range on demand. For looping, this is \n\
slightly faster than range() and more memory efficient.");
static PyObject *
range_item(rangeobject *r, Py_ssize_t i)
{
if (i < 0 || i >= r->len) {
PyErr_SetString(PyExc_IndexError,
"xrange object index out of range");
return NULL;
}
return PyInt_FromSsize_t(r->start + (i % r->len) * r->step);
}