mirror of
https://github.com/RGBCube/serenity
synced 2025-05-14 15:14:58 +00:00
AK: Add an optional starting offset to CircularBuffer::offset_of
This parameter allows to start searching after an offset. For example, to resume a search. It is unfortunately a breaking change in API so this patch also modifies one user and one test.
This commit is contained in:
parent
34922c0cc0
commit
9a7accddb7
4 changed files with 57 additions and 9 deletions
|
@ -52,19 +52,29 @@ bool CircularBuffer::is_wrapping_around() const
|
||||||
return capacity() <= m_reading_head + m_used_space;
|
return capacity() <= m_reading_head + m_used_space;
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<size_t> CircularBuffer::offset_of(StringView needle, Optional<size_t> until) const
|
Optional<size_t> CircularBuffer::offset_of(StringView needle, Optional<size_t> from, Optional<size_t> until) const
|
||||||
{
|
{
|
||||||
|
auto const read_from = from.value_or(0);
|
||||||
auto const read_until = until.value_or(m_used_space);
|
auto const read_until = until.value_or(m_used_space);
|
||||||
|
VERIFY(read_from <= read_until);
|
||||||
|
|
||||||
Array<ReadonlyBytes, 2> spans {};
|
Array<ReadonlyBytes, 2> spans {};
|
||||||
spans[0] = next_read_span();
|
spans[0] = next_read_span();
|
||||||
|
|
||||||
if (spans[0].size() > read_until)
|
if (read_from > 0)
|
||||||
spans[0] = spans[0].trim(read_until);
|
spans[0] = spans[0].slice(min(spans[0].size(), read_from));
|
||||||
else if (is_wrapping_around())
|
|
||||||
spans[1] = m_buffer.span().slice(0, read_until - spans[0].size());
|
|
||||||
|
|
||||||
return AK::memmem(spans.begin(), spans.end(), needle.bytes());
|
if (spans[0].size() + read_from > read_until)
|
||||||
|
spans[0] = spans[0].trim(read_until - read_from);
|
||||||
|
|
||||||
|
if (is_wrapping_around())
|
||||||
|
spans[1] = m_buffer.span().slice(max(spans[0].size(), read_from) - spans[0].size(), min(read_until, m_used_space) - spans[0].size());
|
||||||
|
|
||||||
|
auto maybe_found = AK::memmem(spans.begin(), spans.end(), needle.bytes());
|
||||||
|
if (maybe_found.has_value())
|
||||||
|
*maybe_found += read_from;
|
||||||
|
|
||||||
|
return maybe_found;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CircularBuffer::clear()
|
void CircularBuffer::clear()
|
||||||
|
|
|
@ -36,7 +36,7 @@ public:
|
||||||
[[nodiscard]] size_t used_space() const;
|
[[nodiscard]] size_t used_space() const;
|
||||||
[[nodiscard]] size_t capacity() const;
|
[[nodiscard]] size_t capacity() const;
|
||||||
|
|
||||||
Optional<size_t> offset_of(StringView needle, Optional<size_t> until = {}) const;
|
Optional<size_t> offset_of(StringView needle, Optional<size_t> from = {}, Optional<size_t> until = {}) const;
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
|
|
|
@ -272,6 +272,44 @@ TEST_CASE(offset_of)
|
||||||
EXPECT(result.has_value());
|
EXPECT(result.has_value());
|
||||||
EXPECT_EQ(result.value(), 13ul);
|
EXPECT_EQ(result.value(), 13ul);
|
||||||
|
|
||||||
result = circular_buffer.offset_of("!Well"sv, 12);
|
result = circular_buffer.offset_of("!Well"sv, {}, 12);
|
||||||
EXPECT(!result.has_value());
|
EXPECT(!result.has_value());
|
||||||
|
|
||||||
|
result = circular_buffer.offset_of("e"sv, 2);
|
||||||
|
EXPECT(result.has_value());
|
||||||
|
EXPECT_EQ(result.value(), 9ul);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE(offset_of_with_until_and_after)
|
||||||
|
{
|
||||||
|
auto const source = "Well Hello Friends!"sv;
|
||||||
|
auto byte_buffer_or_error = ByteBuffer::copy(source.bytes());
|
||||||
|
EXPECT(!byte_buffer_or_error.is_error());
|
||||||
|
auto byte_buffer = byte_buffer_or_error.release_value();
|
||||||
|
|
||||||
|
auto circular_buffer_or_error = CircularBuffer::create_initialized(byte_buffer);
|
||||||
|
EXPECT(!circular_buffer_or_error.is_error());
|
||||||
|
auto circular_buffer = circular_buffer_or_error.release_value();
|
||||||
|
|
||||||
|
auto result = circular_buffer.offset_of("Well Hello Friends!"sv, 0, 19);
|
||||||
|
EXPECT_EQ(result.value_or(42), 0ul);
|
||||||
|
|
||||||
|
result = circular_buffer.offset_of(" Hello"sv, 4, 10);
|
||||||
|
EXPECT_EQ(result.value_or(42), 4ul);
|
||||||
|
|
||||||
|
result = circular_buffer.offset_of("el"sv, 3, 10);
|
||||||
|
EXPECT_EQ(result.value_or(42), 6ul);
|
||||||
|
|
||||||
|
safe_discard(circular_buffer, 5);
|
||||||
|
auto written_bytes = circular_buffer.write(byte_buffer.span().trim(5));
|
||||||
|
EXPECT_EQ(written_bytes, 5ul);
|
||||||
|
|
||||||
|
result = circular_buffer.offset_of("Hello Friends!Well "sv, 0, 19);
|
||||||
|
EXPECT_EQ(result.value_or(42), 0ul);
|
||||||
|
|
||||||
|
result = circular_buffer.offset_of("o Frie"sv, 4, 10);
|
||||||
|
EXPECT_EQ(result.value_or(42), 4ul);
|
||||||
|
|
||||||
|
result = circular_buffer.offset_of("el"sv, 3, 14);
|
||||||
|
EXPECT_EQ(result.value_or(42), 15ul);
|
||||||
}
|
}
|
||||||
|
|
|
@ -719,7 +719,7 @@ public:
|
||||||
Optional<size_t> longest_match;
|
Optional<size_t> longest_match;
|
||||||
size_t match_size = 0;
|
size_t match_size = 0;
|
||||||
for (auto& candidate : candidates) {
|
for (auto& candidate : candidates) {
|
||||||
auto const result = m_buffer.offset_of(candidate, readable_size);
|
auto const result = m_buffer.offset_of(candidate, {}, readable_size);
|
||||||
if (result.has_value()) {
|
if (result.has_value()) {
|
||||||
auto previous_match = longest_match.value_or(*result);
|
auto previous_match = longest_match.value_or(*result);
|
||||||
if ((previous_match < *result) || (previous_match == *result && match_size < candidate.length())) {
|
if ((previous_match < *result) || (previous_match == *result && match_size < candidate.length())) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue