[Zope-Checkins] CVS: Zope3/lib/python/Persistence/BTrees - BTreeModuleTemplate.c:1.7 BTreeTemplate.c:1.32 BucketTemplate.c:1.11

Tim Peters tim.one@comcast.net
Wed, 19 Jun 2002 22:39:06 -0400


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

Modified Files:
	BTreeModuleTemplate.c BTreeTemplate.c BucketTemplate.c 
Log Message:
BTree_length_or_nonzero():  Sped this.  In the nonzero case,
a BTree is empty if and only if its firstbucket pointer is
NULL, so there's no need to keep checking nonzero inside the
loop.  Also, the pointers here are all local, so there's no
need to incref and decref them -- the apparent necessity was
just an artifact of using the bucket assignment macros.  So
stopped using those macros, and the need for incref/decref
operations went away too.

PyVar_AssignB(), ASSIGNB(), ASSIGNBC():  Turned out these
are no longer used anywhere anymore, so removed them.

PER_UNUSE():  New macro to capture the endlessly repeated
PER_ALLOW_DEACTIVATION + PER_ACCESSED pair.  As the comment
says, so sue me <wink>.

Bucket_deleteNextBucket():  Documented & simplified.


=== Zope3/lib/python/Persistence/BTrees/BTreeModuleTemplate.c 1.6 => 1.7 ===
 #endif
 
+/* So sue me.  This pair gets used all over the place, so much so that it
+ * interferes with understanding non-persistence parts of algorithms.
+ * PER_UNUSE can be used after a successul PER_USE or PER_USE_OR_RETURN.
+ * It allows the object to become ghostified, and tells the persistence
+ * machinery that the object's fields were used recently.
+ */
+#define PER_UNUSE(OBJ) do {             \
+    PER_ALLOW_DEACTIVATION(OBJ);        \
+    PER_ACCESSED(OBJ);                  \
+} while (0)
+
 /*
   The tp_name slots of the various BTree types contain the fully
   qualified names of the types, e.g. Persistence.BTrees.OOBTree.OOBTree.
@@ -110,10 +121,6 @@
 } Bucket;
 
 #define BUCKET(O) ((Bucket*)(O))
-
-static void PyVar_AssignB(Bucket **v, Bucket *e) { Py_XDECREF(*v); *v=e;}
-#define ASSIGNB(V,E) PyVar_AssignB(&(V),(E))
-#define ASSIGNBC(V,E) (Py_INCREF((E)), PyVar_AssignB(&(V),(E)))
 
 /* A BTree is complicated.  See Maintainer.txt.
  */


=== Zope3/lib/python/Persistence/BTrees/BTreeTemplate.c 1.31 => 1.32 ===
 }
 
+/*
+ * Return the number of elements in a BTree.  nonzero is a Boolean, and
+ * when true requests just a non-empty/empty result.  Testing for emptiness
+ * is efficient (constant-time).  Getting the true length takes time
+ * proportional to the number of leaves (buckets).
+ *
+ * Return:
+ *     When nonzero true:
+ *          -1  error
+ *           0  empty
+ *           1  not empty
+ *     When nonzero false (possibly expensive!):
+ *          -1  error
+ *        >= 0  number of elements.
+ */
 static int
 BTree_length_or_nonzero(BTree *self, int nonzero)
 {
-  int c=0;
-  Bucket *b, *n;
+    int result;
+    Bucket *b;
+    Bucket *next;
 
-  PER_USE_OR_RETURN(self, -1);
-  b = self->firstbucket;
-  Py_XINCREF(b);
-  PyPersist_DECREF(self);
-  PyPersist_SetATime(self);
+    PER_USE_OR_RETURN(self, -1);
+    b = self->firstbucket;
+    PER_UNUSE(self);
+    if (nonzero)
+        return b != NULL;
 
-  while (b != NULL)
-    {
-      PER_USE_OR_RETURN(b, -1);
-      c += b->len;
-      if (nonzero && c)
-        {
-          /* Short-circuit if all we care about is nonempty */
-          PyPersist_DECREF(b);
-          PyPersist_SetATime(b);
-          Py_DECREF(b);
-          return 1;
-        }
-      n = b->next;
-      Py_XINCREF(n);
-      PyPersist_DECREF(b);
-      PyPersist_SetATime(b);
-      ASSIGNB(b, n);
+    result = 0;
+    while (b) {
+        PER_USE_OR_RETURN(b, -1);
+        result += b->len;
+        next = b->next;
+        PER_UNUSE(b);
+        b = next;
     }
-
-  return c;
+    return result;
 }
 
 static int


=== Zope3/lib/python/Persistence/BTrees/BucketTemplate.c 1.10 => 1.11 ===
 }
 
+/* Set self->next to self->next->next, i.e. unlink self's successor from
+ * the chain.
+ *
+ * Return:
+ *     -1       error
+ *      0       OK
+ */
 static int
 Bucket_deleteNextBucket(Bucket *self)
 {
     int result = -1;    /* until proven innocent */
+    Bucket *successor;
 
-    PyPersist_INCREF(self);
-    if (!PyPersist_IS_STICKY(self))
-	return -1;
-    if (self->next) {
-	Bucket *n;
-	if (Bucket_nextBucket(self->next, &n) < 0)
-	    goto Done;
-	Py_DECREF(self->next);
-	self->next = n;
+    PER_USE_OR_RETURN(self, -1);
+    successor = self->next;
+    if (successor) {
+        Bucket *next;
+        /* Before:  self -> successor -> next
+         * After:   self --------------> next
+         */
+        UNLESS (PER_USE(successor)) goto Done;
+        next = successor->next;
+        PER_UNUSE(successor);
+
+        Py_XINCREF(next);       /* it may be NULL, of course */
+        self->next = next;
+        Py_DECREF(successor);
 	if (PER_CHANGED(self) < 0)
 	    goto Done;
     }
-    PyPersist_DECREF(self);
-    PyPersist_SetATime(self);
     result = 0;
 
 Done:
-    PyPersist_DECREF(self);
-    PyPersist_SetATime(self);
+    PER_UNUSE(self);
     return result;
 }