diff --git a/AK/String.cpp b/AK/String.cpp index 78fe2c3dd3..4fcdd2e979 100644 --- a/AK/String.cpp +++ b/AK/String.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -328,6 +329,21 @@ Optional String::find_byte_offset(u32 code_point, size_t from_byte_offse return {}; } +Optional String::find_byte_offset(StringView substring, size_t from_byte_offset) const +{ + auto view = bytes_as_string_view(); + if (from_byte_offset >= view.length()) + return {}; + + auto index = memmem_optional( + view.characters_without_null_termination() + from_byte_offset, view.length() - from_byte_offset, + substring.characters_without_null_termination(), substring.length()); + + if (index.has_value()) + return *index + from_byte_offset; + return {}; +} + bool String::operator==(String const& other) const { if (is_short_string()) diff --git a/AK/String.h b/AK/String.h index ff72f4e35e..c59242a409 100644 --- a/AK/String.h +++ b/AK/String.h @@ -133,6 +133,7 @@ public: ErrorOr> split(u32 separator, SplitBehavior = SplitBehavior::Nothing) const; Optional find_byte_offset(u32 code_point, size_t from_byte_offset = 0) const; + Optional find_byte_offset(StringView substring, size_t from_byte_offset = 0) const; [[nodiscard]] bool operator==(String const&) const; [[nodiscard]] bool operator!=(String const& other) const { return !(*this == other); } diff --git a/Tests/AK/TestString.cpp b/Tests/AK/TestString.cpp index 86218d694d..5c1572eebc 100644 --- a/Tests/AK/TestString.cpp +++ b/Tests/AK/TestString.cpp @@ -320,8 +320,11 @@ TEST_CASE(find_byte_offset) { { String string {}; - auto index = string.find_byte_offset(0); - EXPECT(!index.has_value()); + auto index1 = string.find_byte_offset(0); + EXPECT(!index1.has_value()); + + auto index2 = string.find_byte_offset(""sv); + EXPECT(!index2.has_value()); } { auto string = MUST(String::from_utf8("foo"sv)); @@ -338,6 +341,21 @@ TEST_CASE(find_byte_offset) auto index4 = string.find_byte_offset('b'); EXPECT(!index4.has_value()); } + { + auto string = MUST(String::from_utf8("foo"sv)); + + auto index1 = string.find_byte_offset("fo"sv); + EXPECT_EQ(index1, 0u); + + auto index2 = string.find_byte_offset("oo"sv); + EXPECT_EQ(index2, 1u); + + auto index3 = string.find_byte_offset("o"sv, *index2 + 1); + EXPECT_EQ(index3, 2u); + + auto index4 = string.find_byte_offset("fooo"sv); + EXPECT(!index4.has_value()); + } { auto string = MUST(String::from_utf8("ωΣωΣω"sv)); @@ -356,6 +374,24 @@ TEST_CASE(find_byte_offset) auto index5 = string.find_byte_offset(0x03C9U, 6); EXPECT_EQ(index5, 8u); } + { + auto string = MUST(String::from_utf8("ωΣωΣω"sv)); + + auto index1 = string.find_byte_offset("ω"sv); + EXPECT_EQ(index1, 0u); + + auto index2 = string.find_byte_offset("Σ"sv); + EXPECT_EQ(index2, 2u); + + auto index3 = string.find_byte_offset("ω"sv, 2); + EXPECT_EQ(index3, 4u); + + auto index4 = string.find_byte_offset("Σ"sv, 4); + EXPECT_EQ(index4, 6u); + + auto index5 = string.find_byte_offset("ω"sv, 6); + EXPECT_EQ(index5, 8u); + } } TEST_CASE(repeated)