blob: fbcd733d1fb07779a7a586a5e14c6bcdeaaab424 [file] [log] [blame]
Petr Machataa11cbed2012-05-05 00:07:38 +02001/*
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
6 *
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.
11 *
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.
16 *
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
20 * 02110-1301 USA
21 */
22
Juan Cespedescac15c32003-01-31 18:58:58 +010023#include <stdio.h>
24#include <stdlib.h>
Juan Cespedes7186e2a2003-01-31 19:56:34 +010025#include <string.h>
Juan Cespedesa0ccf392003-02-01 19:02:37 +010026#include <assert.h>
Juan Cespedescac15c32003-01-31 18:58:58 +010027
Juan Cespedes8d1b92b2009-07-03 10:39:34 +020028#include "common.h"
Juan Cespedescac15c32003-01-31 18:58:58 +010029
30/*
Petr Machataa11cbed2012-05-05 00:07:38 +020031 * Dictionary based on code by Morten Eriksen <mortene@sim.no>.
32 */
Juan Cespedescac15c32003-01-31 18:58:58 +010033
Juan Cespedescac15c32003-01-31 18:58:58 +010034struct dict_entry {
35 unsigned int hash;
Ian Wienand2d45b1a2006-02-20 22:48:07 +010036 void *key;
37 void *value;
38 struct dict_entry *next;
Juan Cespedescac15c32003-01-31 18:58:58 +010039};
40
41/* #define DICTTABLESIZE 97 */
Ian Wienand2d45b1a2006-02-20 22:48:07 +010042#define DICTTABLESIZE 997 /* Semi-randomly selected prime number. */
Juan Cespedescac15c32003-01-31 18:58:58 +010043/* #define DICTTABLESIZE 9973 */
44/* #define DICTTABLESIZE 99991 */
45/* #define DICTTABLESIZE 999983 */
46
47struct dict {
Ian Wienand2d45b1a2006-02-20 22:48:07 +010048 struct dict_entry *buckets[DICTTABLESIZE];
Petr Machata345c9b52012-02-10 13:10:03 +010049 unsigned int (*key2hash) (const void *);
50 int (*key_cmp) (const void *, const void *);
Juan Cespedescac15c32003-01-31 18:58:58 +010051};
52
Juan Cespedes8d1b92b2009-07-03 10:39:34 +020053Dict *
Petr Machata345c9b52012-02-10 13:10:03 +010054dict_init(unsigned int (*key2hash) (const void *),
55 int (*key_cmp) (const void *, const void *))
56{
Juan Cespedes8d1b92b2009-07-03 10:39:34 +020057 Dict *d;
Juan Cespedescac15c32003-01-31 18:58:58 +010058 int i;
59
Juan Cespedescd8976d2009-05-14 13:47:58 +020060 debug(DEBUG_FUNCTION, "dict_init()");
61
Juan Cespedes8d1b92b2009-07-03 10:39:34 +020062 d = malloc(sizeof(Dict));
Juan Cespedescac15c32003-01-31 18:58:58 +010063 if (!d) {
64 perror("malloc()");
65 exit(1);
66 }
Ian Wienand2d45b1a2006-02-20 22:48:07 +010067 for (i = 0; i < DICTTABLESIZE; i++) { /* better use memset()? */
Juan Cespedescac15c32003-01-31 18:58:58 +010068 d->buckets[i] = NULL;
69 }
70 d->key2hash = key2hash;
71 d->key_cmp = key_cmp;
72 return d;
73}
74
Juan Cespedesf1350522008-12-16 18:19:58 +010075void
Juan Cespedes8d1b92b2009-07-03 10:39:34 +020076dict_clear(Dict *d) {
Juan Cespedescac15c32003-01-31 18:58:58 +010077 int i;
Ian Wienand2d45b1a2006-02-20 22:48:07 +010078 struct dict_entry *entry, *nextentry;
Juan Cespedescac15c32003-01-31 18:58:58 +010079
Juan Cespedescd8976d2009-05-14 13:47:58 +020080 debug(DEBUG_FUNCTION, "dict_clear()");
Juan Cespedesa0ccf392003-02-01 19:02:37 +010081 assert(d);
Juan Cespedescac15c32003-01-31 18:58:58 +010082 for (i = 0; i < DICTTABLESIZE; i++) {
83 for (entry = d->buckets[i]; entry != NULL; entry = nextentry) {
84 nextentry = entry->next;
85 free(entry);
86 }
87 d->buckets[i] = NULL;
88 }
89 free(d);
90}
91
Juan Cespedesf1350522008-12-16 18:19:58 +010092int
Juan Cespedes8d1b92b2009-07-03 10:39:34 +020093dict_enter(Dict *d, void *key, void *value) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +010094 struct dict_entry *entry, *newentry;
Juan Cespedescd8976d2009-05-14 13:47:58 +020095 unsigned int hash;
96 unsigned int bucketpos;
97
98 debug(DEBUG_FUNCTION, "dict_enter()");
99
100 hash = d->key2hash(key);
101 bucketpos = hash % DICTTABLESIZE;
Juan Cespedescac15c32003-01-31 18:58:58 +0100102
Juan Cespedesa0ccf392003-02-01 19:02:37 +0100103 assert(d);
Juan Cespedescac15c32003-01-31 18:58:58 +0100104 newentry = malloc(sizeof(struct dict_entry));
105 if (!newentry) {
106 perror("malloc");
107 exit(1);
108 }
109
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100110 newentry->hash = hash;
111 newentry->key = key;
Juan Cespedescac15c32003-01-31 18:58:58 +0100112 newentry->value = value;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100113 newentry->next = NULL;
Juan Cespedescac15c32003-01-31 18:58:58 +0100114
115 entry = d->buckets[bucketpos];
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100116 while (entry && entry->next)
117 entry = entry->next;
Juan Cespedescac15c32003-01-31 18:58:58 +0100118
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100119 if (entry)
120 entry->next = newentry;
121 else
122 d->buckets[bucketpos] = newentry;
Juan Cespedescac15c32003-01-31 18:58:58 +0100123
Ian Wienand9a2ad352006-02-20 22:44:45 +0100124 debug(3, "new dict entry at %p[%d]: (%p,%p)", d, bucketpos, key, value);
Juan Cespedescac15c32003-01-31 18:58:58 +0100125 return 0;
126}
127
Juan Cespedesf1350522008-12-16 18:19:58 +0100128void *
Petr Machata77fbb8f2012-04-19 16:57:57 +0200129dict_remove(Dict *d, void *key)
130{
131 assert(d != NULL);
132 debug(DEBUG_FUNCTION, "dict_remove(%p)", key);
133
134 unsigned int hash = d->key2hash(key);
135 unsigned int bucketpos = hash % DICTTABLESIZE;
136
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)
142 continue;
143 if (d->key_cmp(key, entry->key) == 0) {
144 *entryp = entry->next;
145 return entry->value;
146 }
147 }
148 return NULL;
149}
150
151void *
Petr Machata345c9b52012-02-10 13:10:03 +0100152dict_find_entry(Dict *d, const void *key)
153{
Juan Cespedescd8976d2009-05-14 13:47:58 +0200154 unsigned int hash;
155 unsigned int bucketpos;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100156 struct dict_entry *entry;
Juan Cespedescac15c32003-01-31 18:58:58 +0100157
Juan Cespedescd8976d2009-05-14 13:47:58 +0200158 debug(DEBUG_FUNCTION, "dict_find_entry()");
159
160 hash = d->key2hash(key);
161 bucketpos = hash % DICTTABLESIZE;
162
Juan Cespedesa0ccf392003-02-01 19:02:37 +0100163 assert(d);
Juan Cespedescac15c32003-01-31 18:58:58 +0100164 for (entry = d->buckets[bucketpos]; entry; entry = entry->next) {
165 if (hash != entry->hash) {
166 continue;
167 }
168 if (!d->key_cmp(key, entry->key)) {
169 break;
170 }
171 }
172 return entry ? entry->value : NULL;
173}
174
175void
Juan Cespedes8d1b92b2009-07-03 10:39:34 +0200176dict_apply_to_all(Dict *d,
Juan Cespedesf1350522008-12-16 18:19:58 +0100177 void (*func) (void *key, void *value, void *data), void *data) {
Juan Cespedescac15c32003-01-31 18:58:58 +0100178 int i;
179
Juan Cespedescd8976d2009-05-14 13:47:58 +0200180 debug(DEBUG_FUNCTION, "dict_apply_to_all()");
181
Juan Cespedesefe85f02004-04-04 01:31:38 +0200182 if (!d) {
183 return;
184 }
Juan Cespedescac15c32003-01-31 18:58:58 +0100185 for (i = 0; i < DICTTABLESIZE; i++) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100186 struct dict_entry *entry = d->buckets[i];
Juan Cespedescac15c32003-01-31 18:58:58 +0100187 while (entry) {
188 func(entry->key, entry->value, data);
189 entry = entry->next;
190 }
191 }
192}
193
194/*****************************************************************************/
195
Juan Cespedesf1350522008-12-16 18:19:58 +0100196unsigned int
Petr Machata345c9b52012-02-10 13:10:03 +0100197dict_key2hash_string(const void *key)
198{
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100199 const char *s = (const char *)key;
Juan Cespedescac15c32003-01-31 18:58:58 +0100200 unsigned int total = 0, shift = 0;
201
Juan Cespedesa0ccf392003-02-01 19:02:37 +0100202 assert(key);
Juan Cespedescac15c32003-01-31 18:58:58 +0100203 while (*s) {
204 total = total ^ ((*s) << shift);
205 shift += 5;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100206 if (shift > 24)
207 shift -= 24;
Juan Cespedescac15c32003-01-31 18:58:58 +0100208 s++;
209 }
210 return total;
211}
212
Juan Cespedesf1350522008-12-16 18:19:58 +0100213int
Petr Machata345c9b52012-02-10 13:10:03 +0100214dict_key_cmp_string(const void *key1, const void *key2)
215{
Juan Cespedesa0ccf392003-02-01 19:02:37 +0100216 assert(key1);
217 assert(key2);
Juan Cespedescac15c32003-01-31 18:58:58 +0100218 return strcmp((const char *)key1, (const char *)key2);
219}
220
Juan Cespedesf1350522008-12-16 18:19:58 +0100221unsigned int
Petr Machata345c9b52012-02-10 13:10:03 +0100222dict_key2hash_int(const void *key)
223{
Juan Cespedesd914a202004-11-10 00:15:33 +0100224 return (unsigned long)key;
Juan Cespedescac15c32003-01-31 18:58:58 +0100225}
226
Juan Cespedesf1350522008-12-16 18:19:58 +0100227int
Petr Machata345c9b52012-02-10 13:10:03 +0100228dict_key_cmp_int(const void *key1, const void *key2)
229{
Juan Cespedescac15c32003-01-31 18:58:58 +0100230 return key1 - key2;
231}
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200232
Juan Cespedes8d1b92b2009-07-03 10:39:34 +0200233Dict *
Petr Machata534e00f2011-09-27 17:58:38 +0200234dict_clone2(Dict * old, void * (*key_clone)(void *, void *),
235 void * (*value_clone)(void *, void *), void * data)
236{
Juan Cespedes8d1b92b2009-07-03 10:39:34 +0200237 Dict *d;
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200238 int i;
239
Juan Cespedescd8976d2009-05-14 13:47:58 +0200240 debug(DEBUG_FUNCTION, "dict_clone()");
241
Juan Cespedes8d1b92b2009-07-03 10:39:34 +0200242 d = malloc(sizeof(Dict));
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200243 if (!d) {
244 perror("malloc()");
245 exit(1);
246 }
Juan Cespedes8d1b92b2009-07-03 10:39:34 +0200247 memcpy(d, old, sizeof(Dict));
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200248 for (i = 0; i < DICTTABLESIZE; i++) { /* better use memset()? */
249 struct dict_entry *de_old;
250 struct dict_entry **de_new;
251
252 de_old = old->buckets[i];
253 de_new = &d->buckets[i];
254 while (de_old) {
Petr Machata534e00f2011-09-27 17:58:38 +0200255 void * nkey, * nval;
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200256 *de_new = malloc(sizeof(struct dict_entry));
257 if (!*de_new) {
258 perror("malloc()");
259 exit(1);
260 }
261 memcpy(*de_new, de_old, sizeof(struct dict_entry));
Petr Machata534e00f2011-09-27 17:58:38 +0200262
263 /* The error detection is rather weak :-/ */
264 nkey = key_clone(de_old->key, data);
265 if (nkey == NULL && de_old->key != NULL) {
266 perror("key_clone");
267 err:
268 /* XXX Will this actually work? We
269 * simply memcpy the old dictionary
270 * over up there. */
271 dict_clear(d);
272 free(de_new);
273 return NULL;
274 }
275
276 nval = value_clone(de_old->value, data);
277 if (nval == NULL && de_old->value != NULL) {
278 perror("value_clone");
279 goto err;
280 }
281
282 (*de_new)->key = nkey;
283 (*de_new)->value = nval;
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200284 de_new = &(*de_new)->next;
285 de_old = de_old->next;
286 }
287 }
288 return d;
289}
Petr Machata534e00f2011-09-27 17:58:38 +0200290
291struct wrap_clone_cb
292{
293 void * (*key_clone)(void *);
294 void * (*value_clone)(void *);
295};
296
297static void *
298value_clone_1(void * arg, void * data)
299{
300 return ((struct wrap_clone_cb *)data)->value_clone(arg);
301}
302
303static void *
304key_clone_1(void * arg, void * data)
305{
306 return ((struct wrap_clone_cb *)data)->key_clone(arg);
307}
308
309Dict *
310dict_clone(Dict * old, void * (*key_clone)(void *),
311 void * (*value_clone)(void *))
312{
313 struct wrap_clone_cb cb = { key_clone, value_clone };
314 return dict_clone2(old, &key_clone_1, &value_clone_1, &cb);
315}