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