libostd/ostd/event.hh

195 lines
5.4 KiB
C++
Raw Normal View History

2015-07-16 02:37:37 +02:00
/* Signals/slots for OctaSTD.
*
* This file is part of OctaSTD. See COPYING.md for futher information.
*/
2015-07-17 20:00:25 +02:00
#ifndef OSTD_EVENT_HH
#define OSTD_EVENT_HH
2015-07-16 02:37:37 +02:00
#include "ostd/functional.hh"
#include "ostd/utility.hh"
namespace ostd {
2015-07-16 19:55:21 +02:00
namespace detail {
template<typename C, typename ...A>
2015-07-17 20:00:25 +02:00
struct SignalBase {
SignalBase(C *cl): p_class(cl), p_funcs(nullptr), p_nfuncs(0) {}
2015-07-16 19:55:21 +02:00
2016-06-23 20:18:35 +02:00
SignalBase(SignalBase const &ev): p_class(ev.p_class),
p_nfuncs(ev.p_nfuncs) {
2015-07-16 19:55:21 +02:00
using Func = Function<void(C &, A...)>;
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;
}
2015-07-17 20:00:25 +02:00
SignalBase(SignalBase &&ev): p_class(nullptr), p_funcs(nullptr),
2015-07-16 21:47:59 +02:00
p_nfuncs(0) {
swap(ev);
2015-07-16 19:55:21 +02:00
}
2016-06-23 20:18:35 +02:00
SignalBase &operator=(SignalBase const &ev) {
2015-07-16 21:47:59 +02:00
using Func = Function<void(C &, A...)>;
p_class = ev.p_class;
p_nfuncs = ev.p_nfuncs;
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;
return *this;
}
2015-07-17 20:00:25 +02:00
SignalBase &operator=(SignalBase &&ev) {
2015-07-16 21:47:59 +02:00
swap(ev);
return *this;
}
2015-07-17 20:00:25 +02:00
~SignalBase() { clear(); }
2015-07-16 21:47:59 +02:00
2015-07-16 19:55:21 +02:00
void clear() {
for (Size i = 0; i < p_nfuncs; ++i)
p_funcs[i].~Function<void(C &, A...)>();
delete[] (byte *)p_funcs;
p_funcs = nullptr;
p_nfuncs = 0;
}
template<typename F>
Size connect(F &&func) {
using Func = Function<void(C &, A...)>;
2015-07-16 20:21:51 +02:00
for (Size i = 0; i < p_nfuncs; ++i)
if (!p_funcs[i]) {
p_funcs[i] = forward<F>(func);
return i;
}
2015-07-16 19:55:21 +02:00
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<F>(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<typename ...Args>
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...);
}
2015-07-16 21:47:59 +02:00
C *get_class() const {
return p_class;
}
C *set_class(C *cl) {
C *ocl = p_class;
p_class = cl;
return ocl;
}
2015-07-17 20:00:25 +02:00
void swap(SignalBase &ev) {
2015-07-16 21:47:59 +02:00
detail::swap_adl(p_class, ev.p_class);
detail::swap_adl(p_funcs, ev.p_funcs);
detail::swap_adl(p_nfuncs, ev.p_nfuncs);
}
2015-07-16 19:55:21 +02:00
private:
C *p_class;
Function<void(C &, A...)> *p_funcs;
Size p_nfuncs;
};
} /* namespace detail */
2015-07-16 02:37:37 +02:00
template<typename C, typename ...A>
2015-07-17 20:00:25 +02:00
struct Signal {
2015-07-16 19:55:21 +02:00
private:
2015-07-17 20:00:25 +02:00
using Base = detail::SignalBase<C, A...>;
2015-07-16 19:55:21 +02:00
Base p_base;
public:
2015-07-17 20:00:25 +02:00
Signal(C *cl): p_base(cl) {}
2016-06-23 20:18:35 +02:00
Signal(Signal const &ev): p_base(ev.p_base) {}
2015-07-17 20:00:25 +02:00
Signal(Signal &&ev): p_base(move(ev.p_base)) {}
2015-07-16 19:55:21 +02:00
2016-06-23 20:18:35 +02:00
Signal &operator=(Signal const &ev) {
2015-07-16 21:47:59 +02:00
p_base = ev.p_base;
return *this;
}
2015-07-17 20:00:25 +02:00
Signal &operator=(Signal &&ev) {
2015-07-16 21:47:59 +02:00
p_base = move(ev.p_base);
return *this;
}
2015-07-16 19:55:21 +02:00
void clear() { p_base.clear(); }
2015-07-16 02:37:37 +02:00
template<typename F>
2015-07-16 19:55:21 +02:00
Size connect(F &&func) { return p_base.connect(forward<F>(func)); }
bool disconnect(Size idx) { return p_base.disconnect(idx); }
2015-07-16 02:37:37 +02:00
template<typename ...Args>
2015-07-16 19:55:21 +02:00
void emit(Args &&...args) { p_base.emit(forward<Args>(args)...); }
2015-07-16 02:37:37 +02:00
template<typename ...Args>
2015-07-16 19:55:21 +02:00
void operator()(Args &&...args) { emit(forward<Args>(args)...); }
2015-07-16 21:47:59 +02:00
C *get_class() const { return p_base.get_class(); }
C *set_class(C *cl) { return p_base.set_class(cl); }
2015-07-17 20:00:25 +02:00
void swap(Signal &ev) { p_base.swap(ev.p_base); }
2015-07-16 19:55:21 +02:00
};
2015-07-16 02:37:37 +02:00
2015-07-16 19:55:21 +02:00
template<typename C, typename ...A>
2016-06-23 20:18:35 +02:00
struct Signal<C const, A...> {
2015-07-16 02:37:37 +02:00
private:
2016-06-23 20:18:35 +02:00
using Base = detail::SignalBase<C const, A...>;
2015-07-16 19:55:21 +02:00
Base p_base;
public:
2015-07-17 20:00:25 +02:00
Signal(C *cl): p_base(cl) {}
2016-06-23 20:18:35 +02:00
Signal(Signal const &ev): p_base(ev.p_base) {}
2015-07-17 20:00:25 +02:00
Signal(Signal &&ev): p_base(move(ev.p_base)) {}
2015-07-16 19:55:21 +02:00
2016-06-23 20:18:35 +02:00
Signal &operator=(Signal const &ev) {
2015-07-16 21:47:59 +02:00
p_base = ev.p_base;
return *this;
}
2015-07-17 20:00:25 +02:00
Signal &operator=(Signal &&ev) {
2015-07-16 21:47:59 +02:00
p_base = move(ev.p_base);
return *this;
}
2015-07-16 19:55:21 +02:00
void clear() { p_base.clear(); }
template<typename F>
Size connect(F &&func) { return p_base.connect(forward<F>(func)); }
bool disconnect(Size idx) { return p_base.disconnect(idx); }
template<typename ...Args>
void emit(Args &&...args) const { p_base.emit(forward<Args>(args)...); }
template<typename ...Args>
void operator()(Args &&...args) const { emit(forward<Args>(args)...); }
2015-07-16 21:47:59 +02:00
C *get_class() const { return p_base.get_class(); }
C *set_class(C *cl) { return p_base.set_class(cl); }
2015-07-17 20:00:25 +02:00
void swap(Signal &ev) { p_base.swap(ev.p_base); }
2015-07-16 02:37:37 +02:00
};
} /* namespace ostd */
2016-02-07 22:17:15 +01:00
#endif