EnTT  3.10.0
delegate.hpp
1 #ifndef ENTT_SIGNAL_DELEGATE_HPP
2 #define ENTT_SIGNAL_DELEGATE_HPP
3 
4 #include <cstddef>
5 #include <functional>
6 #include <tuple>
7 #include <type_traits>
8 #include <utility>
9 #include "../config/config.h"
10 #include "../core/type_traits.hpp"
11 #include "fwd.hpp"
12 
13 namespace entt {
14 
20 namespace internal {
21 
22 template<typename Ret, typename... Args>
23 auto function_pointer(Ret (*)(Args...)) -> Ret (*)(Args...);
24 
25 template<typename Ret, typename Type, typename... Args, typename Other>
26 auto function_pointer(Ret (*)(Type, Args...), Other &&) -> Ret (*)(Args...);
27 
28 template<typename Class, typename Ret, typename... Args, typename... Other>
29 auto function_pointer(Ret (Class::*)(Args...), Other &&...) -> Ret (*)(Args...);
30 
31 template<typename Class, typename Ret, typename... Args, typename... Other>
32 auto function_pointer(Ret (Class::*)(Args...) const, Other &&...) -> Ret (*)(Args...);
33 
34 template<typename Class, typename Type, typename... Other>
35 auto function_pointer(Type Class::*, Other &&...) -> Type (*)();
36 
37 template<typename... Type>
38 using function_pointer_t = decltype(internal::function_pointer(std::declval<Type>()...));
39 
40 template<typename... Class, typename Ret, typename... Args>
41 [[nodiscard]] constexpr auto index_sequence_for(Ret (*)(Args...)) {
42  return std::index_sequence_for<Class..., Args...>{};
43 }
44 
45 } // namespace internal
46 
53 template<auto>
54 struct connect_arg_t {};
55 
57 template<auto Func>
58 inline constexpr connect_arg_t<Func> connect_arg{};
59 
66 template<typename>
67 class delegate;
68 
81 template<typename Ret, typename... Args>
82 class delegate<Ret(Args...)> {
83  template<auto Candidate, std::size_t... Index>
84  [[nodiscard]] auto wrap(std::index_sequence<Index...>) ENTT_NOEXCEPT {
85  return [](const void *, Args... args) -> Ret {
86  [[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
87  return static_cast<Ret>(std::invoke(Candidate, std::forward<type_list_element_t<Index, type_list<Args...>>>(std::get<Index>(arguments))...));
88  };
89  }
90 
91  template<auto Candidate, typename Type, std::size_t... Index>
92  [[nodiscard]] auto wrap(Type &, std::index_sequence<Index...>) ENTT_NOEXCEPT {
93  return [](const void *payload, Args... args) -> Ret {
94  [[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
95  Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
96  return static_cast<Ret>(std::invoke(Candidate, *curr, std::forward<type_list_element_t<Index, type_list<Args...>>>(std::get<Index>(arguments))...));
97  };
98  }
99 
100  template<auto Candidate, typename Type, std::size_t... Index>
101  [[nodiscard]] auto wrap(Type *, std::index_sequence<Index...>) ENTT_NOEXCEPT {
102  return [](const void *payload, Args... args) -> Ret {
103  [[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
104  Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
105  return static_cast<Ret>(std::invoke(Candidate, curr, std::forward<type_list_element_t<Index, type_list<Args...>>>(std::get<Index>(arguments))...));
106  };
107  }
108 
109 public:
111  using function_type = Ret(const void *, Args...);
113  using type = Ret(Args...);
115  using result_type = Ret;
116 
118  delegate() ENTT_NOEXCEPT
119  : instance{nullptr},
120  fn{nullptr} {}
121 
127  template<auto Candidate>
129  connect<Candidate>();
130  }
131 
139  template<auto Candidate, typename Type>
140  delegate(connect_arg_t<Candidate>, Type &&value_or_instance) ENTT_NOEXCEPT {
141  connect<Candidate>(std::forward<Type>(value_or_instance));
142  }
143 
150  delegate(function_type *function, const void *payload = nullptr) ENTT_NOEXCEPT {
151  connect(function, payload);
152  }
153 
158  template<auto Candidate>
159  void connect() ENTT_NOEXCEPT {
160  instance = nullptr;
161 
162  if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Args...>) {
163  fn = [](const void *, Args... args) -> Ret {
164  return Ret(std::invoke(Candidate, std::forward<Args>(args)...));
165  };
166  } else if constexpr(std::is_member_pointer_v<decltype(Candidate)>) {
167  fn = wrap<Candidate>(internal::index_sequence_for<type_list_element_t<0, type_list<Args...>>>(internal::function_pointer_t<decltype(Candidate)>{}));
168  } else {
169  fn = wrap<Candidate>(internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate)>{}));
170  }
171  }
172 
188  template<auto Candidate, typename Type>
189  void connect(Type &value_or_instance) ENTT_NOEXCEPT {
190  instance = &value_or_instance;
191 
192  if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Type &, Args...>) {
193  fn = [](const void *payload, Args... args) -> Ret {
194  Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
195  return Ret(std::invoke(Candidate, *curr, std::forward<Args>(args)...));
196  };
197  } else {
198  fn = wrap<Candidate>(value_or_instance, internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate), Type>{}));
199  }
200  }
201 
212  template<auto Candidate, typename Type>
213  void connect(Type *value_or_instance) ENTT_NOEXCEPT {
214  instance = value_or_instance;
215 
216  if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Type *, Args...>) {
217  fn = [](const void *payload, Args... args) -> Ret {
218  Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
219  return Ret(std::invoke(Candidate, curr, std::forward<Args>(args)...));
220  };
221  } else {
222  fn = wrap<Candidate>(value_or_instance, internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate), Type>{}));
223  }
224  }
225 
239  void connect(function_type *function, const void *payload = nullptr) ENTT_NOEXCEPT {
240  instance = payload;
241  fn = function;
242  }
243 
249  void reset() ENTT_NOEXCEPT {
250  instance = nullptr;
251  fn = nullptr;
252  }
253 
258  [[nodiscard]] const void *data() const ENTT_NOEXCEPT {
259  return instance;
260  }
261 
274  Ret operator()(Args... args) const {
275  ENTT_ASSERT(static_cast<bool>(*this), "Uninitialized delegate");
276  return fn(instance, std::forward<Args>(args)...);
277  }
278 
283  [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
284  // no need to also test instance
285  return !(fn == nullptr);
286  }
287 
293  [[nodiscard]] bool operator==(const delegate<Ret(Args...)> &other) const ENTT_NOEXCEPT {
294  return fn == other.fn && instance == other.instance;
295  }
296 
297 private:
298  const void *instance;
299  function_type *fn;
300 };
301 
310 template<typename Ret, typename... Args>
311 [[nodiscard]] bool operator!=(const delegate<Ret(Args...)> &lhs, const delegate<Ret(Args...)> &rhs) ENTT_NOEXCEPT {
312  return !(lhs == rhs);
313 }
314 
319 template<auto Candidate>
320 delegate(connect_arg_t<Candidate>) -> delegate<std::remove_pointer_t<internal::function_pointer_t<decltype(Candidate)>>>;
321 
327 template<auto Candidate, typename Type>
328 delegate(connect_arg_t<Candidate>, Type &&) -> delegate<std::remove_pointer_t<internal::function_pointer_t<decltype(Candidate), Type>>>;
329 
335 template<typename Ret, typename... Args>
336 delegate(Ret (*)(const void *, Args...), const void * = nullptr) -> delegate<Ret(Args...)>;
337 
338 } // namespace entt
339 
340 #endif
Ret operator()(Args... args) const
Triggers a delegate.
Definition: delegate.hpp:274
Ret(const void *, Args...) function_type
Function type of the contained target.
Definition: delegate.hpp:111
void reset()
Resets a delegate.
Definition: delegate.hpp:249
delegate()
Default constructor.
Definition: delegate.hpp:118
delegate(connect_arg_t< Candidate >)
Constructs a delegate and connects a free function or an unbound member.
Definition: delegate.hpp:128
void connect(function_type *function, const void *payload=nullptr)
Connects an user defined function with optional payload to a delegate.
Definition: delegate.hpp:239
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:140
Ret result_type
Return type of the delegate.
Definition: delegate.hpp:115
void connect(Type *value_or_instance)
Connects a free function with payload or a bound member to a delegate.
Definition: delegate.hpp:213
bool operator==(const delegate< Ret(Args...)> &other) const
Compares the contents of two delegates.
Definition: delegate.hpp:293
const void * data() const
Returns the instance or the payload linked to a delegate, if any.
Definition: delegate.hpp:258
void connect()
Connects a free function or an unbound member to a delegate.
Definition: delegate.hpp:159
Ret(Args...) type
Function type of the delegate.
Definition: delegate.hpp:113
delegate(function_type *function, const void *payload=nullptr)
Constructs a delegate and connects an user defined function with optional payload.
Definition: delegate.hpp:150
void connect(Type &value_or_instance)
Connects a free function with payload or a bound member to a delegate.
Definition: delegate.hpp:189
Basic delegate implementation.
Definition: delegate.hpp:67
EnTT default namespace.
Definition: dense_map.hpp:22
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:402
constexpr connect_arg_t< Func > connect_arg
Constant of type connect_arg_t used to disambiguate calls.
Definition: delegate.hpp:58
Used to wrap a function or a member of a specified type.
Definition: delegate.hpp:54
A class to use to push around lists of types, nothing more.