blob: 76d384914e52adbc255f48e8b2d345c094a475c8 [file] [log] [blame]
Guido van Rossum12d12c51993-10-26 17:58:25 +00001/* Range object implementation */
2
Guido van Rossumc0b618a1997-05-02 03:12:38 +00003#include "Python.h"
Thomas Woutersefafcea2001-07-09 12:30:54 +00004
Guido van Rossum12d12c51993-10-26 17:58:25 +00005typedef struct {
Guido van Rossumc0b618a1997-05-02 03:12:38 +00006 PyObject_HEAD
Guido van Rossum12d12c51993-10-26 17:58:25 +00007 long start;
8 long step;
9 long len;
Guido van Rossum12d12c51993-10-26 17:58:25 +000010} rangeobject;
11
Raymond Hettingerc4c453f2002-06-05 23:12:45 +000012/* 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.
15 */
16static long
17get_len_of_range(long lo, long hi, long step)
18{
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 ---------------------------------------------------------------*/
31 long n = 0;
32 if (lo < hi) {
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);
37 }
38 return n;
39}
40
41static PyObject *
42range_new(PyTypeObject *type, PyObject *args, PyObject *kw)
43{
Tim Petersfeec4532004-08-08 07:17:39 +000044 rangeobject *obj;
Raymond Hettingerc4c453f2002-06-05 23:12:45 +000045 long ilow = 0, ihigh = 0, istep = 1;
46 long n;
47
Georg Brandl02c42872005-08-26 06:42:30 +000048 if (!_PyArg_NoKeywords("xrange()", kw))
49 return NULL;
50
Raymond Hettingerc4c453f2002-06-05 23:12:45 +000051 if (PyTuple_Size(args) <= 1) {
52 if (!PyArg_ParseTuple(args,
53 "l;xrange() requires 1-3 int arguments",
54 &ihigh))
55 return NULL;
56 }
57 else {
58 if (!PyArg_ParseTuple(args,
59 "ll|l;xrange() requires 1-3 int arguments",
60 &ilow, &ihigh, &istep))
61 return NULL;
62 }
63 if (istep == 0) {
64 PyErr_SetString(PyExc_ValueError, "xrange() arg 3 must not be zero");
65 return NULL;
66 }
67 if (istep > 0)
68 n = get_len_of_range(ilow, ihigh, istep);
69 else
70 n = get_len_of_range(ihigh, ilow, -istep);
71 if (n < 0) {
72 PyErr_SetString(PyExc_OverflowError,
73 "xrange() result has too many items");
74 return NULL;
75 }
Tim Petersfeec4532004-08-08 07:17:39 +000076
77 obj = PyObject_New(rangeobject, &PyRange_Type);
78 if (obj == NULL)
79 return NULL;
80 obj->start = ilow;
81 obj->len = n;
82 obj->step = istep;
83 return (PyObject *) obj;
Raymond Hettingerc4c453f2002-06-05 23:12:45 +000084}
85
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +000086PyDoc_STRVAR(range_doc,
Raymond Hettingerc4c453f2002-06-05 23:12:45 +000087"xrange([start,] stop[, step]) -> xrange object\n\
88\n\
89Like range(), but instead of returning a list, returns an object that\n\
Raymond Hettingerd2bef822002-12-11 07:14:03 +000090generates the numbers in the range on demand. For looping, this is \n\
91slightly faster than range() and more memory efficient.");
Raymond Hettingerc4c453f2002-06-05 23:12:45 +000092
Guido van Rossumc0b618a1997-05-02 03:12:38 +000093static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +000094range_item(rangeobject *r, Py_ssize_t i)
Guido van Rossum12d12c51993-10-26 17:58:25 +000095{
Fred Draked9018322002-05-02 19:56:55 +000096 if (i < 0 || i >= r->len) {
97 PyErr_SetString(PyExc_IndexError,
Guido van Rossum5dadf7e1999-01-09 21:40:35 +000098 "xrange object index out of range");
Fred Draked9018322002-05-02 19:56:55 +000099 return NULL;
100 }
Raymond Hettinger09131662008-02-08 22:30:04 +0000101 return PyInt_FromSsize_t(r->start + i * r->step);
Guido van Rossum12d12c51993-10-26 17:58:25 +0000102}
103
Martin v. Löwis18e16552006-02-15 17:27:45 +0000104static Py_ssize_t
Fred Drake45cfbcc2000-07-09 06:21:27 +0000105range_length(rangeobject *r)
Guido van Rossum12d12c51993-10-26 17:58:25 +0000106{
Martin v. Löwis18e16552006-02-15 17:27:45 +0000107 return (Py_ssize_t)(r->len);
Guido van Rossum7d6aa511993-12-21 22:50:31 +0000108}
109
Guido van Rossumc0b618a1997-05-02 03:12:38 +0000110static PyObject *
Fred Drake45cfbcc2000-07-09 06:21:27 +0000111range_repr(rangeobject *r)
Guido van Rossum12d12c51993-10-26 17:58:25 +0000112{
Barry Warsaw7ce36942001-08-24 18:34:26 +0000113 PyObject *rtn;
Tim Petersd976ab72004-08-08 06:29:10 +0000114
Tim Peters72d421b2000-08-04 03:05:40 +0000115 if (r->start == 0 && r->step == 1)
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000116 rtn = PyString_FromFormat("xrange(%ld)",
Barry Warsaw7ce36942001-08-24 18:34:26 +0000117 r->start + r->len * r->step);
Tim Peters72d421b2000-08-04 03:05:40 +0000118
119 else if (r->step == 1)
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000120 rtn = PyString_FromFormat("xrange(%ld, %ld)",
Barry Warsaw7ce36942001-08-24 18:34:26 +0000121 r->start,
122 r->start + r->len * r->step);
Tim Peters72d421b2000-08-04 03:05:40 +0000123
124 else
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000125 rtn = PyString_FromFormat("xrange(%ld, %ld, %ld)",
Barry Warsaw7ce36942001-08-24 18:34:26 +0000126 r->start,
127 r->start + r->len * r->step,
128 r->step);
Barry Warsaw7ce36942001-08-24 18:34:26 +0000129 return rtn;
Thomas Woutersefafcea2001-07-09 12:30:54 +0000130}
131
Alexandre Vassalotti1f2f61a2008-06-10 03:34:53 +0000132/* Pickling support */
133static PyObject *
Alexandre Vassalotti602d8db2008-06-10 04:01:23 +0000134range_reduce(rangeobject *r, PyObject *args)
Alexandre Vassalotti1f2f61a2008-06-10 03:34:53 +0000135{
Alexandre Vassalotti602d8db2008-06-10 04:01:23 +0000136 return Py_BuildValue("(O(iii))", Py_TYPE(r),
Alexandre Vassalotti1f2f61a2008-06-10 03:34:53 +0000137 r->start,
138 r->start + r->len * r->step,
139 r->step);
140}
141
Guido van Rossumc0b618a1997-05-02 03:12:38 +0000142static PySequenceMethods range_as_sequence = {
Martin v. Löwis18e16552006-02-15 17:27:45 +0000143 (lenfunc)range_length, /* sq_length */
Fred Draked9018322002-05-02 19:56:55 +0000144 0, /* sq_concat */
145 0, /* sq_repeat */
Martin v. Löwis18e16552006-02-15 17:27:45 +0000146 (ssizeargfunc)range_item, /* sq_item */
Fred Draked9018322002-05-02 19:56:55 +0000147 0, /* sq_slice */
Guido van Rossum12d12c51993-10-26 17:58:25 +0000148};
149
Jeremy Hylton938ace62002-07-17 16:30:39 +0000150static PyObject * range_iter(PyObject *seq);
Raymond Hettinger85c20a42003-11-06 14:06:48 +0000151static PyObject * range_reverse(PyObject *seq);
152
153PyDoc_STRVAR(reverse_doc,
154"Returns a reverse iterator.");
155
156static PyMethodDef range_methods[] = {
157 {"__reversed__", (PyCFunction)range_reverse, METH_NOARGS, reverse_doc},
Alexandre Vassalotti602d8db2008-06-10 04:01:23 +0000158 {"__reduce__", (PyCFunction)range_reduce, METH_VARARGS},
Raymond Hettinger85c20a42003-11-06 14:06:48 +0000159 {NULL, NULL} /* sentinel */
160};
Raymond Hettinger48165d42002-06-05 20:08:48 +0000161
Guido van Rossumc0b618a1997-05-02 03:12:38 +0000162PyTypeObject PyRange_Type = {
163 PyObject_HEAD_INIT(&PyType_Type)
Georg Brandl347b3002006-03-30 11:57:00 +0000164 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 */
169 0, /* tp_print */
170 0, /* tp_getattr */
171 0, /* tp_setattr */
172 0, /* tp_compare */
173 (reprfunc)range_repr, /* tp_repr */
174 0, /* tp_as_number */
175 &range_as_sequence, /* tp_as_sequence */
176 0, /* tp_as_mapping */
177 0, /* tp_hash */
178 0, /* tp_call */
179 0, /* tp_str */
180 PyObject_GenericGetAttr, /* tp_getattro */
181 0, /* tp_setattro */
182 0, /* tp_as_buffer */
183 Py_TPFLAGS_DEFAULT, /* tp_flags */
184 range_doc, /* tp_doc */
185 0, /* tp_traverse */
186 0, /* tp_clear */
187 0, /* tp_richcompare */
188 0, /* tp_weaklistoffset */
189 range_iter, /* tp_iter */
190 0, /* tp_iternext */
191 range_methods, /* tp_methods */
192 0, /* tp_members */
193 0, /* tp_getset */
194 0, /* tp_base */
195 0, /* tp_dict */
196 0, /* tp_descr_get */
197 0, /* tp_descr_set */
198 0, /* tp_dictoffset */
199 0, /* tp_init */
200 0, /* tp_alloc */
201 range_new, /* tp_new */
Guido van Rossum12d12c51993-10-26 17:58:25 +0000202};
Raymond Hettinger48165d42002-06-05 20:08:48 +0000203
204/*********************** Xrange Iterator **************************/
205
206typedef struct {
207 PyObject_HEAD
208 long index;
209 long start;
210 long step;
211 long len;
212} rangeiterobject;
213
Raymond Hettinger85c20a42003-11-06 14:06:48 +0000214static PyObject *
Raymond Hettinger48165d42002-06-05 20:08:48 +0000215rangeiter_next(rangeiterobject *r)
216{
Tim Petersd976ab72004-08-08 06:29:10 +0000217 if (r->index < r->len)
Raymond Hettinger48165d42002-06-05 20:08:48 +0000218 return PyInt_FromLong(r->start + (r->index++) * r->step);
Raymond Hettinger48165d42002-06-05 20:08:48 +0000219 return NULL;
220}
221
Raymond Hettinger6b27cda2005-09-24 21:23:05 +0000222static PyObject *
Raymond Hettingeref9bf402004-03-10 10:10:42 +0000223rangeiter_len(rangeiterobject *r)
224{
Raymond Hettinger6b27cda2005-09-24 21:23:05 +0000225 return PyInt_FromLong(r->len - r->index);
Raymond Hettingeref9bf402004-03-10 10:10:42 +0000226}
227
Armin Rigof5b3e362006-02-11 21:32:43 +0000228PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it)).");
Raymond Hettingeref9bf402004-03-10 10:10:42 +0000229
Raymond Hettinger6b27cda2005-09-24 21:23:05 +0000230static PyMethodDef rangeiter_methods[] = {
Armin Rigof5b3e362006-02-11 21:32:43 +0000231 {"__length_hint__", (PyCFunction)rangeiter_len, METH_NOARGS, length_hint_doc},
Raymond Hettinger6b27cda2005-09-24 21:23:05 +0000232 {NULL, NULL} /* sentinel */
233};
Raymond Hettingeref9bf402004-03-10 10:10:42 +0000234
Neal Norwitz56f46f82002-06-06 14:58:21 +0000235static PyTypeObject Pyrangeiter_Type = {
Raymond Hettinger48165d42002-06-05 20:08:48 +0000236 PyObject_HEAD_INIT(&PyType_Type)
237 0, /* ob_size */
Neal Norwitz56f46f82002-06-06 14:58:21 +0000238 "rangeiterator", /* tp_name */
239 sizeof(rangeiterobject), /* tp_basicsize */
Raymond Hettinger48165d42002-06-05 20:08:48 +0000240 0, /* tp_itemsize */
241 /* methods */
242 (destructor)PyObject_Del, /* tp_dealloc */
243 0, /* tp_print */
244 0, /* tp_getattr */
245 0, /* tp_setattr */
246 0, /* tp_compare */
247 0, /* tp_repr */
248 0, /* tp_as_number */
Raymond Hettinger6b27cda2005-09-24 21:23:05 +0000249 0, /* tp_as_sequence */
Raymond Hettinger48165d42002-06-05 20:08:48 +0000250 0, /* tp_as_mapping */
251 0, /* tp_hash */
252 0, /* tp_call */
253 0, /* tp_str */
254 PyObject_GenericGetAttr, /* tp_getattro */
255 0, /* tp_setattro */
256 0, /* tp_as_buffer */
257 Py_TPFLAGS_DEFAULT, /* tp_flags */
258 0, /* tp_doc */
259 0, /* tp_traverse */
260 0, /* tp_clear */
261 0, /* tp_richcompare */
262 0, /* tp_weaklistoffset */
Raymond Hettinger1da1dbf2003-03-17 19:46:11 +0000263 PyObject_SelfIter, /* tp_iter */
Raymond Hettinger48165d42002-06-05 20:08:48 +0000264 (iternextfunc)rangeiter_next, /* tp_iternext */
Raymond Hettinger6b27cda2005-09-24 21:23:05 +0000265 rangeiter_methods, /* tp_methods */
266 0,
Raymond Hettinger48165d42002-06-05 20:08:48 +0000267};
Martin v. Löwis72d20672006-04-11 09:04:12 +0000268
269static PyObject *
270range_iter(PyObject *seq)
271{
272 rangeiterobject *it;
273
274 if (!PyRange_Check(seq)) {
275 PyErr_BadInternalCall();
276 return NULL;
277 }
278 it = PyObject_New(rangeiterobject, &Pyrangeiter_Type);
279 if (it == NULL)
280 return NULL;
281 it->index = 0;
282 it->start = ((rangeobject *)seq)->start;
283 it->step = ((rangeobject *)seq)->step;
284 it->len = ((rangeobject *)seq)->len;
285 return (PyObject *)it;
286}
287
288static PyObject *
289range_reverse(PyObject *seq)
290{
291 rangeiterobject *it;
292 long start, step, len;
293
294 if (!PyRange_Check(seq)) {
295 PyErr_BadInternalCall();
296 return NULL;
297 }
298 it = PyObject_New(rangeiterobject, &Pyrangeiter_Type);
299 if (it == NULL)
300 return NULL;
301
302 start = ((rangeobject *)seq)->start;
303 step = ((rangeobject *)seq)->step;
304 len = ((rangeobject *)seq)->len;
305
306 it->index = 0;
307 it->start = start + (len-1) * step;
308 it->step = -step;
309 it->len = len;
310
311 return (PyObject *)it;
312}