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:
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++) {