#ifndef HASHMAP_H #define HASHMAP_H #include "data/List.h" #include "math/Math.h" #include "utils/StringBuffer.h" #include "utils/Types.h" template struct HashMap final { class Node final { friend HashMap; friend List; K key; public: V value; const K& getKey() const { return key; } private: template Node(const K& key, Args&&... args) : key(key), value(std::forward(args)...) { } }; using Nodes = List>; template class Iterator final { N& nodes; int indexA; int indexB; public: Iterator(N& nodes, int indexA, int indexB) : nodes(nodes), indexA(indexA), indexB(indexB) { skip(); } Iterator& operator++() { indexB++; skip(); return *this; } bool operator!=(const Iterator& other) const { return indexA != other.indexA || indexB != other.indexB; } R& operator*() const { return A(nodes[indexA][indexB]); } private: void skip() { while(indexA < nodes.getLength() && indexB >= nodes[indexA].getLength()) { indexA++; indexB = 0; } } }; template static R& access(R& node) { return node; } template static R& accessValue(I& node) { return node.value; } static const K& accessKey(const Node& node) { return node.getKey(); } template using BaseEntryIterator = Iterator>; using EntryIterator = BaseEntryIterator; using ConstEntryIterator = BaseEntryIterator; template using BaseValueIterator = Iterator>; using ValueIterator = BaseValueIterator; using ConstValueIterator = BaseValueIterator; using ConstKeyIterator = Iterator; template struct IteratorAdapter final { M& map; I begin() const { return I(map.nodes, 0, 0); } I end() const { return I(map.nodes, map.nodes.getLength(), 0); } }; using EntryIteratorAdapter = IteratorAdapter; using ConstEntryIteratorAdapter = IteratorAdapter; using ValueIteratorAdapter = IteratorAdapter; using ConstValueIteratorAdapter = IteratorAdapter; using ConstKeyIteratorAdapter = IteratorAdapter; private: Nodes nodes; int elements; public: HashMap(int minCapacity = 8) : elements(0) { nodes.resize(1 << Math::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; } template HashMap& add(const K& key, VA&& value) { rehash(); Hash h = hash(key); V* v = searchList(key, h); if(v == nullptr) { nodes[h].add(key, std::forward(value)); elements++; } else { *v = std::forward(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.removeBySwap(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; } EntryIteratorAdapter entries() { return {*this}; } ConstEntryIteratorAdapter entries() const { return {*this}; } ConstKeyIteratorAdapter keys() const { return {*this}; } ValueIteratorAdapter values() { return {*this}; } 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 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; } Hash fullHash(unsigned 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