1
/* Range object implementation */
12
/* Return number of items in range/xrange (lo, hi, step). step > 0
13
* required. Return a value < 0 if & only if the true value is too
14
* large to fit in a signed long.
17
get_len_of_range(long lo, long hi, long step)
19
/* -------------------------------------------------------------
20
If lo >= hi, the range is empty.
21
Else if n values are in the range, the last one is
22
lo + (n-1)*step, which must be <= hi-1. Rearranging,
23
n <= (hi - lo - 1)/step + 1, so taking the floor of the RHS gives
24
the proper value. Since lo < hi in this case, hi-lo-1 >= 0, so
25
the RHS is non-negative and so truncation is the same as the
26
floor. Letting M be the largest positive long, the worst case
27
for the RHS numerator is hi=M, lo=-M-1, and then
28
hi-lo-1 = M-(-M-1)-1 = 2*M. Therefore unsigned long has enough
29
precision to compute the RHS exactly.
30
---------------------------------------------------------------*/
33
unsigned long uhi = (unsigned long)hi;
34
unsigned long ulo = (unsigned long)lo;
35
unsigned long diff = uhi - ulo - 1;
36
n = (long)(diff / (unsigned long)step + 1);
42
range_new(PyTypeObject *type, PyObject *args, PyObject *kw)
45
long ilow = 0, ihigh = 0, istep = 1;
48
if (!_PyArg_NoKeywords("xrange()", kw))
51
if (PyTuple_Size(args) <= 1) {
52
if (!PyArg_ParseTuple(args,
53
"l;xrange() requires 1-3 int arguments",
58
if (!PyArg_ParseTuple(args,
59
"ll|l;xrange() requires 1-3 int arguments",
60
&ilow, &ihigh, &istep))
64
PyErr_SetString(PyExc_ValueError, "xrange() arg 3 must not be zero");
68
n = get_len_of_range(ilow, ihigh, istep);
70
n = get_len_of_range(ihigh, ilow, -istep);
72
PyErr_SetString(PyExc_OverflowError,
73
"xrange() result has too many items");
77
obj = PyObject_New(rangeobject, &PyRange_Type);
83
return (PyObject *) obj;
86
PyDoc_STRVAR(range_doc,
87
"xrange([start,] stop[, step]) -> xrange object\n\
89
Like range(), but instead of returning a list, returns an object that\n\
90
generates the numbers in the range on demand. For looping, this is \n\
91
slightly faster than range() and more memory efficient.");
94
range_item(rangeobject *r, Py_ssize_t i)
96
if (i < 0 || i >= r->len) {
97
PyErr_SetString(PyExc_IndexError,
98
"xrange object index out of range");
101
return PyInt_FromSsize_t(r->start + i * r->step);
105
range_length(rangeobject *r)
107
return (Py_ssize_t)(r->len);
111
range_repr(rangeobject *r)
115
if (r->start == 0 && r->step == 1)
116
rtn = PyString_FromFormat("xrange(%ld)",
117
r->start + r->len * r->step);
119
else if (r->step == 1)
120
rtn = PyString_FromFormat("xrange(%ld, %ld)",
122
r->start + r->len * r->step);
125
rtn = PyString_FromFormat("xrange(%ld, %ld, %ld)",
127
r->start + r->len * r->step,
132
/* Pickling support */
134
range_reduce(rangeobject *r, PyObject *args)
136
return Py_BuildValue("(O(iii))", Py_TYPE(r),
138
r->start + r->len * r->step,
142
static PySequenceMethods range_as_sequence = {
143
(lenfunc)range_length, /* sq_length */
146
(ssizeargfunc)range_item, /* sq_item */
150
static PyObject * range_iter(PyObject *seq);
151
static PyObject * range_reverse(PyObject *seq);
153
PyDoc_STRVAR(reverse_doc,
154
"Returns a reverse iterator.");
156
static PyMethodDef range_methods[] = {
157
{"__reversed__", (PyCFunction)range_reverse, METH_NOARGS, reverse_doc},
158
{"__reduce__", (PyCFunction)range_reduce, METH_VARARGS},
159
{NULL, NULL} /* sentinel */
162
PyTypeObject PyRange_Type = {
163
PyObject_HEAD_INIT(&PyType_Type)
164
0, /* Number of items for varobject */
165
"xrange", /* Name of this type */
166
sizeof(rangeobject), /* Basic object size */
167
0, /* Item size for varobject */
168
(destructor)PyObject_Del, /* tp_dealloc */
173
(reprfunc)range_repr, /* tp_repr */
174
0, /* tp_as_number */
175
&range_as_sequence, /* tp_as_sequence */
176
0, /* tp_as_mapping */
180
PyObject_GenericGetAttr, /* tp_getattro */
182
0, /* tp_as_buffer */
183
Py_TPFLAGS_DEFAULT, /* tp_flags */
184
range_doc, /* tp_doc */
187
0, /* tp_richcompare */
188
0, /* tp_weaklistoffset */
189
range_iter, /* tp_iter */
191
range_methods, /* tp_methods */
196
0, /* tp_descr_get */
197
0, /* tp_descr_set */
198
0, /* tp_dictoffset */
201
range_new, /* tp_new */
204
/*********************** Xrange Iterator **************************/
215
rangeiter_next(rangeiterobject *r)
217
if (r->index < r->len)
218
return PyInt_FromLong(r->start + (r->index++) * r->step);
223
rangeiter_len(rangeiterobject *r)
225
return PyInt_FromLong(r->len - r->index);
228
PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it)).");
230
static PyMethodDef rangeiter_methods[] = {
231
{"__length_hint__", (PyCFunction)rangeiter_len, METH_NOARGS, length_hint_doc},
232
{NULL, NULL} /* sentinel */
235
static PyTypeObject Pyrangeiter_Type = {
236
PyObject_HEAD_INIT(&PyType_Type)
238
"rangeiterator", /* tp_name */
239
sizeof(rangeiterobject), /* tp_basicsize */
242
(destructor)PyObject_Del, /* tp_dealloc */
248
0, /* tp_as_number */
249
0, /* tp_as_sequence */
250
0, /* tp_as_mapping */
254
PyObject_GenericGetAttr, /* tp_getattro */
256
0, /* tp_as_buffer */
257
Py_TPFLAGS_DEFAULT, /* tp_flags */
261
0, /* tp_richcompare */
262
0, /* tp_weaklistoffset */
263
PyObject_SelfIter, /* tp_iter */
264
(iternextfunc)rangeiter_next, /* tp_iternext */
265
rangeiter_methods, /* tp_methods */
270
range_iter(PyObject *seq)
274
if (!PyRange_Check(seq)) {
275
PyErr_BadInternalCall();
278
it = PyObject_New(rangeiterobject, &Pyrangeiter_Type);
282
it->start = ((rangeobject *)seq)->start;
283
it->step = ((rangeobject *)seq)->step;
284
it->len = ((rangeobject *)seq)->len;
285
return (PyObject *)it;
289
range_reverse(PyObject *seq)
292
long start, step, len;
294
if (!PyRange_Check(seq)) {
295
PyErr_BadInternalCall();
298
it = PyObject_New(rangeiterobject, &Pyrangeiter_Type);
302
start = ((rangeobject *)seq)->start;
303
step = ((rangeobject *)seq)->step;
304
len = ((rangeobject *)seq)->len;
307
it->start = start + (len-1) * step;
311
return (PyObject *)it;