diff options
-rw-r--r-- | Include/rangeobject.h | 2 | ||||
-rw-r--r-- | Objects/rangeobject.c | 235 | ||||
-rw-r--r-- | Python/bltinmodule.c | 2 |
3 files changed, 221 insertions, 18 deletions
diff --git a/Include/rangeobject.h b/Include/rangeobject.h index 9855cf2..ff6dbc2 100644 --- a/Include/rangeobject.h +++ b/Include/rangeobject.h @@ -19,7 +19,7 @@ extern DL_IMPORT(PyTypeObject) PyRange_Type; #define PyRange_Check(op) ((op)->ob_type == &PyRange_Type) -extern DL_IMPORT(PyObject *) PyRange_New(long, long, long); +extern DL_IMPORT(PyObject *) PyRange_New(long, long, long, int); #ifdef __cplusplus } diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c index 0b0966f..1f446df 100644 --- a/Objects/rangeobject.c +++ b/Objects/rangeobject.c @@ -5,40 +5,92 @@ #include "structmember.h" #include <string.h> +#define WARN(msg) if (PyErr_Warn(PyExc_DeprecationWarning, msg) < 0) \ + return NULL; + typedef struct { PyObject_HEAD long start; long step; long len; + int reps; + long totlen; } 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 * -PyRange_New(long start, long len, long step) +PyRange_New(long start, long len, long step, int reps) { + long totlen = -1; rangeobject *obj = PyObject_NEW(rangeobject, &PyRange_Type); if (obj == NULL) return NULL; + + if (reps != 1) + WARN("PyRange_New's 'repetitions' argument is deprecated"); - if (len == 0) { + if (len == 0 || reps <= 0) { start = 0; len = 0; step = 1; + reps = 1; + totlen = 0; } else { long last = start + (len - 1) * step; if ((step > 0) ? - (last > (PyInt_GetMax() - step)) - :(last < (-1 - PyInt_GetMax() - step))) { + (last > (PyInt_GetMax() - step)) : + (last < (-1 - PyInt_GetMax() - step))) { PyErr_SetString(PyExc_OverflowError, "integer addition"); return NULL; + } + if (! long_mul(len, (long) reps, &totlen)) { + if(!PyErr_ExceptionMatches(PyExc_OverflowError)) + return NULL; + PyErr_Clear(); + totlen = -1; } } obj->start = start; obj->len = len; obj->step = step; + obj->reps = reps; + obj->totlen = totlen; return (PyObject *) obj; } @@ -52,11 +104,12 @@ range_dealloc(rangeobject *r) static PyObject * range_item(rangeobject *r, int i) { - if (i < 0 || i >= r->len) { - PyErr_SetString(PyExc_IndexError, + if (i < 0 || i >= r->totlen) + if (r->totlen!=-1) { + PyErr_SetString(PyExc_IndexError, "xrange object index out of range"); - return NULL; - } + return NULL; + } return PyInt_FromLong(r->start + (i % r->len) * r->step); } @@ -64,7 +117,10 @@ range_item(rangeobject *r, int i) static int range_length(rangeobject *r) { - return r->len; + if (r->totlen == -1) + PyErr_SetString(PyExc_OverflowError, + "xrange object has too many items"); + return r->totlen; } static PyObject * @@ -74,6 +130,7 @@ range_repr(rangeobject *r) * a bit of "(xrange(...) * ...)" text. */ char buf1[250]; + char buf2[250]; if (r->start == 0 && r->step == 1) sprintf(buf1, "xrange(%ld)", r->start + r->len * r->step); @@ -89,18 +146,162 @@ range_repr(rangeobject *r) r->start + r->len * r->step, r->step); - return PyString_FromString(buf1); + if (r->reps != 1) + sprintf(buf2, "(%s * %d)", buf1, r->reps); + + return PyString_FromString(r->reps == 1 ? buf1 : buf2); +} + +static PyObject * +range_repeat(rangeobject *r, int n) +{ + long lreps = 0; + + WARN("xrange object multiplication is deprecated; " + "convert to list instead"); + + 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 (PyErr_Warn(PyExc_DeprecationWarning, + "xrange object comparision is deprecated; " + "convert to list instead") < 0) + return -1; + + 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) +{ + WARN("xrange object slicing is deprecated; " + "convert to list instead"); + + 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; + + WARN("xrange.tolist() is deprecated; use list(xrange) instead"); + + 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.\n" + "(This method is deprecated; use list() instead.)"}, + {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); + if (result) + WARN("xrange object's 'start', 'stop' and 'step' " + "attributes are deprecated"); + } + return result; } static PySequenceMethods range_as_sequence = { (inquiry)range_length, /*sq_length*/ 0, /*sq_concat*/ - 0, /*sq_repeat*/ - (intargfunc)range_item, /*sq_item*/ - 0, /*sq_slice*/ + (intargfunc)range_repeat, /*sq_repeat*/ + (intargfunc)range_item, /*sq_item*/ + (intintargfunc)range_slice, /*sq_slice*/ 0, /*sq_ass_item*/ 0, /*sq_ass_slice*/ - 0, /*sq_contains*/ + 0, /*sq_contains*/ }; PyTypeObject PyRange_Type = { @@ -111,9 +312,9 @@ PyTypeObject PyRange_Type = { 0, /* Item size for varobject */ (destructor)range_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ - 0, /*tp_getattr*/ + (getattrfunc)range_getattr, /*tp_getattr*/ 0, /*tp_setattr*/ - 0, /*tp_compare*/ + (cmpfunc)range_compare, /*tp_compare*/ (reprfunc)range_repr, /*tp_repr*/ 0, /*tp_as_number*/ &range_as_sequence, /*tp_as_sequence*/ @@ -126,3 +327,5 @@ PyTypeObject PyRange_Type = { 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT, /*tp_flags*/ }; + +#undef WARN diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index d23bbf3..11d6f4c 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -1763,7 +1763,7 @@ builtin_xrange(PyObject *self, PyObject *args) "xrange() result has too many items"); return NULL; } - return PyRange_New(ilow, n, istep); + return PyRange_New(ilow, n, istep, 1); } static char xrange_doc[] = |