#ifndef CORE_HPPASHMAP_HPP #define CORE_HPPASHMAP_HPP #include "core/data/LinkedList.hpp" #include "core/data/List.hpp" #include "core/utils/HashCode.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; } template check_return Error toString(String& s) const { CORE_RETURN_ERROR(s.append(key)); CORE_RETURN_ERROR(s.append(" = ")); return s.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: check_return Error copyFrom(const HashMap& other) { HashMap copy; for(const auto& en : other) { CORE_RETURN_ERROR(copy.add(en.getKey(), en.value)); } swap(copy.nodes, nodes); swap(copy.nodePointers, nodePointers); return Error::NONE; } check_return Error rehash(i64 minCapacity) { if(minCapacity <= nodePointers.getLength()) { return Error::NONE; } HashMap map; i64 l = 1l << Math::roundUpLog2(Core::Math::max(minCapacity, 8l)); CORE_RETURN_ERROR(map.nodePointers.resize(l)); for(NodePointerList& list : nodePointers) { for(NodePointer& n : list) { i64 h = map.hashIndex(n->data.key); CORE_RETURN_ERROR(map.nodePointers[h].add(n)); } } Core::swap(map.nodePointers, nodePointers); return Error::NONE; } template check_return Error tryEmplace(V*& v, const K& key, Args&&... args) { CORE_RETURN_ERROR(rehash(nodes.getLength() + 1)); i64 h = hashIndex(key); v = searchList(key, h); if(v != nullptr) { return Error::EXISTING_KEY; } NodePointer np = nullptr; CORE_RETURN_ERROR(nodes.put(np, key, Core::forward(args)...)); Error e = Error::NONE; if(checkError(e, nodePointers[h].add(np))) { nodes.remove(np); return e; } v = &(np->data.value); return Error::NONE; } template check_return Error put(V*& v, const K& key, VA&& value) { CORE_RETURN_ERROR(rehash(nodes.getLength() + 1)); i64 h = hashIndex(key); v = searchList(key, h); if(v != nullptr) { *v = Core::forward(value); return Error::NONE; } NodePointer np = nullptr; CORE_RETURN_ERROR(nodes.put(np, key, Core::forward(value))); Error e = Error::NONE; if(checkError(e, nodePointers[h].add(np))) { nodes.remove(np); return e; } v = &(np->data.value); return Error::NONE; } template check_return Error add(const K& key, VA&& value) { V* v = nullptr; return put(v, key, Core::forward(value)); } check_return Error remove(const K& key) { NodePointerList& list = nodePointers[hashIndex(key)]; for(i64 i = 0; i < list.getLength(); i++) { if(list[i]->data.key == key) { nodes.remove(list[i]); return list.removeBySwap(i); } } return Error::NOT_FOUND; } 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()); } template check_return Error toString(String& s) const { return Core::toString(s, *this); } private: template i64 hashIndex(const H& key) const { return static_cast( hashCode(key) & (static_cast(nodePointers.getLength()) - 1)); } const V* searchList(const K& key, i64 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, i64 h) { return const_cast( static_cast(this)->searchList(key, h)); } }; } #endif