Преглед на файлове

Fix rule of five for hash map, merge hashmap tests

Kajetan Johannes Hammerle преди 3 седмици
родител
ревизия
1a45f42a80

+ 0 - 1
CMakeLists.txt

@@ -40,7 +40,6 @@ set(SRC_TESTS
     "test/modules/LinkedListTests.cpp"
     "test/modules/UniquePointerTests.cpp"
     "test/modules/HashMapTests.cpp"
-    "test/modules/ProbingHashMapTests.cpp"
     "test/modules/StackTests.cpp"
     "test/modules/RingBufferTests.cpp"
     "test/modules/ComponentsTests.cpp"

+ 6 - 4
include/core/data/Components.hpp

@@ -60,17 +60,19 @@ namespace Core {
         };
 
         template<typename... Args>
-        CError put(T*& t, Entity ent, Args&&... args) {
+        bool put(T*& t, Entity ent, Args&&... args) {
             size_t index = components.getLength();
             size_t* indexP = nullptr;
-            CORE_RETURN_ERROR(entityToIndex.tryEmplace(indexP, ent, index));
+            if(!entityToIndex.tryEmplace(indexP, ent, index)) {
+                return false;
+            }
             indexToEntity.add(ent);
             t = &components.put(Core::forward<Args>(args)...);
-            return ErrorCode::NONE;
+            return true;
         }
 
         template<typename... Args>
-        CError add(Entity e, Args&&... args) {
+        bool add(Entity e, Args&&... args) {
             T* t = nullptr;
             return put(t, e, Core::forward<Args>(args)...);
         }

+ 24 - 11
include/core/data/HashMap.hpp

@@ -1,9 +1,10 @@
-#ifndef CORE_HPPASHMAP_HPP
-#define CORE_HPPASHMAP_HPP
+#ifndef CORE_HASHMAP_HPP
+#define CORE_HASHMAP_HPP
 
 #include "core/data/LinkedList.hpp"
 #include "core/data/List.hpp"
 #include "core/utils/HashCode.hpp"
+#include "core/utils/Meta.hpp"
 
 namespace Core {
     template<typename K, typename V>
@@ -117,14 +118,21 @@ namespace Core {
         List<NodePointerList> nodePointers{};
 
     public:
-        CError copyFrom(const HashMap& other) {
-            HashMap copy;
+        HashMap() = default;
+
+        HashMap(const HashMap& other) {
             for(const auto& en : other) {
-                copy.add(en.getKey(), en.value);
+                add(en.getKey(), en.value);
             }
-            swap(copy.nodes, nodes);
-            swap(copy.nodePointers, nodePointers);
-            return ErrorCode::NONE;
+        }
+
+        HashMap(HashMap&& other) {
+            swap(other);
+        }
+
+        HashMap& operator=(HashMap other) {
+            swap(other);
+            return *this;
         }
 
         void rehash(size_t minCapacity) {
@@ -145,17 +153,17 @@ namespace Core {
         }
 
         template<typename... Args>
-        CError tryEmplace(V*& v, const K& key, Args&&... args) {
+        bool tryEmplace(V*& v, const K& key, Args&&... args) {
             rehash(nodes.getLength() + 1);
             size_t h = hashIndex(key);
             v = searchList(key, h);
             if(v != nullptr) {
-                return ErrorCode::EXISTING_KEY;
+                return false;
             }
             NodePointer np = nodes.put(key, Core::forward<Args>(args)...);
             nodePointers[h].add(np);
             v = &(np->data.value);
-            return ErrorCode::NONE;
+            return true;
         }
 
         template<typename VA>
@@ -238,6 +246,11 @@ namespace Core {
             return ConstEntryIterator(nodes.end());
         }
 
+        void swap(HashMap& other) {
+            Core::swap(nodes, other.nodes);
+            Core::swap(nodePointers, other.nodePointers);
+        }
+
         template<typename String>
         CError toString(String& s) const {
             return Core::toString(s, *this);

+ 2 - 7
include/core/data/ProbingHashMap.hpp

@@ -1,15 +1,10 @@
-#ifndef CORE_PROBING_HPPASHMAP_HPP
-#define CORE_PROBING_HPPASHMAP_HPP
-
-#include <stdio.h>
+#ifndef CORE_PROBING_HASHMAP_HPP
+#define CORE_PROBING_HASHMAP_HPP
 
 #include "core/data/List.hpp"
-#include "core/utils/AlignedData.hpp"
 #include "core/utils/ArrayString.hpp"
 #include "core/utils/Error.hpp"
 #include "core/utils/HashCode.hpp"
-#include "core/utils/Logger.hpp"
-#include "core/utils/Meta.hpp"
 #include "core/utils/New.hpp"
 #include "core/utils/Types.hpp"
 

+ 5 - 0
src/Utility.cpp

@@ -72,6 +72,11 @@ void Core::setOutOfMemoryHandler(OutOfMemoryHandler h, void* data) {
 }
 
 void* Core::allocate(size_t n) {
+    // deny too large allocations instantly
+    // this makes LTO happy
+    if(n >= 1024lu * 1024lu * 1024lu * 64lu) {
+        CORE_EXIT(ErrorCode::OUT_OF_MEMORY.code); // CoverageIgnore
+    }
     void* p = malloc(n);
 #ifdef ERROR_SIMULATOR
     if(CORE_ALLOC_FAIL && p != nullptr) {

+ 0 - 1
test/Main.cpp

@@ -48,7 +48,6 @@ int main(int argAmount, const char** args) {
     Core::testMatrix();
     Core::testNew();
     Core::testPlane();
-    Core::testProbingHashMap(light);
     Core::testQuaternion();
     Core::testRandom(light);
     Core::testRingBuffer();

+ 1 - 2
test/Test.hpp

@@ -24,8 +24,7 @@ namespace Core::Test {
             Error e = ErrorCode::NONE;
             FileName fileName(file);
             Result* result = results.search(fileName);
-            if(result == nullptr &&
-               checkError(e, results.tryEmplace(result, fileName))) {
+            if(result == nullptr && !results.tryEmplace(result, fileName)) {
                 warn(file, line, e);
                 return false;
             }

+ 0 - 1
test/Tests.hpp

@@ -26,7 +26,6 @@ namespace Core {
     void testMatrix();
     void testNew();
     void testPlane();
-    void testProbingHashMap(bool light);
     void testQuaternion();
     void testRandom(bool light);
     void testRingBuffer();

+ 15 - 14
test/modules/ComponentsTests.cpp

@@ -11,9 +11,10 @@ static void testAddForEach() {
     int* i1 = nullptr;
     int* i2 = nullptr;
     int* i3 = nullptr;
-    CORE_TEST_ERROR(c.put(i1, 1, 10));
-    CORE_TEST_ERROR(c.put(i2, 5, 20));
-    CORE_TEST_ERROR(c.put(i3, 10, 30));
+    CORE_TEST_TRUE(c.put(i1, 1, 10));
+    CORE_TEST_FALSE(c.put(i1, 1, 20));
+    CORE_TEST_TRUE(c.put(i2, 5, 20));
+    CORE_TEST_TRUE(c.put(i3, 10, 30));
 
     CORE_TEST_NOT_NULL(i1);
     CORE_TEST_NOT_NULL(i2);
@@ -54,9 +55,9 @@ static void testAddConstForEach() {
     int* i1 = nullptr;
     int* i2 = nullptr;
     int* i3 = nullptr;
-    CORE_TEST_ERROR(c.put(i1, 1, 10));
-    CORE_TEST_ERROR(c.put(i2, 5, 20));
-    CORE_TEST_ERROR(c.put(i3, 10, 30));
+    CORE_TEST_TRUE(c.put(i1, 1, 10));
+    CORE_TEST_TRUE(c.put(i2, 5, 20));
+    CORE_TEST_TRUE(c.put(i3, 10, 30));
 
     auto iter = static_cast<const IntComponent&>(c).entities();
     auto pos = iter.begin();
@@ -88,9 +89,9 @@ static void testAddComponentForEach() {
     int* i1 = nullptr;
     int* i2 = nullptr;
     int* i3 = nullptr;
-    CORE_TEST_ERROR(c.put(i1, 1, 10));
-    CORE_TEST_ERROR(c.put(i2, 5, 20));
-    CORE_TEST_ERROR(c.put(i3, 10, 30));
+    CORE_TEST_TRUE(c.put(i1, 1, 10));
+    CORE_TEST_TRUE(c.put(i2, 5, 20));
+    CORE_TEST_TRUE(c.put(i3, 10, 30));
 
     CORE_TEST_NOT_NULL(i1);
     CORE_TEST_NOT_NULL(i2);
@@ -141,15 +142,15 @@ static void testAddComponentForEach() {
 
 static void testRemove() {
     IntComponent c;
-    CORE_TEST_ERROR(c.add(1, 10));
-    CORE_TEST_ERROR(c.add(5, 20));
-    CORE_TEST_ERROR(c.add(10, 30));
+    CORE_TEST_TRUE(c.add(1, 10));
+    CORE_TEST_TRUE(c.add(5, 20));
+    CORE_TEST_TRUE(c.add(10, 30));
 
     CORE_TEST_FALSE(c.remove(20));
     CORE_TEST_TRUE(c.remove(5));
     CORE_TEST_FALSE(c.remove(30));
 
-    CORE_TEST_ERROR(c.add(20, 40));
+    CORE_TEST_TRUE(c.add(20, 40));
     CORE_TEST_TRUE(c.remove(20));
 
     int* i1 = c.search(1);
@@ -189,7 +190,7 @@ static void testRemove() {
 static void testConstSearch() {
     IntComponent c;
     int* i = nullptr;
-    CORE_TEST_ERROR(c.put(i, 1, 10));
+    CORE_TEST_TRUE(c.put(i, 1, 10));
     const IntComponent& cc = c;
     const int* component = cc.search(1);
     if(CORE_TEST_TRUE(component != nullptr)) {

+ 249 - 161
test/modules/HashMapTests.cpp

@@ -1,45 +1,67 @@
-#include "../../src/ErrorSimulator.hpp"
 #include "../Tests.hpp"
 #include "core/data/HashMap.hpp"
+#include "core/data/ProbingHashMap.hpp"
 
+template struct Core::ProbingHashMap<int, int>;
+using ProbingIntMap = Core::ProbingHashMap<int, int>;
 template struct Core::HashMap<int, int>;
 using IntMap = Core::HashMap<int, int>;
 
+constexpr int INVALID = Core::emptyValue<int>();
+
+template<typename T>
+static T getTestIntMap() {
+    T map;
+    map.add(1, 3).add(2, 4).add(3, 5).add(INVALID, 20);
+    return map;
+}
+
+template<typename T>
+static void checkIntMap(T& map) {
+    int* a = map.search(1);
+    int* b = map.search(2);
+    int* c = map.search(3);
+    int* d = map.search(INVALID);
+    if(CORE_TEST_NOT_NULL(a) && CORE_TEST_NOT_NULL(b) &&
+       CORE_TEST_NOT_NULL(c) && CORE_TEST_NOT_NULL(d)) {
+        CORE_TEST_EQUAL(3, *a);
+        CORE_TEST_EQUAL(4, *b);
+        CORE_TEST_EQUAL(5, *c);
+        CORE_TEST_EQUAL(20, *d);
+    }
+}
+
+template<typename T>
 static void testAdd() {
-    IntMap map;
+    T map;
     map.add(5, 4);
     int* value = map.search(5);
-    if(CORE_TEST_NOT_NULL(value)) {
+    CORE_TEST_NOT_NULL(value);
+    if(value != nullptr) {
         CORE_TEST_EQUAL(4, *value);
     }
 }
 
+template<typename T>
 static void testMultipleAdd() {
-    IntMap map;
-    map.add(5, 4).add(10, 3).add(15, 2);
-    CORE_TEST_TRUE(map.contains(5));
-    CORE_TEST_TRUE(map.contains(10));
-    CORE_TEST_TRUE(map.contains(15));
-    int* a = map.search(5);
-    int* b = map.search(10);
-    int* c = map.search(15);
-    CORE_TEST_NOT_NULL(a);
-    CORE_TEST_NOT_NULL(b);
-    CORE_TEST_NOT_NULL(c);
-    if(a != nullptr && b != nullptr && c != nullptr) {
-        CORE_TEST_EQUAL(4, *a);
-        CORE_TEST_EQUAL(3, *b);
-        CORE_TEST_EQUAL(2, *c);
-    }
+    T map = getTestIntMap<T>();
+    CORE_TEST_TRUE(map.contains(1));
+    CORE_TEST_TRUE(map.contains(2));
+    CORE_TEST_TRUE(map.contains(3));
+    checkIntMap(map);
 }
 
+template<typename T>
 static void testSearch() {
-    IntMap map;
+    T map;
+    CORE_TEST_NULL(map.search(6));
+    map.add(5, 4).add(10, 3).add(15, 2);
     CORE_TEST_NULL(map.search(6));
 }
 
+template<typename T>
 static void testAddReplace() {
-    IntMap map;
+    T map;
     map.add(5, 4).add(5, 10);
     CORE_TEST_TRUE(map.contains(5));
     int* a = map.search(5);
@@ -48,39 +70,45 @@ static void testAddReplace() {
     }
 }
 
+template<typename T>
 static void testClear() {
-    IntMap map;
+    T map;
     map.add(5, 4).add(4, 10);
     map.clear();
     CORE_TEST_FALSE(map.contains(5));
     CORE_TEST_FALSE(map.contains(4));
 }
 
+template<typename T>
 static void testOverflow(bool light) {
-    IntMap map;
     int limit = light ? 10000 : 100000;
+    T map;
+    map.add(INVALID, 42);
     for(int i = 0; i < limit; i++) {
         map.add(i, i);
     }
     for(int i = 0; i < limit; i++) {
         CORE_TEST_TRUE(map.contains(i));
     }
+    CORE_TEST_TRUE(map.contains(INVALID));
 }
 
-struct HashMapTestStruct final {
+static int aInstances = 0;
+
+struct HashMapTest {
     int a;
     int b;
 
-    HashMapTestStruct(int a_, int b_) : a(a_), b(b_) {
+    HashMapTest(int a_, int b_) : a(a_), b(b_) {
     }
 
     // none of these should be needed for the hashmap
-    HashMapTestStruct(const HashMapTestStruct&) = delete;
-    HashMapTestStruct(HashMapTestStruct&&) = delete;
-    HashMapTestStruct& operator=(const HashMapTestStruct&) = delete;
-    HashMapTestStruct& operator=(HashMapTestStruct&&) = delete;
+    HashMapTest(const HashMapTest&) = delete;
+    HashMapTest(HashMapTest&&) = delete;
+    HashMapTest& operator=(const HashMapTest&) = delete;
+    HashMapTest& operator=(HashMapTest&&) = delete;
 
-    bool operator==(const HashMapTestStruct& other) const {
+    bool operator==(const HashMapTest& other) const {
         return a == other.a && b == other.b;
     }
 
@@ -95,149 +123,120 @@ struct HashMapTestStruct final {
     }
 };
 
-static void testEmplace() {
-    Core::HashMap<int, HashMapTestStruct> map;
-
-    HashMapTestStruct* ar = nullptr;
-    CORE_TEST_ERROR(map.tryEmplace(ar, 0, 3, 4));
-    CORE_TEST_ERROR(map.tryEmplace(ar, 3, 4, 5));
-    CORE_TEST_ERROR(map.tryEmplace(ar, 20, 5, 6));
-    CORE_TEST_EQUAL(Core::ErrorCode::EXISTING_KEY, map.tryEmplace(ar, 3, 6, 7));
-    CORE_TEST_EQUAL(Core::ErrorCode::EXISTING_KEY,
-                    map.tryEmplace(ar, 20, 7, 8));
-
-    HashMapTestStruct* a = map.search(0);
-    HashMapTestStruct* b = map.search(3);
-    HashMapTestStruct* c = map.search(20);
-
-    CORE_TEST_NOT_NULL(a);
-    CORE_TEST_NOT_NULL(b);
-    CORE_TEST_NOT_NULL(c);
-
-    if(a != nullptr && b != nullptr && c != nullptr) {
-        CORE_TEST_EQUAL(HashMapTestStruct(3, 4), *a);
-        CORE_TEST_EQUAL(HashMapTestStruct(4, 5), *b);
-        CORE_TEST_EQUAL(HashMapTestStruct(5, 6), *c);
+struct ProbingTest final : public HashMapTest {
+    ProbingTest(int a_, int b_) : HashMapTest(a_, b_) {
+        aInstances++;
     }
-}
-
-static void testToString1() {
-    IntMap map;
-    map.add(1, 3).add(2, 4).add(3, 5);
-    CORE_TEST_STRING("[1 = 3, 2 = 4, 3 = 5]", map);
-}
-
-static void testToString2() {
-    IntMap map;
-    map.add(1, 3);
-    CORE_TEST_STRING("[1 = 3]", map);
-}
-
-static void testToString3() {
-    IntMap map;
-    CORE_TEST_STRING("[]", map);
-}
 
-static void testCopy() {
-    IntMap map;
-    map.add(1, 3).add(2, 4).add(3, 5);
-    IntMap copy;
-    CORE_TEST_ERROR(copy.copyFrom(map));
-
-    int* a[6] = {map.search(1),  map.search(2),  map.search(3),
-                 copy.search(1), copy.search(2), copy.search(3)};
-    for(int i = 0; i < 3; i++) {
-        CORE_TEST_NOT_NULL(a[i]);
-        CORE_TEST_NOT_NULL(a[i + 3]);
-        if(a[i] != nullptr && a[i + 3] != nullptr) {
-            CORE_TEST_EQUAL(*(a[i]), *(a[i + 3]));
-        }
+    ProbingTest(const ProbingTest& o) : HashMapTest(o.a, o.b) {
+        aInstances++;
     }
-}
 
-static void testMove() {
-    IntMap map;
-    map.add(1, 3).add(2, 4).add(3, 5);
-    IntMap move(Core::move(map));
+    ProbingTest(ProbingTest&& o) : HashMapTest(o.a, o.b) {
+        aInstances++;
+    }
 
-    int* a = move.search(1);
-    int* b = move.search(2);
-    int* c = move.search(3);
+    ~ProbingTest() {
+        aInstances--;
+    }
 
-    CORE_TEST_NOT_NULL(a);
-    CORE_TEST_NOT_NULL(b);
-    CORE_TEST_NOT_NULL(c);
+    ProbingTest& operator=(ProbingTest o) {
+        a = o.a;
+        b = o.b;
+        return *this;
+    }
+};
 
-    if(a != nullptr && b != nullptr && c != nullptr) {
-        CORE_TEST_EQUAL(3, *a);
-        CORE_TEST_EQUAL(4, *b);
-        CORE_TEST_EQUAL(5, *c);
+template<typename T>
+static void testEmplace() {
+    {
+        Core::ProbingHashMap<int, ProbingTest> map;
+
+        ProbingTest* ar = nullptr;
+        CORE_TEST_TRUE(map.tryEmplace(ar, 0, 3, 4));
+        CORE_TEST_TRUE(map.tryEmplace(ar, 3, 4, 5));
+        CORE_TEST_TRUE(map.tryEmplace(ar, 20, 5, 6));
+        CORE_TEST_FALSE(map.tryEmplace(ar, 3, 6, 7));
+        CORE_TEST_FALSE(map.tryEmplace(ar, 20, 7, 8));
+
+        ProbingTest* a = map.search(0);
+        ProbingTest* b = map.search(3);
+        ProbingTest* c = map.search(20);
+
+        if(CORE_TEST_NOT_NULL(a) && CORE_TEST_NOT_NULL(b) &&
+           CORE_TEST_NOT_NULL(c)) {
+            CORE_TEST_EQUAL(ProbingTest(3, 4), *a);
+            CORE_TEST_EQUAL(ProbingTest(4, 5), *b);
+            CORE_TEST_EQUAL(ProbingTest(5, 6), *c);
+        }
     }
+    CORE_TEST_EQUAL(0, aInstances);
 }
 
-static void testMoveAssignment() {
-    IntMap map;
-    map.add(1, 3).add(2, 4).add(3, 5);
-
-    IntMap move;
-    move = Core::move(map);
-
-    int* a = move.search(1);
-    int* b = move.search(2);
-    int* c = move.search(3);
-
-    CORE_TEST_NOT_NULL(a);
-    CORE_TEST_NOT_NULL(b);
-    CORE_TEST_NOT_NULL(c);
-
-    if(a != nullptr && b != nullptr && c != nullptr) {
-        CORE_TEST_EQUAL(3, *a);
-        CORE_TEST_EQUAL(4, *b);
-        CORE_TEST_EQUAL(5, *c);
+template<typename T>
+static void testToString() {
+    if constexpr(Core::IsSame<T, IntMap>) {
+        CORE_TEST_STRING("[1 = 3, 2 = 4, 3 = 5, 2147483647 = 20]",
+                         getTestIntMap<T>());
+    } else {
+        CORE_TEST_STRING("[2 = 4, 1 = 3, 3 = 5, 2147483647 = 20]",
+                         getTestIntMap<T>());
     }
+    CORE_TEST_STRING("[1 = 3]", T().add(1, 3));
+    CORE_TEST_STRING("[]", T());
 }
 
-static void testRemove() {
-    IntMap map;
-    map.add(1, 3).add(2, 4).add(3, 5);
-
-    CORE_TEST_TRUE(map.remove(2));
-    CORE_TEST_FALSE(map.remove(7));
-
-    int* a = map.search(1);
-    int* b = map.search(2);
-    int* c = map.search(3);
+template<typename T>
+static void testCopy() {
+    T map = getTestIntMap<T>();
+    T copy = map;
+    T copyA;
+    copyA = map;
+    checkIntMap(map);
+    checkIntMap(copy);
+    checkIntMap(copyA);
+    map.add(1, 20).add(2, 30).add(3, 40);
+    checkIntMap(copy);
+    checkIntMap(copyA);
+}
 
-    CORE_TEST_NOT_NULL(a);
-    CORE_TEST_NULL(b);
-    CORE_TEST_NOT_NULL(c);
+template<typename T>
+static void testMove() {
+    T map = getTestIntMap<T>();
+    T move(Core::move(map));
+    checkIntMap(move);
+}
 
-    if(a != nullptr && c != nullptr) {
-        CORE_TEST_EQUAL(3, *a);
-        CORE_TEST_EQUAL(5, *c);
-    }
+template<typename T>
+static void testMoveAssignment() {
+    T map = getTestIntMap<T>();
+    T move;
+    move = Core::move(map);
+    checkIntMap(move);
 }
 
+template<typename T>
 static void testEntryForEach() {
-    IntMap map;
+    T map;
     map.add(5, 4).add(10, 3).add(15, 2);
 
     int counter = 0;
-    for(auto& entry : map) {
+    for(auto entry : map) {
         counter += entry.getKey() + entry.value;
     }
     CORE_TEST_EQUAL(39, counter);
 
-    const IntMap& cmap = map;
+    const T& cmap = map;
     counter = 0;
-    for(const auto& entry : cmap) {
+    for(auto entry : cmap) {
         counter += entry.getKey() + entry.value;
     }
     CORE_TEST_EQUAL(39, counter);
 }
 
+template<typename T>
 static void testKeyForEach() {
-    IntMap map;
+    T map;
     map.add(5, 4).add(10, 3).add(15, 2);
 
     int counter = 0;
@@ -246,7 +245,7 @@ static void testKeyForEach() {
     }
     CORE_TEST_EQUAL(30, counter);
 
-    const IntMap& cmap = map;
+    const T& cmap = map;
     counter = 0;
     for(const int& key : cmap.getKeys()) {
         counter += key;
@@ -254,8 +253,9 @@ static void testKeyForEach() {
     CORE_TEST_EQUAL(30, counter);
 }
 
+template<typename T>
 static void testValueForEach() {
-    IntMap map;
+    T map;
     map.add(5, 4).add(10, 3).add(15, 2);
 
     int counter = 0;
@@ -264,7 +264,7 @@ static void testValueForEach() {
     }
     CORE_TEST_EQUAL(9, counter);
 
-    const IntMap& cmap = map;
+    const T& cmap = map;
     counter = 0;
     for(const int& value : cmap.getValues()) {
         counter += value;
@@ -274,10 +274,11 @@ static void testValueForEach() {
 
 template<typename T>
 static void testType() {
-    Core::HashMap<T, int> m;
+    Core::ProbingHashMap<T, int> m;
     m.add(T(), 3);
 }
 
+template<typename T>
 static void testTypes() {
     testType<char>();
     testType<signed char>();
@@ -292,23 +293,110 @@ static void testTypes() {
     testType<unsigned long long>();
 }
 
+template<typename T>
+static void testInvalid() {
+    T map;
+    int* v;
+    CORE_TEST_TRUE(map.tryEmplace(v, INVALID, 2));
+    if(CORE_TEST_NOT_NULL(v)) {
+        CORE_TEST_EQUAL(2, *v);
+    }
+    CORE_TEST_FALSE(map.tryEmplace(v, INVALID, 6));
+    if(CORE_TEST_NOT_NULL(v)) {
+        CORE_TEST_EQUAL(2, *v);
+    }
+    CORE_TEST_EQUAL(3, map.put(INVALID, 3));
+    v = map.search(INVALID);
+    if(CORE_TEST_NOT_NULL(v)) {
+        CORE_TEST_EQUAL(3, *v);
+    }
+    map.clear();
+    CORE_TEST_NULL(map.search(INVALID));
+}
+
+template<typename T>
+static void testInvalidPut() {
+    T map;
+    CORE_TEST_EQUAL(3, map.put(INVALID, 3));
+    int* v = map.search(INVALID);
+    if(CORE_TEST_NOT_NULL(v)) {
+        CORE_TEST_EQUAL(3, *v);
+    }
+}
+
+template<typename T>
+static void testAddCollisions() {
+    T map;
+    for(int i = 0; i < 8; i++) {
+        map.add(i * 16, i);
+    }
+}
+
+template<typename T>
+static void testMap(bool light) {
+    testAdd<T>();
+    testMultipleAdd<T>();
+    testSearch<T>();
+    testAddReplace<T>();
+    testClear<T>();
+    testOverflow<T>(light);
+    testEmplace<T>();
+    testToString<T>();
+    testCopy<T>();
+    testMove<T>();
+    testMoveAssignment<T>();
+    testEntryForEach<T>();
+    testKeyForEach<T>();
+    testValueForEach<T>();
+    testTypes<T>();
+    testInvalid<T>();
+    testInvalidPut<T>();
+    testAddCollisions<T>();
+}
+
+static void testEmplace() {
+    Core::HashMap<int, HashMapTest> map;
+
+    HashMapTest* ar = nullptr;
+    CORE_TEST_TRUE(map.tryEmplace(ar, 0, 3, 4));
+    CORE_TEST_TRUE(map.tryEmplace(ar, 3, 4, 5));
+    CORE_TEST_TRUE(map.tryEmplace(ar, 20, 5, 6));
+    CORE_TEST_FALSE(map.tryEmplace(ar, 3, 6, 7));
+    CORE_TEST_FALSE(map.tryEmplace(ar, 20, 7, 8));
+
+    HashMapTest* a = map.search(0);
+    HashMapTest* b = map.search(3);
+    HashMapTest* c = map.search(20);
+
+    if(CORE_TEST_NOT_NULL(a) && CORE_TEST_NOT_NULL(b) &&
+       CORE_TEST_NOT_NULL(c)) {
+        CORE_TEST_EQUAL(HashMapTest(3, 4), *a);
+        CORE_TEST_EQUAL(HashMapTest(4, 5), *b);
+        CORE_TEST_EQUAL(HashMapTest(5, 6), *c);
+    }
+}
+
+static void testRemove() {
+    IntMap map;
+    map.add(1, 3).add(2, 4).add(3, 5);
+
+    CORE_TEST_TRUE(map.remove(2));
+    CORE_TEST_FALSE(map.remove(7));
+
+    int* a = map.search(1);
+    int* b = map.search(2);
+    int* c = map.search(3);
+
+    CORE_TEST_NULL(b);
+    if(CORE_TEST_NOT_NULL(a) && CORE_TEST_NOT_NULL(c)) {
+        CORE_TEST_EQUAL(3, *a);
+        CORE_TEST_EQUAL(5, *c);
+    }
+}
+
 void Core::testHashMap(bool light) {
-    testAdd();
-    testMultipleAdd();
-    testSearch();
-    testAddReplace();
-    testClear();
-    testOverflow(light);
+    testMap<ProbingIntMap>(light);
+    testMap<IntMap>(light);
     testEmplace();
-    testToString1();
-    testToString2();
-    testToString3();
-    testCopy();
-    testMove();
-    testMoveAssignment();
     testRemove();
-    testEntryForEach();
-    testKeyForEach();
-    testValueForEach();
-    testTypes();
 }

+ 0 - 311
test/modules/ProbingHashMapTests.cpp

@@ -1,311 +0,0 @@
-#include "../../src/ErrorSimulator.hpp"
-#include "../Tests.hpp"
-#include "core/data/ProbingHashMap.hpp"
-#include "core/utils/Error.hpp"
-#include "core/utils/HashCode.hpp"
-
-template struct Core::ProbingHashMap<int, int>;
-using IntMap = Core::ProbingHashMap<int, int>;
-
-constexpr int INVALID = Core::emptyValue<int>();
-
-static IntMap getTestIntMap() {
-    IntMap map;
-    map.add(1, 3).add(2, 4).add(3, 5).add(INVALID, 20);
-    return map;
-}
-
-static void checkIntMap(IntMap& map) {
-    int* a = map.search(1);
-    int* b = map.search(2);
-    int* c = map.search(3);
-    int* d = map.search(INVALID);
-    if(CORE_TEST_NOT_NULL(a) && CORE_TEST_NOT_NULL(b) &&
-       CORE_TEST_NOT_NULL(c) && CORE_TEST_NOT_NULL(d)) {
-        CORE_TEST_EQUAL(3, *a);
-        CORE_TEST_EQUAL(4, *b);
-        CORE_TEST_EQUAL(5, *c);
-        CORE_TEST_EQUAL(20, *d);
-    }
-}
-
-static void testAdd() {
-    IntMap map;
-    map.add(5, 4);
-    int* value = map.search(5);
-    CORE_TEST_NOT_NULL(value);
-    if(value != nullptr) {
-        CORE_TEST_EQUAL(4, *value);
-    }
-}
-
-static void testMultipleAdd() {
-    IntMap map = getTestIntMap();
-    CORE_TEST_TRUE(map.contains(1));
-    CORE_TEST_TRUE(map.contains(2));
-    CORE_TEST_TRUE(map.contains(3));
-    checkIntMap(map);
-}
-
-static void testSearch() {
-    IntMap map;
-    CORE_TEST_NULL(map.search(6));
-    map.add(5, 4).add(10, 3).add(15, 2);
-    CORE_TEST_NULL(map.search(6));
-}
-
-static void testAddReplace() {
-    IntMap map;
-    map.add(5, 4).add(5, 10);
-    CORE_TEST_TRUE(map.contains(5));
-    int* a = map.search(5);
-    if(CORE_TEST_NOT_NULL(a)) {
-        CORE_TEST_EQUAL(10, *a);
-    }
-}
-
-static void testClear() {
-    IntMap map;
-    map.add(5, 4).add(4, 10);
-    map.clear();
-    CORE_TEST_FALSE(map.contains(5));
-    CORE_TEST_FALSE(map.contains(4));
-}
-
-static void testOverflow(bool light) {
-    int limit = light ? 10000 : 100000;
-    IntMap map;
-    map.add(INVALID, 42);
-    for(int i = 0; i < limit; i++) {
-        map.add(i, i);
-    }
-    for(int i = 0; i < limit; i++) {
-        CORE_TEST_TRUE(map.contains(i));
-    }
-    CORE_TEST_TRUE(map.contains(INVALID));
-}
-
-static int aInstances = 0;
-
-struct ProbingTest final {
-    int a;
-    int b;
-
-    ProbingTest(int a_, int b_) : a(a_), b(b_) {
-        aInstances++;
-    }
-
-    ProbingTest(const ProbingTest& o) : a(o.a), b(o.b) {
-        aInstances++;
-    }
-
-    ProbingTest(ProbingTest&& o) : a(o.a), b(o.b) {
-        aInstances++;
-    }
-
-    ~ProbingTest() {
-        aInstances--;
-    }
-
-    ProbingTest& operator=(const ProbingTest& o) = default;
-    ProbingTest& operator=(ProbingTest&& o) = default;
-
-    bool operator==(const ProbingTest& other) const {
-        return a == other.a && b == other.b;
-    }
-
-    template<typename String>
-    check_return Core::Error toString(String& s) const {
-        CORE_RETURN_ERROR(s.append("A("));
-        CORE_RETURN_ERROR(s.append(a));
-        CORE_RETURN_ERROR(s.append(", "));
-        CORE_RETURN_ERROR(s.append(b));
-        CORE_RETURN_ERROR(s.append(")"));
-        return Core::ErrorCode::NONE;
-    }
-};
-
-static void testEmplace() {
-    {
-        Core::ProbingHashMap<int, ProbingTest> map;
-
-        ProbingTest* ar = nullptr;
-        CORE_TEST_TRUE(map.tryEmplace(ar, 0, 3, 4));
-        CORE_TEST_TRUE(map.tryEmplace(ar, 3, 4, 5));
-        CORE_TEST_TRUE(map.tryEmplace(ar, 20, 5, 6));
-        CORE_TEST_FALSE(map.tryEmplace(ar, 3, 6, 7));
-        CORE_TEST_FALSE(map.tryEmplace(ar, 20, 7, 8));
-
-        ProbingTest* a = map.search(0);
-        ProbingTest* b = map.search(3);
-        ProbingTest* c = map.search(20);
-
-        if(CORE_TEST_NOT_NULL(a) && CORE_TEST_NOT_NULL(b) &&
-           CORE_TEST_NOT_NULL(c)) {
-            CORE_TEST_EQUAL(ProbingTest(3, 4), *a);
-            CORE_TEST_EQUAL(ProbingTest(4, 5), *b);
-            CORE_TEST_EQUAL(ProbingTest(5, 6), *c);
-        }
-    }
-    CORE_TEST_EQUAL(0, aInstances);
-}
-
-static void testToString() {
-    CORE_TEST_STRING("[2 = 4, 1 = 3, 3 = 5, 2147483647 = 20]", getTestIntMap());
-    CORE_TEST_STRING("[1 = 3]", IntMap().add(1, 3));
-    CORE_TEST_STRING("[]", IntMap());
-}
-
-static void testCopy() {
-    IntMap map = getTestIntMap();
-    IntMap copy = map;
-    IntMap copyA;
-    copyA = map;
-    checkIntMap(map);
-    checkIntMap(copy);
-    checkIntMap(copyA);
-}
-
-static void testMove() {
-    IntMap map = getTestIntMap();
-    IntMap move(Core::move(map));
-    checkIntMap(move);
-}
-
-static void testMoveAssignment() {
-    IntMap map = getTestIntMap();
-    IntMap move;
-    move = Core::move(map);
-    checkIntMap(move);
-}
-
-static void testEntryForEach() {
-    IntMap map;
-    map.add(5, 4).add(10, 3).add(15, 2);
-
-    int counter = 0;
-    for(auto entry : map) {
-        counter += entry.getKey() + entry.value;
-    }
-    CORE_TEST_EQUAL(39, counter);
-
-    const IntMap& cmap = map;
-    counter = 0;
-    for(auto entry : cmap) {
-        counter += entry.getKey() + entry.value;
-    }
-    CORE_TEST_EQUAL(39, counter);
-}
-
-static void testKeyForEach() {
-    IntMap map;
-    map.add(5, 4).add(10, 3).add(15, 2);
-
-    int counter = 0;
-    for(const int& key : map.getKeys()) {
-        counter += key;
-    }
-    CORE_TEST_EQUAL(30, counter);
-
-    const IntMap& cmap = map;
-    counter = 0;
-    for(const int& key : cmap.getKeys()) {
-        counter += key;
-    }
-    CORE_TEST_EQUAL(30, counter);
-}
-
-static void testValueForEach() {
-    IntMap map;
-    map.add(5, 4).add(10, 3).add(15, 2);
-
-    int counter = 0;
-    for(int& value : map.getValues()) {
-        counter += value;
-    }
-    CORE_TEST_EQUAL(9, counter);
-
-    const IntMap& cmap = map;
-    counter = 0;
-    for(const int& value : cmap.getValues()) {
-        counter += value;
-    }
-    CORE_TEST_EQUAL(9, counter);
-}
-
-template<typename T>
-static void testType() {
-    Core::ProbingHashMap<T, int> m;
-    m.add(T(), 3);
-}
-
-static void testTypes() {
-    testType<char>();
-    testType<signed char>();
-    testType<signed short>();
-    testType<signed int>();
-    testType<signed long>();
-    testType<signed long long>();
-    testType<unsigned char>();
-    testType<unsigned short>();
-    testType<unsigned int>();
-    testType<unsigned long>();
-    testType<unsigned long long>();
-}
-
-static void testInvalid() {
-    IntMap map;
-    int* v;
-    CORE_TEST_TRUE(map.tryEmplace(v, INVALID, 2));
-    if(CORE_TEST_NOT_NULL(v)) {
-        CORE_TEST_EQUAL(2, *v);
-    }
-    CORE_TEST_FALSE(map.tryEmplace(v, INVALID, 6));
-    if(CORE_TEST_NOT_NULL(v)) {
-        CORE_TEST_EQUAL(2, *v);
-    }
-    CORE_TEST_EQUAL(3, map.put(INVALID, 3));
-    v = map.search(INVALID);
-    if(CORE_TEST_NOT_NULL(v)) {
-        CORE_TEST_EQUAL(3, *v);
-    }
-    map.clear();
-    CORE_TEST_NULL(map.search(INVALID));
-}
-
-static void testInvalidPut() {
-    IntMap map;
-    CORE_TEST_EQUAL(3, map.put(INVALID, 3));
-    int* v = map.search(INVALID);
-    if(CORE_TEST_NOT_NULL(v)) {
-        CORE_TEST_EQUAL(3, *v);
-    }
-}
-
-static void testAddCollisions() {
-    IntMap map;
-    for(int i = 0; i < 8; i++) {
-        map.add(i * 16, i);
-    }
-}
-
-void Core::testProbingHashMap(bool light) {
-    testAdd();
-    testMultipleAdd();
-    testSearch();
-    testAddReplace();
-    testClear();
-    testOverflow(light);
-    testEmplace();
-    testToString();
-    testCopy();
-    testMove();
-    testMoveAssignment();
-    testEntryForEach();
-    testKeyForEach();
-    testValueForEach();
-    testTypes();
-    testInvalid();
-    testInvalidPut();
-    testAddCollisions();
-}

+ 2 - 0
test/modules/UtilityTests.cpp

@@ -21,9 +21,11 @@ static void testIf() {
     CORE_TEST_TRUE((Core::IsSame<Core::If<false, int, double>, double>));
 }
 
+#ifdef ERROR_SIMULATOR
 static void onOutOfMemory(void* p) {
     *static_cast<bool*>(p) = true;
 }
+#endif
 
 static void testAllocateFail() {
 #ifdef ERROR_SIMULATOR