AK: Extract some StringBase helpers for use in an outside class

This commit is contained in:
Timothy Flynn 2025-06-12 19:08:09 -04:00 committed by Tim Flynn
commit 5720d626ce
Notes: github-actions[bot] 2025-07-03 13:54:06 +00:00

View file

@ -14,6 +14,9 @@
namespace AK::Detail { namespace AK::Detail {
struct ShortString { struct ShortString {
static constexpr ShortString create_empty();
static constexpr ShortString create_with_byte_count(size_t byte_count);
ReadonlyBytes bytes() const; ReadonlyBytes bytes() const;
size_t byte_count() const; size_t byte_count() const;
@ -31,9 +34,13 @@ static_assert(sizeof(ShortString) == sizeof(StringData*));
class StringBase { class StringBase {
public: public:
// NOTE: If the least significant bit of the pointer is set, this is a short string.
static constexpr uintptr_t SHORT_STRING_FLAG = 1;
static constexpr unsigned SHORT_STRING_BYTE_COUNT_SHIFT_COUNT = 2;
// Creates an empty (zero-length) String. // Creates an empty (zero-length) String.
constexpr StringBase() constexpr StringBase()
: StringBase(ShortString { .byte_count_and_short_string_flag = SHORT_STRING_FLAG }) : StringBase(ShortString::create_empty())
{ {
} }
@ -42,7 +49,7 @@ public:
constexpr StringBase(StringBase&& other) constexpr StringBase(StringBase&& other)
: m_impl(other.m_impl) : m_impl(other.m_impl)
{ {
other.m_impl = { .short_string = { .byte_count_and_short_string_flag = SHORT_STRING_FLAG } }; other.m_impl = { .short_string = ShortString::create_empty() };
} }
StringBase& operator=(StringBase&&); StringBase& operator=(StringBase&&);
@ -108,10 +115,6 @@ private:
friend class ::AK::FlyString; friend class ::AK::FlyString;
friend struct ::AK::Detail::ShortString; friend struct ::AK::Detail::ShortString;
// NOTE: If the least significant bit of the pointer is set, this is a short string.
static constexpr uintptr_t SHORT_STRING_FLAG = 1;
static constexpr unsigned SHORT_STRING_BYTE_COUNT_SHIFT_COUNT = 2;
explicit StringBase(NonnullRefPtr<Detail::StringData const>); explicit StringBase(NonnullRefPtr<Detail::StringData const>);
explicit constexpr StringBase(nullptr_t) explicit constexpr StringBase(nullptr_t)
@ -131,8 +134,7 @@ private:
VERIFY(is_short_string()); VERIFY(is_short_string());
VERIFY(byte_count <= MAX_SHORT_STRING_BYTE_COUNT); VERIFY(byte_count <= MAX_SHORT_STRING_BYTE_COUNT);
m_impl = { .short_string = {} }; m_impl = { .short_string = ShortString::create_with_byte_count(byte_count) };
m_impl.short_string.byte_count_and_short_string_flag = (byte_count << SHORT_STRING_BYTE_COUNT_SHIFT_COUNT) | SHORT_STRING_FLAG;
return { m_impl.short_string.storage, byte_count }; return { m_impl.short_string.storage, byte_count };
} }
@ -172,6 +174,19 @@ private:
} m_impl; } m_impl;
}; };
constexpr ShortString ShortString::create_empty()
{
return create_with_byte_count(0);
}
constexpr ShortString ShortString::create_with_byte_count(size_t byte_count)
{
ShortString string {};
string.byte_count_and_short_string_flag = (byte_count << StringBase::SHORT_STRING_BYTE_COUNT_SHIFT_COUNT) | StringBase::SHORT_STRING_FLAG;
return string;
}
inline ReadonlyBytes ShortString::bytes() const inline ReadonlyBytes ShortString::bytes() const
{ {
return { storage, byte_count() }; return { storage, byte_count() };
@ -205,7 +220,7 @@ inline u32 StringBase::hash() const
inline size_t StringBase::byte_count() const inline size_t StringBase::byte_count() const
{ {
if (is_short_string()) if (is_short_string())
return m_impl.short_string.byte_count_and_short_string_flag >> StringBase::SHORT_STRING_BYTE_COUNT_SHIFT_COUNT; return m_impl.short_string.byte_count();
if (!m_impl.data) if (!m_impl.data)
return 0; return 0;
@ -235,7 +250,7 @@ inline StringBase& StringBase::operator=(StringBase&& other)
if (!is_short_string() && m_impl.data) if (!is_short_string() && m_impl.data)
data_without_union_member_assertion()->unref(); data_without_union_member_assertion()->unref();
m_impl = exchange(other.m_impl, { .short_string = { .byte_count_and_short_string_flag = SHORT_STRING_FLAG } }); m_impl = exchange(other.m_impl, { .short_string = ShortString::create_empty() });
return *this; return *this;
} }