blob: ba318cdf8c99b2f03f9a839d97ed78bef0deec88 [file] [log] [blame]
Juan Cespedescac15c32003-01-31 18:58:58 +01001#include <stdio.h>
2#include <stdlib.h>
Juan Cespedes7186e2a2003-01-31 19:56:34 +01003#include <string.h>
Juan Cespedesa0ccf392003-02-01 19:02:37 +01004#include <assert.h>
Juan Cespedescac15c32003-01-31 18:58:58 +01005
Juan Cespedes8d1b92b2009-07-03 10:39:34 +02006#include "common.h"
Juan Cespedescac15c32003-01-31 18:58:58 +01007
8/*
9 Dictionary based on code by Morten Eriksen <mortene@sim.no>.
10*/
11
Juan Cespedescac15c32003-01-31 18:58:58 +010012struct dict_entry {
13 unsigned int hash;
Ian Wienand2d45b1a2006-02-20 22:48:07 +010014 void *key;
15 void *value;
16 struct dict_entry *next;
Juan Cespedescac15c32003-01-31 18:58:58 +010017};
18
19/* #define DICTTABLESIZE 97 */
Ian Wienand2d45b1a2006-02-20 22:48:07 +010020#define DICTTABLESIZE 997 /* Semi-randomly selected prime number. */
Juan Cespedescac15c32003-01-31 18:58:58 +010021/* #define DICTTABLESIZE 9973 */
22/* #define DICTTABLESIZE 99991 */
23/* #define DICTTABLESIZE 999983 */
24
25struct dict {
Ian Wienand2d45b1a2006-02-20 22:48:07 +010026 struct dict_entry *buckets[DICTTABLESIZE];
27 unsigned int (*key2hash) (void *);
28 int (*key_cmp) (void *, void *);
Juan Cespedescac15c32003-01-31 18:58:58 +010029};
30
Juan Cespedes8d1b92b2009-07-03 10:39:34 +020031Dict *
Juan Cespedesf1350522008-12-16 18:19:58 +010032dict_init(unsigned int (*key2hash) (void *),
33 int (*key_cmp) (void *, void *)) {
Juan Cespedes8d1b92b2009-07-03 10:39:34 +020034 Dict *d;
Juan Cespedescac15c32003-01-31 18:58:58 +010035 int i;
36
Juan Cespedescd8976d2009-05-14 13:47:58 +020037 debug(DEBUG_FUNCTION, "dict_init()");
38
Juan Cespedes8d1b92b2009-07-03 10:39:34 +020039 d = malloc(sizeof(Dict));
Juan Cespedescac15c32003-01-31 18:58:58 +010040 if (!d) {
41 perror("malloc()");
42 exit(1);
43 }
Ian Wienand2d45b1a2006-02-20 22:48:07 +010044 for (i = 0; i < DICTTABLESIZE; i++) { /* better use memset()? */
Juan Cespedescac15c32003-01-31 18:58:58 +010045 d->buckets[i] = NULL;
46 }
47 d->key2hash = key2hash;
48 d->key_cmp = key_cmp;
49 return d;
50}
51
Juan Cespedesf1350522008-12-16 18:19:58 +010052void
Juan Cespedes8d1b92b2009-07-03 10:39:34 +020053dict_clear(Dict *d) {
Juan Cespedescac15c32003-01-31 18:58:58 +010054 int i;
Ian Wienand2d45b1a2006-02-20 22:48:07 +010055 struct dict_entry *entry, *nextentry;
Juan Cespedescac15c32003-01-31 18:58:58 +010056
Juan Cespedescd8976d2009-05-14 13:47:58 +020057 debug(DEBUG_FUNCTION, "dict_clear()");
Juan Cespedesa0ccf392003-02-01 19:02:37 +010058 assert(d);
Juan Cespedescac15c32003-01-31 18:58:58 +010059 for (i = 0; i < DICTTABLESIZE; i++) {
60 for (entry = d->buckets[i]; entry != NULL; entry = nextentry) {
61 nextentry = entry->next;
62 free(entry);
63 }
64 d->buckets[i] = NULL;
65 }
66 free(d);
67}
68
Juan Cespedesf1350522008-12-16 18:19:58 +010069int
Juan Cespedes8d1b92b2009-07-03 10:39:34 +020070dict_enter(Dict *d, void *key, void *value) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +010071 struct dict_entry *entry, *newentry;
Juan Cespedescd8976d2009-05-14 13:47:58 +020072 unsigned int hash;
73 unsigned int bucketpos;
74
75 debug(DEBUG_FUNCTION, "dict_enter()");
76
77 hash = d->key2hash(key);
78 bucketpos = hash % DICTTABLESIZE;
Juan Cespedescac15c32003-01-31 18:58:58 +010079
Juan Cespedesa0ccf392003-02-01 19:02:37 +010080 assert(d);
Juan Cespedescac15c32003-01-31 18:58:58 +010081 newentry = malloc(sizeof(struct dict_entry));
82 if (!newentry) {
83 perror("malloc");
84 exit(1);
85 }
86
Ian Wienand2d45b1a2006-02-20 22:48:07 +010087 newentry->hash = hash;
88 newentry->key = key;
Juan Cespedescac15c32003-01-31 18:58:58 +010089 newentry->value = value;
Ian Wienand2d45b1a2006-02-20 22:48:07 +010090 newentry->next = NULL;
Juan Cespedescac15c32003-01-31 18:58:58 +010091
92 entry = d->buckets[bucketpos];
Ian Wienand2d45b1a2006-02-20 22:48:07 +010093 while (entry && entry->next)
94 entry = entry->next;
Juan Cespedescac15c32003-01-31 18:58:58 +010095
Ian Wienand2d45b1a2006-02-20 22:48:07 +010096 if (entry)
97 entry->next = newentry;
98 else
99 d->buckets[bucketpos] = newentry;
Juan Cespedescac15c32003-01-31 18:58:58 +0100100
Ian Wienand9a2ad352006-02-20 22:44:45 +0100101 debug(3, "new dict entry at %p[%d]: (%p,%p)", d, bucketpos, key, value);
Juan Cespedescac15c32003-01-31 18:58:58 +0100102 return 0;
103}
104
Juan Cespedesf1350522008-12-16 18:19:58 +0100105void *
Juan Cespedes8d1b92b2009-07-03 10:39:34 +0200106dict_find_entry(Dict *d, void *key) {
Juan Cespedescd8976d2009-05-14 13:47:58 +0200107 unsigned int hash;
108 unsigned int bucketpos;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100109 struct dict_entry *entry;
Juan Cespedescac15c32003-01-31 18:58:58 +0100110
Juan Cespedescd8976d2009-05-14 13:47:58 +0200111 debug(DEBUG_FUNCTION, "dict_find_entry()");
112
113 hash = d->key2hash(key);
114 bucketpos = hash % DICTTABLESIZE;
115
Juan Cespedesa0ccf392003-02-01 19:02:37 +0100116 assert(d);
Juan Cespedescac15c32003-01-31 18:58:58 +0100117 for (entry = d->buckets[bucketpos]; entry; entry = entry->next) {
118 if (hash != entry->hash) {
119 continue;
120 }
121 if (!d->key_cmp(key, entry->key)) {
122 break;
123 }
124 }
125 return entry ? entry->value : NULL;
126}
127
128void
Juan Cespedes8d1b92b2009-07-03 10:39:34 +0200129dict_apply_to_all(Dict *d,
Juan Cespedesf1350522008-12-16 18:19:58 +0100130 void (*func) (void *key, void *value, void *data), void *data) {
Juan Cespedescac15c32003-01-31 18:58:58 +0100131 int i;
132
Juan Cespedescd8976d2009-05-14 13:47:58 +0200133 debug(DEBUG_FUNCTION, "dict_apply_to_all()");
134
Juan Cespedesefe85f02004-04-04 01:31:38 +0200135 if (!d) {
136 return;
137 }
Juan Cespedescac15c32003-01-31 18:58:58 +0100138 for (i = 0; i < DICTTABLESIZE; i++) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100139 struct dict_entry *entry = d->buckets[i];
Juan Cespedescac15c32003-01-31 18:58:58 +0100140 while (entry) {
141 func(entry->key, entry->value, data);
142 entry = entry->next;
143 }
144 }
145}
146
147/*****************************************************************************/
148
Juan Cespedesf1350522008-12-16 18:19:58 +0100149unsigned int
150dict_key2hash_string(void *key) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100151 const char *s = (const char *)key;
Juan Cespedescac15c32003-01-31 18:58:58 +0100152 unsigned int total = 0, shift = 0;
153
Juan Cespedesa0ccf392003-02-01 19:02:37 +0100154 assert(key);
Juan Cespedescac15c32003-01-31 18:58:58 +0100155 while (*s) {
156 total = total ^ ((*s) << shift);
157 shift += 5;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100158 if (shift > 24)
159 shift -= 24;
Juan Cespedescac15c32003-01-31 18:58:58 +0100160 s++;
161 }
162 return total;
163}
164
Juan Cespedesf1350522008-12-16 18:19:58 +0100165int
166dict_key_cmp_string(void *key1, void *key2) {
Juan Cespedesa0ccf392003-02-01 19:02:37 +0100167 assert(key1);
168 assert(key2);
Juan Cespedescac15c32003-01-31 18:58:58 +0100169 return strcmp((const char *)key1, (const char *)key2);
170}
171
Juan Cespedesf1350522008-12-16 18:19:58 +0100172unsigned int
173dict_key2hash_int(void *key) {
Juan Cespedesd914a202004-11-10 00:15:33 +0100174 return (unsigned long)key;
Juan Cespedescac15c32003-01-31 18:58:58 +0100175}
176
Juan Cespedesf1350522008-12-16 18:19:58 +0100177int
178dict_key_cmp_int(void *key1, void *key2) {
Juan Cespedescac15c32003-01-31 18:58:58 +0100179 return key1 - key2;
180}
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200181
Juan Cespedes8d1b92b2009-07-03 10:39:34 +0200182Dict *
Petr Machata534e00f2011-09-27 17:58:38 +0200183dict_clone2(Dict * old, void * (*key_clone)(void *, void *),
184 void * (*value_clone)(void *, void *), void * data)
185{
Juan Cespedes8d1b92b2009-07-03 10:39:34 +0200186 Dict *d;
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200187 int i;
188
Juan Cespedescd8976d2009-05-14 13:47:58 +0200189 debug(DEBUG_FUNCTION, "dict_clone()");
190
Juan Cespedes8d1b92b2009-07-03 10:39:34 +0200191 d = malloc(sizeof(Dict));
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200192 if (!d) {
193 perror("malloc()");
194 exit(1);
195 }
Juan Cespedes8d1b92b2009-07-03 10:39:34 +0200196 memcpy(d, old, sizeof(Dict));
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200197 for (i = 0; i < DICTTABLESIZE; i++) { /* better use memset()? */
198 struct dict_entry *de_old;
199 struct dict_entry **de_new;
200
201 de_old = old->buckets[i];
202 de_new = &d->buckets[i];
203 while (de_old) {
Petr Machata534e00f2011-09-27 17:58:38 +0200204 void * nkey, * nval;
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200205 *de_new = malloc(sizeof(struct dict_entry));
206 if (!*de_new) {
207 perror("malloc()");
208 exit(1);
209 }
210 memcpy(*de_new, de_old, sizeof(struct dict_entry));
Petr Machata534e00f2011-09-27 17:58:38 +0200211
212 /* The error detection is rather weak :-/ */
213 nkey = key_clone(de_old->key, data);
214 if (nkey == NULL && de_old->key != NULL) {
215 perror("key_clone");
216 err:
217 /* XXX Will this actually work? We
218 * simply memcpy the old dictionary
219 * over up there. */
220 dict_clear(d);
221 free(de_new);
222 return NULL;
223 }
224
225 nval = value_clone(de_old->value, data);
226 if (nval == NULL && de_old->value != NULL) {
227 perror("value_clone");
228 goto err;
229 }
230
231 (*de_new)->key = nkey;
232 (*de_new)->value = nval;
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200233 de_new = &(*de_new)->next;
234 de_old = de_old->next;
235 }
236 }
237 return d;
238}
Petr Machata534e00f2011-09-27 17:58:38 +0200239
240struct wrap_clone_cb
241{
242 void * (*key_clone)(void *);
243 void * (*value_clone)(void *);
244};
245
246static void *
247value_clone_1(void * arg, void * data)
248{
249 return ((struct wrap_clone_cb *)data)->value_clone(arg);
250}
251
252static void *
253key_clone_1(void * arg, void * data)
254{
255 return ((struct wrap_clone_cb *)data)->key_clone(arg);
256}
257
258Dict *
259dict_clone(Dict * old, void * (*key_clone)(void *),
260 void * (*value_clone)(void *))
261{
262 struct wrap_clone_cb cb = { key_clone, value_clone };
263 return dict_clone2(old, &key_clone_1, &value_clone_1, &cb);
264}