summaryrefslogtreecommitdiff
path: root/AK
diff options
context:
space:
mode:
authorTim Schumacher <timschumi@gmx.de>2022-12-31 23:35:45 +0100
committerAndrew Kaster <andrewdkaster@gmail.com>2023-01-13 17:34:45 -0700
commitd717a0800319588e012d778fca61af89ddcf8132 (patch)
tree08c980d3770fb60c2569afd5863b7d97888851f7 /AK
parentafc0e461e123489808930e5433f0d8b3f95d9256 (diff)
downloadserenity-d717a0800319588e012d778fca61af89ddcf8132.zip
AK: Add `CircularBuffer::read_with_seekback`
Diffstat (limited to 'AK')
-rw-r--r--AK/CircularBuffer.cpp37
-rw-r--r--AK/CircularBuffer.h6
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 {};
};
}