#ifndef CORE_HASHMAP_H #define CORE_HASHMAP_H #include "data/LinkedList.h" #include "data/List.h" #include "utils/ArrayString.h" #include "utils/HashCode.h" namespace Core { template<typename K, typename V> struct HashMap final { class Node final { friend HashMap; friend List<Node>; friend LinkedList<Node>; K key; public: V value; const K& getKey() const { return key; } template<typename String> check_return Error toString(String& s) const { CORE_RETURN_ERROR(s.append(key)); CORE_RETURN_ERROR(s.append(" = ")); return s.append(value); } private: template<typename... Args> Node(const K& key_, Args&&... args) : key(key_), value(Core::forward<Args>(args)...) { } }; private: using NodePointer = LinkedList<Node>::Node*; using NodePointerList = List<NodePointer>; using NodeIterator = LinkedList<Node>::Iterator; using ConstNodeIterator = LinkedList<Node>::ConstIterator; template<typename N, typename I, typename R, R& (*A)(I&)> 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<typename R> static R& access(R& node) { return node; } template<typename I, typename R> static R& accessValue(I& node) { return node.value; } static const K& accessKey(const Node& node) { return node.getKey(); } template<typename N, typename R> using BaseEntryIterator = Iterator<N, R, R, access<R>>; using EntryIterator = BaseEntryIterator<NodeIterator, Node>; using ConstEntryIterator = BaseEntryIterator<ConstNodeIterator, const Node>; template<typename N, typename I, typename R> using BaseValueIterator = Iterator<N, I, R, accessValue<I, R>>; using ValueIterator = BaseValueIterator<NodeIterator, Node, V>; using ConstValueIterator = BaseValueIterator<ConstNodeIterator, const Node, const V>; using ConstKeyIterator = Iterator<ConstNodeIterator, const Node, const K, accessKey>; template<typename M, typename I> struct IteratorAdapter final { M& map; I begin() const { return I(map.nodes.begin()); } I end() const { return I(map.nodes.end()); } }; using ValueIteratorAdapter = IteratorAdapter<HashMap, ValueIterator>; using ConstValueIteratorAdapter = IteratorAdapter<const HashMap, ConstValueIterator>; using ConstKeyIteratorAdapter = IteratorAdapter<const HashMap, ConstKeyIterator>; private: LinkedList<Node> nodes; List<NodePointerList> 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(int minCapacity) { if(minCapacity <= nodePointers.getLength()) { return Error::NONE; } HashMap<K, V> map; int l = Core::Math::max(1 << Math::roundUpLog2(minCapacity), 8); CORE_RETURN_ERROR(map.nodePointers.resize(l)); for(NodePointerList& list : nodePointers) { for(NodePointer& n : list) { int h = map.hashIndex(n->data.key); CORE_RETURN_ERROR(map.nodePointers[h].add(n)); } } Core::swap(map.nodePointers, nodePointers); return Error::NONE; } template<typename... Args> check_return Error tryEmplace(V*& v, const K& key, Args&&... args) { CORE_RETURN_ERROR(rehash(nodes.getLength() + 1)); int 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>(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<typename VA> check_return Error put(V*& v, const K& key, VA&& value) { CORE_RETURN_ERROR(rehash(nodes.getLength() + 1)); int h = hashIndex(key); v = searchList(key, h); if(v != nullptr) { *v = Core::forward<VA>(value); return Error::NONE; } NodePointer np = nullptr; CORE_RETURN_ERROR(nodes.put(np, key, Core::forward<VA>(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<typename VA> check_return Error add(const K& key, VA&& value) { V* v = nullptr; return put(v, key, Core::forward<VA>(value)); } check_return Error remove(const K& key) { NodePointerList& list = nodePointers[hashIndex(key)]; for(int 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<typename String> check_return Error toString(String& s) const { return Core::toString(s, *this); } private: template<typename H> int hashIndex(const H& key) const { return static_cast<int>(hashCode(key)) & (nodePointers.getLength() - 1); } const V* searchList(const K& key, int 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, int h) { return const_cast<V*>( static_cast<const HashMap*>(this)->searchList(key, h)); } }; } #endif