Cleanup Tuple to allow self-typing.
authorRalph Ronnquist <ralph.ronnquist@gmail.com>
Wed, 13 Jul 2022 04:04:20 +0000 (14:04 +1000)
committerRalph Ronnquist <ralph.ronnquist@gmail.com>
Wed, 13 Jul 2022 04:04:20 +0000 (14:04 +1000)
17 files changed:
tests/example-relation.c
tests/relationtests.c
vector/BindingTable.c
vector/BindingTable.h
vector/HashVector.c
vector/HashVector.h
vector/Makefile
vector/Query.c
vector/Query.h
vector/QueryCallbacks.h [new file with mode: 0644]
vector/Relation.c
vector/Relation.h
vector/Tuple.c [new file with mode: 0644]
vector/Tuple.h [new file with mode: 0644]
vector/TupleSchema.c
vector/TupleSchema.h
vector/Vector.c

index 2c76f6462df1ab042d328fdfee2439f206ea9d5e..73b0dc0b66b94fd1c21aac82b6dcf9d2f28ab990 100644 (file)
@@ -16,20 +16,21 @@ char *val(void* t) {
     return "(null)";
 }
 
-void prtuple(char *pre, tuple *t) {
+void prtuple(char *pre, Tuple *t) {
     if ( t ) {
-       fprintf( stderr, "%s<%s, %s>\n", pre, val((*t)[0]), val((*t)[1]) );
+       fprintf( stderr, "%s<%s, %s>\n", pre,
+                val(t->elements[0]), val(t->elements[1]) );
     } else {
        // fprintf( stderr, "%s< >\n", pre );
     }
 }
 
 void prdropout(const VectorIndex index,const void *t) {
-    prtuple( ".. ", (tuple*)t );
+    prtuple( ".. ", (Tuple*)t );
 }
 
 void add_Relation(Relation *r,char *p,char *c) {
-    tuple *t = tuple_create( 2, p, c);
+    Tuple *t = Tuple_create( 2, p, c);
     prtuple( "Adding: ", t );
     Vector *dropped = Relation_add( r, t );
     if ( dropped ) {
@@ -41,25 +42,26 @@ void add_Relation(Relation *r,char *p,char *c) {
 }
 
 typedef union {
+    Tuple tup;
     struct {
+       void *type;
        void *c1;
        void *c2;
     } cols;
-    void *tup[2];
-} tuple2;
+} Tuple2;
 
 int main(int argc,char **argv) {
     Relation *rltn2 = Relation_create(
        TupleSchema_create(
-           2, tuple_create( 2, (void*) &stringitem, (void*) &stringitem ) ) );
+           2, Tuple_create( 2, (void*) &stringitem, (void*) &stringitem ) ) );
     Relation_add_constraint( rltn2, 0, 1 );
     add_Relation( rltn2, "benton", "holly" );
     add_Relation( rltn2, "benton", "molly");
     add_Relation( rltn2, "gully", "holly");
     add_Relation( rltn2, "gully", "vanitha");
     VectorIndex index = 0;
-    tuple2 q1 = {{ "benton", 0 }};
-    tuple *t;
+    Tuple2 q1 = (Tuple2) { .cols = { 0, "benton", 0 }};
+    Tuple *t;
     prtuple( "Simple query: ", &q1.tup );
     for ( ; index < rltn2->content.table.size; index++ ) {
        t = Relation_next( rltn2, &index, &q1.tup );
@@ -72,14 +74,14 @@ int main(int argc,char **argv) {
        prtuple( ".. ", t );
     }
     // Test Generic query
-    q1 = (tuple2) {{ 0, 0 }};
+    q1 = (Tuple2) { .cols = { 0, 0, 0 }};
     prtuple( "Generic query: ", &q1.tup );
     for ( index = 0 ; index < rltn2->content.table.size; index++ ) {
        t = Relation_next( rltn2, &index, &q1.tup );
        prtuple( ".. ", t );
     }
     // Test deletion
-    q1 = (tuple2) {{ "gully", 0 }};
+    q1 = (Tuple2) { .cols = { 0, "gully", 0 }};
     prtuple( "Deletion query: ", &q1.tup );
     Vector *deleted = Relation_delete( rltn2, &q1.tup );
     for ( index = 0 ; index < rltn2->content.table.size; index++ ) {
@@ -87,7 +89,7 @@ int main(int argc,char **argv) {
        prtuple( ".. ", t );
     }
     for ( index = 0 ; index < deleted->size; index++ ) {
-       tuple **p = (tuple**) Vector_next_used( deleted, &index );
+       Tuple **p = (Tuple**) Vector_next_used( deleted, &index );
        prtuple( "** ", p? *p : 0 );
     }
     return 0;
index 7b565b626c456ff4877904d8a16d010305ae6251..459af748dc99d73acf448b058815128e19df985e 100644 (file)
@@ -7,7 +7,7 @@
 
 #define SIZE(x) (sizeof(x)/sizeof(void*))
 
-static char *tuple2string(Relation *r,tuple *t) {
+static char *tuple2string(Relation *r,Tuple *t) {
     #define LIMIT 10000
     static char tmp[10][ LIMIT ];
     static int i = 0;
@@ -24,15 +24,15 @@ static char *tuple2string(Relation *r,tuple *t) {
     return tmp[i++];
 }
 
-static void query_report(Relation *r,tuple *query) {
+static void query_report(Relation *r,Tuple *query) {
     VectorIndex i;
     for ( i = 0; i < r->content.table.size; i++ ) {
-       tuple *t = HashVector_next( &r->content, &i, query );
+       Tuple *t = HashVector_next( &r->content, &i, query );
        fprintf( stderr, "check %s\n", tuple2string( r, t ) );
     }
 }
 
-static void query_report_all(Relation *r,tuple *query[]) {
+static void query_report_all(Relation *r,Tuple *query[]) {
     int j;
     for ( j = 0; query[j]; j++ ) {
        fprintf( stderr, "query %s\n", tuple2string( r, query[j] ) );
@@ -46,7 +46,7 @@ static void knockout_report(Relation *r,Vector *v) {
     VectorIndex i;
     if ( v ) {
        for ( i = 0; i < v->size; i++ ) {
-           tuple **t = (tuple **) Vector_next_used( v, &i );
+           Tuple **t = (Tuple **) Vector_next_used( v, &i );
            fprintf( stderr, "knock %s\n", tuple2string( r, t? *t : 0 ) );
        }
        Vector_resize( v, 0, Vector_clear_any, 0 );
@@ -55,7 +55,7 @@ static void knockout_report(Relation *r,Vector *v) {
 }
 
 // Test addition with several tuples, terminated by 0                          
-static void test_Relation_add(Relation *r,tuple *query[]) {
+static void test_Relation_add(Relation *r,Tuple *query[]) {
     int j;
     for ( j = 0; query[j]; j++ ) {
        fprintf( stderr, "add %s\n", tuple2string( r, query[j] ) );
@@ -64,7 +64,7 @@ static void test_Relation_add(Relation *r,tuple *query[]) {
 }
 
 // Test deletion with several queries, terminated by 0
-static void test_Relation_delete(Relation *r,tuple *query[]) {
+static void test_Relation_delete(Relation *r,Tuple *query[]) {
     int j;
     for ( j = 0; query[j]; j++ ) {
        fprintf( stderr, "delete %s\n", tuple2string( r, query[j] ) );
@@ -75,14 +75,14 @@ static void test_Relation_delete(Relation *r,tuple *query[]) {
 int main(int argc,char **argv) {
 
     // AxB
-    tuple *data2[] = {
+    Tuple *data2[] = {
        TUPLE( "a", "b" ),
        TUPLE( "a", "c" ),
        TUPLE( "a", "d" ),
        TUPLE( "b", "d" ),
        0
     };
-    tuple *query2[] = {
+    Tuple *query2[] = {
        TUPLE( "a", 0 ),
        TUPLE( 0, "d" ),
        0
@@ -95,7 +95,7 @@ int main(int argc,char **argv) {
     test_Relation_delete( &rel2, query2 );
     
     // AxBxC
-    tuple *data3[] = {
+    Tuple *data3[] = {
        TUPLE( "a", "b", "c" ), // <a,b,?> <a,?,c> ***
        TUPLE( "a", "c", "d" ), // <a,c,?> <a,?,d> ***
        TUPLE( "a", "b", "e" ), // <a,b,?> <a,?,e> => -<a,b,c>
@@ -105,7 +105,7 @@ int main(int argc,char **argv) {
        TUPLE( "f", "b", "d" ), // <f,b,?> <f,?,c>
        0
     };
-    tuple *query3[] = {
+    Tuple *query3[] = {
        TUPLE( "a", 0, "d" ),
        TUPLE( 0, 0, "d" ),
        TUPLE( 0, "c", 0 ),
index 7f9d3440ef79e8b679e6873121bfcad8abcc5408..e3ef2147e91bf3ea286546e74a5e104bdf9e0af0 100644 (file)
@@ -117,11 +117,11 @@ void *BindingTable_get(BindingTable *bt,char *name) {
     return 0;
 }
 
-void BindingTable_deref(BindingTable *bt,int arity,tuple *t) {
+void BindingTable_deref(BindingTable *bt,int arity,Tuple *t) {
     int i;
     for ( i = 0; i < arity; i++ ) {
-       if ( (*t)[i] ) {
-           (*t)[i] = BindingTable_get( bt, (*t)[i] );
+       if ( t->elements[i] ) {
+           t->elements[i] = BindingTable_get( bt, t->elements[i] );
        }
     }
 }
@@ -141,16 +141,15 @@ int BindingTable_unify(
 
 #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*) memcpy(
-       malloc( arity * sizeof( void* ) ), t, arity * sizeof( void* ) );
+Tuple *BindingTable_tuple_get(BindingTable *bt,int arity,Tuple *t) {
+    Tuple *vt = Tuple_clone( arity, t );
     BindingTable_deref( bt, arity, vt );
     return vt;
 }
 
-void BindingTable_tuple_set(BindingTable *bt,int arity,tuple *nm,tuple *vs) {
+void BindingTable_tuple_set(BindingTable *bt,int arity,Tuple *nm,Tuple *vs) {
     int i;
     for ( i = 0; i < arity; i++ ) {
-       BindingTable_set( bt, (*nm)[i], (*vs)[i] );
+       BindingTable_set( bt, nm->elements[i], vs->elements[i] );
     }
 }
index 8ce6b7e106c9c6f8ef79b0e1bab5398ced990f75..47938b8ebafad0a3da088fc6fee8c08ddace9cf0 100644 (file)
@@ -81,7 +81,7 @@ extern void *BindingTable_get(BindingTable *bt,char *name);
  *
  * \param t is the tuple of (char*) names to dereference.
  */
-void BindingTable_deref(BindingTable *bt,int arity,tuple *t);
+void BindingTable_deref(BindingTable *bt,int arity,Tuple *t);
 
 /**
  * \brief Unify two named bindings with option equal-value callback.
index b4c6184002b2e66baf5590764a1dfc65a56e2665..dbf1ab2ee3c6cbeaa17cefff205483e4ebaf1059 100644 (file)
@@ -63,8 +63,8 @@ void *HashVector_find(HashVector *hv,void *key) {
     return ( slot && *slot && *slot != HV_HOLE )? *slot : 0;
 }
 
-// Find the keyed element at or after the index. Update index and
-// return item.
+// Find any element at or after the index that admits to the key.
+// Update index and return item.
 void *HashVector_next(HashVector *hv,VectorIndex *index,void *key) {
     unsigned long i = index? *index : 0;
     for ( ; i < hv->table.size; i++ ) {
index 0b4a0f6c19c38c7fac86a3a1c93448cb79b6fedd..387f7ce53cbe3782fee880af84e5f6c0af71a238 100644 (file)
@@ -73,7 +73,7 @@ typedef struct {
 #define HV_HOLE ((void*) 1)
 
 /**
- * \brief Find the keyed item.
+ * \brief Lookup the first item with the given key.
  *
  * \param hv is the \ref HashVector concerned.
  *
@@ -86,18 +86,21 @@ typedef struct {
 void *HashVector_find(HashVector *hv,void *key);
 
 /**
- * \brief Scan the table for th next key-matching item at or after the
- * given index.
+ * \brief Scan the table for any subsequent item that admits to the
+ * given partial key.
  *
  * \param hv is the \ref HashVector concerned.
  *
  * \param index is a pointer to the index to advance.
  * \
- * \param key is the Query key
+ * \param key is the query key
  *
  * \returns the next matching item, or \b 0 if none, with the index
  * updated.
  *
+ * This function is used where the query key doesn't fully identify an
+ * item, and is thus a partial key that 
+ *
  * \related HashVector
  */
 extern void *HashVector_next(HashVector *hv,VectorIndex *i,void *key);
index 0f342d35332e604ac4ff10a76363abe10335ad92..6d3da9202730c97e636444c9295515f3c6875d91 100644 (file)
@@ -1,6 +1,6 @@
 LIBRARY = libvector.a
 LIBOBJS = Vector.o HashVector.o
-LIBOBJS += TupleSchema.o integeritem.o  stringitem.o
+LIBOBJS += Tuple.o TupleSchema.o integeritem.o  stringitem.o
 LIBOBJS += Relation.o
 LIBOBJS += BindingTable.o Query.o
 
index 68efa3fb73f1d568bf1aa58a7fdb9cf5a0bb1f4c..c13ecde73e418e4c399f190fc7ad4f370e46809f 100644 (file)
@@ -2,79 +2,21 @@
 #include <stdlib.h>
 #include <string.h>
 #include <Query.h>
-#include <BindingTable.h>
+#include <QueryCallbacks.h>
 
-enum NextState {
-    /**
-     * This state tells the "next" function that it should capture the
-     * incoming BindingTable state and provide the initial Binding of
-     * a new sucession of bindings.
-     */
-    initial, 
-    /**
-     * This state tells the "next" function that it should update the
-     * bidning table with a subsequent Binding in the current
-     * succession of bindings.
-     */
-    subsequent,
-    /**
-     * This state tells the "next" function that it should just
-     * restore the Binding table to its incoming state.
-     */
-    restore
-};
+/* ==================== AssignmentQuery ==================== */
 
 /**
- * A struct Query_callbacks record defines the callbacks for a
- * specific Query type.
+ * AssignmentQuery represents an assignment of values to names.
+ * \extends Query
+ * \related Query
  */
-struct QueryCallbacks {
-    /**
-     * \brief 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.
-     */
-    void (*reclaim)(Query *this);
-    void (*start)(Query *this,BindingTable *bt,enum NextState s);
-    /**
-     * \brief 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.
-     */
-    int (*next)(Query *this,BindingTable *bt,enum NextState state);
-};
-
-/* ==================== AssignmentQuery ==================== */
 typedef struct {
     struct QueryCallbacks *def;
     int arity;
-    tuple *names;
-    tuple *values;
-    tuple *saved;
+    Tuple *names;
+    Tuple *values;
+    Tuple *saved;
 } AssignmentQuery;
 
 // Release any memory.
@@ -84,11 +26,11 @@ static void AssignmentQuery_reclaim(Query *this) {
     free( this );
 }
 
-static int AssignmentQuery_check(int arity,tuple *a,tuple *b) {
+static int AssignmentQuery_check(int arity,Tuple *a,Tuple *b) {
     int i;
     for ( i = 0; i < arity; i++ ) {
-       char *value = (*a)[i];
-       char *current = (*b)[i];
+       char *value = a->elements[i];
+       char *current = b->elements[i];
        if ( value && current && current != value &&
             strcmp( current, value ) != 0 ) {
            return 0;
@@ -98,12 +40,12 @@ static int AssignmentQuery_check(int arity,tuple *a,tuple *b) {
 }
 
 static void AssignmentQuery_assign(
-    BindingTable *bt,int n,tuple *names,tuple *values,int all)
+    BindingTable *bt,int n,Tuple *names,Tuple *values,int all)
 {
     int i;
     for ( i = 0; i < n; i++ ) {
-       if ( all || (*values)[i] ) {
-           BindingTable_set( bt, (*names)[i], (*values)[i] );
+       if ( all || values->elements[i] ) {
+           BindingTable_set( bt, names->elements[i], values->elements[i] );
        }
     }
 }
@@ -116,9 +58,10 @@ static int AssignmentQuery_next(
     switch ( state ) {
     case initial:
        if ( q->saved == 0 ) {
-           q->saved = (tuple*) malloc( q->arity * sizeof( void* ) );
+           q->saved = Tuple_clone( q->arity, q->names );
+       } else {
+           memcpy( q->saved, q->names, q->arity * sizeof( void* ) );
        }
-       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 ) ) {
@@ -147,7 +90,7 @@ static struct QueryCallbacks AssignmentQuery_def = {
  * Return a Query object representing an assignment of one or more
  * variables.
  */
-Query *Query_assign(int arity,tuple *names,tuple *values) {
+Query *Query_assign(int arity,Tuple *names,Tuple *values) {
     AssignmentQuery *q = (AssignmentQuery*)
        malloc( sizeof( AssignmentQuery ) );
     (*q) = (AssignmentQuery) {
@@ -161,6 +104,12 @@ Query *Query_assign(int arity,tuple *names,tuple *values) {
 }
 
 /* ==================== conjunction ==================== */
+
+/**
+ * ConjunctionQuery represents a conjunction of sub queries.
+ * \extends Query
+ * \related Query
+ */
 typedef struct {
     struct QueryCallbacks *def;
     int active;
@@ -241,6 +190,12 @@ Query *Query_and(int n,...) {
 }
 
 /* ==================== disjunction ==================== */
+
+/**
+ * DisjunctionQuery represents a disjunction of sub queries.
+ * \extends Query
+ * \related Query
+ */
 typedef struct {
     struct QueryCallbacks *def;
     int index;
@@ -313,13 +268,19 @@ Query *Query_or(int n,...) {
 }
 
 /* ==================== Relation access ==================== */
+
+/**
+ * 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;
+    Tuple *names;
+    Tuple *values;
+    Tuple *saved;
 } RelationQuery;
 
 // Release any memory.
@@ -339,15 +300,16 @@ static int RelationQuery_next(
     switch ( state ) {
     case initial:
        if ( q->saved == 0 ) {
-           q->saved = (tuple*) malloc( arity * sizeof( void* ) );
+           q->saved = Tuple_clone( arity, q->names );
+       } else {
+           memcpy( q->saved, q->names, arity * sizeof( void* ) );
        }
-       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 );
+           Tuple *values = Relation_next( q->rel, &index, q->values );
            if ( values ) {
                q->index = index;
                AssignmentQuery_assign( bt, arity, q->names, values, 1 );
@@ -374,7 +336,7 @@ static struct QueryCallbacks RelationQuery_def = {
  * Return a Query object representing an Relation of one or more
  * variables.
  */
-Query *Query_Relation(Relation *r,tuple *names,tuple *values) {
+Query *Query_Relation(Relation *r,Tuple *names,Tuple *values) {
     RelationQuery *q = (RelationQuery*) malloc( sizeof( RelationQuery ) );
     (*q) = (RelationQuery) {
        .def = &RelationQuery_def,
@@ -385,3 +347,14 @@ Query *Query_Relation(Relation *r,tuple *names,tuple *values) {
     };
     return (Query*) q;
 }
+
+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 );
+}
index a8eb17520f2c12a5958f9310a57f6d7acc0801a6..f13083d6df426c4ecf72f677ae1b46ca4e14fcf8 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <TupleSchema.h>
 #include <Relation.h>
+#include <BindingTable.h>
 
 struct QueryCallbacks;
 
@@ -32,13 +33,80 @@ typedef struct {
  *
  * \related Query
  */
-extern Query *Query_assign(int arity,tuple *names,tuple *values);
+extern Query *Query_assign(int arity,Tuple *names,Tuple *values);
 
 /**
- * \brief Create a lookup_Query record for lookup data in a Relation.
+ * \brief Create a Query record for lookup data in a Relation.
+ *
+ * \param r is the relation being queried.
+ *
+ * \param names is a same-arity tuple of binding names for the
+ * columns, using \b 0 for unnamed columns.
+ *
+ * \param values is a same--arity tuple of query values, using \b 0 for
+ * columns to enumerate.
+ *
+ * The names and values tuples identify bindings and values to use for
+ * the search query, and which bindings to set up from the successive
+ * results. Names that are bound beforhand identify constraining
+ * values, and the names that are unbound gain successive values from
+ * the matching tuples.
+ *
+ * \related Query
+ */
+extern Query *Query_Relation(Relation *r,Tuple *names,Tuple *values);
+
+/**
+ * \brief Create a Query record for a conjunction of queries.
+ *
+ * \param n is the number of sub queries.
+ *
+ * \param ... are the sub queries.
+ *
+ * The conjunction query processes the sub queries in order resulting
+ * in the sequence of their combined bindings.
+ *
+ * \related Query
  */
-extern Query *Query_lookup(Relation *r,...);
+extern Query *Query_and(int n,...);
 
+/**
+ * \brief Create a Query record for a disjunction of queries.
+ *
+ * \param n is the number of sub queries.
+ *
+ * \param ... are the sub queries.
+ *
+ * The disjunction query processed the sub queries in order to find
+ * all their individual "true" binding combinations. It processes one
+ * sub query at a time to exhaustion and provide their individudal
+ * binding sequences separately.
+ *
+ * \related Query
+ */
+extern Query *Query_or(int n,...);
 
+/**
+ * \brief Invoke a consequent callback function for each successful
+ * binding of a query.
+ *
+ * \param q is the antecedent query to process.
+ *
+ * \param bt is the binding table to use.
+ *
+ * \param consequent is the callback function to invoke for each
+ * binding.
+ * \param data is the caller's context data.
+ *
+ * This function prrocesses the Query for establishing its binding
+ * sequence and inokes the consequent callback function for each
+ * binding as it is provided.
+ * 
+ * \related Query
+ */
+extern void Query_rule(
+    Query *q,BindingTable *bt,
+    int (*consequent)(BindingTable *bt,void *data),
+    void *data );
 
 #endif
diff --git a/vector/QueryCallbacks.h b/vector/QueryCallbacks.h
new file mode 100644 (file)
index 0000000..0414ddb
--- /dev/null
@@ -0,0 +1,73 @@
+#ifndef QueryCallbacks_H
+#define QueryCallbacks_H
+
+enum NextState {
+    /**
+     * This state tells the "next" function that it should capture the
+     * incoming BindingTable state and provide the initial Binding of
+     * a new sucession of bindings.
+     */
+    initial, 
+    /**
+     * This state tells the "next" function that it should update the
+     * bidning table with a subsequent Binding in the current
+     * succession of bindings.
+     */
+    subsequent,
+    /**
+     * This state tells the "next" function that it should just
+     * restore the Binding table to its incoming state.
+     */
+    restore
+};
+
+/**
+ * A struct Query_callbacks record defines the callbacks for a
+ * specific Query type.
+ */
+struct QueryCallbacks {
+    /**
+     * \brief 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.
+     */
+    void (*reclaim)(Query *this);
+    /**
+     * \brief 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.
+     */
+    int (*next)(Query *this,BindingTable *bt,enum NextState state);
+    /**
+     * This callback function adds its binding names to the
+     * hashvector.
+     */
+    void (*bindings)(Query *this,HashVector *hv);
+};
+
+
+#endif
index 0b7450f3b3b0aec251e6c99b707bfef8bcc1222b..4a6417053c73bff4f223f00064f2c839b2d8504d 100644 (file)
@@ -30,12 +30,13 @@ Relation *Relation_create(TupleSchema *schema) {
 int Relation_add_constraint(Relation *r,...) {
     va_list ap;
     TupleSchema *ts = (TupleSchema *) r->content.type;
-    tuple *columns = (tuple*) calloc( ts->arity, sizeof( void* ) );
+    Tuple *columns = (Tuple*) malloc(
+       sizeof( Tuple ) + ts->arity * sizeof( void* ) );
     int i = 0;
     va_start( ap, r );
     for ( ; i < ts->arity; i++ ) {
        if ( va_arg( ap, int ) ) {
-           (*columns)[i] = ts->columns[i];
+           columns->elements[i] = ts->columns->elements[i];
        }
     }
     va_end( ap );
@@ -85,7 +86,7 @@ static int knockout_add(VectorIndex index,void *item,void *data) {
 // Find and remove all collisions for a Query, unless "add" is
 // non-zero in which case the function aborts if there is any match in
 // the main content.
-static int knockout_clear(Knockout *this,Relation *r,tuple *item,int add) {
+static int knockout_clear(Knockout *this,Relation *r,Tuple *item,int add) {
     (*this) = (Knockout) {
        .rel = r,
        .knockouts = {
@@ -120,7 +121,7 @@ static int knockout_clear(Knockout *this,Relation *r,tuple *item,int add) {
 
 // add a tuple to a Relation and return a Vector of knocked out
 // tuples, if any, or 0 otherwise.
-Vector *Relation_add(Relation *r,tuple *item) {
+Vector *Relation_add(Relation *r,Tuple *item) {
     Knockout data;
     if ( knockout_clear( &data, r, item, 1 ) ) {
        // Add the new tuple
@@ -131,13 +132,13 @@ Vector *Relation_add(Relation *r,tuple *item) {
     return 0;
 }
 
-Vector *Relation_delete(Relation *r,tuple *item) {
+Vector *Relation_delete(Relation *r,Tuple *item) {
     Knockout data;
     (void) knockout_clear( &data, r, item, 0 );
     return HashVector_contents( &data.knockouts, single_index_level, 0 );
 }
 
-void *Relation_next(Relation *r,VectorIndex *index,tuple *Query) {
-    return HashVector_next( &r->content, index, Query );
+void *Relation_next(Relation *r,VectorIndex *index,Tuple *query) {
+    return HashVector_next( &r->content, index, query );
 }
 
index 76c500210574e48fd3c1b9441074cf82d4578c88..852101a0dbd250a2f36c4aa17e76b4ceda10fc0c 100644 (file)
@@ -91,7 +91,7 @@ extern int Relation_add_constraint(Relation *r,...);
  *
  * \related Relation
  */
-extern Vector *Relation_add(Relation *r,tuple *t);
+extern Vector *Relation_add(Relation *r,Tuple *t);
 
 /**
  * \brief Delete all tuples matching to the Query \ref tuple fromt the
@@ -109,7 +109,7 @@ extern Vector *Relation_add(Relation *r,tuple *t);
  *
  * \related Relation
  */
-extern Vector *Relation_delete(Relation *r,tuple *Query);
+extern Vector *Relation_delete(Relation *r,Tuple *query);
 
 /**
  * \brief Return the next \ref tuple in the \ref Relation that matches
@@ -126,7 +126,7 @@ extern Vector *Relation_delete(Relation *r,tuple *Query);
  *
  * \related Relation
  */
-extern void *Relation_next(Relation *r,VectorIndex *index,tuple *Query);
+extern void *Relation_next(Relation *r,VectorIndex *index,Tuple *query);
 
 /**
  * \brief Lay out a dynamic \ref Relation initializer for a Relation
diff --git a/vector/Tuple.c b/vector/Tuple.c
new file mode 100644 (file)
index 0000000..06eba85
--- /dev/null
@@ -0,0 +1,35 @@
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <Tuple.h>
+
+// Allocate
+Tuple *Tuple_create(int arity,...) {
+    va_list ap;
+    int i;
+    Tuple *t = (Tuple *) malloc( sizeof( Tuple ) + arity * sizeof( void* ) );
+    t->types = 0; // unknown types
+    va_start( ap, arity );
+    for ( i = 0; i < arity; i++ ) {
+       t->elements[i] = va_arg( ap, void* );
+    }
+    va_end( ap );
+    return t;
+}
+
+Tuple *Tuple_clone(int arity,Tuple *t) {
+    Tuple *ct = (Tuple *)malloc( sizeof( Tuple ) + arity * sizeof( void* ) );
+    memcpy( ct, t, arity * sizeof( void* ) );
+    return ct;
+}
+
+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;
+}
diff --git a/vector/Tuple.h b/vector/Tuple.h
new file mode 100644 (file)
index 0000000..b14d196
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef Tuple_H
+#define Tuple_H
+
+#include <ItemKeyFun.h>
+
+typedef struct TupleSchema TupleSchema;
+
+/**
+ * A Tuple is a "self typed" array of elements.
+ */
+typedef struct {
+    TupleSchema *types;
+    void *elements[];
+} Tuple;
+
+extern ItemKeyFun *Tuple_elementType(Tuple *t,unsigned long index);
+
+/**
+ * Create a tuples with given values.
+ *
+ * \related TupleSchema
+ */
+extern Tuple *Tuple_create(int arity,...);
+
+/**
+ * \brief Create a tuples as a clone of a given tuple
+ *
+ * \related TupleSchema
+ */
+extern Tuple *Tuple_clone(int arity,Tuple *t);
+
+
+#endif
index 378ac9aa762d9f28a092c432407c0e5a8b2c3739..5616b2dd5a6bf722b5c762095c997d05669c6c45 100644 (file)
@@ -3,8 +3,6 @@
 #include <string.h>
 #include <TupleSchema.h>
 
-#define COLUMN def->columns
-
 /**
  * This callback function returns the hashcode of a key.
  *
  */
 static unsigned long TupleSchema_hashcode(void *this,void *key) {
     TupleSchema *def = (TupleSchema *) this;
-    tuple *kp = (tuple*) key;
+    ItemKeyFun **columns = (ItemKeyFun**) def->columns->elements;
+    Tuple *kp = (Tuple*) key;
     int i = 0;
     unsigned long value = 5381;
     for ( ; i < def->arity; i++ ) {
-       if ( COLUMN[i] ) {
+       if ( columns[i] ) {
            value <<= 3;
-           if ( (*kp)[i] ) {
-               value += COLUMN[i]->hashcode( COLUMN[i], (*kp)[i] );
+           if ( kp->elements[i] ) {
+               value += columns[i]->hashcode( columns[i], kp->elements[i] );
            }
        }
        value += 17;
@@ -45,12 +44,14 @@ static unsigned long TupleSchema_hashcode(void *this,void *key) {
  */
 static int TupleSchema_haskey(void *this,void *item,void *key) {
     TupleSchema *def = (TupleSchema *) this;
-    tuple *kp = (tuple*) key;
-    tuple *tp = (tuple*) item;
+    ItemKeyFun **columns = (ItemKeyFun**) def->columns->elements;
+    Tuple *kp = (Tuple*) key;
+    Tuple *tp = (Tuple*) item;
     int i = 0;
     for ( ; i < def->arity; i++ ) {
-       if ( COLUMN[i] && (*kp)[i] ) {
-           if ( COLUMN[i]->haskey( COLUMN[i], (*tp)[i], (*kp)[i] ) == 0 ) {
+       if ( columns[i] && kp->elements[i] ) {
+           if ( columns[i]->haskey(
+                    columns[i], tp->elements[i], kp->elements[i] ) == 0 ) {
                return 0;
            }
        }
@@ -63,31 +64,35 @@ static int TupleSchema_haskey(void *this,void *item,void *key) {
  * This callback function returns the key of an item by considering
  * the arity and mask.
  */
-static void *tupleitem_itemkey(void *this,void *item) {
+static void *TupleSchema_itemkey(void *this,void *item) {
     TupleSchema *def = (TupleSchema *) this;
-    tuple *tp = (tuple*) item;
+    ItemKeyFun **columns = (ItemKeyFun**) def->columns->elements;
+    Tuple *tp = (Tuple*) item;
+    Tuple *key = Tuple_clone( def->arity, tp );
     int i;
-    int keylen = def->arity;
-    void **parts = calloc( keylen, sizeof( void* ) );
     for ( i = 0; i < def->arity; i++ ) {
-       if ( COLUMN[i] ) {
-           parts[i] = COLUMN[i]->itemkey( COLUMN[i], (*tp)[i] );
+       if ( columns[i] ) {
+           key->elements[i] = columns[i]->itemkey(
+               columns[i], tp->elements[i] );
+       } else {
+           key->elements[i] = 0;
        }
     }
-    return (void*) parts;
+    return (void*) key;
 }
 
 /**
  * This callback function handles a key obtained from the itemkey
  * callback function to reclaim temporary allocation.
  */
-static void tupleitem_releasekey(void *this,void *key) {
+static void TupleSchema_releasekey(void *this,void *key) {
     TupleSchema *def = (TupleSchema *) this;
-    tuple *kp = (tuple*) key;
+    ItemKeyFun **columns = (ItemKeyFun**) def->columns->elements;
+    Tuple *kp = (Tuple*) key;
     int i;
     for ( i = 0; i < def->arity; i++ ) {
-       if ( COLUMN[i] ) {
-           COLUMN[i]->releasekey( COLUMN[i], (*kp)[i] );
+       if ( columns[i] ) {
+           columns[i]->releasekey( columns[i], kp->elements[i] );
        }
     }
     free( key );
@@ -99,55 +104,36 @@ static void tupleitem_releasekey(void *this,void *key) {
  * This callback function writes a representation of an item into
  * a character buffer.
  */
-static int tupleitem_tostring(void *this,void *item,char *buffer,int limit) {
+static int TupleSchema_tostring(void *this,void *item,char *buffer,int limit) {
     TupleSchema *def = (TupleSchema *) this;
-    tuple *t = (tuple*) item;
+    ItemKeyFun **columns = (ItemKeyFun**) def->columns->elements;
+    Tuple *t = (Tuple*) item;
     char *x = "<";
     int a, i;
     for ( i = 0; i < def->arity; i++ ) {
        OUT( snprintf( buffer, limit, x ) );
        x = ",";
-       OUT( def->columns[i]->tostring(
-                def->columns[i], (*t)[i], buffer, limit ) );
+       OUT( columns[i]->tostring(
+                columns[i], t->elements[i], buffer, limit ) );
     }
     OUT( snprintf( buffer, limit, ">" ) );
     return a;
 }
 
-
-// Allocate
-tuple *tuple_create(int arity,...) {
-    va_list ap;
-    int i;
-    tuple *t = (tuple *)malloc( arity * sizeof( void* ) );
-    va_start( ap, arity );
-    for ( i = 0; i < arity; i++ ) {
-       (*t)[i] = va_arg( ap, void* );
-    }
-    va_end( ap );
-    return t;
-}
-
-tuple *tuple_clone(int arity,tuple *t) {
-    tuple *ct = (tuple *)malloc( arity * sizeof( void* ) );
-    memcpy( ct, t, arity * sizeof( void* ) );
-    return ct;
-}
-
 ItemKeyFun TupleSchema_callbacks = {
     .hashcode = TupleSchema_hashcode,
     .haskey = TupleSchema_haskey,
-    .itemkey = tupleitem_itemkey,
-    .releasekey = tupleitem_releasekey,
-    .tostring = tupleitem_tostring
+    .itemkey = TupleSchema_itemkey,
+    .releasekey = TupleSchema_releasekey,
+    .tostring = TupleSchema_tostring
 };
 
-TupleSchema *TupleSchema_create(int arity,tuple *columns) {
+TupleSchema *TupleSchema_create(int arity,Tuple *columns) {
     TupleSchema *ts = (TupleSchema*) malloc( sizeof( TupleSchema ) );
     (*ts) = (TupleSchema) {
        .base = TupleSchema_callbacks,
        .arity = arity,
-       .columns = (ItemKeyFun**) columns
+       .columns = columns
     };
     return ts;
 }
@@ -158,7 +144,7 @@ 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 = COPYA( ItemKeyFun*, schema->columns, schema->arity );
+    masked->columns = Tuple_clone( schema->arity, schema->columns );
     va_list ap;
     int i;
     va_start( ap, schema );
@@ -167,19 +153,8 @@ TupleSchema *TupleSchema_mask(TupleSchema *schema,...) {
        if ( i < 0 || i >= schema->arity ) {
            break;
        }
-       masked->columns[i] = 0;
+       masked->columns->elements[i] = 0;
     };
     va_end( ap );
     return masked;
 }
-
-unsigned long tuple_mask(int arity,tuple *t) {
-    unsigned long mask = 0;
-    while ( arity-- > 0 ) {
-       mask <<= 1;
-       if ( (*t)[ arity ] ) {
-           mask++;
-       }
-    }
-    return mask;
-}
index 0549284e2fe91d31af7d4d1db8f43187f2af1fbf..72fdc1e5bdc28a5059280c5576a1e042a7477202 100644 (file)
@@ -1,12 +1,7 @@
 #ifndef tupleitem_H
 #define tupleitem_H
 
-#include <ItemKeyFun.h>
-
-/**
- * A tuple is an array of void*
- */
-typedef void *tuple[];
+#include <Tuple.h>
 
 /**
  * A TupleSchema record declares the ItemKeyFun functions for tuple
@@ -16,7 +11,7 @@ typedef void *tuple[];
  *
  * \extends ItemKeyFun
  */
-typedef struct {
+typedef struct TupleSchema {
     /**
      * These are the ItemKeyFun callback functions to support
      * HashVector use for tuple items. The functions expects their
@@ -31,10 +26,11 @@ typedef struct {
     int arity;
 
     /**
-     * This points to an array of pointers to the tuple item domains
-     * as represented by their associated ItemKeyFun records.
+     * This points to tuple whose elements is array of pointers to the
+     * tuple item domains as represented by their associated
+     * ItemKeyFun records.
      */
-    ItemKeyFun **columns;
+    Tuple *columns;
 } TupleSchema;
 
 /**
@@ -42,14 +38,7 @@ typedef struct {
  *
  * \related TupleSchema
  */
-extern tuple *tuple_create(int arity,...);
-
-/**
- * Create a tuples with given values.
- *
- * \related TupleSchema
- */
-extern TupleSchema *TupleSchema_create(int arity,tuple *columns);
+extern TupleSchema *TupleSchema_create(int arity,Tuple *columns);
 
 /**
  * Copy the given TupleSchema into a new TupleSchema with some columns
@@ -65,7 +54,7 @@ extern TupleSchema *TupleSchema_mask(TupleSchema *schema,...);
  *
  * \related TupleSchema
  */
-extern int TupleSchema_match(TupleSchema *def,tuple *Query,tuple *item);
+extern int TupleSchema_match(TupleSchema *def,Tuple *query,Tuple *item);
 
 /**
  * \brief Generic macro to determine the number of expressions in a
@@ -83,7 +72,7 @@ extern int TupleSchema_match(TupleSchema *def,tuple *Query,tuple *item);
  *
  * \related TupleSchema
  */
-#define TUPLE(...) tuple_create( NUMARGS(__VA_ARGS__), __VA_ARGS__ )
+#define TUPLE(...) Tuple_create( NUMARGS(__VA_ARGS__), __VA_ARGS__ )
 
 /**
  * \brief Create a \ref TupleSchema with the given column "types".
index 31b4065bbfd09a8d2fd44f01ad2a4827bc033edb..35833a5c6b6bd861304a68279f7113f5d09df332 100644 (file)
@@ -632,13 +632,13 @@ void Vector_iterate(Vector *pv,
     }
 }
 
-struct find_data {
+struct FindData {
     void *value;
     VectorIndex index;
 };
 
 static int Vector_find_item(VectorIndex index, void *item,void *data) {
-    struct find_data *fd = (struct find_data*)data;
+    struct FindData *fd = (struct FindData*)data;
     if ( fd->value != item ) {
        return 0;
     }
@@ -647,7 +647,7 @@ static int Vector_find_item(VectorIndex index, void *item,void *data) {
 }
 
 VectorIndex Vector_find(Vector *pv,void *value) {
-    struct find_data fd = {
+    struct FindData fd = {
        .value = value,
        .index = pv->size
     };