EnTT  3.2.2
delegate.hpp
1 #ifndef ENTT_SIGNAL_DELEGATE_HPP
2 #define ENTT_SIGNAL_DELEGATE_HPP
3 
4 
5 #include <tuple>
6 #include <cstring>
7 #include <utility>
8 #include <algorithm>
9 #include <functional>
10 #include <type_traits>
11 #include "../config/config.h"
12 
13 
14 namespace entt {
15 
16 
23 namespace internal {
24 
25 
26 template<typename Ret, typename... Args>
27 auto to_function_pointer(Ret(*)(Args...)) -> Ret(*)(Args...);
28 
29 
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...);
32 
33 
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...);
36 
37 
38 template<typename Class, typename Ret, typename... Args>
39 auto to_function_pointer(Ret(Class:: *)(Args...), const Class *) -> Ret(*)(Args...);
40 
41 
42 template<typename Class, typename Ret, typename... Args>
43 auto to_function_pointer(Ret(Class:: *)(Args...) const, const Class *) -> Ret(*)(Args...);
44 
45 
46 template<typename Class, typename Type>
47 auto to_function_pointer(Type Class:: *, const Class *) -> Type(*)();
48 
49 
50 template<typename... Type>
51 using to_function_pointer_t = decltype(internal::to_function_pointer(std::declval<Type>()...));
52 
53 
54 template<typename Ret, typename... Args>
55 constexpr auto index_sequence_for(Ret(*)(Args...)) {
56  return std::index_sequence_for<Args...>{};
57 }
58 
59 
60 }
61 
62 
70 template<auto>
71 struct connect_arg_t {};
72 
73 
75 template<auto Func>
77 
78 
85 template<typename>
86 class delegate;
87 
88 
102 template<typename Ret, typename... Args>
103 class delegate<Ret(Args...)> {
104  using proto_fn_type = Ret(const void *, std::tuple<Args &&...>);
105 
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...>>...>);
109  data = nullptr;
110 
111  fn = [](const void *, std::tuple<Args &&...> args) -> Ret {
112  // Ret(...) makes void(...) eat the return values to avoid errors
113  return Ret(std::invoke(Function, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(args))...));
114  };
115  }
116 
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;
121 
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));
124  // Ret(...) makes void(...) eat the return values to avoid errors
125  return Ret(std::invoke(Candidate, *curr, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(args))...));
126  };
127  }
128 
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;
133 
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));
136  // Ret(...) makes void(...) eat the return values to avoid errors
137  return Ret(std::invoke(Candidate, curr, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(args))...));
138  };
139  }
140 
141 public:
143  using function_type = Ret(Args...);
144 
146  delegate() ENTT_NOEXCEPT
147  : fn{nullptr}, data{nullptr}
148  {}
149 
154  template<auto Function>
156  : delegate{}
157  {
158  connect<Function>();
159  }
160 
168  template<auto Candidate, typename Type>
169  delegate(connect_arg_t<Candidate>, Type &value_or_instance) ENTT_NOEXCEPT
170  : delegate{}
171  {
172  connect<Candidate>(value_or_instance);
173  }
174 
182  template<auto Candidate, typename Type>
183  delegate(connect_arg_t<Candidate>, Type *value_or_instance) ENTT_NOEXCEPT
184  : delegate{}
185  {
186  connect<Candidate>(value_or_instance);
187  }
188 
193  template<auto Function>
194  void connect() ENTT_NOEXCEPT {
195  connect<Function>(internal::index_sequence_for(internal::to_function_pointer_t<decltype(Function)>{}));
196  }
197 
213  template<auto Candidate, 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 *>{}));
216  }
217 
233  template<auto Candidate, 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 *>{}));
236  }
237 
243  void reset() ENTT_NOEXCEPT {
244  fn = nullptr;
245  data = nullptr;
246  }
247 
252  const void * instance() const ENTT_NOEXCEPT {
253  return data;
254  }
255 
270  Ret operator()(Args... args) const {
271  ENTT_ASSERT(fn);
272  return fn(data, std::forward_as_tuple(std::forward<Args>(args)...));
273  }
274 
279  explicit operator bool() const ENTT_NOEXCEPT {
280  // no need to test also data
281  return fn;
282  }
283 
289  bool operator==(const delegate<Ret(Args...)> &other) const ENTT_NOEXCEPT {
290  return fn == other.fn && data == other.data;
291  }
292 
293 private:
294  proto_fn_type *fn;
295  const void *data;
296 };
297 
298 
307 template<typename Ret, typename... Args>
308 bool operator!=(const delegate<Ret(Args...)> &lhs, const delegate<Ret(Args...)> &rhs) ENTT_NOEXCEPT {
309  return !(lhs == rhs);
310 }
311 
312 
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)>>>;
324 
325 
335 template<auto Candidate, 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 *>>>;
338 
339 
349 template<auto Candidate, 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 *>>>;
352 
353 
354 }
355 
356 
357 #endif // ENTT_SIGNAL_DELEGATE_HPP
entt::delegate< Ret(Args...)>::delegate
delegate(connect_arg_t< Function >) ENTT_NOEXCEPT
Constructs a delegate and connects a free function to it.
Definition: delegate.hpp:155
entt::delegate< Ret(Args...)>::reset
void reset() ENTT_NOEXCEPT
Resets a delegate.
Definition: delegate.hpp:243
entt::delegate< Ret(Args...)>::connect
void connect(Type &value_or_instance) ENTT_NOEXCEPT
Connects a member function for a given instance or a free function with payload to a delegate.
Definition: delegate.hpp:214
entt::delegate
delegate(connect_arg_t< Function >) ENTT_NOEXCEPT -> delegate< std::remove_pointer_t< internal::to_function_pointer_t< decltype(Function)>>>
Deduction guide.
entt::delegate< Ret(Args...)>::operator()
Ret operator()(Args... args) const
Triggers a delegate.
Definition: delegate.hpp:270
entt::connect_arg
constexpr connect_arg_t< Func > connect_arg
Constant of type connect_arg_t used to disambiguate calls.
Definition: delegate.hpp:76
entt::delegate< Ret(Args...)>::delegate
delegate(connect_arg_t< Candidate >, Type &value_or_instance) ENTT_NOEXCEPT
Constructs a delegate and connects a member for a given instance or a free function with payload.
Definition: delegate.hpp:169
entt::delegate< Ret(Args...)>::delegate
delegate() ENTT_NOEXCEPT
Default constructor.
Definition: delegate.hpp:146
entt::delegate< Ret(Args...)>::connect
void connect() ENTT_NOEXCEPT
Connects a free function to a delegate.
Definition: delegate.hpp:194
entt
EnTT default namespace.
Definition: algorithm.hpp:12
entt::delegate< Ret(Args...)>::function_type
Ret(Args...) function_type
Function type of the delegate.
Definition: delegate.hpp:143
entt::delegate< Ret(Args...)>::instance
const void * instance() const ENTT_NOEXCEPT
Returns the instance or the payload linked to a delegate, if any.
Definition: delegate.hpp:252
entt::operator!=
constexpr bool operator!=(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs) ENTT_NOEXCEPT
Compares two hashed strings.
Definition: hashed_string.hpp:217
entt::connect_arg_t
Used to wrap a function or a member of a specified type.
Definition: delegate.hpp:71
entt::delegate< Ret(Args...)>::delegate
delegate(connect_arg_t< Candidate >, Type *value_or_instance) ENTT_NOEXCEPT
Constructs a delegate and connects a member for a given instance or a free function with payload.
Definition: delegate.hpp:183
entt::delegate
Basic delegate implementation.
Definition: delegate.hpp:86
entt::delegate< Ret(Args...)>::operator==
bool operator==(const delegate< Ret(Args...)> &other) const ENTT_NOEXCEPT
Compares the contents of two delegates.
Definition: delegate.hpp:289
entt::delegate< Ret(Args...)>::connect
void connect(Type *value_or_instance) ENTT_NOEXCEPT
Connects a member function for a given instance or a free function with payload to a delegate.
Definition: delegate.hpp:234