diff --git a/AK/CircularBuffer.cpp b/AK/CircularBuffer.cpp index dbb57fc495d..9f011d741f3 100644 --- a/AK/CircularBuffer.cpp +++ b/AK/CircularBuffer.cpp @@ -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 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 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> SearchableCircularBuffer::find_ Vector 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 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); diff --git a/AK/CircularBuffer.h b/AK/CircularBuffer.h index 962e2a19c9b..f535b9c72c2 100644 --- a/AK/CircularBuffer.h +++ b/AK/CircularBuffer.h @@ -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 create_empty(size_t size); static ErrorOr create_initialized(ByteBuffer); + [[nodiscard]] size_t search_limit() const; + struct Match { size_t distance; size_t length; @@ -76,6 +78,10 @@ public: ErrorOr> find_copy_in_seekback(Vector 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); };