blob: d7e14db7e809dabd0d842eb3700bc25b2f75897f [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 Machata345c9b52012-02-10 13:10:03 +0100107dict_find_entry(Dict *d, const void *key)
108{
Juan Cespedescd8976d2009-05-14 13:47:58 +0200109 unsigned int hash;
110 unsigned int bucketpos;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100111 struct dict_entry *entry;
Juan Cespedescac15c32003-01-31 18:58:58 +0100112
Juan Cespedescd8976d2009-05-14 13:47:58 +0200113 debug(DEBUG_FUNCTION, "dict_find_entry()");
114
115 hash = d->key2hash(key);
116 bucketpos = hash % DICTTABLESIZE;
117
Juan Cespedesa0ccf392003-02-01 19:02:37 +0100118 assert(d);
Juan Cespedescac15c32003-01-31 18:58:58 +0100119 for (entry = d->buckets[bucketpos]; entry; entry = entry->next) {
120 if (hash != entry->hash) {
121 continue;
122 }
123 if (!d->key_cmp(key, entry->key)) {
124 break;
125 }
126 }
127 return entry ? entry->value : NULL;
128}
129
130void
Juan Cespedes8d1b92b2009-07-03 10:39:34 +0200131dict_apply_to_all(Dict *d,
Juan Cespedesf1350522008-12-16 18:19:58 +0100132 void (*func) (void *key, void *value, void *data), void *data) {
Juan Cespedescac15c32003-01-31 18:58:58 +0100133 int i;
134
Juan Cespedescd8976d2009-05-14 13:47:58 +0200135 debug(DEBUG_FUNCTION, "dict_apply_to_all()");
136
Juan Cespedesefe85f02004-04-04 01:31:38 +0200137 if (!d) {
138 return;
139 }
Juan Cespedescac15c32003-01-31 18:58:58 +0100140 for (i = 0; i < DICTTABLESIZE; i++) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100141 struct dict_entry *entry = d->buckets[i];
Juan Cespedescac15c32003-01-31 18:58:58 +0100142 while (entry) {
143 func(entry->key, entry->value, data);
144 entry = entry->next;
145 }
146 }
147}
148
149/*****************************************************************************/
150
Juan Cespedesf1350522008-12-16 18:19:58 +0100151unsigned int
Petr Machata345c9b52012-02-10 13:10:03 +0100152dict_key2hash_string(const void *key)
153{
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100154 const char *s = (const char *)key;
Juan Cespedescac15c32003-01-31 18:58:58 +0100155 unsigned int total = 0, shift = 0;
156
Juan Cespedesa0ccf392003-02-01 19:02:37 +0100157 assert(key);
Juan Cespedescac15c32003-01-31 18:58:58 +0100158 while (*s) {
159 total = total ^ ((*s) << shift);
160 shift += 5;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100161 if (shift > 24)
162 shift -= 24;
Juan Cespedescac15c32003-01-31 18:58:58 +0100163 s++;
164 }
165 return total;
166}
167
Juan Cespedesf1350522008-12-16 18:19:58 +0100168int
Petr Machata345c9b52012-02-10 13:10:03 +0100169dict_key_cmp_string(const void *key1, const void *key2)
170{
Juan Cespedesa0ccf392003-02-01 19:02:37 +0100171 assert(key1);
172 assert(key2);
Juan Cespedescac15c32003-01-31 18:58:58 +0100173 return strcmp((const char *)key1, (const char *)key2);
174}
175
Juan Cespedesf1350522008-12-16 18:19:58 +0100176unsigned int
Petr Machata345c9b52012-02-10 13:10:03 +0100177dict_key2hash_int(const void *key)
178{
Juan Cespedesd914a202004-11-10 00:15:33 +0100179 return (unsigned long)key;
Juan Cespedescac15c32003-01-31 18:58:58 +0100180}
181
Juan Cespedesf1350522008-12-16 18:19:58 +0100182int
Petr Machata345c9b52012-02-10 13:10:03 +0100183dict_key_cmp_int(const void *key1, const void *key2)
184{
Juan Cespedescac15c32003-01-31 18:58:58 +0100185 return key1 - key2;
186}
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200187
Juan Cespedes8d1b92b2009-07-03 10:39:34 +0200188Dict *
Petr Machata534e00f2011-09-27 17:58:38 +0200189dict_clone2(Dict * old, void * (*key_clone)(void *, void *),
190 void * (*value_clone)(void *, void *), void * data)
191{
Juan Cespedes8d1b92b2009-07-03 10:39:34 +0200192 Dict *d;
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200193 int i;
194
Juan Cespedescd8976d2009-05-14 13:47:58 +0200195 debug(DEBUG_FUNCTION, "dict_clone()");
196
Juan Cespedes8d1b92b2009-07-03 10:39:34 +0200197 d = malloc(sizeof(Dict));
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200198 if (!d) {
199 perror("malloc()");
200 exit(1);
201 }
Juan Cespedes8d1b92b2009-07-03 10:39:34 +0200202 memcpy(d, old, sizeof(Dict));
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200203 for (i = 0; i < DICTTABLESIZE; i++) { /* better use memset()? */
204 struct dict_entry *de_old;
205 struct dict_entry **de_new;
206
207 de_old = old->buckets[i];
208 de_new = &d->buckets[i];
209 while (de_old) {
Petr Machata534e00f2011-09-27 17:58:38 +0200210 void * nkey, * nval;
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200211 *de_new = malloc(sizeof(struct dict_entry));
212 if (!*de_new) {
213 perror("malloc()");
214 exit(1);
215 }
216 memcpy(*de_new, de_old, sizeof(struct dict_entry));
Petr Machata534e00f2011-09-27 17:58:38 +0200217
218 /* The error detection is rather weak :-/ */
219 nkey = key_clone(de_old->key, data);
220 if (nkey == NULL && de_old->key != NULL) {
221 perror("key_clone");
222 err:
223 /* XXX Will this actually work? We
224 * simply memcpy the old dictionary
225 * over up there. */
226 dict_clear(d);
227 free(de_new);
228 return NULL;
229 }
230
231 nval = value_clone(de_old->value, data);
232 if (nval == NULL && de_old->value != NULL) {
233 perror("value_clone");
234 goto err;
235 }
236
237 (*de_new)->key = nkey;
238 (*de_new)->value = nval;
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200239 de_new = &(*de_new)->next;
240 de_old = de_old->next;
241 }
242 }
243 return d;
244}
Petr Machata534e00f2011-09-27 17:58:38 +0200245
246struct wrap_clone_cb
247{
248 void * (*key_clone)(void *);
249 void * (*value_clone)(void *);
250};
251
252static void *
253value_clone_1(void * arg, void * data)
254{
255 return ((struct wrap_clone_cb *)data)->value_clone(arg);
256}
257
258static void *
259key_clone_1(void * arg, void * data)
260{
261 return ((struct wrap_clone_cb *)data)->key_clone(arg);
262}
263
264Dict *
265dict_clone(Dict * old, void * (*key_clone)(void *),
266 void * (*value_clone)(void *))
267{
268 struct wrap_clone_cb cb = { key_clone, value_clone };
269 return dict_clone2(old, &key_clone_1, &value_clone_1, &cb);
270}