Parcourir la source

Search pointer to optimize hashmap search

Kajetan Johannes Hammerle il y a 11 mois
Parent
commit
32ddc680de
3 fichiers modifiés avec 52 ajouts et 6 suppressions
  1. 10 3
      include/core/HashMap.h
  2. 5 0
      performance/Main.c
  3. 37 3
      src/HashMap.c

+ 10 - 3
include/core/HashMap.h

@@ -3,10 +3,14 @@
 
 #include "core/Types.h"
 
+struct CoreHashMap;
+typedef struct CoreHashMap 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);
 
-typedef struct {
+struct CoreHashMap {
     void* keys;
     void* values;
     size_t keySize;
@@ -15,10 +19,13 @@ typedef struct {
     size_t entries;
     CoreHasher hasher;
     CoreEqual equal;
-} CoreHashMap;
+    CoreSearchValue search;
+};
 
+CoreHashMap coreInitHashMap(size_t keySize, size_t valueSize, CoreHasher hasher,
+                            CoreEqual equal);
 #define CORE_HASH_MAP(keySize, valueSize, hasher, equal)                       \
-    ((CoreHashMap){nullptr, nullptr, keySize, valueSize, 0, 0, hasher, equal})
+    coreInitHashMap(keySize, valueSize, hasher, equal)
 void coreDestroyHashMap(CoreHashMap* m);
 void coreRehashHashMap(CoreHashMap* m, size_t minCapacity);
 void* coreHashMapPutPointer(CoreHashMap* m, const void* key, const void* value);

+ 5 - 0
performance/Main.c

@@ -31,18 +31,22 @@ static i64 testEmptySearch(const CoreHashMap* m) {
 }
 
 static void fillOrder(CoreHashMap* m) {
+    i64 nanos = coreNanos();
     for(int i = 0; i < 10000; i++) {
         coreHashMapPut(m, int, i, int, i* i);
     }
+    printf("Fill Order: %ldns\n", coreNanos() - nanos);
 }
 
 static void fillChaos(CoreHashMap* m) {
+    i64 nanos = coreNanos();
     CoreRandom random;
     coreInitRandom(&random, 0);
     for(int i = 0; i < 10000; i++) {
         int r = coreRandomI32(&random, 0, 10000);
         coreHashMapPut(m, int, r, int, r* r);
     }
+    printf("Fill Chaos: %ldns\n", coreNanos() - nanos);
 }
 
 static i64 average(CoreHashMap* m, i64 (*f)(const CoreHashMap* m), int n) {
@@ -57,6 +61,7 @@ static void order(int n) {
     CoreHashMap m =
         CORE_HASH_MAP(sizeof(int), sizeof(int), coreHash, coreEqual);
     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));

+ 37 - 3
src/HashMap.c

@@ -45,6 +45,28 @@ static size_t searchSlot(CoreHashMap* m, const void* key) {
     }
 }
 
+static void* searchValueU32(const CoreHashMap* m, const void* rawKey) {
+    u32 key = *(const u32*)rawKey;
+    if(m->capacity != 0) {
+        if(key == 0) {
+            size_t i = m->capacity - 1;
+            return ((u32*)m->keys)[i] == 0 ? getValue(m, i) : nullptr;
+        }
+        size_t baseHash = ((size_t)key) * 514685581u;
+        size_t end = m->capacity - 2;
+        for(size_t i = 0; i <= end; i++) {
+            size_t hash = (baseHash + i) & end;
+            u32 keyEntry = *(u32*)getKey(m, hash);
+            if(keyEntry == key) {
+                return getValue(m, hash);
+            } else if(keyEntry == 0) {
+                return nullptr;
+            }
+        }
+    }
+    return nullptr;
+}
+
 static void* searchValue(const CoreHashMap* m, const void* key) {
     if(m->capacity != 0) {
         if(isInvalidKey(m, key)) {
@@ -74,6 +96,18 @@ static size_t roundUp2(size_t n) {
     return w;
 }
 
+CoreHashMap coreInitHashMap(size_t keySize, size_t valueSize, CoreHasher hasher,
+                            CoreEqual equal) {
+    CoreSearchValue search = searchValue;
+    if(hasher == coreHash && equal == coreEqual) {
+        switch(keySize) {
+            case sizeof(u32): search = searchValueU32; break;
+        }
+    }
+    return (CoreHashMap){nullptr, nullptr, keySize, valueSize, 0,
+                         0,       hasher,  equal,   search};
+}
+
 void coreDestroyHashMap(CoreHashMap* m) {
     coreFree(m->keys);
     coreFree(m->values);
@@ -88,7 +122,7 @@ void coreRehashHashMap(CoreHashMap* m, size_t minCapacity) {
     CoreHashMap map =
         CORE_HASH_MAP(m->keySize, m->valueSize, m->hasher, m->equal);
     size_t keyBytes = l * m->keySize;
-    map.keys = coreAllocate(l * m->keySize);
+    map.keys = coreAllocate(keyBytes);
     memset(map.keys, 0, keyBytes);
     memset(getKey(&map, l - 1), 1, m->keySize);
     map.values = coreAllocate(l * m->valueSize);
@@ -129,11 +163,11 @@ void* coreHashMapPutPointer(CoreHashMap* m, const void* key,
 }
 
 void* coreHashMapSearchPointer(CoreHashMap* m, const void* key) {
-    return searchValue(m, key);
+    return m->search(m, key);
 }
 
 const void* coreHashMapSearchPointerC(const CoreHashMap* m, const void* key) {
-    return searchValue(m, key);
+    return m->search(m, key);
 }
 
 bool coreHashMapContainsPointer(const CoreHashMap* m, const void* key) {