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-03-22 03:10:12 +00:00
# include "TypeTraits/TypeTraits.h"
2023-01-19 11:34:17 +00:00
# include "Miscellaneous/Compare.h"
2022-03-22 03:10:12 +00:00
# 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.
2022-12-16 11:30:55 +00:00
NAMESPACE_PRIVATE_BEGIN
template < typename T >
2022-12-18 11:28:33 +00:00
concept CFAnyPlaceable = CDestructible < TDecay < T > > & & CCopyConstructible < TDecay < T > > & & CMoveConstructible < TDecay < T > > ;
2022-12-16 11:30:55 +00:00
NAMESPACE_PRIVATE_END
2022-12-29 13:55:02 +00:00
/**
* The class any describes a type - safe container for single values of any copy and move constructible type .
* An object of class any stores an instance of any type that satisfies the constructor requirements or is empty ,
* and this is referred to as the state of the class any object . The stored instance is called the contained object .
*/
2022-12-30 11:11:01 +00:00
class alignas ( 16 ) FAny final
2022-11-13 14:21:00 +00:00
{
2022-11-15 11:28:43 +00:00
public :
2022-12-29 13:55:02 +00:00
/** Constructs an empty object. */
2022-12-15 15:38:51 +00:00
FORCEINLINE constexpr FAny ( ) { Invalidate ( ) ; }
2022-11-13 14:21:00 +00:00
2022-12-29 13:55:02 +00:00
/** Constructs an empty object. */
2022-12-15 15:38:51 +00:00
FORCEINLINE constexpr FAny ( FInvalid ) : FAny ( ) { }
2022-11-13 14:21:00 +00:00
2022-12-29 13:55:02 +00:00
/** Copies content of other into a new instance. This may use the object's copy constructor. */
2022-12-16 15:23:05 +00:00
FAny ( const FAny & InValue )
2022-12-15 15:38:51 +00:00
: 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-29 13:55:02 +00:00
/** Moves content of other into a new instance. This may use the object's move constructor. */
2022-12-16 15:23:05 +00:00
FAny ( FAny & & InValue )
2022-12-15 15:38:51 +00:00
: 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-12-29 13:55:02 +00:00
/** Constructs an object with initial content an object of type TDecay<T>, direct-initialized from Forward<T>(InValue). */
template < typename T > requires ( ! CSameAs < FAny , TDecay < T > > & & ! CTInPlaceType < TDecay < T > >
& & NAMESPACE_PRIVATE : : CFAnyPlaceable < T > & & CConstructibleFrom < TDecay < T > , T & & > )
FORCEINLINE FAny ( T & & InValue ) : FAny ( InPlaceType < T > , Forward < T > ( InValue ) )
{ }
/** Constructs an object with initial content an object of type TDecay<T>, direct-non-list-initialized from Forward<Ts>(Args).... */
2022-12-16 11:30:55 +00:00
template < typename T , typename . . . Ts > requires ( NAMESPACE_PRIVATE : : CFAnyPlaceable < 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-31 11:19:30 +00:00
/** Constructs an object with initial content an object of type TDecay<T>, direct-non-list-initialized from IL, Forward<Ts>(Args).... */
template < typename T , typename U , typename . . . Ts > requires ( NAMESPACE_PRIVATE : : CFAnyPlaceable < T > & & CConstructibleFrom < TDecay < T > , initializer_list < U > , Ts & & . . . > )
FORCEINLINE explicit FAny ( TInPlaceType < T > , initializer_list < U > IL , Ts & & . . . Args )
{
EmplaceImpl < T > ( IL , Forward < Ts > ( Args ) . . . ) ;
}
2022-03-22 03:10:12 +00:00
2022-12-29 13:55:02 +00:00
/** Destroys the contained object, if any, as if by a call to Reset(). */
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-29 13:55:02 +00:00
/** Assigns by copying the state of 'InValue'. This may use the object's copy constructor or copy assignment operator. */
2022-12-16 15:23:05 +00:00
FAny & operator = ( const FAny & InValue )
2022-03-22 03:10:12 +00:00
{
2022-12-29 13:55:02 +00:00
if ( & InValue = = this ) UNLIKELY return * this ;
2022-04-03 14:55:17 +00:00
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-29 13:55:02 +00:00
/** Assigns by moving the state of 'InValue'. This may use the object's move constructor or move assignment operator. */
2022-12-16 15:23:05 +00:00
FAny & operator = ( FAny & & InValue )
2022-03-22 03:10:12 +00:00
{
2022-12-29 13:55:02 +00:00
if ( & InValue = = this ) UNLIKELY return * this ;
2022-04-03 14:55:17 +00:00
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-29 13:55:02 +00:00
/** Assigns the type and value of 'InValue'. This may use the object's constructor or assignment operator. */
2022-12-19 10:00:52 +00:00
template < typename T > requires ( ! CSameAs < FAny , TDecay < T > > & & ! CTInPlaceType < TDecay < T > >
2022-12-16 11:30:55 +00:00
& & NAMESPACE_PRIVATE : : CFAnyPlaceable < T > & & CConstructibleFrom < TDecay < T > , T & & > )
2022-12-15 15:38:51 +00:00
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-29 13:55:02 +00:00
if constexpr ( CAssignableFrom < DecayedType , T & & > )
2022-03-22 03:10:12 +00:00
{
2022-12-29 13:55:02 +00:00
if ( HoldsAlternative < DecayedType > ( ) )
{
GetValue < DecayedType > ( ) = Forward < T > ( InValue ) ;
return * this ;
}
2022-03-22 03:10:12 +00:00
}
2022-12-29 13:55:02 +00:00
Destroy ( ) ;
EmplaceImpl < DecayedType > ( Forward < T > ( InValue ) ) ;
2022-03-22 03:10:12 +00:00
return * this ;
}
2022-12-18 11:11:53 +00:00
2022-12-29 13:55:02 +00:00
/** Check if the contained value is equivalent to 'InValue'. */
template < typename T > requires ( ! CSameAs < FAny , TRemoveCVRef < T > > & & NAMESPACE_PRIVATE : : CFAnyPlaceable < T > & & CEqualityComparable < T > )
NODISCARD FORCEINLINE constexpr bool operator = = ( const T & InValue ) const &
2022-12-18 11:11:53 +00:00
{
return HoldsAlternative < T > ( ) ? GetValue < T > ( ) = = InValue : false ;
}
2022-12-29 13:55:02 +00:00
/** Check that the contained value is in ordered relationship with 'InValue'. */
template < typename T > requires ( ! CSameAs < FAny , TRemoveCVRef < T > > & & NAMESPACE_PRIVATE : : CFAnyPlaceable < T > & & CSynthThreeWayComparable < T > )
NODISCARD FORCEINLINE constexpr partial_ordering operator < = > ( const T & InValue ) const &
2022-12-18 11:11:53 +00:00
{
return HoldsAlternative < T > ( ) ? SynthThreeWayCompare ( GetValue < T > ( ) , InValue ) : partial_ordering : : unordered ;
}
2022-12-29 13:55:02 +00:00
/** @return true if instance does not contain a value, otherwise false. */
NODISCARD FORCEINLINE constexpr bool operator = = ( FInvalid ) const & { return ! IsValid ( ) ; }
/**
* Changes the contained object to one of type TDecay < T > constructed from the arguments .
* First destroys the current contained object ( if any ) by Reset ( ) , then constructs an object of type
* TDecay < T > , direct - non - list - initialized from Forward < Ts > ( Args ) . . . , as the contained object .
*
2022-12-31 11:19:30 +00:00
* @ param Args - The arguments to be passed to the constructor of the contained object .
2022-12-29 13:55:02 +00:00
*
* @ return A reference to the new contained object .
*/
2022-12-16 11:30:55 +00:00
template < typename T , typename . . . Ts > requires ( NAMESPACE_PRIVATE : : CFAnyPlaceable < 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-31 11:19:30 +00:00
/**
* Changes the contained object to one of type TDecay < T > constructed from the arguments .
* First destroys the current contained object ( if any ) by Reset ( ) , then constructs an object of type
* TDecay < T > , direct - non - list - initialized from IL , Forward < Ts > ( Args ) . . . , as the contained object .
*
* @ param IL , Args - The arguments to be passed to the constructor of the contained object .
*
* @ return A reference to the new contained object .
*/
template < typename T , typename U , typename . . . Ts > requires ( NAMESPACE_PRIVATE : : CFAnyPlaceable < T > & & CConstructibleFrom < TDecay < T > , initializer_list < U > , Ts & & . . . > )
FORCEINLINE TDecay < T > & Emplace ( initializer_list < U > IL , Ts & & . . . Args )
{
Destroy ( ) ;
EmplaceImpl < T > ( IL , Forward < Ts > ( Args ) . . . ) ;
return GetValue < TDecay < T > > ( ) ;
}
2022-12-29 13:55:02 +00: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 ( ) ? GetTypeInfoImpl ( ) : typeid ( void ) ; }
2022-04-05 09:00:33 +00:00
2022-12-29 13:55:02 +00:00
/** @return true if instance contains a value, otherwise false. */
NODISCARD FORCEINLINE constexpr bool IsValid ( ) const { return TypeInfo ! = 0 ; }
NODISCARD FORCEINLINE constexpr explicit operator bool ( ) const { return TypeInfo ! = 0 ; }
2022-03-22 03:10:12 +00:00
2022-12-29 13:55:02 +00:00
/** @return true if the any currently holds the alternative 'T', false otherwise. */
template < typename T > NODISCARD FORCEINLINE constexpr bool HoldsAlternative ( ) const { return IsValid ( ) ? GetTypeInfo ( ) = = typeid ( T ) : false ; }
2022-12-15 15:38:51 +00:00
2022-12-29 13:55:02 +00:00
/** @return The contained object. */
2022-12-16 11:30:55 +00:00
template < typename T > requires ( CSameAs < T , TDecay < T > > & & NAMESPACE_PRIVATE : : CFAnyPlaceable < T > )
2022-12-29 13:55:02 +00:00
NODISCARD 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 ( ) ) ; }
/** @return The contained object. */
2022-12-16 11:30:55 +00:00
template < typename T > requires ( CSameAs < T , TDecay < T > > & & NAMESPACE_PRIVATE : : CFAnyPlaceable < T > )
2022-12-29 13:55:02 +00:00
NODISCARD 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 ( ) ) ) ; }
/** @return The contained object. */
2022-12-16 11:30:55 +00:00
template < typename T > requires ( CSameAs < T , TDecay < T > > & & NAMESPACE_PRIVATE : : CFAnyPlaceable < T > )
2022-12-29 13:55:02 +00:00
NODISCARD 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 ( ) ) ; }
/** @return The contained object. */
2022-12-16 11:30:55 +00:00
template < typename T > requires ( CSameAs < T , TDecay < T > > & & NAMESPACE_PRIVATE : : CFAnyPlaceable < T > )
2022-12-29 13:55:02 +00:00
NODISCARD 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 ( ) ) ) ; }
/** @return The contained object when HoldsAlternative<T>() returns true, 'DefaultValue' otherwise. */
2022-12-16 11:30:55 +00:00
template < typename T > requires ( CSameAs < T , TDecay < T > > & & NAMESPACE_PRIVATE : : CFAnyPlaceable < T > )
2022-12-29 13:55:02 +00:00
NODISCARD FORCEINLINE constexpr T & Get ( T & DefaultValue ) & { return HoldsAlternative < T > ( ) ? GetValue < T > ( ) : DefaultValue ; }
/** @return The contained object when HoldsAlternative<T>() returns true, 'DefaultValue' otherwise. */
2022-12-16 11:30:55 +00:00
template < typename T > requires ( CSameAs < T , TDecay < T > > & & NAMESPACE_PRIVATE : : CFAnyPlaceable < T > )
2022-12-29 13:55:02 +00:00
NODISCARD FORCEINLINE constexpr const T & Get ( const T & DefaultValue ) const & { return HoldsAlternative < T > ( ) ? GetValue < T > ( ) : DefaultValue ; }
2022-11-13 14:21:00 +00:00
2022-12-29 13:55:02 +00:00
/** If not empty, destroys the contained object. */
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
2022-12-29 13:55:02 +00:00
/** Overloads the Swap algorithm for FAny. */
2022-12-19 10:00:52 +00:00
friend void Swap ( FAny & A , FAny & B )
2022-04-30 15:38:09 +00:00
{
2022-12-19 10:00:52 +00:00
if ( ! A . IsValid ( ) & & ! B . IsValid ( ) ) return ;
2022-12-15 15:38:51 +00:00
2022-12-19 10:00:52 +00:00
if ( A . IsValid ( ) & & ! B . IsValid ( ) )
2022-04-30 15:38:09 +00:00
{
2022-12-19 10:00:52 +00:00
B = MoveTemp ( A ) ;
A . Reset ( ) ;
2022-04-30 15:38:09 +00:00
}
2022-12-19 10:00:52 +00:00
else if ( ! A . IsValid ( ) & & B . IsValid ( ) )
2022-04-30 15:38:09 +00:00
{
2022-12-19 10:00:52 +00:00
A = MoveTemp ( B ) ;
B . Reset ( ) ;
2022-04-30 15:38:09 +00:00
}
2022-12-19 10:00:52 +00:00
else
2022-04-30 15:38:09 +00:00
{
2022-12-19 10:00:52 +00:00
FAny Temp = MoveTemp ( A ) ;
A = MoveTemp ( B ) ;
B = MoveTemp ( Temp ) ;
2022-04-30 15:38:09 +00:00
}
}
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 )
{
2022-12-18 11:28:33 +00:00
if constexpr ( CSwappable < T > )
{
2022-12-19 10:00:52 +00:00
Swap ( * reinterpret_cast < T * > ( A ) , * reinterpret_cast < T * > ( B ) ) ;
2022-12-18 11:28:33 +00:00
}
else
{
TAlignedStorage < sizeof ( T ) , alignof ( T ) > TempBuffer ;
new ( & TempBuffer ) T ( MoveTemp ( * reinterpret_cast < T * > ( A ) ) ) ;
reinterpret_cast < T * > ( A ) - > ~ T ( ) ;
new ( A ) T ( MoveTemp ( * reinterpret_cast < T * > ( B ) ) ) ;
reinterpret_cast < T * > ( B ) - > ~ T ( ) ;
new ( B ) T ( MoveTemp ( * reinterpret_cast < T * > ( & TempBuffer ) ) ) ;
reinterpret_cast < T * > ( & TempBuffer ) - > ~ T ( ) ;
}
2022-12-15 15:38:51 +00:00
}
}
{ }
} ;
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-12-16 15:23:05 +00:00
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-16 15:23:05 +00:00
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 ; }
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