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-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-03-15 19:26:31 +08:00
{
2022-11-15 19:28:43 +08:00
public :
2022-04-22 22:28:44 +08:00
constexpr TVariant () : TypeIndex ( 0xFF ) { };
2022-03-15 19:26:31 +08:00
constexpr TVariant ( FInvalid ) : TVariant () { };
2022-11-17 23:17:50 +08:00
constexpr TVariant ( const TVariant & InValue ) requires ( true && ... && CTriviallyCopyConstructible < Ts > ) = default ;
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-11-17 23:17:50 +08:00
constexpr TVariant ( TVariant && InValue ) requires ( true && ... && CTriviallyMoveConstructible < Ts > ) = default ;
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-11-16 22:03:54 +08:00
template < size_t I , typename ... ArgTypes > requires ( I < sizeof ...( Ts )
&& CConstructibleFrom < TVariantAlternative < I , TVariant < Ts ... >> , ArgTypes ... > )
2022-03-15 19:26:31 +08:00
constexpr explicit TVariant ( TInPlaceIndex < I > , ArgTypes && ... Args )
: TypeIndex ( I )
{
2022-11-16 19:13:37 +08:00
using SelectedType = TVariantAlternative < I , TVariant < Ts ... >> ;
2022-12-12 22:07:12 +08:00
new ( & Value ) SelectedType ( Forward < ArgTypes > ( Args )...);
2022-03-15 19:26:31 +08:00
}
2022-11-16 22:03:54 +08:00
template < typename T , typename ... ArgTypes > requires ( CConstructibleFrom < T , ArgTypes ... > )
2022-03-15 19:26:31 +08:00
constexpr explicit TVariant ( TInPlaceType < T > , ArgTypes && ... Args )
2022-11-16 19:13:37 +08:00
: TVariant ( InPlaceIndex < TVariantIndex < T , TVariant < Ts ... >>> , Forward < ArgTypes > ( Args )...)
2022-03-15 19:26:31 +08:00
{ }
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-11-21 23:28:19 +08:00
&& ! CBaseOf < TVariant , TRemoveCVRef < T >> )
2022-12-03 23:12:29 +08:00
constexpr TVariant ( T && InValue ) : TVariant ( InPlaceType < NAMESPACE_PRIVATE :: TVariantSelectedType < T , Ts ... >> , Forward < T > ( InValue ))
2022-03-15 19:26:31 +08:00
{ }
2022-11-17 23:17:50 +08:00
constexpr ~ TVariant () requires ( true && ... && CTriviallyDestructible < Ts > ) = default ;
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-11-17 23:17:50 +08:00
constexpr TVariant & operator = ( const TVariant & InValue ) requires ( true && ... && ( CTriviallyCopyConstructible < Ts > && CTriviallyCopyAssignable < Ts > )) = default ;
constexpr TVariant & operator = ( const TVariant & InValue ) requires (( true && ... && ( CCopyConstructible < Ts > && CCopyAssignable < Ts > ))
&& ! ( 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-11-17 23:17:50 +08:00
constexpr TVariant & operator = ( TVariant && InValue ) requires ( true && ... && ( CTriviallyMoveConstructible < Ts > && CTriviallyMoveAssignable < Ts > )) = default ;
constexpr TVariant & operator = ( TVariant && InValue ) requires (( true && ... && ( CMoveConstructible < Ts > && CMoveAssignable < Ts > ))
&& ! ( 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-03 23:12:29 +08:00
template < typename T > requires ( requires { typename NAMESPACE_PRIVATE :: TVariantSelectedType < T , Ts ... > ; })
2022-03-15 19:26:31 +08:00
constexpr TVariant & operator = ( T && InValue )
{
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-11-16 22:03:54 +08:00
template < size_t I , typename ... ArgTypes > requires ( I < sizeof ...( Ts )
&& CConstructibleFrom < TVariantAlternative < I , TVariant < Ts ... >> , ArgTypes ... > )
2022-11-16 19:13:37 +08:00
constexpr TVariantAlternative < I , TVariant < Ts ... >>& Emplace ( ArgTypes && ... 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-12 22:07:12 +08:00
SelectedType * Result = new ( & Value ) SelectedType ( Forward < ArgTypes > ( Args )...);
2022-03-15 19:26:31 +08:00
TypeIndex = I ;
return * Result ;
}
2022-11-16 22:03:54 +08:00
template < typename T , typename ... ArgTypes > requires ( CConstructibleFrom < T , ArgTypes ... > )
2022-03-15 19:26:31 +08:00
constexpr T & Emplace ( ArgTypes && ... Args )
{
2022-11-16 19:13:37 +08:00
return Emplace < TVariantIndex < T , TVariant < Ts ... >>> ( Forward < ArgTypes > ( Args )...);
2022-03-15 19:26:31 +08:00
}
2022-05-12 23:36:32 +08:00
constexpr const type_info & GetTypeInfo () const { return IsValid () ? * TypeInfos [ GetIndex ()] : typeid ( void ); }
2022-05-03 18:22:41 +08:00
2022-04-22 22:28:44 +08:00
constexpr size_t GetIndex () const { return TypeIndex != 0xFF ? TypeIndex : INDEX_NONE ; }
constexpr bool IsValid () const { return TypeIndex != 0xFF ; }
constexpr explicit operator bool () const { return TypeIndex != 0xFF ; }
2022-03-15 19:26:31 +08:00
2022-11-21 23:28:19 +08:00
template < size_t I > constexpr bool HoldsAlternative () const { return IsValid () ? GetIndex () == I : false ; }
2022-11-16 19:13:37 +08:00
template < typename T > constexpr bool HoldsAlternative () const { return IsValid () ? GetIndex () == TVariantIndex < T , TVariant < Ts ... >> : false ; }
2022-03-15 19:26:31 +08:00
2022-11-16 19:13:37 +08:00
template < size_t I > requires ( I < sizeof ...( Ts )) 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 )) 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 )) 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 )) 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-06-16 23:37:29 +08:00
template < typename T > 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 > 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 > 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 > 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-11-16 19:13:37 +08:00
template < size_t I > requires ( I < sizeof ...( Ts )) constexpr decltype ( auto ) Get ( TVariantAlternative < I , TVariant < Ts ... >>& DefaultValue ) & { return HoldsAlternative < I > () ? GetValue < I > () : DefaultValue ; }
template < size_t I > requires ( I < sizeof ...( Ts )) 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-06-16 23:37:29 +08:00
template < typename T > constexpr decltype ( auto ) Get ( T & DefaultValue ) & { return HoldsAlternative < T > () ? GetValue < T > () : DefaultValue ; }
template < typename T > constexpr decltype ( auto ) Get ( const T & DefaultValue ) const & { return HoldsAlternative < T > () ? GetValue < T > () : DefaultValue ; }
2022-03-15 19:26:31 +08:00
constexpr void Reset ()
{
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-11-16 19:13:37 +08:00
constexpr size_t GetTypeHash () const requires ( true && ... && CHashable < Ts > )
2022-04-22 22:28:44 +08:00
{
if ( ! IsValid ()) return 114514 ;
2022-05-12 23:36:32 +08:00
using NAMESPACE_REDCRAFT :: GetTypeHash ;
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
return HashCombine ( GetTypeHash ( GetIndex ()), HashImpl [ GetIndex ()]( & Value ));
2022-04-22 22:28:44 +08:00
}
2022-11-16 19:13:37 +08:00
constexpr void Swap ( TVariant & InValue ) requires ( true && ... && ( CMoveConstructible < Ts > && CSwappable < Ts > ))
2022-04-14 22:41:22 +08:00
{
if ( ! IsValid () && ! InValue . IsValid ()) return ;
if ( IsValid () && ! InValue . IsValid ())
{
InValue = MoveTemp ( * this );
Reset ();
return ;
}
if ( InValue . IsValid () && ! IsValid ())
{
* this = MoveTemp ( InValue );
InValue . Reset ();
return ;
}
if ( GetIndex () == InValue . GetIndex ())
{
2022-05-12 23:36:32 +08:00
using NAMESPACE_REDCRAFT :: Swap ;
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
SwapImpl [ GetIndex ()]( & Value , & InValue . Value );
2022-04-14 22:41:22 +08:00
return ;
}
TVariant Temp = MoveTemp ( * this );
* this = MoveTemp ( InValue );
InValue = MoveTemp ( Temp );
}
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-11-16 19:13:37 +08:00
friend constexpr bool operator == ( const TVariant & LHS , const TVariant & RHS ) requires ( true && ... && CEqualityComparable < Ts > )
2022-03-15 19:26:31 +08:00
{
if ( LHS . GetIndex () != RHS . GetIndex ()) return false ;
if ( LHS . IsValid () == false ) return true ;
2022-05-12 23:36:32 +08:00
using FCompareImpl = bool ( * )( const void * , const void * );
2022-11-16 19:13:37 +08:00
constexpr FCompareImpl CompareImpl [] = { []( const void * LHS , const void * RHS ) -> bool { return * reinterpret_cast < const Ts *> ( LHS ) == * reinterpret_cast < const Ts *> ( RHS ); }... };
2022-05-12 23:36:32 +08:00
return CompareImpl [ LHS . GetIndex ()]( & LHS . Value , & RHS . Value );
2022-05-03 18:22:41 +08:00
}
2022-11-16 19:13:37 +08:00
friend constexpr partial_ordering operator <=> ( const TVariant & LHS , const TVariant & RHS ) requires ( true && ... && CSynthThreeWayComparable < Ts > )
2022-05-03 18:22:41 +08:00
{
if ( LHS . GetIndex () != RHS . GetIndex ()) return partial_ordering :: unordered ;
if ( LHS . IsValid () == false ) return partial_ordering :: equivalent ;
2022-05-12 23:36:32 +08:00
using FCompareImpl = partial_ordering ( * )( const void * , const void * );
2022-11-16 19:13:37 +08:00
constexpr FCompareImpl CompareImpl [] = { []( const void * LHS , const void * RHS ) -> partial_ordering { return SynthThreeWayCompare ( * reinterpret_cast < const Ts *> ( LHS ), * reinterpret_cast < const Ts *> ( RHS )); }...};
2022-05-12 23:36:32 +08:00
return CompareImpl [ LHS . GetIndex ()]( & LHS . Value , & RHS . Value );
2022-03-15 19:26:31 +08:00
}
};
2022-11-21 23:28:19 +08:00
template < typename T , typename ... Ts > requires ( ! CBaseOf < TVariant < Ts ... > , T > && CEqualityComparable < T > )
2022-11-16 19:13:37 +08:00
constexpr bool operator == ( const TVariant < Ts ... >& LHS , const T & RHS )
2022-03-15 19:26:31 +08:00
{
return LHS . template HoldsAlternative < T > () ? LHS . template GetValue < T > () == RHS : false ;
}
2022-11-16 19:13:37 +08:00
template < typename ... Ts >
constexpr bool operator == ( const TVariant < Ts ... >& LHS , FInvalid )
2022-03-22 11:12:05 +08:00
{
return ! LHS . IsValid ();
}
2022-12-03 23:14:25 +08:00
NAMESPACE_PRIVATE_BEGIN
template < typename F , typename ... VariantTypes >
struct TVariantVisitImpl
{
struct GetTotalNum
{
static constexpr size_t Do ()
{
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
{
static constexpr size_t Do ( initializer_list < size_t > Indices )
{
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
{
static constexpr size_t Do ( size_t EncodedIndex , size_t Extent )
{
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 ... >>
{
static constexpr decltype ( auto ) Do ( F && Func , VariantTypes && ... Variants )
{
return Invoke ( Forward < F > ( Func ), Forward < VariantTypes > ( Variants ). template GetValue < DecodeExtent :: Do ( EncodedIndex , ExtentIndices ) > ()...);
}
template < typename Ret >
struct Result
{
static constexpr Ret Do ( F && Func , VariantTypes && ... Variants )
{
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 ... >>
{
static constexpr decltype ( auto ) Do ( F && Func , VariantTypes && ... Variants )
{
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
{
static constexpr Ret Do ( F && Func , VariantTypes && ... Variants )
{
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 )...);
}
};
};
static constexpr decltype ( auto ) Do ( F && Func , VariantTypes && ... Variants )
{
return InvokeVariant < TMakeIndexSequence < GetTotalNum :: Do () >>:: Do ( Forward < F > ( Func ), Forward < VariantTypes > ( Variants )...);
}
template < typename Ret >
struct Result
{
static constexpr Ret Do ( F && Func , VariantTypes && ... Variants )
{
return InvokeVariant < TMakeIndexSequence < GetTotalNum :: Do () >>:: template Result < Ret >:: Do ( Forward < F > ( Func ), Forward < VariantTypes > ( Variants )...);
}
};
};
NAMESPACE_PRIVATE_END
template < typename F , typename FirstVariantType , typename ... VariantTypes >
requires ( CTVariant < TRemoveReference < FirstVariantType >> && ( true && ... && CTVariant < TRemoveReference < VariantTypes >> ))
constexpr decltype ( auto ) Visit ( F && Func , FirstVariantType && FirstVariant , VariantTypes && ... Variants )
{
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 )...);
}
template < typename Ret , typename F , typename FirstVariantType , typename ... VariantTypes >
requires ( CTVariant < TRemoveReference < FirstVariantType >> && ( true && ... && CTVariant < TRemoveReference < VariantTypes >> ))
constexpr Ret Visit ( F && Func , FirstVariantType && FirstVariant , VariantTypes && ... Variants )
{
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