]> granicus.if.org Git - python/commitdiff
Tidied up the implementations of reversed (including the custom ones
authorRaymond Hettinger <python@rcn.com>
Wed, 10 Mar 2004 10:10:42 +0000 (10:10 +0000)
committerRaymond Hettinger <python@rcn.com>
Wed, 10 Mar 2004 10:10:42 +0000 (10:10 +0000)
for xrange and list objects).

* list.__reversed__ now checks the length of the sequence object before
  calling PyList_GET_ITEM() because the mutable could have changed length.

* all three implementations are now tranparent with respect to length and
  maintain the invariant len(it) == len(list(it)) even when the underlying
  sequence mutates.

* __builtin__.reversed() now frees the underlying sequence as soon
  as the iterator is exhausted.

* the code paths were rearranged so that the most common paths
  do not require a jump.

Lib/test/test_enumerate.py
Objects/enumobject.c
Objects/listobject.c
Objects/rangeobject.c

index 34bc71db243768753bd3ba05b408c528d0327e3d..200779fb98775da92d1a8c28c3f825aaa1a49b1b 100644 (file)
@@ -143,8 +143,8 @@ class TestReversed(unittest.TestCase):
 
     def test_len(self):
         # This is an implementation detail, not an interface requirement
-        s = 'hello'
-        self.assertEqual(len(reversed(s)), len(s))
+        for s in ('hello', tuple('hello'), list('hello'), xrange(5)):
+            self.assertEqual(len(reversed(s)), len(s))
 
 def test_main(verbose=None):
     testclasses = (EnumerateTestCase, SubclassTestCase, TestEmpty, TestBig,
index 1d13123558d9fbe7a4566720efb0a1ed17ea3cde..28719a9ce359f65d4ec5c40c973249b371377999 100644 (file)
@@ -217,23 +217,21 @@ static PyObject *
 reversed_next(reversedobject *ro)
 {
        PyObject *item;
+       long index = ro->index;
 
-       if (ro->index < 0)
-               return NULL;
-
-       assert(PySequence_Check(ro->seq));
-       item = PySequence_GetItem(ro->seq, ro->index);
-       if (item == NULL)
-               return NULL;
-
-       ro->index--;
-       return item;
-}
-
-static int
-reversed_len(reversedobject *ro)
-{
-       return PyObject_Size(ro->seq);
+       if (index >= 0) {
+               item = PySequence_GetItem(ro->seq, index);
+               if (item != NULL) {
+                       ro->index--;
+                       return item;
+               }
+       }
+       ro->index = -1;
+       if (ro->seq != NULL) {
+               Py_DECREF(ro->seq);
+               ro->seq = NULL;
+       }
+       return NULL;
 }
 
 PyDoc_STRVAR(reversed_doc,
@@ -241,6 +239,12 @@ PyDoc_STRVAR(reversed_doc,
 "\n"
 "Return a reverse iterator");
 
+static int
+reversed_len(reversedobject *ro)
+{
+       return ro->index + 1;
+}
+
 static PySequenceMethods reversed_as_sequence = {
        (inquiry)reversed_len,          /* sq_length */
        0,                              /* sq_concat */
index 47f4a37b9984c8cf74c1ef021076a3ebc05a9fef..500f823a9c56c7fc48f5b6a50dfb8b7973812e41 100644 (file)
@@ -2793,21 +2793,35 @@ listreviter_traverse(listreviterobject *it, visitproc visit, void *arg)
 static PyObject *
 listreviter_next(listreviterobject *it)
 {
-       PyObject *item = NULL;
+       PyObject *item;
+       long index = it->it_index;
+       PyListObject *seq = it->it_seq;
 
-       assert(PyList_Check(it->it_seq));
-       if (it->it_index >= 0) {
-               assert(it->it_index < PyList_GET_SIZE(it->it_seq));
-               item = PyList_GET_ITEM(it->it_seq, it->it_index);
+       if (index>=0 && index < PyList_GET_SIZE(seq)) {
+               item = PyList_GET_ITEM(seq, index);
                it->it_index--;
                Py_INCREF(item);
-       } else if (it->it_seq != NULL) {
-               Py_DECREF(it->it_seq);
+               return item;
+       }
+       it->it_index = -1;
+       if (seq != NULL) {
                it->it_seq = NULL;
+               Py_DECREF(seq);
        }
-       return item;
+       return NULL;
 }
 
+static int
+listreviter_len(listreviterobject *it)
+{
+       return it->it_index + 1;
+}
+
+static PySequenceMethods listreviter_as_sequence = {
+       (inquiry)listreviter_len,       /* sq_length */
+       0,                              /* sq_concat */
+};
+
 PyTypeObject PyListRevIter_Type = {
        PyObject_HEAD_INIT(&PyType_Type)
        0,                                      /* ob_size */
@@ -2822,7 +2836,7 @@ PyTypeObject PyListRevIter_Type = {
        0,                                      /* tp_compare */
        0,                                      /* tp_repr */
        0,                                      /* tp_as_number */
-       0,                                      /* tp_as_sequence */
+       &listreviter_as_sequence,               /* tp_as_sequence */
        0,                                      /* tp_as_mapping */
        0,                                      /* tp_hash */
        0,                                      /* tp_call */
index 1f5672804f31c2acbfbdda2031d2c16cf32fdb8c..a6d1611a155bc84725a97d2c672e540ebf6edb83 100644 (file)
@@ -288,6 +288,18 @@ rangeiter_next(rangeiterobject *r)
        return NULL;
 }
 
+static int
+rangeiter_len(rangeiterobject *r)
+{
+       return r->len - r->index;
+}
+
+static PySequenceMethods rangeiter_as_sequence = {
+       (inquiry)rangeiter_len,         /* sq_length */
+       0,                              /* sq_concat */
+};
+
+
 static PyTypeObject Pyrangeiter_Type = {
        PyObject_HEAD_INIT(&PyType_Type)
        0,                                      /* ob_size */
@@ -302,7 +314,7 @@ static PyTypeObject Pyrangeiter_Type = {
        0,                                      /* tp_compare */
        0,                                      /* tp_repr */
        0,                                      /* tp_as_number */
-       0,                                      /* tp_as_sequence */
+       &rangeiter_as_sequence,                 /* tp_as_sequence */
        0,                                      /* tp_as_mapping */
        0,                                      /* tp_hash */
        0,                                      /* tp_call */