feat(templates): add common functors and the corresponding testing
This commit is contained in:
parent
92523a13b2
commit
ceccf9d722
@ -1155,6 +1155,87 @@ void TestFunction()
|
||||
always_check(FunctionDebug.Output[10] == 720);
|
||||
always_check(FunctionDebug.Output[11] == 5040);
|
||||
}
|
||||
|
||||
{
|
||||
TFunction<bool(bool)> Identity = TIdentity<>();
|
||||
TFunction<bool(bool)> NotIdentity = NotFn(Identity);
|
||||
|
||||
always_check(Identity(true));
|
||||
always_check(NotIdentity(false));
|
||||
}
|
||||
|
||||
{
|
||||
always_check(TPlus <int32>()(4, 2) == 6);
|
||||
always_check(TMinus <int32>()(4, 2) == 2);
|
||||
always_check(TMultiplies<int32>()(4, 2) == 8);
|
||||
always_check(TDivides <int32>()(4, 2) == 2);
|
||||
always_check(TModulus <int32>()(4, 2) == 0);
|
||||
always_check(TNegate <int32>()(4 ) == -4);
|
||||
|
||||
always_check(TEqualTo <int32>()(4, 2) == false);
|
||||
always_check(TNotEqualTo <int32>()(4, 2) == true);
|
||||
always_check(TGreater <int32>()(4, 2) == true);
|
||||
always_check(TLess <int32>()(4, 2) == false);
|
||||
always_check(TGreaterEqual<int32>()(4, 2) == true);
|
||||
always_check(TLessEqual <int32>()(4, 2) == false);
|
||||
|
||||
always_check(TLogicalAnd<int32>()(4, 2) == true);
|
||||
always_check(TLogicalOr <int32>()(4, 2) == true);
|
||||
always_check(TLogicalNot<int32>()(4 ) == false);
|
||||
|
||||
always_check(TBitAnd<int32>()(4, 2) == 0);
|
||||
always_check(TBitOr <int32>()(4, 2) == 6);
|
||||
always_check(TBitXor<int32>()(4, 2) == 6);
|
||||
always_check(TBitNot<int32>()(4 ) == -5);
|
||||
}
|
||||
|
||||
{
|
||||
TFunction<int32(int32, int32)> TempA = TPlus <>();
|
||||
TFunction<int32(int32, int32)> TempB = TMinus <>();
|
||||
TFunction<int32(int32, int32)> TempC = TMultiplies<>();
|
||||
TFunction<int32(int32, int32)> TempD = TDivides <>();
|
||||
TFunction<int32(int32, int32)> TempE = TModulus <>();
|
||||
TFunction<int32(int32 )> TempF = TNegate <>();
|
||||
|
||||
always_check(TempA(4, 2) == 6);
|
||||
always_check(TempB(4, 2) == 2);
|
||||
always_check(TempC(4, 2) == 8);
|
||||
always_check(TempD(4, 2) == 2);
|
||||
always_check(TempE(4, 2) == 0);
|
||||
always_check(TempF(4 ) == -4);
|
||||
|
||||
TFunction<bool(int32, int32)> TempG = TEqualTo <>();
|
||||
TFunction<bool(int32, int32)> TempH = TNotEqualTo <>();
|
||||
TFunction<bool(int32, int32)> TempI = TGreater <>();
|
||||
TFunction<bool(int32, int32)> TempJ = TLess <>();
|
||||
TFunction<bool(int32, int32)> TempK = TGreaterEqual<>();
|
||||
TFunction<bool(int32, int32)> TempL = TLessEqual <>();
|
||||
|
||||
always_check(TempG(4, 2) == false);
|
||||
always_check(TempH(4, 2) == true);
|
||||
always_check(TempI(4, 2) == true);
|
||||
always_check(TempJ(4, 2) == false);
|
||||
always_check(TempK(4, 2) == true);
|
||||
always_check(TempL(4, 2) == false);
|
||||
|
||||
TFunction<bool(int32, int32)> TempM = TLogicalAnd<>();
|
||||
TFunction<bool(int32, int32)> TempN = TLogicalOr <>();
|
||||
TFunction<bool(int32 )> TempO = TLogicalNot<>();
|
||||
|
||||
always_check(TempM(4, 2) == true);
|
||||
always_check(TempN(4, 2) == true);
|
||||
always_check(TempO(4 ) == false);
|
||||
|
||||
TFunction<int32(int32, int32)> TempP = TBitAnd<>();
|
||||
TFunction<int32(int32, int32)> TempQ = TBitOr <>();
|
||||
TFunction<int32(int32, int32)> TempR = TBitXor<>();
|
||||
TFunction<int32(int32 )> TempS = TBitNot<>();
|
||||
|
||||
always_check(TempP(4, 2) == 0);
|
||||
always_check(TempQ(4, 2) == 6);
|
||||
always_check(TempR(4, 2) == 6);
|
||||
always_check(TempS(4 ) == -5);
|
||||
}
|
||||
}
|
||||
|
||||
NAMESPACE_UNNAMED_BEGIN
|
||||
|
@ -2,12 +2,17 @@
|
||||
|
||||
#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
|
||||
@ -454,6 +459,203 @@ static_assert(sizeof(TFunctionRef<void()>) == 16, "The byte size of TFunction
|
||||
static_assert(sizeof(TFunction<void()>) == 64, "The byte size of TFunction is unexpected");
|
||||
static_assert(sizeof(TUniqueFunction<void()>) == 64, "The byte size of TUniqueFunction is unexpected");
|
||||
|
||||
template <typename T = void>
|
||||
struct TIdentity
|
||||
{
|
||||
using Type = T;
|
||||
|
||||
constexpr T&& operator()(T&& InValue) const
|
||||
{
|
||||
return Forward<T>(InValue);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct TIdentity<void>
|
||||
{
|
||||
using Type = void;
|
||||
|
||||
template<typename T>
|
||||
constexpr T&& operator()(T&& InValue) const
|
||||
{
|
||||
return Forward<T>(InValue);
|
||||
}
|
||||
};
|
||||
|
||||
NAMESPACE_PRIVATE_BEGIN
|
||||
|
||||
template <typename F>
|
||||
struct NotFunctionType
|
||||
{
|
||||
F Func;
|
||||
|
||||
NotFunctionType(const NotFunctionType&) = default;
|
||||
NotFunctionType(NotFunctionType&&) = default;
|
||||
|
||||
template <typename InF>
|
||||
constexpr NotFunctionType(InF&& InFunc) : Func(Forward<InF>(InFunc)) { }
|
||||
|
||||
template <typename... Types> requires TIsInvocable<F&, Types&&...>::Value
|
||||
constexpr auto operator()(Types&&... Args) &
|
||||
-> decltype(!Invoke(Func, Forward<Types>(Args)...))
|
||||
{
|
||||
return !Invoke(Func, Forward<Types>(Args)...);
|
||||
}
|
||||
|
||||
template <typename... Types> requires TIsInvocable<F&&, Types&&...>::Value
|
||||
constexpr auto operator()(Types&&... Args) &&
|
||||
-> decltype(!Invoke(MoveTemp(Func), Forward<Types>(Args)...))
|
||||
{
|
||||
return !Invoke(MoveTemp(Func), Forward<Types>(Args)...);
|
||||
}
|
||||
|
||||
template <typename... Types> requires TIsInvocable<const F&, Types&&...>::Value
|
||||
constexpr auto operator()(Types&&... Args) const&
|
||||
-> decltype(!Invoke(Func, Forward<Types>(Args)...))
|
||||
{
|
||||
return !Invoke(Func, 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)...))
|
||||
{
|
||||
return !Invoke(MoveTemp(Func), Forward<Types>(Args)...);
|
||||
}
|
||||
};
|
||||
|
||||
NAMESPACE_PRIVATE_END
|
||||
|
||||
template <typename F>
|
||||
constexpr NAMESPACE_PRIVATE::NotFunctionType<typename TDecay<F>::Type> NotFn(F&& Func)
|
||||
{
|
||||
return NAMESPACE_PRIVATE::NotFunctionType<typename TDecay<F>::Type>(Forward<F>(Func));
|
||||
}
|
||||
|
||||
#define FUNCTOR_UNARY_OPERATOR_IMPL(Name, Operator, ReturnType, ConceptT, ConceptU) \
|
||||
template <typename T = void> requires (CSameAs<T, void> || ConceptT) \
|
||||
struct Name \
|
||||
{ \
|
||||
constexpr ReturnType operator()(const T& InValue) const { \
|
||||
return Operator InValue; \
|
||||
} \
|
||||
}; \
|
||||
\
|
||||
template <> \
|
||||
struct Name<void> \
|
||||
{ \
|
||||
template <typename U> requires ConceptU \
|
||||
constexpr auto operator()(U&& InValue) const \
|
||||
-> decltype(Operator Forward<U>(InValue)) \
|
||||
{ \
|
||||
return Operator Forward<U>(InValue); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define FUNCTOR_BINARY_OPERATOR_IMPL(Name, Operator, ReturnType, ConceptT, ConceptTU) \
|
||||
template <typename T = void> requires (CSameAs<T, void> || ConceptT) \
|
||||
struct Name \
|
||||
{ \
|
||||
constexpr ReturnType operator()(const T& LHS, const T& RHS) const \
|
||||
{ \
|
||||
return LHS Operator RHS; \
|
||||
} \
|
||||
}; \
|
||||
\
|
||||
template <> \
|
||||
struct Name<void> \
|
||||
{ \
|
||||
template <typename T, typename U> requires ConceptTU \
|
||||
constexpr auto operator()(T&& LHS, U&& RHS) const \
|
||||
-> decltype(Forward<T>(LHS) Operator Forward<U>(RHS)) \
|
||||
{ \
|
||||
return Forward<T>(LHS) Operator Forward<U>(RHS); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define FUNCTOR_UNARY_OPERATOR_A_IMPL(Name, Operator) \
|
||||
FUNCTOR_UNARY_OPERATOR_IMPL \
|
||||
( \
|
||||
Name, Operator, T, \
|
||||
(requires(const T& InValue) { { Operator InValue } -> CConvertibleTo<T>; }), \
|
||||
(requires(U&& InValue) { Operator Forward<U>(InValue); }) \
|
||||
)
|
||||
|
||||
#define FUNCTOR_BINARY_OPERATOR_A_IMPL(Name, Operator) \
|
||||
FUNCTOR_BINARY_OPERATOR_IMPL \
|
||||
( \
|
||||
Name, Operator, T, \
|
||||
(requires(const T& LHS, const T& RHS) { { LHS Operator RHS } -> CConvertibleTo<T>; }), \
|
||||
(requires(T&& LHS, U&& RHS) { Forward<T>(LHS) Operator Forward<U>(RHS); }) \
|
||||
)
|
||||
|
||||
#define FUNCTOR_UNARY_OPERATOR_B_IMPL(Name, Operator) \
|
||||
FUNCTOR_UNARY_OPERATOR_IMPL \
|
||||
( \
|
||||
Name, Operator, bool, \
|
||||
(requires(const T& InValue) { { Operator InValue } -> CBooleanTestable; }), \
|
||||
(requires(U&& InValue) { { Operator Forward<U>(InValue) } -> CBooleanTestable; }) \
|
||||
)
|
||||
|
||||
#define FUNCTOR_BINARY_OPERATOR_B_IMPL(Name, Operator) \
|
||||
FUNCTOR_BINARY_OPERATOR_IMPL \
|
||||
( \
|
||||
Name, Operator, bool, \
|
||||
(requires(const T& LHS, const T& RHS) { { LHS Operator RHS } -> CBooleanTestable; }), \
|
||||
(requires(T&& LHS, U&& RHS) { { Forward<T>(LHS) Operator Forward<U>(RHS) } -> CBooleanTestable; }) \
|
||||
)
|
||||
|
||||
#define FUNCTOR_BINARY_OPERATOR_C_IMPL(Name, Operator) \
|
||||
FUNCTOR_BINARY_OPERATOR_IMPL \
|
||||
( \
|
||||
Name, Operator, bool, \
|
||||
(CEqualityComparable<T>), \
|
||||
(CEqualityComparableWith<T, U>) \
|
||||
)
|
||||
|
||||
#define FUNCTOR_BINARY_OPERATOR_D_IMPL(Name, Operator) \
|
||||
FUNCTOR_BINARY_OPERATOR_IMPL \
|
||||
( \
|
||||
Name, Operator, bool, \
|
||||
(CTotallyOrdered<T>), \
|
||||
(CTotallyOrderedWith<T, U>) \
|
||||
)
|
||||
|
||||
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 (TNegate, -);
|
||||
|
||||
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, <=);
|
||||
|
||||
FUNCTOR_BINARY_OPERATOR_B_IMPL(TLogicalAnd, &&);
|
||||
FUNCTOR_BINARY_OPERATOR_B_IMPL(TLogicalOr, ||);
|
||||
FUNCTOR_UNARY_OPERATOR_B_IMPL (TLogicalNot, ! );
|
||||
|
||||
FUNCTOR_BINARY_OPERATOR_A_IMPL(TBitAnd, &);
|
||||
FUNCTOR_BINARY_OPERATOR_A_IMPL(TBitOr, |);
|
||||
FUNCTOR_BINARY_OPERATOR_A_IMPL(TBitXor, ^);
|
||||
FUNCTOR_UNARY_OPERATOR_A_IMPL (TBitNot, ~);
|
||||
|
||||
#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
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Templates/Utility.h"
|
||||
#include "TypeTraits/TypeTraits.h"
|
||||
|
||||
NAMESPACE_REDCRAFT_BEGIN
|
||||
@ -13,6 +14,7 @@ struct InvokeFunction
|
||||
{
|
||||
template <typename F, typename... Types>
|
||||
static auto Invoke(F&& Object, Types&&... Args)
|
||||
-> decltype(Forward<F>(Object)(Forward<Types>(Args)...))
|
||||
{
|
||||
return Forward<F>(Object)(Forward<Types>(Args)...);
|
||||
}
|
||||
@ -21,15 +23,15 @@ struct InvokeFunction
|
||||
struct InvokeMemberFunction
|
||||
{
|
||||
template <typename F, typename ObjectType, typename... Types>
|
||||
static auto Invoke(F&& Func, ObjectType&& Object, Types&&... Args) ->
|
||||
decltype((Forward<ObjectType>(Object)->*Func)(Forward<Types>(Args)...))
|
||||
static auto Invoke(F&& Func, ObjectType&& Object, Types&&... Args)
|
||||
-> decltype((Forward<ObjectType>(Object)->*Func)(Forward<Types>(Args)...))
|
||||
{
|
||||
return (Forward<ObjectType>(Object)->*Func)(Forward<Types>(Args)...);
|
||||
}
|
||||
|
||||
template <typename F, typename ObjectType, typename... Types>
|
||||
static auto Invoke(F&& Func, ObjectType&& Object, Types&&... Args) ->
|
||||
decltype((Forward<ObjectType>(Object).*Func)(Forward<Types>(Args)...))
|
||||
static auto Invoke(F&& Func, ObjectType&& Object, Types&&... Args)
|
||||
-> decltype((Forward<ObjectType>(Object).*Func)(Forward<Types>(Args)...))
|
||||
{
|
||||
return (Forward<ObjectType>(Object).*Func)(Forward<Types>(Args)...);
|
||||
}
|
||||
@ -38,15 +40,15 @@ struct InvokeMemberFunction
|
||||
struct InvokeMemberObject
|
||||
{
|
||||
template <typename F, typename ObjectType>
|
||||
static auto Invoke(F&& Func, ObjectType&& Object) ->
|
||||
decltype(Forward<ObjectType>(Object)->*Func)
|
||||
static auto Invoke(F&& Func, ObjectType&& Object)
|
||||
-> decltype(Forward<ObjectType>(Object)->*Func)
|
||||
{
|
||||
return (Forward<ObjectType>(Object)->*Func);
|
||||
}
|
||||
|
||||
template <typename F, typename ObjectType>
|
||||
static auto Invoke(F&& Func, ObjectType&& Object) ->
|
||||
decltype(Forward<ObjectType>(Object).*Func)
|
||||
static auto Invoke(F&& Func, ObjectType&& Object)
|
||||
-> decltype(Forward<ObjectType>(Object).*Func)
|
||||
{
|
||||
return (Forward<ObjectType>(Object).*Func);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user