mirror of
https://github.com/LadybirdBrowser/ladybird
synced 2026-04-25 17:25:08 +02:00
AK: Add SentinelOptional
We specialize `Optional<T>` for value types that inherently support some kind of "empty" value or whose value range allow for a unlikely to be useful sentinel value that can mean "empty", instead of the boolean flag a regular Optional<T> needs to store. Because of padding, this often means saving 4 to 8 bytes per instance. By extending the new `SentinelOptional<T, Traits>`, these specializations are significantly simplified to just having to define what the sentinel value is, and how to identify a sentinel value.
This commit is contained in:
committed by
Jelle Raaijmakers
parent
9e245b014c
commit
e123d48043
Notes:
github-actions[bot]
2026-03-20 11:04:58 +00:00
Author: https://github.com/gmta Commit: https://github.com/LadybirdBrowser/ladybird/commit/e123d480436 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/8508 Reviewed-by: https://github.com/konradekk
100
AK/FlyString.h
100
AK/FlyString.h
@@ -84,7 +84,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class Optional<FlyString>;
|
friend struct SentinelOptionalTraits<FlyString>;
|
||||||
|
|
||||||
explicit constexpr FlyString(nullptr_t)
|
explicit constexpr FlyString(nullptr_t)
|
||||||
: m_data(nullptr)
|
: m_data(nullptr)
|
||||||
@@ -102,99 +102,15 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
class Optional<FlyString> : public OptionalBase<FlyString> {
|
struct SentinelOptionalTraits<FlyString> {
|
||||||
template<typename U>
|
static constexpr FlyString sentinel_value() { return FlyString(nullptr); }
|
||||||
friend class Optional;
|
static constexpr bool is_sentinel(FlyString const& value) { return value.is_invalid(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
class Optional<FlyString> : public SentinelOptional<FlyString> {
|
||||||
public:
|
public:
|
||||||
using ValueType = FlyString;
|
using SentinelOptional::SentinelOptional;
|
||||||
|
|
||||||
constexpr Optional() = default;
|
|
||||||
|
|
||||||
template<SameAs<OptionalNone> V>
|
|
||||||
constexpr Optional(V) { }
|
|
||||||
|
|
||||||
constexpr Optional(Optional<FlyString> const& other)
|
|
||||||
{
|
|
||||||
if (other.has_value())
|
|
||||||
m_value = other.m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr Optional(Optional&& other)
|
|
||||||
: m_value(move(other.m_value))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U = FlyString>
|
|
||||||
requires(!IsSame<OptionalNone, RemoveCVReference<U>>)
|
|
||||||
explicit(!IsConvertible<U&&, FlyString>) constexpr Optional(U&& value)
|
|
||||||
requires(!IsSame<RemoveCVReference<U>, Optional<FlyString>> && IsConstructible<FlyString, U &&>)
|
|
||||||
: m_value(forward<U>(value))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<SameAs<OptionalNone> V>
|
|
||||||
constexpr Optional& operator=(V)
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr Optional& operator=(Optional const& other)
|
|
||||||
{
|
|
||||||
if (this != &other) {
|
|
||||||
clear();
|
|
||||||
m_value = other.m_value;
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr Optional& operator=(Optional&& other)
|
|
||||||
{
|
|
||||||
if (this != &other) {
|
|
||||||
clear();
|
|
||||||
m_value = other.m_value;
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr void clear()
|
|
||||||
{
|
|
||||||
m_value = FlyString(nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr bool has_value() const
|
|
||||||
{
|
|
||||||
return !m_value.is_invalid();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr FlyString& value() &
|
|
||||||
{
|
|
||||||
VERIFY(has_value());
|
|
||||||
return m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr FlyString const& value() const&
|
|
||||||
{
|
|
||||||
VERIFY(has_value());
|
|
||||||
return m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr FlyString value() &&
|
|
||||||
{
|
|
||||||
return release_value();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr FlyString release_value()
|
|
||||||
{
|
|
||||||
VERIFY(has_value());
|
|
||||||
FlyString released_value = move(m_value);
|
|
||||||
clear();
|
|
||||||
return released_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
FlyString m_value = FlyString(nullptr);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
|
|||||||
@@ -661,9 +661,77 @@ struct Traits<Optional<T>> : public DefaultTraits<Optional<T>> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct SentinelOptionalTraits;
|
||||||
|
|
||||||
|
template<typename T, typename Traits = SentinelOptionalTraits<T>>
|
||||||
|
class SentinelOptional : public OptionalBase<T> {
|
||||||
|
public:
|
||||||
|
SentinelOptional() = default;
|
||||||
|
|
||||||
|
template<SameAs<OptionalNone> V>
|
||||||
|
constexpr SentinelOptional(V) { }
|
||||||
|
|
||||||
|
template<typename U = T>
|
||||||
|
requires(!IsSame<OptionalNone, RemoveCVReference<U>>)
|
||||||
|
explicit(!IsConvertible<U&&, T>) constexpr SentinelOptional(U&& value)
|
||||||
|
requires(!IsSame<RemoveCVReference<U>, SentinelOptional> && !IsSame<RemoveCVReference<U>, Optional<T>> && IsConstructible<T, U &&>)
|
||||||
|
: m_value(forward<U>(value))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename U = T>
|
||||||
|
requires(!IsOneOfIgnoringCVReference<U, SentinelOptional, Optional<T>, OptionalNone> && IsConstructible<T, U &&>)
|
||||||
|
constexpr SentinelOptional& operator=(U&& value)
|
||||||
|
{
|
||||||
|
m_value = T(forward<U>(value));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr void clear()
|
||||||
|
{
|
||||||
|
m_value = Traits::sentinel_value();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr bool has_value() const
|
||||||
|
{
|
||||||
|
return !Traits::is_sentinel(m_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Self>
|
||||||
|
[[nodiscard]] constexpr auto& value(this Self& self)
|
||||||
|
{
|
||||||
|
VERIFY(self.has_value());
|
||||||
|
return self.m_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr T value() &&
|
||||||
|
{
|
||||||
|
return release_value();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Self>
|
||||||
|
[[nodiscard]] constexpr auto& unchecked_value(this Self& self)
|
||||||
|
{
|
||||||
|
ASSERT(self.has_value());
|
||||||
|
return self.m_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr T release_value()
|
||||||
|
{
|
||||||
|
VERIFY(has_value());
|
||||||
|
return exchange(m_value, Traits::sentinel_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
T m_value { Traits::sentinel_value() };
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if USING_AK_GLOBALLY
|
#if USING_AK_GLOBALLY
|
||||||
using AK::Optional;
|
using AK::Optional;
|
||||||
using AK::OptionalNone;
|
using AK::OptionalNone;
|
||||||
|
using AK::SentinelOptional;
|
||||||
|
using AK::SentinelOptionalTraits;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
98
AK/String.h
98
AK/String.h
@@ -217,7 +217,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
friend class ::AK::FlyString;
|
friend class ::AK::FlyString;
|
||||||
friend class Optional<String>;
|
friend struct SentinelOptionalTraits<String>;
|
||||||
|
|
||||||
using ShortString = Detail::ShortString;
|
using ShortString = Detail::ShortString;
|
||||||
|
|
||||||
@@ -238,97 +238,15 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
class Optional<String> : public OptionalBase<String> {
|
struct SentinelOptionalTraits<String> {
|
||||||
template<typename U>
|
static constexpr String sentinel_value() { return String(nullptr); }
|
||||||
friend class Optional;
|
static constexpr bool is_sentinel(String const& value) { return value.is_invalid(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
class Optional<String> : public SentinelOptional<String> {
|
||||||
public:
|
public:
|
||||||
using ValueType = String;
|
using SentinelOptional::SentinelOptional;
|
||||||
|
|
||||||
constexpr Optional() = default;
|
|
||||||
|
|
||||||
template<SameAs<OptionalNone> V>
|
|
||||||
constexpr Optional(V) { }
|
|
||||||
|
|
||||||
constexpr Optional(Optional<String> const& other)
|
|
||||||
{
|
|
||||||
if (other.has_value())
|
|
||||||
m_value = other.m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr Optional(Optional&& other)
|
|
||||||
: m_value(move(other.m_value))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U = String>
|
|
||||||
requires(!IsSame<OptionalNone, RemoveCVReference<U>>)
|
|
||||||
explicit(!IsConvertible<U&&, String>) constexpr Optional(U&& value)
|
|
||||||
requires(!IsSame<RemoveCVReference<U>, Optional<String>> && IsConstructible<String, U &&>)
|
|
||||||
: m_value(forward<U>(value))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<SameAs<OptionalNone> V>
|
|
||||||
constexpr Optional& operator=(V)
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr Optional& operator=(Optional const& other)
|
|
||||||
{
|
|
||||||
if (this != &other) {
|
|
||||||
m_value = other.m_value;
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr Optional& operator=(Optional&& other)
|
|
||||||
{
|
|
||||||
if (this != &other) {
|
|
||||||
m_value = move(other.m_value);
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr void clear()
|
|
||||||
{
|
|
||||||
m_value = String(nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr bool has_value() const
|
|
||||||
{
|
|
||||||
return !m_value.is_invalid();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr String& value() &
|
|
||||||
{
|
|
||||||
VERIFY(has_value());
|
|
||||||
return m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr String const& value() const&
|
|
||||||
{
|
|
||||||
VERIFY(has_value());
|
|
||||||
return m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr String value() &&
|
|
||||||
{
|
|
||||||
return release_value();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr String release_value()
|
|
||||||
{
|
|
||||||
VERIFY(has_value());
|
|
||||||
String released_value = move(m_value);
|
|
||||||
clear();
|
|
||||||
return released_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
String m_value { nullptr };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
|
|||||||
@@ -136,12 +136,12 @@ public:
|
|||||||
[[nodiscard]] ALWAYS_INLINE size_t code_unit_offset_of(size_t code_point_offset) const { return m_data.code_unit_offset_of(code_point_offset); }
|
[[nodiscard]] ALWAYS_INLINE size_t code_unit_offset_of(size_t code_point_offset) const { return m_data.code_unit_offset_of(code_point_offset); }
|
||||||
[[nodiscard]] ALWAYS_INLINE size_t code_point_offset_of(size_t code_unit_offset) const { return m_data.code_point_offset_of(code_unit_offset); }
|
[[nodiscard]] ALWAYS_INLINE size_t code_point_offset_of(size_t code_unit_offset) const { return m_data.code_point_offset_of(code_unit_offset); }
|
||||||
|
|
||||||
constexpr Utf16FlyString(Badge<Optional<Utf16FlyString>>, nullptr_t)
|
constexpr Utf16FlyString(Badge<SentinelOptionalTraits<Utf16FlyString>>, nullptr_t)
|
||||||
: m_data(Badge<Utf16FlyString> {}, nullptr)
|
: m_data(Badge<Utf16FlyString> {}, nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] constexpr bool is_invalid(Badge<Optional<Utf16FlyString>>) const { return m_data.raw({}) == 0; }
|
[[nodiscard]] constexpr bool is_invalid(Badge<SentinelOptionalTraits<Utf16FlyString>>) const { return m_data.raw({}) == 0; }
|
||||||
|
|
||||||
// This is primarily interesting to unit tests.
|
// This is primarily interesting to unit tests.
|
||||||
[[nodiscard]] static size_t number_of_utf16_fly_strings();
|
[[nodiscard]] static size_t number_of_utf16_fly_strings();
|
||||||
@@ -159,93 +159,15 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
class Optional<Utf16FlyString> : public OptionalBase<Utf16FlyString> {
|
struct SentinelOptionalTraits<Utf16FlyString> {
|
||||||
template<typename U>
|
static constexpr Utf16FlyString sentinel_value() { return Utf16FlyString({}, nullptr); }
|
||||||
friend class Optional;
|
static constexpr bool is_sentinel(Utf16FlyString const& value) { return value.is_invalid({}); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
class Optional<Utf16FlyString> : public SentinelOptional<Utf16FlyString> {
|
||||||
public:
|
public:
|
||||||
using ValueType = Utf16FlyString;
|
using SentinelOptional::SentinelOptional;
|
||||||
|
|
||||||
constexpr Optional() = default;
|
|
||||||
|
|
||||||
template<SameAs<OptionalNone> V>
|
|
||||||
constexpr Optional(V) { }
|
|
||||||
|
|
||||||
constexpr Optional(Optional<Utf16FlyString> const& other)
|
|
||||||
: m_value(other.m_value)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr Optional(Optional&& other)
|
|
||||||
: m_value(move(other.m_value))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U = Utf16FlyString>
|
|
||||||
requires(!IsSame<OptionalNone, RemoveCVReference<U>>)
|
|
||||||
explicit(!IsConvertible<U&&, Utf16FlyString>) constexpr Optional(U&& value)
|
|
||||||
requires(!IsSame<RemoveCVReference<U>, Optional<Utf16FlyString>> && IsConstructible<Utf16FlyString, U &&>)
|
|
||||||
: m_value(forward<U>(value))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<SameAs<OptionalNone> V>
|
|
||||||
constexpr Optional& operator=(V)
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr Optional& operator=(Optional const& other)
|
|
||||||
{
|
|
||||||
if (this != &other)
|
|
||||||
m_value = other.m_value;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr Optional& operator=(Optional&& other)
|
|
||||||
{
|
|
||||||
if (this != &other)
|
|
||||||
m_value = other.m_value;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr void clear()
|
|
||||||
{
|
|
||||||
m_value = empty_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr bool has_value() const
|
|
||||||
{
|
|
||||||
return !m_value.is_invalid({});
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr Utf16FlyString& value() &
|
|
||||||
{
|
|
||||||
VERIFY(has_value());
|
|
||||||
return m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr Utf16FlyString const& value() const&
|
|
||||||
{
|
|
||||||
VERIFY(has_value());
|
|
||||||
return m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr Utf16FlyString value() &&
|
|
||||||
{
|
|
||||||
return release_value();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr Utf16FlyString release_value()
|
|
||||||
{
|
|
||||||
VERIFY(has_value());
|
|
||||||
return exchange(m_value, empty_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static constexpr Utf16FlyString empty_value { {}, nullptr };
|
|
||||||
Utf16FlyString m_value { empty_value };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
|
|||||||
@@ -41,99 +41,15 @@ private:
|
|||||||
namespace AK {
|
namespace AK {
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
class Optional<JS::Bytecode::IdentifierTableIndex> : public OptionalBase<JS::Bytecode::IdentifierTableIndex> {
|
struct SentinelOptionalTraits<JS::Bytecode::IdentifierTableIndex> {
|
||||||
template<typename U>
|
static constexpr JS::Bytecode::IdentifierTableIndex sentinel_value() { return { JS::Bytecode::IdentifierTableIndex::invalid }; }
|
||||||
friend class Optional;
|
static constexpr bool is_sentinel(JS::Bytecode::IdentifierTableIndex const& value) { return !value.is_valid(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
class Optional<JS::Bytecode::IdentifierTableIndex> : public SentinelOptional<JS::Bytecode::IdentifierTableIndex> {
|
||||||
public:
|
public:
|
||||||
using ValueType = JS::Bytecode::IdentifierTableIndex;
|
using SentinelOptional::SentinelOptional;
|
||||||
|
|
||||||
Optional() = default;
|
|
||||||
|
|
||||||
template<SameAs<OptionalNone> V>
|
|
||||||
Optional(V) { }
|
|
||||||
|
|
||||||
Optional(Optional<JS::Bytecode::IdentifierTableIndex> const& other)
|
|
||||||
{
|
|
||||||
if (other.has_value())
|
|
||||||
m_value = other.m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
Optional(Optional&& other)
|
|
||||||
: m_value(other.m_value)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U = JS::Bytecode::IdentifierTableIndex>
|
|
||||||
requires(!IsSame<OptionalNone, RemoveCVReference<U>>)
|
|
||||||
explicit(!IsConvertible<U&&, JS::Bytecode::IdentifierTableIndex>) Optional(U&& value)
|
|
||||||
requires(!IsSame<RemoveCVReference<U>, Optional<JS::Bytecode::IdentifierTableIndex>> && IsConstructible<JS::Bytecode::IdentifierTableIndex, U &&>)
|
|
||||||
: m_value(forward<U>(value))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<SameAs<OptionalNone> 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.value = JS::Bytecode::IdentifierTableIndex::invalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] bool has_value() const
|
|
||||||
{
|
|
||||||
return m_value.is_valid();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] JS::Bytecode::IdentifierTableIndex& value() &
|
|
||||||
{
|
|
||||||
VERIFY(has_value());
|
|
||||||
return m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] JS::Bytecode::IdentifierTableIndex const& value() const&
|
|
||||||
{
|
|
||||||
VERIFY(has_value());
|
|
||||||
return m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] JS::Bytecode::IdentifierTableIndex value() &&
|
|
||||||
{
|
|
||||||
return release_value();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] JS::Bytecode::IdentifierTableIndex release_value()
|
|
||||||
{
|
|
||||||
VERIFY(has_value());
|
|
||||||
JS::Bytecode::IdentifierTableIndex released_value = m_value;
|
|
||||||
clear();
|
|
||||||
return released_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
JS::Bytecode::IdentifierTableIndex m_value { JS::Bytecode::IdentifierTableIndex::invalid };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,99 +62,15 @@ private:
|
|||||||
namespace AK {
|
namespace AK {
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
class Optional<JS::Bytecode::Operand> : public OptionalBase<JS::Bytecode::Operand> {
|
struct SentinelOptionalTraits<JS::Bytecode::Operand> {
|
||||||
template<typename U>
|
static JS::Bytecode::Operand sentinel_value() { return JS::Bytecode::Operand { JS::Bytecode::Operand::ShouldMakeInvalid::Indeed }; }
|
||||||
friend class Optional;
|
static bool is_sentinel(JS::Bytecode::Operand const& value) { return value.is_invalid(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
class Optional<JS::Bytecode::Operand> : public SentinelOptional<JS::Bytecode::Operand> {
|
||||||
public:
|
public:
|
||||||
using ValueType = JS::Bytecode::Operand;
|
using SentinelOptional::SentinelOptional;
|
||||||
|
|
||||||
Optional() = default;
|
|
||||||
|
|
||||||
template<SameAs<OptionalNone> V>
|
|
||||||
Optional(V) { }
|
|
||||||
|
|
||||||
Optional(Optional<JS::Bytecode::Operand> const& other)
|
|
||||||
{
|
|
||||||
if (other.has_value())
|
|
||||||
m_value = other.m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
Optional(Optional&& other)
|
|
||||||
: m_value(other.m_value)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U = JS::Bytecode::Operand>
|
|
||||||
requires(!IsSame<OptionalNone, RemoveCVReference<U>>)
|
|
||||||
explicit(!IsConvertible<U&&, JS::Bytecode::Operand>) Optional(U&& value)
|
|
||||||
requires(!IsSame<RemoveCVReference<U>, Optional<JS::Bytecode::Operand>> && IsConstructible<JS::Bytecode::Operand, U &&>)
|
|
||||||
: m_value(forward<U>(value))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<SameAs<OptionalNone> 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::Bytecode::Operand { JS::Bytecode::Operand::ShouldMakeInvalid::Indeed };
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] bool has_value() const
|
|
||||||
{
|
|
||||||
return !m_value.is_invalid();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] JS::Bytecode::Operand& value() &
|
|
||||||
{
|
|
||||||
VERIFY(has_value());
|
|
||||||
return m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] JS::Bytecode::Operand const& value() const&
|
|
||||||
{
|
|
||||||
VERIFY(has_value());
|
|
||||||
return m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] JS::Bytecode::Operand value() &&
|
|
||||||
{
|
|
||||||
return release_value();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] JS::Bytecode::Operand release_value()
|
|
||||||
{
|
|
||||||
VERIFY(has_value());
|
|
||||||
JS::Bytecode::Operand released_value = m_value;
|
|
||||||
clear();
|
|
||||||
return released_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
JS::Bytecode::Operand m_value { JS::Bytecode::Operand::ShouldMakeInvalid::Indeed };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,99 +47,15 @@ private:
|
|||||||
namespace AK {
|
namespace AK {
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
class Optional<JS::Bytecode::PropertyKeyTableIndex> : public OptionalBase<JS::Bytecode::PropertyKeyTableIndex> {
|
struct SentinelOptionalTraits<JS::Bytecode::PropertyKeyTableIndex> {
|
||||||
template<typename U>
|
static constexpr JS::Bytecode::PropertyKeyTableIndex sentinel_value() { return { JS::Bytecode::PropertyKeyTableIndex::invalid }; }
|
||||||
friend class Optional;
|
static constexpr bool is_sentinel(JS::Bytecode::PropertyKeyTableIndex const& value) { return !value.is_valid(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
class Optional<JS::Bytecode::PropertyKeyTableIndex> : public SentinelOptional<JS::Bytecode::PropertyKeyTableIndex> {
|
||||||
public:
|
public:
|
||||||
using ValueType = JS::Bytecode::PropertyKeyTableIndex;
|
using SentinelOptional::SentinelOptional;
|
||||||
|
|
||||||
Optional() = default;
|
|
||||||
|
|
||||||
template<SameAs<OptionalNone> V>
|
|
||||||
Optional(V) { }
|
|
||||||
|
|
||||||
Optional(Optional<JS::Bytecode::PropertyKeyTableIndex> const& other)
|
|
||||||
{
|
|
||||||
if (other.has_value())
|
|
||||||
m_value = other.m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
Optional(Optional&& other)
|
|
||||||
: m_value(other.m_value)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U = JS::Bytecode::PropertyKeyTableIndex>
|
|
||||||
requires(!IsSame<OptionalNone, RemoveCVReference<U>>)
|
|
||||||
explicit(!IsConvertible<U&&, JS::Bytecode::PropertyKeyTableIndex>) Optional(U&& value)
|
|
||||||
requires(!IsSame<RemoveCVReference<U>, Optional<JS::Bytecode::PropertyKeyTableIndex>> && IsConstructible<JS::Bytecode::PropertyKeyTableIndex, U &&>)
|
|
||||||
: m_value(forward<U>(value))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<SameAs<OptionalNone> 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.value = JS::Bytecode::PropertyKeyTableIndex::invalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] bool has_value() const
|
|
||||||
{
|
|
||||||
return m_value.is_valid();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] JS::Bytecode::PropertyKeyTableIndex& value() &
|
|
||||||
{
|
|
||||||
VERIFY(has_value());
|
|
||||||
return m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] JS::Bytecode::PropertyKeyTableIndex const& value() const&
|
|
||||||
{
|
|
||||||
VERIFY(has_value());
|
|
||||||
return m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] JS::Bytecode::PropertyKeyTableIndex value() &&
|
|
||||||
{
|
|
||||||
return release_value();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] JS::Bytecode::PropertyKeyTableIndex release_value()
|
|
||||||
{
|
|
||||||
VERIFY(has_value());
|
|
||||||
JS::Bytecode::PropertyKeyTableIndex released_value = m_value;
|
|
||||||
clear();
|
|
||||||
return released_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
JS::Bytecode::PropertyKeyTableIndex m_value { JS::Bytecode::PropertyKeyTableIndex::invalid };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,99 +39,15 @@ private:
|
|||||||
namespace AK {
|
namespace AK {
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
class Optional<JS::Bytecode::StringTableIndex> : public OptionalBase<JS::Bytecode::StringTableIndex> {
|
struct SentinelOptionalTraits<JS::Bytecode::StringTableIndex> {
|
||||||
template<typename U>
|
static constexpr JS::Bytecode::StringTableIndex sentinel_value() { return { JS::Bytecode::StringTableIndex::invalid }; }
|
||||||
friend class Optional;
|
static constexpr bool is_sentinel(JS::Bytecode::StringTableIndex const& value) { return !value.is_valid(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
class Optional<JS::Bytecode::StringTableIndex> : public SentinelOptional<JS::Bytecode::StringTableIndex> {
|
||||||
public:
|
public:
|
||||||
using ValueType = JS::Bytecode::StringTableIndex;
|
using SentinelOptional::SentinelOptional;
|
||||||
|
|
||||||
Optional() = default;
|
|
||||||
|
|
||||||
template<SameAs<OptionalNone> V>
|
|
||||||
Optional(V) { }
|
|
||||||
|
|
||||||
Optional(Optional<JS::Bytecode::StringTableIndex> const& other)
|
|
||||||
{
|
|
||||||
if (other.has_value())
|
|
||||||
m_value = other.m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
Optional(Optional&& other)
|
|
||||||
: m_value(other.m_value)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U = JS::Bytecode::StringTableIndex>
|
|
||||||
requires(!IsSame<OptionalNone, RemoveCVReference<U>>)
|
|
||||||
explicit(!IsConvertible<U&&, JS::Bytecode::StringTableIndex>) Optional(U&& value)
|
|
||||||
requires(!IsSame<RemoveCVReference<U>, Optional<JS::Bytecode::StringTableIndex>> && IsConstructible<JS::Bytecode::StringTableIndex, U &&>)
|
|
||||||
: m_value(forward<U>(value))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<SameAs<OptionalNone> 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.value = JS::Bytecode::StringTableIndex::invalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] bool has_value() const
|
|
||||||
{
|
|
||||||
return m_value.is_valid();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] JS::Bytecode::StringTableIndex& value() &
|
|
||||||
{
|
|
||||||
VERIFY(has_value());
|
|
||||||
return m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] JS::Bytecode::StringTableIndex const& value() const&
|
|
||||||
{
|
|
||||||
VERIFY(has_value());
|
|
||||||
return m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] JS::Bytecode::StringTableIndex value() &&
|
|
||||||
{
|
|
||||||
return release_value();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] JS::Bytecode::StringTableIndex release_value()
|
|
||||||
{
|
|
||||||
VERIFY(has_value());
|
|
||||||
JS::Bytecode::StringTableIndex released_value = m_value;
|
|
||||||
clear();
|
|
||||||
return released_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
JS::Bytecode::StringTableIndex m_value { JS::Bytecode::StringTableIndex::invalid };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
class EmptyTag {
|
class EmptyTag {
|
||||||
};
|
};
|
||||||
friend AK::Optional<Completion>;
|
friend struct AK::SentinelOptionalTraits<Completion>;
|
||||||
|
|
||||||
constexpr Completion(EmptyTag)
|
constexpr Completion(EmptyTag)
|
||||||
: m_type(Type::Empty)
|
: m_type(Type::Empty)
|
||||||
@@ -135,88 +135,15 @@ private:
|
|||||||
namespace AK {
|
namespace AK {
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
class Optional<JS::Completion> : public OptionalBase<JS::Completion> {
|
struct SentinelOptionalTraits<JS::Completion> {
|
||||||
template<typename U>
|
static constexpr JS::Completion sentinel_value() { return JS::Completion(JS::Completion::EmptyTag {}); }
|
||||||
friend class Optional;
|
static constexpr bool is_sentinel(JS::Completion const& value) { return value.is_empty(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
class Optional<JS::Completion> : public SentinelOptional<JS::Completion> {
|
||||||
public:
|
public:
|
||||||
using ValueType = JS::Completion;
|
using SentinelOptional::SentinelOptional;
|
||||||
|
|
||||||
constexpr Optional() = default;
|
|
||||||
|
|
||||||
constexpr Optional(Optional<JS::Completion> const& other)
|
|
||||||
{
|
|
||||||
if (other.has_value())
|
|
||||||
m_value = other.m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr Optional(Optional&& other)
|
|
||||||
: m_value(move(other.m_value))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U = JS::Completion>
|
|
||||||
explicit(!IsConvertible<U&&, JS::Completion>) constexpr Optional(U&& value)
|
|
||||||
requires(!IsSame<RemoveCVReference<U>, Optional<JS::Completion>> && IsConstructible<JS::Completion, U &&>)
|
|
||||||
: m_value(forward<U>(value))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr Optional& operator=(Optional const& other)
|
|
||||||
{
|
|
||||||
if (this != &other) {
|
|
||||||
clear();
|
|
||||||
m_value = other.m_value;
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr Optional& operator=(Optional&& other)
|
|
||||||
{
|
|
||||||
if (this != &other) {
|
|
||||||
clear();
|
|
||||||
m_value = other.m_value;
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr void clear()
|
|
||||||
{
|
|
||||||
m_value = JS::Completion(JS::Completion::EmptyTag {});
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr bool has_value() const
|
|
||||||
{
|
|
||||||
return !m_value.is_empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr JS::Completion& value() &
|
|
||||||
{
|
|
||||||
VERIFY(has_value());
|
|
||||||
return m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr JS::Completion const& value() const&
|
|
||||||
{
|
|
||||||
VERIFY(has_value());
|
|
||||||
return m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr JS::Completion value() &&
|
|
||||||
{
|
|
||||||
return release_value();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr JS::Completion release_value()
|
|
||||||
{
|
|
||||||
VERIFY(has_value());
|
|
||||||
JS::Completion released_value = m_value;
|
|
||||||
clear();
|
|
||||||
return released_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
JS::Completion m_value { JS::Completion::EmptyTag {} };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
friend Traits<PropertyKey>;
|
friend Traits<PropertyKey>;
|
||||||
friend class Optional<PropertyKey>;
|
friend struct AK::SentinelOptionalTraits<PropertyKey>;
|
||||||
|
|
||||||
enum class ShouldMakeEmptyOptional {
|
enum class ShouldMakeEmptyOptional {
|
||||||
Indeed,
|
Indeed,
|
||||||
@@ -242,99 +242,15 @@ struct Formatter<JS::PropertyKey> : Formatter<Utf16String> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
class Optional<JS::PropertyKey> : public OptionalBase<JS::PropertyKey> {
|
struct SentinelOptionalTraits<JS::PropertyKey> {
|
||||||
template<typename U>
|
static JS::PropertyKey sentinel_value() { return JS::PropertyKey { JS::PropertyKey::ShouldMakeEmptyOptional::Indeed }; }
|
||||||
friend class Optional;
|
static bool is_sentinel(JS::PropertyKey const& value) { return value.is_empty_optional(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
class Optional<JS::PropertyKey> : public SentinelOptional<JS::PropertyKey> {
|
||||||
public:
|
public:
|
||||||
using ValueType = JS::PropertyKey;
|
using SentinelOptional::SentinelOptional;
|
||||||
|
|
||||||
Optional() = default;
|
|
||||||
|
|
||||||
template<SameAs<OptionalNone> V>
|
|
||||||
Optional(V) { }
|
|
||||||
|
|
||||||
Optional(Optional<JS::PropertyKey> const& other)
|
|
||||||
{
|
|
||||||
if (other.has_value())
|
|
||||||
m_value = other.m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
Optional(Optional&& other)
|
|
||||||
: m_value(other.m_value)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U = JS::PropertyKey>
|
|
||||||
requires(!IsSame<OptionalNone, RemoveCVReference<U>>)
|
|
||||||
explicit(!IsConvertible<U&&, JS::PropertyKey>) Optional(U&& value)
|
|
||||||
requires(!IsSame<RemoveCVReference<U>, Optional<JS::PropertyKey>> && IsConstructible<JS::PropertyKey, U &&>)
|
|
||||||
: m_value(forward<U>(value))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<SameAs<OptionalNone> 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::PropertyKey { JS::PropertyKey::ShouldMakeEmptyOptional::Indeed };
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] bool has_value() const
|
|
||||||
{
|
|
||||||
return !m_value.is_empty_optional();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] JS::PropertyKey& value() &
|
|
||||||
{
|
|
||||||
VERIFY(has_value());
|
|
||||||
return m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] JS::PropertyKey const& value() const&
|
|
||||||
{
|
|
||||||
VERIFY(has_value());
|
|
||||||
return m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] JS::PropertyKey value() &&
|
|
||||||
{
|
|
||||||
return release_value();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] JS::PropertyKey release_value()
|
|
||||||
{
|
|
||||||
VERIFY(has_value());
|
|
||||||
JS::PropertyKey released_value = m_value;
|
|
||||||
clear();
|
|
||||||
return released_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
JS::PropertyKey m_value { JS::PropertyKey::ShouldMakeEmptyOptional::Indeed };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,99 +99,15 @@ struct Traits<JS::Utf16String> : public DefaultTraits<JS::Utf16String> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
class Optional<JS::Utf16String> : public OptionalBase<JS::Utf16String> {
|
struct SentinelOptionalTraits<JS::Utf16String> {
|
||||||
template<typename U>
|
static JS::Utf16String sentinel_value() { return JS::Utf16String::invalid(); }
|
||||||
friend class Optional;
|
static bool is_sentinel(JS::Utf16String const& value) { return !value.is_valid(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
class Optional<JS::Utf16String> : public SentinelOptional<JS::Utf16String> {
|
||||||
public:
|
public:
|
||||||
using ValueType = JS::Utf16String;
|
using SentinelOptional::SentinelOptional;
|
||||||
|
|
||||||
Optional() = default;
|
|
||||||
|
|
||||||
template<SameAs<OptionalNone> V>
|
|
||||||
Optional(V) { }
|
|
||||||
|
|
||||||
Optional(Optional<JS::Utf16String> const& other)
|
|
||||||
{
|
|
||||||
if (other.has_value())
|
|
||||||
m_value = other.m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
Optional(Optional&& other)
|
|
||||||
: m_value(other.m_value)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U = JS::Utf16String>
|
|
||||||
requires(!IsSame<OptionalNone, RemoveCVReference<U>>)
|
|
||||||
explicit(!IsConvertible<U&&, JS::Utf16String>) Optional(U&& value)
|
|
||||||
requires(!IsSame<RemoveCVReference<U>, Optional<JS::Utf16String>> && IsConstructible<JS::Utf16String, U &&>)
|
|
||||||
: m_value(forward<U>(value))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<SameAs<OptionalNone> 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() };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -608,99 +608,15 @@ namespace AK {
|
|||||||
static_assert(sizeof(JS::Value) == sizeof(double));
|
static_assert(sizeof(JS::Value) == sizeof(double));
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
class Optional<JS::Value> : public OptionalBase<JS::Value> {
|
struct SentinelOptionalTraits<JS::Value> {
|
||||||
template<typename U>
|
static constexpr JS::Value sentinel_value() { return JS::js_special_empty_value(); }
|
||||||
friend class Optional;
|
static constexpr bool is_sentinel(JS::Value const& value) { return value.is_special_empty_value(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
class Optional<JS::Value> : public SentinelOptional<JS::Value> {
|
||||||
public:
|
public:
|
||||||
using ValueType = JS::Value;
|
using SentinelOptional::SentinelOptional;
|
||||||
|
|
||||||
constexpr Optional() = default;
|
|
||||||
|
|
||||||
template<SameAs<OptionalNone> V>
|
|
||||||
constexpr Optional(V) { }
|
|
||||||
|
|
||||||
constexpr Optional(Optional<JS::Value> const& other)
|
|
||||||
{
|
|
||||||
if (other.has_value())
|
|
||||||
m_value = other.m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr Optional(Optional&& other)
|
|
||||||
: m_value(other.m_value)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U = JS::Value>
|
|
||||||
requires(!IsSame<OptionalNone, RemoveCVReference<U>>)
|
|
||||||
explicit(!IsConvertible<U&&, JS::Value>) constexpr Optional(U&& value)
|
|
||||||
requires(!IsSame<RemoveCVReference<U>, Optional<JS::Value>> && IsConstructible<JS::Value, U &&>)
|
|
||||||
: m_value(forward<U>(value))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<SameAs<OptionalNone> V>
|
|
||||||
constexpr Optional& operator=(V)
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr Optional& operator=(Optional const& other)
|
|
||||||
{
|
|
||||||
if (this != &other) {
|
|
||||||
clear();
|
|
||||||
m_value = other.m_value;
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr Optional& operator=(Optional&& other)
|
|
||||||
{
|
|
||||||
if (this != &other) {
|
|
||||||
clear();
|
|
||||||
m_value = other.m_value;
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr void clear()
|
|
||||||
{
|
|
||||||
m_value = JS::js_special_empty_value();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr bool has_value() const
|
|
||||||
{
|
|
||||||
return !m_value.is_special_empty_value();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr JS::Value& value() &
|
|
||||||
{
|
|
||||||
VERIFY(has_value());
|
|
||||||
return m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr JS::Value const& value() const&
|
|
||||||
{
|
|
||||||
VERIFY(has_value());
|
|
||||||
return m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr JS::Value value() &&
|
|
||||||
{
|
|
||||||
return release_value();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr JS::Value release_value()
|
|
||||||
{
|
|
||||||
VERIFY(has_value());
|
|
||||||
JS::Value released_value = m_value;
|
|
||||||
clear();
|
|
||||||
return released_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
JS::Value m_value { JS::js_special_empty_value() };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include <AK/ByteString.h>
|
#include <AK/ByteString.h>
|
||||||
#include <AK/FlyString.h>
|
#include <AK/FlyString.h>
|
||||||
|
#include <AK/NumericLimits.h>
|
||||||
#include <AK/Optional.h>
|
#include <AK/Optional.h>
|
||||||
#include <AK/String.h>
|
#include <AK/String.h>
|
||||||
#include <AK/Vector.h>
|
#include <AK/Vector.h>
|
||||||
@@ -662,3 +663,66 @@ TEST_CASE(flystring_specialization)
|
|||||||
EXPECT_EQ((Optional<FlyString> {}).value_or("fallback_value"_fly_string), "fallback_value"sv);
|
EXPECT_EQ((Optional<FlyString> {}).value_or("fallback_value"_fly_string), "fallback_value"sv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct SentinelInt {
|
||||||
|
u32 value { 0 };
|
||||||
|
static constexpr u32 invalid = NumericLimits<u32>::max();
|
||||||
|
bool is_valid() const { return value != invalid; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct AK::SentinelOptionalTraits<SentinelInt> {
|
||||||
|
static constexpr SentinelInt sentinel_value() { return { SentinelInt::invalid }; }
|
||||||
|
static constexpr bool is_sentinel(SentinelInt const& v) { return !v.is_valid(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
class AK::Optional<SentinelInt> : public SentinelOptional<SentinelInt> {
|
||||||
|
public:
|
||||||
|
using SentinelOptional::SentinelOptional;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_CASE(sentinel_optional)
|
||||||
|
{
|
||||||
|
static_assert(sizeof(Optional<SentinelInt>) == sizeof(SentinelInt));
|
||||||
|
static_assert(sizeof(Optional<FlyString>) == sizeof(FlyString));
|
||||||
|
static_assert(sizeof(Optional<String>) == sizeof(String));
|
||||||
|
|
||||||
|
{
|
||||||
|
Optional<SentinelInt> empty;
|
||||||
|
EXPECT(!empty.has_value());
|
||||||
|
|
||||||
|
Optional<SentinelInt> with_value { SentinelInt { 42 } };
|
||||||
|
EXPECT(with_value.has_value());
|
||||||
|
EXPECT_EQ(with_value->value, 42u);
|
||||||
|
|
||||||
|
with_value = {};
|
||||||
|
EXPECT(!with_value.has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Optional<SentinelInt> a { SentinelInt { 7 } };
|
||||||
|
Optional<SentinelInt> b = a;
|
||||||
|
EXPECT(b.has_value());
|
||||||
|
EXPECT_EQ(b->value, 7u);
|
||||||
|
|
||||||
|
Optional<SentinelInt> c = move(a);
|
||||||
|
EXPECT(c.has_value());
|
||||||
|
EXPECT_EQ(c->value, 7u);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Optional<SentinelInt> opt { SentinelInt { 5 } };
|
||||||
|
auto released = opt.release_value();
|
||||||
|
EXPECT_EQ(released.value, 5u);
|
||||||
|
EXPECT(!opt.has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Optional<SentinelInt> opt;
|
||||||
|
EXPECT_EQ(opt.value_or(SentinelInt { 99 }).value, 99u);
|
||||||
|
|
||||||
|
opt = SentinelInt { 10 };
|
||||||
|
EXPECT_EQ(opt.value_or(SentinelInt { 99 }).value, 10u);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user