BAN: Generalize HashMapIterator to IteratorDouble

This iterator should be able to iterate any container within container
with type iterator defined.

This also fixed bug if first entry in outer container is empty container.
This commit is contained in:
Bananymous 2023-07-12 09:29:05 +03:00
parent a9c10d0751
commit 4285729d5c
2 changed files with 115 additions and 98 deletions

View File

@ -30,7 +30,7 @@ namespace BAN
using size_type = size_t;
using key_type = Key;
using value_type = T;
using iterator = HashMapIterator<HashMap>;
using iterator = IteratorDouble<Entry, Vector, LinkedList, HashMap>;
public:
HashMap() = default;
@ -46,8 +46,8 @@ namespace BAN
template<typename... Args>
ErrorOr<void> emplace(const Key&, Args&&...);
iterator begin() { return iterator(m_buckets, m_buckets.begin()); }
iterator end() { return iterator(m_buckets, m_buckets.end()); }
iterator begin() { return iterator(m_buckets.end(), m_buckets.begin()); }
iterator end() { return iterator(m_buckets.end(), m_buckets.end()); }
ErrorOr<void> reserve(size_type);
@ -74,99 +74,6 @@ namespace BAN
friend iterator;
};
template<typename Container>
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<LinkedList<KeyValue>>& container, Vector<LinkedList<KeyValue>>::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<LinkedList<KeyValue>>& m_container;
Vector<LinkedList<KeyValue>>::iterator m_bucket_iterator;
LinkedList<KeyValue>::iterator m_entry_iterator;
friend Container;
};
template<typename Key, typename T, typename HASH>
HashMap<Key, T, HASH>::HashMap(const HashMap<Key, T, HASH>& other)
{
@ -348,4 +255,4 @@ namespace BAN
return m_buckets[index];
}
}
}

View File

@ -156,4 +156,114 @@ namespace BAN
friend Container;
};
}
template<typename T, template <typename> typename OuterContainer, template <typename> typename InnerContainer, typename Container>
class IteratorDouble
{
public:
using Inner = InnerContainer<T>;
using Outer = OuterContainer<Inner>;
public:
IteratorDouble() = default;
const T& operator*() const
{
ASSERT(*this);
ASSERT(m_outer_current != m_outer_end);
ASSERT(m_inner_current);
return m_inner_current.operator*();
}
T& operator*()
{
ASSERT(*this);
ASSERT(m_outer_current != m_outer_end);
ASSERT(m_inner_current);
return m_inner_current.operator*();
}
const T* operator->() const
{
ASSERT(*this);
ASSERT(m_outer_current != m_outer_end);
ASSERT(m_inner_current);
return m_inner_current.operator->();
}
T* operator->()
{
ASSERT(*this);
ASSERT(m_outer_current != m_outer_end);
ASSERT(m_inner_current);
return m_inner_current.operator->();
}
IteratorDouble& operator++()
{
ASSERT(*this);
ASSERT(m_outer_current != m_outer_end);
ASSERT(m_inner_current);
m_inner_current++;
find_valid_or_end();
return *this;
}
IteratorDouble operator++(int)
{
auto temp = *this;
++(*this);
return temp;
}
bool operator==(const IteratorDouble& other) const
{
if (!*this || !other)
return false;
if (m_outer_end != other.m_outer_end)
return false;
if (m_outer_current != other.m_outer_current)
return false;
if (m_outer_current == m_outer_end)
return true;
return m_inner_current == other.m_inner_current;
}
bool operator!=(const IteratorDouble& other) const
{
return !(*this == other);
}
operator bool() const
{
return m_outer_end && m_outer_current;
}
private:
IteratorDouble(Outer::iterator outer_end, Outer::iterator outer_current)
: m_outer_end(outer_end)
, m_outer_current(outer_current)
{
if (outer_current != outer_end)
{
m_inner_current = m_outer_current->begin();
find_valid_or_end();
}
}
void find_valid_or_end()
{
while (m_inner_current == m_outer_current->end())
{
m_outer_current++;
if (m_outer_current == m_outer_end)
break;
m_inner_current = m_outer_current->begin();
}
}
private:
Outer::iterator m_outer_end;
Outer::iterator m_outer_current;
Inner::iterator m_inner_current;
friend Container;
};
}