]>
Commit | Line | Data |
---|---|---|
53b2ba57 DM |
1 | /* Range object implementation */\r |
2 | \r | |
3 | #include "Python.h"\r | |
4 | \r | |
5 | typedef struct {\r | |
6 | PyObject_HEAD\r | |
7 | long start;\r | |
8 | long step;\r | |
9 | long len;\r | |
10 | } rangeobject;\r | |
11 | \r | |
12 | /* Return number of items in range (lo, hi, step). step != 0\r | |
13 | * required. The result always fits in an unsigned long.\r | |
14 | */\r | |
15 | static unsigned long\r | |
16 | get_len_of_range(long lo, long hi, long step)\r | |
17 | {\r | |
18 | /* -------------------------------------------------------------\r | |
19 | If step > 0 and lo >= hi, or step < 0 and lo <= hi, the range is empty.\r | |
20 | Else for step > 0, if n values are in the range, the last one is\r | |
21 | lo + (n-1)*step, which must be <= hi-1. Rearranging,\r | |
22 | n <= (hi - lo - 1)/step + 1, so taking the floor of the RHS gives\r | |
23 | the proper value. Since lo < hi in this case, hi-lo-1 >= 0, so\r | |
24 | the RHS is non-negative and so truncation is the same as the\r | |
25 | floor. Letting M be the largest positive long, the worst case\r | |
26 | for the RHS numerator is hi=M, lo=-M-1, and then\r | |
27 | hi-lo-1 = M-(-M-1)-1 = 2*M. Therefore unsigned long has enough\r | |
28 | precision to compute the RHS exactly. The analysis for step < 0\r | |
29 | is similar.\r | |
30 | ---------------------------------------------------------------*/\r | |
31 | assert(step != 0);\r | |
32 | if (step > 0 && lo < hi)\r | |
33 | return 1UL + (hi - 1UL - lo) / step;\r | |
34 | else if (step < 0 && lo > hi)\r | |
35 | return 1UL + (lo - 1UL - hi) / (0UL - step);\r | |
36 | else\r | |
37 | return 0UL;\r | |
38 | }\r | |
39 | \r | |
40 | /* Return a stop value suitable for reconstructing the xrange from\r | |
41 | * a (start, stop, step) triple. Used in range_repr and range_reduce.\r | |
42 | * Computes start + len * step, clipped to the range [LONG_MIN, LONG_MAX].\r | |
43 | */\r | |
44 | static long\r | |
45 | get_stop_for_range(rangeobject *r)\r | |
46 | {\r | |
47 | long last;\r | |
48 | \r | |
49 | if (r->len == 0)\r | |
50 | return r->start;\r | |
51 | \r | |
52 | /* The tricky bit is avoiding overflow. We first compute the last entry in\r | |
53 | the xrange, start + (len - 1) * step, which is guaranteed to lie within\r | |
54 | the range of a long, and then add step to it. See the range_reverse\r | |
55 | comments for an explanation of the casts below.\r | |
56 | */\r | |
57 | last = (long)(r->start + (unsigned long)(r->len - 1) * r->step);\r | |
58 | if (r->step > 0)\r | |
59 | return last > LONG_MAX - r->step ? LONG_MAX : last + r->step;\r | |
60 | else\r | |
61 | return last < LONG_MIN - r->step ? LONG_MIN : last + r->step;\r | |
62 | }\r | |
63 | \r | |
64 | static PyObject *\r | |
65 | range_new(PyTypeObject *type, PyObject *args, PyObject *kw)\r | |
66 | {\r | |
67 | rangeobject *obj;\r | |
68 | long ilow = 0, ihigh = 0, istep = 1;\r | |
69 | unsigned long n;\r | |
70 | \r | |
71 | if (!_PyArg_NoKeywords("xrange()", kw))\r | |
72 | return NULL;\r | |
73 | \r | |
74 | if (PyTuple_Size(args) <= 1) {\r | |
75 | if (!PyArg_ParseTuple(args,\r | |
76 | "l;xrange() requires 1-3 int arguments",\r | |
77 | &ihigh))\r | |
78 | return NULL;\r | |
79 | }\r | |
80 | else {\r | |
81 | if (!PyArg_ParseTuple(args,\r | |
82 | "ll|l;xrange() requires 1-3 int arguments",\r | |
83 | &ilow, &ihigh, &istep))\r | |
84 | return NULL;\r | |
85 | }\r | |
86 | if (istep == 0) {\r | |
87 | PyErr_SetString(PyExc_ValueError, "xrange() arg 3 must not be zero");\r | |
88 | return NULL;\r | |
89 | }\r | |
90 | n = get_len_of_range(ilow, ihigh, istep);\r | |
91 | if (n > (unsigned long)LONG_MAX || (long)n > PY_SSIZE_T_MAX) {\r | |
92 | PyErr_SetString(PyExc_OverflowError,\r | |
93 | "xrange() result has too many items");\r | |
94 | return NULL;\r | |
95 | }\r | |
96 | \r | |
97 | obj = PyObject_New(rangeobject, &PyRange_Type);\r | |
98 | if (obj == NULL)\r | |
99 | return NULL;\r | |
100 | obj->start = ilow;\r | |
101 | obj->len = (long)n;\r | |
102 | obj->step = istep;\r | |
103 | return (PyObject *) obj;\r | |
104 | }\r | |
105 | \r | |
106 | PyDoc_STRVAR(range_doc,\r | |
107 | "xrange(stop) -> xrange object\n\\r | |
108 | xrange(start, stop[, step]) -> xrange object\n\\r | |
109 | \n\\r | |
110 | Like range(), but instead of returning a list, returns an object that\n\\r | |
111 | generates the numbers in the range on demand. For looping, this is \n\\r | |
112 | slightly faster than range() and more memory efficient.");\r | |
113 | \r | |
114 | static PyObject *\r | |
115 | range_item(rangeobject *r, Py_ssize_t i)\r | |
116 | {\r | |
117 | if (i < 0 || i >= r->len) {\r | |
118 | PyErr_SetString(PyExc_IndexError,\r | |
119 | "xrange object index out of range");\r | |
120 | return NULL;\r | |
121 | }\r | |
122 | /* do calculation entirely using unsigned longs, to avoid\r | |
123 | undefined behaviour due to signed overflow. */\r | |
124 | return PyInt_FromLong((long)(r->start + (unsigned long)i * r->step));\r | |
125 | }\r | |
126 | \r | |
127 | static Py_ssize_t\r | |
128 | range_length(rangeobject *r)\r | |
129 | {\r | |
130 | return (Py_ssize_t)(r->len);\r | |
131 | }\r | |
132 | \r | |
133 | static PyObject *\r | |
134 | range_repr(rangeobject *r)\r | |
135 | {\r | |
136 | PyObject *rtn;\r | |
137 | \r | |
138 | if (r->start == 0 && r->step == 1)\r | |
139 | rtn = PyString_FromFormat("xrange(%ld)",\r | |
140 | get_stop_for_range(r));\r | |
141 | \r | |
142 | else if (r->step == 1)\r | |
143 | rtn = PyString_FromFormat("xrange(%ld, %ld)",\r | |
144 | r->start,\r | |
145 | get_stop_for_range(r));\r | |
146 | \r | |
147 | else\r | |
148 | rtn = PyString_FromFormat("xrange(%ld, %ld, %ld)",\r | |
149 | r->start,\r | |
150 | get_stop_for_range(r),\r | |
151 | r->step);\r | |
152 | return rtn;\r | |
153 | }\r | |
154 | \r | |
155 | /* Pickling support */\r | |
156 | static PyObject *\r | |
157 | range_reduce(rangeobject *r, PyObject *args)\r | |
158 | {\r | |
159 | return Py_BuildValue("(O(lll))", Py_TYPE(r),\r | |
160 | r->start,\r | |
161 | get_stop_for_range(r),\r | |
162 | r->step);\r | |
163 | }\r | |
164 | \r | |
165 | static PySequenceMethods range_as_sequence = {\r | |
166 | (lenfunc)range_length, /* sq_length */\r | |
167 | 0, /* sq_concat */\r | |
168 | 0, /* sq_repeat */\r | |
169 | (ssizeargfunc)range_item, /* sq_item */\r | |
170 | 0, /* sq_slice */\r | |
171 | };\r | |
172 | \r | |
173 | static PyObject * range_iter(PyObject *seq);\r | |
174 | static PyObject * range_reverse(PyObject *seq);\r | |
175 | \r | |
176 | PyDoc_STRVAR(reverse_doc,\r | |
177 | "Returns a reverse iterator.");\r | |
178 | \r | |
179 | static PyMethodDef range_methods[] = {\r | |
180 | {"__reversed__", (PyCFunction)range_reverse, METH_NOARGS, reverse_doc},\r | |
181 | {"__reduce__", (PyCFunction)range_reduce, METH_VARARGS},\r | |
182 | {NULL, NULL} /* sentinel */\r | |
183 | };\r | |
184 | \r | |
185 | PyTypeObject PyRange_Type = {\r | |
186 | PyObject_HEAD_INIT(&PyType_Type)\r | |
187 | 0, /* Number of items for varobject */\r | |
188 | "xrange", /* Name of this type */\r | |
189 | sizeof(rangeobject), /* Basic object size */\r | |
190 | 0, /* Item size for varobject */\r | |
191 | (destructor)PyObject_Del, /* tp_dealloc */\r | |
192 | 0, /* tp_print */\r | |
193 | 0, /* tp_getattr */\r | |
194 | 0, /* tp_setattr */\r | |
195 | 0, /* tp_compare */\r | |
196 | (reprfunc)range_repr, /* tp_repr */\r | |
197 | 0, /* tp_as_number */\r | |
198 | &range_as_sequence, /* tp_as_sequence */\r | |
199 | 0, /* tp_as_mapping */\r | |
200 | 0, /* tp_hash */\r | |
201 | 0, /* tp_call */\r | |
202 | 0, /* tp_str */\r | |
203 | PyObject_GenericGetAttr, /* tp_getattro */\r | |
204 | 0, /* tp_setattro */\r | |
205 | 0, /* tp_as_buffer */\r | |
206 | Py_TPFLAGS_DEFAULT, /* tp_flags */\r | |
207 | range_doc, /* tp_doc */\r | |
208 | 0, /* tp_traverse */\r | |
209 | 0, /* tp_clear */\r | |
210 | 0, /* tp_richcompare */\r | |
211 | 0, /* tp_weaklistoffset */\r | |
212 | range_iter, /* tp_iter */\r | |
213 | 0, /* tp_iternext */\r | |
214 | range_methods, /* tp_methods */\r | |
215 | 0, /* tp_members */\r | |
216 | 0, /* tp_getset */\r | |
217 | 0, /* tp_base */\r | |
218 | 0, /* tp_dict */\r | |
219 | 0, /* tp_descr_get */\r | |
220 | 0, /* tp_descr_set */\r | |
221 | 0, /* tp_dictoffset */\r | |
222 | 0, /* tp_init */\r | |
223 | 0, /* tp_alloc */\r | |
224 | range_new, /* tp_new */\r | |
225 | };\r | |
226 | \r | |
227 | /*********************** Xrange Iterator **************************/\r | |
228 | \r | |
229 | typedef struct {\r | |
230 | PyObject_HEAD\r | |
231 | long index;\r | |
232 | long start;\r | |
233 | long step;\r | |
234 | long len;\r | |
235 | } rangeiterobject;\r | |
236 | \r | |
237 | static PyObject *\r | |
238 | rangeiter_next(rangeiterobject *r)\r | |
239 | {\r | |
240 | if (r->index < r->len)\r | |
241 | return PyInt_FromLong(r->start + (r->index++) * r->step);\r | |
242 | return NULL;\r | |
243 | }\r | |
244 | \r | |
245 | static PyObject *\r | |
246 | rangeiter_len(rangeiterobject *r)\r | |
247 | {\r | |
248 | return PyInt_FromLong(r->len - r->index);\r | |
249 | }\r | |
250 | \r | |
251 | PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it)).");\r | |
252 | \r | |
253 | static PyMethodDef rangeiter_methods[] = {\r | |
254 | {"__length_hint__", (PyCFunction)rangeiter_len, METH_NOARGS, length_hint_doc},\r | |
255 | {NULL, NULL} /* sentinel */\r | |
256 | };\r | |
257 | \r | |
258 | static PyTypeObject Pyrangeiter_Type = {\r | |
259 | PyObject_HEAD_INIT(&PyType_Type)\r | |
260 | 0, /* ob_size */\r | |
261 | "rangeiterator", /* tp_name */\r | |
262 | sizeof(rangeiterobject), /* tp_basicsize */\r | |
263 | 0, /* tp_itemsize */\r | |
264 | /* methods */\r | |
265 | (destructor)PyObject_Del, /* tp_dealloc */\r | |
266 | 0, /* tp_print */\r | |
267 | 0, /* tp_getattr */\r | |
268 | 0, /* tp_setattr */\r | |
269 | 0, /* tp_compare */\r | |
270 | 0, /* tp_repr */\r | |
271 | 0, /* tp_as_number */\r | |
272 | 0, /* tp_as_sequence */\r | |
273 | 0, /* tp_as_mapping */\r | |
274 | 0, /* tp_hash */\r | |
275 | 0, /* tp_call */\r | |
276 | 0, /* tp_str */\r | |
277 | PyObject_GenericGetAttr, /* tp_getattro */\r | |
278 | 0, /* tp_setattro */\r | |
279 | 0, /* tp_as_buffer */\r | |
280 | Py_TPFLAGS_DEFAULT, /* tp_flags */\r | |
281 | 0, /* tp_doc */\r | |
282 | 0, /* tp_traverse */\r | |
283 | 0, /* tp_clear */\r | |
284 | 0, /* tp_richcompare */\r | |
285 | 0, /* tp_weaklistoffset */\r | |
286 | PyObject_SelfIter, /* tp_iter */\r | |
287 | (iternextfunc)rangeiter_next, /* tp_iternext */\r | |
288 | rangeiter_methods, /* tp_methods */\r | |
289 | 0,\r | |
290 | };\r | |
291 | \r | |
292 | static PyObject *\r | |
293 | range_iter(PyObject *seq)\r | |
294 | {\r | |
295 | rangeiterobject *it;\r | |
296 | \r | |
297 | if (!PyRange_Check(seq)) {\r | |
298 | PyErr_BadInternalCall();\r | |
299 | return NULL;\r | |
300 | }\r | |
301 | it = PyObject_New(rangeiterobject, &Pyrangeiter_Type);\r | |
302 | if (it == NULL)\r | |
303 | return NULL;\r | |
304 | it->index = 0;\r | |
305 | it->start = ((rangeobject *)seq)->start;\r | |
306 | it->step = ((rangeobject *)seq)->step;\r | |
307 | it->len = ((rangeobject *)seq)->len;\r | |
308 | return (PyObject *)it;\r | |
309 | }\r | |
310 | \r | |
311 | static PyObject *\r | |
312 | range_reverse(PyObject *seq)\r | |
313 | {\r | |
314 | rangeiterobject *it;\r | |
315 | long start, step, len;\r | |
316 | \r | |
317 | if (!PyRange_Check(seq)) {\r | |
318 | PyErr_BadInternalCall();\r | |
319 | return NULL;\r | |
320 | }\r | |
321 | it = PyObject_New(rangeiterobject, &Pyrangeiter_Type);\r | |
322 | if (it == NULL)\r | |
323 | return NULL;\r | |
324 | \r | |
325 | start = ((rangeobject *)seq)->start;\r | |
326 | step = ((rangeobject *)seq)->step;\r | |
327 | len = ((rangeobject *)seq)->len;\r | |
328 | \r | |
329 | it->index = 0;\r | |
330 | it->len = len;\r | |
331 | /* the casts below guard against signed overflow by turning it\r | |
332 | into unsigned overflow instead. The correctness of this\r | |
333 | code still depends on conversion from unsigned long to long\r | |
334 | wrapping modulo ULONG_MAX+1, which isn't guaranteed (see\r | |
335 | C99 6.3.1.3p3) but seems to hold in practice for all\r | |
336 | platforms we're likely to meet.\r | |
337 | \r | |
338 | If step == LONG_MIN then we still end up with LONG_MIN\r | |
339 | after negation; but this works out, since we've still got\r | |
340 | the correct value modulo ULONG_MAX+1, and the range_item\r | |
341 | calculation is also done modulo ULONG_MAX+1.\r | |
342 | */\r | |
343 | it->start = (long)(start + (unsigned long)(len-1) * step);\r | |
344 | it->step = (long)(0UL-step);\r | |
345 | \r | |
346 | return (PyObject *)it;\r | |
347 | }\r |