/* Signals/slots for OctaSTD. * * This file is part of OctaSTD. See COPYING.md for futher information. */ #ifndef OSTD_SIGNAL_HH #define OSTD_SIGNAL_HH #include "ostd/functional.hh" #include "ostd/utility.hh" namespace ostd { namespace detail { template struct EventBase { EventBase(C *cl): p_class(cl), p_funcs(nullptr), p_nfuncs(0) {} EventBase(const EventBase &ev): p_class(ev.p_class), p_nfuncs(ev.p_nfuncs) { using Func = Function; Func *nbuf = (Func *)new byte[sizeof(Func) * p_nfuncs]; for (Size i = 0; i < p_nfuncs; ++i) new (&nbuf[i]) Func(ev.p_funcs[i]); p_funcs = nbuf; } EventBase(EventBase &&ev): p_class(ev.p_class), p_funcs(ev.p_funcs), p_nfuncs(ev.p_nfuncs) { ev.p_class = nullptr; ev.p_funcs = nullptr; ev.p_nfuncs = 0; } void clear() { for (Size i = 0; i < p_nfuncs; ++i) p_funcs[i].~Function(); delete[] (byte *)p_funcs; p_funcs = nullptr; p_nfuncs = 0; } template Size connect(F &&func) { using Func = Function; Func *nbuf = (Func *)new byte[sizeof(Func) * (p_nfuncs + 1)]; for (Size i = 0; i < p_nfuncs; ++i) { new (&nbuf[i]) Func(move(p_funcs[i])); p_funcs[i].~Func(); } new (&nbuf[p_nfuncs]) Func(forward(func)); delete[] (byte *)p_funcs; p_funcs = nbuf; return p_nfuncs++; } bool disconnect(Size idx) { if ((idx >= p_nfuncs) || !p_funcs[idx]) return false; p_funcs[idx] = nullptr; return true; } template void emit(Args &&...args) const { if (!p_class) return; for (Size i = 0; i < p_nfuncs; ++i) if (p_funcs[i]) p_funcs[i](*p_class, args...); } private: C *p_class; Function *p_funcs; Size p_nfuncs; }; } /* namespace detail */ template struct Event { private: using Base = detail::EventBase; Base p_base; public: Event(C *cl): p_base(cl) {} Event(const Event &ev): p_base(ev.p_base) {} Event(Event &&ev): p_base(move(ev.p_base)) {} ~Event() { clear(); } void clear() { p_base.clear(); } template Size connect(F &&func) { return p_base.connect(forward(func)); } bool disconnect(Size idx) { return p_base.disconnect(idx); } template void emit(Args &&...args) { p_base.emit(forward(args)...); } template void operator()(Args &&...args) { emit(forward(args)...); } }; template struct Event { private: using Base = detail::EventBase; Base p_base; public: Event(C *cl): p_base(cl) {} Event(const Event &ev): p_base(ev.p_base) {} Event(Event &&ev): p_base(move(ev.p_base)) {} ~Event() { clear(); } void clear() { p_base.clear(); } template Size connect(F &&func) { return p_base.connect(forward(func)); } bool disconnect(Size idx) { return p_base.disconnect(idx); } template void emit(Args &&...args) const { p_base.emit(forward(args)...); } template void operator()(Args &&...args) const { emit(forward(args)...); } }; } /* namespace ostd */ #endif