cpython/Objects/rangeobject.c

215 lines
5.3 KiB
C

/* Range object implementation */
#include "Python.h"
typedef struct {
PyObject_HEAD
long start;
long step;
long len;
} 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;
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 PySequenceMethods range_as_sequence = {
(inquiry)range_length, /* sq_length */
0, /* sq_concat */
0, /* sq_repeat */
(intargfunc)range_item, /* sq_item */
0, /* sq_slice */
};
staticforward PyObject * range_iter(PyObject *seq);
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 */
0, /* 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_iter, /* tp_iter */
};
/*********************** Xrange Iterator **************************/
typedef struct {
PyObject_HEAD
long index;
long start;
long step;
long len;
} rangeiterobject;
PyTypeObject Pyrangeiter_Type;
PyObject *
range_iter(PyObject *seq)
{
rangeiterobject *it;
if (!PyRange_Check(seq)) {
PyErr_BadInternalCall();
return NULL;
}
it = PyObject_New(rangeiterobject, &Pyrangeiter_Type);
if (it == NULL)
return NULL;
it->index = 0;
it->start = ((rangeobject *)seq)->start;
it->step = ((rangeobject *)seq)->step;
it->len = ((rangeobject *)seq)->len;
return (PyObject *)it;
}
static PyObject *
rangeiter_getiter(PyObject *it)
{
Py_INCREF(it);
return it;
}
static PyObject *
rangeiter_next(rangeiterobject *r)
{
if (r->index < r->len)
return PyInt_FromLong(r->start + (r->index++) * r->step);
PyErr_SetObject(PyExc_StopIteration, Py_None);
return NULL;
}
static PyMethodDef rangeiter_methods[] = {
{"next", (PyCFunction)rangeiter_next, METH_NOARGS,
"it.next() -- get the next value, or raise StopIteration"},
{NULL, NULL} /* sentinel */
};
PyTypeObject Pyrangeiter_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0, /* ob_size */
"rangeiterator", /* tp_name */
sizeof(rangeiterobject), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
(destructor)PyObject_Del, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
0, /* tp_as_number */
0, /* 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)rangeiter_getiter, /* tp_iter */
(iternextfunc)rangeiter_next, /* tp_iternext */
rangeiter_methods, /* tp_methods */
};