# entered, it will be relative to the location where doxygen was started. If
# left blank the current directory will be used.
-OUTPUT_DIRECTORY = /home/ralph/src/borta/misc/docs
+OUTPUT_DIRECTORY = /home/ralph/src/borta/rrqmisc/docs
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
# directories (in 2 levels) under the output directory of each output format and
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
-INPUT = /home/ralph/src/borta/misc/vector
+INPUT = /home/ralph/src/borta/rrqmisc/vector
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
-default: libhtable.a
+LIBRARY = librrqhtable.a
+LIBOBJS = htable.o
-.INTERMEDIATE: htable.o
-htable.o: CFLAGS = -Wall -g
-htable.o: htable.c
+default: $(LIBRARY) example-htable
+CLEANRM += $(LIBRARY)
-libhtable.a: htable.o
- $(AR) r $@ $^
-CLEANRM += libhtable.a
+include ../common.mk
.INTERMEDIATE: example-htable.o
example-htable: CFLAGS = -Wall -g
-example-htable: LDLIBS = libhtable.a
-example-htable: example-htable.o libhtable.a
+example-htable: example-htable.o $(LIBRARY)
+
CLEANRM += example-htable
-clean:
- rm -f $(CLEANRM)
--- /dev/null
+#include <stdarg.h>
+#include <stdlib.h>
+#include <AndQuery.h>
+
+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;
+}
+
--- /dev/null
+#ifndef AndQuery_H
+#define AndQuery_H
+
+#include <Query.h>
+
+/**
+ * AndQuery represents a conjunction of sub queries.
+ * \extends Query
+ * \related Query
+ */
+typedef struct {
+ struct QueryCallbacks *def;
+ int active;
+ int size;
+ Query **conjuncts;
+} AndQuery;
+
+
+#endif
--- /dev/null
+#include <stdlib.h>
+#include <string.h>
+#include <AssignQuery.h>
+
+// 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;
+}
--- /dev/null
+#ifndef AssignQuery_H
+#define AssignQuery_H
+
+#include <QueryCallbacks.h>
+#include <Tuple.h>
+
+/**
+ * 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
--- /dev/null
+#include <string.h>
+#include <HashVector.h>
+#include <Binding.h>
+
+/**
+ * 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
+};
+
--- /dev/null
+#ifndef Binding_H
+#define Binding_H
+
+#include <ItemKeyFun.h>
+
+/**
+ * \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
--- /dev/null
+#include <BindingTable.h>
+#include <string.h>
+#include <stdlib.h>
+
+BindingTable *BindingTable_create() {
+ BindingTable *this = (BindingTable*) malloc( sizeof( BindingTable ) );
+ (*this) = (HashVector) {
+ .table = (Vector) {
+ .variant = Nibble_index_levels, .size = 16, .entries = 0
+ }, .fill = 0, .holes = 0, .type = &Bindingitem
+ };
+ return this;
+}
+
+void BindingTable_release(BindingTable *bt) {
+ if ( bt ) {
+ Vector_resize( &bt->table, 0, Vector_free_any, 0 );
+ free( bt );
+ }
+}
+
+void BindingTable_set(BindingTable *bt,char *name,void *value) {
+ Binding *b = (Binding*) HashVector_find( bt, name );
+ if ( b == 0 ) {
+ b = (Binding*) malloc( sizeof( Binding ) );
+ b->name = name;
+ HashVector_add( bt, b );
+ }
+ b->value = value;
+}
+
+void *BindingTable_get(BindingTable *bt,char *name) {
+ Binding *b = (Binding*) HashVector_find( bt, name );
+ return b? b->value : 0;
+}
+
+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 );
+ void *v2 = BindingTable_get( bt, n2 );
+ if ( v2 && v1 == 0 ) {
+ BindingTable_set( bt, n1, v2 );
+ }
+ if ( v1 && v2 == 0 ) {
+ BindingTable_set( bt, n2, v1 );
+ }
+ return ( v1 && v2 )? ( eq? ( eq( v1, v2 ) == 0 ) : ( v1 == v2 ) ) : 1;
+}
+#endif
+
+Tuple *BindingTable_get_all(BindingTable *bt,Tuple *t) {
+ Tuple *vt = Tuple_clone( t );
+ BindingTable_deref( bt, vt );
+ return vt;
+}
+
+void BindingTable_set_all(BindingTable *bt,Tuple *nm,Tuple *vs,int all) {
+ int i;
+ for ( i = 0; i < nm->size; i++ ) {
+ BindingTable_set( bt, nm->elements[i], vs->elements[i] );
+ }
+}
--- /dev/null
+#ifndef BindingTable_H
+#define BindingTable_H
+
+#include <HashVector.h>
+#include <TupleSchema.h>
+#include <Binding.h>
+
+/**
+ * A BindingTable is a chain of \ref HashVector "HashVectors" of
+ * Binding items that associate a (char*) name with a (void*) value.
+ */
+typedef HashVector/*<Binding>*/ BindingTable;
+
+/**
+ * \brief Allocate a new \ref BindingTable.
+ *
+ * \returns the allocated \ref bandingtable.
+ *
+ * \related BindingTable
+ */
+extern BindingTable *BindingTable_create();
+
+/**
+ * \brief Reclaim a \ref BindingTable with all its bindings.
+ *
+ * \param bt is the \ref BindingTable to reclaim.
+ *
+ * \related BindingTable
+ */
+extern void BindingTable_release(BindingTable *bt);
+
+/**
+ * \brief Set a Binding in a \ref BindingTable.
+ *
+ * \param bt is the \ref BindingTable concerned.
+ *
+ * \param name is the Binding name.
+ *
+ * \param value is the Binding value.
+ *
+ * \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
+ */
+extern void BindingTable_set(BindingTable *bt,char *name,void *value);
+
+/**
+ * \brief Get a Binding from a BindingTable chain.
+ *
+ * \param bt is the first BindingTable concerned.
+ *
+ * \param name is the Binding variable name.
+ *
+ * \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.
+ *
+ * \note Not also that a name can be made unbound on top of being
+ * bound by setting it to \b 0.
+ *
+ * \related BindingTable
+ */
+extern void *BindingTable_get(BindingTable *bt,char *name);
+
+/**
+ * \brief Replace all names with their values.
+ *
+ * \param bt is the BindingTable concerned.
+ *
+ * \param t is the tuple of (char*) names to dereference.
+ */
+extern void BindingTable_deref(BindingTable *bt,Tuple *t);
+
+/**
+ * \brief Set values for names, optionally unbinding names as well.
+ *
+ * \param bt is the bindingtable concerned.
+ *
+ * \param nm is the Tuple of names to bind.
+ *
+ * \param vs is the Tuple of values.
+ *
+ * \param all is a flag to assign all (1) or only non-zero (0) values.
+ *
+ * \note The values tuple must be as wide as the names tuple.
+ */
+extern void BindingTable_set_all(BindingTable *bt,Tuple *nm,Tuple *vs,int all);
+
+#endif
--- /dev/null
+LIBRARY = librrqlogic.a
+LIBOBJS += Tuple.o TupleSchema.o Relation.o
+LIBOBJS += Binding.o BindingTable.o
+LIBOBJS += Query.o
+LIBOBJS += AssignQuery.o RelationQuery.o
+LIBOBJS += NotQuery.o AndQuery.o OrQuery.o
+#LIBOBJS += View.o
+
+default: $(LIBRARY)
+
+all: default
+
+include ../common.mk
--- /dev/null
+#include <stdlib.h>
+#include <NotQuery.h>
+
+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;
+}
--- /dev/null
+#ifndef NotQuery_H
+#define NotQuery_H
+
+#include <Query.h>
+
+/**
+ * NotQuery represents logical negation.
+ *
+ * \extends Query
+ */
+typedef struct NotQuery {
+ struct QueryCallbacks *def;
+ Query *query;
+} NotQuery;
+
+#endif
--- /dev/null
+#include <stdarg.h>
+#include <stdlib.h>
+#include <OrQuery.h>
+
+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;
+}
+
--- /dev/null
+#ifndef OrQuery_H
+#define OrQuery_H
+
+#include <Query.h>
+
+/**
+ * OrQuery represents a disjunction of sub queries.
+ *
+ * \extends Query
+ */
+typedef struct {
+ struct QueryCallbacks *def;
+ int index;
+ int size;
+ Query **disjuncts;
+} OrQuery;
+
+#endif
--- /dev/null
+#include <Query.h>
+
+/**
+ * \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.
+ */
+void Query_reclaim(Query *this) {
+ this->def->reclaim( 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.
+ */
+int Query_next(Query *this,BindingTable *bt,enum NextState state) {
+ return this->def->next( this, bt, state );
+}
+
+/**
+ * \brief Trampoline for the callback function that adds its binding
+ * names to the hashvector.
+ */
+void Query_variables(Query *this,HashVector *hv) {
+ this->def->variables( this, hv );
+}
+
+void Query_eval(
+ Query *q,BindingTable *bt,
+ int (*consequent)(BindingTable *bt,void *data),
+ void *data )
+{
+ if ( Query_next( q, bt, initial ) && consequent( bt, data ) ) {
+ while ( Query_next( q, bt, subsequent ) && consequent( bt, data ) );
+ }
+ (void) Query_next( q, bt, restore );
+}
+
+/* ==================== Snapshotting a query ==================== */
+
+/**
+ * The data used for bindings capture in snapshotting.
+ */
+struct Query_snapshot_data {
+ Tuple *names;
+ Vector *v;
+};
+
+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;
+}
+
+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;
+}
--- /dev/null
+#ifndef Query_H
+#define Query_H
+
+#include <QueryCallbacks.h>
+#include <BindingTable.h>
+#include <Relation.h>
+
+/**
+ * A Query is an implementation of a generic ABI over relations. It's
+ * more or less a "virtual Relation" representing a logical composite
+ * access of actual relations, and as such its active part is held in
+ * a separate \ref Querytype record similar to how \ref ItemKeyFun
+ * records define valye types.
+ */
+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.
+ *
+ * \param arity is the assignment tuple arity.
+ *
+ * \param names is the (char*) names to assign.
+ *
+ * \param values is the (void*) values to asign.
+ *
+ * The two tuples must have the same arity for assigning names[i] to
+ * values[i]. This Query makes the given names have the given values,
+ * once for each (*next) call following a (*reset) call.
+ *
+ * \related Query
+ */
+extern Query *Query_assign(int arity,Tuple *names,Tuple *values);
+
+/**
+ * \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_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_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
--- /dev/null
+#ifndef QueryCallbacks_H
+#define QueryCallbacks_H
+
+#include <BindingTable.h>
+
+typedef struct Query Query; // forward
+
+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.
+ */
+typedef 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);
+
+ /**
+ * \brief This callback function adds its binding names to the
+ * hashvector.
+ */
+ void (*variables)(Query *this,HashVector *hv);
+} QueryCallbacks;
+
+#endif
--- /dev/null
+#include <stdarg.h>
+#include <stdlib.h>
+#include <Relation.h>
+
+Relation *Relation_create(TupleSchema *schema) {
+ Relation *r = (Relation *) malloc( sizeof( Relation ) );
+ (*r) = (Relation) {
+ .content = (HashVector) {
+ .table = (Vector) {
+ .variant = Nibble_index_levels,
+ .size = 16,
+ .entries = 0
+ },
+ .fill = 0, .holes = 0, .type = (ItemKeyFun*) schema
+ },
+ .constraints = (Vector) {
+ .variant = single_index_level,
+ .size = 0,
+ .entries = 0
+ },
+ };
+ return r;
+}
+
+#define COPYA(T,P,N) (T*) memcpy( malloc( N * sizeof(T) ), P, N * sizeof( T ) )
+#define COPY(T,P) COPYA(T,P,1)
+
+// Add an indexing HashVector to the Relation using the given column
+// flags with 1 indicating key column and 0 indicating value column.
+int Relation_add_constraint(Relation *r,...) {
+ va_list ap;
+ TupleSchema *ts = (TupleSchema *) r->content.type;
+ Tuple *columns = Tuple_clone( ts->columns );
+ int i = 0;
+ va_start( ap, r );
+ for ( ; i < columns->size; i++ ) {
+ if ( va_arg( ap, int ) == 0 ) {
+ columns->elements[i] = 0;
+ }
+ }
+ va_end( ap );
+ ts = TupleSchema_create( columns );
+ i = (int) r->constraints.size;
+ Vector_append(
+ &r->constraints,
+ HashVector_create( Nibble_index_levels, (ItemKeyFun*) ts ) );
+ return i;
+}
+
+//============== Adding an item =============
+// Iteration context for adding or Querying a Relation
+typedef struct {
+ Relation *rel;
+ HashVector knockouts;
+ void *item;
+} Knockout;
+
+// Determine matches to ((Knockout*)data)->key in
+// (HashVector*)item, optionally using ((Knockout*)data)->columns
+// for ignoring full matches to the key tuple.
+static int knockout_check(VectorIndex index,void *item,void *data) {
+ Knockout *kod = (Knockout*) data;
+ void *key = kod->item;
+ HashVector *hv = (HashVector*) item;
+ TupleSchema *type = (TupleSchema *)hv->type;
+ VectorIndex i = 0;
+ for ( ; i < hv->table.size; i++ ) {
+ void *old = HashVector_next( hv, &i );
+ if ( old ) {
+ if ( key && type->base.haskey( type, old, key ) == 0 ) {
+ continue;
+ }
+ HashVector_add( &kod->knockouts, old );
+ }
+ }
+ return 0;
+}
+
+// delete the (tuple*)item from the (HashVector*)data
+static int knockout_delete(VectorIndex index,void *item,void *data) {
+ HashVector_delete( (HashVector*) item, data );
+ return 0;
+}
+
+// add the (tuple*)data to the (HashVector*)item
+static int knockout_add(VectorIndex index,void *item,void *data) {
+ HashVector_add( (HashVector*)item, data );
+ return 0;
+}
+
+// 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) {
+ (*this) = (Knockout) {
+ .rel = r,
+ .knockouts = {
+ .table = {
+ .variant = Nibble_index_levels, .size = 16, .entries = 0
+ },
+ .fill = 0, .holes = 0, .type = r->content.type,
+ },
+ .item = item
+ };
+ knockout_check( 0, &r->content, this );
+ if ( add ) {
+ if ( this->knockouts.fill > 0 ) {
+ return 0;
+ }
+ // Find all constraint knockouts for addition
+ Vector_iterate( &r->constraints, 0, knockout_check, this );
+ }
+ if ( this->knockouts.fill > 0 ) {
+ // Delete them from all tables
+ VectorIndex i;
+ for ( i = 0; i < this->knockouts.table.size; i++ ) {
+ void *t = HashVector_next( &this->knockouts, &i );
+ if ( t ) {
+ HashVector_delete( &r->content, t );
+ Vector_iterate( &r->constraints, 0, knockout_delete, t );
+ }
+ }
+ }
+ return 1;
+}
+
+// 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) {
+ Knockout data;
+ if ( knockout_clear( &data, r, item, 1 ) ) {
+ // Add the new tuple
+ HashVector_add( &r->content, item );
+ Vector_iterate( &r->constraints, 0, knockout_add, item );
+ return HashVector_contents( &data.knockouts, single_index_level, 0 );
+ }
+ return 0;
+}
+
+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) {
+ HashVector *hv = &r->content;
+ void *key = query;
+ TupleSchema *type = (TupleSchema *) hv->type;
+ for ( ; (*index) < hv->table.size; (*index)++ ) {
+ void *old = HashVector_next( hv, index );
+ if ( old ) {
+ if ( key && type->base.haskey( type, old, key ) == 0 ) {
+ continue;
+ }
+ return old;
+ }
+ }
+ (*index) = hv->table.size;
+ return 0;
+}
+
--- /dev/null
+#ifndef Relation_H
+#define Relation_H
+
+#include <HashVector.h>
+#include <TupleSchema.h>
+
+/**
+ * A Relation is an implementation of a tuple set with (optional) key
+ * constraints. The store is a \ref HashVector whose \b type is a \ref
+ * TupleSchema that defines the columns. The key constraints are
+ * represented as additional \ref HashVector "HashVectors" whose \ref
+ * TupleSchema "TupleSchemas" are clones of the column schema with
+ * some columns excluded.
+ *
+ * \extends HashVector
+ */
+typedef struct {
+ /**
+ * This is the primary content store for the Relation. Its type
+ * should be a TupleSchema declaring the "item types" for the
+ * Relation columns.
+ */
+ HashVector content;
+
+ /**
+ * This is a collection of relational constraints, if any, which
+ * are represented as HashVectors whose TupleSchemas are clones of
+ * the content TupleSchema with some columns excluded.
+ */
+ Vector constraints;
+} Relation;
+
+/**
+ * \brief Create a Relation for the given TupleSchema.
+ *
+ * \param schema is the column schema
+ *
+ * \returns the allocated Relation record.
+ *
+ * The given TupleSchema is set up as the type of the content
+ * HashVector, which also is initialised as a Nibble_index_levels
+ * variant Vector.
+ *
+ * \related Relation
+ */
+extern Relation *Relation_create(TupleSchema *schema);
+
+/**
+ * \brief Add a key constraint to a \ref Relation.
+ *
+ * \param r is the Relation concerned.
+ *
+ * \param ... are the column flags indicating key (1) or value (0)
+ * column for all columns.
+ *
+ * \returns the index into the constraints \ref Vector for the added
+ * constraint.
+ *
+ * This function adds a \ref HashVector with a \ref TupleSchema as its
+ * item type cloned from the content type and then modified to
+ * represent the constraint. Namely that the key columns have their
+ * "column type" set while value columsn are reset.
+ *
+ * The \b constraint \ref HashVectors are used when \ref tuple
+ * "tuples" are added to the \ref Relation so as to identify the
+ * already contained \ref tuple "tuples" that contradict the addition
+ * by means of having the same constraint key. The already contained
+ * \ref tuple "tuples" are then "knocked out" from the Relation by the
+ * new addition.
+ *
+ * \see Relation_add
+ * \related Relation
+ */
+extern int Relation_add_constraint(Relation *r,...);
+
+/**
+ * \brief Add the tuple to the Relation.
+ *
+ * \param r is the \ref Relation concerned.
+ *
+ * \param t is the \ref tuple to add.
+ *
+ * \returns a Vector of all knocked out tuples.
+ *
+ * This function adds the \ref tuple \b t to the \ref Relation \b r,
+ * and it returns a \ref Vector (single_index_level variant) of all
+ * same-key constraint tuples. The returned Vector is malloc-ed and it
+ * must be free-ed by the caller. If the tuple is already contained or
+ * there are no other same-key tuples knocked out, then \b 0 is
+ * returned.
+ *
+ * \related Relation
+ */
+extern Vector *Relation_add(Relation *r,Tuple *t);
+
+/**
+ * \brief Delete all tuples matching to the Query \ref tuple fromt the
+ * \ref Relation.
+ *
+ * \param r is the \ref Relation concerned.
+ *
+ * \param t is the \ref tuple to delete.
+ *
+ * \returns a \Vector Vector of all knocked out tuples, i.e. the
+ * same-key tuples, if any, contained in the Relation
+ *
+ * Note that deletion uses a "Query" tuple, which means that some
+ * columns may be null to mark that them match to any value.
+ *
+ * \related Relation
+ */
+extern Vector *Relation_delete(Relation *r,Tuple *query);
+
+/**
+ * \brief Return the next \ref tuple in the \ref Relation that matches
+ * to the Query \ref tuple, at or after the index.
+ *
+ * \param r is the \ref Relation concerned.
+ *
+ * \param index is a pointer to the \ref Vector index to update.
+ *
+ * \param Query is a Query \tuple tuple for selection of certain
+ * column values.
+ *
+ * \returns any such matching \tuple tuple and an updateed *index.
+ *
+ * \related Relation
+ */
+extern void *Relation_next(Relation *r,VectorIndex *index,Tuple *query);
+
+/**
+ * \brief Lay out a dynamic \ref Relation initializer for a Relation
+ * wth the given column "types".
+ *
+ * This defines a \ref Relation intializer that creates the \ref
+ * TupleSchema for the given columns.
+ *
+ * \note The initializer cannot be used statically.
+ *
+ * The \b content \ref HashVector is a \ref Nibble_index_level variant
+ * with an initial size of 16 slots.
+ *
+ * The constraints \ref Vector is a \ref BitPair_index_level variant
+ * with initial size 0.
+ *
+ * The \b content \ref HashVector \b type is set up with an allocated
+ * \ref TupleSchema that has an allocated \ref tuple that declares the
+ * column "types" view the given \ref ItemKeyFun pointers. Any add
+ * constraints will need to clone that \ref TupleSchema and then clear
+ * the column slots for the constraint value columns, typically by
+ * using \ref TupleSchema_mask for this.
+ *
+ * \related Relation
+ */
+#define RELATION(...) (Relation) { \
+ .content = { \
+ .table = { .variant = Nibble_index_levels, .size=16, .entries=0 }, \
+ .fill = 0, .holes = 0, \
+ .type = (ItemKeyFun*) TUPLESCHEMA( __VA_ARGS__ ) \
+ }, \
+ .constraints = { .variant = BitPair_index_levels, .size=0, .entries=0 } \
+}
+
+#endif
--- /dev/null
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <RelationQuery.h>
+
+// 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;
+}
+
--- /dev/null
+#ifndef RelationQuery_H
+#define RelationQuery_H
+
+#include <Relation.h>
+#include <Query.h>
+
+/**
+ * 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
--- /dev/null
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <Tuple.h>
+
+// Allocate zero-ed
+Tuple *Tuple_calloc(unsigned long arity) {
+ Tuple *t = (Tuple *) malloc( sizeof( Tuple ) + arity * sizeof( void* ) );
+ t->size = arity;
+ memset( t->elements, 0, arity * sizeof( void* ) );
+ return t;
+}
+
+// Allocate with values
+Tuple *Tuple_create(int arity,...) {
+ va_list ap;
+ int i;
+ Tuple *t = (Tuple *) malloc( sizeof( Tuple ) + arity * sizeof( void* ) );
+ t->size = arity;
+ va_start( ap, arity );
+ for ( i = 0; i < arity; i++ ) {
+ t->elements[i] = va_arg( ap, void* );
+ }
+ va_end( ap );
+ return t;
+}
+
+// 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;
+}
--- /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 {
+ /**
+ * The number of elements.
+ */
+ unsigned long size;
+ /**
+ * Base address for element pointers, which thus follow this
+ * struct in memory.
+ */
+ void *elements[];
+} Tuple;
+
+/**
+ * \brief Create an untyped tuple with given values.
+ *
+ * \related Tuple
+ */
+extern Tuple *Tuple_create(int arity,...);
+
+/**
+ * \brief Create an untyped tuple with 0 values.
+ *
+ * \related Tuple
+ */
+extern Tuple *Tuple_calloc(unsigned long arity);
+
+/**
+ * \brief Create a tuple as a clone of a given tuple.
+ *
+ * \related Tuple
+ */
+extern Tuple *Tuple_clone(Tuple *t);
+
+#endif
--- /dev/null
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <TupleSchema.h>
+
+/**
+ * This callback function returns the hashcode of a key.
+ *
+ * \param this is a pointer to the ItemKeyFun record from where this
+ * callback got invoked
+ *
+ * \param key is the key to produce a hascode for
+ *
+ * \returns the hashcode which is a VectorIndex (i.e. unsigned long)
+ *
+ * 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 TupleSchema_hashcode(void *this,void *key) {
+ TupleSchema *def = (TupleSchema *) this;
+ ItemKeyFun **columns = (ItemKeyFun**) def->columns->elements;
+ Tuple *kp = (Tuple*) key;
+ int i = 0;
+ unsigned long value = 5381;
+ for ( ; i < def->columns->size; i++ ) {
+ if ( columns[i] ) {
+ value <<= 3;
+ if ( kp->elements[i] ) {
+ value += columns[i]->hashcode( columns[i], kp->elements[i] );
+ }
+ }
+ value += 17;
+ }
+ return value;
+}
+
+/**
+ * This callback function determines whether an item has a
+ * given key or not.
+ */
+static int TupleSchema_haskey(void *this,void *item,void *key) {
+ TupleSchema *def = (TupleSchema *) this;
+ ItemKeyFun **columns = (ItemKeyFun**) def->columns->elements;
+ Tuple *kp = (Tuple*) key;
+ Tuple *tp = (Tuple*) item;
+ int i = 0;
+ 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 ) {
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+
+/**
+ * This callback function returns the key of an item by considering
+ * the arity and mask.
+ */
+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( tp );
+ int i;
+ for ( i = 0; i < def->columns->size; i++ ) {
+ if ( columns[i] ) {
+ key->elements[i] = columns[i]->itemkey(
+ columns[i], tp->elements[i] );
+ } else {
+ key->elements[i] = 0;
+ }
+ }
+ return (void*) key;
+}
+
+/**
+ * This callback function handles a key obtained from the itemkey
+ * callback function to reclaim temporary allocation.
+ */
+static void TupleSchema_releasekey(void *this,void *key) {
+ TupleSchema *def = (TupleSchema *) this;
+ ItemKeyFun **columns = (ItemKeyFun**) def->columns->elements;
+ Tuple *kp = (Tuple*) key;
+ int i;
+ for ( i = 0; i < def->columns->size; i++ ) {
+ if ( columns[i] ) {
+ columns[i]->releasekey( columns[i], kp->elements[i] );
+ }
+ }
+ free( key );
+}
+
+#define OUT(X) a = X; if ( a > limit ) return 0; buffer += a; limit -= a
+
+/**
+ * This callback function writes a representation of an item into
+ * a character buffer.
+ */
+static int TupleSchema_tostring(void *this,void *item,char *buffer,int limit) {
+ TupleSchema *def = (TupleSchema *) this;
+ ItemKeyFun **columns = (ItemKeyFun**) def->columns->elements;
+ Tuple *t = (Tuple*) item;
+ char *x = "<";
+ int a, i;
+ for ( i = 0; i < def->columns->size; i++ ) {
+ OUT( snprintf( buffer, limit, x ) );
+ x = ",";
+ OUT( columns[i]->tostring(
+ columns[i], t->elements[i], buffer, limit ) );
+ }
+ OUT( snprintf( buffer, limit, ">" ) );
+ return a;
+}
+
+ItemKeyFun TupleSchema_callbacks = {
+ .hashcode = TupleSchema_hashcode,
+ .haskey = TupleSchema_haskey,
+ .itemkey = TupleSchema_itemkey,
+ .releasekey = TupleSchema_releasekey,
+ .tostring = TupleSchema_tostring
+};
+
+TupleSchema *TupleSchema_create(Tuple *columns) {
+ TupleSchema *ts = (TupleSchema*) malloc( sizeof( TupleSchema ) );
+ (*ts) = (TupleSchema) {
+ .base = TupleSchema_callbacks,
+ .columns = columns
+ };
+ return ts;
+}
+
+#define COPYA(T,P,N) (T*) memcpy( malloc( N * sizeof(T) ), P, N * sizeof( T ) )
+#define COPY(T,P) COPYA(T,P,1)
+
+// Duplicate a TupleSchema with optionally some columns reset.
+TupleSchema *TupleSchema_mask(TupleSchema *schema,...) {
+ TupleSchema *masked = COPY(TupleSchema,schema);
+ 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->columns->size ) {
+ break;
+ }
+ masked->columns->elements[i] = 0;
+ };
+ va_end( ap );
+ return masked;
+}
--- /dev/null
+#ifndef tupleitem_H
+#define tupleitem_H
+
+#include <Tuple.h>
+
+/**
+ * A TupleSchema record declares the ItemKeyFun functions for tuple
+ * items together with applicable arity and domain combinations.
+ * Records are created dynamically via the \ref TupleSchema_create
+ * function or the \ref TUPLESCHEMA convenience macro.
+ *
+ * \extends ItemKeyFun
+ */
+typedef struct TupleSchema {
+ /**
+ * These are the ItemKeyFun callback functions to support
+ * HashVector use for tuple items. The functions expects their
+ * ItemKeyFun pointer to be within a TupleSchema record so as to
+ * provide the handling of the tuple columns.
+ */
+ ItemKeyFun base;
+
+ /**
+ * This points to tuple whose elements is array of pointers to the
+ * tuple item domains as represented by their associated
+ * ItemKeyFun records.
+ */
+ Tuple *columns;
+} TupleSchema;
+
+/**
+ * Create a tuples with given values.
+ *
+ * \related TupleSchema
+ */
+extern TupleSchema *TupleSchema_create(Tuple *columns);
+
+/**
+ * Copy the given TupleSchema into a new TupleSchema with some columns
+ * masked. This represents a sub-index type using the unmasked columns
+ * for indexing.
+ *
+ * \related TupleSchema
+ */
+extern TupleSchema *TupleSchema_mask(TupleSchema *schema,...);
+
+/**
+ * \brief Return 1/0 to indicate whether the Query matches the item.
+ *
+ * \related TupleSchema
+ */
+extern int TupleSchema_match(TupleSchema *def,Tuple *query,Tuple *item);
+
+/**
+ * \brief Generic macro to determine the number of expressions in a
+ * __VA_ARGS__
+ *
+ * \related TupleSchema
+ */
+#define NUMARGS(...) (sizeof((void*[]){__VA_ARGS__})/sizeof(void*))
+
+/**
+ * \brief Create a tuple with the given values.
+ *
+ * This invokes \ref tuple_create to allocate and assign a void*
+ * array with the given values.
+ *
+ * \related TupleSchema
+ */
+#define TUPLE(...) Tuple_create( NUMARGS(__VA_ARGS__), __VA_ARGS__ )
+
+/**
+ * \brief Create a \ref TupleSchema with the given column "types".
+ *
+ * This invokes \ref TupleSchema_create to allocate and initialize a
+ * \ref TupleSchema for the given columns via the \ref TUPLE macro.
+ *
+ * \related TupleSchema
+ */
+#define TUPLESCHEMA(...) \
+ TupleSchema_create( TUPLE( __VA_ARGS__ ) )
+
+
+#endif
default: socket-sniff
-CFLAGS = -Wall -I../vector -g -fmax-errors=1
-LDLIBS = -L../vector -lvector
+RRQLIBS = typing vector
+INCDIRS = $(addprefix -I../,$(RRQLIBS))
+
+CFLAGS = -Wall $(INCDIRS)
+CFLAGS += -g -fmax-errors=1
+LDLIBS = -L../vector -lvector -lm
.INTERMEDIATE: socket-sniff.o
#include <sys/types.h>
#include <unistd.h>
-#include <hashvector.h>
+#include <HashVector.h>
+#include <stringitem.h>
// Seconds between outputs
static int DELAY = 5;
exit( 1 );
}
-// Return pointer to the key for an item
-static void *Countp_itemkey(void *item) {
+// Returns the hashcode for a key
+static unsigned long Countp_hashcode(void *this,void *key) {
+ return HashVector_hashcode( key, IPBUFMAX );
+}
+
+// Return pointer a key for an item (could be temporary allocation)
+static void *Countp_itemkey(void *this,void *item) {
return ((Count*) item)->ip;
}
// Return 1 if the item has the key, or 0 otherwise.
-static int Countp_haskey(void *item,void *key) {
- return memcmp( key, Countp_itemkey( item ), IPBUFMAX ) == 0;
+static int Countp_haskey(void *this,void *item,void *key) {
+ return memcmp( key, Countp_itemkey( this, item ), IPBUFMAX ) == 0;
}
-// Returns the hashcode for a key
-static unsigned long Countp_hashcode(void *key) {
- return hashvector_hashcode( key, IPBUFMAX );
+#if 0
+// Releasing a key does nothing
+static void Countp_releasekey(void *this,void *item) {
}
+#endif
-// The hashvector of seen IP
-static hashvector TBL = {
- .table = { VECTOR_SLOTS, 0 },
+static ItemKeyFun Countp_itemkeyfun = {
+ .hashcode = Countp_hashcode,
+ .haskey = Countp_haskey,
+ .itemkey = Countp_itemkey,
+ //.releasekey = Countp_releasekey,
+ //.tostring = Countp_tostring
+};
+
+// The HashVector of seen IP
+static HashVector TBL = {
+ .table = { Nibble_index_levels, 16, 0 },
.fill = 0,
.holes = 0,
- .keyhashcode = Countp_hashcode,
- .itemkey = Countp_itemkey,
- .haskey = Countp_haskey
+ .type = &Countp_itemkeyfun,
};
// The Count records in time order
/*============================================================
* Reading ignore lines.
*/
+#if 0
// Return pointer to the key for an item
-static void *charp_itemkey(void *item) {
+static void *charp_itemkey(void *this,void *item) {
return item;
}
// Return 1 if the item has the key, or 0 otherwise.
-static int charp_haskey(void *item,void *key) {
+static int charp_haskey(void *this,void *item,void *key) {
return strcmp( key, item ) == 0;
}
// Returns the hashcode for a key
-static unsigned long charp_hashcode(void *key) {
- return hashvector_hashcode( key, strlen( (const char *) key ) );
+static unsigned long charp_hashcode(void *this,void *key) {
+ return HashVector_hashcode( key, strlen( (const char *) key ) );
}
+#endif
-static hashvector IGN = {
+static HashVector IGN = {
.table = { 256, 0 },
.fill = 0,
.holes = 0,
- .keyhashcode = charp_hashcode,
- .itemkey = charp_itemkey,
- .haskey = charp_haskey
+ .type = &stringitem
};
static void read_ignore_file(char *filename) {
char *ip = calloc( 1, p - cur + 1 );
memcpy( ip, cur, p - cur );
cur = p + 1;
- hashvector_add( &IGN, ip );
+ HashVector_add( &IGN, ip );
}
}
return a->last - b->last;
}
-static int Countp_fade_and_print(unsigned long index,void *x,void *d) {
+static int Countp_fade_and_print(VectorIndex index,void *x,void *d) {
if ( x ) {
Count *item = (Count *) x;
item->last = item->accum;
return 0;
}
-static int Countp_reclaim(vector *pv,unsigned long ix,void *item,void *data) {
+static int Countp_reclaim(Vector *pv,unsigned long ix,void *item,void *data) {
return 0;
}
// ip points to [ IPBUFMAX ] of ip address in text
static void add_show_table(char *ip,size_t length) {
static time_t show = 0;
- Count *item;
- int i = hashvector_find( &TBL, ip, (void**) &item );
+ Count *item = HashVector_find( &TBL, ip );
struct timeval now;
if ( gettimeofday( &now, 0 ) ) {
perror( "gettimeofday" );
exit( 1 );
}
- if ( i == 0 ) {
+ if ( item == 0 ) {
item = (Count *) calloc( 1, sizeof( Count ) );
memcpy( item->ip, ip, strlen( ip ) );
- hashvector_add( &TBL, item );
- item->ignore = hashvector_find( &IGN, ip, 0 );
+ HashVector_add( &TBL, item );
+ item->ignore = (HashVector_find( &IGN, ip ) != 0);
+ int i;
for ( i = strlen( ip )-1; i > 1; i-- ) {
if ( ip[i] == '.' || ip[i] == ':' ) {
- item->ignore |= hashvector_find( &IGN, ip, 0 );
+ item->ignore |= (HashVector_find( &IGN, ip ) != 0);
}
ip[i] = 0;
}
trail.head->prev = 0;
}
fprintf( stdout, "drop %s\n", old->ip );
- hashvector_delete( &TBL, old );
+ HashVector_delete( &TBL, old );
free( old );
}
if ( now.tv_sec < show ) {
show = now.tv_sec;
}
show += DELAY; // Time for next output
- vector ordered = { 0, 0 };
- hashvector_contents( &TBL, &ordered );
- vector_qsort( &ordered, Countp_compare );
- vector_iterate( &ordered, Countp_fade_and_print, 0 );
- vector_resize( &ordered, 0, Countp_reclaim, 0 );
+ Vector ordered = { Nibble_index_levels, 0, 0 };
+ HashVector_contents( &TBL, Nibble_index_levels, &ordered );
+ Vector_qsort( &ordered, Countp_compare );
+ Vector_iterate( &ordered, 0, Countp_fade_and_print, 0 );
+ Vector_resize( &ordered, 0, Countp_reclaim, 0 );
fprintf( stdout, "==%ld/%ld/%ld\n", TBL.fill, TBL.holes, TBL.table.size );
}
default: ${BIN}
-CFLAGS = -Wall -I../vector -g -fmax-errors=1
+RRQLIBS = typing vector logic
+INCDIRS = $(addprefix -I../,$(RRQLIBS))
+
+CFLAGS = -Wall $(INCDIRS)
+CFLAGS += -g -fmax-errors=1
LDLIBS = -L../vector -lvector -lm
.INTERMEDIATE: ${OBJ}
int main(int argc,char **argv) {
Relation *rltn2 = Relation_create(
TupleSchema_create(
- 2, Tuple_create( 2, (void*) &stringitem, (void*) &stringitem ) ) );
+ Tuple_create( 2, (void*) &stringitem, (void*) &stringitem ) ) );
Relation_add_constraint( rltn2, 0, 1 );
add_Relation( rltn2, "benton", "holly" );
add_Relation( rltn2, "benton", "molly");
--- /dev/null
+/**
+ * Trampoline functions for the ItemKeyFun callbacks.
+ */
+
+#include <assert.h>
+#include <ItemKeyFun.h>
+
+/**
+ * \brief Trampoline function for the ItemKeyFun.hashcode callback.
+ *
+ * The default is to use the pointer itself.
+ */
+unsigned long ItemKeyFun_hashcode(void *this,void *key) {
+ ItemKeyFun *type = (ItemKeyFun*) this;
+ assert( type );
+ return type->hashcode? type->hashcode( type, key ) : (unsigned long) key;
+}
+
+/**
+ * \brief Trampoline function for the ItemKeyFun.itemkey callback.
+ */
+void *ItemKeyFun_itemkey(void *this,void *item) {
+ ItemKeyFun *type = (ItemKeyFun*) this;
+ assert( type );
+ return type->itemkey? type->itemkey( type, item ) : item;
+}
+
+/**
+ * \brief Trampoline function for the ItemKeyFun.haskey callback.
+ */
+int ItemKeyFun_haskey(void *this,void *item,void *key) {
+ ItemKeyFun *type = (ItemKeyFun*) this;
+ assert( type );
+ if ( type->haskey ) {
+ return type->haskey( this, item, key );
+ }
+ void *ikey = ItemKeyFun_itemkey( this, item );
+ int n = ikey == key;
+ ItemKeyFun_releasekey( this, ikey );
+ return n;
+}
+
+/**
+ * \brief Trampoline function for the ItemKeyFun.releasekey callback.
+ */
+void ItemKeyFun_releasekey(void *this,void *key) {
+ ItemKeyFun *type = (ItemKeyFun*) this;
+ assert( type );
+ if ( type->releasekey ) {
+ type->releasekey( type, key );
+ }
+}
+
+/**
+ * \brief Trampoline function for the ItemKeyFun.tostring callback.
+ */
+int ItemKeyFun_tostring(void *this,void *item,char *buffer,int limit) {
+ ItemKeyFun *type = (ItemKeyFun*) this;
+ assert( type );
+ if ( type->tostring ) {
+ return type->tostring( type, item, buffer, limit );
+ }
+ void *key = ItemKeyFun_itemkey( this, item );
+ int n = snprintf( buffer, limit, "{%p/%p@%p}", type, key, item );
+ ItemKeyFun_releasekey( this, key );
+ return n;
+}
--- /dev/null
+#ifndef ItemKeyFun_H
+#define ItemKeyFun_H
+
+#include <stdio.h>
+
+/**
+ * \struct ItemKeyFun
+ *
+ * ItemKeyFun provides a meta-level representation for abstracting
+ * items as pairs of keys and payload, and having a hashcode mapping
+ * for keys. The key part is used for identifying items under the idea
+ * that all items that have the same key are the same; distinct
+ * representations of the same abstract entity. The hashcode scrambles
+ * the key part in a consistent way into an ideal table index for the
+ * items that have that key. Different keys may yield the same
+ * hashcode.
+ */
+typedef struct {
+
+ /**
+ * 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.
+ */
+ unsigned long (*hashcode)(void *this,void *key);
+
+ /**
+ * This callback function should determine whether an item has a
+ * given key or not.
+ */
+ int (*haskey)(void *this,void *item,void *key);
+
+ /**
+ * 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.
+ */
+ void *(*itemkey)(void *this,void *item);
+
+ /**
+ * This callback function should handle a key obtained from the
+ * itemkey callback function, e.g., reclaim temporary allocation.
+ */
+ void (*releasekey)(void *this,void *key);
+
+ /**
+ * This callback function writes a representation of an item into
+ * a character buffer.
+ */
+ int (*tostring)(void *this,void *item,char *buffer,int limit);
+
+} ItemKeyFun;
+
+/**
+ * \brief Trampoline function for the ItemKeyFun.hashcode callback.
+ *
+ * The default is to use the pointer itself.
+ */
+extern unsigned long ItemKeyFun_hashcode(void *this,void *key);
+
+/**
+ * \brief Trampoline function for the ItemKeyFun.haskey callback.
+ */
+extern int ItemKeyFun_haskey(void *this,void *item,void *key);
+
+/**
+ * \brief Trampoline function for the ItemKeyFun.itemkey callback.
+ */
+extern void *ItemKeyFun_itemkey(void *this,void *item);
+
+/**
+ * \brief Trampoline function for the ItemKeyFun.releasekey callback.
+ */
+extern void ItemKeyFun_releasekey(void *this,void *key);
+
+/**
+ * \brief Trampoline function for the ItemKeyFun.tostring callback.
+ */
+extern int ItemKeyFun_tostring(void *this,void *item,char *buffer,int limit);
+
+#endif
--- /dev/null
+LIBRARY = librrqtyping.a
+LIBOBJS += ItemKeyFun.o integeritem.o stringitem.o
+
+default: $(LIBRARY)
+
+all: default
+
+include ../common.mk
--- /dev/null
+#include <integeritem.h>
+
+/**
+ * This callback function returns 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 integeritem_hashcode(void *this,void *key) {
+ return (unsigned long) key;
+}
+
+/**
+ * This callback function determines whether an item has a
+ * given key or not.
+ */
+static int integeritem_haskey(void *this,void *item,void *key) {
+ return item == key;
+}
+
+/**
+ * This callback function returns the key of an item by considering
+ * the arity and schema.
+ */
+static void *integeritem_itemkey(void *this,void *item) {
+ return item;
+}
+
+/**
+ * This callback function handles a key obtained from the itemkey
+ * callback function to reclaim temporary allocation.
+ */
+static void integeritem_releasekey(void *this,void *key) {
+}
+
+/**
+ * This callback function writes a representation of an item into
+ * a character buffer.
+ */
+static int integeritem_tostring(void *this,void *item,char *buffer,int limit) {
+ return snprintf( buffer, limit, "%lld", (long long) item );
+}
+
+ItemKeyFun integeritem = {
+ .hashcode = integeritem_hashcode,
+ .haskey = integeritem_haskey,
+ .itemkey = integeritem_itemkey,
+ .releasekey = integeritem_releasekey,
+ .tostring = integeritem_tostring
+};
--- /dev/null
+#ifndef integeritem_H
+#define integeritem_H
+
+#include <ItemKeyFun.h>
+
+/**
+ * The stringitem record declares the ItemKeyFun functions for integer
+ * items.
+ */
+extern ItemKeyFun integeritem;
+
+#endif
--- /dev/null
+#include <string.h>
+#include <stringitem.h>
+#include <HashVector.h>
+
+/**
+ * This callback function returns 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 stringitem_hashcode(void *this,void *key) {
+ return HashVector_hashcode( (unsigned char*)key, strlen( (char*)key ) );
+}
+
+/**
+ * This callback function determines whether an item has a
+ * given key or not.
+ */
+static int stringitem_haskey(void *this,void *item,void *key) {
+ return strcmp( item, key ) == 0;
+}
+
+/**
+ * This callback function returns the key of an item by considering
+ * the arity and schema.
+ */
+static void *stringitem_itemkey(void *this,void *item) {
+ return item;
+}
+
+/**
+ * This callback function handles a key obtained from the itemkey
+ * callback function to reclaim temporary allocation.
+ */
+static void stringitem_releasekey(void *this,void *key) {
+}
+
+/**
+ * This callback function writes a representation of an item into
+ * a character buffer.
+ */
+static int stringitem_tostring(void *this,void *item,char *buffer,int limit) {
+ if ( item ) {
+ return snprintf( buffer, limit, "\"%s\"", (char*) item );
+ }
+ return snprintf( buffer, limit, "(null)" );
+}
+
+ItemKeyFun stringitem = {
+ .hashcode = stringitem_hashcode,
+ .haskey = stringitem_haskey,
+ .itemkey = stringitem_itemkey,
+ .releasekey = stringitem_releasekey,
+ .tostring = stringitem_tostring
+};
--- /dev/null
+#ifndef stringitem_H
+#define stringitem_H
+
+#include <ItemKeyFun.h>
+
+/**
+ * The stringitem record declares the ItemKeyFun functions for string
+ * items.
+ */
+extern ItemKeyFun stringitem;
+
+#endif
+++ /dev/null
-#include <stdarg.h>
-#include <stdlib.h>
-#include <AndQuery.h>
-
-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;
-}
-
+++ /dev/null
-#ifndef AndQuery_H
-#define AndQuery_H
-
-#include <Query.h>
-
-/**
- * AndQuery represents a conjunction of sub queries.
- * \extends Query
- * \related Query
- */
-typedef struct {
- struct QueryCallbacks *def;
- int active;
- int size;
- Query **conjuncts;
-} AndQuery;
-
-
-#endif
+++ /dev/null
-#include <stdlib.h>
-#include <string.h>
-#include <AssignQuery.h>
-
-// 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;
-}
+++ /dev/null
-#ifndef AssignQuery_H
-#define AssignQuery_H
-
-#include <QueryCallbacks.h>
-#include <Tuple.h>
-
-/**
- * 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
+++ /dev/null
-#include <string.h>
-#include <HashVector.h>
-#include <Binding.h>
-
-/**
- * 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
-};
-
+++ /dev/null
-#ifndef Binding_H
-#define Binding_H
-
-#include <ItemKeyFun.h>
-
-/**
- * \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
+++ /dev/null
-#include <BindingTable.h>
-#include <string.h>
-#include <stdlib.h>
-
-BindingTable *BindingTable_create() {
- BindingTable *this = (BindingTable*) malloc( sizeof( BindingTable ) );
- (*this) = (HashVector) {
- .table = (Vector) {
- .variant = Nibble_index_levels, .size = 16, .entries = 0
- }, .fill = 0, .holes = 0, .type = &Bindingitem
- };
- return this;
-}
-
-void BindingTable_release(BindingTable *bt) {
- if ( bt ) {
- Vector_resize( &bt->table, 0, Vector_free_any, 0 );
- free( bt );
- }
-}
-
-void BindingTable_set(BindingTable *bt,char *name,void *value) {
- Binding *b = (Binding*) HashVector_find( bt, name );
- if ( b == 0 ) {
- b = (Binding*) malloc( sizeof( Binding ) );
- b->name = name;
- HashVector_add( bt, b );
- }
- b->value = value;
-}
-
-void *BindingTable_get(BindingTable *bt,char *name) {
- Binding *b = (Binding*) HashVector_find( bt, name );
- return b? b->value : 0;
-}
-
-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 );
- void *v2 = BindingTable_get( bt, n2 );
- if ( v2 && v1 == 0 ) {
- BindingTable_set( bt, n1, v2 );
- }
- if ( v1 && v2 == 0 ) {
- BindingTable_set( bt, n2, v1 );
- }
- return ( v1 && v2 )? ( eq? ( eq( v1, v2 ) == 0 ) : ( v1 == v2 ) ) : 1;
-}
-#endif
-
-Tuple *BindingTable_get_all(BindingTable *bt,Tuple *t) {
- Tuple *vt = Tuple_clone( t );
- BindingTable_deref( bt, vt );
- return vt;
-}
-
-void BindingTable_set_all(BindingTable *bt,Tuple *nm,Tuple *vs,int all) {
- int i;
- for ( i = 0; i < nm->size; i++ ) {
- BindingTable_set( bt, nm->elements[i], vs->elements[i] );
- }
-}
+++ /dev/null
-#ifndef BindingTable_H
-#define BindingTable_H
-
-#include <HashVector.h>
-#include <TupleSchema.h>
-#include <Binding.h>
-
-/**
- * A BindingTable is a chain of \ref HashVector "HashVectors" of
- * Binding items that associate a (char*) name with a (void*) value.
- */
-typedef HashVector/*<Binding>*/ BindingTable;
-
-/**
- * \brief Allocate a new \ref BindingTable.
- *
- * \returns the allocated \ref bandingtable.
- *
- * \related BindingTable
- */
-extern BindingTable *BindingTable_create();
-
-/**
- * \brief Reclaim a \ref BindingTable with all its bindings.
- *
- * \param bt is the \ref BindingTable to reclaim.
- *
- * \related BindingTable
- */
-extern void BindingTable_release(BindingTable *bt);
-
-/**
- * \brief Set a Binding in a \ref BindingTable.
- *
- * \param bt is the \ref BindingTable concerned.
- *
- * \param name is the Binding name.
- *
- * \param value is the Binding value.
- *
- * \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
- */
-extern void BindingTable_set(BindingTable *bt,char *name,void *value);
-
-/**
- * \brief Get a Binding from a BindingTable chain.
- *
- * \param bt is the first BindingTable concerned.
- *
- * \param name is the Binding variable name.
- *
- * \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.
- *
- * \note Not also that a name can be made unbound on top of being
- * bound by setting it to \b 0.
- *
- * \related BindingTable
- */
-extern void *BindingTable_get(BindingTable *bt,char *name);
-
-/**
- * \brief Replace all names with their values.
- *
- * \param bt is the BindingTable concerned.
- *
- * \param t is the tuple of (char*) names to dereference.
- */
-extern void BindingTable_deref(BindingTable *bt,Tuple *t);
-
-/**
- * \brief Set values for names, optionally unbinding names as well.
- *
- * \param bt is the bindingtable concerned.
- *
- * \param nm is the Tuple of names to bind.
- *
- * \param vs is the Tuple of values.
- *
- * \param all is a flag to assign all (1) or only non-zero (0) values.
- *
- * \note The values tuple must be as wide as the names tuple.
- */
-extern void BindingTable_set_all(BindingTable *bt,Tuple *nm,Tuple *vs,int all);
-
-#endif
#include <stdlib.h>
#include <HashVector.h>
-#define SELF hv->type
-
// Find the slot for the keyed element, and return pointer to it, or
// to the first of holes encountered while considering collisions.
// Returns a pointer to the place for the item, or 0 in case of OOM or
{
if ( itemkey ) {
// Get actual key from keying item
- key = hv->type->itemkey( SELF, key );
+ key = ItemKeyFun_itemkey( hv->type, key );
}
- unsigned long index = hv->type->hashcode( SELF, key ) % hv->table.size;
+ unsigned long index = ItemKeyFun_hashcode( hv->type, key ) % hv->table.size;
*i = index;
void **hole = 0;
void **p = 0;
p = Vector_entry( &hv->table, (*i) );
if ( p == 0 ) {
if ( itemkey ) {
- hv->type->releasekey( SELF, key );
+ ItemKeyFun_releasekey( hv->type, key );
}
return 0; // This basically means OOM, and is a failure condition.
}
if ( (*p) == 0 ) {
if ( itemkey ) {
- hv->type->releasekey( SELF, key );
+ ItemKeyFun_releasekey( hv->type, key );
}
return ( hole )? hole : p; // Not found; it's place is here.
}
if ( hole == 0 ) {
hole = p; // Remember the first hole
}
- } else if ( hv->type->haskey( SELF, (*p), key ) ) {
+ } else if ( ItemKeyFun_haskey( hv->type, (*p), key ) ) {
if ( itemkey ) {
- hv->type->releasekey( SELF, key );
+ ItemKeyFun_releasekey( hv->type, key );
}
return p; // Found
}
}
if ( (*i) == index ) {
if ( itemkey ) {
- hv->type->releasekey( SELF, key );
+ ItemKeyFun_releasekey( hv->type, key );
}
return 0; // Overfull HashVector!
}
+++ /dev/null
-#ifndef ItemKeyFun_H
-#define ItemKeyFun_H
-
-#include <stdio.h>
-
-/**
- * \struct ItemKeyFun
- *
- * ItemKeyFun provides a meta-level representation for abstracting
- * items as pairs of keys and payload, and having a hashcode mapping
- * for keys. The key part is used for identifying items under the idea
- * that all items that have the same key are the same; distinct
- * representations of the same abstract entity. The hashcode scrambles
- * the key part in a consistent way into an ideal table index for the
- * items that have that key. Different keys may yield the same
- * hashcode.
- */
-typedef struct {
-
-#define SELF void *this
- /**
- * 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.
- */
- unsigned long (*hashcode)(SELF,void *key);
-
- /**
- * This callback function should determine whether an item has a
- * given key or not.
- */
- int (*haskey)(SELF,void *item,void *key);
-
- /**
- * 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.
- */
- void *(*itemkey)(SELF,void *item);
-
- /**
- * This callback function should handle a key obtained from the
- * itemkey callback function, e.g., reclaim temporary allocation.
- */
- void (*releasekey)(SELF,void *key);
-
- /**
- * This callback function writes a representation of an item into
- * a character buffer.
- */
- int (*tostring)(SELF,void *item,char *buffer,int limit);
-
-#undef SELF
-} ItemKeyFun;
-
-#endif
-LIBRARY = libvector.a
+LIBRARY = librrqvector.a
LIBOBJS = Vector.o HashVector.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)
-
-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
-$1.o: $1.c | $1.h
-endef
-
-$(foreach OBJ,$(LIBOBJS:.o=),$(eval $(call STDCC,$(OBJ))))
-
CLEANRM += $(LIBRARY)
-$(LIBRARY): $(LIBOBJS)
- $(AR) r $@ $^
-clean:
- rm -f $(CLEANRM)
+include ../common.mk
+++ /dev/null
-#include <stdlib.h>
-#include <NotQuery.h>
-
-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;
-}
+++ /dev/null
-#ifndef NotQuery_H
-#define NotQuery_H
-
-#include <Query.h>
-
-/**
- * NotQuery represents logical negation.
- *
- * \extends Query
- */
-typedef struct NotQuery {
- struct QueryCallbacks *def;
- Query *query;
-} NotQuery;
-
-#endif
+++ /dev/null
-#include <stdarg.h>
-#include <stdlib.h>
-#include <OrQuery.h>
-
-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;
-}
-
+++ /dev/null
-#ifndef OrQuery_H
-#define OrQuery_H
-
-#include <Query.h>
-
-/**
- * OrQuery represents a disjunction of sub queries.
- *
- * \extends Query
- */
-typedef struct {
- struct QueryCallbacks *def;
- int index;
- int size;
- Query **disjuncts;
-} OrQuery;
-
-#endif
+++ /dev/null
-#include <Query.h>
-
-/**
- * \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.
- */
-void Query_reclaim(Query *this) {
- this->def->reclaim( 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.
- */
-int Query_next(Query *this,BindingTable *bt,enum NextState state) {
- return this->def->next( this, bt, state );
-}
-
-/**
- * \brief Trampoline for the callback function that adds its binding
- * names to the hashvector.
- */
-void Query_variables(Query *this,HashVector *hv) {
- this->def->variables( this, hv );
-}
-
-void Query_eval(
- Query *q,BindingTable *bt,
- int (*consequent)(BindingTable *bt,void *data),
- void *data )
-{
- if ( Query_next( q, bt, initial ) && consequent( bt, data ) ) {
- while ( Query_next( q, bt, subsequent ) && consequent( bt, data ) );
- }
- (void) Query_next( q, bt, restore );
-}
-
-/* ==================== Snapshotting a query ==================== */
-
-/**
- * The data used for bindings capture in snapshotting.
- */
-struct Query_snapshot_data {
- Tuple *names;
- Vector *v;
-};
-
-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;
-}
-
-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;
-}
+++ /dev/null
-#ifndef Query_H
-#define Query_H
-
-#include <QueryCallbacks.h>
-#include <BindingTable.h>
-#include <Relation.h>
-
-/**
- * A Query is an implementation of a generic ABI over relations. It's
- * more or less a "virtual Relation" representing a logical composite
- * access of actual relations, and as such its active part is held in
- * a separate \ref Querytype record similar to how \ref ItemKeyFun
- * records define valye types.
- */
-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.
- *
- * \param arity is the assignment tuple arity.
- *
- * \param names is the (char*) names to assign.
- *
- * \param values is the (void*) values to asign.
- *
- * The two tuples must have the same arity for assigning names[i] to
- * values[i]. This Query makes the given names have the given values,
- * once for each (*next) call following a (*reset) call.
- *
- * \related Query
- */
-extern Query *Query_assign(int arity,Tuple *names,Tuple *values);
-
-/**
- * \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_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_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
+++ /dev/null
-#ifndef QueryCallbacks_H
-#define QueryCallbacks_H
-
-#include <BindingTable.h>
-
-typedef struct Query Query; // forward
-
-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.
- */
-typedef 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);
-
- /**
- * \brief This callback function adds its binding names to the
- * hashvector.
- */
- void (*variables)(Query *this,HashVector *hv);
-} QueryCallbacks;
-
-#endif
+++ /dev/null
-#include <stdarg.h>
-#include <stdlib.h>
-#include <Relation.h>
-
-Relation *Relation_create(TupleSchema *schema) {
- Relation *r = (Relation *) malloc( sizeof( Relation ) );
- (*r) = (Relation) {
- .content = (HashVector) {
- .table = (Vector) {
- .variant = Nibble_index_levels,
- .size = 16,
- .entries = 0
- },
- .fill = 0, .holes = 0, .type = (ItemKeyFun*) schema
- },
- .constraints = (Vector) {
- .variant = single_index_level,
- .size = 0,
- .entries = 0
- },
- };
- return r;
-}
-
-#define COPYA(T,P,N) (T*) memcpy( malloc( N * sizeof(T) ), P, N * sizeof( T ) )
-#define COPY(T,P) COPYA(T,P,1)
-
-// Add an indexing HashVector to the Relation using the given column
-// flags with 1 indicating key column and 0 indicating value column.
-int Relation_add_constraint(Relation *r,...) {
- va_list ap;
- TupleSchema *ts = (TupleSchema *) r->content.type;
- Tuple *columns = Tuple_clone( ts->columns );
- int i = 0;
- va_start( ap, r );
- for ( ; i < columns->size; i++ ) {
- if ( va_arg( ap, int ) == 0 ) {
- columns->elements[i] = 0;
- }
- }
- va_end( ap );
- ts = TupleSchema_create( columns );
- i = (int) r->constraints.size;
- Vector_append(
- &r->constraints,
- HashVector_create( Nibble_index_levels, (ItemKeyFun*) ts ) );
- return i;
-}
-
-//============== Adding an item =============
-// Iteration context for adding or Querying a Relation
-typedef struct {
- Relation *rel;
- HashVector knockouts;
- void *item;
-} Knockout;
-
-// Determine matches to ((Knockout*)data)->key in
-// (HashVector*)item, optionally using ((Knockout*)data)->columns
-// for ignoring full matches to the key tuple.
-static int knockout_check(VectorIndex index,void *item,void *data) {
- Knockout *kod = (Knockout*) data;
- void *key = kod->item;
- HashVector *hv = (HashVector*) item;
- TupleSchema *type = (TupleSchema *)hv->type;
- VectorIndex i = 0;
- for ( ; i < hv->table.size; i++ ) {
- void *old = HashVector_next( hv, &i );
- if ( old ) {
- if ( key && type->base.haskey( type, old, key ) == 0 ) {
- continue;
- }
- HashVector_add( &kod->knockouts, old );
- }
- }
- return 0;
-}
-
-// delete the (tuple*)item from the (HashVector*)data
-static int knockout_delete(VectorIndex index,void *item,void *data) {
- HashVector_delete( (HashVector*) item, data );
- return 0;
-}
-
-// add the (tuple*)data to the (HashVector*)item
-static int knockout_add(VectorIndex index,void *item,void *data) {
- HashVector_add( (HashVector*)item, data );
- return 0;
-}
-
-// 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) {
- (*this) = (Knockout) {
- .rel = r,
- .knockouts = {
- .table = {
- .variant = Nibble_index_levels, .size = 16, .entries = 0
- },
- .fill = 0, .holes = 0, .type = r->content.type,
- },
- .item = item
- };
- knockout_check( 0, &r->content, this );
- if ( add ) {
- if ( this->knockouts.fill > 0 ) {
- return 0;
- }
- // Find all constraint knockouts for addition
- Vector_iterate( &r->constraints, 0, knockout_check, this );
- }
- if ( this->knockouts.fill > 0 ) {
- // Delete them from all tables
- VectorIndex i;
- for ( i = 0; i < this->knockouts.table.size; i++ ) {
- void *t = HashVector_next( &this->knockouts, &i );
- if ( t ) {
- HashVector_delete( &r->content, t );
- Vector_iterate( &r->constraints, 0, knockout_delete, t );
- }
- }
- }
- return 1;
-}
-
-// 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) {
- Knockout data;
- if ( knockout_clear( &data, r, item, 1 ) ) {
- // Add the new tuple
- HashVector_add( &r->content, item );
- Vector_iterate( &r->constraints, 0, knockout_add, item );
- return HashVector_contents( &data.knockouts, single_index_level, 0 );
- }
- return 0;
-}
-
-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) {
- HashVector *hv = &r->content;
- void *key = query;
- TupleSchema *type = (TupleSchema *) hv->type;
- for ( ; (*index) < hv->table.size; (*index)++ ) {
- void *old = HashVector_next( hv, index );
- if ( old ) {
- if ( key && type->base.haskey( type, old, key ) == 0 ) {
- continue;
- }
- return old;
- }
- }
- (*index) = hv->table.size;
- return 0;
-}
-
+++ /dev/null
-#ifndef Relation_H
-#define Relation_H
-
-#include <HashVector.h>
-#include <TupleSchema.h>
-
-/**
- * A Relation is an implementation of a tuple set with (optional) key
- * constraints. The store is a \ref HashVector whose \b type is a \ref
- * TupleSchema that defines the columns. The key constraints are
- * represented as additional \ref HashVector "HashVectors" whose \ref
- * TupleSchema "TupleSchemas" are clones of the column schema with
- * some columns excluded.
- *
- * \extends HashVector
- */
-typedef struct {
- /**
- * This is the primary content store for the Relation. Its type
- * should be a TupleSchema declaring the "item types" for the
- * Relation columns.
- */
- HashVector content;
-
- /**
- * This is a collection of relational constraints, if any, which
- * are represented as HashVectors whose TupleSchemas are clones of
- * the content TupleSchema with some columns excluded.
- */
- Vector constraints;
-} Relation;
-
-/**
- * \brief Create a Relation for the given TupleSchema.
- *
- * \param schema is the column schema
- *
- * \returns the allocated Relation record.
- *
- * The given TupleSchema is set up as the type of the content
- * HashVector, which also is initialised as a Nibble_index_levels
- * variant Vector.
- *
- * \related Relation
- */
-extern Relation *Relation_create(TupleSchema *schema);
-
-/**
- * \brief Add a key constraint to a \ref Relation.
- *
- * \param r is the Relation concerned.
- *
- * \param ... are the column flags indicating key (1) or value (0)
- * column for all columns.
- *
- * \returns the index into the constraints \ref Vector for the added
- * constraint.
- *
- * This function adds a \ref HashVector with a \ref TupleSchema as its
- * item type cloned from the content type and then modified to
- * represent the constraint. Namely that the key columns have their
- * "column type" set while value columsn are reset.
- *
- * The \b constraint \ref HashVectors are used when \ref tuple
- * "tuples" are added to the \ref Relation so as to identify the
- * already contained \ref tuple "tuples" that contradict the addition
- * by means of having the same constraint key. The already contained
- * \ref tuple "tuples" are then "knocked out" from the Relation by the
- * new addition.
- *
- * \see Relation_add
- * \related Relation
- */
-extern int Relation_add_constraint(Relation *r,...);
-
-/**
- * \brief Add the tuple to the Relation.
- *
- * \param r is the \ref Relation concerned.
- *
- * \param t is the \ref tuple to add.
- *
- * \returns a Vector of all knocked out tuples.
- *
- * This function adds the \ref tuple \b t to the \ref Relation \b r,
- * and it returns a \ref Vector (single_index_level variant) of all
- * same-key constraint tuples. The returned Vector is malloc-ed and it
- * must be free-ed by the caller. If the tuple is already contained or
- * there are no other same-key tuples knocked out, then \b 0 is
- * returned.
- *
- * \related Relation
- */
-extern Vector *Relation_add(Relation *r,Tuple *t);
-
-/**
- * \brief Delete all tuples matching to the Query \ref tuple fromt the
- * \ref Relation.
- *
- * \param r is the \ref Relation concerned.
- *
- * \param t is the \ref tuple to delete.
- *
- * \returns a \Vector Vector of all knocked out tuples, i.e. the
- * same-key tuples, if any, contained in the Relation
- *
- * Note that deletion uses a "Query" tuple, which means that some
- * columns may be null to mark that them match to any value.
- *
- * \related Relation
- */
-extern Vector *Relation_delete(Relation *r,Tuple *query);
-
-/**
- * \brief Return the next \ref tuple in the \ref Relation that matches
- * to the Query \ref tuple, at or after the index.
- *
- * \param r is the \ref Relation concerned.
- *
- * \param index is a pointer to the \ref Vector index to update.
- *
- * \param Query is a Query \tuple tuple for selection of certain
- * column values.
- *
- * \returns any such matching \tuple tuple and an updateed *index.
- *
- * \related Relation
- */
-extern void *Relation_next(Relation *r,VectorIndex *index,Tuple *query);
-
-/**
- * \brief Lay out a dynamic \ref Relation initializer for a Relation
- * wth the given column "types".
- *
- * This defines a \ref Relation intializer that creates the \ref
- * TupleSchema for the given columns.
- *
- * \note The initializer cannot be used statically.
- *
- * The \b content \ref HashVector is a \ref Nibble_index_level variant
- * with an initial size of 16 slots.
- *
- * The constraints \ref Vector is a \ref BitPair_index_level variant
- * with initial size 0.
- *
- * The \b content \ref HashVector \b type is set up with an allocated
- * \ref TupleSchema that has an allocated \ref tuple that declares the
- * column "types" view the given \ref ItemKeyFun pointers. Any add
- * constraints will need to clone that \ref TupleSchema and then clear
- * the column slots for the constraint value columns, typically by
- * using \ref TupleSchema_mask for this.
- *
- * \related Relation
- */
-#define RELATION(...) (Relation) { \
- .content = { \
- .table = { .variant = Nibble_index_levels, .size=16, .entries=0 }, \
- .fill = 0, .holes = 0, \
- .type = (ItemKeyFun*) TUPLESCHEMA( __VA_ARGS__ ) \
- }, \
- .constraints = { .variant = BitPair_index_levels, .size=0, .entries=0 } \
-}
-
-#endif
+++ /dev/null
-#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
-#include <RelationQuery.h>
-
-// 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;
-}
-
+++ /dev/null
-#ifndef RelationQuery_H
-#define RelationQuery_H
-
-#include <Relation.h>
-#include <Query.h>
-
-/**
- * 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
+++ /dev/null
-#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
-#include <Tuple.h>
-
-// Allocate zero-ed
-Tuple *Tuple_calloc(unsigned long arity) {
- Tuple *t = (Tuple *) malloc( sizeof( Tuple ) + arity * sizeof( void* ) );
- t->size = arity;
- memset( t->elements, 0, arity * sizeof( void* ) );
- return t;
-}
-
-// Allocate with values
-Tuple *Tuple_create(int arity,...) {
- va_list ap;
- int i;
- Tuple *t = (Tuple *) malloc( sizeof( Tuple ) + arity * sizeof( void* ) );
- t->size = arity;
- va_start( ap, arity );
- for ( i = 0; i < arity; i++ ) {
- t->elements[i] = va_arg( ap, void* );
- }
- va_end( ap );
- return t;
-}
-
-// 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;
-}
+++ /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 {
- /**
- * The number of elements.
- */
- unsigned long size;
- /**
- * Base address for element pointers, which thus follow this
- * struct in memory.
- */
- void *elements[];
-} Tuple;
-
-/**
- * \brief Create an untyped tuple with given values.
- *
- * \related Tuple
- */
-extern Tuple *Tuple_create(int arity,...);
-
-/**
- * \brief Create an untyped tuple with 0 values.
- *
- * \related Tuple
- */
-extern Tuple *Tuple_calloc(unsigned long arity);
-
-/**
- * \brief Create a tuple as a clone of a given tuple.
- *
- * \related Tuple
- */
-extern Tuple *Tuple_clone(Tuple *t);
-
-#endif
+++ /dev/null
-#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
-#include <TupleSchema.h>
-
-/**
- * This callback function returns the hashcode of a key.
- *
- * \param this is a pointer to the ItemKeyFun record from where this
- * callback got invoked
- *
- * \param key is the key to produce a hascode for
- *
- * \returns the hashcode which is a VectorIndex (i.e. unsigned long)
- *
- * 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 TupleSchema_hashcode(void *this,void *key) {
- TupleSchema *def = (TupleSchema *) this;
- ItemKeyFun **columns = (ItemKeyFun**) def->columns->elements;
- Tuple *kp = (Tuple*) key;
- int i = 0;
- unsigned long value = 5381;
- for ( ; i < def->columns->size; i++ ) {
- if ( columns[i] ) {
- value <<= 3;
- if ( kp->elements[i] ) {
- value += columns[i]->hashcode( columns[i], kp->elements[i] );
- }
- }
- value += 17;
- }
- return value;
-}
-
-/**
- * This callback function determines whether an item has a
- * given key or not.
- */
-static int TupleSchema_haskey(void *this,void *item,void *key) {
- TupleSchema *def = (TupleSchema *) this;
- ItemKeyFun **columns = (ItemKeyFun**) def->columns->elements;
- Tuple *kp = (Tuple*) key;
- Tuple *tp = (Tuple*) item;
- int i = 0;
- 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 ) {
- return 0;
- }
- }
- }
- return 1;
-}
-
-
-/**
- * This callback function returns the key of an item by considering
- * the arity and mask.
- */
-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( tp );
- int i;
- for ( i = 0; i < def->columns->size; i++ ) {
- if ( columns[i] ) {
- key->elements[i] = columns[i]->itemkey(
- columns[i], tp->elements[i] );
- } else {
- key->elements[i] = 0;
- }
- }
- return (void*) key;
-}
-
-/**
- * This callback function handles a key obtained from the itemkey
- * callback function to reclaim temporary allocation.
- */
-static void TupleSchema_releasekey(void *this,void *key) {
- TupleSchema *def = (TupleSchema *) this;
- ItemKeyFun **columns = (ItemKeyFun**) def->columns->elements;
- Tuple *kp = (Tuple*) key;
- int i;
- for ( i = 0; i < def->columns->size; i++ ) {
- if ( columns[i] ) {
- columns[i]->releasekey( columns[i], kp->elements[i] );
- }
- }
- free( key );
-}
-
-#define OUT(X) a = X; if ( a > limit ) return 0; buffer += a; limit -= a
-
-/**
- * This callback function writes a representation of an item into
- * a character buffer.
- */
-static int TupleSchema_tostring(void *this,void *item,char *buffer,int limit) {
- TupleSchema *def = (TupleSchema *) this;
- ItemKeyFun **columns = (ItemKeyFun**) def->columns->elements;
- Tuple *t = (Tuple*) item;
- char *x = "<";
- int a, i;
- for ( i = 0; i < def->columns->size; i++ ) {
- OUT( snprintf( buffer, limit, x ) );
- x = ",";
- OUT( columns[i]->tostring(
- columns[i], t->elements[i], buffer, limit ) );
- }
- OUT( snprintf( buffer, limit, ">" ) );
- return a;
-}
-
-ItemKeyFun TupleSchema_callbacks = {
- .hashcode = TupleSchema_hashcode,
- .haskey = TupleSchema_haskey,
- .itemkey = TupleSchema_itemkey,
- .releasekey = TupleSchema_releasekey,
- .tostring = TupleSchema_tostring
-};
-
-TupleSchema *TupleSchema_create(Tuple *columns) {
- TupleSchema *ts = (TupleSchema*) malloc( sizeof( TupleSchema ) );
- (*ts) = (TupleSchema) {
- .base = TupleSchema_callbacks,
- .columns = columns
- };
- return ts;
-}
-
-#define COPYA(T,P,N) (T*) memcpy( malloc( N * sizeof(T) ), P, N * sizeof( T ) )
-#define COPY(T,P) COPYA(T,P,1)
-
-// Duplicate a TupleSchema with optionally some columns reset.
-TupleSchema *TupleSchema_mask(TupleSchema *schema,...) {
- TupleSchema *masked = COPY(TupleSchema,schema);
- 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->columns->size ) {
- break;
- }
- masked->columns->elements[i] = 0;
- };
- va_end( ap );
- return masked;
-}
+++ /dev/null
-#ifndef tupleitem_H
-#define tupleitem_H
-
-#include <Tuple.h>
-
-/**
- * A TupleSchema record declares the ItemKeyFun functions for tuple
- * items together with applicable arity and domain combinations.
- * Records are created dynamically via the \ref TupleSchema_create
- * function or the \ref TUPLESCHEMA convenience macro.
- *
- * \extends ItemKeyFun
- */
-typedef struct TupleSchema {
- /**
- * These are the ItemKeyFun callback functions to support
- * HashVector use for tuple items. The functions expects their
- * ItemKeyFun pointer to be within a TupleSchema record so as to
- * provide the handling of the tuple columns.
- */
- ItemKeyFun base;
-
- /**
- * This points to tuple whose elements is array of pointers to the
- * tuple item domains as represented by their associated
- * ItemKeyFun records.
- */
- Tuple *columns;
-} TupleSchema;
-
-/**
- * Create a tuples with given values.
- *
- * \related TupleSchema
- */
-extern TupleSchema *TupleSchema_create(Tuple *columns);
-
-/**
- * Copy the given TupleSchema into a new TupleSchema with some columns
- * masked. This represents a sub-index type using the unmasked columns
- * for indexing.
- *
- * \related TupleSchema
- */
-extern TupleSchema *TupleSchema_mask(TupleSchema *schema,...);
-
-/**
- * \brief Return 1/0 to indicate whether the Query matches the item.
- *
- * \related TupleSchema
- */
-extern int TupleSchema_match(TupleSchema *def,Tuple *query,Tuple *item);
-
-/**
- * \brief Generic macro to determine the number of expressions in a
- * __VA_ARGS__
- *
- * \related TupleSchema
- */
-#define NUMARGS(...) (sizeof((void*[]){__VA_ARGS__})/sizeof(void*))
-
-/**
- * \brief Create a tuple with the given values.
- *
- * This invokes \ref tuple_create to allocate and assign a void*
- * array with the given values.
- *
- * \related TupleSchema
- */
-#define TUPLE(...) Tuple_create( NUMARGS(__VA_ARGS__), __VA_ARGS__ )
-
-/**
- * \brief Create a \ref TupleSchema with the given column "types".
- *
- * This invokes \ref TupleSchema_create to allocate and initialize a
- * \ref TupleSchema for the given columns via the \ref TUPLE macro.
- *
- * \related TupleSchema
- */
-#define TUPLESCHEMA(...) \
- TupleSchema_create( NUMARGS( __VA_ARGS__ ), TUPLE( __VA_ARGS__ ) )
-
-
-#endif
+++ /dev/null
-#include <integeritem.h>
-
-/**
- * This callback function returns 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 integeritem_hashcode(void *this,void *key) {
- return (unsigned long) key;
-}
-
-/**
- * This callback function determines whether an item has a
- * given key or not.
- */
-static int integeritem_haskey(void *this,void *item,void *key) {
- return item == key;
-}
-
-/**
- * This callback function returns the key of an item by considering
- * the arity and schema.
- */
-static void *integeritem_itemkey(void *this,void *item) {
- return item;
-}
-
-/**
- * This callback function handles a key obtained from the itemkey
- * callback function to reclaim temporary allocation.
- */
-static void integeritem_releasekey(void *this,void *key) {
-}
-
-/**
- * This callback function writes a representation of an item into
- * a character buffer.
- */
-static int integeritem_tostring(void *this,void *item,char *buffer,int limit) {
- return snprintf( buffer, limit, "%lld", (long long) item );
-}
-
-ItemKeyFun integeritem = {
- .hashcode = integeritem_hashcode,
- .haskey = integeritem_haskey,
- .itemkey = integeritem_itemkey,
- .releasekey = integeritem_releasekey,
- .tostring = integeritem_tostring
-};
+++ /dev/null
-#ifndef integeritem_H
-#define integeritem_H
-
-#include <ItemKeyFun.h>
-
-/**
- * The stringitem record declares the ItemKeyFun functions for integer
- * items.
- */
-extern ItemKeyFun integeritem;
-
-#endif
+++ /dev/null
-/** \mainpage rrq C hacks: Vectors And Such
-
-This software is an implementation platform for vector based
-representations.
-
-- \ref itemkeyfun is an implementation of an abstracted type notion
- that is focussed on what the \ref hashvector needs in terms of
- callbacks for its separation between the hash management
- functionality and the contained items. This name is choosen so as to
- avoid some connotations common to the term "type".
-
-- \ref array and \ref vector are two implementations of an abstract
- array notion using an indexing tree of 16 and 256 pointers
- respectively. The indexing tree is balanced into levels matching to
- the needs of the vector size. When the size of a vector is changed
- then indexing levels are added or removed as needed. However
- indexing pages are allocated on a needs basis. The level 0 indexing
- pages hold the actual data as void* pointers
-
-- \ref hasharray and \ref hashvector are two implementations of an
- abstract hashtable using \ref array and \ref vector as backing store
- respectively. It also uses the \ref itemkeyfn type abstraction of
- items being compunded as pairs of key and payload. This separates
- the hashing code from the type abstraction.
-
-\subsubsection s0 itemkeyfun actualizations
-
-- \ref integeritem is an plain actualization of an itemkeyfun record
- for integer items other than 0 and 1, i.e. where the void* slots of
- a tuple are reinterpreted as 64-bit integers rather than "item
- pointers".
-
-\note Note that a hashvector cannot directly contain integer items
- since 0 and 1 are treated as indicating unused and holed slots.
-
-- stringitem is a plain actualization of an itemkeyfun record for
- null-terminated character strings.
-
-- tupleschema is a specialization of the itemkeyfun type scheme
- intended for tuple items that are arrays of items that are further
- type via itemkeyfun records. A tupleschema actualization includes
- the applicable arity and an array of pointers to itemkeyfun
- actualizations that declare the itemkeyfun types of the parts
- (columns).
-
-*/
+++ /dev/null
-#include <string.h>
-#include <stringitem.h>
-#include <HashVector.h>
-
-/**
- * This callback function returns 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 stringitem_hashcode(void *this,void *key) {
- return HashVector_hashcode( (unsigned char*)key, strlen( (char*)key ) );
-}
-
-/**
- * This callback function determines whether an item has a
- * given key or not.
- */
-static int stringitem_haskey(void *this,void *item,void *key) {
- return strcmp( item, key ) == 0;
-}
-
-/**
- * This callback function returns the key of an item by considering
- * the arity and schema.
- */
-static void *stringitem_itemkey(void *this,void *item) {
- return item;
-}
-
-/**
- * This callback function handles a key obtained from the itemkey
- * callback function to reclaim temporary allocation.
- */
-static void stringitem_releasekey(void *this,void *key) {
-}
-
-/**
- * This callback function writes a representation of an item into
- * a character buffer.
- */
-static int stringitem_tostring(void *this,void *item,char *buffer,int limit) {
- if ( item ) {
- return snprintf( buffer, limit, "\"%s\"", (char*) item );
- }
- return snprintf( buffer, limit, "(null)" );
-}
-
-ItemKeyFun stringitem = {
- .hashcode = stringitem_hashcode,
- .haskey = stringitem_haskey,
- .itemkey = stringitem_itemkey,
- .releasekey = stringitem_releasekey,
- .tostring = stringitem_tostring
-};
+++ /dev/null
-#ifndef stringitem_H
-#define stringitem_H
-
-#include <ItemKeyFun.h>
-
-/**
- * The stringitem record declares the ItemKeyFun functions for string
- * items.
- */
-extern ItemKeyFun stringitem;
-
-#endif