2022-03-22 03:10:12 +00:00
# pragma once
# include "CoreTypes.h"
# include "Memory/Memory.h"
# include "Templates/Utility.h"
# include "TypeTraits/TypeTraits.h"
# include "Miscellaneous/TypeInfo.h"
# include "Miscellaneous/AssertionMacros.h"
NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN ( Redcraft )
NAMESPACE_MODULE_BEGIN ( Utility )
NAMESPACE_PRIVATE_BEGIN
template < typename T >
void * AnyCopyNew ( const void * Source )
{
if constexpr ( ! TIsCopyConstructible < T > : : Value ) check_no_entry ( ) ;
else return new T ( * reinterpret_cast < const T * > ( Source ) ) ;
return nullptr ;
}
using FAnyCopyNewFunc = void * ( * ) ( const void * ) ;
template < typename T >
void * AnyMoveNew ( void * Source )
{
if constexpr ( ! TIsMoveConstructible < T > : : Value ) check_no_entry ( ) ;
else return new T ( MoveTemp ( * reinterpret_cast < T * > ( Source ) ) ) ;
return nullptr ;
}
using FAnyMoveNewFunc = void * ( * ) ( void * ) ;
template < typename T >
void AnyDelete ( void * InValue )
{
delete reinterpret_cast < T * > ( InValue ) ;
}
using FAnyDeleteFunc = void ( * ) ( void * ) ;
template < typename T >
void AnyDestroy ( void * InValue )
{
if constexpr ( ! TIsTriviallyDestructible < T > : : Value )
{
typedef T DestructOptionalType ;
reinterpret_cast < T * > ( InValue ) - > DestructOptionalType : : ~ DestructOptionalType ( ) ;
}
}
using FAnyDestroyFunc = void ( * ) ( void * ) ;
template < typename T >
void AnyCopyConstruct ( void * Target , const void * Source )
{
if constexpr ( ! TIsCopyConstructible < T > : : Value ) check_no_entry ( ) ;
else new ( reinterpret_cast < T * > ( Target ) ) T ( * reinterpret_cast < const T * > ( Source ) ) ;
}
using FAnyCopyConstructFunc = void ( * ) ( void * , const void * ) ;
template < typename T >
void AnyMoveConstruct ( void * Target , void * Source )
{
if constexpr ( ! TIsMoveConstructible < T > : : Value ) check_no_entry ( ) ;
else new ( reinterpret_cast < T * > ( Target ) ) T ( MoveTemp ( * reinterpret_cast < T * > ( Source ) ) ) ;
}
using FAnyMoveConstructFunc = void ( * ) ( void * , void * ) ;
template < typename T >
void AnyCopyAssign ( void * Target , const void * Source )
{
2022-04-05 05:20:00 +00:00
if constexpr ( TIsCopyAssignable < T > : : Value ) * reinterpret_cast < T * > ( Target ) = * reinterpret_cast < const T * > ( Source ) ;
else if constexpr ( TIsCopyConstructible < T > : : Value ) { AnyDestroy < T > ( Target ) ; AnyCopyConstruct < T > ( Target , Source ) ; }
else check_no_entry ( ) ;
2022-03-22 03:10:12 +00:00
}
using FAnyCopyAssignFunc = void ( * ) ( void * , const void * ) ;
template < typename T >
void AnyMoveAssign ( void * Target , void * Source )
{
2022-04-05 05:20:00 +00:00
if constexpr ( TIsMoveAssignable < T > : : Value ) * reinterpret_cast < T * > ( Target ) = MoveTemp ( * reinterpret_cast < T * > ( Source ) ) ;
else if constexpr ( TIsMoveConstructible < T > : : Value ) { AnyDestroy < T > ( Target ) ; AnyMoveConstruct < T > ( Target , Source ) ; }
else check_no_entry ( ) ;
2022-03-22 03:10:12 +00:00
}
using FAnyMoveAssignFunc = void ( * ) ( void * , void * ) ;
2022-04-14 14:41:22 +00:00
template < typename T >
void AnySwap ( void * A , void * B )
{
if constexpr ( TIsSwappable < T > : : Value ) Swap ( * reinterpret_cast < T * > ( A ) , * reinterpret_cast < T * > ( B ) ) ;
else check_no_entry ( ) ;
}
using FAnySwapFunc = void ( * ) ( void * , void * ) ;
2022-03-22 03:10:12 +00:00
struct FAnyRTTI
{
bool bIsInline ;
FAnyCopyNewFunc CopyNew ;
FAnyMoveNewFunc MoveNew ;
FAnyDeleteFunc Delete ;
FAnyDestroyFunc Destroy ;
FAnyCopyConstructFunc CopyConstruct ;
FAnyMoveConstructFunc MoveConstruct ;
FAnyCopyAssignFunc CopyAssign ;
FAnyMoveAssignFunc MoveAssign ;
2022-04-14 14:41:22 +00:00
FAnySwapFunc SwapObject ;
2022-03-22 03:10:12 +00:00
} ;
template < typename T , bool bInIsInline >
struct TAnyRTTIHelper
{
static constexpr FAnyRTTI RTTI =
{
bInIsInline ,
AnyCopyNew < T > ,
AnyMoveNew < T > ,
AnyDelete < T > ,
AnyDestroy < T > ,
AnyCopyConstruct < T > ,
AnyMoveConstruct < T > ,
AnyCopyAssign < T > ,
AnyMoveAssign < T > ,
2022-04-14 14:41:22 +00:00
AnySwap < T > ,
2022-03-22 03:10:12 +00:00
} ;
} ;
NAMESPACE_PRIVATE_END
2022-04-05 05:20:00 +00:00
inline constexpr size_t ANY_DEFAULT_INLINE_SIZE = 48 ;
inline constexpr size_t ANY_DEFAULT_INLINE_ALIGNMENT = 16 ;
2022-03-31 09:36:48 +00:00
template < size_t InlineSize , size_t InlineAlignment = ANY_DEFAULT_INLINE_ALIGNMENT >
2022-03-22 03:10:12 +00:00
struct TAny
{
template < typename T >
struct TIsInlineStorable : TBoolConstant < sizeof ( T ) < = InlineSize & & alignof ( T ) < = InlineAlignment > { } ;
template < typename T >
struct TIsTriviallyStorable : TBoolConstant < TIsInlineStorable < T > : : Value & & TIsTrivial < T > : : Value & & TIsTriviallyCopyable < T > : : Value > { } ;
2022-04-05 09:00:33 +00:00
constexpr TAny ( ) : TypeInfo ( nullptr ) , RTTI ( nullptr ) { }
2022-03-22 03:10:12 +00:00
2022-04-03 14:55:17 +00:00
constexpr TAny ( FInvalid ) : TAny ( ) { }
2022-03-22 03:10:12 +00:00
2022-04-05 09:00:33 +00:00
FORCEINLINE TAny ( const TAny & InValue )
2022-03-22 03:10:12 +00:00
: TypeInfo ( InValue . TypeInfo ) , RTTI ( InValue . RTTI )
{
if ( ! IsValid ( ) ) return ;
if ( IsTrivial ( ) ) Memory : : Memcpy ( InlineValue , InValue . InlineValue ) ;
else if ( IsInline ( ) ) RTTI - > CopyConstruct ( GetData ( ) , InValue . GetData ( ) ) ;
else DynamicValue = RTTI - > CopyNew ( InValue . GetData ( ) ) ;
}
2022-04-05 09:00:33 +00:00
FORCEINLINE TAny ( TAny & & InValue )
2022-03-22 03:10:12 +00:00
: TypeInfo ( InValue . TypeInfo ) , RTTI ( InValue . RTTI )
{
if ( ! IsValid ( ) ) return ;
if ( IsTrivial ( ) ) Memory : : Memcpy ( InlineValue , InValue . InlineValue ) ;
else if ( IsInline ( ) ) RTTI - > MoveConstruct ( GetData ( ) , InValue . GetData ( ) ) ;
else
{
DynamicValue = InValue . DynamicValue ;
2022-04-05 09:00:33 +00:00
InValue . TypeInfo = nullptr ;
2022-03-22 03:10:12 +00:00
}
}
template < typename T , typename . . . Types > requires TIsObject < typename TDecay < T > : : Type > : : Value
& & ( ! TIsArray < typename TDecay < T > : : Type > : : Value ) & & TIsDestructible < typename TDecay < T > : : Type > : : Value
& & TIsConstructible < typename TDecay < T > : : Type , Types . . . > : : Value
2022-04-05 09:00:33 +00:00
FORCEINLINE explicit TAny ( TInPlaceType < T > , Types & & . . . Args )
2022-03-22 03:10:12 +00:00
{
using SelectedType = typename TDecay < T > : : Type ;
2022-04-03 14:55:17 +00:00
EmplaceImpl < SelectedType > ( Forward < Types > ( Args ) . . . ) ;
2022-03-22 03:10:12 +00:00
}
2022-03-31 09:36:48 +00:00
template < typename T > requires ( ! TIsSame < typename TDecay < T > : : Type , TAny > : : Value ) & & ( ! TIsTInPlaceType < typename TDecay < T > : : Type > : : Value )
2022-03-22 03:10:12 +00:00
& & TIsObject < typename TDecay < T > : : Type > : : Value & & ( ! TIsArray < typename TDecay < T > : : Type > : : Value ) & & TIsDestructible < typename TDecay < T > : : Type > : : Value
& & TIsConstructible < typename TDecay < T > : : Type , T & & > : : Value
2022-04-05 09:00:33 +00:00
FORCEINLINE TAny ( T & & InValue ) : TAny ( InPlaceType < typename TDecay < T > : : Type > , Forward < T > ( InValue ) )
2022-03-22 03:10:12 +00:00
{ }
2022-04-05 09:00:33 +00:00
FORCEINLINE ~ TAny ( )
2022-03-22 03:10:12 +00:00
{
2022-04-05 09:00:33 +00:00
ResetImpl ( ) ;
2022-03-22 03:10:12 +00:00
}
2022-04-05 09:00:33 +00:00
FORCEINLINE TAny & operator = ( const TAny & InValue )
2022-03-22 03:10:12 +00:00
{
2022-04-03 14:55:17 +00:00
if ( & InValue = = this ) return * this ;
2022-03-22 03:10:12 +00:00
if ( ! InValue . IsValid ( ) )
{
Reset ( ) ;
}
2022-04-05 09:00:33 +00:00
else if ( GetTypeInfo ( ) = = InValue . GetTypeInfo ( ) )
2022-03-22 03:10:12 +00:00
{
if ( IsTrivial ( ) ) Memory : : Memcpy ( InlineValue , InValue . InlineValue ) ;
else RTTI - > CopyAssign ( GetData ( ) , InValue . GetData ( ) ) ;
}
else
{
2022-04-05 09:00:33 +00:00
ResetImpl ( ) ;
2022-03-22 03:10:12 +00:00
TypeInfo = InValue . TypeInfo ;
RTTI = InValue . RTTI ;
if ( IsTrivial ( ) ) Memory : : Memcpy ( InlineValue , InValue . InlineValue ) ;
else if ( IsInline ( ) ) RTTI - > CopyConstruct ( GetData ( ) , InValue . GetData ( ) ) ;
else DynamicValue = RTTI - > CopyNew ( InValue . GetData ( ) ) ;
}
return * this ;
}
2022-04-05 09:00:33 +00:00
FORCEINLINE TAny & operator = ( TAny & & InValue )
2022-03-22 03:10:12 +00:00
{
2022-04-03 14:55:17 +00:00
if ( & InValue = = this ) return * this ;
2022-03-22 03:10:12 +00:00
if ( ! InValue . IsValid ( ) )
{
Reset ( ) ;
}
2022-04-05 09:00:33 +00:00
else if ( GetTypeInfo ( ) = = InValue . GetTypeInfo ( ) )
2022-03-22 03:10:12 +00:00
{
if ( IsTrivial ( ) ) Memory : : Memcpy ( InlineValue , InValue . InlineValue ) ;
else if ( IsInline ( ) ) RTTI - > MoveAssign ( GetData ( ) , InValue . GetData ( ) ) ;
else
{
RTTI - > Delete ( DynamicValue ) ;
DynamicValue = InValue . DynamicValue ;
2022-04-05 09:00:33 +00:00
InValue . TypeInfo = nullptr ;
2022-03-22 03:10:12 +00:00
}
}
else
{
2022-04-05 09:00:33 +00:00
ResetImpl ( ) ;
2022-03-22 03:10:12 +00:00
TypeInfo = InValue . TypeInfo ;
RTTI = InValue . RTTI ;
if ( IsTrivial ( ) ) Memory : : Memcpy ( InlineValue , InValue . InlineValue ) ;
else if ( IsInline ( ) ) RTTI - > MoveConstruct ( GetData ( ) , InValue . GetData ( ) ) ;
else DynamicValue = RTTI - > MoveNew ( InValue . GetData ( ) ) ;
}
return * this ;
}
2022-03-31 09:36:48 +00:00
template < typename T > requires ( ! TIsSame < typename TDecay < T > : : Type , TAny > : : Value ) & & ( ! TIsTInPlaceType < typename TDecay < T > : : Type > : : Value )
2022-03-22 03:10:12 +00:00
& & TIsObject < typename TDecay < T > : : Type > : : Value & & ( ! TIsArray < typename TDecay < T > : : Type > : : Value ) & & TIsDestructible < typename TDecay < T > : : Type > : : Value
& & TIsConstructible < typename TDecay < T > : : Type , T & & > : : Value
2022-04-05 09:00:33 +00:00
FORCEINLINE TAny & operator = ( T & & InValue )
2022-03-22 03:10:12 +00:00
{
using SelectedType = typename TDecay < T > : : Type ;
2022-04-05 09:00:33 +00:00
if ( HoldsAlternative < SelectedType > ( ) )
2022-03-22 03:10:12 +00:00
{
if constexpr ( TIsTriviallyStorable < SelectedType > : : Value )
Memory : : Memcpy ( & InlineValue , & InValue , sizeof ( SelectedType ) ) ;
else GetValue < SelectedType > ( ) = Forward < T > ( InValue ) ;
}
else
{
Reset ( ) ;
2022-04-03 14:55:17 +00:00
EmplaceImpl < SelectedType > ( Forward < T > ( InValue ) ) ;
2022-03-22 03:10:12 +00:00
}
return * this ;
}
template < typename T , typename . . . Types > requires TIsObject < typename TDecay < T > : : Type > : : Value
& & ( ! TIsArray < typename TDecay < T > : : Type > : : Value ) & & TIsDestructible < typename TDecay < T > : : Type > : : Value
& & TIsConstructible < typename TDecay < T > : : Type , T & & > : : Value
2022-04-05 09:00:33 +00:00
FORCEINLINE typename TDecay < T > : : Type & Emplace ( Types & & . . . Args )
2022-03-22 03:10:12 +00:00
{
2022-04-05 09:00:33 +00:00
ResetImpl ( ) ;
2022-03-22 03:10:12 +00:00
using SelectedType = typename TDecay < T > : : Type ;
2022-04-03 14:55:17 +00:00
EmplaceImpl < SelectedType > ( Forward < Types > ( Args ) . . . ) ;
2022-03-22 03:10:12 +00:00
return GetValue < SelectedType > ( ) ;
}
2022-04-05 09:00:33 +00:00
constexpr const FTypeInfo & GetTypeInfo ( ) const { return TypeInfo ! = nullptr ? * TypeInfo : Typeid ( void ) ; }
constexpr bool IsValid ( ) const { return TypeInfo ! = nullptr ; }
constexpr explicit operator bool ( ) const { return TypeInfo ! = nullptr ; }
2022-04-03 14:55:17 +00:00
constexpr bool IsInline ( ) const { return RTTI ! = nullptr ? RTTI - > bIsInline : true ; }
constexpr bool IsTrivial ( ) const { return RTTI = = nullptr ; }
2022-03-22 03:10:12 +00:00
2022-04-05 09:00:33 +00:00
template < typename T > constexpr bool HoldsAlternative ( ) const { return IsValid ( ) ? GetTypeInfo ( ) = = Typeid ( T ) : false ; }
2022-03-22 03:10:12 +00:00
constexpr void * GetData ( ) { return IsInline ( ) ? & InlineValue : DynamicValue ; }
constexpr const void * GetData ( ) const { return IsInline ( ) ? & InlineValue : DynamicValue ; }
2022-03-23 09:49:30 +00:00
template < typename T > requires TIsSame < T , typename TDecay < T > : : Type > : : Value & & TIsObject < typename TDecay < T > : : Type > : : Value & & ( ! TIsArray < typename TDecay < T > : : Type > : : Value ) & & TIsDestructible < typename TDecay < T > : : Type > : : Value
constexpr T & GetValue ( ) & { checkf ( HoldsAlternative < T > ( ) , TEXT ( " It is an error to call GetValue() on an wrong TAny. Please either check HoldsAlternative() or use Get(DefaultValue) instead. " ) ) ; return * reinterpret_cast < T * > ( GetData ( ) ) ; }
2022-03-22 03:10:12 +00:00
2022-03-23 09:49:30 +00:00
template < typename T > requires TIsSame < T , typename TDecay < T > : : Type > : : Value & & TIsObject < typename TDecay < T > : : Type > : : Value & & ( ! TIsArray < typename TDecay < T > : : Type > : : Value ) & & TIsDestructible < typename TDecay < T > : : Type > : : Value
constexpr T & & GetValue ( ) & & { checkf ( HoldsAlternative < T > ( ) , TEXT ( " It is an error to call GetValue() on an wrong TAny. Please either check HoldsAlternative() or use Get(DefaultValue) instead. " ) ) ; return MoveTemp ( * reinterpret_cast < T * > ( GetData ( ) ) ) ; }
template < typename T > requires TIsSame < T , typename TDecay < T > : : Type > : : Value & & TIsObject < typename TDecay < T > : : Type > : : Value & & ( ! TIsArray < typename TDecay < T > : : Type > : : Value ) & & TIsDestructible < typename TDecay < T > : : Type > : : Value
constexpr const T & GetValue ( ) const & { checkf ( HoldsAlternative < T > ( ) , TEXT ( " It is an error to call GetValue() on an wrong TAny. Please either check HoldsAlternative() or use Get(DefaultValue) instead. " ) ) ; return * reinterpret_cast < const T * > ( GetData ( ) ) ; }
template < typename T > requires TIsSame < T , typename TDecay < T > : : Type > : : Value & & TIsObject < typename TDecay < T > : : Type > : : Value & & ( ! TIsArray < typename TDecay < T > : : Type > : : Value ) & & TIsDestructible < typename TDecay < T > : : Type > : : Value
constexpr const T & & GetValue ( ) const & & { checkf ( HoldsAlternative < T > ( ) , TEXT ( " It is an error to call GetValue() on an wrong TAny. Please either check HoldsAlternative() or use Get(DefaultValue) instead. " ) ) ; return MoveTemp ( * reinterpret_cast < const T * > ( GetData ( ) ) ) ; }
template < typename T > requires TIsSame < T , typename TDecay < T > : : Type > : : Value & & TIsObject < typename TDecay < T > : : Type > : : Value & & ( ! TIsArray < typename TDecay < T > : : Type > : : Value ) & & TIsDestructible < typename TDecay < T > : : Type > : : Value
constexpr T & Get ( T & DefaultValue ) & { return HoldsAlternative < T > ( ) ? GetValue < T > ( ) : DefaultValue ; }
template < typename T > requires TIsSame < T , typename TDecay < T > : : Type > : : Value & & TIsObject < typename TDecay < T > : : Type > : : Value & & ( ! TIsArray < typename TDecay < T > : : Type > : : Value ) & & TIsDestructible < typename TDecay < T > : : Type > : : Value
constexpr const T & Get ( const T & DefaultValue ) const & { return HoldsAlternative < T > ( ) ? GetValue < T > ( ) : DefaultValue ; }
2022-03-22 03:10:12 +00:00
2022-04-05 09:00:33 +00:00
FORCEINLINE void Reset ( )
2022-03-22 03:10:12 +00:00
{
2022-04-05 09:00:33 +00:00
TypeInfo = nullptr ;
ResetImpl ( ) ;
2022-03-22 03:10:12 +00:00
}
2022-04-14 14:41:22 +00:00
constexpr void Swap ( TAny & InValue )
{
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 ( GetTypeInfo ( ) = = InValue . GetTypeInfo ( ) )
{
RTTI - > SwapObject ( GetData ( ) , InValue . GetData ( ) ) ;
return ;
}
TAny Temp = MoveTemp ( * this ) ;
* this = MoveTemp ( InValue ) ;
InValue = MoveTemp ( Temp ) ;
}
2022-03-22 03:10:12 +00:00
private :
union
{
TAlignedStorage < InlineSize , InlineAlignment > : : Type InlineValue ;
void * DynamicValue ;
} ;
2022-04-05 09:00:33 +00:00
const FTypeInfo * TypeInfo ;
2022-03-22 03:10:12 +00:00
const NAMESPACE_PRIVATE : : FAnyRTTI * RTTI ;
2022-04-03 14:55:17 +00:00
template < typename SelectedType , typename . . . Types >
2022-04-05 05:20:00 +00:00
FORCEINLINE void EmplaceImpl ( Types & & . . . Args )
2022-04-03 14:55:17 +00:00
{
2022-04-05 09:00:33 +00:00
TypeInfo = & Typeid ( SelectedType ) ;
2022-04-03 14:55:17 +00:00
if constexpr ( TIsTriviallyStorable < SelectedType > : : Value )
{
new ( & InlineValue ) SelectedType ( Forward < Types > ( Args ) . . . ) ;
RTTI = nullptr ;
}
else if constexpr ( TIsInlineStorable < SelectedType > : : Value )
{
new ( & InlineValue ) SelectedType ( Forward < Types > ( Args ) . . . ) ;
RTTI = & NAMESPACE_PRIVATE : : TAnyRTTIHelper < SelectedType , true > : : RTTI ;
}
else
{
DynamicValue = new SelectedType ( Forward < Types > ( Args ) . . . ) ;
RTTI = & NAMESPACE_PRIVATE : : TAnyRTTIHelper < SelectedType , false > : : RTTI ;
}
}
2022-04-05 09:00:33 +00:00
FORCEINLINE void ResetImpl ( )
{
if ( ! IsValid ( ) | | IsTrivial ( ) ) return ;
else if ( IsInline ( ) ) RTTI - > Destroy ( & InlineValue ) ;
else RTTI - > Delete ( DynamicValue ) ;
}
2022-03-22 03:10:12 +00:00
} ;
template < typename T , size_t InlineSize , size_t InlineAlignment >
constexpr bool operator = = ( const TAny < InlineSize , InlineAlignment > & LHS , const T & RHS )
{
return LHS . template HoldsAlternative < T > ( ) ? LHS . template GetValue < T > ( ) = = RHS : false ;
}
template < size_t InlineSize , size_t InlineAlignment >
constexpr bool operator = = ( const TAny < InlineSize , InlineAlignment > & LHS , FInvalid )
{
return ! LHS . IsValid ( ) ;
}
2022-03-31 09:36:48 +00:00
template < typename T > struct TIsTAny : FFalse { } ;
template < size_t InlineSize , size_t InlineAlignment > struct TIsTAny < TAny < InlineSize , InlineAlignment > > : FTrue { } ;
using FAny = TAny < ANY_DEFAULT_INLINE_SIZE > ;
2022-03-22 03:10:12 +00:00
static_assert ( sizeof ( FAny ) = = 64 , " The byte size of FAny is unexpected " ) ;
NAMESPACE_MODULE_END ( Utility )
NAMESPACE_MODULE_END ( Redcraft )
NAMESPACE_REDCRAFT_END