diff --git a/BAN/include/BAN/Queue.h b/BAN/include/BAN/Queue.h index b230bc0a..fd6e94d5 100644 --- a/BAN/include/BAN/Queue.h +++ b/BAN/include/BAN/Queue.h @@ -2,10 +2,7 @@ #include #include -#include - -#include -#include +#include namespace BAN { @@ -14,15 +11,23 @@ namespace BAN class Queue { public: - using size_type = uint32_t; + using size_type = size_t; using value_type = T; public: Queue() = default; + Queue(Queue&&); + Queue(const Queue&); ~Queue(); - [[nodiscard]] ErrorOr Push(const T& value); + Queue& operator=(Queue&&); + Queue& operator=(const Queue&); + + [[nodiscard]] ErrorOr Push(T&&); + [[nodiscard]] ErrorOr Push(const T&); + void Pop(); + void Clear(); bool Empty() const; size_type Size() const; @@ -32,35 +37,102 @@ namespace BAN private: [[nodiscard]] ErrorOr EnsureCapacity(size_type size); + T* Address(size_type, uint8_t* = nullptr) const; private: - T* m_data = nullptr; + uint8_t* m_data = nullptr; size_type m_capacity = 0; size_type m_size = 0; }; + template + Queue::Queue(Queue&& 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 + Queue::Queue(const Queue& other) + { + MUST(EnsureCapacity(other.Size())); + for (size_type i = 0; i < other.Size(); i++) + new (Address(i)) T(*Address(i, other.m_data)); + m_size = other.m_size; + } + template Queue::~Queue() { - for (size_type i = 0; i < m_size; i++) - m_data[i].~T(); - delete[] m_data; + Clear(); + } + + template + Queue& Queue::operator=(Queue&& 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; + + return *this; + } + + template + Queue& Queue::operator=(const Queue& other) + { + Clear(); + MUST(EnsureCapacity(other.Size())); + for (size_type i = 0; i < other.Size(); i++) + new (Address(i)) T(*Address(i, other.m_data)); + m_size = other.m_size; + return *this; + } + + template + ErrorOr Queue::Push(T&& value) + { + TRY(EnsureCapacity(m_size + 1)); + new (Address(m_size)) T(Move(value)); + m_size++; + return {}; } template ErrorOr Queue::Push(const T& value) { - TRY(EnsureCapacity(m_size + 1)); - m_data[m_size++] = value; - return {}; + return Push(Move(T(value))); } template void Queue::Pop() { ASSERT(m_size > 0); - m_data->~T(); - memmove(m_data, m_data + 1, sizeof(T) * (--m_size)); + for (size_type i = 0; i < m_size - 1; i++) + *Address(i) = Move(*Address(i + 1)); + Address(m_size - 1)->~T(); + m_size--; + } + + template + void Queue::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 @@ -79,14 +151,14 @@ namespace BAN const T& Queue::Front() const { ASSERT(m_size > 0); - return *m_data; + return *Address(0); } template T& Queue::Front() { ASSERT(m_size > 0); - return *m_data; + return *Address(0); } template @@ -95,15 +167,26 @@ namespace BAN if (m_capacity > size) return {}; size_type new_cap = BAN::Math::max(size, m_capacity * 3 / 2); - T* new_data = new T[new_cap]; + uint8_t* new_data = (uint8_t*)BAN::allocator(new_cap * sizeof(T)); if (new_data == nullptr) return Error::FromString("Queue: 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_capacity = new_cap; return {}; } + template + T* Queue::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