1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 09:08:12 +00:00

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.
This commit is contained in:
Timothy Flynn 2023-01-20 07:20:01 -05:00 committed by Tim Flynn
parent e634778679
commit d48266a420
3 changed files with 45 additions and 16 deletions

View file

@ -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) String::String(String const& other)
: m_data(other.m_data) : m_data(other.m_data)
{ {
@ -207,7 +202,7 @@ String& String::operator=(String const& other)
return *this; return *this;
} }
String::~String() void String::destroy_string()
{ {
if (!is_short_string()) if (!is_short_string())
m_data->unref(); m_data->unref();

View file

@ -37,7 +37,11 @@ public:
String& operator=(String&&); String& operator=(String&&);
String& operator=(String const&); String& operator=(String const&);
~String(); constexpr ~String()
{
if (!is_constant_evaluated())
destroy_string();
}
// Creates an empty (zero-length) String. // Creates an empty (zero-length) String.
String(); String();
@ -45,6 +49,20 @@ public:
// Creates a new String from a sequence of UTF-8 encoded code points. // Creates a new String from a sequence of UTF-8 encoded code points.
static ErrorOr<String> from_utf8(StringView); 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. // 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_lowercase(Optional<StringView> const& locale = {}) const;
ErrorOr<String> to_uppercase(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(NonnullRefPtr<Detail::StringData>);
explicit String(ShortString);
explicit constexpr String(ShortString short_string)
: m_short_string(short_string)
{
}
void destroy_string();
union { union {
ShortString m_short_string; ShortString m_short_string;

View file

@ -34,15 +34,25 @@ TEST_CASE(move_assignment)
TEST_CASE(short_strings) TEST_CASE(short_strings)
{ {
#ifdef AK_ARCH_64_BIT #ifdef AK_ARCH_64_BIT
auto string = MUST(String::from_utf8("abcdefg"sv)); auto string1 = MUST(String::from_utf8("abcdefg"sv));
EXPECT_EQ(string.is_short_string(), true); EXPECT_EQ(string1.is_short_string(), true);
EXPECT_EQ(string.bytes().size(), 7u); EXPECT_EQ(string1.bytes().size(), 7u);
EXPECT_EQ(string.bytes_as_string_view(), "abcdefg"sv); 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 #else
auto string = MUST(String::from_utf8("abc"sv)); auto string1 = MUST(String::from_utf8("abc"sv));
EXPECT_EQ(string.is_short_string(), true); EXPECT_EQ(string1.is_short_string(), true);
EXPECT_EQ(string.bytes().size(), 3u); EXPECT_EQ(string1.bytes().size(), 3u);
EXPECT_EQ(string.bytes_as_string_view(), "abc"sv); 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 #endif
} }