EnTT  3.5.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 [[nodiscard]] 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>
71 inline constexpr connect_arg_t<Func> connect_arg{};
72 
73 
80 template<typename>
81 class delegate;
82 
83 
96 template<typename Ret, typename... Args>
97 class delegate<Ret(Args...)> {
98  template<auto Candidate, std::size_t... Index>
99  [[nodiscard]] auto wrap(std::index_sequence<Index...>) ENTT_NOEXCEPT {
100  return [](const void *, Args... args) -> Ret {
101  [[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
102  return Ret(std::invoke(Candidate, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(arguments))...));
103  };
104  }
105 
106  template<auto Candidate, typename Type, std::size_t... Index>
107  [[nodiscard]] auto wrap(Type &, std::index_sequence<Index...>) ENTT_NOEXCEPT {
108  return [](const void *payload, Args... args) -> Ret {
109  [[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
110  Type *curr = static_cast<Type *>(const_cast<std::conditional_t<std::is_const_v<Type>, const void *, void *>>(payload));
111  return Ret(std::invoke(Candidate, *curr, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(arguments))...));
112  };
113  }
114 
115  template<auto Candidate, typename Type, std::size_t... Index>
116  [[nodiscard]] auto wrap(Type *, std::index_sequence<Index...>) ENTT_NOEXCEPT {
117  return [](const void *payload, Args... args) -> Ret {
118  [[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
119  Type *curr = static_cast<Type *>(const_cast<std::conditional_t<std::is_const_v<Type>, const void *, void *>>(payload));
120  return Ret(std::invoke(Candidate, curr, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(arguments))...));
121  };
122  }
123 
124 public:
126  using function_type = Ret(const void *, Args...);
128  using type = Ret(Args...);
130  using result_type = Ret;
131 
133  delegate() ENTT_NOEXCEPT
134  : fn{nullptr}, data{nullptr}
135  {}
136 
142  template<auto Candidate>
144  connect<Candidate>();
145  }
146 
154  template<auto Candidate, typename Type>
155  delegate(connect_arg_t<Candidate>, Type &&value_or_instance) ENTT_NOEXCEPT {
156  connect<Candidate>(std::forward<Type>(value_or_instance));
157  }
158 
165  delegate(function_type *function, const void *payload = nullptr) ENTT_NOEXCEPT {
166  connect(function, payload);
167  }
168 
173  template<auto Candidate>
174  void connect() ENTT_NOEXCEPT {
175  data = nullptr;
176 
177  if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Args...>) {
178  fn = [](const void *, Args... args) -> Ret {
179  return Ret(std::invoke(Candidate, std::forward<Args>(args)...));
180  };
181  } else if constexpr(std::is_member_pointer_v<decltype(Candidate)>) {
182  fn = wrap<Candidate>(internal::index_sequence_for<std::tuple_element_t<0, std::tuple<Args...>>>(internal::function_pointer_t<decltype(Candidate)>{}));
183  } else {
184  fn = wrap<Candidate>(internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate)>{}));
185  }
186  }
187 
203  template<auto Candidate, typename Type>
204  void connect(Type &value_or_instance) ENTT_NOEXCEPT {
205  data = &value_or_instance;
206 
207  if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Type &, Args...>) {
208  fn = [](const void *payload, Args... args) -> Ret {
209  Type *curr = static_cast<Type *>(const_cast<std::conditional_t<std::is_const_v<Type>, const void *, void *>>(payload));
210  return Ret(std::invoke(Candidate, *curr, std::forward<Args>(args)...));
211  };
212  } else {
213  fn = wrap<Candidate>(value_or_instance, internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate), Type>{}));
214  }
215  }
216 
227  template<auto Candidate, typename Type>
228  void connect(Type *value_or_instance) ENTT_NOEXCEPT {
229  data = value_or_instance;
230 
231  if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Type *, Args...>) {
232  fn = [](const void *payload, Args... args) -> Ret {
233  Type *curr = static_cast<Type *>(const_cast<std::conditional_t<std::is_const_v<Type>, const void *, void *>>(payload));
234  return Ret(std::invoke(Candidate, curr, std::forward<Args>(args)...));
235  };
236  } else {
237  fn = wrap<Candidate>(value_or_instance, internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate), Type>{}));
238  }
239  }
240 
254  void connect(function_type *function, const void *payload = nullptr) ENTT_NOEXCEPT {
255  fn = function;
256  data = payload;
257  }
258 
264  void reset() ENTT_NOEXCEPT {
265  fn = nullptr;
266  data = nullptr;
267  }
268 
273  [[nodiscard]] const void * instance() const ENTT_NOEXCEPT {
274  return data;
275  }
276 
291  Ret operator()(Args... args) const {
292  ENTT_ASSERT(fn);
293  return fn(data, std::forward<Args>(args)...);
294  }
295 
300  [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
301  // no need to test also data
302  return !(fn == nullptr);
303  }
304 
310  [[nodiscard]] bool operator==(const delegate<Ret(Args...)> &other) const ENTT_NOEXCEPT {
311  return fn == other.fn && data == other.data;
312  }
313 
314 private:
315  function_type *fn;
316  const void *data;
317 };
318 
319 
328 template<typename Ret, typename... Args>
329 [[nodiscard]] bool operator!=(const delegate<Ret(Args...)> &lhs, const delegate<Ret(Args...)> &rhs) ENTT_NOEXCEPT {
330  return !(lhs == rhs);
331 }
332 
333 
338 template<auto Candidate>
340 -> delegate<std::remove_pointer_t<internal::function_pointer_t<decltype(Candidate)>>>;
341 
342 
348 template<auto Candidate, typename Type>
349 delegate(connect_arg_t<Candidate>, Type &&) ENTT_NOEXCEPT
350 -> delegate<std::remove_pointer_t<internal::function_pointer_t<decltype(Candidate), Type>>>;
351 
352 
354 template<typename Ret, typename... Args>
355 delegate(Ret(*)(const void *, Args...), const void * = nullptr) ENTT_NOEXCEPT
356 -> delegate<Ret(Args...)>;
357 
358 
359 }
360 
361 
362 #endif
entt::delegate< Ret(Args...)>::connect
void connect(function_type *function, const void *payload=nullptr) noexcept
Connects an user defined function with optional payload to a delegate.
Definition: delegate.hpp:254
entt::delegate< Ret(Args...)>::type
Ret(Args...) type
Function type of the delegate.
Definition: delegate.hpp:128
entt::delegate< Ret(Args...)>::delegate
delegate() noexcept
Default constructor.
Definition: delegate.hpp:133
entt::delegate< Ret(Args...)>::reset
void reset() noexcept
Resets a delegate.
Definition: delegate.hpp:264
entt::delegate< Ret(Args...)>::operator()
Ret operator()(Args... args) const
Triggers a delegate.
Definition: delegate.hpp:291
entt::delegate< Ret(Args...)>::function_type
Ret(const void *, Args...) function_type
Function type of the contained target.
Definition: delegate.hpp:126
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< Ret(Args...)>::connect
void connect(Type &value_or_instance) noexcept
Connects a free function with payload or a bound member to a delegate.
Definition: delegate.hpp:204
entt::delegate
delegate(connect_arg_t< Candidate >) noexcept -> delegate< std::remove_pointer_t< internal::function_pointer_t< decltype(Candidate)>>>
Deduction guide.
entt
EnTT default namespace.
Definition: algorithm.hpp:13
entt::delegate< Ret(Args...)>::result_type
Ret result_type
Return type of the delegate.
Definition: delegate.hpp:130
entt::delegate< Ret(Args...)>::operator==
bool operator==(const delegate< Ret(Args...)> &other) const noexcept
Compares the contents of two delegates.
Definition: delegate.hpp:310
entt::delegate< Ret(Args...)>::delegate
delegate(function_type *function, const void *payload=nullptr) noexcept
Constructs a delegate and connects an user defined function with optional payload.
Definition: delegate.hpp:165
entt::delegate< Ret(Args...)>::connect
void connect(Type *value_or_instance) noexcept
Connects a free function with payload or a bound member to a delegate.
Definition: delegate.hpp:228
entt::connect_arg_t
Used to wrap a function or a member of a specified type.
Definition: delegate.hpp:66
entt::delegate< Ret(Args...)>::connect
void connect() noexcept
Connects a free function or an unbound member to a delegate.
Definition: delegate.hpp:174
entt::delegate< Ret(Args...)>::delegate
delegate(connect_arg_t< Candidate >) noexcept
Constructs a delegate and connects a free function or an unbound member.
Definition: delegate.hpp:143
entt::operator!=
constexpr bool operator!=(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs) noexcept
Compares two hashed strings.
Definition: hashed_string.hpp:227
entt::delegate< Ret(Args...)>::delegate
delegate(connect_arg_t< Candidate >, Type &&value_or_instance) 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...)>::instance
const void * instance() const noexcept
Returns the instance or the payload linked to a delegate, if any.
Definition: delegate.hpp:273