1#ifndef ENTT_SIGNAL_DELEGATE_HPP
2#define ENTT_SIGNAL_DELEGATE_HPP
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"
18template<
typename Ret,
typename... Args>
19auto function_pointer(Ret (*)(Args...)) -> Ret (*)(Args...);
21template<
typename Ret,
typename Type,
typename... Args,
typename Other>
22auto function_pointer(Ret (*)(Type, Args...), Other &&) -> Ret (*)(Args...);
24template<
typename Class,
typename Ret,
typename... Args,
typename... Other>
25auto function_pointer(Ret (Class::*)(Args...), Other &&...) -> Ret (*)(Args...);
27template<
typename Class,
typename Ret,
typename... Args,
typename... Other>
28auto function_pointer(Ret (Class::*)(Args...)
const, Other &&...) -> Ret (*)(Args...);
30template<
typename Class,
typename Type,
typename... Other>
31requires stl::is_member_object_pointer_v<Type Class::*>
32auto function_pointer(Type Class::*, Other &&...) -> Type (*)();
34template<
typename... Type>
35using function_pointer_t =
decltype(function_pointer(stl::declval<Type>()...));
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...>{};
66template<
typename Ret,
typename... Args>
68 using return_type = stl::remove_const_t<Ret>;
69 using delegate_type = return_type(
const void *, Args...);
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)...);
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 {
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))...));
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 {
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))...));
102 using function_type = Ret(
const void *, Args...);
104 using type = Ret(Args...);
106 using result_type = Ret;
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)...);
128 delegate(function_type *function,
const void *payload =
nullptr) noexcept {
129 connect(function, payload);
136 template<auto Cand
idate>
137 void connect() noexcept {
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)...));
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)>{}));
147 fn = wrap<Candidate>(internal::index_sequence_for(internal::function_pointer_t<
decltype(Candidate)>{}));
166 template<auto Cand
idate,
typename Type>
167 void connect(Type &value_or_instance)
noexcept {
168 instance = &value_or_instance;
170 if constexpr(stl::is_invocable_r_v<Ret,
decltype(Candidate), Type &, Args...>) {
171 fn = [](
const void *payload, Args... args) -> return_type {
173 return Ret(stl::invoke(Candidate, *curr, stl::forward<Args>(args)...));
176 fn = wrap<Candidate>(value_or_instance, internal::index_sequence_for(internal::function_pointer_t<
decltype(Candidate), Type>{}));
190 template<auto Cand
idate,
typename Type>
191 void connect(Type *value_or_instance)
noexcept {
192 instance = value_or_instance;
194 if constexpr(stl::is_invocable_r_v<Ret,
decltype(Candidate), Type *, Args...>) {
195 fn = [](
const void *payload, Args... args) -> return_type {
197 return Ret(stl::invoke(Candidate, curr, stl::forward<Args>(args)...));
200 fn = wrap<Candidate>(value_or_instance, internal::index_sequence_for(internal::function_pointer_t<
decltype(Candidate), Type>{}));
217 void connect(function_type *function,
const void *payload =
nullptr) noexcept {
218 ENTT_ASSERT(function !=
nullptr,
"Uninitialized function pointer");
228 void reset() noexcept {
237 [[nodiscard]] function_type *target() const noexcept {
245 [[nodiscard]]
const void *data() const noexcept {
261 Ret operator()(Args... args)
const {
262 ENTT_ASSERT(
static_cast<bool>(*
this),
"Uninitialized delegate");
263 return fn(instance, stl::forward<Args>(args)...);
270 [[nodiscard]]
explicit operator bool() const noexcept {
272 return !(fn ==
nullptr);
280 [[nodiscard]]
bool operator==(
const delegate<Ret(Args...)> &other)
const noexcept {
281 return fn == other.fn && instance == other.instance;
285 const void *instance{};
293template<auto Cand
idate>
301template<auto Cand
idate,
typename Type>
309template<
typename Ret,
typename... Args>
Basic delegate implementation.
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.
A class to use to push around lists of types, nothing more.