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
;