#ifndef CORE_HASHMAP_HPP #define CORE_HASHMAP_HPP #include "core/data/LinkedList.hpp" #include "core/data/List.hpp" #include "core/utils/ArrayString.hpp" #include "core/utils/HashCode.hpp" #include "core/utils/Meta.hpp" namespace Core { template struct HashMap final { class Node final { friend HashMap; friend List; friend LinkedList; K key; public: V value; const K& getKey() const { return key; } void toString(BufferString& s) const { s.append(key).append(" = ").append(value); } private: template Node(const K& key_, Args&&... args) : key(key_), value(Core::forward(args)...) { } }; private: using NodePointer = LinkedList::Node*; using NodePointerList = List; using NodeIterator = LinkedList::Iterator; using ConstNodeIterator = LinkedList::ConstIterator; template class Iterator final { N iterator; public: Iterator(N iterator_) : iterator(iterator_) { } Iterator& operator++() { ++iterator; return *this; } bool operator!=(const Iterator& other) const { return iterator != other.iterator; } R& operator*() const { return A(*iterator); } }; 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.begin()); } I end() const { return I(map.nodes.end()); } }; using ValueIteratorAdapter = IteratorAdapter; using ConstValueIteratorAdapter = IteratorAdapter; using ConstKeyIteratorAdapter = IteratorAdapter; private: LinkedList nodes{}; List nodePointers{}; public: HashMap() = default; HashMap(const HashMap& other) { for(const auto& en : other) { add(en.getKey(), en.value); } } HashMap(HashMap&& other) { swap(other); } HashMap& operator=(HashMap other) { swap(other); return *this; } void rehash(size_t minCapacity) { if(minCapacity <= nodePointers.getLength()) { return; } HashMap map; size_t l = 1lu << Math::roundUpLog2(Core::Math::max(minCapacity, 8lu)); map.nodePointers.resize(l); for(NodePointerList& list : nodePointers) { for(NodePointer& n : list) { size_t h = map.hashIndex(n->data.key); map.nodePointers[h].add(n); } } Core::swap(map.nodePointers, nodePointers); } template 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 false; } NodePointer np = nodes.put(key, Core::forward(args)...); nodePointers[h].add(np); v = &(np->data.value); return true; } template V& put(const K& key, VA&& value) { rehash(nodes.getLength() + 1); size_t h = hashIndex(key); V* v = searchList(key, h); if(v != nullptr) { *v = Core::forward(value); return *v; } NodePointer np = nodes.put(key, Core::forward(value)); nodePointers[h].add(np); return np->data.value; } template HashMap& add(const K& key, VA&& value) { put(key, Core::forward(value)); return *this; } bool remove(const K& key) { NodePointerList& list = nodePointers[hashIndex(key)]; for(size_t i = 0; i < list.getLength(); i++) { if(list[i]->data.key == key) { nodes.remove(list[i]); list.removeBySwap(i); return true; } } return false; } const V* search(const K& key) const { return searchList(key, hashIndex(key)); } V* search(const K& key) { return searchList(key, hashIndex(key)); } bool contains(const K& key) const { return search(key) != nullptr; } HashMap& clear() { nodes.clear(); for(NodePointerList& n : nodePointers) { n.clear(); } return *this; } ConstKeyIteratorAdapter getKeys() const { return {*this}; } ValueIteratorAdapter getValues() { return {*this}; } ConstValueIteratorAdapter getValues() const { return {*this}; } EntryIterator begin() { return EntryIterator(nodes.begin()); } EntryIterator end() { return EntryIterator(nodes.end()); } ConstEntryIterator begin() const { return ConstEntryIterator(nodes.begin()); } ConstEntryIterator end() const { return ConstEntryIterator(nodes.end()); } void swap(HashMap& other) { Core::swap(nodes, other.nodes); Core::swap(nodePointers, other.nodePointers); } void toString(BufferString& s) const { Core::toString(s, *this); } private: template size_t hashIndex(const H& key) const { return hashCode(key) & (nodePointers.getLength() - 1); } const V* searchList(const K& key, size_t h) const { if(nodePointers.getLength() == 0) { return nullptr; } for(const NodePointer& n : nodePointers[h]) { if(n->data.key == key) { return &n->data.value; } } return nullptr; } V* searchList(const K& key, size_t h) { return const_cast( static_cast(this)->searchList(key, h)); } }; } #endif