-
Notifications
You must be signed in to change notification settings - Fork 62
/
Copy pathfunction_traits.hpp
229 lines (182 loc) · 10.9 KB
/
function_traits.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
#pragma once
#include <type_traits>
#include <tuple>
#define EOS_VM_HAS_MEMBER(ARG, NAME) \
eosio::vm::detail::overloaded { \
[](auto&& f, std::enable_if_t<std::is_class_v<std::decay_t<decltype(f)>> && \
eosio::vm::detail::pass_type< \
decltype(&std::decay_t<decltype(f)>::type::NAME)>(), int> = 0) constexpr { \
return true; \
}, [](...) constexpr { return false; } \
}(eosio::vm::detail::wrapper_t<decltype(ARG)>{})
#define EOS_VM_HAS_MEMBER_TY(TY, NAME) \
eosio::vm::detail::overloaded { \
[](auto&& f, std::enable_if_t<std::is_class_v<TY> && \
eosio::vm::detail::pass_type< \
decltype(&std::decay_t<decltype(f)>::type::NAME)>(), int> = 0) constexpr { \
return true; \
}, [](...) constexpr { return false; } \
}(eosio::vm::detail::wrapper_t<TY>{})
#define EOS_VM_HAS_TEMPLATE_MEMBER(ARG, NAME) \
eosio::vm::detail::overloaded { \
[&](auto&& f, std::enable_if_t<std::is_class_v<std::decay_t<decltype(f)>> && \
eosio::vm::detail::pass_type< \
decltype(&std::decay_t<decltype(f)>::type::template NAME)>(), int> = 0) constexpr { \
return true; \
}, [](...) constexpr { return false; } \
}(eosio::vm::detail::wrapper_t<decltype(ARG)>{})
#define EOS_VM_HAS_TEMPLATE_MEMBER_TY(TY, NAME) \
eosio::vm::detail::overloaded { \
[](auto&& f, std::enable_if_t<std::is_class_v<TY> && \
eosio::vm::detail::pass_type< \
decltype(&std::decay_t<decltype(f)>::type::template NAME)>(), int> = 0) constexpr { \
return true; \
}, [](...) constexpr { return false; } \
}(eosio::vm::detail::wrapper_t<TY>{})
// Workaround for compiler bug handling C++g17 auto template parameters.
// The parameter is not treated as being type-dependent in all contexts,
// causing early evaluation of the containing expression.
// Tested at Apple LLVM version 10.0.1 (clang-1001.0.46.4)
#define AUTO_PARAM_WORKAROUND(X) eosio::vm::detail::make_dependent<decltype(X)>(X)
namespace eosio { namespace vm {
struct freestanding {};
namespace detail {
template <typename T>
constexpr bool pass_type() { return true; }
template <typename>
constexpr bool is_callable_impl(...) {
return false;
}
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
template <typename T>
struct wrapper_t {
using type = T;
constexpr wrapper_t() {}
constexpr wrapper_t(T&&) {}
};
template <typename T, typename U>
inline constexpr U&& make_dependent(U&& u) { return static_cast<U&&>(u); }
}
namespace detail {
template <bool Decay, typename R, typename... Args>
constexpr auto get_types(R(Args...)) -> std::tuple<R, freestanding,
std::tuple<std::conditional_t<Decay, std::decay_t<Args>, Args>...>>;
template <bool Decay, typename R, typename Cls, typename... Args>
constexpr auto get_types(R (Cls::*)(Args...)) -> std::tuple<R, Cls,
std::tuple<std::conditional_t<Decay, std::decay_t<Args>, Args>...>>;
template <bool Decay, typename R, typename Cls, typename... Args>
constexpr auto get_types(R (Cls::*)(Args...)const) -> std::tuple<R, Cls,
std::tuple<std::conditional_t<Decay, std::decay_t<Args>, Args>...>>;
template <bool Decay, typename R, typename Cls, typename... Args>
constexpr auto get_types(R (Cls::*)(Args...)&) -> std::tuple<R, Cls,
std::tuple<std::conditional_t<Decay, std::decay_t<Args>, Args>...>>;
template <bool Decay, typename R, typename Cls, typename... Args>
constexpr auto get_types(R (Cls::*)(Args...)&&) -> std::tuple<R, Cls,
std::tuple<std::conditional_t<Decay, std::decay_t<Args>, Args>...>>;
template <bool Decay, typename R, typename Cls, typename... Args>
constexpr auto get_types(R (Cls::*)(Args...)const &) -> std::tuple<R, Cls,
std::tuple<std::conditional_t<Decay, std::decay_t<Args>, Args>...>>;
template <bool Decay, typename R, typename Cls, typename... Args>
constexpr auto get_types(R (Cls::*)(Args...)const &&) -> std::tuple<R, Cls,
std::tuple<std::conditional_t<Decay, std::decay_t<Args>, Args>...>>;
template <bool Decay, typename F>
constexpr auto get_types(F&& fn) {
if constexpr (std::is_invocable_v<decltype(fn)>)
return get_types<Decay>(&F::operator());
else
return get_types<Decay>(fn);
}
template <bool Decay, typename F>
using get_types_t = decltype(get_types<Decay>(std::declval<F>()));
template <std::size_t Sz, std::size_t N, std::size_t I, typename... Args>
struct pack_from;
template <std::size_t Sz, std::size_t N, std::size_t I, typename Arg, typename... Args>
struct pack_from<Sz, N, I, Arg, Args...> {
static_assert(Sz > N, "index out of range");
using type = typename pack_from<Sz, N, I+1, Args...>::type;
};
template <std::size_t Sz, std::size_t N, typename Arg, typename... Args>
struct pack_from<Sz, N, N, Arg, Args...> {
using type = std::tuple<Arg, Args...>;
};
template <std::size_t N, typename... Args>
using pack_from_t = typename pack_from<sizeof...(Args), N, 0, Args...>::type;
template <std::size_t N, typename R, typename... Args>
constexpr auto parameters_from_impl(R(Args...)) -> pack_from_t<N, Args...>;
template <std::size_t N, typename R, typename Cls, typename... Args>
constexpr auto parameters_from_impl(R(Cls::*)(Args...)) -> pack_from_t<N, Args...>;
template <std::size_t N, typename R, typename Cls, typename... Args>
constexpr auto parameters_from_impl(R(Cls::*)(Args...)const) -> pack_from_t<N, Args...>;
template <std::size_t N, typename R, typename Cls, typename... Args>
constexpr auto parameters_from_impl(R(Cls::*)(Args...)&) -> pack_from_t<N, Args...>;
template <std::size_t N, typename R, typename Cls, typename... Args>
constexpr auto parameters_from_impl(R(Cls::*)(Args...)&&) -> pack_from_t<N, Args...>;
template <std::size_t N, typename R, typename Cls, typename... Args>
constexpr auto parameters_from_impl(R(Cls::*)(Args...)const &) -> pack_from_t<N, Args...>;
template <std::size_t N, typename R, typename Cls, typename... Args>
constexpr auto parameters_from_impl(R(Cls::*)(Args...)const &&) -> pack_from_t<N, Args...>;
template <std::size_t N, typename F>
constexpr auto parameters_from_impl(F&& fn) {
if constexpr (std::is_invocable_v<decltype(fn)>)
return parameters_from_impl<N>(&F::operator());
else
return parameters_from_impl<N>(fn);
}
template <std::size_t N, typename F>
using parameters_from_impl_t = decltype(parameters_from_impl<N>(std::declval<F>()));
} // ns eosio::vm::detail
template <typename R, typename... Args>
constexpr bool is_function(R(*)(Args...)) { return true; }
template <typename F>
constexpr bool is_function(F&&) { return false; }
template <typename R, typename Cls, typename... Args>
constexpr bool is_member_function(R(Cls::*)(Args...)) { return true; }
template <typename R, typename Cls, typename... Args>
constexpr bool is_member_function(R(Cls::*)(Args...)const ) { return true; }
template <typename R, typename Cls, typename... Args>
constexpr bool is_member_function(R(Cls::*)(Args...)& ) { return true; }
template <typename R, typename Cls, typename... Args>
constexpr bool is_member_function(R(Cls::*)(Args...)&& ) { return true; }
template <typename R, typename Cls, typename... Args>
constexpr bool is_member_function(R(Cls::*)(Args...)const & ) { return true; }
template <typename R, typename Cls, typename... Args>
constexpr bool is_member_function(R(Cls::*)(Args...)const && ) { return true; }
template <typename F>
constexpr bool is_member_function(F&&) { return false; }
template <auto FN>
inline constexpr static bool is_function_v = is_function(AUTO_PARAM_WORKAROUND(FN));
template <auto FN>
inline constexpr static bool is_member_function_v = is_member_function(AUTO_PARAM_WORKAROUND(FN));
template <typename F>
constexpr bool is_class(F&&) { return std::is_class_v<F>; }
template <typename F>
constexpr auto return_type(F&& fn) -> std::tuple_element_t<0, detail::get_types_t<false, F>>;
template <auto FN>
using return_type_t = decltype(return_type(AUTO_PARAM_WORKAROUND(FN)));
template <typename F>
constexpr auto class_from_member(F&& fn) -> std::tuple_element_t<1, detail::get_types_t<false, F>>;
template <auto FN>
using class_from_member_t = decltype(class_from_member(AUTO_PARAM_WORKAROUND(FN)));
template <typename F>
constexpr auto flatten_parameters(F&& fn) -> std::tuple_element_t<2, detail::get_types_t<false, F>>;
template <auto FN>
using flatten_parameters_t = decltype(flatten_parameters(AUTO_PARAM_WORKAROUND(FN)));
template <typename F>
constexpr auto decayed_flatten_parameters(F&& fn) -> std::tuple_element_t<2, detail::get_types_t<true, F>>;
template <auto FN>
using decayed_flatten_parameters_t = decltype(decayed_flatten_parameters(AUTO_PARAM_WORKAROUND(FN)));
template <std::size_t N, typename F>
constexpr auto parameter_at(F&& fn) -> std::tuple_element_t<N,
decltype(flatten_parameters(std::declval<F>()))>;
template <std::size_t N, auto FN>
using parameter_at_t = decltype(parameter_at<N>(AUTO_PARAM_WORKAROUND(FN)));
template <std::size_t N, typename F>
constexpr auto parameters_from(F&& fn) -> detail::parameters_from_impl_t<N, F>;
template <std::size_t N, auto FN>
using parameters_from_t = decltype(parameters_from<N>(AUTO_PARAM_WORKAROUND(FN)));
template <typename F>
inline constexpr static std::size_t arity(F&& fn) { return std::tuple_size_v<decltype(flatten_parameters(fn))>; }
template <auto FN>
inline constexpr static std::size_t arity_v = arity(FN);
}}