diff --git a/BAN/include/BAN/HashMap.h b/BAN/include/BAN/HashMap.h index b9e0a5827..c1ad9d672 100644 --- a/BAN/include/BAN/HashMap.h +++ b/BAN/include/BAN/HashMap.h @@ -7,13 +7,30 @@ namespace BAN { + template + class HashMapIterator; + template> class HashMap { + public: + struct Entry + { + template + Entry(const Key& key, Args&&... args) + : key(key) + , value(forward(args)...) + {} + + Key key; + T value; + }; + public: using size_type = size_t; using key_type = Key; using value_type = T; + using iterator = HashMapIterator; public: HashMap() = default; @@ -29,6 +46,9 @@ namespace BAN template ErrorOr emplace(const Key&, Args&&...); + iterator begin() { return iterator(m_buckets, m_buckets.begin()); } + iterator end() { return iterator(m_buckets, m_buckets.end()); } + ErrorOr reserve(size_type); void remove(const Key&); @@ -42,19 +62,6 @@ namespace BAN bool empty() const; size_type size() const; - private: - struct Entry - { - template - Entry(const Key& key, Args&&... args) - : key(key) - , value(forward(args)...) - {} - - Key key; - T value; - }; - private: ErrorOr rebucket(size_type); LinkedList& get_bucket(const Key&); @@ -63,6 +70,101 @@ namespace BAN private: Vector> m_buckets; size_type m_size = 0; + + friend iterator; + }; + + template + class HashMapIterator + { + public: + using KeyValue = typename Container::Entry; + + public: + HashMapIterator() = default; + + const KeyValue& operator*() const + { + ASSERT(*this); + ASSERT(!at_end()); + return *m_entry_iterator; + } + KeyValue& operator*() + { + ASSERT(*this); + ASSERT(!at_end()); + return *m_entry_iterator; + } + + HashMapIterator& operator++() + { + ASSERT(*this); + ASSERT(!at_end()); + ++m_entry_iterator; + while (m_entry_iterator == m_bucket_iterator->end()) + { + ++m_bucket_iterator; + if (m_bucket_iterator == m_container.end()) + { + m_entry_iterator = {}; + break; + } + m_entry_iterator = m_bucket_iterator->begin(); + } + return *this; + } + + HashMapIterator operator++(int) + { + auto temp = *this; + ++(*this); + return temp; + } + + bool operator==(const HashMapIterator& other) const + { + if (&m_container != &other.m_container) + return false; + if (m_bucket_iterator != other.m_bucket_iterator) + return false; + if (m_bucket_iterator == m_container.end()) + return true; + if (m_entry_iterator && other.m_entry_iterator) + return m_entry_iterator == other.m_entry_iterator; + if (!m_entry_iterator && !other.m_entry_iterator) + return true; + return false; + } + bool operator!=(const HashMapIterator& other) const + { + return !(*this == other); + } + + operator bool() const + { + return m_bucket_iterator && m_entry_iterator; + } + + private: + HashMapIterator(Vector>& container, Vector>::iterator current) + : m_container(container) + , m_bucket_iterator(current) + { + if (current != container.end()) + m_entry_iterator = current->begin(); + } + + bool at_end() const + { + return m_bucket_iterator == m_container.end(); + } + + private: + Vector>& m_container; + Vector>::iterator m_bucket_iterator; + LinkedList::iterator m_entry_iterator; + + friend Container; }; template