blob: 2f5d164d9a815e72d251f95a808bdb48f95e5445 [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
48 if (PyTuple_Size(args) <= 1) {
49 if (!PyArg_ParseTuple(args,
50 "l;xrange() requires 1-3 int arguments",
51 &ihigh))
52 return NULL;
53 }
54 else {
55 if (!PyArg_ParseTuple(args,
56 "ll|l;xrange() requires 1-3 int arguments",
57 &ilow, &ihigh, &istep))
58 return NULL;
59 }
60 if (istep == 0) {
61 PyErr_SetString(PyExc_ValueError, "xrange() arg 3 must not be zero");
62 return NULL;
63 }
64 if (istep > 0)
65 n = get_len_of_range(ilow, ihigh, istep);
66 else
67 n = get_len_of_range(ihigh, ilow, -istep);
68 if (n < 0) {
69 PyErr_SetString(PyExc_OverflowError,
70 "xrange() result has too many items");
71 return NULL;
72 }
Tim Petersfeec4532004-08-08 07:17:39 +000073
74 obj = PyObject_New(rangeobject, &PyRange_Type);
75 if (obj == NULL)
76 return NULL;
77 obj->start = ilow;
78 obj->len = n;
79 obj->step = istep;
80 return (PyObject *) obj;
Raymond Hettingerc4c453f2002-06-05 23:12:45 +000081}
82
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +000083PyDoc_STRVAR(range_doc,
Raymond Hettingerc4c453f2002-06-05 23:12:45 +000084"xrange([start,] stop[, step]) -> xrange object\n\
85\n\
86Like range(), but instead of returning a list, returns an object that\n\
Raymond Hettingerd2bef822002-12-11 07:14:03 +000087generates the numbers in the range on demand. For looping, this is \n\
88slightly faster than range() and more memory efficient.");
Raymond Hettingerc4c453f2002-06-05 23:12:45 +000089
Guido van Rossumc0b618a1997-05-02 03:12:38 +000090static PyObject *
Fred Drake45cfbcc2000-07-09 06:21:27 +000091range_item(rangeobject *r, int i)
Guido van Rossum12d12c51993-10-26 17:58:25 +000092{
Fred Draked9018322002-05-02 19:56:55 +000093 if (i < 0 || i >= r->len) {
94 PyErr_SetString(PyExc_IndexError,
Guido van Rossum5dadf7e1999-01-09 21:40:35 +000095 "xrange object index out of range");
Fred Draked9018322002-05-02 19:56:55 +000096 return NULL;
97 }
Guido van Rossumc0b618a1997-05-02 03:12:38 +000098 return PyInt_FromLong(r->start + (i % r->len) * r->step);
Guido van Rossum12d12c51993-10-26 17:58:25 +000099}
100
101static int
Fred Drake45cfbcc2000-07-09 06:21:27 +0000102range_length(rangeobject *r)
Guido van Rossum12d12c51993-10-26 17:58:25 +0000103{
Guido van Rossumd4774fb2002-09-11 15:55:48 +0000104#if LONG_MAX != INT_MAX
105 if (r->len > INT_MAX) {
106 PyErr_SetString(PyExc_ValueError,
107 "xrange object size cannot be reported");
108 return -1;
109 }
110#endif
111 return (int)(r->len);
Guido van Rossum7d6aa511993-12-21 22:50:31 +0000112}
113
Guido van Rossumc0b618a1997-05-02 03:12:38 +0000114static PyObject *
Fred Drake45cfbcc2000-07-09 06:21:27 +0000115range_repr(rangeobject *r)
Guido van Rossum12d12c51993-10-26 17:58:25 +0000116{
Barry Warsaw7ce36942001-08-24 18:34:26 +0000117 PyObject *rtn;
Tim Petersd976ab72004-08-08 06:29:10 +0000118
Tim Peters72d421b2000-08-04 03:05:40 +0000119 if (r->start == 0 && r->step == 1)
Barry Warsaw7ce36942001-08-24 18:34:26 +0000120 rtn = PyString_FromFormat("xrange(%ld)",
121 r->start + r->len * r->step);
Tim Peters72d421b2000-08-04 03:05:40 +0000122
123 else if (r->step == 1)
Barry Warsaw7ce36942001-08-24 18:34:26 +0000124 rtn = PyString_FromFormat("xrange(%ld, %ld)",
125 r->start,
126 r->start + r->len * r->step);
Tim Peters72d421b2000-08-04 03:05:40 +0000127
128 else
Barry Warsaw7ce36942001-08-24 18:34:26 +0000129 rtn = PyString_FromFormat("xrange(%ld, %ld, %ld)",
130 r->start,
131 r->start + r->len * r->step,
132 r->step);
Barry Warsaw7ce36942001-08-24 18:34:26 +0000133 return rtn;
Thomas Woutersefafcea2001-07-09 12:30:54 +0000134}
135
Guido van Rossumc0b618a1997-05-02 03:12:38 +0000136static PySequenceMethods range_as_sequence = {
Fred Draked9018322002-05-02 19:56:55 +0000137 (inquiry)range_length, /* sq_length */
138 0, /* sq_concat */
139 0, /* sq_repeat */
140 (intargfunc)range_item, /* sq_item */
141 0, /* sq_slice */
Guido van Rossum12d12c51993-10-26 17:58:25 +0000142};
143
Jeremy Hylton938ace62002-07-17 16:30:39 +0000144static PyObject * range_iter(PyObject *seq);
Raymond Hettinger85c20a42003-11-06 14:06:48 +0000145static PyObject * range_reverse(PyObject *seq);
146
147PyDoc_STRVAR(reverse_doc,
148"Returns a reverse iterator.");
149
150static PyMethodDef range_methods[] = {
151 {"__reversed__", (PyCFunction)range_reverse, METH_NOARGS, reverse_doc},
152 {NULL, NULL} /* sentinel */
153};
Raymond Hettinger48165d42002-06-05 20:08:48 +0000154
Guido van Rossumc0b618a1997-05-02 03:12:38 +0000155PyTypeObject PyRange_Type = {
156 PyObject_HEAD_INIT(&PyType_Type)
Fred Draked9018322002-05-02 19:56:55 +0000157 0, /* Number of items for varobject */
158 "xrange", /* Name of this type */
159 sizeof(rangeobject), /* Basic object size */
160 0, /* Item size for varobject */
161 (destructor)PyObject_Del, /* tp_dealloc */
162 0, /* tp_print */
163 0, /* tp_getattr */
164 0, /* tp_setattr */
165 0, /* tp_compare */
166 (reprfunc)range_repr, /* tp_repr */
167 0, /* tp_as_number */
168 &range_as_sequence, /* tp_as_sequence */
169 0, /* tp_as_mapping */
170 0, /* tp_hash */
171 0, /* tp_call */
172 0, /* tp_str */
Raymond Hettinger5ae8e012002-11-07 16:55:54 +0000173 PyObject_GenericGetAttr, /* tp_getattro */
Fred Draked9018322002-05-02 19:56:55 +0000174 0, /* tp_setattro */
175 0, /* tp_as_buffer */
176 Py_TPFLAGS_DEFAULT, /* tp_flags */
Raymond Hettingerc4c453f2002-06-05 23:12:45 +0000177 range_doc, /* tp_doc */
Martin v. Löwise4526592002-05-08 08:49:27 +0000178 0, /* tp_traverse */
179 0, /* tp_clear */
180 0, /* tp_richcompare */
181 0, /* tp_weaklistoffset */
Raymond Hettingerc4c453f2002-06-05 23:12:45 +0000182 (getiterfunc)range_iter, /* tp_iter */
183 0, /* tp_iternext */
Tim Petersd976ab72004-08-08 06:29:10 +0000184 range_methods, /* tp_methods */
Raymond Hettingerc4c453f2002-06-05 23:12:45 +0000185 0, /* tp_members */
186 0, /* tp_getset */
187 0, /* tp_base */
188 0, /* tp_dict */
189 0, /* tp_descr_get */
190 0, /* tp_descr_set */
191 0, /* tp_dictoffset */
192 0, /* tp_init */
193 0, /* tp_alloc */
194 range_new, /* tp_new */
Guido van Rossum12d12c51993-10-26 17:58:25 +0000195};
Raymond Hettinger48165d42002-06-05 20:08:48 +0000196
197/*********************** Xrange Iterator **************************/
198
199typedef struct {
200 PyObject_HEAD
201 long index;
202 long start;
203 long step;
204 long len;
205} rangeiterobject;
206
Jeremy Hylton938ace62002-07-17 16:30:39 +0000207static PyTypeObject Pyrangeiter_Type;
Raymond Hettinger48165d42002-06-05 20:08:48 +0000208
Neal Norwitz56f46f82002-06-06 14:58:21 +0000209static PyObject *
Raymond Hettinger48165d42002-06-05 20:08:48 +0000210range_iter(PyObject *seq)
211{
212 rangeiterobject *it;
213
214 if (!PyRange_Check(seq)) {
215 PyErr_BadInternalCall();
216 return NULL;
217 }
218 it = PyObject_New(rangeiterobject, &Pyrangeiter_Type);
219 if (it == NULL)
220 return NULL;
221 it->index = 0;
222 it->start = ((rangeobject *)seq)->start;
223 it->step = ((rangeobject *)seq)->step;
224 it->len = ((rangeobject *)seq)->len;
225 return (PyObject *)it;
226}
227
228static PyObject *
Raymond Hettinger85c20a42003-11-06 14:06:48 +0000229range_reverse(PyObject *seq)
230{
231 rangeiterobject *it;
232 long start, step, len;
233
234 if (!PyRange_Check(seq)) {
235 PyErr_BadInternalCall();
236 return NULL;
237 }
238 it = PyObject_New(rangeiterobject, &Pyrangeiter_Type);
239 if (it == NULL)
240 return NULL;
241
242 start = ((rangeobject *)seq)->start;
243 step = ((rangeobject *)seq)->step;
244 len = ((rangeobject *)seq)->len;
245
246 it->index = 0;
247 it->start = start + (len-1) * step;
248 it->step = -step;
249 it->len = len;
250
251 return (PyObject *)it;
252}
253
254static PyObject *
Raymond Hettinger48165d42002-06-05 20:08:48 +0000255rangeiter_next(rangeiterobject *r)
256{
Tim Petersd976ab72004-08-08 06:29:10 +0000257 if (r->index < r->len)
Raymond Hettinger48165d42002-06-05 20:08:48 +0000258 return PyInt_FromLong(r->start + (r->index++) * r->step);
Raymond Hettinger48165d42002-06-05 20:08:48 +0000259 return NULL;
260}
261
Raymond Hettingeref9bf402004-03-10 10:10:42 +0000262static int
263rangeiter_len(rangeiterobject *r)
264{
265 return r->len - r->index;
266}
267
268static PySequenceMethods rangeiter_as_sequence = {
269 (inquiry)rangeiter_len, /* sq_length */
270 0, /* sq_concat */
271};
272
273
Neal Norwitz56f46f82002-06-06 14:58:21 +0000274static PyTypeObject Pyrangeiter_Type = {
Raymond Hettinger48165d42002-06-05 20:08:48 +0000275 PyObject_HEAD_INIT(&PyType_Type)
276 0, /* ob_size */
Neal Norwitz56f46f82002-06-06 14:58:21 +0000277 "rangeiterator", /* tp_name */
278 sizeof(rangeiterobject), /* tp_basicsize */
Raymond Hettinger48165d42002-06-05 20:08:48 +0000279 0, /* tp_itemsize */
280 /* methods */
281 (destructor)PyObject_Del, /* tp_dealloc */
282 0, /* tp_print */
283 0, /* tp_getattr */
284 0, /* tp_setattr */
285 0, /* tp_compare */
286 0, /* tp_repr */
287 0, /* tp_as_number */
Raymond Hettingeref9bf402004-03-10 10:10:42 +0000288 &rangeiter_as_sequence, /* tp_as_sequence */
Raymond Hettinger48165d42002-06-05 20:08:48 +0000289 0, /* tp_as_mapping */
290 0, /* tp_hash */
291 0, /* tp_call */
292 0, /* tp_str */
293 PyObject_GenericGetAttr, /* tp_getattro */
294 0, /* tp_setattro */
295 0, /* tp_as_buffer */
296 Py_TPFLAGS_DEFAULT, /* tp_flags */
297 0, /* tp_doc */
298 0, /* tp_traverse */
299 0, /* tp_clear */
300 0, /* tp_richcompare */
301 0, /* tp_weaklistoffset */
Raymond Hettinger1da1dbf2003-03-17 19:46:11 +0000302 PyObject_SelfIter, /* tp_iter */
Raymond Hettinger48165d42002-06-05 20:08:48 +0000303 (iternextfunc)rangeiter_next, /* tp_iternext */
Guido van Rossum86d593e2002-07-16 20:47:50 +0000304 0, /* tp_methods */
Raymond Hettinger48165d42002-06-05 20:08:48 +0000305};