1 /*
2  * Copyright 2018 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #ifndef SkCallableTraits_DEFINED
9 #define SkCallableTraits_DEFINED
10 
11 #include <type_traits>
12 #include <tuple>
13 
14 template <typename R, typename... Args> struct sk_base_callable_traits {
15     using return_type = R;
16     static constexpr std::size_t arity = sizeof...(Args);
17     template <std::size_t N> struct argument {
18         static_assert(N < arity, "");
19         using type = typename std::tuple_element<N, std::tuple<Args...>>::type;
20     };
21 };
22 
23 #define SK_CALLABLE_TRAITS__COMMA ,
24 
25 #define SK_CALLABLE_TRAITS__VARARGS(quals, _) \
26 SK_CALLABLE_TRAITS__INSTANCE(quals,) \
27 SK_CALLABLE_TRAITS__INSTANCE(quals, SK_CALLABLE_TRAITS__COMMA ...)
28 
29 #ifdef __cpp_noexcept_function_type
30 #define SK_CALLABLE_TRAITS__NE_VARARGS(quals, _) \
31 SK_CALLABLE_TRAITS__VARARGS(quals,) \
32 SK_CALLABLE_TRAITS__VARARGS(quals noexcept,)
33 #else
34 #define SK_CALLABLE_TRAITS__NE_VARARGS(quals, _) \
35 SK_CALLABLE_TRAITS__VARARGS(quals,)
36 #endif
37 
38 #define SK_CALLABLE_TRAITS__REF_NE_VARARGS(quals, _) \
39 SK_CALLABLE_TRAITS__NE_VARARGS(quals,) \
40 SK_CALLABLE_TRAITS__NE_VARARGS(quals &,) \
41 SK_CALLABLE_TRAITS__NE_VARARGS(quals &&,)
42 
43 #define SK_CALLABLE_TRAITS__CV_REF_NE_VARARGS() \
44 SK_CALLABLE_TRAITS__REF_NE_VARARGS(,) \
45 SK_CALLABLE_TRAITS__REF_NE_VARARGS(const,) \
46 SK_CALLABLE_TRAITS__REF_NE_VARARGS(volatile,) \
47 SK_CALLABLE_TRAITS__REF_NE_VARARGS(const volatile,)
48 
49 /** Infer the return_type and argument<N> of a callable type T. */
50 template <typename T> struct SkCallableTraits : SkCallableTraits<decltype(&T::operator())> {};
51 
52 // function (..., (const, volatile), (&, &&), noexcept)
53 #define SK_CALLABLE_TRAITS__INSTANCE(quals, varargs) \
54 template <typename R, typename... Args> \
55 struct SkCallableTraits<R(Args... varargs) quals> : sk_base_callable_traits<R, Args...> {};
56 
57 SK_CALLABLE_TRAITS__CV_REF_NE_VARARGS()
58 #undef SK_CALLABLE_TRAITS__INSTANCE
59 
60 // pointer to function (..., noexcept)
61 #define SK_CALLABLE_TRAITS__INSTANCE(quals, varargs) \
62 template <typename R, typename... Args> \
63 struct SkCallableTraits<R(*)(Args... varargs) quals> : sk_base_callable_traits<R, Args...> {};
64 
65 SK_CALLABLE_TRAITS__NE_VARARGS(,)
66 #undef SK_CALLABLE_TRAITS__INSTANCE
67 
68 // pointer to method (..., (const, volatile), (&, &&), noexcept)
69 #define SK_CALLABLE_TRAITS__INSTANCE(quals, varargs) \
70 template <typename T, typename R, typename... Args> \
71 struct SkCallableTraits<R(T::*)(Args... varargs) quals> : sk_base_callable_traits<R, Args...> {};
72 
73 SK_CALLABLE_TRAITS__CV_REF_NE_VARARGS()
74 #undef SK_CALLABLE_TRAITS__INSTANCE
75 
76 // pointer to field
77 template <typename T, typename R>
78 struct SkCallableTraits<R T::*> : sk_base_callable_traits<typename std::add_lvalue_reference<R>::type> {};
79 
80 #undef SK_CALLABLE_TRAITS__CV_REF_NE_VARARGS
81 #undef SK_CALLABLE_TRAITS__REF_NE_VARARGS
82 #undef SK_CALLABLE_TRAITS__NE_VARARGS
83 #undef SK_CALLABLE_TRAITS__VARARGS
84 #undef SK_CALLABLE_TRAITS__COMMA
85 
86 #endif
87