traits: Add SignatureOf helper

This a more powerful version of the ParamType class.
It provide all the same information as before, plus function return type
and number of parameters.

Change-Id: If03feed0c1b94434fa95340b6b6277621b4f81b4
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/69100
Auto-Submit: Ben Clayton <bclayton@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
Ben Clayton 2021-11-11 16:07:12 +00:00 committed by Tint LUCI CQ
parent 5c9a80b6f6
commit 1a8171c08b
6 changed files with 113 additions and 64 deletions

View File

@ -675,10 +675,10 @@ if(${TINT_BUILD_TESTS})
resolver/intrinsic_validation_test.cc resolver/intrinsic_validation_test.cc
resolver/is_host_shareable_test.cc resolver/is_host_shareable_test.cc
resolver/is_storeable_test.cc resolver/is_storeable_test.cc
resolver/pipeline_overridable_constant_test.cc
resolver/ptr_ref_test.cc resolver/ptr_ref_test.cc
resolver/ptr_ref_validation_test.cc resolver/ptr_ref_validation_test.cc
resolver/resolver_constants_test.cc resolver/resolver_constants_test.cc
resolver/pipeline_overridable_constant_test.cc
resolver/resolver_test_helper.cc resolver/resolver_test_helper.cc
resolver/resolver_test_helper.h resolver/resolver_test_helper.h
resolver/resolver_test.cc resolver/resolver_test.cc
@ -693,11 +693,6 @@ if(${TINT_BUILD_TESTS})
resolver/var_let_test.cc resolver/var_let_test.cc
resolver/var_let_validation_test.cc resolver/var_let_validation_test.cc
scope_stack_test.cc scope_stack_test.cc
sem/intrinsic_test.cc
symbol_table_test.cc
symbol_test.cc
transform/transform_test.cc
test_main.cc
sem/atomic_type_test.cc sem/atomic_type_test.cc
sem/bool_type_test.cc sem/bool_type_test.cc
sem/depth_multisampled_texture_type_test.cc sem/depth_multisampled_texture_type_test.cc
@ -705,6 +700,7 @@ if(${TINT_BUILD_TESTS})
sem/external_texture_type_test.cc sem/external_texture_type_test.cc
sem/f32_type_test.cc sem/f32_type_test.cc
sem/i32_type_test.cc sem/i32_type_test.cc
sem/intrinsic_test.cc
sem/matrix_type_test.cc sem/matrix_type_test.cc
sem/multisampled_texture_type_test.cc sem/multisampled_texture_type_test.cc
sem/pointer_type_test.cc sem/pointer_type_test.cc
@ -718,6 +714,11 @@ if(${TINT_BUILD_TESTS})
sem/type_manager_test.cc sem/type_manager_test.cc
sem/u32_type_test.cc sem/u32_type_test.cc
sem/vector_type_test.cc sem/vector_type_test.cc
symbol_table_test.cc
symbol_test.cc
test_main.cc
traits_test.cc
transform/transform_test.cc
utils/defer_test.cc utils/defer_test.cc
utils/enum_set_test.cc utils/enum_set_test.cc
utils/get_or_create_test.cc utils/get_or_create_test.cc

View File

@ -62,7 +62,7 @@ template <TraverseOrder ORDER = TraverseOrder::LeftToRight, typename CALLBACK>
bool TraverseExpressions(const ast::Expression* root, bool TraverseExpressions(const ast::Expression* root,
diag::List& diags, diag::List& diags,
CALLBACK&& callback) { CALLBACK&& callback) {
using EXPR_TYPE = std::remove_pointer_t<traits::ParamTypeT<CALLBACK, 0>>; using EXPR_TYPE = std::remove_pointer_t<traits::ParameterType<CALLBACK, 0>>;
std::vector<const ast::Expression*> to_visit{root}; std::vector<const ast::Expression*> to_visit{root};
auto push_pair = [&](const ast::Expression* left, auto push_pair = [&](const ast::Expression* left,

View File

@ -303,7 +303,8 @@ class Castable : public BASE {
/// object is of, or derives from the class `TO`. /// object is of, or derives from the class `TO`.
template <int FLAGS = 0, typename Pred = detail::Infer> template <int FLAGS = 0, typename Pred = detail::Infer>
inline bool Is(Pred&& pred) const { inline bool Is(Pred&& pred) const {
using TO = typename std::remove_pointer<traits::ParamTypeT<Pred, 0>>::type; using TO =
typename std::remove_pointer<traits::ParameterType<Pred, 0>>::type;
return tint::Is<TO, FLAGS>(static_cast<const CLASS*>(this), return tint::Is<TO, FLAGS>(static_cast<const CLASS*>(this),
std::forward<Pred>(pred)); std::forward<Pred>(pred));
} }

View File

@ -62,7 +62,7 @@ class CloneContext {
/// F is a pointer of (or derives from) type T. /// F is a pointer of (or derives from) type T.
template <typename F, typename T> template <typename F, typename T>
using ParamTypeIsPtrOf = traits::IsTypeOrDerived< using ParamTypeIsPtrOf = traits::IsTypeOrDerived<
typename std::remove_pointer<traits::ParamTypeT<F, 0>>::type, typename std::remove_pointer<traits::ParameterType<F, 0>>::type,
T>; T>;
public: public:
@ -274,7 +274,7 @@ class CloneContext {
template <typename F> template <typename F>
traits::EnableIf<ParamTypeIsPtrOf<F, Cloneable>::value, CloneContext>& traits::EnableIf<ParamTypeIsPtrOf<F, Cloneable>::value, CloneContext>&
ReplaceAll(F&& replacer) { ReplaceAll(F&& replacer) {
using TPtr = traits::ParamTypeT<F, 0>; using TPtr = traits::ParameterType<F, 0>;
using T = typename std::remove_pointer<TPtr>::type; using T = typename std::remove_pointer<TPtr>::type;
for (auto& transform : transforms_) { for (auto& transform : transforms_) {
if (transform.typeinfo->Is(TypeInfo::Of<T>()) || if (transform.typeinfo->Is(TypeInfo::Of<T>()) ||

View File

@ -28,44 +28,63 @@ using Decay = typename std::decay<T>::type;
template <int N, typename... Types> template <int N, typename... Types>
using NthTypeOf = typename std::tuple_element<N, std::tuple<Types...>>::type; using NthTypeOf = typename std::tuple_element<N, std::tuple<Types...>>::type;
/// ParamType is a traits helper that infers the type of the `N`th parameter /// Signature describes the signature of a function.
/// of the function, method, static method, lambda, or function-like object `F`. template <typename RETURN, typename... PARAMETERS>
template <typename F, int N> struct Signature {
struct ParamType { /// The return type of the function signature
/// The type of the `N`th parameter of the function-like object `F` using ret = RETURN;
using type = typename ParamType<decltype(&F::operator()), N>::type; /// The parameters of the function signature held in a std::tuple
using parameters = std::tuple<PARAMETERS...>;
/// The type of the Nth parameter of function signature
template <std::size_t N>
using parameter = NthTypeOf<N, PARAMETERS...>;
/// The total number of parameters
static constexpr std::size_t parameter_count = sizeof...(PARAMETERS);
}; };
/// ParamType specialization for a regular function or static method. /// SignatureOf is a traits helper that infers the signature of the function,
template <typename R, int N, typename... Args> /// method, static method, lambda, or function-like object `F`.
struct ParamType<R (*)(Args...), N> { template <typename F>
/// Arg is the raw type of the `N`th parameter of the function struct SignatureOf {
using Arg = NthTypeOf<N, Args...>; /// The signature of the function-like object `F`
/// The type of the `N`th parameter of the function using type = typename SignatureOf<decltype(&F::operator())>::type;
using type = Decay<Arg>;
}; };
/// ParamType specialization for a non-static method. /// SignatureOf specialization for a regular function or static method.
template <typename R, typename C, int N, typename... Args> template <typename R, typename... ARGS>
struct ParamType<R (C::*)(Args...), N> { struct SignatureOf<R (*)(ARGS...)> {
/// Arg is the raw type of the `N`th parameter of the function /// The signature of the function-like object `F`
using Arg = NthTypeOf<N, Args...>; using type = Signature<typename std::decay<R>::type,
/// The type of the `N`th parameter of the function typename std::decay<ARGS>::type...>;
using type = Decay<Arg>;
}; };
/// ParamType specialization for a non-static, const method. /// SignatureOf specialization for a non-static method.
template <typename R, typename C, int N, typename... Args> template <typename R, typename C, typename... ARGS>
struct ParamType<R (C::*)(Args...) const, N> { struct SignatureOf<R (C::*)(ARGS...)> {
/// Arg is the raw type of the `N`th parameter of the function /// The signature of the function-like object `F`
using Arg = NthTypeOf<N, Args...>; using type = Signature<typename std::decay<R>::type,
/// The type of the `N`th parameter of the function typename std::decay<ARGS>::type...>;
using type = Decay<Arg>;
}; };
/// ParamTypeT is an alias to `typename ParamType<F, N>::type`. /// SignatureOf specialization for a non-static, const method.
template <typename F, int N> template <typename R, typename C, typename... ARGS>
using ParamTypeT = typename ParamType<F, N>::type; struct SignatureOf<R (C::*)(ARGS...) const> {
/// The signature of the function-like object `F`
using type = Signature<typename std::decay<R>::type,
typename std::decay<ARGS>::type...>;
};
/// SignatureOfT is an alias to `typename SignatureOf<F>::type`.
template <typename F>
using SignatureOfT = typename SignatureOf<F>::type;
/// ParameterType is an alias to `typename SignatureOf<F>::type::parameter<N>`.
template <typename F, std::size_t N>
using ParameterType = typename SignatureOfT<F>::template parameter<N>;
/// ReturnType is an alias to `typename SignatureOf<F>::type::ret`.
template <typename F>
using ReturnType = typename SignatureOfT<F>::ret;
/// `IsTypeOrDerived<T, BASE>::value` is true iff `T` is of type `BASE`, or /// `IsTypeOrDerived<T, BASE>::value` is true iff `T` is of type `BASE`, or
/// derives from `BASE`. /// derives from `BASE`.

View File

@ -28,10 +28,15 @@ void F3(int, S, float) {}
TEST(ParamType, Function) { TEST(ParamType, Function) {
F1({}); // Avoid unused method warning F1({}); // Avoid unused method warning
F3(0, {}, 0); // Avoid unused method warning F3(0, {}, 0); // Avoid unused method warning
static_assert(std::is_same<ParamTypeT<decltype(&F1), 0>, S>::value, ""); static_assert(std::is_same<ParameterType<decltype(&F1), 0>, S>::value, "");
static_assert(std::is_same<ParamTypeT<decltype(&F3), 0>, int>::value, ""); static_assert(std::is_same<ParameterType<decltype(&F3), 0>, int>::value, "");
static_assert(std::is_same<ParamTypeT<decltype(&F3), 1>, S>::value, ""); static_assert(std::is_same<ParameterType<decltype(&F3), 1>, S>::value, "");
static_assert(std::is_same<ParamTypeT<decltype(&F3), 2>, float>::value, ""); static_assert(std::is_same<ParameterType<decltype(&F3), 2>, float>::value,
"");
static_assert(std::is_same<ReturnType<decltype(&F1)>, void>::value, "");
static_assert(std::is_same<ReturnType<decltype(&F3)>, void>::value, "");
static_assert(SignatureOfT<decltype(&F1)>::parameter_count == 1, "");
static_assert(SignatureOfT<decltype(&F3)>::parameter_count == 3, "");
} }
TEST(ParamType, Method) { TEST(ParamType, Method) {
@ -42,11 +47,16 @@ TEST(ParamType, Method) {
}; };
C().F1({}); // Avoid unused method warning C().F1({}); // Avoid unused method warning
C().F3(0, {}, 0); // Avoid unused method warning C().F3(0, {}, 0); // Avoid unused method warning
static_assert(std::is_same<ParamTypeT<decltype(&C::F1), 0>, S>::value, ""); static_assert(std::is_same<ParameterType<decltype(&C::F1), 0>, S>::value, "");
static_assert(std::is_same<ParamTypeT<decltype(&C::F3), 0>, int>::value, ""); static_assert(std::is_same<ParameterType<decltype(&C::F3), 0>, int>::value,
static_assert(std::is_same<ParamTypeT<decltype(&C::F3), 1>, S>::value, "");
static_assert(std::is_same<ParamTypeT<decltype(&C::F3), 2>, float>::value,
""); "");
static_assert(std::is_same<ParameterType<decltype(&C::F3), 1>, S>::value, "");
static_assert(std::is_same<ParameterType<decltype(&C::F3), 2>, float>::value,
"");
static_assert(std::is_same<ReturnType<decltype(&C::F1)>, void>::value, "");
static_assert(std::is_same<ReturnType<decltype(&C::F3)>, void>::value, "");
static_assert(SignatureOfT<decltype(&C::F1)>::parameter_count == 1, "");
static_assert(SignatureOfT<decltype(&C::F3)>::parameter_count == 3, "");
} }
TEST(ParamType, ConstMethod) { TEST(ParamType, ConstMethod) {
@ -57,11 +67,16 @@ TEST(ParamType, ConstMethod) {
}; };
C().F1({}); // Avoid unused method warning C().F1({}); // Avoid unused method warning
C().F3(0, {}, 0); // Avoid unused method warning C().F3(0, {}, 0); // Avoid unused method warning
static_assert(std::is_same<ParamTypeT<decltype(&C::F1), 0>, S>::value, ""); static_assert(std::is_same<ParameterType<decltype(&C::F1), 0>, S>::value, "");
static_assert(std::is_same<ParamTypeT<decltype(&C::F3), 0>, int>::value, ""); static_assert(std::is_same<ParameterType<decltype(&C::F3), 0>, int>::value,
static_assert(std::is_same<ParamTypeT<decltype(&C::F3), 1>, S>::value, "");
static_assert(std::is_same<ParamTypeT<decltype(&C::F3), 2>, float>::value,
""); "");
static_assert(std::is_same<ParameterType<decltype(&C::F3), 1>, S>::value, "");
static_assert(std::is_same<ParameterType<decltype(&C::F3), 2>, float>::value,
"");
static_assert(std::is_same<ReturnType<decltype(&C::F1)>, void>::value, "");
static_assert(std::is_same<ReturnType<decltype(&C::F3)>, void>::value, "");
static_assert(SignatureOfT<decltype(&C::F1)>::parameter_count == 1, "");
static_assert(SignatureOfT<decltype(&C::F3)>::parameter_count == 3, "");
} }
TEST(ParamType, StaticMethod) { TEST(ParamType, StaticMethod) {
@ -72,29 +87,42 @@ TEST(ParamType, StaticMethod) {
}; };
C::F1({}); // Avoid unused method warning C::F1({}); // Avoid unused method warning
C::F3(0, {}, 0); // Avoid unused method warning C::F3(0, {}, 0); // Avoid unused method warning
static_assert(std::is_same<ParamTypeT<decltype(&C::F1), 0>, S>::value, ""); static_assert(std::is_same<ParameterType<decltype(&C::F1), 0>, S>::value, "");
static_assert(std::is_same<ParamTypeT<decltype(&C::F3), 0>, int>::value, ""); static_assert(std::is_same<ParameterType<decltype(&C::F3), 0>, int>::value,
static_assert(std::is_same<ParamTypeT<decltype(&C::F3), 1>, S>::value, "");
static_assert(std::is_same<ParamTypeT<decltype(&C::F3), 2>, float>::value,
""); "");
static_assert(std::is_same<ParameterType<decltype(&C::F3), 1>, S>::value, "");
static_assert(std::is_same<ParameterType<decltype(&C::F3), 2>, float>::value,
"");
static_assert(std::is_same<ReturnType<decltype(&C::F1)>, void>::value, "");
static_assert(std::is_same<ReturnType<decltype(&C::F3)>, void>::value, "");
static_assert(SignatureOfT<decltype(&C::F1)>::parameter_count == 1, "");
static_assert(SignatureOfT<decltype(&C::F3)>::parameter_count == 3, "");
} }
TEST(ParamType, FunctionLike) { TEST(ParamType, FunctionLike) {
using F1 = std::function<void(S)>; using F1 = std::function<void(S)>;
using F3 = std::function<void(int, S, float)>; using F3 = std::function<void(int, S, float)>;
static_assert(std::is_same<ParamTypeT<F1, 0>, S>::value, ""); static_assert(std::is_same<ParameterType<F1, 0>, S>::value, "");
static_assert(std::is_same<ParamTypeT<F3, 0>, int>::value, ""); static_assert(std::is_same<ParameterType<F3, 0>, int>::value, "");
static_assert(std::is_same<ParamTypeT<F3, 1>, S>::value, ""); static_assert(std::is_same<ParameterType<F3, 1>, S>::value, "");
static_assert(std::is_same<ParamTypeT<F3, 2>, float>::value, ""); static_assert(std::is_same<ParameterType<F3, 2>, float>::value, "");
static_assert(std::is_same<ReturnType<F1>, void>::value, "");
static_assert(std::is_same<ReturnType<F3>, void>::value, "");
static_assert(SignatureOfT<F1>::parameter_count == 1, "");
static_assert(SignatureOfT<F3>::parameter_count == 3, "");
} }
TEST(ParamType, Lambda) { TEST(ParamType, Lambda) {
auto l1 = [](S) {}; auto l1 = [](S) {};
auto l3 = [](int, S, float) {}; auto l3 = [](int, S, float) {};
static_assert(std::is_same<ParamTypeT<decltype(l1), 0>, S>::value, ""); static_assert(std::is_same<ParameterType<decltype(l1), 0>, S>::value, "");
static_assert(std::is_same<ParamTypeT<decltype(l3), 0>, int>::value, ""); static_assert(std::is_same<ParameterType<decltype(l3), 0>, int>::value, "");
static_assert(std::is_same<ParamTypeT<decltype(l3), 1>, S>::value, ""); static_assert(std::is_same<ParameterType<decltype(l3), 1>, S>::value, "");
static_assert(std::is_same<ParamTypeT<decltype(l3), 2>, float>::value, ""); static_assert(std::is_same<ParameterType<decltype(l3), 2>, float>::value, "");
static_assert(std::is_same<ReturnType<decltype(l1)>, void>::value, "");
static_assert(std::is_same<ReturnType<decltype(l3)>, void>::value, "");
static_assert(SignatureOfT<decltype(l1)>::parameter_count == 1, "");
static_assert(SignatureOfT<decltype(l3)>::parameter_count == 3, "");
} }
} // namespace traits } // namespace traits