blob: 5095e5254bd67b491a41fff1ef80aa2ce6bf9c51 [file] [log] [blame]
Guido van Rossum12d12c51993-10-26 17:58:25 +00001
2/* Range object implementation */
3
Guido van Rossumc0b618a1997-05-02 03:12:38 +00004#include "Python.h"
Fred Drake0b796fa2000-11-08 19:42:43 +00005#include "structmember.h"
6#include <string.h>
Guido van Rossum12d12c51993-10-26 17:58:25 +00007
Thomas Woutersefafcea2001-07-09 12:30:54 +00008#define WARN(msg) if (PyErr_Warn(PyExc_DeprecationWarning, msg) < 0) \
9 return NULL;
10
Guido van Rossum12d12c51993-10-26 17:58:25 +000011typedef struct {
Guido van Rossumc0b618a1997-05-02 03:12:38 +000012 PyObject_HEAD
Guido van Rossum12d12c51993-10-26 17:58:25 +000013 long start;
14 long step;
15 long len;
Thomas Woutersefafcea2001-07-09 12:30:54 +000016 int reps;
17 long totlen;
Guido van Rossum12d12c51993-10-26 17:58:25 +000018} rangeobject;
19
Thomas Woutersefafcea2001-07-09 12:30:54 +000020static int
21long_mul(long i, long j, long *kk)
Guido van Rossum12d12c51993-10-26 17:58:25 +000022{
Thomas Woutersefafcea2001-07-09 12:30:54 +000023 PyObject *a;
24 PyObject *b;
25 PyObject *c;
26
27 if ((a = PyInt_FromLong(i)) == NULL)
28 return 0;
29
30 if ((b = PyInt_FromLong(j)) == NULL)
31 return 0;
32
33 c = PyNumber_Multiply(a, b);
34
35 Py_DECREF(a);
36 Py_DECREF(b);
37
38 if (c == NULL)
39 return 0;
40
Guido van Rossum03b3f042001-12-04 16:36:39 +000041 if (!PyInt_Check(c)) {
42 Py_DECREF(c);
43 goto overflow;
44 }
45
Thomas Woutersefafcea2001-07-09 12:30:54 +000046 *kk = PyInt_AS_LONG(c);
47 Py_DECREF(c);
48
49 if (*kk > INT_MAX) {
Guido van Rossum03b3f042001-12-04 16:36:39 +000050 overflow:
Thomas Woutersefafcea2001-07-09 12:30:54 +000051 PyErr_SetString(PyExc_OverflowError,
52 "integer multiplication");
53 return 0;
54 }
55 else
56 return 1;
57}
58
59PyObject *
60PyRange_New(long start, long len, long step, int reps)
61{
62 long totlen = -1;
Guido van Rossumc0b618a1997-05-02 03:12:38 +000063 rangeobject *obj = PyObject_NEW(rangeobject, &PyRange_Type);
Guido van Rossum12d12c51993-10-26 17:58:25 +000064
Guido van Rossum9e8f4ea2000-12-14 14:59:53 +000065 if (obj == NULL)
66 return NULL;
Thomas Woutersefafcea2001-07-09 12:30:54 +000067
68 if (reps != 1)
69 WARN("PyRange_New's 'repetitions' argument is deprecated");
Guido van Rossum9e8f4ea2000-12-14 14:59:53 +000070
Thomas Woutersefafcea2001-07-09 12:30:54 +000071 if (len == 0 || reps <= 0) {
Guido van Rossum65e0b992001-01-15 18:58:56 +000072 start = 0;
73 len = 0;
74 step = 1;
Thomas Woutersefafcea2001-07-09 12:30:54 +000075 reps = 1;
76 totlen = 0;
Guido van Rossum65e0b992001-01-15 18:58:56 +000077 }
78 else {
79 long last = start + (len - 1) * step;
80 if ((step > 0) ?
Thomas Woutersefafcea2001-07-09 12:30:54 +000081 (last > (PyInt_GetMax() - step)) :
82 (last < (-1 - PyInt_GetMax() - step))) {
Guido van Rossum65e0b992001-01-15 18:58:56 +000083 PyErr_SetString(PyExc_OverflowError,
84 "integer addition");
85 return NULL;
Thomas Woutersefafcea2001-07-09 12:30:54 +000086 }
87 if (! long_mul(len, (long) reps, &totlen)) {
88 if(!PyErr_ExceptionMatches(PyExc_OverflowError))
89 return NULL;
90 PyErr_Clear();
91 totlen = -1;
Guido van Rossum65e0b992001-01-15 18:58:56 +000092 }
93 }
94
Guido van Rossum12d12c51993-10-26 17:58:25 +000095 obj->start = start;
96 obj->len = len;
97 obj->step = step;
Thomas Woutersefafcea2001-07-09 12:30:54 +000098 obj->reps = reps;
99 obj->totlen = totlen;
Guido van Rossum12d12c51993-10-26 17:58:25 +0000100
Guido van Rossumc0b618a1997-05-02 03:12:38 +0000101 return (PyObject *) obj;
Guido van Rossum12d12c51993-10-26 17:58:25 +0000102}
103
104static void
Fred Drake45cfbcc2000-07-09 06:21:27 +0000105range_dealloc(rangeobject *r)
Guido van Rossum12d12c51993-10-26 17:58:25 +0000106{
Guido van Rossumb18618d2000-05-03 23:44:39 +0000107 PyObject_DEL(r);
Guido van Rossum12d12c51993-10-26 17:58:25 +0000108}
109
Guido van Rossumc0b618a1997-05-02 03:12:38 +0000110static PyObject *
Fred Drake45cfbcc2000-07-09 06:21:27 +0000111range_item(rangeobject *r, int i)
Guido van Rossum12d12c51993-10-26 17:58:25 +0000112{
Thomas Woutersefafcea2001-07-09 12:30:54 +0000113 if (i < 0 || i >= r->totlen)
114 if (r->totlen!=-1) {
115 PyErr_SetString(PyExc_IndexError,
Guido van Rossum5dadf7e1999-01-09 21:40:35 +0000116 "xrange object index out of range");
Thomas Woutersefafcea2001-07-09 12:30:54 +0000117 return NULL;
118 }
Guido van Rossum12d12c51993-10-26 17:58:25 +0000119
Guido van Rossumc0b618a1997-05-02 03:12:38 +0000120 return PyInt_FromLong(r->start + (i % r->len) * r->step);
Guido van Rossum12d12c51993-10-26 17:58:25 +0000121}
122
123static int
Fred Drake45cfbcc2000-07-09 06:21:27 +0000124range_length(rangeobject *r)
Guido van Rossum12d12c51993-10-26 17:58:25 +0000125{
Thomas Woutersefafcea2001-07-09 12:30:54 +0000126 if (r->totlen == -1)
127 PyErr_SetString(PyExc_OverflowError,
128 "xrange object has too many items");
129 return r->totlen;
Guido van Rossum7d6aa511993-12-21 22:50:31 +0000130}
131
Guido van Rossumc0b618a1997-05-02 03:12:38 +0000132static PyObject *
Fred Drake45cfbcc2000-07-09 06:21:27 +0000133range_repr(rangeobject *r)
Guido van Rossum12d12c51993-10-26 17:58:25 +0000134{
Barry Warsaw7ce36942001-08-24 18:34:26 +0000135 PyObject *rtn;
136
Tim Peters72d421b2000-08-04 03:05:40 +0000137 if (r->start == 0 && r->step == 1)
Barry Warsaw7ce36942001-08-24 18:34:26 +0000138 rtn = PyString_FromFormat("xrange(%ld)",
139 r->start + r->len * r->step);
Tim Peters72d421b2000-08-04 03:05:40 +0000140
141 else if (r->step == 1)
Barry Warsaw7ce36942001-08-24 18:34:26 +0000142 rtn = PyString_FromFormat("xrange(%ld, %ld)",
143 r->start,
144 r->start + r->len * r->step);
Tim Peters72d421b2000-08-04 03:05:40 +0000145
146 else
Barry Warsaw7ce36942001-08-24 18:34:26 +0000147 rtn = PyString_FromFormat("xrange(%ld, %ld, %ld)",
148 r->start,
149 r->start + r->len * r->step,
150 r->step);
151 if (r->reps != 1) {
152 PyObject *extra = PyString_FromFormat(
153 "(%s * %d)",
154 PyString_AS_STRING(rtn), r->reps);
155 Py_DECREF(rtn);
156 rtn = extra;
157 }
158 return rtn;
Thomas Woutersefafcea2001-07-09 12:30:54 +0000159}
160
161static PyObject *
162range_repeat(rangeobject *r, int n)
163{
164 long lreps = 0;
165
166 WARN("xrange object multiplication is deprecated; "
167 "convert to list instead");
168
169 if (n <= 0)
170 return (PyObject *) PyRange_New(0, 0, 1, 1);
171
172 else if (n == 1) {
173 Py_INCREF(r);
174 return (PyObject *) r;
175 }
176
177 else if (! long_mul((long) r->reps, (long) n, &lreps))
178 return NULL;
179
180 else
181 return (PyObject *) PyRange_New(
182 r->start,
183 r->len,
184 r->step,
185 (int) lreps);
186}
187
188static int
189range_compare(rangeobject *r1, rangeobject *r2)
190{
191
192 if (PyErr_Warn(PyExc_DeprecationWarning,
193 "xrange object comparision is deprecated; "
194 "convert to list instead") < 0)
195 return -1;
196
197 if (r1->start != r2->start)
198 return r1->start - r2->start;
199
200 else if (r1->step != r2->step)
201 return r1->step - r2->step;
202
203 else if (r1->len != r2->len)
204 return r1->len - r2->len;
205
206 else
207 return r1->reps - r2->reps;
208}
209
210static PyObject *
211range_slice(rangeobject *r, int low, int high)
212{
213 WARN("xrange object slicing is deprecated; "
214 "convert to list instead");
215
216 if (r->reps != 1) {
217 PyErr_SetString(PyExc_TypeError,
218 "cannot slice a replicated xrange");
219 return NULL;
220 }
221 if (low < 0)
222 low = 0;
223 else if (low > r->len)
224 low = r->len;
225 if (high < 0)
226 high = 0;
227 if (high < low)
228 high = low;
229 else if (high > r->len)
230 high = r->len;
231
232 if (low == 0 && high == r->len) {
233 Py_INCREF(r);
234 return (PyObject *) r;
235 }
236
237 return (PyObject *) PyRange_New(
238 low * r->step + r->start,
239 high - low,
240 r->step,
241 1);
242}
243
244static PyObject *
245range_tolist(rangeobject *self, PyObject *args)
246{
247 PyObject *thelist;
248 int j;
249
250 WARN("xrange.tolist() is deprecated; use list(xrange) instead");
251
Thomas Woutersefafcea2001-07-09 12:30:54 +0000252 if (self->totlen == -1)
253 return PyErr_NoMemory();
254
255 if ((thelist = PyList_New(self->totlen)) == NULL)
256 return NULL;
257
258 for (j = 0; j < self->totlen; ++j)
259 if ((PyList_SetItem(thelist, j, (PyObject *) PyInt_FromLong(
260 self->start + (j % self->len) * self->step))) < 0)
261 return NULL;
262
263 return thelist;
264}
265
266static PyObject *
267range_getattr(rangeobject *r, char *name)
268{
269 PyObject *result;
270
271 static PyMethodDef range_methods[] = {
Martin v. Löwise3eb1f22001-08-16 13:15:00 +0000272 {"tolist", (PyCFunction)range_tolist, METH_NOARGS,
Thomas Woutersefafcea2001-07-09 12:30:54 +0000273 "tolist() -> list\n"
274 "Return a list object with the same values.\n"
275 "(This method is deprecated; use list() instead.)"},
276 {NULL, NULL}
277 };
278 static struct memberlist range_members[] = {
279 {"step", T_LONG, offsetof(rangeobject, step), RO},
280 {"start", T_LONG, offsetof(rangeobject, start), RO},
281 {"stop", T_LONG, 0, RO},
282 {NULL, 0, 0, 0}
283 };
284
285 result = Py_FindMethod(range_methods, (PyObject *) r, name);
286 if (result == NULL) {
287 PyErr_Clear();
288 if (strcmp("stop", name) == 0)
289 result = PyInt_FromLong(r->start + (r->len * r->step));
290 else
291 result = PyMember_Get((char *)r, range_members, name);
292 if (result)
293 WARN("xrange object's 'start', 'stop' and 'step' "
294 "attributes are deprecated");
295 }
296 return result;
Fred Drake56780252000-06-15 14:50:20 +0000297}
298
Guido van Rossumc0b618a1997-05-02 03:12:38 +0000299static PySequenceMethods range_as_sequence = {
Fred Drake0b796fa2000-11-08 19:42:43 +0000300 (inquiry)range_length, /*sq_length*/
Guido van Rossum3f561662001-07-05 13:27:48 +0000301 0, /*sq_concat*/
Thomas Woutersefafcea2001-07-09 12:30:54 +0000302 (intargfunc)range_repeat, /*sq_repeat*/
303 (intargfunc)range_item, /*sq_item*/
304 (intintargfunc)range_slice, /*sq_slice*/
Fred Drake0b796fa2000-11-08 19:42:43 +0000305 0, /*sq_ass_item*/
306 0, /*sq_ass_slice*/
Thomas Woutersefafcea2001-07-09 12:30:54 +0000307 0, /*sq_contains*/
Guido van Rossum12d12c51993-10-26 17:58:25 +0000308};
309
Guido van Rossumc0b618a1997-05-02 03:12:38 +0000310PyTypeObject PyRange_Type = {
311 PyObject_HEAD_INIT(&PyType_Type)
Guido van Rossum12d12c51993-10-26 17:58:25 +0000312 0, /* Number of items for varobject */
Guido van Rossum2586bf01993-11-01 16:21:44 +0000313 "xrange", /* Name of this type */
Guido van Rossum12d12c51993-10-26 17:58:25 +0000314 sizeof(rangeobject), /* Basic object size */
315 0, /* Item size for varobject */
Tim Peters6d6c1a32001-08-02 04:15:00 +0000316 (destructor)range_dealloc, /*tp_dealloc*/
317 0, /*tp_print*/
318 (getattrfunc)range_getattr, /*tp_getattr*/
319 0, /*tp_setattr*/
320 (cmpfunc)range_compare, /*tp_compare*/
321 (reprfunc)range_repr, /*tp_repr*/
322 0, /*tp_as_number*/
323 &range_as_sequence, /*tp_as_sequence*/
324 0, /*tp_as_mapping*/
325 0, /*tp_hash*/
326 0, /*tp_call*/
327 0, /*tp_str*/
328 PyObject_GenericGetAttr, /*tp_getattro*/
329 0, /*tp_setattro*/
330 0, /*tp_as_buffer*/
331 Py_TPFLAGS_DEFAULT, /*tp_flags*/
332 0, /* tp_doc */
333 0, /* tp_traverse */
334 0, /* tp_clear */
335 0, /* tp_richcompare */
336 0, /* tp_weaklistoffset */
337 0, /* tp_iter */
338 0, /* tp_iternext */
339 0, /* tp_methods */
340 0, /* tp_members */
341 0, /* tp_getset */
342 0, /* tp_base */
343 0, /* tp_dict */
Guido van Rossum12d12c51993-10-26 17:58:25 +0000344};
Thomas Woutersefafcea2001-07-09 12:30:54 +0000345
346#undef WARN