2#include "gaia/config/config.h"
8#include "gaia/cnt/darray.h"
9#include "gaia/core/func.h"
10#include "gaia/core/utility.h"
16 template <
typename Ret,
typename... Args>
17 auto func_ptr(Ret (*)(Args...)) -> Ret (*)(Args...);
19 template <
typename Ret,
typename Type,
typename... Args,
typename Other>
20 auto func_ptr(Ret (*)(Type, Args...), Other&&) -> Ret (*)(Args...);
22 template <
typename Class,
typename Ret,
typename... Args,
typename... Other>
23 auto func_ptr(Ret (Class::*)(Args...), Other&&...) -> Ret (*)(Args...);
25 template <
typename Class,
typename Ret,
typename... Args,
typename... Other>
26 auto func_ptr(Ret (Class::*)(Args...) const, Other&&...) -> Ret (*)(Args...);
28 template <
typename Class,
typename Type,
typename... Other>
29 auto func_ptr(Type Class::*, Other&&...) -> Type (*)();
31 template <
typename... Type>
32 using func_ptr_t =
decltype(detail::func_ptr(std::declval<Type>()...));
34 template <
typename... Class,
typename Ret,
typename... Args>
35 GAIA_NODISCARD
constexpr auto index_sequence_for(Ret (*)(Args...)) {
36 return std::index_sequence_for<Class..., Args...>{};
41 struct connect_arg_t {};
44 inline constexpr connect_arg_t<Func> connect_arg{};
50 template <
typename Function>
52 template <
typename Function>
66 template <
typename Ret,
typename... Args>
68 using func_type = Ret(
const void*, Args...);
70 func_type* m_fnc =
nullptr;
71 const void* m_ctx =
nullptr;
78 template <auto FuncToBind>
79 delegate(detail::connect_arg_t<FuncToBind>)
noexcept {
87 template <auto FuncToBind,
typename Type>
88 delegate(detail::connect_arg_t<FuncToBind>, Type&& value_or_instance)
noexcept {
89 bind<FuncToBind>(GAIA_FWD(value_or_instance));
95 delegate(func_type* func,
const void* data =
nullptr) noexcept {
101 template <auto FuncToBind>
105 if constexpr (std::is_invocable_r_v<Ret,
decltype(FuncToBind), Args...>) {
106 m_fnc = [](
const void*, Args... args) {
107 return Ret(invoke(FuncToBind, GAIA_FWD(args)...));
109 }
else if constexpr (std::is_member_pointer_v<
decltype(FuncToBind)>) {
110 m_fnc = wrap<FuncToBind>(detail::index_sequence_for<std::tuple_element_t<0, std::tuple<Args...>>>(
111 detail::func_ptr_t<
decltype(FuncToBind)>{}));
113 m_fnc = wrap<FuncToBind>(detail::index_sequence_for(detail::func_ptr_t<
decltype(FuncToBind)>{}));
123 template <auto FuncToBind,
typename Type>
124 void bind(Type& value_or_instance)
noexcept {
125 m_ctx = &value_or_instance;
127 if constexpr (std::is_invocable_r_v<Ret,
decltype(FuncToBind), Type&, Args...>) {
128 using const_or_not_type = std::conditional_t<std::is_const_v<Type>,
const void*,
void*>;
129 m_fnc = [](
const void* ctx, Args... args) {
130 auto pType =
static_cast<Type*
>(
const_cast<const_or_not_type
>(ctx));
131 return Ret(invoke(FuncToBind, *pType, GAIA_FWD(args)...));
134 m_fnc = wrap<FuncToBind>(
135 value_or_instance, detail::index_sequence_for(detail::func_ptr_t<
decltype(FuncToBind), Type>{}));
143 template <auto FuncToBind,
typename Type>
144 void bind(Type* value_or_instance)
noexcept {
145 m_ctx = value_or_instance;
147 if constexpr (std::is_invocable_r_v<Ret,
decltype(FuncToBind), Type*, Args...>) {
148 using const_or_not_type = std::conditional_t<std::is_const_v<Type>,
const void*,
void*>;
149 m_fnc = [](
const void* ctx, Args... args) {
150 auto pType =
static_cast<Type*
>(
const_cast<const_or_not_type
>(ctx));
151 return Ret(invoke(FuncToBind, pType, GAIA_FWD(args)...));
154 m_fnc = wrap<FuncToBind>(
155 value_or_instance, detail::index_sequence_for(detail::func_ptr_t<
decltype(FuncToBind), Type>{}));
163 void bind(func_type* function,
const void* context =
nullptr) noexcept {
177 return m_fnc !=
nullptr;
182 GAIA_NODISCARD
const void*
instance() const noexcept {
190 GAIA_ASSERT(m_fnc !=
nullptr &&
"Trying to call an unbound delegate!");
191 return m_fnc(m_ctx, GAIA_FWD(args)...);
196 GAIA_NODISCARD
explicit operator bool() const noexcept {
198 return m_fnc !=
nullptr;
205 return m_fnc == other.m_fnc && m_ctx == other.m_ctx;
212 return !operator==(other);
216 template <
auto FuncToBind, std::size_t... Index>
217 GAIA_NODISCARD
auto wrap(std::index_sequence<Index...>)
noexcept {
218 return [](
const void*, Args... args) {
219 [[maybe_unused]]
const auto argsFwd = std::forward_as_tuple(GAIA_FWD(args)...);
220 return Ret(invoke(FuncToBind, GAIA_FWD(std::get<Index>(argsFwd))...));
224 template <
auto FuncToBind,
typename Type, std::size_t... Index>
225 GAIA_NODISCARD
auto wrap(Type&, std::index_sequence<Index...>)
noexcept {
226 using const_or_not_type = std::conditional_t<std::is_const_v<Type>,
const void*,
void*>;
227 return [](
const void* ctx, Args... args) {
228 [[maybe_unused]]
const auto argsFwd = std::forward_as_tuple(GAIA_FWD(args)...);
229 auto pType =
static_cast<Type*
>(
const_cast<const_or_not_type
>(ctx));
230 return Ret(invoke(FuncToBind, *pType, GAIA_FWD(std::get<Index>(argsFwd))...));
234 template <
auto FuncToBind,
typename Type, std::size_t... Index>
235 GAIA_NODISCARD
auto wrap(Type*, std::index_sequence<Index...>)
noexcept {
236 using const_or_not_type = std::conditional_t<std::is_const_v<Type>,
const void*,
void*>;
237 return [](
const void* ctx, Args... args) {
238 [[maybe_unused]]
const auto argsFwd = std::forward_as_tuple(GAIA_FWD(args)...);
239 auto pType =
static_cast<Type*
>(
const_cast<const_or_not_type
>(ctx));
240 return Ret(invoke(FuncToBind, pType, GAIA_FWD(std::get<Index>(argsFwd))...));
251 template <
typename Ret,
typename... Args>
252 GAIA_NODISCARD
bool operator==(
const delegate<Ret(Args...)>& lhs,
const delegate<Ret(Args...)>& rhs)
noexcept {
262 template <
typename Ret,
typename... Args>
263 GAIA_NODISCARD
bool operator!=(
const delegate<Ret(Args...)>& lhs,
const delegate<Ret(Args...)>& rhs)
noexcept {
271 delegate(detail::connect_arg_t<Func> tag)
noexcept
272 -> delegate<std::remove_pointer_t<detail::func_ptr_t<
decltype(Func)>>>;
279 template <auto Func,
typename Type>
280 delegate(detail::connect_arg_t<Func> tag, Type&& value_or_instance)
noexcept
281 -> delegate<std::remove_pointer_t<detail::func_ptr_t<
decltype(Func), Type>>>;
288 template <
typename Ret,
typename... Args>
289 delegate(Ret (*func)(
const void*, Args...),
const void* data =
nullptr) noexcept -> delegate<Ret(Args...)>;
295 template <typename Ret, typename... Args>
296 class signal<Ret(Args...)>;
300 template <
typename Ret,
typename... Args>
301 using container = cnt::darray<delegate<Ret(Args...)>>;
309 template <
typename Ret,
typename... Args>
311 friend class sink<Ret(Args...)>;
315 detail::container<Ret, Args...> m_listeners;
319 using size_type =
typename detail::container<Ret, Args...>::size_type;
326 return m_listeners.size();
331 GAIA_NODISCARD
bool empty() const noexcept {
332 return m_listeners.empty();
338 for (
auto&& call: std::as_const(m_listeners))
354 template <
typename Ret,
typename... Args>
357 using func_type = Ret(
const void*, Args...);
370 m_s->m_listeners.reserve(m_s->m_listeners.size() + other.m_s->m_listeners.size());
371 for (
auto&& listener: other.m_s->m_listeners)
372 m_s->m_listeners.push_back(GAIA_MOV(listener));
380 template <auto FuncToBind>
383 call.template bind<FuncToBind>();
393 template <auto FuncToBind,
typename Type>
394 void bind(Type& value_or_instance) {
396 call.template bind<FuncToBind>(value_or_instance);
404 void bind(func_type* func,
const void* data =
nullptr) {
405 if (func ==
nullptr && data ==
nullptr)
409 call.bind(func, data);
415 template <auto FuncToUnbind>
418 call.template bind<FuncToUnbind>();
420 m_s->m_listeners.retain([&](
const auto& l) {
429 template <auto FuncToUnbind,
typename Type>
432 call.template bind<FuncToUnbind>(value_or_instance);
434 auto& listeners = m_s->m_listeners;
435 for (uint32_t i = 0; i < listeners.size();) {
436 if (listeners[i] != call) {
441 core::swap_erase_unsafe(listeners, i);
448 template <
typename Type>
450 if (!value_or_instance)
453 auto& listeners = m_s->m_listeners;
454 for (uint32_t i = 0; i < listeners.size();) {
455 if (listeners[i].instance() != value_or_instance) {
460 core::swap_erase_unsafe(listeners, i);
467 template <
typename Type>
469 unbind(&value_or_instance);
474 m_s->m_listeners.clear();
478 void bind_internal(
const delegate<Ret(Args...)>& call) {
479 if (!core::has(m_s->m_listeners, call))
480 m_s->m_listeners.push_back(GAIA_MOV(call));
488 template <
typename Ret,
typename... Args>
489 sink(signal<Ret(Args...)>& ref)
noexcept -> sink<Ret(Args...)>;
delegate(detail::connect_arg_t< FuncToBind >, Type &&value_or_instance) noexcept
Constructs a delegate by binding a free function with context or a bound member to it.
Definition signal.h:88
void bind(func_type *function, const void *context=nullptr) noexcept
Binds an user defined function with optional context to a delegate. The context is returned as the fi...
Definition signal.h:163
void reset() noexcept
Resets a delegate. After a reset, a delegate cannot be invoked anymore.
Definition signal.h:169
GAIA_NODISCARD bool has_func() const noexcept
Returns the functor pointer linked to a delegate, if any.
Definition signal.h:176
void bind() noexcept
Binds a free function or an unbound member to a delegate.
Definition signal.h:102
void bind(Type &value_or_instance) noexcept
Binds a free function with context or a bound member to a delegate. When used to bind a ree function ...
Definition signal.h:124
Ret operator()(Args... args) const
The delegate invokes the underlying function and returns the result.
Definition signal.h:189
delegate(func_type *func, const void *data=nullptr) noexcept
Constructs a delegate by binding a function with optional context to it.
Definition signal.h:95
GAIA_NODISCARD bool operator!=(const delegate< Ret(Args...)> &other) const noexcept
Compares the contents of two delegates.
Definition signal.h:211
GAIA_NODISCARD bool operator==(const delegate< Ret(Args...)> &other) const noexcept
Compares the contents of two delegates.
Definition signal.h:204
GAIA_NODISCARD const void * instance() const noexcept
Returns the instance or the context linked to a delegate, if any.
Definition signal.h:182
delegate(detail::connect_arg_t< FuncToBind >) noexcept
Constructs a delegate by binding a free function or an unbound member to it.
Definition signal.h:79
void bind(Type *value_or_instance) noexcept
Binds a free function with context or a bound member to a delegate.
Definition signal.h:144
Signal is a container of listener which it can notify. It works directly with references to classes a...
Definition signal.h:310
GAIA_NODISCARD size_type size() const noexcept
Number of listeners connected to the signal.
Definition signal.h:325
typename detail::container< Ret, Args... >::size_type size_type
Type used to represent listener counts.
Definition signal.h:319
GAIA_NODISCARD bool empty() const noexcept
Check is there is any listener bound to the signal.
Definition signal.h:331
void emit(Args... args)
Signals all listeners.
Definition signal.h:337
Sink is a helper class used to bind listeners to signals. The separation between signal and sink make...
Definition signal.h:355
sink(signal< Ret(Args...)> &ref) noexcept
Constructs a sink that is allowed to modify a given signal.
Definition signal.h:364
void move_from(sink &other)
Moves signals from another sink to this one. Result is stored in this object. The sink we merge from ...
Definition signal.h:369
void bind()
Binds a free function or an unbound member to a signal. The signal handler performs checks to avoid m...
Definition signal.h:381
void bind(Type &value_or_instance)
Binds a free function with context or a bound member to a signal. When used to bind a free function w...
Definition signal.h:394
void unbind(Type &value_or_instance)
Unbinds a free function with context or bound members from a signal.
Definition signal.h:468
void unbind(Type *value_or_instance)
Unbinds a free function with context or bound members from a signal.
Definition signal.h:449
void unbind(Type &value_or_instance)
Unbinds a free function with context or a bound member from a signal.
Definition signal.h:430
void bind(func_type *func, const void *data=nullptr)
Binds an user defined function with optional context to a signal. The context is returned as the firs...
Definition signal.h:404
void reset()
Unbinds all listeners from a signal.
Definition signal.h:473
void unbind()
Unbinds a free function or an unbound member from a signal.
Definition signal.h:416