diff --git a/AK/Utf16View.h b/AK/Utf16View.h index 751c8a49bca..93c60b4b3fc 100644 --- a/AK/Utf16View.h +++ b/AK/Utf16View.h @@ -425,6 +425,15 @@ public: return it.m_iterator.utf16 - m_string.utf16; } + [[nodiscard]] constexpr Utf16CodePointIterator iterator_at_code_unit_offset(size_t code_unit_offset) const + { + VERIFY(code_unit_offset <= length_in_code_units()); + + if (has_ascii_storage()) + return { m_string.ascii + code_unit_offset, length_in_code_units() - code_unit_offset }; + return { m_string.utf16 + code_unit_offset, length_in_code_units() - code_unit_offset }; + } + Utf16String replace(Utf16View const& needle, Utf16View const& replacement, ReplaceMode) const; Utf16String escape_html_entities() const; diff --git a/Tests/AK/TestUtf16View.cpp b/Tests/AK/TestUtf16View.cpp index 99562ae657c..b621143c7c0 100644 --- a/Tests/AK/TestUtf16View.cpp +++ b/Tests/AK/TestUtf16View.cpp @@ -571,6 +571,18 @@ TEST_CASE(iterator_offset) EXPECT_EQ(view.iterator_offset(view.end()), view.length_in_code_units()); } +TEST_CASE(iterator_at_code_unit_offset) +{ + Utf16View view { u"😂 foo 😀 bar"sv }; + + for (size_t i = 0; i < view.length_in_code_units(); ++i) { + auto it = view.iterator_at_code_unit_offset(i); + EXPECT_EQ(*it, view.code_point_at(i)); + } + + EXPECT_EQ(view.iterator_at_code_unit_offset(view.length_in_code_units()), view.end()); +} + TEST_CASE(replace) { auto result = u""sv.replace({}, {}, ReplaceMode::FirstOnly);