Browse Source

Hashed string for maps

Kajetan Johannes Hammerle 1 week ago
parent
commit
e18779e368

+ 1 - 0
CMakeLists.txt

@@ -61,6 +61,7 @@ set(SRC_TESTS
     "test/modules/FileReaderTests.cpp"
     "test/modules/ErrorTests.cpp"
     "test/modules/NewTests.cpp"
+    "test/modules/HashedStringTests.cpp"
 )
 
 set(SRC_PERFORMANCE

+ 65 - 0
include/core/utils/HashedString.hpp

@@ -0,0 +1,65 @@
+#ifndef CORE_HASHED_STRING_HPP
+#define CORE_HASHED_STRING_HPP
+
+#include <string.h>
+
+#include "core/utils/Types.hpp"
+
+namespace Core {
+    struct StringHash {
+        i32 length = 0;
+        u32 hash = 0;
+    };
+
+    constexpr StringHash hashString(const char* s) {
+        StringHash h;
+        while(*s != '\0') {
+            h.length++;
+            h.hash = 2120251889u * h.hash + static_cast<u32>(*(s++));
+        }
+        return h;
+    }
+
+    template<i32 N>
+    class HashedString {
+        static_assert(N > 0, "length of hashed string must be positive");
+        StringHash hash;
+        char data[N];
+
+    public:
+        HashedString() : hash() {
+        }
+
+        HashedString(const char* s) : hash(hashString(s)) {
+            strncpy(data, s, N);
+        }
+
+        bool operator==(const HashedString& other) const {
+            return hash.length == other.hash.length &&
+                   hash.hash == other.hash.hash &&
+                   strcmp(data, other.data) == 0;
+        }
+
+        bool operator!=(const HashedString& other) const {
+            return !(*this == other);
+        }
+
+        i32 getLength() const {
+            return hash.length;
+        }
+
+        constexpr i32 getCapacity() const {
+            return N - 1;
+        }
+
+        u32 hashCode() const {
+            return hash.hash;
+        }
+
+        operator const char*() const {
+            return data;
+        }
+    };
+}
+
+#endif

+ 1 - 2
include/core/utils/Types.hpp

@@ -1,7 +1,6 @@
 #ifndef CORE_TYPES_HPP
 #define CORE_TYPES_HPP
 
-#include <limits.h>
 #include <stdint.h>
 
 using i64 = int64_t;
@@ -14,4 +13,4 @@ using u16 = uint16_t;
 using u8 = uint8_t;
 using c32 = char32_t;
 
-#endif
+#endif

+ 1 - 0
test/Main.cpp

@@ -38,6 +38,7 @@ int main(int argAmount, const char** args) {
     Core::testError();
     Core::testFileReader();
     Core::testFrustum();
+    Core::testHashedString();
     Core::testHashMap(light, outOfMemoryTest);
     Core::testLinkedList(light, outOfMemoryTest);
     Core::testList(light);

+ 2 - 1
test/Tests.hpp

@@ -17,6 +17,7 @@ namespace Core {
     void testError();
     void testFileReader();
     void testFrustum();
+    void testHashedString();
     void testHashMap(bool light, bool outOfMemoryTest);
     void testLinkedList(bool light, bool outOfMemoryTest);
     void testList(bool light);
@@ -37,4 +38,4 @@ namespace Core {
     void testView();
 }
 
-#endif
+#endif

+ 73 - 0
test/modules/HashedStringTests.cpp

@@ -0,0 +1,73 @@
+#include "../Tests.hpp"
+#include "core/data/HashMap.hpp"
+#include "core/utils/HashedString.hpp"
+
+template class Core::HashedString<32>;
+
+using HString = Core::HashedString<32>;
+
+static void testComparison() {
+    HString a("test");
+    HString b("testA");
+    HString c("");
+    HString d("Btest");
+
+    CORE_TEST_TRUE(a == a);
+    CORE_TEST_TRUE(b == b);
+    CORE_TEST_TRUE(c == c);
+    CORE_TEST_TRUE(d == d);
+    CORE_TEST_TRUE(a != b);
+    CORE_TEST_TRUE(a != c);
+    CORE_TEST_TRUE(a != d);
+    CORE_TEST_TRUE(b != a);
+    CORE_TEST_TRUE(b != c);
+    CORE_TEST_TRUE(b != d);
+    CORE_TEST_TRUE(c != a);
+    CORE_TEST_TRUE(c != b);
+    CORE_TEST_TRUE(c != d);
+    CORE_TEST_TRUE(d != a);
+    CORE_TEST_TRUE(d != b);
+    CORE_TEST_TRUE(d != c);
+}
+
+static void testLength() {
+    HString s("test");
+    CORE_TEST_EQUAL(4, s.getLength());
+}
+
+static void testHashCode() {
+    HString a;
+    HString b("wusi");
+    CORE_TEST_EQUAL(a.hashCode(), 0u);
+    CORE_TEST_TRUE(b.hashCode() != 0u);
+}
+
+static void testAsHashMapKey() {
+    Core::HashMap<HString, int> map;
+    CORE_TEST_ERROR(map.add("wusi", 3));
+    CORE_TEST_ERROR(map.add("hiThere", 7));
+    CORE_TEST_ERROR(map.add("baum123", 5));
+
+    int* a = map.search("wusi");
+    int* b = map.search("hiThere");
+    int* c = map.search("baum123");
+    int* d = map.search("423hifd");
+
+    CORE_TEST_NOT_NULL(a);
+    CORE_TEST_NOT_NULL(b);
+    CORE_TEST_NOT_NULL(c);
+    CORE_TEST_NULL(d);
+
+    if(a != nullptr && b != nullptr && c != nullptr) {
+        CORE_TEST_EQUAL(3, *a);
+        CORE_TEST_EQUAL(7, *b);
+        CORE_TEST_EQUAL(5, *c);
+    }
+}
+
+void Core::testHashedString() {
+    testComparison();
+    testLength();
+    testHashCode();
+    testAsHashMapKey();
+}