diff --git a/Redcraft.Utility/Source/Private/Testing/ConceptsTesting.cpp b/Redcraft.Utility/Source/Private/Testing/ConceptsTesting.cpp index 3f8ce40..ac575e1 100644 --- a/Redcraft.Utility/Source/Private/Testing/ConceptsTesting.cpp +++ b/Redcraft.Utility/Source/Private/Testing/ConceptsTesting.cpp @@ -183,6 +183,15 @@ void TestConcepts() always_check((CSwappableWith)); + // Invocable.h + + always_check((CInvocable void { }) >)); + always_check((CRegularInvocable int32 { return A; }), int32 >)); + always_check((CPredicate bool { return (A + B + C) == 0; }), int32, int32, int32 >)); + always_check((CRelation bool { return (A ^ B) == 0; }), int32, int32 >)); + always_check((CEquivalenceRelation bool { return A == B; }), int32, int32 >)); + always_check((CStrictWeakOrder bool { return A < B; }), int32, int32 >)); + } NAMESPACE_MODULE_END(Utility) diff --git a/Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp b/Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp new file mode 100644 index 0000000..bf14baf --- /dev/null +++ b/Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp @@ -0,0 +1,49 @@ +#include "Testing/TemplatesTesting.h" +#include "Misc/AssertionMacros.h" +#include "Templates/Templates.h" + +NAMESPACE_REDCRAFT_BEGIN +NAMESPACE_MODULE_BEGIN(Redcraft) +NAMESPACE_MODULE_BEGIN(Utility) + +void TestTemplates() +{ + TestInvoke(); +} + +NAMESPACE_UNNAMED_BEGIN + +int32 TestFunctionA(int32 A, int32 B, int32 C) +{ + return A + B + C; +} + +struct FTestStructA +{ + int32 Num; + FTestStructA(int32 InNum) : Num(InNum) { } + int32 Add(int32 A) const { return Num + A; } +}; + +NAMESPACE_UNNAMED_END + +void TestInvoke() +{ + Invoke([=]() { }); + FTestStructA TempA(123); + always_check(Invoke(TestFunctionA, 1, 2, 3) == 6); + always_check(Invoke(&FTestStructA::Add, TempA, 1) == 124); + always_check(Invoke(&FTestStructA::Add, &TempA, 1) == 124); + int32 TempB = Invoke(&FTestStructA::Num, &TempA); + int32 TempC = Invoke(&FTestStructA::Num, TempA); + always_check(TempB == 123); + always_check(TempC == 123); + int64 TempD = InvokeResult(&FTestStructA::Num, &TempA); + int64 TempE = InvokeResult(&FTestStructA::Num, TempA); + always_check(TempD == 123); + always_check(TempE == 123); +} + +NAMESPACE_MODULE_END(Utility) +NAMESPACE_MODULE_END(Redcraft) +NAMESPACE_REDCRAFT_END diff --git a/Redcraft.Utility/Source/Private/Testing/TypeTraitsTesting.cpp b/Redcraft.Utility/Source/Private/Testing/TypeTraitsTesting.cpp index 06dac7f..ba5fd83 100644 --- a/Redcraft.Utility/Source/Private/Testing/TypeTraitsTesting.cpp +++ b/Redcraft.Utility/Source/Private/Testing/TypeTraitsTesting.cpp @@ -313,11 +313,16 @@ void TestTypeTraits() always_check(!(TIsConvertible::Value)); always_check((TIsConvertible::Value)); - always_check((TIsInvocable::Value)); - always_check((TIsInvocable::Value)); - always_check((TIsInvocable::Value)); - always_check(!(TIsInvocable::Value)); - always_check(!(TIsInvocable::Value)); + always_check((TIsInvocable::Value)); + always_check((TIsInvocable::Value)); + always_check(!(TIsInvocable::Value)); + always_check((TIsInvocable::Value)); + + always_check((TIsInvocableResult::Value)); + always_check((TIsInvocableResult::Value)); + always_check((TIsInvocableResult::Value)); + always_check(!(TIsInvocableResult::Value)); + always_check(!(TIsInvocableResult::Value)); always_check((TIsSame::Type>::Value)); always_check(!(TIsSame::Type>::Value)); diff --git a/Redcraft.Utility/Source/Public/Concepts/Concepts.h b/Redcraft.Utility/Source/Public/Concepts/Concepts.h index 57c389f..2a28385 100644 --- a/Redcraft.Utility/Source/Public/Concepts/Concepts.h +++ b/Redcraft.Utility/Source/Public/Concepts/Concepts.h @@ -4,6 +4,7 @@ #include "Concepts/Same.h" #include "Concepts/Derived.h" #include "Concepts/Objects.h" +#include "Concepts/Invocable.h" #include "Concepts/Swappable.h" #include "Concepts/Assignable.h" #include "Concepts/Comparable.h" @@ -12,10 +13,3 @@ #include "Concepts/Destructible.h" #include "Concepts/Constructible.h" #include "Concepts/BooleanTestable.h" - -//template concept CInvocable; // Prerequisites: Invoke, Forward -//template concept CRegularInvocable; // Prerequisites: Invoke, Forward -//template concept CPredicate; // Prerequisites: CBooleanTestable, CRegularInvocable -//template concept CRelation; // Prerequisites: CPredicate -//template concept CEquivalenceRelation // Prerequisites: CRelation -//template concept CStrictWeakOrder // Prerequisites: CRelation diff --git a/Redcraft.Utility/Source/Public/Concepts/Invocable.h b/Redcraft.Utility/Source/Public/Concepts/Invocable.h new file mode 100644 index 0000000..8300ff1 --- /dev/null +++ b/Redcraft.Utility/Source/Public/Concepts/Invocable.h @@ -0,0 +1,32 @@ +#pragma once + +#include "CoreTypes.h" +#include "TypeTraits/TypeTraits.h" + +NAMESPACE_REDCRAFT_BEGIN +NAMESPACE_MODULE_BEGIN(Redcraft) +NAMESPACE_MODULE_BEGIN(Utility) + +template +concept CInvocable = requires(F&& Func, Types&&... Args) { Invoke(Forward(Func), Forward(Args)...); }; + +template +concept CRegularInvocable = CInvocable; + +template +concept CPredicate = CRegularInvocable && CBooleanTestable::Type>; + +template +concept CRelation = + CPredicate && CPredicate && + CPredicate && CPredicate; + +template +concept CEquivalenceRelation = CRelation; + +template +concept CStrictWeakOrder = CRelation; + +NAMESPACE_MODULE_END(Utility) +NAMESPACE_MODULE_END(Redcraft) +NAMESPACE_REDCRAFT_END diff --git a/Redcraft.Utility/Source/Public/Templates/Invoke.h b/Redcraft.Utility/Source/Public/Templates/Invoke.h new file mode 100644 index 0000000..9b2eeb6 --- /dev/null +++ b/Redcraft.Utility/Source/Public/Templates/Invoke.h @@ -0,0 +1,98 @@ +#pragma once + +#include "CoreTypes.h" +#include "TypeTraits/Miscellaneous.h" + + +NAMESPACE_REDCRAFT_BEGIN +NAMESPACE_MODULE_BEGIN(Redcraft) +NAMESPACE_MODULE_BEGIN(Utility) + +NAMESPACE_PRIVATE_BEGIN + +struct InvokeFunction +{ + template + static auto Invoke(F&& Object, Types&&... Args) + { + return Object(Forward(Args)...); + } +}; + +struct InvokeMemberFunction +{ + template + static auto Invoke(F&& Func, ObjectType&& Object, Types&&... Args) -> + decltype((Object->*Func)(Forward(Args)...)) + { + return (Object->*Func)(Forward(Args)...); + } + + template + static auto Invoke(F&& Func, ObjectType&& Object, Types&&... Args) -> + decltype((Object.*Func)(Forward(Args)...)) + { + return (Object.*Func)(Forward(Args)...); + } +}; + +struct InvokeMemberObject +{ + template + static auto Invoke(F&& Func, ObjectType&& Object) -> + decltype(Object->*Func) + { + return (Object->*Func); + } + + template + static auto Invoke(F&& Func, ObjectType&& Object) -> + decltype(Object.*Func) + { + return (Object.*Func); + } +}; + +template ::Type, + bool IsMemberFunction = TIsMemberFunctionPointer::Value, + bool IsMemberObject = TIsMemberObjectPointer::Value> + struct InvokeMember; + +template +struct InvokeMember : InvokeMemberFunction { }; + +template +struct InvokeMember : InvokeMemberObject { }; + +template +struct InvokeMember : InvokeFunction { }; + +template +struct InvokeImpl; + +template +struct InvokeImpl : InvokeFunction { }; + +template +struct InvokeImpl : InvokeMember { }; + +NAMESPACE_PRIVATE_END + +template requires TIsInvocable::Value +constexpr auto Invoke(F&& Func, Types&&... Args) +{ + return NAMESPACE_PRIVATE::InvokeImpl::Invoke(Forward(Func), Forward(Args)...); +} + +template requires TIsInvocableResult::Value +constexpr R InvokeResult(F&& Func, Types&&... Args) +{ + if constexpr (TIsVoid::Value) Invoke(Forward(Func), Forward(Args)...); + else return Invoke(Forward(Func), Forward(Args)...); +} + +NAMESPACE_MODULE_END(Utility) +NAMESPACE_MODULE_END(Redcraft) +NAMESPACE_REDCRAFT_END diff --git a/Redcraft.Utility/Source/Public/Templates/Templates.h b/Redcraft.Utility/Source/Public/Templates/Templates.h index f1e8c87..8326b94 100644 --- a/Redcraft.Utility/Source/Public/Templates/Templates.h +++ b/Redcraft.Utility/Source/Public/Templates/Templates.h @@ -4,3 +4,4 @@ #include "Templates/Utility.h" #include "Templates/Container.h" #include "Templates/Noncopyable.h" +#include "Templates/Invoke.h" diff --git a/Redcraft.Utility/Source/Public/Testing/TemplatesTesting.h b/Redcraft.Utility/Source/Public/Testing/TemplatesTesting.h new file mode 100644 index 0000000..025f903 --- /dev/null +++ b/Redcraft.Utility/Source/Public/Testing/TemplatesTesting.h @@ -0,0 +1,14 @@ +#pragma once + +#include "CoreTypes.h" + +NAMESPACE_REDCRAFT_BEGIN +NAMESPACE_MODULE_BEGIN(Redcraft) +NAMESPACE_MODULE_BEGIN(Utility) + +void REDCRAFTUTILITY_API TestTemplates(); +void REDCRAFTUTILITY_API TestInvoke(); + +NAMESPACE_MODULE_END(Utility) +NAMESPACE_MODULE_END(Redcraft) +NAMESPACE_REDCRAFT_END diff --git a/Redcraft.Utility/Source/Public/TypeTraits/Miscellaneous.h b/Redcraft.Utility/Source/Public/TypeTraits/Miscellaneous.h index 32b64b8..f99f78f 100644 --- a/Redcraft.Utility/Source/Public/TypeTraits/Miscellaneous.h +++ b/Redcraft.Utility/Source/Public/TypeTraits/Miscellaneous.h @@ -28,10 +28,11 @@ NAMESPACE_PRIVATE_END template struct TRank : TConstant> { }; template struct TExtent : TConstant> { }; -template struct TIsSame : TBoolConstant> { }; -template struct TIsBaseOf : TBoolConstant> { }; -template struct TIsConvertible : TBoolConstant> { }; -template struct TIsInvocable : TBoolConstant> { }; +template struct TIsSame : TBoolConstant> { }; +template struct TIsBaseOf : TBoolConstant> { }; +template struct TIsConvertible : TBoolConstant> { }; +template struct TIsInvocable : TBoolConstant> { }; +template struct TIsInvocableResult : TBoolConstant> { }; // FIXME: The result for char(&())[2] is wrong on MSVC template struct TRemoveConst { using Type = NAMESPACE_STD::remove_const_t; }; template struct TRemoveVolatile { using Type = NAMESPACE_STD::remove_volatile_t; };