}
}
-// Find the keyed element, and assign the x pointer, or assign 0.
-// Returns 1 if element is found and 0 otherwise.
-int hashvector_find(hashvector *hv,void *key,void **x) {
- unsigned long i;
- void **p = hashvector_find_slot( hv, key, &i, 0 );
- if ( p && *p && *p != HV_HOLE ) {
- if ( x ) {
- *x = *p;
+// Find the keyed element at or after the index. Update index and
+// return item.
+void *hashvector_next(hashvector *hv,vector_index *index,void *key) {
+ unsigned long i = index? *index : 0;
+ for ( ; i < hv->table.size; i++ ) {
+ void **p = hashvector_find_slot( hv, key, &i, 0 );
+ if ( p == 0 ) {
+ break;
}
- return 1;
+ if ( *p && *p != HV_HOLE ) {
+ if ( key && hv->type->haskey( hv->type, key, *p ) == 0 ) {
+ continue;
+ }
+ if ( index ) {
+ (*index) = i;
+ }
+ return *p;
+ }
+ }
+ if ( index ) {
+ (*index) = hv->table.size;
}
return 0;
}
}
-hashvector *hashvector_create(int variant,itemkeyfun *type) {
+hashvector *hashvector_create(enum vector_variant variant,itemkeyfun *type) {
hashvector *hv = (hashvector*) malloc( sizeof( hashvector ) );
(*hv) = (hashvector) {
.table = (vector) {
#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 nominated
// column indexes being the value part. the key must be a clone of the
// relation columns but with some columns reset.
-int relation_addindex(relation *r,tupleschema *key) {
- tupleschema *primary = r->columns;
+int relation_add_contraint(relation *r,tupleschema *key) {
+ tupleschema *primary = (tupleschema *) r->content.type;
if ( primary->arity != key->arity ) {
- return -1;
+ return -1; // no good
}
int i = 0;
for ( ; i < primary->arity; i++ ) {
return -1;
}
}
- i = (int) r->indexes.size;
- vector_append( &r->indexes, hashvector_create( 1, (itemkeyfun*) key ) );
+ i = (int) r->constraints.size;
+ vector_append(
+ &r->constraints,
+ hashvector_create( nibble_index_levels, &key->base ) );
return i;
}
-relation *relation_create(int arity,tupleschema *schema) {
- relation *r = (relation *) malloc( sizeof( relation ) );
- (*r) = (relation) {
- .indexes = {
- .variant = 2,
- .size = 0,
- .entries = 0
- },
- .columns = schema
- };
- return r;
-}
-
+//============== Adding an item =============
// Iteration context for adding or querying a relation
typedef struct {
- itemkeyfun *columns;
+ relation *rel;
vector knockouts;
- void *key;
-} knockoutdata;
+ void *item;
+} knockout;
-// Determine matches to ((knockoutdata*)data)->key in
-// (hashvector*)item, optionally using ((knockoutdata*)data)->columns
+// 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(vector_index index,void *item,void *data) {
- knockoutdata *kod = (knockoutdata*) data;
- void *old = 0;
- if ( hashvector_find( (hashvector*) item, kod->key, &old ) ) {
- if ( kod->columns == 0 ||
- kod->columns->haskey( kod->columns, old, kod->key ) == 0 ) {
- if ( vector_find( &kod->knockouts, old ) >= kod->knockouts.size ) {
- vector_append( &kod->knockouts, old );
- }
- }
+ knockout *kod = (knockout*) data;
+ void *old = hashvector_next( (hashvector*) item, 0, kod->item );
+ if ( old ) {
+ vector_append( &kod->knockouts, old );
}
return 0;
}
return 0;
}
-// 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 *x) {
- knockoutdata data = {
- .columns = &(r->columns->functions),
- .knockouts = { .variant = 2, .size = 0, .entries = 0 },
- .key = x
+// 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 = {
+ .variant = bitpair_index_levels,
+ .size = 0, .entries = 0
+ },
+ .item = item
};
- // Find all knockouts
- vector_iterate( &r->indexes, 0, knockout_check, &data );
- // Delete them
- vector_iterate( &r->indexes, 0, knockout_delete, &data.knockouts );
- // Add the new tuple
- vector_iterate( &r->indexes, 0, knockout_add, x );
- if ( data.knockouts.size == 0 ) {
+ knockout_check( 0, &r->content, this );
+ if ( add && this->knockouts.size > 0 ) {
return 0;
}
- return vector_clone( 3, &data.knockouts );
+ // Find all constraint knockouts
+ vector_iterate( &r->constraints, 0, knockout_check, this );
+ if ( this->knockouts.size > 0 ) {
+ // Delete them from all tables
+ vector_iterate(
+ &this->knockouts, 0, knockout_delete_item, &r->content );
+ vector_iterate(
+ &r->constraints, 0, knockout_delete, &this->knockouts );
+ }
+ 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 );
+ if ( data.knockouts.size > 0 ) {
+ return vector_clone( single_index_level, &data.knockouts );
+ }
+ }
+ return 0;
+}
+
+vector *relation_delete(relation *r,tuple *item) {
+ knockout data;
+ (void) knockout_clear( &data, r, item, 0 );
+ if ( data.knockouts.size > 0 ) {
+ return vector_clone( single_index_level, &data.knockouts );
+ }
+ return 0;
}
+void *relation_next(relation *r,vector_index *index,tuple *query) {
+ return hashvector_next( &r->content, index, query );
+}
#include <tupleitem.h>
/**
- * A relation is an implementation of a tuple set with a primary key
- * through a hashvector whose "type" defines the key. Additional
- * hashvectors may be added to impose additional key restrictions and
- * the final relation is the intersection of them all.
- *
- * The relation record itself holds the column schema whereas the
- * indexes hold key schemas that in practice are copies of the column
- * schema with some columns blanked out.
+ * A relation is an implementation of a tuple set with (optinal) key
+ * constraints. The store is a hashvector whose "type" is a
+ * tupleschema that defines the columns. The key constraints are
+ * represented as additional hashvectors whose tupleschemas are clones
+ * of the column schema with some columns excluded.
*/
typedef struct {
- vector indexes; // one or more indexes over the tuple collection
- tupleschema *columns;
+ /**
+ * 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;
/**
- * Create a relation of the given arity and tupleschema.
+ * Create a relation for the given tupleschema.
*/
-extern relation *relation_create(int arity,tupleschema *schema);
+extern relation *relation_create(tupleschema *schema);
/**
* Add a a key index to the relation by identifying the value part for
/**
- * Add a tuple to a relation.
+ * \brief Add a tuple to a relation.
+ * \param r is th relation concerned.
+ * \param t is the tuple to add.
+ *
* \returns a vector of all knocked out tuples.
*/
extern vector *relation_add(relation *r,tuple *t);
+/**
+ * \brief Delete all tuples matching to the query.
+ * \returns all deleted tuples.
+ */
+extern vector *relation_delete(relation *r,tuple *query);
+
+/**
+ * \brief Return next tuple matching the query at or after the index.
+ * \returns any such matching tuple and updates *index to its index.
+ */
+extern void *relation_next(relation *r,vector_index *index,tuple *query);
+
#endif