2022-03-09 15:17:54 +00:00
# pragma once
# include "CoreTypes.h"
2022-03-13 15:18:07 +00:00
# include "Concepts/Comparable.h"
2022-03-09 15:17:54 +00:00
# include "TypeTraits/TypeTraits.h"
# include "Miscellaneous/AssertionMacros.h"
NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN ( Redcraft )
NAMESPACE_MODULE_BEGIN ( Utility )
2022-03-23 09:49:30 +00:00
template < typename OptionalType > requires TIsObject < OptionalType > : : Value & & ( ! TIsArray < OptionalType > : : Value ) & & TIsDestructible < OptionalType > : : Value
2022-03-09 15:17:54 +00:00
struct TOptional
{
public :
2022-03-23 09:49:30 +00:00
using ValueType = OptionalType ;
2022-03-09 15:17:54 +00:00
constexpr TOptional ( ) : bIsValid ( false ) { }
2022-03-14 10:03:57 +00:00
constexpr TOptional ( FInvalid ) : TOptional ( ) { }
2022-03-13 15:18:07 +00:00
template < typename . . . Types > requires TIsConstructible < OptionalType , Types . . . > : : Value
2022-03-14 10:03:57 +00:00
constexpr explicit TOptional ( FInPlace , Types & & . . . Args )
2022-03-09 15:17:54 +00:00
: bIsValid ( true )
{
2022-03-13 15:18:07 +00:00
new ( & Value ) OptionalType ( Forward < Types > ( Args ) . . . ) ;
2022-03-09 15:17:54 +00:00
}
2022-03-13 15:18:07 +00:00
template < typename T = OptionalType > requires TIsConstructible < OptionalType , T & & > : : Value
2022-03-14 10:03:57 +00:00
& & ( ! TIsSame < typename TRemoveCVRef < T > : : Type , FInPlace > : : Value ) & & ( ! TIsSame < typename TRemoveCVRef < T > : : Type , TOptional > : : Value )
2022-03-23 09:49:30 +00:00
constexpr explicit ( ! TIsConvertible < T & & , OptionalType > : : Value ) TOptional ( T & & InValue )
2022-03-13 15:18:07 +00:00
: TOptional ( InPlace , Forward < T > ( InValue ) )
2022-03-09 15:17:54 +00:00
{ }
2022-03-13 15:18:07 +00:00
constexpr TOptional ( const TOptional & InValue )
: bIsValid ( InValue . IsValid ( ) )
{
if ( InValue . IsValid ( ) ) new ( & Value ) OptionalType ( InValue . GetValue ( ) ) ;
}
constexpr TOptional ( TOptional & & InValue )
: bIsValid ( InValue . IsValid ( ) )
{
if ( InValue . IsValid ( ) ) new ( & Value ) OptionalType ( MoveTemp ( InValue . GetValue ( ) ) ) ;
}
2022-03-09 15:17:54 +00:00
2022-03-13 15:18:07 +00:00
template < typename T = OptionalType > requires TIsConstructible < OptionalType , const T & > : : Value
2022-03-23 09:49:30 +00:00
constexpr explicit ( ! TIsConvertible < const T & , OptionalType > : : Value ) TOptional ( const TOptional < T > & InValue )
2022-03-13 15:18:07 +00:00
: bIsValid ( InValue . IsValid ( ) )
2022-03-09 15:17:54 +00:00
{
2022-03-13 15:18:07 +00:00
if ( InValue . IsValid ( ) ) new ( & Value ) OptionalType ( InValue . GetValue ( ) ) ;
2022-03-09 15:17:54 +00:00
}
2022-03-13 15:18:07 +00:00
template < typename T = OptionalType > requires TIsConstructible < OptionalType , T & & > : : Value
2022-03-23 09:49:30 +00:00
constexpr explicit ( ! TIsConvertible < T & & , OptionalType > : : Value ) TOptional ( TOptional < T > & & InValue )
2022-03-13 15:18:07 +00:00
: bIsValid ( InValue . IsValid ( ) )
2022-03-09 15:17:54 +00:00
{
2022-03-13 15:18:07 +00:00
if ( InValue . IsValid ( ) ) new ( & Value ) OptionalType ( MoveTemp ( InValue . GetValue ( ) ) ) ;
2022-03-09 15:17:54 +00:00
}
constexpr ~ TOptional ( )
{
2022-03-23 09:49:30 +00:00
if constexpr ( ! TIsTriviallyDestructible < OptionalType > : : Value ) Reset ( ) ;
2022-03-09 15:17:54 +00:00
}
2022-03-13 15:18:07 +00:00
constexpr TOptional & operator = ( const TOptional & InValue )
2022-03-09 15:17:54 +00:00
{
2022-03-13 15:18:07 +00:00
if ( & InValue = = this ) return * this ;
2022-03-09 15:17:54 +00:00
2022-03-13 15:18:07 +00:00
if ( ! InValue . IsValid ( ) )
{
Reset ( ) ;
return * this ;
}
2022-03-09 15:17:54 +00:00
2022-03-13 15:18:07 +00:00
if ( IsValid ( ) ) GetValue ( ) = InValue . GetValue ( ) ;
else
2022-03-09 15:17:54 +00:00
{
2022-03-13 15:18:07 +00:00
new ( & Value ) OptionalType ( InValue . GetValue ( ) ) ;
2022-03-09 15:17:54 +00:00
bIsValid = true ;
}
return * this ;
}
2022-03-13 15:18:07 +00:00
constexpr TOptional & operator = ( TOptional & & InValue )
2022-03-09 15:17:54 +00:00
{
2022-03-13 15:18:07 +00:00
if ( & InValue = = this ) return * this ;
2022-03-09 15:17:54 +00:00
2022-03-13 15:18:07 +00:00
if ( ! InValue . IsValid ( ) )
{
Reset ( ) ;
return * this ;
}
2022-03-09 15:17:54 +00:00
2022-03-13 15:18:07 +00:00
if ( IsValid ( ) ) GetValue ( ) = MoveTemp ( InValue . GetValue ( ) ) ;
else
2022-03-09 15:17:54 +00:00
{
2022-03-13 15:18:07 +00:00
new ( & Value ) OptionalType ( MoveTemp ( InValue . GetValue ( ) ) ) ;
2022-03-09 15:17:54 +00:00
bIsValid = true ;
}
return * this ;
}
2022-03-13 15:18:07 +00:00
template < typename T = OptionalType > requires TIsConstructible < OptionalType , const T & > : : Value
constexpr TOptional & operator = ( const TOptional < T > & InValue )
2022-03-09 15:17:54 +00:00
{
2022-03-13 15:18:07 +00:00
if ( ! InValue . IsValid ( ) )
{
Reset ( ) ;
return * this ;
}
2022-03-09 15:17:54 +00:00
2022-03-13 15:18:07 +00:00
if ( IsValid ( ) ) GetValue ( ) = InValue . GetValue ( ) ;
else
{
new ( & Value ) OptionalType ( InValue . GetValue ( ) ) ;
bIsValid = true ;
}
2022-03-09 15:17:54 +00:00
return * this ;
}
2022-03-13 15:18:07 +00:00
template < typename T = OptionalType > requires TIsConstructible < OptionalType , T & & > : : Value
constexpr TOptional & operator = ( TOptional < T > & & InValue )
{
if ( ! InValue . IsValid ( ) )
{
Reset ( ) ;
return * this ;
}
if ( IsValid ( ) ) GetValue ( ) = MoveTemp ( InValue . GetValue ( ) ) ;
else
{
new ( & Value ) OptionalType ( MoveTemp ( InValue . GetValue ( ) ) ) ;
bIsValid = true ;
}
return * this ;
}
template < typename T = OptionalType > requires TIsConstructible < OptionalType , T & & > : : Value
constexpr TOptional & operator = ( T & & InValue )
{
if ( IsValid ( ) ) GetValue ( ) = Forward < T > ( InValue ) ;
else
{
new ( & Value ) OptionalType ( Forward < T > ( InValue ) ) ;
bIsValid = true ;
}
return * this ;
}
2022-03-09 15:17:54 +00:00
template < typename . . . ArgsType >
2022-03-13 15:18:07 +00:00
constexpr OptionalType & Emplace ( ArgsType & & . . . Args )
2022-03-09 15:17:54 +00:00
{
Reset ( ) ;
2022-03-13 15:18:07 +00:00
OptionalType * Result = new ( & Value ) OptionalType ( Forward < ArgsType > ( Args ) . . . ) ;
2022-03-09 15:17:54 +00:00
bIsValid = true ;
return * Result ;
}
constexpr bool IsValid ( ) const { return bIsValid ; }
constexpr explicit operator bool ( ) const { return bIsValid ; }
2022-03-23 09:49:30 +00:00
constexpr void * GetData ( ) { return & Value ; }
constexpr const void * GetData ( ) const { return & Value ; }
2022-03-09 15:17:54 +00:00
2022-03-23 09:49:30 +00:00
constexpr OptionalType & GetValue ( ) & { checkf ( IsValid ( ) , TEXT ( " It is an error to call GetValue() on an unset TOptional. Please either check IsValid() or use Get(DefaultValue) instead. " ) ) ; return * reinterpret_cast < OptionalType * > ( & Value ) ; }
constexpr OptionalType & & GetValue ( ) & & { checkf ( IsValid ( ) , TEXT ( " It is an error to call GetValue() on an unset TOptional. Please either check IsValid() or use Get(DefaultValue) instead. " ) ) ; return MoveTemp ( * reinterpret_cast < OptionalType * > ( & Value ) ) ; }
constexpr const OptionalType & GetValue ( ) const & { checkf ( IsValid ( ) , TEXT ( " It is an error to call GetValue() on an unset TOptional. Please either check IsValid() or use Get(DefaultValue) instead. " ) ) ; return * reinterpret_cast < const OptionalType * > ( & Value ) ; }
constexpr const OptionalType & & GetValue ( ) const & & { checkf ( IsValid ( ) , TEXT ( " It is an error to call GetValue() on an unset TOptional. Please either check IsValid() or use Get(DefaultValue) instead. " ) ) ; return MoveTemp ( * reinterpret_cast < const OptionalType * > ( & Value ) ) ; }
2022-03-09 15:17:54 +00:00
2022-03-13 15:18:07 +00:00
constexpr const OptionalType * operator - > ( ) const { return & GetValue ( ) ; }
constexpr OptionalType * operator - > ( ) { return & GetValue ( ) ; }
2022-03-09 15:17:54 +00:00
2022-03-13 15:18:07 +00:00
constexpr OptionalType & operator * ( ) & { return GetValue ( ) ; }
constexpr OptionalType & & operator * ( ) & & { return GetValue ( ) ; }
constexpr const OptionalType & operator * ( ) const & { return GetValue ( ) ; }
constexpr const OptionalType & & operator * ( ) const & & { return GetValue ( ) ; }
2022-03-09 15:17:54 +00:00
2022-03-23 09:49:30 +00:00
constexpr OptionalType & Get ( OptionalType & DefaultValue ) & { return IsValid ( ) ? GetValue ( ) : DefaultValue ; }
constexpr const OptionalType & Get ( const OptionalType & DefaultValue ) const & { return IsValid ( ) ? GetValue ( ) : DefaultValue ; }
2022-03-09 15:17:54 +00:00
constexpr void Reset ( )
{
if ( bIsValid )
{
bIsValid = false ;
2022-03-13 15:18:07 +00:00
typedef OptionalType DestructOptionalType ;
( ( OptionalType * ) & Value ) - > DestructOptionalType : : ~ DestructOptionalType ( ) ;
2022-03-09 15:17:54 +00:00
}
}
private :
2022-03-13 15:18:07 +00:00
TAlignedStorage < sizeof ( OptionalType ) , alignof ( OptionalType ) > : : Type Value ;
2022-03-09 15:17:54 +00:00
bool bIsValid ;
} ;
template < typename T >
TOptional ( T ) - > TOptional < T > ;
template < typename T , typename U >
constexpr bool operator = = ( const TOptional < T > & LHS , const TOptional < U > & RHS )
{
2022-03-13 15:18:07 +00:00
if ( LHS . IsValid ( ) ! = RHS . IsValid ( ) ) return false ;
2022-03-09 15:17:54 +00:00
if ( LHS . IsValid ( ) = = false ) return true ;
return * LHS = = * RHS ;
}
template < typename T , typename U >
constexpr bool operator ! = ( const TOptional < T > & LHS , const TOptional < U > & RHS )
{
2022-03-13 15:18:07 +00:00
if ( LHS . IsValid ( ) ! = RHS . IsValid ( ) ) return true ;
2022-03-15 03:52:46 +00:00
if ( LHS . IsValid ( ) = = false ) return false ;
2022-03-09 15:17:54 +00:00
return * LHS ! = * RHS ;
}
2022-03-13 15:18:07 +00:00
template < typename T , typename U >
constexpr bool operator = = ( const TOptional < T > & LHS , const U & RHS )
{
return LHS . IsValid ( ) ? * LHS = = RHS : false ;
}
template < typename T , typename U >
constexpr bool operator ! = ( const TOptional < T > & LHS , const U & RHS )
{
return LHS . IsValid ( ) ? * LHS ! = RHS : true ;
}
template < typename T , typename U >
constexpr bool operator = = ( const T & LHS , const TOptional < U > & RHS )
{
return RHS . IsValid ( ) ? LHS = = * RHS : false ;
}
template < typename T , typename U >
constexpr bool operator ! = ( const T & LHS , const TOptional < U > & RHS )
{
return RHS . IsValid ( ) ? LHS ! = * RHS : true ;
}
2022-03-09 15:17:54 +00:00
2022-03-22 03:12:05 +00:00
template < typename T >
constexpr bool operator = = ( const TOptional < T > & LHS , FInvalid )
{
return ! LHS . IsValid ( ) ;
}
template < typename T >
constexpr bool operator ! = ( const TOptional < T > & LHS , FInvalid )
{
return LHS . IsValid ( ) ;
}
template < typename T >
constexpr bool operator = = ( FInvalid , const TOptional < T > & RHS )
{
return ! RHS . IsValid ( ) ;
}
template < typename T >
constexpr bool operator ! = ( FInvalid , const TOptional < T > & RHS )
{
return RHS . IsValid ( ) ;
}
2022-03-14 10:03:57 +00:00
template < typename T >
constexpr TOptional < typename TDecay < T > : : Type > MakeOptional ( FInvalid )
{
return TOptional < typename TDecay < T > : : Type > ( Invalid ) ;
}
2022-03-09 15:17:54 +00:00
template < typename T >
constexpr TOptional < typename TDecay < T > : : Type > MakeOptional ( T & & InValue )
{
return TOptional < typename TDecay < T > : : Type > ( Forward < T > ( InValue ) ) ;
}
template < typename T , typename . . . Types >
constexpr TOptional < T > MakeOptional ( Types & & . . . Args )
{
return TOptional < T > ( InPlace , Forward < T > ( Args ) . . . ) ;
}
2022-03-13 15:18:07 +00:00
template < typename T > requires TIsMoveConstructible < T > : : Value & & TIsSwappable < T > : : Value
2022-03-09 15:17:54 +00:00
constexpr void Swap ( TOptional < T > & A , TOptional < T > & B )
{
if ( ! A & & ! B ) return ;
if ( A & & ! B )
{
2022-03-13 15:18:07 +00:00
B = MoveTemp ( A ) ;
2022-03-09 15:17:54 +00:00
A . Reset ( ) ;
return ;
}
if ( B & & ! A )
{
2022-03-13 15:18:07 +00:00
A = MoveTemp ( B ) ;
2022-03-09 15:17:54 +00:00
B . Reset ( ) ;
return ;
}
Swap ( * A , * B ) ;
}
NAMESPACE_MODULE_END ( Utility )
NAMESPACE_MODULE_END ( Redcraft )
NAMESPACE_REDCRAFT_END