2 /* Range object implementation */
5 #include "structmember.h"
18 PyRange_New(long start
, long len
, long step
, int reps
)
20 rangeobject
*obj
= PyObject_NEW(rangeobject
, &PyRange_Type
);
30 return (PyObject
*) obj
;
34 range_dealloc(rangeobject
*r
)
40 range_item(rangeobject
*r
, int i
)
42 if (i
< 0 || i
>= r
->len
* r
->reps
) {
43 PyErr_SetString(PyExc_IndexError
,
44 "xrange object index out of range");
48 return PyInt_FromLong(r
->start
+ (i
% r
->len
) * r
->step
);
52 range_length(rangeobject
*r
)
54 return r
->len
* r
->reps
;
58 range_repr(rangeobject
*r
)
60 /* buffers must be big enough to hold 3 longs + an int +
61 * a bit of "(xrange(...) * ...)" text.
66 if (r
->start
== 0 && r
->step
== 1)
67 sprintf(buf1
, "xrange(%ld)", r
->start
+ r
->len
* r
->step
);
69 else if (r
->step
== 1)
70 sprintf(buf1
, "xrange(%ld, %ld)",
72 r
->start
+ r
->len
* r
->step
);
75 sprintf(buf1
, "xrange(%ld, %ld, %ld)",
77 r
->start
+ r
->len
* r
->step
,
81 sprintf(buf2
, "(%s * %d)", buf1
, r
->reps
);
83 return PyString_FromString(r
->reps
== 1 ? buf1
: buf2
);
87 range_concat(rangeobject
*r
, PyObject
*obj
)
89 PyErr_SetString(PyExc_TypeError
, "cannot concatenate xrange objects");
94 range_repeat(rangeobject
*r
, int n
)
97 return (PyObject
*) PyRange_New(0, 0, 1, 1);
101 return (PyObject
*) r
;
105 return (PyObject
*) PyRange_New(
113 range_compare(rangeobject
*r1
, rangeobject
*r2
)
115 if (r1
->start
!= r2
->start
)
116 return r1
->start
- r2
->start
;
118 else if (r1
->step
!= r2
->step
)
119 return r1
->step
- r2
->step
;
121 else if (r1
->len
!= r2
->len
)
122 return r1
->len
- r2
->len
;
125 return r1
->reps
- r2
->reps
;
129 range_slice(rangeobject
*r
, int low
, int high
)
132 PyErr_SetString(PyExc_TypeError
,
133 "cannot slice a replicated xrange");
138 else if (low
> r
->len
)
144 else if (high
> r
->len
)
147 if (low
== 0 && high
== r
->len
) {
149 return (PyObject
*) r
;
152 return (PyObject
*) PyRange_New(
153 low
* r
->step
+ r
->start
,
160 range_tolist(rangeobject
*self
, PyObject
*args
)
164 int len
= self
->len
* self
->reps
;
166 if (! PyArg_ParseTuple(args
, ":tolist"))
169 if ((thelist
= PyList_New(len
)) == NULL
)
172 for (j
= 0; j
< len
; ++j
)
173 if ((PyList_SetItem(thelist
, j
, (PyObject
*) PyInt_FromLong(
174 self
->start
+ (j
% self
->len
) * self
->step
))) < 0)
181 range_getattr(rangeobject
*r
, char *name
)
185 static PyMethodDef range_methods
[] = {
186 {"tolist", (PyCFunction
)range_tolist
, METH_VARARGS
,
188 "Return a list object with the same values."},
191 static struct memberlist range_members
[] = {
192 {"step", T_LONG
, offsetof(rangeobject
, step
), RO
},
193 {"start", T_LONG
, offsetof(rangeobject
, start
), RO
},
194 {"stop", T_LONG
, 0, RO
},
198 result
= Py_FindMethod(range_methods
, (PyObject
*) r
, name
);
199 if (result
== NULL
) {
201 if (strcmp("stop", name
) == 0)
202 result
= PyInt_FromLong(r
->start
+ (r
->len
* r
->step
));
204 result
= PyMember_Get((char *)r
, range_members
, name
);
210 range_contains(rangeobject
*r
, PyObject
*obj
)
212 long num
= PyInt_AsLong(obj
);
214 if (num
< 0 && PyErr_Occurred())
218 if ((num
< r
->start
) || ((num
- r
->start
) % r
->step
))
220 if (num
>= (r
->start
+ (r
->len
* r
->step
)))
224 if ((num
> r
->start
) || ((num
- r
->start
) % r
->step
))
226 if (num
<= (r
->start
+ (r
->len
* r
->step
)))
232 static PySequenceMethods range_as_sequence
= {
233 (inquiry
)range_length
, /*sq_length*/
234 (binaryfunc
)range_concat
, /*sq_concat*/
235 (intargfunc
)range_repeat
, /*sq_repeat*/
236 (intargfunc
)range_item
, /*sq_item*/
237 (intintargfunc
)range_slice
, /*sq_slice*/
240 (objobjproc
)range_contains
, /*sq_contains*/
243 PyTypeObject PyRange_Type
= {
244 PyObject_HEAD_INIT(&PyType_Type
)
245 0, /* Number of items for varobject */
246 "xrange", /* Name of this type */
247 sizeof(rangeobject
), /* Basic object size */
248 0, /* Item size for varobject */
249 (destructor
)range_dealloc
, /*tp_dealloc*/
251 (getattrfunc
)range_getattr
, /*tp_getattr*/
253 (cmpfunc
)range_compare
, /*tp_compare*/
254 (reprfunc
)range_repr
, /*tp_repr*/
256 &range_as_sequence
, /*tp_as_sequence*/
264 Py_TPFLAGS_DEFAULT
, /*tp_flags*/