1 #ifndef ENTT_SIGNAL_DELEGATE_HPP
2 #define ENTT_SIGNAL_DELEGATE_HPP
10 #include "../core/type_traits.hpp"
11 #include "../config/config.h"
26 template<
typename Ret,
typename... Args>
27 auto function_pointer(Ret(*)(Args...)) -> Ret(*)(Args...);
30 template<
typename Ret,
typename Type,
typename... Args,
typename Other>
31 auto function_pointer(Ret(*)(Type, Args...), Other &&) -> Ret(*)(Args...);
34 template<
typename Class,
typename Ret,
typename... Args,
typename... Other>
35 auto function_pointer(Ret(Class:: *)(Args...), Other &&...) -> Ret(*)(Args...);
38 template<
typename Class,
typename Ret,
typename... Args,
typename... Other>
39 auto function_pointer(Ret(Class:: *)(Args...)
const, Other &&...) -> Ret(*)(Args...);
42 template<
typename Class,
typename Type,
typename... Other>
43 auto function_pointer(Type Class:: *, Other &&...) -> Type(*)();
46 template<
typename... Type>
47 using function_pointer_t = decltype(internal::function_pointer(std::declval<Type>()...));
50 template<
typename... Class,
typename Ret,
typename... Args>
51 [[nodiscard]] constexpr
auto index_sequence_for(Ret(*)(Args...)) {
52 return std::index_sequence_for<Class..., Args...>{};
97 template<
typename Ret,
typename... Args>
99 template<
auto Candidate, std::size_t... Index>
100 [[nodiscard]]
auto wrap(std::index_sequence<Index...>) ENTT_NOEXCEPT {
101 return [](
const void *, Args... args) -> Ret {
102 [[maybe_unused]]
const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
107 template<
auto Candidate,
typename Type, std::size_t... Index>
108 [[nodiscard]]
auto wrap(Type &, std::index_sequence<Index...>) ENTT_NOEXCEPT {
109 return [](
const void *payload, Args... args) -> Ret {
110 [[maybe_unused]]
const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
116 template<
auto Candidate,
typename Type, std::size_t... Index>
117 [[nodiscard]]
auto wrap(Type *, std::index_sequence<Index...>) ENTT_NOEXCEPT {
118 return [](
const void *payload, Args... args) -> Ret {
119 [[maybe_unused]]
const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
135 : fn{
nullptr}, data{
nullptr}
143 template<auto Cand
idate>
145 connect<Candidate>();
155 template<auto Cand
idate,
typename Type>
157 connect<Candidate>(std::forward<Type>(value_or_instance));
167 connect(
function, payload);
174 template<auto Cand
idate>
178 if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Args...>) {
179 fn = [](
const void *, Args... args) -> Ret {
180 return Ret(std::invoke(Candidate, std::forward<Args>(args)...));
182 }
else if constexpr(std::is_member_pointer_v<decltype(Candidate)>) {
185 fn = wrap<Candidate>(internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate)>{}));
204 template<auto Cand
idate,
typename Type>
205 void connect(Type &value_or_instance) ENTT_NOEXCEPT {
206 data = &value_or_instance;
208 if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Type &, Args...>) {
209 fn = [](
const void *payload, Args... args) -> Ret {
211 return Ret(std::invoke(Candidate, *curr, std::forward<Args>(args)...));
214 fn = wrap<Candidate>(value_or_instance, internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate), Type>{}));
228 template<auto Cand
idate,
typename Type>
229 void connect(Type *value_or_instance) ENTT_NOEXCEPT {
230 data = value_or_instance;
232 if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Type *, Args...>) {
233 fn = [](
const void *payload, Args... args) -> Ret {
235 return Ret(std::invoke(Candidate, curr, std::forward<Args>(args)...));
238 fn = wrap<Candidate>(value_or_instance, internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate), Type>{}));
274 [[nodiscard]]
const void *
instance() const ENTT_NOEXCEPT {
291 ENTT_ASSERT(
static_cast<bool>(*
this),
"Uninitialized delegate");
292 return fn(data, std::forward<Args>(args)...);
299 [[nodiscard]]
explicit operator bool() const ENTT_NOEXCEPT {
301 return !(fn ==
nullptr);
310 return fn == other.fn && data == other.data;
327 template<
typename Ret,
typename... Args>
329 return !(lhs == rhs);
337 template<auto Cand
idate>
339 ->
delegate<std::remove_pointer_t<internal::function_pointer_t<decltype(Candidate)>>>;
347 template<auto Cand
idate,
typename Type>
349 ->
delegate<std::remove_pointer_t<internal::function_pointer_t<decltype(Candidate), Type>>>;
357 template<
typename Ret,
typename... Args>
358 delegate(Ret(*)(
const void *, Args...),
const void * =
nullptr)
Ret operator()(Args... args) const
Triggers a delegate.
const void * instance() const
Returns the instance or the payload linked to a delegate, if any.
Ret(const void *, Args...) function_type
Function type of the contained target.
void reset()
Resets a delegate.
delegate()
Default constructor.
delegate(connect_arg_t< Candidate >)
Constructs a delegate and connects a free function or an unbound member.
void connect(function_type *function, const void *payload=nullptr)
Connects an user defined function with optional payload to a delegate.
delegate(connect_arg_t< Candidate >, Type &&value_or_instance)
Constructs a delegate and connects a free function with payload or a bound member.
Ret result_type
Return type of the delegate.
void connect(Type *value_or_instance)
Connects a free function with payload or a bound member to a delegate.
bool operator==(const delegate< Ret(Args...)> &other) const
Compares the contents of two delegates.
void connect()
Connects a free function or an unbound member to a delegate.
Ret(Args...) type
Function type of the delegate.
delegate(function_type *function, const void *payload=nullptr)
Constructs a delegate and connects an user defined function with optional payload.
void connect(Type &value_or_instance)
Connects a free function with payload or a bound member to a delegate.
Basic delegate implementation.
typename constness_as< To, From >::type constness_as_t
Alias template to facilitate the transcription of the constness.
delegate(connect_arg_t< Candidate >) -> delegate< std::remove_pointer_t< internal::function_pointer_t< decltype(Candidate)>>>
Deduction guide.
typename type_list_element< Index, List >::type type_list_element_t
Helper type.
bool operator!=(const basic_any< Len, Align > &lhs, const basic_any< Len, Align > &rhs)
Checks if two wrappers differ in their content.
constexpr connect_arg_t< Func > connect_arg
Constant of type connect_arg_t used to disambiguate calls.
Used to wrap a function or a member of a specified type.
A class to use to push around lists of types, nothing more.