diff options
author | Timothy Flynn <trflynn89@pm.me> | 2023-01-20 07:20:01 -0500 |
---|---|---|
committer | Tim Flynn <trflynn89@pm.me> | 2023-01-20 14:24:12 -0500 |
commit | d48266a42039b801f5833e9a28634eb94eff7953 (patch) | |
tree | 71b06e42428c1e57ba5773d2efe51a2d615dcb5e | |
parent | e63477867988d2488d7493f7e716d587fde488d0 (diff) | |
download | serenity-d48266a42039b801f5833e9a28634eb94eff7953.zip |
AK: Support creating known short string literals at compile time
In cases where we know a string literal will fit in the short string
storage, we can do so at compile time without needing to handle error
propagation. If the provided string literal is too long, a compilation
error will be emitted due to the failed VERIFY statement being a non-
constant expression.
-rw-r--r-- | AK/String.cpp | 7 | ||||
-rw-r--r-- | AK/String.h | 28 | ||||
-rw-r--r-- | Tests/AK/TestString.cpp | 26 |
3 files changed, 45 insertions, 16 deletions
diff --git a/AK/String.cpp b/AK/String.cpp index 88a3c5d4fb..f480f73d7d 100644 --- a/AK/String.cpp +++ b/AK/String.cpp @@ -169,11 +169,6 @@ String::String(NonnullRefPtr<Detail::StringData> data) { } -String::String(ShortString short_string) - : m_short_string(short_string) -{ -} - String::String(String const& other) : m_data(other.m_data) { @@ -207,7 +202,7 @@ String& String::operator=(String const& other) return *this; } -String::~String() +void String::destroy_string() { if (!is_short_string()) m_data->unref(); diff --git a/AK/String.h b/AK/String.h index 7bcf722a47..72e0d83731 100644 --- a/AK/String.h +++ b/AK/String.h @@ -37,7 +37,11 @@ public: String& operator=(String&&); String& operator=(String const&); - ~String(); + constexpr ~String() + { + if (!is_constant_evaluated()) + destroy_string(); + } // Creates an empty (zero-length) String. String(); @@ -45,6 +49,20 @@ public: // Creates a new String from a sequence of UTF-8 encoded code points. static ErrorOr<String> from_utf8(StringView); + // Creates a new String from a short sequence of UTF-8 encoded code points. If the provided string + // does not fit in the short string storage, a compilation error will be emitted. + static consteval String from_utf8_short_string(StringView string) + { + VERIFY(string.length() <= MAX_SHORT_STRING_BYTE_COUNT); + + ShortString short_string; + for (size_t i = 0; i < string.length(); ++i) + short_string.storage[i] = string.characters_without_null_termination()[i]; + short_string.byte_count_and_short_string_flag = (string.length() << 1) | SHORT_STRING_FLAG; + + return String { short_string }; + } + // Creates a new String by case-transforming this String. Using these methods require linking LibUnicode into your application. ErrorOr<String> to_lowercase(Optional<StringView> const& locale = {}) const; ErrorOr<String> to_uppercase(Optional<StringView> const& locale = {}) const; @@ -160,7 +178,13 @@ private: }; explicit String(NonnullRefPtr<Detail::StringData>); - explicit String(ShortString); + + explicit constexpr String(ShortString short_string) + : m_short_string(short_string) + { + } + + void destroy_string(); union { ShortString m_short_string; diff --git a/Tests/AK/TestString.cpp b/Tests/AK/TestString.cpp index d78854b626..c089cfcf72 100644 --- a/Tests/AK/TestString.cpp +++ b/Tests/AK/TestString.cpp @@ -34,15 +34,25 @@ TEST_CASE(move_assignment) TEST_CASE(short_strings) { #ifdef AK_ARCH_64_BIT - auto string = MUST(String::from_utf8("abcdefg"sv)); - EXPECT_EQ(string.is_short_string(), true); - EXPECT_EQ(string.bytes().size(), 7u); - EXPECT_EQ(string.bytes_as_string_view(), "abcdefg"sv); + auto string1 = MUST(String::from_utf8("abcdefg"sv)); + EXPECT_EQ(string1.is_short_string(), true); + EXPECT_EQ(string1.bytes().size(), 7u); + EXPECT_EQ(string1.bytes_as_string_view(), "abcdefg"sv); + + constexpr auto string2 = String::from_utf8_short_string("abcdefg"sv); + EXPECT_EQ(string2.is_short_string(), true); + EXPECT_EQ(string2.bytes().size(), 7u); + EXPECT_EQ(string2, string1); #else - auto string = MUST(String::from_utf8("abc"sv)); - EXPECT_EQ(string.is_short_string(), true); - EXPECT_EQ(string.bytes().size(), 3u); - EXPECT_EQ(string.bytes_as_string_view(), "abc"sv); + auto string1 = MUST(String::from_utf8("abc"sv)); + EXPECT_EQ(string1.is_short_string(), true); + EXPECT_EQ(string1.bytes().size(), 3u); + EXPECT_EQ(string1.bytes_as_string_view(), "abc"sv); + + constexpr auto string2 = String::from_utf8_short_string("abc"sv); + EXPECT_EQ(string2.is_short_string(), true); + EXPECT_EQ(string2.bytes().size(), 3u); + EXPECT_EQ(string2, string1); #endif } |