EnTT 4.0.0
Loading...
Searching...
No Matches
delegate.hpp
1#ifndef ENTT_SIGNAL_DELEGATE_HPP
2#define ENTT_SIGNAL_DELEGATE_HPP
3
4#include "../config/config.h"
5#include "../core/type_traits.hpp"
6#include "../stl/cstddef.hpp"
7#include "../stl/functional.hpp"
8#include "../stl/tuple.hpp"
9#include "../stl/type_traits.hpp"
10#include "../stl/utility.hpp"
11#include "fwd.hpp"
12
13namespace entt {
14
16namespace internal {
17
18template<typename Ret, typename... Args>
19auto function_pointer(Ret (*)(Args...)) -> Ret (*)(Args...);
20
21template<typename Ret, typename Type, typename... Args, typename Other>
22auto function_pointer(Ret (*)(Type, Args...), Other &&) -> Ret (*)(Args...);
23
24template<typename Class, typename Ret, typename... Args, typename... Other>
25auto function_pointer(Ret (Class::*)(Args...), Other &&...) -> Ret (*)(Args...);
26
27template<typename Class, typename Ret, typename... Args, typename... Other>
28auto function_pointer(Ret (Class::*)(Args...) const, Other &&...) -> Ret (*)(Args...);
29
30template<typename Class, typename Type, typename... Other>
31requires stl::is_member_object_pointer_v<Type Class::*>
32auto function_pointer(Type Class::*, Other &&...) -> Type (*)();
33
34template<typename... Type>
35using function_pointer_t = decltype(function_pointer(stl::declval<Type>()...));
36
37template<typename... Class, typename Ret, typename... Args>
38[[nodiscard]] ENTT_CONSTEVAL auto index_sequence_for(Ret (*)(Args...)) {
39 return stl::index_sequence_for<Class..., Args...>{};
40}
41
42} // namespace internal
44
51template<typename>
53
66template<typename Ret, typename... Args>
67class delegate<Ret(Args...)> {
68 using return_type = stl::remove_const_t<Ret>;
69 using delegate_type = return_type(const void *, Args...);
70
71 template<auto Candidate, stl::size_t... Index>
72 [[nodiscard]] auto wrap(stl::index_sequence<Index...>) noexcept {
73 return [](const void *, Args... args) -> return_type {
74 [[maybe_unused]] const auto arguments = stl::forward_as_tuple(stl::forward<Args>(args)...);
75 [[maybe_unused]] constexpr auto offset = !stl::is_invocable_r_v<Ret, decltype(Candidate), type_list_element_t<Index, type_list<Args...>>...> * (sizeof...(Args) - sizeof...(Index));
76 return static_cast<Ret>(stl::invoke(Candidate, stl::forward<type_list_element_t<Index + offset, type_list<Args...>>>(stl::get<Index + offset>(arguments))...));
77 };
78 }
79
80 template<auto Candidate, typename Type, stl::size_t... Index>
81 [[nodiscard]] auto wrap(Type &, stl::index_sequence<Index...>) noexcept {
82 return [](const void *payload, Args... args) -> return_type {
83 Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
84 [[maybe_unused]] const auto arguments = stl::forward_as_tuple(stl::forward<Args>(args)...);
85 [[maybe_unused]] constexpr auto offset = !stl::is_invocable_r_v<Ret, decltype(Candidate), Type &, type_list_element_t<Index, type_list<Args...>>...> * (sizeof...(Args) - sizeof...(Index));
86 return static_cast<Ret>(stl::invoke(Candidate, *curr, stl::forward<type_list_element_t<Index + offset, type_list<Args...>>>(stl::get<Index + offset>(arguments))...));
87 };
88 }
89
90 template<auto Candidate, typename Type, stl::size_t... Index>
91 [[nodiscard]] auto wrap(Type *, stl::index_sequence<Index...>) noexcept {
92 return [](const void *payload, Args... args) -> return_type {
93 Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
94 [[maybe_unused]] const auto arguments = stl::forward_as_tuple(stl::forward<Args>(args)...);
95 [[maybe_unused]] constexpr auto offset = !stl::is_invocable_r_v<Ret, decltype(Candidate), Type *, type_list_element_t<Index, type_list<Args...>>...> * (sizeof...(Args) - sizeof...(Index));
96 return static_cast<Ret>(stl::invoke(Candidate, curr, stl::forward<type_list_element_t<Index + offset, type_list<Args...>>>(stl::get<Index + offset>(arguments))...));
97 };
98 }
99
100public:
102 using function_type = Ret(const void *, Args...);
104 using type = Ret(Args...);
106 using result_type = Ret;
107
109 delegate() noexcept = default;
110
117 template<auto Candidate, typename... Type>
118 delegate(connect_arg_t<Candidate>, Type &&...value_or_instance) noexcept {
119 connect<Candidate>(stl::forward<Type>(value_or_instance)...);
120 }
121
128 delegate(function_type *function, const void *payload = nullptr) noexcept {
129 connect(function, payload);
130 }
131
136 template<auto Candidate>
137 void connect() noexcept {
138 instance = nullptr;
139
140 if constexpr(stl::is_invocable_r_v<Ret, decltype(Candidate), Args...>) {
141 fn = [](const void *, Args... args) -> return_type {
142 return Ret(stl::invoke(Candidate, stl::forward<Args>(args)...));
143 };
144 } else if constexpr(stl::is_member_pointer_v<decltype(Candidate)>) {
145 fn = wrap<Candidate>(internal::index_sequence_for<type_list_element_t<0, type_list<Args...>>>(internal::function_pointer_t<decltype(Candidate)>{}));
146 } else {
147 fn = wrap<Candidate>(internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate)>{}));
148 }
149 }
150
166 template<auto Candidate, typename Type>
167 void connect(Type &value_or_instance) noexcept {
168 instance = &value_or_instance;
169
170 if constexpr(stl::is_invocable_r_v<Ret, decltype(Candidate), Type &, Args...>) {
171 fn = [](const void *payload, Args... args) -> return_type {
172 Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
173 return Ret(stl::invoke(Candidate, *curr, stl::forward<Args>(args)...));
174 };
175 } else {
176 fn = wrap<Candidate>(value_or_instance, internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate), Type>{}));
177 }
178 }
179
190 template<auto Candidate, typename Type>
191 void connect(Type *value_or_instance) noexcept {
192 instance = value_or_instance;
193
194 if constexpr(stl::is_invocable_r_v<Ret, decltype(Candidate), Type *, Args...>) {
195 fn = [](const void *payload, Args... args) -> return_type {
196 Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
197 return Ret(stl::invoke(Candidate, curr, stl::forward<Args>(args)...));
198 };
199 } else {
200 fn = wrap<Candidate>(value_or_instance, internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate), Type>{}));
201 }
202 }
203
217 void connect(function_type *function, const void *payload = nullptr) noexcept {
218 ENTT_ASSERT(function != nullptr, "Uninitialized function pointer");
219 instance = payload;
220 fn = function;
221 }
222
228 void reset() noexcept {
229 instance = nullptr;
230 fn = nullptr;
231 }
232
237 [[nodiscard]] function_type *target() const noexcept {
238 return fn;
239 }
240
245 [[nodiscard]] const void *data() const noexcept {
246 return instance;
247 }
248
261 Ret operator()(Args... args) const {
262 ENTT_ASSERT(static_cast<bool>(*this), "Uninitialized delegate");
263 return fn(instance, stl::forward<Args>(args)...);
264 }
265
270 [[nodiscard]] explicit operator bool() const noexcept {
271 // no need to also test instance
272 return !(fn == nullptr);
273 }
274
280 [[nodiscard]] bool operator==(const delegate<Ret(Args...)> &other) const noexcept {
281 return fn == other.fn && instance == other.instance;
282 }
283
284private:
285 const void *instance{};
286 delegate_type *fn{};
287};
288
293template<auto Candidate>
294delegate(connect_arg_t<Candidate>) -> delegate<stl::remove_pointer_t<internal::function_pointer_t<decltype(Candidate)>>>;
295
301template<auto Candidate, typename Type>
302delegate(connect_arg_t<Candidate>, Type &&) -> delegate<stl::remove_pointer_t<internal::function_pointer_t<decltype(Candidate), Type>>>;
303
309template<typename Ret, typename... Args>
310delegate(Ret (*)(const void *, Args...), const void * = nullptr) -> delegate<Ret(Args...)>;
311
312} // namespace entt
313
314#endif
Basic delegate implementation.
Definition delegate.hpp:52
EnTT default namespace.
Definition dense_map.hpp:25
type_list_element< Index, List >::type type_list_element_t
Helper type.
delegate(connect_arg_t< Candidate >) -> delegate< stl::remove_pointer_t< internal::function_pointer_t< decltype(Candidate)> > >
Deduction guide.
constness_as< To, From >::type constness_as_t
Alias template to facilitate the transcription of the constness.
Disambiguation tag for constructors and the like.
Definition fwd.hpp:32
A class to use to push around lists of types, nothing more.