Browse Source

Import for HashMap

Kajetan Johannes Hammerle 9 months ago
parent
commit
50257ebfd0
7 changed files with 300 additions and 325 deletions
  1. 43 30
      include/core/HashMap.h
  2. 6 1
      include/core/ToString.h
  3. 12 28
      performance/Main.c
  4. 5 5
      src/Components.c
  5. 47 91
      src/HashMap.c
  6. 28 8
      src/ToString.c
  7. 159 162
      test/modules/HashMapTests.c

+ 43 - 30
include/core/HashMap.h

@@ -3,14 +3,14 @@
 
 #include "core/Types.h"
 
-struct CoreHashMap;
-typedef struct CoreHashMap CoreHashMap;
+struct CoreHashMapT;
+typedef struct CoreHashMapT CoreHashMap;
 
 typedef size_t (*CoreHasher)(const void* key, size_t n);
 typedef bool (*CoreEqual)(const void* keyA, const void* keyB, size_t n);
 typedef void* (*CoreSearchValue)(const CoreHashMap* m, const void* key);
 
-struct CoreHashMap {
+struct CoreHashMapT {
     void* keys;
     void* values;
     size_t keySize;
@@ -27,29 +27,20 @@ void coreInitHashMapF(CoreHashMap* m, size_t keySize, size_t valueSize,
                       CoreHasher hasher, CoreEqual equal);
 void coreDestroyHashMap(CoreHashMap* m);
 void coreRehashHashMap(CoreHashMap* m, size_t minCapacity);
-void* coreHashMapPutPointer(CoreHashMap* m, const void* key, const void* value);
-#define coreHashMapPut(m, kType, key, vType, ...)                              \
-    coreHashMapPutPointer(m, &(kType){key}, &(vType){__VA_ARGS__})
-void* coreHashMapSearchPointer(CoreHashMap* m, const void* key);
-#define coreHashMapSearch(m, kType, key, vType)                                \
-    ((vType*)coreHashMapSearchPointer(m, &(kType){key}))
-const void* coreHashMapSearchPointerC(const CoreHashMap* m, const void* key);
-#define coreHashMapSearchC(m, kType, key, vType)                               \
-    ((const vType*)coreHashMapSearchPointerC(m, &(kType){key}))
-bool coreHashMapContainsPointer(const CoreHashMap* m, const void* key);
-#define coreHashMapContains(m, kType, key)                                     \
-    coreHashMapContainsPointer(m, &(kType){key})
+void* corePutHashMapPair(CoreHashMap* m, const void* key, const void* value);
+#define corePutTypedHashMapPair(m, kType, key, vType, ...)                     \
+    corePutHashMapPair(m, &(kType){key}, &(vType){__VA_ARGS__})
+void* coreSearchHashMapKey(const CoreHashMap* m, const void* key);
+#define coreSearchTypedHashMapKey(m, kType, key, vType)                        \
+    ((vType*)coreSearchHashMapKey(m, &(kType){key}))
 void coreClearHashMap(CoreHashMap* m);
-bool coreHashMapRemovePointer(CoreHashMap* m, const void* key);
-#define coreHashMapRemove(m, kType, key)                                       \
-    coreHashMapRemovePointer(m, &(kType){key})
-size_t coreToStringHashMap(const CoreHashMap* m, char* buffer, size_t n,
-                           CoreToString keyString, CoreToString valueString);
-void coreSwapHashMap(CoreHashMap* a, CoreHashMap* b);
+bool coreRemoveHashMapKey(CoreHashMap* m, const void* key);
+#define coreRemoveTypedHashMapKey(m, kType, key)                               \
+    coreRemoveHashMapKey(m, &(kType){key})
 
 size_t coreHashString(const void* key, size_t n);
-size_t coreHash(const void* key, size_t n);
-bool coreEqual(const void* keyA, const void* keyB, size_t n);
+size_t coreHashKey(const void* key, size_t n);
+bool coreCompareKeys(const void* keyA, const void* keyB, size_t n);
 
 typedef struct {
     const void* key;
@@ -65,12 +56,34 @@ typedef struct {
     CoreHashMapNode node;
 } CoreHashMapIterator;
 
-void coreInitHashMapIterator(CoreHashMapIterator* mi, CoreHashMap* m);
-bool coreHashMapHasNext(CoreHashMapIterator* mi);
-CoreHashMapNode* coreHashMapNext(CoreHashMapIterator* mi);
-#define coreHashMapKeyPointer(node, type) ((const type*)node->key)
-#define coreHashMapKey(node, type) (*coreHashMapKeyPointer(node, type))
-#define coreHashMapValuePointer(node, type) ((type*)node->value)
-#define coreHashMapValue(node, type) (*coreHashMapValuePointer(node, type))
+void coreInitHashMapIterator(CoreHashMapIterator* mi, const CoreHashMap* m);
+bool coreHasNextHashMapNode(CoreHashMapIterator* mi);
+CoreHashMapNode* coreNextHashMapNode(CoreHashMapIterator* mi);
+
+#ifdef IMPORT_CORE
+#define HashMap CoreHashMap
+#define Hasher CoreHasher
+#define Equal CoreEqual
+#define SearchValue CoreSearchValue
+#define initHashMap coreInitHashMap
+#define initHashMapF coreInitHashMapF
+#define destroyHashMap coreDestroyHashMap
+#define rehashHashMap coreRehashHashMap
+#define putHashMapPair corePutHashMapPair
+#define putTypedHashMapPair corePutTypedHashMapPair
+#define searchHashMapKey coreSearchHashMapKey
+#define searchTypedHashMapKey coreSearchTypedHashMapKey
+#define clearHashMap coreClearHashMap
+#define removeHashMapKey coreRemoveHashMapKey
+#define removeTypedHashMapKey coreRemoveTypedHashMapKey
+#define hashString coreHashString
+#define hashKey coreHashKey
+#define compareKeys coreCompareKeys
+#define HashMapNode CoreHashMapNode
+#define HashMapIterator CoreHashMapIterator
+#define initHashMapIterator coreInitHashMapIterator
+#define hasNextHashMapNode coreHasNextHashMapNode
+#define nextHashMapNode coreNextHashMapNode
+#endif
 
 #endif

+ 6 - 1
include/core/ToString.h

@@ -16,6 +16,9 @@ size_t coreToStringList(const struct CoreListT* l, char* buffer, size_t n,
 struct CoreQueueT;
 size_t coreToStringQueue(const struct CoreQueueT* r, char* buffer, size_t n,
                          CoreToString c);
+struct CoreHashMapT;
+size_t coreToStringHashMap(const struct CoreHashMapT* m, char* buffer, size_t n,
+                           CoreToString keyString, CoreToString valueString);
 
 #define CORE_STRUCT_TO_STRING(type)                                            \
     struct Core##type##T;                                                      \
@@ -33,6 +36,7 @@ CORE_STRUCT_TO_STRING(Plane)
 #define stringAdd coreStringAdd
 #define toStringList coreToStringList
 #define toStringQueue coreToStringQueue
+#define toStringHashMap coreToStringHashMap
 #define toStringBitArray coreToStringBitArray
 #define toStringBox coreToStringBox
 #define toStringMatrix coreToStringMatrix
@@ -53,7 +57,8 @@ CORE_STRUCT_TO_STRING(Plane)
         CORE_STRUCT_PAIR(Matrix),                                              \
         CORE_STRUCT_PAIR(Plane),                                               \
         CORE_STRUCT_PAIR(List),                                                \
-        CORE_STRUCT_PAIR(Queue))(t, __VA_ARGS__)
+        CORE_STRUCT_PAIR(Queue),                                               \
+        CORE_STRUCT_PAIR(HashMap))(t, __VA_ARGS__)
 #endif
 
 #endif

+ 12 - 28
performance/Main.c

@@ -4,12 +4,12 @@
 #include "core/Random.h"
 #include "core/Utility.h"
 
-static i64 testSearch(const CoreHashMap* m) {
+static i64 testSearch(const HashMap* m) {
     i64 nanos = coreGetNanos();
     volatile int sum = 0;
     for(int i = 0; i < 10000; i++) {
         for(int k = -5000; k < 5000; k++) {
-            const int* s = coreHashMapSearchC(m, int, i + k, int);
+            const int* s = coreSearchTypedHashMapKey(m, int, i + k, int);
             if(s != nullptr) {
                 sum = sum + *s;
             }
@@ -18,11 +18,11 @@ static i64 testSearch(const CoreHashMap* m) {
     return coreGetNanos() - nanos;
 }
 
-static i64 testEmptySearch(const CoreHashMap* m) {
+static i64 testEmptySearch(const HashMap* m) {
     i64 nanos = coreGetNanos();
     volatile int sum = 0;
     for(int i = 0; i < 100'000'000; i++) {
-        const int* s = coreHashMapSearchC(m, int, -i, int);
+        const int* s = coreSearchTypedHashMapKey(m, int, -i, int);
         if(s != nullptr) {
             sum = sum + *s;
         }
@@ -30,26 +30,26 @@ static i64 testEmptySearch(const CoreHashMap* m) {
     return coreGetNanos() - nanos;
 }
 
-static void fillOrder(CoreHashMap* m) {
+static void fillOrder(HashMap* m) {
     i64 nanos = coreGetNanos();
     for(int i = 0; i < 10000; i++) {
-        coreHashMapPut(m, int, i, int, i* i);
+        corePutTypedHashMapPair(m, int, i, int, i* i);
     }
     printf("Fill Order: %ldns\n", coreGetNanos() - nanos);
 }
 
-static void fillChaos(CoreHashMap* m) {
+static void fillChaos(HashMap* m) {
     i64 nanos = coreGetNanos();
-    CoreRandom random;
+    Random random;
     coreInitRandom(&random, 0);
     for(int i = 0; i < 10000; i++) {
         int r = coreRandomI32(&random, 0, 10000);
-        coreHashMapPut(m, int, r, int, r* r);
+        corePutTypedHashMapPair(m, int, r, int, r* r);
     }
     printf("Fill Chaos: %ldns\n", coreGetNanos() - nanos);
 }
 
-static i64 average(CoreHashMap* m, i64 (*f)(const CoreHashMap* m), int n) {
+static i64 average(HashMap* m, i64 (*f)(const HashMap* m), int n) {
     i64 sum = 0;
     for(int i = 0; i < n; i++) {
         sum += f(m);
@@ -58,10 +58,9 @@ static i64 average(CoreHashMap* m, i64 (*f)(const CoreHashMap* m), int n) {
 }
 
 static void order(int n) {
-    CoreHashMap m;
+    HashMap m;
     coreInitHashMap(&m, sizeof(int), sizeof(int));
     fillOrder(&m);
-    m.hasher = nullptr;
     puts("Order Probing");
     printf("Search | %ld ms\n", average(&m, testSearch, n));
     printf("EmptySearch | %ld ms\n", average(&m, testEmptySearch, n));
@@ -69,7 +68,7 @@ static void order(int n) {
 }
 
 static void chaos(int n) {
-    CoreHashMap m;
+    HashMap m;
     coreInitHashMap(&m, sizeof(int), sizeof(int));
     fillChaos(&m);
     puts("Chaos Probing");
@@ -78,23 +77,8 @@ static void chaos(int n) {
     coreDestroyHashMap(&m);
 }
 
-/*static void testProbing(int n) {
-    Core::ProbingHashMap<int, int> m;
-    Core::ProbingHashMap<int, int> m2;
-    fillOrder(m);
-    fillChaos(m2);
-    Logger::log(Logger::COLOR_GRAY, "Order | Chaos");
-    Logger::log(Logger::COLOR_GRAY, "Search | # ms | # ms",
-                average(m, testSearch, n), average(m2, testSearch, n));
-    Logger::log(Logger::COLOR_GRAY, "EmptySearch | # ms | # ms",
-                average(m, testEmptySearch, n),
-                average(m2, testEmptySearch, n));
-}*/
-
 int main() {
-    //(void)testProbing;
     order(3);
     chaos(3);
-    // testProbing(3);
     return 0;
 }

+ 5 - 5
src/Components.c

@@ -18,13 +18,13 @@ void* coreComponentsGetOrAdd(CoreComponents* c, CoreEntity e) {
         return component;
     }
     size_t index = c->components.length;
-    coreHashMapPutPointer(&c->entityToIndex, &e, &index);
+    corePutHashMapPair(&c->entityToIndex, &e, &index);
     coreAddListData(&c->indexToEntity, &e);
     return coreAddEmptyListData(&c->components);
 }
 
 void* coreComponentsSearch(CoreComponents* c, CoreEntity e) {
-    size_t* index = coreHashMapSearchPointer(&c->entityToIndex, &e);
+    size_t* index = coreSearchHashMapKey(&c->entityToIndex, &e);
     if(index == nullptr) {
         return nullptr;
     }
@@ -32,13 +32,13 @@ void* coreComponentsSearch(CoreComponents* c, CoreEntity e) {
 }
 
 bool coreComponentsRemove(CoreComponents* c, CoreEntity e) {
-    size_t* indexP = coreHashMapSearchPointer(&c->entityToIndex, &e);
+    size_t* indexP = coreSearchHashMapKey(&c->entityToIndex, &e);
     if(indexP == nullptr) {
         return false;
     }
     size_t lastIndex = c->components.length - 1;
     size_t index = *indexP;
-    coreHashMapRemovePointer(&c->entityToIndex, &e);
+    coreRemoveHashMapKey(&c->entityToIndex, &e);
     coreRemoveListIndexBySwap(&c->components, index);
     if(index == lastIndex) {
         coreRemoveListIndexBySwap(&c->indexToEntity, index);
@@ -47,7 +47,7 @@ bool coreComponentsRemove(CoreComponents* c, CoreEntity e) {
     CoreEntity other =
         coreGetTypedListIndex(&c->indexToEntity, lastIndex, CoreEntity);
     coreRemoveListIndexBySwap(&c->indexToEntity, index);
-    coreHashMapPutPointer(&c->entityToIndex, &other, &index);
+    corePutHashMapPair(&c->entityToIndex, &other, &index);
     return true;
 }
 

+ 47 - 91
src/HashMap.c

@@ -1,12 +1,8 @@
 #include "core/HashMap.h"
 
-#include <stdio.h>
-#include <string.h>
-
-#include "core/ToString.h"
 #include "core/Utility.h"
 
-static bool isInvalidKey(const CoreHashMap* m, const void* key) {
+static bool isInvalidKey(const HashMap* m, const void* key) {
     const char* c = key;
     for(size_t i = m->keySize; i > 0; i--) {
         if(*(c++) != 0) {
@@ -16,18 +12,18 @@ static bool isInvalidKey(const CoreHashMap* m, const void* key) {
     return true;
 }
 
-static void* getKey(const CoreHashMap* m, size_t index) {
+static void* getKey(const HashMap* m, size_t index) {
     return (char*)m->keys + m->keySize * index;
 }
 
-static void* getValue(const CoreHashMap* m, size_t index) {
+static void* getValue(const HashMap* m, size_t index) {
     return (char*)m->values + m->valueSize * index;
 }
 
-static size_t searchSlot(CoreHashMap* m, const void* key) {
+static size_t searchSlot(HashMap* m, const void* key) {
     size_t rehashFactor = 2;
     while(true) {
-        coreRehashHashMap(m, m->entries * rehashFactor + 1);
+        rehashHashMap(m, m->entries * rehashFactor + 1);
         if(isInvalidKey(m, key)) {
             return m->capacity - 1;
         }
@@ -47,7 +43,7 @@ static size_t searchSlot(CoreHashMap* m, const void* key) {
 }
 
 #define SEARCH_VALUE(type, Type)                                               \
-    static void* searchValue##Type(const CoreHashMap* m, const void* rawKey) { \
+    static void* searchValue##Type(const HashMap* m, const void* rawKey) {     \
         type key = *(const type*)rawKey;                                       \
         if(m->capacity != 0) {                                                 \
             if(key == 0) {                                                     \
@@ -71,7 +67,7 @@ static size_t searchSlot(CoreHashMap* m, const void* key) {
 SEARCH_VALUE(u32, U32)
 SEARCH_VALUE(u64, U64)
 
-static void* searchValue(const CoreHashMap* m, const void* key) {
+static void* searchValue(const HashMap* m, const void* key) {
     if(m->capacity != 0) {
         if(isInvalidKey(m, key)) {
             size_t i = m->capacity - 1;
@@ -100,14 +96,14 @@ static size_t roundUp2(size_t n) {
     return w;
 }
 
-void coreInitHashMap(CoreHashMap* m, size_t keySize, size_t valueSize) {
-    coreInitHashMapF(m, keySize, valueSize, coreHash, coreEqual);
+void initHashMap(HashMap* m, size_t keySize, size_t valueSize) {
+    initHashMapF(m, keySize, valueSize, hashKey, compareKeys);
 }
 
-void coreInitHashMapF(CoreHashMap* m, size_t keySize, size_t valueSize,
-                      CoreHasher hasher, CoreEqual equal) {
-    CoreSearchValue search = searchValue;
-    if(hasher == coreHash && equal == coreEqual) {
+void initHashMapF(HashMap* m, size_t keySize, size_t valueSize, Hasher hasherF,
+                  Equal equal) {
+    SearchValue search = searchValue;
+    if(hasherF == hashKey && equal == compareKeys) {
         switch(keySize) {
             case sizeof(u32): search = searchValueU32; break;
             case sizeof(u64): search = searchValueU64; break;
@@ -119,29 +115,29 @@ void coreInitHashMapF(CoreHashMap* m, size_t keySize, size_t valueSize,
     m->valueSize = valueSize;
     m->capacity = 0;
     m->entries = 0;
-    m->hasher = hasher;
+    m->hasher = hasherF;
     m->equal = equal;
     m->search = search;
 }
 
-void coreDestroyHashMap(CoreHashMap* m) {
-    coreFree(m->keys);
-    coreFree(m->values);
-    *m = (CoreHashMap){0};
+void destroyHashMap(HashMap* m) {
+    cFree(m->keys);
+    cFree(m->values);
+    *m = (HashMap){0};
 }
 
-void coreRehashHashMap(CoreHashMap* m, size_t minCapacity) {
+void rehashHashMap(HashMap* m, size_t minCapacity) {
     if(minCapacity <= m->capacity) {
         return;
     }
-    size_t l = roundUp2(coreMaxSize(minCapacity, 8lu)) + 1;
-    CoreHashMap map;
-    coreInitHashMapF(&map, m->keySize, m->valueSize, m->hasher, m->equal);
+    size_t l = roundUp2(maxSize(minCapacity, 8lu)) + 1;
+    HashMap map;
+    initHashMapF(&map, m->keySize, m->valueSize, m->hasher, m->equal);
     size_t keyBytes = l * m->keySize;
-    map.keys = coreAllocate(keyBytes);
+    map.keys = cAllocate(keyBytes);
     memset(map.keys, 0, keyBytes);
     memset(getKey(&map, l - 1), 1, m->keySize);
-    map.values = coreAllocate(l * m->valueSize);
+    map.values = cAllocate(l * m->valueSize);
     map.capacity = l;
 
     size_t length = m->capacity;
@@ -150,20 +146,19 @@ void coreRehashHashMap(CoreHashMap* m, size_t minCapacity) {
         for(size_t i = 0; i < length; i++) {
             void* keyEntry = getKey(m, i);
             if(!isInvalidKey(m, keyEntry)) {
-                coreHashMapPutPointer(&map, keyEntry, getValue(m, i));
+                putHashMapPair(&map, keyEntry, getValue(m, i));
             }
         }
         void* keyEntry = getKey(m, length);
         if(isInvalidKey(m, keyEntry)) {
-            coreHashMapPutPointer(&map, keyEntry, getValue(m, length));
+            putHashMapPair(&map, keyEntry, getValue(m, length));
         }
     }
-    coreSwapHashMap(&map, m);
-    coreDestroyHashMap(&map);
+    swap(&map, m);
+    destroyHashMap(&map);
 }
 
-void* coreHashMapPutPointer(CoreHashMap* m, const void* key,
-                            const void* value) {
+void* putHashMapPair(HashMap* m, const void* key, const void* value) {
     size_t index = searchSlot(m, key);
     void* keyEntry = getKey(m, index);
     if(m->equal(keyEntry, key, m->keySize)) {
@@ -178,19 +173,11 @@ void* coreHashMapPutPointer(CoreHashMap* m, const void* key,
     return v;
 }
 
-void* coreHashMapSearchPointer(CoreHashMap* m, const void* key) {
-    return m->search(m, key);
-}
-
-const void* coreHashMapSearchPointerC(const CoreHashMap* m, const void* key) {
+void* searchHashMapKey(const HashMap* m, const void* key) {
     return m->search(m, key);
 }
 
-bool coreHashMapContainsPointer(const CoreHashMap* m, const void* key) {
-    return coreHashMapSearchPointerC(m, key) != nullptr;
-}
-
-void coreClearHashMap(CoreHashMap* m) {
+void clearHashMap(HashMap* m) {
     if(m->keys == nullptr) {
         return;
     }
@@ -199,58 +186,27 @@ void coreClearHashMap(CoreHashMap* m) {
     memset(getKey(m, m->capacity - 1), 1, m->keySize);
 }
 
-bool coreHashMapRemovePointer(CoreHashMap* m, const void* key) {
+bool removeHashMapKey(HashMap* m, const void* key) {
     // ToDo: This is a very slow remove
-    CoreHashMap n;
-    coreInitHashMapF(&n, m->keySize, m->valueSize, m->hasher, m->equal);
-    CoreHashMapIterator i;
-    coreInitHashMapIterator(&i, m);
+    HashMap n;
+    initHashMapF(&n, m->keySize, m->valueSize, m->hasher, m->equal);
+    HashMapIterator i;
+    initHashMapIterator(&i, m);
     bool r = false;
-    while(coreHashMapHasNext(&i)) {
-        CoreHashMapNode* node = coreHashMapNext(&i);
+    while(hasNextHashMapNode(&i)) {
+        HashMapNode* node = nextHashMapNode(&i);
         if(!m->equal(key, node->key, n.keySize)) {
-            coreHashMapPutPointer(&n, node->key, node->value);
+            putHashMapPair(&n, node->key, node->value);
         } else {
             r = true;
         }
     }
-    coreSwapHashMap(&n, m);
-    coreDestroyHashMap(&n);
+    swap(&n, m);
+    destroyHashMap(&n);
     return r;
 }
 
-size_t coreToStringHashMap(const CoreHashMap* m, char* buffer, size_t n,
-                           CoreToString keyString, CoreToString valueString) {
-    size_t w = 0;
-    coreStringAdd(&w, &buffer, &n, coreToString(buffer, n, "["));
-    char* end = getKey(m, m->capacity);
-    char* key = m->keys;
-    char* value = m->values;
-    bool notFirst = false;
-    while(key != end) {
-        if(isInvalidKey(m, key) == (key + m->keySize == end)) {
-            if(notFirst) {
-                coreStringAdd(&w, &buffer, &n, coreToString(buffer, n, ", "));
-            }
-            notFirst = true;
-            coreStringAdd(&w, &buffer, &n, keyString(key, buffer, n));
-            coreStringAdd(&w, &buffer, &n, coreToString(buffer, n, " = "));
-            coreStringAdd(&w, &buffer, &n, valueString(value, buffer, n));
-        }
-        key += m->keySize;
-        value += m->valueSize;
-    }
-    coreStringAdd(&w, &buffer, &n, coreToString(buffer, n, "]"));
-    return w;
-}
-
-void coreSwapHashMap(CoreHashMap* a, CoreHashMap* b) {
-    CoreHashMap tmp = *a;
-    *a = *b;
-    *b = tmp;
-}
-
-size_t coreHashString(const void* key, size_t n) {
+size_t hashString(const void* key, size_t n) {
     if(n != sizeof(char*)) {
         return 0;
     }
@@ -262,7 +218,7 @@ size_t coreHashString(const void* key, size_t n) {
     return h;
 }
 
-size_t coreHash(const void* key, size_t n) {
+size_t hashKey(const void* key, size_t n) {
     size_t h = 0;
     if(n <= sizeof(size_t)) {
         memcpy(&h, key, n);
@@ -285,11 +241,11 @@ size_t coreHash(const void* key, size_t n) {
     return h;
 }
 
-bool coreEqual(const void* keyA, const void* keyB, size_t n) {
+bool compareKeys(const void* keyA, const void* keyB, size_t n) {
     return memcmp(keyA, keyB, n) == 0;
 }
 
-void coreInitHashMapIterator(CoreHashMapIterator* mi, CoreHashMap* m) {
+void initHashMapIterator(HashMapIterator* mi, const HashMap* m) {
     mi->key = m->keys;
     mi->endKey = mi->key + m->capacity * m->keySize;
     mi->value = m->values;
@@ -297,7 +253,7 @@ void coreInitHashMapIterator(CoreHashMapIterator* mi, CoreHashMap* m) {
     mi->map = m;
 }
 
-bool coreHashMapHasNext(CoreHashMapIterator* mi) {
+bool hasNextHashMapNode(HashMapIterator* mi) {
     while(mi->key != mi->endKey) {
         char* nextKey = mi->key + mi->map->keySize;
         if(isInvalidKey(mi->map, mi->key) == (nextKey == mi->endKey)) {
@@ -309,7 +265,7 @@ bool coreHashMapHasNext(CoreHashMapIterator* mi) {
     return mi->key != mi->endKey;
 }
 
-CoreHashMapNode* coreHashMapNext(CoreHashMapIterator* mi) {
+HashMapNode* nextHashMapNode(HashMapIterator* mi) {
     mi->node.key = mi->key;
     mi->node.value = mi->value;
     mi->key += mi->map->keySize;

+ 28 - 8
src/ToString.c

@@ -5,6 +5,7 @@
 
 #include "core/BitArray.h"
 #include "core/Box.h"
+#include "core/HashMap.h"
 #include "core/List.h"
 #include "core/Matrix.h"
 #include "core/Plane.h"
@@ -98,20 +99,39 @@ size_t toStringList(const List* l, char* buffer, size_t n, ToString c) {
     return w;
 }
 
-size_t coreToStringQueue(const CoreQueue* r, char* buffer, size_t n,
-                         CoreToString c) {
+size_t toStringQueue(const Queue* r, char* buffer, size_t n, ToString c) {
     size_t w = 0;
-    coreStringAdd(&w, &buffer, &n, coreToString(buffer, n, "["));
+    stringAdd(&w, &buffer, &n, coreToString(buffer, n, "["));
     size_t end = r->length;
     if(end > 0) {
         end--;
         for(size_t i = 0; i < end; i++) {
-            coreStringAdd(&w, &buffer, &n,
-                          c(coreGetQueueIndex(r, i), buffer, n));
-            coreStringAdd(&w, &buffer, &n, coreToString(buffer, n, ", "));
+            stringAdd(&w, &buffer, &n, c(getQueueIndex(r, i), buffer, n));
+            stringAdd(&w, &buffer, &n, coreToString(buffer, n, ", "));
+        }
+        stringAdd(&w, &buffer, &n, c(getQueueIndex(r, end), buffer, n));
+    }
+    stringAdd(&w, &buffer, &n, coreToString(buffer, n, "]"));
+    return w;
+}
+
+size_t toStringHashMap(const HashMap* m, char* buffer, size_t n,
+                       ToString keyString, ToString valueString) {
+    size_t w = 0;
+    stringAdd(&w, &buffer, &n, coreToString(buffer, n, "["));
+    bool notFirst = false;
+    HashMapIterator i;
+    initHashMapIterator(&i, m);
+    while(hasNextHashMapNode(&i)) {
+        HashMapNode* node = nextHashMapNode(&i);
+        if(notFirst) {
+            stringAdd(&w, &buffer, &n, coreToString(buffer, n, ", "));
         }
-        coreStringAdd(&w, &buffer, &n, c(coreGetQueueIndex(r, end), buffer, n));
+        notFirst = true;
+        stringAdd(&w, &buffer, &n, keyString(node->key, buffer, n));
+        stringAdd(&w, &buffer, &n, coreToString(buffer, n, " = "));
+        stringAdd(&w, &buffer, &n, valueString(node->value, buffer, n));
     }
-    coreStringAdd(&w, &buffer, &n, coreToString(buffer, n, "]"));
+    stringAdd(&w, &buffer, &n, coreToString(buffer, n, "]"));
     return w;
 }

+ 159 - 162
test/modules/HashMapTests.c

@@ -3,214 +3,211 @@
 #include "core/ToString.h"
 #include "core/Utility.h"
 
-static CoreHashMap createIntMap() {
-    CoreHashMap map;
-    coreInitHashMap(&map, sizeof(int), sizeof(int));
+static HashMap createIntMap() {
+    HashMap map;
+    initHashMap(&map, sizeof(int), sizeof(int));
     return map;
 }
 
-static CoreHashMap getTestIntMap() {
-    CoreHashMap map = createIntMap();
-    coreHashMapPut(&map, int, 1, int, 3);
-    coreHashMapPut(&map, int, 2, int, 4);
-    coreHashMapPut(&map, int, 3, int, 5);
-    coreHashMapPut(&map, int, 0, int, 20);
+static HashMap getTestIntMap() {
+    HashMap map = createIntMap();
+    putTypedHashMapPair(&map, int, 1, int, 3);
+    putTypedHashMapPair(&map, int, 2, int, 4);
+    putTypedHashMapPair(&map, int, 3, int, 5);
+    putTypedHashMapPair(&map, int, 0, int, 20);
     return map;
 }
 
-static void checkIntMap(CoreHashMap* map) {
-    int* a = coreHashMapSearch(map, int, 1, int);
-    int* b = coreHashMapSearch(map, int, 2, int);
-    const int* c = coreHashMapSearchC(map, int, 3, int);
-    const int* d = coreHashMapSearchC(map, int, 0, int);
-    if(CORE_TEST_NOT_NULL(a) && CORE_TEST_NOT_NULL(b) &&
-       CORE_TEST_NOT_NULL(c) && CORE_TEST_NOT_NULL(d)) {
-        CORE_TEST_INT(3, *a);
-        CORE_TEST_INT(4, *b);
-        CORE_TEST_INT(5, *c);
-        CORE_TEST_INT(20, *d);
+static void checkIntMap(HashMap* map) {
+    int* a = searchTypedHashMapKey(map, int, 1, int);
+    int* b = searchTypedHashMapKey(map, int, 2, int);
+    int* c = searchTypedHashMapKey(map, int, 3, int);
+    int* d = searchTypedHashMapKey(map, int, 0, int);
+    if(TEST_NOT_NULL(a) && TEST_NOT_NULL(b) && TEST_NOT_NULL(c) &&
+       TEST_NOT_NULL(d)) {
+        TEST_INT(3, *a);
+        TEST_INT(4, *b);
+        TEST_INT(5, *c);
+        TEST_INT(20, *d);
     }
 }
 
 static void testAdd() {
-    CoreHashMap map = createIntMap();
-    coreHashMapPut(&map, int, 5, int, 4);
-    int* value = coreHashMapSearch(&map, int, 5, int);
-    if(CORE_TEST_NOT_NULL(value)) {
-        CORE_TEST_INT(4, *value);
+    HashMap map = createIntMap();
+    putTypedHashMapPair(&map, int, 5, int, 4);
+    int* value = searchTypedHashMapKey(&map, int, 5, int);
+    if(TEST_NOT_NULL(value)) {
+        TEST_INT(4, *value);
     }
-    coreDestroyHashMap(&map);
+    destroyHashMap(&map);
 }
 
 static void testMultipleAdd() {
-    CoreHashMap map = getTestIntMap();
-    CORE_TEST_TRUE(coreHashMapContains(&map, int, 0));
-    CORE_TEST_TRUE(coreHashMapContains(&map, int, 1));
-    CORE_TEST_TRUE(coreHashMapContains(&map, int, 2));
-    CORE_TEST_TRUE(coreHashMapContains(&map, int, 3));
+    HashMap map = getTestIntMap();
+    TEST_NOT_NULL(searchTypedHashMapKey(&map, int, 0, int));
+    TEST_NOT_NULL(searchTypedHashMapKey(&map, int, 1, int));
+    TEST_NOT_NULL(searchTypedHashMapKey(&map, int, 2, int));
+    TEST_NOT_NULL(searchTypedHashMapKey(&map, int, 3, int));
     checkIntMap(&map);
-    coreDestroyHashMap(&map);
+    destroyHashMap(&map);
 }
 
 static void testSearch() {
-    CoreHashMap map = getTestIntMap();
-    CORE_TEST_NULL(coreHashMapSearch(&map, int, 6, int));
-    coreHashMapPut(&map, int, 5, int, 4);
-    coreHashMapPut(&map, int, 10, int, 3);
-    coreHashMapPut(&map, int, 15, int, 2);
-    CORE_TEST_NULL(coreHashMapSearch(&map, int, 6, int));
-    coreDestroyHashMap(&map);
+    HashMap map = getTestIntMap();
+    TEST_NULL(searchTypedHashMapKey(&map, int, 6, int));
+    putTypedHashMapPair(&map, int, 5, int, 4);
+    putTypedHashMapPair(&map, int, 10, int, 3);
+    putTypedHashMapPair(&map, int, 15, int, 2);
+    TEST_NULL(searchTypedHashMapKey(&map, int, 6, int));
+    destroyHashMap(&map);
 }
 
 static void testSearchEmpty() {
-    CoreHashMap map = createIntMap();
-    CORE_TEST_NULL(coreHashMapSearch(&map, int, 6, int));
-    coreDestroyHashMap(&map);
+    HashMap map = createIntMap();
+    TEST_NULL(searchTypedHashMapKey(&map, int, 6, int));
+    destroyHashMap(&map);
 }
 
 static void testAddReplace() {
-    CoreHashMap map = getTestIntMap();
-    coreHashMapPut(&map, int, 5, int, 4);
-    coreHashMapPut(&map, int, 5, int, 10);
-    CORE_TEST_TRUE(coreHashMapContains(&map, int, 5));
-    int* a = coreHashMapSearch(&map, int, 5, int);
-    if(CORE_TEST_NOT_NULL(a)) {
-        CORE_TEST_INT(10, *a);
+    HashMap map = getTestIntMap();
+    putTypedHashMapPair(&map, int, 5, int, 4);
+    putTypedHashMapPair(&map, int, 5, int, 10);
+    TEST_NOT_NULL(searchTypedHashMapKey(&map, int, 5, int));
+    int* a = searchTypedHashMapKey(&map, int, 5, int);
+    if(TEST_NOT_NULL(a)) {
+        TEST_INT(10, *a);
     }
-    coreDestroyHashMap(&map);
+    destroyHashMap(&map);
 }
 
 static void testClear() {
-    CoreHashMap map = getTestIntMap();
-    coreHashMapPut(&map, int, 5, int, 4);
-    coreHashMapPut(&map, int, 4, int, 10);
-    coreClearHashMap(&map);
-    CORE_TEST_FALSE(coreHashMapContains(&map, int, 5));
-    CORE_TEST_FALSE(coreHashMapContains(&map, int, 4));
-    coreDestroyHashMap(&map);
+    HashMap map = getTestIntMap();
+    putTypedHashMapPair(&map, int, 5, int, 4);
+    putTypedHashMapPair(&map, int, 4, int, 10);
+    clearHashMap(&map);
+    TEST_NULL(searchTypedHashMapKey(&map, int, 5, int));
+    TEST_NULL(searchTypedHashMapKey(&map, int, 4, int));
+    destroyHashMap(&map);
 }
 
 static void testClearEmpty() {
-    CoreHashMap map = createIntMap();
-    coreClearHashMap(&map);
-    coreDestroyHashMap(&map);
+    HashMap map = createIntMap();
+    clearHashMap(&map);
+    destroyHashMap(&map);
 }
 
 static void testOverflow(bool light) {
     int limit = light ? 10000 : 100000;
-    CoreHashMap map = getTestIntMap();
+    HashMap map = getTestIntMap();
     for(int i = 0; i < limit; i++) {
-        coreHashMapPut(&map, int, i, int, i);
+        putTypedHashMapPair(&map, int, i, int, i);
     }
     for(int i = 0; i < limit; i++) {
-        CORE_TEST_TRUE(coreHashMapContains(&map, int, i));
+        TEST_NOT_NULL(searchTypedHashMapKey(&map, int, i, int));
     }
-    coreDestroyHashMap(&map);
+    destroyHashMap(&map);
 }
 
 static void testToString() {
-    CoreHashMap map = getTestIntMap();
+    HashMap map = getTestIntMap();
     char buffer[128];
-    size_t n = coreToStringHashMap(&map, buffer, sizeof(buffer),
-                                   coreToStringInt, coreToStringInt);
-    CORE_TEST_SIZE(29, n);
-    CORE_TEST_STRING("[2 = 4, 1 = 3, 3 = 5, 0 = 20]", buffer);
-
-    coreClearHashMap(&map);
-    coreHashMapPut(&map, int, 1, int, 3);
-    n = coreToStringHashMap(&map, buffer, sizeof(buffer), coreToStringInt,
-                            coreToStringInt);
-    CORE_TEST_SIZE(7, n);
-    CORE_TEST_STRING("[1 = 3]", buffer);
-
-    coreClearHashMap(&map);
-    n = coreToStringHashMap(&map, buffer, sizeof(buffer), coreToStringInt,
-                            coreToStringInt);
-    CORE_TEST_SIZE(2, n);
-    CORE_TEST_STRING("[]", buffer);
-
-    coreDestroyHashMap(&map);
+    size_t n = toString(&map, buffer, sizeof(buffer), toStringInt, toStringInt);
+    TEST_SIZE(29, n);
+    TEST_STRING("[2 = 4, 1 = 3, 3 = 5, 0 = 20]", buffer);
+
+    clearHashMap(&map);
+    putTypedHashMapPair(&map, int, 1, int, 3);
+    n = toString(&map, buffer, sizeof(buffer), toStringInt, toStringInt);
+    TEST_SIZE(7, n);
+    TEST_STRING("[1 = 3]", buffer);
+
+    clearHashMap(&map);
+    n = toString(&map, buffer, sizeof(buffer), toStringInt, toStringInt);
+    TEST_SIZE(2, n);
+    TEST_STRING("[]", buffer);
+
+    destroyHashMap(&map);
 }
 
 static void testEntryForEach() {
-    CoreHashMap map = createIntMap();
-    coreHashMapPut(&map, int, 0, int, -1);
-    coreHashMapPut(&map, int, 5, int, 4);
-    coreHashMapPut(&map, int, 10, int, 3);
-    coreHashMapPut(&map, int, 15, int, 2);
+    HashMap map = createIntMap();
+    putTypedHashMapPair(&map, int, 0, int, -1);
+    putTypedHashMapPair(&map, int, 5, int, 4);
+    putTypedHashMapPair(&map, int, 10, int, 3);
+    putTypedHashMapPair(&map, int, 15, int, 2);
 
     int counter = 0;
-    CoreHashMapIterator i;
-    coreInitHashMapIterator(&i, &map);
-    while(coreHashMapHasNext(&i)) {
-        CoreHashMapNode* n = coreHashMapNext(&i);
-        counter += coreHashMapKey(n, int) + coreHashMapValue(n, int);
+    HashMapIterator i;
+    initHashMapIterator(&i, &map);
+    while(hasNextHashMapNode(&i)) {
+        HashMapNode* n = nextHashMapNode(&i);
+        counter += *(const int*)n->key + *(int*)n->value;
     }
-    CORE_TEST_INT(38, counter);
+    TEST_INT(38, counter);
 
-    coreDestroyHashMap(&map);
+    destroyHashMap(&map);
 }
 
 static void testInvalidPut() {
-    CoreHashMap map = createIntMap();
+    HashMap map = createIntMap();
 
     char buffer[128];
     coreToStringHashMap(&map, buffer, sizeof(buffer), coreToStringInt,
                         coreToStringInt);
-    CORE_TEST_STRING("[]", buffer);
+    TEST_STRING("[]", buffer);
 
-    coreHashMapPut(&map, int, 0, int, 3);
-    int* v = coreHashMapSearch(&map, int, 0, int);
-    if(CORE_TEST_NOT_NULL(v)) {
-        CORE_TEST_INT(3, *v);
+    putTypedHashMapPair(&map, int, 0, int, 3);
+    int* v = searchTypedHashMapKey(&map, int, 0, int);
+    if(TEST_NOT_NULL(v)) {
+        TEST_INT(3, *v);
     }
     coreToStringHashMap(&map, buffer, sizeof(buffer), coreToStringInt,
                         coreToStringInt);
-    CORE_TEST_STRING("[0 = 3]", buffer);
+    TEST_STRING("[0 = 3]", buffer);
 
-    coreClearHashMap(&map);
-    CORE_TEST_NULL(coreHashMapSearch(&map, int, 0, int));
+    clearHashMap(&map);
+    TEST_NULL(searchTypedHashMapKey(&map, int, 0, int));
 
-    coreDestroyHashMap(&map);
+    destroyHashMap(&map);
 }
 
 static void testAddCollisions() {
-    CoreHashMap map = getTestIntMap();
+    HashMap map = getTestIntMap();
     for(int i = 0; i < 16; i++) {
-        coreHashMapPut(&map, int, i * 64, int, i);
+        putTypedHashMapPair(&map, int, i * 64, int, i);
     }
-    coreDestroyHashMap(&map);
+    destroyHashMap(&map);
 }
 
 static void testRemove() {
-    CoreHashMap map = createIntMap();
-    coreHashMapPut(&map, int, 1, int, 3);
-    coreHashMapPut(&map, int, 2, int, 4);
-    coreHashMapPut(&map, int, 3, int, 5);
-
-    CORE_TEST_TRUE(coreHashMapRemove(&map, size_t, 2));
-    CORE_TEST_FALSE(coreHashMapRemove(&map, size_t, 7));
-
-    int* a = coreHashMapSearch(&map, int, 1, int);
-    int* b = coreHashMapSearch(&map, int, 2, int);
-    int* c = coreHashMapSearch(&map, int, 3, int);
-
-    CORE_TEST_NULL(b);
-    if(CORE_TEST_NOT_NULL(a) && CORE_TEST_NOT_NULL(c)) {
-        CORE_TEST_INT(3, *a);
-        CORE_TEST_INT(5, *c);
+    HashMap map = createIntMap();
+    putTypedHashMapPair(&map, int, 1, int, 3);
+    putTypedHashMapPair(&map, int, 2, int, 4);
+    putTypedHashMapPair(&map, int, 3, int, 5);
+
+    TEST_TRUE(removeTypedHashMapKey(&map, size_t, 2));
+    TEST_FALSE(removeTypedHashMapKey(&map, size_t, 7));
+
+    int* a = searchTypedHashMapKey(&map, int, 1, int);
+    int* b = searchTypedHashMapKey(&map, int, 2, int);
+    int* c = searchTypedHashMapKey(&map, int, 3, int);
+
+    TEST_NULL(b);
+    if(TEST_NOT_NULL(a) && TEST_NOT_NULL(c)) {
+        TEST_INT(3, *a);
+        TEST_INT(5, *c);
     }
 
-    coreDestroyHashMap(&map);
+    destroyHashMap(&map);
 }
 
 static void testHash() {
     u32 buffer[] = {0xFFAA00BB, 0x00000000, 0x00FF00FF};
-    CORE_TEST_SIZE(0xFF550044, coreHash(buffer, sizeof(buffer)));
+    TEST_SIZE(0xFF550044, hashKey(buffer, sizeof(buffer)));
 
     const char* s = "wusi";
-    CORE_TEST_TRUE(coreHashString(&s, sizeof(&s)) != 0);
-    CORE_TEST_SIZE(0, coreHashString(&s, 1));
+    TEST_TRUE(hashString(&s, sizeof(&s)) != 0);
+    TEST_SIZE(0, hashString(&s, 1));
 }
 
 typedef struct {
@@ -219,56 +216,56 @@ typedef struct {
 } A;
 
 static void testSearchStruct() {
-    CoreHashMap map;
-    coreInitHashMap(&map, sizeof(A), sizeof(int));
+    HashMap map;
+    initHashMap(&map, sizeof(A), sizeof(int));
     A a = {1, 2};
     A b = {1, 3};
     A c = {0, 0};
-    CORE_TEST_NULL(coreHashMapSearchPointer(&map, &a));
-    CORE_TEST_NULL(coreHashMapSearchPointer(&map, &b));
-    CORE_TEST_NULL(coreHashMapSearchPointer(&map, &c));
+    TEST_NULL(searchHashMapKey(&map, &a));
+    TEST_NULL(searchHashMapKey(&map, &b));
+    TEST_NULL(searchHashMapKey(&map, &c));
     int v = 3;
-    coreHashMapPutPointer(&map, &a, &v);
+    putHashMapPair(&map, &a, &v);
 
-    int* ap = coreHashMapSearchPointer(&map, &a);
-    if(CORE_TEST_NOT_NULL(ap)) {
-        CORE_TEST_INT(3, *ap);
+    int* ap = searchHashMapKey(&map, &a);
+    if(TEST_NOT_NULL(ap)) {
+        TEST_INT(3, *ap);
     }
-    CORE_TEST_NULL(coreHashMapSearchPointer(&map, &b));
-    CORE_TEST_NULL(coreHashMapSearchPointer(&map, &c));
+    TEST_NULL(searchHashMapKey(&map, &b));
+    TEST_NULL(searchHashMapKey(&map, &c));
 
     v = 4;
-    coreHashMapPutPointer(&map, &c, &v);
-    int* cp = coreHashMapSearchPointer(&map, &c);
-    if(CORE_TEST_NOT_NULL(cp)) {
-        CORE_TEST_INT(4, *cp);
+    putHashMapPair(&map, &c, &v);
+    int* cp = searchHashMapKey(&map, &c);
+    if(TEST_NOT_NULL(cp)) {
+        TEST_INT(4, *cp);
     }
 
-    coreDestroyHashMap(&map);
+    destroyHashMap(&map);
 }
 
 static void testSearchSize() {
-    CoreHashMap map;
-    coreInitHashMap(&map, sizeof(size_t), sizeof(int));
-    CORE_TEST_NULL(coreHashMapSearch(&map, size_t, 0, int));
-    CORE_TEST_NULL(coreHashMapSearch(&map, size_t, 1, int));
-    CORE_TEST_NULL(coreHashMapSearch(&map, size_t, 2, int));
-    coreHashMapPut(&map, size_t, 1, int, 3);
-
-    int* ap = coreHashMapSearch(&map, size_t, 1, int);
-    if(CORE_TEST_NOT_NULL(ap)) {
-        CORE_TEST_INT(3, *ap);
+    HashMap map;
+    initHashMap(&map, sizeof(size_t), sizeof(int));
+    TEST_NULL(searchTypedHashMapKey(&map, size_t, 0, int));
+    TEST_NULL(searchTypedHashMapKey(&map, size_t, 1, int));
+    TEST_NULL(searchTypedHashMapKey(&map, size_t, 2, int));
+    putTypedHashMapPair(&map, size_t, 1, int, 3);
+
+    int* ap = searchTypedHashMapKey(&map, size_t, 1, int);
+    if(TEST_NOT_NULL(ap)) {
+        TEST_INT(3, *ap);
     }
-    CORE_TEST_NULL(coreHashMapSearch(&map, size_t, 0, int));
-    CORE_TEST_NULL(coreHashMapSearch(&map, size_t, 2, int));
+    TEST_NULL(searchTypedHashMapKey(&map, size_t, 0, int));
+    TEST_NULL(searchTypedHashMapKey(&map, size_t, 2, int));
 
-    coreHashMapPut(&map, size_t, 0, int, 4);
-    int* cp = coreHashMapSearch(&map, size_t, 0, int);
-    if(CORE_TEST_NOT_NULL(cp)) {
-        CORE_TEST_INT(4, *cp);
+    putTypedHashMapPair(&map, size_t, 0, int, 4);
+    int* cp = searchTypedHashMapKey(&map, size_t, 0, int);
+    if(TEST_NOT_NULL(cp)) {
+        TEST_INT(4, *cp);
     }
 
-    coreDestroyHashMap(&map);
+    destroyHashMap(&map);
 }
 
 void testHashMap(bool light) {