EnTT 3.13.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
16namespace internal {
17
18template<typename Ret, typename... Args>
19constexpr auto function_pointer(Ret (*)(Args...)) -> Ret (*)(Args...);
20
21template<typename Ret, typename Type, typename... Args, typename Other>
22constexpr auto function_pointer(Ret (*)(Type, Args...), Other &&) -> Ret (*)(Args...);
23
24template<typename Class, typename Ret, typename... Args, typename... Other>
25constexpr auto function_pointer(Ret (Class::*)(Args...), Other &&...) -> Ret (*)(Args...);
26
27template<typename Class, typename Ret, typename... Args, typename... Other>
28constexpr auto function_pointer(Ret (Class::*)(Args...) const, Other &&...) -> Ret (*)(Args...);
29
30template<typename Class, typename Type, typename... Other>
31constexpr auto function_pointer(Type Class::*, Other &&...) -> Type (*)();
32
33template<typename... Type>
34using function_pointer_t = decltype(function_pointer(std::declval<Type>()...));
35
36template<typename... Class, typename Ret, typename... Args>
37[[nodiscard]] constexpr auto index_sequence_for(Ret (*)(Args...)) {
38 return std::index_sequence_for<Class..., Args...>{};
39}
40
41} // namespace internal
50template<typename>
52
65template<typename Ret, typename... Args>
66class delegate<Ret(Args...)> {
67 template<auto Candidate, std::size_t... Index>
68 [[nodiscard]] auto wrap(std::index_sequence<Index...>) noexcept {
69 return [](const void *, Args... args) -> Ret {
70 [[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
71
72 if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), type_list_element_t<Index, type_list<Args...>>...>) {
73 return static_cast<Ret>(std::invoke(Candidate, std::forward<type_list_element_t<Index, type_list<Args...>>>(std::get<Index>(arguments))...));
74 } else {
75 constexpr auto offset = sizeof...(Args) - sizeof...(Index);
76 return static_cast<Ret>(std::invoke(Candidate, std::forward<type_list_element_t<Index + offset, type_list<Args...>>>(std::get<Index + offset>(arguments))...));
77 }
78 };
79 }
80
81 template<auto Candidate, typename Type, std::size_t... Index>
82 [[nodiscard]] auto wrap(Type &, std::index_sequence<Index...>) noexcept {
83 return [](const void *payload, Args... args) -> Ret {
84 [[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
85 Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
86
87 if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Type &, type_list_element_t<Index, type_list<Args...>>...>) {
88 return static_cast<Ret>(std::invoke(Candidate, *curr, std::forward<type_list_element_t<Index, type_list<Args...>>>(std::get<Index>(arguments))...));
89 } else {
90 constexpr auto offset = sizeof...(Args) - sizeof...(Index);
91 return static_cast<Ret>(std::invoke(Candidate, *curr, std::forward<type_list_element_t<Index + offset, type_list<Args...>>>(std::get<Index + offset>(arguments))...));
92 }
93 };
94 }
95
96 template<auto Candidate, typename Type, std::size_t... Index>
97 [[nodiscard]] auto wrap(Type *, std::index_sequence<Index...>) noexcept {
98 return [](const void *payload, Args... args) -> Ret {
99 [[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
100 Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
101
102 if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Type *, type_list_element_t<Index, type_list<Args...>>...>) {
103 return static_cast<Ret>(std::invoke(Candidate, curr, std::forward<type_list_element_t<Index, type_list<Args...>>>(std::get<Index>(arguments))...));
104 } else {
105 constexpr auto offset = sizeof...(Args) - sizeof...(Index);
106 return static_cast<Ret>(std::invoke(Candidate, curr, std::forward<type_list_element_t<Index + offset, type_list<Args...>>>(std::get<Index + offset>(arguments))...));
107 }
108 };
109 }
110
111public:
113 using function_type = Ret(const void *, Args...);
115 using type = Ret(Args...);
117 using result_type = Ret;
118
120 delegate() noexcept
121 : instance{nullptr},
122 fn{nullptr} {}
123
130 template<auto Candidate, typename... Type>
131 delegate(connect_arg_t<Candidate>, Type &&...value_or_instance) noexcept {
132 connect<Candidate>(std::forward<Type>(value_or_instance)...);
133 }
134
141 delegate(function_type *function, const void *payload = nullptr) noexcept {
142 connect(function, payload);
143 }
144
149 template<auto Candidate>
150 void connect() noexcept {
151 instance = nullptr;
152
153 if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Args...>) {
154 fn = [](const void *, Args... args) -> Ret {
155 return Ret(std::invoke(Candidate, std::forward<Args>(args)...));
156 };
157 } else if constexpr(std::is_member_pointer_v<decltype(Candidate)>) {
158 fn = wrap<Candidate>(internal::index_sequence_for<type_list_element_t<0, type_list<Args...>>>(internal::function_pointer_t<decltype(Candidate)>{}));
159 } else {
160 fn = wrap<Candidate>(internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate)>{}));
161 }
162 }
163
179 template<auto Candidate, typename Type>
180 void connect(Type &value_or_instance) noexcept {
181 instance = &value_or_instance;
182
183 if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Type &, Args...>) {
184 fn = [](const void *payload, Args... args) -> Ret {
185 Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
186 return Ret(std::invoke(Candidate, *curr, std::forward<Args>(args)...));
187 };
188 } else {
189 fn = wrap<Candidate>(value_or_instance, internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate), Type>{}));
190 }
191 }
192
203 template<auto Candidate, typename Type>
204 void connect(Type *value_or_instance) noexcept {
205 instance = value_or_instance;
206
207 if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Type *, Args...>) {
208 fn = [](const void *payload, Args... args) -> Ret {
209 Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
210 return Ret(std::invoke(Candidate, curr, std::forward<Args>(args)...));
211 };
212 } else {
213 fn = wrap<Candidate>(value_or_instance, internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate), Type>{}));
214 }
215 }
216
230 void connect(function_type *function, const void *payload = nullptr) noexcept {
231 ENTT_ASSERT(function != nullptr, "Uninitialized function pointer");
232 instance = payload;
233 fn = function;
234 }
235
241 void reset() noexcept {
242 instance = nullptr;
243 fn = nullptr;
244 }
245
250 [[nodiscard]] function_type *target() const noexcept {
251 return fn;
252 }
253
258 [[nodiscard]] const void *data() const 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 noexcept {
284 // no need to also test instance
285 return !(fn == nullptr);
286 }
287
293 [[nodiscard]] bool operator==(const delegate<Ret(Args...)> &other) const noexcept {
294 return fn == other.fn && instance == other.instance;
295 }
296
297private:
298 const void *instance;
299 function_type *fn;
300};
301
310template<typename Ret, typename... Args>
311[[nodiscard]] bool operator!=(const delegate<Ret(Args...)> &lhs, const delegate<Ret(Args...)> &rhs) noexcept {
312 return !(lhs == rhs);
313}
314
319template<auto Candidate>
320delegate(connect_arg_t<Candidate>) -> delegate<std::remove_pointer_t<internal::function_pointer_t<decltype(Candidate)>>>;
321
327template<auto Candidate, typename Type>
328delegate(connect_arg_t<Candidate>, Type &&) -> delegate<std::remove_pointer_t<internal::function_pointer_t<decltype(Candidate), Type>>>;
329
335template<typename Ret, typename... Args>
336delegate(Ret (*)(const void *, Args...), const void * = nullptr) -> delegate<Ret(Args...)>;
337
338} // namespace entt
339
340#endif
bool operator==(const delegate< Ret(Args...)> &other) const noexcept
Compares the contents of two delegates.
Definition delegate.hpp:293
Ret operator()(Args... args) const
Triggers a delegate.
Definition delegate.hpp:274
void reset() noexcept
Resets a delegate.
Definition delegate.hpp:241
Ret(const void *, Args...) function_type
Function type of the contained target.
Definition delegate.hpp:113
delegate() noexcept
Default constructor.
Definition delegate.hpp:120
delegate(function_type *function, const void *payload=nullptr) noexcept
Constructs a delegate and connects an user defined function with optional payload.
Definition delegate.hpp:141
void connect(Type &value_or_instance) noexcept
Connects a free function with payload or a bound member to a delegate.
Definition delegate.hpp:180
delegate(connect_arg_t< Candidate >, Type &&...value_or_instance) noexcept
Constructs a delegate with a given object or payload, if any.
Definition delegate.hpp:131
void connect(Type *value_or_instance) noexcept
Connects a free function with payload or a bound member to a delegate.
Definition delegate.hpp:204
void connect() noexcept
Connects a free function or an unbound member to a delegate.
Definition delegate.hpp:150
Ret result_type
Return type of the delegate.
Definition delegate.hpp:117
const void * data() const noexcept
Returns the instance or the payload linked to a delegate, if any.
Definition delegate.hpp:258
void connect(function_type *function, const void *payload=nullptr) noexcept
Connects an user defined function with optional payload to a delegate.
Definition delegate.hpp:230
function_type * target() const noexcept
Returns a pointer to the stored callable function target, if any.
Definition delegate.hpp:250
Ret(Args...) type
Function type of the delegate.
Definition delegate.hpp:115
Basic delegate implementation.
Definition delegate.hpp:51
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.