EnTT 3.14.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, typename = std::enable_if_t<std::is_member_object_pointer_v<Type Class::*>>>
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 using return_type = std::remove_const_t<Ret>;
68 using delegate_type = return_type(const void *, Args...);
69
70 template<auto Candidate, std::size_t... Index>
71 [[nodiscard]] auto wrap(std::index_sequence<Index...>) noexcept {
72 return [](const void *, Args... args) -> return_type {
73 [[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
74 [[maybe_unused]] constexpr auto offset = !std::is_invocable_r_v<Ret, decltype(Candidate), type_list_element_t<Index, type_list<Args...>>...> * (sizeof...(Args) - sizeof...(Index));
75 return static_cast<Ret>(std::invoke(Candidate, std::forward<type_list_element_t<Index + offset, type_list<Args...>>>(std::get<Index + offset>(arguments))...));
76 };
77 }
78
79 template<auto Candidate, typename Type, std::size_t... Index>
80 [[nodiscard]] auto wrap(Type &, std::index_sequence<Index...>) noexcept {
81 return [](const void *payload, Args... args) -> return_type {
82 Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
83 [[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
84 [[maybe_unused]] constexpr auto offset = !std::is_invocable_r_v<Ret, decltype(Candidate), Type &, type_list_element_t<Index, type_list<Args...>>...> * (sizeof...(Args) - sizeof...(Index));
85 return static_cast<Ret>(std::invoke(Candidate, *curr, std::forward<type_list_element_t<Index + offset, type_list<Args...>>>(std::get<Index + offset>(arguments))...));
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) -> return_type {
92 Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
93 [[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
94 [[maybe_unused]] constexpr auto offset = !std::is_invocable_r_v<Ret, decltype(Candidate), Type *, type_list_element_t<Index, type_list<Args...>>...> * (sizeof...(Args) - sizeof...(Index));
95 return static_cast<Ret>(std::invoke(Candidate, curr, std::forward<type_list_element_t<Index + offset, type_list<Args...>>>(std::get<Index + offset>(arguments))...));
96 };
97 }
98
99public:
101 using function_type = Ret(const void *, Args...);
103 using type = Ret(Args...);
106
109
120
127 delegate(function_type *function, const void *payload = nullptr) noexcept {
128 connect(function, payload);
129 }
130
135 template<auto Candidate>
137 instance = nullptr;
138
139 if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Args...>) {
140 fn = [](const void *, Args... args) -> return_type {
141 return Ret(std::invoke(Candidate, std::forward<Args>(args)...));
142 };
143 } else if constexpr(std::is_member_pointer_v<decltype(Candidate)>) {
144 fn = wrap<Candidate>(internal::index_sequence_for<type_list_element_t<0, type_list<Args...>>>(internal::function_pointer_t<decltype(Candidate)>{}));
145 } else {
146 fn = wrap<Candidate>(internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate)>{}));
147 }
148 }
149
165 template<auto Candidate, typename Type>
166 void connect(Type &value_or_instance) noexcept {
167 instance = &value_or_instance;
168
169 if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Type &, Args...>) {
170 fn = [](const void *payload, Args... args) -> return_type {
171 Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
172 return Ret(std::invoke(Candidate, *curr, std::forward<Args>(args)...));
173 };
174 } else {
175 fn = wrap<Candidate>(value_or_instance, internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate), Type>{}));
176 }
177 }
178
189 template<auto Candidate, typename Type>
190 void connect(Type *value_or_instance) noexcept {
191 instance = value_or_instance;
192
193 if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Type *, Args...>) {
194 fn = [](const void *payload, Args... args) -> return_type {
195 Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
196 return Ret(std::invoke(Candidate, curr, std::forward<Args>(args)...));
197 };
198 } else {
199 fn = wrap<Candidate>(value_or_instance, internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate), Type>{}));
200 }
201 }
202
216 void connect(function_type *function, const void *payload = nullptr) noexcept {
217 ENTT_ASSERT(function != nullptr, "Uninitialized function pointer");
218 instance = payload;
219 fn = function;
220 }
221
228 instance = nullptr;
229 fn = nullptr;
230 }
231
237 return fn;
238 }
239
244 [[nodiscard]] const void *data() const noexcept {
245 return instance;
246 }
247
261 ENTT_ASSERT(static_cast<bool>(*this), "Uninitialized delegate");
262 return fn(instance, std::forward<Args>(args)...);
263 }
264
269 [[nodiscard]] explicit operator bool() const noexcept {
270 // no need to also test instance
271 return !(fn == nullptr);
272 }
273
279 [[nodiscard]] bool operator==(const delegate<Ret(Args...)> &other) const noexcept {
280 return fn == other.fn && instance == other.instance;
281 }
282
283private:
284 const void *instance{};
285 delegate_type *fn{};
286};
287
296template<typename Ret, typename... Args>
297[[nodiscard]] bool operator!=(const delegate<Ret(Args...)> &lhs, const delegate<Ret(Args...)> &rhs) noexcept {
298 return !(lhs == rhs);
299}
300
305template<auto Candidate>
306delegate(connect_arg_t<Candidate>) -> delegate<std::remove_pointer_t<internal::function_pointer_t<decltype(Candidate)>>>;
307
313template<auto Candidate, typename Type>
314delegate(connect_arg_t<Candidate>, Type &&) -> delegate<std::remove_pointer_t<internal::function_pointer_t<decltype(Candidate), Type>>>;
315
321template<typename Ret, typename... Args>
322delegate(Ret (*)(const void *, Args...), const void * = nullptr) -> delegate<Ret(Args...)>;
323
324} // namespace entt
325
326#endif
bool operator==(const delegate< Ret(Args...)> &other) const noexcept
Compares the contents of two delegates.
Definition delegate.hpp:279
Ret operator()(Args... args) const
Triggers a delegate.
Definition delegate.hpp:260
void reset() noexcept
Resets a delegate.
Definition delegate.hpp:227
Ret(const void *, Args...) function_type
Function type of the contained target.
Definition delegate.hpp:101
delegate(function_type *function, const void *payload=nullptr) noexcept
Constructs a delegate and connects an user defined function with optional payload.
Definition delegate.hpp:127
void connect(Type &value_or_instance) noexcept
Connects a free function with payload or a bound member to a delegate.
Definition delegate.hpp:166
void connect(Type *value_or_instance) noexcept
Connects a free function with payload or a bound member to a delegate.
Definition delegate.hpp:190
void connect() noexcept
Connects a free function or an unbound member to a delegate.
Definition delegate.hpp:136
Ret result_type
Return type of the delegate.
Definition delegate.hpp:105
const void * data() const noexcept
Returns the instance or the payload linked to a delegate, if any.
Definition delegate.hpp:244
delegate() noexcept=default
Default constructor.
void connect(function_type *function, const void *payload=nullptr) noexcept
Connects an user defined function with optional payload to a delegate.
Definition delegate.hpp:216
function_type * target() const noexcept
Returns a pointer to the stored callable function target, if any.
Definition delegate.hpp:236
Ret(Args...) type
Function type of the delegate.
Definition delegate.hpp:103
Basic delegate implementation.
Definition delegate.hpp:51
EnTT default namespace.
Definition dense_map.hpp:22
constexpr Type make_obj_using_allocator(const Allocator &allocator, Args &&...args)
Uses-allocator construction utility (waiting for C++20).
Definition memory.hpp:219
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.
delegate(connect_arg_t< Candidate >) -> delegate< std::remove_pointer_t< internal::function_pointer_t< decltype(Candidate)> > >
Deduction guide.
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.