diff options
author | davidot <davidot@serenityos.org> | 2022-02-28 21:33:45 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2022-08-15 17:11:25 +0200 |
commit | 8381e7f1e665d30a0cc770492c67d8cfd5ea0bc8 (patch) | |
tree | ddc5551411536e441e8376fad373c565bbff87c7 /Userland/Libraries/LibJS/Runtime | |
parent | 8be96cd7ff505257206f88736cb0ed45ac0a0f15 (diff) | |
download | serenity-8381e7f1e665d30a0cc770492c67d8cfd5ea0bc8.zip |
LibJS: Specialize Optional<Value>
Values can be "empty" which only has a valid meaning for array holes.
We can however use this state the represent the empty state of an
Optional<Value> which is used in a lot of placed, because of Completion
having one.
This saves 8 bytes for every Optional<Value>.
Diffstat (limited to 'Userland/Libraries/LibJS/Runtime')
-rw-r--r-- | Userland/Libraries/LibJS/Runtime/Value.h | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/Value.h b/Userland/Libraries/LibJS/Runtime/Value.h index 6bcbdeb6ac..b23aa93eb0 100644 --- a/Userland/Libraries/LibJS/Runtime/Value.h +++ b/Userland/Libraries/LibJS/Runtime/Value.h @@ -434,6 +434,110 @@ inline bool Value::operator==(Value const& value) const { return same_value(*thi namespace AK { template<> +class Optional<JS::Value> { + template<typename U> + friend class Optional; + +public: + using ValueType = JS::Value; + + Optional() = default; + + Optional(Optional<JS::Value> const& other) + { + if (other.has_value()) + m_value = other.m_value; + } + + Optional(Optional&& other) + : m_value(other.m_value) + { + } + + template<typename U = JS::Value> + explicit(!IsConvertible<U&&, JS::Value>) Optional(U&& value) requires(!IsSame<RemoveCVReference<U>, Optional<JS::Value>> && IsConstructible<JS::Value, U&&>) + : m_value(forward<U>(value)) + { + } + + 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 = {}; + } + + [[nodiscard]] bool has_value() const + { + return !m_value.is_empty(); + } + + [[nodiscard]] JS::Value& value() & + { + VERIFY(has_value()); + return m_value; + } + + [[nodiscard]] JS::Value const& value() const& + { + VERIFY(has_value()); + return m_value; + } + + [[nodiscard]] JS::Value value() && + { + return release_value(); + } + + [[nodiscard]] JS::Value release_value() + { + VERIFY(has_value()); + JS::Value released_value = m_value; + clear(); + return released_value; + } + + JS::Value value_or(JS::Value const& fallback) const& + { + if (has_value()) + return value(); + return fallback; + } + + [[nodiscard]] JS::Value value_or(JS::Value&& fallback) && + { + if (has_value()) + return value(); + return fallback; + } + + JS::Value const& operator*() const { return value(); } + JS::Value& operator*() { return value(); } + + JS::Value const* operator->() const { return &value(); } + JS::Value* operator->() { return &value(); } + +private: + JS::Value m_value; +}; + +template<> struct Formatter<JS::Value> : Formatter<StringView> { ErrorOr<void> format(FormatBuilder& builder, JS::Value value) { |