diff options
author | Michal Schmidt <mschmidt@redhat.com> | 2014-09-15 16:43:59 -0400 |
---|---|---|
committer | Anthony G. Basile <blueness@gentoo.org> | 2014-09-15 16:43:59 -0400 |
commit | 7398282096ba4a74b11c18082cab7db32c2b0da1 (patch) | |
tree | 77eaf24ef7c223963ab4d498d5f350932b17ff6c /src/shared/hashmap.c | |
parent | 35257b404e1b449bcfbcbbf7dd4a713927bec8ed (diff) |
hashmap: introduce hash_ops to make struct Hashmap smaller
It is redundant to store 'hash' and 'compare' function pointers in
struct Hashmap separately. The functions always comprise a pair.
Store a single pointer to struct hash_ops instead.
systemd keeps hundreds of hashmaps, so this saves a little bit of
memory.
Signed-off-by: Anthony G. Basile <blueness@gentoo.org>
Diffstat (limited to 'src/shared/hashmap.c')
-rw-r--r-- | src/shared/hashmap.c | 111 |
1 files changed, 55 insertions, 56 deletions
diff --git a/src/shared/hashmap.c b/src/shared/hashmap.c index 38dce11921..95ef918ed3 100644 --- a/src/shared/hashmap.c +++ b/src/shared/hashmap.c @@ -37,8 +37,7 @@ struct hashmap_entry { }; struct Hashmap { - hash_func_t hash_func; - compare_func_t compare_func; + const struct hash_ops *hash_ops; struct hashmap_entry *iterate_list_head, *iterate_list_tail; @@ -119,6 +118,11 @@ int string_compare_func(const void *a, const void *b) { return strcmp(a, b); } +const struct hash_ops string_hash_ops = { + .hash = string_hash_func, + .compare = string_compare_func +}; + unsigned long trivial_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) { uint64_t u; siphash24((uint8_t*) &u, &p, sizeof(p), hash_key); @@ -129,8 +133,13 @@ int trivial_compare_func(const void *a, const void *b) { return a < b ? -1 : (a > b ? 1 : 0); } +const struct hash_ops trivial_hash_ops = { + .hash = trivial_hash_func, + .compare = trivial_compare_func +}; + static unsigned bucket_hash(Hashmap *h, const void *p) { - return (unsigned) (h->hash_func(p, h->hash_key) % h->n_buckets); + return (unsigned) (h->hash_ops->hash(p, h->hash_key) % h->n_buckets); } static void get_hash_key(uint8_t hash_key[HASH_KEY_SIZE], bool reuse_is_ok) { @@ -152,7 +161,7 @@ static void get_hash_key(uint8_t hash_key[HASH_KEY_SIZE], bool reuse_is_ok) { memcpy(hash_key, current, sizeof(current)); } -Hashmap *hashmap_new(hash_func_t hash_func, compare_func_t compare_func) { +Hashmap *hashmap_new(const struct hash_ops *hash_ops) { bool b; Hashmap *h; size_t size; @@ -174,8 +183,7 @@ Hashmap *hashmap_new(hash_func_t hash_func, compare_func_t compare_func) { return NULL; } - h->hash_func = hash_func ? hash_func : trivial_hash_func; - h->compare_func = compare_func ? compare_func : trivial_compare_func; + h->hash_ops = hash_ops ? hash_ops : &trivial_hash_ops; h->n_buckets = INITIAL_N_BUCKETS; h->n_entries = 0; @@ -314,7 +322,7 @@ static struct hashmap_entry *hash_scan(Hashmap *h, unsigned hash, const void *ke assert(hash < h->n_buckets); for (e = h->buckets[hash]; e; e = e->bucket_next) - if (h->compare_func(e->key, key) == 0) + if (h->hash_ops->compare(e->key, key) == 0) return e; return NULL; @@ -346,7 +354,7 @@ static bool resize_buckets(Hashmap *h) { for (i = h->iterate_list_head; i; i = i->iterate_next) { unsigned long old_bucket, new_bucket; - old_bucket = h->hash_func(i->key, h->hash_key) % h->n_buckets; + old_bucket = h->hash_ops->hash(i->key, h->hash_key) % h->n_buckets; /* First, drop from old bucket table */ if (i->bucket_next) @@ -358,7 +366,7 @@ static bool resize_buckets(Hashmap *h) { h->buckets[old_bucket] = i->bucket_next; /* Then, add to new backet table */ - new_bucket = h->hash_func(i->key, nkey) % m; + new_bucket = h->hash_ops->hash(i->key, nkey) % m; i->bucket_next = n[new_bucket]; i->bucket_previous = NULL; @@ -378,19 +386,10 @@ static bool resize_buckets(Hashmap *h) { return true; } -int hashmap_put(Hashmap *h, const void *key, void *value) { - struct hashmap_entry *e; - unsigned hash; - - assert(h); +static int __hashmap_put(Hashmap *h, const void *key, void *value, unsigned hash) { + /* For when we know no such entry exists yet */ - hash = bucket_hash(h, key); - e = hash_scan(h, hash, key); - if (e) { - if (e->value == value) - return 0; - return -EEXIST; - } + struct hashmap_entry *e; if (resize_buckets(h)) hash = bucket_hash(h, key); @@ -411,6 +410,23 @@ int hashmap_put(Hashmap *h, const void *key, void *value) { return 1; } +int hashmap_put(Hashmap *h, const void *key, void *value) { + struct hashmap_entry *e; + unsigned hash; + + assert(h); + + hash = bucket_hash(h, key); + e = hash_scan(h, hash, key); + if (e) { + if (e->value == value) + return 0; + return -EEXIST; + } + + return __hashmap_put(h, key, value, hash); +} + void* hashmap_get(Hashmap *h, const void *key) { unsigned hash; struct hashmap_entry *e; @@ -426,6 +442,24 @@ void* hashmap_get(Hashmap *h, const void *key) { return e->value; } +void* hashmap_get2(Hashmap *h, const void *key, void **key2) { + unsigned hash; + struct hashmap_entry *e; + + if (!h) + return NULL; + + hash = bucket_hash(h, key); + e = hash_scan(h, hash, key); + if (!e) + return NULL; + + if (key2) + *key2 = (void*) e->key; + + return e->value; +} + bool hashmap_contains(Hashmap *h, const void *key) { unsigned hash; @@ -471,41 +505,6 @@ at_end: return NULL; } -void *hashmap_iterate_backwards(Hashmap *h, Iterator *i, const void **key) { - struct hashmap_entry *e; - - assert(i); - - if (!h) - goto at_beginning; - - if (*i == ITERATOR_FIRST) - goto at_beginning; - - if (*i == ITERATOR_LAST && !h->iterate_list_tail) - goto at_beginning; - - e = *i == ITERATOR_LAST ? h->iterate_list_tail : (struct hashmap_entry*) *i; - - if (e->iterate_previous) - *i = (Iterator) e->iterate_previous; - else - *i = ITERATOR_FIRST; - - if (key) - *key = e->key; - - return e->value; - -at_beginning: - *i = ITERATOR_FIRST; - - if (key) - *key = NULL; - - return NULL; -} - void* hashmap_steal_first(Hashmap *h) { void *data; |