This commit was manufactured by cvs2svn to create tag 'r201'.
[python/dscho.git] / Objects / rangeobject.c
blobb3ce0c8650a9dfe717cd619164daa34683f41962
2 /* Range object implementation */
4 #include "Python.h"
5 #include "structmember.h"
6 #include <string.h>
8 typedef struct {
9 PyObject_HEAD
10 long start;
11 long step;
12 long len;
13 int reps;
14 } rangeobject;
17 PyObject *
18 PyRange_New(long start, long len, long step, int reps)
20 rangeobject *obj = PyObject_NEW(rangeobject, &PyRange_Type);
22 obj->start = start;
23 obj->len = len;
24 obj->step = step;
25 obj->reps = reps;
27 return (PyObject *) obj;
30 static void
31 range_dealloc(rangeobject *r)
33 PyObject_DEL(r);
36 static PyObject *
37 range_item(rangeobject *r, int i)
39 if (i < 0 || i >= r->len * r->reps) {
40 PyErr_SetString(PyExc_IndexError,
41 "xrange object index out of range");
42 return NULL;
45 return PyInt_FromLong(r->start + (i % r->len) * r->step);
48 static int
49 range_length(rangeobject *r)
51 return r->len * r->reps;
54 static PyObject *
55 range_repr(rangeobject *r)
57 /* buffers must be big enough to hold 3 longs + an int +
58 * a bit of "(xrange(...) * ...)" text.
60 char buf1[250];
61 char buf2[250];
63 if (r->start == 0 && r->step == 1)
64 sprintf(buf1, "xrange(%ld)", r->start + r->len * r->step);
66 else if (r->step == 1)
67 sprintf(buf1, "xrange(%ld, %ld)",
68 r->start,
69 r->start + r->len * r->step);
71 else
72 sprintf(buf1, "xrange(%ld, %ld, %ld)",
73 r->start,
74 r->start + r->len * r->step,
75 r->step);
77 if (r->reps != 1)
78 sprintf(buf2, "(%s * %d)", buf1, r->reps);
80 return PyString_FromString(r->reps == 1 ? buf1 : buf2);
83 static PyObject *
84 range_concat(rangeobject *r, PyObject *obj)
86 PyErr_SetString(PyExc_TypeError, "cannot concatenate xrange objects");
87 return NULL;
90 static PyObject *
91 range_repeat(rangeobject *r, int n)
93 if (n < 0)
94 return (PyObject *) PyRange_New(0, 0, 1, 1);
96 else if (n == 1) {
97 Py_INCREF(r);
98 return (PyObject *) r;
101 else
102 return (PyObject *) PyRange_New(
103 r->start,
104 r->len,
105 r->step,
106 r->reps * n);
109 static int
110 range_compare(rangeobject *r1, rangeobject *r2)
112 if (r1->start != r2->start)
113 return r1->start - r2->start;
115 else if (r1->step != r2->step)
116 return r1->step - r2->step;
118 else if (r1->len != r2->len)
119 return r1->len - r2->len;
121 else
122 return r1->reps - r2->reps;
125 static PyObject *
126 range_slice(rangeobject *r, int low, int high)
128 if (r->reps != 1) {
129 PyErr_SetString(PyExc_TypeError,
130 "cannot slice a replicated xrange");
131 return NULL;
133 if (low < 0)
134 low = 0;
135 else if (low > r->len)
136 low = r->len;
137 if (high < 0)
138 high = 0;
139 if (high < low)
140 high = low;
141 else if (high > r->len)
142 high = r->len;
144 if (low == 0 && high == r->len) {
145 Py_INCREF(r);
146 return (PyObject *) r;
149 return (PyObject *) PyRange_New(
150 low * r->step + r->start,
151 high - low,
152 r->step,
156 static PyObject *
157 range_tolist(rangeobject *self, PyObject *args)
159 PyObject *thelist;
160 int j;
161 int len = self->len * self->reps;
163 if (! PyArg_ParseTuple(args, ":tolist"))
164 return NULL;
166 if ((thelist = PyList_New(len)) == NULL)
167 return NULL;
169 for (j = 0; j < len; ++j)
170 if ((PyList_SetItem(thelist, j, (PyObject *) PyInt_FromLong(
171 self->start + (j % self->len) * self->step))) < 0)
172 return NULL;
174 return thelist;
177 static PyObject *
178 range_getattr(rangeobject *r, char *name)
180 static PyMethodDef range_methods[] = {
181 {"tolist", (PyCFunction)range_tolist, METH_VARARGS,
182 "tolist() -> list\n"
183 "Return a list object with the same values."},
184 {NULL, NULL}
187 return Py_FindMethod(range_methods, (PyObject *) r, name);
190 static int
191 range_contains(rangeobject *r, PyObject *obj)
193 long num = PyInt_AsLong(obj);
195 if (num < 0 && PyErr_Occurred())
196 return -1;
198 if (r->step > 0) {
199 if ((num < r->start) || ((num - r->start) % r->step))
200 return 0;
201 if (num >= (r->start + (r->len * r->step)))
202 return 0;
204 else {
205 if ((num > r->start) || ((num - r->start) % r->step))
206 return 0;
207 if (num <= (r->start + (r->len * r->step)))
208 return 0;
210 return 1;
213 static PySequenceMethods range_as_sequence = {
214 (inquiry)range_length, /*sq_length*/
215 (binaryfunc)range_concat, /*sq_concat*/
216 (intargfunc)range_repeat, /*sq_repeat*/
217 (intargfunc)range_item, /*sq_item*/
218 (intintargfunc)range_slice, /*sq_slice*/
219 0, /*sq_ass_item*/
220 0, /*sq_ass_slice*/
221 (objobjproc)range_contains, /*sq_contains*/
224 PyTypeObject PyRange_Type = {
225 PyObject_HEAD_INIT(&PyType_Type)
226 0, /* Number of items for varobject */
227 "xrange", /* Name of this type */
228 sizeof(rangeobject), /* Basic object size */
229 0, /* Item size for varobject */
230 (destructor)range_dealloc, /*tp_dealloc*/
231 0, /*tp_print*/
232 (getattrfunc)range_getattr, /*tp_getattr*/
233 0, /*tp_setattr*/
234 (cmpfunc)range_compare, /*tp_compare*/
235 (reprfunc)range_repr, /*tp_repr*/
236 0, /*tp_as_number*/
237 &range_as_sequence, /*tp_as_sequence*/
238 0, /*tp_as_mapping*/
239 0, /*tp_hash*/
240 0, /*tp_call*/
241 0, /*tp_str*/
242 0, /*tp_getattro*/
243 0, /*tp_setattro*/
244 0, /*tp_as_buffer*/
245 Py_TPFLAGS_DEFAULT, /*tp_flags*/