aboutsummaryrefslogtreecommitdiff
path: root/src/map.cpp
diff options
context:
space:
mode:
authorGinger Bill <bill@gingerbill.org>2017-06-08 13:26:48 +0100
committerGinger Bill <bill@gingerbill.org>2017-06-08 13:26:48 +0100
commit5cad7d44a6f51afe97b3176a6c55d53d96cc40b7 (patch)
tree168fb0dd68957894a56c66d28e5c0af88e7eca59 /src/map.cpp
parent2b96be0ae8b74e6081a00d740dfcbe205f76fb22 (diff)
Use templated `Map` for extra type safety
Diffstat (limited to 'src/map.cpp')
-rw-r--r--src/map.cpp229
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