From 70415c6caff1be78a995e363e8274dc2473c9d2b Mon Sep 17 00:00:00 2001 From: Stephen Seo Date: Sat, 21 Sep 2024 18:43:23 +0900 Subject: [PATCH] Impl. way to set custom hasher for hash_map --- src/data_structures/hash_map.c | 20 ++++++++++++-------- src/data_structures/hash_map.h | 11 +++++++++++ 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/data_structures/hash_map.c b/src/data_structures/hash_map.c index cdbb700..c292e82 100644 --- a/src/data_structures/hash_map.c +++ b/src/data_structures/hash_map.c @@ -74,8 +74,7 @@ int simple_archiver_hash_map_internal_pick_in_list(void *data, void *ud) { : 0; } -uint64_t simple_archiver_hash_map_internal_key_to_hash(const void *key, - size_t key_size) { +uint64_t simple_archiver_hash_default_fn(const void *key, size_t key_size) { uint64_t seed = 0; uint64_t temp = 0; size_t count = 0; @@ -106,6 +105,7 @@ int simple_archiver_hash_map_internal_rehash(SDArchiverHashMap *hash_map) { return 1; } SDArchiverHashMap new_hash_map; + new_hash_map.hash_fn = hash_map->hash_fn; new_hash_map.buckets_size = hash_map->buckets_size * 2; // Pointers have the same size (at least on the same machine), so // sizeof(void*) should be ok. @@ -146,7 +146,14 @@ int simple_archiver_hash_map_internal_rehash(SDArchiverHashMap *hash_map) { } SDArchiverHashMap *simple_archiver_hash_map_init(void) { + return simple_archiver_hash_map_init_custom_hasher( + simple_archiver_hash_default_fn); +} + +SDArchiverHashMap *simple_archiver_hash_map_init_custom_hasher( + uint64_t (*hash_fn)(const void *, size_t)) { SDArchiverHashMap *hash_map = malloc(sizeof(SDArchiverHashMap)); + hash_map->hash_fn = hash_fn; hash_map->buckets_size = SC_SA_DS_HASH_MAP_START_BUCKET_SIZE; // Pointers have the same size (at least on the same machine), so // sizeof(void*) should be ok. @@ -193,8 +200,7 @@ int simple_archiver_hash_map_insert(SDArchiverHashMap *hash_map, void *value, data->value_cleanup_fn = value_cleanup_fn; data->key_cleanup_fn = key_cleanup_fn; - uint64_t hash = simple_archiver_hash_map_internal_key_to_hash(key, key_size) % - hash_map->buckets_size; + uint64_t hash = hash_map->hash_fn(key, key_size) % hash_map->buckets_size; int result = simple_archiver_list_add_front( hash_map->buckets[hash], data, simple_archiver_hash_map_internal_cleanup_data); @@ -225,8 +231,7 @@ int simple_archiver_hash_map_insert(SDArchiverHashMap *hash_map, void *value, void *simple_archiver_hash_map_get(const SDArchiverHashMap *hash_map, const void *key, size_t key_size) { - uint64_t hash = simple_archiver_hash_map_internal_key_to_hash(key, key_size) % - hash_map->buckets_size; + uint64_t hash = hash_map->hash_fn(key, key_size) % hash_map->buckets_size; SDArchiverLLNode *node = hash_map->buckets[hash]->head; while (node) { @@ -244,8 +249,7 @@ void *simple_archiver_hash_map_get(const SDArchiverHashMap *hash_map, int simple_archiver_hash_map_remove(SDArchiverHashMap *hash_map, void *key, size_t key_size) { - uint64_t hash = simple_archiver_hash_map_internal_key_to_hash(key, key_size) % - hash_map->buckets_size; + uint64_t hash = hash_map->hash_fn(key, key_size) % hash_map->buckets_size; SDArchiverHashMapKeyData key_data; key_data.key = key; diff --git a/src/data_structures/hash_map.h b/src/data_structures/hash_map.h index 22d91fe..4fe302f 100644 --- a/src/data_structures/hash_map.h +++ b/src/data_structures/hash_map.h @@ -32,10 +32,21 @@ typedef struct SDArchiverHashMap { SDArchiverLinkedList **buckets; size_t buckets_size; size_t count; + uint64_t (*hash_fn)(const void *, size_t); } SDArchiverHashMap; +uint64_t simple_archiver_hash_default_fn(const void *key, size_t key_size); + SDArchiverHashMap *simple_archiver_hash_map_init(void); +/// Creates a hash map that will use the custom hash function instead of the +/// default. Note that the hash function must return a 64-bit unsigned integer +/// as specified by the function's api. The first parameter of hash_fn is a +/// pointer to the key to be hashed, and the second parameter is the size of +/// the key in bytes. +SDArchiverHashMap *simple_archiver_hash_map_init_custom_hasher( + uint64_t (*hash_fn)(const void *, size_t)); + /// It is recommended to use the double-pointer version of hash-map free as /// that will ensure the variable holding the pointer will end up pointing to /// NULL after free.