diff options
| author | Ginger Bill <bill@gingerbill.org> | 2017-06-08 13:26:48 +0100 |
|---|---|---|
| committer | Ginger Bill <bill@gingerbill.org> | 2017-06-08 13:26:48 +0100 |
| commit | 5cad7d44a6f51afe97b3176a6c55d53d96cc40b7 (patch) | |
| tree | 168fb0dd68957894a56c66d28e5c0af88e7eca59 /src/map.cpp | |
| parent | 2b96be0ae8b74e6081a00d740dfcbe205f76fb22 (diff) | |
Use templated `Map` for extra type safety
Diffstat (limited to 'src/map.cpp')
| -rw-r--r-- | src/map.cpp | 229 |
1 files changed, 114 insertions, 115 deletions
diff --git a/src/map.cpp b/src/map.cpp index f03e83424..d45d2bccb 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -1,38 +1,30 @@ -/* - Example of usage: - - #define MAP_TYPE String - #define MAP_PROC map_string_ - #define MAP_NAME MapString - #include "map.cpp" -*/ // 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_*` stuff to be #ifdefed out +// TODO(bill): I should probably allow the `multi_map_*` stuff to be #ifdefed out #ifndef MAP_UTIL_STUFF #define MAP_UTIL_STUFF // NOTE(bill): This util stuff is the same for every `Map` -typedef struct MapFindResult { +struct MapFindResult { isize hash_index; isize entry_prev; isize entry_index; -} MapFindResult; +}; -typedef enum HashKeyKind { +enum HashKeyKind { HashKey_Default, HashKey_String, HashKey_Pointer, -} HashKeyKind; +}; -typedef struct HashKey { +struct HashKey { HashKeyKind kind; u64 key; union { String string; // if String, s.len > 0 void * ptr; }; -} HashKey; +}; gb_inline HashKey hashing_proc(void const *data, isize len) { HashKey h = {HashKey_Default}; @@ -73,75 +65,75 @@ bool hash_key_equal(HashKey a, HashKey b) { } return false; } -#endif - -#define _J2_IND(a, b) a##b -#define _J2(a, b) _J2_IND(a, b) +bool operator==(HashKey a, HashKey b) { return hash_key_equal(a, b); } +bool operator!=(HashKey a, HashKey b) { return !hash_key_equal(a, b); } -/* -MAP_TYPE - Entry type -MAP_PROC - Function prefix (e.g. entity_map_) -MAP_NAME - Name of Map (e.g. EntityMap) -*/ -#define MAP_ENTRY _J2(MAP_NAME,Entry) +#endif -typedef struct MAP_ENTRY { +template <typename T> +struct MapEntry { HashKey key; isize next; - MAP_TYPE value; -} MAP_ENTRY; - -typedef struct MAP_NAME { - Array<isize> hashes; - Array<MAP_ENTRY> entries; -} MAP_NAME; - -void _J2(MAP_PROC,init) (MAP_NAME *h, gbAllocator a); -void _J2(MAP_PROC,init_with_reserve)(MAP_NAME *h, gbAllocator a, isize capacity); -void _J2(MAP_PROC,destroy) (MAP_NAME *h); -MAP_TYPE *_J2(MAP_PROC,get) (MAP_NAME *h, HashKey key); -void _J2(MAP_PROC,set) (MAP_NAME *h, HashKey key, MAP_TYPE value); -void _J2(MAP_PROC,remove) (MAP_NAME *h, HashKey key); -void _J2(MAP_PROC,clear) (MAP_NAME *h); -void _J2(MAP_PROC,grow) (MAP_NAME *h); -void _J2(MAP_PROC,rehash) (MAP_NAME *h, isize new_count); + T value; +}; + +template <typename T> +struct Map { + Array<isize> hashes; + Array<MapEntry<T> > entries; +}; + + +template <typename T> void map_init (Map<T> *h, gbAllocator a); +template <typename T> void map_init_with_reserve(Map<T> *h, gbAllocator a, isize capacity); +template <typename T> void map_destroy (Map<T> *h); +template <typename T> T * map_get (Map<T> *h, HashKey key); +template <typename T> void map_set (Map<T> *h, HashKey key, T const &value); +template <typename T> void map_remove (Map<T> *h, HashKey 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); // Mutlivalued map procedure -MAP_ENTRY *_J2(MAP_PROC,multi_find_first)(MAP_NAME *h, HashKey key); -MAP_ENTRY *_J2(MAP_PROC,multi_find_next) (MAP_NAME *h, MAP_ENTRY *e); - -isize _J2(MAP_PROC,multi_count) (MAP_NAME *h, HashKey key); -void _J2(MAP_PROC,multi_get_all) (MAP_NAME *h, HashKey key, MAP_TYPE *items); -void _J2(MAP_PROC,multi_insert) (MAP_NAME *h, HashKey key, MAP_TYPE value); -void _J2(MAP_PROC,multi_remove) (MAP_NAME *h, HashKey key, MAP_ENTRY *e); -void _J2(MAP_PROC,multi_remove_all)(MAP_NAME *h, HashKey key); +template <typename T> MapEntry<T> * multi_map_find_first(Map<T> *h, HashKey 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 key); +template <typename T> void multi_map_get_all (Map<T> *h, HashKey key, T *items); +template <typename T> void multi_map_insert (Map<T> *h, HashKey key, T const &value); +template <typename T> void multi_map_remove (Map<T> *h, HashKey key, MapEntry<T> *e); +template <typename T> void multi_map_remove_all(Map<T> *h, HashKey key); -gb_inline void _J2(MAP_PROC,init)(MAP_NAME *h, gbAllocator a) { +template <typename T> +gb_inline void map_init(Map<T> *h, gbAllocator a) { array_init(&h->hashes, a); array_init(&h->entries, a); } -gb_inline void _J2(MAP_PROC,init_with_reserve)(MAP_NAME *h, gbAllocator a, isize capacity) { +template <typename T> +gb_inline void map_init_with_reserve(Map<T> *h, gbAllocator a, isize capacity) { array_init(&h->hashes, a, capacity); array_init(&h->entries, a, capacity); } -gb_inline void _J2(MAP_PROC,destroy)(MAP_NAME *h) { +template <typename T> +gb_inline void map_destroy(Map<T> *h) { array_free(&h->entries); array_free(&h->hashes); } -gb_internal isize _J2(MAP_PROC,_add_entry)(MAP_NAME *h, HashKey key) { - MAP_ENTRY e = {}; +template <typename T> +gb_internal isize map__add_entry(Map<T> *h, HashKey key) { + MapEntry<T> e = {}; e.key = key; e.next = -1; array_add(&h->entries, e); return h->entries.count-1; } -gb_internal MapFindResult _J2(MAP_PROC,_find)(MAP_NAME *h, HashKey key) { +template <typename T> +gb_internal MapFindResult map__find(Map<T> *h, HashKey key) { MapFindResult fr = {-1, -1, -1}; if (h->hashes.count > 0) { fr.hash_index = key.key % h->hashes.count; @@ -157,7 +149,8 @@ gb_internal MapFindResult _J2(MAP_PROC,_find)(MAP_NAME *h, HashKey key) { return fr; } -gb_internal MapFindResult _J2(MAP_PROC,_find_from_entry)(MAP_NAME *h, MAP_ENTRY *e) { +template <typename T> +gb_internal MapFindResult map__find_from_entry(Map<T> *h, MapEntry<T> *e) { MapFindResult fr = {-1, -1, -1}; if (h->hashes.count > 0) { fr.hash_index = e->key.key % h->hashes.count; @@ -173,33 +166,35 @@ gb_internal MapFindResult _J2(MAP_PROC,_find_from_entry)(MAP_NAME *h, MAP_ENTRY return fr; } - -gb_internal b32 _J2(MAP_PROC,_full)(MAP_NAME *h) { +template <typename T> +gb_internal b32 map__full(Map<T> *h) { return 0.75f * h->hashes.count <= h->entries.count; } -gb_inline void _J2(MAP_PROC,grow)(MAP_NAME *h) { +template <typename T> +gb_inline void map_grow(Map<T> *h) { isize new_count = ARRAY_GROW_FORMULA(h->entries.count); - _J2(MAP_PROC,rehash)(h, new_count); + map_rehash(h, new_count); } -void _J2(MAP_PROC,rehash)(MAP_NAME *h, isize new_count) { +template <typename T> +void map_rehash(Map<T> *h, isize new_count) { isize i, j; - MAP_NAME nh = {}; - _J2(MAP_PROC,init)(&nh, h->hashes.allocator); + Map<T> nh = {}; + map_init(&nh, h->hashes.allocator); array_resize(&nh.hashes, new_count); array_reserve(&nh.entries, h->entries.count); for (i = 0; i < new_count; i++) { nh.hashes[i] = -1; } for (i = 0; i < h->entries.count; i++) { - MAP_ENTRY *e = &h->entries[i]; + MapEntry<T> *e = &h->entries[i]; MapFindResult fr; if (nh.hashes.count == 0) { - _J2(MAP_PROC,grow)(&nh); + map_grow(&nh); } - fr = _J2(MAP_PROC,_find)(&nh, e->key); - j = _J2(MAP_PROC,_add_entry)(&nh, e->key); + fr = map__find(&nh, e->key); + j = map__add_entry(&nh, e->key); if (fr.entry_prev < 0) { nh.hashes[fr.hash_index] = j; } else { @@ -207,32 +202,34 @@ void _J2(MAP_PROC,rehash)(MAP_NAME *h, isize new_count) { } nh.entries[j].next = fr.entry_index; nh.entries[j].value = e->value; - if (_J2(MAP_PROC,_full)(&nh)) { - _J2(MAP_PROC,grow)(&nh); + if (map__full(&nh)) { + map_grow(&nh); } } - _J2(MAP_PROC,destroy)(h); + map_destroy(h); *h = nh; } -gb_inline MAP_TYPE *_J2(MAP_PROC,get)(MAP_NAME *h, HashKey key) { - isize index = _J2(MAP_PROC,_find)(h, key).entry_index; +template <typename T> +gb_inline T *map_get(Map<T> *h, HashKey key) { + isize index = map__find(h, key).entry_index; if (index >= 0) { return &h->entries[index].value; } return NULL; } -void _J2(MAP_PROC,set)(MAP_NAME *h, HashKey key, MAP_TYPE value) { +template <typename T> +void map_set(Map<T> *h, HashKey key, T const &value) { isize index; MapFindResult fr; if (h->hashes.count == 0) - _J2(MAP_PROC,grow)(h); - fr = _J2(MAP_PROC,_find)(h, key); + map_grow(h); + fr = map__find(h, key); if (fr.entry_index >= 0) { index = fr.entry_index; } else { - index = _J2(MAP_PROC,_add_entry)(h, key); + index = map__add_entry(h, key); if (fr.entry_prev >= 0) { h->entries[fr.entry_prev].next = index; } else { @@ -241,14 +238,14 @@ void _J2(MAP_PROC,set)(MAP_NAME *h, HashKey key, MAP_TYPE value) { } h->entries[index].value = value; - if (_J2(MAP_PROC,_full)(h)) { - _J2(MAP_PROC,grow)(h); + if (map__full(h)) { + map_grow(h); } } - -void _J2(MAP_PROC,_erase)(MAP_NAME *h, MapFindResult fr) { +template <typename T> +void map__erase(Map<T> *h, MapFindResult fr) { MapFindResult last; if (fr.entry_prev < 0) { h->hashes[fr.hash_index] = h->entries[fr.entry_index].next; @@ -260,7 +257,7 @@ void _J2(MAP_PROC,_erase)(MAP_NAME *h, MapFindResult fr) { return; } h->entries[fr.entry_index] = h->entries[h->entries.count-1]; - last = _J2(MAP_PROC,_find)(h, h->entries[fr.entry_index].key); + last = map__find(h, h->entries[fr.entry_index].key); if (last.entry_prev >= 0) { h->entries[last.entry_prev].next = fr.entry_index; } else { @@ -268,29 +265,33 @@ void _J2(MAP_PROC,_erase)(MAP_NAME *h, MapFindResult fr) { } } -void _J2(MAP_PROC,remove)(MAP_NAME *h, HashKey key) { - MapFindResult fr = _J2(MAP_PROC,_find)(h, key); +template <typename T> +void map_remove(Map<T> *h, HashKey key) { + MapFindResult fr = map__find(h, key); if (fr.entry_index >= 0) { - _J2(MAP_PROC,_erase)(h, fr); + map__erase(h, fr); } } -gb_inline void _J2(MAP_PROC,clear)(MAP_NAME *h) { +template <typename T> +gb_inline void map_clear(Map<T> *h) { array_clear(&h->hashes); array_clear(&h->entries); } #if 1 -MAP_ENTRY *_J2(MAP_PROC,multi_find_first)(MAP_NAME *h, HashKey key) { - isize i = _J2(MAP_PROC,_find)(h, key).entry_index; +template <typename T> +MapEntry<T> *multi_map_find_first(Map<T> *h, HashKey key) { + isize i = map__find(h, key).entry_index; if (i < 0) { return NULL; } return &h->entries[i]; } -MAP_ENTRY *_J2(MAP_PROC,multi_find_next)(MAP_NAME *h, MAP_ENTRY *e) { +template <typename T> +MapEntry<T> *multi_map_find_next(Map<T> *h, MapEntry<T> *e) { isize i = e->next; while (i >= 0) { if (hash_key_equal(h->entries[i].key, e->key)) { @@ -301,34 +302,37 @@ MAP_ENTRY *_J2(MAP_PROC,multi_find_next)(MAP_NAME *h, MAP_ENTRY *e) { return NULL; } -isize _J2(MAP_PROC,multi_count)(MAP_NAME *h, HashKey key) { +template <typename T> +isize multi_map_count(Map<T> *h, HashKey key) { isize count = 0; - MAP_ENTRY *e = _J2(MAP_PROC,multi_find_first)(h, key); + MapEntry<T> *e = multi_map_find_first(h, key); while (e != NULL) { count++; - e = _J2(MAP_PROC,multi_find_next)(h, e); + e = multi_map_find_next(h, e); } return count; } -void _J2(MAP_PROC,multi_get_all)(MAP_NAME *h, HashKey key, MAP_TYPE *items) { +template <typename T> +void multi_map_get_all(Map<T> *h, HashKey key, T *items) { isize i = 0; - MAP_ENTRY *e = _J2(MAP_PROC,multi_find_first)(h, key); + MapEntry<T> *e = multi_map_find_first(h, key); while (e != NULL) { items[i++] = e->value; - e = _J2(MAP_PROC,multi_find_next)(h, e); + e = multi_map_find_next(h, e); } } -void _J2(MAP_PROC,multi_insert)(MAP_NAME *h, HashKey key, MAP_TYPE value) { +template <typename T> +void multi_map_insert(Map<T> *h, HashKey key, T const &value) { MapFindResult fr; isize i; if (h->hashes.count == 0) { - _J2(MAP_PROC,grow)(h); + map_grow(h); } // Make - fr = _J2(MAP_PROC,_find)(h, key); - i = _J2(MAP_PROC,_add_entry)(h, key); + fr = map__find(h, key); + i = map__add_entry(h, key); if (fr.entry_prev < 0) { h->hashes[fr.hash_index] = i; } else { @@ -337,28 +341,23 @@ void _J2(MAP_PROC,multi_insert)(MAP_NAME *h, HashKey key, MAP_TYPE value) { h->entries[i].next = fr.entry_index; h->entries[i].value = value; // Grow if needed - if (_J2(MAP_PROC,_full)(h)) { - _J2(MAP_PROC,grow)(h); + if (map__full(h)) { + map_grow(h); } } -void _J2(MAP_PROC,multi_remove)(MAP_NAME *h, HashKey key, MAP_ENTRY *e) { - MapFindResult fr = _J2(MAP_PROC,_find_from_entry)(h, e); +template <typename T> +void multi_map_remove(Map<T> *h, HashKey key, MapEntry<T> *e) { + MapFindResult fr = map__find_from_entry(h, e); if (fr.entry_index >= 0) { - _J2(MAP_PROC,_erase)(h, fr); + map__erase(h, fr); } } -void _J2(MAP_PROC,multi_remove_all)(MAP_NAME *h, HashKey key) { - while (_J2(MAP_PROC,get)(h, key) != NULL) { - _J2(MAP_PROC,remove)(h, key); +template <typename T> +void multi_map_remove_all(Map<T> *h, HashKey key) { + while (map_get(h, key) != NULL) { + map_remove(h, key); } } #endif - - -#undef _J2 -#undef MAP_TYPE -#undef MAP_PROC -#undef MAP_NAME -#undef MAP_ENTRY |