diff --git a/BAN/include/BAN/Vector.h b/BAN/include/BAN/Vector.h index 4b701f70b..ac5faa118 100644 --- a/BAN/include/BAN/Vector.h +++ b/BAN/include/BAN/Vector.h @@ -2,13 +2,12 @@ #include #include -#include - -#include +#include namespace BAN { + // T must be move assignable, move constructable (and copy constructable for some functions) template class Vector { @@ -18,14 +17,21 @@ namespace BAN public: Vector() = default; + Vector(Vector&&); Vector(const Vector&); ~Vector(); + Vector& operator=(Vector&&); + Vector& operator=(const Vector&); + + [[nodiscard]] ErrorOr PushBack(T&&); [[nodiscard]] ErrorOr PushBack(const T&); + [[nodiscard]] ErrorOr Insert(T&&, size_type); [[nodiscard]] ErrorOr Insert(const T&, size_type); void PopBack(); void Remove(size_type); + void Clear(); bool Has(const T&) const; @@ -42,39 +48,97 @@ namespace BAN bool Empty() const; size_type Size() const; - size_type Capasity() const; + size_type Capacity() const; private: + T* Address(size_type, uint8_t* = nullptr) const; [[nodiscard]] ErrorOr EnsureCapasity(size_type); private: - T* m_data = nullptr; - size_type m_capasity = 0; + uint8_t* m_data = nullptr; + size_type m_capacity = 0; size_type m_size = 0; }; + template + Vector::Vector(Vector&& other) + { + m_data = other.m_data; + m_capacity = other.m_capacity; + m_size = other.m_size; + + other.m_data = nullptr; + other.m_capacity = 0; + other.m_size = 0; + } + template Vector::Vector(const Vector& other) { MUST(EnsureCapasity(other.m_size)); for (size_type i = 0; i < other.m_size; i++) - m_data[i] = other[i]; + new (Address(i)) T(other[i]); m_size = other.m_size; } template Vector::~Vector() { - for (size_type i = 0; i < m_size; i++) - m_data[i].~T(); - delete[] m_data; + Clear(); + } + + template + Vector& Vector::operator=(Vector&& other) + { + Clear(); + + m_data = other.m_data; + m_capacity = other.m_capacity; + m_size = other.m_size; + + other.m_data = nullptr; + other.m_capacity = 0; + other.m_size = 0; + } + + template + Vector& Vector::operator=(const Vector& other) + { + Clear(); + MUST(EnsureCapasity(other.Size())); + for (size_type i = 0; i < other.Size(); i++) + new (Address(i)) T(other[i]); + m_size = other.m_size; + return *this; + } + + template + ErrorOr Vector::PushBack(T&& value) + { + TRY(EnsureCapasity(m_size + 1)); + new (Address(m_size)) T(Move(value)); + m_size++; + return {}; } template ErrorOr Vector::PushBack(const T& value) { + return PushBack(Move(T(value))); + } + + template + ErrorOr Vector::Insert(T&& value, size_type index) + { + ASSERT(index <= m_size); TRY(EnsureCapasity(m_size + 1)); - m_data[m_size] = value; + if (index < m_size) + { + new (Address(m_size)) T(Move(*Address(m_size - 1))); + for (size_type i = m_size - 1; i > index; i--) + *Address(i) = Move(*Address(i - 1)); + } + *Address(index) = Move(value); m_size++; return {}; } @@ -82,19 +146,14 @@ namespace BAN template ErrorOr Vector::Insert(const T& value, size_type index) { - ASSERT(index <= m_size); - TRY(EnsureCapasity(m_size + 1)); - memmove(m_data + index + 1, m_data + index, (m_size - index) * sizeof(T)); - m_data[index] = value; - m_size++; - return {}; + return Insert(Move(T(value)), index); } template void Vector::PopBack() { ASSERT(m_size > 0); - m_data[m_size - 1].~T(); + Address(m_size - 1)->~T(); m_size--; } @@ -102,16 +161,28 @@ namespace BAN void Vector::Remove(size_type index) { ASSERT(index < m_size); - m_data[index].~T(); - memmove(m_data + index, m_data + index + 1, (m_size - index - 1) * sizeof(T)); + for (size_type i = index; i < m_size - 1; i++) + *Address(i) = Move(*Address(i + 1)); + Address(m_size - 1)->~T(); m_size--; } + template + void Vector::Clear() + { + for (size_type i = 0; i < m_size; i++) + Address(i)->~T(); + BAN::deallocator(m_data); + m_data = nullptr; + m_capacity = 0; + m_size = 0; + } + template bool Vector::Has(const T& other) const { for (size_type i = 0; i < m_size; i++) - if (m_data[i] == other) + if (*Address(i) == other) return true; return false; } @@ -120,59 +191,53 @@ namespace BAN const T& Vector::operator[](size_type index) const { ASSERT(index < m_size); - return m_data[index]; + return *Address(index); } template T& Vector::operator[](size_type index) { ASSERT(index < m_size); - return m_data[index]; + return *Address(index); } template const T& Vector::Back() const { ASSERT(m_size > 0); - return m_data[m_size - 1]; + return *Address(m_size - 1); } template T& Vector::Back() { ASSERT(m_size > 0); - return m_data[m_size - 1]; + return *Address(m_size - 1); } template const T& Vector::Front() const { ASSERT(m_size > 0); - return m_data[0]; + return *Address(0); } template T& Vector::Front() { ASSERT(m_size > 0); - return m_data[0]; + return *Address(0); } template ErrorOr Vector::Resize(size_type size) { + TRY(EnsureCapasity(size)); if (size < m_size) - { for (size_type i = size; i < m_size; i++) - m_data[i].~T(); - m_size = size; - } - else if (size > m_size) - { - TRY(EnsureCapasity(size)); + Address(i)->~T(); + if (size > m_size) for (size_type i = m_size; i < size; i++) - m_data[i] = T(); - m_size = size; - } + new (Address(i)) T(); m_size = size; return {}; } @@ -197,26 +262,37 @@ namespace BAN } template - typename Vector::size_type Vector::Capasity() const + typename Vector::size_type Vector::Capacity() const { - return m_capasity; + return m_capacity; } template ErrorOr Vector::EnsureCapasity(size_type size) { - if (m_capasity >= size) + if (m_capacity >= size) return {}; - size_type new_cap = BAN::Math::max(size, m_capasity * 3 / 2); - T* new_data = new T[new_cap]; + size_type new_cap = BAN::Math::max(size, m_capacity * 3 / 2); + uint8_t* new_data = (uint8_t*)BAN::allocator(new_cap * sizeof(T)); if (new_data == nullptr) return Error::FromString("Vector: Could not allocate memory"); - if (m_data) - memcpy(new_data, m_data, m_size * sizeof(T)); - delete[] m_data; + for (size_type i = 0; i < m_size; i++) + { + new (Address(i, new_data)) T(Move(*Address(i))); + Address(i)->~T(); + } + BAN::deallocator(m_data); m_data = new_data; - m_capasity = new_cap; + m_capacity = new_cap; return {}; } + template + T* Vector::Address(size_type index, uint8_t* base) const + { + if (base == nullptr) + base = m_data; + return (T*)(base + index * sizeof(T)); + } + } \ No newline at end of file