#ifndef CORE_RINGBUFFER_HPP #define CORE_RINGBUFFER_HPP #include "core/utils/AlignedData.hpp" #include "core/utils/ArrayString.hpp" namespace Core { template class RingBuffer final { static_assert(N > 0, "RingBuffer size must be positive"); AlignedType data[static_cast(N)]; i64 writeIndex; i64 readIndex; i64 values; public: RingBuffer() : writeIndex(0), readIndex(0), values(0) { } RingBuffer(const RingBuffer& other) : RingBuffer() { copy(other); } RingBuffer(RingBuffer&& other) : RingBuffer() { move(Core::move(other)); other.clear(); } ~RingBuffer() { clear(); } RingBuffer& operator=(const RingBuffer& other) { if(&other != this) { clear(); copy(other); } return *this; } RingBuffer& operator=(RingBuffer&& other) { if(&other != this) { clear(); move(Core::move(other)); other.clear(); } return *this; } template check_return Error put(T*& t, Args&&... args) { if(getLength() >= N) { return Error::CAPACITY_REACHED; } t = new(data + writeIndex) T(Core::forward(args)...); writeIndex = (writeIndex + 1) % N; values++; return Error::NONE; } template check_return Error add(Args&&... args) { T* t = nullptr; return put(t, Core::forward(args)...); } T& operator[](i64 index) { return reinterpret_cast(data)[(index + readIndex) % N]; } const T& operator[](i64 index) const { return reinterpret_cast(data)[(index + readIndex) % N]; } i64 getLength() const { return values; } bool canRemove() const { return getLength() > 0; } void clear() { for(i64 i = 0; i < getLength(); i++) { (*this)[i].~T(); } writeIndex = 0; readIndex = 0; values = 0; } check_return Error remove() { if(!canRemove()) { return Error::INVALID_STATE; } values--; (*this)[0].~T(); readIndex = (readIndex + 1) % N; return Error::NONE; } template check_return Error toString(String& s) const { CORE_RETURN_ERROR(s.append("[")); i64 end = getLength(); if(end > 0) { end--; for(i64 i = 0; i < end; i++) { CORE_RETURN_ERROR(s.append((*this)[i])); CORE_RETURN_ERROR(s.append(", ")); } CORE_RETURN_ERROR(s.append((*this)[end])); } return s.append("]"); } private: void copy(const RingBuffer& other) { for(i64 i = 0; i < other.getLength(); i++) { (void)add(other[i]); } } void move(RingBuffer&& other) { for(i64 i = 0; i < other.getLength(); i++) { (void)add(Core::move(other[i])); } } }; } #endif