2020-01-18 09:38:21 +01:00
/*
2024-10-04 13:19:50 +02:00
* Copyright ( c ) 2018 - 2021 , Andreas Kling < andreas @ ladybird . org >
2021-07-02 17:42:50 +02:00
* Copyright ( c ) 2021 , Daniel Bertalan < dani @ danielbertalan . dev >
2025-09-17 15:45:45 +02:00
* Copyright ( c ) 2025 , Jelle Raaijmakers < jelle @ ladybird . org >
2020-01-18 09:38:21 +01:00
*
2021-04-22 01:24:48 -07:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-01-18 09:38:21 +01:00
*/
2019-07-08 11:29:38 +02:00
# pragma once
# include <AK/Assertions.h>
2025-07-15 00:22:12 +02:00
# include <AK/Concepts.h>
# include <AK/Forward.h>
2024-10-30 13:44:20 +01:00
# include <AK/Noncopyable.h>
2025-07-15 00:22:12 +02:00
# include <AK/Platform.h>
# include <AK/StdLibExtraDetails.h>
2020-02-06 11:55:06 +01:00
# include <AK/StdLibExtras.h>
2025-07-06 20:42:40 +12:00
# include <AK/Traits.h>
2022-12-09 20:12:24 +03:30
# include <AK/Try.h>
2020-03-08 12:34:33 +01:00
# include <AK/Types.h>
2020-11-21 18:02:56 -07:00
# include <AK/kmalloc.h>
2019-07-08 11:29:38 +02:00
2020-02-14 22:29:06 +01:00
namespace AK {
2022-12-09 20:12:24 +03:30
namespace Detail {
2025-05-13 07:06:33 -04:00
2022-12-09 20:12:24 +03:30
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 07:06:33 -04:00
2025-07-15 00:22:12 +02:00
template < typename Self , typename T >
struct AddConstIfNeeded {
using Type = Conditional < IsConst < RemoveReference < Self > > & & ! IsConst < T > , AddConst < T > , T > ;
} ;
2022-12-09 20:12:24 +03:30
}
template < auto condition , typename T >
using ConditionallyResultType = typename Detail : : ConditionallyResultType < condition , T > : : Type ;
2025-07-15 00:22:12 +02:00
template < typename Self , typename T >
using AddConstIfNeeded = typename Detail : : AddConstIfNeeded < Self , T > : : Type ;
2022-12-09 20:12:24 +03:30
2021-09-07 20:46:23 +00: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 15:36:34 +04:30
template < typename >
class Optional ;
2022-12-09 23:14:40 +03:30
struct OptionalNone {
2025-04-11 15:55:43 +02:00
explicit constexpr OptionalNone ( ) = default ;
2022-12-09 23:14:40 +03:30
} ;
2025-07-15 00:22:12 +02:00
template < typename T >
requires ( ! IsLvalueReference < T > )
class [ [ nodiscard ] ] OptionalBase {
2024-10-29 11:35:36 +01:00
public :
using ValueType = T ;
2025-07-15 00:22:12 +02:00
template < typename Self , SameAs < OptionalNone > V >
ALWAYS_INLINE constexpr Self & operator = ( this Self & self , V )
2024-10-29 11:35:36 +01:00
{
2025-07-15 00:22:12 +02:00
self . clear ( ) ;
return self ;
2024-10-29 11:35:36 +01:00
}
2025-07-15 00:22:12 +02:00
template < typename Self >
[ [ nodiscard ] ] ALWAYS_INLINE constexpr AddConstIfNeeded < Self , T > * ptr ( this Self & self )
2024-10-29 11:35:36 +01:00
{
2025-07-15 00:22:12 +02:00
return self . has_value ( ) ? & self . value ( ) : nullptr ;
2024-10-29 11:35:36 +01:00
}
2025-07-15 00:22:12 +02:00
template < typename O = T , typename Fallback = O , typename Self >
[ [ nodiscard ] ] ALWAYS_INLINE constexpr O value_or ( this Self & & self , Fallback & & fallback )
2024-10-29 11:35:36 +01:00
{
2025-07-15 00:22:12 +02:00
if ( self . has_value ( ) )
return forward < Self > ( self ) . value ( ) ;
return forward < Fallback > ( fallback ) ;
2024-10-29 11:35:36 +01:00
}
2025-07-15 00:22:12 +02:00
template < typename Callback , typename O = T , typename Self >
[ [ nodiscard ] ] ALWAYS_INLINE constexpr O value_or_lazy_evaluated ( this Self & & self , Callback callback )
2024-10-29 11:35:36 +01:00
{
2025-07-15 00:22:12 +02:00
if ( self . has_value ( ) )
return forward < Self > ( self ) . value ( ) ;
2024-10-29 11:35:36 +01:00
return callback ( ) ;
}
2025-07-15 00:22:12 +02:00
template < typename Callback , typename O = T , typename Self >
[ [ nodiscard ] ] ALWAYS_INLINE constexpr Optional < O > value_or_lazy_evaluated_optional ( this Self & & self , Callback callback )
2024-10-29 11:35:36 +01:00
{
2025-07-15 00:22:12 +02:00
if ( self . has_value ( ) )
return forward < Self > ( self ) ;
2024-10-29 11:35:36 +01:00
return callback ( ) ;
}
2025-07-15 00:22:12 +02:00
template < typename Callback , typename O = T , typename Self >
[ [ nodiscard ] ] ALWAYS_INLINE constexpr ErrorOr < O > try_value_or_lazy_evaluated ( this Self & & self , Callback callback )
2024-10-29 11:35:36 +01:00
{
2025-07-15 00:22:12 +02:00
if ( self . has_value ( ) )
return forward < Self > ( self ) . value ( ) ;
2024-10-29 11:35:36 +01:00
return TRY ( callback ( ) ) ;
}
2025-07-15 00:22:12 +02:00
template < typename Callback , typename O = T , typename Self >
[ [ nodiscard ] ] ALWAYS_INLINE constexpr ErrorOr < Optional < O > > try_value_or_lazy_evaluated_optional ( this Self & & self , Callback callback )
2024-10-29 11:35:36 +01:00
{
2025-07-15 00:22:12 +02:00
if ( self . has_value ( ) )
return forward < Self > ( self ) ;
2024-10-29 11:35:36 +01:00
return TRY ( callback ( ) ) ;
}
2025-07-15 00:22:12 +02:00
template < typename Callable , typename Self >
[ [ nodiscard ] ] ALWAYS_INLINE constexpr T & ensure ( this Self & self , Callable callable )
2025-09-17 15:45:45 +02:00
{
2025-07-15 00:22:12 +02:00
if ( ! self . has_value ( ) )
self = callable ( ) ;
return self . value ( ) ;
2025-09-17 15:45:45 +02:00
}
2025-07-15 00:22:12 +02:00
template < typename Self >
[ [ nodiscard ] ] ALWAYS_INLINE constexpr auto operator * ( this Self & & self ) - > decltype ( forward < Self > ( self ) . value ( ) ) { return forward < Self > ( self ) . value ( ) ; }
template < typename Self >
[ [ nodiscard ] ] ALWAYS_INLINE constexpr AddConstIfNeeded < Self , T > * operator - > ( this Self & & self ) { return & self . value ( ) ; }
2024-10-29 11:35:36 +01:00
2025-07-15 00:22:12 +02:00
template < typename F ,
typename MappedType = decltype ( declval < F > ( ) ( declval < T & > ( ) ) ) ,
auto IsErrorOr = IsSpecializationOf < MappedType , ErrorOr > ,
typename OptionalType = Optional < ConditionallyResultType < IsErrorOr , MappedType > > ,
typename Self >
ALWAYS_INLINE constexpr Conditional < IsErrorOr , ErrorOr < OptionalType > , OptionalType > map ( this Self & & self , F & & mapper )
2024-10-29 11:35:36 +01:00
{
if constexpr ( IsErrorOr ) {
2025-07-15 00:22:12 +02:00
if ( self . has_value ( ) )
return OptionalType { TRY ( mapper ( forward < Self > ( self ) . value ( ) ) ) } ;
2024-10-29 11:35:36 +01:00
return OptionalType { } ;
} else {
2025-07-15 00:22:12 +02:00
if ( self . has_value ( ) )
return OptionalType { mapper ( forward < Self > ( self ) . value ( ) ) } ;
2024-10-29 11:35:36 +01:00
return OptionalType { } ;
}
}
} ;
2019-07-08 11:29:38 +02:00
template < typename T >
2025-07-15 00:22:12 +02:00
requires ( ! IsLvalueReference < T > ) class [ [ nodiscard ] ] Optional < T > : public OptionalBase < T > {
2022-01-23 13:03:29 +02:00
template < typename U >
friend class Optional ;
2022-04-03 15:36:34 +04:30
static_assert ( ! IsLvalueReference < T > & & ! IsRvalueReference < T > ) ;
2019-07-08 11:29:38 +02:00
public :
2021-04-15 10:32:48 -04:00
using ValueType = T ;
2025-04-11 15:55:43 +02:00
ALWAYS_INLINE constexpr Optional ( )
{
construct_null_if_necessary ( ) ;
}
2019-07-08 11:29:38 +02:00
2022-12-09 23:14:40 +03:30
template < SameAs < OptionalNone > V >
2025-04-11 15:55:43 +02:00
ALWAYS_INLINE constexpr Optional ( V )
{
construct_null_if_necessary ( ) ;
}
2022-12-09 23:14:40 +03:30
template < SameAs < OptionalNone > V >
2025-04-11 15:55:43 +02:00
ALWAYS_INLINE constexpr Optional & operator = ( V )
2022-12-09 23:14:40 +03:30
{
clear ( ) ;
return * this ;
}
2024-10-30 13:44:20 +01:00
AK_MAKE_CONDITIONALLY_COPYABLE ( Optional , < T > ) ;
2025-04-11 16:00:53 +02:00
AK_MAKE_CONDITIONALLY_MOVABLE ( Optional , < T > ) ;
2024-10-30 13:44:20 +01:00
AK_MAKE_CONDITIONALLY_DESTRUCTIBLE ( Optional , < T > ) ;
2019-07-08 11:29:38 +02:00
2025-04-11 15:55:43 +02:00
ALWAYS_INLINE constexpr Optional ( Optional const & other )
2022-10-17 00:06:11 +02:00
requires ( ! IsTriviallyCopyConstructible < T > )
2019-07-08 11:29:38 +02:00
: m_has_value ( other . m_has_value )
{
2022-01-23 13:03:29 +02:00
if ( other . has_value ( ) )
2025-04-11 15:55:43 +02:00
construct_at < RemoveConst < T > > ( & m_storage , other . value ( ) ) ;
else
construct_null_if_necessary ( ) ;
2019-07-08 11:29:38 +02:00
}
2025-04-11 15:55:43 +02:00
ALWAYS_INLINE constexpr Optional ( Optional & & other )
requires ( ! IsTriviallyMoveConstructible < T > )
2021-05-08 12:22:57 +03:00
: m_has_value ( other . m_has_value )
{
2022-01-23 13:03:29 +02:00
if ( other . has_value ( ) )
2025-04-11 15:55:43 +02:00
construct_at < RemoveConst < T > > ( & m_storage , other . release_value ( ) ) ;
else
construct_null_if_necessary ( ) ;
2022-01-23 13:03:29 +02:00
}
template < typename U >
2025-04-11 15:55:43 +02: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 22:53:16 +01:00
: m_has_value ( other . has_value ( ) )
2022-01-23 13:03:29 +02:00
{
if ( other . has_value ( ) )
2025-04-11 15:55:43 +02:00
construct_at < RemoveConst < T > > ( & m_storage , other . value ( ) ) ;
else
construct_null_if_necessary ( ) ;
2022-01-23 13:03:29 +02:00
}
template < typename U >
2025-04-11 15:55:43 +02: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 22:53:16 +01:00
: m_has_value ( other . has_value ( ) )
2022-01-23 13:03:29 +02:00
{
if ( other . has_value ( ) )
2025-04-11 15:55:43 +02:00
construct_at < RemoveConst < T > > ( & m_storage , other . release_value ( ) ) ;
else
construct_null_if_necessary ( ) ;
2021-05-08 12:22:57 +03:00
}
2021-07-02 17:42:50 +02:00
template < typename U = T >
2022-12-09 23:14:40 +03:30
requires ( ! IsSame < OptionalNone , RemoveCVReference < U > > )
2025-04-11 15:55:43 +02:00
ALWAYS_INLINE explicit ( ! IsConvertible < U & & , T > ) constexpr Optional ( U & & value )
2022-10-17 00:06:11 +02:00
requires ( ! IsSame < RemoveCVReference < U > , Optional < T > > & & IsConstructible < T , U & & > )
2021-05-08 12:22:57 +03:00
: m_has_value ( true )
{
2025-04-11 15:55:43 +02:00
construct_at < RemoveConst < T > > ( & m_storage , forward < U > ( value ) ) ;
2021-05-08 12:22:57 +03:00
}
2025-04-11 15:55:43 +02:00
ALWAYS_INLINE constexpr Optional & operator = ( Optional const & other )
2022-10-17 00:06:11 +02:00
requires ( ! IsTriviallyCopyConstructible < T > | | ! IsTriviallyDestructible < T > )
2019-07-08 11:29:38 +02:00
{
if ( this ! = & other ) {
clear ( ) ;
m_has_value = other . m_has_value ;
2025-04-11 15:55:43 +02:00
if ( other . has_value ( ) )
construct_at < RemoveConst < T > > ( & m_storage , other . value ( ) ) ;
2019-07-08 11:29:38 +02:00
}
return * this ;
}
2025-04-11 16:00:53 +02: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 15:55:43 +02:00
ALWAYS_INLINE constexpr Optional & operator = ( Optional & & other )
2025-04-11 16:00:53 +02: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 11:29:38 +02:00
{
if ( this ! = & other ) {
clear ( ) ;
m_has_value = other . m_has_value ;
2025-04-11 15:55:43 +02:00
if ( other . has_value ( ) )
construct_at < RemoveConst < T > > ( & m_storage , other . release_value ( ) ) ;
2019-07-08 11:29:38 +02:00
}
return * this ;
}
2025-04-11 16:00:53 +02: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 15:55:43 +02:00
ALWAYS_INLINE constexpr ~ Optional ( )
2024-10-22 16:47:01 +02:00
requires ( ! IsTriviallyDestructible < T > & & IsDestructible < T > )
2019-07-08 11:29:38 +02:00
{
clear ( ) ;
}
2025-04-11 15:55:43 +02:00
ALWAYS_INLINE constexpr void clear ( )
2019-07-08 11:29:38 +02:00
{
if ( m_has_value ) {
value ( ) . ~ T ( ) ;
m_has_value = false ;
}
}
2020-08-29 19:18:01 +02:00
template < typename . . . Parameters >
2025-04-11 15:55:43 +02:00
ALWAYS_INLINE constexpr void emplace ( Parameters & & . . . parameters )
2020-08-29 19:18:01 +02:00
{
clear ( ) ;
m_has_value = true ;
2025-04-11 15:55:43 +02:00
construct_at < RemoveConst < T > > ( & m_storage , forward < Parameters > ( parameters ) . . . ) ;
2020-08-29 19:18:01 +02:00
}
2022-12-10 19:36:32 +03:30
template < typename Callable >
2025-04-11 15:55:43 +02:00
ALWAYS_INLINE constexpr void lazy_emplace ( Callable callable )
2022-12-10 19:36:32 +03:30
{
clear ( ) ;
m_has_value = true ;
2025-04-11 15:55:43 +02:00
construct_at < RemoveConst < T > > ( & m_storage , callable ( ) ) ;
2022-12-10 19:36:32 +03:30
}
2025-04-11 15:55:43 +02:00
[ [ nodiscard ] ] ALWAYS_INLINE constexpr bool has_value ( ) const { return m_has_value ; }
2019-07-08 11:29:38 +02:00
2025-04-11 15:55:43 +02:00
[ [ nodiscard ] ] ALWAYS_INLINE constexpr T & value ( ) &
2019-07-08 11:29:38 +02:00
{
2021-02-23 20:42:32 +01:00
VERIFY ( m_has_value ) ;
2025-04-11 15:55:43 +02:00
return m_storage ;
2019-07-08 11:29:38 +02:00
}
2025-04-11 15:55:43 +02:00
[ [ nodiscard ] ] ALWAYS_INLINE constexpr T const & value ( ) const &
2019-07-08 11:29:38 +02:00
{
2021-02-23 20:42:32 +01:00
VERIFY ( m_has_value ) ;
2025-04-11 15:55:43 +02:00
return m_storage ;
2019-07-08 11:29:38 +02:00
}
2025-04-11 15:55:43 +02:00
[ [ nodiscard ] ] ALWAYS_INLINE constexpr T value ( ) & &
2021-09-04 00:44:10 +02:00
{
return release_value ( ) ;
}
2025-04-11 15:55:43 +02:00
[ [ nodiscard ] ] ALWAYS_INLINE constexpr T release_value ( )
2019-07-08 11:29:38 +02:00
{
2021-02-23 20:42:32 +01:00
VERIFY ( m_has_value ) ;
2019-07-08 11:29:38 +02:00
T released_value = move ( value ( ) ) ;
value ( ) . ~ T ( ) ;
2019-08-05 21:47:36 +02:00
m_has_value = false ;
2019-07-08 11:29:38 +02:00
return released_value ;
}
private :
2025-04-11 15:55:43 +02: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 11:29:38 +02:00
bool m_has_value { false } ;
} ;
2022-04-03 15:36:34 +04:30
template < typename T >
requires ( IsLvalueReference < T > ) class [ [ nodiscard ] ] Optional < T > {
2024-11-25 12:54:43 +01:00
AK_MAKE_DEFAULT_COPYABLE ( Optional ) ;
AK_MAKE_DEFAULT_MOVABLE ( Optional ) ;
2022-04-03 15:36:34 +04:30
template < typename >
friend class Optional ;
template < typename U >
2025-08-22 17:17:27 +02:00
constexpr static bool CanBePlacedInOptional = IsSame < RemoveReference < T > , RemoveReference < AddConstToReferencedType < U > > > & & ( IsBaseOf < RemoveReference < T > , RemoveReference < U > > | | IsSame < RemoveCVReference < T > , RemoveCVReference < U > > ) ;
2022-04-03 15:36:34 +04:30
public :
using ValueType = T ;
2025-04-11 15:55:43 +02:00
ALWAYS_INLINE constexpr Optional ( ) = default ;
2022-04-03 15:36:34 +04:30
2023-11-28 00:22:46 -05:00
template < SameAs < OptionalNone > V >
2025-04-11 15:55:43 +02:00
ALWAYS_INLINE constexpr Optional ( V ) { }
2023-11-28 00:22:46 -05:00
template < SameAs < OptionalNone > V >
2025-04-11 15:55:43 +02:00
ALWAYS_INLINE constexpr Optional & operator = ( V )
2023-11-28 00:22:46 -05:00
{
clear ( ) ;
return * this ;
}
2022-04-03 15:36:34 +04:30
template < typename U = T >
2025-04-11 15:55:43 +02:00
ALWAYS_INLINE constexpr Optional ( U & value )
2022-10-17 00:06:11 +02:00
requires ( CanBePlacedInOptional < U & > )
2022-04-03 15:36:34 +04:30
: m_pointer ( & value )
{
}
2025-04-11 15:55:43 +02:00
ALWAYS_INLINE constexpr Optional ( RemoveReference < T > & value )
2022-04-03 15:36:34 +04:30
: m_pointer ( & value )
{
}
template < typename U >
2025-04-11 15:55:43 +02:00
ALWAYS_INLINE constexpr Optional ( Optional < U > & other )
2022-10-17 00:06:11 +02:00
requires ( CanBePlacedInOptional < U > )
2024-10-27 10:13:43 +01:00
: m_pointer ( other . ptr ( ) )
{
}
template < typename U >
2025-04-11 15:55:43 +02:00
ALWAYS_INLINE constexpr Optional ( Optional < U > const & other )
2024-10-27 10:13:43 +01:00
requires ( CanBePlacedInOptional < U const > )
: m_pointer ( other . ptr ( ) )
2022-04-03 15:36:34 +04:30
{
}
template < typename U >
2025-04-11 15:55:43 +02:00
ALWAYS_INLINE constexpr Optional ( Optional < U > & & other )
2022-10-17 00:06:11 +02:00
requires ( CanBePlacedInOptional < U > )
2024-10-27 10:13:43 +01:00
: m_pointer ( other . ptr ( ) )
2022-04-03 15:36:34 +04:30
{
other . m_pointer = nullptr ;
}
template < typename U >
2025-04-11 15:55:43 +02:00
ALWAYS_INLINE constexpr Optional & operator = ( Optional < U > & other )
2022-10-17 00:06:11 +02:00
requires ( CanBePlacedInOptional < U > )
2022-04-03 15:36:34 +04:30
{
2024-10-27 10:13:43 +01:00
m_pointer = other . ptr ( ) ;
return * this ;
}
template < typename U >
2025-04-11 15:55:43 +02:00
ALWAYS_INLINE constexpr Optional & operator = ( Optional < U > const & other )
2024-10-27 10:13:43 +01:00
requires ( CanBePlacedInOptional < U const > )
{
m_pointer = other . ptr ( ) ;
2022-04-03 15:36:34 +04:30
return * this ;
}
template < typename U >
2025-04-11 15:55:43 +02:00
ALWAYS_INLINE constexpr Optional & operator = ( Optional < U > & & other )
2024-10-27 10:13:43 +01:00
requires ( CanBePlacedInOptional < U > & & IsLvalueReference < U > )
2022-04-03 15:36:34 +04:30
{
m_pointer = other . m_pointer ;
other . m_pointer = nullptr ;
return * this ;
}
template < typename U >
2023-11-28 00:22:46 -05:00
requires ( ! IsSame < OptionalNone , RemoveCVReference < U > > )
2025-04-11 15:55:43 +02:00
ALWAYS_INLINE constexpr Optional & operator = ( U & value )
2024-11-25 00:25:57 +01:00
requires ( CanBePlacedInOptional < U > )
2022-04-03 15:36:34 +04:30
{
m_pointer = & value ;
return * this ;
}
2024-11-25 00:25:57 +01: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 15:55:43 +02:00
ALWAYS_INLINE constexpr void clear ( )
2022-04-03 15:36:34 +04:30
{
m_pointer = nullptr ;
}
2025-04-11 15:55:43 +02:00
[ [ nodiscard ] ] ALWAYS_INLINE constexpr bool has_value ( ) const { return m_pointer ! = nullptr ; }
2022-04-03 15:36:34 +04:30
2025-07-15 00:22:12 +02:00
[ [ nodiscard ] ] ALWAYS_INLINE constexpr RemoveReference < T > * ptr ( )
2024-10-27 10:13:43 +01:00
{
return m_pointer ;
}
2025-07-15 00:22:12 +02:00
[ [ nodiscard ] ] ALWAYS_INLINE constexpr RemoveReference < T > const * ptr ( ) const
2024-10-27 10:13:43 +01:00
{
return m_pointer ;
}
2025-04-11 15:55:43 +02:00
[ [ nodiscard ] ] ALWAYS_INLINE constexpr T value ( )
2022-04-03 15:36:34 +04:30
{
VERIFY ( m_pointer ) ;
return * m_pointer ;
}
2025-04-11 15:55:43 +02:00
[ [ nodiscard ] ] ALWAYS_INLINE constexpr AddConstToReferencedType < T > value ( ) const
2022-04-03 15:36:34 +04:30
{
VERIFY ( m_pointer ) ;
return * m_pointer ;
}
template < typename U >
2025-07-15 00:22:12 +02:00
requires ( IsBaseOf < RemoveCVReference < T > , U > ) [ [ nodiscard ] ] ALWAYS_INLINE constexpr AddConstToReferencedType < T > value_or ( U & fallback ) const
2022-04-03 15:36:34 +04:30
{
if ( m_pointer )
return value ( ) ;
return fallback ;
}
// Note that this ends up copying the value.
2025-04-11 15:55:43 +02:00
[ [ nodiscard ] ] ALWAYS_INLINE constexpr RemoveCVReference < T > value_or ( RemoveCVReference < T > fallback ) const
2022-04-03 15:36:34 +04:30
{
if ( m_pointer )
return value ( ) ;
return fallback ;
}
2025-04-11 15:55:43 +02:00
[ [ nodiscard ] ] ALWAYS_INLINE constexpr T release_value ( )
2022-04-03 15:36:34 +04:30
{
return * exchange ( m_pointer , nullptr ) ;
}
2025-04-11 15:55:43 +02:00
ALWAYS_INLINE constexpr AddConstToReferencedType < T > operator * ( ) const { return value ( ) ; }
ALWAYS_INLINE constexpr T operator * ( ) { return value ( ) ; }
2022-04-03 15:36:34 +04:30
2025-07-15 00:22:12 +02:00
ALWAYS_INLINE constexpr RawPtr < AddConst < RemoveReference < T > > > operator - > ( ) const { return & value ( ) ; }
ALWAYS_INLINE constexpr RawPtr < RemoveReference < T > > operator - > ( ) { return & value ( ) ; }
2022-04-03 15:36:34 +04:30
2024-11-25 13:23:31 +01:00
// Conversion operators from Optional<T&> -> Optional<T>, implicit when T is trivially copyable.
2025-04-11 15:55:43 +02:00
ALWAYS_INLINE constexpr operator Optional < RemoveCVReference < T > > ( ) const
2024-11-25 13:23:31 +01:00
requires ( IsTriviallyCopyable < RemoveCVReference < T > > )
2022-04-03 15:36:34 +04:30
{
if ( has_value ( ) )
return Optional < RemoveCVReference < T > > ( value ( ) ) ;
return { } ;
}
2024-11-25 13:23:31 +01:00
// Conversion operators from Optional<T&> -> Optional<T>, explicit when T is not trivially copyable, since this is usually a mistake.
2025-04-11 15:55:43 +02:00
ALWAYS_INLINE explicit constexpr operator Optional < RemoveCVReference < T > > ( ) const
2024-11-25 13:23:31 +01: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 20:14:06 +03:30
template < typename Callback >
2025-04-11 15:55:43 +02:00
[ [ nodiscard ] ] ALWAYS_INLINE constexpr T value_or_lazy_evaluated ( Callback callback ) const
2022-12-09 20:14:06 +03:30
{
if ( m_pointer ! = nullptr )
return value ( ) ;
return callback ( ) ;
}
template < typename Callback >
2025-04-11 15:55:43 +02:00
[ [ nodiscard ] ] ALWAYS_INLINE constexpr Optional < T > value_or_lazy_evaluated_optional ( Callback callback ) const
2022-12-09 20:14:06 +03:30
{
if ( m_pointer ! = nullptr )
return value ( ) ;
return callback ( ) ;
}
template < typename Callback >
2025-04-11 15:55:43 +02:00
[ [ nodiscard ] ] ALWAYS_INLINE constexpr ErrorOr < T > try_value_or_lazy_evaluated ( Callback callback ) const
2022-12-09 20:14:06 +03:30
{
if ( m_pointer ! = nullptr )
return value ( ) ;
return TRY ( callback ( ) ) ;
}
template < typename Callback >
2025-04-11 15:55:43 +02:00
[ [ nodiscard ] ] ALWAYS_INLINE constexpr ErrorOr < Optional < T > > try_value_or_lazy_evaluated_optional ( Callback callback ) const
2022-12-09 20:14:06 +03:30
{
if ( m_pointer ! = nullptr )
return value ( ) ;
return TRY ( callback ( ) ) ;
}
2025-09-17 15:45:45 +02:00
template < typename Callback >
[ [ nodiscard ] ] ALWAYS_INLINE constexpr T ensure ( Callback callback ) &
{
if ( m_pointer = = nullptr )
m_pointer = & callback ( ) ;
return * m_pointer ;
}
2022-12-09 20:12:24 +03:30
template < typename F , typename MappedType = decltype ( declval < F > ( ) ( declval < T & > ( ) ) ) , auto IsErrorOr = IsSpecializationOf < MappedType , ErrorOr > , typename OptionalType = Optional < ConditionallyResultType < IsErrorOr , MappedType > > >
2025-04-11 15:55:43 +02:00
ALWAYS_INLINE constexpr Conditional < IsErrorOr , ErrorOr < OptionalType > , OptionalType > map ( F & & mapper )
2022-12-09 20:12:24 +03:30
{
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 15:55:43 +02:00
ALWAYS_INLINE constexpr Conditional < IsErrorOr , ErrorOr < OptionalType > , OptionalType > map ( F & & mapper ) const
2022-12-09 20:12:24 +03:30
{
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 15:36:34 +04:30
private :
RemoveReference < T > * m_pointer { nullptr } ;
} ;
2024-12-29 00:25:21 -05:00
template < typename T1 , typename T2 >
2025-04-11 15:55:43 +02:00
ALWAYS_INLINE constexpr bool operator = = ( Optional < T1 > const & first , Optional < T2 > const & second )
2024-12-29 00:25:21 -05:00
{
return first . has_value ( ) = = second . has_value ( )
& & ( ! first . has_value ( ) | | first . value ( ) = = second . value ( ) ) ;
}
template < typename T1 , typename T2 >
2025-04-11 15:55:43 +02:00
ALWAYS_INLINE constexpr bool operator = = ( Optional < T1 > const & first , T2 const & second )
2024-12-29 00:25:21 -05:00
{
return first . has_value ( ) & & first . value ( ) = = second ;
}
2025-03-13 18:29:59 +13:00
template < typename T >
2025-04-11 15:55:43 +02:00
ALWAYS_INLINE constexpr bool operator = = ( Optional < T > const & first , OptionalNone )
2025-03-13 18:29:59 +13:00
{
return ! first . has_value ( ) ;
}
2025-07-06 20:42:40 +12:00
template < typename T >
struct Traits < Optional < T > > : public DefaultTraits < Optional < T > > {
static unsigned hash ( Optional < T > const & optional )
{
// Arbitrary-ish value for an empty optional, but not 0 as that is a common 'hash' for many T's.
if ( ! optional . has_value ( ) )
return 13 ;
return Traits < T > : : hash ( optional . value ( ) ) ;
}
} ;
2020-02-14 22:29:06 +01:00
}
2022-11-26 12:18:30 +01:00
# if USING_AK_GLOBALLY
2020-02-14 22:29:06 +01:00
using AK : : Optional ;
2023-01-14 23:15:04 -05:00
using AK : : OptionalNone ;
2022-11-26 12:18:30 +01:00
# endif