blob: e55d36764c57d7e7d4f1afe79e6d1d9441708a0e [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
6#include "debug.h"
7
8/*
9 Dictionary based on code by Morten Eriksen <mortene@sim.no>.
10*/
11
12#include "dict.h"
13
14struct dict_entry {
15 unsigned int hash;
Ian Wienand2d45b1a2006-02-20 22:48:07 +010016 void *key;
17 void *value;
18 struct dict_entry *next;
Juan Cespedescac15c32003-01-31 18:58:58 +010019};
20
21/* #define DICTTABLESIZE 97 */
Ian Wienand2d45b1a2006-02-20 22:48:07 +010022#define DICTTABLESIZE 997 /* Semi-randomly selected prime number. */
Juan Cespedescac15c32003-01-31 18:58:58 +010023/* #define DICTTABLESIZE 9973 */
24/* #define DICTTABLESIZE 99991 */
25/* #define DICTTABLESIZE 999983 */
26
27struct dict {
Ian Wienand2d45b1a2006-02-20 22:48:07 +010028 struct dict_entry *buckets[DICTTABLESIZE];
29 unsigned int (*key2hash) (void *);
30 int (*key_cmp) (void *, void *);
Juan Cespedescac15c32003-01-31 18:58:58 +010031};
32
Juan Cespedesf1350522008-12-16 18:19:58 +010033struct dict *
34dict_init(unsigned int (*key2hash) (void *),
35 int (*key_cmp) (void *, void *)) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +010036 struct dict *d;
Juan Cespedescac15c32003-01-31 18:58:58 +010037 int i;
38
Juan Cespedescd8976d2009-05-14 13:47:58 +020039 debug(DEBUG_FUNCTION, "dict_init()");
40
Juan Cespedescac15c32003-01-31 18:58:58 +010041 d = malloc(sizeof(struct dict));
42 if (!d) {
43 perror("malloc()");
44 exit(1);
45 }
Ian Wienand2d45b1a2006-02-20 22:48:07 +010046 for (i = 0; i < DICTTABLESIZE; i++) { /* better use memset()? */
Juan Cespedescac15c32003-01-31 18:58:58 +010047 d->buckets[i] = NULL;
48 }
49 d->key2hash = key2hash;
50 d->key_cmp = key_cmp;
51 return d;
52}
53
Juan Cespedesf1350522008-12-16 18:19:58 +010054void
55dict_clear(struct dict *d) {
Juan Cespedescac15c32003-01-31 18:58:58 +010056 int i;
Ian Wienand2d45b1a2006-02-20 22:48:07 +010057 struct dict_entry *entry, *nextentry;
Juan Cespedescac15c32003-01-31 18:58:58 +010058
Juan Cespedescd8976d2009-05-14 13:47:58 +020059 debug(DEBUG_FUNCTION, "dict_clear()");
Juan Cespedesa0ccf392003-02-01 19:02:37 +010060 assert(d);
Juan Cespedescac15c32003-01-31 18:58:58 +010061 for (i = 0; i < DICTTABLESIZE; i++) {
62 for (entry = d->buckets[i]; entry != NULL; entry = nextentry) {
63 nextentry = entry->next;
64 free(entry);
65 }
66 d->buckets[i] = NULL;
67 }
68 free(d);
69}
70
Juan Cespedesf1350522008-12-16 18:19:58 +010071int
72dict_enter(struct dict *d, void *key, void *value) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +010073 struct dict_entry *entry, *newentry;
Juan Cespedescd8976d2009-05-14 13:47:58 +020074 unsigned int hash;
75 unsigned int bucketpos;
76
77 debug(DEBUG_FUNCTION, "dict_enter()");
78
79 hash = d->key2hash(key);
80 bucketpos = hash % DICTTABLESIZE;
Juan Cespedescac15c32003-01-31 18:58:58 +010081
Juan Cespedesa0ccf392003-02-01 19:02:37 +010082 assert(d);
Juan Cespedescac15c32003-01-31 18:58:58 +010083 newentry = malloc(sizeof(struct dict_entry));
84 if (!newentry) {
85 perror("malloc");
86 exit(1);
87 }
88
Ian Wienand2d45b1a2006-02-20 22:48:07 +010089 newentry->hash = hash;
90 newentry->key = key;
Juan Cespedescac15c32003-01-31 18:58:58 +010091 newentry->value = value;
Ian Wienand2d45b1a2006-02-20 22:48:07 +010092 newentry->next = NULL;
Juan Cespedescac15c32003-01-31 18:58:58 +010093
94 entry = d->buckets[bucketpos];
Ian Wienand2d45b1a2006-02-20 22:48:07 +010095 while (entry && entry->next)
96 entry = entry->next;
Juan Cespedescac15c32003-01-31 18:58:58 +010097
Ian Wienand2d45b1a2006-02-20 22:48:07 +010098 if (entry)
99 entry->next = newentry;
100 else
101 d->buckets[bucketpos] = newentry;
Juan Cespedescac15c32003-01-31 18:58:58 +0100102
Ian Wienand9a2ad352006-02-20 22:44:45 +0100103 debug(3, "new dict entry at %p[%d]: (%p,%p)", d, bucketpos, key, value);
Juan Cespedescac15c32003-01-31 18:58:58 +0100104 return 0;
105}
106
Juan Cespedesf1350522008-12-16 18:19:58 +0100107void *
108dict_find_entry(struct dict *d, void *key) {
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
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100131dict_apply_to_all(struct 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
152dict_key2hash_string(void *key) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100153 const char *s = (const char *)key;
Juan Cespedescac15c32003-01-31 18:58:58 +0100154 unsigned int total = 0, shift = 0;
155
Juan Cespedesa0ccf392003-02-01 19:02:37 +0100156 assert(key);
Juan Cespedescac15c32003-01-31 18:58:58 +0100157 while (*s) {
158 total = total ^ ((*s) << shift);
159 shift += 5;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100160 if (shift > 24)
161 shift -= 24;
Juan Cespedescac15c32003-01-31 18:58:58 +0100162 s++;
163 }
164 return total;
165}
166
Juan Cespedesf1350522008-12-16 18:19:58 +0100167int
168dict_key_cmp_string(void *key1, void *key2) {
Juan Cespedesa0ccf392003-02-01 19:02:37 +0100169 assert(key1);
170 assert(key2);
Juan Cespedescac15c32003-01-31 18:58:58 +0100171 return strcmp((const char *)key1, (const char *)key2);
172}
173
Juan Cespedesf1350522008-12-16 18:19:58 +0100174unsigned int
175dict_key2hash_int(void *key) {
Juan Cespedesd914a202004-11-10 00:15:33 +0100176 return (unsigned long)key;
Juan Cespedescac15c32003-01-31 18:58:58 +0100177}
178
Juan Cespedesf1350522008-12-16 18:19:58 +0100179int
180dict_key_cmp_int(void *key1, void *key2) {
Juan Cespedescac15c32003-01-31 18:58:58 +0100181 return key1 - key2;
182}
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200183
184struct dict *
185dict_clone(struct dict *old, void * (*key_clone)(void*), void * (*value_clone)(void*)) {
186 struct dict *d;
187 int i;
188
Juan Cespedescd8976d2009-05-14 13:47:58 +0200189 debug(DEBUG_FUNCTION, "dict_clone()");
190
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200191 d = malloc(sizeof(struct dict));
192 if (!d) {
193 perror("malloc()");
194 exit(1);
195 }
196 memcpy(d, old, sizeof(struct dict));
197 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) {
204 *de_new = malloc(sizeof(struct dict_entry));
205 if (!*de_new) {
206 perror("malloc()");
207 exit(1);
208 }
209 memcpy(*de_new, de_old, sizeof(struct dict_entry));
210 (*de_new)->key = key_clone(de_old->key);
211 (*de_new)->value = value_clone(de_old->value);
212 de_new = &(*de_new)->next;
213 de_old = de_old->next;
214 }
215 }
216 return d;
217}