Browse Source

Gotta hash them all

Kajetan Johannes Hammerle 1 year ago
parent
commit
5898048f6f
10 changed files with 146 additions and 29 deletions
  1. 1 1
      data/BitArray.cpp
  2. 2 18
      data/HashMap.h
  3. 2 2
      data/Stack.h
  4. 1 0
      meson.build
  5. 21 0
      tests/HashMapTests.cpp
  6. 4 4
      utils/ArrayString.h
  7. 60 0
      utils/HashCode.cpp
  8. 37 0
      utils/HashCode.h
  9. 0 2
      utils/Types.h
  10. 18 2
      utils/Utility.h

+ 1 - 1
data/BitArray.cpp

@@ -101,7 +101,7 @@ int Core::BitArray::getInternalByteSize() const {
     if(bits <= 0 || length <= 0) {
         return 0;
     }
-    return getArrayLength(length, bits) * static_cast<int>(sizeof(int));
+    return getArrayLength(length, bits) * CoreSize(int);
 }
 
 int Core::BitArray::select(int index) const {

+ 2 - 18
data/HashMap.h

@@ -4,6 +4,7 @@
 #include "data/LinkedList.h"
 #include "data/List.h"
 #include "utils/ArrayString.h"
+#include "utils/HashCode.h"
 
 namespace Core {
     template<typename K, typename V>
@@ -284,27 +285,10 @@ namespace Core {
     private:
         template<typename H>
         int hashIndex(const H& key) const {
-            return static_cast<int>(fullHash(key)) &
+            return static_cast<int>(hashCode(key)) &
                    (nodePointers.getLength() - 1);
         }
 
-        template<typename H>
-        Hash fullHash(const H& key) const {
-            return key.hashCode();
-        }
-
-        Hash fullHash(int key) const {
-            static_assert(sizeof(key) == sizeof(Hash),
-                          "unwanted loose of precision in hash");
-            return static_cast<Hash>(key);
-        }
-
-        Hash fullHash(unsigned int key) const {
-            static_assert(sizeof(key) == sizeof(Hash),
-                          "unwanted loose of precision in hash");
-            return key;
-        }
-
         const V* searchList(const K& key, int h) const {
             if(nodePointers.getLength() == 0) {
                 return nullptr;

+ 2 - 2
data/Stack.h

@@ -1,5 +1,5 @@
-#ifndef STACK_H
-#define STACK_H
+#ifndef CORE_STACK_H
+#define CORE_STACK_H
 
 #include "data/ArrayList.h"
 #include "data/List.h"

+ 1 - 0
meson.build

@@ -3,6 +3,7 @@ project('core', 'cpp', default_options : ['cpp_std=c++2a'])
 src = [
     'utils/Logger.cpp',
     'utils/Utility.cpp',
+    'utils/HashCode.cpp',
     'data/BitArray.cpp',
 ]
 

+ 21 - 0
tests/HashMapTests.cpp

@@ -309,6 +309,26 @@ static void testValueForEach(Core::Test& test) {
     test.checkEqual(9, counter, "const value iterator");
 }
 
+template<typename T>
+static void testType(Core::Test& test) {
+    Core::HashMap<T, int> m;
+    test.checkFalse(m.add(T(), 3), "test type");
+}
+
+static void testTypes(Core::Test& test) {
+    testType<char>(test);
+    testType<signed char>(test);
+    testType<signed short>(test);
+    testType<signed int>(test);
+    testType<signed long>(test);
+    testType<signed long long>(test);
+    testType<unsigned char>(test);
+    testType<unsigned short>(test);
+    testType<unsigned int>(test);
+    testType<unsigned long>(test);
+    testType<unsigned long long>(test);
+}
+
 void Core::HashMapTests::test() {
     Core::Test test("HashMap");
     testAdd(test);
@@ -328,5 +348,6 @@ void Core::HashMapTests::test() {
     testEntryForEach(test);
     testKeyForEach(test);
     testValueForEach(test);
+    testTypes(test);
     test.finalize();
 }

+ 4 - 4
utils/ArrayString.h

@@ -14,9 +14,9 @@ namespace Core {
     class ArrayString final {
     public:
         int length;
-        Hash hash;
+        u32 hash;
         static constexpr int DATA_LENGTH =
-            (N - Math::max(IntSize(length), IntSize(hash))) / IntSize(u32);
+            (N - Math::max(CoreSize(length), CoreSize(hash))) / CoreSize(u32);
         static_assert(DATA_LENGTH > 0, "Size of array string too small");
         u32 data[static_cast<unsigned int>(DATA_LENGTH)];
 
@@ -209,7 +209,7 @@ namespace Core {
             data[0] = '\0';
         }
 
-        Hash hashCode() const {
+        u32 hashCode() const {
             return hash;
         }
 
@@ -307,7 +307,7 @@ namespace Core {
         }
 
         void addToHash(u32 u) {
-            hash = static_cast<Hash>(2120251889) * hash + static_cast<Hash>(u);
+            hash = static_cast<u32>(2120251889) * hash + static_cast<u32>(u);
         }
 
         // returns true on error

+ 60 - 0
utils/HashCode.cpp

@@ -0,0 +1,60 @@
+#include "utils/HashCode.h"
+
+#include <string.h>
+
+template<typename T>
+u32 hashNumber(T t) {
+    constexpr u32 L = sizeof(T) / 4 + (sizeof(T) % 4 != 0);
+    u32 parts[L];
+    memset(parts, 0, sizeof(parts));
+    memcpy(parts, &t, sizeof(T));
+    u32 hash = 0;
+    for(u32 i = 0; i < L; i++) {
+        hash ^= parts[i];
+    }
+    return hash;
+}
+
+u32 Core::hashCode(char key) {
+    return hashNumber(key);
+}
+
+u32 Core::hashCode(signed char key) {
+    return hashNumber(key);
+}
+
+u32 Core::hashCode(signed short key) {
+    return hashNumber(key);
+}
+
+u32 Core::hashCode(signed int key) {
+    return hashNumber(key);
+}
+
+u32 Core::hashCode(signed long key) {
+    return hashNumber(key);
+}
+
+u32 Core::hashCode(signed long long key) {
+    return hashNumber(key);
+}
+
+u32 Core::hashCode(unsigned char key) {
+    return hashNumber(key);
+}
+
+u32 Core::hashCode(unsigned short key) {
+    return hashNumber(key);
+}
+
+u32 Core::hashCode(unsigned int key) {
+    return hashNumber(key);
+}
+
+u32 Core::hashCode(unsigned long key) {
+    return hashNumber(key);
+}
+
+u32 Core::hashCode(unsigned long long key) {
+    return hashNumber(key);
+}

+ 37 - 0
utils/HashCode.h

@@ -0,0 +1,37 @@
+#ifndef CORE_HASH_CODE_H
+#define CORE_HASH_CODE_H
+
+#include "utils/Types.h"
+
+namespace Core {
+    template<typename H>
+    u32 hashCode(const H& key) {
+        return key.hashCode();
+    }
+
+    /*inline u32 hashCode(int key) {
+        static_assert(sizeof(key) == sizeof(u32),
+                      "unwanted loose of precision in hash");
+        return static_cast<u32>(key);
+    }
+
+    inline u32 hashCode(unsigned int key) {
+        static_assert(sizeof(key) == sizeof(u32),
+                      "unwanted loose of precision in hash");
+        return key;
+    }*/
+
+    u32 hashCode(char key);
+    u32 hashCode(signed char key);
+    u32 hashCode(signed short key);
+    u32 hashCode(signed int key);
+    u32 hashCode(signed long key);
+    u32 hashCode(signed long long key);
+    u32 hashCode(unsigned char key);
+    u32 hashCode(unsigned short key);
+    u32 hashCode(unsigned int key);
+    u32 hashCode(unsigned long key);
+    u32 hashCode(unsigned long long key);
+}
+
+#endif

+ 0 - 2
utils/Types.h

@@ -12,6 +12,4 @@ typedef uint32_t u32;
 typedef uint16_t u16;
 typedef uint8_t u8;
 
-typedef u32 Hash;
-
 #endif

+ 18 - 2
utils/Utility.h

@@ -3,7 +3,7 @@
 
 #include <stdlib.h>
 
-#define IntSize(t) static_cast<int>(sizeof(t))
+#define CoreSize(t) static_cast<int>(sizeof(t))
 
 namespace Core {
     namespace Internal {
@@ -66,7 +66,7 @@ namespace Core {
         static constexpr int map[16] = {0, 1, 1, 2, 1, 2, 2, 3,
                                         1, 2, 2, 3, 2, 3, 3, 4};
         int sum = 0;
-        for(int i = 0; i < static_cast<int>(sizeof(T) * 8); i += 4) {
+        for(int i = 0; i < CoreSize(T) * 8; i += 4) {
             sum += map[(t >> i) & 0xF];
         }
         return sum;
@@ -76,6 +76,22 @@ namespace Core {
 
     void exitWithHandler(int value);
     void setExitHandler(ExitHandler eh, void*);
+
+    template<typename T, typename W>
+    struct HasToString {
+        typedef char one;
+        struct two {
+            char x[2];
+        };
+
+        template<typename C>
+        static one test(decltype(&C::toString));
+        template<typename C>
+        static two test(...);
+
+    public:
+        enum { value = sizeof(test<T>(0)) == sizeof(char) };
+    };
 }
 
 void* operator new(size_t bytes) noexcept;