EnTT  3.1.0
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<Payload &, Type &>>>
31 auto to_function_pointer(Ret(*)(Type &, Args...), Payload &) -> Ret(*)(Args...);
32 
33 
34 template<typename Class, typename Ret, typename... Args>
35 auto to_function_pointer(Ret(Class:: *)(Args...), const Class &) -> Ret(*)(Args...);
36 
37 
38 template<typename Class, typename Ret, typename... Args>
39 auto to_function_pointer(Ret(Class:: *)(Args...) const, const Class &) -> Ret(*)(Args...);
40 
41 
42 template<typename Class, typename Type>
43 auto to_function_pointer(Type Class:: *, const Class &) -> Type(*)();
44 
45 
46 template<typename>
47 struct function_extent;
48 
49 
50 template<typename Ret, typename... Args>
51 struct function_extent<Ret(*)(Args...)> {
52  static constexpr auto value = sizeof...(Args);
53 };
54 
55 
56 template<typename Func>
57 constexpr auto function_extent_v = function_extent<Func>::value;
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 = nullptr;
124 
125  if constexpr(std::is_const_v<Type>) {
126  curr = static_cast<Type *>(payload);
127  } else {
128  curr = static_cast<Type *>(const_cast<void *>(payload));
129  }
130 
131  // Ret(...) makes void(...) eat the return values to avoid errors
132  return Ret(std::invoke(Candidate, *curr, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(args))...));
133  };
134  }
135 
136 public:
138  using function_type = Ret(Args...);
139 
141  delegate() ENTT_NOEXCEPT
142  : fn{nullptr}, data{nullptr}
143  {}
144 
149  template<auto Function>
151  : delegate{}
152  {
153  connect<Function>();
154  }
155 
163  template<auto Candidate, typename Type>
164  delegate(connect_arg_t<Candidate>, Type &value_or_instance) ENTT_NOEXCEPT
165  : delegate{}
166  {
167  connect<Candidate>(value_or_instance);
168  }
169 
174  template<auto Function>
175  void connect() ENTT_NOEXCEPT {
176  constexpr auto extent = internal::function_extent_v<decltype(internal::to_function_pointer(std::declval<decltype(Function)>()))>;
177  connect<Function>(std::make_index_sequence<extent>{});
178  }
179 
195  template<auto Candidate, typename Type>
196  void connect(Type &value_or_instance) ENTT_NOEXCEPT {
197  constexpr auto extent = internal::function_extent_v<decltype(internal::to_function_pointer(std::declval<decltype(Candidate)>(), value_or_instance))>;
198  connect<Candidate>(value_or_instance, std::make_index_sequence<extent>{});
199  }
200 
206  void reset() ENTT_NOEXCEPT {
207  fn = nullptr;
208  data = nullptr;
209  }
210 
215  const void * instance() const ENTT_NOEXCEPT {
216  return data;
217  }
218 
233  Ret operator()(Args... args) const {
234  ENTT_ASSERT(fn);
235  return fn(data, std::forward_as_tuple(std::forward<Args>(args)...));
236  }
237 
242  explicit operator bool() const ENTT_NOEXCEPT {
243  // no need to test also data
244  return fn;
245  }
246 
252  bool operator==(const delegate<Ret(Args...)> &other) const ENTT_NOEXCEPT {
253  return fn == other.fn && data == other.data;
254  }
255 
256 private:
257  proto_fn_type *fn;
258  const void *data;
259 };
260 
261 
270 template<typename Ret, typename... Args>
271 bool operator!=(const delegate<Ret(Args...)> &lhs, const delegate<Ret(Args...)> &rhs) ENTT_NOEXCEPT {
272  return !(lhs == rhs);
273 }
274 
275 
284 template<auto Function>
285 delegate(connect_arg_t<Function>) ENTT_NOEXCEPT
287 
288 
299 template<auto Candidate, typename Type>
300 delegate(connect_arg_t<Candidate>, Type &value_or_instance) ENTT_NOEXCEPT
302 
303 
304 }
305 
306 
307 #endif // ENTT_SIGNAL_DELEGATE_HPP
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:164
constexpr connect_arg_t< Func > connect_arg
Constant of type connect_arg_t used to disambiguate calls.
Definition: delegate.hpp:76
Used to wrap a function or a member of a specified type.
Definition: delegate.hpp:71
constexpr bool operator!=(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs) ENTT_NOEXCEPT
Compares two hashed strings.
EnTT default namespace.
Definition: algorithm.hpp:12
void connect() ENTT_NOEXCEPT
Connects a free function to a delegate.
Definition: delegate.hpp:175
Basic delegate implementation.
Definition: delegate.hpp:86
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:196
const void * instance() const ENTT_NOEXCEPT
Returns the instance or the payload linked to a delegate, if any.
Definition: delegate.hpp:215
Ret operator()(Args... args) const
Triggers a delegate.
Definition: delegate.hpp:233
Ret(Args...) function_type
Function type of the delegate.
Definition: delegate.hpp:138
void reset() ENTT_NOEXCEPT
Resets a delegate.
Definition: delegate.hpp:206
delegate(connect_arg_t< Function >) ENTT_NOEXCEPT
Constructs a delegate and connects a free function to it.
Definition: delegate.hpp:150
delegate(connect_arg_t< Function >) ENTT_NOEXCEPT -> delegate< std::remove_pointer_t< decltype(internal::to_function_pointer(Function))>>
Deduction guide.
delegate() ENTT_NOEXCEPT
Default constructor.
Definition: delegate.hpp:141
bool operator==(const delegate< Ret(Args...)> &other) const ENTT_NOEXCEPT
Compares the contents of two delegates.
Definition: delegate.hpp:252