mirror of https://github.com/python/cpython
171 lines
3.6 KiB
C
171 lines
3.6 KiB
C
|
|
/* Range object implementation */
|
|
|
|
#include "Python.h"
|
|
|
|
typedef struct {
|
|
PyObject_HEAD
|
|
long start;
|
|
long step;
|
|
long len;
|
|
long index;
|
|
int used; /* Set to 1 if called by range_getiter */
|
|
} rangeobject;
|
|
|
|
PyObject *
|
|
PyRange_New(long start, long len, long step, int reps)
|
|
{
|
|
rangeobject *obj;
|
|
|
|
if (reps != 1) {
|
|
PyErr_SetString(PyExc_ValueError,
|
|
"PyRange_New's 'repetitions' argument must be 1");
|
|
return NULL;
|
|
}
|
|
|
|
obj = PyObject_New(rangeobject, &PyRange_Type);
|
|
if (obj == NULL)
|
|
return NULL;
|
|
|
|
if (len == 0) {
|
|
start = 0;
|
|
len = 0;
|
|
step = 1;
|
|
}
|
|
else {
|
|
long last = start + (len - 1) * step;
|
|
if ((step > 0) ?
|
|
(last > (PyInt_GetMax() - step)) :
|
|
(last < (-1 - PyInt_GetMax() - step))) {
|
|
PyErr_SetString(PyExc_OverflowError,
|
|
"integer addition");
|
|
return NULL;
|
|
}
|
|
}
|
|
obj->start = start;
|
|
obj->len = len;
|
|
obj->step = step;
|
|
obj->index = 0;
|
|
obj->used = 0;
|
|
|
|
return (PyObject *) obj;
|
|
}
|
|
|
|
static PyObject *
|
|
range_item(rangeobject *r, int i)
|
|
{
|
|
if (i < 0 || i >= r->len) {
|
|
PyErr_SetString(PyExc_IndexError,
|
|
"xrange object index out of range");
|
|
return NULL;
|
|
}
|
|
return PyInt_FromLong(r->start + (i % r->len) * r->step);
|
|
}
|
|
|
|
static int
|
|
range_length(rangeobject *r)
|
|
{
|
|
return r->len;
|
|
}
|
|
|
|
static PyObject *
|
|
range_repr(rangeobject *r)
|
|
{
|
|
PyObject *rtn;
|
|
|
|
if (r->start == 0 && r->step == 1)
|
|
rtn = PyString_FromFormat("xrange(%ld)",
|
|
r->start + r->len * r->step);
|
|
|
|
else if (r->step == 1)
|
|
rtn = PyString_FromFormat("xrange(%ld, %ld)",
|
|
r->start,
|
|
r->start + r->len * r->step);
|
|
|
|
else
|
|
rtn = PyString_FromFormat("xrange(%ld, %ld, %ld)",
|
|
r->start,
|
|
r->start + r->len * r->step,
|
|
r->step);
|
|
return rtn;
|
|
}
|
|
|
|
static PyObject *
|
|
range_getiter(rangeobject *r)
|
|
{
|
|
rangeobject *obj;
|
|
if (r->used == 0 || r->index >= r->len) {
|
|
Py_INCREF(r);
|
|
r->used = 1;
|
|
r->index = 0;
|
|
return (PyObject *)r;
|
|
}
|
|
|
|
obj = PyObject_NEW(rangeobject, &PyRange_Type);
|
|
if (obj == NULL)
|
|
return NULL;
|
|
|
|
obj->start = r->start;
|
|
obj->len = r->len;
|
|
obj->step = r->step;
|
|
obj->index = 0;
|
|
obj->used = 1;
|
|
return (PyObject *) obj;
|
|
}
|
|
|
|
static PyObject *
|
|
range_next(rangeobject *r)
|
|
{
|
|
if (r->index >= r->len) {
|
|
PyErr_SetObject(PyExc_StopIteration, Py_None);
|
|
return NULL;
|
|
}
|
|
return PyInt_FromLong(r->start + (r->index++) * r->step);
|
|
}
|
|
|
|
static PyMethodDef range_methods[] = {
|
|
{"next", (PyCFunction)range_next, METH_NOARGS,
|
|
"it.next() -- get the next value, or raise StopIteration"},
|
|
{NULL, NULL} /* sentinel */
|
|
};
|
|
|
|
static PySequenceMethods range_as_sequence = {
|
|
(inquiry)range_length, /* sq_length */
|
|
0, /* sq_concat */
|
|
0, /* sq_repeat */
|
|
(intargfunc)range_item, /* sq_item */
|
|
0, /* sq_slice */
|
|
};
|
|
|
|
PyTypeObject PyRange_Type = {
|
|
PyObject_HEAD_INIT(&PyType_Type)
|
|
0, /* Number of items for varobject */
|
|
"xrange", /* Name of this type */
|
|
sizeof(rangeobject), /* Basic object size */
|
|
0, /* Item size for varobject */
|
|
(destructor)PyObject_Del, /* tp_dealloc */
|
|
0, /* tp_print */
|
|
0, /* tp_getattr */
|
|
0, /* tp_setattr */
|
|
0, /* tp_compare */
|
|
(reprfunc)range_repr, /* tp_repr */
|
|
0, /* tp_as_number */
|
|
&range_as_sequence, /* tp_as_sequence */
|
|
0, /* tp_as_mapping */
|
|
0, /* tp_hash */
|
|
0, /* tp_call */
|
|
0, /* tp_str */
|
|
PyObject_GenericGetAttr, /* tp_getattro */
|
|
0, /* tp_setattro */
|
|
0, /* tp_as_buffer */
|
|
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
|
0, /* tp_doc */
|
|
0, /* tp_traverse */
|
|
0, /* tp_clear */
|
|
0, /* tp_richcompare */
|
|
0, /* tp_weaklistoffset */
|
|
(getiterfunc)range_getiter, /* tp_iter */
|
|
(iternextfunc)range_next, /* tp_iternext */
|
|
range_methods, /* tp_methods */
|
|
};
|