Commit d9b60aaa authored by Tim Peters's avatar Tim Peters

A step on the way to repairing negative weights used with the weighted

intersection and union functions:  get the concept of weight entirely out
of the internal set iteration protocol.  The caller wants values, or
doesn't, and that's just a Boolean.  This makes for some nice little
internal simplifications, but doesn't yet change any semantics.
parent 1fc26e1d
......@@ -183,14 +183,13 @@ staticforward PyExtensionClass BTreeType;
/* SetIteration structs are used in the internal set iteration protocol.
* When you want to iterate over a set or bucket or BTree (even an
* individual key!),
* 1. Declare a new iterator and a "merge" int:
* 1. Declare a new iterator:
* SetIteration si = {0,0,0};
* int merge = 0;
* Using "{0,0,0}" or "{0,0}" appear most common. Only one {0} is
* necssary. At least one must be given so that finiSetIteration() works
* correctly even if you don't get around to calling initSetIteration().
* 2. Initialize it via
* initSetIteration(&si, PyObject *s, int weight, &merge)
* initSetIteration(&si, PyObject *s, useValues)
* It's an error if that returns an int < 0. In case of error on the
* init call, calling finiSetIteration(&si) is optional. But if the
* init call succeeds, you must eventually call finiSetIteration(),
......@@ -200,8 +199,7 @@ staticforward PyExtensionClass BTreeType;
* If the set isn't empty, this sets si.position to an int >= 0,
* si.key to the element's key (of type KEY_TYPE), and maybe si.value to
* the element's value (of type VALUE_TYPE). si.value is defined
* iff merge was set to true by the initSetIteration() call, which is
* equivalent to whether si.usesValue is true.
* iff si.usesValue is true.
* 4. Process all the elements:
* while (si.position >= 0) {
* do something with si.key and/or si.value;
......@@ -219,7 +217,6 @@ typedef struct SetIteration_s
PyObject *set; /* the set, bucket, BTree, ..., being iterated */
int position; /* initialized to 0; set to -1 by next() when done */
int usesValue; /* true iff 'set' has values & we iterate them */
int hasValue; /* true iff 'set' has values (as well as keys) */
KEY_TYPE key; /* next() sets to next key */
VALUE_TYPE value; /* next() may set to next value */
int (*next)(struct SetIteration_s*); /* function to get next key+value */
......@@ -376,7 +373,7 @@ static char BTree_module_documentation[] =
"\n"
MASTER_ID
BTREEITEMSTEMPLATE_C
"$Id: BTreeModuleTemplate.c,v 1.36 2002/06/20 02:40:01 tim_one Exp $\n"
"$Id: BTreeModuleTemplate.c,v 1.37 2002/06/25 22:02:27 tim_one Exp $\n"
BTREETEMPLATE_C
BUCKETTEMPLATE_C
KEYMACROS_H
......
......@@ -12,7 +12,7 @@
****************************************************************************/
#define MERGETEMPLATE_C "$Id: MergeTemplate.c,v 1.14 2002/06/08 04:41:44 tim_one Exp $\n"
#define MERGETEMPLATE_C "$Id: MergeTemplate.c,v 1.15 2002/06/25 22:02:27 tim_one Exp $\n"
/****************************************************************************
Set operations
......@@ -58,12 +58,13 @@ bucket_merge(Bucket *s1, Bucket *s2, Bucket *s3)
Bucket *r=0;
PyObject *s;
SetIteration i1 = {0,0,0}, i2 = {0,0,0}, i3 = {0,0,0};
int cmp12, cmp13, cmp23, mapping=0, set;
int cmp12, cmp13, cmp23, mapping, set;
if (initSetIteration(&i1, OBJECT(s1), 0, &mapping) < 0) goto err;
if (initSetIteration(&i2, OBJECT(s2), 0, &mapping) < 0) goto err;
if (initSetIteration(&i3, OBJECT(s3), 0, &mapping) < 0) goto err;
if (initSetIteration(&i1, OBJECT(s1), 1) < 0) goto err;
if (initSetIteration(&i2, OBJECT(s2), 1) < 0) goto err;
if (initSetIteration(&i3, OBJECT(s3), 1) < 0) goto err;
mapping = i1.usesValue | i2.usesValue | i3.usesValue;
set = ! mapping;
if (mapping)
......
......@@ -16,7 +16,7 @@
Set operations
****************************************************************************/
#define SETOPTEMPLATE_C "$Id: SetOpTemplate.c,v 1.25 2002/06/23 19:36:12 tim_one Exp $\n"
#define SETOPTEMPLATE_C "$Id: SetOpTemplate.c,v 1.26 2002/06/25 22:02:27 tim_one Exp $\n"
#ifdef INTSET_H
static int
......@@ -66,24 +66,19 @@ nextKeyAsSet(SetIteration *i)
* Start the set iteration protocol. See the comments at struct SetIteration.
*
* Arguments
* i The address of a SetIteration control struct.
* s The address of the set, bucket, BTree, ..., to be iterated.
* w If w < 0, ignore values when iterating.
* merge Is set to 1 if s has values (as well as keys) and w >= 0.
* The value on input is ignored.
* i The address of a SetIteration control struct.
* s The address of the set, bucket, BTree, ..., to be iterated.
* useValues Boolean; if true, and s has values (is a mapping), copy
* them into i->value each time i->next() is called; else
* ignore s's values even if s is a mapping.
*
* Return
* 0 on success; -1 and an exception set if error.
* *merge is set to 1 if s has values and w >= 0, else merge is left
* alone.
* i.usesValue is also set to 1 if s has values and w >= 0, else
* .usesValue is set to 0.
* i.usesValue is set to 1 (true) if s has values and useValues was
* true; else usesValue is set to 0 (false).
* i.set gets a new reference to s, or to some other object used to
* iterate over s.
* i.position is set to 0.
* i.hasValue is set to true if s has values, and to false otherwise.
* Note that this is done independent of w's value, and when w < 0
* may differ from i.usesValue.
* i.next is set to an appropriate iteration function.
* i.key and i.value are left alone.
*
......@@ -102,20 +97,18 @@ nextKeyAsSet(SetIteration *i)
* A SetIteration struct has been cleaned up iff i.set is NULL.
*/
static int
initSetIteration(SetIteration *i, PyObject *s, int w, int *merge)
initSetIteration(SetIteration *i, PyObject *s, int useValues)
{
i->set = NULL;
i->position = -1; /* set to 0 only on normal return */
i->hasValue = 0; /* assume it's a set */
i->usesValue = 0; /* assume it's a set or that values aren't iterated */
if (ExtensionClassSubclassInstance_Check(s, &BucketType))
{
i->set = s;
Py_INCREF(s);
i->hasValue = 1;
if (w >= 0)
if (useValues)
{
i->usesValue = 1;
i->next = nextBucket;
......@@ -133,9 +126,8 @@ initSetIteration(SetIteration *i, PyObject *s, int w, int *merge)
{
i->set = BTree_rangeSearch(BTREE(s), NULL, 'i');
UNLESS(i->set) return -1;
i->hasValue = 1;
if (w >= 0)
if (useValues)
{
i->usesValue = 1;
i->next = nextBTreeItems;
......@@ -176,7 +168,6 @@ initSetIteration(SetIteration *i, PyObject *s, int w, int *merge)
return -1;
}
*merge |= i->usesValue;
i->position = 0;
return 0;
......@@ -214,17 +205,18 @@ set_operation(PyObject *s1, PyObject *s2,
{
Bucket *r=0;
SetIteration i1 = {0,0,0}, i2 = {0,0,0};
int cmp, merge=0;
int cmp, merge;
if (initSetIteration(&i1, s1, w1, &merge) < 0) goto err;
if (initSetIteration(&i2, s2, w2, &merge) < 0) goto err;
if (initSetIteration(&i1, s1, w1 >= 0) < 0) goto err;
if (initSetIteration(&i2, s2, w2 >= 0) < 0) goto err;
merge = i1.usesValue | i2.usesValue;
if (merge)
{
#ifndef MERGE
if (c12 && i1.hasValue && i2.hasValue) goto invalid_set_operation;
if (c12 && i1.usesValue && i2.usesValue) goto invalid_set_operation;
#endif
if (! i1.hasValue && i2.hasValue)
if (! i1.usesValue && i2.usesValue)
{
SetIteration t;
int i;
......@@ -237,9 +229,9 @@ set_operation(PyObject *s1, PyObject *s2,
i1.value=MERGE_DEFAULT;
i2.value=MERGE_DEFAULT;
#else
if (i1.hasValue)
if (i1.usesValue)
{
if (! i2.hasValue && c2) goto invalid_set_operation;
if (! i2.usesValue && c2) goto invalid_set_operation;
}
else
{
......@@ -506,9 +498,7 @@ multiunion_m(PyObject *ignored, PyObject *args)
}
else {
/* No cheap way: iterate over set's elements one at a time. */
int merge; /* dummy needed for initSetIteration */
if (initSetIteration(&setiter, set, -1, &merge) < 0) goto Error;
if (initSetIteration(&setiter, set, 0) < 0) goto Error;
if (setiter.next(&setiter) < 0) goto Error;
while (setiter.position >= 0) {
if (result->len >= result->size && Bucket_grow(result, -1, 1) < 0)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment