2#include "gaia/config/config.h"
8#include "gaia/cnt/darray.h"
9#include "gaia/core/func.h"
10#include "gaia/core/utility.h"
15 template <
typename Ret,
typename... Args>
16 auto func_ptr(Ret (*)(Args...)) -> Ret (*)(Args...);
18 template <
typename Ret,
typename Type,
typename... Args,
typename Other>
19 auto func_ptr(Ret (*)(Type, Args...), Other&&) -> Ret (*)(Args...);
21 template <
typename Class,
typename Ret,
typename... Args,
typename... Other>
22 auto func_ptr(Ret (Class::*)(Args...), Other&&...) -> Ret (*)(Args...);
24 template <
typename Class,
typename Ret,
typename... Args,
typename... Other>
25 auto func_ptr(Ret (Class::*)(Args...) const, Other&&...) -> Ret (*)(Args...);
27 template <
typename Class,
typename Type,
typename... Other>
28 auto func_ptr(Type Class::*, Other&&...) -> Type (*)();
30 template <
typename... Type>
31 using func_ptr_t =
decltype(detail::func_ptr(std::declval<Type>()...));
33 template <
typename... Class,
typename Ret,
typename... Args>
34 GAIA_NODISCARD
constexpr auto index_sequence_for(Ret (*)(Args...)) {
35 return std::index_sequence_for<Class..., Args...>{};
48 template <
typename Function>
50 template <
typename Function>
64 template <
typename Ret,
typename... Args>
66 using func_type = Ret(
const void*, Args...);
68 func_type* m_fnc =
nullptr;
69 const void* m_ctx =
nullptr;
76 template <auto FuncToBind>
85 template <auto FuncToBind,
typename Type>
87 bind<FuncToBind>(GAIA_FWD(value_or_instance));
93 delegate(func_type* func,
const void* data =
nullptr) noexcept {
99 template <auto FuncToBind>
103 if constexpr (std::is_invocable_r_v<Ret,
decltype(FuncToBind), Args...>) {
104 m_fnc = [](
const void*, Args... args) {
105 return Ret(invoke(FuncToBind, GAIA_FWD(args)...));
107 }
else if constexpr (std::is_member_pointer_v<
decltype(FuncToBind)>) {
108 m_fnc = wrap<FuncToBind>(detail::index_sequence_for<std::tuple_element_t<0, std::tuple<Args...>>>(
109 detail::func_ptr_t<
decltype(FuncToBind)>{}));
111 m_fnc = wrap<FuncToBind>(detail::index_sequence_for(detail::func_ptr_t<
decltype(FuncToBind)>{}));
121 template <auto FuncToBind,
typename Type>
122 void bind(Type& value_or_instance)
noexcept {
123 m_ctx = &value_or_instance;
125 if constexpr (std::is_invocable_r_v<Ret,
decltype(FuncToBind), Type&, Args...>) {
126 using const_or_not_type = std::conditional_t<std::is_const_v<Type>,
const void*,
void*>;
127 m_fnc = [](
const void* ctx, Args... args) {
128 auto pType =
static_cast<Type*
>(
const_cast<const_or_not_type
>(ctx));
129 return Ret(invoke(FuncToBind, *pType, GAIA_FWD(args)...));
132 m_fnc = wrap<FuncToBind>(
133 value_or_instance, detail::index_sequence_for(detail::func_ptr_t<
decltype(FuncToBind), Type>{}));
141 template <auto FuncToBind,
typename Type>
142 void bind(Type* value_or_instance)
noexcept {
143 m_ctx = value_or_instance;
145 if constexpr (std::is_invocable_r_v<Ret,
decltype(FuncToBind), Type*, Args...>) {
146 using const_or_not_type = std::conditional_t<std::is_const_v<Type>,
const void*,
void*>;
147 m_fnc = [](
const void* ctx, Args... args) {
148 auto pType =
static_cast<Type*
>(
const_cast<const_or_not_type
>(ctx));
149 return Ret(invoke(FuncToBind, pType, GAIA_FWD(args)...));
152 m_fnc = wrap<FuncToBind>(
153 value_or_instance, detail::index_sequence_for(detail::func_ptr_t<
decltype(FuncToBind), Type>{}));
161 void bind(func_type* function,
const void* context =
nullptr) noexcept {
175 return m_fnc !=
nullptr;
180 GAIA_NODISCARD
const void*
instance() const noexcept {
188 GAIA_ASSERT(m_fnc !=
nullptr &&
"Trying to call an unbound delegate!");
189 return m_fnc(m_ctx, GAIA_FWD(args)...);
194 GAIA_NODISCARD
explicit operator bool() const noexcept {
196 return m_fnc !=
nullptr;
203 return m_fnc == other.m_fnc && m_ctx == other.m_ctx;
210 return !operator==(other);
214 template <
auto FuncToBind, std::size_t... Index>
215 GAIA_NODISCARD
auto wrap(std::index_sequence<Index...>)
noexcept {
216 return [](
const void*, Args... args) {
217 [[maybe_unused]]
const auto argsFwd = std::forward_as_tuple(GAIA_FWD(args)...);
218 return Ret(invoke(FuncToBind, GAIA_FWD(std::get<Index>(argsFwd))...));
222 template <
auto FuncToBind,
typename Type, std::size_t... Index>
223 GAIA_NODISCARD
auto wrap(Type&, std::index_sequence<Index...>)
noexcept {
224 using const_or_not_type = std::conditional_t<std::is_const_v<Type>,
const void*,
void*>;
225 return [](
const void* ctx, Args... args) {
226 [[maybe_unused]]
const auto argsFwd = std::forward_as_tuple(GAIA_FWD(args)...);
227 auto pType =
static_cast<Type*
>(
const_cast<const_or_not_type
>(ctx));
228 return Ret(invoke(FuncToBind, *pType, GAIA_FWD(std::get<Index>(argsFwd))...));
232 template <
auto FuncToBind,
typename Type, std::size_t... Index>
233 GAIA_NODISCARD
auto wrap(Type*, std::index_sequence<Index...>)
noexcept {
234 using const_or_not_type = std::conditional_t<std::is_const_v<Type>,
const void*,
void*>;
235 return [](
const void* ctx, Args... args) {
236 [[maybe_unused]]
const auto argsFwd = std::forward_as_tuple(GAIA_FWD(args)...);
237 auto pType =
static_cast<Type*
>(
const_cast<const_or_not_type
>(ctx));
238 return Ret(invoke(FuncToBind, pType, GAIA_FWD(std::get<Index>(argsFwd))...));
249 template <
typename Ret,
typename... Args>
250 GAIA_NODISCARD
bool operator==(
const delegate<Ret(Args...)>& lhs,
const delegate<Ret(Args...)>& rhs)
noexcept {
260 template <
typename Ret,
typename... Args>
261 GAIA_NODISCARD
bool operator!=(
const delegate<Ret(Args...)>& lhs,
const delegate<Ret(Args...)>& rhs)
noexcept {
266 delegate(detail::connect_arg_t<Func>)
noexcept
267 -> delegate<std::remove_pointer_t<detail::func_ptr_t<
decltype(Func)>>>;
269 template <auto Func,
typename Type>
270 delegate(detail::connect_arg_t<Func>, Type&&) noexcept
271 -> delegate<std::remove_pointer_t<detail::func_ptr_t<decltype(Func), Type>>>;
273 template <typename Ret, typename... Args>
274 delegate(Ret (*)(const
void*, Args...), const
void* =
nullptr) noexcept -> delegate<Ret(Args...)>;
280 template <typename Ret, typename... Args>
281 class signal<Ret(Args...)>;
284 template <
typename Ret,
typename... Args>
285 using container = cnt::darray<delegate<Ret(Args...)>>;
292 template <
typename Ret,
typename... Args>
294 friend class sink<Ret(Args...)>;
306 GAIA_NODISCARD size_type
size() const noexcept {
307 return m_listeners.size();
312 GAIA_NODISCARD
bool empty() const noexcept {
313 return m_listeners.empty();
319 for (
auto&& call: std::as_const(m_listeners))
335 template <
typename Ret,
typename... Args>
338 using func_type = Ret(
const void*, Args...);
351 m_s->m_listeners.reserve(m_s->m_listeners.size() + other.m_s->m_listeners.size());
352 for (
auto&& listener: other.m_s->m_listeners)
353 m_s->m_listeners.push_back(GAIA_MOV(listener));
361 template <auto FuncToBind>
364 call.template bind<FuncToBind>();
374 template <auto FuncToBind,
typename Type>
375 void bind(Type& value_or_instance) {
377 call.template bind<FuncToBind>(value_or_instance);
385 void bind(func_type* func,
const void* data =
nullptr) {
386 if (func ==
nullptr && data ==
nullptr)
390 call.bind(func, data);
396 template <auto FuncToUnbind>
399 call.template bind<FuncToUnbind>();
401 m_s->m_listeners.retain([&](
const auto& l) {
410 template <auto FuncToUnbind,
typename Type>
413 call.template bind<FuncToUnbind>(value_or_instance);
415 auto& listeners = m_s->m_listeners;
416 for (uint32_t i = 0; i < listeners.size();) {
417 if (listeners[i] != call) {
422 core::swap_erase_unsafe(listeners, i);
429 template <
typename Type>
431 if (!value_or_instance)
434 auto& listeners = m_s->m_listeners;
435 for (uint32_t i = 0; i < listeners.size();) {
436 if (listeners[i].instance() != value_or_instance) {
441 core::swap_erase_unsafe(listeners, i);
448 template <
typename Type>
450 unbind(&value_or_instance);
455 m_s->m_listeners.clear();
459 void bind_internal(
const delegate<Ret(Args...)>& call) {
460 if (!core::has(m_s->m_listeners, call))
461 m_s->m_listeners.push_back(GAIA_MOV(call));
465 template <
typename Ret,
typename... Args>
466 sink(signal<Ret(Args...)>&) noexcept -> sink<Ret(Args...)>;
Array with variable size of elements of type.
Definition darray_impl.h:25
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:86
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:161
void reset() noexcept
Resets a delegate. After a reset, a delegate cannot be invoked anymore.
Definition signal.h:167
GAIA_NODISCARD bool has_func() const noexcept
Returns the functor pointer linked to a delegate, if any.
Definition signal.h:174
void bind() noexcept
Binds a free function or an unbound member to a delegate.
Definition signal.h:100
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:122
Ret operator()(Args... args) const
The delegate invokes the underlying function and returns the result.
Definition signal.h:187
delegate(func_type *func, const void *data=nullptr) noexcept
Constructs a delegate by binding a function with optional context to it.
Definition signal.h:93
GAIA_NODISCARD bool operator!=(const delegate< Ret(Args...)> &other) const noexcept
Compares the contents of two delegates.
Definition signal.h:209
GAIA_NODISCARD bool operator==(const delegate< Ret(Args...)> &other) const noexcept
Compares the contents of two delegates.
Definition signal.h:202
GAIA_NODISCARD const void * instance() const noexcept
Returns the instance or the context linked to a delegate, if any.
Definition signal.h:180
delegate(detail::connect_arg_t< FuncToBind >) noexcept
Constructs a delegate by binding a free function or an unbound member to it.
Definition signal.h:77
void bind(Type *value_or_instance) noexcept
Binds a free function with context or a bound member to a delegate.
Definition signal.h:142
Signal is a container of listener which it can notify. It works directly with references to classes a...
Definition signal.h:293
GAIA_NODISCARD size_type size() const noexcept
Number of listeners connected to the signal.
Definition signal.h:306
GAIA_NODISCARD bool empty() const noexcept
Check is there is any listener bound to the signal.
Definition signal.h:312
void emit(Args... args)
Signals all listeners.
Definition signal.h:318
Sink is a helper class used to bind listeners to signals. The separation between signal and sink make...
Definition signal.h:336
sink(signal< Ret(Args...)> &ref) noexcept
Constructs a sink that is allowed to modify a given signal.
Definition signal.h:345
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:350
void bind()
Binds a free function or an unbound member to a signal. The signal handler performs checks to avoid m...
Definition signal.h:362
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:375
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 bound members from a signal.
Definition signal.h:430
void unbind(Type &value_or_instance)
Unbinds a free function with context or a bound member from a signal.
Definition signal.h:411
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:385
void reset()
Unbinds all listeners from a signal.
Definition signal.h:454
void unbind()
Unbinds a free function or an unbound member from a signal.
Definition signal.h:397
Checks if endianess was detected correctly at compile-time.
Definition bitset.h:9