blob: 486a4611402857005e5049e9a0ee38b93d0a2b0e [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 *
183dict_clone(Dict *old, void * (*key_clone)(void*), void * (*value_clone)(void*)) {
184 Dict *d;
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200185 int i;
186
Juan Cespedescd8976d2009-05-14 13:47:58 +0200187 debug(DEBUG_FUNCTION, "dict_clone()");
188
Juan Cespedes8d1b92b2009-07-03 10:39:34 +0200189 d = malloc(sizeof(Dict));
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200190 if (!d) {
191 perror("malloc()");
192 exit(1);
193 }
Juan Cespedes8d1b92b2009-07-03 10:39:34 +0200194 memcpy(d, old, sizeof(Dict));
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200195 for (i = 0; i < DICTTABLESIZE; i++) { /* better use memset()? */
196 struct dict_entry *de_old;
197 struct dict_entry **de_new;
198
199 de_old = old->buckets[i];
200 de_new = &d->buckets[i];
201 while (de_old) {
202 *de_new = malloc(sizeof(struct dict_entry));
203 if (!*de_new) {
204 perror("malloc()");
205 exit(1);
206 }
207 memcpy(*de_new, de_old, sizeof(struct dict_entry));
208 (*de_new)->key = key_clone(de_old->key);
209 (*de_new)->value = value_clone(de_old->value);
210 de_new = &(*de_new)->next;
211 de_old = de_old->next;
212 }
213 }
214 return d;
215}