feat(templates): add common functors and the corresponding testing

This commit is contained in:
2022-04-08 11:44:36 +08:00
parent 92523a13b2
commit ceccf9d722
3 changed files with 293 additions and 8 deletions

View File

@ -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

View File

@ -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);
}