#pragma once #include #include #include #include #include namespace BAN { template class CircularQueue { public: using size_type = size_t; using value_type = T; public: CircularQueue() = default; ~CircularQueue(); void push(const T&); void push(T&&); template void emplace(Args&&... args); void pop(); const T& front() const; T& front(); const T& back() const; T& back(); size_type size() const { return m_size; } bool empty() const { return size() == 0; } bool full() const { return size() == capacity(); } static constexpr size_type capacity() { return S; } private: T* element_at(size_type); const T* element_at(size_type) const; private: alignas(T) uint8_t m_storage[sizeof(T) * capacity()]; size_type m_first { 0 }; size_type m_size { 0 }; }; template CircularQueue::~CircularQueue() { for (size_type i = 0; i < m_size; i++) element_at((m_first + i) % capacity())->~T(); } template void CircularQueue::push(const T& value) { emplace(BAN::move(T(value))); } template void CircularQueue::push(T&& value) { emplace(BAN::move(value)); } template template void CircularQueue::emplace(Args&&... args) { ASSERT(!full()); new (element_at(((m_first + m_size) % capacity()))) T(BAN::forward(args)...); m_size++; } template void CircularQueue::pop() { ASSERT(!empty()); element_at(m_first)->~T(); m_first = (m_first + 1) % capacity(); m_size--; } template const T& CircularQueue::front() const { ASSERT(!empty()); return *element_at(m_first); } template T& CircularQueue::front() { ASSERT(!empty()); return *element_at(m_first); } template const T& CircularQueue::back() const { ASSERT(!empty()); return *element_at((m_first + m_size - 1) % capacity()); } template T& CircularQueue::back() { ASSERT(!empty()); return *element_at((m_first + m_size - 1) % capacity()); } template const T* CircularQueue::element_at(size_type index) const { ASSERT(index < capacity()); return (const T*)(m_storage + index * sizeof(T)); } template T* CircularQueue::element_at(size_type index) { ASSERT(index < capacity()); return (T*)(m_storage + index * sizeof(T)); } }