[Zope-Checkins] CVS: Zope/lib/python/BTrees - Interfaces.py:1.18 SetOpTemplate.c:1.27

Tim Peters tim.one@comcast.net
Tue, 25 Jun 2002 18:46:42 -0400


Update of /cvs-repository/Zope/lib/python/BTrees
In directory cvs.zope.org:/tmp/cvs-serv20938/lib/python/BTrees

Modified Files:
	Interfaces.py SetOpTemplate.c 
Log Message:
Negative weights behave as documented now for weightedUnion and
weightedIntersection.


=== Zope/lib/python/BTrees/Interfaces.py 1.17 => 1.18 ===
                   c2[key]  if the key is in c2 and c2 is a mapping
 
-        XXX All of the above is wrong if either weight is negative.  I think
-        XXX that's a bug in the implementation and will fix it.
-
         Note that c1 and c2 must be collections.
 
         """
@@ -347,9 +344,6 @@
 
             v2 is 1        if c2 is a set
                   c2[key]  if c2 is a mapping
-
-        XXX All of the above is wrong if either weight is negative.  I think
-        XXX that's a bug in the implementation and will fix it.
 
         Note that c1 and c2 must be collections.
         """


=== Zope/lib/python/BTrees/SetOpTemplate.c 1.26 => 1.27 ===
 }
 
+/* This is the workhorse for all set merge operations:  the weighted and
+ * unweighted flavors of union and intersection, and set difference.  The
+ * algorithm is conceptually simple but the code is complicated due to all
+ * the options.
+ *
+ * s1, s2
+ *     The input collections to be merged.
+ *
+ * usevalues1, usevalues2
+ *     Booleans.  In the output, should values from s1 (or s2) be used?  This
+ *     only makes sense when an operation intends to support mapping outputs;
+ *     these should both be false for operations that want pure set outputs.
+ *
+ * w1, w2
+ *     If usevalues1(2) are true, these are the weights to apply to the
+ *     input values.
+ *
+ * c1
+ *     Boolean.  Should keys that appear in c1 but not c2 appear in the output?
+ * c12
+ *     Boolean.  Should keys that appear in both inputs appear in the output?
+ * c2
+ *     Boolean.  Should keys that appear in c2 but not c1 appear in the output?
+ *
+ * Returns NULL if error, else a Set or Bucket, depending on whether a set or
+ * mapping was requested.
+ */
 static PyObject *
 set_operation(PyObject *s1, PyObject *s2,
+              int usevalues1, int usevalues2,
               int w1, int w2,
               int c1, int c12, int c2)
 {
@@ -207,8 +235,8 @@
   SetIteration i1 = {0,0,0}, i2 = {0,0,0};
   int cmp, merge;
 
-  if (initSetIteration(&i1, s1, w1 >= 0) < 0) goto err;
-  if (initSetIteration(&i2, s2, w2 >= 0) < 0) goto err;
+  if (initSetIteration(&i1, s1, usevalues1) < 0) goto err;
+  if (initSetIteration(&i2, s2, usevalues2) < 0) goto err;
   merge = i1.usesValue | i2.usesValue;
 
   if (merge)
@@ -336,14 +364,16 @@
   UNLESS(PyArg_ParseTuple(args, "OO", &o1, &o2)) return NULL;
 
 
-  if (o1==Py_None || o2==Py_None)
+  if (o1 == Py_None || o2 == Py_None)
     {
       /* difference(None, X) -> None; difference(X, None) -> X */
       Py_INCREF(o1);
       return o1;
     }
 
-  return set_operation(o1, o2, 1, -1, 1, 0, 0);
+  return set_operation(o1, o2, 1, 0, /* preserve values from o1, ignore o2's */
+                       1, 0,         /* o1's values multiplied by 1 */
+                       1, 0, 0);     /* take only keys unique to o1 */
 }
 
 static PyObject *
@@ -358,13 +388,15 @@
       Py_INCREF(o2);
       return o2;
     }
-  else if (o2==Py_None)
+  else if (o2 == Py_None)
     {
       Py_INCREF(o1);
       return o1;
     }
 
-  return set_operation(o1, o2, -1, -1, 1, 1, 1);
+  return set_operation(o1, o2, 0, 0,    /* ignore values in both */
+                       1, 1,            /* the weights are irrelevant */
+                       1, 1, 1);        /* take all keys */
 }
 
 static PyObject *
@@ -374,18 +406,20 @@
 
   UNLESS(PyArg_ParseTuple(args, "OO", &o1, &o2)) return NULL;
 
-  if (o1==Py_None)
+  if (o1 == Py_None)
     {
       Py_INCREF(o2);
       return o2;
     }
-  else if (o2==Py_None)
+  else if (o2 == Py_None)
     {
       Py_INCREF(o1);
       return o1;
     }
 
-  return set_operation(o1, o2, -1, -1, 0, 1, 0);
+  return set_operation(o1, o2, 0, 0,    /* ignore values in both */
+                       1, 1,            /* the weights are irrelevant */
+                       0, 1, 0);        /* take only keys common to both */
 }
 
 #ifdef MERGE
@@ -394,16 +428,16 @@
 wunion_m(PyObject *ignored, PyObject *args)
 {
   PyObject *o1, *o2;
-  int w1=1, w2=1;
+  int w1 = 1, w2 = 1;
 
   UNLESS(PyArg_ParseTuple(args, "OO|ii", &o1, &o2, &w1, &w2)) return NULL;
 
-  if (o1==Py_None)
-    return Py_BuildValue("iO", (o2==Py_None ? 0 : w2), o2);
-  else if (o2==Py_None)
+  if (o1 == Py_None)
+    return Py_BuildValue("iO", (o2 == Py_None ? 0 : w2), o2);
+  else if (o2 == Py_None)
     return Py_BuildValue("iO", w1, o1);
 
-  o1=set_operation(o1, o2, w1, w2, 1, 1, 1);
+  o1 = set_operation(o1, o2, 1, 1, w1, w2, 1, 1, 1);
   if (o1) ASSIGN(o1, Py_BuildValue("iO", 1, o1));
 
   return o1;
@@ -413,16 +447,16 @@
 wintersection_m(PyObject *ignored, PyObject *args)
 {
   PyObject *o1, *o2;
-  int w1=1, w2=1;
+  int w1 = 1, w2 = 1;
 
   UNLESS(PyArg_ParseTuple(args, "OO|ii", &o1, &o2, &w1, &w2)) return NULL;
 
-  if (o1==Py_None)
-    return Py_BuildValue("iO", (o2==Py_None ? 0 : w2), o2);
-  else if (o2==Py_None)
+  if (o1 == Py_None)
+    return Py_BuildValue("iO", (o2 == Py_None ? 0 : w2), o2);
+  else if (o2 == Py_None)
     return Py_BuildValue("iO", w1, o1);
 
-  o1=set_operation(o1, o2, w1, w2, 0, 1, 0);
+  o1 = set_operation(o1, o2, 1, 1, w1, w2, 0, 1, 0);
   if (o1)
     ASSIGN(o1, Py_BuildValue("iO",
             ((o1->ob_type == (PyTypeObject*)(&SetType)) ? w2+w1 : 1),