2022-03-15 19:26:31 +08:00
#pragma once
#include "CoreTypes.h"
#include "Templates/Invoke.h"
#include "Templates/Utility.h"
2022-04-22 22:28:44 +08:00
#include "Templates/TypeHash.h"
2022-03-15 19:26:31 +08:00
#include "TypeTraits/TypeTraits.h"
2022-12-03 23:11:05 +08:00
#include "Templates/Meta.h"
2022-05-12 23:36:32 +08:00
#include "Memory/MemoryOperator.h"
2022-05-03 18:22:41 +08:00
#include "Miscellaneous/Compare.h"
2022-03-22 11:12:05 +08:00
#include "Miscellaneous/AssertionMacros.h"
2022-03-15 19:26:31 +08:00
NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN ( Redcraft )
NAMESPACE_MODULE_BEGIN ( Utility )
2022-11-17 18:48:20 +08:00
template < typename ... Ts > requires ( sizeof ...( Ts ) > 0 && ( true && ... && CDestructible < Ts > ))
2022-11-15 19:28:43 +08:00
class TVariant ;
2022-06-16 23:37:29 +08:00
2022-03-15 19:26:31 +08:00
NAMESPACE_PRIVATE_BEGIN
2022-11-17 18:48:20 +08:00
template < typename T > struct TIsTVariant : FFalse { };
2022-11-16 19:13:37 +08:00
template < typename ... Ts > struct TIsTVariant < TVariant < Ts ... >> : FTrue { };
2022-06-16 23:37:29 +08:00
2022-12-03 23:11:05 +08:00
template < typename VariantType >
2022-06-16 23:37:29 +08:00
struct TVariantNumImpl ;
2022-11-16 19:13:37 +08:00
template < typename ... Ts >
2022-12-03 23:11:05 +08:00
struct TVariantNumImpl < TVariant < Ts ... >> : TConstant < size_t , Meta :: TSize < TTypeSequence < Ts ... >>> { };
2022-06-16 23:37:29 +08:00
2022-12-03 23:11:05 +08:00
template < typename T , typename VariantType >
2022-06-16 23:37:29 +08:00
struct TVariantIndexImpl ;
2022-03-15 19:26:31 +08:00
2022-11-16 19:13:37 +08:00
template < typename T , typename ... Ts >
2022-12-03 23:11:05 +08:00
struct TVariantIndexImpl < T , TVariant < Ts ... >> : TConstant < size_t , Meta :: TIndex < T , TTypeSequence < Ts ... >>> { };
2022-06-16 23:37:29 +08:00
2022-12-03 23:11:05 +08:00
template < size_t I , typename VariantType >
2022-06-16 23:37:29 +08:00
struct TVariantAlternativeImpl ;
2022-12-03 23:11:05 +08:00
template < size_t I , typename ... Ts >
struct TVariantAlternativeImpl < I , TVariant < Ts ... >>
2022-06-16 23:37:29 +08:00
{
2022-12-03 23:11:05 +08:00
using Type = Meta :: TType < I , TTypeSequence < Ts ... >> ;
2022-06-16 23:37:29 +08:00
};
2022-12-03 23:12:29 +08:00
template < typename T , typename TSequence >
struct TVariantOverloadType
2022-03-15 19:26:31 +08:00
{
2022-12-03 23:12:29 +08:00
using FrontType = Meta :: TFront < TSequence > ;
using NextSequence = Meta :: TPop < TSequence > ;
using NextUniqueSequence = typename TVariantOverloadType < T , NextSequence >:: Type ;
2022-03-15 19:26:31 +08:00
2022-12-03 23:12:29 +08:00
// T_i x[] = { Forward<T>(t) };
static constexpr bool bConditional = requires { DeclVal < void ( FrontType ( && )[ 1 ]) > ()({ DeclVal < T > () }); };
2022-03-15 19:26:31 +08:00
2022-12-03 23:12:29 +08:00
using Type = TConditional < bConditional , Meta :: TPush < FrontType , NextUniqueSequence > , NextUniqueSequence > ;
2022-03-15 19:26:31 +08:00
};
template < typename T >
2022-12-03 23:12:29 +08:00
struct TVariantOverloadType < T , TTypeSequence <>>
2022-03-15 19:26:31 +08:00
{
2022-12-03 23:12:29 +08:00
using Type = TTypeSequence <> ;
2022-03-15 19:26:31 +08:00
};
2022-12-03 23:12:29 +08:00
template < typename T , typename ... Ts >
using TVariantSelectedType = Meta :: TOverloadResolution < T , typename NAMESPACE_PRIVATE :: TVariantOverloadType < T , TTypeSequence < Ts ... >>:: Type > ;
2022-03-15 19:26:31 +08:00
NAMESPACE_PRIVATE_END
2022-06-16 23:37:29 +08:00
template < typename T >
2022-11-17 20:57:54 +08:00
concept CTVariant = NAMESPACE_PRIVATE :: TIsTVariant < TRemoveCV < T >>:: Value ;
2022-06-16 23:37:29 +08:00
2022-11-17 20:57:54 +08:00
template < CTVariant T >
2022-12-03 23:11:05 +08:00
inline constexpr size_t TVariantNum = NAMESPACE_PRIVATE :: TVariantNumImpl < TRemoveCV < T >>:: Value ;
2022-06-16 23:37:29 +08:00
2022-11-17 20:57:54 +08:00
template < typename T , CTVariant U >
2022-12-03 23:11:05 +08:00
inline constexpr size_t TVariantIndex = NAMESPACE_PRIVATE :: TVariantIndexImpl < T , TRemoveCV < U >>:: Value ;
2022-06-16 23:37:29 +08:00
2022-11-17 20:57:54 +08:00
template < size_t I , CTVariant U >
2022-12-03 23:11:05 +08:00
using TVariantAlternative = TCopyCV < U , typename NAMESPACE_PRIVATE :: TVariantAlternativeImpl < I , TRemoveCV < U >>:: Type > ;
2022-06-16 23:37:29 +08:00
2022-12-29 21:55:02 +08:00
/**
* The class template TVariant represents a type-safe union. An instance of TVariant
* holds a value of one of its alternative types, or in the case of invalid - no value.
*/
2022-11-17 18:48:20 +08:00
template < typename ... Ts > requires ( sizeof ...( Ts ) > 0 && ( true && ... && CDestructible < Ts > ))
2022-12-30 19:11:01 +08:00
class TVariant final
2022-03-15 19:26:31 +08:00
{
2022-11-15 19:28:43 +08:00
public :
2022-12-29 21:55:02 +08:00
/** Constructs an invalid object. */
2022-12-13 22:02:39 +08:00
FORCEINLINE constexpr TVariant () : TypeIndex ( 0xFF ) { };
2022-03-15 19:26:31 +08:00
2022-12-29 21:55:02 +08:00
/** Constructs an invalid object. */
2022-12-13 22:02:39 +08:00
FORCEINLINE constexpr TVariant ( FInvalid ) : TVariant () { };
2022-03-15 19:26:31 +08:00
2022-12-29 21:55:02 +08:00
/** Copies content of other into a new instance. */
2022-12-13 22:02:39 +08:00
FORCEINLINE constexpr TVariant ( const TVariant & InValue ) requires ( true && ... && CTriviallyCopyConstructible < Ts > ) = default ;
2022-11-17 23:17:50 +08:00
2022-12-29 21:55:02 +08:00
/** Copies content of other into a new instance. */
2022-12-13 22:02:39 +08:00
FORCEINLINE constexpr TVariant ( const TVariant & InValue ) requires (( true && ... && CCopyConstructible < Ts > ) && ! ( true && ... && CTriviallyCopyConstructible < Ts > ))
2022-04-22 22:28:44 +08:00
: TypeIndex ( static_cast < uint8 > ( InValue . GetIndex ()))
2022-03-15 19:26:31 +08:00
{
2022-05-12 23:36:32 +08:00
if ( IsValid ()) CopyConstructImpl [ InValue . GetIndex ()]( & Value , & InValue . Value );
2022-03-15 19:26:31 +08:00
}
2022-12-29 21:55:02 +08:00
/** Moves content of other into a new instance. */
2022-12-13 22:02:39 +08:00
FORCEINLINE constexpr TVariant ( TVariant && InValue ) requires ( true && ... && CTriviallyMoveConstructible < Ts > ) = default ;
2022-11-17 23:17:50 +08:00
2022-12-29 21:55:02 +08:00
/** Moves content of other into a new instance. */
2022-12-13 22:02:39 +08:00
FORCEINLINE constexpr TVariant ( TVariant && InValue ) requires (( true && ... && CMoveConstructible < Ts > ) && ! ( true && ... && CTriviallyMoveConstructible < Ts > ))
2022-04-22 22:28:44 +08:00
: TypeIndex ( static_cast < uint8 > ( InValue . GetIndex ()))
2022-03-15 19:26:31 +08:00
{
2022-05-12 23:36:32 +08:00
if ( IsValid ()) MoveConstructImpl [ InValue . GetIndex ()]( & Value , & InValue . Value );
2022-03-15 19:26:31 +08:00
}
2022-12-29 21:55:02 +08:00
/**
* Converting constructor. Constructs a variant holding the alternative type that would be selected
* by overload resolution for the expression F(Forward<T>(InValue)) if there was an overload of
* imaginary function F(T) for every T from Ts... in scope at the same time, except that an overload F(T)
* is only considered if the declaration T X[] = { Forward<T>(InValue) }; is valid for some invented variable x.
* Direct-initializes the contained value as if by direct non-list-initialization from Forward<T>(InValue).
*/
2022-12-03 23:12:29 +08:00
template < typename T > requires ( requires { typename NAMESPACE_PRIVATE :: TVariantSelectedType < T , Ts ... > ; }
2022-11-16 22:03:54 +08:00
&& ! CTInPlaceType < TRemoveCVRef < T >> && ! CTInPlaceIndex < TRemoveCVRef < T >>
2022-12-19 18:00:52 +08:00
&& ! CSameAs < TVariant , TRemoveCVRef < T >> )
2022-12-13 22:02:39 +08:00
FORCEINLINE constexpr TVariant ( T && InValue ) : TVariant ( InPlaceType < NAMESPACE_PRIVATE :: TVariantSelectedType < T , Ts ... >> , Forward < T > ( InValue ))
2022-03-15 19:26:31 +08:00
{ }
2022-12-29 21:55:02 +08:00
/** Constructs a variant with the specified alternative T and initializes the contained value with the arguments Forward<Us>(Args).... */
template < typename T , typename ... Us > requires ( CConstructibleFrom < T , Us ... > )
FORCEINLINE constexpr explicit TVariant ( TInPlaceType < T > , Us && ... Args )
: TVariant ( InPlaceIndex < TVariantIndex < T , TVariant < Ts ... >>> , Forward < Us > ( Args )...)
{ }
2022-03-15 19:26:31 +08:00
2022-12-29 21:55:02 +08:00
/** Constructs a variant with the alternative T specified by the index I and initializes the contained value with the arguments Forward<Us>(Args).... */
template < size_t I , typename ... Us > requires ( I < sizeof ...( Ts )
&& CConstructibleFrom < TVariantAlternative < I , TVariant < Ts ... >> , Us ... > )
FORCEINLINE constexpr explicit TVariant ( TInPlaceIndex < I > , Us && ... Args )
: TypeIndex ( I )
{
using SelectedType = TVariantAlternative < I , TVariant < Ts ... >> ;
new ( & Value ) SelectedType ( Forward < Us > ( Args )...);
}
/** Destroys the contained object, if any, as if by a call to Reset(). */
2022-12-13 22:02:39 +08:00
FORCEINLINE constexpr ~ TVariant () requires ( true && ... && CTriviallyDestructible < Ts > ) = default ;
2022-11-17 23:17:50 +08:00
2022-12-29 21:55:02 +08:00
/** Destroys the contained object, if any, as if by a call to Reset(). */
2022-12-13 22:02:39 +08:00
FORCEINLINE constexpr ~ TVariant () requires ( ! ( true && ... && CTriviallyDestructible < Ts > ))
2022-03-15 19:26:31 +08:00
{
2022-11-17 23:17:50 +08:00
Reset ();
2022-03-15 19:26:31 +08:00
}
2022-12-29 21:55:02 +08:00
/** Assigns by copying the state of 'InValue'. */
2022-12-13 22:02:39 +08:00
FORCEINLINE constexpr TVariant & operator = ( const TVariant & InValue ) requires ( true && ... && ( CTriviallyCopyConstructible < Ts > && CTriviallyCopyAssignable < Ts > )) = default ;
2022-11-17 23:17:50 +08:00
2022-12-29 21:55:02 +08:00
/** Assigns by copying the state of 'InValue'. */
2022-12-16 23:23:05 +08:00
constexpr TVariant & operator = ( const TVariant & InValue ) requires (( true && ... && ( CCopyConstructible < Ts > && CCopyAssignable < Ts > ))
2022-11-17 23:17:50 +08:00
&& ! ( true && ... && ( CTriviallyCopyConstructible < Ts > && CTriviallyCopyAssignable < Ts > )))
2022-03-15 19:26:31 +08:00
{
if ( & InValue == this ) return * this ;
if ( ! InValue . IsValid ())
{
Reset ();
return * this ;
}
2022-05-12 23:36:32 +08:00
if ( GetIndex () == InValue . GetIndex ()) CopyAssignImpl [ InValue . GetIndex ()]( & Value , & InValue . Value );
2022-03-15 19:26:31 +08:00
else
{
Reset ();
2022-05-12 23:36:32 +08:00
CopyConstructImpl [ InValue . GetIndex ()]( & Value , & InValue . Value );
2022-04-22 22:28:44 +08:00
TypeIndex = static_cast < uint8 > ( InValue . GetIndex ());
2022-03-15 19:26:31 +08:00
}
return * this ;
}
2022-12-29 21:55:02 +08:00
/** Assigns by moving the state of 'InValue'. */
2022-12-13 22:02:39 +08:00
FORCEINLINE constexpr TVariant & operator = ( TVariant && InValue ) requires ( true && ... && ( CTriviallyMoveConstructible < Ts > && CTriviallyMoveAssignable < Ts > )) = default ;
2022-11-17 23:17:50 +08:00
2022-12-29 21:55:02 +08:00
/** Assigns by moving the state of 'InValue'. */
2022-12-16 23:23:05 +08:00
constexpr TVariant & operator = ( TVariant && InValue ) requires (( true && ... && ( CMoveConstructible < Ts > && CMoveAssignable < Ts > ))
2022-11-17 23:17:50 +08:00
&& ! ( true && ... && ( CTriviallyMoveConstructible < Ts > && CTriviallyMoveAssignable < Ts > )))
2022-03-15 19:26:31 +08:00
{
if ( & InValue == this ) return * this ;
if ( ! InValue . IsValid ())
{
Reset ();
return * this ;
}
2022-05-12 23:36:32 +08:00
if ( GetIndex () == InValue . GetIndex ()) MoveAssignImpl [ InValue . GetIndex ()]( & Value , & InValue . Value );
2022-03-15 19:26:31 +08:00
else
{
Reset ();
2022-05-12 23:36:32 +08:00
MoveConstructImpl [ InValue . GetIndex ()]( & Value , & InValue . Value );
2022-04-22 22:28:44 +08:00
TypeIndex = static_cast < uint8 > ( InValue . GetIndex ());
2022-03-15 19:26:31 +08:00
}
return * this ;
}
2022-12-29 21:55:02 +08:00
/** Converting assignment. Constructs a variant holding the alternative type that would be selected by overload resolution. */
2022-12-03 23:12:29 +08:00
template < typename T > requires ( requires { typename NAMESPACE_PRIVATE :: TVariantSelectedType < T , Ts ... > ; })
2022-12-13 22:02:39 +08:00
FORCEINLINE constexpr TVariant & operator = ( T && InValue )
2022-03-15 19:26:31 +08:00
{
2022-12-03 23:12:29 +08:00
using SelectedType = NAMESPACE_PRIVATE :: TVariantSelectedType < T , Ts ... > ;
2022-03-15 19:26:31 +08:00
2022-11-16 19:13:37 +08:00
if ( GetIndex () == TVariantIndex < SelectedType , TVariant < Ts ... >> ) GetValue < SelectedType > () = Forward < T > ( InValue );
2022-03-15 19:26:31 +08:00
else
{
Reset ();
2022-12-12 22:07:12 +08:00
new ( & Value ) SelectedType ( Forward < T > ( InValue ));
2022-11-16 19:13:37 +08:00
TypeIndex = TVariantIndex < SelectedType , TVariant < Ts ... >> ;
2022-03-15 19:26:31 +08:00
}
return * this ;
}
2022-12-29 21:55:02 +08:00
/** Check if the two variants are equivalent. */
NODISCARD friend constexpr bool operator == ( const TVariant & LHS , const TVariant & RHS ) requires ( true && ... && CEqualityComparable < Ts > )
2022-12-18 19:11:53 +08:00
{
if ( LHS . GetIndex () != RHS . GetIndex ()) return false ;
if ( LHS . IsValid () == false ) return true ;
using FCompareImpl = bool ( * )( const void * , const void * );
constexpr FCompareImpl CompareImpl [] = { []( const void * LHS , const void * RHS ) -> bool { return * reinterpret_cast < const Ts *> ( LHS ) == * reinterpret_cast < const Ts *> ( RHS ); }... };
return CompareImpl [ LHS . GetIndex ()]( & LHS . Value , & RHS . Value );
}
2022-12-29 21:55:02 +08:00
/** Check the order relationship between two variants. */
NODISCARD friend constexpr partial_ordering operator <=> ( const TVariant & LHS , const TVariant & RHS ) requires ( true && ... && CSynthThreeWayComparable < Ts > )
2022-12-18 19:11:53 +08:00
{
if ( LHS . GetIndex () != RHS . GetIndex ()) return partial_ordering :: unordered ;
if ( LHS . IsValid () == false ) return partial_ordering :: equivalent ;
using FCompareImpl = partial_ordering ( * )( const void * , const void * );
constexpr FCompareImpl CompareImpl [] = { []( const void * LHS , const void * RHS ) -> partial_ordering { return SynthThreeWayCompare ( * reinterpret_cast < const Ts *> ( LHS ), * reinterpret_cast < const Ts *> ( RHS )); }...};
return CompareImpl [ LHS . GetIndex ()]( & LHS . Value , & RHS . Value );
}
2022-12-29 21:55:02 +08:00
/** Check if the variant value is equivalent to 'InValue'. */
2022-12-19 18:00:52 +08:00
template < typename T > requires ( ! CSameAs < TVariant , T > && CEqualityComparable < T > )
2022-12-29 21:55:02 +08:00
NODISCARD FORCEINLINE constexpr bool operator == ( const T & InValue ) const &
2022-12-18 19:11:53 +08:00
{
return HoldsAlternative < T > () ? GetValue < T > () == InValue : false ;
}
2022-12-29 21:55:02 +08:00
/** Check that the variant value is in ordered relationship with 'InValue'. */
2022-12-19 18:00:52 +08:00
template < typename T > requires ( ! CSameAs < TVariant , T > && CEqualityComparable < T > )
2022-12-29 21:55:02 +08:00
NODISCARD FORCEINLINE constexpr partial_ordering operator <=> ( const T & InValue ) const &
2022-12-18 19:11:53 +08:00
{
return HoldsAlternative < T > () ? SynthThreeWayCompare ( GetValue < T > (), InValue ) : partial_ordering :: unordered ;
}
2022-03-15 19:26:31 +08:00
2022-12-29 21:55:02 +08:00
/** @return true if instance does not contain a value, otherwise false. */
NODISCARD FORCEINLINE constexpr bool operator == ( FInvalid ) const & { return ! IsValid (); }
/** Equivalent to Emplace<I>(Forward<Us>(Args)...), where I is the zero-based index of T in Types.... */
template < typename T , typename ... Us > requires ( CConstructibleFrom < T , Us ... > )
FORCEINLINE constexpr T & Emplace ( Us && ... Args )
{
return Emplace < TVariantIndex < T , TVariant < Ts ... >>> ( Forward < Us > ( Args )...);
}
/**
* First, destroys the currently contained value if any.
* Then direct-initializes the contained value as if constructing a value of type T with the arguments Forward<Us>(Args)....
*
* @param Args - The arguments to be passed to the constructor of the contained object.
*
* @return A reference to the new contained object.
*/
template < size_t I , typename ... Us > requires ( I < sizeof ...( Ts )
&& CConstructibleFrom < TVariantAlternative < I , TVariant < Ts ... >> , Us ... > )
FORCEINLINE constexpr TVariantAlternative < I , TVariant < Ts ... >>& Emplace ( Us && ... Args )
2022-03-15 19:26:31 +08:00
{
Reset ();
2022-11-16 19:13:37 +08:00
using SelectedType = TVariantAlternative < I , TVariant < Ts ... >> ;
2022-12-29 21:55:02 +08:00
SelectedType * Result = new ( & Value ) SelectedType ( Forward < Us > ( Args )...);
2022-03-15 19:26:31 +08:00
TypeIndex = I ;
return * Result ;
}
2022-12-29 21:55:02 +08:00
/** @return The typeid of the contained value if instance is non-empty, otherwise typeid(void). */
NODISCARD FORCEINLINE constexpr const type_info & GetTypeInfo () const { return IsValid () ? * TypeInfos [ GetIndex ()] : typeid ( void ); }
2022-03-15 19:26:31 +08:00
2022-12-29 21:55:02 +08:00
/** @return The zero-based index of the alternative held by the variant. */
NODISCARD FORCEINLINE constexpr size_t GetIndex () const { return IsValid () ? TypeIndex : INDEX_NONE ; }
2022-05-03 18:22:41 +08:00
2022-12-29 21:55:02 +08:00
/** @return true if instance contains a value, otherwise false. */
NODISCARD FORCEINLINE constexpr bool IsValid () const { return TypeIndex != 0xFF ; }
NODISCARD FORCEINLINE constexpr explicit operator bool () const { return TypeIndex != 0xFF ; }
2022-03-15 19:26:31 +08:00
2022-12-29 21:55:02 +08:00
/** @return true if the variant currently holds the alternative, false otherwise. */
template < size_t I > NODISCARD FORCEINLINE constexpr bool HoldsAlternative () const { return IsValid () ? GetIndex () == I : false ; }
template < typename T > NODISCARD FORCEINLINE constexpr bool HoldsAlternative () const { return IsValid () ? GetIndex () == TVariantIndex < T , TVariant < Ts ... >> : false ; }
2022-03-15 19:26:31 +08:00
2022-12-29 21:55:02 +08:00
/** @return The contained object. */
template < size_t I > requires ( I < sizeof ...( Ts )) NODISCARD FORCEINLINE constexpr decltype ( auto ) GetValue () & { checkf ( HoldsAlternative < I > (), TEXT ( "It is an error to call GetValue() on an wrong TVariant. Please either check HoldsAlternative() or use Get(DefaultValue) instead." )); return * reinterpret_cast < TVariantAlternative < I , TVariant < Ts ... >>*> ( & Value ); }
template < size_t I > requires ( I < sizeof ...( Ts )) NODISCARD FORCEINLINE constexpr decltype ( auto ) GetValue () && { checkf ( HoldsAlternative < I > (), TEXT ( "It is an error to call GetValue() on an wrong TVariant. Please either check HoldsAlternative() or use Get(DefaultValue) instead." )); return MoveTemp ( * reinterpret_cast < TVariantAlternative < I , TVariant < Ts ... >>*> ( & Value )); }
template < size_t I > requires ( I < sizeof ...( Ts )) NODISCARD FORCEINLINE constexpr decltype ( auto ) GetValue () const & { checkf ( HoldsAlternative < I > (), TEXT ( "It is an error to call GetValue() on an wrong TVariant. Please either check HoldsAlternative() or use Get(DefaultValue) instead." )); return * reinterpret_cast < const TVariantAlternative < I , TVariant < Ts ... >>*> ( & Value ); }
template < size_t I > requires ( I < sizeof ...( Ts )) NODISCARD FORCEINLINE constexpr decltype ( auto ) GetValue () const && { checkf ( HoldsAlternative < I > (), TEXT ( "It is an error to call GetValue() on an wrong TVariant. Please either check HoldsAlternative() or use Get(DefaultValue) instead." )); return MoveTemp ( * reinterpret_cast < const TVariantAlternative < I , TVariant < Ts ... >>*> ( & Value )); }
2022-03-15 19:26:31 +08:00
2022-12-29 21:55:02 +08:00
/** @return The contained object. */
template < typename T > NODISCARD FORCEINLINE constexpr decltype ( auto ) GetValue () & { checkf ( HoldsAlternative < T > (), TEXT ( "It is an error to call GetValue() on an wrong TVariant. Please either check HoldsAlternative() or use Get(DefaultValue) instead." )); return * reinterpret_cast < T *> ( & Value ); }
template < typename T > NODISCARD FORCEINLINE constexpr decltype ( auto ) GetValue () && { checkf ( HoldsAlternative < T > (), TEXT ( "It is an error to call GetValue() on an wrong TVariant. Please either check HoldsAlternative() or use Get(DefaultValue) instead." )); return MoveTemp ( * reinterpret_cast < T *> ( & Value )); }
template < typename T > NODISCARD FORCEINLINE constexpr decltype ( auto ) GetValue () const & { checkf ( HoldsAlternative < T > (), TEXT ( "It is an error to call GetValue() on an wrong TVariant. Please either check HoldsAlternative() or use Get(DefaultValue) instead." )); return * reinterpret_cast < const T *> ( & Value ); }
template < typename T > NODISCARD FORCEINLINE constexpr decltype ( auto ) GetValue () const && { checkf ( HoldsAlternative < T > (), TEXT ( "It is an error to call GetValue() on an wrong TVariant. Please either check HoldsAlternative() or use Get(DefaultValue) instead." )); return MoveTemp ( * reinterpret_cast < const T *> ( & Value )); }
2022-03-15 19:26:31 +08:00
2022-12-29 21:55:02 +08:00
/** @return The contained object when HoldsAlternative<I>() returns true, 'DefaultValue' otherwise. */
template < size_t I > requires ( I < sizeof ...( Ts )) NODISCARD FORCEINLINE constexpr decltype ( auto ) Get ( TVariantAlternative < I , TVariant < Ts ... >>& DefaultValue ) & { return HoldsAlternative < I > () ? GetValue < I > () : DefaultValue ; }
template < size_t I > requires ( I < sizeof ...( Ts )) NODISCARD FORCEINLINE constexpr decltype ( auto ) Get ( const TVariantAlternative < I , TVariant < Ts ... >>& DefaultValue ) const & { return HoldsAlternative < I > () ? GetValue < I > () : DefaultValue ; }
2022-03-15 19:26:31 +08:00
2022-12-29 21:55:02 +08:00
/** @return The contained object when HoldsAlternative<T>() returns true, 'DefaultValue' otherwise. */
template < typename T > NODISCARD FORCEINLINE constexpr decltype ( auto ) Get ( T & DefaultValue ) & { return HoldsAlternative < T > () ? GetValue < T > () : DefaultValue ; }
template < typename T > NODISCARD FORCEINLINE constexpr decltype ( auto ) Get ( const T & DefaultValue ) const & { return HoldsAlternative < T > () ? GetValue < T > () : DefaultValue ; }
2022-03-15 19:26:31 +08:00
2022-12-29 21:55:02 +08:00
/** If not empty, destroys the contained object. */
2022-12-13 22:02:39 +08:00
FORCEINLINE constexpr void Reset ()
2022-03-15 19:26:31 +08:00
{
2022-03-17 09:22:48 +08:00
if ( GetIndex () == INDEX_NONE ) return ;
2022-03-15 19:26:31 +08:00
2022-11-16 19:13:37 +08:00
if constexpr ( ! ( true && ... && CTriviallyDestructible < Ts > ))
2022-03-23 17:49:30 +08:00
{
2022-05-12 23:36:32 +08:00
DestroyImpl [ GetIndex ()]( & Value );
2022-03-23 17:49:30 +08:00
}
2022-03-15 19:26:31 +08:00
2022-04-22 22:28:44 +08:00
TypeIndex = static_cast < uint8 > ( INDEX_NONE );
2022-03-15 19:26:31 +08:00
}
2022-04-22 22:28:44 +08:00
2022-12-29 21:55:02 +08:00
/** Overloads the GetTypeHash algorithm for TVariant. */
NODISCARD friend FORCEINLINE constexpr size_t GetTypeHash ( const TVariant & A ) requires ( true && ... && CHashable < Ts > )
2022-04-22 22:28:44 +08:00
{
2022-12-19 18:00:52 +08:00
if ( ! A . IsValid ()) return 114514 ;
2022-05-12 23:36:32 +08:00
using FHashImpl = size_t ( * )( const void * );
2022-11-16 19:13:37 +08:00
constexpr FHashImpl HashImpl [] = { []( const void * This ) -> size_t { return GetTypeHash ( * reinterpret_cast < const Ts *> ( This )); }... };
2022-05-12 23:36:32 +08:00
2022-12-19 18:00:52 +08:00
return HashCombine ( GetTypeHash ( A . GetIndex ()), HashImpl [ A . GetIndex ()]( & A . Value ));
2022-04-22 22:28:44 +08:00
}
2022-12-29 21:55:02 +08:00
/** Overloads the Swap algorithm for TVariant. */
2022-12-19 18:00:52 +08:00
friend constexpr void Swap ( TVariant & A , TVariant & B ) requires ( true && ... && ( CMoveConstructible < Ts > && CSwappable < Ts > ))
2022-04-14 22:41:22 +08:00
{
2022-12-19 18:00:52 +08:00
if ( ! A . IsValid () && ! B . IsValid ()) return ;
2022-04-14 22:41:22 +08:00
2022-12-19 18:00:52 +08:00
if ( A . IsValid () && ! B . IsValid ())
2022-04-14 22:41:22 +08:00
{
2022-12-19 18:00:52 +08:00
B = MoveTemp ( A );
A . Reset ();
2022-04-14 22:41:22 +08:00
}
2022-12-19 18:00:52 +08:00
else if ( ! A . IsValid () && B . IsValid ())
2022-04-14 22:41:22 +08:00
{
2022-12-19 18:00:52 +08:00
A = MoveTemp ( B );
B . Reset ();
2022-04-14 22:41:22 +08:00
}
2022-12-19 18:00:52 +08:00
else if ( A . GetIndex () == B . GetIndex ())
2022-04-14 22:41:22 +08:00
{
2022-05-12 23:36:32 +08:00
using FSwapImpl = void ( * )( void * , void * );
2022-11-16 19:13:37 +08:00
constexpr FSwapImpl SwapImpl [] = { []( void * A , void * B ) { Swap ( * reinterpret_cast < Ts *> ( A ), * reinterpret_cast < Ts *> ( B )); }... };
2022-05-12 23:36:32 +08:00
2022-12-19 18:00:52 +08:00
SwapImpl [ A . GetIndex ()]( & A . Value , & B . Value );
}
else
{
TVariant Temp = MoveTemp ( A );
A = MoveTemp ( B );
B = MoveTemp ( Temp );
2022-04-14 22:41:22 +08:00
}
}
2022-03-15 19:26:31 +08:00
private :
2022-05-03 18:22:41 +08:00
2022-11-16 19:13:37 +08:00
static constexpr const type_info * TypeInfos [] = { & typeid ( Ts )... };
2022-05-12 23:36:32 +08:00
using FCopyConstructImpl = void ( * )( void * , const void * );
using FMoveConstructImpl = void ( * )( void * , void * );
using FCopyAssignImpl = void ( * )( void * , const void * );
using FMoveAssignImpl = void ( * )( void * , void * );
using FDestroyImpl = void ( * )( void * );
2022-11-16 19:13:37 +08:00
static constexpr FCopyConstructImpl CopyConstructImpl [] = { []( void * A , const void * B ) { if constexpr ( requires ( Ts * A , const Ts * B ) { Memory :: CopyConstruct ( A , B ); }) Memory :: CopyConstruct ( reinterpret_cast < Ts *> ( A ), reinterpret_cast < const Ts *> ( B )); else checkf ( false , TEXT ( "The type '%s' is not copy constructible." ), typeid ( Ts ). name ()); }... };
static constexpr FMoveConstructImpl MoveConstructImpl [] = { []( void * A , void * B ) { if constexpr ( requires ( Ts * A , Ts * B ) { Memory :: MoveConstruct ( A , B ); }) Memory :: MoveConstruct ( reinterpret_cast < Ts *> ( A ), reinterpret_cast < Ts *> ( B )); else checkf ( false , TEXT ( "The type '%s' is not move constructible." ), typeid ( Ts ). name ()); }... };
static constexpr FCopyAssignImpl CopyAssignImpl [] = { []( void * A , const void * B ) { if constexpr ( requires ( Ts * A , const Ts * B ) { Memory :: CopyAssign ( A , B ); }) Memory :: CopyAssign ( reinterpret_cast < Ts *> ( A ), reinterpret_cast < const Ts *> ( B )); else checkf ( false , TEXT ( "The type '%s' is not copy assignable." ), typeid ( Ts ). name ()); }... };
static constexpr FMoveAssignImpl MoveAssignImpl [] = { []( void * A , void * B ) { if constexpr ( requires ( Ts * A , Ts * B ) { Memory :: MoveAssign ( A , B ); }) Memory :: MoveAssign ( reinterpret_cast < Ts *> ( A ), reinterpret_cast < Ts *> ( B )); else checkf ( false , TEXT ( "The type '%s' is not move assignable." ), typeid ( Ts ). name ()); }... };
2022-11-16 22:03:54 +08:00
static constexpr FDestroyImpl DestroyImpl [] = { []( void * A ) { if constexpr ( requires ( Ts * A ) { Memory :: Destruct ( A ); }) Memory :: Destruct ( reinterpret_cast < Ts *> ( A ) ); else checkf ( false , TEXT ( "The type '%s' is not destructible." ), typeid ( Ts ). name ()); }... };
2022-03-15 19:26:31 +08:00
2022-11-16 19:13:37 +08:00
TAlignedUnion < 1 , Ts ... > Value ;
2022-04-22 22:28:44 +08:00
uint8 TypeIndex ;
2022-03-15 19:26:31 +08:00
};
2022-12-03 23:14:25 +08:00
NAMESPACE_PRIVATE_BEGIN
template < typename F , typename ... VariantTypes >
struct TVariantVisitImpl
{
struct GetTotalNum
{
2022-12-13 22:02:39 +08:00
FORCEINLINE static constexpr size_t Do ()
2022-12-03 23:14:25 +08:00
{
if ( sizeof ...( VariantTypes ) == 0 ) return 0 ;
constexpr size_t VariantNums [] = { TVariantNum < TRemoveReference < VariantTypes >> ... };
size_t Result = 1 ;
for ( size_t Index = 0 ; Index < sizeof ...( VariantTypes ); ++ Index )
{
Result *= VariantNums [ Index ];
}
return Result ;
};
};
struct EncodeIndices
{
2022-12-13 22:02:39 +08:00
FORCEINLINE static constexpr size_t Do ( initializer_list < size_t > Indices )
2022-12-03 23:14:25 +08:00
{
constexpr size_t VariantNums [] = { TVariantNum < TRemoveReference < VariantTypes >> ... };
size_t Result = 0 ;
for ( size_t Index = 0 ; Index < sizeof ...( VariantTypes ); ++ Index )
{
Result *= VariantNums [ Index ];
Result += GetData ( Indices )[ Index ];
}
return Result ;
};
};
struct DecodeExtent
{
2022-12-13 22:02:39 +08:00
FORCEINLINE static constexpr size_t Do ( size_t EncodedIndex , size_t Extent )
2022-12-03 23:14:25 +08:00
{
constexpr size_t VariantNums [] = { TVariantNum < TRemoveReference < VariantTypes >> ... };
for ( size_t Index = Extent + 1 ; Index < sizeof ...( VariantTypes ); ++ Index )
{
EncodedIndex /= VariantNums [ Index ];
}
return EncodedIndex % VariantNums [ Extent ];
};
};
template < size_t EncodedIndex , typename >
struct InvokeEncoded ;
template < size_t EncodedIndex , size_t ... ExtentIndices >
struct InvokeEncoded < EncodedIndex , TIndexSequence < ExtentIndices ... >>
{
2022-12-13 22:02:39 +08:00
FORCEINLINE static constexpr decltype ( auto ) Do ( F && Func , VariantTypes && ... Variants )
2022-12-03 23:14:25 +08:00
{
return Invoke ( Forward < F > ( Func ), Forward < VariantTypes > ( Variants ). template GetValue < DecodeExtent :: Do ( EncodedIndex , ExtentIndices ) > ()...);
}
template < typename Ret >
struct Result
{
2022-12-13 22:02:39 +08:00
FORCEINLINE static constexpr Ret Do ( F && Func , VariantTypes && ... Variants )
2022-12-03 23:14:25 +08:00
{
return InvokeResult < Ret > ( Forward < F > ( Func ), Forward < VariantTypes > ( Variants ). template GetValue < DecodeExtent :: Do ( EncodedIndex , ExtentIndices ) > ()...);
}
};
};
template < typename >
struct InvokeVariant ;
template < size_t ... EncodedIndices >
struct InvokeVariant < TIndexSequence < EncodedIndices ... >>
{
2022-12-13 22:02:39 +08:00
FORCEINLINE static constexpr decltype ( auto ) Do ( F && Func , VariantTypes && ... Variants )
2022-12-03 23:14:25 +08:00
{
using ExtentIndices = TIndexSequenceFor < VariantTypes ... > ;
using ResultType = TCommonType < decltype ( InvokeEncoded < EncodedIndices , ExtentIndices >:: Do ( Forward < F > ( Func ), Forward < VariantTypes > ( Variants )...))... > ;
using InvokeImplType = ResultType ( * )( F && , VariantTypes && ...);
constexpr InvokeImplType InvokeImpl [] = { InvokeEncoded < EncodedIndices , ExtentIndices >:: template Result < ResultType >:: Do ... };
return InvokeImpl [ EncodeIndices :: Do ({ Variants . GetIndex ()... })]( Forward < F > ( Func ), Forward < VariantTypes > ( Variants )...);
}
template < typename Ret >
struct Result
{
2022-12-13 22:02:39 +08:00
FORCEINLINE static constexpr Ret Do ( F && Func , VariantTypes && ... Variants )
2022-12-03 23:14:25 +08:00
{
using ExtentIndices = TIndexSequenceFor < VariantTypes ... > ;
using InvokeImplType = Ret ( * )( F && , VariantTypes && ...);
constexpr InvokeImplType InvokeImpl [] = { InvokeEncoded < EncodedIndices , ExtentIndices >:: template Result < Ret >:: Do ... };
return InvokeImpl [ EncodeIndices :: Do ({ Variants . GetIndex ()... })]( Forward < F > ( Func ), Forward < VariantTypes > ( Variants )...);
}
};
};
2022-12-13 22:02:39 +08:00
FORCEINLINE static constexpr decltype ( auto ) Do ( F && Func , VariantTypes && ... Variants )
2022-12-03 23:14:25 +08:00
{
return InvokeVariant < TMakeIndexSequence < GetTotalNum :: Do () >>:: Do ( Forward < F > ( Func ), Forward < VariantTypes > ( Variants )...);
}
template < typename Ret >
struct Result
{
2022-12-13 22:02:39 +08:00
FORCEINLINE static constexpr Ret Do ( F && Func , VariantTypes && ... Variants )
2022-12-03 23:14:25 +08:00
{
return InvokeVariant < TMakeIndexSequence < GetTotalNum :: Do () >>:: template Result < Ret >:: Do ( Forward < F > ( Func ), Forward < VariantTypes > ( Variants )...);
}
};
};
NAMESPACE_PRIVATE_END
2022-12-29 21:55:02 +08:00
/** Applies the visitor 'Func' (Callable that can be called with any combination of types from variants) to the variants 'Variants'. */
2022-12-03 23:14:25 +08:00
template < typename F , typename FirstVariantType , typename ... VariantTypes >
requires ( CTVariant < TRemoveReference < FirstVariantType >> && ( true && ... && CTVariant < TRemoveReference < VariantTypes >> ))
2022-12-16 23:23:05 +08:00
constexpr decltype ( auto ) Visit ( F && Func , FirstVariantType && FirstVariant , VariantTypes && ... Variants )
2022-12-03 23:14:25 +08:00
{
checkf (( true && ... && Variants . IsValid ()), TEXT ( "It is an error to call Visit() on an wrong TVariant. Please either check IsValid()." ));
return NAMESPACE_PRIVATE :: TVariantVisitImpl < F , FirstVariantType , VariantTypes ... >:: Do ( Forward < F > ( Func ), Forward < FirstVariantType > ( FirstVariant ), Forward < VariantTypes > ( Variants )...);
}
2022-12-29 21:55:02 +08:00
/** Applies the visitor 'Func' (Callable that can be called with any combination of types from variants) to the variants 'Variants'. */
2022-12-03 23:14:25 +08:00
template < typename Ret , typename F , typename FirstVariantType , typename ... VariantTypes >
requires ( CTVariant < TRemoveReference < FirstVariantType >> && ( true && ... && CTVariant < TRemoveReference < VariantTypes >> ))
2022-12-16 23:23:05 +08:00
constexpr Ret Visit ( F && Func , FirstVariantType && FirstVariant , VariantTypes && ... Variants )
2022-12-03 23:14:25 +08:00
{
checkf (( true && ... && Variants . IsValid ()), TEXT ( "It is an error to call Visit() on an wrong TVariant. Please either check IsValid()." ));
return NAMESPACE_PRIVATE :: TVariantVisitImpl < F , FirstVariantType , VariantTypes ... >:: template Result < Ret >:: Do ( Forward < F > ( Func ), Forward < FirstVariantType > ( FirstVariant ), Forward < VariantTypes > ( Variants )...);
}
2022-03-15 19:26:31 +08:00
NAMESPACE_MODULE_END ( Utility )
NAMESPACE_MODULE_END ( Redcraft )
NAMESPACE_REDCRAFT_END