blob: 1f446df2dd4c82cfcb0ff7160a240ec62896210c [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{
Tim Peters72d421b2000-08-04 03:05:40 +0000129 /* buffers must be big enough to hold 3 longs + an int +
130 * a bit of "(xrange(...) * ...)" text.
131 */
132 char buf1[250];
Thomas Woutersefafcea2001-07-09 12:30:54 +0000133 char buf2[250];
Fred Drake2b83b462000-08-03 17:43:02 +0000134
Tim Peters72d421b2000-08-04 03:05:40 +0000135 if (r->start == 0 && r->step == 1)
Fred Drakec76e0e52000-08-04 02:34:41 +0000136 sprintf(buf1, "xrange(%ld)", r->start + r->len * r->step);
Tim Peters72d421b2000-08-04 03:05:40 +0000137
138 else if (r->step == 1)
139 sprintf(buf1, "xrange(%ld, %ld)",
140 r->start,
141 r->start + r->len * r->step);
142
143 else
144 sprintf(buf1, "xrange(%ld, %ld, %ld)",
Fred Drakec76e0e52000-08-04 02:34:41 +0000145 r->start,
146 r->start + r->len * r->step,
147 r->step);
Tim Peters72d421b2000-08-04 03:05:40 +0000148
Thomas Woutersefafcea2001-07-09 12:30:54 +0000149 if (r->reps != 1)
150 sprintf(buf2, "(%s * %d)", buf1, r->reps);
151
152 return PyString_FromString(r->reps == 1 ? buf1 : buf2);
153}
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
246 if (! PyArg_ParseTuple(args, ":tolist"))
247 return NULL;
248
249 if (self->totlen == -1)
250 return PyErr_NoMemory();
251
252 if ((thelist = PyList_New(self->totlen)) == NULL)
253 return NULL;
254
255 for (j = 0; j < self->totlen; ++j)
256 if ((PyList_SetItem(thelist, j, (PyObject *) PyInt_FromLong(
257 self->start + (j % self->len) * self->step))) < 0)
258 return NULL;
259
260 return thelist;
261}
262
263static PyObject *
264range_getattr(rangeobject *r, char *name)
265{
266 PyObject *result;
267
268 static PyMethodDef range_methods[] = {
269 {"tolist", (PyCFunction)range_tolist, METH_VARARGS,
270 "tolist() -> list\n"
271 "Return a list object with the same values.\n"
272 "(This method is deprecated; use list() instead.)"},
273 {NULL, NULL}
274 };
275 static struct memberlist range_members[] = {
276 {"step", T_LONG, offsetof(rangeobject, step), RO},
277 {"start", T_LONG, offsetof(rangeobject, start), RO},
278 {"stop", T_LONG, 0, RO},
279 {NULL, 0, 0, 0}
280 };
281
282 result = Py_FindMethod(range_methods, (PyObject *) r, name);
283 if (result == NULL) {
284 PyErr_Clear();
285 if (strcmp("stop", name) == 0)
286 result = PyInt_FromLong(r->start + (r->len * r->step));
287 else
288 result = PyMember_Get((char *)r, range_members, name);
289 if (result)
290 WARN("xrange object's 'start', 'stop' and 'step' "
291 "attributes are deprecated");
292 }
293 return result;
Fred Drake56780252000-06-15 14:50:20 +0000294}
295
Guido van Rossumc0b618a1997-05-02 03:12:38 +0000296static PySequenceMethods range_as_sequence = {
Fred Drake0b796fa2000-11-08 19:42:43 +0000297 (inquiry)range_length, /*sq_length*/
Guido van Rossum3f561662001-07-05 13:27:48 +0000298 0, /*sq_concat*/
Thomas Woutersefafcea2001-07-09 12:30:54 +0000299 (intargfunc)range_repeat, /*sq_repeat*/
300 (intargfunc)range_item, /*sq_item*/
301 (intintargfunc)range_slice, /*sq_slice*/
Fred Drake0b796fa2000-11-08 19:42:43 +0000302 0, /*sq_ass_item*/
303 0, /*sq_ass_slice*/
Thomas Woutersefafcea2001-07-09 12:30:54 +0000304 0, /*sq_contains*/
Guido van Rossum12d12c51993-10-26 17:58:25 +0000305};
306
Guido van Rossumc0b618a1997-05-02 03:12:38 +0000307PyTypeObject PyRange_Type = {
308 PyObject_HEAD_INIT(&PyType_Type)
Guido van Rossum12d12c51993-10-26 17:58:25 +0000309 0, /* Number of items for varobject */
Guido van Rossum2586bf01993-11-01 16:21:44 +0000310 "xrange", /* Name of this type */
Guido van Rossum12d12c51993-10-26 17:58:25 +0000311 sizeof(rangeobject), /* Basic object size */
312 0, /* Item size for varobject */
Guido van Rossum03093a21994-09-28 15:51:32 +0000313 (destructor)range_dealloc, /*tp_dealloc*/
Fred Drake2b83b462000-08-03 17:43:02 +0000314 0, /*tp_print*/
Thomas Woutersefafcea2001-07-09 12:30:54 +0000315 (getattrfunc)range_getattr, /*tp_getattr*/
Guido van Rossum12d12c51993-10-26 17:58:25 +0000316 0, /*tp_setattr*/
Thomas Woutersefafcea2001-07-09 12:30:54 +0000317 (cmpfunc)range_compare, /*tp_compare*/
Fred Drake2b83b462000-08-03 17:43:02 +0000318 (reprfunc)range_repr, /*tp_repr*/
Guido van Rossum12d12c51993-10-26 17:58:25 +0000319 0, /*tp_as_number*/
320 &range_as_sequence, /*tp_as_sequence*/
321 0, /*tp_as_mapping*/
Fred Drake56780252000-06-15 14:50:20 +0000322 0, /*tp_hash*/
323 0, /*tp_call*/
324 0, /*tp_str*/
325 0, /*tp_getattro*/
326 0, /*tp_setattro*/
327 0, /*tp_as_buffer*/
328 Py_TPFLAGS_DEFAULT, /*tp_flags*/
Guido van Rossum12d12c51993-10-26 17:58:25 +0000329};
Thomas Woutersefafcea2001-07-09 12:30:54 +0000330
331#undef WARN