blob: aad50fd9b935d03b65209f59bd6f79fd3392063e [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;
Petr Machatad3202de2012-10-26 23:10:21 +0200145 void *value = entry->value;
146 free(entry);
147 return value;
Petr Machata77fbb8f2012-04-19 16:57:57 +0200148 }
149 }
150 return NULL;
151}
152
153void *
Petr Machata345c9b52012-02-10 13:10:03 +0100154dict_find_entry(Dict *d, const void *key)
155{
Juan Cespedescd8976d2009-05-14 13:47:58 +0200156 unsigned int hash;
157 unsigned int bucketpos;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100158 struct dict_entry *entry;
Juan Cespedescac15c32003-01-31 18:58:58 +0100159
Juan Cespedescd8976d2009-05-14 13:47:58 +0200160 debug(DEBUG_FUNCTION, "dict_find_entry()");
161
162 hash = d->key2hash(key);
163 bucketpos = hash % DICTTABLESIZE;
164
Juan Cespedesa0ccf392003-02-01 19:02:37 +0100165 assert(d);
Juan Cespedescac15c32003-01-31 18:58:58 +0100166 for (entry = d->buckets[bucketpos]; entry; entry = entry->next) {
167 if (hash != entry->hash) {
168 continue;
169 }
170 if (!d->key_cmp(key, entry->key)) {
171 break;
172 }
173 }
174 return entry ? entry->value : NULL;
175}
176
177void
Juan Cespedes8d1b92b2009-07-03 10:39:34 +0200178dict_apply_to_all(Dict *d,
Juan Cespedesf1350522008-12-16 18:19:58 +0100179 void (*func) (void *key, void *value, void *data), void *data) {
Juan Cespedescac15c32003-01-31 18:58:58 +0100180 int i;
181
Juan Cespedescd8976d2009-05-14 13:47:58 +0200182 debug(DEBUG_FUNCTION, "dict_apply_to_all()");
183
Juan Cespedesefe85f02004-04-04 01:31:38 +0200184 if (!d) {
185 return;
186 }
Juan Cespedescac15c32003-01-31 18:58:58 +0100187 for (i = 0; i < DICTTABLESIZE; i++) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100188 struct dict_entry *entry = d->buckets[i];
Juan Cespedescac15c32003-01-31 18:58:58 +0100189 while (entry) {
190 func(entry->key, entry->value, data);
191 entry = entry->next;
192 }
193 }
194}
195
196/*****************************************************************************/
197
Juan Cespedesf1350522008-12-16 18:19:58 +0100198unsigned int
Petr Machata345c9b52012-02-10 13:10:03 +0100199dict_key2hash_string(const void *key)
200{
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100201 const char *s = (const char *)key;
Juan Cespedescac15c32003-01-31 18:58:58 +0100202 unsigned int total = 0, shift = 0;
203
Juan Cespedesa0ccf392003-02-01 19:02:37 +0100204 assert(key);
Juan Cespedescac15c32003-01-31 18:58:58 +0100205 while (*s) {
206 total = total ^ ((*s) << shift);
207 shift += 5;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100208 if (shift > 24)
209 shift -= 24;
Juan Cespedescac15c32003-01-31 18:58:58 +0100210 s++;
211 }
212 return total;
213}
214
Juan Cespedesf1350522008-12-16 18:19:58 +0100215int
Petr Machata345c9b52012-02-10 13:10:03 +0100216dict_key_cmp_string(const void *key1, const void *key2)
217{
Juan Cespedesa0ccf392003-02-01 19:02:37 +0100218 assert(key1);
219 assert(key2);
Juan Cespedescac15c32003-01-31 18:58:58 +0100220 return strcmp((const char *)key1, (const char *)key2);
221}
222
Juan Cespedesf1350522008-12-16 18:19:58 +0100223unsigned int
Petr Machata345c9b52012-02-10 13:10:03 +0100224dict_key2hash_int(const void *key)
225{
Juan Cespedesd914a202004-11-10 00:15:33 +0100226 return (unsigned long)key;
Juan Cespedescac15c32003-01-31 18:58:58 +0100227}
228
Juan Cespedesf1350522008-12-16 18:19:58 +0100229int
Petr Machata345c9b52012-02-10 13:10:03 +0100230dict_key_cmp_int(const void *key1, const void *key2)
231{
Juan Cespedescac15c32003-01-31 18:58:58 +0100232 return key1 - key2;
233}
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200234
Juan Cespedes8d1b92b2009-07-03 10:39:34 +0200235Dict *
Petr Machata534e00f2011-09-27 17:58:38 +0200236dict_clone2(Dict * old, void * (*key_clone)(void *, void *),
237 void * (*value_clone)(void *, void *), void * data)
238{
Juan Cespedes8d1b92b2009-07-03 10:39:34 +0200239 Dict *d;
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200240 int i;
241
Juan Cespedescd8976d2009-05-14 13:47:58 +0200242 debug(DEBUG_FUNCTION, "dict_clone()");
243
Juan Cespedes8d1b92b2009-07-03 10:39:34 +0200244 d = malloc(sizeof(Dict));
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200245 if (!d) {
246 perror("malloc()");
247 exit(1);
248 }
Juan Cespedes8d1b92b2009-07-03 10:39:34 +0200249 memcpy(d, old, sizeof(Dict));
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200250 for (i = 0; i < DICTTABLESIZE; i++) { /* better use memset()? */
251 struct dict_entry *de_old;
252 struct dict_entry **de_new;
253
254 de_old = old->buckets[i];
255 de_new = &d->buckets[i];
256 while (de_old) {
Petr Machata534e00f2011-09-27 17:58:38 +0200257 void * nkey, * nval;
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200258 *de_new = malloc(sizeof(struct dict_entry));
259 if (!*de_new) {
260 perror("malloc()");
261 exit(1);
262 }
263 memcpy(*de_new, de_old, sizeof(struct dict_entry));
Petr Machata534e00f2011-09-27 17:58:38 +0200264
265 /* The error detection is rather weak :-/ */
266 nkey = key_clone(de_old->key, data);
267 if (nkey == NULL && de_old->key != NULL) {
268 perror("key_clone");
269 err:
270 /* XXX Will this actually work? We
271 * simply memcpy the old dictionary
272 * over up there. */
273 dict_clear(d);
274 free(de_new);
275 return NULL;
276 }
277
278 nval = value_clone(de_old->value, data);
279 if (nval == NULL && de_old->value != NULL) {
280 perror("value_clone");
281 goto err;
282 }
283
284 (*de_new)->key = nkey;
285 (*de_new)->value = nval;
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200286 de_new = &(*de_new)->next;
287 de_old = de_old->next;
288 }
289 }
290 return d;
291}
Petr Machata534e00f2011-09-27 17:58:38 +0200292
293struct wrap_clone_cb
294{
295 void * (*key_clone)(void *);
296 void * (*value_clone)(void *);
297};
298
299static void *
300value_clone_1(void * arg, void * data)
301{
302 return ((struct wrap_clone_cb *)data)->value_clone(arg);
303}
304
305static void *
306key_clone_1(void * arg, void * data)
307{
308 return ((struct wrap_clone_cb *)data)->key_clone(arg);
309}
310
311Dict *
312dict_clone(Dict * old, void * (*key_clone)(void *),
313 void * (*value_clone)(void *))
314{
315 struct wrap_clone_cb cb = { key_clone, value_clone };
316 return dict_clone2(old, &key_clone_1, &value_clone_1, &cb);
317}