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