AK: Add search-related helpers to CircularBuffer

This factors out a lot of complicated math into somewhat understandable
functions.

While at it, rename `next_read_span_with_seekback` to
`next_seekback_span` to keep the naming consistent and to avoid making
function names any longer.
This commit is contained in:
Tim Schumacher 2023-06-02 00:01:15 +02:00 committed by Linus Groh
parent d12036132e
commit 2109f61b0d
Notes: sideshowbarker 2024-07-17 02:55:44 +09:00
2 changed files with 29 additions and 11 deletions

View File

@ -53,6 +53,11 @@ size_t CircularBuffer::seekback_limit() const
return m_seekback_limit;
}
size_t SearchableCircularBuffer::search_limit() const
{
return m_seekback_limit - m_used_space;
}
bool CircularBuffer::is_wrapping_around() const
{
return capacity() <= m_reading_head + m_used_space;
@ -113,7 +118,7 @@ ReadonlyBytes CircularBuffer::next_read_span(size_t offset) const
return m_buffer.span().slice(reading_head, min(capacity() - reading_head, used_space));
}
ReadonlyBytes CircularBuffer::next_read_span_with_seekback(size_t distance) const
ReadonlyBytes CircularBuffer::next_seekback_span(size_t distance) const
{
VERIFY(m_seekback_limit <= capacity());
VERIFY(distance <= m_seekback_limit);
@ -124,6 +129,17 @@ ReadonlyBytes CircularBuffer::next_read_span_with_seekback(size_t distance) cons
return m_buffer.span().slice(read_offset, min(capacity() - read_offset, distance));
}
ReadonlyBytes SearchableCircularBuffer::next_search_span(size_t distance) const
{
VERIFY(search_limit() <= capacity());
VERIFY(distance <= search_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 - distance) % capacity();
return m_buffer.span().slice(read_offset, min(capacity() - read_offset, distance));
}
size_t CircularBuffer::write(ReadonlyBytes bytes)
{
auto remaining = bytes.size();
@ -178,7 +194,7 @@ ErrorOr<Bytes> CircularBuffer::read_with_seekback(Bytes bytes, size_t distance)
auto remaining = bytes.size();
while (remaining > 0) {
auto const next_span = next_read_span_with_seekback(distance);
auto const next_span = next_seekback_span(distance);
if (next_span.size() == 0)
break;
@ -244,7 +260,7 @@ ErrorOr<size_t> CircularBuffer::copy_from_seekback(size_t distance, size_t lengt
if (empty_space() == 0)
break;
auto next_span = next_read_span_with_seekback(distance);
auto next_span = next_seekback_span(distance);
if (next_span.size() == 0)
break;
@ -297,15 +313,11 @@ ErrorOr<Vector<SearchableCircularBuffer::Match>> SearchableCircularBuffer::find_
Vector<Match> matches;
// Use memmem to find the initial matches.
// Note: We have the read head as our reference point, but `next_read_span_with_seekback` isn't aware of that and continues to use the write head.
// Therefore, we need to make sure to slice off the extraneous bytes from the end of the span and shift the returned distances by the correct amount.
size_t haystack_offset_from_start = 0;
Vector<ReadonlyBytes, 2> haystack;
haystack.append(next_read_span_with_seekback(m_seekback_limit));
if (haystack[0].size() < m_seekback_limit - used_space())
haystack.append(next_read_span_with_seekback(m_seekback_limit - haystack[0].size()));
haystack.last() = haystack.last().trim(haystack.last().size() - used_space());
haystack.append(next_search_span(search_limit()));
if (haystack[0].size() < search_limit())
haystack.append(next_search_span(search_limit() - haystack[0].size()));
auto needle = next_read_span().trim(minimum_length);

View File

@ -51,7 +51,7 @@ protected:
[[nodiscard]] Bytes next_write_span();
[[nodiscard]] ReadonlyBytes next_read_span(size_t offset = 0) const;
[[nodiscard]] ReadonlyBytes next_read_span_with_seekback(size_t distance) const;
[[nodiscard]] ReadonlyBytes next_seekback_span(size_t distance) const;
ByteBuffer m_buffer {};
@ -65,6 +65,8 @@ public:
static ErrorOr<SearchableCircularBuffer> create_empty(size_t size);
static ErrorOr<SearchableCircularBuffer> create_initialized(ByteBuffer);
[[nodiscard]] size_t search_limit() const;
struct Match {
size_t distance;
size_t length;
@ -76,6 +78,10 @@ public:
ErrorOr<Vector<Match>> find_copy_in_seekback(Vector<size_t> const& distances, size_t maximum_length, size_t minimum_length = 2) const;
private:
// Note: This function has a similar purpose as next_seekback_span, but they differ in their reference point.
// Seekback operations start counting their distance at the write head, while search operations start counting their distance at the read head.
[[nodiscard]] ReadonlyBytes next_search_span(size_t distance) const;
SearchableCircularBuffer(ByteBuffer);
};