From b558b4dba6532ef56fef0a230fb51346ca841976 Mon Sep 17 00:00:00 2001 From: Jelle Raaijmakers Date: Tue, 10 Jun 2025 15:11:08 +0200 Subject: [PATCH] AK: Add `Span::index_of(ReadonlySpan)` This will be used for case-sensitive substring index matches in a later commit. --- AK/Span.h | 18 ++++++++++++++++++ Tests/AK/TestSpan.cpp | 15 +++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/AK/Span.h b/AK/Span.h index 6a1644ebdf1..b7afbe59491 100644 --- a/AK/Span.h +++ b/AK/Span.h @@ -307,6 +307,24 @@ public: return { data(), size() }; } + Optional index_of(ReadonlySpan other, size_t start_offset = 0) const + { + Checked maximum_offset { start_offset }; + maximum_offset += other.size(); + if (maximum_offset.has_overflow() || maximum_offset.value() > size()) + return {}; + + if (other.is_empty()) + return start_offset; + + for (size_t index = start_offset; index <= size() - other.size(); ++index) { + if (TypedTransfer::compare(data() + index, other.data(), other.size())) + return index; + } + + return {}; + } + template Optional last_matching(TUnaryPredicate const& predicate) { diff --git a/Tests/AK/TestSpan.cpp b/Tests/AK/TestSpan.cpp index 6644d78d651..fab9cf4916d 100644 --- a/Tests/AK/TestSpan.cpp +++ b/Tests/AK/TestSpan.cpp @@ -180,3 +180,18 @@ TEST_CASE(compare_different_constness) EXPECT_EQ(array, vector.span()); } + +TEST_CASE(index_of) +{ + constexpr Array haystack { 1, 2, 3, 4, 5 }; + constexpr Array needle_1 { 2, 3, 4 }; + constexpr Array needle_2 { 2, 4 }; + constexpr Array needle_3 {}; + + EXPECT_EQ(1u, haystack.span().index_of(needle_1.span()).value()); + EXPECT(!haystack.span().index_of(needle_1.span(), 2).has_value()); + EXPECT(!haystack.span().index_of(needle_2.span()).has_value()); + EXPECT_EQ(0u, haystack.span().index_of(needle_3.span())); + EXPECT_EQ(1u, haystack.span().index_of(needle_3.span(), 1)); + EXPECT(!haystack.span().index_of(needle_3.span(), 16).has_value()); +}