libostd/ostd/event.hh

218 lines
6.1 KiB
C++
Raw Permalink Normal View History

2017-04-06 20:14:52 +02:00
/* signals/slots for libostd.
2015-07-16 02:37:37 +02:00
*
2017-04-06 20:14:52 +02:00
* This file is part of libostd. See COPYING.md for futher information.
2015-07-16 02:37:37 +02:00
*/
2015-07-17 20:00:25 +02:00
#ifndef OSTD_EVENT_HH
#define OSTD_EVENT_HH
2015-07-16 02:37:37 +02:00
2017-04-09 16:44:45 +02:00
#include <cstddef>
2017-02-08 01:06:50 +01:00
#include <functional>
2017-02-16 20:39:05 +01:00
#include <utility>
2015-07-16 02:37:37 +02:00
namespace ostd {
2015-07-16 19:55:21 +02:00
namespace detail {
template<typename C, typename ...A>
2017-02-16 20:39:05 +01:00
struct signal_base {
signal_base(C *cl): p_class(cl), p_funcs(nullptr), p_nfuncs(0) {}
2015-07-16 19:55:21 +02:00
2017-02-16 20:39:05 +01:00
signal_base(signal_base const &ev):
p_class(ev.p_class), p_nfuncs(ev.p_nfuncs)
{
using func_t = std::function<void(C &, A...)>;
2017-04-04 00:30:07 +02:00
auto *bufp = new unsigned char[sizeof(func_t) * p_nfuncs];
func_t *nbuf = reinterpret_cast<func_t *>(bufp);
2017-04-09 16:44:45 +02:00
for (std::size_t i = 0; i < p_nfuncs; ++i)
new (&nbuf[i]) func_t(ev.p_funcs[i]);
2015-07-16 19:55:21 +02:00
p_funcs = nbuf;
}
2017-02-16 20:39:05 +01:00
signal_base(signal_base &&ev):
p_class(nullptr), p_funcs(nullptr), p_nfuncs(0)
{
2015-07-16 21:47:59 +02:00
swap(ev);
2015-07-16 19:55:21 +02:00
}
2017-02-16 20:39:05 +01:00
signal_base &operator=(signal_base const &ev) {
using func_t = std::function<void(C &, A...)>;
2015-07-16 21:47:59 +02:00
p_class = ev.p_class;
p_nfuncs = ev.p_nfuncs;
2017-04-04 00:30:07 +02:00
auto *bufp = new unsigned char[sizeof(func_t) * p_nfuncs];
func_t *nbuf = reinterpret_cast<func_t *>(bufp);
2017-04-09 16:44:45 +02:00
for (std::size_t i = 0; i < p_nfuncs; ++i) {
new (&nbuf[i]) func_t(ev.p_funcs[i]);
}
2015-07-16 21:47:59 +02:00
p_funcs = nbuf;
return *this;
}
2017-02-16 20:39:05 +01:00
signal_base &operator=(signal_base &&ev) {
2015-07-16 21:47:59 +02:00
swap(ev);
return *this;
}
2017-02-16 20:39:05 +01:00
~signal_base() { clear(); }
2015-07-16 21:47:59 +02:00
2015-07-16 19:55:21 +02:00
void clear() {
2017-04-09 16:44:45 +02:00
for (std::size_t i = 0; i < p_nfuncs; ++i) {
using func = std::function<void(C &, A...)>;
p_funcs[i].~func();
}
2017-04-04 00:30:07 +02:00
delete[] reinterpret_cast<unsigned char *>(p_funcs);
2015-07-16 19:55:21 +02:00
p_funcs = nullptr;
p_nfuncs = 0;
}
template<typename F>
2017-04-09 16:44:45 +02:00
std::size_t connect(F &&func) {
using func_t = std::function<void(C &, A...)>;
2017-04-09 16:44:45 +02:00
for (std::size_t i = 0; i < p_nfuncs; ++i) {
2015-07-16 20:21:51 +02:00
if (!p_funcs[i]) {
2017-01-25 01:44:22 +01:00
p_funcs[i] = std::forward<F>(func);
2015-07-16 20:21:51 +02:00
return i;
}
2016-07-02 05:56:23 +02:00
}
2017-04-04 00:30:07 +02:00
auto *bufp = new unsigned char[sizeof(func_t) * (p_nfuncs + 1)];
func_t *nbuf = reinterpret_cast<func_t *>(bufp);
2017-04-09 16:44:45 +02:00
for (std::size_t i = 0; i < p_nfuncs; ++i) {
new (&nbuf[i]) func_t(std::move(p_funcs[i]));
p_funcs[i].~func_t();
2015-07-16 19:55:21 +02:00
}
new (&nbuf[p_nfuncs]) func_t(std::forward<F>(func));
2017-04-04 00:30:07 +02:00
delete[] reinterpret_cast<unsigned char *>(p_funcs);
2015-07-16 19:55:21 +02:00
p_funcs = nbuf;
return p_nfuncs++;
}
2017-04-09 16:44:45 +02:00
bool disconnect(std::size_t idx) {
if ((idx >= p_nfuncs) || !p_funcs[idx]) {
return false;
}
2015-07-16 19:55:21 +02:00
p_funcs[idx] = nullptr;
return true;
}
template<typename ...Args>
void emit(Args &&...args) const {
if (!p_class) {
return;
}
2017-04-09 16:44:45 +02:00
for (std::size_t i = 0; i < p_nfuncs; ++i) {
if (p_funcs[i]) {
p_funcs[i](*p_class, args...);
}
}
2015-07-16 19:55:21 +02:00
}
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;
}
2017-02-16 20:39:05 +01:00
void swap(signal_base &ev) {
2017-01-29 15:56:02 +01: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 21:47:59 +02:00
}
2015-07-16 19:55:21 +02:00
private:
C *p_class;
std::function<void(C &, A...)> *p_funcs;
2017-04-09 16:44:45 +02:00
std::size_t p_nfuncs;
2015-07-16 19:55:21 +02:00
};
} /* namespace detail */
2015-07-16 02:37:37 +02:00
template<typename C, typename ...A>
2017-02-16 20:39:05 +01:00
struct signal {
2015-07-16 19:55:21 +02:00
private:
2017-02-16 20:39:05 +01:00
using base_t = detail::signal_base<C, A...>;
base_t p_base;
2015-07-16 19:55:21 +02:00
public:
2017-02-16 20:39:05 +01:00
signal(C *cl): p_base(cl) {}
signal(signal const &ev): p_base(ev.p_base) {}
signal(signal &&ev): p_base(std::move(ev.p_base)) {}
2015-07-16 19:55:21 +02:00
2017-02-16 20:39:05 +01:00
signal &operator=(signal const &ev) {
2015-07-16 21:47:59 +02:00
p_base = ev.p_base;
return *this;
}
2017-02-16 20:39:05 +01:00
signal &operator=(signal &&ev) {
2017-01-25 01:44:22 +01:00
p_base = std::move(ev.p_base);
2015-07-16 21:47:59 +02:00
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>
2017-04-09 16:44:45 +02:00
std::size_t connect(F &&func) { return p_base.connect(std::forward<F>(func)); }
2015-07-16 19:55:21 +02:00
2017-04-09 16:44:45 +02:00
bool disconnect(std::size_t idx) { return p_base.disconnect(idx); }
2015-07-16 02:37:37 +02:00
template<typename ...Args>
2017-01-25 01:44:22 +01:00
void emit(Args &&...args) { p_base.emit(std::forward<Args>(args)...); }
2015-07-16 02:37:37 +02:00
template<typename ...Args>
2017-01-25 01:44:22 +01:00
void operator()(Args &&...args) { emit(std::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); }
2017-02-16 20:39:05 +01: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>
2017-02-16 20:39:05 +01:00
struct signal<C const, A...> {
2015-07-16 02:37:37 +02:00
private:
2017-02-16 20:39:05 +01:00
using base_t = detail::signal_base<C const, A...>;
base_t p_base;
2015-07-16 19:55:21 +02:00
public:
2017-02-16 20:39:05 +01:00
signal(C *cl): p_base(cl) {}
signal(signal const &ev): p_base(ev.p_base) {}
signal(signal &&ev): p_base(std::move(ev.p_base)) {}
2015-07-16 19:55:21 +02:00
2017-02-16 20:39:05 +01:00
signal &operator=(signal const &ev) {
2015-07-16 21:47:59 +02:00
p_base = ev.p_base;
return *this;
}
2017-02-16 20:39:05 +01:00
signal &operator=(signal &&ev) {
2017-01-25 01:44:22 +01:00
p_base = std::move(ev.p_base);
2015-07-16 21:47:59 +02:00
return *this;
}
2015-07-16 19:55:21 +02:00
void clear() { p_base.clear(); }
template<typename F>
2017-04-09 16:44:45 +02:00
std::size_t connect(F &&func) { return p_base.connect(std::forward<F>(func)); }
2015-07-16 19:55:21 +02:00
2017-04-09 16:44:45 +02:00
bool disconnect(std::size_t idx) { return p_base.disconnect(idx); }
2015-07-16 19:55:21 +02:00
template<typename ...Args>
2017-01-25 01:44:22 +01:00
void emit(Args &&...args) const { p_base.emit(std::forward<Args>(args)...); }
2015-07-16 19:55:21 +02:00
template<typename ...Args>
2017-01-25 01:44:22 +01:00
void operator()(Args &&...args) const { emit(std::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); }
2017-02-16 20:39:05 +01:00
void swap(signal &ev) { p_base.swap(ev.p_base); }
2015-07-16 02:37:37 +02:00
};
2017-01-29 15:56:02 +01:00
template<typename C, typename ...A>
2017-02-16 20:39:05 +01:00
inline void swap(signal<C, A...> &a, signal<C, A...> &b) {
2017-01-29 15:56:02 +01:00
a.swap(b);
}
2015-07-16 02:37:37 +02:00
} /* namespace ostd */
2016-02-07 22:17:15 +01:00
#endif