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 ) {
}
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 );
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++ ) {
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;
#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;
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] ) );
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 );
}
// 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] ) );
}
// 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] ) );
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
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>
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 ),
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] );
}
}
}
#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] );
}
}
*
* \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.
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++ ) {
#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.
*
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);
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
#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.
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;
}
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] );
}
}
}
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 ) ) {
* 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) {
}
/* ==================== conjunction ==================== */
+
+/**
+ * ConjunctionQuery represents a conjunction of sub queries.
+ * \extends Query
+ * \related Query
+ */
typedef struct {
struct QueryCallbacks *def;
int active;
}
/* ==================== disjunction ==================== */
+
+/**
+ * DisjunctionQuery represents a disjunction of sub queries.
+ * \extends Query
+ * \related Query
+ */
typedef struct {
struct QueryCallbacks *def;
int index;
}
/* ==================== 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.
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 );
* 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,
};
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 );
+}
#include <TupleSchema.h>
#include <Relation.h>
+#include <BindingTable.h>
struct QueryCallbacks;
*
* \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
--- /dev/null
+#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
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 );
// 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 = {
// 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
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 );
}
*
* \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
*
* \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
*
* \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
--- /dev/null
+#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;
+}
--- /dev/null
+#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
#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;
*/
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;
}
}
* 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 );
* 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;
}
// 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 );
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;
-}
#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
*
* \extends ItemKeyFun
*/
-typedef struct {
+typedef struct TupleSchema {
/**
* These are the ItemKeyFun callback functions to support
* HashVector use for tuple items. The functions expects their
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;
/**
*
* \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
*
* \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
*
* \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".
}
}
-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;
}
}
VectorIndex Vector_find(Vector *pv,void *value) {
- struct find_data fd = {
+ struct FindData fd = {
.value = value,
.index = pv->size
};