#ifndef HASHMAP_H #define HASHMAP_H #include "utils/Array.h" #include "utils/List.h" #include "utils/StringBuffer.h" #include "utils/Types.h" #include "utils/Utils.h" #include template struct HashMap final { class Node { friend HashMap; friend List; K key; public: V value; const K& getKey() const { return key; } private: int next; Node(const K& key, const V& value) : key(key), value(value), next(-1) { } Node(const K& key, V&& value) : key(key), value(std::move(value)), next(-1) { } template Node(const K& key, Args&&... args) : key(key), value(std::forward(args)...), next(-1) { } }; private: List> nodes; int elements; public: HashMap(int minCapacity = 8) : elements(0) { nodes.resize(1 << Utils::roundUpLog2(minCapacity)); } template bool tryEmplace(const K& key, Args&&... args) { rehash(); Hash h = hash(key); V* v = searchList(key, h); if(v == nullptr) { nodes[h].add(key, std::forward(args)...); elements++; return false; } return true; } HashMap& add(const K& key, const V& value) { rehash(); Hash h = hash(key); V* v = searchList(key, h); if(v == nullptr) { nodes[h].add(key, value); elements++; } else { *v = value; } return *this; } HashMap& add(const K& key, V&& value) { rehash(); Hash h = hash(key); V* v = searchList(key, h); if(v == nullptr) { nodes[h].add(key, std::move(value)); elements++; } else { *v = std::move(value); } return *this; } bool remove(const K& key) { List& list = nodes[hash(key)]; for(int i = 0; i < list.getLength(); i++) { if(list[i].key == key) { list.remove(i); return true; } } return false; } const V* search(const K& key) const { return searchList(key, hash(key)); } V* search(const K& key) { return searchList(key, hash(key)); } bool contains(const K& key) const { return search(key) != nullptr; } HashMap& clear() { for(List& n : nodes) { n.clear(); } elements = 0; return *this; } Node* begin() { return nodes.begin(); } Node* end() { return nodes.end(); } const Node* begin() const { return nodes.begin(); } const Node* end() const { return nodes.end(); } template void toString(StringBuffer& s) const { s.append("["); bool c = false; for(const List& list : nodes) { for(const Node& n : list) { if(c) { s.append(", "); } s.append(n.key).append(" = ").append(n.value); c = true; } } s.append("]"); } private: template Hash hash(const H& key) const { return fullHash(key) & (nodes.getLength() - 1); } template Hash fullHash(const H& key) const { return key.hashCode(); } Hash fullHash(int key) const { return key; } void rehash() { if(elements < nodes.getLength()) { return; } HashMap map(nodes.getLength() * 2); for(List& list : nodes) { for(Node& n : list) { map.tryEmplace(n.key, std::move(n.value)); } } *this = std::move(map); } const V* searchList(const K& key, Hash h) const { for(const Node& n : nodes[h]) { if(n.key == key) { return &n.value; } } return nullptr; } V* searchList(const K& key, Hash h) { return const_cast( static_cast(this)->searchList(key, h)); } }; #endif