Cleanup Tuple to allow self-typing.
[rrq/rrqmisc.git] / vector / BindingTable.c
1 #include <BindingTable.h>
2 #include <string.h>
3 #include <stdlib.h>
4
5 /**
6  * A Binding is an association between a name (char*) and a value
7  * (void*).
8  */
9 typedef struct {
10     char *name;
11     void *value;
12 } Binding;
13
14 /**
15  * This callback function should return the hashcode of a key. The
16  * hashcode is used for indexing into the backing Vector for
17  * finding the an item via its key. The same key must map
18  * consistently to the same hashcode while the hashtable contains
19  * an item with that key. Different keys map map to the same
20  * hashcode, in which case the Vector placement is made at the
21  * first empty or hole slot following the hashcode index.
22  */
23 static unsigned long binding_hashcode(void *this,void *key) {
24     char *name = (char *) key;
25     unsigned long n = strlen( name );
26     return HashVector_hashcode( (unsigned char *) name, n );
27 }
28
29 /**
30  * This callback function should determine whether an item has a
31  * given key or not.
32  */
33 static int binding_haskey(void *this,void *item,void *key) {
34     Binding *b = (Binding*) item;
35     char *name = (char *) key;
36     return strcmp( name, (char*) b->name ) == 0;
37 }
38
39 /**
40  * This callback function should return a (possibly temporary) key
41  * of an item. It can be anything (i.e., with or without internal
42  * structure) as it is treated as an identifier that other
43  * callbacks recognize. It is merely understood as a value in an
44  * identity domain.
45  */
46 static void *binding_itemkey(void *this,void *item) {
47     Binding *b = (Binding*) item;
48     return b->name;
49 }
50     
51
52 /**
53  * This callback function should handle a key obtained from the
54  * itemkey callback function, e.g., reclaim temporary allocation.
55  */
56 static void binding_releasekey(void *this,void *key) {
57 }
58
59 /**
60  * This callback function writes a representation of an item into
61  * a character buffer.
62  */
63 static int binding_tostring(void *this,void *item,char *buffer,int limit) {
64     Binding *b = (Binding*) item;
65     return snprintf( buffer, limit, "{%s,%p}", b->name, b->value );
66 }
67
68 /**
69  * This is the "item type" for Binding items.
70  */
71 ItemKeyFun bindingitem = {
72     .hashcode = binding_hashcode,
73     .haskey = binding_haskey,
74     .itemkey = binding_itemkey,
75     .releasekey = binding_releasekey,
76     .tostring = binding_tostring
77 };
78
79 BindingTable *BindingTable_create(BindingTable *next) {
80     BindingTable *this = (BindingTable*) malloc( sizeof( BindingTable ) );
81     this->table = (HashVector) {
82         .table = (Vector) {
83             .variant = Nibble_index_levels, .size = 16, .entries = 0
84         }, .fill = 0, .holes = 0, .type = &bindingitem
85     };
86     this->next = next;
87     return this;
88 }
89
90 BindingTable *BindingTable_release(BindingTable *bt) {
91     if ( bt ) {
92         BindingTable *next = bt->next;
93         Vector_resize( &bt->table.table, 0, Vector_free_any, 0 );
94         free( bt );
95         return next;
96     }
97     return 0;
98 }
99
100 void BindingTable_set(BindingTable *bt,char *name,void *value) {
101     Binding *b = (Binding*) HashVector_find( &bt->table, name );
102     if ( b == 0 ) {
103         b = (Binding*) malloc( sizeof( Binding ) );
104         b->name = name;
105         HashVector_add( &bt->table, b );
106     }
107     b->value = value;
108 }
109
110 void *BindingTable_get(BindingTable *bt,char *name) {
111     for ( ; bt; bt = bt->next ) {
112         Binding *b = (Binding*) HashVector_find( &bt->table, name );
113         if ( b ) {
114             return b->value;
115         }
116     }
117     return 0;
118 }
119
120 void BindingTable_deref(BindingTable *bt,int arity,Tuple *t) {
121     int i;
122     for ( i = 0; i < arity; i++ ) {
123         if ( t->elements[i] ) {
124             t->elements[i] = BindingTable_get( bt, t->elements[i] );
125         }
126     }
127 }
128
129 int BindingTable_unify(
130     BindingTable *bt,char *n1,char *n2,int (*eq)(void*,void*)) {
131     void *v1 = BindingTable_get( bt, n1 );
132     void *v2 = BindingTable_get( bt, n2 );
133     if ( v2 && v1 == 0 ) {
134         BindingTable_set( bt, n1, v2 );
135     }
136     if ( v1 && v2 == 0 ) {
137         BindingTable_set( bt, n2, v1 );
138     }
139     return ( v1 && v2 )? ( eq? ( eq( v1, v2 ) == 0 ) : ( v1 == v2 ) ) : 1;
140 }
141
142 #define COPYA(T,P,N) (T*) memcpy( malloc( N * sizeof(T) ), P, N * sizeof( T ) )
143
144 Tuple *BindingTable_tuple_get(BindingTable *bt,int arity,Tuple *t) {
145     Tuple *vt = Tuple_clone( arity, t );
146     BindingTable_deref( bt, arity, vt );
147     return vt;
148 }
149
150 void BindingTable_tuple_set(BindingTable *bt,int arity,Tuple *nm,Tuple *vs) {
151     int i;
152     for ( i = 0; i < arity; i++ ) {
153         BindingTable_set( bt, nm->elements[i], vs->elements[i] );
154     }
155 }