From 86ac5d4b2d510ebf7ca2d74e59a94a839e686fb0 Mon Sep 17 00:00:00 2001 From: Stefano Cossu Date: Mon, 21 Feb 2022 17:47:30 -0800 Subject: [PATCH 1/4] Add hashmap_iter function. --- hashmap.c | 39 +++++++++++++++++++++++++++++++++++++++ hashmap.h | 1 + 2 files changed, 40 insertions(+) diff --git a/hashmap.c b/hashmap.c index b05231e..3547cb1 100644 --- a/hashmap.c +++ b/hashmap.c @@ -408,6 +408,38 @@ bool hashmap_scan(struct hashmap *map, return true; } + +// hashmap_iter iterates one key at a time yielding a reference to an +// entry at each iteration. Useful to write simple loops and avoid writing +// dedicated callbacks and udata structures, as in hashmap_scan. +// +// map is a hash map handle. i is a pointer to a size_t cursor that +// should be initialized to 0 at the beginning of the loop. item is a void +// pointer pointer that is populated with the retrieved item. Note that this +// is NOT a copy of the item stored in the hash map and can be directly +// modified. +// +// This function has not been tested for thread safety. +// +// The function returns true if an item was retrieved; false if the end of the +// iteration has been reached. +bool hashmap_iter(struct hashmap *map, size_t *i, void **item) +{ + struct bucket *bucket; + + do { + if (*i >= map->nbuckets) return false; + + bucket = bucket_at(map, *i); + *i++; + } while (!bucket->dib); + + *item = bucket_item(bucket); + + return true; +} + + //----------------------------------------------------------------------------- // SipHash reference C implementation // @@ -738,6 +770,13 @@ static void all() { while (!(vals2 = xmalloc(N * sizeof(int)))) {} memset(vals2, 0, N * sizeof(int)); assert(hashmap_scan(map, iter_ints, &vals2)); + + // Test hashmap_iter. This does the same as hashmap_scan above. + size_t iter = 0; + void *iter_val; + while (hashmap_iter (map, &iter, &iter_val)) { + assert (iter_ints(iter_val, &vals2)); + } for (int i = 0; i < N; i++) { assert(vals2[i] == 1); } diff --git a/hashmap.h b/hashmap.h index d5cb64a..95eb659 100644 --- a/hashmap.h +++ b/hashmap.h @@ -41,6 +41,7 @@ void *hashmap_delete(struct hashmap *map, void *item); void *hashmap_probe(struct hashmap *map, uint64_t position); bool hashmap_scan(struct hashmap *map, bool (*iter)(const void *item, void *udata), void *udata); +bool hashmap_iter(struct hashmap *map, size_t *i, void **item); uint64_t hashmap_sip(const void *data, size_t len, uint64_t seed0, uint64_t seed1); From 774694ec6dd36f1bb8e5fd3a55a2c47e48295e21 Mon Sep 17 00:00:00 2001 From: Stefano Cossu Date: Mon, 7 Mar 2022 20:38:21 -0800 Subject: [PATCH 2/4] Correct cursor increase. --- hashmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hashmap.c b/hashmap.c index 3547cb1..faa88c8 100644 --- a/hashmap.c +++ b/hashmap.c @@ -431,7 +431,7 @@ bool hashmap_iter(struct hashmap *map, size_t *i, void **item) if (*i >= map->nbuckets) return false; bucket = bucket_at(map, *i); - *i++; + (*i)++; } while (!bucket->dib); *item = bucket_item(bucket); From cdd1eff2eecd1b95fd3b2384b08bfaf18e10b0ef Mon Sep 17 00:00:00 2001 From: Stefano Cossu Date: Fri, 18 Mar 2022 09:43:55 -0700 Subject: [PATCH 3/4] Add comment about hashmap_delete. --- hashmap.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/hashmap.c b/hashmap.c index faa88c8..fa21374 100644 --- a/hashmap.c +++ b/hashmap.c @@ -248,7 +248,7 @@ static bool resize(struct hashmap *map, size_t new_cap) { // replaced then it is returned otherwise NULL is returned. This operation // may allocate memory. If the system is unable to allocate additional // memory then NULL is returned and hashmap_oom() returns true. -void *hashmap_set(struct hashmap *map, void *item) { +void *hashmap_set(struct hashmap *map, const void *item) { if (!item) { panic("item is null"); } @@ -419,6 +419,10 @@ bool hashmap_scan(struct hashmap *map, // is NOT a copy of the item stored in the hash map and can be directly // modified. // +// Note that if hashmap_delete() is called on the hashmap being iterated, +// the buckets are rearranged and the iterator must be reset to 0, otherwise +// unexpected results may be returned after deletion. +// // This function has not been tested for thread safety. // // The function returns true if an item was retrieved; false if the end of the From d9b23a5a4df7e572ec897357292cf377eca9b229 Mon Sep 17 00:00:00 2001 From: Stefano Cossu Date: Fri, 18 Mar 2022 09:56:42 -0700 Subject: [PATCH 4/4] Remove unintended signature change. --- hashmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hashmap.c b/hashmap.c index fa21374..4b97cce 100644 --- a/hashmap.c +++ b/hashmap.c @@ -248,7 +248,7 @@ static bool resize(struct hashmap *map, size_t new_cap) { // replaced then it is returned otherwise NULL is returned. This operation // may allocate memory. If the system is unable to allocate additional // memory then NULL is returned and hashmap_oom() returns true. -void *hashmap_set(struct hashmap *map, const void *item) { +void *hashmap_set(struct hashmap *map, void *item) { if (!item) { panic("item is null"); }