1 #ifndef ENTT_SIGNAL_DELEGATE_HPP
2 #define ENTT_SIGNAL_DELEGATE_HPP
10 #include <type_traits>
11 #include "../config/config.h"
26 template<
typename Ret,
typename... Args>
27 auto to_function_pointer(Ret(*)(Args...)) -> Ret(*)(Args...);
30 template<
typename Ret,
typename... Args,
typename Type,
typename Payload,
typename = std::enable_if_t<std::is_convertible_v<const Payload *, const Type *>>>
31 auto to_function_pointer(Ret(*)(Type &, Args...),
const Payload *) -> Ret(*)(Args...);
34 template<
typename Ret,
typename... Args,
typename Type,
typename Payload,
typename = std::enable_if_t<std::is_convertible_v<const Payload *, const Type *>>>
35 auto to_function_pointer(Ret(*)(Type *, Args...),
const Payload *) -> Ret(*)(Args...);
38 template<
typename Class,
typename Ret,
typename... Args>
39 auto to_function_pointer(Ret(Class:: *)(Args...),
const Class *) -> Ret(*)(Args...);
42 template<
typename Class,
typename Ret,
typename... Args>
43 auto to_function_pointer(Ret(Class:: *)(Args...)
const,
const Class *) -> Ret(*)(Args...);
46 template<
typename Class,
typename Type>
47 auto to_function_pointer(Type Class:: *,
const Class *) -> Type(*)();
50 template<
typename... Type>
51 using to_function_pointer_t = decltype(internal::to_function_pointer(std::declval<Type>()...));
54 template<
typename Ret,
typename... Args>
55 constexpr
auto index_sequence_for(Ret(*)(Args...)) {
56 return std::index_sequence_for<Args...>{};
102 template<
typename Ret,
typename... Args>
104 using proto_fn_type = Ret(
const void *, std::tuple<Args &&...>);
106 template<
auto Function, std::size_t... Index>
107 void connect(std::index_sequence<Index...>) ENTT_NOEXCEPT {
108 static_assert(std::is_invocable_r_v<Ret, decltype(Function), std::tuple_element_t<Index, std::tuple<Args...>>...>);
111 fn = [](
const void *, std::tuple<Args &&...> args) -> Ret {
113 return Ret(std::invoke(Function, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(args))...));
117 template<
auto Candidate,
typename Type, std::size_t... Index>
118 void connect(Type &value_or_instance, std::index_sequence<Index...>) ENTT_NOEXCEPT {
119 static_assert(std::is_invocable_r_v<Ret, decltype(Candidate), Type &, std::tuple_element_t<Index, std::tuple<Args...>>...>);
120 data = &value_or_instance;
122 fn = [](
const void *payload, std::tuple<Args &&...> args) -> Ret {
123 Type *curr = static_cast<Type *>(
const_cast<std::conditional_t<std::is_const_v<Type>,
const void *,
void *
>>(payload));
125 return Ret(std::invoke(Candidate, *curr, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(args))...));
129 template<
auto Candidate,
typename Type, std::size_t... Index>
130 void connect(Type *value_or_instance, std::index_sequence<Index...>) ENTT_NOEXCEPT {
131 static_assert(std::is_invocable_r_v<Ret, decltype(Candidate), Type *, std::tuple_element_t<Index, std::tuple<Args...>>...>);
132 data = value_or_instance;
134 fn = [](
const void *payload, std::tuple<Args &&...> args) -> Ret {
135 Type *curr = static_cast<Type *>(
const_cast<std::conditional_t<std::is_const_v<Type>,
const void *,
void *
>>(payload));
137 return Ret(std::invoke(Candidate, curr, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(args))...));
147 : fn{
nullptr}, data{
nullptr}
154 template<auto Function>
168 template<auto Cand
idate,
typename Type>
172 connect<Candidate>(value_or_instance);
182 template<auto Cand
idate,
typename Type>
186 connect<Candidate>(value_or_instance);
193 template<auto Function>
195 connect<Function>(internal::index_sequence_for(internal::to_function_pointer_t<decltype(Function)>{}));
213 template<auto Cand
idate,
typename Type>
214 void connect(Type &value_or_instance) ENTT_NOEXCEPT {
215 connect<Candidate>(value_or_instance, internal::index_sequence_for(internal::to_function_pointer_t<decltype(Candidate), Type *>{}));
233 template<auto Cand
idate,
typename Type>
234 void connect(Type *value_or_instance) ENTT_NOEXCEPT {
235 connect<Candidate>(value_or_instance, internal::index_sequence_for(internal::to_function_pointer_t<decltype(Candidate), Type *>{}));
272 return fn(data, std::forward_as_tuple(std::forward<Args>(args)...));
279 explicit operator bool() const ENTT_NOEXCEPT {
290 return fn == other.fn && data == other.data;
307 template<
typename Ret,
typename... Args>
309 return !(lhs == rhs);
321 template<auto Function>
322 delegate(connect_arg_t<Function>) ENTT_NOEXCEPT
323 ->
delegate<std::remove_pointer_t<internal::to_function_pointer_t<decltype(Function)>>>;
335 template<auto Cand
idate,
typename Type>
336 delegate(connect_arg_t<Candidate>, Type &) ENTT_NOEXCEPT
337 ->
delegate<std::remove_pointer_t<internal::to_function_pointer_t<decltype(Candidate), Type *>>>;
349 template<auto Cand
idate,
typename Type>
350 delegate(connect_arg_t<Candidate>, Type *) ENTT_NOEXCEPT
351 ->
delegate<std::remove_pointer_t<internal::to_function_pointer_t<decltype(Candidate), Type *>>>;
357 #endif // ENTT_SIGNAL_DELEGATE_HPP