diff --git a/AK/CircularBuffer.cpp b/AK/CircularBuffer.cpp index 71c26cd8bd..2d8b279e6b 100644 --- a/AK/CircularBuffer.cpp +++ b/AK/CircularBuffer.cpp @@ -71,6 +71,7 @@ void CircularBuffer::clear() { m_reading_head = 0; m_used_space = 0; + m_seekback_limit = 0; } Bytes CircularBuffer::next_write_span() @@ -85,6 +86,17 @@ ReadonlyBytes CircularBuffer::next_read_span() const return m_buffer.span().slice(m_reading_head, min(capacity() - m_reading_head, m_used_space)); } +ReadonlyBytes CircularBuffer::next_read_span_with_seekback(size_t distance) const +{ + VERIFY(m_seekback_limit <= capacity()); + VERIFY(distance <= m_seekback_limit); + + // Note: We are adding the capacity once here to ensure that we can wrap around the negative space by using modulo. + auto read_offset = (capacity() + m_reading_head + m_used_space - distance) % capacity(); + + return m_buffer.span().slice(read_offset, min(capacity() - read_offset, m_seekback_limit)); +} + size_t CircularBuffer::write(ReadonlyBytes bytes) { auto remaining = bytes.size(); @@ -98,6 +110,10 @@ size_t CircularBuffer::write(ReadonlyBytes bytes) m_used_space += written_bytes; + m_seekback_limit += written_bytes; + if (m_seekback_limit > capacity()) + m_seekback_limit = capacity(); + remaining -= written_bytes; } @@ -127,6 +143,27 @@ Bytes CircularBuffer::read(Bytes bytes) return bytes.trim(bytes.size() - remaining); } +ErrorOr CircularBuffer::read_with_seekback(Bytes bytes, size_t distance) +{ + if (distance > m_seekback_limit) + return Error::from_string_literal("Tried a seekback read beyond the seekback limit"); + + auto remaining = bytes.size(); + + while (remaining > 0) { + auto const next_span = next_read_span_with_seekback(distance); + if (next_span.size() == 0) + break; + + auto written_bytes = next_span.copy_trimmed_to(bytes.slice(bytes.size() - remaining)); + + distance -= written_bytes; + remaining -= written_bytes; + } + + return bytes.trim(bytes.size() - remaining); +} + ErrorOr CircularBuffer::discard(size_t discarding_size) { if (m_used_space < discarding_size) diff --git a/AK/CircularBuffer.h b/AK/CircularBuffer.h index 0f121986f4..08452d4606 100644 --- a/AK/CircularBuffer.h +++ b/AK/CircularBuffer.h @@ -42,6 +42,10 @@ public: Bytes read(Bytes bytes); ErrorOr discard(size_t discarded_bytes); + /// Compared to `read()`, this starts reading from an offset that is `distance` bytes + /// before the current write pointer and allows for reading already-read data. + ErrorOr read_with_seekback(Bytes bytes, size_t distance); + [[nodiscard]] size_t empty_space() const; [[nodiscard]] size_t used_space() const; [[nodiscard]] size_t capacity() const; @@ -57,11 +61,13 @@ private: [[nodiscard]] Bytes next_write_span(); [[nodiscard]] ReadonlyBytes next_read_span() const; + [[nodiscard]] ReadonlyBytes next_read_span_with_seekback(size_t distance) const; ByteBuffer m_buffer {}; size_t m_reading_head {}; size_t m_used_space {}; + size_t m_seekback_limit {}; }; }