From: Ralph Ronnquist Date: Sun, 17 Jul 2022 00:16:54 +0000 (+1000) Subject: refactoring X-Git-Url: https://git.rrq.au/?a=commitdiff_plain;h=48cdb87442b7b3f1cdde9c1710ed90ec773dce97;p=rrq%2Frrqmisc.git refactoring --- diff --git a/vector/AndQuery.c b/vector/AndQuery.c new file mode 100644 index 0000000..169ff9e --- /dev/null +++ b/vector/AndQuery.c @@ -0,0 +1,85 @@ +#include +#include +#include + +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 index 0000000..7871eea --- /dev/null +++ b/vector/AndQuery.h @@ -0,0 +1,19 @@ +#ifndef AndQuery_H +#define AndQuery_H + +#include + +/** + * 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 index 0000000..bb264aa --- /dev/null +++ b/vector/AssignQuery.c @@ -0,0 +1,84 @@ +#include +#include +#include + +// 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 index 0000000..2e38b87 --- /dev/null +++ b/vector/AssignQuery.h @@ -0,0 +1,23 @@ +#ifndef AssignQuery_H +#define AssignQuery_H + +#include +#include + +/** + * 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 index 0000000..9bcc0c1 --- /dev/null +++ b/vector/Binding.c @@ -0,0 +1,60 @@ +#include +#include +#include + +/** + * 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 index 0000000..2d1a0b3 --- /dev/null +++ b/vector/Binding.h @@ -0,0 +1,23 @@ +#ifndef Binding_H +#define Binding_H + +#include + +/** + * \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 diff --git a/vector/BindingTable.c b/vector/BindingTable.c index e3ef214..2728516 100644 --- a/vector/BindingTable.c +++ b/vector/BindingTable.c @@ -2,130 +2,48 @@ #include #include -/** - * 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] ); } } diff --git a/vector/BindingTable.h b/vector/BindingTable.h index 47938b8..aa4ee6e 100644 --- a/vector/BindingTable.h +++ b/vector/BindingTable.h @@ -3,36 +3,31 @@ #include #include +#include /** * 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/**/ 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 diff --git a/vector/Makefile b/vector/Makefile index 6d3da92..a3feec4 100644 --- a/vector/Makefile +++ b/vector/Makefile @@ -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 index 0000000..8418715 --- /dev/null +++ b/vector/NotQuery.c @@ -0,0 +1,41 @@ +#include +#include + +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 index 0000000..f2bf7ed --- /dev/null +++ b/vector/NotQuery.h @@ -0,0 +1,16 @@ +#ifndef NotQuery_H +#define NotQuery_H + +#include + +/** + * 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 index 0000000..5a48e5e --- /dev/null +++ b/vector/OrQuery.c @@ -0,0 +1,76 @@ +#include +#include +#include + +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 index 0000000..9528356 --- /dev/null +++ b/vector/OrQuery.h @@ -0,0 +1,18 @@ +#ifndef OrQuery_H +#define OrQuery_H + +#include + +/** + * OrQuery represents a disjunction of sub queries. + * + * \extends Query + */ +typedef struct { + struct QueryCallbacks *def; + int index; + int size; + Query **disjuncts; +} OrQuery; + +#endif diff --git a/vector/Query.c b/vector/Query.c index c13ecde..94a39d7 100644 --- a/vector/Query.c +++ b/vector/Query.c @@ -1,360 +1,88 @@ -#include -#include -#include #include -#include - -/* ==================== 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; } diff --git a/vector/Query.h b/vector/Query.h index 188a1ea..4b2fa6a 100644 --- a/vector/Query.h +++ b/vector/Query.h @@ -1,11 +1,9 @@ #ifndef Query_H #define Query_H -#include -#include +#include #include - -struct QueryCallbacks; +#include /** * 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 diff --git a/vector/QueryCallbacks.h b/vector/QueryCallbacks.h index ad4461b..5d36e0b 100644 --- a/vector/QueryCallbacks.h +++ b/vector/QueryCallbacks.h @@ -1,9 +1,9 @@ #ifndef QueryCallbacks_H #define QueryCallbacks_H -typedef struct HashVector HashVector; -typedef struct Query Query; -typedef struct BindingTable BindingTable;; +#include + +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. diff --git a/vector/Relation.c b/vector/Relation.c index 0f671ab..868a477 100644 --- a/vector/Relation.c +++ b/vector/Relation.c @@ -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 index 0000000..aa4bdbd --- /dev/null +++ b/vector/RelationQuery.c @@ -0,0 +1,78 @@ +#include +#include +#include +#include + +// 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 index 0000000..4c50a53 --- /dev/null +++ b/vector/RelationQuery.h @@ -0,0 +1,21 @@ +#ifndef RelationQuery_H +#define RelationQuery_H + +#include +#include + +/** + * 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 index 0000000..1539366 --- /dev/null +++ b/vector/StackVector.h @@ -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 diff --git a/vector/Tuple.c b/vector/Tuple.c index e5341bd..2b5b04e 100644 --- a/vector/Tuple.c +++ b/vector/Tuple.c @@ -3,19 +3,20 @@ #include #include -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 diff --git a/vector/Tuple.h b/vector/Tuple.h index fb6bbd6..ea439c5 100644 --- a/vector/Tuple.h +++ b/vector/Tuple.h @@ -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 diff --git a/vector/TupleSchema.c b/vector/TupleSchema.c index 5616b2d..5a92b64 100644 --- a/vector/TupleSchema.c +++ b/vector/TupleSchema.c @@ -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; diff --git a/vector/TupleSchema.h b/vector/TupleSchema.h index 72fdc1e..7bfb67d 100644 --- a/vector/TupleSchema.h +++ b/vector/TupleSchema.h @@ -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 diff --git a/vector/View.c b/vector/View.c index 5da2bcc..5b3179a 100644 --- a/vector/View.c +++ b/vector/View.c @@ -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; } diff --git a/vector/View.h b/vector/View.h index 92e38e4..e60ff8e 100644 --- a/vector/View.h +++ b/vector/View.h @@ -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