BAN: Cleanup Vector code

*Applies to last patch also!*

Remove duplicate code in iterators. We used to have separate iterator
and const_iterator but now they are the same class with some enable_if
magic to disable references from const_iterator

This introduces some 'bad things' you can for example call
const_iterator.operator*<false>() to obtain non const reference. I
don't think this matters since you could use const_cast or something
else to work around const if you really tried
This commit is contained in:
Bananymous 2023-02-06 19:23:39 +02:00
parent 08dfb0e1db
commit 338771c5b0
1 changed files with 52 additions and 74 deletions

View File

@ -8,48 +8,8 @@
namespace BAN namespace BAN
{ {
template<typename T> template<typename T, bool CONST>
class Vector; class VectorIterator;
template<typename T>
class VectorIterator
{
public:
VectorIterator() = default;
VectorIterator(const VectorIterator& other) : m_data(other.m_data) { }
VectorIterator& operator=(const VectorIterator& other) { m_data = other.m_data; return *this; }
VectorIterator& operator++() { m_data++; return *this; }
T& operator*() { return *m_data; }
const T& operator*() const { return *m_data; }
T* operator->() { return m_data; }
const T* operator->() const { return m_data; }
bool operator==(const VectorIterator<T>& other) const { return !(*this != other); }
bool operator!=(const VectorIterator<T>& other) const { return m_data != other.m_data; }
private:
VectorIterator(T* data) : m_data(data) { }
private:
T* m_data = nullptr;
friend class Vector<T>;
};
template<typename T>
class VectorConstIterator
{
public:
VectorConstIterator() = default;
VectorConstIterator(const VectorConstIterator& other) : m_data(other.m_data) { }
VectorConstIterator& operator=(const VectorConstIterator& other) { m_data = other.m_data; return *this; }
VectorConstIterator& operator++() { m_data++; return *this; }
const T& operator*() const { return *m_data; }
const T* operator->() const { return m_data; }
bool operator==(const VectorConstIterator<T>& other) const { return !(*this != other); }
bool operator!=(const VectorConstIterator<T>& other) const { return m_data != other.m_data; }
private:
VectorConstIterator(T* data) : m_data(data) { }
private:
const T* m_data = nullptr;
friend class Vector<T>;
};
// T must be move assignable, move constructable (and copy constructable for some functions) // T must be move assignable, move constructable (and copy constructable for some functions)
template<typename T> template<typename T>
@ -58,8 +18,8 @@ namespace BAN
public: public:
using size_type = size_t; using size_type = size_t;
using value_type = T; using value_type = T;
using iterator = VectorIterator<T>; using iterator = VectorIterator<T, false>;
using const_iterator = VectorConstIterator<T>; using const_iterator = VectorIterator<T, true>;
public: public:
Vector() = default; Vector() = default;
@ -79,16 +39,16 @@ namespace BAN
[[nodiscard]] ErrorOr<void> insert(size_type, T&&); [[nodiscard]] ErrorOr<void> insert(size_type, T&&);
[[nodiscard]] ErrorOr<void> insert(size_type, const T&); [[nodiscard]] ErrorOr<void> insert(size_type, const T&);
iterator begin(); iterator begin() { return iterator(address_of(0)); }
iterator end(); const_iterator begin() const { return const_iterator(address_of(0)); }
const_iterator begin() const; iterator end() { return iterator(address_of(m_size)); }
const_iterator end() const; const_iterator end() const { return const_iterator(address_of(m_size)); }
void pop_back(); void pop_back();
void remove(size_type); void remove(size_type);
void clear(); void clear();
bool has(const T&) const; bool contains(const T&) const;
const T& operator[](size_type) const; const T& operator[](size_type) const;
T& operator[](size_type); T& operator[](size_type);
@ -116,6 +76,48 @@ namespace BAN
size_type m_size = 0; size_type m_size = 0;
}; };
template<typename T, bool CONST>
class VectorIterator
{
public:
using value_type = T;
public:
VectorIterator() = default;
template<bool C>
VectorIterator(const VectorIterator<T, C>& other, enable_if_t<C == CONST || !C>)
: m_data(other.m_data)
{
}
VectorIterator<T, CONST>& operator++() { m_data++; return *this; }
VectorIterator<T, CONST>& operator--() { m_data--; return *this; }
VectorIterator<T, CONST> operator++(int) { auto temp = *this; ++(*this); return temp; }
VectorIterator<T, CONST> operator--(int) { auto temp = *this; --(*this); return temp; }
template<bool ENABLE = !CONST>
enable_if_t<ENABLE, T&> operator*() { ASSERT(m_data); return *m_data; }
const T& operator*() const { ASSERT(m_data); return *m_data; }
template<bool ENABLE = !CONST>
enable_if_t<ENABLE, T*> operator->() { ASSERT(m_data); return m_data; }
const T* operator->() const { ASSERT(m_data); return m_data; }
bool operator==(const VectorIterator<T, CONST>& other) const { return m_data == other.m_data; }
bool operator!=(const VectorIterator<T, CONST>& other) const { return !(*this == other); }
private:
VectorIterator(T* data) : m_data(data) { }
private:
T* m_data = nullptr;
friend class Vector<T>;
friend class VectorIterator<T, !CONST>;
};
template<typename T> template<typename T>
Vector<T>::Vector(Vector<T>&& other) Vector<T>::Vector(Vector<T>&& other)
{ {
@ -242,30 +244,6 @@ namespace BAN
return insert(move(T(value)), index); return insert(move(T(value)), index);
} }
template<typename T>
typename Vector<T>::iterator Vector<T>::begin()
{
return VectorIterator<T>(address_of(0));
}
template<typename T>
typename Vector<T>::iterator Vector<T>::end()
{
return VectorIterator<T>(address_of(m_size));
}
template<typename T>
typename Vector<T>::const_iterator Vector<T>::begin() const
{
return VectorConstIterator<T>(address_of(0));
}
template<typename T>
typename Vector<T>::const_iterator Vector<T>::end() const
{
return VectorConstIterator<T>(address_of(m_size));
}
template<typename T> template<typename T>
void Vector<T>::pop_back() void Vector<T>::pop_back()
{ {
@ -296,7 +274,7 @@ namespace BAN
} }
template<typename T> template<typename T>
bool Vector<T>::has(const T& other) const bool Vector<T>::contains(const T& other) const
{ {
for (size_type i = 0; i < m_size; i++) for (size_type i = 0; i < m_size; i++)
if (*address_of(i) == other) if (*address_of(i) == other)