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; ...@@ -183,14 +183,13 @@ staticforward PyExtensionClass BTreeType;
/* SetIteration structs are used in the internal set iteration protocol. /* SetIteration structs are used in the internal set iteration protocol.
* When you want to iterate over a set or bucket or BTree (even an * When you want to iterate over a set or bucket or BTree (even an
* individual key!), * individual key!),
* 1. Declare a new iterator and a "merge" int: * 1. Declare a new iterator:
* SetIteration si = {0,0,0}; * SetIteration si = {0,0,0};
* int merge = 0;
* Using "{0,0,0}" or "{0,0}" appear most common. Only one {0} is * 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 * necssary. At least one must be given so that finiSetIteration() works
* correctly even if you don't get around to calling initSetIteration(). * correctly even if you don't get around to calling initSetIteration().
* 2. Initialize it via * 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 * 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, calling finiSetIteration(&si) is optional. But if the
* init call succeeds, you must eventually call finiSetIteration(), * init call succeeds, you must eventually call finiSetIteration(),
...@@ -200,8 +199,7 @@ staticforward PyExtensionClass BTreeType; ...@@ -200,8 +199,7 @@ staticforward PyExtensionClass BTreeType;
* If the set isn't empty, this sets si.position to an int >= 0, * 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 * 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 * the element's value (of type VALUE_TYPE). si.value is defined
* iff merge was set to true by the initSetIteration() call, which is * iff si.usesValue is true.
* equivalent to whether si.usesValue is true.
* 4. Process all the elements: * 4. Process all the elements:
* while (si.position >= 0) { * while (si.position >= 0) {
* do something with si.key and/or si.value; * do something with si.key and/or si.value;
...@@ -219,7 +217,6 @@ typedef struct SetIteration_s ...@@ -219,7 +217,6 @@ typedef struct SetIteration_s
PyObject *set; /* the set, bucket, BTree, ..., being iterated */ PyObject *set; /* the set, bucket, BTree, ..., being iterated */
int position; /* initialized to 0; set to -1 by next() when done */ int position; /* initialized to 0; set to -1 by next() when done */
int usesValue; /* true iff 'set' has values & we iterate them */ 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 */ KEY_TYPE key; /* next() sets to next key */
VALUE_TYPE value; /* next() may set to next value */ VALUE_TYPE value; /* next() may set to next value */
int (*next)(struct SetIteration_s*); /* function to get next key+value */ int (*next)(struct SetIteration_s*); /* function to get next key+value */
...@@ -376,7 +373,7 @@ static char BTree_module_documentation[] = ...@@ -376,7 +373,7 @@ static char BTree_module_documentation[] =
"\n" "\n"
MASTER_ID MASTER_ID
BTREEITEMSTEMPLATE_C 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 BTREETEMPLATE_C
BUCKETTEMPLATE_C BUCKETTEMPLATE_C
KEYMACROS_H KEYMACROS_H
......
...@@ -12,7 +12,7 @@ ...@@ -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 Set operations
...@@ -58,12 +58,13 @@ bucket_merge(Bucket *s1, Bucket *s2, Bucket *s3) ...@@ -58,12 +58,13 @@ bucket_merge(Bucket *s1, Bucket *s2, Bucket *s3)
Bucket *r=0; Bucket *r=0;
PyObject *s; PyObject *s;
SetIteration i1 = {0,0,0}, i2 = {0,0,0}, i3 = {0,0,0}; 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(&i1, OBJECT(s1), 1) < 0) goto err;
if (initSetIteration(&i2, OBJECT(s2), 0, &mapping) < 0) goto err; if (initSetIteration(&i2, OBJECT(s2), 1) < 0) goto err;
if (initSetIteration(&i3, OBJECT(s3), 0, &mapping) < 0) goto err; if (initSetIteration(&i3, OBJECT(s3), 1) < 0) goto err;
mapping = i1.usesValue | i2.usesValue | i3.usesValue;
set = ! mapping; set = ! mapping;
if (mapping) if (mapping)
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
Set operations 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 #ifdef INTSET_H
static int static int
...@@ -68,22 +68,17 @@ nextKeyAsSet(SetIteration *i) ...@@ -68,22 +68,17 @@ nextKeyAsSet(SetIteration *i)
* Arguments * Arguments
* i The address of a SetIteration control struct. * i The address of a SetIteration control struct.
* s The address of the set, bucket, BTree, ..., to be iterated. * s The address of the set, bucket, BTree, ..., to be iterated.
* w If w < 0, ignore values when iterating. * useValues Boolean; if true, and s has values (is a mapping), copy
* merge Is set to 1 if s has values (as well as keys) and w >= 0. * them into i->value each time i->next() is called; else
* The value on input is ignored. * ignore s's values even if s is a mapping.
* *
* Return * Return
* 0 on success; -1 and an exception set if error. * 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 * i.usesValue is set to 1 (true) if s has values and useValues was
* alone. * true; else usesValue is set to 0 (false).
* i.usesValue is also set to 1 if s has values and w >= 0, else
* .usesValue is set to 0.
* i.set gets a new reference to s, or to some other object used to * i.set gets a new reference to s, or to some other object used to
* iterate over s. * iterate over s.
* i.position is set to 0. * 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.next is set to an appropriate iteration function.
* i.key and i.value are left alone. * i.key and i.value are left alone.
* *
...@@ -102,20 +97,18 @@ nextKeyAsSet(SetIteration *i) ...@@ -102,20 +97,18 @@ nextKeyAsSet(SetIteration *i)
* A SetIteration struct has been cleaned up iff i.set is NULL. * A SetIteration struct has been cleaned up iff i.set is NULL.
*/ */
static int static int
initSetIteration(SetIteration *i, PyObject *s, int w, int *merge) initSetIteration(SetIteration *i, PyObject *s, int useValues)
{ {
i->set = NULL; i->set = NULL;
i->position = -1; /* set to 0 only on normal return */ 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 */ i->usesValue = 0; /* assume it's a set or that values aren't iterated */
if (ExtensionClassSubclassInstance_Check(s, &BucketType)) if (ExtensionClassSubclassInstance_Check(s, &BucketType))
{ {
i->set = s; i->set = s;
Py_INCREF(s); Py_INCREF(s);
i->hasValue = 1;
if (w >= 0) if (useValues)
{ {
i->usesValue = 1; i->usesValue = 1;
i->next = nextBucket; i->next = nextBucket;
...@@ -133,9 +126,8 @@ initSetIteration(SetIteration *i, PyObject *s, int w, int *merge) ...@@ -133,9 +126,8 @@ initSetIteration(SetIteration *i, PyObject *s, int w, int *merge)
{ {
i->set = BTree_rangeSearch(BTREE(s), NULL, 'i'); i->set = BTree_rangeSearch(BTREE(s), NULL, 'i');
UNLESS(i->set) return -1; UNLESS(i->set) return -1;
i->hasValue = 1;
if (w >= 0) if (useValues)
{ {
i->usesValue = 1; i->usesValue = 1;
i->next = nextBTreeItems; i->next = nextBTreeItems;
...@@ -176,7 +168,6 @@ initSetIteration(SetIteration *i, PyObject *s, int w, int *merge) ...@@ -176,7 +168,6 @@ initSetIteration(SetIteration *i, PyObject *s, int w, int *merge)
return -1; return -1;
} }
*merge |= i->usesValue;
i->position = 0; i->position = 0;
return 0; return 0;
...@@ -214,17 +205,18 @@ set_operation(PyObject *s1, PyObject *s2, ...@@ -214,17 +205,18 @@ set_operation(PyObject *s1, PyObject *s2,
{ {
Bucket *r=0; Bucket *r=0;
SetIteration i1 = {0,0,0}, i2 = {0,0,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(&i1, s1, w1 >= 0) < 0) goto err;
if (initSetIteration(&i2, s2, w2, &merge) < 0) goto err; if (initSetIteration(&i2, s2, w2 >= 0) < 0) goto err;
merge = i1.usesValue | i2.usesValue;
if (merge) if (merge)
{ {
#ifndef MERGE #ifndef MERGE
if (c12 && i1.hasValue && i2.hasValue) goto invalid_set_operation; if (c12 && i1.usesValue && i2.usesValue) goto invalid_set_operation;
#endif #endif
if (! i1.hasValue && i2.hasValue) if (! i1.usesValue && i2.usesValue)
{ {
SetIteration t; SetIteration t;
int i; int i;
...@@ -237,9 +229,9 @@ set_operation(PyObject *s1, PyObject *s2, ...@@ -237,9 +229,9 @@ set_operation(PyObject *s1, PyObject *s2,
i1.value=MERGE_DEFAULT; i1.value=MERGE_DEFAULT;
i2.value=MERGE_DEFAULT; i2.value=MERGE_DEFAULT;
#else #else
if (i1.hasValue) if (i1.usesValue)
{ {
if (! i2.hasValue && c2) goto invalid_set_operation; if (! i2.usesValue && c2) goto invalid_set_operation;
} }
else else
{ {
...@@ -506,9 +498,7 @@ multiunion_m(PyObject *ignored, PyObject *args) ...@@ -506,9 +498,7 @@ multiunion_m(PyObject *ignored, PyObject *args)
} }
else { else {
/* No cheap way: iterate over set's elements one at a time. */ /* No cheap way: iterate over set's elements one at a time. */
int merge; /* dummy needed for initSetIteration */ if (initSetIteration(&setiter, set, 0) < 0) goto Error;
if (initSetIteration(&setiter, set, -1, &merge) < 0) goto Error;
if (setiter.next(&setiter) < 0) goto Error; if (setiter.next(&setiter) < 0) goto Error;
while (setiter.position >= 0) { while (setiter.position >= 0) {
if (result->len >= result->size && Bucket_grow(result, -1, 1) < 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