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:
|
||||
friend class Optional<FlyString>;
|
||||
friend struct SentinelOptionalTraits<FlyString>;
|
||||
|
||||
explicit constexpr FlyString(nullptr_t)
|
||||
: m_data(nullptr)
|
||||
@@ -102,99 +102,15 @@ private:
|
||||
};
|
||||
|
||||
template<>
|
||||
class Optional<FlyString> : public OptionalBase<FlyString> {
|
||||
template<typename U>
|
||||
friend class Optional;
|
||||
struct SentinelOptionalTraits<FlyString> {
|
||||
static constexpr FlyString sentinel_value() { return FlyString(nullptr); }
|
||||
static constexpr bool is_sentinel(FlyString const& value) { return value.is_invalid(); }
|
||||
};
|
||||
|
||||
template<>
|
||||
class Optional<FlyString> : public SentinelOptional<FlyString> {
|
||||
public:
|
||||
using ValueType = FlyString;
|
||||
|
||||
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);
|
||||
using SentinelOptional::SentinelOptional;
|
||||
};
|
||||
|
||||
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
|
||||
using AK::Optional;
|
||||
using AK::OptionalNone;
|
||||
using AK::SentinelOptional;
|
||||
using AK::SentinelOptionalTraits;
|
||||
#endif
|
||||
|
||||
98
AK/String.h
98
AK/String.h
@@ -217,7 +217,7 @@ public:
|
||||
|
||||
private:
|
||||
friend class ::AK::FlyString;
|
||||
friend class Optional<String>;
|
||||
friend struct SentinelOptionalTraits<String>;
|
||||
|
||||
using ShortString = Detail::ShortString;
|
||||
|
||||
@@ -238,97 +238,15 @@ private:
|
||||
};
|
||||
|
||||
template<>
|
||||
class Optional<String> : public OptionalBase<String> {
|
||||
template<typename U>
|
||||
friend class Optional;
|
||||
struct SentinelOptionalTraits<String> {
|
||||
static constexpr String sentinel_value() { return String(nullptr); }
|
||||
static constexpr bool is_sentinel(String const& value) { return value.is_invalid(); }
|
||||
};
|
||||
|
||||
template<>
|
||||
class Optional<String> : public SentinelOptional<String> {
|
||||
public:
|
||||
using ValueType = String;
|
||||
|
||||
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 };
|
||||
using SentinelOptional::SentinelOptional;
|
||||
};
|
||||
|
||||
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_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)
|
||||
{
|
||||
}
|
||||
|
||||
[[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.
|
||||
[[nodiscard]] static size_t number_of_utf16_fly_strings();
|
||||
@@ -159,93 +159,15 @@ private:
|
||||
};
|
||||
|
||||
template<>
|
||||
class Optional<Utf16FlyString> : public OptionalBase<Utf16FlyString> {
|
||||
template<typename U>
|
||||
friend class Optional;
|
||||
struct SentinelOptionalTraits<Utf16FlyString> {
|
||||
static constexpr Utf16FlyString sentinel_value() { return Utf16FlyString({}, nullptr); }
|
||||
static constexpr bool is_sentinel(Utf16FlyString const& value) { return value.is_invalid({}); }
|
||||
};
|
||||
|
||||
template<>
|
||||
class Optional<Utf16FlyString> : public SentinelOptional<Utf16FlyString> {
|
||||
public:
|
||||
using ValueType = Utf16FlyString;
|
||||
|
||||
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 };
|
||||
using SentinelOptional::SentinelOptional;
|
||||
};
|
||||
|
||||
template<>
|
||||
|
||||
@@ -41,99 +41,15 @@ private:
|
||||
namespace AK {
|
||||
|
||||
template<>
|
||||
class Optional<JS::Bytecode::IdentifierTableIndex> : public OptionalBase<JS::Bytecode::IdentifierTableIndex> {
|
||||
template<typename U>
|
||||
friend class Optional;
|
||||
struct SentinelOptionalTraits<JS::Bytecode::IdentifierTableIndex> {
|
||||
static constexpr JS::Bytecode::IdentifierTableIndex sentinel_value() { return { JS::Bytecode::IdentifierTableIndex::invalid }; }
|
||||
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:
|
||||
using ValueType = JS::Bytecode::IdentifierTableIndex;
|
||||
|
||||
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 };
|
||||
using SentinelOptional::SentinelOptional;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -62,99 +62,15 @@ private:
|
||||
namespace AK {
|
||||
|
||||
template<>
|
||||
class Optional<JS::Bytecode::Operand> : public OptionalBase<JS::Bytecode::Operand> {
|
||||
template<typename U>
|
||||
friend class Optional;
|
||||
struct SentinelOptionalTraits<JS::Bytecode::Operand> {
|
||||
static JS::Bytecode::Operand sentinel_value() { return JS::Bytecode::Operand { JS::Bytecode::Operand::ShouldMakeInvalid::Indeed }; }
|
||||
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:
|
||||
using ValueType = JS::Bytecode::Operand;
|
||||
|
||||
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 };
|
||||
using SentinelOptional::SentinelOptional;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -47,99 +47,15 @@ private:
|
||||
namespace AK {
|
||||
|
||||
template<>
|
||||
class Optional<JS::Bytecode::PropertyKeyTableIndex> : public OptionalBase<JS::Bytecode::PropertyKeyTableIndex> {
|
||||
template<typename U>
|
||||
friend class Optional;
|
||||
struct SentinelOptionalTraits<JS::Bytecode::PropertyKeyTableIndex> {
|
||||
static constexpr JS::Bytecode::PropertyKeyTableIndex sentinel_value() { return { JS::Bytecode::PropertyKeyTableIndex::invalid }; }
|
||||
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:
|
||||
using ValueType = JS::Bytecode::PropertyKeyTableIndex;
|
||||
|
||||
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 };
|
||||
using SentinelOptional::SentinelOptional;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -39,99 +39,15 @@ private:
|
||||
namespace AK {
|
||||
|
||||
template<>
|
||||
class Optional<JS::Bytecode::StringTableIndex> : public OptionalBase<JS::Bytecode::StringTableIndex> {
|
||||
template<typename U>
|
||||
friend class Optional;
|
||||
struct SentinelOptionalTraits<JS::Bytecode::StringTableIndex> {
|
||||
static constexpr JS::Bytecode::StringTableIndex sentinel_value() { return { JS::Bytecode::StringTableIndex::invalid }; }
|
||||
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:
|
||||
using ValueType = JS::Bytecode::StringTableIndex;
|
||||
|
||||
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 };
|
||||
using SentinelOptional::SentinelOptional;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ public:
|
||||
private:
|
||||
class EmptyTag {
|
||||
};
|
||||
friend AK::Optional<Completion>;
|
||||
friend struct AK::SentinelOptionalTraits<Completion>;
|
||||
|
||||
constexpr Completion(EmptyTag)
|
||||
: m_type(Type::Empty)
|
||||
@@ -135,88 +135,15 @@ private:
|
||||
namespace AK {
|
||||
|
||||
template<>
|
||||
class Optional<JS::Completion> : public OptionalBase<JS::Completion> {
|
||||
template<typename U>
|
||||
friend class Optional;
|
||||
struct SentinelOptionalTraits<JS::Completion> {
|
||||
static constexpr JS::Completion sentinel_value() { return JS::Completion(JS::Completion::EmptyTag {}); }
|
||||
static constexpr bool is_sentinel(JS::Completion const& value) { return value.is_empty(); }
|
||||
};
|
||||
|
||||
template<>
|
||||
class Optional<JS::Completion> : public SentinelOptional<JS::Completion> {
|
||||
public:
|
||||
using ValueType = JS::Completion;
|
||||
|
||||
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 {} };
|
||||
using SentinelOptional::SentinelOptional;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -179,7 +179,7 @@ public:
|
||||
|
||||
private:
|
||||
friend Traits<PropertyKey>;
|
||||
friend class Optional<PropertyKey>;
|
||||
friend struct AK::SentinelOptionalTraits<PropertyKey>;
|
||||
|
||||
enum class ShouldMakeEmptyOptional {
|
||||
Indeed,
|
||||
@@ -242,99 +242,15 @@ struct Formatter<JS::PropertyKey> : Formatter<Utf16String> {
|
||||
};
|
||||
|
||||
template<>
|
||||
class Optional<JS::PropertyKey> : public OptionalBase<JS::PropertyKey> {
|
||||
template<typename U>
|
||||
friend class Optional;
|
||||
struct SentinelOptionalTraits<JS::PropertyKey> {
|
||||
static JS::PropertyKey sentinel_value() { return JS::PropertyKey { JS::PropertyKey::ShouldMakeEmptyOptional::Indeed }; }
|
||||
static bool is_sentinel(JS::PropertyKey const& value) { return value.is_empty_optional(); }
|
||||
};
|
||||
|
||||
template<>
|
||||
class Optional<JS::PropertyKey> : public SentinelOptional<JS::PropertyKey> {
|
||||
public:
|
||||
using ValueType = JS::PropertyKey;
|
||||
|
||||
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 };
|
||||
using SentinelOptional::SentinelOptional;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -99,99 +99,15 @@ struct Traits<JS::Utf16String> : public DefaultTraits<JS::Utf16String> {
|
||||
};
|
||||
|
||||
template<>
|
||||
class Optional<JS::Utf16String> : public OptionalBase<JS::Utf16String> {
|
||||
template<typename U>
|
||||
friend class Optional;
|
||||
struct SentinelOptionalTraits<JS::Utf16String> {
|
||||
static JS::Utf16String sentinel_value() { return JS::Utf16String::invalid(); }
|
||||
static bool is_sentinel(JS::Utf16String const& value) { return !value.is_valid(); }
|
||||
};
|
||||
|
||||
template<>
|
||||
class Optional<JS::Utf16String> : public SentinelOptional<JS::Utf16String> {
|
||||
public:
|
||||
using ValueType = JS::Utf16String;
|
||||
|
||||
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() };
|
||||
using SentinelOptional::SentinelOptional;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -608,99 +608,15 @@ namespace AK {
|
||||
static_assert(sizeof(JS::Value) == sizeof(double));
|
||||
|
||||
template<>
|
||||
class Optional<JS::Value> : public OptionalBase<JS::Value> {
|
||||
template<typename U>
|
||||
friend class Optional;
|
||||
struct SentinelOptionalTraits<JS::Value> {
|
||||
static constexpr JS::Value sentinel_value() { return JS::js_special_empty_value(); }
|
||||
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:
|
||||
using ValueType = JS::Value;
|
||||
|
||||
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() };
|
||||
using SentinelOptional::SentinelOptional;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <AK/ByteString.h>
|
||||
#include <AK/FlyString.h>
|
||||
#include <AK/NumericLimits.h>
|
||||
#include <AK/Optional.h>
|
||||
#include <AK/String.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);
|
||||
}
|
||||
}
|
||||
|
||||
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