blob: b32ef8ee4b146d14d00a4da53f26e86ad8ae8928 [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];
Petr Machata345c9b52012-02-10 13:10:03 +010027 unsigned int (*key2hash) (const void *);
28 int (*key_cmp) (const void *, const void *);
Juan Cespedescac15c32003-01-31 18:58:58 +010029};
30
Juan Cespedes8d1b92b2009-07-03 10:39:34 +020031Dict *
Petr Machata345c9b52012-02-10 13:10:03 +010032dict_init(unsigned int (*key2hash) (const void *),
33 int (*key_cmp) (const void *, const void *))
34{
Juan Cespedes8d1b92b2009-07-03 10:39:34 +020035 Dict *d;
Juan Cespedescac15c32003-01-31 18:58:58 +010036 int i;
37
Juan Cespedescd8976d2009-05-14 13:47:58 +020038 debug(DEBUG_FUNCTION, "dict_init()");
39
Juan Cespedes8d1b92b2009-07-03 10:39:34 +020040 d = malloc(sizeof(Dict));
Juan Cespedescac15c32003-01-31 18:58:58 +010041 if (!d) {
42 perror("malloc()");
43 exit(1);
44 }
Ian Wienand2d45b1a2006-02-20 22:48:07 +010045 for (i = 0; i < DICTTABLESIZE; i++) { /* better use memset()? */
Juan Cespedescac15c32003-01-31 18:58:58 +010046 d->buckets[i] = NULL;
47 }
48 d->key2hash = key2hash;
49 d->key_cmp = key_cmp;
50 return d;
51}
52
Juan Cespedesf1350522008-12-16 18:19:58 +010053void
Juan Cespedes8d1b92b2009-07-03 10:39:34 +020054dict_clear(Dict *d) {
Juan Cespedescac15c32003-01-31 18:58:58 +010055 int i;
Ian Wienand2d45b1a2006-02-20 22:48:07 +010056 struct dict_entry *entry, *nextentry;
Juan Cespedescac15c32003-01-31 18:58:58 +010057
Juan Cespedescd8976d2009-05-14 13:47:58 +020058 debug(DEBUG_FUNCTION, "dict_clear()");
Juan Cespedesa0ccf392003-02-01 19:02:37 +010059 assert(d);
Juan Cespedescac15c32003-01-31 18:58:58 +010060 for (i = 0; i < DICTTABLESIZE; i++) {
61 for (entry = d->buckets[i]; entry != NULL; entry = nextentry) {
62 nextentry = entry->next;
63 free(entry);
64 }
65 d->buckets[i] = NULL;
66 }
67 free(d);
68}
69
Juan Cespedesf1350522008-12-16 18:19:58 +010070int
Juan Cespedes8d1b92b2009-07-03 10:39:34 +020071dict_enter(Dict *d, void *key, void *value) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +010072 struct dict_entry *entry, *newentry;
Juan Cespedescd8976d2009-05-14 13:47:58 +020073 unsigned int hash;
74 unsigned int bucketpos;
75
76 debug(DEBUG_FUNCTION, "dict_enter()");
77
78 hash = d->key2hash(key);
79 bucketpos = hash % DICTTABLESIZE;
Juan Cespedescac15c32003-01-31 18:58:58 +010080
Juan Cespedesa0ccf392003-02-01 19:02:37 +010081 assert(d);
Juan Cespedescac15c32003-01-31 18:58:58 +010082 newentry = malloc(sizeof(struct dict_entry));
83 if (!newentry) {
84 perror("malloc");
85 exit(1);
86 }
87
Ian Wienand2d45b1a2006-02-20 22:48:07 +010088 newentry->hash = hash;
89 newentry->key = key;
Juan Cespedescac15c32003-01-31 18:58:58 +010090 newentry->value = value;
Ian Wienand2d45b1a2006-02-20 22:48:07 +010091 newentry->next = NULL;
Juan Cespedescac15c32003-01-31 18:58:58 +010092
93 entry = d->buckets[bucketpos];
Ian Wienand2d45b1a2006-02-20 22:48:07 +010094 while (entry && entry->next)
95 entry = entry->next;
Juan Cespedescac15c32003-01-31 18:58:58 +010096
Ian Wienand2d45b1a2006-02-20 22:48:07 +010097 if (entry)
98 entry->next = newentry;
99 else
100 d->buckets[bucketpos] = newentry;
Juan Cespedescac15c32003-01-31 18:58:58 +0100101
Ian Wienand9a2ad352006-02-20 22:44:45 +0100102 debug(3, "new dict entry at %p[%d]: (%p,%p)", d, bucketpos, key, value);
Juan Cespedescac15c32003-01-31 18:58:58 +0100103 return 0;
104}
105
Juan Cespedesf1350522008-12-16 18:19:58 +0100106void *
Petr Machata77fbb8f2012-04-19 16:57:57 +0200107dict_remove(Dict *d, void *key)
108{
109 assert(d != NULL);
110 debug(DEBUG_FUNCTION, "dict_remove(%p)", key);
111
112 unsigned int hash = d->key2hash(key);
113 unsigned int bucketpos = hash % DICTTABLESIZE;
114
115 struct dict_entry **entryp;
116 for (entryp = &d->buckets[bucketpos]; (*entryp) != NULL;
117 entryp = &(*entryp)->next) {
118 struct dict_entry *entry = *entryp;
119 if (hash != entry->hash)
120 continue;
121 if (d->key_cmp(key, entry->key) == 0) {
122 *entryp = entry->next;
123 return entry->value;
124 }
125 }
126 return NULL;
127}
128
129void *
Petr Machata345c9b52012-02-10 13:10:03 +0100130dict_find_entry(Dict *d, const void *key)
131{
Juan Cespedescd8976d2009-05-14 13:47:58 +0200132 unsigned int hash;
133 unsigned int bucketpos;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100134 struct dict_entry *entry;
Juan Cespedescac15c32003-01-31 18:58:58 +0100135
Juan Cespedescd8976d2009-05-14 13:47:58 +0200136 debug(DEBUG_FUNCTION, "dict_find_entry()");
137
138 hash = d->key2hash(key);
139 bucketpos = hash % DICTTABLESIZE;
140
Juan Cespedesa0ccf392003-02-01 19:02:37 +0100141 assert(d);
Juan Cespedescac15c32003-01-31 18:58:58 +0100142 for (entry = d->buckets[bucketpos]; entry; entry = entry->next) {
143 if (hash != entry->hash) {
144 continue;
145 }
146 if (!d->key_cmp(key, entry->key)) {
147 break;
148 }
149 }
150 return entry ? entry->value : NULL;
151}
152
153void
Juan Cespedes8d1b92b2009-07-03 10:39:34 +0200154dict_apply_to_all(Dict *d,
Juan Cespedesf1350522008-12-16 18:19:58 +0100155 void (*func) (void *key, void *value, void *data), void *data) {
Juan Cespedescac15c32003-01-31 18:58:58 +0100156 int i;
157
Juan Cespedescd8976d2009-05-14 13:47:58 +0200158 debug(DEBUG_FUNCTION, "dict_apply_to_all()");
159
Juan Cespedesefe85f02004-04-04 01:31:38 +0200160 if (!d) {
161 return;
162 }
Juan Cespedescac15c32003-01-31 18:58:58 +0100163 for (i = 0; i < DICTTABLESIZE; i++) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100164 struct dict_entry *entry = d->buckets[i];
Juan Cespedescac15c32003-01-31 18:58:58 +0100165 while (entry) {
166 func(entry->key, entry->value, data);
167 entry = entry->next;
168 }
169 }
170}
171
172/*****************************************************************************/
173
Juan Cespedesf1350522008-12-16 18:19:58 +0100174unsigned int
Petr Machata345c9b52012-02-10 13:10:03 +0100175dict_key2hash_string(const void *key)
176{
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100177 const char *s = (const char *)key;
Juan Cespedescac15c32003-01-31 18:58:58 +0100178 unsigned int total = 0, shift = 0;
179
Juan Cespedesa0ccf392003-02-01 19:02:37 +0100180 assert(key);
Juan Cespedescac15c32003-01-31 18:58:58 +0100181 while (*s) {
182 total = total ^ ((*s) << shift);
183 shift += 5;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100184 if (shift > 24)
185 shift -= 24;
Juan Cespedescac15c32003-01-31 18:58:58 +0100186 s++;
187 }
188 return total;
189}
190
Juan Cespedesf1350522008-12-16 18:19:58 +0100191int
Petr Machata345c9b52012-02-10 13:10:03 +0100192dict_key_cmp_string(const void *key1, const void *key2)
193{
Juan Cespedesa0ccf392003-02-01 19:02:37 +0100194 assert(key1);
195 assert(key2);
Juan Cespedescac15c32003-01-31 18:58:58 +0100196 return strcmp((const char *)key1, (const char *)key2);
197}
198
Juan Cespedesf1350522008-12-16 18:19:58 +0100199unsigned int
Petr Machata345c9b52012-02-10 13:10:03 +0100200dict_key2hash_int(const void *key)
201{
Juan Cespedesd914a202004-11-10 00:15:33 +0100202 return (unsigned long)key;
Juan Cespedescac15c32003-01-31 18:58:58 +0100203}
204
Juan Cespedesf1350522008-12-16 18:19:58 +0100205int
Petr Machata345c9b52012-02-10 13:10:03 +0100206dict_key_cmp_int(const void *key1, const void *key2)
207{
Juan Cespedescac15c32003-01-31 18:58:58 +0100208 return key1 - key2;
209}
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200210
Juan Cespedes8d1b92b2009-07-03 10:39:34 +0200211Dict *
Petr Machata534e00f2011-09-27 17:58:38 +0200212dict_clone2(Dict * old, void * (*key_clone)(void *, void *),
213 void * (*value_clone)(void *, void *), void * data)
214{
Juan Cespedes8d1b92b2009-07-03 10:39:34 +0200215 Dict *d;
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200216 int i;
217
Juan Cespedescd8976d2009-05-14 13:47:58 +0200218 debug(DEBUG_FUNCTION, "dict_clone()");
219
Juan Cespedes8d1b92b2009-07-03 10:39:34 +0200220 d = malloc(sizeof(Dict));
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200221 if (!d) {
222 perror("malloc()");
223 exit(1);
224 }
Juan Cespedes8d1b92b2009-07-03 10:39:34 +0200225 memcpy(d, old, sizeof(Dict));
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200226 for (i = 0; i < DICTTABLESIZE; i++) { /* better use memset()? */
227 struct dict_entry *de_old;
228 struct dict_entry **de_new;
229
230 de_old = old->buckets[i];
231 de_new = &d->buckets[i];
232 while (de_old) {
Petr Machata534e00f2011-09-27 17:58:38 +0200233 void * nkey, * nval;
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200234 *de_new = malloc(sizeof(struct dict_entry));
235 if (!*de_new) {
236 perror("malloc()");
237 exit(1);
238 }
239 memcpy(*de_new, de_old, sizeof(struct dict_entry));
Petr Machata534e00f2011-09-27 17:58:38 +0200240
241 /* The error detection is rather weak :-/ */
242 nkey = key_clone(de_old->key, data);
243 if (nkey == NULL && de_old->key != NULL) {
244 perror("key_clone");
245 err:
246 /* XXX Will this actually work? We
247 * simply memcpy the old dictionary
248 * over up there. */
249 dict_clear(d);
250 free(de_new);
251 return NULL;
252 }
253
254 nval = value_clone(de_old->value, data);
255 if (nval == NULL && de_old->value != NULL) {
256 perror("value_clone");
257 goto err;
258 }
259
260 (*de_new)->key = nkey;
261 (*de_new)->value = nval;
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200262 de_new = &(*de_new)->next;
263 de_old = de_old->next;
264 }
265 }
266 return d;
267}
Petr Machata534e00f2011-09-27 17:58:38 +0200268
269struct wrap_clone_cb
270{
271 void * (*key_clone)(void *);
272 void * (*value_clone)(void *);
273};
274
275static void *
276value_clone_1(void * arg, void * data)
277{
278 return ((struct wrap_clone_cb *)data)->value_clone(arg);
279}
280
281static void *
282key_clone_1(void * arg, void * data)
283{
284 return ((struct wrap_clone_cb *)data)->key_clone(arg);
285}
286
287Dict *
288dict_clone(Dict * old, void * (*key_clone)(void *),
289 void * (*value_clone)(void *))
290{
291 struct wrap_clone_cb cb = { key_clone, value_clone };
292 return dict_clone2(old, &key_clone_1, &value_clone_1, &cb);
293}