refactoring
[rrq/rrqmisc.git] / vector / TupleSchema.c
1 #include <stdarg.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <TupleSchema.h>
5
6 /**
7  * This callback function returns the hashcode of a key.
8  *
9  * \param this is a pointer to the ItemKeyFun record from where this
10  * callback got invoked
11  *
12  * \param key is the key to produce a hascode for
13  *
14  * \returns the hashcode which is a VectorIndex (i.e. unsigned long)
15  *
16  * The hashcode is used for indexing into the backing Vector for
17  * finding the an item via its key. The same key must map consistently
18  * to the same hashcode while the hashtable contains an item with that
19  * key. Different keys map map to the same hashcode, in which case the
20  * Vector placement is made at the first empty or hole slot following
21  * the hashcode index.
22  */
23 static unsigned long TupleSchema_hashcode(void *this,void *key) {
24     TupleSchema *def = (TupleSchema *) this;
25     ItemKeyFun **columns = (ItemKeyFun**) def->columns->elements;
26     Tuple *kp = (Tuple*) key;
27     int i = 0;
28     unsigned long value = 5381;
29     for ( ; i < def->columns->size; i++ ) {
30         if ( columns[i] ) {
31             value <<= 3;
32             if ( kp->elements[i] ) {
33                 value += columns[i]->hashcode( columns[i], kp->elements[i] );
34             }
35         }
36         value += 17;
37     }
38     return value;
39 }
40
41 /**
42  * This callback function determines whether an item has a
43  * given key or not.
44  */
45 static int TupleSchema_haskey(void *this,void *item,void *key) {
46     TupleSchema *def = (TupleSchema *) this;
47     ItemKeyFun **columns = (ItemKeyFun**) def->columns->elements;
48     Tuple *kp = (Tuple*) key;
49     Tuple *tp = (Tuple*) item;
50     int i = 0;
51     for ( ; i < def->columns->size; i++ ) {
52         if ( columns[i] && kp->elements[i] ) {
53             if ( columns[i]->haskey(
54                      columns[i], tp->elements[i], kp->elements[i] ) == 0 ) {
55                 return 0;
56             }
57         }
58     }
59     return 1;
60 }
61
62
63 /**
64  * This callback function returns the key of an item by considering
65  * the arity and mask.
66  */
67 static void *TupleSchema_itemkey(void *this,void *item) {
68     TupleSchema *def = (TupleSchema *) this;
69     ItemKeyFun **columns = (ItemKeyFun**) def->columns->elements;
70     Tuple *tp = (Tuple*) item;
71     Tuple *key = Tuple_clone( tp );
72     int i;
73     for ( i = 0; i < def->columns->size; i++ ) {
74         if ( columns[i] ) {
75             key->elements[i] = columns[i]->itemkey(
76                 columns[i], tp->elements[i] );
77         } else {
78             key->elements[i] = 0;
79         }
80     }
81     return (void*) key;
82 }
83
84 /**
85  * This callback function handles a key obtained from the itemkey
86  * callback function to reclaim temporary allocation.
87  */
88 static void TupleSchema_releasekey(void *this,void *key) {
89     TupleSchema *def = (TupleSchema *) this;
90     ItemKeyFun **columns = (ItemKeyFun**) def->columns->elements;
91     Tuple *kp = (Tuple*) key;
92     int i;
93     for ( i = 0; i < def->columns->size; i++ ) {
94         if ( columns[i] ) {
95             columns[i]->releasekey( columns[i], kp->elements[i] );
96         }
97     }
98     free( key );
99 }
100
101 #define OUT(X) a = X; if ( a > limit ) return 0; buffer += a; limit -= a
102
103 /**
104  * This callback function writes a representation of an item into
105  * a character buffer.
106  */
107 static int TupleSchema_tostring(void *this,void *item,char *buffer,int limit) {
108     TupleSchema *def = (TupleSchema *) this;
109     ItemKeyFun **columns = (ItemKeyFun**) def->columns->elements;
110     Tuple *t = (Tuple*) item;
111     char *x = "<";
112     int a, i;
113     for ( i = 0; i < def->columns->size; i++ ) {
114         OUT( snprintf( buffer, limit, x ) );
115         x = ",";
116         OUT( columns[i]->tostring(
117                  columns[i], t->elements[i], buffer, limit ) );
118     }
119     OUT( snprintf( buffer, limit, ">" ) );
120     return a;
121 }
122
123 ItemKeyFun TupleSchema_callbacks = {
124     .hashcode = TupleSchema_hashcode,
125     .haskey = TupleSchema_haskey,
126     .itemkey = TupleSchema_itemkey,
127     .releasekey = TupleSchema_releasekey,
128     .tostring = TupleSchema_tostring
129 };
130
131 TupleSchema *TupleSchema_create(Tuple *columns) {
132     TupleSchema *ts = (TupleSchema*) malloc( sizeof( TupleSchema ) );
133     (*ts) = (TupleSchema) {
134         .base = TupleSchema_callbacks,
135         .columns = columns
136     };
137     return ts;
138 }
139
140 #define COPYA(T,P,N) (T*) memcpy( malloc( N * sizeof(T) ), P, N * sizeof( T ) )
141 #define COPY(T,P) COPYA(T,P,1)
142
143 // Duplicate a TupleSchema with optionally some columns reset.
144 TupleSchema *TupleSchema_mask(TupleSchema *schema,...) {
145     TupleSchema *masked = COPY(TupleSchema,schema);
146     masked->columns = Tuple_clone( schema->columns );
147     va_list ap;
148     int i;
149     va_start( ap, schema );
150     for ( ;; ) {
151         i = va_arg( ap, int );
152         if ( i < 0 || i >= schema->columns->size ) {
153             break;
154         }
155         masked->columns->elements[i] = 0;
156     };
157     va_end( ap );
158     return masked;
159 }