Benjamin Peterson <[EMAIL PROTECTED]> added the comment:

On Thu, May 1, 2008 at 9:38 PM, Alexander Belopolsky
<[EMAIL PROTECTED]> wrote:
>
>  Alexander Belopolsky <[EMAIL PROTECTED]> added the comment:
>
>  The start/step/stop getter functions should INCREF return values.  Is
>  there a reason not to adapt slice implementation:

No, its much simpler.

Added file: http://bugs.python.org/file10155/range_lean_and_mean2.patch

__________________________________
Tracker <[EMAIL PROTECTED]>
<http://bugs.python.org/issue2735>
__________________________________
Index: Objects/rangeobject.c
===================================================================
--- Objects/rangeobject.c       (revision 62626)
+++ Objects/rangeobject.c       (working copy)
@@ -1,6 +1,7 @@
 /* Range object implementation */
 
 #include "Python.h"
+#include "structmember.h"
 
 /* Support objects whose length is > PY_SSIZE_T_MAX.
 
@@ -14,6 +15,7 @@
     PyObject *start;
     PyObject *stop;
     PyObject *step;
+    PyObject *length;
 } rangeobject;
 
 /* Helper function for validating step.  Always returns a new reference or
@@ -43,6 +45,9 @@
     return step;
 }
 
+static PyObject* range_compute_length(PyObject *start,
+                                      PyObject *stop, PyObject *step);
+
 /* XXX(nnorwitz): should we error check if the user passes any empty ranges?
    range(-10)
    range(0, -5)
@@ -52,7 +57,7 @@
 range_new(PyTypeObject *type, PyObject *args, PyObject *kw)
 {
     rangeobject *obj = NULL;
-    PyObject *start = NULL, *stop = NULL, *step = NULL;
+    PyObject *start = NULL, *stop = NULL, *step = NULL, *length = NULL;
 
     if (!_PyArg_NoKeywords("range()", kw))
         return NULL;
@@ -81,25 +86,30 @@
             goto Fail;
     }
 
+    length = range_compute_length(start, stop, step);
+    if (length == NULL)
+       goto Fail;
     obj = PyObject_New(rangeobject, &PyRange_Type);
     if (obj == NULL)
         goto Fail;
     obj->start = start;
     obj->stop = stop;
     obj->step = step;
+    obj->length = length;
     return (PyObject *) obj;
 
 Fail:
     Py_XDECREF(start);
     Py_XDECREF(stop);
     Py_XDECREF(step);
+    Py_XDECREF(length);
     return NULL;
 }
 
 PyDoc_STRVAR(range_doc,
 "range([start,] stop[, step]) -> range object\n\
 \n\
-Returns an iterator that generates the numbers in the range on demand.");
+Returns a virtual sequence of numbers from start to stop by step.");
 
 static void
 range_dealloc(rangeobject *r)
@@ -107,6 +117,7 @@
     Py_DECREF(r->start);
     Py_DECREF(r->stop);
     Py_DECREF(r->step);
+    Py_DECREF(r->length);
     PyObject_Del(r);
 }
 
@@ -116,8 +127,8 @@
  * Arguments MUST return 1 with either PyLong_Check() or
  * PyLong_Check().  Return -1 when there is an error.
  */
-static PyObject*
-range_length_obj(rangeobject *r)
+static PyObject *
+range_compute_length(PyObject *start, PyObject *stop, PyObject *step)
 {
     /* -------------------------------------------------------------
     Algorithm is equal to that of get_len_of_range(), but it operates
@@ -125,7 +136,6 @@
     ---------------------------------------------------------------*/
     int cmp_result, cmp_call;
     PyObject *lo, *hi;
-    PyObject *step = NULL;
     PyObject *diff = NULL;
     PyObject *one = NULL;
     PyObject *tmp1 = NULL, *tmp2 = NULL, *result;
@@ -134,23 +144,22 @@
     PyObject *zero = PyLong_FromLong(0);
     if (zero == NULL)
         return NULL;
-    cmp_call = PyObject_Cmp(r->step, zero, &cmp_result);
+    cmp_call = PyObject_Cmp(step, zero, &cmp_result);
     Py_DECREF(zero);
     if (cmp_call == -1)
         return NULL;
 
     assert(cmp_result != 0);
     if (cmp_result > 0) {
-        lo = r->start;
-        hi = r->stop;
-        step = r->step;
+        lo = start;
+        hi = stop;
         Py_INCREF(step);
     } else {
-        lo = r->stop;
-        hi = r->start;
-        step = PyNumber_Negative(r->step);
+        lo = stop;
+        hi = start;
+        step = PyNumber_Negative(step);
         if (!step)
-            return NULL;
+            goto Fail;
     }
 
     /* if (lo >= hi), return length of 0. */
@@ -193,46 +202,11 @@
 static Py_ssize_t
 range_length(rangeobject *r)
 {
-    PyObject *len = range_length_obj(r);
-    Py_ssize_t result = -1;
-    if (len) {
-        result = PyLong_AsSsize_t(len);
-        Py_DECREF(len);
-    }
-    return result;
+    return PyLong_AsSsize_t(r->length);
 }
 
-/* range(...)[x] is necessary for:  seq[:] = range(...) */
 
 static PyObject *
-range_item(rangeobject *r, Py_ssize_t i)
-{
-    Py_ssize_t len = range_length(r);
-    PyObject *rem, *incr, *result;
-
-    /* XXX(nnorwitz): should negative indices be supported? */
-    /* XXX(nnorwitz): should support range[x] where x > PY_SSIZE_T_MAX? */
-    if (i < 0 || i >= len) {
-        if (!PyErr_Occurred())
-            PyErr_SetString(PyExc_IndexError,
-                            "range object index out of range");
-        return NULL;
-    }
-
-    /* XXX(nnorwitz): optimize for short ints. */
-    rem = PyLong_FromSsize_t(i);
-    if (!rem)
-        return NULL;
-    incr = PyNumber_Multiply(rem, r->step);
-    Py_DECREF(rem);
-    if (!incr)
-        return NULL;
-    result = PyNumber_Add(r->start, incr);
-    Py_DECREF(incr);
-    return result;
-}
-
-static PyObject *
 range_repr(rangeobject *r)
 {
     Py_ssize_t istep;
@@ -252,12 +226,22 @@
                                     r->start, r->stop, r->step);
 }
 
+static PyMemberDef range_members[] = {
+    {"start", T_OBJECT, offsetof(rangeobject, start), READONLY},
+    {"stop", T_OBJECT, offsetof(rangeobject, stop), READONLY},
+    {"step", T_OBJECT, offsetof(rangeobject, step), READONLY},
+    {0}
+};
+
 static PySequenceMethods range_as_sequence = {
     (lenfunc)range_length,     /* sq_length */
-    0,                 /* sq_concat */
-    0,                 /* sq_repeat */
-    (ssizeargfunc)range_item, /* sq_item */
-    0,                 /* sq_slice */
+    0,                         /* sq_concat */
+    0,                         /* sq_repeat */
+    0,                          /* sq_item */
+    0,                         /* sq_slice */
+    0,                          /* sq_ass_item */ 
+    0,                          /* sq_ass_slice */ 
+    0,                          /* sq_contains */ 
 };
 
 static PyObject * range_iter(PyObject *seq);
@@ -285,7 +269,7 @@
        (reprfunc)range_repr,   /* tp_repr */
        0,                      /* tp_as_number */
        &range_as_sequence,     /* tp_as_sequence */
-       0,                      /* tp_as_mapping */
+       0,                      /* tp_as_mapping */
        0,                      /* tp_hash */
        0,                      /* tp_call */
        0,                      /* tp_str */
@@ -301,8 +285,8 @@
        range_iter,             /* tp_iter */
        0,                      /* tp_iternext */
        range_methods,          /* tp_methods */
-       0,                      /* tp_members */
-       0,                      /* tp_getset */
+       range_members,          /* tp_members */
+       0,                      /* tp_getset */
        0,                      /* tp_base */
        0,                      /* tp_dict */
        0,                      /* tp_descr_get */
@@ -647,9 +631,7 @@
         return NULL;
 
     /* start + (len - 1) * step */
-    len = range_length_obj(range);
-    if (!len)
-        goto create_failure;
+    len = range->length;
 
     one = PyLong_FromLong(1);
     if (!one)
Index: Lib/test/test_range.py
===================================================================
--- Lib/test/test_range.py      (revision 62626)
+++ Lib/test/test_range.py      (working copy)
@@ -61,6 +61,16 @@
         self.assertEqual(repr(range(1, 2)), 'range(1, 2)')
         self.assertEqual(repr(range(1, 2, 3)), 'range(1, 2, 3)')
 
+    def test_attributes(self):
+        r = range(0, 10, 2)
+        self.assertEqual(r.start, 0)
+        self.assertEqual(r.stop, 10)
+        self.assertEqual(r.step, 2)
+        r = range(10)
+        self.assertEqual(r.start, 0)
+        self.assertEqual(r.stop, 10)
+        self.assertEqual(r.step, 1)
+
 def test_main():
     test.test_support.run_unittest(RangeTest)
 
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to