From f15d94b02c1aba32aba88ae5603296e983f40dce Mon Sep 17 00:00:00 2001 From: Francesco Date: Tue, 2 Dec 2025 02:24:29 +0100 Subject: [PATCH] feat(hashmap): add hm_get_keys and hm_free_keys --- hashmap/myhashmap.c | 109 ++++++++++++++++++++++++++++++++++++++++++++ hashmap/myhashmap.h | 21 +++++++++ 2 files changed, 130 insertions(+) diff --git a/hashmap/myhashmap.c b/hashmap/myhashmap.c index b71145d..2585ae1 100644 --- a/hashmap/myhashmap.c +++ b/hashmap/myhashmap.c @@ -464,3 +464,112 @@ void hm_clear(hashmap_s *hashmap) { mtx_unlock(&hashmap->locks[i]); } } + +void **hm_get_keys(hashmap_s *hashmap, size_t *count) { + if (hashmap == NULL || count == NULL) { + return NULL; + } + + /* Lock all mutexes */ + for (size_t i = 0; i < hashmap->num_locks; ++i) { + mtx_lock(&hashmap->locks[i]); + } + + size_t size = atomic_load(&hashmap->size); + *count = 0; + + if (size == 0) { + for (size_t i = 0; i < hashmap->num_locks; ++i) { + mtx_unlock(&hashmap->locks[i]); + } + return NULL; + } + + /* Allocate array for key pointers */ + void **keys = malloc(sizeof(void *) * size); + if (keys == NULL) { + for (size_t i = 0; i < hashmap->num_locks; ++i) { + mtx_unlock(&hashmap->locks[i]); + } + return NULL; + } + + size_t index = 0; + + /* Iterate through all buckets */ + for (size_t i = 0; i < MYCLIB_HASHMAP_SIZE && index < size; ++i) { + bucket_s *bucket = &hashmap->map[i]; + + if (bucket->key != NULL) { + keys[index] = malloc(hashmap->key_size); + if (keys[index] == NULL) { + /* Cleanup on failure */ + for (size_t j = 0; j < index; ++j) { + if (hashmap->free_key != NULL) { + hashmap->free_key(keys[j]); + } else { + free(keys[j]); + } + } + free(keys); + for (size_t j = 0; j < hashmap->num_locks; ++j) { + mtx_unlock(&hashmap->locks[j]); + } + return NULL; + } + memcpy(keys[index], bucket->key, hashmap->key_size); + index++; + } + + /* Iterate through chain */ + bucket = bucket->next; + while (bucket != NULL && index < size) { + keys[index] = malloc(hashmap->key_size); + if (keys[index] == NULL) { + /* Cleanup on failure */ + for (size_t j = 0; j < index; ++j) { + if (hashmap->free_key != NULL) { + hashmap->free_key(keys[j]); + } else { + free(keys[j]); + } + } + free(keys); + for (size_t j = 0; j < hashmap->num_locks; ++j) { + mtx_unlock(&hashmap->locks[j]); + } + return NULL; + } + memcpy(keys[index], bucket->key, hashmap->key_size); + index++; + bucket = bucket->next; + } + } + + *count = index; + + /* Unlock all mutexes */ + for (size_t i = 0; i < hashmap->num_locks; ++i) { + mtx_unlock(&hashmap->locks[i]); + } + + return keys; +} + +void hm_free_keys(hashmap_s *hashmap, void **keys, size_t count) { + if (keys == NULL) { + return; + } + + for (size_t i = 0; i < count; ++i) { + if (keys[i] != NULL) { + if (hashmap != NULL && hashmap->free_key != NULL) { + hashmap->free_key(keys[i]); + } else { + free(keys[i]); + } + } + } + + free(keys); +} diff --git a/hashmap/myhashmap.h b/hashmap/myhashmap.h index fd33eda..919ccb1 100644 --- a/hashmap/myhashmap.h +++ b/hashmap/myhashmap.h @@ -163,4 +163,25 @@ void hm_foreach(hashmap_s *hashmap, void (*callback)(bucket_s *bucket)); */ void hm_clear(hashmap_s *hashmap); +/** + * @brief Get all keys from the hash map. + * + * Returns an array of pointers to copies of all keys in the hashmap. + * The caller is responsible for freeing the array and each key. + * + * @param[in] hashmap Pointer to the hash map. + * @param[out] count Pointer to store the number of keys returned. + * @return Array of key pointers, or NULL on failure. Must be freed with hm_free_keys(). + */ +void **hm_get_keys(hashmap_s *hashmap, size_t *count); + +/** + * @brief Free the array returned by hm_get_keys. + * + * @param[in] hashmap Pointer to the hash map (needed for free_key function). + * @param[in] keys Array of keys returned by hm_get_keys. + * @param[in] count Number of keys in the array. + */ +void hm_free_keys(hashmap_s *hashmap, void **keys, size_t count); + #endif /* MYCLIB_HASHMAP_H */