From 9db9b2f9be16b4aa5da890dda081f9872b384fad Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Fri, 13 Jan 2023 11:34:00 -0500 Subject: [PATCH] AK: Add a somewhat naive implementation of String::reverse This will reverse the String's code points (i.e. not just its bytes), but is not aware of grapheme clusters. --- AK/String.cpp | 20 ++++++++++++++++++++ AK/String.h | 1 + Tests/AK/TestString.cpp | 17 +++++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/AK/String.cpp b/AK/String.cpp index 828adcdce1..ed0f8d4bb6 100644 --- a/AK/String.cpp +++ b/AK/String.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include namespace AK { @@ -319,6 +320,25 @@ ErrorOr String::replace(StringView needle, StringView replacement, Repla return StringUtils::replace(*this, needle, replacement, replace_mode); } +ErrorOr String::reverse() const +{ + // FIXME: This handles multi-byte code points, but not e.g. grapheme clusters. + // FIXME: We could avoid allocating a temporary vector if Utf8View supports reverse iteration. + auto code_point_length = code_points().length(); + + Vector code_points; + TRY(code_points.try_ensure_capacity(code_point_length)); + + for (auto code_point : this->code_points()) + code_points.unchecked_append(code_point); + + auto builder = TRY(StringBuilder::create(code_point_length * sizeof(u32))); + while (!code_points.is_empty()) + TRY(builder.try_append_code_point(code_points.take_last())); + + return builder.to_string(); +} + bool String::is_short_string() const { return has_short_string_bit(reinterpret_cast(m_data)); diff --git a/AK/String.h b/AK/String.h index 3991922aa6..7e8af38f63 100644 --- a/AK/String.h +++ b/AK/String.h @@ -69,6 +69,7 @@ public: [[nodiscard]] StringView bytes_as_string_view() const; ErrorOr replace(StringView needle, StringView replacement, ReplaceMode replace_mode) const; + ErrorOr reverse() 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 3faaa3b654..966764b941 100644 --- a/Tests/AK/TestString.cpp +++ b/Tests/AK/TestString.cpp @@ -108,6 +108,23 @@ TEST_CASE(replace) } } +TEST_CASE(reverse) +{ + auto test_reverse = [](auto test, auto expected) { + auto string = MUST(String::from_utf8(test)); + auto result = MUST(string.reverse()); + + EXPECT_EQ(result, expected); + }; + + test_reverse(""sv, ""sv); + test_reverse("a"sv, "a"sv); + test_reverse("ab"sv, "ba"sv); + test_reverse("ab cd ef"sv, "fe dc ba"sv); + test_reverse("😀"sv, "😀"sv); + test_reverse("ab😀cd"sv, "dc😀ba"sv); +} + TEST_CASE(to_lowercase) { {