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 | |
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>
-rw-r--r-- | src/shared/cgroup-util.c | 2 | ||||
-rw-r--r-- | src/shared/conf-files.c | 2 | ||||
-rw-r--r-- | src/shared/hashmap.c | 111 | ||||
-rw-r--r-- | src/shared/hashmap.h | 11 | ||||
-rw-r--r-- | src/shared/set.c | 8 | ||||
-rw-r--r-- | src/shared/set.h | 2 |
6 files changed, 69 insertions, 67 deletions
diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c index 76ab747292..3f9018cf1f 100644 --- a/src/shared/cgroup-util.c +++ b/src/shared/cgroup-util.c @@ -84,7 +84,7 @@ int cg_kill(const char *controller, const char *path, int sig, bool sigcont, boo * tasks list, to properly handle forking processes */ if (!s) { - s = allocated_set = set_new(trivial_hash_func, trivial_compare_func); + s = allocated_set = set_new(NULL); if (!s) return -ENOMEM; } diff --git a/src/shared/conf-files.c b/src/shared/conf-files.c index 6675a1c26c..c68f361136 100644 --- a/src/shared/conf-files.c +++ b/src/shared/conf-files.c @@ -107,7 +107,7 @@ static int conf_files_list_strv_internal(char ***strv, const char *suffix, const if (!path_strv_resolve_uniq(dirs, root)) return -ENOMEM; - fh = hashmap_new(string_hash_func, string_compare_func); + fh = hashmap_new(&string_hash_ops); if (!fh) return -ENOMEM; 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; diff --git a/src/shared/hashmap.h b/src/shared/hashmap.h index b739262ab3..53b04eb033 100644 --- a/src/shared/hashmap.h +++ b/src/shared/hashmap.h @@ -41,27 +41,34 @@ typedef _IteratorStruct* Iterator; typedef unsigned long (*hash_func_t)(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]); typedef int (*compare_func_t)(const void *a, const void *b); +struct hash_ops { + hash_func_t hash; + compare_func_t compare; +}; + unsigned long string_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) _pure_; int string_compare_func(const void *a, const void *b) _pure_; +extern const struct hash_ops string_hash_ops; /* This will compare the passed pointers directly, and will not * dereference them. This is hence not useful for strings or * suchlike. */ unsigned long trivial_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) _pure_; int trivial_compare_func(const void *a, const void *b) _const_; +extern const struct hash_ops trivial_hash_ops; -Hashmap *hashmap_new(hash_func_t hash_func, compare_func_t compare_func); +Hashmap *hashmap_new(const struct hash_ops *hash_ops); void hashmap_free(Hashmap *h); void hashmap_free_free(Hashmap *h); int hashmap_put(Hashmap *h, const void *key, void *value); void *hashmap_get(Hashmap *h, const void *key); +void *hashmap_get2(Hashmap *h, const void *key, void **rkey); bool hashmap_contains(Hashmap *h, const void *key); unsigned hashmap_size(Hashmap *h) _pure_; void *hashmap_iterate(Hashmap *h, Iterator *i, const void **key); -void *hashmap_iterate_backwards(Hashmap *h, Iterator *i, const void **key); void hashmap_clear(Hashmap *h); void hashmap_clear_free(Hashmap *h); diff --git a/src/shared/set.c b/src/shared/set.c index 8b89d45cc4..4b8c76feca 100644 --- a/src/shared/set.c +++ b/src/shared/set.c @@ -27,8 +27,8 @@ /* For now this is not much more than a wrapper around a hashmap */ -Set *set_new(hash_func_t hash_func, compare_func_t compare_func) { - return MAKE_SET(hashmap_new(hash_func, compare_func)); +Set *set_new(const struct hash_ops *hash_ops) { + return MAKE_SET(hashmap_new(hash_ops)); } void set_free(Set* s) { @@ -50,7 +50,3 @@ bool set_contains(Set *s, void *value) { void *set_iterate(Set *s, Iterator *i) { return hashmap_iterate(MAKE_HASHMAP(s), i, NULL); } - -void *set_iterate_backwards(Set *s, Iterator *i) { - return hashmap_iterate_backwards(MAKE_HASHMAP(s), i, NULL); -} diff --git a/src/shared/set.h b/src/shared/set.h index 39a5a495f5..b2f473428e 100644 --- a/src/shared/set.h +++ b/src/shared/set.h @@ -30,7 +30,7 @@ typedef struct Set Set; -Set *set_new(hash_func_t hash_func, compare_func_t compare_func); +Set *set_new(const struct hash_ops *hash_ops); void set_free(Set* s); int set_put(Set *s, void *value); |