Rip out the fancy behaviors of xrange that nobody uses: repeat, slice,

contains, tolist(), and the start/stop/step attributes.  This includes
removing the 4th ('repeat') argument to PyRange_New().
This commit is contained in:
Guido van Rossum 2001-07-05 13:27:48 +00:00
parent 25ddc6330f
commit 3f56166b1a
3 changed files with 18 additions and 229 deletions

View File

@ -775,12 +775,8 @@ xrange object will always take the same amount of memory, no matter the
size of the range it represents. There are no consistent performance size of the range it represents. There are no consistent performance
advantages. advantages.
XRange objects behave like tuples, and offer a single method: XRange objects have very little behavior: they only support indexing
and the \function{len()} function.
\begin{methoddesc}[xrange]{tolist}{}
Return a list object which represents the same values as the xrange
object.
\end{methoddesc}
\subsubsection{Mutable Sequence Types \label{typesseq-mutable}} \subsubsection{Mutable Sequence Types \label{typesseq-mutable}}

View File

@ -19,7 +19,7 @@ extern DL_IMPORT(PyTypeObject) PyRange_Type;
#define PyRange_Check(op) ((op)->ob_type == &PyRange_Type) #define PyRange_Check(op) ((op)->ob_type == &PyRange_Type)
extern DL_IMPORT(PyObject *) PyRange_New(long, long, long, int); extern DL_IMPORT(PyObject *) PyRange_New(long, long, long);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -10,58 +10,20 @@ typedef struct {
long start; long start;
long step; long step;
long len; long len;
int reps;
long totlen;
} rangeobject; } rangeobject;
static int
long_mul(long i, long j, long *kk)
{
PyObject *a;
PyObject *b;
PyObject *c;
if ((a = PyInt_FromLong(i)) == NULL)
return 0;
if ((b = PyInt_FromLong(j)) == NULL)
return 0;
c = PyNumber_Multiply(a, b);
Py_DECREF(a);
Py_DECREF(b);
if (c == NULL)
return 0;
*kk = PyInt_AS_LONG(c);
Py_DECREF(c);
if (*kk > INT_MAX) {
PyErr_SetString(PyExc_OverflowError,
"integer multiplication");
return 0;
}
else
return 1;
}
PyObject * PyObject *
PyRange_New(long start, long len, long step, int reps) PyRange_New(long start, long len, long step)
{ {
long totlen = -1;
rangeobject *obj = PyObject_NEW(rangeobject, &PyRange_Type); rangeobject *obj = PyObject_NEW(rangeobject, &PyRange_Type);
if (obj == NULL) if (obj == NULL)
return NULL; return NULL;
if (len == 0 || reps <= 0) { if (len == 0) {
start = 0; start = 0;
len = 0; len = 0;
step = 1; step = 1;
reps = 1;
totlen = 0;
} }
else { else {
long last = start + (len - 1) * step; long last = start + (len - 1) * step;
@ -71,20 +33,12 @@ PyRange_New(long start, long len, long step, int reps)
PyErr_SetString(PyExc_OverflowError, PyErr_SetString(PyExc_OverflowError,
"integer addition"); "integer addition");
return NULL; return NULL;
}
if (! long_mul(len, (long) reps, &totlen)) {
if(!PyErr_ExceptionMatches(PyExc_OverflowError))
return NULL;
PyErr_Clear();
totlen = -1;
} }
} }
obj->start = start; obj->start = start;
obj->len = len; obj->len = len;
obj->step = step; obj->step = step;
obj->reps = reps;
obj->totlen = totlen;
return (PyObject *) obj; return (PyObject *) obj;
} }
@ -98,12 +52,11 @@ range_dealloc(rangeobject *r)
static PyObject * static PyObject *
range_item(rangeobject *r, int i) range_item(rangeobject *r, int i)
{ {
if (i < 0 || i >= r->totlen) if (i < 0 || i >= r->len) {
if (r->totlen!=-1) { PyErr_SetString(PyExc_IndexError,
PyErr_SetString(PyExc_IndexError,
"xrange object index out of range"); "xrange object index out of range");
return NULL; return NULL;
} }
return PyInt_FromLong(r->start + (i % r->len) * r->step); return PyInt_FromLong(r->start + (i % r->len) * r->step);
} }
@ -111,10 +64,7 @@ range_item(rangeobject *r, int i)
static int static int
range_length(rangeobject *r) range_length(rangeobject *r)
{ {
if (r->totlen == -1) return r->len;
PyErr_SetString(PyExc_OverflowError,
"xrange object has too many items");
return r->totlen;
} }
static PyObject * static PyObject *
@ -124,7 +74,6 @@ range_repr(rangeobject *r)
* a bit of "(xrange(...) * ...)" text. * a bit of "(xrange(...) * ...)" text.
*/ */
char buf1[250]; char buf1[250];
char buf2[250];
if (r->start == 0 && r->step == 1) if (r->start == 0 && r->step == 1)
sprintf(buf1, "xrange(%ld)", r->start + r->len * r->step); sprintf(buf1, "xrange(%ld)", r->start + r->len * r->step);
@ -140,174 +89,18 @@ range_repr(rangeobject *r)
r->start + r->len * r->step, r->start + r->len * r->step,
r->step); r->step);
if (r->reps != 1) return PyString_FromString(buf1);
sprintf(buf2, "(%s * %d)", buf1, r->reps);
return PyString_FromString(r->reps == 1 ? buf1 : buf2);
}
static PyObject *
range_concat(rangeobject *r, PyObject *obj)
{
PyErr_SetString(PyExc_TypeError, "cannot concatenate xrange objects");
return NULL;
}
static PyObject *
range_repeat(rangeobject *r, int n)
{
long lreps = 0;
if (n <= 0)
return (PyObject *) PyRange_New(0, 0, 1, 1);
else if (n == 1) {
Py_INCREF(r);
return (PyObject *) r;
}
else if (! long_mul((long) r->reps, (long) n, &lreps))
return NULL;
else
return (PyObject *) PyRange_New(
r->start,
r->len,
r->step,
(int) lreps);
}
static int
range_compare(rangeobject *r1, rangeobject *r2)
{
if (r1->start != r2->start)
return r1->start - r2->start;
else if (r1->step != r2->step)
return r1->step - r2->step;
else if (r1->len != r2->len)
return r1->len - r2->len;
else
return r1->reps - r2->reps;
}
static PyObject *
range_slice(rangeobject *r, int low, int high)
{
if (r->reps != 1) {
PyErr_SetString(PyExc_TypeError,
"cannot slice a replicated xrange");
return NULL;
}
if (low < 0)
low = 0;
else if (low > r->len)
low = r->len;
if (high < 0)
high = 0;
if (high < low)
high = low;
else if (high > r->len)
high = r->len;
if (low == 0 && high == r->len) {
Py_INCREF(r);
return (PyObject *) r;
}
return (PyObject *) PyRange_New(
low * r->step + r->start,
high - low,
r->step,
1);
}
static PyObject *
range_tolist(rangeobject *self, PyObject *args)
{
PyObject *thelist;
int j;
if (! PyArg_ParseTuple(args, ":tolist"))
return NULL;
if (self->totlen == -1)
return PyErr_NoMemory();
if ((thelist = PyList_New(self->totlen)) == NULL)
return NULL;
for (j = 0; j < self->totlen; ++j)
if ((PyList_SetItem(thelist, j, (PyObject *) PyInt_FromLong(
self->start + (j % self->len) * self->step))) < 0)
return NULL;
return thelist;
}
static PyObject *
range_getattr(rangeobject *r, char *name)
{
PyObject *result;
static PyMethodDef range_methods[] = {
{"tolist", (PyCFunction)range_tolist, METH_VARARGS,
"tolist() -> list\n"
"Return a list object with the same values."},
{NULL, NULL}
};
static struct memberlist range_members[] = {
{"step", T_LONG, offsetof(rangeobject, step), RO},
{"start", T_LONG, offsetof(rangeobject, start), RO},
{"stop", T_LONG, 0, RO},
{NULL, 0, 0, 0}
};
result = Py_FindMethod(range_methods, (PyObject *) r, name);
if (result == NULL) {
PyErr_Clear();
if (strcmp("stop", name) == 0)
result = PyInt_FromLong(r->start + (r->len * r->step));
else
result = PyMember_Get((char *)r, range_members, name);
}
return result;
}
static int
range_contains(rangeobject *r, PyObject *obj)
{
long num = PyInt_AsLong(obj);
if (num < 0 && PyErr_Occurred())
return -1;
if (r->step > 0) {
if ((num < r->start) || ((num - r->start) % r->step))
return 0;
if (num >= (r->start + (r->len * r->step)))
return 0;
}
else {
if ((num > r->start) || ((num - r->start) % r->step))
return 0;
if (num <= (r->start + (r->len * r->step)))
return 0;
}
return 1;
} }
static PySequenceMethods range_as_sequence = { static PySequenceMethods range_as_sequence = {
(inquiry)range_length, /*sq_length*/ (inquiry)range_length, /*sq_length*/
(binaryfunc)range_concat, /*sq_concat*/ 0, /*sq_concat*/
(intargfunc)range_repeat, /*sq_repeat*/ 0, /*sq_repeat*/
(intargfunc)range_item, /*sq_item*/ (intargfunc)range_item, /*sq_item*/
(intintargfunc)range_slice, /*sq_slice*/ 0, /*sq_slice*/
0, /*sq_ass_item*/ 0, /*sq_ass_item*/
0, /*sq_ass_slice*/ 0, /*sq_ass_slice*/
(objobjproc)range_contains, /*sq_contains*/ 0, /*sq_contains*/
}; };
PyTypeObject PyRange_Type = { PyTypeObject PyRange_Type = {
@ -318,9 +111,9 @@ PyTypeObject PyRange_Type = {
0, /* Item size for varobject */ 0, /* Item size for varobject */
(destructor)range_dealloc, /*tp_dealloc*/ (destructor)range_dealloc, /*tp_dealloc*/
0, /*tp_print*/ 0, /*tp_print*/
(getattrfunc)range_getattr, /*tp_getattr*/ 0, /*tp_getattr*/
0, /*tp_setattr*/ 0, /*tp_setattr*/
(cmpfunc)range_compare, /*tp_compare*/ 0, /*tp_compare*/
(reprfunc)range_repr, /*tp_repr*/ (reprfunc)range_repr, /*tp_repr*/
0, /*tp_as_number*/ 0, /*tp_as_number*/
&range_as_sequence, /*tp_as_sequence*/ &range_as_sequence, /*tp_as_sequence*/