]> granicus.if.org Git - python/commitdiff
Re-add 'advanced' xrange features, adding DeprecationWarnings as discussed
authorThomas Wouters <thomas@python.org>
Mon, 9 Jul 2001 12:30:54 +0000 (12:30 +0000)
committerThomas Wouters <thomas@python.org>
Mon, 9 Jul 2001 12:30:54 +0000 (12:30 +0000)
on python-dev. The features will still vanish, however, just one release
later.

Include/rangeobject.h
Objects/rangeobject.c
Python/bltinmodule.c

index 9855cf2a5d8d5130437899016676c1d995a3b293..ff6dbc2871798188e67aeb8c1dc41a5841e61f25 100644 (file)
@@ -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
 }
index 0b0966f622632ec4cc9e9ff1b8b7b28cca2471a1..1f446df2dd4c82cfcb0ff7160a240ec62896210c 100644 (file)
@@ -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
index d23bbf3c67ee9ec3a216b4c5eebe2f56b2891aa4..11d6f4c41cb7234ba5dce0250a6b0ae38b8f74c1 100644 (file)
@@ -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[] =