Browse Source

improved hashmap iterators, start of ecs

Kajetan Johannes Hammerle 2 years ago
parent
commit
cb75cc1a35
4 changed files with 274 additions and 33 deletions
  1. 2 0
      Main.cpp
  2. 47 0
      ecs/Components.h
  3. 50 18
      tests/HashMapTests.cpp
  4. 175 15
      utils/HashMap.h

+ 2 - 0
Main.cpp

@@ -1,3 +1,5 @@
+#include "ecs/Components.h"
+#include "math/Vector.h"
 #include "rendering/Window.h"
 #include "tests/ArrayListTests.h"
 #include "tests/ArrayTests.h"

+ 47 - 0
ecs/Components.h

@@ -0,0 +1,47 @@
+#include "utils/HashMap.h"
+#include "utils/List.h"
+#include "utils/Types.h"
+
+typedef uint32 Entity;
+
+template<typename T>
+class Components final {
+    HashMap<Entity, T> components;
+
+public:
+    Components() {
+    }
+
+    template<typename... Args>
+    void add(Entity e, Args&&... args) {
+        components.tryEmplace(e, std::forward<Args>(args)...);
+    }
+
+    void remove(Entity e) {
+        components.remove(e);
+    }
+
+    T* search(Entity e) {
+        return components.search(e);
+    }
+
+    const T* search(Entity e) const {
+        return components.search(e);
+    }
+
+    auto begin() {
+        return components.begin();
+    }
+
+    const auto begin() const {
+        return components.begin();
+    }
+
+    auto end() {
+        return components.end();
+    }
+
+    const auto end() const {
+        return components.end();
+    }
+};

+ 50 - 18
tests/HashMapTests.cpp

@@ -239,28 +239,58 @@ static void testRemove(Test& test) {
     }
 }
 
-static void testForEach(Test& test) {
+static void testEntryForEach(Test& test) {
     IntMap map;
     map.add(5, 4).add(10, 3).add(15, 2);
 
-    auto iter = map.begin();
-    test.checkEqual(true, iter != map.end(), "not at end 1");
-    ++iter;
-    test.checkEqual(true, iter != map.end(), "not at end 2");
-    ++iter;
-    test.checkEqual(true, iter != map.end(), "not at end 3");
-    ++iter;
-    test.checkEqual(false, iter != map.end(), "at end");
+    int counter = 0;
+    for(auto& entry : map.entries()) {
+        counter += entry.getKey() + entry.value;
+    }
+    test.checkEqual(39, counter, "entry iterator");
+
+    const IntMap& cmap = map;
+    counter = 0;
+    for(const auto& entry : cmap.entries()) {
+        counter += entry.getKey() + entry.value;
+    }
+    test.checkEqual(39, counter, "const entry iterator");
+}
+
+static void testKeyForEach(Test& test) {
+    IntMap map;
+    map.add(5, 4).add(10, 3).add(15, 2);
+
+    int counter = 0;
+    for(const int& key : map.keys()) {
+        counter += key;
+    }
+    test.checkEqual(30, counter, "key iterator");
 
     const IntMap& cmap = map;
-    auto citer = cmap.begin();
-    test.checkEqual(true, citer != cmap.end(), "not at end 1");
-    ++citer;
-    test.checkEqual(true, citer != cmap.end(), "not at end 2");
-    ++citer;
-    test.checkEqual(true, citer != cmap.end(), "not at end 3");
-    ++citer;
-    test.checkEqual(false, citer != cmap.end(), "at end");
+    counter = 0;
+    for(const int& key : cmap.keys()) {
+        counter += key;
+    }
+    test.checkEqual(30, counter, "const key iterator");
+}
+
+static void testValueForEach(Test& test) {
+    IntMap map;
+    map.add(5, 4).add(10, 3).add(15, 2);
+
+    int counter = 0;
+    for(int& value : map.values()) {
+        counter += value;
+    }
+    test.checkEqual(9, counter, "value iterator");
+
+    const IntMap& cmap = map;
+    counter = 0;
+    for(const int& value : cmap.values()) {
+        counter += value;
+    }
+    test.checkEqual(9, counter, "const value iterator");
 }
 
 void HashMapTests::test() {
@@ -280,6 +310,8 @@ void HashMapTests::test() {
     testMove(test);
     testMoveAssignment(test);
     testRemove(test);
-    testForEach(test);
+    testEntryForEach(test);
+    testKeyForEach(test);
+    testValueForEach(test);
     test.finalize();
 }

+ 175 - 15
utils/HashMap.h

@@ -9,7 +9,7 @@
 
 template<typename K, typename V>
 struct HashMap final {
-    class Node {
+    class Node final {
         friend HashMap;
         friend List<Node>;
         K key;
@@ -38,24 +38,24 @@ struct HashMap final {
     };
 
     template<typename N, typename R>
-    class BaseIterator {
+    class BaseEntryIterator final {
         N& nodes;
         int indexA;
         int indexB;
 
     public:
-        BaseIterator(N& nodes, int indexA, int indexB)
+        BaseEntryIterator(N& nodes, int indexA, int indexB)
             : nodes(nodes), indexA(indexA), indexB(indexB) {
             skip();
         }
 
-        BaseIterator& operator++() {
+        BaseEntryIterator& operator++() {
             indexB++;
             skip();
             return *this;
         }
 
-        bool operator!=(const BaseIterator& other) const {
+        bool operator!=(const BaseEntryIterator& other) const {
             return indexA != other.indexA || indexB != other.indexB;
         }
 
@@ -73,8 +73,144 @@ struct HashMap final {
         }
     };
 
-    typedef BaseIterator<List<List<Node>>, Node> Iterator;
-    typedef BaseIterator<const List<List<Node>>, const Node> ConstIterator;
+    typedef BaseEntryIterator<List<List<Node>>, Node> EntryIterator;
+    typedef BaseEntryIterator<const List<List<Node>>, const Node>
+        ConstEntryIterator;
+
+    struct EntryIteratorAdapter final {
+        HashMap& map;
+
+        EntryIterator begin() {
+            return EntryIterator(map.nodes, 0, 0);
+        }
+
+        EntryIterator end() {
+            return EntryIterator(map.nodes, map.nodes.getLength(), 0);
+        }
+    };
+
+    struct ConstEntryIteratorAdapter final {
+        const HashMap& map;
+
+        ConstEntryIterator begin() const {
+            return ConstEntryIterator(map.nodes, 0, 0);
+        }
+
+        ConstEntryIterator end() const {
+            return ConstEntryIterator(map.nodes, map.nodes.getLength(), 0);
+        }
+    };
+
+    template<typename N, typename R>
+    class BaseValueIterator final {
+        N& nodes;
+        int indexA;
+        int indexB;
+
+    public:
+        BaseValueIterator(N& nodes, int indexA, int indexB)
+            : nodes(nodes), indexA(indexA), indexB(indexB) {
+            skip();
+        }
+
+        BaseValueIterator& operator++() {
+            indexB++;
+            skip();
+            return *this;
+        }
+
+        bool operator!=(const BaseValueIterator& other) const {
+            return indexA != other.indexA || indexB != other.indexB;
+        }
+
+        R& operator*() {
+            return nodes[indexA][indexB].value;
+        }
+
+    private:
+        void skip() {
+            while(indexA < nodes.getLength() &&
+                  indexB >= nodes[indexA].getLength()) {
+                indexA++;
+                indexB = 0;
+            }
+        }
+    };
+
+    typedef BaseValueIterator<List<List<Node>>, V> ValueIterator;
+    typedef BaseValueIterator<const List<List<Node>>, const V>
+        ConstValueIterator;
+
+    struct ValueIteratorAdapter final {
+        HashMap& map;
+
+        ValueIterator begin() {
+            return ValueIterator(map.nodes, 0, 0);
+        }
+
+        ValueIterator end() {
+            return ValueIterator(map.nodes, map.nodes.getLength(), 0);
+        }
+    };
+
+    struct ConstValueIteratorAdapter final {
+        const HashMap& map;
+
+        ConstValueIterator begin() const {
+            return ConstValueIterator(map.nodes, 0, 0);
+        }
+
+        ConstValueIterator end() const {
+            return ConstValueIterator(map.nodes, map.nodes.getLength(), 0);
+        }
+    };
+
+    class ConstKeyIterator final {
+        const List<List<Node>>& nodes;
+        int indexA;
+        int indexB;
+
+    public:
+        ConstKeyIterator(const List<List<Node>>& nodes, int indexA, int indexB)
+            : nodes(nodes), indexA(indexA), indexB(indexB) {
+            skip();
+        }
+
+        ConstKeyIterator& operator++() {
+            indexB++;
+            skip();
+            return *this;
+        }
+
+        bool operator!=(const ConstKeyIterator& other) const {
+            return indexA != other.indexA || indexB != other.indexB;
+        }
+
+        const K& operator*() {
+            return nodes[indexA][indexB].getKey();
+        }
+
+    private:
+        void skip() {
+            while(indexA < nodes.getLength() &&
+                  indexB >= nodes[indexA].getLength()) {
+                indexA++;
+                indexB = 0;
+            }
+        }
+    };
+
+    struct ConstKeyIteratorAdapter final {
+        const HashMap& map;
+
+        ConstKeyIterator begin() const {
+            return ConstKeyIterator(map.nodes, 0, 0);
+        }
+
+        ConstKeyIterator end() const {
+            return ConstKeyIterator(map.nodes, map.nodes.getLength(), 0);
+        }
+    };
 
 private:
     List<List<Node>> nodes;
@@ -155,20 +291,40 @@ public:
         return *this;
     }
 
-    Iterator begin() {
-        return Iterator(nodes, 0, 0);
+    EntryIteratorAdapter entries() {
+        return {*this};
     }
 
-    Iterator end() {
-        return Iterator(nodes, nodes.getLength(), 0);
+    const ConstEntryIteratorAdapter entries() const {
+        return {*this};
     }
 
-    ConstIterator begin() const {
-        return ConstIterator(nodes, 0, 0);
+    const ConstKeyIteratorAdapter keys() const {
+        return {*this};
     }
 
-    ConstIterator end() const {
-        return ConstIterator(nodes, nodes.getLength(), 0);
+    ValueIteratorAdapter values() {
+        return {*this};
+    }
+
+    const ConstValueIteratorAdapter values() const {
+        return {*this};
+    }
+
+    EntryIterator begin() {
+        return EntryIterator(nodes, 0, 0);
+    }
+
+    EntryIterator end() {
+        return EntryIterator(nodes, nodes.getLength(), 0);
+    }
+
+    ConstEntryIterator begin() const {
+        return ConstEntryIterator(nodes, 0, 0);
+    }
+
+    ConstEntryIterator end() const {
+        return ConstEntryIterator(nodes, nodes.getLength(), 0);
     }
 
     template<int L>
@@ -202,6 +358,10 @@ private:
         return key;
     }
 
+    Hash fullHash(unsigned int key) const {
+        return key;
+    }
+
     void rehash() {
         if(elements < nodes.getLength()) {
             return;