From c6bdb38bb77d45f9d5083706723c84c37db56c9c Mon Sep 17 00:00:00 2001 From: Alexander Rosenberg Date: Sun, 7 Sep 2025 00:22:44 -0700 Subject: [PATCH] Allow passing stack-allocated structs to ht_new --- src/ht.c | 57 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/src/ht.c b/src/ht.c index d50ed99..c4babfc 100644 --- a/src/ht.c +++ b/src/ht.c @@ -59,9 +59,9 @@ typedef struct Bucket { * A hash table. */ struct HTTable { - const HTTableFunctions *fns; //!< Set of functions to use for hashing, etc. - const HTAllocator *alloc; //!< Set of memory allocation functions. - const HTThreshold *thresh; //!< Thresholds for resizing, etc. + HTTableFunctions fns; //!< Set of functions to use for hashing, etc. + HTAllocator alloc; //!< Set of memory allocation functions. + HTThreshold thresh; //!< Thresholds for resizing, etc. size_t table_size; //alloc->malloc(size, ht->alloc->user_data); + return ht->alloc.malloc(size, ht->alloc.user_data); } /** @@ -99,7 +99,7 @@ static void *zeroed_malloc(const HTTable *ht, size_t size) { * @param ptr The pointer to free */ static inline void free_for_table(const HTTable *ht, void *ptr) { - ht->alloc->free(ptr, ht->alloc->user_data); + ht->alloc.free(ptr, ht->alloc.user_data); } /** @@ -108,8 +108,8 @@ static inline void free_for_table(const HTTable *ht, void *ptr) { * @param key The key to free */ static inline void free_table_key(const HTTable *ht, void *key) { - if (ht->fns->destroy_key) { - ht->fns->destroy_key(key, ht->fns->user_data); + if (ht->fns.destroy_key) { + ht->fns.destroy_key(key, ht->fns.user_data); } } @@ -119,13 +119,14 @@ static inline void free_table_key(const HTTable *ht, void *key) { * @param value The value to free */ static inline void free_table_value(const HTTable *ht, void *value) { - if (ht->fns->destroy_value) { - ht->fns->destroy_value(value, ht->fns->user_data); + if (ht->fns.destroy_value) { + ht->fns.destroy_value(value, ht->fns.user_data); } } /** - * Create and return a new hash table. + * Create and return a new hash table. A copy of all of the passed values is + * made. * @param fns The HTTableFunctions to use for the table * @param alloc The HTAllocator to use, or NULL to use the standard C malloc and * free @@ -144,12 +145,12 @@ HTTable *ht_new(const HTTableFunctions *fns, const HTAllocator *alloc, if (!ht) { return NULL; } - ht->fns = fns; - ht->alloc = alloc; - ht->thresh = thresh; + ht->fns = *fns; + ht->alloc = *alloc; + ht->thresh = *thresh; ht->count = 0; - ht->table_size = ht->thresh->initial_size; + ht->table_size = ht->thresh.initial_size; ht->buckets = zeroed_malloc(ht, sizeof(Bucket *) * ht->table_size); if (!ht->buckets) { free_for_table(ht, ht); @@ -281,7 +282,7 @@ bool ht_equal(const HTTable *ht1, const HTTable *ht2) { * @return The growth threshold */ static inline size_t calculate_growth_threshold(HTTable *ht) { - return (size_t) (ht->table_size * ht->thresh->growth_threshold); + return (size_t) (ht->table_size * ht->thresh.growth_threshold); } /** @@ -291,7 +292,7 @@ static inline size_t calculate_growth_threshold(HTTable *ht) { * @return The shrink threshold */ static inline size_t calculate_shrink_threshold(HTTable *ht) { - return (size_t) (ht->table_size * ht->thresh->shrink_threshold); + return (size_t) (ht->table_size * ht->thresh.shrink_threshold); } /** @@ -301,8 +302,8 @@ static inline size_t calculate_shrink_threshold(HTTable *ht) { * @return Wether the operation succeeded (true means success) */ static bool resize_to(HTTable *ht, size_t new_size) { - if (new_size < ht->thresh->initial_size) { - new_size = ht->thresh->initial_size; + if (new_size < ht->thresh.initial_size) { + new_size = ht->thresh.initial_size; } if (ht->table_size == new_size) { return true; @@ -331,11 +332,11 @@ static bool resize_to(HTTable *ht, size_t new_size) { static bool maybe_resize(HTTable *ht, size_t delta) { size_t new_count = ht->count + delta; if (new_count >= calculate_growth_threshold(ht)) { - size_t new_size = ht->table_size * ht->thresh->growth_factor; + size_t new_size = ht->table_size * ht->thresh.growth_factor; return resize_to(ht, new_size); } else if (new_count <= calculate_shrink_threshold(ht) - && ht->table_size != ht->thresh->initial_size) { - size_t new_size = ht->table_size / ht->thresh->growth_factor; + && ht->table_size != ht->thresh.initial_size) { + size_t new_size = ht->table_size / ht->thresh.growth_factor; return resize_to(ht, new_size); } return true; @@ -352,7 +353,7 @@ static bool maybe_resize(HTTable *ht, size_t delta) { static bool bucket_matches(const HTTable *ht, Bucket *bucket, uint64_t hash, const void *key) { return bucket && bucket->hash == hash - && ht->fns->equal(bucket->key, key, ht->fns->user_data); + && ht->fns.equal(bucket->key, key, ht->fns.user_data); } /** @@ -387,7 +388,7 @@ static Bucket **find_bucket(const HTTable *ht, uint64_t hash, const void *key) { * @return The key's hash */ static inline uint64_t hash_for_table(const HTTable *ht, const void *key) { - return ht->fns->hash(key, ht->fns->user_data); + return ht->fns.hash(key, ht->fns.user_data); } /** @@ -436,7 +437,7 @@ bool ht_clear(HTTable *ht) { free_bucket(ht, bucket); } free_for_table(ht, ht->buckets); - ht->table_size = ht->thresh->initial_size; + ht->table_size = ht->thresh.initial_size; ht->buckets = zeroed_malloc(ht, sizeof(Bucket) * ht->table_size); ht->count = 0; if (!ht->buckets) { @@ -544,7 +545,7 @@ bool ht_steal_all(HTTable *ht, void ***keys, void ***values) { } } Bucket **new_buckets = - zeroed_malloc(ht, sizeof(Bucket) * ht->thresh->initial_size); + zeroed_malloc(ht, sizeof(Bucket) * ht->thresh.initial_size); if (!new_buckets) { if (keys) { free_for_table(ht, *keys); @@ -556,7 +557,7 @@ bool ht_steal_all(HTTable *ht, void ***keys, void ***values) { } size_t old_table_size = ht->table_size; Bucket **old_buckets = ht->buckets; - ht->table_size = ht->thresh->initial_size; + ht->table_size = ht->thresh.initial_size; ht->count = 0; ht->buckets = new_buckets; size_t out_i = 0; @@ -731,7 +732,7 @@ bool ht_find(HTTable *ht, ht_foreach_callback_t callback, void *user_data, */ bool ht_steal_from(HTTable *ht, HTTable *src) { Bucket **new_buckets = - zeroed_malloc(src, sizeof(Bucket) * src->thresh->initial_size); + zeroed_malloc(src, sizeof(Bucket) * src->thresh.initial_size); if (!new_buckets) { return NULL; } @@ -739,7 +740,7 @@ bool ht_steal_from(HTTable *ht, HTTable *src) { Bucket **old_buckets = src->buckets; src->buckets = new_buckets; src->count = 0; - src->table_size = src->thresh->initial_size; + src->table_size = src->thresh.initial_size; bool no_errors = true; for (size_t i = 0; i < old_table_size; ++i) {