EnTT  3.3.2
delegate.hpp
1 #ifndef ENTT_SIGNAL_DELEGATE_HPP
2 #define ENTT_SIGNAL_DELEGATE_HPP
3 
4 
5 #include <tuple>
6 #include <cstddef>
7 #include <utility>
8 #include <functional>
9 #include <type_traits>
10 #include "../config/config.h"
11 
12 
13 namespace entt {
14 
15 
22 namespace internal {
23 
24 
25 template<typename Ret, typename... Args>
26 auto function_pointer(Ret(*)(Args...)) -> Ret(*)(Args...);
27 
28 
29 template<typename Ret, typename Type, typename... Args, typename Other>
30 auto function_pointer(Ret(*)(Type, Args...), Other &&) -> Ret(*)(Args...);
31 
32 
33 template<typename Class, typename Ret, typename... Args, typename... Other>
34 auto function_pointer(Ret(Class:: *)(Args...), Other &&...) -> Ret(*)(Args...);
35 
36 
37 template<typename Class, typename Ret, typename... Args, typename... Other>
38 auto function_pointer(Ret(Class:: *)(Args...) const, Other &&...) -> Ret(*)(Args...);
39 
40 
41 template<typename Class, typename Type, typename... Other>
42 auto function_pointer(Type Class:: *, Other &&...) -> Type(*)();
43 
44 
45 template<typename... Type>
46 using function_pointer_t = decltype(internal::function_pointer(std::declval<Type>()...));
47 
48 
49 template<typename... Class, typename Ret, typename... Args>
50 constexpr auto index_sequence_for(Ret(*)(Args...)) {
51  return std::index_sequence_for<Class..., Args...>{};
52 }
53 
54 
55 }
56 
57 
65 template<auto>
66 struct connect_arg_t {};
67 
68 
70 template<auto Func>
72 
73 
80 template<typename>
81 class delegate;
82 
83 
96 template<typename Ret, typename... Args>
97 class delegate<Ret(Args...)> {
98  using proto_fn_type = Ret(const void *, Args...);
99 
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))...));
105  };
106  }
107 
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))...));
114  };
115  }
116 
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))...));
123  };
124  }
125 
126 public:
128  using function_type = Ret(Args...);
129 
131  delegate() ENTT_NOEXCEPT
132  : fn{nullptr}, data{nullptr}
133  {}
134 
140  template<auto Candidate>
142  : delegate{}
143  {
144  connect<Candidate>();
145  }
146 
154  template<auto Candidate, typename Type>
155  delegate(connect_arg_t<Candidate>, Type &&value_or_instance) ENTT_NOEXCEPT
156  : delegate{}
157  {
158  connect<Candidate>(std::forward<Type>(value_or_instance));
159  }
160 
165  template<auto Candidate>
166  void connect() ENTT_NOEXCEPT {
167  data = nullptr;
168 
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)...));
172  };
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)>{}));
175  } else {
176  fn = wrap<Candidate>(internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate)>{}));
177  }
178  }
179 
195  template<auto Candidate, typename Type>
196  void connect(Type &value_or_instance) ENTT_NOEXCEPT {
197  data = &value_or_instance;
198 
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)...));
203  };
204  } else {
205  fn = wrap<Candidate>(value_or_instance, internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate), Type>{}));
206  }
207  }
208 
219  template<auto Candidate, typename Type>
220  void connect(Type *value_or_instance) ENTT_NOEXCEPT {
221  data = value_or_instance;
222 
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)...));
227  };
228  } else {
229  fn = wrap<Candidate>(value_or_instance, internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate), Type>{}));
230  }
231  }
232 
238  void reset() ENTT_NOEXCEPT {
239  fn = nullptr;
240  data = nullptr;
241  }
242 
247  const void * instance() const ENTT_NOEXCEPT {
248  return data;
249  }
250 
265  Ret operator()(Args... args) const {
266  ENTT_ASSERT(fn);
267  return fn(data, std::forward<Args>(args)...);
268  }
269 
274  explicit operator bool() const ENTT_NOEXCEPT {
275  // no need to test also data
276  return !(fn == nullptr);
277  }
278 
284  bool operator==(const delegate<Ret(Args...)> &other) const ENTT_NOEXCEPT {
285  return fn == other.fn && data == other.data;
286  }
287 
288 private:
289  proto_fn_type *fn;
290  const void *data;
291 };
292 
293 
302 template<typename Ret, typename... Args>
303 bool operator!=(const delegate<Ret(Args...)> &lhs, const delegate<Ret(Args...)> &rhs) ENTT_NOEXCEPT {
304  return !(lhs == rhs);
305 }
306 
307 
312 template<auto Candidate>
313 delegate(connect_arg_t<Candidate>) ENTT_NOEXCEPT
314 -> delegate<std::remove_pointer_t<internal::function_pointer_t<decltype(Candidate)>>>;
315 
316 
322 template<auto Candidate, typename Type>
323 delegate(connect_arg_t<Candidate>, Type &&) ENTT_NOEXCEPT
324 -> delegate<std::remove_pointer_t<internal::function_pointer_t<decltype(Candidate), Type>>>;
325 
326 
327 }
328 
329 
330 #endif
entt::delegate< Ret(Args...)>::reset
void reset() ENTT_NOEXCEPT
Resets a delegate.
Definition: delegate.hpp:238
entt::delegate< Ret(Args...)>::connect
void connect(Type &value_or_instance) ENTT_NOEXCEPT
Connects a free function with payload or a bound member to a delegate.
Definition: delegate.hpp:196
entt::delegate< Ret(Args...)>::operator()
Ret operator()(Args... args) const
Triggers a delegate.
Definition: delegate.hpp:265
entt::connect_arg
constexpr connect_arg_t< Func > connect_arg
Constant of type connect_arg_t used to disambiguate calls.
Definition: delegate.hpp:71
entt::delegate
delegate(connect_arg_t< Candidate >) ENTT_NOEXCEPT -> delegate< std::remove_pointer_t< internal::function_pointer_t< decltype(Candidate)>>>
Deduction guide.
entt::delegate< Ret(Args...)>::delegate
delegate() ENTT_NOEXCEPT
Default constructor.
Definition: delegate.hpp:131
entt::delegate< Ret(Args...)>::connect
void connect() ENTT_NOEXCEPT
Connects a free function or an unbound member to a delegate.
Definition: delegate.hpp:166
entt
EnTT default namespace.
Definition: algorithm.hpp:13
entt::delegate< Ret(Args...)>::function_type
Ret(Args...) function_type
Function type of the delegate.
Definition: delegate.hpp:128
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:247
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:226
entt::connect_arg_t
Used to wrap a function or a member of a specified type.
Definition: delegate.hpp:66
entt::delegate< Ret(Args...)>::delegate
delegate(connect_arg_t< Candidate >, Type &&value_or_instance) ENTT_NOEXCEPT
Constructs a delegate and connects a free function with payload or a bound member.
Definition: delegate.hpp:155
entt::delegate
Basic delegate implementation.
Definition: delegate.hpp:81
entt::delegate< Ret(Args...)>::delegate
delegate(connect_arg_t< Candidate >) ENTT_NOEXCEPT
Constructs a delegate and connects a free function or an unbound member.
Definition: delegate.hpp:141
entt::delegate< Ret(Args...)>::operator==
bool operator==(const delegate< Ret(Args...)> &other) const ENTT_NOEXCEPT
Compares the contents of two delegates.
Definition: delegate.hpp:284
entt::delegate< Ret(Args...)>::connect
void connect(Type *value_or_instance) ENTT_NOEXCEPT
Connects a free function with payload or a bound member to a delegate.
Definition: delegate.hpp:220