rework Relation_next and HashVector_next to void query handling in HashVector
[rrq/rrqmisc.git] / vector / Query.c
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 );
+}