aboutsummaryrefslogtreecommitdiff
path: root/libctf
diff options
context:
space:
mode:
Diffstat (limited to 'libctf')
-rw-r--r--libctf/ctf-hash.c149
-rw-r--r--libctf/ctf-impl.h13
-rw-r--r--libctf/ctf-open.c12
3 files changed, 148 insertions, 26 deletions
diff --git a/libctf/ctf-hash.c b/libctf/ctf-hash.c
index a11d11e..8b5c379 100644
--- a/libctf/ctf-hash.c
+++ b/libctf/ctf-hash.c
@@ -46,13 +46,54 @@ typedef struct ctf_helem
ctf_dynhash_t *owner; /* The hash that owns us. */
} ctf_helem_t;
-/* Equally, the key_free and value_free may not exist. */
+/* Equally, the key_free_ and value_free_ may not exist: if neither do, the
+ arg will not exist either. */
struct ctf_dynhash
{
struct htab *htab;
- ctf_hash_free_fun key_free;
- ctf_hash_free_fun value_free;
+
+ /* The freeing functions may be of type ctf_hash_free_fun, if arg is NULL,
+ or ctf_hash_free_arg_fun, if it is not.
+
+ Everything from this point on is allocated only if we have at least one
+ freeing function defined. */
+
+#ifdef __GNUC__
+ __extension__
+ union
+ {
+ ctf_hash_free_fun key_free_;
+ ctf_hash_free_arg_fun key_arg_free_;
+ };
+
+ __extension__
+ union
+ {
+ ctf_hash_free_fun value_free_;
+ ctf_hash_free_arg_fun value_arg_free_;
+ };
+#else
+ union
+ {
+ ctf_hash_free_fun key_free_;
+ ctf_hash_free_arg_fun key_arg_free_;
+ } _k;
+
+ union
+ {
+ ctf_hash_free_fun value_free_;
+ ctf_hash_free_arg_fun value_arg_free_;
+ } _v;
+
+#define key_free_ _k.key_free_
+#define key_arg_free_ _k.key_arg_free_
+#define value_free_ _v.value_free_
+#define value_arg_free_ _v.value_arg_free_
+
+#endif
+
+ void *arg; /* arg to freeing functions. */
};
/* Hash and eq functions for the dynhash and hash. */
@@ -146,17 +187,30 @@ ctf_dynhash_item_free (void *item)
{
ctf_helem_t *helem = item;
- if (helem->owner->key_free && helem->key)
- helem->owner->key_free (helem->key);
- if (helem->owner->value_free && helem->value)
- helem->owner->value_free (helem->value);
+ if (helem->owner->key_free_ && helem->key)
+ {
+ if (!helem->owner->arg)
+ helem->owner->key_free_ (helem->key);
+ else
+ helem->owner->key_arg_free_ (helem->key, helem->owner->arg);
+ }
+ if (helem->owner->value_free_ && helem->value)
+ {
+ if (!helem->owner->arg)
+ helem->owner->value_free_ (helem->value);
+ else
+ {
+ helem->owner->value_arg_free_ (helem->value, helem->owner->arg);
+ }
+ }
free (helem);
}
ctf_dynhash_t *
ctf_dynhash_create_sized (unsigned long nelems, ctf_hash_fun hash_fun,
- ctf_hash_eq_fun eq_fun, ctf_hash_free_fun key_free,
- ctf_hash_free_fun value_free)
+ ctf_hash_eq_fun eq_fun,
+ ctf_hash_free_arg_fun key_free,
+ ctf_hash_free_arg_fun value_free, void *arg)
{
ctf_dynhash_t *dynhash;
htab_del del = ctf_dynhash_item_free;
@@ -165,7 +219,7 @@ ctf_dynhash_create_sized (unsigned long nelems, ctf_hash_fun hash_fun,
dynhash = malloc (sizeof (ctf_dynhash_t));
else
{
- void *p = malloc (offsetof (ctf_dynhash_t, key_free));
+ void *p = malloc (offsetof (ctf_dynhash_t, key_free_));
dynhash = p;
}
if (!dynhash)
@@ -183,20 +237,44 @@ ctf_dynhash_create_sized (unsigned long nelems, ctf_hash_fun hash_fun,
if (key_free || value_free)
{
- dynhash->key_free = key_free;
- dynhash->value_free = value_free;
+ dynhash->key_arg_free_ = key_free;
+ dynhash->value_arg_free_ = value_free;
+ dynhash->arg = arg;
}
return dynhash;
}
ctf_dynhash_t *
+ctf_dynhash_create_arg (ctf_hash_fun hash_fun, ctf_hash_eq_fun eq_fun,
+ ctf_hash_free_arg_fun key_free,
+ ctf_hash_free_arg_fun value_free,
+ void *arg)
+{
+ /* 7 is arbitrary and not benchmarked yet. */
+
+ return ctf_dynhash_create_sized (7, hash_fun, eq_fun, key_free, value_free, arg);
+}
+
+ctf_dynhash_t *
ctf_dynhash_create (ctf_hash_fun hash_fun, ctf_hash_eq_fun eq_fun,
ctf_hash_free_fun key_free, ctf_hash_free_fun value_free)
{
+ union cast
+ {
+ ctf_hash_free_fun in;
+ ctf_hash_free_arg_fun out;
+ };
+ union cast key_arg_free;
+ union cast value_arg_free;
+
+ key_arg_free.in = key_free;
+ value_arg_free.in = value_free;
+
/* 7 is arbitrary and not benchmarked yet. */
- return ctf_dynhash_create_sized (7, hash_fun, eq_fun, key_free, value_free);
+ return ctf_dynhash_create_sized (7, hash_fun, eq_fun, key_arg_free.out,
+ value_arg_free.out, NULL);
}
static ctf_helem_t **
@@ -209,7 +287,8 @@ ctf_hashtab_lookup (struct htab *htab, const void *key, enum insert_option inser
static ctf_helem_t *
ctf_hashtab_insert (struct htab *htab, void *key, void *value,
ctf_hash_free_fun key_free,
- ctf_hash_free_fun value_free)
+ ctf_hash_free_fun value_free,
+ void *arg)
{
ctf_helem_t **slot;
@@ -238,10 +317,37 @@ ctf_hashtab_insert (struct htab *htab, void *key, void *value,
}
else
{
+ union cast
+ {
+ ctf_hash_free_fun in;
+ ctf_hash_free_arg_fun out;
+ };
+
if (key_free)
- key_free (key);
+ {
+ {if (!arg)
+ key_free (key);
+ else
+ {
+ union cast key_arg_free;
+
+ key_arg_free.in = key_free;
+ key_arg_free.out (key, arg);
+ }
+ }
+ }
if (value_free)
- value_free ((*slot)->value);
+ {
+ if (!arg)
+ value_free ((*slot)->value);
+ else
+ {
+ union cast value_arg_free;
+
+ value_arg_free.in = value_free;
+ value_arg_free.out ((*slot)->value, arg);
+ }
+ }
}
(*slot)->value = value;
return *slot;
@@ -252,14 +358,16 @@ ctf_dynhash_insert (ctf_dynhash_t *hp, void *key, void *value)
{
ctf_helem_t *slot;
ctf_hash_free_fun key_free = NULL, value_free = NULL;
+ void *arg = NULL;
if (hp->htab->del_f == ctf_dynhash_item_free)
{
- key_free = hp->key_free;
- value_free = hp->value_free;
+ key_free = hp->key_free_;
+ value_free = hp->value_free_;
+ arg = hp->arg;
}
slot = ctf_hashtab_insert (hp->htab, key, value,
- key_free, value_free);
+ key_free, value_free, arg);
if (!slot)
return -errno;
@@ -579,7 +687,8 @@ ctf_dynhash_destroy (ctf_dynhash_t *hp)
/* The dynset, used for sets of keys with no value. The implementation of this
can be much simpler, because without a value the slot can simply be the
stored key, which means we don't need to store the freeing functions and the
- dynset itself is just a htab. */
+ dynset itself is just a htab. There is no support for freeing
+ functions with args. */
ctf_dynset_t *
ctf_dynset_create (htab_hash hash_fun, htab_eq eq_fun,
diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h
index c50f06e..90b0b95 100644
--- a/libctf/ctf-impl.h
+++ b/libctf/ctf-impl.h
@@ -651,7 +651,12 @@ extern int ctf_hash_eq_string (const void *, const void *);
extern int ctf_hash_eq_type_key (const void *, const void *);
extern int ctf_hash_eq_type_id_key (const void *, const void *);
+/* Freeing functions. ctf_hash_free_fun is used unless the arg
+ parameter to ctf_dynhash_create_{arg,sized} is non-NULL.
+ There is no way to pass a NULL arg to ctf_hash_free_arg_fun. */
+
typedef void (*ctf_hash_free_fun) (void *);
+typedef void (*ctf_hash_free_arg_fun) (void *, void *);
typedef void (*ctf_hash_iter_f) (void *key, void *value, void *arg);
typedef int (*ctf_hash_iter_remove_f) (void *key, void *value, void *arg);
@@ -661,10 +666,14 @@ typedef int (*ctf_hash_sort_f) (const ctf_next_hkv_t *, const ctf_next_hkv_t *,
extern ctf_dynhash_t *ctf_dynhash_create (ctf_hash_fun, ctf_hash_eq_fun,
ctf_hash_free_fun, ctf_hash_free_fun);
+extern ctf_dynhash_t *ctf_dynhash_create_arg (ctf_hash_fun, ctf_hash_eq_fun,
+ ctf_hash_free_arg_fun,
+ ctf_hash_free_arg_fun, void *);
extern ctf_dynhash_t *ctf_dynhash_create_sized (unsigned long, ctf_hash_fun,
ctf_hash_eq_fun,
- ctf_hash_free_fun,
- ctf_hash_free_fun);
+ ctf_hash_free_arg_fun,
+ ctf_hash_free_arg_fun,
+ void *);
extern int ctf_dynhash_insert (ctf_dynhash_t *, void *, void *);
extern void ctf_dynhash_remove (ctf_dynhash_t *, const void *);
diff --git a/libctf/ctf-open.c b/libctf/ctf-open.c
index 219831b..4cf18f0 100644
--- a/libctf/ctf-open.c
+++ b/libctf/ctf-open.c
@@ -791,17 +791,20 @@ init_static_types (ctf_dict_t *fp, ctf_header_t *cth)
if ((fp->ctf_structs
= ctf_dynhash_create_sized (pop[CTF_K_STRUCT], ctf_hash_string,
- ctf_hash_eq_string, NULL, NULL)) == NULL)
+ ctf_hash_eq_string,
+ NULL, NULL, NULL)) == NULL)
return ENOMEM;
if ((fp->ctf_unions
= ctf_dynhash_create_sized (pop[CTF_K_UNION], ctf_hash_string,
- ctf_hash_eq_string, NULL, NULL)) == NULL)
+ ctf_hash_eq_string,
+ NULL, NULL, NULL)) == NULL)
return ENOMEM;
if ((fp->ctf_enums
= ctf_dynhash_create_sized (pop[CTF_K_ENUM], ctf_hash_string,
- ctf_hash_eq_string, NULL, NULL)) == NULL)
+ ctf_hash_eq_string,
+ NULL, NULL, NULL)) == NULL)
return ENOMEM;
if ((fp->ctf_names
@@ -816,7 +819,8 @@ init_static_types (ctf_dict_t *fp, ctf_header_t *cth)
pop[CTF_K_RESTRICT] +
pop_enumerators,
ctf_hash_string,
- ctf_hash_eq_string, NULL, NULL)) == NULL)
+ ctf_hash_eq_string,
+ NULL, NULL, NULL)) == NULL)
return ENOMEM;
if ((fp->ctf_conflicting_enums