blob: 24765f4dec77d36ad774b69652ead41962337333 [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
41 *kk = PyInt_AS_LONG(c);
42 Py_DECREF(c);
43
44 if (*kk > INT_MAX) {
45 PyErr_SetString(PyExc_OverflowError,
46 "integer multiplication");
47 return 0;
48 }
49 else
50 return 1;
51}
52
53PyObject *
54PyRange_New(long start, long len, long step, int reps)
55{
56 long totlen = -1;
Guido van Rossumc0b618a1997-05-02 03:12:38 +000057 rangeobject *obj = PyObject_NEW(rangeobject, &PyRange_Type);
Guido van Rossum12d12c51993-10-26 17:58:25 +000058
Guido van Rossum9e8f4ea2000-12-14 14:59:53 +000059 if (obj == NULL)
60 return NULL;
Thomas Woutersefafcea2001-07-09 12:30:54 +000061
62 if (reps != 1)
63 WARN("PyRange_New's 'repetitions' argument is deprecated");
Guido van Rossum9e8f4ea2000-12-14 14:59:53 +000064
Thomas Woutersefafcea2001-07-09 12:30:54 +000065 if (len == 0 || reps <= 0) {
Guido van Rossum65e0b992001-01-15 18:58:56 +000066 start = 0;
67 len = 0;
68 step = 1;
Thomas Woutersefafcea2001-07-09 12:30:54 +000069 reps = 1;
70 totlen = 0;
Guido van Rossum65e0b992001-01-15 18:58:56 +000071 }
72 else {
73 long last = start + (len - 1) * step;
74 if ((step > 0) ?
Thomas Woutersefafcea2001-07-09 12:30:54 +000075 (last > (PyInt_GetMax() - step)) :
76 (last < (-1 - PyInt_GetMax() - step))) {
Guido van Rossum65e0b992001-01-15 18:58:56 +000077 PyErr_SetString(PyExc_OverflowError,
78 "integer addition");
79 return NULL;
Thomas Woutersefafcea2001-07-09 12:30:54 +000080 }
81 if (! long_mul(len, (long) reps, &totlen)) {
82 if(!PyErr_ExceptionMatches(PyExc_OverflowError))
83 return NULL;
84 PyErr_Clear();
85 totlen = -1;
Guido van Rossum65e0b992001-01-15 18:58:56 +000086 }
87 }
88
Guido van Rossum12d12c51993-10-26 17:58:25 +000089 obj->start = start;
90 obj->len = len;
91 obj->step = step;
Thomas Woutersefafcea2001-07-09 12:30:54 +000092 obj->reps = reps;
93 obj->totlen = totlen;
Guido van Rossum12d12c51993-10-26 17:58:25 +000094
Guido van Rossumc0b618a1997-05-02 03:12:38 +000095 return (PyObject *) obj;
Guido van Rossum12d12c51993-10-26 17:58:25 +000096}
97
98static void
Fred Drake45cfbcc2000-07-09 06:21:27 +000099range_dealloc(rangeobject *r)
Guido van Rossum12d12c51993-10-26 17:58:25 +0000100{
Guido van Rossumb18618d2000-05-03 23:44:39 +0000101 PyObject_DEL(r);
Guido van Rossum12d12c51993-10-26 17:58:25 +0000102}
103
Guido van Rossumc0b618a1997-05-02 03:12:38 +0000104static PyObject *
Fred Drake45cfbcc2000-07-09 06:21:27 +0000105range_item(rangeobject *r, int i)
Guido van Rossum12d12c51993-10-26 17:58:25 +0000106{
Thomas Woutersefafcea2001-07-09 12:30:54 +0000107 if (i < 0 || i >= r->totlen)
108 if (r->totlen!=-1) {
109 PyErr_SetString(PyExc_IndexError,
Guido van Rossum5dadf7e1999-01-09 21:40:35 +0000110 "xrange object index out of range");
Thomas Woutersefafcea2001-07-09 12:30:54 +0000111 return NULL;
112 }
Guido van Rossum12d12c51993-10-26 17:58:25 +0000113
Guido van Rossumc0b618a1997-05-02 03:12:38 +0000114 return PyInt_FromLong(r->start + (i % r->len) * r->step);
Guido van Rossum12d12c51993-10-26 17:58:25 +0000115}
116
117static int
Fred Drake45cfbcc2000-07-09 06:21:27 +0000118range_length(rangeobject *r)
Guido van Rossum12d12c51993-10-26 17:58:25 +0000119{
Thomas Woutersefafcea2001-07-09 12:30:54 +0000120 if (r->totlen == -1)
121 PyErr_SetString(PyExc_OverflowError,
122 "xrange object has too many items");
123 return r->totlen;
Guido van Rossum7d6aa511993-12-21 22:50:31 +0000124}
125
Guido van Rossumc0b618a1997-05-02 03:12:38 +0000126static PyObject *
Fred Drake45cfbcc2000-07-09 06:21:27 +0000127range_repr(rangeobject *r)
Guido van Rossum12d12c51993-10-26 17:58:25 +0000128{
Barry Warsaw7ce36942001-08-24 18:34:26 +0000129 PyObject *rtn;
130
Tim Peters72d421b2000-08-04 03:05:40 +0000131 if (r->start == 0 && r->step == 1)
Barry Warsaw7ce36942001-08-24 18:34:26 +0000132 rtn = PyString_FromFormat("xrange(%ld)",
133 r->start + r->len * r->step);
Tim Peters72d421b2000-08-04 03:05:40 +0000134
135 else if (r->step == 1)
Barry Warsaw7ce36942001-08-24 18:34:26 +0000136 rtn = PyString_FromFormat("xrange(%ld, %ld)",
137 r->start,
138 r->start + r->len * r->step);
Tim Peters72d421b2000-08-04 03:05:40 +0000139
140 else
Barry Warsaw7ce36942001-08-24 18:34:26 +0000141 rtn = PyString_FromFormat("xrange(%ld, %ld, %ld)",
142 r->start,
143 r->start + r->len * r->step,
144 r->step);
145 if (r->reps != 1) {
146 PyObject *extra = PyString_FromFormat(
147 "(%s * %d)",
148 PyString_AS_STRING(rtn), r->reps);
149 Py_DECREF(rtn);
150 rtn = extra;
151 }
152 return rtn;
Thomas Woutersefafcea2001-07-09 12:30:54 +0000153}
154
155static PyObject *
156range_repeat(rangeobject *r, int n)
157{
158 long lreps = 0;
159
160 WARN("xrange object multiplication is deprecated; "
161 "convert to list instead");
162
163 if (n <= 0)
164 return (PyObject *) PyRange_New(0, 0, 1, 1);
165
166 else if (n == 1) {
167 Py_INCREF(r);
168 return (PyObject *) r;
169 }
170
171 else if (! long_mul((long) r->reps, (long) n, &lreps))
172 return NULL;
173
174 else
175 return (PyObject *) PyRange_New(
176 r->start,
177 r->len,
178 r->step,
179 (int) lreps);
180}
181
182static int
183range_compare(rangeobject *r1, rangeobject *r2)
184{
185
186 if (PyErr_Warn(PyExc_DeprecationWarning,
187 "xrange object comparision is deprecated; "
188 "convert to list instead") < 0)
189 return -1;
190
191 if (r1->start != r2->start)
192 return r1->start - r2->start;
193
194 else if (r1->step != r2->step)
195 return r1->step - r2->step;
196
197 else if (r1->len != r2->len)
198 return r1->len - r2->len;
199
200 else
201 return r1->reps - r2->reps;
202}
203
204static PyObject *
205range_slice(rangeobject *r, int low, int high)
206{
207 WARN("xrange object slicing is deprecated; "
208 "convert to list instead");
209
210 if (r->reps != 1) {
211 PyErr_SetString(PyExc_TypeError,
212 "cannot slice a replicated xrange");
213 return NULL;
214 }
215 if (low < 0)
216 low = 0;
217 else if (low > r->len)
218 low = r->len;
219 if (high < 0)
220 high = 0;
221 if (high < low)
222 high = low;
223 else if (high > r->len)
224 high = r->len;
225
226 if (low == 0 && high == r->len) {
227 Py_INCREF(r);
228 return (PyObject *) r;
229 }
230
231 return (PyObject *) PyRange_New(
232 low * r->step + r->start,
233 high - low,
234 r->step,
235 1);
236}
237
238static PyObject *
239range_tolist(rangeobject *self, PyObject *args)
240{
241 PyObject *thelist;
242 int j;
243
244 WARN("xrange.tolist() is deprecated; use list(xrange) instead");
245
Thomas Woutersefafcea2001-07-09 12:30:54 +0000246 if (self->totlen == -1)
247 return PyErr_NoMemory();
248
249 if ((thelist = PyList_New(self->totlen)) == NULL)
250 return NULL;
251
252 for (j = 0; j < self->totlen; ++j)
253 if ((PyList_SetItem(thelist, j, (PyObject *) PyInt_FromLong(
254 self->start + (j % self->len) * self->step))) < 0)
255 return NULL;
256
257 return thelist;
258}
259
260static PyObject *
261range_getattr(rangeobject *r, char *name)
262{
263 PyObject *result;
264
265 static PyMethodDef range_methods[] = {
Martin v. Löwise3eb1f22001-08-16 13:15:00 +0000266 {"tolist", (PyCFunction)range_tolist, METH_NOARGS,
Thomas Woutersefafcea2001-07-09 12:30:54 +0000267 "tolist() -> list\n"
268 "Return a list object with the same values.\n"
269 "(This method is deprecated; use list() instead.)"},
270 {NULL, NULL}
271 };
272 static struct memberlist range_members[] = {
273 {"step", T_LONG, offsetof(rangeobject, step), RO},
274 {"start", T_LONG, offsetof(rangeobject, start), RO},
275 {"stop", T_LONG, 0, RO},
276 {NULL, 0, 0, 0}
277 };
278
279 result = Py_FindMethod(range_methods, (PyObject *) r, name);
280 if (result == NULL) {
281 PyErr_Clear();
282 if (strcmp("stop", name) == 0)
283 result = PyInt_FromLong(r->start + (r->len * r->step));
284 else
285 result = PyMember_Get((char *)r, range_members, name);
286 if (result)
287 WARN("xrange object's 'start', 'stop' and 'step' "
288 "attributes are deprecated");
289 }
290 return result;
Fred Drake56780252000-06-15 14:50:20 +0000291}
292
Guido van Rossumc0b618a1997-05-02 03:12:38 +0000293static PySequenceMethods range_as_sequence = {
Fred Drake0b796fa2000-11-08 19:42:43 +0000294 (inquiry)range_length, /*sq_length*/
Guido van Rossum3f561662001-07-05 13:27:48 +0000295 0, /*sq_concat*/
Thomas Woutersefafcea2001-07-09 12:30:54 +0000296 (intargfunc)range_repeat, /*sq_repeat*/
297 (intargfunc)range_item, /*sq_item*/
298 (intintargfunc)range_slice, /*sq_slice*/
Fred Drake0b796fa2000-11-08 19:42:43 +0000299 0, /*sq_ass_item*/
300 0, /*sq_ass_slice*/
Thomas Woutersefafcea2001-07-09 12:30:54 +0000301 0, /*sq_contains*/
Guido van Rossum12d12c51993-10-26 17:58:25 +0000302};
303
Guido van Rossumc0b618a1997-05-02 03:12:38 +0000304PyTypeObject PyRange_Type = {
305 PyObject_HEAD_INIT(&PyType_Type)
Guido van Rossum12d12c51993-10-26 17:58:25 +0000306 0, /* Number of items for varobject */
Guido van Rossum2586bf01993-11-01 16:21:44 +0000307 "xrange", /* Name of this type */
Guido van Rossum12d12c51993-10-26 17:58:25 +0000308 sizeof(rangeobject), /* Basic object size */
309 0, /* Item size for varobject */
Tim Peters6d6c1a32001-08-02 04:15:00 +0000310 (destructor)range_dealloc, /*tp_dealloc*/
311 0, /*tp_print*/
312 (getattrfunc)range_getattr, /*tp_getattr*/
313 0, /*tp_setattr*/
314 (cmpfunc)range_compare, /*tp_compare*/
315 (reprfunc)range_repr, /*tp_repr*/
316 0, /*tp_as_number*/
317 &range_as_sequence, /*tp_as_sequence*/
318 0, /*tp_as_mapping*/
319 0, /*tp_hash*/
320 0, /*tp_call*/
321 0, /*tp_str*/
322 PyObject_GenericGetAttr, /*tp_getattro*/
323 0, /*tp_setattro*/
324 0, /*tp_as_buffer*/
325 Py_TPFLAGS_DEFAULT, /*tp_flags*/
326 0, /* tp_doc */
327 0, /* tp_traverse */
328 0, /* tp_clear */
329 0, /* tp_richcompare */
330 0, /* tp_weaklistoffset */
331 0, /* tp_iter */
332 0, /* tp_iternext */
333 0, /* tp_methods */
334 0, /* tp_members */
335 0, /* tp_getset */
336 0, /* tp_base */
337 0, /* tp_dict */
Guido van Rossum12d12c51993-10-26 17:58:25 +0000338};
Thomas Woutersefafcea2001-07-09 12:30:54 +0000339
340#undef WARN