1 #ifndef ENTT_SIGNAL_DELEGATE_HPP
2 #define ENTT_SIGNAL_DELEGATE_HPP
10 #include "../config/config.h"
25 template<
typename Ret,
typename... Args>
26 auto function_pointer(Ret(*)(Args...)) -> Ret(*)(Args...);
29 template<
typename Ret,
typename Type,
typename... Args,
typename Other>
30 auto function_pointer(Ret(*)(Type, Args...), Other &&) -> Ret(*)(Args...);
33 template<
typename Class,
typename Ret,
typename... Args,
typename... Other>
34 auto function_pointer(Ret(Class:: *)(Args...), Other &&...) -> Ret(*)(Args...);
37 template<
typename Class,
typename Ret,
typename... Args,
typename... Other>
38 auto function_pointer(Ret(Class:: *)(Args...)
const, Other &&...) -> Ret(*)(Args...);
41 template<
typename Class,
typename Type,
typename... Other>
42 auto function_pointer(Type Class:: *, Other &&...) -> Type(*)();
45 template<
typename... Type>
46 using function_pointer_t = decltype(internal::function_pointer(std::declval<Type>()...));
49 template<
typename... Class,
typename Ret,
typename... Args>
50 constexpr
auto index_sequence_for(Ret(*)(Args...)) {
51 return std::index_sequence_for<Class..., Args...>{};
96 template<
typename Ret,
typename... Args>
98 using proto_fn_type = Ret(
const void *, Args...);
100 template<
auto Candidate, std::size_t... Index>
101 auto wrap(std::index_sequence<Index...>) ENTT_NOEXCEPT {
102 return [](
const void *, Args... args) -> Ret {
103 const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
104 return Ret(std::invoke(Candidate, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(arguments))...));
108 template<
auto Candidate,
typename Type, std::size_t... Index>
109 auto wrap(Type &, std::index_sequence<Index...>) ENTT_NOEXCEPT {
110 return [](
const void *payload, Args... args) -> Ret {
111 const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
112 Type *curr = static_cast<Type *>(
const_cast<std::conditional_t<std::is_const_v<Type>,
const void *,
void *
>>(payload));
113 return Ret(std::invoke(Candidate, *curr, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(arguments))...));
117 template<
auto Candidate,
typename Type, std::size_t... Index>
118 auto wrap(Type *, std::index_sequence<Index...>) ENTT_NOEXCEPT {
119 return [](
const void *payload, Args... args) -> Ret {
120 const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
121 Type *curr = static_cast<Type *>(
const_cast<std::conditional_t<std::is_const_v<Type>,
const void *,
void *
>>(payload));
122 return Ret(std::invoke(Candidate, curr, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(arguments))...));
132 : fn{
nullptr}, data{
nullptr}
140 template<auto Cand
idate>
144 connect<Candidate>();
154 template<auto Cand
idate,
typename Type>
158 connect<Candidate>(std::forward<Type>(value_or_instance));
165 template<auto Cand
idate>
169 if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Args...>) {
170 fn = [](
const void *, Args... args) -> Ret {
171 return Ret(std::invoke(Candidate, std::forward<Args>(args)...));
173 }
else if constexpr(std::is_member_pointer_v<decltype(Candidate)>) {
174 fn = wrap<Candidate>(internal::index_sequence_for<std::tuple_element_t<0, std::tuple<Args...>>>(internal::function_pointer_t<decltype(Candidate)>{}));
176 fn = wrap<Candidate>(internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate)>{}));
195 template<auto Cand
idate,
typename Type>
196 void connect(Type &value_or_instance) ENTT_NOEXCEPT {
197 data = &value_or_instance;
199 if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Type &, Args...>) {
200 fn = [](
const void *payload, Args... args) -> Ret {
201 Type *curr = static_cast<Type *>(
const_cast<std::conditional_t<std::is_const_v<Type>,
const void *,
void *
>>(payload));
202 return Ret(std::invoke(Candidate, *curr, std::forward<Args>(args)...));
205 fn = wrap<Candidate>(value_or_instance, internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate), Type>{}));
219 template<auto Cand
idate,
typename Type>
220 void connect(Type *value_or_instance) ENTT_NOEXCEPT {
221 data = value_or_instance;
223 if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Type *, Args...>) {
224 fn = [](
const void *payload, Args... args) -> Ret {
225 Type *curr = static_cast<Type *>(
const_cast<std::conditional_t<std::is_const_v<Type>,
const void *,
void *
>>(payload));
226 return Ret(std::invoke(Candidate, curr, std::forward<Args>(args)...));
229 fn = wrap<Candidate>(value_or_instance, internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate), Type>{}));
267 return fn(data, std::forward<Args>(args)...);
274 explicit operator bool() const ENTT_NOEXCEPT {
276 return !(fn ==
nullptr);
285 return fn == other.fn && data == other.data;
302 template<
typename Ret,
typename... Args>
304 return !(lhs == rhs);
312 template<auto Cand
idate>
313 delegate(connect_arg_t<Candidate>) ENTT_NOEXCEPT
314 ->
delegate<std::remove_pointer_t<internal::function_pointer_t<decltype(Candidate)>>>;
322 template<auto Cand
idate,
typename Type>
323 delegate(connect_arg_t<Candidate>, Type &&) ENTT_NOEXCEPT
324 ->
delegate<std::remove_pointer_t<internal::function_pointer_t<decltype(Candidate), Type>>>;