X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=hashmap.c;h=a81bcc422ec219fea5c1d0d034c1c2856d112da7;hp=1b2e059ddeb6b0c06b9dd6f7b8585fb084585d95;hb=f00b3eda2f92b2dcd13c50749ec5e7fce6720b52;hpb=6091827530d6dd43479d6709fb6e9f745c11e900 diff --git a/hashmap.c b/hashmap.c index 1b2e059dd..a81bcc422 100644 --- a/hashmap.c +++ b/hashmap.c @@ -18,7 +18,6 @@ struct hashmap_entry { const void *key; void *value; - struct hashmap_entry *bucket_next, *bucket_previous; struct hashmap_entry *iterate_next, *iterate_previous; }; @@ -107,12 +106,19 @@ void hashmap_free(Hashmap*h) { if (!h) return; - while (h->iterate_list_head) - remove_entry(h, h->iterate_list_head); + hashmap_clear(h); free(h); } +void hashmap_clear(Hashmap *h) { + if (!h) + return; + + while (h->iterate_list_head) + remove_entry(h, h->iterate_list_head); +} + static struct hashmap_entry *hash_scan(Hashmap *h, unsigned hash, const void *key) { struct hashmap_entry *e; assert(h); @@ -133,8 +139,13 @@ int hashmap_put(Hashmap *h, const void *key, void *value) { hash = h->hash_func(key) % NBUCKETS; - if (hash_scan(h, hash, key)) + if ((e = hash_scan(h, hash, key))) { + + if (e->value == value) + return 0; + return -EEXIST; + } if (!(e = new(struct hashmap_entry, 1))) return -ENOMEM; @@ -167,6 +178,22 @@ int hashmap_put(Hashmap *h, const void *key, void *value) { return 0; } +int hashmap_replace(Hashmap *h, const void *key, void *value) { + struct hashmap_entry *e; + unsigned hash; + + assert(h); + + hash = h->hash_func(key) % NBUCKETS; + + if ((e = hash_scan(h, hash, key))) { + e->value = value; + return 0; + } + + return hashmap_put(h, key, value); +} + void* hashmap_get(Hashmap *h, const void *key) { unsigned hash; struct hashmap_entry *e; @@ -201,6 +228,26 @@ void* hashmap_remove(Hashmap *h, const void *key) { return data; } +void* hashmap_remove_value(Hashmap *h, const void *key, void *value) { + struct hashmap_entry *e; + unsigned hash; + + if (!h) + return NULL; + + hash = h->hash_func(key) % NBUCKETS; + + if (!(e = hash_scan(h, hash, key))) + return NULL; + + if (e->value != value) + return NULL; + + remove_entry(h, e); + + return value; +} + void *hashmap_iterate(Hashmap *h, void **state, const void **key) { struct hashmap_entry *e; @@ -323,3 +370,38 @@ bool hashmap_isempty(Hashmap *h) { return h->n_entries == 0; } + +int hashmap_merge(Hashmap *h, Hashmap *other) { + struct hashmap_entry *e; + + assert(h); + + if (!other) + return 0; + + for (e = other->iterate_list_head; e; e = e->iterate_next) { + int r; + + if ((r = hashmap_put(h, e->key, e->value)) < 0) + if (r != -EEXIST) + return r; + } + + return 0; +} + +Hashmap *hashmap_copy(Hashmap *h) { + Hashmap *copy; + + assert(h); + + if (!(copy = hashmap_new(h->hash_func, h->compare_func))) + return NULL; + + if (hashmap_merge(copy, h) < 0) { + hashmap_free(copy); + return NULL; + } + + return copy; +}