mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-25 09:00:22 +00:00
Compare commits
3 commits
2442776238
...
d538490d80
Author | SHA1 | Date | |
---|---|---|---|
|
d538490d80 | ||
|
2c9860cd60 | ||
|
89d789ac4e |
10 changed files with 226 additions and 162 deletions
|
@ -21,7 +21,7 @@ class FlyString {
|
||||||
AK_MAKE_DEFAULT_COPYABLE(FlyString);
|
AK_MAKE_DEFAULT_COPYABLE(FlyString);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FlyString() = default;
|
constexpr FlyString() = default;
|
||||||
|
|
||||||
static ErrorOr<FlyString> from_utf8(StringView);
|
static ErrorOr<FlyString> from_utf8(StringView);
|
||||||
static FlyString from_utf8_without_validation(ReadonlyBytes);
|
static FlyString from_utf8_without_validation(ReadonlyBytes);
|
||||||
|
@ -83,7 +83,7 @@ public:
|
||||||
private:
|
private:
|
||||||
friend class Optional<FlyString>;
|
friend class Optional<FlyString>;
|
||||||
|
|
||||||
explicit FlyString(nullptr_t)
|
explicit constexpr FlyString(nullptr_t)
|
||||||
: m_data(Detail::StringBase(nullptr))
|
: m_data(Detail::StringBase(nullptr))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -106,38 +106,38 @@ class Optional<FlyString> : public OptionalBase<FlyString> {
|
||||||
public:
|
public:
|
||||||
using ValueType = FlyString;
|
using ValueType = FlyString;
|
||||||
|
|
||||||
Optional() = default;
|
constexpr Optional() = default;
|
||||||
|
|
||||||
template<SameAs<OptionalNone> V>
|
template<SameAs<OptionalNone> V>
|
||||||
Optional(V) { }
|
constexpr Optional(V) { }
|
||||||
|
|
||||||
Optional(Optional<FlyString> const& other)
|
constexpr Optional(Optional<FlyString> const& other)
|
||||||
{
|
{
|
||||||
if (other.has_value())
|
if (other.has_value())
|
||||||
m_value = other.m_value;
|
m_value = other.m_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional(Optional&& other)
|
Optional(Optional&& other)
|
||||||
: m_value(other.m_value)
|
: m_value(move(other.m_value))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U = FlyString>
|
template<typename U = FlyString>
|
||||||
requires(!IsSame<OptionalNone, RemoveCVReference<U>>)
|
requires(!IsSame<OptionalNone, RemoveCVReference<U>>)
|
||||||
explicit(!IsConvertible<U&&, FlyString>) Optional(U&& value)
|
explicit(!IsConvertible<U&&, FlyString>) constexpr Optional(U&& value)
|
||||||
requires(!IsSame<RemoveCVReference<U>, Optional<FlyString>> && IsConstructible<FlyString, U &&>)
|
requires(!IsSame<RemoveCVReference<U>, Optional<FlyString>> && IsConstructible<FlyString, U &&>)
|
||||||
: m_value(forward<U>(value))
|
: m_value(forward<U>(value))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template<SameAs<OptionalNone> V>
|
template<SameAs<OptionalNone> V>
|
||||||
Optional& operator=(V)
|
constexpr Optional& operator=(V)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional& operator=(Optional const& other)
|
constexpr Optional& operator=(Optional const& other)
|
||||||
{
|
{
|
||||||
if (this != &other) {
|
if (this != &other) {
|
||||||
clear();
|
clear();
|
||||||
|
@ -146,7 +146,7 @@ public:
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional& operator=(Optional&& other)
|
constexpr Optional& operator=(Optional&& other)
|
||||||
{
|
{
|
||||||
if (this != &other) {
|
if (this != &other) {
|
||||||
clear();
|
clear();
|
||||||
|
@ -156,40 +156,40 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename O>
|
template<typename O>
|
||||||
ALWAYS_INLINE bool operator==(Optional<O> const& other) const
|
ALWAYS_INLINE constexpr bool operator==(Optional<O> const& other) const
|
||||||
{
|
{
|
||||||
return has_value() == other.has_value() && (!has_value() || value() == other.value());
|
return has_value() == other.has_value() && (!has_value() || value() == other.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename O>
|
template<typename O>
|
||||||
ALWAYS_INLINE bool operator==(O const& other) const
|
ALWAYS_INLINE constexpr bool operator==(O const& other) const
|
||||||
{
|
{
|
||||||
return has_value() && value() == other;
|
return has_value() && value() == other;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear()
|
constexpr void clear()
|
||||||
{
|
{
|
||||||
m_value = FlyString(nullptr);
|
m_value = FlyString(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] bool has_value() const
|
[[nodiscard]] constexpr bool has_value() const
|
||||||
{
|
{
|
||||||
return !m_value.is_invalid();
|
return !m_value.is_invalid();
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] FlyString& value() &
|
[[nodiscard]] constexpr FlyString& value() &
|
||||||
{
|
{
|
||||||
VERIFY(has_value());
|
VERIFY(has_value());
|
||||||
return m_value;
|
return m_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] FlyString const& value() const&
|
[[nodiscard]] constexpr FlyString const& value() const&
|
||||||
{
|
{
|
||||||
VERIFY(has_value());
|
VERIFY(has_value());
|
||||||
return m_value;
|
return m_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] FlyString value() &&
|
[[nodiscard]] constexpr FlyString value() &&
|
||||||
{
|
{
|
||||||
return release_value();
|
return release_value();
|
||||||
}
|
}
|
||||||
|
|
195
AK/Optional.h
195
AK/Optional.h
|
@ -46,7 +46,7 @@ template<typename>
|
||||||
class Optional;
|
class Optional;
|
||||||
|
|
||||||
struct OptionalNone {
|
struct OptionalNone {
|
||||||
explicit OptionalNone() = default;
|
explicit constexpr OptionalNone() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, typename Self = Optional<T>>
|
template<typename T, typename Self = Optional<T>>
|
||||||
|
@ -55,30 +55,30 @@ public:
|
||||||
using ValueType = T;
|
using ValueType = T;
|
||||||
|
|
||||||
template<SameAs<OptionalNone> V>
|
template<SameAs<OptionalNone> V>
|
||||||
Self& operator=(V)
|
constexpr Self& operator=(V)
|
||||||
{
|
{
|
||||||
static_cast<Self&>(*this).clear();
|
static_cast<Self&>(*this).clear();
|
||||||
return static_cast<Self&>(*this);
|
return static_cast<Self&>(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] ALWAYS_INLINE T* ptr() &
|
[[nodiscard]] ALWAYS_INLINE constexpr T* ptr() &
|
||||||
{
|
{
|
||||||
return static_cast<Self&>(*this).has_value() ? __builtin_launder(reinterpret_cast<T*>(&static_cast<Self&>(*this).value())) : nullptr;
|
return static_cast<Self&>(*this).has_value() ? __builtin_launder(reinterpret_cast<T*>(&static_cast<Self&>(*this).value())) : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] ALWAYS_INLINE T const* ptr() const&
|
[[nodiscard]] ALWAYS_INLINE constexpr T const* ptr() const&
|
||||||
{
|
{
|
||||||
return static_cast<Self const&>(*this).has_value() ? __builtin_launder(reinterpret_cast<T const*>(&static_cast<Self const&>(*this).value())) : nullptr;
|
return static_cast<Self const&>(*this).has_value() ? __builtin_launder(reinterpret_cast<T const*>(&static_cast<Self const&>(*this).value())) : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] ALWAYS_INLINE T value_or(T const& fallback) const&
|
[[nodiscard]] ALWAYS_INLINE constexpr T value_or(T const& fallback) const&
|
||||||
{
|
{
|
||||||
if (static_cast<Self const&>(*this).has_value())
|
if (static_cast<Self const&>(*this).has_value())
|
||||||
return static_cast<Self const&>(*this).value();
|
return static_cast<Self const&>(*this).value();
|
||||||
return fallback;
|
return fallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] ALWAYS_INLINE T value_or(T&& fallback) &&
|
[[nodiscard]] ALWAYS_INLINE constexpr T value_or(T&& fallback) &&
|
||||||
{
|
{
|
||||||
if (static_cast<Self&>(*this).has_value())
|
if (static_cast<Self&>(*this).has_value())
|
||||||
return move(static_cast<Self&>(*this).value());
|
return move(static_cast<Self&>(*this).value());
|
||||||
|
@ -86,7 +86,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Callback, typename O = T>
|
template<typename Callback, typename O = T>
|
||||||
[[nodiscard]] ALWAYS_INLINE O value_or_lazy_evaluated(Callback callback) const
|
[[nodiscard]] ALWAYS_INLINE constexpr O value_or_lazy_evaluated(Callback callback) const
|
||||||
{
|
{
|
||||||
if (static_cast<Self const&>(*this).has_value())
|
if (static_cast<Self const&>(*this).has_value())
|
||||||
return static_cast<Self const&>(*this).value();
|
return static_cast<Self const&>(*this).value();
|
||||||
|
@ -94,7 +94,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Callback, typename O = T>
|
template<typename Callback, typename O = T>
|
||||||
[[nodiscard]] ALWAYS_INLINE Optional<O> value_or_lazy_evaluated_optional(Callback callback) const
|
[[nodiscard]] ALWAYS_INLINE constexpr Optional<O> value_or_lazy_evaluated_optional(Callback callback) const
|
||||||
{
|
{
|
||||||
if (static_cast<Self const&>(*this).has_value())
|
if (static_cast<Self const&>(*this).has_value())
|
||||||
return static_cast<Self const&>(*this).value();
|
return static_cast<Self const&>(*this).value();
|
||||||
|
@ -102,7 +102,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Callback, typename O = T>
|
template<typename Callback, typename O = T>
|
||||||
[[nodiscard]] ALWAYS_INLINE ErrorOr<O> try_value_or_lazy_evaluated(Callback callback) const
|
[[nodiscard]] ALWAYS_INLINE constexpr ErrorOr<O> try_value_or_lazy_evaluated(Callback callback) const
|
||||||
{
|
{
|
||||||
if (static_cast<Self const&>(*this).has_value())
|
if (static_cast<Self const&>(*this).has_value())
|
||||||
return static_cast<Self const&>(*this).value();
|
return static_cast<Self const&>(*this).value();
|
||||||
|
@ -110,7 +110,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Callback, typename O = T>
|
template<typename Callback, typename O = T>
|
||||||
[[nodiscard]] ALWAYS_INLINE ErrorOr<Optional<O>> try_value_or_lazy_evaluated_optional(Callback callback) const
|
[[nodiscard]] ALWAYS_INLINE constexpr ErrorOr<Optional<O>> try_value_or_lazy_evaluated_optional(Callback callback) const
|
||||||
{
|
{
|
||||||
if (static_cast<Self const&>(*this).has_value())
|
if (static_cast<Self const&>(*this).has_value())
|
||||||
return static_cast<Self const&>(*this).value();
|
return static_cast<Self const&>(*this).value();
|
||||||
|
@ -118,7 +118,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename O>
|
template<typename O>
|
||||||
ALWAYS_INLINE bool operator==(Optional<O> const& other) const
|
ALWAYS_INLINE constexpr bool operator==(Optional<O> const& other) const
|
||||||
{
|
{
|
||||||
return static_cast<Self const&>(*this).has_value() == (other).has_value()
|
return static_cast<Self const&>(*this).has_value() == (other).has_value()
|
||||||
&& (!static_cast<Self const&>(*this).has_value() || static_cast<Self const&>(*this).value() == (other).value());
|
&& (!static_cast<Self const&>(*this).has_value() || static_cast<Self const&>(*this).value() == (other).value());
|
||||||
|
@ -126,19 +126,19 @@ public:
|
||||||
|
|
||||||
template<typename O>
|
template<typename O>
|
||||||
requires(!Detail::IsBaseOf<OptionalBase<T, Self>, O>)
|
requires(!Detail::IsBaseOf<OptionalBase<T, Self>, O>)
|
||||||
ALWAYS_INLINE bool operator==(O const& other) const
|
ALWAYS_INLINE constexpr bool operator==(O const& other) const
|
||||||
{
|
{
|
||||||
return static_cast<Self const&>(*this).has_value() && static_cast<Self const&>(*this).value() == other;
|
return static_cast<Self const&>(*this).has_value() && static_cast<Self const&>(*this).value() == other;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] ALWAYS_INLINE T const& operator*() const { return static_cast<Self const&>(*this).value(); }
|
[[nodiscard]] ALWAYS_INLINE constexpr T const& operator*() const { return static_cast<Self const&>(*this).value(); }
|
||||||
[[nodiscard]] ALWAYS_INLINE T& operator*() { return static_cast<Self&>(*this).value(); }
|
[[nodiscard]] ALWAYS_INLINE constexpr T& operator*() { return static_cast<Self&>(*this).value(); }
|
||||||
|
|
||||||
ALWAYS_INLINE T const* operator->() const { return &static_cast<Self const&>(*this).value(); }
|
ALWAYS_INLINE constexpr T const* operator->() const { return &static_cast<Self const&>(*this).value(); }
|
||||||
ALWAYS_INLINE T* operator->() { return &static_cast<Self&>(*this).value(); }
|
ALWAYS_INLINE constexpr T* operator->() { return &static_cast<Self&>(*this).value(); }
|
||||||
|
|
||||||
template<typename F, typename MappedType = decltype(declval<F>()(declval<T&>())), auto IsErrorOr = IsSpecializationOf<MappedType, ErrorOr>, typename OptionalType = Optional<ConditionallyResultType<IsErrorOr, MappedType>>>
|
template<typename F, typename MappedType = decltype(declval<F>()(declval<T&>())), auto IsErrorOr = IsSpecializationOf<MappedType, ErrorOr>, typename OptionalType = Optional<ConditionallyResultType<IsErrorOr, MappedType>>>
|
||||||
ALWAYS_INLINE Conditional<IsErrorOr, ErrorOr<OptionalType>, OptionalType> map(F&& mapper)
|
ALWAYS_INLINE constexpr Conditional<IsErrorOr, ErrorOr<OptionalType>, OptionalType> map(F&& mapper)
|
||||||
{
|
{
|
||||||
if constexpr (IsErrorOr) {
|
if constexpr (IsErrorOr) {
|
||||||
if (static_cast<Self&>(*this).has_value())
|
if (static_cast<Self&>(*this).has_value())
|
||||||
|
@ -153,7 +153,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename F, typename MappedType = decltype(declval<F>()(declval<T&>())), auto IsErrorOr = IsSpecializationOf<MappedType, ErrorOr>, typename OptionalType = Optional<ConditionallyResultType<IsErrorOr, MappedType>>>
|
template<typename F, typename MappedType = decltype(declval<F>()(declval<T&>())), auto IsErrorOr = IsSpecializationOf<MappedType, ErrorOr>, typename OptionalType = Optional<ConditionallyResultType<IsErrorOr, MappedType>>>
|
||||||
ALWAYS_INLINE Conditional<IsErrorOr, ErrorOr<OptionalType>, OptionalType> map(F&& mapper) const
|
ALWAYS_INLINE constexpr Conditional<IsErrorOr, ErrorOr<OptionalType>, OptionalType> map(F&& mapper) const
|
||||||
{
|
{
|
||||||
if constexpr (IsErrorOr) {
|
if constexpr (IsErrorOr) {
|
||||||
if (static_cast<Self const&>(*this).has_value())
|
if (static_cast<Self const&>(*this).has_value())
|
||||||
|
@ -178,13 +178,19 @@ requires(!IsLvalueReference<T>) class [[nodiscard]] Optional<T> : public Optiona
|
||||||
public:
|
public:
|
||||||
using ValueType = T;
|
using ValueType = T;
|
||||||
|
|
||||||
ALWAYS_INLINE Optional() = default;
|
ALWAYS_INLINE constexpr Optional()
|
||||||
|
: m_null()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
template<SameAs<OptionalNone> V>
|
template<SameAs<OptionalNone> V>
|
||||||
Optional(V) { }
|
constexpr Optional(V)
|
||||||
|
: m_null()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
template<SameAs<OptionalNone> V>
|
template<SameAs<OptionalNone> V>
|
||||||
Optional& operator=(V)
|
constexpr Optional& operator=(V)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -194,143 +200,146 @@ public:
|
||||||
AK_MAKE_CONDITIONALLY_NONMOVABLE(Optional, <T>);
|
AK_MAKE_CONDITIONALLY_NONMOVABLE(Optional, <T>);
|
||||||
AK_MAKE_CONDITIONALLY_DESTRUCTIBLE(Optional, <T>);
|
AK_MAKE_CONDITIONALLY_DESTRUCTIBLE(Optional, <T>);
|
||||||
|
|
||||||
ALWAYS_INLINE Optional(Optional const& other)
|
ALWAYS_INLINE constexpr Optional(Optional const& other)
|
||||||
requires(!IsTriviallyCopyConstructible<T>)
|
requires(!IsTriviallyCopyConstructible<T>)
|
||||||
: m_has_value(other.m_has_value)
|
: m_has_value(other.m_has_value)
|
||||||
{
|
{
|
||||||
if (other.has_value())
|
if (other.has_value())
|
||||||
new (&m_storage) T(other.value());
|
construct_at(&m_value, other.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE Optional(Optional&& other)
|
ALWAYS_INLINE constexpr Optional(Optional&& other)
|
||||||
: m_has_value(other.m_has_value)
|
: m_has_value(other.m_has_value)
|
||||||
{
|
{
|
||||||
if (other.has_value())
|
if (other.has_value())
|
||||||
new (&m_storage) T(other.release_value());
|
construct_at(&m_value, other.release_value());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
requires(IsConstructible<T, U const&> && !IsSpecializationOf<T, Optional> && !IsSpecializationOf<U, Optional>) ALWAYS_INLINE explicit Optional(Optional<U> const& other)
|
requires(IsConstructible<T, U const&> && !IsSpecializationOf<T, Optional> && !IsSpecializationOf<U, Optional>) ALWAYS_INLINE explicit constexpr Optional(Optional<U> const& other)
|
||||||
: m_has_value(other.has_value())
|
: m_has_value(other.has_value())
|
||||||
{
|
{
|
||||||
if (other.has_value())
|
if (other.has_value())
|
||||||
new (&m_storage) T(other.value());
|
construct_at(&m_value, other.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
requires(IsConstructible<T, U &&> && !IsSpecializationOf<T, Optional> && !IsSpecializationOf<U, Optional>) ALWAYS_INLINE explicit Optional(Optional<U>&& other)
|
requires(IsConstructible<T, U &&> && !IsSpecializationOf<T, Optional> && !IsSpecializationOf<U, Optional>) ALWAYS_INLINE explicit constexpr Optional(Optional<U>&& other)
|
||||||
: m_has_value(other.has_value())
|
: m_has_value(other.has_value())
|
||||||
{
|
{
|
||||||
if (other.has_value())
|
if (other.has_value())
|
||||||
new (&m_storage) T(other.release_value());
|
construct_at(&m_value, other.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U = T>
|
template<typename U = T>
|
||||||
requires(!IsSame<OptionalNone, RemoveCVReference<U>>)
|
requires(!IsSame<OptionalNone, RemoveCVReference<U>>)
|
||||||
ALWAYS_INLINE explicit(!IsConvertible<U&&, T>) Optional(U&& value)
|
ALWAYS_INLINE explicit(!IsConvertible<U&&, T>) constexpr Optional(U&& value)
|
||||||
requires(!IsSame<RemoveCVReference<U>, Optional<T>> && IsConstructible<T, U &&>)
|
requires(!IsSame<RemoveCVReference<U>, Optional<T>> && IsConstructible<T, U &&>)
|
||||||
: m_has_value(true)
|
: m_has_value(true)
|
||||||
{
|
{
|
||||||
new (&m_storage) T(forward<U>(value));
|
construct_at(&m_value, forward<U>(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE Optional& operator=(Optional const& other)
|
ALWAYS_INLINE constexpr Optional& operator=(Optional const& other)
|
||||||
requires(!IsTriviallyCopyConstructible<T> || !IsTriviallyDestructible<T>)
|
requires(!IsTriviallyCopyConstructible<T> || !IsTriviallyDestructible<T>)
|
||||||
{
|
{
|
||||||
if (this != &other) {
|
if (this != &other) {
|
||||||
clear();
|
clear();
|
||||||
m_has_value = other.m_has_value;
|
m_has_value = other.m_has_value;
|
||||||
if (other.has_value()) {
|
if (other.has_value()) {
|
||||||
new (&m_storage) T(other.value());
|
construct_at(&m_value, other.value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE Optional& operator=(Optional&& other)
|
ALWAYS_INLINE constexpr Optional& operator=(Optional&& other)
|
||||||
{
|
{
|
||||||
if (this != &other) {
|
if (this != &other) {
|
||||||
clear();
|
clear();
|
||||||
m_has_value = other.m_has_value;
|
m_has_value = other.m_has_value;
|
||||||
if (other.has_value()) {
|
if (other.has_value()) {
|
||||||
new (&m_storage) T(other.release_value());
|
construct_at(&m_value, other.release_value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename O>
|
template<typename O>
|
||||||
ALWAYS_INLINE bool operator==(Optional<O> const& other) const
|
ALWAYS_INLINE constexpr bool operator==(Optional<O> const& other) const
|
||||||
{
|
{
|
||||||
return has_value() == other.has_value() && (!has_value() || value() == other.value());
|
return has_value() == other.has_value() && (!has_value() || value() == other.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename O>
|
template<typename O>
|
||||||
ALWAYS_INLINE bool operator==(O const& other) const
|
ALWAYS_INLINE constexpr bool operator==(O const& other) const
|
||||||
{
|
{
|
||||||
return has_value() && value() == other;
|
return has_value() && value() == other;
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE ~Optional()
|
ALWAYS_INLINE constexpr ~Optional()
|
||||||
requires(!IsTriviallyDestructible<T> && IsDestructible<T>)
|
requires(!IsTriviallyDestructible<T> && IsDestructible<T>)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE void clear()
|
ALWAYS_INLINE constexpr void clear()
|
||||||
{
|
{
|
||||||
if (m_has_value) {
|
if (m_has_value) {
|
||||||
value().~T();
|
m_value.~T();
|
||||||
m_has_value = false;
|
m_has_value = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Parameters>
|
template<typename... Parameters>
|
||||||
ALWAYS_INLINE void emplace(Parameters&&... parameters)
|
ALWAYS_INLINE constexpr void emplace(Parameters&&... parameters)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
m_has_value = true;
|
m_has_value = true;
|
||||||
new (&m_storage) T(forward<Parameters>(parameters)...);
|
construct_at(&m_value, forward<Parameters>(parameters)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Callable>
|
template<typename Callable>
|
||||||
ALWAYS_INLINE void lazy_emplace(Callable callable)
|
ALWAYS_INLINE constexpr void lazy_emplace(Callable callable)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
m_has_value = true;
|
m_has_value = true;
|
||||||
new (&m_storage) T { callable() };
|
construct_at(&m_value, callable());
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] ALWAYS_INLINE bool has_value() const { return m_has_value; }
|
[[nodiscard]] ALWAYS_INLINE constexpr bool has_value() const { return m_has_value; }
|
||||||
|
|
||||||
[[nodiscard]] ALWAYS_INLINE T& value() &
|
[[nodiscard]] ALWAYS_INLINE constexpr T& value() &
|
||||||
{
|
{
|
||||||
VERIFY(m_has_value);
|
VERIFY(m_has_value);
|
||||||
return *__builtin_launder(reinterpret_cast<T*>(&m_storage));
|
return m_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] ALWAYS_INLINE T const& value() const&
|
[[nodiscard]] ALWAYS_INLINE constexpr T const& value() const&
|
||||||
{
|
{
|
||||||
VERIFY(m_has_value);
|
VERIFY(m_has_value);
|
||||||
return *__builtin_launder(reinterpret_cast<T const*>(&m_storage));
|
return m_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] ALWAYS_INLINE T value() &&
|
[[nodiscard]] ALWAYS_INLINE constexpr T value() &&
|
||||||
{
|
{
|
||||||
return release_value();
|
return release_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] ALWAYS_INLINE T release_value()
|
[[nodiscard]] ALWAYS_INLINE constexpr T release_value()
|
||||||
{
|
{
|
||||||
VERIFY(m_has_value);
|
VERIFY(m_has_value);
|
||||||
T released_value = move(value());
|
T released_value = move(m_value);
|
||||||
value().~T();
|
m_value.~T();
|
||||||
m_has_value = false;
|
m_has_value = false;
|
||||||
return released_value;
|
return released_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
alignas(T) u8 m_storage[sizeof(T)];
|
union {
|
||||||
|
char m_null;
|
||||||
|
T m_value;
|
||||||
|
};
|
||||||
bool m_has_value { false };
|
bool m_has_value { false };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -345,76 +354,76 @@ requires(IsLvalueReference<T>) class [[nodiscard]] Optional<T> {
|
||||||
public:
|
public:
|
||||||
using ValueType = T;
|
using ValueType = T;
|
||||||
|
|
||||||
ALWAYS_INLINE Optional() = default;
|
ALWAYS_INLINE constexpr Optional() = default;
|
||||||
|
|
||||||
template<SameAs<OptionalNone> V>
|
template<SameAs<OptionalNone> V>
|
||||||
Optional(V) { }
|
constexpr Optional(V) { }
|
||||||
|
|
||||||
template<SameAs<OptionalNone> V>
|
template<SameAs<OptionalNone> V>
|
||||||
Optional& operator=(V)
|
constexpr Optional& operator=(V)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U = T>
|
template<typename U = T>
|
||||||
ALWAYS_INLINE Optional(U& value)
|
ALWAYS_INLINE constexpr Optional(U& value)
|
||||||
requires(CanBePlacedInOptional<U&>)
|
requires(CanBePlacedInOptional<U&>)
|
||||||
: m_pointer(&value)
|
: m_pointer(&value)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE Optional(RemoveReference<T>& value)
|
ALWAYS_INLINE constexpr Optional(RemoveReference<T>& value)
|
||||||
: m_pointer(&value)
|
: m_pointer(&value)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE Optional(Optional const& other)
|
ALWAYS_INLINE constexpr Optional(Optional const& other)
|
||||||
: m_pointer(other.m_pointer)
|
: m_pointer(other.m_pointer)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE Optional(Optional&& other)
|
ALWAYS_INLINE constexpr Optional(Optional&& other)
|
||||||
: m_pointer(other.m_pointer)
|
: m_pointer(other.m_pointer)
|
||||||
{
|
{
|
||||||
other.m_pointer = nullptr;
|
other.m_pointer = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
ALWAYS_INLINE Optional(Optional<U>& other)
|
ALWAYS_INLINE constexpr Optional(Optional<U>& other)
|
||||||
requires(CanBePlacedInOptional<U>)
|
requires(CanBePlacedInOptional<U>)
|
||||||
: m_pointer(other.ptr())
|
: m_pointer(other.ptr())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
ALWAYS_INLINE Optional(Optional<U> const& other)
|
ALWAYS_INLINE constexpr Optional(Optional<U> const& other)
|
||||||
requires(CanBePlacedInOptional<U const>)
|
requires(CanBePlacedInOptional<U const>)
|
||||||
: m_pointer(other.ptr())
|
: m_pointer(other.ptr())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
ALWAYS_INLINE Optional(Optional<U>&& other)
|
ALWAYS_INLINE constexpr Optional(Optional<U>&& other)
|
||||||
requires(CanBePlacedInOptional<U>)
|
requires(CanBePlacedInOptional<U>)
|
||||||
: m_pointer(other.ptr())
|
: m_pointer(other.ptr())
|
||||||
{
|
{
|
||||||
other.m_pointer = nullptr;
|
other.m_pointer = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE Optional& operator=(Optional& other)
|
ALWAYS_INLINE constexpr Optional& operator=(Optional& other)
|
||||||
{
|
{
|
||||||
m_pointer = other.m_pointer;
|
m_pointer = other.m_pointer;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE Optional& operator=(Optional const& other)
|
ALWAYS_INLINE constexpr Optional& operator=(Optional const& other)
|
||||||
{
|
{
|
||||||
m_pointer = other.m_pointer;
|
m_pointer = other.m_pointer;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE Optional& operator=(Optional&& other)
|
ALWAYS_INLINE constexpr Optional& operator=(Optional&& other)
|
||||||
{
|
{
|
||||||
m_pointer = other.m_pointer;
|
m_pointer = other.m_pointer;
|
||||||
other.m_pointer = nullptr;
|
other.m_pointer = nullptr;
|
||||||
|
@ -422,7 +431,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
ALWAYS_INLINE Optional& operator=(Optional<U>& other)
|
ALWAYS_INLINE constexpr Optional& operator=(Optional<U>& other)
|
||||||
requires(CanBePlacedInOptional<U>)
|
requires(CanBePlacedInOptional<U>)
|
||||||
{
|
{
|
||||||
m_pointer = other.ptr();
|
m_pointer = other.ptr();
|
||||||
|
@ -430,7 +439,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
ALWAYS_INLINE Optional& operator=(Optional<U> const& other)
|
ALWAYS_INLINE constexpr Optional& operator=(Optional<U> const& other)
|
||||||
requires(CanBePlacedInOptional<U const>)
|
requires(CanBePlacedInOptional<U const>)
|
||||||
{
|
{
|
||||||
m_pointer = other.ptr();
|
m_pointer = other.ptr();
|
||||||
|
@ -438,7 +447,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
ALWAYS_INLINE Optional& operator=(Optional<U>&& other)
|
ALWAYS_INLINE constexpr Optional& operator=(Optional<U>&& other)
|
||||||
requires(CanBePlacedInOptional<U> && IsLvalueReference<U>)
|
requires(CanBePlacedInOptional<U> && IsLvalueReference<U>)
|
||||||
{
|
{
|
||||||
m_pointer = other.m_pointer;
|
m_pointer = other.m_pointer;
|
||||||
|
@ -449,44 +458,44 @@ public:
|
||||||
// Note: Disallows assignment from a temporary as this does not do any lifetime extension.
|
// Note: Disallows assignment from a temporary as this does not do any lifetime extension.
|
||||||
template<typename U>
|
template<typename U>
|
||||||
requires(!IsSame<OptionalNone, RemoveCVReference<U>>)
|
requires(!IsSame<OptionalNone, RemoveCVReference<U>>)
|
||||||
ALWAYS_INLINE Optional& operator=(U&& value)
|
ALWAYS_INLINE constexpr Optional& operator=(U&& value)
|
||||||
requires(CanBePlacedInOptional<U> && IsLvalueReference<U>)
|
requires(CanBePlacedInOptional<U> && IsLvalueReference<U>)
|
||||||
{
|
{
|
||||||
m_pointer = &value;
|
m_pointer = &value;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE void clear()
|
ALWAYS_INLINE constexpr void clear()
|
||||||
{
|
{
|
||||||
m_pointer = nullptr;
|
m_pointer = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] ALWAYS_INLINE bool has_value() const { return m_pointer != nullptr; }
|
[[nodiscard]] ALWAYS_INLINE constexpr bool has_value() const { return m_pointer != nullptr; }
|
||||||
|
|
||||||
[[nodiscard]] ALWAYS_INLINE RemoveReference<T>* ptr()
|
[[nodiscard]] ALWAYS_INLINE constexpr RemoveReference<T>* ptr()
|
||||||
{
|
{
|
||||||
return m_pointer;
|
return m_pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] ALWAYS_INLINE RemoveReference<T> const* ptr() const
|
[[nodiscard]] ALWAYS_INLINE constexpr RemoveReference<T> const* ptr() const
|
||||||
{
|
{
|
||||||
return m_pointer;
|
return m_pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] ALWAYS_INLINE T value()
|
[[nodiscard]] ALWAYS_INLINE constexpr T value()
|
||||||
{
|
{
|
||||||
VERIFY(m_pointer);
|
VERIFY(m_pointer);
|
||||||
return *m_pointer;
|
return *m_pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] ALWAYS_INLINE AddConstToReferencedType<T> value() const
|
[[nodiscard]] ALWAYS_INLINE constexpr AddConstToReferencedType<T> value() const
|
||||||
{
|
{
|
||||||
VERIFY(m_pointer);
|
VERIFY(m_pointer);
|
||||||
return *m_pointer;
|
return *m_pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
requires(IsBaseOf<RemoveCVReference<T>, U>) [[nodiscard]] ALWAYS_INLINE AddConstToReferencedType<T> value_or(U& fallback) const
|
requires(IsBaseOf<RemoveCVReference<T>, U>) [[nodiscard]] ALWAYS_INLINE constexpr AddConstToReferencedType<T> value_or(U& fallback) const
|
||||||
{
|
{
|
||||||
if (m_pointer)
|
if (m_pointer)
|
||||||
return value();
|
return value();
|
||||||
|
@ -494,38 +503,38 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note that this ends up copying the value.
|
// Note that this ends up copying the value.
|
||||||
[[nodiscard]] ALWAYS_INLINE RemoveCVReference<T> value_or(RemoveCVReference<T> fallback) const
|
[[nodiscard]] ALWAYS_INLINE constexpr RemoveCVReference<T> value_or(RemoveCVReference<T> fallback) const
|
||||||
{
|
{
|
||||||
if (m_pointer)
|
if (m_pointer)
|
||||||
return value();
|
return value();
|
||||||
return fallback;
|
return fallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] ALWAYS_INLINE T release_value()
|
[[nodiscard]] ALWAYS_INLINE constexpr T release_value()
|
||||||
{
|
{
|
||||||
return *exchange(m_pointer, nullptr);
|
return *exchange(m_pointer, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
ALWAYS_INLINE bool operator==(Optional<U> const& other) const
|
ALWAYS_INLINE constexpr bool operator==(Optional<U> const& other) const
|
||||||
{
|
{
|
||||||
return has_value() == other.has_value() && (!has_value() || value() == other.value());
|
return has_value() == other.has_value() && (!has_value() || value() == other.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
ALWAYS_INLINE bool operator==(U const& other) const
|
ALWAYS_INLINE constexpr bool operator==(U const& other) const
|
||||||
{
|
{
|
||||||
return has_value() && value() == other;
|
return has_value() && value() == other;
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE AddConstToReferencedType<T> operator*() const { return value(); }
|
ALWAYS_INLINE constexpr AddConstToReferencedType<T> operator*() const { return value(); }
|
||||||
ALWAYS_INLINE T operator*() { return value(); }
|
ALWAYS_INLINE constexpr T operator*() { return value(); }
|
||||||
|
|
||||||
ALWAYS_INLINE RawPtr<AddConst<RemoveReference<T>>> operator->() const { return &value(); }
|
ALWAYS_INLINE constexpr RawPtr<AddConst<RemoveReference<T>>> operator->() const { return &value(); }
|
||||||
ALWAYS_INLINE RawPtr<RemoveReference<T>> operator->() { return &value(); }
|
ALWAYS_INLINE constexpr RawPtr<RemoveReference<T>> operator->() { return &value(); }
|
||||||
|
|
||||||
// Conversion operators from Optional<T&> -> Optional<T>
|
// Conversion operators from Optional<T&> -> Optional<T>
|
||||||
ALWAYS_INLINE operator Optional<RemoveCVReference<T>>() const
|
ALWAYS_INLINE constexpr operator Optional<RemoveCVReference<T>>() const
|
||||||
{
|
{
|
||||||
if (has_value())
|
if (has_value())
|
||||||
return Optional<RemoveCVReference<T>>(value());
|
return Optional<RemoveCVReference<T>>(value());
|
||||||
|
@ -533,7 +542,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Callback>
|
template<typename Callback>
|
||||||
[[nodiscard]] ALWAYS_INLINE T value_or_lazy_evaluated(Callback callback) const
|
[[nodiscard]] ALWAYS_INLINE constexpr T value_or_lazy_evaluated(Callback callback) const
|
||||||
{
|
{
|
||||||
if (m_pointer != nullptr)
|
if (m_pointer != nullptr)
|
||||||
return value();
|
return value();
|
||||||
|
@ -541,7 +550,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Callback>
|
template<typename Callback>
|
||||||
[[nodiscard]] ALWAYS_INLINE Optional<T> value_or_lazy_evaluated_optional(Callback callback) const
|
[[nodiscard]] ALWAYS_INLINE constexpr Optional<T> value_or_lazy_evaluated_optional(Callback callback) const
|
||||||
{
|
{
|
||||||
if (m_pointer != nullptr)
|
if (m_pointer != nullptr)
|
||||||
return value();
|
return value();
|
||||||
|
@ -549,7 +558,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Callback>
|
template<typename Callback>
|
||||||
[[nodiscard]] ALWAYS_INLINE ErrorOr<T> try_value_or_lazy_evaluated(Callback callback) const
|
[[nodiscard]] ALWAYS_INLINE constexpr ErrorOr<T> try_value_or_lazy_evaluated(Callback callback) const
|
||||||
{
|
{
|
||||||
if (m_pointer != nullptr)
|
if (m_pointer != nullptr)
|
||||||
return value();
|
return value();
|
||||||
|
@ -557,7 +566,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Callback>
|
template<typename Callback>
|
||||||
[[nodiscard]] ALWAYS_INLINE ErrorOr<Optional<T>> try_value_or_lazy_evaluated_optional(Callback callback) const
|
[[nodiscard]] ALWAYS_INLINE constexpr ErrorOr<Optional<T>> try_value_or_lazy_evaluated_optional(Callback callback) const
|
||||||
{
|
{
|
||||||
if (m_pointer != nullptr)
|
if (m_pointer != nullptr)
|
||||||
return value();
|
return value();
|
||||||
|
@ -565,7 +574,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename F, typename MappedType = decltype(declval<F>()(declval<T&>())), auto IsErrorOr = IsSpecializationOf<MappedType, ErrorOr>, typename OptionalType = Optional<ConditionallyResultType<IsErrorOr, MappedType>>>
|
template<typename F, typename MappedType = decltype(declval<F>()(declval<T&>())), auto IsErrorOr = IsSpecializationOf<MappedType, ErrorOr>, typename OptionalType = Optional<ConditionallyResultType<IsErrorOr, MappedType>>>
|
||||||
ALWAYS_INLINE Conditional<IsErrorOr, ErrorOr<OptionalType>, OptionalType> map(F&& mapper)
|
ALWAYS_INLINE constexpr Conditional<IsErrorOr, ErrorOr<OptionalType>, OptionalType> map(F&& mapper)
|
||||||
{
|
{
|
||||||
if constexpr (IsErrorOr) {
|
if constexpr (IsErrorOr) {
|
||||||
if (m_pointer != nullptr)
|
if (m_pointer != nullptr)
|
||||||
|
@ -580,7 +589,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename F, typename MappedType = decltype(declval<F>()(declval<T&>())), auto IsErrorOr = IsSpecializationOf<MappedType, ErrorOr>, typename OptionalType = Optional<ConditionallyResultType<IsErrorOr, MappedType>>>
|
template<typename F, typename MappedType = decltype(declval<F>()(declval<T&>())), auto IsErrorOr = IsSpecializationOf<MappedType, ErrorOr>, typename OptionalType = Optional<ConditionallyResultType<IsErrorOr, MappedType>>>
|
||||||
ALWAYS_INLINE Conditional<IsErrorOr, ErrorOr<OptionalType>, OptionalType> map(F&& mapper) const
|
ALWAYS_INLINE constexpr Conditional<IsErrorOr, ErrorOr<OptionalType>, OptionalType> map(F&& mapper) const
|
||||||
{
|
{
|
||||||
if constexpr (IsErrorOr) {
|
if constexpr (IsErrorOr) {
|
||||||
if (m_pointer != nullptr)
|
if (m_pointer != nullptr)
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <AK/Platform.h>
|
#include <AK/Platform.h>
|
||||||
#include <AK/StdLibExtraDetails.h>
|
#include <AK/StdLibExtraDetails.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace AK {
|
namespace AK {
|
||||||
|
@ -31,6 +32,7 @@ requires(AK::Detail::IsIntegral<T>)
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
void compiletime_fail(Args...);
|
void compiletime_fail(Args...);
|
||||||
|
|
||||||
|
using std::construct_at;
|
||||||
using std::forward;
|
using std::forward;
|
||||||
using std::move;
|
using std::move;
|
||||||
}
|
}
|
||||||
|
|
34
AK/String.h
34
AK/String.h
|
@ -236,38 +236,38 @@ class Optional<String> : public OptionalBase<String> {
|
||||||
public:
|
public:
|
||||||
using ValueType = String;
|
using ValueType = String;
|
||||||
|
|
||||||
Optional() = default;
|
constexpr Optional() = default;
|
||||||
|
|
||||||
template<SameAs<OptionalNone> V>
|
template<SameAs<OptionalNone> V>
|
||||||
Optional(V) { }
|
constexpr Optional(V) { }
|
||||||
|
|
||||||
Optional(Optional<String> const& other)
|
constexpr Optional(Optional<String> const& other)
|
||||||
{
|
{
|
||||||
if (other.has_value())
|
if (other.has_value())
|
||||||
m_value = other.m_value;
|
m_value = other.m_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional(Optional&& other)
|
constexpr Optional(Optional&& other)
|
||||||
: m_value(move(other.m_value))
|
: m_value(move(other.m_value))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U = String>
|
template<typename U = String>
|
||||||
requires(!IsSame<OptionalNone, RemoveCVReference<U>>)
|
requires(!IsSame<OptionalNone, RemoveCVReference<U>>)
|
||||||
explicit(!IsConvertible<U&&, String>) Optional(U&& value)
|
explicit(!IsConvertible<U&&, String>) constexpr Optional(U&& value)
|
||||||
requires(!IsSame<RemoveCVReference<U>, Optional<String>> && IsConstructible<String, U &&>)
|
requires(!IsSame<RemoveCVReference<U>, Optional<String>> && IsConstructible<String, U &&>)
|
||||||
: m_value(forward<U>(value))
|
: m_value(forward<U>(value))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template<SameAs<OptionalNone> V>
|
template<SameAs<OptionalNone> V>
|
||||||
Optional& operator=(V)
|
constexpr Optional& operator=(V)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional& operator=(Optional const& other)
|
constexpr Optional& operator=(Optional const& other)
|
||||||
{
|
{
|
||||||
if (this != &other) {
|
if (this != &other) {
|
||||||
m_value = other.m_value;
|
m_value = other.m_value;
|
||||||
|
@ -275,7 +275,7 @@ public:
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional& operator=(Optional&& other)
|
constexpr Optional& operator=(Optional&& other)
|
||||||
{
|
{
|
||||||
if (this != &other) {
|
if (this != &other) {
|
||||||
m_value = move(other.m_value);
|
m_value = move(other.m_value);
|
||||||
|
@ -284,48 +284,48 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename O>
|
template<typename O>
|
||||||
ALWAYS_INLINE bool operator==(Optional<O> const& other) const
|
ALWAYS_INLINE constexpr bool operator==(Optional<O> const& other) const
|
||||||
{
|
{
|
||||||
return has_value() == other.has_value() && (!has_value() || value() == other.value());
|
return has_value() == other.has_value() && (!has_value() || value() == other.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename O>
|
template<typename O>
|
||||||
ALWAYS_INLINE bool operator==(O const& other) const
|
ALWAYS_INLINE constexpr bool operator==(O const& other) const
|
||||||
{
|
{
|
||||||
return has_value() && value() == other;
|
return has_value() && value() == other;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear()
|
constexpr void clear()
|
||||||
{
|
{
|
||||||
m_value = String(nullptr);
|
m_value = String(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] bool has_value() const
|
[[nodiscard]] constexpr bool has_value() const
|
||||||
{
|
{
|
||||||
return !m_value.is_invalid();
|
return !m_value.is_invalid();
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] String& value() &
|
[[nodiscard]] constexpr String& value() &
|
||||||
{
|
{
|
||||||
VERIFY(has_value());
|
VERIFY(has_value());
|
||||||
return m_value;
|
return m_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] String const& value() const&
|
[[nodiscard]] constexpr String const& value() const&
|
||||||
{
|
{
|
||||||
VERIFY(has_value());
|
VERIFY(has_value());
|
||||||
return m_value;
|
return m_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] String value() &&
|
[[nodiscard]] constexpr String value() &&
|
||||||
{
|
{
|
||||||
return release_value();
|
return release_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] String release_value()
|
[[nodiscard]] constexpr String release_value()
|
||||||
{
|
{
|
||||||
VERIFY(has_value());
|
VERIFY(has_value());
|
||||||
String released_value = m_value;
|
String released_value = move(m_value);
|
||||||
clear();
|
clear();
|
||||||
return released_value;
|
return released_value;
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,7 +164,7 @@ class Optional<JS::Completion> : public OptionalBase<JS::Completion> {
|
||||||
public:
|
public:
|
||||||
using ValueType = JS::Completion;
|
using ValueType = JS::Completion;
|
||||||
|
|
||||||
Optional() = default;
|
constexpr Optional() = default;
|
||||||
|
|
||||||
Optional(Optional<JS::Completion> const& other)
|
Optional(Optional<JS::Completion> const& other)
|
||||||
{
|
{
|
||||||
|
@ -172,19 +172,19 @@ public:
|
||||||
m_value = other.m_value;
|
m_value = other.m_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional(Optional&& other)
|
constexpr Optional(Optional&& other)
|
||||||
: m_value(move(other.m_value))
|
: m_value(move(other.m_value))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U = JS::Completion>
|
template<typename U = JS::Completion>
|
||||||
explicit(!IsConvertible<U&&, JS::Completion>) Optional(U&& value)
|
explicit(!IsConvertible<U&&, JS::Completion>) constexpr Optional(U&& value)
|
||||||
requires(!IsSame<RemoveCVReference<U>, Optional<JS::Completion>> && IsConstructible<JS::Completion, U &&>)
|
requires(!IsSame<RemoveCVReference<U>, Optional<JS::Completion>> && IsConstructible<JS::Completion, U &&>)
|
||||||
: m_value(forward<U>(value))
|
: m_value(forward<U>(value))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional& operator=(Optional const& other)
|
constexpr Optional& operator=(Optional const& other)
|
||||||
{
|
{
|
||||||
if (this != &other) {
|
if (this != &other) {
|
||||||
clear();
|
clear();
|
||||||
|
@ -193,7 +193,7 @@ public:
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional& operator=(Optional&& other)
|
constexpr Optional& operator=(Optional&& other)
|
||||||
{
|
{
|
||||||
if (this != &other) {
|
if (this != &other) {
|
||||||
clear();
|
clear();
|
||||||
|
@ -207,18 +207,18 @@ public:
|
||||||
m_value = JS::Completion(JS::Completion::EmptyTag {});
|
m_value = JS::Completion(JS::Completion::EmptyTag {});
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] bool has_value() const
|
[[nodiscard]] constexpr bool has_value() const
|
||||||
{
|
{
|
||||||
return !m_value.is_empty();
|
return !m_value.is_empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] JS::Completion& value() &
|
[[nodiscard]] constexpr JS::Completion& value() &
|
||||||
{
|
{
|
||||||
VERIFY(has_value());
|
VERIFY(has_value());
|
||||||
return m_value;
|
return m_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] JS::Completion const& value() const&
|
[[nodiscard]] constexpr JS::Completion const& value() const&
|
||||||
{
|
{
|
||||||
VERIFY(has_value());
|
VERIFY(has_value());
|
||||||
return m_value;
|
return m_value;
|
||||||
|
|
|
@ -154,7 +154,7 @@ public:
|
||||||
return !is_nan() && !is_infinity();
|
return !is_nan() && !is_infinity();
|
||||||
}
|
}
|
||||||
|
|
||||||
Value()
|
constexpr Value()
|
||||||
: Value(EMPTY_TAG << GC::TAG_SHIFT, (u64)0)
|
: Value(EMPTY_TAG << GC::TAG_SHIFT, (u64)0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -419,7 +419,7 @@ private:
|
||||||
ThrowCompletionOr<Value> to_numeric_slow_case(VM&) const;
|
ThrowCompletionOr<Value> to_numeric_slow_case(VM&) const;
|
||||||
ThrowCompletionOr<Value> to_primitive_slow_case(VM&, PreferredType) const;
|
ThrowCompletionOr<Value> to_primitive_slow_case(VM&, PreferredType) const;
|
||||||
|
|
||||||
Value(u64 tag, u64 val)
|
constexpr Value(u64 tag, u64 val)
|
||||||
{
|
{
|
||||||
ASSERT(!(tag & val));
|
ASSERT(!(tag & val));
|
||||||
m_value.encoded = tag | val;
|
m_value.encoded = tag | val;
|
||||||
|
@ -544,10 +544,10 @@ class Optional<JS::Value> : public OptionalBase<JS::Value> {
|
||||||
public:
|
public:
|
||||||
using ValueType = JS::Value;
|
using ValueType = JS::Value;
|
||||||
|
|
||||||
Optional() = default;
|
constexpr Optional() = default;
|
||||||
|
|
||||||
template<SameAs<OptionalNone> V>
|
template<SameAs<OptionalNone> V>
|
||||||
Optional(V) { }
|
constexpr Optional(V) { }
|
||||||
|
|
||||||
Optional(Optional<JS::Value> const& other)
|
Optional(Optional<JS::Value> const& other)
|
||||||
{
|
{
|
||||||
|
@ -555,27 +555,27 @@ public:
|
||||||
m_value = other.m_value;
|
m_value = other.m_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional(Optional&& other)
|
constexpr Optional(Optional&& other)
|
||||||
: m_value(other.m_value)
|
: m_value(other.m_value)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U = JS::Value>
|
template<typename U = JS::Value>
|
||||||
requires(!IsSame<OptionalNone, RemoveCVReference<U>>)
|
requires(!IsSame<OptionalNone, RemoveCVReference<U>>)
|
||||||
explicit(!IsConvertible<U&&, JS::Value>) Optional(U&& value)
|
explicit(!IsConvertible<U&&, JS::Value>) constexpr Optional(U&& value)
|
||||||
requires(!IsSame<RemoveCVReference<U>, Optional<JS::Value>> && IsConstructible<JS::Value, U &&>)
|
requires(!IsSame<RemoveCVReference<U>, Optional<JS::Value>> && IsConstructible<JS::Value, U &&>)
|
||||||
: m_value(forward<U>(value))
|
: m_value(forward<U>(value))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template<SameAs<OptionalNone> V>
|
template<SameAs<OptionalNone> V>
|
||||||
Optional& operator=(V)
|
constexpr Optional& operator=(V)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional& operator=(Optional const& other)
|
constexpr Optional& operator=(Optional const& other)
|
||||||
{
|
{
|
||||||
if (this != &other) {
|
if (this != &other) {
|
||||||
clear();
|
clear();
|
||||||
|
@ -584,7 +584,7 @@ public:
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional& operator=(Optional&& other)
|
constexpr Optional& operator=(Optional&& other)
|
||||||
{
|
{
|
||||||
if (this != &other) {
|
if (this != &other) {
|
||||||
clear();
|
clear();
|
||||||
|
@ -594,34 +594,34 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename O>
|
template<typename O>
|
||||||
ALWAYS_INLINE bool operator==(Optional<O> const& other) const
|
ALWAYS_INLINE constexpr bool operator==(Optional<O> const& other) const
|
||||||
{
|
{
|
||||||
return has_value() == other.has_value() && (!has_value() || value() == other.value());
|
return has_value() == other.has_value() && (!has_value() || value() == other.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename O>
|
template<typename O>
|
||||||
ALWAYS_INLINE bool operator==(O const& other) const
|
ALWAYS_INLINE constexpr bool operator==(O const& other) const
|
||||||
{
|
{
|
||||||
return has_value() && value() == other;
|
return has_value() && value() == other;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear()
|
constexpr void clear()
|
||||||
{
|
{
|
||||||
m_value = {};
|
m_value = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] bool has_value() const
|
[[nodiscard]] constexpr bool has_value() const
|
||||||
{
|
{
|
||||||
return !m_value.is_empty();
|
return !m_value.is_empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] JS::Value& value() &
|
[[nodiscard]] constexpr JS::Value& value() &
|
||||||
{
|
{
|
||||||
VERIFY(has_value());
|
VERIFY(has_value());
|
||||||
return m_value;
|
return m_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] JS::Value const& value() const&
|
[[nodiscard]] constexpr JS::Value const& value() const&
|
||||||
{
|
{
|
||||||
VERIFY(has_value());
|
VERIFY(has_value());
|
||||||
return m_value;
|
return m_value;
|
||||||
|
|
|
@ -130,6 +130,9 @@ bool assume(T const& expression, StringView expression_string, SourceLocation lo
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
consteval void expect_consteval(T) { }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define EXPECT(x) \
|
#define EXPECT(x) \
|
||||||
|
@ -179,6 +182,8 @@ bool assume(T const& expression, StringView expression_string, SourceLocation lo
|
||||||
::Test::set_current_test_result(::Test::TestResult::Failed); \
|
::Test::set_current_test_result(::Test::TestResult::Failed); \
|
||||||
} while (false)
|
} while (false)
|
||||||
|
|
||||||
|
#define EXPECT_CONSTEVAL(...) ::Test::expect_consteval(__VA_ARGS__)
|
||||||
|
|
||||||
// To use, specify the lambda to execute in a sub process and verify it exits:
|
// To use, specify the lambda to execute in a sub process and verify it exits:
|
||||||
// EXPECT_CRASH("This should fail", []{
|
// EXPECT_CRASH("This should fail", []{
|
||||||
// return Test::Crash::Failure::DidNotCrash;
|
// return Test::Crash::Failure::DidNotCrash;
|
||||||
|
|
|
@ -706,7 +706,6 @@ void PaintableWithLines::paint(PaintContext& context, PaintPhase phase) const
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bool should_clip_overflow = computed_values().overflow_x() != CSS::Overflow::Visible && computed_values().overflow_y() != CSS::Overflow::Visible;
|
bool should_clip_overflow = computed_values().overflow_x() != CSS::Overflow::Visible && computed_values().overflow_y() != CSS::Overflow::Visible;
|
||||||
Optional<u32> corner_clip_id;
|
|
||||||
|
|
||||||
auto clip_box = absolute_padding_box_rect();
|
auto clip_box = absolute_padding_box_rect();
|
||||||
if (get_clip_rect().has_value()) {
|
if (get_clip_rect().has_value()) {
|
||||||
|
|
|
@ -13,6 +13,17 @@
|
||||||
#include <AK/String.h>
|
#include <AK/String.h>
|
||||||
#include <AK/Vector.h>
|
#include <AK/Vector.h>
|
||||||
|
|
||||||
|
struct DontCopyMe {
|
||||||
|
constexpr DontCopyMe() { }
|
||||||
|
~DontCopyMe() = default;
|
||||||
|
DontCopyMe(DontCopyMe&&) = default;
|
||||||
|
DontCopyMe& operator=(DontCopyMe&&) = default;
|
||||||
|
DontCopyMe(DontCopyMe const&) = delete;
|
||||||
|
DontCopyMe& operator=(DontCopyMe const&) = delete;
|
||||||
|
|
||||||
|
int x { 13 };
|
||||||
|
};
|
||||||
|
|
||||||
TEST_CASE(basic_optional)
|
TEST_CASE(basic_optional)
|
||||||
{
|
{
|
||||||
Optional<int> x;
|
Optional<int> x;
|
||||||
|
@ -39,17 +50,6 @@ TEST_CASE(move_optional)
|
||||||
|
|
||||||
TEST_CASE(optional_rvalue_ref_qualified_getters)
|
TEST_CASE(optional_rvalue_ref_qualified_getters)
|
||||||
{
|
{
|
||||||
struct DontCopyMe {
|
|
||||||
DontCopyMe() { }
|
|
||||||
~DontCopyMe() = default;
|
|
||||||
DontCopyMe(DontCopyMe&&) = default;
|
|
||||||
DontCopyMe& operator=(DontCopyMe&&) = default;
|
|
||||||
DontCopyMe(DontCopyMe const&) = delete;
|
|
||||||
DontCopyMe& operator=(DontCopyMe const&) = delete;
|
|
||||||
|
|
||||||
int x { 13 };
|
|
||||||
};
|
|
||||||
|
|
||||||
auto make_an_optional = []() -> Optional<DontCopyMe> {
|
auto make_an_optional = []() -> Optional<DontCopyMe> {
|
||||||
return DontCopyMe {};
|
return DontCopyMe {};
|
||||||
};
|
};
|
||||||
|
@ -122,6 +122,54 @@ TEST_CASE(comparison_with_numeric_types)
|
||||||
EXPECT_NE(opt1, -2);
|
EXPECT_NE(opt1, -2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE(test_constexpr)
|
||||||
|
{
|
||||||
|
int i = 13;
|
||||||
|
DontCopyMe dcm {};
|
||||||
|
|
||||||
|
EXPECT_CONSTEVAL(Optional<int> {});
|
||||||
|
EXPECT_CONSTEVAL(Optional<DontCopyMe> {});
|
||||||
|
EXPECT_CONSTEVAL(Optional<int const> {});
|
||||||
|
EXPECT_CONSTEVAL(Optional<DontCopyMe const> {});
|
||||||
|
EXPECT_CONSTEVAL(Optional<int&> {});
|
||||||
|
EXPECT_CONSTEVAL(Optional<DontCopyMe&> {});
|
||||||
|
EXPECT_CONSTEVAL(Optional<int const&> {});
|
||||||
|
EXPECT_CONSTEVAL(Optional<DontCopyMe const&> {});
|
||||||
|
|
||||||
|
EXPECT_CONSTEVAL(Optional<int> { 13 });
|
||||||
|
EXPECT_CONSTEVAL(Optional<DontCopyMe> { DontCopyMe {} });
|
||||||
|
EXPECT_CONSTEVAL(Optional<int const> { 13 });
|
||||||
|
EXPECT_CONSTEVAL(Optional<DontCopyMe const> { DontCopyMe {} });
|
||||||
|
EXPECT_CONSTEVAL(Optional<int&> { i });
|
||||||
|
EXPECT_CONSTEVAL(Optional<DontCopyMe&> { dcm });
|
||||||
|
EXPECT_CONSTEVAL(Optional<int const&> { 13 });
|
||||||
|
EXPECT_CONSTEVAL(Optional<DontCopyMe const&> { DontCopyMe {} });
|
||||||
|
|
||||||
|
static_assert(!Optional<int> {}.has_value());
|
||||||
|
static_assert(!Optional<DontCopyMe> {}.has_value());
|
||||||
|
static_assert(!Optional<int const> {}.has_value());
|
||||||
|
static_assert(!Optional<DontCopyMe const> {}.has_value());
|
||||||
|
static_assert(!Optional<int&> {}.has_value());
|
||||||
|
static_assert(!Optional<DontCopyMe&> {}.has_value());
|
||||||
|
static_assert(!Optional<int const&> {}.has_value());
|
||||||
|
static_assert(!Optional<DontCopyMe const&> {}.has_value());
|
||||||
|
|
||||||
|
static_assert(Optional<int> { 13 }.has_value());
|
||||||
|
static_assert(Optional<DontCopyMe> { DontCopyMe {} }.has_value());
|
||||||
|
static_assert(Optional<int const> { 13 }.has_value());
|
||||||
|
static_assert(Optional<DontCopyMe const> { DontCopyMe {} }.has_value());
|
||||||
|
static_assert(Optional<int&> { i }.has_value());
|
||||||
|
static_assert(Optional<DontCopyMe&> { dcm }.has_value());
|
||||||
|
static_assert(Optional<int const&> { 13 }.has_value());
|
||||||
|
static_assert(Optional<DontCopyMe const&> { DontCopyMe {} }.has_value());
|
||||||
|
|
||||||
|
static_assert(Optional<int> { 13 }.value() == 13);
|
||||||
|
static_assert(Optional<DontCopyMe> { DontCopyMe {} }.value().x == 13);
|
||||||
|
static_assert(Optional<int const> { 13 }.value() == 13);
|
||||||
|
static_assert(Optional<int const&> { 13 }.value() == 13);
|
||||||
|
static_assert(Optional<DontCopyMe const&> { DontCopyMe {} }.value().x == 13);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE(test_copy_ctor_and_dtor_called)
|
TEST_CASE(test_copy_ctor_and_dtor_called)
|
||||||
{
|
{
|
||||||
#ifdef AK_HAVE_CONDITIONALLY_TRIVIAL
|
#ifdef AK_HAVE_CONDITIONALLY_TRIVIAL
|
||||||
|
|
|
@ -11,6 +11,7 @@ list(APPEND CLANG_PLUGINS_COMPILE_OPTIONS_FOR_TESTS
|
||||||
-Wno-literal-range
|
-Wno-literal-range
|
||||||
-Wno-unknown-warning-option
|
-Wno-unknown-warning-option
|
||||||
-Wno-unqualified-std-cast-call
|
-Wno-unqualified-std-cast-call
|
||||||
|
-fgnuc-version=4.2.1 # NOTE: Clang default as of 10.0.0
|
||||||
)
|
)
|
||||||
|
|
||||||
# Ensure we always check for invalid function field types regardless of the value of ENABLE_CLANG_PLUGINS_INVALID_FUNCTION_MEMBERS
|
# Ensure we always check for invalid function field types regardless of the value of ENABLE_CLANG_PLUGINS_INVALID_FUNCTION_MEMBERS
|
||||||
|
|
Loading…
Reference in a new issue