summaryrefslogtreecommitdiff
path: root/dict.c
diff options
context:
space:
mode:
Diffstat (limited to 'dict.c')
-rw-r--r--dict.c130
1 files changed, 116 insertions, 14 deletions
diff --git a/dict.c b/dict.c
index 486a461..aad50fd 100644
--- a/dict.c
+++ b/dict.c
@@ -1,3 +1,25 @@
+/*
+ * This file is part of ltrace.
+ * Copyright (C) 2011,2012 Petr Machata
+ * Copyright (C) 2003,2004,2008,2009 Juan Cespedes
+ * Copyright (C) 2006 Ian Wienand
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -6,8 +28,8 @@
#include "common.h"
/*
- Dictionary based on code by Morten Eriksen <mortene@sim.no>.
-*/
+ * Dictionary based on code by Morten Eriksen <mortene@sim.no>.
+ */
struct dict_entry {
unsigned int hash;
@@ -24,13 +46,14 @@ struct dict_entry {
struct dict {
struct dict_entry *buckets[DICTTABLESIZE];
- unsigned int (*key2hash) (void *);
- int (*key_cmp) (void *, void *);
+ unsigned int (*key2hash) (const void *);
+ int (*key_cmp) (const void *, const void *);
};
Dict *
-dict_init(unsigned int (*key2hash) (void *),
- int (*key_cmp) (void *, void *)) {
+dict_init(unsigned int (*key2hash) (const void *),
+ int (*key_cmp) (const void *, const void *))
+{
Dict *d;
int i;
@@ -103,7 +126,33 @@ dict_enter(Dict *d, void *key, void *value) {
}
void *
-dict_find_entry(Dict *d, void *key) {
+dict_remove(Dict *d, void *key)
+{
+ assert(d != NULL);
+ debug(DEBUG_FUNCTION, "dict_remove(%p)", key);
+
+ unsigned int hash = d->key2hash(key);
+ unsigned int bucketpos = hash % DICTTABLESIZE;
+
+ struct dict_entry **entryp;
+ for (entryp = &d->buckets[bucketpos]; (*entryp) != NULL;
+ entryp = &(*entryp)->next) {
+ struct dict_entry *entry = *entryp;
+ if (hash != entry->hash)
+ continue;
+ if (d->key_cmp(key, entry->key) == 0) {
+ *entryp = entry->next;
+ void *value = entry->value;
+ free(entry);
+ return value;
+ }
+ }
+ return NULL;
+}
+
+void *
+dict_find_entry(Dict *d, const void *key)
+{
unsigned int hash;
unsigned int bucketpos;
struct dict_entry *entry;
@@ -147,7 +196,8 @@ dict_apply_to_all(Dict *d,
/*****************************************************************************/
unsigned int
-dict_key2hash_string(void *key) {
+dict_key2hash_string(const void *key)
+{
const char *s = (const char *)key;
unsigned int total = 0, shift = 0;
@@ -163,24 +213,29 @@ dict_key2hash_string(void *key) {
}
int
-dict_key_cmp_string(void *key1, void *key2) {
+dict_key_cmp_string(const void *key1, const void *key2)
+{
assert(key1);
assert(key2);
return strcmp((const char *)key1, (const char *)key2);
}
unsigned int
-dict_key2hash_int(void *key) {
+dict_key2hash_int(const void *key)
+{
return (unsigned long)key;
}
int
-dict_key_cmp_int(void *key1, void *key2) {
+dict_key_cmp_int(const void *key1, const void *key2)
+{
return key1 - key2;
}
Dict *
-dict_clone(Dict *old, void * (*key_clone)(void*), void * (*value_clone)(void*)) {
+dict_clone2(Dict * old, void * (*key_clone)(void *, void *),
+ void * (*value_clone)(void *, void *), void * data)
+{
Dict *d;
int i;
@@ -199,17 +254,64 @@ dict_clone(Dict *old, void * (*key_clone)(void*), void * (*value_clone)(void*))
de_old = old->buckets[i];
de_new = &d->buckets[i];
while (de_old) {
+ void * nkey, * nval;
*de_new = malloc(sizeof(struct dict_entry));
if (!*de_new) {
perror("malloc()");
exit(1);
}
memcpy(*de_new, de_old, sizeof(struct dict_entry));
- (*de_new)->key = key_clone(de_old->key);
- (*de_new)->value = value_clone(de_old->value);
+
+ /* The error detection is rather weak :-/ */
+ nkey = key_clone(de_old->key, data);
+ if (nkey == NULL && de_old->key != NULL) {
+ perror("key_clone");
+ err:
+ /* XXX Will this actually work? We
+ * simply memcpy the old dictionary
+ * over up there. */
+ dict_clear(d);
+ free(de_new);
+ return NULL;
+ }
+
+ nval = value_clone(de_old->value, data);
+ if (nval == NULL && de_old->value != NULL) {
+ perror("value_clone");
+ goto err;
+ }
+
+ (*de_new)->key = nkey;
+ (*de_new)->value = nval;
de_new = &(*de_new)->next;
de_old = de_old->next;
}
}
return d;
}
+
+struct wrap_clone_cb
+{
+ void * (*key_clone)(void *);
+ void * (*value_clone)(void *);
+};
+
+static void *
+value_clone_1(void * arg, void * data)
+{
+ return ((struct wrap_clone_cb *)data)->value_clone(arg);
+}
+
+static void *
+key_clone_1(void * arg, void * data)
+{
+ return ((struct wrap_clone_cb *)data)->key_clone(arg);
+}
+
+Dict *
+dict_clone(Dict * old, void * (*key_clone)(void *),
+ void * (*value_clone)(void *))
+{
+ struct wrap_clone_cb cb = { key_clone, value_clone };
+ return dict_clone2(old, &key_clone_1, &value_clone_1, &cb);
+}