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 static PySequenceMethods range_as_sequence
= {
133 (lenfunc
)range_length
, /* sq_length */
136 (ssizeargfunc
)range_item
, /* sq_item */
140 static PyObject
* range_iter(PyObject
*seq
);
141 static PyObject
* range_reverse(PyObject
*seq
);
143 PyDoc_STRVAR(reverse_doc
,
144 "Returns a reverse iterator.");
146 static PyMethodDef range_methods
[] = {
147 {"__reversed__", (PyCFunction
)range_reverse
, METH_NOARGS
, reverse_doc
},
148 {NULL
, NULL
} /* sentinel */
151 PyTypeObject PyRange_Type
= {
152 PyObject_HEAD_INIT(&PyType_Type
)
153 0, /* Number of items for varobject */
154 "xrange", /* Name of this type */
155 sizeof(rangeobject
), /* Basic object size */
156 0, /* Item size for varobject */
157 (destructor
)PyObject_Del
, /* tp_dealloc */
162 (reprfunc
)range_repr
, /* tp_repr */
163 0, /* tp_as_number */
164 &range_as_sequence
, /* tp_as_sequence */
165 0, /* tp_as_mapping */
169 PyObject_GenericGetAttr
, /* tp_getattro */
171 0, /* tp_as_buffer */
172 Py_TPFLAGS_DEFAULT
, /* tp_flags */
173 range_doc
, /* tp_doc */
176 0, /* tp_richcompare */
177 0, /* tp_weaklistoffset */
178 range_iter
, /* tp_iter */
180 range_methods
, /* tp_methods */
185 0, /* tp_descr_get */
186 0, /* tp_descr_set */
187 0, /* tp_dictoffset */
190 range_new
, /* tp_new */
193 /*********************** Xrange Iterator **************************/
204 rangeiter_next(rangeiterobject
*r
)
206 if (r
->index
< r
->len
)
207 return PyInt_FromLong(r
->start
+ (r
->index
++) * r
->step
);
212 rangeiter_len(rangeiterobject
*r
)
214 return PyInt_FromLong(r
->len
- r
->index
);
217 PyDoc_STRVAR(length_hint_doc
, "Private method returning an estimate of len(list(it)).");
219 static PyMethodDef rangeiter_methods
[] = {
220 {"__length_hint__", (PyCFunction
)rangeiter_len
, METH_NOARGS
, length_hint_doc
},
221 {NULL
, NULL
} /* sentinel */
224 static PyTypeObject Pyrangeiter_Type
= {
225 PyObject_HEAD_INIT(&PyType_Type
)
227 "rangeiterator", /* tp_name */
228 sizeof(rangeiterobject
), /* tp_basicsize */
231 (destructor
)PyObject_Del
, /* tp_dealloc */
237 0, /* tp_as_number */
238 0, /* tp_as_sequence */
239 0, /* tp_as_mapping */
243 PyObject_GenericGetAttr
, /* tp_getattro */
245 0, /* tp_as_buffer */
246 Py_TPFLAGS_DEFAULT
, /* tp_flags */
250 0, /* tp_richcompare */
251 0, /* tp_weaklistoffset */
252 PyObject_SelfIter
, /* tp_iter */
253 (iternextfunc
)rangeiter_next
, /* tp_iternext */
254 rangeiter_methods
, /* tp_methods */
259 range_iter(PyObject
*seq
)
263 if (!PyRange_Check(seq
)) {
264 PyErr_BadInternalCall();
267 it
= PyObject_New(rangeiterobject
, &Pyrangeiter_Type
);
271 it
->start
= ((rangeobject
*)seq
)->start
;
272 it
->step
= ((rangeobject
*)seq
)->step
;
273 it
->len
= ((rangeobject
*)seq
)->len
;
274 return (PyObject
*)it
;
278 range_reverse(PyObject
*seq
)
281 long start
, step
, len
;
283 if (!PyRange_Check(seq
)) {
284 PyErr_BadInternalCall();
287 it
= PyObject_New(rangeiterobject
, &Pyrangeiter_Type
);
291 start
= ((rangeobject
*)seq
)->start
;
292 step
= ((rangeobject
*)seq
)->step
;
293 len
= ((rangeobject
*)seq
)->len
;
296 it
->start
= start
+ (len
-1) * step
;
300 return (PyObject
*)it
;