feat(templates): add Invoke function and corresponding peripheral tools
This commit is contained in:
		| @@ -183,6 +183,15 @@ void TestConcepts() | ||||
|  | ||||
| 	always_check((CSwappableWith<int32&, int32&>)); | ||||
|  | ||||
| 	// Invocable.h | ||||
|  | ||||
| 	always_check((CInvocable          <decltype([](                         ) -> void  {                          })                      >)); | ||||
| 	always_check((CRegularInvocable   <decltype([](int32 A                  ) -> int32 { return A;                }), int32               >)); | ||||
| 	always_check((CPredicate          <decltype([](int32 A, int32 B, int32 C) -> bool  { return (A + B + C) == 0; }), int32, int32, int32 >)); | ||||
| 	always_check((CRelation           <decltype([](int32 A, int32 B         ) -> bool  { return (A ^ B) == 0;     }), int32, int32        >)); | ||||
| 	always_check((CEquivalenceRelation<decltype([](int32 A, int32 B         ) -> bool  { return A == B;           }), int32, int32        >)); | ||||
| 	always_check((CStrictWeakOrder    <decltype([](int32 A, int32 B         ) -> bool  { return A < B;            }), int32, int32        >)); | ||||
|  | ||||
| } | ||||
|  | ||||
| NAMESPACE_MODULE_END(Utility) | ||||
|   | ||||
							
								
								
									
										49
									
								
								Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								Redcraft.Utility/Source/Private/Testing/TemplatesTesting.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -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<int64>(&FTestStructA::Num, &TempA); | ||||
| 	int64 TempE = InvokeResult<int64>(&FTestStructA::Num, TempA); | ||||
| 	always_check(TempD == 123); | ||||
| 	always_check(TempE == 123); | ||||
| } | ||||
|  | ||||
| NAMESPACE_MODULE_END(Utility) | ||||
| NAMESPACE_MODULE_END(Redcraft) | ||||
| NAMESPACE_REDCRAFT_END | ||||
| @@ -313,11 +313,16 @@ void TestTypeTraits() | ||||
| 	always_check(!(TIsConvertible<FTestStructE*, FTestStructH*>::Value)); | ||||
| 	always_check((TIsConvertible<FTestStructW, FTestStructV>::Value)); | ||||
|  | ||||
| 	always_check((TIsInvocable<void, int32()>::Value)); | ||||
| 	always_check((TIsInvocable<int32, int32()>::Value)); | ||||
| 	always_check((TIsInvocable<int32, int32(int32), int32>::Value)); | ||||
| 	always_check(!(TIsInvocable<int32, int32(int32), FTestStructA>::Value)); | ||||
| 	always_check(!(TIsInvocable<FTestStructA, int32(int32), int32>::Value)); | ||||
| 	always_check((TIsInvocable<int32()>::Value)); | ||||
| 	always_check((TIsInvocable<int32(int32), int32>::Value)); | ||||
| 	always_check(!(TIsInvocable<int32(int32), FTestStructA>::Value)); | ||||
| 	always_check((TIsInvocable<int32(int32), int32>::Value)); | ||||
|  | ||||
| 	always_check((TIsInvocableResult<void, int32()>::Value)); | ||||
| 	always_check((TIsInvocableResult<int32, int32()>::Value)); | ||||
| 	always_check((TIsInvocableResult<int32, int32(int32), int32>::Value)); | ||||
| 	always_check(!(TIsInvocableResult<int32, int32(int32), FTestStructA>::Value)); | ||||
| 	always_check(!(TIsInvocableResult<FTestStructA, int32(int32), int32>::Value)); | ||||
|  | ||||
| 	always_check((TIsSame<int32, TRemoveConst<int32>::Type>::Value)); | ||||
| 	always_check(!(TIsSame<int32, TRemoveConst<int32*>::Type>::Value)); | ||||
|   | ||||
| @@ -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 <typename F, typename... Args> concept CInvocable;                // Prerequisites: Invoke, Forward | ||||
| //template <typename F, typename... Args> concept CRegularInvocable;         // Prerequisites: Invoke, Forward | ||||
| //template <typename F, typename... Args> concept CPredicate;                // Prerequisites: CBooleanTestable, CRegularInvocable | ||||
| //template <typename F, typename T, typename U> concept CRelation;           // Prerequisites: CPredicate | ||||
| //template <typename F, typename T, typename U> concept CEquivalenceRelation // Prerequisites: CRelation | ||||
| //template <typename F, typename T, typename U> concept CStrictWeakOrder     // Prerequisites: CRelation | ||||
|   | ||||
							
								
								
									
										32
									
								
								Redcraft.Utility/Source/Public/Concepts/Invocable.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								Redcraft.Utility/Source/Public/Concepts/Invocable.h
									
									
									
									
									
										Normal file
									
								
							| @@ -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 <typename F, typename... Types> | ||||
| concept CInvocable = requires(F&& Func, Types&&... Args) { Invoke(Forward<F>(Func), Forward<Types>(Args)...); }; | ||||
|  | ||||
| template <typename F, typename... Types> | ||||
| concept CRegularInvocable = CInvocable<F, Types...>; | ||||
|  | ||||
| template <typename F, typename... Types> | ||||
| concept CPredicate = CRegularInvocable<F, Types...> && CBooleanTestable<typename TInvokeResult<F, Types...>::Type>; | ||||
|  | ||||
| template <typename R, typename T, typename U> | ||||
| concept CRelation = | ||||
| 	CPredicate<R, T, T> && CPredicate<R, U, U> && | ||||
| 	CPredicate<R, T, U> && CPredicate<R, U, T>; | ||||
|  | ||||
| template <typename R, typename T, typename U> | ||||
| concept CEquivalenceRelation = CRelation<R, T, U>; | ||||
|  | ||||
| template <typename R, typename T, typename U> | ||||
| concept CStrictWeakOrder = CRelation<R, T, U>; | ||||
|  | ||||
| NAMESPACE_MODULE_END(Utility) | ||||
| NAMESPACE_MODULE_END(Redcraft) | ||||
| NAMESPACE_REDCRAFT_END | ||||
							
								
								
									
										98
									
								
								Redcraft.Utility/Source/Public/Templates/Invoke.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								Redcraft.Utility/Source/Public/Templates/Invoke.h
									
									
									
									
									
										Normal file
									
								
							| @@ -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 <typename F, typename... Types> | ||||
| 	static auto Invoke(F&& Object, Types&&... Args) | ||||
| 	{ | ||||
| 		return Object(Forward<Types>(Args)...); | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| struct InvokeMemberFunction | ||||
| { | ||||
| 	template <typename F, typename ObjectType, typename... Types> | ||||
| 	static auto Invoke(F&& Func, ObjectType&& Object, Types&&... Args) -> | ||||
| 		decltype((Object->*Func)(Forward<Types>(Args)...)) | ||||
| 	{ | ||||
| 		return (Object->*Func)(Forward<Types>(Args)...); | ||||
| 	} | ||||
|  | ||||
| 	template <typename F, typename ObjectType, typename... Types> | ||||
| 	static auto Invoke(F&& Func, ObjectType&& Object, Types&&... Args) -> | ||||
| 		decltype((Object.*Func)(Forward<Types>(Args)...)) | ||||
| 	{ | ||||
| 		return (Object.*Func)(Forward<Types>(Args)...); | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| struct InvokeMemberObject | ||||
| { | ||||
| 	template <typename F, typename ObjectType> | ||||
| 	static auto Invoke(F&& Func, ObjectType&& Object) -> | ||||
| 		decltype(Object->*Func) | ||||
| 	{ | ||||
| 		return (Object->*Func); | ||||
| 	} | ||||
|  | ||||
| 	template <typename F, typename ObjectType> | ||||
| 	static auto Invoke(F&& Func, ObjectType&& Object) -> | ||||
| 		decltype(Object.*Func) | ||||
| 	{ | ||||
| 		return (Object.*Func); | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| template <typename F, | ||||
| 	typename T, | ||||
| 	typename Decayed = typename TDecay<F>::Type, | ||||
| 	bool IsMemberFunction = TIsMemberFunctionPointer<Decayed>::Value, | ||||
| 	bool IsMemberObject = TIsMemberObjectPointer<Decayed>::Value> | ||||
| 	struct InvokeMember; | ||||
|  | ||||
| template <typename F, typename T, typename Decayed> | ||||
| struct InvokeMember<F, T, Decayed,  true, false> : InvokeMemberFunction { }; | ||||
|  | ||||
| template <typename F, typename T, typename Decayed> | ||||
| struct InvokeMember<F, T, Decayed, false,  true> : InvokeMemberObject { }; | ||||
|  | ||||
| template <typename F, typename T, typename Decayed> | ||||
| struct InvokeMember<F, T, Decayed, false, false> : InvokeFunction { }; | ||||
|  | ||||
| template <typename F, typename... Types> | ||||
| struct InvokeImpl; | ||||
|  | ||||
| template <typename F> | ||||
| struct InvokeImpl<F> : InvokeFunction { }; | ||||
|  | ||||
| template <typename F, typename T, typename... Types> | ||||
| struct InvokeImpl<F, T, Types...> : InvokeMember<F, T> { }; | ||||
|  | ||||
| NAMESPACE_PRIVATE_END | ||||
|  | ||||
| template <typename F, typename... Types> requires TIsInvocable<F, Types...>::Value | ||||
| constexpr auto Invoke(F&& Func, Types&&... Args) | ||||
| { | ||||
| 	return NAMESPACE_PRIVATE::InvokeImpl<F, Types...>::Invoke(Forward<F>(Func), Forward<Types>(Args)...); | ||||
| } | ||||
|  | ||||
| template <typename R, typename F, typename... Types> requires TIsInvocableResult<R, F, Types...>::Value | ||||
| constexpr R InvokeResult(F&& Func, Types&&... Args) | ||||
| { | ||||
| 	if constexpr (TIsVoid<R>::Value) Invoke(Forward<F>(Func), Forward<Types>(Args)...); | ||||
| 	else                      return Invoke(Forward<F>(Func), Forward<Types>(Args)...); | ||||
| } | ||||
|  | ||||
| NAMESPACE_MODULE_END(Utility) | ||||
| NAMESPACE_MODULE_END(Redcraft) | ||||
| NAMESPACE_REDCRAFT_END | ||||
| @@ -4,3 +4,4 @@ | ||||
| #include "Templates/Utility.h" | ||||
| #include "Templates/Container.h" | ||||
| #include "Templates/Noncopyable.h" | ||||
| #include "Templates/Invoke.h" | ||||
|   | ||||
							
								
								
									
										14
									
								
								Redcraft.Utility/Source/Public/Testing/TemplatesTesting.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								Redcraft.Utility/Source/Public/Testing/TemplatesTesting.h
									
									
									
									
									
										Normal file
									
								
							| @@ -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 | ||||
| @@ -28,10 +28,11 @@ NAMESPACE_PRIVATE_END | ||||
| template <typename T>               struct TRank   : TConstant<size_t, NAMESPACE_STD::rank_v<T>>      { }; | ||||
| template <typename T, size_t I = 0> struct TExtent : TConstant<size_t, NAMESPACE_STD::extent_v<T, I>> { }; | ||||
|  | ||||
| template <typename T, typename U> struct TIsSame                          : TBoolConstant<NAMESPACE_STD::is_same_v<T, U>>                 { }; | ||||
| template <typename T, typename U> struct TIsBaseOf                        : TBoolConstant<NAMESPACE_STD::is_base_of_v<T, U>>              { }; | ||||
| template <typename T, typename U> struct TIsConvertible                   : TBoolConstant<NAMESPACE_STD::is_convertible_v<T, U>>          { }; | ||||
| template <typename R, typename F, typename... Args> struct TIsInvocable   : TBoolConstant<NAMESPACE_STD::is_invocable_r_v<R, F, Args...>> { }; | ||||
| template <typename T, typename U> struct TIsSame                              : TBoolConstant<NAMESPACE_STD::is_same_v<T, U>>                 { }; | ||||
| template <typename T, typename U> struct TIsBaseOf                            : TBoolConstant<NAMESPACE_STD::is_base_of_v<T, U>>              { }; | ||||
| template <typename T, typename U> struct TIsConvertible                       : TBoolConstant<NAMESPACE_STD::is_convertible_v<T, U>>          { }; | ||||
| template <typename F, typename... Args> struct TIsInvocable                   : TBoolConstant<NAMESPACE_STD::is_invocable_v<F, Args...>>      { }; | ||||
| template <typename R, typename F, typename... Args> struct TIsInvocableResult : TBoolConstant<NAMESPACE_STD::is_invocable_r_v<R, F, Args...>> { }; // FIXME: The result for char(&())[2] is wrong on MSVC | ||||
|  | ||||
| template <typename T> struct TRemoveConst      { using Type = NAMESPACE_STD::remove_const_t<T>;       }; | ||||
| template <typename T> struct TRemoveVolatile   { using Type = NAMESPACE_STD::remove_volatile_t<T>;    }; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user