EnTT  3.8.1
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 "../core/type_traits.hpp"
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 function_pointer(Ret(*)(Args...)) -> Ret(*)(Args...);
28 
29 
30 template<typename Ret, typename Type, typename... Args, typename Other>
31 auto function_pointer(Ret(*)(Type, Args...), Other &&) -> Ret(*)(Args...);
32 
33 
34 template<typename Class, typename Ret, typename... Args, typename... Other>
35 auto function_pointer(Ret(Class:: *)(Args...), Other &&...) -> Ret(*)(Args...);
36 
37 
38 template<typename Class, typename Ret, typename... Args, typename... Other>
39 auto function_pointer(Ret(Class:: *)(Args...) const, Other &&...) -> Ret(*)(Args...);
40 
41 
42 template<typename Class, typename Type, typename... Other>
43 auto function_pointer(Type Class:: *, Other &&...) -> Type(*)();
44 
45 
46 template<typename... Type>
47 using function_pointer_t = decltype(internal::function_pointer(std::declval<Type>()...));
48 
49 
50 template<typename... Class, typename Ret, typename... Args>
51 [[nodiscard]] constexpr auto index_sequence_for(Ret(*)(Args...)) {
52  return std::index_sequence_for<Class..., Args...>{};
53 }
54 
55 
56 }
57 
58 
66 template<auto>
67 struct connect_arg_t {};
68 
69 
71 template<auto Func>
72 inline constexpr connect_arg_t<Func> connect_arg{};
73 
74 
81 template<typename>
82 class delegate;
83 
84 
97 template<typename Ret, typename... Args>
98 class delegate<Ret(Args...)> {
99  template<auto Candidate, std::size_t... Index>
100  [[nodiscard]] auto wrap(std::index_sequence<Index...>) ENTT_NOEXCEPT {
101  return [](const void *, Args... args) -> Ret {
102  [[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
103  return static_cast<Ret>(std::invoke(Candidate, std::forward<type_list_element_t<Index, type_list<Args...>>>(std::get<Index>(arguments))...));
104  };
105  }
106 
107  template<auto Candidate, typename Type, std::size_t... Index>
108  [[nodiscard]] auto wrap(Type &, std::index_sequence<Index...>) ENTT_NOEXCEPT {
109  return [](const void *payload, Args... args) -> Ret {
110  [[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
111  Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
112  return static_cast<Ret>(std::invoke(Candidate, *curr, std::forward<type_list_element_t<Index, type_list<Args...>>>(std::get<Index>(arguments))...));
113  };
114  }
115 
116  template<auto Candidate, typename Type, std::size_t... Index>
117  [[nodiscard]] auto wrap(Type *, std::index_sequence<Index...>) ENTT_NOEXCEPT {
118  return [](const void *payload, Args... args) -> Ret {
119  [[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
120  Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
121  return static_cast<Ret>(std::invoke(Candidate, curr, std::forward<type_list_element_t<Index, type_list<Args...>>>(std::get<Index>(arguments))...));
122  };
123  }
124 
125 public:
127  using function_type = Ret(const void *, Args...);
129  using type = Ret(Args...);
131  using result_type = Ret;
132 
134  delegate() ENTT_NOEXCEPT
135  : fn{nullptr}, data{nullptr}
136  {}
137 
143  template<auto Candidate>
145  connect<Candidate>();
146  }
147 
155  template<auto Candidate, typename Type>
156  delegate(connect_arg_t<Candidate>, Type &&value_or_instance) ENTT_NOEXCEPT {
157  connect<Candidate>(std::forward<Type>(value_or_instance));
158  }
159 
166  delegate(function_type *function, const void *payload = nullptr) ENTT_NOEXCEPT {
167  connect(function, payload);
168  }
169 
174  template<auto Candidate>
175  void connect() ENTT_NOEXCEPT {
176  data = nullptr;
177 
178  if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Args...>) {
179  fn = [](const void *, Args... args) -> Ret {
180  return Ret(std::invoke(Candidate, std::forward<Args>(args)...));
181  };
182  } else if constexpr(std::is_member_pointer_v<decltype(Candidate)>) {
183  fn = wrap<Candidate>(internal::index_sequence_for<type_list_element_t<0, type_list<Args...>>>(internal::function_pointer_t<decltype(Candidate)>{}));
184  } else {
185  fn = wrap<Candidate>(internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate)>{}));
186  }
187  }
188 
204  template<auto Candidate, typename Type>
205  void connect(Type &value_or_instance) ENTT_NOEXCEPT {
206  data = &value_or_instance;
207 
208  if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Type &, Args...>) {
209  fn = [](const void *payload, Args... args) -> Ret {
210  Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
211  return Ret(std::invoke(Candidate, *curr, std::forward<Args>(args)...));
212  };
213  } else {
214  fn = wrap<Candidate>(value_or_instance, internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate), Type>{}));
215  }
216  }
217 
228  template<auto Candidate, typename Type>
229  void connect(Type *value_or_instance) ENTT_NOEXCEPT {
230  data = value_or_instance;
231 
232  if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Type *, Args...>) {
233  fn = [](const void *payload, Args... args) -> Ret {
234  Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
235  return Ret(std::invoke(Candidate, curr, std::forward<Args>(args)...));
236  };
237  } else {
238  fn = wrap<Candidate>(value_or_instance, internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate), Type>{}));
239  }
240  }
241 
255  void connect(function_type *function, const void *payload = nullptr) ENTT_NOEXCEPT {
256  fn = function;
257  data = payload;
258  }
259 
265  void reset() ENTT_NOEXCEPT {
266  fn = nullptr;
267  data = nullptr;
268  }
269 
274  [[nodiscard]] const void * instance() const ENTT_NOEXCEPT {
275  return data;
276  }
277 
290  Ret operator()(Args... args) const {
291  ENTT_ASSERT(static_cast<bool>(*this), "Uninitialized delegate");
292  return fn(data, std::forward<Args>(args)...);
293  }
294 
299  [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
300  // no need to test also data
301  return !(fn == nullptr);
302  }
303 
309  [[nodiscard]] bool operator==(const delegate<Ret(Args...)> &other) const ENTT_NOEXCEPT {
310  return fn == other.fn && data == other.data;
311  }
312 
313 private:
314  function_type *fn;
315  const void *data;
316 };
317 
318 
327 template<typename Ret, typename... Args>
328 [[nodiscard]] bool operator!=(const delegate<Ret(Args...)> &lhs, const delegate<Ret(Args...)> &rhs) ENTT_NOEXCEPT {
329  return !(lhs == rhs);
330 }
331 
332 
337 template<auto Candidate>
339 -> delegate<std::remove_pointer_t<internal::function_pointer_t<decltype(Candidate)>>>;
340 
341 
347 template<auto Candidate, typename Type>
349 -> delegate<std::remove_pointer_t<internal::function_pointer_t<decltype(Candidate), Type>>>;
350 
351 
357 template<typename Ret, typename... Args>
358 delegate(Ret(*)(const void *, Args...), const void * = nullptr)
359 -> delegate<Ret(Args...)>;
360 
361 
362 }
363 
364 
365 #endif
Ret operator()(Args... args) const
Triggers a delegate.
Definition: delegate.hpp:290
const void * instance() const
Returns the instance or the payload linked to a delegate, if any.
Definition: delegate.hpp:274
Ret(const void *, Args...) function_type
Function type of the contained target.
Definition: delegate.hpp:127
void reset()
Resets a delegate.
Definition: delegate.hpp:265
delegate()
Default constructor.
Definition: delegate.hpp:134
delegate(connect_arg_t< Candidate >)
Constructs a delegate and connects a free function or an unbound member.
Definition: delegate.hpp:144
void connect(function_type *function, const void *payload=nullptr)
Connects an user defined function with optional payload to a delegate.
Definition: delegate.hpp:255
delegate(connect_arg_t< Candidate >, Type &&value_or_instance)
Constructs a delegate and connects a free function with payload or a bound member.
Definition: delegate.hpp:156
Ret result_type
Return type of the delegate.
Definition: delegate.hpp:131
void connect(Type *value_or_instance)
Connects a free function with payload or a bound member to a delegate.
Definition: delegate.hpp:229
bool operator==(const delegate< Ret(Args...)> &other) const
Compares the contents of two delegates.
Definition: delegate.hpp:309
void connect()
Connects a free function or an unbound member to a delegate.
Definition: delegate.hpp:175
Ret(Args...) type
Function type of the delegate.
Definition: delegate.hpp:129
delegate(function_type *function, const void *payload=nullptr)
Constructs a delegate and connects an user defined function with optional payload.
Definition: delegate.hpp:166
void connect(Type &value_or_instance)
Connects a free function with payload or a bound member to a delegate.
Definition: delegate.hpp:205
Basic delegate implementation.
Definition: delegate.hpp:82
EnTT default namespace.
Definition: algorithm.hpp:13
typename constness_as< To, From >::type constness_as_t
Alias template to facilitate the transcription of the constness.
delegate(connect_arg_t< Candidate >) -> delegate< std::remove_pointer_t< internal::function_pointer_t< decltype(Candidate)>>>
Deduction guide.
typename type_list_element< Index, List >::type type_list_element_t
Helper type.
bool operator!=(const basic_any< Len, Align > &lhs, const basic_any< Len, Align > &rhs)
Checks if two wrappers differ in their content.
Definition: any.hpp:368
constexpr connect_arg_t< Func > connect_arg
Constant of type connect_arg_t used to disambiguate calls.
Definition: delegate.hpp:72
Used to wrap a function or a member of a specified type.
Definition: delegate.hpp:67
A class to use to push around lists of types, nothing more.