2 * This file is part of ltrace.
3 * Copyright (C) 2011,2012 Petr Machata
4 * Copyright (C) 2003,2004,2008,2009 Juan Cespedes
5 * Copyright (C) 2006 Ian Wienand
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
31 * Dictionary based on code by Morten Eriksen <mortene@sim.no>.
38 struct dict_entry *next;
41 /* #define DICTTABLESIZE 97 */
42 #define DICTTABLESIZE 997 /* Semi-randomly selected prime number. */
43 /* #define DICTTABLESIZE 9973 */
44 /* #define DICTTABLESIZE 99991 */
45 /* #define DICTTABLESIZE 999983 */
48 struct dict_entry *buckets[DICTTABLESIZE];
49 unsigned int (*key2hash) (const void *);
50 int (*key_cmp) (const void *, const void *);
54 dict_init(unsigned int (*key2hash) (const void *),
55 int (*key_cmp) (const void *, const void *))
60 debug(DEBUG_FUNCTION, "dict_init()");
62 d = malloc(sizeof(Dict));
67 for (i = 0; i < DICTTABLESIZE; i++) { /* better use memset()? */
70 d->key2hash = key2hash;
78 struct dict_entry *entry, *nextentry;
80 debug(DEBUG_FUNCTION, "dict_clear()");
82 for (i = 0; i < DICTTABLESIZE; i++) {
83 for (entry = d->buckets[i]; entry != NULL; entry = nextentry) {
84 nextentry = entry->next;
93 dict_enter(Dict *d, void *key, void *value) {
94 struct dict_entry *entry, *newentry;
96 unsigned int bucketpos;
98 debug(DEBUG_FUNCTION, "dict_enter()");
100 hash = d->key2hash(key);
101 bucketpos = hash % DICTTABLESIZE;
104 newentry = malloc(sizeof(struct dict_entry));
110 newentry->hash = hash;
112 newentry->value = value;
113 newentry->next = NULL;
115 entry = d->buckets[bucketpos];
116 while (entry && entry->next)
120 entry->next = newentry;
122 d->buckets[bucketpos] = newentry;
124 debug(3, "new dict entry at %p[%d]: (%p,%p)", d, bucketpos, key, value);
129 dict_remove(Dict *d, void *key)
132 debug(DEBUG_FUNCTION, "dict_remove(%p)", key);
134 unsigned int hash = d->key2hash(key);
135 unsigned int bucketpos = hash % DICTTABLESIZE;
137 struct dict_entry **entryp;
138 for (entryp = &d->buckets[bucketpos]; (*entryp) != NULL;
139 entryp = &(*entryp)->next) {
140 struct dict_entry *entry = *entryp;
141 if (hash != entry->hash)
143 if (d->key_cmp(key, entry->key) == 0) {
144 *entryp = entry->next;
145 void *value = entry->value;
154 dict_find_entry(Dict *d, const void *key)
157 unsigned int bucketpos;
158 struct dict_entry *entry;
160 debug(DEBUG_FUNCTION, "dict_find_entry()");
162 hash = d->key2hash(key);
163 bucketpos = hash % DICTTABLESIZE;
166 for (entry = d->buckets[bucketpos]; entry; entry = entry->next) {
167 if (hash != entry->hash) {
170 if (!d->key_cmp(key, entry->key)) {
174 return entry ? entry->value : NULL;
178 dict_apply_to_all(Dict *d,
179 void (*func) (void *key, void *value, void *data), void *data) {
182 debug(DEBUG_FUNCTION, "dict_apply_to_all()");
187 for (i = 0; i < DICTTABLESIZE; i++) {
188 struct dict_entry *entry = d->buckets[i];
190 func(entry->key, entry->value, data);
196 /*****************************************************************************/
199 dict_key2hash_string(const void *key)
201 const char *s = (const char *)key;
202 unsigned int total = 0, shift = 0;
206 total = total ^ ((*s) << shift);
216 dict_key_cmp_string(const void *key1, const void *key2)
220 return strcmp((const char *)key1, (const char *)key2);
224 dict_key2hash_int(const void *key)
226 return (unsigned long)key;
230 dict_key_cmp_int(const void *key1, const void *key2)
236 dict_clone2(Dict * old, void * (*key_clone)(void *, void *),
237 void * (*value_clone)(void *, void *), void * data)
242 debug(DEBUG_FUNCTION, "dict_clone()");
244 d = malloc(sizeof(Dict));
249 memcpy(d, old, sizeof(Dict));
250 for (i = 0; i < DICTTABLESIZE; i++) { /* better use memset()? */
251 struct dict_entry *de_old;
252 struct dict_entry **de_new;
254 de_old = old->buckets[i];
255 de_new = &d->buckets[i];
258 *de_new = malloc(sizeof(struct dict_entry));
263 memcpy(*de_new, de_old, sizeof(struct dict_entry));
265 /* The error detection is rather weak :-/ */
266 nkey = key_clone(de_old->key, data);
267 if (nkey == NULL && de_old->key != NULL) {
270 /* XXX Will this actually work? We
271 * simply memcpy the old dictionary
278 nval = value_clone(de_old->value, data);
279 if (nval == NULL && de_old->value != NULL) {
280 perror("value_clone");
284 (*de_new)->key = nkey;
285 (*de_new)->value = nval;
286 de_new = &(*de_new)->next;
287 de_old = de_old->next;
295 void * (*key_clone)(void *);
296 void * (*value_clone)(void *);
300 value_clone_1(void * arg, void * data)
302 return ((struct wrap_clone_cb *)data)->value_clone(arg);
306 key_clone_1(void * arg, void * data)
308 return ((struct wrap_clone_cb *)data)->key_clone(arg);
312 dict_clone(Dict * old, void * (*key_clone)(void *),
313 void * (*value_clone)(void *))
315 struct wrap_clone_cb cb = { key_clone, value_clone };
316 return dict_clone2(old, &key_clone_1, &value_clone_1, &cb);