[Zope-Checkins] CVS: Zope3/lib/python/Persistence/BTrees - BTreeItemsTemplate.c:1.9

Tim Peters tim.one@comcast.net
Wed, 17 Jul 2002 16:40:07 -0400


Update of /cvs-repository/Zope3/lib/python/Persistence/BTrees
In directory cvs.zope.org:/tmp/cvs-serv29274

Modified Files:
	BTreeItemsTemplate.c 
Log Message:
Refinements due to clarification of the iteration protocol recently
hammered out on Python-Dev:

+ It's unnecessary and undesirable for an iterator to supply both
  tp_iternext and an explicit next() method.  Got rid of the latter
  for BTreeItems iterators.  Python supplies a next() method wrapper
  automatically then.

+ Since the BTreeIter_next() function no longer has to serve for both
  tp_iternext and explict next(), remove the coded for explicitly raising
  StopIteration at termination.  That's required of explicit next()
  methods, but not necessary for tp_iternext slots (and is also undesirable
  for them, because it costs extra cycles and the caller may not require
  it).

+ As was recently done for dict iterators in the core, if the BTreeItems
  iterator detects that mutation has occurred between calls to
  BTreeIter_next, the error it raises is made sticky (i.e., call the
  iterator again, and you're going to get the same complaint again).  It's
  quite unlikely that a BTreeItems iterator will detect mutation, though.

+ The BTreeItems iterator already made StopIteration a sink state, so
  nothing new to do there.


=== Zope3/lib/python/Persistence/BTrees/BTreeItemsTemplate.c 1.8 => 1.9 ===
 	PyObject_Del(bi);
 }
 
-/* The implementation of the iterator's .next() method.  Returns "the next"
- * item; returns NULL if error; returns NULL and sets StopIteration if the
+/* The implementation of the iterator's tp_iternext slot.  Returns "the next"
+ * item; returns NULL if error; returns NULL without setting an error if the
  * iteration is exhausted (that's the way to terminate the iteration protocol).
  */
 static PyObject *
@@ -617,18 +617,18 @@
         int i = items->currentoffset;
 	Bucket *bucket = items->currentbucket;
 
-        if (bucket == NULL) {
-            PyErr_SetObject(PyExc_StopIteration, Py_None);
+        if (bucket == NULL)	/* iteration termination is sticky */
 	    return NULL;
-        }
 
         PER_USE_OR_RETURN(bucket, NULL);
         if (i >= bucket->len) {
-            /* We never leave this routine with i >= len:  somebody else
-             * mutated the current bucket.
+            /* We never leave this routine normally with i >= len:  somebody
+             * else mutated the current bucket.
              */
 	    PyErr_SetString(PyExc_RuntimeError,
 		            "the bucket being iterated changed size");
+	    /* Arrange for that this error is sticky too. */
+	    items->currentoffset = INT_MAX;
 	    goto Done;
 	}
 
@@ -664,12 +664,6 @@
     return it;
 }
 
-static PyMethodDef btreeiter_methods[] = {
-	{"next", (PyCFunction)BTreeIter_next, METH_VARARGS,
-	 "it.next() -- get the next value, or raise StopIteration"},
-	{NULL,		NULL}		/* sentinel */
-};
-
 static PyTypeObject BTreeIter_Type = {
         PyObject_HEAD_INIT(NULL)
 	0,					/* ob_size */
@@ -700,7 +694,7 @@
 	0,					/* tp_weaklistoffset */
 	(getiterfunc)BTreeIter_getiter,		/* tp_iter */
 	(iternextfunc)BTreeIter_next,	        /* tp_iternext */
-	btreeiter_methods,			/* tp_methods */
+	0,					/* tp_methods */
 	0,					/* tp_members */
 	0,					/* tp_getset */
 	0,					/* tp_base */