Kajetan Johannes Hammerle пре 3 година
родитељ
комит
2d4355a911
3 измењених фајлова са 231 додато и 1 уклоњено
  1. 93 1
      Main.cpp
  2. 50 0
      utils/Array.h
  3. 88 0
      utils/HashMap.h

+ 93 - 1
Main.cpp

@@ -1,6 +1,98 @@
 #include <iostream>
 
+#include "utils/HashMap.h"
+
+constexpr int MAP_MIN_CAPACITY = 5;
+typedef HashMap<int, int, MAP_MIN_CAPACITY> IntMap;
+
+const char* RED = "\033[0;31m";
+const char* GREEN = "\033[0;32m";
+
+int tests = 0;
+int successTests = 0;
+
+void finalizeTest() {
+    std::cout << ((successTests == tests) ? GREEN : RED);
+    std::cout << successTests << " / " << tests << " succeeded\n";
+    tests = 0;
+    successTests = 0;
+}
+
+template<typename T>
+void checkEqual(const T& wanted, const T& actual, const char* text) {
+    if(wanted == actual) {
+        tests++;
+        successTests++;
+        std::cout << GREEN << tests << ": " << text << "\n";
+    } else {
+        tests++;
+        std::cout << RED << tests << ": " << text << " - ";
+        std::cout << RED << "expected '" << wanted << "' got '" << actual << "'\n";
+    }
+}
+
+namespace Map {
+
+    void testAdd() {
+        IntMap map;
+        map.add(5, 4);
+        checkEqual(true, map.contains(5), "map contains added value");
+        checkEqual(true, map.search(5, -1) == 4, "map search finds added value");
+    }
+
+    void testMultipleAdd() {
+        IntMap map;
+        map.add(5, 4);
+        map.add(10, 3);
+        map.add(15, 2);
+        checkEqual(true, map.contains(5), "map contains added value 1");
+        checkEqual(true, map.contains(10), "map contains added value 2");
+        checkEqual(true, map.contains(15), "map contains added value 3");
+        checkEqual(true, map.search(5, -1) == 4, "map search finds added value 1");
+        checkEqual(true, map.search(10, -1) == 3, "map search finds added value 2");
+        checkEqual(true, map.search(15, -1) == 2, "map search finds added value 3");
+    }
+
+    void testAddReplace() {
+        IntMap map;
+        map.add(5, 4);
+        map.add(5, 10);
+        checkEqual(true, map.contains(5), "map contains replaced value");
+        checkEqual(true, map.search(5, -1) == 10, "map search finds replaced value");
+    }
+
+    void testClear() {
+        IntMap map;
+        map.add(5, 4);
+        map.add(4, 10);
+        map.clear();
+
+        checkEqual(false, map.contains(5), "map does not contain cleared values");
+        checkEqual(false, map.contains(4), "map does not contain cleared values");
+    }
+
+    void testOverflow() {
+        IntMap map;
+        for(int i = 0; i < 1000000; i++) {
+            map.add(i, i);
+        }
+        for(int i = 0; i < MAP_MIN_CAPACITY; i++) {
+            checkEqual(true, map.contains(i), "map still contains values after overflow");
+        }
+        checkEqual(true, true, "map survives overflow");
+    }
+
+    void test() {
+        testAdd();
+        testMultipleAdd();
+        testAddReplace();
+        testClear();
+        testOverflow();
+        finalizeTest();
+    }
+}
+
 int main() {
-    std::cout << "test2\n";
+    Map::test();
     return 0;
 }

+ 50 - 0
utils/Array.h

@@ -0,0 +1,50 @@
+#ifndef ARRAY_H
+#define ARRAY_H
+
+template<typename T, int N>
+class Array final {
+    T data[N];
+
+public:
+    Array() = default;
+
+    Array(const T& t) {
+        fill(t);
+    }
+    
+    void fill(const T& t) {
+        for(int i = 0; i < N; i++) {
+            data[i] = t;
+        }
+    }
+
+    T& operator[](int index) {
+        return data[index];
+    }
+
+    const T& operator[](int index) const {
+        return data[index];
+    }
+
+    T* begin() {
+        return data;
+    }
+
+    T* end() {
+        return data + N;
+    }
+
+    const T* begin() const {
+        return data;
+    }
+
+    const T* end() const {
+        return data + N;
+    }
+
+    constexpr int getLength() const {
+        return N;
+    }
+};
+
+#endif

+ 88 - 0
utils/HashMap.h

@@ -0,0 +1,88 @@
+#ifndef HASHMAP_H
+#define HASHMAP_H
+
+#include "utils/Array.h"
+
+template<typename K, typename V, int N_MIN>
+class HashMap {
+
+    static constexpr int getCapacity() {
+        int i = 1;
+        while(i < N_MIN) {
+            i <<= 1;
+        }
+        return i;
+    }
+
+    static constexpr int CAPACITY = getCapacity();
+    static constexpr int MASK = CAPACITY - 1;
+
+    Array<bool, CAPACITY> used;
+    Array<K, CAPACITY> keys;
+    Array<V, CAPACITY> values;
+
+    int searchIndex(const K& key) const {
+        int base = hash(key);
+        for(int i = 0; i < CAPACITY; i++) {
+            int h = (base + i) & MASK;
+            if(!used[h]) {
+                return -1;
+            } else if(keys[h] == key) {
+                return h;
+            }
+        }
+        return -1;
+    }
+
+public:
+
+    HashMap() : used(false) {
+    }
+
+    void add(const K& key, const V& value) {
+        int base = hash(key);
+        for(int i = 0; i < CAPACITY; i++) {
+            int h = (base + i) & MASK;
+            if(!used[h]) {
+                used[h] = true;
+                keys[h] = key;
+                values[h] = value;
+                return;
+            } else if(keys[h] == key) {
+                values[h] = value;
+                return;
+            }
+        }
+    }
+
+    const V& search(const K& key, const V& notFound) const {
+        int index = searchIndex(key);
+        return index == -1 ? notFound : values[index];
+    }
+
+    V& search(const K& key, V& notFound) {
+        int index = searchIndex(key);
+        return index == -1 ? notFound : values[index];
+    }
+
+    bool contains(const K& key) const {
+        return searchIndex(key) != -1;
+    }
+
+    void clear() {
+        used.fill(false);
+    }
+
+private:
+
+    template<typename H>
+    static int hash(const H& key) {
+        return key.hashCode();
+    }
+
+    static int hash(int key) {
+        return key;
+    }
+};
+
+#endif