// SPDX-License-Identifier: BSD-2-Clause // author: Max Kellermann #ifndef DYNAMIC_FIFO_BUFFER_HXX #define DYNAMIC_FIFO_BUFFER_HXX #include "ForeignFifoBuffer.hxx" /** * A first-in-first-out buffer: you can append data at the end, and * read data from the beginning. This class automatically shifts the * buffer as needed. It is not thread safe. */ template class DynamicFifoBuffer : protected ForeignFifoBuffer { public: using typename ForeignFifoBuffer::size_type; using typename ForeignFifoBuffer::pointer; using typename ForeignFifoBuffer::const_pointer; using typename ForeignFifoBuffer::Range; /** * Construct without allocating a buffer. */ explicit constexpr DynamicFifoBuffer(std::nullptr_t n) noexcept :ForeignFifoBuffer(n) {} /** * Allocate a buffer with the given capacity. */ explicit DynamicFifoBuffer(size_type _capacity) noexcept :ForeignFifoBuffer(new T[_capacity], _capacity) {} ~DynamicFifoBuffer() noexcept { delete[] GetBuffer(); } DynamicFifoBuffer(const DynamicFifoBuffer &) = delete; using ForeignFifoBuffer::GetCapacity; using ForeignFifoBuffer::Clear; using ForeignFifoBuffer::empty; using ForeignFifoBuffer::IsFull; using ForeignFifoBuffer::GetAvailable; using ForeignFifoBuffer::Read; using ForeignFifoBuffer::Consume; using ForeignFifoBuffer::Write; using ForeignFifoBuffer::Append; void Grow(size_type new_capacity) noexcept { assert(new_capacity > GetCapacity()); T *old_data = GetBuffer(); T *new_data = new T[new_capacity]; ForeignFifoBuffer::MoveBuffer(new_data, new_capacity); delete[] old_data; } void WantWrite(size_type n) noexcept { if (ForeignFifoBuffer::WantWrite(n)) /* we already have enough space */ return; const size_type in_use = GetAvailable(); const size_type required_capacity = in_use + n; size_type new_capacity = GetCapacity(); do { new_capacity <<= 1; } while (new_capacity < required_capacity); Grow(new_capacity); } /** * Write data to the buffer, growing it as needed. Returns a * writable pointer. */ pointer Write(size_type n) noexcept { WantWrite(n); return Write().data(); } /** * Append data to the buffer, growing it as needed. */ void Append(std::span src) noexcept { std::copy(src.begin(), src.end(), Write(src.size())); Append(src.size()); } protected: using ForeignFifoBuffer::GetBuffer; }; #endif