#pragma once #include "CoreTypes.h" #include "Memory/Memory.h" #include "Concepts/Same.h" #include "Templates/Any.h" #include "Templates/Tuple.h" #include "Templates/Invoke.h" #include "Templates/Utility.h" #include "Templates/Container.h" #include "Concepts/Comparable.h" #include "Concepts/Convertible.h" #include "TypeTraits/TypeTraits.h" #include "Miscellaneous/TypeInfo.h" #include "Concepts/BooleanTestable.h" #include "Miscellaneous/AssertionMacros.h" NAMESPACE_REDCRAFT_BEGIN NAMESPACE_MODULE_BEGIN(Redcraft) NAMESPACE_MODULE_BEGIN(Utility) NAMESPACE_PRIVATE_BEGIN enum class EFunctionType { Reference, Object, Unique, }; enum class EFunctionSpecifiers { None, LValue, RValue, Const, ConstLValue, ConstRValue, }; template 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 FFunctionIsBoundImpl { template static constexpr bool F(const T& Func) { if constexpr (TIsPointer::Value || TIsMemberPointer::Value || TIsTFunctionImpl::Value) { return !!Func; } else { return true; } } }; template struct TIsInvocableResultWithSpecifiers : FFalse { }; template struct TIsInvocableResultWithSpecifiers : TBoolConstant::Value && TIsInvocableResult::Value> { }; template struct TIsInvocableResultWithSpecifiers : TIsInvocableResult { }; template struct TIsInvocableResultWithSpecifiers : TIsInvocableResult { }; template struct TIsInvocableResultWithSpecifiers : TBoolConstant::Value && TIsInvocableResult::Value> { }; template struct TIsInvocableResultWithSpecifiers : TIsInvocableResult { }; template struct TIsInvocableResultWithSpecifiers : TIsInvocableResult { }; template struct TFunctionCallImpl; template struct TFunctionCallImpl { static inline R F(void* Func, Types&&... Args) { return InvokeResult(*reinterpret_cast(Func), Forward(Args)...); } }; template struct TFunctionCallImpl { static inline R F(void* Func, Types&&... Args) { return InvokeResult(*reinterpret_cast(Func), Forward(Args)...); } }; template struct TFunctionCallImpl { static inline R F(void* Func, Types&&... Args) { return InvokeResult(MoveTemp(*reinterpret_cast(Func)), Forward(Args)...); } }; template struct TFunctionCallImpl { static inline R F(void* Func, Types&&... Args) { return InvokeResult(AsConst(*reinterpret_cast(Func)), Forward(Args)...); } }; template struct TFunctionCallImpl { static inline R F(void* Func, Types&&... Args) { return InvokeResult(AsConst(*reinterpret_cast(Func)), Forward(Args)...); } }; template struct TFunctionCallImpl { static inline R F(void* Func, Types&&... Args) { return InvokeResult(MoveTemp(AsConst(*reinterpret_cast(Func))), Forward(Args)...); } }; template struct TFunctionImpl { public: using ResultType = R; using ArgumentType = TTuple; constexpr TFunctionImpl(nullptr_t = nullptr) requires (FunctionType != EFunctionType::Reference) : Call(nullptr) { } TFunctionImpl(const TFunctionImpl& InValue) requires (FunctionType != EFunctionType::Unique) : Call(InValue.Call), Storage(InValue.Storage) { } TFunctionImpl(TFunctionImpl&& InValue) : Call(InValue.Call), 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 DecayedFunctorType = typename TDecay::Type; if constexpr (FunctionType == EFunctionType::Reference) { checkf(FFunctionIsBoundImpl::F(InValue), TEXT("Cannot bind a null/unbound callable to a TFunctionRef")); } if (!FFunctionIsBoundImpl::F(InValue)) Call = 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 DecayedFunctorType = typename TDecay::Type; EmplaceImpl(Forward(Args)...); } template requires (FunctionType == EFunctionType::Reference) && (OtherFunctionType != EFunctionType::Reference) FORCEINLINE TFunctionImpl(const TFunctionImpl& InValue) { checkf(FFunctionIsBoundImpl::F(InValue), TEXT("Cannot bind a null/unbound callable to a TFunctionRef")); EmplaceImpl>(InValue); } FORCEINLINE TFunctionImpl(const TFunctionImpl& InValue) requires (FunctionType == EFunctionType::Unique) : Call((*reinterpret_cast(&InValue)).Call), Storage((*reinterpret_cast(&InValue)).Storage) { } FORCEINLINE TFunctionImpl(TFunctionImpl&& InValue) requires (FunctionType == EFunctionType::Unique) : Call((*reinterpret_cast(&InValue)).Call), Storage(MoveTemp((*reinterpret_cast(&InValue)).Storage)) { InValue.Reset(); } ~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 DecayedFunctorType = typename TDecay::Type; if (!FFunctionIsBoundImpl::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 DecayedFunctorType = 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)...); } constexpr bool IsValid() const { return Call != nullptr; } constexpr explicit operator bool() const { return Call != nullptr; } FORCEINLINE void* GetData() { if constexpr (FunctionType != EFunctionType::Reference) return Storage.GetData(); else return Storage; } FORCEINLINE const void* GetData() const { if constexpr (FunctionType != EFunctionType::Reference) return Storage.GetData(); else return Storage; } FORCEINLINE const FTypeInfo& TargetType() const requires (FunctionType != EFunctionType::Reference) { 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(); } constexpr void Reset() requires (FunctionType != EFunctionType::Reference) { Call = nullptr; } constexpr void Swap(TFunctionImpl& InValue) requires (FunctionType != EFunctionType::Reference) { if (!IsValid() && !InValue.IsValid()) return; if (IsValid() && !InValue.IsValid()) { InValue = MoveTemp(*this); Reset(); return; } if (InValue.IsValid() && !IsValid()) { *this = MoveTemp(InValue); InValue.Reset(); return; } NAMESPACE_REDCRAFT::Swap(Call, InValue.Call); NAMESPACE_REDCRAFT::Swap(Storage, InValue.Storage); } private: using CallFunc = ResultType(*)(void*, Types&&...); using StorageType = typename TConditional>::Type; CallFunc Call; StorageType Storage; template FORCEINLINE void EmplaceImpl(ArgTypes&&... Args) { if constexpr (FunctionType == EFunctionType::Reference) Storage = ((void*)&Args, ...); else Storage.template Emplace(Forward(Args)...); Call = &TFunctionCallImpl::F; } FORCEINLINE ResultType CallImpl(Types&&... Args) const { checkf(IsValid(), TEXT("Attempting to call an unbound TFunction!")); return Call(const_cast(*this).GetData(), Forward(Args)...); } FORCEINLINE void AssignImpl(const TFunctionImpl& InValue) { if (InValue.IsValid()) { Call = InValue.Call; Storage = InValue.Storage; } else Reset(); } FORCEINLINE void AssignImpl(TFunctionImpl&& InValue) { if (InValue.IsValid()) { Call = InValue.Call; Storage = MoveTemp(InValue.Storage); InValue.Reset(); } else Reset(); } }; 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 = 32; inline constexpr size_t FUNCTION_DEFAULT_INLINE_ALIGNMENT = 16; template using TFunctionRef = typename NAMESPACE_PRIVATE::TFunctionSelect::Type; template using TFunction = typename NAMESPACE_PRIVATE::TFunctionSelect::Type; template using TUniqueFunction = typename NAMESPACE_PRIVATE::TFunctionSelect::Type; template struct TIsTFunctionRef : NAMESPACE_PRIVATE::TIsTFunctionRef { }; template struct TIsTFunction : NAMESPACE_PRIVATE::TIsTFunction { }; template struct TIsTUniqueFunction : NAMESPACE_PRIVATE::TIsTUniqueFunction { }; template constexpr bool operator==(const TFunctionRef& LHS, nullptr_t) { return !LHS; } template constexpr bool operator==(const TFunction& LHS, nullptr_t) { return !LHS; } template constexpr bool operator==(const TUniqueFunction& LHS, nullptr_t) { return !LHS; } static_assert(sizeof(TFunctionRef) == 16, "The byte size of TFunctionRef is unexpected"); static_assert(sizeof(TFunction) == 64, "The byte size of TFunction is unexpected"); static_assert(sizeof(TUniqueFunction) == 64, "The byte size of TUniqueFunction is unexpected"); template struct TIdentity { using Type = T; constexpr T&& operator()(T&& InValue) const { return Forward(InValue); } }; template <> struct TIdentity { using Type = void; template constexpr T&& operator()(T&& InValue) const { return Forward(InValue); } }; NAMESPACE_PRIVATE_BEGIN template struct NotFunctionType { F Func; NotFunctionType(const NotFunctionType&) = default; NotFunctionType(NotFunctionType&&) = default; template constexpr NotFunctionType(InF&& InFunc) : Func(Forward(InFunc)) { } template requires TIsInvocable::Value constexpr auto operator()(Types&&... Args) & -> decltype(!Invoke(Func, Forward(Args)...)) { return !Invoke(Func, Forward(Args)...); } template requires TIsInvocable::Value constexpr auto operator()(Types&&... Args) && -> decltype(!Invoke(MoveTemp(Func), Forward(Args)...)) { return !Invoke(MoveTemp(Func), Forward(Args)...); } template requires TIsInvocable::Value constexpr auto operator()(Types&&... Args) const& -> decltype(!Invoke(Func, Forward(Args)...)) { return !Invoke(Func, Forward(Args)...); } template requires TIsInvocable::Value constexpr auto operator()(Types&&... Args) const&& -> decltype(!Invoke(MoveTemp(Func), Forward(Args)...)) { return !Invoke(MoveTemp(Func), Forward(Args)...); } }; NAMESPACE_PRIVATE_END template constexpr NAMESPACE_PRIVATE::NotFunctionType::Type> NotFn(F&& Func) { return NAMESPACE_PRIVATE::NotFunctionType::Type>(Forward(Func)); } #define FUNCTOR_UNARY_OPERATOR_IMPL(Name, Operator, ConceptT, ConceptU) \ template requires (CSameAs || ConceptT) \ struct Name \ { \ constexpr auto operator()(const T& InValue) const \ -> decltype(Operator InValue) \ { \ return Operator InValue; \ } \ }; \ \ template <> \ struct Name \ { \ template requires ConceptU \ constexpr auto operator()(U&& InValue) const \ -> decltype(Operator Forward(InValue)) \ { \ return Operator Forward(InValue); \ } \ } #define FUNCTOR_BINARY_OPERATOR_IMPL(Name, Operator, ConceptT, ConceptTU) \ template requires (CSameAs || ConceptT) \ struct Name \ { \ constexpr auto operator()(const T& LHS, const T& RHS) const \ -> decltype(LHS Operator RHS) \ { \ return LHS Operator RHS; \ } \ }; \ \ template <> \ struct Name \ { \ template requires ConceptTU \ constexpr auto operator()(T&& LHS, U&& RHS) const \ -> decltype(Forward(LHS) Operator Forward(RHS)) \ { \ return Forward(LHS) Operator Forward(RHS); \ } \ } #define FUNCTOR_UNARY_OPERATOR_A_IMPL(Name, Operator) \ FUNCTOR_UNARY_OPERATOR_IMPL \ ( \ Name, Operator, \ (requires(const T& InValue) { { Operator InValue } -> CConvertibleTo; }), \ (requires(U&& InValue) { Operator Forward(InValue); }) \ ) #define FUNCTOR_BINARY_OPERATOR_A_IMPL(Name, Operator) \ FUNCTOR_BINARY_OPERATOR_IMPL \ ( \ Name, Operator, \ (requires(const T& LHS, const T& RHS) { { LHS Operator RHS } -> CConvertibleTo; }), \ (requires(T&& LHS, U&& RHS) { Forward(LHS) Operator Forward(RHS); }) \ ) #define FUNCTOR_UNARY_OPERATOR_B_IMPL(Name, Operator) \ FUNCTOR_UNARY_OPERATOR_IMPL \ ( \ Name, Operator, \ (requires(const T& InValue) { { Operator InValue } -> CBooleanTestable; }), \ (requires(U&& InValue) { { Operator Forward(InValue) } -> CBooleanTestable; }) \ ) #define FUNCTOR_BINARY_OPERATOR_B_IMPL(Name, Operator) \ FUNCTOR_BINARY_OPERATOR_IMPL \ ( \ Name, Operator, \ (requires(const T& LHS, const T& RHS) { { LHS Operator RHS } -> CBooleanTestable; }), \ (requires(T&& LHS, U&& RHS) { { Forward(LHS) Operator Forward(RHS) } -> CBooleanTestable; }) \ ) #define FUNCTOR_BINARY_OPERATOR_C_IMPL(Name, Operator) \ FUNCTOR_BINARY_OPERATOR_IMPL \ ( \ Name, Operator, \ (CEqualityComparable), \ (CEqualityComparableWith) \ ) #define FUNCTOR_BINARY_OPERATOR_D_IMPL(Name, Operator) \ FUNCTOR_BINARY_OPERATOR_IMPL \ ( \ Name, Operator, \ (CTotallyOrdered), \ (CTotallyOrderedWith) \ ) FUNCTOR_UNARY_OPERATOR_A_IMPL (TPromote, +); FUNCTOR_UNARY_OPERATOR_A_IMPL (TNegate, -); FUNCTOR_BINARY_OPERATOR_A_IMPL(TPlus, +); FUNCTOR_BINARY_OPERATOR_A_IMPL(TMinus, -); FUNCTOR_BINARY_OPERATOR_A_IMPL(TMultiplies, *); FUNCTOR_BINARY_OPERATOR_A_IMPL(TDivides, /); FUNCTOR_BINARY_OPERATOR_A_IMPL(TModulus, %); FUNCTOR_UNARY_OPERATOR_A_IMPL (TBitNot, ~ ); FUNCTOR_BINARY_OPERATOR_A_IMPL(TBitAnd, & ); FUNCTOR_BINARY_OPERATOR_A_IMPL(TBitOr, | ); FUNCTOR_BINARY_OPERATOR_A_IMPL(TBitXor, ^ ); FUNCTOR_BINARY_OPERATOR_A_IMPL(TBitLsh, <<); FUNCTOR_BINARY_OPERATOR_A_IMPL(TBitRsh, >>); FUNCTOR_BINARY_OPERATOR_B_IMPL(TLogicalAnd, &&); FUNCTOR_BINARY_OPERATOR_B_IMPL(TLogicalOr, ||); FUNCTOR_UNARY_OPERATOR_B_IMPL (TLogicalNot, ! ); FUNCTOR_BINARY_OPERATOR_C_IMPL(TEqualTo, ==); FUNCTOR_BINARY_OPERATOR_C_IMPL(TNotEqualTo, !=); FUNCTOR_BINARY_OPERATOR_D_IMPL(TGreater, > ); FUNCTOR_BINARY_OPERATOR_D_IMPL(TLess, < ); FUNCTOR_BINARY_OPERATOR_D_IMPL(TGreaterEqual, >=); FUNCTOR_BINARY_OPERATOR_D_IMPL(TLessEqual, <=); #undef FUNCTOR_BINARY_OPERATOR_D_IMPL #undef FUNCTOR_BINARY_OPERATOR_C_IMPL #undef FUNCTOR_BINARY_OPERATOR_B_IMPL #undef FUNCTOR_UNARY_OPERATOR_B_IMPL #undef FUNCTOR_BINARY_OPERATOR_A_IMPL #undef FUNCTOR_UNARY_OPERATOR_A_IMPL #undef FUNCTOR_BINARY_OPERATOR_IMPL #undef FUNCTOR_UNARY_OPERATOR_IMPL NAMESPACE_MODULE_END(Utility) NAMESPACE_MODULE_END(Redcraft) NAMESPACE_REDCRAFT_END