libhmap-c

C hashmap library
git clone https://git.sinitax.com/sinitax/libhmap-c
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

commit 3b486140d8b81ef57051cb13050851835da555bf
parent 2cc02a318e3c42e536715e1af1213f25a2440da2
Author: Louis Burda <quent.burda@gmail.com>
Date:   Sun, 19 Mar 2023 00:29:26 +0100

Add copy, swap and allow setting keycmp func

Diffstat:
Minclude/hashmap.h | 28+++++++++++++++++-----------
Mlibhashmap.api | 3+++
Mlibhashmap.lds | 5++++-
Msrc/hashmap.c | 85+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
Msrc/test.c | 3++-
5 files changed, 92 insertions(+), 32 deletions(-)

diff --git a/include/hashmap.h b/include/hashmap.h @@ -9,7 +9,9 @@ #define HASHMAP_ITER(map, iter) \ hashmap_iter_init(iter); hashmap_iter_next(map, iter); -typedef uint32_t (*map_hash_func)(const void *data, size_t size); +typedef uint32_t (*hashmap_hash_func)(const void *data, size_t size); +typedef bool (*hashmap_keycmp_func)(const void *key1, size_t size1, + const void *key2, size_t size2); struct hashmap_link { void *key; @@ -25,20 +27,23 @@ struct hashmap_iter { }; struct hashmap { - map_hash_func hash; + hashmap_hash_func hash; + hashmap_keycmp_func keycmp; struct hashmap_link **buckets; size_t size; const struct allocator *allocator; }; -int hashmap_init(struct hashmap *map, size_t size, map_hash_func hasher, - const struct allocator *allocator); +int hashmap_init(struct hashmap *map, size_t size, hashmap_hash_func hasher, + hashmap_keycmp_func keycmp, const struct allocator *allocator); void hashmap_deinit(struct hashmap *map); -int hashmap_alloc(struct hashmap **map, size_t size, map_hash_func hasher, - const struct allocator *allocator); +int hashmap_alloc(struct hashmap **map, size_t size, hashmap_hash_func hasher, + hashmap_keycmp_func keycmp, const struct allocator *allocator); void hashmap_free(struct hashmap *map); +int hashmap_copy(struct hashmap *dst, const struct hashmap *src); +void hashmap_swap(struct hashmap *m1, struct hashmap *m2); void hashmap_clear(struct hashmap *map); struct hashmap_link *hashmap_get(struct hashmap *map, @@ -46,14 +51,15 @@ struct hashmap_link *hashmap_get(struct hashmap *map, struct hashmap_link *hashmap_pop(struct hashmap *map, const void *key, size_t size); -void hashmap_link_set(struct hashmap *map, +int hashmap_link_set(struct hashmap *map, struct hashmap_link *link, void *key, size_t key_size, void *value, size_t value_size); -int hashmap_set(struct hashmap *map, void *key, size_t key_size, - void *value, size_t value_size); +int hashmap_set(struct hashmap *map, struct hashmap_link **link, + void *key, size_t key_size, void *value, size_t value_size); void hashmap_iter_init(struct hashmap_iter *iter); -bool hashmap_iter_next(struct hashmap *map, struct hashmap_iter *iter); +bool hashmap_iter_next(const struct hashmap *map, struct hashmap_iter *iter); uint32_t hashmap_str_hasher(const void *data, size_t size); - +bool hashmap_default_keycmp(const void *key1, size_t size1, + const void *key2, size_t size2); diff --git a/libhashmap.api b/libhashmap.api @@ -1,6 +1,8 @@ hashmap_init hashmap_deinit +hashmap_copy +hashmap_swap hashmap_clear hashmap_get @@ -13,3 +15,4 @@ hashmap_iter_init hashmap_iter_next hashmap_str_hasher +hashmap_default_keycmp diff --git a/libhashmap.lds b/libhashmap.lds @@ -1,7 +1,9 @@ -LIBHASHMAP_1.1 { +LIBHASHMAP_1.2 { hashmap_init; hashmap_deinit; + hashmap_copy; + hashmap_swap; hashmap_clear; hashmap_get; @@ -14,4 +16,5 @@ LIBHASHMAP_1.1 { hashmap_iter_next; hashmap_str_hasher; + hashmap_default_keycmp; }; diff --git a/src/hashmap.c b/src/hashmap.c @@ -14,12 +14,6 @@ hashmap_key_bucket(struct hashmap *map, const void *key, size_t size) return map->hash(key, size) % map->size; } -static inline bool -hashmap_key_cmp(const void *a, size_t asize, const void *b, size_t bsize) -{ - return asize == bsize && !memcmp(a, b, asize); -} - struct hashmap_link ** hashmap_get_linkp(struct hashmap *map, const void *key, size_t size) { @@ -28,7 +22,7 @@ hashmap_get_linkp(struct hashmap *map, const void *key, size_t size) iter = &map->buckets[hashmap_key_bucket(map, key, size)]; while (*iter != NULL) { link = *iter; - if (hashmap_key_cmp(link->key, link->key_size, key, size)) + if (map->keycmp(link->key, link->key_size, key, size)) return iter; iter = &(*iter)->next; } @@ -56,12 +50,13 @@ hashmap_link_alloc(struct hashmap *map, struct hashmap_link **out, } int -hashmap_init(struct hashmap *map, size_t size, map_hash_func hasher, - const struct allocator *allocator) +hashmap_init(struct hashmap *map, size_t size, hashmap_hash_func hasher, + hashmap_keycmp_func keycmp, const struct allocator *allocator) { int rc; map->allocator = allocator; + map->keycmp = keycmp; map->size = size; map->hash = hasher; @@ -81,15 +76,15 @@ hashmap_deinit(struct hashmap *map) } int -hashmap_alloc(struct hashmap **map, size_t size, map_hash_func hasher, - const struct allocator *allocator) +hashmap_alloc(struct hashmap **map, size_t size, hashmap_hash_func hasher, + hashmap_keycmp_func keycmp, const struct allocator *allocator) { int rc; rc = allocator->alloc((void **)map, sizeof(struct hashmap)); if (rc) return -rc; - rc = hashmap_init(*map, size, hasher, allocator); + rc = hashmap_init(*map, size, hasher, keycmp, allocator); if (rc) { allocator->free(*map); return rc; @@ -108,6 +103,43 @@ hashmap_free(struct hashmap *map) allocator->free(map); } +int +hashmap_copy(struct hashmap *dst, const struct hashmap *src) +{ + struct hashmap_iter iter; + void *key, *value; + size_t key_size; + size_t value_size; + int rc; + + for (HASHMAP_ITER(src, &iter)) { + key_size = iter.link->key_size; + rc = dst->allocator->alloc(&key, key_size); + if (rc) return -rc; + memcpy(key, iter.link->key, key_size); + + value_size = iter.link->value_size; + rc = dst->allocator->alloc(&value, value_size); + if (rc) return -rc; + memcpy(value, iter.link->value, value_size); + + rc = hashmap_set(dst, NULL, key, key_size, value, value_size); + if (rc) return rc; + } + + return 0; +} + +void +hashmap_swap(struct hashmap *m1, struct hashmap *m2) +{ + struct hashmap tmp; + + memcpy(&tmp, m1, sizeof(struct hashmap)); + memcpy(m1, m2, sizeof(struct hashmap)); + memcpy(m2, &tmp, sizeof(struct hashmap)); +} + void hashmap_clear(struct hashmap *map) { @@ -152,22 +184,28 @@ hashmap_pop(struct hashmap *map, const void *key, size_t size) return NULL; } -void +int hashmap_link_set(struct hashmap *map, struct hashmap_link *link, void *key, size_t key_size, void *value, size_t value_size) { - map->allocator->free(link->key); + int rc; + + rc = map->allocator->free(link->key); + if (rc) return -rc; link->key = key; link->key_size = key_size; - map->allocator->free(link->value); + rc = map->allocator->free(link->value); + if (rc) return -rc; link->value = value; link->value_size = value_size; + + return 0; } int -hashmap_set(struct hashmap *map, void *key, size_t key_size, - void *value, size_t value_size) +hashmap_set(struct hashmap *map, struct hashmap_link **link, + void *key, size_t key_size, void *value, size_t value_size) { struct hashmap_link **iter; int rc; @@ -179,14 +217,17 @@ hashmap_set(struct hashmap *map, void *key, size_t key_size, } if (*iter) { - hashmap_link_set(map, *iter, + rc = hashmap_link_set(map, *iter, key, key_size, value, value_size); + if (rc) return rc; } else { rc = hashmap_link_alloc(map, iter, key, key_size, value, value_size); if (rc) return rc; } + if (link) *link = *iter; + return 0; } @@ -198,7 +239,7 @@ hashmap_iter_init(struct hashmap_iter *iter) } bool -hashmap_iter_next(struct hashmap *map, struct hashmap_iter *iter) +hashmap_iter_next(const struct hashmap *map, struct hashmap_iter *iter) { size_t i; @@ -234,3 +275,9 @@ hashmap_str_hasher(const void *data, size_t size) return hash; } +bool +hashmap_default_keycmp(const void *key1, size_t size1, + const void *key2, size_t size2) +{ + return size1 == size2 && !memcmp(key1, key2, size1); +} diff --git a/src/test.c b/src/test.c @@ -15,7 +15,8 @@ main(int argc, const char **argv) void *key, *value; int i, rc; - rc = hashmap_init(&hashmap, 10, hashmap_str_hasher, &stdlib_heap_allocator); + rc = hashmap_init(&hashmap, 10, hashmap_str_hasher, + hashmap_default_keycmp, &stdlib_heap_allocator); if (rc) LIBHASHMAP_ERR(rc); for (i = 1; i < argc; i++) {