2020-01-18 05:38:21 -03:00
/*
2024-10-04 08:19:50 -03:00
* Copyright ( c ) 2018 - 2021 , Andreas Kling < andreas @ ladybird . org >
2021-07-02 12:42:50 -03:00
* Copyright ( c ) 2021 , Daniel Bertalan < dani @ danielbertalan . dev >
2020-01-18 05:38:21 -03:00
*
2021-04-22 05:24:48 -03:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-01-18 05:38:21 -03:00
*/
2019-07-08 06:29:38 -03:00
# pragma once
# include <AK/Assertions.h>
2024-10-30 09:44:20 -03:00
# include <AK/Noncopyable.h>
2020-02-06 07:55:06 -03:00
# include <AK/StdLibExtras.h>
2022-12-09 13:42:24 -03:00
# include <AK/Try.h>
2020-03-08 08:34:33 -03:00
# include <AK/Types.h>
2020-11-21 22:02:56 -03:00
# include <AK/kmalloc.h>
2019-07-08 06:29:38 -03:00
2020-02-14 18:29:06 -03:00
namespace AK {
2022-12-09 13:42:24 -03:00
namespace Detail {
2025-05-13 08:06:33 -03:00
2022-12-09 13:42:24 -03:00
template < auto condition , typename T >
struct ConditionallyResultType ;
template < typename T >
struct ConditionallyResultType < true , T > {
using Type = typename T : : ResultType ;
} ;
template < typename T >
struct ConditionallyResultType < false , T > {
using Type = T ;
} ;
2025-05-13 08:06:33 -03:00
2022-12-09 13:42:24 -03:00
}
template < auto condition , typename T >
using ConditionallyResultType = typename Detail : : ConditionallyResultType < condition , T > : : Type ;
2021-09-07 17:46:23 -03:00
// NOTE: If you're here because of an internal compiler error in GCC 10.3.0+,
// it's because of the following bug:
//
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96745
//
// Make sure you didn't accidentally make your destructor private before
// you start bug hunting. :^)
2022-04-03 08:06:34 -03:00
template < typename >
class Optional ;
2022-12-09 16:44:40 -03:00
struct OptionalNone {
2025-04-11 10:55:43 -03:00
explicit constexpr OptionalNone ( ) = default ;
2022-12-09 16:44:40 -03:00
} ;
2024-10-29 07:35:36 -03:00
template < typename T , typename Self = Optional < T > >
requires ( ! IsLvalueReference < Self > ) class [ [ nodiscard ] ] OptionalBase {
public :
using ValueType = T ;
template < SameAs < OptionalNone > V >
2025-04-11 10:55:43 -03:00
ALWAYS_INLINE constexpr Self & operator = ( V )
2024-10-29 07:35:36 -03:00
{
static_cast < Self & > ( * this ) . clear ( ) ;
return static_cast < Self & > ( * this ) ;
}
2025-04-11 10:55:43 -03:00
[ [ nodiscard ] ] ALWAYS_INLINE constexpr T * ptr ( ) &
2024-10-29 07:35:36 -03:00
{
return static_cast < Self & > ( * this ) . has_value ( ) ? __builtin_launder ( reinterpret_cast < T * > ( & static_cast < Self & > ( * this ) . value ( ) ) ) : nullptr ;
}
2025-04-11 10:55:43 -03:00
[ [ nodiscard ] ] ALWAYS_INLINE constexpr T const * ptr ( ) const &
2024-10-29 07:35:36 -03:00
{
return static_cast < Self const & > ( * this ) . has_value ( ) ? __builtin_launder ( reinterpret_cast < T const * > ( & static_cast < Self const & > ( * this ) . value ( ) ) ) : nullptr ;
}
2024-11-26 14:17:44 -03:00
template < typename O = T , typename Fallback = O >
2025-04-11 10:55:43 -03:00
[ [ nodiscard ] ] ALWAYS_INLINE constexpr O value_or ( Fallback const & fallback ) const &
2024-10-29 07:35:36 -03:00
{
if ( static_cast < Self const & > ( * this ) . has_value ( ) )
return static_cast < Self const & > ( * this ) . value ( ) ;
return fallback ;
}
2024-11-26 14:17:44 -03:00
template < typename O = T , typename Fallback = O >
requires ( ! IsLvalueReference < O > & & ! IsRvalueReference < O > )
2025-04-11 10:55:43 -03:00
[ [ nodiscard ] ] ALWAYS_INLINE constexpr O value_or ( Fallback & & fallback ) & &
2024-10-29 07:35:36 -03:00
{
if ( static_cast < Self & > ( * this ) . has_value ( ) )
return move ( static_cast < Self & > ( * this ) . value ( ) ) ;
return move ( fallback ) ;
}
template < typename Callback , typename O = T >
2025-04-11 10:55:43 -03:00
[ [ nodiscard ] ] ALWAYS_INLINE constexpr O value_or_lazy_evaluated ( Callback callback ) const
2024-10-29 07:35:36 -03:00
{
if ( static_cast < Self const & > ( * this ) . has_value ( ) )
return static_cast < Self const & > ( * this ) . value ( ) ;
return callback ( ) ;
}
template < typename Callback , typename O = T >
2025-04-11 10:55:43 -03:00
[ [ nodiscard ] ] ALWAYS_INLINE constexpr Optional < O > value_or_lazy_evaluated_optional ( Callback callback ) const
2024-10-29 07:35:36 -03:00
{
if ( static_cast < Self const & > ( * this ) . has_value ( ) )
return static_cast < Self const & > ( * this ) . value ( ) ;
return callback ( ) ;
}
template < typename Callback , typename O = T >
2025-04-11 10:55:43 -03:00
[ [ nodiscard ] ] ALWAYS_INLINE constexpr ErrorOr < O > try_value_or_lazy_evaluated ( Callback callback ) const
2024-10-29 07:35:36 -03:00
{
if ( static_cast < Self const & > ( * this ) . has_value ( ) )
return static_cast < Self const & > ( * this ) . value ( ) ;
return TRY ( callback ( ) ) ;
}
template < typename Callback , typename O = T >
2025-04-11 10:55:43 -03:00
[ [ nodiscard ] ] ALWAYS_INLINE constexpr ErrorOr < Optional < O > > try_value_or_lazy_evaluated_optional ( Callback callback ) const
2024-10-29 07:35:36 -03:00
{
if ( static_cast < Self const & > ( * this ) . has_value ( ) )
return static_cast < Self const & > ( * this ) . value ( ) ;
return TRY ( callback ( ) ) ;
}
2025-04-11 10:55:43 -03:00
[ [ nodiscard ] ] ALWAYS_INLINE constexpr T const & operator * ( ) const { return static_cast < Self const & > ( * this ) . value ( ) ; }
[ [ nodiscard ] ] ALWAYS_INLINE constexpr T & operator * ( ) { return static_cast < Self & > ( * this ) . value ( ) ; }
2024-10-29 07:35:36 -03:00
2025-04-11 10:55:43 -03:00
ALWAYS_INLINE constexpr T const * operator - > ( ) const { return & static_cast < Self const & > ( * this ) . value ( ) ; }
ALWAYS_INLINE constexpr T * operator - > ( ) { return & static_cast < Self & > ( * this ) . value ( ) ; }
2024-10-29 07:35:36 -03:00
template < typename F , typename MappedType = decltype ( declval < F > ( ) ( declval < T & > ( ) ) ) , auto IsErrorOr = IsSpecializationOf < MappedType , ErrorOr > , typename OptionalType = Optional < ConditionallyResultType < IsErrorOr , MappedType > > >
2025-04-11 10:55:43 -03:00
ALWAYS_INLINE constexpr Conditional < IsErrorOr , ErrorOr < OptionalType > , OptionalType > map ( F & & mapper )
2024-10-29 07:35:36 -03:00
{
if constexpr ( IsErrorOr ) {
if ( static_cast < Self & > ( * this ) . has_value ( ) )
return OptionalType { TRY ( mapper ( static_cast < Self & > ( * this ) . value ( ) ) ) } ;
return OptionalType { } ;
} else {
if ( static_cast < Self & > ( * this ) . has_value ( ) )
return OptionalType { mapper ( static_cast < Self & > ( * this ) . value ( ) ) } ;
return OptionalType { } ;
}
}
template < typename F , typename MappedType = decltype ( declval < F > ( ) ( declval < T & > ( ) ) ) , auto IsErrorOr = IsSpecializationOf < MappedType , ErrorOr > , typename OptionalType = Optional < ConditionallyResultType < IsErrorOr , MappedType > > >
2025-04-11 10:55:43 -03:00
ALWAYS_INLINE constexpr Conditional < IsErrorOr , ErrorOr < OptionalType > , OptionalType > map ( F & & mapper ) const
2024-10-29 07:35:36 -03:00
{
if constexpr ( IsErrorOr ) {
if ( static_cast < Self const & > ( * this ) . has_value ( ) )
return OptionalType { TRY ( mapper ( static_cast < Self const & > ( * this ) . value ( ) ) ) } ;
return OptionalType { } ;
} else {
if ( static_cast < Self const & > ( * this ) . has_value ( ) )
return OptionalType { mapper ( static_cast < Self const & > ( * this ) . value ( ) ) } ;
return OptionalType { } ;
}
}
} ;
2019-07-08 06:29:38 -03:00
template < typename T >
2024-10-29 07:35:36 -03:00
requires ( ! IsLvalueReference < T > ) class [ [ nodiscard ] ] Optional < T > : public OptionalBase < T , Optional < T > > {
2022-01-23 08:03:29 -03:00
template < typename U >
friend class Optional ;
2022-04-03 08:06:34 -03:00
static_assert ( ! IsLvalueReference < T > & & ! IsRvalueReference < T > ) ;
2019-07-08 06:29:38 -03:00
public :
2021-04-15 11:32:48 -03:00
using ValueType = T ;
2025-04-11 10:55:43 -03:00
ALWAYS_INLINE constexpr Optional ( )
{
construct_null_if_necessary ( ) ;
}
2019-07-08 06:29:38 -03:00
2022-12-09 16:44:40 -03:00
template < SameAs < OptionalNone > V >
2025-04-11 10:55:43 -03:00
ALWAYS_INLINE constexpr Optional ( V )
{
construct_null_if_necessary ( ) ;
}
2022-12-09 16:44:40 -03:00
template < SameAs < OptionalNone > V >
2025-04-11 10:55:43 -03:00
ALWAYS_INLINE constexpr Optional & operator = ( V )
2022-12-09 16:44:40 -03:00
{
clear ( ) ;
return * this ;
}
2024-10-30 09:44:20 -03:00
AK_MAKE_CONDITIONALLY_COPYABLE ( Optional , < T > ) ;
2025-04-11 11:00:53 -03:00
AK_MAKE_CONDITIONALLY_MOVABLE ( Optional , < T > ) ;
2024-10-30 09:44:20 -03:00
AK_MAKE_CONDITIONALLY_DESTRUCTIBLE ( Optional , < T > ) ;
2019-07-08 06:29:38 -03:00
2025-04-11 10:55:43 -03:00
ALWAYS_INLINE constexpr Optional ( Optional const & other )
2022-10-16 19:06:11 -03:00
requires ( ! IsTriviallyCopyConstructible < T > )
2019-07-08 06:29:38 -03:00
: m_has_value ( other . m_has_value )
{
2022-01-23 08:03:29 -03:00
if ( other . has_value ( ) )
2025-04-11 10:55:43 -03:00
construct_at < RemoveConst < T > > ( & m_storage , other . value ( ) ) ;
else
construct_null_if_necessary ( ) ;
2019-07-08 06:29:38 -03:00
}
2025-04-11 10:55:43 -03:00
ALWAYS_INLINE constexpr Optional ( Optional & & other )
requires ( ! IsTriviallyMoveConstructible < T > )
2021-05-08 06:22:57 -03:00
: m_has_value ( other . m_has_value )
{
2022-01-23 08:03:29 -03:00
if ( other . has_value ( ) )
2025-04-11 10:55:43 -03:00
construct_at < RemoveConst < T > > ( & m_storage , other . release_value ( ) ) ;
else
construct_null_if_necessary ( ) ;
2022-01-23 08:03:29 -03:00
}
template < typename U >
2025-04-11 10:55:43 -03:00
requires ( IsConstructible < T , U const & > & & ! IsSpecializationOf < T , Optional > & & ! IsSpecializationOf < U , Optional > & & ( ! IsLvalueReference < U > | | IsTriviallyCopyConstructible < U > ) ) ALWAYS_INLINE explicit constexpr Optional ( Optional < U > const & other )
2024-10-28 18:53:16 -03:00
: m_has_value ( other . has_value ( ) )
2022-01-23 08:03:29 -03:00
{
if ( other . has_value ( ) )
2025-04-11 10:55:43 -03:00
construct_at < RemoveConst < T > > ( & m_storage , other . value ( ) ) ;
else
construct_null_if_necessary ( ) ;
2022-01-23 08:03:29 -03:00
}
template < typename U >
2025-04-11 10:55:43 -03:00
requires ( IsConstructible < T , U & & > & & ! IsSpecializationOf < T , Optional > & & ! IsSpecializationOf < U , Optional > & & ( ! IsLvalueReference < U > | | IsTriviallyMoveConstructible < U > ) ) ALWAYS_INLINE explicit constexpr Optional ( Optional < U > & & other )
2024-10-28 18:53:16 -03:00
: m_has_value ( other . has_value ( ) )
2022-01-23 08:03:29 -03:00
{
if ( other . has_value ( ) )
2025-04-11 10:55:43 -03:00
construct_at < RemoveConst < T > > ( & m_storage , other . release_value ( ) ) ;
else
construct_null_if_necessary ( ) ;
2021-05-08 06:22:57 -03:00
}
2021-07-02 12:42:50 -03:00
template < typename U = T >
2022-12-09 16:44:40 -03:00
requires ( ! IsSame < OptionalNone , RemoveCVReference < U > > )
2025-04-11 10:55:43 -03:00
ALWAYS_INLINE explicit ( ! IsConvertible < U & & , T > ) constexpr Optional ( U & & value )
2022-10-16 19:06:11 -03:00
requires ( ! IsSame < RemoveCVReference < U > , Optional < T > > & & IsConstructible < T , U & & > )
2021-05-08 06:22:57 -03:00
: m_has_value ( true )
{
2025-04-11 10:55:43 -03:00
construct_at < RemoveConst < T > > ( & m_storage , forward < U > ( value ) ) ;
2021-05-08 06:22:57 -03:00
}
2025-04-11 10:55:43 -03:00
ALWAYS_INLINE constexpr Optional & operator = ( Optional const & other )
2022-10-16 19:06:11 -03:00
requires ( ! IsTriviallyCopyConstructible < T > | | ! IsTriviallyDestructible < T > )
2019-07-08 06:29:38 -03:00
{
if ( this ! = & other ) {
clear ( ) ;
m_has_value = other . m_has_value ;
2025-04-11 10:55:43 -03:00
if ( other . has_value ( ) )
construct_at < RemoveConst < T > > ( & m_storage , other . value ( ) ) ;
2019-07-08 06:29:38 -03:00
}
return * this ;
}
2025-04-11 11:00:53 -03:00
Optional & operator = ( Optional & & other )
requires ( ! IsMoveConstructible < T > | | ! IsDestructible < T > )
= delete ;
// Note: This overload is optional. It exists purely to match the SerenityOS and `std::optional` behaviour.
// The only (observable) difference between this overload and the next one is that this one calls the move assignment operator when both `this` and `other` have a value.
// The other overload just unconditionally calls the move constructor.
2025-04-11 10:55:43 -03:00
ALWAYS_INLINE constexpr Optional & operator = ( Optional & & other )
2025-04-11 11:00:53 -03:00
requires ( IsMoveAssignable < T > & & IsMoveConstructible < T > & & ( ! IsTriviallyMoveAssignable < T > | | ! IsTriviallyMoveConstructible < T > | | ! IsTriviallyDestructible < T > ) )
{
if ( this ! = & other ) {
if ( has_value ( ) & & other . has_value ( ) ) {
value ( ) = other . release_value ( ) ;
} else if ( has_value ( ) ) {
value ( ) . ~ T ( ) ;
m_has_value = false ;
} else if ( other . has_value ( ) ) {
m_has_value = true ;
construct_at < RemoveConst < T > > ( & m_storage , other . release_value ( ) ) ;
}
}
return * this ;
}
// Allow for move constructible but non-move assignable types, such as those containing const or reference fields,
// Note: This overload can also handle move assignable types perfectly fine, but the behaviour would be slightly different.
ALWAYS_INLINE constexpr Optional & operator = ( Optional & & other )
requires ( ! IsMoveAssignable < T > & & IsMoveConstructible < T > & & ( ! IsTriviallyMoveConstructible < T > | | ! IsTriviallyDestructible < T > ) )
2019-07-08 06:29:38 -03:00
{
if ( this ! = & other ) {
clear ( ) ;
m_has_value = other . m_has_value ;
2025-04-11 10:55:43 -03:00
if ( other . has_value ( ) )
construct_at < RemoveConst < T > > ( & m_storage , other . release_value ( ) ) ;
2019-07-08 06:29:38 -03:00
}
return * this ;
}
2025-04-11 11:00:53 -03:00
template < class U = T >
requires ( ! IsOneOfIgnoringCVReference < U , Optional < T > , OptionalNone > & & ! ( IsSame < U , T > & & IsScalar < U > ) )
// Note: We restrict this to `!IsScalar<U>` to prevent undesired overload resolution for `= {}`.
ALWAYS_INLINE constexpr Optional < T > & operator = ( U & & value )
requires ( IsConstructible < T , U & & > )
{
if constexpr ( IsAssignable < AddLvalueReference < T > , AddRvalueReference < U > > ) {
if ( m_has_value )
m_storage = forward < U > ( value ) ;
else
construct_at < RemoveConst < T > > ( & m_storage , forward < U > ( value ) ) ;
m_has_value = true ;
} else {
emplace ( forward < U > ( value ) ) ;
}
return * this ;
}
2025-04-11 10:55:43 -03:00
ALWAYS_INLINE constexpr ~ Optional ( )
2024-10-22 11:47:01 -03:00
requires ( ! IsTriviallyDestructible < T > & & IsDestructible < T > )
2019-07-08 06:29:38 -03:00
{
clear ( ) ;
}
2025-04-11 10:55:43 -03:00
ALWAYS_INLINE constexpr void clear ( )
2019-07-08 06:29:38 -03:00
{
if ( m_has_value ) {
value ( ) . ~ T ( ) ;
m_has_value = false ;
}
}
2020-08-29 14:18:01 -03:00
template < typename . . . Parameters >
2025-04-11 10:55:43 -03:00
ALWAYS_INLINE constexpr void emplace ( Parameters & & . . . parameters )
2020-08-29 14:18:01 -03:00
{
clear ( ) ;
m_has_value = true ;
2025-04-11 10:55:43 -03:00
construct_at < RemoveConst < T > > ( & m_storage , forward < Parameters > ( parameters ) . . . ) ;
2020-08-29 14:18:01 -03:00
}
2022-12-10 13:06:32 -03:00
template < typename Callable >
2025-04-11 10:55:43 -03:00
ALWAYS_INLINE constexpr void lazy_emplace ( Callable callable )
2022-12-10 13:06:32 -03:00
{
clear ( ) ;
m_has_value = true ;
2025-04-11 10:55:43 -03:00
construct_at < RemoveConst < T > > ( & m_storage , callable ( ) ) ;
2022-12-10 13:06:32 -03:00
}
2025-04-11 10:55:43 -03:00
[ [ nodiscard ] ] ALWAYS_INLINE constexpr bool has_value ( ) const { return m_has_value ; }
2019-07-08 06:29:38 -03:00
2025-04-11 10:55:43 -03:00
[ [ nodiscard ] ] ALWAYS_INLINE constexpr T & value ( ) &
2019-07-08 06:29:38 -03:00
{
2021-02-23 16:42:32 -03:00
VERIFY ( m_has_value ) ;
2025-04-11 10:55:43 -03:00
return m_storage ;
2019-07-08 06:29:38 -03:00
}
2025-04-11 10:55:43 -03:00
[ [ nodiscard ] ] ALWAYS_INLINE constexpr T const & value ( ) const &
2019-07-08 06:29:38 -03:00
{
2021-02-23 16:42:32 -03:00
VERIFY ( m_has_value ) ;
2025-04-11 10:55:43 -03:00
return m_storage ;
2019-07-08 06:29:38 -03:00
}
2025-04-11 10:55:43 -03:00
[ [ nodiscard ] ] ALWAYS_INLINE constexpr T value ( ) & &
2021-09-03 19:44:10 -03:00
{
return release_value ( ) ;
}
2025-04-11 10:55:43 -03:00
[ [ nodiscard ] ] ALWAYS_INLINE constexpr T release_value ( )
2019-07-08 06:29:38 -03:00
{
2021-02-23 16:42:32 -03:00
VERIFY ( m_has_value ) ;
2019-07-08 06:29:38 -03:00
T released_value = move ( value ( ) ) ;
value ( ) . ~ T ( ) ;
2019-08-05 16:47:36 -03:00
m_has_value = false ;
2019-07-08 06:29:38 -03:00
return released_value ;
}
private :
2025-04-11 10:55:43 -03:00
ALWAYS_INLINE constexpr void construct_null_if_necessary ( bool should_construct = is_constant_evaluated ( ) )
{
// OPTIMIZATION: Only construct the `m_null` member when we are constant-evaluating.
// Otherwise, this generates an unnecessary zero-fill.
# if defined(AK_COMPILER_GCC)
// NOTE: GCCs -Wuninitialized warning ends up checking this as well.
should_construct = true ;
# endif
if ( should_construct )
construct_at ( & m_null ) ;
}
union {
// FIXME: GCC seems to have an issue with uninitialized unions and non trivial types,
// which forces us to have an equally sized trivial null member in the union
// to pseudo-initialize the union.
struct {
u8 _ [ sizeof ( T ) ] ;
} m_null ;
RemoveConst < T > m_storage ;
} ;
2019-07-08 06:29:38 -03:00
bool m_has_value { false } ;
} ;
2022-04-03 08:06:34 -03:00
template < typename T >
requires ( IsLvalueReference < T > ) class [ [ nodiscard ] ] Optional < T > {
2024-11-25 08:54:43 -03:00
AK_MAKE_DEFAULT_COPYABLE ( Optional ) ;
AK_MAKE_DEFAULT_MOVABLE ( Optional ) ;
2022-04-03 08:06:34 -03:00
template < typename >
friend class Optional ;
template < typename U >
constexpr static bool CanBePlacedInOptional = IsSame < RemoveReference < T > , RemoveReference < AddConstToReferencedType < U > > > & & ( IsBaseOf < RemoveCVReference < T > , RemoveCVReference < U > > | | IsSame < RemoveCVReference < T > , RemoveCVReference < U > > ) ;
public :
using ValueType = T ;
2025-04-11 10:55:43 -03:00
ALWAYS_INLINE constexpr Optional ( ) = default ;
2022-04-03 08:06:34 -03:00
2023-11-28 02:22:46 -03:00
template < SameAs < OptionalNone > V >
2025-04-11 10:55:43 -03:00
ALWAYS_INLINE constexpr Optional ( V ) { }
2023-11-28 02:22:46 -03:00
template < SameAs < OptionalNone > V >
2025-04-11 10:55:43 -03:00
ALWAYS_INLINE constexpr Optional & operator = ( V )
2023-11-28 02:22:46 -03:00
{
clear ( ) ;
return * this ;
}
2022-04-03 08:06:34 -03:00
template < typename U = T >
2025-04-11 10:55:43 -03:00
ALWAYS_INLINE constexpr Optional ( U & value )
2022-10-16 19:06:11 -03:00
requires ( CanBePlacedInOptional < U & > )
2022-04-03 08:06:34 -03:00
: m_pointer ( & value )
{
}
2025-04-11 10:55:43 -03:00
ALWAYS_INLINE constexpr Optional ( RemoveReference < T > & value )
2022-04-03 08:06:34 -03:00
: m_pointer ( & value )
{
}
template < typename U >
2025-04-11 10:55:43 -03:00
ALWAYS_INLINE constexpr Optional ( Optional < U > & other )
2022-10-16 19:06:11 -03:00
requires ( CanBePlacedInOptional < U > )
2024-10-27 06:13:43 -03:00
: m_pointer ( other . ptr ( ) )
{
}
template < typename U >
2025-04-11 10:55:43 -03:00
ALWAYS_INLINE constexpr Optional ( Optional < U > const & other )
2024-10-27 06:13:43 -03:00
requires ( CanBePlacedInOptional < U const > )
: m_pointer ( other . ptr ( ) )
2022-04-03 08:06:34 -03:00
{
}
template < typename U >
2025-04-11 10:55:43 -03:00
ALWAYS_INLINE constexpr Optional ( Optional < U > & & other )
2022-10-16 19:06:11 -03:00
requires ( CanBePlacedInOptional < U > )
2024-10-27 06:13:43 -03:00
: m_pointer ( other . ptr ( ) )
2022-04-03 08:06:34 -03:00
{
other . m_pointer = nullptr ;
}
template < typename U >
2025-04-11 10:55:43 -03:00
ALWAYS_INLINE constexpr Optional & operator = ( Optional < U > & other )
2022-10-16 19:06:11 -03:00
requires ( CanBePlacedInOptional < U > )
2022-04-03 08:06:34 -03:00
{
2024-10-27 06:13:43 -03:00
m_pointer = other . ptr ( ) ;
return * this ;
}
template < typename U >
2025-04-11 10:55:43 -03:00
ALWAYS_INLINE constexpr Optional & operator = ( Optional < U > const & other )
2024-10-27 06:13:43 -03:00
requires ( CanBePlacedInOptional < U const > )
{
m_pointer = other . ptr ( ) ;
2022-04-03 08:06:34 -03:00
return * this ;
}
template < typename U >
2025-04-11 10:55:43 -03:00
ALWAYS_INLINE constexpr Optional & operator = ( Optional < U > & & other )
2024-10-27 06:13:43 -03:00
requires ( CanBePlacedInOptional < U > & & IsLvalueReference < U > )
2022-04-03 08:06:34 -03:00
{
m_pointer = other . m_pointer ;
other . m_pointer = nullptr ;
return * this ;
}
template < typename U >
2023-11-28 02:22:46 -03:00
requires ( ! IsSame < OptionalNone , RemoveCVReference < U > > )
2025-04-11 10:55:43 -03:00
ALWAYS_INLINE constexpr Optional & operator = ( U & value )
2024-11-24 20:25:57 -03:00
requires ( CanBePlacedInOptional < U > )
2022-04-03 08:06:34 -03:00
{
m_pointer = & value ;
return * this ;
}
2024-11-24 20:25:57 -03:00
// Note: Disallows assignment from a temporary as this does not do any lifetime extension.
template < typename U >
requires ( ! IsSame < OptionalNone , RemoveCVReference < U > > )
ALWAYS_INLINE consteval Optional & operator = ( RemoveReference < U > const & & value )
requires ( CanBePlacedInOptional < U > )
= delete ;
2025-04-11 10:55:43 -03:00
ALWAYS_INLINE constexpr void clear ( )
2022-04-03 08:06:34 -03:00
{
m_pointer = nullptr ;
}
2025-04-11 10:55:43 -03:00
[ [ nodiscard ] ] ALWAYS_INLINE constexpr bool has_value ( ) const { return m_pointer ! = nullptr ; }
2022-04-03 08:06:34 -03:00
2024-10-27 06:13:43 -03:00
[ [ nodiscard ] ] ALWAYS_INLINE RemoveReference < T > * ptr ( )
{
return m_pointer ;
}
[ [ nodiscard ] ] ALWAYS_INLINE RemoveReference < T > const * ptr ( ) const
{
return m_pointer ;
}
2025-04-11 10:55:43 -03:00
[ [ nodiscard ] ] ALWAYS_INLINE constexpr T value ( )
2022-04-03 08:06:34 -03:00
{
VERIFY ( m_pointer ) ;
return * m_pointer ;
}
2025-04-11 10:55:43 -03:00
[ [ nodiscard ] ] ALWAYS_INLINE constexpr AddConstToReferencedType < T > value ( ) const
2022-04-03 08:06:34 -03:00
{
VERIFY ( m_pointer ) ;
return * m_pointer ;
}
template < typename U >
2025-04-11 10:55:43 -03:00
requires ( IsBaseOf < RemoveCVReference < T > , U > ) [ [ nodiscard ] ] ALWAYS_INLINE constexpr AddConstToReferencedType < T > value_or ( U & fallback ) const
2022-04-03 08:06:34 -03:00
{
if ( m_pointer )
return value ( ) ;
return fallback ;
}
// Note that this ends up copying the value.
2025-04-11 10:55:43 -03:00
[ [ nodiscard ] ] ALWAYS_INLINE constexpr RemoveCVReference < T > value_or ( RemoveCVReference < T > fallback ) const
2022-04-03 08:06:34 -03:00
{
if ( m_pointer )
return value ( ) ;
return fallback ;
}
2025-04-11 10:55:43 -03:00
[ [ nodiscard ] ] ALWAYS_INLINE constexpr T release_value ( )
2022-04-03 08:06:34 -03:00
{
return * exchange ( m_pointer , nullptr ) ;
}
2025-04-11 10:55:43 -03:00
ALWAYS_INLINE constexpr AddConstToReferencedType < T > operator * ( ) const { return value ( ) ; }
ALWAYS_INLINE constexpr T operator * ( ) { return value ( ) ; }
2022-04-03 08:06:34 -03:00
ALWAYS_INLINE RawPtr < AddConst < RemoveReference < T > > > operator - > ( ) const { return & value ( ) ; }
ALWAYS_INLINE RawPtr < RemoveReference < T > > operator - > ( ) { return & value ( ) ; }
2024-11-25 09:23:31 -03:00
// Conversion operators from Optional<T&> -> Optional<T>, implicit when T is trivially copyable.
2025-04-11 10:55:43 -03:00
ALWAYS_INLINE constexpr operator Optional < RemoveCVReference < T > > ( ) const
2024-11-25 09:23:31 -03:00
requires ( IsTriviallyCopyable < RemoveCVReference < T > > )
2022-04-03 08:06:34 -03:00
{
if ( has_value ( ) )
return Optional < RemoveCVReference < T > > ( value ( ) ) ;
return { } ;
}
2024-11-25 09:23:31 -03:00
// Conversion operators from Optional<T&> -> Optional<T>, explicit when T is not trivially copyable, since this is usually a mistake.
2025-04-11 10:55:43 -03:00
ALWAYS_INLINE explicit constexpr operator Optional < RemoveCVReference < T > > ( ) const
2024-11-25 09:23:31 -03:00
requires ( ! IsTriviallyCopyable < RemoveCVReference < T > > )
{
if ( has_value ( ) )
return Optional < RemoveCVReference < T > > ( value ( ) ) ;
return { } ;
}
ALWAYS_INLINE constexpr Optional < RemoveCVReference < T > > copy ( ) const
{
return static_cast < Optional < RemoveCVReference < T > > > ( * this ) ;
}
2022-12-09 13:44:06 -03:00
template < typename Callback >
2025-04-11 10:55:43 -03:00
[ [ nodiscard ] ] ALWAYS_INLINE constexpr T value_or_lazy_evaluated ( Callback callback ) const
2022-12-09 13:44:06 -03:00
{
if ( m_pointer ! = nullptr )
return value ( ) ;
return callback ( ) ;
}
template < typename Callback >
2025-04-11 10:55:43 -03:00
[ [ nodiscard ] ] ALWAYS_INLINE constexpr Optional < T > value_or_lazy_evaluated_optional ( Callback callback ) const
2022-12-09 13:44:06 -03:00
{
if ( m_pointer ! = nullptr )
return value ( ) ;
return callback ( ) ;
}
template < typename Callback >
2025-04-11 10:55:43 -03:00
[ [ nodiscard ] ] ALWAYS_INLINE constexpr ErrorOr < T > try_value_or_lazy_evaluated ( Callback callback ) const
2022-12-09 13:44:06 -03:00
{
if ( m_pointer ! = nullptr )
return value ( ) ;
return TRY ( callback ( ) ) ;
}
template < typename Callback >
2025-04-11 10:55:43 -03:00
[ [ nodiscard ] ] ALWAYS_INLINE constexpr ErrorOr < Optional < T > > try_value_or_lazy_evaluated_optional ( Callback callback ) const
2022-12-09 13:44:06 -03:00
{
if ( m_pointer ! = nullptr )
return value ( ) ;
return TRY ( callback ( ) ) ;
}
2022-12-09 13:42:24 -03:00
template < typename F , typename MappedType = decltype ( declval < F > ( ) ( declval < T & > ( ) ) ) , auto IsErrorOr = IsSpecializationOf < MappedType , ErrorOr > , typename OptionalType = Optional < ConditionallyResultType < IsErrorOr , MappedType > > >
2025-04-11 10:55:43 -03:00
ALWAYS_INLINE constexpr Conditional < IsErrorOr , ErrorOr < OptionalType > , OptionalType > map ( F & & mapper )
2022-12-09 13:42:24 -03:00
{
if constexpr ( IsErrorOr ) {
if ( m_pointer ! = nullptr )
return OptionalType { TRY ( mapper ( value ( ) ) ) } ;
return OptionalType { } ;
} else {
if ( m_pointer ! = nullptr )
return OptionalType { mapper ( value ( ) ) } ;
return OptionalType { } ;
}
}
template < typename F , typename MappedType = decltype ( declval < F > ( ) ( declval < T & > ( ) ) ) , auto IsErrorOr = IsSpecializationOf < MappedType , ErrorOr > , typename OptionalType = Optional < ConditionallyResultType < IsErrorOr , MappedType > > >
2025-04-11 10:55:43 -03:00
ALWAYS_INLINE constexpr Conditional < IsErrorOr , ErrorOr < OptionalType > , OptionalType > map ( F & & mapper ) const
2022-12-09 13:42:24 -03:00
{
if constexpr ( IsErrorOr ) {
if ( m_pointer ! = nullptr )
return OptionalType { TRY ( mapper ( value ( ) ) ) } ;
return OptionalType { } ;
} else {
if ( m_pointer ! = nullptr )
return OptionalType { mapper ( value ( ) ) } ;
return OptionalType { } ;
}
}
2022-04-03 08:06:34 -03:00
private :
RemoveReference < T > * m_pointer { nullptr } ;
} ;
2024-12-29 02:25:21 -03:00
template < typename T1 , typename T2 >
2025-04-11 10:55:43 -03:00
ALWAYS_INLINE constexpr bool operator = = ( Optional < T1 > const & first , Optional < T2 > const & second )
2024-12-29 02:25:21 -03:00
{
return first . has_value ( ) = = second . has_value ( )
& & ( ! first . has_value ( ) | | first . value ( ) = = second . value ( ) ) ;
}
template < typename T1 , typename T2 >
2025-04-11 10:55:43 -03:00
ALWAYS_INLINE constexpr bool operator = = ( Optional < T1 > const & first , T2 const & second )
2024-12-29 02:25:21 -03:00
{
return first . has_value ( ) & & first . value ( ) = = second ;
}
2025-03-13 02:29:59 -03:00
template < typename T >
2025-04-11 10:55:43 -03:00
ALWAYS_INLINE constexpr bool operator = = ( Optional < T > const & first , OptionalNone )
2025-03-13 02:29:59 -03:00
{
return ! first . has_value ( ) ;
}
2020-02-14 18:29:06 -03:00
}
2022-11-26 08:18:30 -03:00
# if USING_AK_GLOBALLY
2020-02-14 18:29:06 -03:00
using AK : : Optional ;
2023-01-15 01:15:04 -03:00
using AK : : OptionalNone ;
2022-11-26 08:18:30 -03:00
# endif