summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimothy Flynn <trflynn89@pm.me>2023-01-20 07:20:01 -0500
committerTim Flynn <trflynn89@pm.me>2023-01-20 14:24:12 -0500
commitd48266a42039b801f5833e9a28634eb94eff7953 (patch)
tree71b06e42428c1e57ba5773d2efe51a2d615dcb5e
parente63477867988d2488d7493f7e716d587fde488d0 (diff)
downloadserenity-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.cpp7
-rw-r--r--AK/String.h28
-rw-r--r--Tests/AK/TestString.cpp26
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
}