diff options
| author | gingerBill <gingerBill@users.noreply.github.com> | 2021-11-05 18:12:40 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-11-05 18:12:40 +0000 |
| commit | ee259e42298eca0e4e5d6b8681c2403c3bf7a80e (patch) | |
| tree | 7bfd15490ddc4be6fcd41b4f969df6c901d98f76 /src/map.cpp | |
| parent | e963fc4d6a2b8fc63f46bb57b2c727999ce39e29 (diff) | |
| parent | 36985f8da0cea59cb1912f62ae4e700983159b6a (diff) | |
Merge pull request #1273 from odin-lang/compiler-map-improvements
Compiler Map Improvements
Diffstat (limited to 'src/map.cpp')
| -rw-r--r-- | src/map.cpp | 363 |
1 files changed, 0 insertions, 363 deletions
diff --git a/src/map.cpp b/src/map.cpp deleted file mode 100644 index cc91e51d4..000000000 --- a/src/map.cpp +++ /dev/null @@ -1,363 +0,0 @@ -// A `Map` is an unordered hash table which can allow for a key to point to multiple values -// with the use of the `multi_*` procedures. -// TODO(bill): I should probably allow the `multi_map_*` stuff to be #ifdefed out - -#define MAP_ENABLE_MULTI_MAP 1 - -#ifndef MAP_UTIL_STUFF -#define MAP_UTIL_STUFF -// NOTE(bill): This util stuff is the same for every `Map` - -typedef u32 MapIndex; - -struct MapFindResult { - MapIndex hash_index; - MapIndex entry_prev; - MapIndex entry_index; -}; - -enum : MapIndex { MAP_SENTINEL = ~(MapIndex)0 }; - - -struct HashKey { - u64 key; -}; -GB_STATIC_ASSERT(gb_size_of(u64) >= gb_size_of(void *)); - -gb_inline HashKey hashing_proc(void const *data, isize len) { - HashKey h = {}; - h.key = fnv64a(data, len); - return h; -} - -gb_inline HashKey hash_pointer(void const *ptr) { - HashKey h = {}; - h.key = cast(u64)cast(uintptr)ptr; - return h; -} - -gb_inline HashKey hash_integer(u64 u) { - HashKey h = {}; - h.key = u; - return h; -} -gb_inline HashKey hash_f64(f64 f) { - HashKey h = {}; - h.key = bit_cast<u64>(f); - return h; -} - -gb_inline bool hash_key_equal(HashKey a, HashKey b) { - return a.key == b.key; -} -gb_inline bool operator==(HashKey a, HashKey b) { return hash_key_equal(a, b); } -gb_inline bool operator!=(HashKey a, HashKey b) { return !hash_key_equal(a, b); } - -#endif - -template <typename T> -struct MapEntry { - HashKey key; - MapIndex next; - T value; -}; - -template <typename T> -struct Map { - Slice<MapIndex> hashes; - Array<MapEntry<T> > entries; -}; - - -template <typename T> void map_init (Map<T> *h, gbAllocator a, isize capacity = 16); -template <typename T> void map_destroy (Map<T> *h); -template <typename T> T * map_get (Map<T> *h, HashKey const &key); -template <typename T> T & map_must_get (Map<T> *h, HashKey const &key); -template <typename T> void map_set (Map<T> *h, HashKey const &key, T const &value); -template <typename T> void map_remove (Map<T> *h, HashKey const &key); -template <typename T> void map_clear (Map<T> *h); -template <typename T> void map_grow (Map<T> *h); -template <typename T> void map_rehash (Map<T> *h, isize new_count); -template <typename T> void map_reserve (Map<T> *h, isize cap); - -#if MAP_ENABLE_MULTI_MAP -// Mutlivalued map procedure -template <typename T> MapEntry<T> * multi_map_find_first(Map<T> *h, HashKey const &key); -template <typename T> MapEntry<T> * multi_map_find_next (Map<T> *h, MapEntry<T> *e); - -template <typename T> isize multi_map_count (Map<T> *h, HashKey const &key); -template <typename T> void multi_map_get_all (Map<T> *h, HashKey const &key, T *items); -template <typename T> void multi_map_insert (Map<T> *h, HashKey const &key, T const &value); -template <typename T> void multi_map_remove (Map<T> *h, HashKey const &key, MapEntry<T> *e); -template <typename T> void multi_map_remove_all(Map<T> *h, HashKey const &key); -#endif - -template <typename T> -gb_inline void map_init(Map<T> *h, gbAllocator a, isize capacity) { - capacity = next_pow2_isize(capacity); - slice_init(&h->hashes, a, capacity); - array_init(&h->entries, a, 0, capacity); - for (isize i = 0; i < capacity; i++) { - h->hashes.data[i] = MAP_SENTINEL; - } -} - -template <typename T> -gb_inline void map_destroy(Map<T> *h) { - slice_free(&h->hashes, h->entries.allocator); - array_free(&h->entries); -} - -template <typename T> -gb_internal MapIndex map__add_entry(Map<T> *h, HashKey const &key) { - MapEntry<T> e = {}; - e.key = key; - e.next = MAP_SENTINEL; - array_add(&h->entries, e); - return cast(MapIndex)(h->entries.count-1); -} - -template <typename T> -gb_internal MapFindResult map__find(Map<T> *h, HashKey const &key) { - MapFindResult fr = {MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL}; - if (h->hashes.count == 0) { - return fr; - } - fr.hash_index = cast(MapIndex)(key.key & (h->hashes.count-1)); - fr.entry_index = h->hashes.data[fr.hash_index]; - while (fr.entry_index != MAP_SENTINEL) { - if (hash_key_equal(h->entries.data[fr.entry_index].key, key)) { - return fr; - } - fr.entry_prev = fr.entry_index; - fr.entry_index = h->entries.data[fr.entry_index].next; - } - return fr; -} - -template <typename T> -gb_internal MapFindResult map__find_from_entry(Map<T> *h, MapEntry<T> *e) { - MapFindResult fr = {MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL}; - if (h->hashes.count == 0) { - return fr; - } - fr.hash_index = cast(MapIndex)(e->key.key & (h->hashes.count-1)); - fr.entry_index = h->hashes.data[fr.hash_index]; - while (fr.entry_index != MAP_SENTINEL) { - if (&h->entries.data[fr.entry_index] == e) { - return fr; - } - fr.entry_prev = fr.entry_index; - fr.entry_index = h->entries.data[fr.entry_index].next; - } - return fr; -} - -template <typename T> -gb_internal b32 map__full(Map<T> *h) { - return 0.75f * h->hashes.count <= h->entries.count; -} - -template <typename T> -gb_inline void map_grow(Map<T> *h) { - isize new_count = gb_max(h->hashes.count<<1, 16); - map_rehash(h, new_count); -} - -template <typename T> -void map_reset_entries(Map<T> *h) { - for (isize i = 0; i < h->hashes.count; i++) { - h->hashes.data[i] = MAP_SENTINEL; - } - for (isize i = 0; i < h->entries.count; i++) { - MapFindResult fr; - MapEntry<T> *e = &h->entries.data[i]; - e->next = MAP_SENTINEL; - fr = map__find_from_entry(h, e); - if (fr.entry_prev == MAP_SENTINEL) { - h->hashes[fr.hash_index] = cast(MapIndex)i; - } else { - h->entries[fr.entry_prev].next = cast(MapIndex)i; - } - } -} - -template <typename T> -void map_reserve(Map<T> *h, isize cap) { - array_reserve(&h->entries, cap); - if (h->entries.count*2 < h->hashes.count) { - return; - } - slice_resize(&h->hashes, h->entries.allocator, cap*2); - map_reset_entries(h); -} - - -template <typename T> -void map_rehash(Map<T> *h, isize new_count) { - map_reserve(h, new_count); -} - -template <typename T> -T *map_get(Map<T> *h, HashKey const &key) { - isize index = map__find(h, key).entry_index; - if (index != MAP_SENTINEL) { - return &h->entries.data[index].value; - } - return nullptr; -} - -template <typename T> -T &map_must_get(Map<T> *h, HashKey const &key) { - isize index = map__find(h, key).entry_index; - GB_ASSERT(index != MAP_SENTINEL); - return h->entries.data[index].value; -} - -template <typename T> -void map_set(Map<T> *h, HashKey const &key, T const &value) { - MapIndex index; - MapFindResult fr; - if (h->hashes.count == 0) { - map_grow(h); - } - fr = map__find(h, key); - if (fr.entry_index != MAP_SENTINEL) { - index = fr.entry_index; - } else { - index = map__add_entry(h, key); - if (fr.entry_prev != MAP_SENTINEL) { - h->entries.data[fr.entry_prev].next = index; - } else { - h->hashes.data[fr.hash_index] = index; - } - } - h->entries.data[index].value = value; - - if (map__full(h)) { - map_grow(h); - } -} - - -template <typename T> -void map__erase(Map<T> *h, MapFindResult const &fr) { - MapFindResult last; - if (fr.entry_prev == MAP_SENTINEL) { - h->hashes.data[fr.hash_index] = h->entries.data[fr.entry_index].next; - } else { - h->entries.data[fr.entry_prev].next = h->entries.data[fr.entry_index].next; - } - if (fr.entry_index == h->entries.count-1) { - array_pop(&h->entries); - return; - } - h->entries.data[fr.entry_index] = h->entries.data[h->entries.count-1]; - array_pop(&h->entries); - - last = map__find(h, h->entries.data[fr.entry_index].key); - if (last.entry_prev != MAP_SENTINEL) { - h->entries.data[last.entry_prev].next = fr.entry_index; - } else { - h->hashes.data[last.hash_index] = fr.entry_index; - } -} - -template <typename T> -void map_remove(Map<T> *h, HashKey const &key) { - MapFindResult fr = map__find(h, key); - if (fr.entry_index != MAP_SENTINEL) { - map__erase(h, fr); - } -} - -template <typename T> -gb_inline void map_clear(Map<T> *h) { - array_clear(&h->entries); - for (isize i = 0; i < h->hashes.count; i++) { - h->hashes.data[i] = MAP_SENTINEL; - } -} - - -#if MAP_ENABLE_MULTI_MAP -template <typename T> -MapEntry<T> *multi_map_find_first(Map<T> *h, HashKey const &key) { - isize i = map__find(h, key).entry_index; - if (i == MAP_SENTINEL) { - return nullptr; - } - return &h->entries.data[i]; -} - -template <typename T> -MapEntry<T> *multi_map_find_next(Map<T> *h, MapEntry<T> *e) { - isize i = e->next; - while (i != MAP_SENTINEL) { - if (hash_key_equal(h->entries.data[i].key, e->key)) { - return &h->entries.data[i]; - } - i = h->entries.data[i].next; - } - return nullptr; -} - -template <typename T> -isize multi_map_count(Map<T> *h, HashKey const &key) { - isize count = 0; - MapEntry<T> *e = multi_map_find_first(h, key); - while (e != nullptr) { - count++; - e = multi_map_find_next(h, e); - } - return count; -} - -template <typename T> -void multi_map_get_all(Map<T> *h, HashKey const &key, T *items) { - isize i = 0; - MapEntry<T> *e = multi_map_find_first(h, key); - while (e != nullptr) { - items[i++] = e->value; - e = multi_map_find_next(h, e); - } -} - -template <typename T> -void multi_map_insert(Map<T> *h, HashKey const &key, T const &value) { - MapFindResult fr; - MapIndex i; - if (h->hashes.count == 0) { - map_grow(h); - } - // Make - fr = map__find(h, key); - i = map__add_entry(h, key); - if (fr.entry_prev == MAP_SENTINEL) { - h->hashes.data[fr.hash_index] = i; - } else { - h->entries.data[fr.entry_prev].next = i; - } - h->entries.data[i].next = fr.entry_index; - h->entries.data[i].value = value; - // Grow if needed - if (map__full(h)) { - map_grow(h); - } -} - -template <typename T> -void multi_map_remove(Map<T> *h, HashKey const &key, MapEntry<T> *e) { - MapFindResult fr = map__find_from_entry(h, e); - if (fr.entry_index != MAP_SENTINEL) { - map__erase(h, fr); - } -} - -template <typename T> -void multi_map_remove_all(Map<T> *h, HashKey const &key) { - while (map_get(h, key) != nullptr) { - map_remove(h, key); - } -} -#endif |