EnTT 3.12.0
Loading...
Searching...
No Matches
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
13namespace entt {
14
20namespace internal {
21
22template<typename Ret, typename... Args>
23constexpr auto function_pointer(Ret (*)(Args...)) -> Ret (*)(Args...);
24
25template<typename Ret, typename Type, typename... Args, typename Other>
26constexpr auto function_pointer(Ret (*)(Type, Args...), Other &&) -> Ret (*)(Args...);
27
28template<typename Class, typename Ret, typename... Args, typename... Other>
29constexpr auto function_pointer(Ret (Class::*)(Args...), Other &&...) -> Ret (*)(Args...);
30
31template<typename Class, typename Ret, typename... Args, typename... Other>
32constexpr auto function_pointer(Ret (Class::*)(Args...) const, Other &&...) -> Ret (*)(Args...);
33
34template<typename Class, typename Type, typename... Other>
35constexpr auto function_pointer(Type Class::*, Other &&...) -> Type (*)();
36
37template<typename... Type>
38using function_pointer_t = decltype(function_pointer(std::declval<Type>()...));
39
40template<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
58template<typename>
60
73template<typename Ret, typename... Args>
74class delegate<Ret(Args...)> {
75 template<auto Candidate, std::size_t... Index>
76 [[nodiscard]] auto wrap(std::index_sequence<Index...>) noexcept {
77 return [](const void *, Args... args) -> Ret {
78 [[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
79
80 if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), type_list_element_t<Index, type_list<Args...>>...>) {
81 return static_cast<Ret>(std::invoke(Candidate, std::forward<type_list_element_t<Index, type_list<Args...>>>(std::get<Index>(arguments))...));
82 } else {
83 constexpr auto offset = sizeof...(Args) - sizeof...(Index);
84 return static_cast<Ret>(std::invoke(Candidate, std::forward<type_list_element_t<Index + offset, type_list<Args...>>>(std::get<Index + offset>(arguments))...));
85 }
86 };
87 }
88
89 template<auto Candidate, typename Type, std::size_t... Index>
90 [[nodiscard]] auto wrap(Type &, std::index_sequence<Index...>) noexcept {
91 return [](const void *payload, Args... args) -> Ret {
92 [[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
93 Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
94
95 if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Type &, type_list_element_t<Index, type_list<Args...>>...>) {
96 return static_cast<Ret>(std::invoke(Candidate, *curr, std::forward<type_list_element_t<Index, type_list<Args...>>>(std::get<Index>(arguments))...));
97 } else {
98 constexpr auto offset = sizeof...(Args) - sizeof...(Index);
99 return static_cast<Ret>(std::invoke(Candidate, *curr, std::forward<type_list_element_t<Index + offset, type_list<Args...>>>(std::get<Index + offset>(arguments))...));
100 }
101 };
102 }
103
104 template<auto Candidate, typename Type, std::size_t... Index>
105 [[nodiscard]] auto wrap(Type *, std::index_sequence<Index...>) noexcept {
106 return [](const void *payload, Args... args) -> Ret {
107 [[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
108 Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
109
110 if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Type *, type_list_element_t<Index, type_list<Args...>>...>) {
111 return static_cast<Ret>(std::invoke(Candidate, curr, std::forward<type_list_element_t<Index, type_list<Args...>>>(std::get<Index>(arguments))...));
112 } else {
113 constexpr auto offset = sizeof...(Args) - sizeof...(Index);
114 return static_cast<Ret>(std::invoke(Candidate, curr, std::forward<type_list_element_t<Index + offset, type_list<Args...>>>(std::get<Index + offset>(arguments))...));
115 }
116 };
117 }
118
119public:
121 using function_type = Ret(const void *, Args...);
123 using type = Ret(Args...);
125 using result_type = Ret;
126
128 delegate() noexcept
129 : instance{nullptr},
130 fn{nullptr} {}
131
138 template<auto Candidate, typename... Type>
139 delegate(connect_arg_t<Candidate>, Type &&...value_or_instance) noexcept {
140 connect<Candidate>(std::forward<Type>(value_or_instance)...);
141 }
142
149 delegate(function_type *function, const void *payload = nullptr) noexcept {
150 connect(function, payload);
151 }
152
157 template<auto Candidate>
158 void connect() noexcept {
159 instance = nullptr;
160
161 if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Args...>) {
162 fn = [](const void *, Args... args) -> Ret {
163 return Ret(std::invoke(Candidate, std::forward<Args>(args)...));
164 };
165 } else if constexpr(std::is_member_pointer_v<decltype(Candidate)>) {
166 fn = wrap<Candidate>(internal::index_sequence_for<type_list_element_t<0, type_list<Args...>>>(internal::function_pointer_t<decltype(Candidate)>{}));
167 } else {
168 fn = wrap<Candidate>(internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate)>{}));
169 }
170 }
171
187 template<auto Candidate, typename Type>
188 void connect(Type &value_or_instance) noexcept {
189 instance = &value_or_instance;
190
191 if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Type &, Args...>) {
192 fn = [](const void *payload, Args... args) -> Ret {
193 Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
194 return Ret(std::invoke(Candidate, *curr, std::forward<Args>(args)...));
195 };
196 } else {
197 fn = wrap<Candidate>(value_or_instance, internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate), Type>{}));
198 }
199 }
200
211 template<auto Candidate, typename Type>
212 void connect(Type *value_or_instance) noexcept {
213 instance = value_or_instance;
214
215 if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Type *, Args...>) {
216 fn = [](const void *payload, Args... args) -> Ret {
217 Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
218 return Ret(std::invoke(Candidate, curr, std::forward<Args>(args)...));
219 };
220 } else {
221 fn = wrap<Candidate>(value_or_instance, internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate), Type>{}));
222 }
223 }
224
238 void connect(function_type *function, const void *payload = nullptr) noexcept {
239 ENTT_ASSERT(function != nullptr, "Uninitialized function pointer");
240 instance = payload;
241 fn = function;
242 }
243
249 void reset() noexcept {
250 instance = nullptr;
251 fn = nullptr;
252 }
253
258 [[nodiscard]] function_type *target() const noexcept {
259 return fn;
260 }
261
266 [[nodiscard]] const void *data() const noexcept {
267 return instance;
268 }
269
282 Ret operator()(Args... args) const {
283 ENTT_ASSERT(static_cast<bool>(*this), "Uninitialized delegate");
284 return fn(instance, std::forward<Args>(args)...);
285 }
286
291 [[nodiscard]] explicit operator bool() const noexcept {
292 // no need to also test instance
293 return !(fn == nullptr);
294 }
295
301 [[nodiscard]] bool operator==(const delegate<Ret(Args...)> &other) const noexcept {
302 return fn == other.fn && instance == other.instance;
303 }
304
305private:
306 const void *instance;
307 function_type *fn;
308};
309
318template<typename Ret, typename... Args>
319[[nodiscard]] bool operator!=(const delegate<Ret(Args...)> &lhs, const delegate<Ret(Args...)> &rhs) noexcept {
320 return !(lhs == rhs);
321}
322
327template<auto Candidate>
328delegate(connect_arg_t<Candidate>) -> delegate<std::remove_pointer_t<internal::function_pointer_t<decltype(Candidate)>>>;
329
335template<auto Candidate, typename Type>
336delegate(connect_arg_t<Candidate>, Type &&) -> delegate<std::remove_pointer_t<internal::function_pointer_t<decltype(Candidate), Type>>>;
337
343template<typename Ret, typename... Args>
344delegate(Ret (*)(const void *, Args...), const void * = nullptr) -> delegate<Ret(Args...)>;
345
346} // namespace entt
347
348#endif
bool operator==(const delegate< Ret(Args...)> &other) const noexcept
Compares the contents of two delegates.
Definition: delegate.hpp:301
Ret operator()(Args... args) const
Triggers a delegate.
Definition: delegate.hpp:282
void reset() noexcept
Resets a delegate.
Definition: delegate.hpp:249
Ret(const void *, Args...) function_type
Function type of the contained target.
Definition: delegate.hpp:121
delegate() noexcept
Default constructor.
Definition: delegate.hpp:128
delegate(function_type *function, const void *payload=nullptr) noexcept
Constructs a delegate and connects an user defined function with optional payload.
Definition: delegate.hpp:149
void connect(Type &value_or_instance) noexcept
Connects a free function with payload or a bound member to a delegate.
Definition: delegate.hpp:188
delegate(connect_arg_t< Candidate >, Type &&...value_or_instance) noexcept
Constructs a delegate with a given object or payload, if any.
Definition: delegate.hpp:139
void connect(Type *value_or_instance) noexcept
Connects a free function with payload or a bound member to a delegate.
Definition: delegate.hpp:212
void connect() noexcept
Connects a free function or an unbound member to a delegate.
Definition: delegate.hpp:158
Ret result_type
Return type of the delegate.
Definition: delegate.hpp:125
const void * data() const noexcept
Returns the instance or the payload linked to a delegate, if any.
Definition: delegate.hpp:266
void connect(function_type *function, const void *payload=nullptr) noexcept
Connects an user defined function with optional payload to a delegate.
Definition: delegate.hpp:238
function_type * target() const noexcept
Returns a pointer to the stored callable function target, if any.
Definition: delegate.hpp:258
Ret(Args...) type
Function type of the delegate.
Definition: delegate.hpp:123
Basic delegate implementation.
Definition: delegate.hpp:59
EnTT default namespace.
Definition: dense_map.hpp:21
typename constness_as< To, From >::type constness_as_t
Alias template to facilitate the transcription of the constness.
typename type_list_element< Index, List >::type type_list_element_t
Helper type.
constexpr bool operator!=(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs) noexcept
Compares two hashed strings.
Disambiguation tag for constructors and the like.
Definition: fwd.hpp:32
A class to use to push around lists of types, nothing more.