From 58de9483c458a25a691d648ce13b81227c327d03 Mon Sep 17 00:00:00 2001 From: Ralph Ronnquist Date: Wed, 13 Jul 2022 14:04:20 +1000 Subject: [PATCH] Cleanup Tuple to allow self-typing. --- tests/example-relation.c | 26 ++++---- tests/relationtests.c | 22 +++---- vector/BindingTable.c | 15 ++--- vector/BindingTable.h | 2 +- vector/HashVector.c | 4 +- vector/HashVector.h | 11 ++-- vector/Makefile | 2 +- vector/Query.c | 137 ++++++++++++++++----------------------- vector/Query.h | 74 ++++++++++++++++++++- vector/QueryCallbacks.h | 73 +++++++++++++++++++++ vector/Relation.c | 15 +++-- vector/Relation.h | 6 +- vector/Tuple.c | 35 ++++++++++ vector/Tuple.h | 33 ++++++++++ vector/TupleSchema.c | 101 +++++++++++------------------ vector/TupleSchema.h | 29 +++------ vector/Vector.c | 6 +- 17 files changed, 371 insertions(+), 220 deletions(-) create mode 100644 vector/QueryCallbacks.h create mode 100644 vector/Tuple.c create mode 100644 vector/Tuple.h diff --git a/tests/example-relation.c b/tests/example-relation.c index 2c76f64..73b0dc0 100644 --- a/tests/example-relation.c +++ b/tests/example-relation.c @@ -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; diff --git a/tests/relationtests.c b/tests/relationtests.c index 7b565b6..459af74 100644 --- a/tests/relationtests.c +++ b/tests/relationtests.c @@ -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" ), // *** TUPLE( "a", "c", "d" ), // *** TUPLE( "a", "b", "e" ), // => - @@ -105,7 +105,7 @@ int main(int argc,char **argv) { TUPLE( "f", "b", "d" ), // 0 }; - tuple *query3[] = { + Tuple *query3[] = { TUPLE( "a", 0, "d" ), TUPLE( 0, 0, "d" ), TUPLE( 0, "c", 0 ), diff --git a/vector/BindingTable.c b/vector/BindingTable.c index 7f9d344..e3ef214 100644 --- a/vector/BindingTable.c +++ b/vector/BindingTable.c @@ -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] ); } } diff --git a/vector/BindingTable.h b/vector/BindingTable.h index 8ce6b7e..47938b8 100644 --- a/vector/BindingTable.h +++ b/vector/BindingTable.h @@ -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. diff --git a/vector/HashVector.c b/vector/HashVector.c index b4c6184..dbf1ab2 100644 --- a/vector/HashVector.c +++ b/vector/HashVector.c @@ -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++ ) { diff --git a/vector/HashVector.h b/vector/HashVector.h index 0b4a0f6..387f7ce 100644 --- a/vector/HashVector.h +++ b/vector/HashVector.h @@ -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); diff --git a/vector/Makefile b/vector/Makefile index 0f342d3..6d3da92 100644 --- a/vector/Makefile +++ b/vector/Makefile @@ -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 diff --git a/vector/Query.c b/vector/Query.c index 68efa3f..c13ecde 100644 --- a/vector/Query.c +++ b/vector/Query.c @@ -2,79 +2,21 @@ #include #include #include -#include +#include -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 ); +} diff --git a/vector/Query.h b/vector/Query.h index a8eb175..f13083d 100644 --- a/vector/Query.h +++ b/vector/Query.h @@ -3,6 +3,7 @@ #include #include +#include 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 index 0000000..0414ddb --- /dev/null +++ b/vector/QueryCallbacks.h @@ -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 diff --git a/vector/Relation.c b/vector/Relation.c index 0b7450f..4a64170 100644 --- a/vector/Relation.c +++ b/vector/Relation.c @@ -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 ); } diff --git a/vector/Relation.h b/vector/Relation.h index 76c5002..852101a 100644 --- a/vector/Relation.h +++ b/vector/Relation.h @@ -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 index 0000000..06eba85 --- /dev/null +++ b/vector/Tuple.c @@ -0,0 +1,35 @@ +#include +#include +#include +#include + +// 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 index 0000000..b14d196 --- /dev/null +++ b/vector/Tuple.h @@ -0,0 +1,33 @@ +#ifndef Tuple_H +#define Tuple_H + +#include + +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 diff --git a/vector/TupleSchema.c b/vector/TupleSchema.c index 378ac9a..5616b2d 100644 --- a/vector/TupleSchema.c +++ b/vector/TupleSchema.c @@ -3,8 +3,6 @@ #include #include -#define COLUMN def->columns - /** * This callback function returns the hashcode of a key. * @@ -24,14 +22,15 @@ */ 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; -} diff --git a/vector/TupleSchema.h b/vector/TupleSchema.h index 0549284..72fdc1e 100644 --- a/vector/TupleSchema.h +++ b/vector/TupleSchema.h @@ -1,12 +1,7 @@ #ifndef tupleitem_H #define tupleitem_H -#include - -/** - * A tuple is an array of void* - */ -typedef void *tuple[]; +#include /** * 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". diff --git a/vector/Vector.c b/vector/Vector.c index 31b4065..35833a5 100644 --- a/vector/Vector.c +++ b/vector/Vector.c @@ -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 }; -- 2.39.2