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