refactor(templates): TFunction replaces using type aliases with derived classes

This commit is contained in:
_Redstone_c_ 2022-05-14 22:52:21 +08:00
parent eeef55e9b4
commit 13e3b49118
2 changed files with 376 additions and 310 deletions

View File

@ -1158,6 +1158,30 @@ void TestFunction()
TUniqueFunction<void()> UniqueG; UniqueG = MoveTemp(UniqueA);
}
{
struct FFunctor
{
int32 A;
FFunctor(int32 InA) : A(InA) { }
int32 operator()() const { return A; }
};
FFunctor Functor(0xCC);
// TFunctionRef<void()> RefA;
TFunction<void()> ObjectA;
TUniqueFunction<void()> UniqueA;
// RefA = Functor;
ObjectA = Functor;
UniqueA = Functor;
// RefA.Emplace<FFunctor>(0xCC);
ObjectA.Emplace<FFunctor>(0xCC);
UniqueA.Emplace<FFunctor>(0xCC);
}
{
TFunction<void(int32)> Display = PrintNum;
Display(-9);

View File

@ -6,10 +6,7 @@
#include "Templates/Invoke.h"
#include "Memory/Alignment.h"
#include "Templates/Utility.h"
#include "Templates/TypeHash.h"
#include "TypeTraits/TypeTraits.h"
#include "Miscellaneous/TypeInfo.h"
#include "Concepts/BooleanTestable.h"
#include "Miscellaneous/AssertionMacros.h"
// NOTE: Disable alignment limit warning
@ -19,297 +16,136 @@ NAMESPACE_REDCRAFT_BEGIN
NAMESPACE_MODULE_BEGIN(Redcraft)
NAMESPACE_MODULE_BEGIN(Utility)
inline constexpr size_t FUNCTION_DEFAULT_INLINE_SIZE = ANY_DEFAULT_INLINE_SIZE - sizeof(uintptr);
inline constexpr size_t FUNCTION_DEFAULT_INLINE_ALIGNMENT = ANY_DEFAULT_INLINE_ALIGNMENT;
template <typename F> requires TIsFunction<F>::Value
struct TFunctionRef;
template <typename F, size_t InlineSize, size_t InlineAlignment> requires TIsFunction<F>::Value && (Memory::IsValidAlignment(InlineAlignment))
struct TFunction;
template <typename F, size_t InlineSize, size_t InlineAlignment> requires TIsFunction<F>::Value && (Memory::IsValidAlignment(InlineAlignment))
struct TUniqueFunction;
template <typename T> struct TIsTFunctionRef : FFalse { };
template <typename F> struct TIsTFunctionRef<TFunctionRef<F>> : FTrue { };
template <typename T> struct TIsTFunction : FFalse { };
template <typename F, size_t I, size_t J> struct TIsTFunction<TFunction<F, I, J>> : FTrue { };
template <typename T> struct TIsTUniqueFunction : FFalse { };
template <typename F, size_t I, size_t J> struct TIsTUniqueFunction<TUniqueFunction<F, I, J>> : FTrue { };
NAMESPACE_PRIVATE_BEGIN
enum class EFunctionType
template <typename T>
constexpr bool FunctionIsBound(const T& Func)
{
Reference,
Object,
Unique,
};
enum class EFunctionSpecifiers
{
None,
LValue,
RValue,
Const,
ConstLValue,
ConstRValue,
};
template <typename F, size_t InlineSize, size_t InlineAlignment, EFunctionSpecifiers Specifiers, EFunctionType FunctionType> requires (Memory::IsValidAlignment(InlineAlignment))
struct TFunctionImpl;
template <typename T> struct TIsTFunctionImpl : FFalse { };
template <typename F, size_t I, size_t J, EFunctionSpecifiers S, EFunctionType E> struct TIsTFunctionImpl<TFunctionImpl<F, I, J, S, E>> : FTrue { };
template <typename T> struct TIsTFunctionRef : FFalse { };
template <typename F, size_t I, size_t J, EFunctionSpecifiers S> struct TIsTFunctionRef<TFunctionImpl<F, I, J, S, EFunctionType::Reference>> : FTrue { };
template <typename T> struct TIsTFunction : FFalse { };
template <typename F, size_t I, size_t J, EFunctionSpecifiers S> struct TIsTFunction<TFunctionImpl<F, I, J, S, EFunctionType::Object>> : FTrue { };
template <typename T> struct TIsTUniqueFunction : FFalse { };
template <typename F, size_t I, size_t J, EFunctionSpecifiers S> struct TIsTUniqueFunction<TFunctionImpl<F, I, J, S, EFunctionType::Unique>> : FTrue { };
struct FFunctionIsBound
{
template <typename T>
static constexpr bool F(const T& Func)
if constexpr (TIsPointer<T>::Value || TIsMemberPointer<T>::Value || TIsTFunctionRef<T>::Value || TIsTFunction<T>::Value || TIsTUniqueFunction<T>::Value)
{
if constexpr (TIsPointer<T>::Value || TIsMemberPointer<T>::Value || TIsTFunctionImpl<T>::Value)
{
return !!Func;
}
else
{
return true;
}
return !!Func;
}
};
else
{
return true;
}
}
template <EFunctionSpecifiers Specifiers, typename R, typename F, typename... Types>
struct TIsInvocableResultWithSpecifiers : FFalse { };
template <typename Signature, typename F> struct TIsInvocableSignature : FFalse { };
template <typename R, typename F, typename... Types>
struct TIsInvocableResultWithSpecifiers<EFunctionSpecifiers::None, R, F, Types...>
: TBoolConstant<TIsInvocableResult<R, F, Types...>::Value && TIsInvocableResult<R, F&, Types...>::Value>
template <typename Ret, typename... Types, typename F>
struct TIsInvocableSignature<Ret(Types...), F>
: TBoolConstant<TIsInvocableResult<Ret, F, Types...>::Value && TIsInvocableResult<Ret, F&, Types...>::Value>
{ };
template <typename R, typename F, typename... Types>
struct TIsInvocableResultWithSpecifiers<EFunctionSpecifiers::LValue, R, F, Types...> : TIsInvocableResult<R, F&, Types...> { };
template <typename Ret, typename... Types, typename F> struct TIsInvocableSignature<Ret(Types...) & , F> : TIsInvocableResult<Ret, F&, Types...> { };
template <typename Ret, typename... Types, typename F> struct TIsInvocableSignature<Ret(Types...) &&, F> : TIsInvocableResult<Ret, F , Types...> { };
template <typename R, typename F, typename... Types>
struct TIsInvocableResultWithSpecifiers<EFunctionSpecifiers::RValue, R, F, Types...> : TIsInvocableResult<R, F, Types...> { };
template <typename R, typename F, typename... Types>
struct TIsInvocableResultWithSpecifiers<EFunctionSpecifiers::Const, R, F, Types...>
: TBoolConstant<TIsInvocableResult<R, const F, Types...>::Value && TIsInvocableResult<R, const F&, Types...>::Value>
template <typename Ret, typename... Types, typename F>
struct TIsInvocableSignature<Ret(Types...) const, F>
: TBoolConstant<TIsInvocableResult<Ret, const F, Types...>::Value && TIsInvocableResult<Ret, const F&, Types...>::Value>
{ };
template <typename R, typename F, typename... Types>
struct TIsInvocableResultWithSpecifiers<EFunctionSpecifiers::ConstLValue, R, F, Types...> : TIsInvocableResult<R, const F&, Types...> { };
template <typename Ret, typename... Types, typename F> struct TIsInvocableSignature<Ret(Types...) const& , F> : TIsInvocableResult<Ret, const F&, Types...> { };
template <typename Ret, typename... Types, typename F> struct TIsInvocableSignature<Ret(Types...) const&&, F> : TIsInvocableResult<Ret, const F , Types...> { };
template <typename R, typename F, typename... Types>
struct TIsInvocableResultWithSpecifiers<EFunctionSpecifiers::ConstRValue, R, F, Types...> : TIsInvocableResult<R, const F, Types...> { };
template <typename F> struct TFunctionInfo;
template <typename Ret, typename... Types> struct TFunctionInfo<Ret(Types...) > { using Fn = Ret(Types...); using CVRef = int; };
template <typename Ret, typename... Types> struct TFunctionInfo<Ret(Types...) & > { using Fn = Ret(Types...); using CVRef = int&; };
template <typename Ret, typename... Types> struct TFunctionInfo<Ret(Types...) && > { using Fn = Ret(Types...); using CVRef = int&&; };
template <typename Ret, typename... Types> struct TFunctionInfo<Ret(Types...) const > { using Fn = Ret(Types...); using CVRef = const int; };
template <typename Ret, typename... Types> struct TFunctionInfo<Ret(Types...) const& > { using Fn = Ret(Types...); using CVRef = const int&; };
template <typename Ret, typename... Types> struct TFunctionInfo<Ret(Types...) const&&> { using Fn = Ret(Types...); using CVRef = const int&&; };
template <typename T, EFunctionSpecifiers Specifiers> struct TFunctionCallConst;
template <typename T> struct TFunctionCallConst<T, EFunctionSpecifiers::None> { using Type = T; };
template <typename T> struct TFunctionCallConst<T, EFunctionSpecifiers::LValue> { using Type = T; };
template <typename T> struct TFunctionCallConst<T, EFunctionSpecifiers::RValue> { using Type = T; };
template <typename T> struct TFunctionCallConst<T, EFunctionSpecifiers::Const> { using Type = const T; };
template <typename T> struct TFunctionCallConst<T, EFunctionSpecifiers::ConstLValue> { using Type = const T; };
template <typename T> struct TFunctionCallConst<T, EFunctionSpecifiers::ConstRValue> { using Type = const T; };
template <typename F, typename CVRef, size_t InlineSize, size_t InlineAlignment, bool bIsRef> struct TFunctionImpl;
template <typename T, EFunctionSpecifiers Specifiers> struct TFunctionCallConstRef;
template <typename T> struct TFunctionCallConstRef<T, EFunctionSpecifiers::None> { using Type = T& ; };
template <typename T> struct TFunctionCallConstRef<T, EFunctionSpecifiers::LValue> { using Type = T& ; };
template <typename T> struct TFunctionCallConstRef<T, EFunctionSpecifiers::RValue> { using Type = T&&; };
template <typename T> struct TFunctionCallConstRef<T, EFunctionSpecifiers::Const> { using Type = const T& ; };
template <typename T> struct TFunctionCallConstRef<T, EFunctionSpecifiers::ConstLValue> { using Type = const T& ; };
template <typename T> struct TFunctionCallConstRef<T, EFunctionSpecifiers::ConstRValue> { using Type = const T&&; };
template <typename R, typename... Types, size_t InlineSize, size_t InlineAlignment, EFunctionSpecifiers Specifiers, EFunctionType FunctionType>
struct alignas(InlineAlignment) TFunctionImpl<R(Types...), InlineSize, InlineAlignment, Specifiers, FunctionType>
template <typename Ret, typename... Types, typename CVRef, size_t InlineSize, size_t InlineAlignment, bool bIsRef>
struct alignas(InlineAlignment) TFunctionImpl<Ret(Types...), CVRef, InlineSize, InlineAlignment, bIsRef>
{
public:
using ResultType = R;
using ResultType = Ret;
using ArgumentType = TTuple<Types...>;
constexpr TFunctionImpl(nullptr_t = nullptr) requires (FunctionType != EFunctionType::Reference) : Callable(nullptr) { }
TFunctionImpl(const TFunctionImpl& InValue) requires (FunctionType != EFunctionType::Unique)
: Callable(InValue.Callable), Storage(InValue.Storage)
{ }
TFunctionImpl(TFunctionImpl&& InValue)
: Callable(InValue.Callable), Storage(MoveTemp(InValue.Storage))
{ if constexpr (FunctionType != EFunctionType::Reference) InValue.Reset(); }
template <typename T> requires (!TIsTFunctionImpl<typename TDecay<T>::Type>::Value) && (!TIsTInPlaceType<typename TDecay<T>::Type>::Value)
&& TIsInvocableResultWithSpecifiers<Specifiers, ResultType, typename TDecay<T>::Type, Types...>::Value
&& (FunctionType == EFunctionType::Reference || TIsConstructible<typename TDecay<T>::Type, T&&>::Value)
&& ((FunctionType == EFunctionType::Object && TIsCopyConstructible<typename TDecay<T>::Type>::Value)
|| (FunctionType == EFunctionType::Unique && TIsMoveConstructible<typename TDecay<T>::Type>::Value)
|| FunctionType == EFunctionType::Reference)
FORCEINLINE TFunctionImpl(T&& InValue)
{
using DecayedType = typename TDecay<T>::Type;
if constexpr (FunctionType == EFunctionType::Reference)
{
checkf(FFunctionIsBound::F(InValue), TEXT("Cannot bind a null/unbound callable to a TFunctionRef"));
}
if (!FFunctionIsBound::F(InValue)) Callable = nullptr;
else EmplaceImpl<DecayedType>(Forward<T>(InValue));
}
template <typename T, typename... ArgTypes> requires (FunctionType != EFunctionType::Reference)
&& TIsInvocableResultWithSpecifiers<Specifiers, ResultType, typename TDecay<T>::Type, Types...>::Value && TIsConstructible<typename TDecay<T>::Type, ArgTypes...>::Value
&& ((FunctionType == EFunctionType::Object && TIsCopyConstructible<typename TDecay<T>::Type>::Value)
|| (FunctionType == EFunctionType::Unique && TIsMoveConstructible<typename TDecay<T>::Type>::Value))
FORCEINLINE TFunctionImpl(TInPlaceType<T>, ArgTypes&&... Args)
{
using DecayedType = typename TDecay<T>::Type;
EmplaceImpl<DecayedType>(Forward<ArgTypes>(Args)...);
}
// Construct TFunctionRef from TFunction or TFunctionUnique
template <size_t OtherInlineSize, size_t OtherInlineAlignment, EFunctionType OtherFunctionType>
requires (FunctionType == EFunctionType::Reference) && (OtherFunctionType != EFunctionType::Reference) && (TIsSame<typename TFunctionCallConst<void, Specifiers>::Type, void>::Value)
FORCEINLINE TFunctionImpl(TFunctionImpl<R(Types...), OtherInlineSize, OtherInlineAlignment, Specifiers, OtherFunctionType>& InValue)
{
checkf(FFunctionIsBound::F(InValue), TEXT("Cannot bind a null/unbound callable to a TFunctionRef"));
EmplaceImpl<TFunctionImpl<R(Types...), OtherInlineSize, OtherInlineAlignment, Specifiers, OtherFunctionType>>(InValue);
}
// Construct TFunctionRef from TFunction or TFunctionUnique
template <size_t OtherInlineSize, size_t OtherInlineAlignment, EFunctionType OtherFunctionType>
requires (FunctionType == EFunctionType::Reference) && (OtherFunctionType != EFunctionType::Reference) && (TIsSame<typename TFunctionCallConst<void, Specifiers>::Type, const void>::Value)
FORCEINLINE TFunctionImpl(const TFunctionImpl<R(Types...), OtherInlineSize, OtherInlineAlignment, Specifiers, OtherFunctionType>& InValue)
{
checkf(FFunctionIsBound::F(InValue), TEXT("Cannot bind a null/unbound callable to a TFunctionRef"));
EmplaceImpl<TFunctionImpl<R(Types...), OtherInlineSize, OtherInlineAlignment, Specifiers, OtherFunctionType>>(InValue);
}
FORCEINLINE TFunctionImpl(const TFunctionImpl<R(Types...), InlineSize, InlineAlignment, Specifiers, EFunctionType::Object>& InValue) requires (FunctionType == EFunctionType::Unique)
: Callable((*reinterpret_cast<const TFunctionImpl*>(&InValue)).Callable), Storage((*reinterpret_cast<const TFunctionImpl*>(&InValue)).Storage)
{ }
FORCEINLINE TFunctionImpl(TFunctionImpl<R(Types...), InlineSize, InlineAlignment, Specifiers, EFunctionType::Object>&& InValue) requires (FunctionType == EFunctionType::Unique)
: Callable((*reinterpret_cast<TFunctionImpl*>(&InValue)).Callable), Storage(MoveTemp((*reinterpret_cast<TFunctionImpl*>(&InValue)).Storage))
{ InValue.Reset(); }
TFunctionImpl() = default;
TFunctionImpl(const TFunctionImpl&) = default;
TFunctionImpl(TFunctionImpl&& InValue) = default;
TFunctionImpl& operator=(const TFunctionImpl&) = default;
TFunctionImpl& operator=(TFunctionImpl&&) = default;
~TFunctionImpl() = default;
FORCEINLINE TFunctionImpl& operator=(const TFunctionImpl& InValue) requires (FunctionType == EFunctionType::Object)
{
AssignImpl(InValue);
return *this;
}
FORCEINLINE TFunctionImpl& operator=(TFunctionImpl&& InValue) requires (FunctionType != EFunctionType::Reference)
{
if (&InValue == this) return *this;
AssignImpl(MoveTemp(InValue));
return *this;
}
FORCEINLINE TFunctionImpl& operator=(const TFunctionImpl<R(Types...), InlineSize, InlineAlignment, Specifiers, EFunctionType::Object>& InValue) requires (FunctionType == EFunctionType::Unique)
{
AssignImpl(*reinterpret_cast<const TFunctionImpl*>(&InValue));
return *this;
}
FORCEINLINE TFunctionImpl& operator=(TFunctionImpl<R(Types...), InlineSize, InlineAlignment, Specifiers, EFunctionType::Object>&& InValue) requires (FunctionType == EFunctionType::Unique)
{
AssignImpl(MoveTemp(*reinterpret_cast<TFunctionImpl*>(&InValue)));
return *this;
}
constexpr TFunctionImpl& operator=(nullptr_t) requires (FunctionType != EFunctionType::Reference) { Reset(); return *this; }
template <typename T> requires (FunctionType != EFunctionType::Reference) && (!TIsTFunctionImpl<typename TDecay<T>::Type>::Value)
&& TIsInvocableResultWithSpecifiers<Specifiers, ResultType, typename TDecay<T>::Type, Types...>::Value
&& TIsConstructible<typename TDecay<T>::Type, T&&>::Value
&& ((FunctionType == EFunctionType::Object && TIsCopyConstructible<typename TDecay<T>::Type>::Value)
|| (FunctionType == EFunctionType::Unique && TIsMoveConstructible<typename TDecay<T>::Type>::Value))
FORCEINLINE TFunctionImpl& operator=(T&& InValue)
{
using DecayedType = typename TDecay<T>::Type;
if (!FFunctionIsBound::F(InValue)) Reset();
else EmplaceImpl<DecayedType>(Forward<T>(InValue));
return *this;
}
template <typename T, typename... ArgTypes> requires (FunctionType != EFunctionType::Reference)
&& TIsInvocableResultWithSpecifiers<Specifiers, ResultType, typename TDecay<T>::Type, Types...>::Value
&& TIsConstructible<typename TDecay<T>::Type, ArgTypes...>::Value
&& ((FunctionType == EFunctionType::Object && TIsCopyConstructible<typename TDecay<T>::Type>::Value)
|| (FunctionType == EFunctionType::Unique && TIsMoveConstructible<typename TDecay<T>::Type>::Value))
FORCEINLINE typename TDecay<T>::Type& Emplace(ArgTypes&&... Args)
{
using DecayedType = typename TDecay<T>::Type;
EmplaceImpl<DecayedType>(Forward<ArgTypes>(Args)...);
return Target<DecayedType>();
}
FORCEINLINE ResultType operator()(Types... Args) requires (Specifiers == EFunctionSpecifiers::None ) { return CallImpl(Forward<Types>(Args)...); }
FORCEINLINE ResultType operator()(Types... Args) & requires (Specifiers == EFunctionSpecifiers::LValue ) { return CallImpl(Forward<Types>(Args)...); }
FORCEINLINE ResultType operator()(Types... Args) && requires (Specifiers == EFunctionSpecifiers::RValue ) { return CallImpl(Forward<Types>(Args)...); }
FORCEINLINE ResultType operator()(Types... Args) const requires (Specifiers == EFunctionSpecifiers::Const ) { return CallImpl(Forward<Types>(Args)...); }
FORCEINLINE ResultType operator()(Types... Args) const& requires (Specifiers == EFunctionSpecifiers::ConstLValue) { return CallImpl(Forward<Types>(Args)...); }
FORCEINLINE ResultType operator()(Types... Args) const&& requires (Specifiers == EFunctionSpecifiers::ConstRValue) { return CallImpl(Forward<Types>(Args)...); }
FORCEINLINE ResultType operator()(Types... Args) requires (TIsSame<CVRef, int >::Value) { return CallImpl(Forward<Types>(Args)...); }
FORCEINLINE ResultType operator()(Types... Args) & requires (TIsSame<CVRef, int& >::Value) { return CallImpl(Forward<Types>(Args)...); }
FORCEINLINE ResultType operator()(Types... Args) && requires (TIsSame<CVRef, int&&>::Value) { return CallImpl(Forward<Types>(Args)...); }
FORCEINLINE ResultType operator()(Types... Args) const requires (TIsSame<CVRef, const int >::Value) { return CallImpl(Forward<Types>(Args)...); }
FORCEINLINE ResultType operator()(Types... Args) const& requires (TIsSame<CVRef, const int& >::Value) { return CallImpl(Forward<Types>(Args)...); }
FORCEINLINE ResultType operator()(Types... Args) const&& requires (TIsSame<CVRef, const int&&>::Value) { return CallImpl(Forward<Types>(Args)...); }
constexpr bool IsValid() const { return Callable != nullptr; }
constexpr explicit operator bool() const { return Callable != nullptr; }
FORCEINLINE const FTypeInfo& TargetType() const requires (FunctionType != EFunctionType::Reference) { return IsValid() ? Storage.GetTypeInfo() : Typeid(void); };
FORCEINLINE const type_info& TargetType() const requires (!bIsRef) { return IsValid() ? Storage.GetTypeInfo() : typeid(void); };
template <typename T> FORCEINLINE T& Target() & requires (FunctionType != EFunctionType::Reference) && 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 { return static_cast< StorageType& >(Storage).template GetValue<T>(); }
template <typename T> FORCEINLINE T&& Target() && requires (FunctionType != EFunctionType::Reference) && 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 { return static_cast< StorageType&&>(Storage).template GetValue<T>(); }
template <typename T> FORCEINLINE const T& Target() const& requires (FunctionType != EFunctionType::Reference) && 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 { return static_cast<const StorageType& >(Storage).template GetValue<T>(); }
template <typename T> FORCEINLINE const T&& Target() const&& requires (FunctionType != EFunctionType::Reference) && 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 { return static_cast<const StorageType&&>(Storage).template GetValue<T>(); }
template <typename T> FORCEINLINE T& Target() & requires (!bIsRef) && 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 { return static_cast< StorageType& >(Storage).template GetValue<T>(); }
template <typename T> FORCEINLINE T&& Target() && requires (!bIsRef) && 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 { return static_cast< StorageType&&>(Storage).template GetValue<T>(); }
template <typename T> FORCEINLINE const T& Target() const& requires (!bIsRef) && 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 { return static_cast<const StorageType& >(Storage).template GetValue<T>(); }
template <typename T> FORCEINLINE const T&& Target() const&& requires (!bIsRef) && 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 { return static_cast<const StorageType&&>(Storage).template GetValue<T>(); }
constexpr void Reset() requires (FunctionType != EFunctionType::Reference) { Callable = nullptr; }
constexpr void Swap(TFunctionImpl& InValue) requires (FunctionType != EFunctionType::Reference)
constexpr void Swap(TFunctionImpl& InValue) requires (!bIsRef)
{
using NAMESPACE_REDCRAFT::Swap;
if (!IsValid() && !InValue.IsValid()) return;
if (IsValid() && !InValue.IsValid())
{
InValue = MoveTemp(*this);
Reset();
ResetImpl();
return;
}
if (InValue.IsValid() && !IsValid())
{
*this = MoveTemp(InValue);
InValue.Reset();
InValue.ResetImpl();
return;
}
NAMESPACE_REDCRAFT::Swap(Callable, InValue.Callable);
NAMESPACE_REDCRAFT::Swap(Storage, InValue.Storage);
Swap(Callable, InValue.Callable);
Swap(Storage, InValue.Storage);
}
private:
using StorageType = typename TConditional<FunctionType == EFunctionType::Reference, typename TFunctionCallConst<void, Specifiers>::Type*, TAny<InlineSize, 1>>::Type;
using StorageRef = typename TConditional<FunctionType == EFunctionType::Reference, typename TFunctionCallConst<void, Specifiers>::Type*, typename TFunctionCallConstRef<StorageType, Specifiers>::Type&>::Type;
using StorageType = typename TConditional<bIsRef, typename TCopyConst<CVRef, void>::Type*, TAny<InlineSize, 1>>::Type;
using StorageRef = typename TConditional<bIsRef, typename TCopyConst<CVRef, void>::Type*, typename TCopyCVRef<CVRef, StorageType>::Type&>::Type;
using CallFunc = ResultType(*)(StorageRef, Types&&...);
StorageType Storage;
CallFunc Callable;
template <typename DecayedType, typename... ArgTypes>
FORCEINLINE void EmplaceImpl(ArgTypes&&... Args)
{
using CallableType = typename TFunctionCallConst<DecayedType, Specifiers>::Type;
if constexpr (FunctionType == EFunctionType::Reference) Storage = ((reinterpret_cast<StorageType>(&Args)), ...);
else Storage.template Emplace<DecayedType>(Forward<ArgTypes>(Args)...);
Callable = [](StorageRef Storage, Types&&... Args) -> ResultType
{
const auto GetFunc = [&Storage]() -> decltype(auto)
{
if constexpr (FunctionType == EFunctionType::Reference) return *reinterpret_cast<CallableType*>(Storage);
else return Storage.template GetValue<DecayedType>();
};
return InvokeResult<R>(Forward<typename TFunctionCallConstRef<CallableType, Specifiers>::Type>(GetFunc()), Forward<Types>(Args)...);
};
}
FORCEINLINE ResultType CallImpl(Types&&... Args)
{
checkf(IsValid(), TEXT("Attempting to call an unbound TFunction!"));
@ -322,6 +158,34 @@ private:
return Callable(Storage, Forward<Types>(Args)...);
}
protected:
template <typename DecayedType, typename... ArgTypes>
FORCEINLINE void EmplaceImpl(ArgTypes&&... Args)
{
using CallableType = typename TCopyConst<typename TRemoveReference<CVRef>::Type, DecayedType>::Type;
if constexpr (bIsRef) Storage = ((reinterpret_cast<StorageType>(AddressOf(Args))), ...);
else Storage.template Emplace<DecayedType>(Forward<ArgTypes>(Args)...);
Callable = [](StorageRef Storage, Types&&... Args) -> ResultType
{
using InvokeType = typename TConditional<
TIsReference<CVRef>::Value,
typename TCopyCVRef<CVRef, CallableType>::Type,
typename TCopyCVRef<CVRef, CallableType>::Type&
>::Type;
const auto GetFunc = [&Storage]() -> InvokeType
{
if constexpr (!bIsRef) return Storage.template GetValue<DecayedType>();
else return static_cast<InvokeType>(*reinterpret_cast<CallableType*>(Storage));
};
return InvokeResult<ResultType>(GetFunc(), Forward<Types>(Args)...);
};
}
FORCEINLINE void AssignImpl(const TFunctionImpl& InValue)
{
if (InValue.IsValid())
@ -329,7 +193,7 @@ private:
Callable = InValue.Callable;
Storage = InValue.Storage;
}
else Reset();
else ResetImpl();
}
FORCEINLINE void AssignImpl(TFunctionImpl&& InValue)
@ -338,69 +202,247 @@ private:
{
Callable = InValue.Callable;
Storage = MoveTemp(InValue.Storage);
InValue.Reset();
InValue.ResetImpl();
}
else Reset();
else ResetImpl();
}
};
constexpr void ResetImpl() { Callable = nullptr; }
template <typename F, size_t InlineSize, size_t InlineAlignment, EFunctionType FunctionType>
struct TFunctionSelect;
template <typename R, typename... Types, size_t InlineSize, size_t InlineAlignment, EFunctionType FunctionType>
struct TFunctionSelect<R(Types...) , InlineSize, InlineAlignment, FunctionType>
{
using Type = TFunctionImpl<R(Types...), InlineSize, InlineAlignment, EFunctionSpecifiers::None, FunctionType>;
};
template <typename R, typename... Types, size_t InlineSize, size_t InlineAlignment, EFunctionType FunctionType>
struct TFunctionSelect<R(Types...) & , InlineSize, InlineAlignment, FunctionType>
{
using Type = TFunctionImpl<R(Types...), InlineSize, InlineAlignment, EFunctionSpecifiers::LValue, FunctionType>;
};
template <typename R, typename... Types, size_t InlineSize, size_t InlineAlignment, EFunctionType FunctionType>
struct TFunctionSelect<R(Types...) && , InlineSize, InlineAlignment, FunctionType>
{
using Type = TFunctionImpl<R(Types...), InlineSize, InlineAlignment, EFunctionSpecifiers::RValue, FunctionType>;
};
template <typename R, typename... Types, size_t InlineSize, size_t InlineAlignment, EFunctionType FunctionType>
struct TFunctionSelect<R(Types...) const , InlineSize, InlineAlignment, FunctionType>
{
using Type = TFunctionImpl<R(Types...), InlineSize, InlineAlignment, EFunctionSpecifiers::Const, FunctionType>;
};
template <typename R, typename... Types, size_t InlineSize, size_t InlineAlignment, EFunctionType FunctionType>
struct TFunctionSelect<R(Types...) const& , InlineSize, InlineAlignment, FunctionType>
{
using Type = TFunctionImpl<R(Types...), InlineSize, InlineAlignment, EFunctionSpecifiers::ConstLValue, FunctionType>;
};
template <typename R, typename... Types, size_t InlineSize, size_t InlineAlignment, EFunctionType FunctionType>
struct TFunctionSelect<R(Types...) const&&, InlineSize, InlineAlignment, FunctionType>
{
using Type = TFunctionImpl<R(Types...), InlineSize, InlineAlignment, EFunctionSpecifiers::ConstRValue, FunctionType>;
};
NAMESPACE_PRIVATE_END
inline constexpr size_t FUNCTION_DEFAULT_INLINE_SIZE = ANY_DEFAULT_INLINE_SIZE - sizeof(uintptr);
inline constexpr size_t FUNCTION_DEFAULT_INLINE_ALIGNMENT = ANY_DEFAULT_INLINE_ALIGNMENT;
template <typename F> requires TIsFunction<F>::Value
struct TFunctionRef
: public NAMESPACE_PRIVATE::TFunctionImpl<
typename NAMESPACE_PRIVATE::TFunctionInfo<F>::Fn,
typename NAMESPACE_PRIVATE::TFunctionInfo<F>::CVRef,
FUNCTION_DEFAULT_INLINE_SIZE,
FUNCTION_DEFAULT_INLINE_ALIGNMENT,
true>
{
private:
template <typename F>
using TFunctionRef = typename NAMESPACE_PRIVATE::TFunctionSelect<F, FUNCTION_DEFAULT_INLINE_SIZE, FUNCTION_DEFAULT_INLINE_ALIGNMENT, NAMESPACE_PRIVATE::EFunctionType::Reference>::Type;
using Super = NAMESPACE_PRIVATE::TFunctionImpl<
typename NAMESPACE_PRIVATE::TFunctionInfo<F>::Fn,
typename NAMESPACE_PRIVATE::TFunctionInfo<F>::CVRef,
FUNCTION_DEFAULT_INLINE_SIZE,
FUNCTION_DEFAULT_INLINE_ALIGNMENT,
true>;
public:
TFunctionRef() = delete;
TFunctionRef(const TFunctionRef& InValue) = default;
TFunctionRef(TFunctionRef&& InValue) = default;
TFunctionRef& operator=(const TFunctionRef& InValue) = delete;
TFunctionRef& operator=(TFunctionRef&& InValue) = delete;
template <typename T> requires (!TIsTFunctionRef<typename TDecay<T>::Type>::Value) && (!TIsTInPlaceType<typename TDecay<T>::Type>::Value)
&& NAMESPACE_PRIVATE::TIsInvocableSignature<F, typename TDecay<T>::Type>::Value
FORCEINLINE TFunctionRef(T&& InValue)
{
using DecayedType = typename TDecay<T>::Type;
checkf(NAMESPACE_PRIVATE::FunctionIsBound(InValue), TEXT("Cannot bind a null/unbound callable to a TFunctionRef"));
Super::template EmplaceImpl<DecayedType>(Forward<T>(InValue));
}
template <typename T>
TFunctionRef(const T&&) = delete;
};
template <typename F, size_t InlineSize = FUNCTION_DEFAULT_INLINE_SIZE, size_t InlineAlignment = FUNCTION_DEFAULT_INLINE_ALIGNMENT>
using TFunction = typename NAMESPACE_PRIVATE::TFunctionSelect<F, InlineSize, InlineAlignment, NAMESPACE_PRIVATE::EFunctionType::Object>::Type;
requires TIsFunction<F>::Value && (Memory::IsValidAlignment(InlineAlignment))
struct TFunction
: public NAMESPACE_PRIVATE::TFunctionImpl<
typename NAMESPACE_PRIVATE::TFunctionInfo<F>::Fn,
typename NAMESPACE_PRIVATE::TFunctionInfo<F>::CVRef,
InlineSize,
InlineAlignment,
false>
{
private:
using Super = NAMESPACE_PRIVATE::TFunctionImpl<
typename NAMESPACE_PRIVATE::TFunctionInfo<F>::Fn,
typename NAMESPACE_PRIVATE::TFunctionInfo<F>::CVRef,
InlineSize,
InlineAlignment,
false>;
public:
constexpr TFunction(nullptr_t = nullptr) { Super::ResetImpl(); }
FORCEINLINE TFunction(const TFunction& InValue) = default;
FORCEINLINE TFunction(TFunction&& InValue) : Super(MoveTemp(InValue)) { InValue.ResetImpl(); }
FORCEINLINE TFunction& operator=(const TFunction& InValue)
{
Super::AssignImpl(InValue);
return *this;
}
FORCEINLINE TFunction& operator=(TFunction&& InValue)
{
if (&InValue == this) return *this;
Super::AssignImpl(MoveTemp(InValue));
return *this;
}
template <typename T> requires (!TIsTInPlaceType<typename TDecay<T>::Type>::Value)
&& (!TIsTFunctionRef<typename TDecay<T>::Type>::Value) && (!TIsTFunction<typename TDecay<T>::Type>::Value) && (!TIsTUniqueFunction<typename TDecay<T>::Type>::Value)
&& TIsConstructible<typename TDecay<T>::Type, T&&>::Value && TIsCopyConstructible<typename TDecay<T>::Type>::Value
&& NAMESPACE_PRIVATE::TIsInvocableSignature<F, typename TDecay<T>::Type>::Value
FORCEINLINE TFunction(T&& InValue)
{
using DecayedType = typename TDecay<T>::Type;
if (!NAMESPACE_PRIVATE::FunctionIsBound(InValue)) Super::ResetImpl();
else Super::template EmplaceImpl<DecayedType>(Forward<T>(InValue));
}
template <typename T, typename... ArgTypes> requires NAMESPACE_PRIVATE::TIsInvocableSignature<F, typename TDecay<T>::Type>::Value
&& TIsConstructible<typename TDecay<T>::Type, ArgTypes...>::Value && TIsCopyConstructible<typename TDecay<T>::Type>::Value
FORCEINLINE TFunction(TInPlaceType<T>, ArgTypes&&... Args)
{
using DecayedType = typename TDecay<T>::Type;
Super::template EmplaceImpl<DecayedType>(Forward<ArgTypes>(Args)...);
}
constexpr TFunction& operator=(nullptr_t) { Super::ResetImpl(); return *this; }
template <typename T> requires NAMESPACE_PRIVATE::TIsInvocableSignature<F, typename TDecay<T>::Type>::Value
&& (!TIsTFunctionRef<typename TDecay<T>::Type>::Value) && (!TIsTFunction<typename TDecay<T>::Type>::Value) && (!TIsTUniqueFunction<typename TDecay<T>::Type>::Value)
&& TIsConstructible<typename TDecay<T>::Type, T&&>::Value && TIsCopyConstructible<typename TDecay<T>::Type>::Value
FORCEINLINE TFunction& operator=(T&& InValue)
{
using DecayedType = typename TDecay<T>::Type;
if (!NAMESPACE_PRIVATE::FunctionIsBound(InValue)) Super::ResetImpl();
else Super::template EmplaceImpl<DecayedType>(Forward<T>(InValue));
return *this;
}
template <typename T, typename... ArgTypes> requires NAMESPACE_PRIVATE::TIsInvocableSignature<F, typename TDecay<T>::Type>::Value
&& TIsConstructible<typename TDecay<T>::Type, ArgTypes...>::Value&& TIsCopyConstructible<typename TDecay<T>::Type>::Value
FORCEINLINE typename TDecay<T>::Type& Emplace(ArgTypes&&... Args)
{
using DecayedType = typename TDecay<T>::Type;
Super::template EmplaceImpl<DecayedType>(Forward<ArgTypes>(Args)...);
return Super::template Target<DecayedType>();
}
constexpr void Reset() { Super::ResetImpl(); }
};
template <typename F, size_t InlineSize = FUNCTION_DEFAULT_INLINE_SIZE, size_t InlineAlignment = FUNCTION_DEFAULT_INLINE_ALIGNMENT>
using TUniqueFunction = typename NAMESPACE_PRIVATE::TFunctionSelect<F, InlineSize, InlineAlignment, NAMESPACE_PRIVATE::EFunctionType::Unique>::Type;
requires TIsFunction<F>::Value && (Memory::IsValidAlignment(InlineAlignment))
struct TUniqueFunction
: public NAMESPACE_PRIVATE::TFunctionImpl<
typename NAMESPACE_PRIVATE::TFunctionInfo<F>::Fn,
typename NAMESPACE_PRIVATE::TFunctionInfo<F>::CVRef,
InlineSize,
InlineAlignment,
false>
{
private:
template <typename T> struct TIsTFunctionRef : NAMESPACE_PRIVATE::TIsTFunctionRef<T> { };
template <typename T> struct TIsTFunction : NAMESPACE_PRIVATE::TIsTFunction<T> { };
template <typename T> struct TIsTUniqueFunction : NAMESPACE_PRIVATE::TIsTUniqueFunction<T> { };
using Super = NAMESPACE_PRIVATE::TFunctionImpl<
typename NAMESPACE_PRIVATE::TFunctionInfo<F>::Fn,
typename NAMESPACE_PRIVATE::TFunctionInfo<F>::CVRef,
InlineSize,
InlineAlignment,
false>;
public:
constexpr TUniqueFunction(nullptr_t = nullptr) { Super::ResetImpl(); }
FORCEINLINE TUniqueFunction(const TUniqueFunction& InValue) = delete;
TUniqueFunction(TUniqueFunction&& InValue) : Super(MoveTemp(InValue)) { InValue.ResetImpl(); }
FORCEINLINE TUniqueFunction& operator=(const TUniqueFunction& InValue) = delete;
FORCEINLINE TUniqueFunction& operator=(TUniqueFunction&& InValue)
{
if (&InValue == this) return *this;
Super::AssignImpl(MoveTemp(InValue));
return *this;
}
FORCEINLINE TUniqueFunction(const TFunction<F, InlineSize, InlineAlignment>& InValue)
: Super(*reinterpret_cast<const TUniqueFunction*>(&InValue))
{ }
FORCEINLINE TUniqueFunction(TFunction<F, InlineSize, InlineAlignment>&& InValue)
: Super(MoveTemp(*reinterpret_cast<const TUniqueFunction*>(&InValue)))
{
InValue.Reset();
}
FORCEINLINE TUniqueFunction& operator=(const TFunction<F, InlineSize, InlineAlignment>& InValue)
{
Super::AssignImpl(*reinterpret_cast<const TUniqueFunction*>(&InValue));
return *this;
}
FORCEINLINE TUniqueFunction& operator=(TFunction<F, InlineSize, InlineAlignment>&& InValue)
{
Super::AssignImpl(MoveTemp(*reinterpret_cast<TUniqueFunction*>(&InValue)));
return *this;
}
template <typename T> requires (!TIsTInPlaceType<typename TDecay<T>::Type>::Value)
&& (!TIsTFunctionRef<typename TDecay<T>::Type>::Value) && (!TIsTFunction<typename TDecay<T>::Type>::Value) && (!TIsTUniqueFunction<typename TDecay<T>::Type>::Value)
&& TIsConstructible<typename TDecay<T>::Type, T&&>::Value && TIsMoveConstructible<typename TDecay<T>::Type>::Value
&& NAMESPACE_PRIVATE::TIsInvocableSignature<F, typename TDecay<T>::Type>::Value
FORCEINLINE TUniqueFunction(T&& InValue)
{
using DecayedType = typename TDecay<T>::Type;
if (!NAMESPACE_PRIVATE::FunctionIsBound(InValue)) Super::ResetImpl();
else Super::template EmplaceImpl<DecayedType>(Forward<T>(InValue));
}
template <typename T, typename... ArgTypes> requires NAMESPACE_PRIVATE::TIsInvocableSignature<F, typename TDecay<T>::Type>::Value
&& TIsConstructible<typename TDecay<T>::Type, ArgTypes...>::Value && TIsMoveConstructible<typename TDecay<T>::Type>::Value
FORCEINLINE TUniqueFunction(TInPlaceType<T>, ArgTypes&&... Args)
{
using DecayedType = typename TDecay<T>::Type;
Super::template EmplaceImpl<DecayedType>(Forward<ArgTypes>(Args)...);
}
constexpr TUniqueFunction& operator=(nullptr_t) { Super::ResetImpl(); return *this; }
template <typename T> requires NAMESPACE_PRIVATE::TIsInvocableSignature<F, typename TDecay<T>::Type>::Value
&& (!TIsTFunctionRef<typename TDecay<T>::Type>::Value) && (!TIsTFunction<typename TDecay<T>::Type>::Value) && (!TIsTUniqueFunction<typename TDecay<T>::Type>::Value)
&& TIsConstructible<typename TDecay<T>::Type, T&&>::Value&& TIsMoveConstructible<typename TDecay<T>::Type>::Value
FORCEINLINE TUniqueFunction& operator=(T&& InValue)
{
using DecayedType = typename TDecay<T>::Type;
if (!NAMESPACE_PRIVATE::FunctionIsBound(InValue)) Super::ResetImpl();
else Super::template EmplaceImpl<DecayedType>(Forward<T>(InValue));
return *this;
}
template <typename T, typename... ArgTypes> requires NAMESPACE_PRIVATE::TIsInvocableSignature<F, typename TDecay<T>::Type>::Value
&& TIsConstructible<typename TDecay<T>::Type, ArgTypes...>::Value&& TIsMoveConstructible<typename TDecay<T>::Type>::Value
FORCEINLINE typename TDecay<T>::Type& Emplace(ArgTypes&&... Args)
{
using DecayedType = typename TDecay<T>::Type;
Super::template EmplaceImpl<DecayedType>(Forward<ArgTypes>(Args)...);
return Super::template Target<DecayedType>();
}
constexpr void Reset() { Super::ResetImpl(); }
};
template <typename F>
constexpr bool operator==(const TFunctionRef<F>& LHS, nullptr_t)
@ -426,51 +468,51 @@ static_assert(sizeof(TUniqueFunction<void()>) == 64, "The byte size of TUniqueFu
NAMESPACE_PRIVATE_BEGIN
template <typename F>
struct NotFunctionType
struct TNotFunction
{
F Func;
F Storage;
NotFunctionType(const NotFunctionType&) = default;
NotFunctionType(NotFunctionType&&) = default;
TNotFunction(const TNotFunction&) = default;
TNotFunction(TNotFunction&&) = default;
template <typename InF>
constexpr NotFunctionType(InF&& InFunc) : Func(Forward<InF>(InFunc)) { }
constexpr TNotFunction(InF&& InFunc) : Storage(Forward<InF>(InFunc)) { }
template <typename... Types> requires TIsInvocable<F&, Types&&...>::Value
constexpr auto operator()(Types&&... Args) &
-> decltype(!Invoke(Func, Forward<Types>(Args)...))
constexpr auto operator()(Types&&... Args) &
-> decltype(!Invoke(Storage, Forward<Types>(Args)...))
{
return !Invoke(Func, Forward<Types>(Args)...);
return !Invoke(Storage, Forward<Types>(Args)...);
}
template <typename... Types> requires TIsInvocable<F&&, Types&&...>::Value
constexpr auto operator()(Types&&... Args) &&
-> decltype(!Invoke(MoveTemp(Func), Forward<Types>(Args)...))
constexpr auto operator()(Types&&... Args) &&
-> decltype(!Invoke(MoveTemp(Storage), Forward<Types>(Args)...))
{
return !Invoke(MoveTemp(Func), Forward<Types>(Args)...);
return !Invoke(MoveTemp(Storage), Forward<Types>(Args)...);
}
template <typename... Types> requires TIsInvocable<const F&, Types&&...>::Value
constexpr auto operator()(Types&&... Args) const&
-> decltype(!Invoke(Func, Forward<Types>(Args)...))
constexpr auto operator()(Types&&... Args) const&
-> decltype(!Invoke(Storage, Forward<Types>(Args)...))
{
return !Invoke(Func, Forward<Types>(Args)...);
return !Invoke(Storage, Forward<Types>(Args)...);
}
template <typename... Types> requires TIsInvocable<const F&&, Types&&...>::Value
constexpr auto operator()(Types&&... Args) const&&
-> decltype(!Invoke(MoveTemp(Func), Forward<Types>(Args)...))
constexpr auto operator()(Types&&... Args) const&&
-> decltype(!Invoke(MoveTemp(Storage), Forward<Types>(Args)...))
{
return !Invoke(MoveTemp(Func), Forward<Types>(Args)...);
return !Invoke(MoveTemp(Storage), Forward<Types>(Args)...);
}
};
NAMESPACE_PRIVATE_END
template <typename F>
constexpr NAMESPACE_PRIVATE::NotFunctionType<typename TDecay<F>::Type> NotFn(F&& Func)
constexpr NAMESPACE_PRIVATE::TNotFunction<typename TDecay<F>::Type> NotFn(F&& Func)
{
return NAMESPACE_PRIVATE::NotFunctionType<typename TDecay<F>::Type>(Forward<F>(Func));
return NAMESPACE_PRIVATE::TNotFunction<typename TDecay<F>::Type>(Forward<F>(Func));
}
NAMESPACE_MODULE_END(Utility)