revamp relation implementation
[rrq/rrqmisc.git] / vector / relation.c
index 330b3def071f70feec70438e4aa6fa95f212628d..8ab343f6cb739104768bd02116a5472f9ce8dfee 100644 (file)
@@ -1,16 +1,36 @@
 #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++ ) {
@@ -18,44 +38,29 @@ int relation_addindex(relation *r,tupleschema *key) {
            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;
 }
@@ -78,23 +83,58 @@ static int knockout_add(vector_index index,void *item,void *data) {
     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 );
+}