diff --git a/lib/include/hashmap.h b/lib/include/hashmap.h index d5cb64a..fd8891a 100644 --- a/lib/include/hashmap.h +++ b/lib/include/hashmap.h @@ -1,3 +1,4 @@ +// https://github.com/tidwall/hashmap.c // Copyright 2020 Joshua J Baker. All rights reserved. // Use of this source code is governed by an MIT-style // license that can be found in the LICENSE file. @@ -11,44 +12,32 @@ struct hashmap; -struct hashmap *hashmap_new(size_t elsize, size_t cap, - uint64_t seed0, uint64_t seed1, - uint64_t (*hash)(const void *item, - uint64_t seed0, uint64_t seed1), - int (*compare)(const void *a, const void *b, - void *udata), - void (*elfree)(void *item), - void *udata); -struct hashmap *hashmap_new_with_allocator( - void *(*malloc)(size_t), - void *(*realloc)(void *, size_t), - void (*free)(void*), - size_t elsize, size_t cap, - uint64_t seed0, uint64_t seed1, - uint64_t (*hash)(const void *item, - uint64_t seed0, uint64_t seed1), - int (*compare)(const void *a, const void *b, - void *udata), - void (*elfree)(void *item), - void *udata); +struct hashmap *hashmap_new(size_t elsize, size_t cap, uint64_t seed0, uint64_t seed1, + uint64_t (*hash)(const void *item, uint64_t seed0, uint64_t seed1), + int (*compare)(const void *a, const void *b, void *udata), + void (*elfree)(void *item), void *udata); +struct hashmap * +hashmap_new_with_allocator(void *(*malloc)(size_t), void *(*realloc)(void *, size_t), + void (*free)(void *), size_t elsize, size_t cap, uint64_t seed0, + uint64_t seed1, + uint64_t (*hash)(const void *item, uint64_t seed0, uint64_t seed1), + int (*compare)(const void *a, const void *b, void *udata), + void (*elfree)(void *item), void *udata); void hashmap_free(struct hashmap *map); void hashmap_clear(struct hashmap *map, bool update_cap); size_t hashmap_count(struct hashmap *map); bool hashmap_oom(struct hashmap *map); void *hashmap_get(struct hashmap *map, const void *item); -void *hashmap_set(struct hashmap *map, void *item); +void *hashmap_set(struct hashmap *map, const void *item); 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); - -uint64_t hashmap_sip(const void *data, size_t len, - uint64_t seed0, uint64_t seed1); -uint64_t hashmap_murmur(const void *data, size_t len, - uint64_t seed0, uint64_t seed1); +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); +uint64_t hashmap_murmur(const void *data, size_t len, uint64_t seed0, uint64_t seed1); // DEPRECATED: use `hashmap_new_with_allocator` -void hashmap_set_allocator(void *(*malloc)(size_t), void (*free)(void*)); +void hashmap_set_allocator(void *(*malloc)(size_t), void (*free)(void *)); #endif diff --git a/lib/vendor/hashmap.c b/lib/vendor/hashmap.c index e9abcec..2efcb0e 100644 --- a/lib/vendor/hashmap.c +++ b/lib/vendor/hashmap.c @@ -2,13 +2,14 @@ // Use of this source code is governed by an MIT-style // license that can be found in the LICENSE file. -#include -#include -#include -#include -#include #include "hashmap.h" +#include +#include +#include +#include +#include + static void *(*_malloc)(size_t) = NULL; static void *(*_realloc)(void *, size_t) = NULL; static void (*_free)(void *) = NULL; @@ -23,7 +24,7 @@ void hashmap_set_allocator(void *(*malloc)(size_t), void (*free)(void*)) } #define panic(_msg_) { \ - /*fprintf(stderr, "panic: %s (%s:%d)\n", (_msg_), __FILE__, __LINE__);*/ \ + fprintf(stderr, "panic: %s (%s:%d)\n", (_msg_), __FILE__, __LINE__); \ exit(1); \ } @@ -248,7 +249,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"); } @@ -408,6 +409,42 @@ 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. +// +// 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 +// 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 +775,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); }