AK: Add CircularBuffer::read_with_seekback

This commit is contained in:
Tim Schumacher 2022-12-31 23:35:45 +01:00 committed by Andrew Kaster
parent afc0e461e1
commit d717a08003
Notes: sideshowbarker 2024-07-17 05:19:06 +09:00
2 changed files with 43 additions and 0 deletions

View file

@ -71,6 +71,7 @@ void CircularBuffer::clear()
{ {
m_reading_head = 0; m_reading_head = 0;
m_used_space = 0; m_used_space = 0;
m_seekback_limit = 0;
} }
Bytes CircularBuffer::next_write_span() 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)); 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) size_t CircularBuffer::write(ReadonlyBytes bytes)
{ {
auto remaining = bytes.size(); auto remaining = bytes.size();
@ -98,6 +110,10 @@ size_t CircularBuffer::write(ReadonlyBytes bytes)
m_used_space += written_bytes; m_used_space += written_bytes;
m_seekback_limit += written_bytes;
if (m_seekback_limit > capacity())
m_seekback_limit = capacity();
remaining -= written_bytes; remaining -= written_bytes;
} }
@ -127,6 +143,27 @@ Bytes CircularBuffer::read(Bytes bytes)
return bytes.trim(bytes.size() - remaining); return bytes.trim(bytes.size() - remaining);
} }
ErrorOr<Bytes> 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<void> CircularBuffer::discard(size_t discarding_size) ErrorOr<void> CircularBuffer::discard(size_t discarding_size)
{ {
if (m_used_space < discarding_size) if (m_used_space < discarding_size)

View file

@ -42,6 +42,10 @@ public:
Bytes read(Bytes bytes); Bytes read(Bytes bytes);
ErrorOr<void> discard(size_t discarded_bytes); ErrorOr<void> 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<Bytes> read_with_seekback(Bytes bytes, size_t distance);
[[nodiscard]] size_t empty_space() const; [[nodiscard]] size_t empty_space() const;
[[nodiscard]] size_t used_space() const; [[nodiscard]] size_t used_space() const;
[[nodiscard]] size_t capacity() const; [[nodiscard]] size_t capacity() const;
@ -57,11 +61,13 @@ private:
[[nodiscard]] Bytes next_write_span(); [[nodiscard]] Bytes next_write_span();
[[nodiscard]] ReadonlyBytes next_read_span() const; [[nodiscard]] ReadonlyBytes next_read_span() const;
[[nodiscard]] ReadonlyBytes next_read_span_with_seekback(size_t distance) const;
ByteBuffer m_buffer {}; ByteBuffer m_buffer {};
size_t m_reading_head {}; size_t m_reading_head {};
size_t m_used_space {}; size_t m_used_space {};
size_t m_seekback_limit {};
}; };
} }