From 13e3b4911861d6cf5d3b2e8f2f598bd68bd7dc9f Mon Sep 17 00:00:00 2001 From: _Redstone_c_ Date: Sat, 14 May 2022 22:52:21 +0800 Subject: [PATCH] refactor(templates): TFunction replaces using type aliases with derived classes --- .../Private/Testing/TemplatesTesting.cpp | 24 + .../Source/Public/Templates/Function.h | 662 ++++++++++-------- 2 files changed, 376 insertions(+), 310 deletions(-) diff --git a/Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp b/Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp index cd2c0e2..9224b50 100644 --- a/Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp +++ b/Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp @@ -1158,6 +1158,30 @@ void TestFunction() TUniqueFunction UniqueG; UniqueG = MoveTemp(UniqueA); } + { + struct FFunctor + { + int32 A; + FFunctor(int32 InA) : A(InA) { } + int32 operator()() const { return A; } + }; + + FFunctor Functor(0xCC); + +// TFunctionRef RefA; + TFunction ObjectA; + TUniqueFunction UniqueA; + +// RefA = Functor; + ObjectA = Functor; + UniqueA = Functor; + +// RefA.Emplace(0xCC); + ObjectA.Emplace(0xCC); + UniqueA.Emplace(0xCC); + + } + { TFunction Display = PrintNum; Display(-9); diff --git a/Redcraft.Utility/Source/Public/Templates/Function.h b/Redcraft.Utility/Source/Public/Templates/Function.h index c34a584..c74147d 100644 --- a/Redcraft.Utility/Source/Public/Templates/Function.h +++ b/Redcraft.Utility/Source/Public/Templates/Function.h @@ -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 requires TIsFunction::Value +struct TFunctionRef; + +template requires TIsFunction::Value && (Memory::IsValidAlignment(InlineAlignment)) +struct TFunction; + +template requires TIsFunction::Value && (Memory::IsValidAlignment(InlineAlignment)) +struct TUniqueFunction; + +template struct TIsTFunctionRef : FFalse { }; +template struct TIsTFunctionRef> : FTrue { }; + +template struct TIsTFunction : FFalse { }; +template struct TIsTFunction> : FTrue { }; + +template struct TIsTUniqueFunction : FFalse { }; +template struct TIsTUniqueFunction> : FTrue { }; + NAMESPACE_PRIVATE_BEGIN -enum class EFunctionType +template +constexpr bool FunctionIsBound(const T& Func) { - Reference, - Object, - Unique, -}; - -enum class EFunctionSpecifiers -{ - None, - LValue, - RValue, - Const, - ConstLValue, - ConstRValue, -}; - -template requires (Memory::IsValidAlignment(InlineAlignment)) -struct TFunctionImpl; - -template struct TIsTFunctionImpl : FFalse { }; -template struct TIsTFunctionImpl> : FTrue { }; - -template struct TIsTFunctionRef : FFalse { }; -template struct TIsTFunctionRef> : FTrue { }; - -template struct TIsTFunction : FFalse { }; -template struct TIsTFunction> : FTrue { }; - -template struct TIsTUniqueFunction : FFalse { }; -template struct TIsTUniqueFunction> : FTrue { }; - -struct FFunctionIsBound -{ - template - static constexpr bool F(const T& Func) + if constexpr (TIsPointer::Value || TIsMemberPointer::Value || TIsTFunctionRef::Value || TIsTFunction::Value || TIsTUniqueFunction::Value) { - if constexpr (TIsPointer::Value || TIsMemberPointer::Value || TIsTFunctionImpl::Value) - { - return !!Func; - } - else - { - return true; - } + return !!Func; } -}; + else + { + return true; + } +} -template -struct TIsInvocableResultWithSpecifiers : FFalse { }; +template struct TIsInvocableSignature : FFalse { }; -template -struct TIsInvocableResultWithSpecifiers - : TBoolConstant::Value && TIsInvocableResult::Value> +template +struct TIsInvocableSignature + : TBoolConstant::Value && TIsInvocableResult::Value> { }; -template -struct TIsInvocableResultWithSpecifiers : TIsInvocableResult { }; +template struct TIsInvocableSignature : TIsInvocableResult { }; +template struct TIsInvocableSignature : TIsInvocableResult { }; -template -struct TIsInvocableResultWithSpecifiers : TIsInvocableResult { }; - -template -struct TIsInvocableResultWithSpecifiers - : TBoolConstant::Value && TIsInvocableResult::Value> +template +struct TIsInvocableSignature + : TBoolConstant::Value && TIsInvocableResult::Value> { }; -template -struct TIsInvocableResultWithSpecifiers : TIsInvocableResult { }; +template struct TIsInvocableSignature : TIsInvocableResult { }; +template struct TIsInvocableSignature : TIsInvocableResult { }; -template -struct TIsInvocableResultWithSpecifiers : TIsInvocableResult { }; +template struct TFunctionInfo; +template struct TFunctionInfo { using Fn = Ret(Types...); using CVRef = int; }; +template struct TFunctionInfo { using Fn = Ret(Types...); using CVRef = int&; }; +template struct TFunctionInfo { using Fn = Ret(Types...); using CVRef = int&&; }; +template struct TFunctionInfo { using Fn = Ret(Types...); using CVRef = const int; }; +template struct TFunctionInfo { using Fn = Ret(Types...); using CVRef = const int&; }; +template struct TFunctionInfo { using Fn = Ret(Types...); using CVRef = const int&&; }; -template struct TFunctionCallConst; -template struct TFunctionCallConst { using Type = T; }; -template struct TFunctionCallConst { using Type = T; }; -template struct TFunctionCallConst { using Type = T; }; -template struct TFunctionCallConst { using Type = const T; }; -template struct TFunctionCallConst { using Type = const T; }; -template struct TFunctionCallConst { using Type = const T; }; +template struct TFunctionImpl; -template struct TFunctionCallConstRef; -template struct TFunctionCallConstRef { using Type = T& ; }; -template struct TFunctionCallConstRef { using Type = T& ; }; -template struct TFunctionCallConstRef { using Type = T&&; }; -template struct TFunctionCallConstRef { using Type = const T& ; }; -template struct TFunctionCallConstRef { using Type = const T& ; }; -template struct TFunctionCallConstRef { using Type = const T&&; }; - -template -struct alignas(InlineAlignment) TFunctionImpl +template +struct alignas(InlineAlignment) TFunctionImpl { public: - using ResultType = R; + using ResultType = Ret; using ArgumentType = TTuple; - 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 requires (!TIsTFunctionImpl::Type>::Value) && (!TIsTInPlaceType::Type>::Value) - && TIsInvocableResultWithSpecifiers::Type, Types...>::Value - && (FunctionType == EFunctionType::Reference || TIsConstructible::Type, T&&>::Value) - && ((FunctionType == EFunctionType::Object && TIsCopyConstructible::Type>::Value) - || (FunctionType == EFunctionType::Unique && TIsMoveConstructible::Type>::Value) - || FunctionType == EFunctionType::Reference) - FORCEINLINE TFunctionImpl(T&& InValue) - { - using DecayedType = typename TDecay::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(Forward(InValue)); - } - - template requires (FunctionType != EFunctionType::Reference) - && TIsInvocableResultWithSpecifiers::Type, Types...>::Value && TIsConstructible::Type, ArgTypes...>::Value - && ((FunctionType == EFunctionType::Object && TIsCopyConstructible::Type>::Value) - || (FunctionType == EFunctionType::Unique && TIsMoveConstructible::Type>::Value)) - FORCEINLINE TFunctionImpl(TInPlaceType, ArgTypes&&... Args) - { - using DecayedType = typename TDecay::Type; - EmplaceImpl(Forward(Args)...); - } - - // Construct TFunctionRef from TFunction or TFunctionUnique - template - requires (FunctionType == EFunctionType::Reference) && (OtherFunctionType != EFunctionType::Reference) && (TIsSame::Type, void>::Value) - FORCEINLINE TFunctionImpl(TFunctionImpl& InValue) - { - checkf(FFunctionIsBound::F(InValue), TEXT("Cannot bind a null/unbound callable to a TFunctionRef")); - EmplaceImpl>(InValue); - } - - // Construct TFunctionRef from TFunction or TFunctionUnique - template - requires (FunctionType == EFunctionType::Reference) && (OtherFunctionType != EFunctionType::Reference) && (TIsSame::Type, const void>::Value) - FORCEINLINE TFunctionImpl(const TFunctionImpl& InValue) - { - checkf(FFunctionIsBound::F(InValue), TEXT("Cannot bind a null/unbound callable to a TFunctionRef")); - EmplaceImpl>(InValue); - } - - FORCEINLINE TFunctionImpl(const TFunctionImpl& InValue) requires (FunctionType == EFunctionType::Unique) - : Callable((*reinterpret_cast(&InValue)).Callable), Storage((*reinterpret_cast(&InValue)).Storage) - { } - - FORCEINLINE TFunctionImpl(TFunctionImpl&& InValue) requires (FunctionType == EFunctionType::Unique) - : Callable((*reinterpret_cast(&InValue)).Callable), Storage(MoveTemp((*reinterpret_cast(&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& InValue) requires (FunctionType == EFunctionType::Unique) - { - AssignImpl(*reinterpret_cast(&InValue)); - return *this; - } - - FORCEINLINE TFunctionImpl& operator=(TFunctionImpl&& InValue) requires (FunctionType == EFunctionType::Unique) - { - AssignImpl(MoveTemp(*reinterpret_cast(&InValue))); - return *this; - } - - constexpr TFunctionImpl& operator=(nullptr_t) requires (FunctionType != EFunctionType::Reference) { Reset(); return *this; } - - template requires (FunctionType != EFunctionType::Reference) && (!TIsTFunctionImpl::Type>::Value) - && TIsInvocableResultWithSpecifiers::Type, Types...>::Value - && TIsConstructible::Type, T&&>::Value - && ((FunctionType == EFunctionType::Object && TIsCopyConstructible::Type>::Value) - || (FunctionType == EFunctionType::Unique && TIsMoveConstructible::Type>::Value)) - FORCEINLINE TFunctionImpl& operator=(T&& InValue) - { - using DecayedType = typename TDecay::Type; - - if (!FFunctionIsBound::F(InValue)) Reset(); - else EmplaceImpl(Forward(InValue)); - - return *this; - } - - template requires (FunctionType != EFunctionType::Reference) - && TIsInvocableResultWithSpecifiers::Type, Types...>::Value - && TIsConstructible::Type, ArgTypes...>::Value - && ((FunctionType == EFunctionType::Object && TIsCopyConstructible::Type>::Value) - || (FunctionType == EFunctionType::Unique && TIsMoveConstructible::Type>::Value)) - FORCEINLINE typename TDecay::Type& Emplace(ArgTypes&&... Args) - { - using DecayedType = typename TDecay::Type; - EmplaceImpl(Forward(Args)...); - return Target(); - } - - FORCEINLINE ResultType operator()(Types... Args) requires (Specifiers == EFunctionSpecifiers::None ) { return CallImpl(Forward(Args)...); } - FORCEINLINE ResultType operator()(Types... Args) & requires (Specifiers == EFunctionSpecifiers::LValue ) { return CallImpl(Forward(Args)...); } - FORCEINLINE ResultType operator()(Types... Args) && requires (Specifiers == EFunctionSpecifiers::RValue ) { return CallImpl(Forward(Args)...); } - FORCEINLINE ResultType operator()(Types... Args) const requires (Specifiers == EFunctionSpecifiers::Const ) { return CallImpl(Forward(Args)...); } - FORCEINLINE ResultType operator()(Types... Args) const& requires (Specifiers == EFunctionSpecifiers::ConstLValue) { return CallImpl(Forward(Args)...); } - FORCEINLINE ResultType operator()(Types... Args) const&& requires (Specifiers == EFunctionSpecifiers::ConstRValue) { return CallImpl(Forward(Args)...); } + FORCEINLINE ResultType operator()(Types... Args) requires (TIsSame::Value) { return CallImpl(Forward(Args)...); } + FORCEINLINE ResultType operator()(Types... Args) & requires (TIsSame::Value) { return CallImpl(Forward(Args)...); } + FORCEINLINE ResultType operator()(Types... Args) && requires (TIsSame::Value) { return CallImpl(Forward(Args)...); } + FORCEINLINE ResultType operator()(Types... Args) const requires (TIsSame::Value) { return CallImpl(Forward(Args)...); } + FORCEINLINE ResultType operator()(Types... Args) const& requires (TIsSame::Value) { return CallImpl(Forward(Args)...); } + FORCEINLINE ResultType operator()(Types... Args) const&& requires (TIsSame::Value) { return CallImpl(Forward(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 FORCEINLINE T& Target() & requires (FunctionType != EFunctionType::Reference) && TIsSame::Type>::Value && TIsObject::Type>::Value && (!TIsArray::Type>::Value) && TIsDestructible::Type>::Value { return static_cast< StorageType& >(Storage).template GetValue(); } - template FORCEINLINE T&& Target() && requires (FunctionType != EFunctionType::Reference) && TIsSame::Type>::Value && TIsObject::Type>::Value && (!TIsArray::Type>::Value) && TIsDestructible::Type>::Value { return static_cast< StorageType&&>(Storage).template GetValue(); } - template FORCEINLINE const T& Target() const& requires (FunctionType != EFunctionType::Reference) && TIsSame::Type>::Value && TIsObject::Type>::Value && (!TIsArray::Type>::Value) && TIsDestructible::Type>::Value { return static_cast(Storage).template GetValue(); } - template FORCEINLINE const T&& Target() const&& requires (FunctionType != EFunctionType::Reference) && TIsSame::Type>::Value && TIsObject::Type>::Value && (!TIsArray::Type>::Value) && TIsDestructible::Type>::Value { return static_cast(Storage).template GetValue(); } + template FORCEINLINE T& Target() & requires (!bIsRef) && TIsSame::Type>::Value && TIsObject::Type>::Value && (!TIsArray::Type>::Value) && TIsDestructible::Type>::Value { return static_cast< StorageType& >(Storage).template GetValue(); } + template FORCEINLINE T&& Target() && requires (!bIsRef) && TIsSame::Type>::Value && TIsObject::Type>::Value && (!TIsArray::Type>::Value) && TIsDestructible::Type>::Value { return static_cast< StorageType&&>(Storage).template GetValue(); } + template FORCEINLINE const T& Target() const& requires (!bIsRef) && TIsSame::Type>::Value && TIsObject::Type>::Value && (!TIsArray::Type>::Value) && TIsDestructible::Type>::Value { return static_cast(Storage).template GetValue(); } + template FORCEINLINE const T&& Target() const&& requires (!bIsRef) && TIsSame::Type>::Value && TIsObject::Type>::Value && (!TIsArray::Type>::Value) && TIsDestructible::Type>::Value { return static_cast(Storage).template GetValue(); } - 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::Type*, TAny>::Type; - using StorageRef = typename TConditional::Type*, typename TFunctionCallConstRef::Type&>::Type; + using StorageType = typename TConditional::Type*, TAny>::Type; + using StorageRef = typename TConditional::Type*, typename TCopyCVRef::Type&>::Type; using CallFunc = ResultType(*)(StorageRef, Types&&...); StorageType Storage; CallFunc Callable; - template - FORCEINLINE void EmplaceImpl(ArgTypes&&... Args) - { - using CallableType = typename TFunctionCallConst::Type; - - if constexpr (FunctionType == EFunctionType::Reference) Storage = ((reinterpret_cast(&Args)), ...); - else Storage.template Emplace(Forward(Args)...); - - Callable = [](StorageRef Storage, Types&&... Args) -> ResultType - { - const auto GetFunc = [&Storage]() -> decltype(auto) - { - if constexpr (FunctionType == EFunctionType::Reference) return *reinterpret_cast(Storage); - else return Storage.template GetValue(); - }; - - return InvokeResult(Forward::Type>(GetFunc()), Forward(Args)...); - }; - } - FORCEINLINE ResultType CallImpl(Types&&... Args) { checkf(IsValid(), TEXT("Attempting to call an unbound TFunction!")); @@ -322,6 +158,34 @@ private: return Callable(Storage, Forward(Args)...); } +protected: + + template + FORCEINLINE void EmplaceImpl(ArgTypes&&... Args) + { + using CallableType = typename TCopyConst::Type, DecayedType>::Type; + + if constexpr (bIsRef) Storage = ((reinterpret_cast(AddressOf(Args))), ...); + else Storage.template Emplace(Forward(Args)...); + + Callable = [](StorageRef Storage, Types&&... Args) -> ResultType + { + using InvokeType = typename TConditional< + TIsReference::Value, + typename TCopyCVRef::Type, + typename TCopyCVRef::Type& + >::Type; + + const auto GetFunc = [&Storage]() -> InvokeType + { + if constexpr (!bIsRef) return Storage.template GetValue(); + else return static_cast(*reinterpret_cast(Storage)); + }; + + return InvokeResult(GetFunc(), Forward(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 -struct TFunctionSelect; - -template -struct TFunctionSelect -{ - using Type = TFunctionImpl; -}; - -template -struct TFunctionSelect -{ - using Type = TFunctionImpl; -}; - -template -struct TFunctionSelect -{ - using Type = TFunctionImpl; -}; - -template -struct TFunctionSelect -{ - using Type = TFunctionImpl; -}; - -template -struct TFunctionSelect -{ - using Type = TFunctionImpl; -}; - -template -struct TFunctionSelect -{ - using Type = TFunctionImpl; }; 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 requires TIsFunction::Value +struct TFunctionRef + : public NAMESPACE_PRIVATE::TFunctionImpl< + typename NAMESPACE_PRIVATE::TFunctionInfo::Fn, + typename NAMESPACE_PRIVATE::TFunctionInfo::CVRef, + FUNCTION_DEFAULT_INLINE_SIZE, + FUNCTION_DEFAULT_INLINE_ALIGNMENT, + true> +{ +private: -template -using TFunctionRef = typename NAMESPACE_PRIVATE::TFunctionSelect::Type; + using Super = NAMESPACE_PRIVATE::TFunctionImpl< + typename NAMESPACE_PRIVATE::TFunctionInfo::Fn, + typename NAMESPACE_PRIVATE::TFunctionInfo::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 requires (!TIsTFunctionRef::Type>::Value) && (!TIsTInPlaceType::Type>::Value) + && NAMESPACE_PRIVATE::TIsInvocableSignature::Type>::Value + FORCEINLINE TFunctionRef(T&& InValue) + { + using DecayedType = typename TDecay::Type; + checkf(NAMESPACE_PRIVATE::FunctionIsBound(InValue), TEXT("Cannot bind a null/unbound callable to a TFunctionRef")); + Super::template EmplaceImpl(Forward(InValue)); + } + + template + TFunctionRef(const T&&) = delete; + +}; template -using TFunction = typename NAMESPACE_PRIVATE::TFunctionSelect::Type; + requires TIsFunction::Value && (Memory::IsValidAlignment(InlineAlignment)) +struct TFunction + : public NAMESPACE_PRIVATE::TFunctionImpl< + typename NAMESPACE_PRIVATE::TFunctionInfo::Fn, + typename NAMESPACE_PRIVATE::TFunctionInfo::CVRef, + InlineSize, + InlineAlignment, + false> +{ +private: + + using Super = NAMESPACE_PRIVATE::TFunctionImpl< + typename NAMESPACE_PRIVATE::TFunctionInfo::Fn, + typename NAMESPACE_PRIVATE::TFunctionInfo::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 requires (!TIsTInPlaceType::Type>::Value) + && (!TIsTFunctionRef::Type>::Value) && (!TIsTFunction::Type>::Value) && (!TIsTUniqueFunction::Type>::Value) + && TIsConstructible::Type, T&&>::Value && TIsCopyConstructible::Type>::Value + && NAMESPACE_PRIVATE::TIsInvocableSignature::Type>::Value + FORCEINLINE TFunction(T&& InValue) + { + using DecayedType = typename TDecay::Type; + if (!NAMESPACE_PRIVATE::FunctionIsBound(InValue)) Super::ResetImpl(); + else Super::template EmplaceImpl(Forward(InValue)); + } + + template requires NAMESPACE_PRIVATE::TIsInvocableSignature::Type>::Value + && TIsConstructible::Type, ArgTypes...>::Value && TIsCopyConstructible::Type>::Value + FORCEINLINE TFunction(TInPlaceType, ArgTypes&&... Args) + { + using DecayedType = typename TDecay::Type; + Super::template EmplaceImpl(Forward(Args)...); + } + + constexpr TFunction& operator=(nullptr_t) { Super::ResetImpl(); return *this; } + + template requires NAMESPACE_PRIVATE::TIsInvocableSignature::Type>::Value + && (!TIsTFunctionRef::Type>::Value) && (!TIsTFunction::Type>::Value) && (!TIsTUniqueFunction::Type>::Value) + && TIsConstructible::Type, T&&>::Value && TIsCopyConstructible::Type>::Value + FORCEINLINE TFunction& operator=(T&& InValue) + { + using DecayedType = typename TDecay::Type; + + if (!NAMESPACE_PRIVATE::FunctionIsBound(InValue)) Super::ResetImpl(); + else Super::template EmplaceImpl(Forward(InValue)); + + return *this; + } + + template requires NAMESPACE_PRIVATE::TIsInvocableSignature::Type>::Value + && TIsConstructible::Type, ArgTypes...>::Value&& TIsCopyConstructible::Type>::Value + FORCEINLINE typename TDecay::Type& Emplace(ArgTypes&&... Args) + { + using DecayedType = typename TDecay::Type; + Super::template EmplaceImpl(Forward(Args)...); + return Super::template Target(); + } + + constexpr void Reset() { Super::ResetImpl(); } + +}; template -using TUniqueFunction = typename NAMESPACE_PRIVATE::TFunctionSelect::Type; + requires TIsFunction::Value && (Memory::IsValidAlignment(InlineAlignment)) +struct TUniqueFunction + : public NAMESPACE_PRIVATE::TFunctionImpl< + typename NAMESPACE_PRIVATE::TFunctionInfo::Fn, + typename NAMESPACE_PRIVATE::TFunctionInfo::CVRef, + InlineSize, + InlineAlignment, + false> +{ +private: -template struct TIsTFunctionRef : NAMESPACE_PRIVATE::TIsTFunctionRef { }; -template struct TIsTFunction : NAMESPACE_PRIVATE::TIsTFunction { }; -template struct TIsTUniqueFunction : NAMESPACE_PRIVATE::TIsTUniqueFunction { }; + using Super = NAMESPACE_PRIVATE::TFunctionImpl< + typename NAMESPACE_PRIVATE::TFunctionInfo::Fn, + typename NAMESPACE_PRIVATE::TFunctionInfo::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& InValue) + : Super(*reinterpret_cast(&InValue)) + { } + + FORCEINLINE TUniqueFunction(TFunction&& InValue) + : Super(MoveTemp(*reinterpret_cast(&InValue))) + { + InValue.Reset(); + } + + FORCEINLINE TUniqueFunction& operator=(const TFunction& InValue) + { + Super::AssignImpl(*reinterpret_cast(&InValue)); + return *this; + } + + FORCEINLINE TUniqueFunction& operator=(TFunction&& InValue) + { + Super::AssignImpl(MoveTemp(*reinterpret_cast(&InValue))); + return *this; + } + + template requires (!TIsTInPlaceType::Type>::Value) + && (!TIsTFunctionRef::Type>::Value) && (!TIsTFunction::Type>::Value) && (!TIsTUniqueFunction::Type>::Value) + && TIsConstructible::Type, T&&>::Value && TIsMoveConstructible::Type>::Value + && NAMESPACE_PRIVATE::TIsInvocableSignature::Type>::Value + FORCEINLINE TUniqueFunction(T&& InValue) + { + using DecayedType = typename TDecay::Type; + if (!NAMESPACE_PRIVATE::FunctionIsBound(InValue)) Super::ResetImpl(); + else Super::template EmplaceImpl(Forward(InValue)); + } + + template requires NAMESPACE_PRIVATE::TIsInvocableSignature::Type>::Value + && TIsConstructible::Type, ArgTypes...>::Value && TIsMoveConstructible::Type>::Value + FORCEINLINE TUniqueFunction(TInPlaceType, ArgTypes&&... Args) + { + using DecayedType = typename TDecay::Type; + Super::template EmplaceImpl(Forward(Args)...); + } + + constexpr TUniqueFunction& operator=(nullptr_t) { Super::ResetImpl(); return *this; } + + template requires NAMESPACE_PRIVATE::TIsInvocableSignature::Type>::Value + && (!TIsTFunctionRef::Type>::Value) && (!TIsTFunction::Type>::Value) && (!TIsTUniqueFunction::Type>::Value) + && TIsConstructible::Type, T&&>::Value&& TIsMoveConstructible::Type>::Value + FORCEINLINE TUniqueFunction& operator=(T&& InValue) + { + using DecayedType = typename TDecay::Type; + + if (!NAMESPACE_PRIVATE::FunctionIsBound(InValue)) Super::ResetImpl(); + else Super::template EmplaceImpl(Forward(InValue)); + + return *this; + } + + template requires NAMESPACE_PRIVATE::TIsInvocableSignature::Type>::Value + && TIsConstructible::Type, ArgTypes...>::Value&& TIsMoveConstructible::Type>::Value + FORCEINLINE typename TDecay::Type& Emplace(ArgTypes&&... Args) + { + using DecayedType = typename TDecay::Type; + Super::template EmplaceImpl(Forward(Args)...); + return Super::template Target(); + } + + constexpr void Reset() { Super::ResetImpl(); } + +}; template constexpr bool operator==(const TFunctionRef& LHS, nullptr_t) @@ -426,51 +468,51 @@ static_assert(sizeof(TUniqueFunction) == 64, "The byte size of TUniqueFu NAMESPACE_PRIVATE_BEGIN template -struct NotFunctionType +struct TNotFunction { - F Func; + F Storage; - NotFunctionType(const NotFunctionType&) = default; - NotFunctionType(NotFunctionType&&) = default; + TNotFunction(const TNotFunction&) = default; + TNotFunction(TNotFunction&&) = default; template - constexpr NotFunctionType(InF&& InFunc) : Func(Forward(InFunc)) { } + constexpr TNotFunction(InF&& InFunc) : Storage(Forward(InFunc)) { } template requires TIsInvocable::Value - constexpr auto operator()(Types&&... Args) & - -> decltype(!Invoke(Func, Forward(Args)...)) + constexpr auto operator()(Types&&... Args) & + -> decltype(!Invoke(Storage, Forward(Args)...)) { - return !Invoke(Func, Forward(Args)...); + return !Invoke(Storage, Forward(Args)...); } template requires TIsInvocable::Value - constexpr auto operator()(Types&&... Args) && - -> decltype(!Invoke(MoveTemp(Func), Forward(Args)...)) + constexpr auto operator()(Types&&... Args) && + -> decltype(!Invoke(MoveTemp(Storage), Forward(Args)...)) { - return !Invoke(MoveTemp(Func), Forward(Args)...); + return !Invoke(MoveTemp(Storage), Forward(Args)...); } template requires TIsInvocable::Value - constexpr auto operator()(Types&&... Args) const& - -> decltype(!Invoke(Func, Forward(Args)...)) + constexpr auto operator()(Types&&... Args) const& + -> decltype(!Invoke(Storage, Forward(Args)...)) { - return !Invoke(Func, Forward(Args)...); + return !Invoke(Storage, Forward(Args)...); } template requires TIsInvocable::Value - constexpr auto operator()(Types&&... Args) const&& - -> decltype(!Invoke(MoveTemp(Func), Forward(Args)...)) + constexpr auto operator()(Types&&... Args) const&& + -> decltype(!Invoke(MoveTemp(Storage), Forward(Args)...)) { - return !Invoke(MoveTemp(Func), Forward(Args)...); + return !Invoke(MoveTemp(Storage), Forward(Args)...); } }; NAMESPACE_PRIVATE_END template -constexpr NAMESPACE_PRIVATE::NotFunctionType::Type> NotFn(F&& Func) +constexpr NAMESPACE_PRIVATE::TNotFunction::Type> NotFn(F&& Func) { - return NAMESPACE_PRIVATE::NotFunctionType::Type>(Forward(Func)); + return NAMESPACE_PRIVATE::TNotFunction::Type>(Forward(Func)); } NAMESPACE_MODULE_END(Utility)