2022-03-22 03:10:12 +00:00
# pragma once
# include "CoreTypes.h"
# include "Memory/Memory.h"
2022-04-27 14:50:56 +00:00
# include "Memory/Alignment.h"
2022-03-22 03:10:12 +00:00
# include "Templates/Utility.h"
2022-04-22 14:28:44 +00:00
# include "Templates/TypeHash.h"
2022-05-12 15:36:32 +00:00
# include "Memory/MemoryOperator.h"
2022-03-22 03:10:12 +00:00
# include "TypeTraits/TypeTraits.h"
# include "Miscellaneous/AssertionMacros.h"
NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN ( Redcraft )
NAMESPACE_MODULE_BEGIN ( Utility )
2022-12-15 15:38:51 +00:00
// NOTE: In the STL, the assignment operation of the std::any type uses the copy-and-swap idiom
// instead of directly calling the assignment operation of the contained value.
// The purpose of this is as follows:
// 1) the copy assignment might not exist.
// 2) the typical case is that the objects are different.
// 3) it is less exception-safe
// But we don't follow the the copy-and-swap idiom, because we assume that no function throws an exception.
class alignas ( 16 ) FAny
2022-11-13 14:21:00 +00:00
{
2022-11-15 11:28:43 +00:00
public :
2022-12-15 15:38:51 +00:00
FORCEINLINE constexpr FAny ( ) { Invalidate ( ) ; }
2022-11-13 14:21:00 +00:00
2022-12-15 15:38:51 +00:00
FORCEINLINE constexpr FAny ( FInvalid ) : FAny ( ) { }
2022-11-13 14:21:00 +00:00
2022-12-15 15:38:51 +00:00
FORCEINLINE FAny ( const FAny & InValue )
: TypeInfo ( InValue . TypeInfo )
2022-03-22 03:10:12 +00:00
{
if ( ! IsValid ( ) ) return ;
2022-04-30 15:38:09 +00:00
switch ( GetRepresentation ( ) )
{
2022-12-15 15:38:51 +00:00
case ERepresentation : : Empty :
break ;
2022-06-21 15:31:46 +00:00
case ERepresentation : : Trivial :
2022-12-15 15:38:51 +00:00
Memory : : Memcpy ( TrivialStorage . Internal , InValue . TrivialStorage . Internal ) ;
2022-04-30 15:38:09 +00:00
break ;
2022-06-21 15:31:46 +00:00
case ERepresentation : : Small :
2022-12-15 15:38:51 +00:00
SmallStorage . RTTI = InValue . SmallStorage . RTTI ;
SmallStorage . RTTI - > CopyConstruct ( & SmallStorage . Internal , & InValue . SmallStorage . Internal ) ;
2022-04-30 15:38:09 +00:00
break ;
2022-06-21 15:31:46 +00:00
case ERepresentation : : Big :
2022-12-15 15:38:51 +00:00
BigStorage . RTTI = InValue . BigStorage . RTTI ;
BigStorage . External = Memory : : Malloc ( BigStorage . RTTI - > TypeSize , BigStorage . RTTI - > TypeAlignment ) ;
BigStorage . RTTI - > CopyConstruct ( BigStorage . External , InValue . BigStorage . External ) ;
2022-04-30 15:38:09 +00:00
break ;
default : check_no_entry ( ) ;
}
2022-03-22 03:10:12 +00:00
}
2022-12-15 15:38:51 +00:00
FORCEINLINE FAny ( FAny & & InValue )
: TypeInfo ( InValue . TypeInfo )
2022-03-22 03:10:12 +00:00
{
if ( ! IsValid ( ) ) return ;
2022-04-30 15:38:09 +00:00
switch ( GetRepresentation ( ) )
2022-03-22 03:10:12 +00:00
{
2022-12-15 15:38:51 +00:00
case ERepresentation : : Empty :
break ;
2022-06-21 15:31:46 +00:00
case ERepresentation : : Trivial :
2022-12-15 15:38:51 +00:00
Memory : : Memmove ( TrivialStorage . Internal , InValue . TrivialStorage . Internal ) ;
2022-04-30 15:38:09 +00:00
break ;
2022-06-21 15:31:46 +00:00
case ERepresentation : : Small :
2022-12-15 15:38:51 +00:00
SmallStorage . RTTI = InValue . SmallStorage . RTTI ;
SmallStorage . RTTI - > MoveConstruct ( & SmallStorage . Internal , & InValue . SmallStorage . Internal ) ;
2022-04-30 15:38:09 +00:00
break ;
2022-06-21 15:31:46 +00:00
case ERepresentation : : Big :
2022-12-15 15:38:51 +00:00
BigStorage . RTTI = InValue . BigStorage . RTTI ;
BigStorage . External = InValue . BigStorage . External ;
InValue . Invalidate ( ) ;
2022-04-30 15:38:09 +00:00
break ;
default : check_no_entry ( ) ;
2022-03-22 03:10:12 +00:00
}
}
2022-11-16 14:03:54 +00:00
template < typename T , typename . . . Ts > requires ( CDestructible < TDecay < T > >
& & CConstructibleFrom < TDecay < T > , Ts & & . . . > )
2022-12-15 15:38:51 +00:00
FORCEINLINE explicit FAny ( TInPlaceType < T > , Ts & & . . . Args )
2022-03-22 03:10:12 +00:00
{
2022-12-15 15:38:51 +00:00
EmplaceImpl < T > ( Forward < Ts > ( Args ) . . . ) ;
2022-03-22 03:10:12 +00:00
}
2022-12-15 15:38:51 +00:00
template < typename T > requires ( ! CBaseOf < FAny , TDecay < T > > & & ! CTInPlaceType < TDecay < T > >
2022-11-21 15:28:19 +00:00
& & CDestructible < TDecay < T > > & & CConstructibleFrom < TDecay < T > , T & & > )
2022-12-15 15:38:51 +00:00
FORCEINLINE FAny ( T & & InValue ) : FAny ( InPlaceType < TDecay < T > > , Forward < T > ( InValue ) )
2022-03-22 03:10:12 +00:00
{ }
2022-12-15 15:38:51 +00:00
FORCEINLINE ~ FAny ( )
2022-03-22 03:10:12 +00:00
{
2022-12-15 15:38:51 +00:00
Destroy ( ) ;
2022-03-22 03:10:12 +00:00
}
2022-12-15 15:38:51 +00:00
FORCEINLINE FAny & operator = ( const FAny & 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
{
2022-04-30 15:38:09 +00:00
switch ( GetRepresentation ( ) )
{
2022-12-15 15:38:51 +00:00
case ERepresentation : : Empty :
break ;
2022-06-21 15:31:46 +00:00
case ERepresentation : : Trivial :
2022-12-15 15:38:51 +00:00
Memory : : Memcpy ( TrivialStorage . Internal , InValue . TrivialStorage . Internal ) ;
2022-04-30 15:38:09 +00:00
break ;
2022-06-21 15:31:46 +00:00
case ERepresentation : : Small :
2022-12-15 15:38:51 +00:00
SmallStorage . RTTI = InValue . SmallStorage . RTTI ;
SmallStorage . RTTI - > CopyAssign ( & SmallStorage . Internal , & InValue . SmallStorage . Internal ) ;
break ;
2022-06-21 15:31:46 +00:00
case ERepresentation : : Big :
2022-12-15 15:38:51 +00:00
BigStorage . RTTI = InValue . BigStorage . RTTI ;
BigStorage . RTTI - > CopyAssign ( BigStorage . External , InValue . BigStorage . External ) ;
2022-04-30 15:38:09 +00:00
break ;
default : check_no_entry ( ) ;
}
2022-03-22 03:10:12 +00:00
}
else
{
2022-12-15 15:38:51 +00:00
Destroy ( ) ;
2022-03-22 03:10:12 +00:00
2022-12-15 15:38:51 +00:00
TypeInfo = InValue . TypeInfo ;
2022-03-22 03:10:12 +00:00
2022-04-30 15:38:09 +00:00
switch ( GetRepresentation ( ) )
{
2022-12-15 15:38:51 +00:00
case ERepresentation : : Empty :
break ;
2022-06-21 15:31:46 +00:00
case ERepresentation : : Trivial :
2022-12-15 15:38:51 +00:00
Memory : : Memcpy ( TrivialStorage . Internal , InValue . TrivialStorage . Internal ) ;
2022-04-30 15:38:09 +00:00
break ;
2022-06-21 15:31:46 +00:00
case ERepresentation : : Small :
2022-12-15 15:38:51 +00:00
SmallStorage . RTTI = InValue . SmallStorage . RTTI ;
SmallStorage . RTTI - > CopyConstruct ( & SmallStorage . Internal , & InValue . SmallStorage . Internal ) ;
2022-04-30 15:38:09 +00:00
break ;
2022-06-21 15:31:46 +00:00
case ERepresentation : : Big :
2022-12-15 15:38:51 +00:00
BigStorage . RTTI = InValue . BigStorage . RTTI ;
BigStorage . External = Memory : : Malloc ( BigStorage . RTTI - > TypeSize , BigStorage . RTTI - > TypeAlignment ) ;
BigStorage . RTTI - > CopyConstruct ( BigStorage . External , InValue . BigStorage . External ) ;
2022-04-30 15:38:09 +00:00
break ;
default : check_no_entry ( ) ;
}
2022-03-22 03:10:12 +00:00
}
return * this ;
}
2022-12-15 15:38:51 +00:00
FORCEINLINE FAny & operator = ( FAny & & 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
{
2022-04-30 15:38:09 +00:00
switch ( GetRepresentation ( ) )
2022-03-22 03:10:12 +00:00
{
2022-12-15 15:38:51 +00:00
case ERepresentation : : Empty :
break ;
2022-06-21 15:31:46 +00:00
case ERepresentation : : Trivial :
2022-12-15 15:38:51 +00:00
Memory : : Memmove ( TrivialStorage . Internal , InValue . TrivialStorage . Internal ) ;
2022-04-30 15:38:09 +00:00
break ;
2022-06-21 15:31:46 +00:00
case ERepresentation : : Small :
2022-12-15 15:38:51 +00:00
SmallStorage . RTTI = InValue . SmallStorage . RTTI ;
SmallStorage . RTTI - > MoveAssign ( & SmallStorage . Internal , & InValue . SmallStorage . Internal ) ;
2022-04-30 15:38:09 +00:00
break ;
2022-06-21 15:31:46 +00:00
case ERepresentation : : Big :
2022-12-15 15:38:51 +00:00
Destroy ( ) ;
BigStorage . RTTI = InValue . BigStorage . RTTI ;
BigStorage . External = InValue . BigStorage . External ;
InValue . Invalidate ( ) ;
2022-04-30 15:38:09 +00:00
break ;
default : check_no_entry ( ) ;
2022-03-22 03:10:12 +00:00
}
}
else
{
2022-12-15 15:38:51 +00:00
Destroy ( ) ;
2022-03-22 03:10:12 +00:00
2022-12-15 15:38:51 +00:00
TypeInfo = InValue . TypeInfo ;
2022-03-22 03:10:12 +00:00
2022-04-30 15:38:09 +00:00
switch ( GetRepresentation ( ) )
{
2022-12-15 15:38:51 +00:00
case ERepresentation : : Empty :
break ;
2022-06-21 15:31:46 +00:00
case ERepresentation : : Trivial :
2022-12-15 15:38:51 +00:00
Memory : : Memmove ( TrivialStorage . Internal , InValue . TrivialStorage . Internal ) ;
2022-04-30 15:38:09 +00:00
break ;
2022-06-21 15:31:46 +00:00
case ERepresentation : : Small :
2022-12-15 15:38:51 +00:00
SmallStorage . RTTI = InValue . SmallStorage . RTTI ;
SmallStorage . RTTI - > MoveConstruct ( & SmallStorage . Internal , & InValue . SmallStorage . Internal ) ;
2022-04-30 15:38:09 +00:00
break ;
2022-06-21 15:31:46 +00:00
case ERepresentation : : Big :
2022-12-15 15:38:51 +00:00
BigStorage . RTTI = InValue . BigStorage . RTTI ;
BigStorage . External = InValue . BigStorage . External ;
InValue . Invalidate ( ) ;
2022-04-30 15:38:09 +00:00
break ;
default : check_no_entry ( ) ;
}
2022-03-22 03:10:12 +00:00
}
return * this ;
}
2022-12-15 15:38:51 +00:00
template < typename T > requires ( ! CBaseOf < FAny , TDecay < T > > & & ! CTInPlaceType < TDecay < T > >
& & CDestructible < TDecay < T > > & & CConstructibleFrom < TDecay < T > , T & & > )
FORCEINLINE FAny & operator = ( T & & InValue )
2022-03-22 03:10:12 +00:00
{
2022-12-15 15:38:51 +00:00
using DecayedType = TDecay < T > ;
2022-03-22 03:10:12 +00:00
2022-12-15 15:38:51 +00:00
if ( HoldsAlternative < DecayedType > ( ) )
2022-03-22 03:10:12 +00:00
{
2022-12-15 15:38:51 +00:00
GetValue < DecayedType > ( ) = Forward < T > ( InValue ) ;
2022-03-22 03:10:12 +00:00
}
else
{
2022-12-15 15:38:51 +00:00
Destroy ( ) ;
EmplaceImpl < DecayedType > ( Forward < T > ( InValue ) ) ;
2022-03-22 03:10:12 +00:00
}
return * this ;
}
2022-11-16 14:03:54 +00:00
template < typename T , typename . . . Ts > requires ( CDestructible < TDecay < T > >
& & CConstructibleFrom < TDecay < T > , Ts & & . . . > )
2022-11-16 11:13:37 +00:00
FORCEINLINE TDecay < T > & Emplace ( Ts & & . . . Args )
2022-03-22 03:10:12 +00:00
{
2022-12-15 15:38:51 +00:00
Destroy ( ) ;
EmplaceImpl < T > ( Forward < Ts > ( Args ) . . . ) ;
return GetValue < TDecay < T > > ( ) ;
2022-03-22 03:10:12 +00:00
}
2022-12-15 15:38:51 +00:00
FORCEINLINE constexpr const type_info & GetTypeInfo ( ) const { return IsValid ( ) ? GetTypeInfoImpl ( ) : typeid ( void ) ; }
2022-04-05 09:00:33 +00:00
2022-12-15 15:38:51 +00:00
FORCEINLINE constexpr bool IsValid ( ) const { return TypeInfo ! = 0 ; }
FORCEINLINE constexpr explicit operator bool ( ) const { return TypeInfo ! = 0 ; }
2022-03-22 03:10:12 +00:00
2022-12-15 15:38:51 +00:00
template < typename T > FORCEINLINE constexpr bool HoldsAlternative ( ) const { return IsValid ( ) ? GetTypeInfo ( ) = = typeid ( T ) : false ; }
template < typename T > requires ( CSameAs < T , TDecay < T > > & & CDestructible < TDecay < T > > )
FORCEINLINE 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 * > ( GetStorage ( ) ) ; }
template < typename T > requires ( CSameAs < T , TDecay < T > > & & CDestructible < TDecay < T > > )
FORCEINLINE 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 * > ( GetStorage ( ) ) ) ; }
template < typename T > requires ( CSameAs < T , TDecay < T > > & & CDestructible < TDecay < T > > )
FORCEINLINE 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 * > ( GetStorage ( ) ) ; }
template < typename T > requires ( CSameAs < T , TDecay < T > > & & CDestructible < TDecay < T > > )
FORCEINLINE 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 * > ( GetStorage ( ) ) ) ; }
2022-03-22 03:10:12 +00:00
2022-11-16 14:03:54 +00:00
template < typename T > requires ( CSameAs < T , TDecay < T > > & & CDestructible < TDecay < T > > )
2022-12-15 15:38:51 +00:00
FORCEINLINE constexpr T & Get ( T & DefaultValue ) & { return HoldsAlternative < T > ( ) ? GetValue < T > ( ) : DefaultValue ; }
2022-03-23 09:49:30 +00:00
2022-11-16 14:03:54 +00:00
template < typename T > requires ( CSameAs < T , TDecay < T > > & & CDestructible < TDecay < T > > )
2022-12-15 15:38:51 +00:00
FORCEINLINE constexpr const T & Get ( const T & DefaultValue ) const & { return HoldsAlternative < T > ( ) ? GetValue < T > ( ) : DefaultValue ; }
2022-11-13 14:21:00 +00:00
2022-04-05 09:00:33 +00:00
FORCEINLINE void Reset ( )
2022-03-22 03:10:12 +00:00
{
2022-12-15 15:38:51 +00:00
Destroy ( ) ;
Invalidate ( ) ;
2022-04-30 15:38:09 +00:00
}
2022-12-15 15:38:51 +00:00
FORCEINLINE void Swap ( FAny & InValue )
2022-04-30 15:38:09 +00:00
{
if ( ! IsValid ( ) & & ! InValue . IsValid ( ) ) return ;
2022-12-15 15:38:51 +00:00
2022-04-30 15:38:09 +00:00
if ( IsValid ( ) & & ! InValue . IsValid ( ) )
{
InValue = MoveTemp ( * this ) ;
Reset ( ) ;
return ;
}
if ( InValue . IsValid ( ) & & ! IsValid ( ) )
{
* this = MoveTemp ( InValue ) ;
InValue . Reset ( ) ;
return ;
}
2022-12-15 15:38:51 +00:00
2022-04-30 15:38:09 +00:00
if ( GetTypeInfo ( ) = = InValue . GetTypeInfo ( ) )
{
2022-12-15 15:38:51 +00:00
switch ( GetRepresentation ( ) )
{
case ERepresentation : : Empty :
break ;
case ERepresentation : : Trivial :
uint8 Buffer [ sizeof ( TrivialStorage . Internal ) ] ;
Memory : : Memmove ( Buffer , TrivialStorage . Internal ) ;
Memory : : Memmove ( TrivialStorage . Internal , InValue . TrivialStorage . Internal ) ;
Memory : : Memmove ( InValue . TrivialStorage . Internal , Buffer ) ;
break ;
case ERepresentation : : Small :
SmallStorage . RTTI - > SwapObject ( & SmallStorage . Internal , & InValue . SmallStorage . Internal ) ;
break ;
case ERepresentation : : Big :
NAMESPACE_REDCRAFT : : Swap ( BigStorage . External , InValue . BigStorage . External ) ;
break ;
default : check_no_entry ( ) ;
}
2022-04-30 15:38:09 +00:00
return ;
}
2022-12-15 15:38:51 +00:00
FAny Temp = MoveTemp ( * this ) ;
2022-04-30 15:38:09 +00:00
* this = MoveTemp ( InValue ) ;
InValue = MoveTemp ( Temp ) ;
}
2022-04-14 14:41:22 +00:00
2022-03-22 03:10:12 +00:00
private :
2022-12-15 15:38:51 +00:00
struct FRTTI
{
const size_t TypeSize ;
const size_t TypeAlignment ;
2022-11-13 14:21:00 +00:00
2022-12-15 15:38:51 +00:00
using FCopyConstruct = void ( * ) ( void * , const void * ) ;
using FMoveConstruct = void ( * ) ( void * , void * ) ;
using FCopyAssign = void ( * ) ( void * , const void * ) ;
using FMoveAssign = void ( * ) ( void * , void * ) ;
using FDestruct = void ( * ) ( void * ) ;
using FSwapObject = void ( * ) ( void * , void * ) ;
2022-04-30 15:38:09 +00:00
2022-12-15 15:38:51 +00:00
const FCopyConstruct CopyConstruct ;
const FMoveConstruct MoveConstruct ;
const FCopyAssign CopyAssign ;
const FMoveAssign MoveAssign ;
const FDestruct Destruct ;
const FSwapObject SwapObject ;
template < typename T >
FORCEINLINE constexpr FRTTI ( TInPlaceType < T > )
: TypeSize ( sizeof ( T ) ) , TypeAlignment ( alignof ( T ) )
, CopyConstruct (
[ ] ( void * A , const void * B )
{
new ( A ) T ( * reinterpret_cast < const T * > ( B ) ) ;
}
)
, MoveConstruct (
[ ] ( void * A , void * B )
{
new ( A ) T ( MoveTemp ( * reinterpret_cast < T * > ( B ) ) ) ;
}
)
, CopyAssign (
[ ] ( void * A , const void * B )
{
if constexpr ( CCopyAssignable < T > )
{
* reinterpret_cast < T * > ( A ) = * reinterpret_cast < const T * > ( B ) ;
}
else
{
reinterpret_cast < T * > ( A ) - > ~ T ( ) ;
new ( A ) T ( * reinterpret_cast < const T * > ( B ) ) ;
}
}
)
, MoveAssign (
[ ] ( void * A , void * B )
{
if constexpr ( CMoveAssignable < T > )
{
* reinterpret_cast < T * > ( A ) = MoveTemp ( * reinterpret_cast < T * > ( B ) ) ;
}
else
{
reinterpret_cast < T * > ( A ) - > ~ T ( ) ;
new ( A ) T ( MoveTemp ( * reinterpret_cast < T * > ( B ) ) ) ;
}
}
)
, Destruct (
[ ] ( void * A )
{
reinterpret_cast < T * > ( A ) - > ~ T ( ) ;
}
)
, SwapObject {
[ ] ( void * A , void * B )
{
NAMESPACE_REDCRAFT : : Swap ( * reinterpret_cast < T * > ( A ) , * reinterpret_cast < T * > ( B ) ) ;
}
}
{ }
} ;
struct FTrivialStorage
2022-05-12 15:36:32 +00:00
{
2022-12-15 15:38:51 +00:00
uint8 Internal [ 64 - sizeof ( uintptr ) ] ;
2022-05-12 15:36:32 +00:00
} ;
2022-12-15 15:38:51 +00:00
struct FSmallStorage
2022-05-12 15:36:32 +00:00
{
2022-12-15 15:38:51 +00:00
uint8 Internal [ sizeof ( FTrivialStorage ) - sizeof ( const FRTTI * ) ] ;
const FRTTI * RTTI ;
} ;
2022-05-12 15:36:32 +00:00
2022-12-15 15:38:51 +00:00
struct FBigStorage
{
uint8 Padding [ sizeof ( FTrivialStorage ) - sizeof ( void * ) - sizeof ( const FRTTI * ) ] ;
void * External ;
const FRTTI * RTTI ;
} ;
2022-05-12 15:36:32 +00:00
2022-12-15 15:38:51 +00:00
static_assert ( sizeof ( FTrivialStorage ) = = sizeof ( FSmallStorage ) ) ;
static_assert ( sizeof ( FTrivialStorage ) = = sizeof ( FBigStorage ) ) ;
2022-05-12 15:36:32 +00:00
2022-12-15 15:38:51 +00:00
static_assert ( alignof ( type_info ) > = 4 ) ;
2022-05-12 15:36:32 +00:00
2022-12-15 15:38:51 +00:00
static constexpr uintptr_t RepresentationMask = 3 ;
enum class ERepresentation : uintptr
{
Empty = 0 , // EmptyType
Trivial = 1 , // TrivialStorage
Small = 2 , // SmallStorage
Big = 3 , // BigStorage
2022-05-12 15:36:32 +00:00
} ;
2022-12-15 15:38:51 +00:00
union
{
FTrivialStorage TrivialStorage ;
FSmallStorage SmallStorage ;
FBigStorage BigStorage ;
} ;
uintptr TypeInfo ;
2022-04-30 15:38:09 +00:00
2022-12-15 15:38:51 +00:00
FORCEINLINE ERepresentation GetRepresentation ( ) const { return static_cast < ERepresentation > ( TypeInfo & RepresentationMask ) ; }
FORCEINLINE const type_info & GetTypeInfoImpl ( ) const { return * reinterpret_cast < const type_info * > ( TypeInfo & ~ RepresentationMask ) ; }
2022-04-30 15:38:09 +00:00
2022-12-15 15:38:51 +00:00
FORCEINLINE void * GetStorage ( )
{
switch ( GetRepresentation ( ) )
{
case ERepresentation : : Empty : return nullptr ;
case ERepresentation : : Trivial : return & TrivialStorage . Internal ;
case ERepresentation : : Small : return & SmallStorage . Internal ;
case ERepresentation : : Big : return BigStorage . External ;
default : check_no_entry ( ) ; return nullptr ;
}
}
FORCEINLINE const void * GetStorage ( ) const
{
switch ( GetRepresentation ( ) )
{
case ERepresentation : : Empty : return nullptr ;
case ERepresentation : : Trivial : return & TrivialStorage . Internal ;
case ERepresentation : : Small : return & SmallStorage . Internal ;
case ERepresentation : : Big : return BigStorage . External ;
default : check_no_entry ( ) ; return nullptr ;
}
}
template < typename T , typename . . . Ts >
2022-11-16 11:13:37 +00:00
FORCEINLINE void EmplaceImpl ( Ts & & . . . Args )
2022-04-03 14:55:17 +00:00
{
2022-12-15 15:38:51 +00:00
using DecayedType = TDecay < T > ;
TypeInfo = reinterpret_cast < uintptr > ( & typeid ( DecayedType ) ) ;
if constexpr ( CEmpty < DecayedType > & & CTrivial < DecayedType > ) return ; // ERepresentation::Empty
2022-04-03 14:55:17 +00:00
2022-12-15 15:38:51 +00:00
constexpr bool bIsTriviallyStorable = sizeof ( DecayedType ) < = sizeof ( TrivialStorage . Internal ) & & alignof ( DecayedType ) < = alignof ( FAny ) & & CTriviallyCopyable < DecayedType > ;
constexpr bool bIsSmallStorable = sizeof ( DecayedType ) < = sizeof ( SmallStorage . Internal ) & & alignof ( DecayedType ) < = alignof ( FAny ) ;
static constexpr const FRTTI SelectedRTTI ( InPlaceType < DecayedType > ) ;
2022-04-30 15:38:09 +00:00
if constexpr ( bIsTriviallyStorable )
2022-04-03 14:55:17 +00:00
{
2022-12-15 15:38:51 +00:00
new ( & TrivialStorage . Internal ) DecayedType ( Forward < Ts > ( Args ) . . . ) ;
TypeInfo | = static_cast < uintptr > ( ERepresentation : : Trivial ) ;
2022-04-03 14:55:17 +00:00
}
2022-12-15 15:38:51 +00:00
else if constexpr ( bIsSmallStorable )
2022-04-03 14:55:17 +00:00
{
2022-12-15 15:38:51 +00:00
new ( & SmallStorage . Internal ) DecayedType ( Forward < Ts > ( Args ) . . . ) ;
SmallStorage . RTTI = & SelectedRTTI ;
TypeInfo | = static_cast < uintptr > ( ERepresentation : : Small ) ;
2022-04-03 14:55:17 +00:00
}
else
{
2022-12-15 15:38:51 +00:00
BigStorage . External = Memory : : Malloc ( sizeof ( DecayedType ) , alignof ( DecayedType ) ) ;
new ( BigStorage . External ) DecayedType ( Forward < Ts > ( Args ) . . . ) ;
BigStorage . RTTI = & SelectedRTTI ;
TypeInfo | = static_cast < uintptr > ( ERepresentation : : Big ) ;
2022-04-03 14:55:17 +00:00
}
}
2022-12-15 15:38:51 +00:00
FORCEINLINE void Destroy ( )
2022-04-05 09:00:33 +00:00
{
2022-04-30 15:38:09 +00:00
if ( ! IsValid ( ) ) return ;
switch ( GetRepresentation ( ) )
{
2022-12-15 15:38:51 +00:00
case ERepresentation : : Empty :
2022-06-21 15:31:46 +00:00
case ERepresentation : : Trivial :
2022-04-30 15:38:09 +00:00
break ;
2022-06-21 15:31:46 +00:00
case ERepresentation : : Small :
2022-12-15 15:38:51 +00:00
SmallStorage . RTTI - > Destruct ( & SmallStorage . Internal ) ;
2022-04-30 15:38:09 +00:00
break ;
2022-06-21 15:31:46 +00:00
case ERepresentation : : Big :
2022-12-15 15:38:51 +00:00
BigStorage . RTTI - > Destruct ( BigStorage . External ) ;
Memory : : Free ( BigStorage . External ) ;
2022-04-30 15:38:09 +00:00
break ;
default : check_no_entry ( ) ;
}
}
2022-12-15 15:38:51 +00:00
FORCEINLINE constexpr void Invalidate ( ) { TypeInfo = 0 ; }
template < typename T > requires ( ! CBaseOf < FAny , TRemoveCVRef < T > > )
friend FORCEINLINE constexpr bool operator = = ( const FAny & LHS , const T & RHS )
2022-04-30 15:38:09 +00:00
{
2022-12-15 15:38:51 +00:00
return LHS . template HoldsAlternative < T > ( ) ? LHS . template GetValue < T > ( ) = = RHS : false ;
2022-04-05 09:00:33 +00:00
}
2022-12-15 15:38:51 +00:00
friend FORCEINLINE constexpr bool operator = = ( const FAny & LHS , FInvalid )
2022-04-30 15:38:09 +00:00
{
2022-12-15 15:38:51 +00:00
return ! LHS . IsValid ( ) ;
2022-04-30 15:38:09 +00:00
}
2022-11-21 15:28:19 +00:00
2022-03-22 03:10:12 +00:00
} ;
2022-11-21 15:28:19 +00:00
static_assert ( sizeof ( FAny ) = = 64 , " The byte size of FAny is unexpected " ) ;
2022-12-15 15:38:51 +00:00
static_assert ( alignof ( FAny ) = = 16 , " The byte alignment of FAny is unexpected " ) ;
2022-05-20 15:35:36 +00:00
2022-03-22 03:10:12 +00:00
NAMESPACE_MODULE_END ( Utility )
NAMESPACE_MODULE_END ( Redcraft )
NAMESPACE_REDCRAFT_END