diff options
author | Tim Schumacher <timschumi@gmx.de> | 2022-12-31 23:35:45 +0100 |
---|---|---|
committer | Andrew Kaster <andrewdkaster@gmail.com> | 2023-01-13 17:34:45 -0700 |
commit | d717a0800319588e012d778fca61af89ddcf8132 (patch) | |
tree | 08c980d3770fb60c2569afd5863b7d97888851f7 /AK | |
parent | afc0e461e123489808930e5433f0d8b3f95d9256 (diff) | |
download | serenity-d717a0800319588e012d778fca61af89ddcf8132.zip |
AK: Add `CircularBuffer::read_with_seekback`
Diffstat (limited to 'AK')
-rw-r--r-- | AK/CircularBuffer.cpp | 37 | ||||
-rw-r--r-- | AK/CircularBuffer.h | 6 |
2 files changed, 43 insertions, 0 deletions
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<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) { 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<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 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 {}; }; } |