From 5451c2e87fac9665663fa60efb2820df366cc2f2 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 30 Mar 2025 00:27:45 +0000 Subject: [PATCH] LibJS: Make Optional use less space By specializing the template, we can shrink it from 16 to 8 bytes. This makes PrimitiveString a measly 32 bytes. :^) --- Libraries/LibJS/Runtime/Utf16String.cpp | 6 ++ Libraries/LibJS/Runtime/Utf16String.h | 101 +++++++++++++++++++++++- 2 files changed, 106 insertions(+), 1 deletion(-) diff --git a/Libraries/LibJS/Runtime/Utf16String.cpp b/Libraries/LibJS/Runtime/Utf16String.cpp index 2bd5a6c04ba..27a24f175cd 100644 --- a/Libraries/LibJS/Runtime/Utf16String.cpp +++ b/Libraries/LibJS/Runtime/Utf16String.cpp @@ -84,6 +84,12 @@ Utf16String Utf16String::create(Utf16View const& string) return Utf16String { Detail::Utf16StringImpl::create(string) }; } +Utf16String Utf16String::invalid() +{ + static auto invalid = Utf16String {}; + return invalid; +} + Utf16String::Utf16String(NonnullRefPtr string) : m_string(move(string)) { diff --git a/Libraries/LibJS/Runtime/Utf16String.h b/Libraries/LibJS/Runtime/Utf16String.h index 233a562ace6..0042a4dd81c 100644 --- a/Libraries/LibJS/Runtime/Utf16String.h +++ b/Libraries/LibJS/Runtime/Utf16String.h @@ -58,6 +58,7 @@ public: [[nodiscard]] static Utf16String create(Utf16Data); [[nodiscard]] static Utf16String create(StringView); [[nodiscard]] static Utf16String create(Utf16View const&); + [[nodiscard]] static Utf16String invalid(); Utf16Data const& string() const; Utf16View view() const; @@ -70,6 +71,7 @@ public: size_t length_in_code_units() const; bool is_empty() const; + bool is_valid() const { return m_string; } [[nodiscard]] u32 hash() const { return m_string->hash(); } [[nodiscard]] bool operator==(Utf16String const& other) const @@ -80,9 +82,10 @@ public: } private: + Utf16String() = default; explicit Utf16String(NonnullRefPtr); - NonnullRefPtr m_string; + RefPtr m_string; }; } @@ -94,4 +97,100 @@ struct Traits : public DefaultTraits { static unsigned hash(JS::Utf16String const& s) { return s.hash(); } }; +template<> +class Optional : public OptionalBase { + template + friend class Optional; + +public: + using ValueType = JS::Utf16String; + + Optional() = default; + + template V> + Optional(V) { } + + Optional(Optional const& other) + { + if (other.has_value()) + m_value = other.m_value; + } + + Optional(Optional&& other) + : m_value(other.m_value) + { + } + + template + requires(!IsSame>) + explicit(!IsConvertible) Optional(U&& value) + requires(!IsSame, Optional> && IsConstructible) + : m_value(forward(value)) + { + } + + template V> + Optional& operator=(V) + { + clear(); + return *this; + } + + Optional& operator=(Optional const& other) + { + if (this != &other) { + clear(); + m_value = other.m_value; + } + return *this; + } + + Optional& operator=(Optional&& other) + { + if (this != &other) { + clear(); + m_value = other.m_value; + } + return *this; + } + + void clear() + { + m_value = JS::Utf16String::invalid(); + } + + [[nodiscard]] bool has_value() const + { + return m_value.is_valid(); + } + + [[nodiscard]] JS::Utf16String& value() & + { + VERIFY(has_value()); + return m_value; + } + + [[nodiscard]] JS::Utf16String const& value() const& + { + VERIFY(has_value()); + return m_value; + } + + [[nodiscard]] JS::Utf16String value() && + { + return release_value(); + } + + [[nodiscard]] JS::Utf16String release_value() + { + VERIFY(has_value()); + JS::Utf16String released_value = m_value; + clear(); + return released_value; + } + +private: + JS::Utf16String m_value { JS::Utf16String::invalid() }; +}; + }