1#ifndef ENTT_SIGNAL_DELEGATE_HPP
2#define ENTT_SIGNAL_DELEGATE_HPP
9#include "../config/config.h"
10#include "../core/type_traits.hpp"
18template<
typename Ret,
typename... Args>
19constexpr auto function_pointer(Ret (*)(Args...)) -> Ret (*)(Args...);
21template<
typename Ret,
typename Type,
typename... Args,
typename Other>
22constexpr auto function_pointer(Ret (*)(Type, Args...), Other &&) -> Ret (*)(Args...);
24template<
typename Class,
typename Ret,
typename... Args,
typename... Other>
25constexpr auto function_pointer(Ret (Class::*)(Args...), Other &&...) -> Ret (*)(Args...);
27template<
typename Class,
typename Ret,
typename... Args,
typename... Other>
28constexpr auto function_pointer(Ret (Class::*)(Args...)
const, Other &&...) -> Ret (*)(Args...);
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 (*)();
33template<
typename... Type>
34using function_pointer_t =
decltype(function_pointer(std::declval<Type>()...));
36template<
typename... Class,
typename Ret,
typename... Args>
37[[nodiscard]]
constexpr auto index_sequence_for(Ret (*)(Args...)) {
38 return std::index_sequence_for<Class..., Args...>{};
65template<
typename Ret,
typename... Args>
67 using return_type = std::remove_const_t<Ret>;
68 using delegate_type = return_type(
const void *, Args...);
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)...);
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 {
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))...));
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 {
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))...));
101 using function_type = Ret(
const void *, Args...);
103 using type = Ret(Args...);
105 using result_type = Ret;
116 template<auto Candidate, typename... Type>
117 delegate(connect_arg_t<Candidate>, Type &&...value_or_instance) noexcept {
118 connect<Candidate>(std::forward<Type>(value_or_instance)...);
127 delegate(function_type *function,
const void *payload =
nullptr) noexcept {
128 connect(function, payload);
135 template<auto Cand
idate>
136 void connect() noexcept {
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)...));
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)>{}));
146 fn = wrap<Candidate>(internal::index_sequence_for(internal::function_pointer_t<
decltype(Candidate)>{}));
165 template<auto Cand
idate,
typename Type>
166 void connect(Type &value_or_instance)
noexcept {
167 instance = &value_or_instance;
169 if constexpr(std::is_invocable_r_v<Ret,
decltype(Candidate), Type &, Args...>) {
170 fn = [](
const void *payload, Args... args) -> return_type {
172 return Ret(std::invoke(Candidate, *curr, std::forward<Args>(args)...));
175 fn = wrap<Candidate>(value_or_instance, internal::index_sequence_for(internal::function_pointer_t<
decltype(Candidate), Type>{}));
189 template<auto Cand
idate,
typename Type>
190 void connect(Type *value_or_instance)
noexcept {
191 instance = value_or_instance;
193 if constexpr(std::is_invocable_r_v<Ret,
decltype(Candidate), Type *, Args...>) {
194 fn = [](
const void *payload, Args... args) -> return_type {
196 return Ret(std::invoke(Candidate, curr, std::forward<Args>(args)...));
199 fn = wrap<Candidate>(value_or_instance, internal::index_sequence_for(internal::function_pointer_t<
decltype(Candidate), Type>{}));
216 void connect(function_type *function,
const void *payload =
nullptr) noexcept {
217 ENTT_ASSERT(function !=
nullptr,
"Uninitialized function pointer");
227 void reset() noexcept {
236 [[nodiscard]] function_type *target() const noexcept {
244 [[nodiscard]]
const void *data() const noexcept {
260 Ret operator()(Args... args)
const {
261 ENTT_ASSERT(
static_cast<bool>(*
this),
"Uninitialized delegate");
262 return fn(instance, std::forward<Args>(args)...);
269 [[nodiscard]]
explicit operator bool() const noexcept {
271 return !(fn ==
nullptr);
280 return fn == other.fn && instance == other.instance;
284 const void *instance{};
296template<
typename Ret,
typename... Args>
298 return !(lhs == rhs);
305template<auto Cand
idate>
313template<auto Cand
idate,
typename Type>
321template<
typename Ret,
typename... Args>
Basic delegate implementation.
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.
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.
A class to use to push around lists of types, nothing more.