aboutsummaryrefslogtreecommitdiff
path: root/libctf/ctf-hash.c
diff options
context:
space:
mode:
Diffstat (limited to 'libctf/ctf-hash.c')
-rw-r--r--libctf/ctf-hash.c68
1 files changed, 47 insertions, 21 deletions
diff --git a/libctf/ctf-hash.c b/libctf/ctf-hash.c
index 1c37d75..caefd99 100644
--- a/libctf/ctf-hash.c
+++ b/libctf/ctf-hash.c
@@ -31,14 +31,19 @@
not support removal. These can be implemented by the same underlying hashmap
if you wish. */
+/* The helem is used for general key/value mappings in both the ctf_hash and
+ ctf_dynhash: the owner may not have space allocated for it, and will be
+ garbage (not NULL!) in that case. */
+
typedef struct ctf_helem
{
void *key; /* Either a pointer, or a coerced ctf_id_t. */
void *value; /* The value (possibly a coerced int). */
- ctf_hash_free_fun key_free;
- ctf_hash_free_fun value_free;
+ ctf_dynhash_t *owner; /* The hash that owns us. */
} ctf_helem_t;
+/* Equally, the key_free and value_free may not exist. */
+
struct ctf_dynhash
{
struct htab *htab;
@@ -106,17 +111,17 @@ ctf_hash_eq_type_mapping_key (const void *a, const void *b)
/* The dynhash, used for hashes whose size is not known at creation time. */
-/* Free a single ctf_helem. */
+/* Free a single ctf_helem with arbitrary key/value functions. */
static void
ctf_dynhash_item_free (void *item)
{
ctf_helem_t *helem = item;
- if (helem->key_free && helem->key)
- helem->key_free (helem->key);
- if (helem->value_free && helem->value)
- helem->value_free (helem->value);
+ 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);
free (helem);
}
@@ -125,21 +130,31 @@ 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)
{
ctf_dynhash_t *dynhash;
+ htab_del del = ctf_dynhash_item_free;
- dynhash = malloc (sizeof (ctf_dynhash_t));
+ if (key_free || value_free)
+ dynhash = malloc (sizeof (ctf_dynhash_t));
+ else
+ dynhash = malloc (offsetof (ctf_dynhash_t, key_free));
if (!dynhash)
return NULL;
- /* 7 is arbitrary and untested for now.. */
+ if (key_free == NULL && value_free == NULL)
+ del = free;
+
+ /* 7 is arbitrary and untested for now. */
if ((dynhash->htab = htab_create_alloc (7, (htab_hash) hash_fun, eq_fun,
- ctf_dynhash_item_free, xcalloc, free)) == NULL)
+ del, xcalloc, free)) == NULL)
{
free (dynhash);
return NULL;
}
- dynhash->key_free = key_free;
- dynhash->value_free = value_free;
+ if (key_free || value_free)
+ {
+ dynhash->key_free = key_free;
+ dynhash->value_free = value_free;
+ }
return dynhash;
}
@@ -162,13 +177,18 @@ ctf_hashtab_insert (struct htab *htab, void *key, void *value,
if (!slot)
{
- errno = -ENOMEM;
+ errno = ENOMEM;
return NULL;
}
if (!*slot)
{
- *slot = malloc (sizeof (ctf_helem_t));
+ /* Only spend space on the owner if we're going to use it: if there is a
+ key or value freeing function. */
+ if (key_free || value_free)
+ *slot = malloc (sizeof (ctf_helem_t));
+ else
+ *slot = malloc (offsetof (ctf_helem_t, owner));
if (!*slot)
return NULL;
(*slot)->key = key;
@@ -188,19 +208,25 @@ int
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;
+ if (hp->htab->del_f == ctf_dynhash_item_free)
+ {
+ key_free = hp->key_free;
+ value_free = hp->value_free;
+ }
slot = ctf_hashtab_insert (hp->htab, key, value,
- hp->key_free, hp->value_free);
+ key_free, value_free);
if (!slot)
return errno;
- /* We need to keep the key_free and value_free around in each item because the
- del function has no visibility into the hash as a whole, only into the
- individual items. */
+ /* Keep track of the owner, so that the del function can get at the key_free
+ and value_free functions. Only do this if one of those functions is set:
+ if not, the owner is not even present in the helem. */
- slot->key_free = hp->key_free;
- slot->value_free = hp->value_free;
+ if (key_free || value_free)
+ slot->owner = hp;
return 0;
}
@@ -208,7 +234,7 @@ ctf_dynhash_insert (ctf_dynhash_t *hp, void *key, void *value)
void
ctf_dynhash_remove (ctf_dynhash_t *hp, const void *key)
{
- ctf_helem_t hep = { (void *) key, NULL, NULL, NULL };
+ ctf_helem_t hep = { (void *) key, NULL, NULL };
htab_remove_elt (hp->htab, &hep);
}