diff --git a/AK/Utf16View.cpp b/AK/Utf16View.cpp index 995eee1754b..6f0f4677714 100644 --- a/AK/Utf16View.cpp +++ b/AK/Utf16View.cpp @@ -208,11 +208,10 @@ size_t Utf16View::code_point_offset_of(size_t code_unit_offset) const size_t code_point_offset = 0; - for (auto it = begin(); it != end(); ++it) { - if (code_unit_offset == 0) - return code_point_offset; - - code_unit_offset -= it.length_in_code_units(); + for (auto it = begin(); it != end();) { + // We know the view is using UTF-16 storage because ASCII storage would have returned early above. + if ((++it).m_iterator.utf16 > m_string.utf16 + code_unit_offset) + break; ++code_point_offset; } diff --git a/AK/Utf16View.h b/AK/Utf16View.h index 5bf79edbc9d..aa5606b91ee 100644 --- a/AK/Utf16View.h +++ b/AK/Utf16View.h @@ -106,6 +106,8 @@ public: } private: + friend Utf16View; + constexpr Utf16CodePointIterator(char const* iterator, size_t length) : m_iterator { .ascii = iterator } , m_remaining_code_units(length) diff --git a/Tests/AK/TestUtf16View.cpp b/Tests/AK/TestUtf16View.cpp index 99d34e296d8..0b50522a5ac 100644 --- a/Tests/AK/TestUtf16View.cpp +++ b/Tests/AK/TestUtf16View.cpp @@ -402,6 +402,26 @@ TEST_CASE(code_unit_offset_of) EXPECT_EQ(view.code_unit_offset_of(11), 13uz); } +TEST_CASE(code_point_offset_of) +{ + Utf16View view { u"😂 foo 😀 bar"sv }; + + EXPECT_EQ(view.code_point_offset_of(0), 0uz); + EXPECT_EQ(view.code_point_offset_of(1), 0uz); + EXPECT_EQ(view.code_point_offset_of(2), 1uz); + EXPECT_EQ(view.code_point_offset_of(3), 2uz); + EXPECT_EQ(view.code_point_offset_of(4), 3uz); + EXPECT_EQ(view.code_point_offset_of(5), 4uz); + EXPECT_EQ(view.code_point_offset_of(6), 5uz); + EXPECT_EQ(view.code_point_offset_of(7), 6uz); + EXPECT_EQ(view.code_point_offset_of(8), 6uz); + EXPECT_EQ(view.code_point_offset_of(9), 7uz); + EXPECT_EQ(view.code_point_offset_of(10), 8uz); + EXPECT_EQ(view.code_point_offset_of(11), 9uz); + EXPECT_EQ(view.code_point_offset_of(12), 10uz); + EXPECT_EQ(view.code_point_offset_of(13), 11uz); +} + TEST_CASE(replace) { auto result = u""sv.replace({}, {}, ReplaceMode::FirstOnly);