diff --git a/AK/Utf16View.cpp b/AK/Utf16View.cpp index 5c0b4c76005..1a5c019fb45 100644 --- a/AK/Utf16View.cpp +++ b/AK/Utf16View.cpp @@ -213,6 +213,25 @@ Utf16View Utf16View::unicode_substring_view(size_t code_point_offset, size_t cod VERIFY_NOT_REACHED(); } +bool Utf16View::starts_with(Utf16View const& needle) const +{ + if (needle.is_empty()) + return true; + if (is_empty()) + return false; + if (needle.length_in_code_units() > length_in_code_units()) + return false; + if (begin_ptr() == needle.begin_ptr()) + return true; + + for (auto this_it = begin(), needle_it = needle.begin(); needle_it != needle.end(); ++needle_it, ++this_it) { + if (*this_it != *needle_it) + return false; + } + + return true; +} + bool Utf16View::validate(size_t& valid_code_units) const { valid_code_units = 0; diff --git a/AK/Utf16View.h b/AK/Utf16View.h index 66668c75009..5d10b9a7b88 100644 --- a/AK/Utf16View.h +++ b/AK/Utf16View.h @@ -111,6 +111,8 @@ public: Utf16View unicode_substring_view(size_t code_point_offset, size_t code_point_length) const; Utf16View unicode_substring_view(size_t code_point_offset) const { return unicode_substring_view(code_point_offset, length_in_code_points() - code_point_offset); } + bool starts_with(Utf16View const&) const; + bool validate(size_t& valid_code_units) const; bool validate() const { diff --git a/Tests/AK/TestUtf16.cpp b/Tests/AK/TestUtf16.cpp index d6418c4d5d1..fef4082818e 100644 --- a/Tests/AK/TestUtf16.cpp +++ b/Tests/AK/TestUtf16.cpp @@ -310,3 +310,29 @@ TEST_CASE(substring_view) EXPECT_EQ(MUST(view.to_utf8(Utf16View::AllowInvalidCodeUnits::No)), "\ufffd"sv); } } + +TEST_CASE(starts_with) +{ + EXPECT(Utf16View {}.starts_with(u"")); + EXPECT(!Utf16View {}.starts_with(u" ")); + + EXPECT(Utf16View { u"a" }.starts_with(u"")); + EXPECT(Utf16View { u"a" }.starts_with(u"a")); + EXPECT(!Utf16View { u"a" }.starts_with(u"b")); + EXPECT(!Utf16View { u"a" }.starts_with(u"ab")); + + EXPECT(Utf16View { u"abc" }.starts_with(u"")); + EXPECT(Utf16View { u"abc" }.starts_with(u"a")); + EXPECT(Utf16View { u"abc" }.starts_with(u"ab")); + EXPECT(Utf16View { u"abc" }.starts_with(u"abc")); + EXPECT(!Utf16View { u"abc" }.starts_with(u"b")); + EXPECT(!Utf16View { u"abc" }.starts_with(u"bc")); + + auto emoji = Utf16View { u"😀🙃" }; + + EXPECT(emoji.starts_with(u"")); + EXPECT(emoji.starts_with(u"😀")); + EXPECT(emoji.starts_with(u"😀🙃")); + EXPECT(!emoji.starts_with(u"a")); + EXPECT(!emoji.starts_with(u"🙃")); +}