#pragma once #include #include #include #include #include namespace BAN { template class Queue { public: using size_type = size_t; using value_type = T; using iterator = IteratorSimple; using const_iterator = ConstIteratorSimple; public: Queue() = default; Queue(Queue&&); Queue(const Queue&); ~Queue(); Queue& operator=(Queue&&); Queue& operator=(const Queue&); ErrorOr push(T&&); ErrorOr push(const T&); template ErrorOr emplace(Args&&...); ErrorOr reserve(size_type); ErrorOr shrink_to_fit(); iterator begin() { return iterator(m_data); } iterator end() { return iterator(m_data + m_size); } const_iterator begin() const { return const_iterator(m_data); } const_iterator end() const { return const_iterator(m_data + m_size); } void pop(); void clear(); bool empty() const; size_type size() const; const T& front() const; T& front(); private: ErrorOr ensure_capacity(size_type size); private: 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(ensure_capacity(other.size())); for (size_type i = 0; i < other.size(); i++) new (m_data + i) T(other.m_data[i]); m_size = other.m_size; } template Queue::~Queue() { 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(ensure_capacity(other.size())); for (size_type i = 0; i < other.size(); i++) new (m_data + i) T(other.m_data[i]); m_size = other.m_size; return *this; } template ErrorOr Queue::push(T&& value) { TRY(ensure_capacity(m_size + 1)); new (m_data + m_size) T(move(value)); m_size++; return {}; } template ErrorOr Queue::push(const T& value) { return push(move(T(value))); } template template ErrorOr Queue::emplace(Args&&... args) { TRY(ensure_capacity(m_size + 1)); new (m_data + m_size) T(forward(args)...); m_size++; return {}; } template ErrorOr Queue::reserve(size_type size) { TRY(ensure_capacity(size)); return {}; } template ErrorOr Queue::shrink_to_fit() { size_type temp = m_capacity; m_capacity = 0; auto error_or = ensure_capacity(m_size); if (error_or.is_error()) { m_capacity = temp; return error_or; } return {}; } template void Queue::pop() { ASSERT(m_size > 0); for (size_type i = 0; i < m_size - 1; i++) m_data[i] = move(m_data[i + 1]); m_data[m_size - 1].~T(); m_size--; } template void Queue::clear() { for (size_type i = 0; i < m_size; i++) m_data[i].~T(); BAN::deallocator(m_data); m_data = nullptr; m_capacity = 0; m_size = 0; } template bool Queue::empty() const { return m_size == 0; } template typename Queue::size_type Queue::size() const { return m_size; } template const T& Queue::front() const { ASSERT(m_size > 0); return m_data[0]; } template T& Queue::front() { ASSERT(m_size > 0); return m_data[0]; } template ErrorOr Queue::ensure_capacity(size_type size) { if (m_capacity > size) return {}; size_type new_cap = BAN::Math::max(size, m_capacity * 2); T* new_data = (T*)BAN::allocator(new_cap * sizeof(T)); if (new_data == nullptr) return Error::from_errno(ENOMEM); for (size_type i = 0; i < m_size; i++) { new (new_data + i) T(move(m_data[i])); m_data[i].~T(); } BAN::deallocator(m_data); m_data = new_data; m_capacity = new_cap; return {}; } }