mirror of
https://github.com/LadybirdBrowser/ladybird
synced 2026-04-25 17:25:08 +02:00
AK: Make short ASCII string literals compile-time constants
Make the _string, _fly_string, _utf16, and _utf16_fly_string UDL operators constexpr, with a fast path for short (<= 7 byte) ASCII literals that folds directly into an inline ShortString. Previously, every "foo"_fly_string (and friends) involved an out-of-line call into the string factory, even though the result is entirely known at compile time.
This commit is contained in:
committed by
Andreas Kling
parent
7c1d359790
commit
0317007ee1
Notes:
github-actions[bot]
2026-04-17 14:24:00 +00:00
Author: https://github.com/awesomekling Commit: https://github.com/LadybirdBrowser/ladybird/commit/0317007ee10 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/8953 Reviewed-by: https://github.com/tcl3
@@ -6,6 +6,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/AllOf.h>
|
||||
#include <AK/Error.h>
|
||||
#include <AK/Format.h>
|
||||
#include <AK/Optional.h>
|
||||
@@ -25,6 +26,16 @@ public:
|
||||
|
||||
static ErrorOr<FlyString> from_utf8(StringView);
|
||||
static FlyString from_utf8_without_validation(ReadonlyBytes);
|
||||
|
||||
[[nodiscard]] static constexpr FlyString from_ascii_short_string_without_validation(char const* data, size_t length)
|
||||
{
|
||||
VERIFY(length <= Detail::MAX_SHORT_STRING_BYTE_COUNT);
|
||||
auto short_string = Detail::ShortString::create_with_byte_count(length);
|
||||
for (size_t i = 0; i < length; ++i)
|
||||
short_string.storage[i] = static_cast<u8>(data[i]);
|
||||
return FlyString { Detail::StringBase { short_string } };
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
requires(IsOneOf<RemoveCVReference<T>, ByteString, FlyString, String>)
|
||||
static ErrorOr<String> from_utf8(T&&) = delete;
|
||||
@@ -131,8 +142,14 @@ struct ASCIICaseInsensitiveFlyStringTraits : public Traits<String> {
|
||||
|
||||
}
|
||||
|
||||
[[nodiscard]] ALWAYS_INLINE AK::FlyString operator""_fly_string(char const* cstring, size_t length)
|
||||
[[nodiscard]] ALWAYS_INLINE constexpr AK::FlyString operator""_fly_string(char const* cstring, size_t length)
|
||||
{
|
||||
// OPTIMIZATION: Short ASCII strings become compile-time constants with no runtime validation or table lookup.
|
||||
if (length <= AK::Detail::MAX_SHORT_STRING_BYTE_COUNT
|
||||
&& AK::all_of(cstring, cstring + length, AK::is_ascii)) {
|
||||
return AK::FlyString::from_ascii_short_string_without_validation(cstring, length);
|
||||
}
|
||||
|
||||
ASSERT(Utf8View(AK::StringView(cstring, length)).validate());
|
||||
return AK::FlyString::from_utf8_without_validation({ cstring, length });
|
||||
}
|
||||
|
||||
18
AK/String.h
18
AK/String.h
@@ -7,6 +7,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/AllOf.h>
|
||||
#include <AK/CharacterTypes.h>
|
||||
#include <AK/Concepts.h>
|
||||
#include <AK/Format.h>
|
||||
@@ -56,6 +57,15 @@ public:
|
||||
[[nodiscard]] static String from_utf8_without_validation(ReadonlyBytes);
|
||||
[[nodiscard]] static String from_ascii_without_validation(ReadonlyBytes);
|
||||
|
||||
[[nodiscard]] static constexpr String from_ascii_short_string_without_validation(char const* data, size_t length)
|
||||
{
|
||||
VERIFY(length <= Detail::MAX_SHORT_STRING_BYTE_COUNT);
|
||||
auto short_string = Detail::ShortString::create_with_byte_count(length);
|
||||
for (size_t i = 0; i < length; ++i)
|
||||
short_string.storage[i] = static_cast<u8>(data[i]);
|
||||
return String { StringBase { short_string } };
|
||||
}
|
||||
|
||||
static ErrorOr<String> from_string_builder(Badge<StringBuilder>, StringBuilder&);
|
||||
[[nodiscard]] static String from_string_builder_without_validation(Badge<StringBuilder>, StringBuilder&);
|
||||
|
||||
@@ -266,8 +276,14 @@ struct ASCIICaseInsensitiveStringTraits : public Traits<String> {
|
||||
|
||||
}
|
||||
|
||||
[[nodiscard]] ALWAYS_INLINE AK::String operator""_string(char const* cstring, size_t length)
|
||||
[[nodiscard]] ALWAYS_INLINE constexpr AK::String operator""_string(char const* cstring, size_t length)
|
||||
{
|
||||
// OPTIMIZATION: Short ASCII strings become compile-time constants with no runtime validation or heap allocation.
|
||||
if (length <= AK::Detail::MAX_SHORT_STRING_BYTE_COUNT
|
||||
&& AK::all_of(cstring, cstring + length, AK::is_ascii)) {
|
||||
return AK::String::from_ascii_short_string_without_validation(cstring, length);
|
||||
}
|
||||
|
||||
ASSERT(Utf8View(AK::StringView(cstring, length)).validate());
|
||||
return AK::String::from_utf8_without_validation({ cstring, length });
|
||||
}
|
||||
|
||||
@@ -146,8 +146,26 @@ public:
|
||||
// This is primarily interesting to unit tests.
|
||||
[[nodiscard]] static size_t number_of_utf16_fly_strings();
|
||||
|
||||
[[nodiscard]] static constexpr Utf16FlyString from_ascii_short_string_without_validation(char const* data, size_t length)
|
||||
{
|
||||
VERIFY(length <= Detail::MAX_SHORT_STRING_BYTE_COUNT);
|
||||
auto short_string = Detail::ShortString::create_with_byte_count(length);
|
||||
for (size_t i = 0; i < length; ++i)
|
||||
short_string.storage[i] = static_cast<u8>(data[i]);
|
||||
return Utf16FlyString { Detail::Utf16StringBase { short_string } };
|
||||
}
|
||||
|
||||
[[nodiscard]] static constexpr Utf16FlyString from_ascii_short_string_without_validation(char16_t const* data, size_t length)
|
||||
{
|
||||
VERIFY(length <= Detail::MAX_SHORT_STRING_BYTE_COUNT);
|
||||
auto short_string = Detail::ShortString::create_with_byte_count(length);
|
||||
for (size_t i = 0; i < length; ++i)
|
||||
short_string.storage[i] = static_cast<u8>(data[i]);
|
||||
return Utf16FlyString { Detail::Utf16StringBase { short_string } };
|
||||
}
|
||||
|
||||
private:
|
||||
ALWAYS_INLINE explicit Utf16FlyString(Detail::Utf16StringBase data)
|
||||
ALWAYS_INLINE constexpr explicit Utf16FlyString(Detail::Utf16StringBase data)
|
||||
: m_data(move(data))
|
||||
{
|
||||
}
|
||||
@@ -202,15 +220,26 @@ inline constexpr bool IsHashCompatible<Utf16FlyString, Utf16String> = true;
|
||||
|
||||
}
|
||||
|
||||
[[nodiscard]] ALWAYS_INLINE AK::Utf16FlyString operator""_utf16_fly_string(char const* string, size_t length)
|
||||
[[nodiscard]] ALWAYS_INLINE constexpr AK::Utf16FlyString operator""_utf16_fly_string(char const* string, size_t length)
|
||||
{
|
||||
// OPTIMIZATION: Short ASCII strings become compile-time constants with no runtime validation or table lookup.
|
||||
if (length <= AK::Detail::MAX_SHORT_STRING_BYTE_COUNT
|
||||
&& AK::all_of(string, string + length, AK::is_ascii)) {
|
||||
return AK::Utf16FlyString::from_ascii_short_string_without_validation(string, length);
|
||||
}
|
||||
|
||||
AK::StringView view { string, length };
|
||||
|
||||
ASSERT(AK::Utf8View { view }.validate());
|
||||
return AK::Utf16FlyString::from_utf8_without_validation(view);
|
||||
}
|
||||
|
||||
[[nodiscard]] ALWAYS_INLINE AK::Utf16FlyString operator""_utf16_fly_string(char16_t const* string, size_t length)
|
||||
[[nodiscard]] ALWAYS_INLINE constexpr AK::Utf16FlyString operator""_utf16_fly_string(char16_t const* string, size_t length)
|
||||
{
|
||||
// OPTIMIZATION: Short ASCII strings become compile-time constants with no runtime work.
|
||||
if (length <= AK::Detail::MAX_SHORT_STRING_BYTE_COUNT
|
||||
&& AK::all_of(string, string + length, AK::is_ascii))
|
||||
return AK::Utf16FlyString::from_ascii_short_string_without_validation(string, length);
|
||||
|
||||
return AK::Utf16FlyString::from_utf16({ string, length });
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/AllOf.h>
|
||||
#include <AK/Badge.h>
|
||||
#include <AK/Error.h>
|
||||
#include <AK/Format.h>
|
||||
@@ -81,6 +82,24 @@ public:
|
||||
return Utf16String { short_string };
|
||||
}
|
||||
|
||||
[[nodiscard]] static constexpr Utf16String from_ascii_short_string_without_validation(char const* data, size_t length)
|
||||
{
|
||||
VERIFY(length <= Detail::MAX_SHORT_STRING_BYTE_COUNT);
|
||||
auto short_string = Detail::ShortString::create_with_byte_count(length);
|
||||
for (size_t i = 0; i < length; ++i)
|
||||
short_string.storage[i] = static_cast<u8>(data[i]);
|
||||
return Utf16String { short_string };
|
||||
}
|
||||
|
||||
[[nodiscard]] static constexpr Utf16String from_ascii_short_string_without_validation(char16_t const* data, size_t length)
|
||||
{
|
||||
VERIFY(length <= Detail::MAX_SHORT_STRING_BYTE_COUNT);
|
||||
auto short_string = Detail::ShortString::create_with_byte_count(length);
|
||||
for (size_t i = 0; i < length; ++i)
|
||||
short_string.storage[i] = static_cast<u8>(data[i]);
|
||||
return Utf16String { short_string };
|
||||
}
|
||||
|
||||
ALWAYS_INLINE static Utf16String from_code_point(u32 code_point)
|
||||
{
|
||||
Array<char16_t, 2> code_units;
|
||||
@@ -331,15 +350,26 @@ struct Traits<Utf16String> : public DefaultTraits<Utf16String> {
|
||||
|
||||
}
|
||||
|
||||
[[nodiscard]] ALWAYS_INLINE AK::Utf16String operator""_utf16(char const* string, size_t length)
|
||||
[[nodiscard]] ALWAYS_INLINE constexpr AK::Utf16String operator""_utf16(char const* string, size_t length)
|
||||
{
|
||||
// OPTIMIZATION: Short ASCII strings become compile-time constants with no runtime validation or heap allocation.
|
||||
if (length <= AK::Detail::MAX_SHORT_STRING_BYTE_COUNT
|
||||
&& AK::all_of(string, string + length, AK::is_ascii)) {
|
||||
return AK::Utf16String::from_ascii_short_string_without_validation(string, length);
|
||||
}
|
||||
|
||||
AK::StringView view { string, length };
|
||||
|
||||
ASSERT(AK::Utf8View { view }.validate());
|
||||
return AK::Utf16String::from_utf8_without_validation(view);
|
||||
}
|
||||
|
||||
[[nodiscard]] ALWAYS_INLINE AK::Utf16String operator""_utf16(char16_t const* string, size_t length)
|
||||
[[nodiscard]] ALWAYS_INLINE constexpr AK::Utf16String operator""_utf16(char16_t const* string, size_t length)
|
||||
{
|
||||
// OPTIMIZATION: Short ASCII strings become compile-time constants with no runtime work.
|
||||
if (length <= AK::Detail::MAX_SHORT_STRING_BYTE_COUNT
|
||||
&& AK::all_of(string, string + length, AK::is_ascii))
|
||||
return AK::Utf16String::from_ascii_short_string_without_validation(string, length);
|
||||
|
||||
return AK::Utf16String::from_utf16({ string, length });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user