refactoring
authorRalph Ronnquist <ralph.ronnquist@gmail.com>
Sun, 17 Jul 2022 00:16:54 +0000 (10:16 +1000)
committerRalph Ronnquist <ralph.ronnquist@gmail.com>
Sun, 17 Jul 2022 00:16:54 +0000 (10:16 +1000)
26 files changed:
vector/AndQuery.c [new file with mode: 0644]
vector/AndQuery.h [new file with mode: 0644]
vector/AssignQuery.c [new file with mode: 0644]
vector/AssignQuery.h [new file with mode: 0644]
vector/Binding.c [new file with mode: 0644]
vector/Binding.h [new file with mode: 0644]
vector/BindingTable.c
vector/BindingTable.h
vector/Makefile
vector/NotQuery.c [new file with mode: 0644]
vector/NotQuery.h [new file with mode: 0644]
vector/OrQuery.c [new file with mode: 0644]
vector/OrQuery.h [new file with mode: 0644]
vector/Query.c
vector/Query.h
vector/QueryCallbacks.h
vector/Relation.c
vector/RelationQuery.c [new file with mode: 0644]
vector/RelationQuery.h [new file with mode: 0644]
vector/StackVector.h [new file with mode: 0644]
vector/Tuple.c
vector/Tuple.h
vector/TupleSchema.c
vector/TupleSchema.h
vector/View.c
vector/View.h

diff --git a/vector/AndQuery.c b/vector/AndQuery.c
new file mode 100644 (file)
index 0000000..169ff9e
--- /dev/null
@@ -0,0 +1,85 @@
+#include <stdarg.h>
+#include <stdlib.h>
+#include <AndQuery.h>
+
+static void AndQuery_reclaim(Query *this) {
+    AndQuery *q = (AndQuery*) this;
+    int i;
+    for ( i = 0; i < q->size; i++ ) {
+       Query_reclaim( q->conjuncts[i] );
+    }
+    free( q->conjuncts );
+    free( this );
+}
+
+static int AndQuery_next(
+    Query *this,BindingTable *bt,enum NextState state)
+{
+    AndQuery *q = (AndQuery*) this;
+    int i = q->size - 1;
+    enum NextState s = subsequent;
+    switch ( state ) {
+    case initial:
+       q->active = 1;
+       i = 0;
+       s = initial;
+       // Fall through?
+    case subsequent:
+       while ( i < q->size ) {
+           if ( Query_next( q->conjuncts[i], bt, s ) ) {
+               continue;
+           }
+           Query_next( q->conjuncts[i], bt, restore );
+           if ( i-- == 0 ) {
+               // The first conjunct now exhausted
+               q->active = 0;
+               return 0;
+           }
+           s = subsequent;
+       }
+       return 1;
+    case restore:
+       if ( q->active ) {
+           for ( ; i >= 0; i-- ) {
+               Query_next( q->conjuncts[i], bt, restore );
+           }
+       }
+       q->active = 0;
+       return 0;
+    }
+    return 0;
+}
+
+static void AndQuery_variables(Query *this,HashVector *hv) {
+    AndQuery *q = (AndQuery*) this;
+    int i; 
+    for ( i = 0; i < q->size; i++ ) {
+       Query_variables( q->conjuncts[i], hv );
+    }
+}
+
+static struct QueryCallbacks AndQuery_def = {
+    .reclaim = AndQuery_reclaim,
+    .next = AndQuery_next,
+    .variables = AndQuery_variables
+};
+
+Query *Query_and(int n,...) {
+    va_list args;
+    AndQuery *q = (AndQuery *)
+       malloc( sizeof( AndQuery ) );
+    (*q) = (AndQuery) {
+       .def = &AndQuery_def,
+       .active = 0,
+       .size = n,
+       .conjuncts = (Query**) malloc( n * sizeof( Query* ) )
+    };
+    int i;
+    va_start( args, n );
+    for ( i = 0; i < n; i++ ) {
+       q->conjuncts[i] = va_arg( args, Query* );
+    }
+    va_end( args );
+    return (Query*) q;
+}
+
diff --git a/vector/AndQuery.h b/vector/AndQuery.h
new file mode 100644 (file)
index 0000000..7871eea
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef AndQuery_H
+#define AndQuery_H
+
+#include <Query.h>
+
+/**
+ * AndQuery represents a conjunction of sub queries.
+ * \extends Query
+ * \related Query
+ */
+typedef struct {
+    struct QueryCallbacks *def;
+    int active;
+    int size;
+    Query **conjuncts;
+} AndQuery;
+
+
+#endif
diff --git a/vector/AssignQuery.c b/vector/AssignQuery.c
new file mode 100644 (file)
index 0000000..bb264aa
--- /dev/null
@@ -0,0 +1,84 @@
+#include <stdlib.h>
+#include <string.h>
+#include <AssignQuery.h>
+
+// Release any memory.
+static void AssignQuery_reclaim(Query *this) {
+    AssignQuery *q = (AssignQuery*) this;
+    free( q->saved );
+    free( this );
+}
+
+static int AssignQuery_check(Tuple *a,Tuple *b) {
+    int i;
+    for ( i = 0; i < a->size; i++ ) {
+       char *value = a->elements[i];
+       char *current = b->elements[i];
+       if ( value && current && current != value &&
+            strcmp( current, value ) != 0 ) {
+           return 0;
+       }
+    }
+    return 1;
+}
+
+// Make names have given values and return 1. If any name has a
+// different value then return 0. Values are strings.
+static int AssignQuery_next(
+    Query *this,BindingTable *bt,enum NextState state) {
+    AssignQuery *q = (AssignQuery*) this;
+    switch ( state ) {
+    case initial:
+       if ( q->saved == 0 ) {
+           q->saved = Tuple_clone( q->names );
+       } else {
+           memcpy( q->saved, q->names, q->names->size * sizeof( void* ) );
+       }
+       BindingTable_deref( bt, q->saved );
+       // Check with new values
+       if ( AssignQuery_check( q->values, q->saved ) ) {
+           BindingTable_set_all( bt, q->names, q->values, 0 );
+           return 1;
+       }
+       // Fall through
+    case subsequent:
+    case restore:
+       if ( q->saved ) {
+           BindingTable_set_all( bt, q->names, q->saved, 1 );
+           free( q->saved );
+           q->saved = 0;
+       }
+       return 0;
+    }
+    return 0;
+}
+
+static void AssignQuery_variables(Query *this,HashVector *hv) {
+    AssignQuery *q = (AssignQuery*) this;
+    unsigned long i;
+    for ( i = 0; i < q->names->size; i++ ) {
+       HashVector_add( hv, q->names->elements[i] );
+    }
+}
+
+static struct QueryCallbacks AssignQuery_def = {
+    .reclaim = AssignQuery_reclaim,
+    .next = AssignQuery_next,
+    .variables = AssignQuery_variables
+};
+
+/**
+ * Return a Query object representing an assignment of one or more
+ * variables.
+ */
+Query *Query_assign(int arity,Tuple *names,Tuple *values) {
+    AssignQuery *q = (AssignQuery*)
+       malloc( sizeof( AssignQuery ) );
+    (*q) = (AssignQuery) {
+       .def = &AssignQuery_def,
+       .names = names,
+       .values = values,
+       .saved = 0
+    };
+    return (Query*) q;
+}
diff --git a/vector/AssignQuery.h b/vector/AssignQuery.h
new file mode 100644 (file)
index 0000000..2e38b87
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef AssignQuery_H
+#define AssignQuery_H
+
+#include <QueryCallbacks.h>
+#include <Tuple.h>
+
+/**
+ * AssignQuery represents an assignment of values to names.
+ *
+ * \extends Query
+ * \related Query
+ */
+typedef struct {
+    struct QueryCallbacks *def;
+    Tuple *names;
+    Tuple *values;
+    Tuple *saved;
+} AssignQuery;
+
+void AssignQuery_assign(
+    BindingTable *bt,Tuple *names,Tuple *values,int all);
+
+#endif
diff --git a/vector/Binding.c b/vector/Binding.c
new file mode 100644 (file)
index 0000000..9bcc0c1
--- /dev/null
@@ -0,0 +1,60 @@
+#include <string.h>
+#include <HashVector.h>
+#include <Binding.h>
+
+/**
+ * This callback function returns the hashcode of a Binding key, which
+ * is its name string.
+ */
+static unsigned long Binding_hashcode(void *this,void *key) {
+    return HashVector_hashcode(
+       (unsigned char *) key, strlen( (char*) key ) );
+}
+
+/**
+ * This callback function determines whether a Binding item has a
+ * given key or not.
+ */
+static int Binding_haskey(void *this,void *item,void *key) {
+    Binding *b = (Binding*) item;
+    char *name = (char *) key;
+    return strcmp( name, (char*) b->name ) == 0;
+}
+
+/**
+ * This callback function returns the key of a Binding itme, which is
+ * its name string.
+ */
+static void *Binding_itemkey(void *this,void *item) {
+    return ((Binding*) item)->name;
+}
+    
+
+/**
+ * This callback function handles the "release" of a Binding key,
+ * which is to do nothing, since the name string memory is not managed
+ * here.
+ */
+static void Binding_releasekey(void *this,void *key) {
+}
+
+/**
+ * This callback function writes a representation of a Binding item
+ * into a character buffer.
+ */
+static int Binding_tostring(void *this,void *item,char *buffer,int limit) {
+    Binding *b = (Binding*) item;
+    return snprintf( buffer, limit, "{%s,%p}", b->name, b->value );
+}
+
+/**
+ * This is the "item type" for Binding items.
+ */
+ItemKeyFun Bindingitem = {
+    .hashcode = Binding_hashcode,
+    .haskey = Binding_haskey,
+    .itemkey = Binding_itemkey,
+    .releasekey = Binding_releasekey,
+    .tostring = Binding_tostring
+};
+
diff --git a/vector/Binding.h b/vector/Binding.h
new file mode 100644 (file)
index 0000000..2d1a0b3
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef Binding_H
+#define Binding_H
+
+#include <ItemKeyFun.h>
+
+/**
+ * \brief A Binding is an association of a (var*) name with a (void*)
+ * value.
+ *
+ * A \b (void*)0 value marks an "unbound" value.
+ */
+typedef struct Binding {
+    char *name;
+    void *value;
+} Binding;
+
+/**
+ * \brief This is the applicable ItemKeyFun callbacks for a Binding
+ * item.
+ */
+extern ItemKeyFun Bindingitem;
+
+#endif
index e3ef2147e91bf3ea286546e74a5e104bdf9e0af0..2728516ec48b8564958da8fc0254c8fe5293f0e0 100644 (file)
 #include <string.h>
 #include <stdlib.h>
 
-/**
- * A Binding is an association between a name (char*) and a value
- * (void*).
- */
-typedef struct {
-    char *name;
-    void *value;
-} Binding;
-
-/**
- * This callback function should return the hashcode of a key. The
- * hashcode is used for indexing into the backing Vector for
- * finding the an item via its key. The same key must map
- * consistently to the same hashcode while the hashtable contains
- * an item with that key. Different keys map map to the same
- * hashcode, in which case the Vector placement is made at the
- * first empty or hole slot following the hashcode index.
- */
-static unsigned long binding_hashcode(void *this,void *key) {
-    char *name = (char *) key;
-    unsigned long n = strlen( name );
-    return HashVector_hashcode( (unsigned char *) name, n );
-}
-
-/**
- * This callback function should determine whether an item has a
- * given key or not.
- */
-static int binding_haskey(void *this,void *item,void *key) {
-    Binding *b = (Binding*) item;
-    char *name = (char *) key;
-    return strcmp( name, (char*) b->name ) == 0;
-}
-
-/**
- * This callback function should return a (possibly temporary) key
- * of an item. It can be anything (i.e., with or without internal
- * structure) as it is treated as an identifier that other
- * callbacks recognize. It is merely understood as a value in an
- * identity domain.
- */
-static void *binding_itemkey(void *this,void *item) {
-    Binding *b = (Binding*) item;
-    return b->name;
-}
-    
-
-/**
- * This callback function should handle a key obtained from the
- * itemkey callback function, e.g., reclaim temporary allocation.
- */
-static void binding_releasekey(void *this,void *key) {
-}
-
-/**
- * This callback function writes a representation of an item into
- * a character buffer.
- */
-static int binding_tostring(void *this,void *item,char *buffer,int limit) {
-    Binding *b = (Binding*) item;
-    return snprintf( buffer, limit, "{%s,%p}", b->name, b->value );
-}
-
-/**
- * This is the "item type" for Binding items.
- */
-ItemKeyFun bindingitem = {
-    .hashcode = binding_hashcode,
-    .haskey = binding_haskey,
-    .itemkey = binding_itemkey,
-    .releasekey = binding_releasekey,
-    .tostring = binding_tostring
-};
-
-BindingTable *BindingTable_create(BindingTable *next) {
+BindingTable *BindingTable_create() {
     BindingTable *this = (BindingTable*) malloc( sizeof( BindingTable ) );
-    this->table = (HashVector) {
+    (*this) = (HashVector) {
        .table = (Vector) {
            .variant = Nibble_index_levels, .size = 16, .entries = 0
-       }, .fill = 0, .holes = 0, .type = &bindingitem
+       }, .fill = 0, .holes = 0, .type = &Bindingitem
     };
-    this->next = next;
     return this;
 }
 
-BindingTable *BindingTable_release(BindingTable *bt) {
+void BindingTable_release(BindingTable *bt) {
     if ( bt ) {
-       BindingTable *next = bt->next;
-       Vector_resize( &bt->table.table, 0, Vector_free_any, 0 );
+       Vector_resize( &bt->table, 0, Vector_free_any, 0 );
        free( bt );
-       return next;
     }
-    return 0;
 }
 
 void BindingTable_set(BindingTable *bt,char *name,void *value) {
-    Binding *b = (Binding*) HashVector_find( &bt->table, name );
+    Binding *b = (Binding*) HashVector_find( bt, name );
     if ( b == 0 ) {
        b = (Binding*) malloc( sizeof( Binding ) );
        b->name = name;
-       HashVector_add( &bt->table, b );
+       HashVector_add( bt, b );
     }
     b->value = value;
 }
 
 void *BindingTable_get(BindingTable *bt,char *name) {
-    for ( ; bt; bt = bt->next ) {
-       Binding *b = (Binding*) HashVector_find( &bt->table, name );
-       if ( b ) {
-           return b->value;
-       }
-    }
-    return 0;
+    Binding *b = (Binding*) HashVector_find( bt, name );
+    return b? b->value : 0;
 }
 
-void BindingTable_deref(BindingTable *bt,int arity,Tuple *t) {
-    int i;
-    for ( i = 0; i < arity; i++ ) {
+void BindingTable_deref(BindingTable *bt,Tuple *t) {
+    unsigned long i;
+    for ( i = 0; i < t->size; i++ ) {
        if ( t->elements[i] ) {
            t->elements[i] = BindingTable_get( bt, t->elements[i] );
        }
     }
 }
 
+#if 0
 int BindingTable_unify(
     BindingTable *bt,char *n1,char *n2,int (*eq)(void*,void*)) {
     void *v1 = BindingTable_get( bt, n1 );
@@ -138,18 +56,17 @@ int BindingTable_unify(
     }
     return ( v1 && v2 )? ( eq? ( eq( v1, v2 ) == 0 ) : ( v1 == v2 ) ) : 1;
 }
+#endif
 
-#define COPYA(T,P,N) (T*) memcpy( malloc( N * sizeof(T) ), P, N * sizeof( T ) )
-
-Tuple *BindingTable_tuple_get(BindingTable *bt,int arity,Tuple *t) {
-    Tuple *vt = Tuple_clone( arity, t );
-    BindingTable_deref( bt, arity, vt );
+Tuple *BindingTable_get_all(BindingTable *bt,Tuple *t) {
+    Tuple *vt = Tuple_clone( t );
+    BindingTable_deref( bt, vt );
     return vt;
 }
 
-void BindingTable_tuple_set(BindingTable *bt,int arity,Tuple *nm,Tuple *vs) {
+void BindingTable_set_all(BindingTable *bt,Tuple *nm,Tuple *vs,int all) {
     int i;
-    for ( i = 0; i < arity; i++ ) {
+    for ( i = 0; i < nm->size; i++ ) {
        BindingTable_set( bt, nm->elements[i], vs->elements[i] );
     }
 }
index 47938b8ebafad0a3da088fc6fee8c08ddace9cf0..aa4ee6e110524b6449194fdccb74afd8621ac9eb 100644 (file)
@@ -3,36 +3,31 @@
 
 #include <HashVector.h>
 #include <TupleSchema.h>
+#include <Binding.h>
 
 /**
  * A BindingTable is a chain of \ref HashVector "HashVectors" of
  * Binding items that associate a (char*) name with a (void*) value.
  */
-typedef struct _BindingTable {
-    HashVector table;
-    struct _BindingTable *next;
-} BindingTable;
+typedef HashVector/*<Binding>*/ BindingTable;
 
 /**
- * \brief Allocate a new \ref BindingTable and chain it to the one given.
+ * \brief Allocate a new \ref BindingTable.
  *
  * \returns the allocated \ref bandingtable.
  *
  * \related BindingTable
  */
-extern BindingTable *BindingTable_create(BindingTable *next);
+extern BindingTable *BindingTable_create();
 
 /**
- * \brief Reclaim a \ref BindingTable with all its bindings and return
- * its chained.
+ * \brief Reclaim a \ref BindingTable with all its bindings.
  *
  * \param bt is the \ref BindingTable to reclaim.
  *
- * \returns the chained \ref BindingTable.
- *
  * \related BindingTable
  */
-extern BindingTable *BindingTable_release(BindingTable *bt);
+extern void BindingTable_release(BindingTable *bt);
 
 /**
  * \brief Set a Binding in a \ref BindingTable.
@@ -46,6 +41,10 @@ extern BindingTable *BindingTable_release(BindingTable *bt);
  * \note Binding names are equal or not by means of strcmp, and each
  * name has a at most single Binding.
  *
+ * The name and the value are held as given with all memory management
+ * the callers responsibility. This function will however create new
+ * Binding objects and reclaim the old ones as needed.
+ *
  * A value of \b 0 indicates "unbound".
  *
  * \related BindingTable
@@ -59,14 +58,13 @@ extern void BindingTable_set(BindingTable *bt,char *name,void *value);
  *
  * \param name is the Binding variable name.
  *
- * \param value is the Binding value.
+ * \returns the value of the found Binding, or \b 0 if none is found.
  *
  * \note Binding names are equal or not by means of strcmp, and each
  * name has a at most single Binding.
  *
- * This function scan's the \ref BindingTable chain for the first
- * assignment, if any, of the name. Note that a name can be made
- * unbound on top of being bound by setting it to \b 0.
+ * \note Not also that a name can be made unbound on top of being
+ * bound by setting it to \b 0.
  *
  * \related BindingTable
  */
@@ -77,32 +75,23 @@ extern void *BindingTable_get(BindingTable *bt,char *name);
  *
  * \param bt is the BindingTable concerned.
  *
- * \param arity is the tuple arity.
- *
  * \param t is the tuple of (char*) names to dereference.
  */
-void BindingTable_deref(BindingTable *bt,int arity,Tuple *t);
+extern void BindingTable_deref(BindingTable *bt,Tuple *t);
 
 /**
- * \brief Unify two named bindings with option equal-value callback.
+ * \brief Set values for names, optionally unbinding names as well.
  *
- * \param bt is the first BindingTable concerned.
- *
- * \param n1 is the first Binding name.
+ * \param bt is the bindingtable concerned.
  *
- * \param n2 is the second Binding name.
+ * \param nm is the Tuple of names to bind.
  *
- * \param eq is the optional equal-value callback that returns 0 if
- * the given values are equal.
+ * \param vs is the Tuple of values.
  *
- * This function updates the top \ref BindingTable by assigning n1 or
- * n2 to any value the other has (in the chain) unless they have
- * different values (in the chain). If both are unassigned, then
- * neither get reassigned in the to both BindingTable/
+ * \param all is a flag to assign all (1) or only non-zero (0) values.
  *
- * \related BindingTable
+ * \note The values tuple must be as wide as the names tuple.
  */
-extern int BindingTable_unify(
-    BindingTable *bt,char *n1,char *n2,int (*eq)(void*,void*));
+extern void BindingTable_set_all(BindingTable *bt,Tuple *nm,Tuple *vs,int all);
 
 #endif
index 6d3da9202730c97e636444c9295515f3c6875d91..a3feec435d9f38d957cc082763f0d6ad8760801f 100644 (file)
@@ -1,8 +1,10 @@
 LIBRARY = libvector.a
 LIBOBJS = Vector.o HashVector.o
-LIBOBJS += Tuple.o TupleSchema.o integeritem.o  stringitem.o
-LIBOBJS += Relation.o
-LIBOBJS += BindingTable.o Query.o
+LIBOBJS += Tuple.o TupleSchema.o integeritem.o stringitem.o Binding.o
+LIBOBJS += BindingTable.o Relation.o Query.o
+LIBOBJS += AssignQuery.o RelationQuery.o
+LIBOBJS += NotQuery.o AndQuery.o OrQuery.o
+#LIBOBJS += View.o
 
 default: $(LIBRARY)
 
@@ -11,6 +13,11 @@ all: default
 CFLAGS = -Wall -g -fmax-errors=1 -I.
 LDLIBS = -lm
 
+%.h:
+       echo "#ifndef ${@:.h=_H}" > $@
+       echo "#define ${@:.h=_H}" >> $@
+       echo "#endif" >> $@
+
 define STDCC
 .INTERMEDIATE: $1.o
 CLEANRM += $1.o
diff --git a/vector/NotQuery.c b/vector/NotQuery.c
new file mode 100644 (file)
index 0000000..8418715
--- /dev/null
@@ -0,0 +1,41 @@
+#include <stdlib.h>
+#include <NotQuery.h>
+
+static void NotQuery_reclaim(Query *this) {
+    NotQuery *q = (NotQuery*) this;
+    Query_reclaim( q->query );
+    free( this );
+}
+
+static int NotQuery_next(
+    Query *this,BindingTable *bt,enum NextState state)
+{
+    NotQuery *q = (NotQuery*) this;
+    if ( state == initial ) {
+       if ( Query_next( q->query, bt, initial ) ) {
+           Query_next( q->query, bt, restore );
+           return 0;
+       }
+       return 1;
+    }
+    return 0;
+}
+
+static void NotQuery_variables(Query *this,HashVector *hv) {
+    Query_variables( ((NotQuery*) this)->query, hv );
+}
+
+static struct QueryCallbacks NotQuery_def = {
+    .reclaim = NotQuery_reclaim,
+    .next = NotQuery_next,
+    .variables = NotQuery_variables
+};
+
+Query *Query_not(Query *q) {
+    NotQuery *nq = (NotQuery*) malloc( sizeof( NotQuery ) );
+    (*nq) = (NotQuery) {
+       .def = &NotQuery_def,
+       .query = q
+    };
+    return (Query*) nq;
+}
diff --git a/vector/NotQuery.h b/vector/NotQuery.h
new file mode 100644 (file)
index 0000000..f2bf7ed
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef NotQuery_H
+#define NotQuery_H
+
+#include <Query.h>
+
+/**
+ * NotQuery represents logical negation.
+ *
+ * \extends Query
+ */
+typedef struct NotQuery {
+    struct QueryCallbacks *def;
+    Query *query;
+} NotQuery;
+
+#endif
diff --git a/vector/OrQuery.c b/vector/OrQuery.c
new file mode 100644 (file)
index 0000000..5a48e5e
--- /dev/null
@@ -0,0 +1,76 @@
+#include <stdarg.h>
+#include <stdlib.h>
+#include <OrQuery.h>
+
+static void OrQuery_reclaim(Query *this) {
+    OrQuery *q = (OrQuery*) this;
+    int i;
+    for ( i = 0; i < q->size; i++ ) {
+       Query_reclaim( q->disjuncts[i] );
+    }
+    free( q->disjuncts );
+    free( this );
+}
+
+static int OrQuery_next( Query *this,BindingTable *bt,enum NextState state) {
+    OrQuery *q = (OrQuery*) this;
+    int i = q->index;
+    enum NextState s = subsequent;
+    switch ( state ) {
+    case initial:
+       i = 0;
+       s = initial;
+    case subsequent:
+       for ( ; i < q->size; i++ ) {
+           if ( Query_next( q->disjuncts[i], bt, s ) ) {
+               q->index = i;
+               return 1;
+           }
+           Query_next( q->disjuncts[i], bt, restore );
+           s = initial;
+       }
+       q->index = -1;
+       return 0;
+    case restore:
+       if ( i >= 0 ) {
+           Query_next( q->disjuncts[i], bt, restore );
+           q->index = -1;
+       }
+       return 0;
+    }
+    return 0;
+}
+
+static void OrQuery_variables(Query *this,HashVector *hv) {
+    OrQuery *q = (OrQuery*) this;
+    int i; 
+    for ( i = 0; i < q->size; i++ ) {
+       Query_variables( q->disjuncts[i], hv );
+    }
+}
+
+static struct QueryCallbacks OrQuery_def = {
+    .reclaim = OrQuery_reclaim,
+    .next = OrQuery_next,
+    .variables = OrQuery_variables
+};
+
+Query *Query_or(int n,...) {
+    va_list args;
+    OrQuery *q = (OrQuery *)
+       malloc( sizeof( OrQuery ) );
+    (*q) = (OrQuery) {
+       .def = &OrQuery_def,
+       .index = -1,
+       .size = n,
+       .disjuncts = (Query**) malloc( n * sizeof( Query* ) ),
+    };
+    int i;
+    va_start( args, n );
+    for ( i = 0; i < n; i++ ) {
+       q->disjuncts[i] = va_arg( args, Query* );
+    }
+    va_end( args );
+    return (Query*) q;
+}
+
diff --git a/vector/OrQuery.h b/vector/OrQuery.h
new file mode 100644 (file)
index 0000000..9528356
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef OrQuery_H
+#define OrQuery_H
+
+#include <Query.h>
+
+/**
+ * OrQuery represents a disjunction of sub queries.
+ *
+ * \extends Query
+ */
+typedef struct {
+    struct QueryCallbacks *def;
+    int index;
+    int size;
+    Query **disjuncts;
+} OrQuery;
+
+#endif
index c13ecde73e418e4c399f190fc7ad4f370e46809f..94a39d744a2b288638d107501edbc7ab088c5b1c 100644 (file)
-#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
 #include <Query.h>
-#include <QueryCallbacks.h>
-
-/* ==================== AssignmentQuery ==================== */
 
 /**
- * AssignmentQuery represents an assignment of values to names.
- * \extends Query
- * \related Query
+ * \brief Trampoline for the callback function to reclaim the Query
+ * memory for a given Query.
+ *
+ * \param this is the specific \ref Query concerned.
+ *
+ * Ground queries recalim their own state memory. Composite
+ * queries first propagate the reclaim call to its components, and
+ * thereafter reclaim their local state memory.
  */
-typedef struct {
-    struct QueryCallbacks *def;
-    int arity;
-    Tuple *names;
-    Tuple *values;
-    Tuple *saved;
-} AssignmentQuery;
-
-// Release any memory.
-static void AssignmentQuery_reclaim(Query *this) {
-    AssignmentQuery *q = (AssignmentQuery*) this;
-    free( q->saved );
-    free( this );
-}
-
-static int AssignmentQuery_check(int arity,Tuple *a,Tuple *b) {
-    int i;
-    for ( i = 0; i < arity; i++ ) {
-       char *value = a->elements[i];
-       char *current = b->elements[i];
-       if ( value && current && current != value &&
-            strcmp( current, value ) != 0 ) {
-           return 0;
-       }
-    }
-    return 1;
-}
-
-static void AssignmentQuery_assign(
-    BindingTable *bt,int n,Tuple *names,Tuple *values,int all)
-{
-    int i;
-    for ( i = 0; i < n; i++ ) {
-       if ( all || values->elements[i] ) {
-           BindingTable_set( bt, names->elements[i], values->elements[i] );
-       }
-    }
-}
-
-// Make names have given values and return 1. If any name has a
-// different value then return 0. Values are strings.
-static int AssignmentQuery_next(
-    Query *this,BindingTable *bt,enum NextState state) {
-    AssignmentQuery *q = (AssignmentQuery*) this;
-    switch ( state ) {
-    case initial:
-       if ( q->saved == 0 ) {
-           q->saved = Tuple_clone( q->arity, q->names );
-       } else {
-           memcpy( q->saved, q->names, q->arity * sizeof( void* ) );
-       }
-       BindingTable_deref( bt, q->arity, q->saved );
-       // Check with new values
-       if ( AssignmentQuery_check( q->arity, q->values, q->saved ) ) {
-           AssignmentQuery_assign( bt, q->arity, q->names, q->values, 0 );
-           return 1;
-       }
-       // Fall through
-    case subsequent:
-    case restore:
-       if ( q->saved ) {
-           AssignmentQuery_assign( bt, q->arity, q->names, q->saved, 1 );
-           free( q->saved );
-           q->saved = 0;
-       }
-       return 0;
-    }
-    return 0;
+void Query_reclaim(Query *this) {
+    this->def->reclaim( this );
 }
 
-static struct QueryCallbacks AssignmentQuery_def = {
-    .reclaim = AssignmentQuery_reclaim,
-    .next = AssignmentQuery_next
-};
-
 /**
- * Return a Query object representing an assignment of one or more
- * variables.
+ * \brief Trampoline for the callback function to update the Binding
+ * table with a succession of alternative bindings.
+ *
+ * \param this is the specific \ref Query concerned.
+ *
+ * \param bt is the Binding table to set bindings in.
+ *
+ * \param s is the call "sub-command" for the function.
+ *
+ * \returns 1 if a new Binding is provided and 0 otherwise.
+ *
+ * This function is called repeatedly for successively obtaining
+ * the alternative bindings that satisfy the Query. The "initial"
+ * state sub-command tells the function to capture the incoming
+ * BindingTable state so that the function can later restore it
+ * upon the "restore" sub-command. Upon the "initial" command, the
+ * function also sets up the Binding table with its first Binding
+ * alternative. This is followed by a series of "subsequent"
+ * sub-command calls for the function to change the BindingTable
+ * for its succession of Binding alternatives. The function should
+ * return 1 after any successful Binding setup, and return 0 when
+ * it cannot setup any (more) Binding.
  */
-Query *Query_assign(int arity,Tuple *names,Tuple *values) {
-    AssignmentQuery *q = (AssignmentQuery*)
-       malloc( sizeof( AssignmentQuery ) );
-    (*q) = (AssignmentQuery) {
-       .def = &AssignmentQuery_def,
-       .arity = arity,
-       .names = names,
-       .values = values,
-       .saved = 0
-    };
-    return (Query*) q;
+int Query_next(Query *this,BindingTable *bt,enum NextState state) {
+    return this->def->next( this, bt, state );
 }
 
-/* ==================== conjunction ==================== */
-
 /**
- * ConjunctionQuery represents a conjunction of sub queries.
- * \extends Query
- * \related Query
+ * \brief Trampoline for the callback function that adds its binding
+ * names to the hashvector.
  */
-typedef struct {
-    struct QueryCallbacks *def;
-    int active;
-    int size;
-    Query **conjuncts;
-} ConjunctionQuery;
-
-static void ConjunctionQuery_reclaim(Query *this) {
-    ConjunctionQuery *q = (ConjunctionQuery*) this;
-    int i;
-    for ( i = 0; i < q->size; i++ ) {
-       q->conjuncts[i]->def->reclaim( q->conjuncts[i] );
-    }
-    free( q->conjuncts );
-    free( this );
+void Query_variables(Query *this,HashVector *hv) {
+    this->def->variables( this, hv );
 }
 
-static int ConjunctionQuery_next(
-    Query *this,BindingTable *bt,enum NextState state)
+void Query_eval(
+    Query *q,BindingTable *bt,
+    int (*consequent)(BindingTable *bt,void *data),
+    void *data )
 {
-    ConjunctionQuery *q = (ConjunctionQuery*) this;
-    int i = q->size - 1;
-    enum NextState s = subsequent;
-    switch ( state ) {
-    case initial:
-       q->active = 1;
-       i = 0;
-       s = initial;
-       // Fall through?
-    case subsequent:
-       while ( i < q->size ) {
-           if ( q->conjuncts[i]->def->next( q->conjuncts[i], bt, s ) ) {
-               continue;
-           }
-           q->conjuncts[i]->def->next( q->conjuncts[i], bt, restore );
-           if ( i-- == 0 ) {
-               // The first conjunct now exhausted
-               q->active = 0;
-               return 0;
-           }
-           s = subsequent;
-       }
-       return 1;
-    case restore:
-       if ( q->active ) {
-           for ( ; i >= 0; i-- ) {
-               q->conjuncts[i]->def->next( q->conjuncts[i], bt, restore );
-           }
-       }
-       q->active = 0;
-       return 0;
-    }
-    return 0;
-}
-
-static struct QueryCallbacks ConjunctionQuery_def = {
-    .reclaim = ConjunctionQuery_reclaim,
-    .next = ConjunctionQuery_next
-};
-
-Query *Query_and(int n,...) {
-    va_list args;
-    ConjunctionQuery *q = (ConjunctionQuery *)
-       malloc( sizeof( ConjunctionQuery ) );
-    (*q) = (ConjunctionQuery) {
-       .def = &ConjunctionQuery_def,
-       .active = 0,
-       .size = n,
-       .conjuncts = (Query**) malloc( n * sizeof( Query* ) )
-    };
-    int i;
-    va_start( args, n );
-    for ( i = 0; i < n; i++ ) {
-       q->conjuncts[i] = va_arg( args, Query* );
-    }
-    va_end( args );
-    return (Query*) q;
-}
-
-/* ==================== disjunction ==================== */
-
-/**
- * DisjunctionQuery represents a disjunction of sub queries.
- * \extends Query
- * \related Query
- */
-typedef struct {
-    struct QueryCallbacks *def;
-    int index;
-    int size;
-    Query **disjuncts;
-} DisjunctionQuery;
-
-static void DisjunctionQuery_reclaim(Query *this) {
-    DisjunctionQuery *q = (DisjunctionQuery*) this;
-    int i;
-    for ( i = 0; i < q->size; i++ ) {
-       q->disjuncts[i]->def->reclaim( q->disjuncts[i] );
-    }
-    free( q->disjuncts );
-    free( this );
-}
-
-static int DisjunctionQuery_next(
-    Query *this,BindingTable *bt,enum NextState state) {
-    DisjunctionQuery *q = (DisjunctionQuery*) this;
-    int i = q->index;
-    enum NextState s = subsequent;
-    switch ( state ) {
-    case initial:
-       i = 0;
-       s = initial;
-    case subsequent:
-       for ( ; i < q->size; i++ ) {
-           if ( q->disjuncts[i]->def->next( q->disjuncts[i], bt, s ) ) {
-               q->index = i;
-               return 1;
-           }
-           q->disjuncts[i]->def->next( q->disjuncts[i], bt, restore );
-           s = initial;
-       }
-       q->index = -1;
-       return 0;
-    case restore:
-       if ( i >= 0 ) {
-           q->disjuncts[i]->def->next( q->disjuncts[i], bt, restore );
-           q->index = -1;
-       }
-       return 0;
-    }
-    return 0;
-}
-
-static struct QueryCallbacks DisjunctionQuery_def = {
-    .reclaim = DisjunctionQuery_reclaim,
-    .next = DisjunctionQuery_next,
-};
-
-Query *Query_or(int n,...) {
-    va_list args;
-    DisjunctionQuery *q = (DisjunctionQuery *)
-       malloc( sizeof( DisjunctionQuery ) );
-    (*q) = (DisjunctionQuery) {
-       .def = &DisjunctionQuery_def,
-       .index = -1,
-       .size = n,
-       .disjuncts = (Query**) malloc( n * sizeof( Query* ) ),
-    };
-    int i;
-    va_start( args, n );
-    for ( i = 0; i < n; i++ ) {
-       q->disjuncts[i] = va_arg( args, Query* );
+    if ( Query_next( q, bt, initial ) && consequent( bt, data ) ) {
+       while ( Query_next( q, bt, subsequent ) && consequent( bt, data ) );
     }
-    va_end( args );
-    return (Query*) q;
+    (void) Query_next( q, bt, restore );
 }
 
-/* ==================== Relation access ==================== */
+/* ==================== Snapshotting a query ==================== */
 
 /**
- * RelationQuery represents a ground query on a relation.
- * \extends Query
- * \related Query
+ * The data used for bindings capture in  snapshotting.
  */
-typedef struct {
-    struct QueryCallbacks *def;
-    Relation *rel;
-    VectorIndex index;
+struct Query_snapshot_data {
     Tuple *names;
-    Tuple *values;
-    Tuple *saved;
-} RelationQuery;
-
-// Release any memory.
-static void RelationQuery_reclaim(Query *this) {
-    RelationQuery *q = (RelationQuery*) this;
-    free( q->saved );
-    free( this );
-}
-
-// Make names have given values and return 1. If any name has a
-// different value then return 0. Values are strings.
-static int RelationQuery_next(
-    Query *this,BindingTable *bt,enum NextState state) {
-    RelationQuery *q = (RelationQuery*) this;
-    int arity = ((TupleSchema*) q->rel->content.type)->arity;
-    VectorIndex index = q->index + 1;
-    switch ( state ) {
-    case initial:
-       if ( q->saved == 0 ) {
-           q->saved = Tuple_clone( arity, q->names );
-       } else {
-           memcpy( q->saved, q->names, arity * sizeof( void* ) );
-       }
-       BindingTable_deref( bt, arity, q->saved );
-       index = 0;
-       // Fall through
-    case subsequent:
-       for ( ; index < q->rel->content.table.size; index++ ) {
-           Tuple *values = Relation_next( q->rel, &index, q->values );
-           if ( values ) {
-               q->index = index;
-               AssignmentQuery_assign( bt, arity, q->names, values, 1 );
-               return 1;
-           }
-       }
-    case restore:
-       if ( q->saved ) {
-           AssignmentQuery_assign( bt, arity, q->names, q->saved, 1 );
-           free( q->saved );
-           q->saved = 0;
-       }
-       return 0;
-    }
-    return 0;
-}
-
-static struct QueryCallbacks RelationQuery_def = {
-    .reclaim = RelationQuery_reclaim,
-    .next = RelationQuery_next
+    Vector *v;
 };
 
-/**
- * Return a Query object representing an Relation of one or more
- * variables.
- */
-Query *Query_Relation(Relation *r,Tuple *names,Tuple *values) {
-    RelationQuery *q = (RelationQuery*) malloc( sizeof( RelationQuery ) );
-    (*q) = (RelationQuery) {
-       .def = &RelationQuery_def,
-       .rel = r,
-       .names = names,
-       .values = values,
-       .saved = 0
-    };
-    return (Query*) q;
+static int Query_snapshot_capture(BindingTable *bt,void *data) {
+    struct Query_snapshot_data *d = (struct Query_snapshot_data*) data;
+    Tuple *values = Tuple_clone( d->names );
+    BindingTable_deref( bt, values );
+    Vector_append( d->v, values );
+    return 1;
 }
 
-void Query_rule(
-    Query *q,BindingTable *bt,
-    int (*consequent)(BindingTable *bt,void *data),
-    void *data )
-{
-    if ( q->def->next( q, bt, initial ) && consequent( bt, data ) ) {
-       while ( q->def->next( q, bt, subsequent ) && consequent( bt, data ) );
-    }
-    (void) q->def->next( q, bt, restore );
+int Query_snapshot(Query *q,Tuple *names,Vector *v) {
+    BindingTable *bt = BindingTable_create( 0 );
+    struct Query_snapshot_data data = {        .names = names, .v = v };
+    Vector_resize( v, 0, Vector_free_any, 0 );
+    Query_eval( q, bt, Query_snapshot_capture, &data );
+    return v->size;
 }
index 188a1eaae1d0383373cd1b32c8209af689b2a470..4b2fa6a08c335711a7daae02e2840d18b07a6484 100644 (file)
@@ -1,11 +1,9 @@
 #ifndef Query_H
 #define Query_H
 
-#include <TupleSchema.h>
-#include <Relation.h>
+#include <QueryCallbacks.h>
 #include <BindingTable.h>
-
-struct QueryCallbacks;
+#include <Relation.h>
 
 /**
  * A Query is an implementation of a generic ABI over relations. It's
@@ -18,6 +16,57 @@ typedef struct Query {
     struct QueryCallbacks *def;
 } Query;
 
+/**
+ * \brief Trampoline for the callback function to reclaim the Query
+ * memory for a given Query.
+ *
+ * \param this is the specific \ref Query concerned.
+ *
+ * Ground queries recalim their own state memory. Composite
+ * queries first propagate the reclaim call to its components, and
+ * thereafter reclaim their local state memory.
+ */
+extern void Query_reclaim(Query *this);
+
+/**
+ * \brief Trampoline for the callback function to update the Binding
+ * table with a succession of alternative bindings.
+ *
+ * \param this is the specific \ref Query concerned.
+ *
+ * \param bt is the Binding table to set bindings in.
+ *
+ * \param s is the call "sub-command" for the function.
+ *
+ * \returns 1 if a new Binding is provided and 0 otherwise.
+ *
+ * This function is called repeatedly for successively obtaining
+ * the alternative bindings that satisfy the Query. The "initial"
+ * state sub-command tells the function to capture the incoming
+ * BindingTable state so that the function can later restore it
+ * upon the "restore" sub-command. Upon the "initial" command, the
+ * function also sets up the Binding table with its first Binding
+ * alternative. This is followed by a series of "subsequent"
+ * sub-command calls for the function to change the BindingTable
+ * for its succession of Binding alternatives. The function should
+ * return 1 after any successful Binding setup, and return 0 when
+ * it cannot setup any (more) Binding.
+ */
+extern int Query_next(Query *this,BindingTable *bt,enum NextState state);
+
+/**
+ * \brief Trampoline for the callback function that adds its binding
+ * names to the hashvector.
+ *
+ * \param this is the query concerned.
+ *
+ * \param hv is the HashVector for collating names.
+ */
+extern void Query_variables(Query *this,HashVector *hv);
+
+
+
+
 /**
  * \brief Creates an assignment Query.
  *
@@ -104,9 +153,38 @@ extern Query *Query_or(int n,...);
  * 
  * \related Query
  */
-extern void Query_rule(
+extern void Query_eval(
     Query *q,BindingTable *bt,
     int (*consequent)(BindingTable *bt,void *data),
     void *data );
 
+/**
+ * \brief Collect all bindings of query.
+ *
+ * \param q is the query to enumerate.
+ *
+ * \param names is the binding names to track.
+ *
+ * \param results is the result store of bindings for the names.
+ *
+ * \returns the number of results.
+ *
+ * This function evaluates the query for one round of bindings, and
+ * stores their value \ref Tuple Tuples in the given vector. The given
+ * vector is first cleared, and any item is reclaimed with \b free.
+ * Correspondingly the binding \ref Tuple Tuples are allocated with \b
+ * malloc for the caller to reclaim (possibly via a successive call to
+ * this function).
+ */
+//extern int Query_snapshot(Query *q,Tuple *names,Vector *v);
+
+/**
+ * \brief Creates an NotQuery.
+ *
+ * \param query is the query to negate.
+ *
+ * \related Query
+ */
+extern Query *Query_not(Query *values);
+
 #endif
index ad4461b426ce36f407fd3e1a8dfd46c3d6994632..5d36e0b6ee4e590ddb876ee7e904f783732d5f42 100644 (file)
@@ -1,9 +1,9 @@
 #ifndef QueryCallbacks_H
 #define QueryCallbacks_H
 
-typedef struct HashVector HashVector;
-typedef struct Query Query;
-typedef struct BindingTable BindingTable;;
+#include <BindingTable.h>
+
+typedef struct Query Query; // forward
 
 enum NextState {
     /**
@@ -41,6 +41,7 @@ typedef struct QueryCallbacks {
      * thereafter reclaim their local state memory.
      */
     void (*reclaim)(Query *this);
+
     /**
      * \brief Callback function to update the Binding table with a
      * succession of alternative bindings.
@@ -66,6 +67,7 @@ typedef struct QueryCallbacks {
      * it cannot setup any (more) Binding.
      */
     int (*next)(Query *this,BindingTable *bt,enum NextState state);
+
     /**
      * \brief This callback function adds its binding names to the
      * hashvector.
index 0f671abce2d09c475f8092e22ff760825211250c..868a47776f0f495e476618bdc7927a5148d98107 100644 (file)
@@ -30,17 +30,16 @@ Relation *Relation_create(TupleSchema *schema) {
 int Relation_add_constraint(Relation *r,...) {
     va_list ap;
     TupleSchema *ts = (TupleSchema *) r->content.type;
-    Tuple *columns = (Tuple*) malloc(
-       sizeof( Tuple ) + ts->arity * sizeof( void* ) );
+    Tuple *columns = Tuple_clone( ts->columns );
     int i = 0;
     va_start( ap, r );
-    for ( ; i < ts->arity; i++ ) {
-       if ( va_arg( ap, int ) ) {
-           columns->elements[i] = ts->columns->elements[i];
+    for ( ; i < columns->size; i++ ) {
+       if ( va_arg( ap, int ) == 0 ) {
+           columns->elements[i] = 0;
        }
     }
     va_end( ap );
-    ts = TupleSchema_create( ts->arity, columns );
+    ts = TupleSchema_create( columns );
     i = (int) r->constraints.size;
     Vector_append(
        &r->constraints,
diff --git a/vector/RelationQuery.c b/vector/RelationQuery.c
new file mode 100644 (file)
index 0000000..aa4bdbd
--- /dev/null
@@ -0,0 +1,78 @@
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <RelationQuery.h>
+
+// Release any memory.
+static void RelationQuery_reclaim(Query *this) {
+    RelationQuery *q = (RelationQuery*) this;
+    free( q->saved );
+    free( this );
+}
+
+// Make names have given values and return 1. If any name has a
+// different value then return 0. Values are strings.
+static int RelationQuery_next(
+    Query *this,BindingTable *bt,enum NextState state) {
+    RelationQuery *q = (RelationQuery*) this;
+    VectorIndex index = q->index + 1;
+    switch ( state ) {
+    case initial:
+       if ( q->saved == 0 ) {
+           q->saved = Tuple_clone( q->names );
+       } else {
+           memcpy( q->saved, q->names, q->names->size * sizeof( void* ) );
+       }
+       BindingTable_deref( bt, q->saved );
+       index = 0;
+       // Fall through
+    case subsequent:
+       for ( ; index < q->rel->content.table.size; index++ ) {
+           Tuple *values = Relation_next( q->rel, &index, q->values );
+           if ( values ) {
+               q->index = index;
+               BindingTable_set_all( bt, q->names, values, 1 );
+               return 1;
+           }
+       }
+    case restore:
+       if ( q->saved ) {
+           BindingTable_set_all( bt, q->names, q->saved, 1 );
+           free( q->saved );
+           q->saved = 0;
+       }
+       return 0;
+    }
+    return 0;
+}
+
+static void RelationQuery_variables(Query *this,HashVector *hv) {
+    RelationQuery *q = (RelationQuery*) this;
+    unsigned long i;
+    for ( i = 0; i < q->names->size; i++ ) {
+       HashVector_add( hv, q->names->elements[i] );
+    }
+}
+
+static struct QueryCallbacks RelationQuery_def = {
+    .reclaim = RelationQuery_reclaim,
+    .next = RelationQuery_next,
+    .variables = RelationQuery_variables
+};
+
+/**
+ * Return a Query object representing an Relation of one or more
+ * variables.
+ */
+Query *Query_relation(Relation *r,Tuple *names,Tuple *values) {
+    RelationQuery *q = (RelationQuery*) malloc( sizeof( RelationQuery ) );
+    (*q) = (RelationQuery) {
+       .def = &RelationQuery_def,
+       .rel = r,
+       .names = names,
+       .values = values,
+       .saved = 0
+    };
+    return (Query*) q;
+}
+
diff --git a/vector/RelationQuery.h b/vector/RelationQuery.h
new file mode 100644 (file)
index 0000000..4c50a53
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef RelationQuery_H
+#define RelationQuery_H
+
+#include <Relation.h>
+#include <Query.h>
+
+/**
+ * RelationQuery represents a ground query on a relation.
+ * \extends Query
+ * \related Query
+ */
+typedef struct {
+    struct QueryCallbacks *def;
+    Relation *rel;
+    VectorIndex index;
+    Tuple *names;
+    Tuple *values;
+    Tuple *saved;
+} RelationQuery;
+
+#endif
diff --git a/vector/StackVector.h b/vector/StackVector.h
new file mode 100644 (file)
index 0000000..1539366
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef StackVector_H
+#define StackVector_H
+
+/**
+ * A StackVector is a management layer around a single_index_level
+ * Vector to allow it to have extra memory allocated
+ */
+#endif
index e5341bd1a807a1ae298630b4d5e964d28e39139b..2b5b04e72ff80a08f423ad5a12321795deeaff57 100644 (file)
@@ -3,19 +3,20 @@
 #include <string.h>
 #include <Tuple.h>
 
-Tuple *Tuple_calloc(int arity) {
+// Allocate zero-ed
+Tuple *Tuple_calloc(unsigned long arity) {
     Tuple *t = (Tuple *) malloc( sizeof( Tuple ) + arity * sizeof( void* ) );
-    t->types = 0;
+    t->size = arity;
     memset( t->elements, 0, arity * sizeof( void* ) );
     return t;
 }
 
-// Allocate
+// Allocate with values
 Tuple *Tuple_create(int arity,...) {
     va_list ap;
     int i;
     Tuple *t = (Tuple *) malloc( sizeof( Tuple ) + arity * sizeof( void* ) );
-    t->types = 0; // unknown types
+    t->size = arity;
     va_start( ap, arity );
     for ( i = 0; i < arity; i++ ) {
        t->elements[i] = va_arg( ap, void* );
@@ -24,21 +25,10 @@ Tuple *Tuple_create(int arity,...) {
     return t;
 }
 
-Tuple *Tuple_clone(int arity,Tuple *t) {
-    Tuple *ct = (Tuple *)malloc( sizeof( Tuple ) + arity * sizeof( void* ) );
-    memcpy( ct, t, arity * sizeof( void* ) );
+// Duplicate
+Tuple *Tuple_clone(Tuple *t) {
+    unsigned long size = t->size * sizeof( void* );
+    Tuple *ct = (Tuple *) malloc( sizeof( Tuple ) + size );
+    memcpy( ct, t, size );
     return ct;
 }
-
-#if 0
-unsigned long Tuple_mask(int arity,Tuple *t) {
-    unsigned long mask = 0;
-    while ( arity-- > 0 ) {
-       mask <<= 1;
-       if ( t->elements[ arity ] ) {
-           mask |= 1;
-       }
-    }
-    return mask;
-}
-#endif
index fb6bbd6582df49326f9ceecfcca7f9c88a06d343..ea439c5dbe3ea9955fbb52565bcc26f722b48916 100644 (file)
@@ -9,7 +9,14 @@ typedef struct TupleSchema TupleSchema;
  * A Tuple is a "self typed" array of elements.
  */
 typedef struct {
-    TupleSchema *types;
+    /**
+     * The number of elements.
+     */
+    unsigned long size;
+    /**
+     * Base address for element pointers, which thus follow this
+     * struct in memory.
+     */
     void *elements[];
 } Tuple;
 
@@ -25,13 +32,13 @@ extern Tuple *Tuple_create(int arity,...);
  *
  * \related Tuple
  */
-extern Tuple *Tuple_calloc(int arity);
+extern Tuple *Tuple_calloc(unsigned long arity);
 
 /**
  * \brief Create a tuple as a clone of a given tuple.
  *
  * \related Tuple
  */
-extern Tuple *Tuple_clone(int arity,Tuple *t);
+extern Tuple *Tuple_clone(Tuple *t);
 
 #endif
index 5616b2dd5a6bf722b5c762095c997d05669c6c45..5a92b64db32d52239fcb83304c0bfcd40e2a2c9f 100644 (file)
@@ -26,7 +26,7 @@ static unsigned long TupleSchema_hashcode(void *this,void *key) {
     Tuple *kp = (Tuple*) key;
     int i = 0;
     unsigned long value = 5381;
-    for ( ; i < def->arity; i++ ) {
+    for ( ; i < def->columns->size; i++ ) {
        if ( columns[i] ) {
            value <<= 3;
            if ( kp->elements[i] ) {
@@ -48,7 +48,7 @@ static int TupleSchema_haskey(void *this,void *item,void *key) {
     Tuple *kp = (Tuple*) key;
     Tuple *tp = (Tuple*) item;
     int i = 0;
-    for ( ; i < def->arity; i++ ) {
+    for ( ; i < def->columns->size; i++ ) {
        if ( columns[i] && kp->elements[i] ) {
            if ( columns[i]->haskey(
                     columns[i], tp->elements[i], kp->elements[i] ) == 0 ) {
@@ -68,9 +68,9 @@ static void *TupleSchema_itemkey(void *this,void *item) {
     TupleSchema *def = (TupleSchema *) this;
     ItemKeyFun **columns = (ItemKeyFun**) def->columns->elements;
     Tuple *tp = (Tuple*) item;
-    Tuple *key = Tuple_clone( def->arity, tp );
+    Tuple *key = Tuple_clone( tp );
     int i;
-    for ( i = 0; i < def->arity; i++ ) {
+    for ( i = 0; i < def->columns->size; i++ ) {
        if ( columns[i] ) {
            key->elements[i] = columns[i]->itemkey(
                columns[i], tp->elements[i] );
@@ -90,7 +90,7 @@ static void TupleSchema_releasekey(void *this,void *key) {
     ItemKeyFun **columns = (ItemKeyFun**) def->columns->elements;
     Tuple *kp = (Tuple*) key;
     int i;
-    for ( i = 0; i < def->arity; i++ ) {
+    for ( i = 0; i < def->columns->size; i++ ) {
        if ( columns[i] ) {
            columns[i]->releasekey( columns[i], kp->elements[i] );
        }
@@ -110,7 +110,7 @@ static int TupleSchema_tostring(void *this,void *item,char *buffer,int limit) {
     Tuple *t = (Tuple*) item;
     char *x = "<";
     int a, i;
-    for ( i = 0; i < def->arity; i++ ) {
+    for ( i = 0; i < def->columns->size; i++ ) {
        OUT( snprintf( buffer, limit, x ) );
        x = ",";
        OUT( columns[i]->tostring(
@@ -128,11 +128,10 @@ ItemKeyFun TupleSchema_callbacks = {
     .tostring = TupleSchema_tostring
 };
 
-TupleSchema *TupleSchema_create(int arity,Tuple *columns) {
+TupleSchema *TupleSchema_create(Tuple *columns) {
     TupleSchema *ts = (TupleSchema*) malloc( sizeof( TupleSchema ) );
     (*ts) = (TupleSchema) {
        .base = TupleSchema_callbacks,
-       .arity = arity,
        .columns = columns
     };
     return ts;
@@ -144,13 +143,13 @@ TupleSchema *TupleSchema_create(int arity,Tuple *columns) {
 // Duplicate a TupleSchema with optionally some columns reset.
 TupleSchema *TupleSchema_mask(TupleSchema *schema,...) {
     TupleSchema *masked = COPY(TupleSchema,schema);
-    masked->columns = Tuple_clone( schema->arity, schema->columns );
+    masked->columns = Tuple_clone( schema->columns );
     va_list ap;
     int i;
     va_start( ap, schema );
     for ( ;; ) {
        i = va_arg( ap, int );
-       if ( i < 0 || i >= schema->arity ) {
+       if ( i < 0 || i >= schema->columns->size ) {
            break;
        }
        masked->columns->elements[i] = 0;
index 72fdc1e5bdc28a5059280c5576a1e042a7477202..7bfb67d33305511c08f95cf6c3552833c50b95e1 100644 (file)
@@ -20,11 +20,6 @@ typedef struct TupleSchema {
      */
     ItemKeyFun base;
 
-    /**
-     * This is the number of columns in a tuple.
-     */
-    int arity;
-
     /**
      * This points to tuple whose elements is array of pointers to the
      * tuple item domains as represented by their associated
@@ -38,7 +33,7 @@ typedef struct TupleSchema {
  *
  * \related TupleSchema
  */
-extern TupleSchema *TupleSchema_create(int arity,Tuple *columns);
+extern TupleSchema *TupleSchema_create(Tuple *columns);
 
 /**
  * Copy the given TupleSchema into a new TupleSchema with some columns
index 5da2bcc0719a466c3d754e099ace0e66826ba9cc..5b3179a9738d0ec8bea182c1a84695790b20dfba 100644 (file)
@@ -27,7 +27,7 @@ typedef struct {
      * This is the collection of bindings for the tracked names being
      * gained at the latest evaluation.
      */
-    HashVector gained;
+    Vector gained;
     /**
      * This is the collection of bindings for the tracked names being
      * last at the latest evaluation.
@@ -39,13 +39,23 @@ static Tuple *View_type_Tuple(HashVector *hv) {
     Tuple *t = Tuple_calloc( hv->fill );
     VectorIndex index = 0;
     for ( ; index < hv->table.size; index++ ) {
-       t->elements[ index ] = &stringitem;
+       t->elements[ index ] = HashVector_next( hv, &index );
     }
     return t;
 }
 
+static void View_reclaim(Query *this) {
+    View *v = (View*) this;
+    TupleSchema *ts = (TupleSchema*) gained->type;
+    Vector_resize( &v->gained, 0, Vector_clear_any, 0 );
+    Vector_resize( &v->lost, 0, Vector_clear_any, 0 );
+    free( ts->columns );
+    free( ts );
+    free( this );
+}
+
 static QueryCallbacks View_def = {
-    .reclaim = 0,
+    .reclaim = View_reclaim,
     .next = 0,
     .variables = 0
 };
@@ -82,5 +92,6 @@ Query *View_create(Query *q) {
            .fill = 0, .holes = 0, .type = (ItemKeyFun*) ts
        }
     };
+    Vector_resize( &hv, 0, Vector_clear_any, 0 );
     return (Query*) vq;
 }
index 92e38e4bc58c681b1d6321d96e04fe62dc9babb8..e60ff8e56ad871530eacca4582a0c962d7591751 100644 (file)
@@ -1,5 +1,19 @@
 #ifndef View_H
 #define View_H
 
+/**
+ * \brief Create a ViewQuery for monitoring the binding stream of a
+ * sub query.
+ *
+ * \param q is the sub query to monitor.
+ *
+ * \returns the ViewQuery qua Query.
+ *
+ * A ViewQuery tracks the binding succession of a sub query, through
+ * each initial, repeated subsequent and final restore sequence, in
+ * order to tell if a binding is new or lost relative to the previous
+ * sequence. The ViewQuery is
+ */
+extern Query *View_create(Query *q);
 
 #endif