uvw 2.12.1
emitter.h
1#ifndef UVW_EMITTER_INCLUDE_H
2#define UVW_EMITTER_INCLUDE_H
3
4#include <algorithm>
5#include <cstddef>
6#include <functional>
7#include <list>
8#include <memory>
9#include <type_traits>
10#include <unordered_map>
11#include <utility>
12#include <uv.h>
13#include "type_info.hpp"
14
15namespace uvw {
16
22struct ErrorEvent {
23 template<typename U, typename = std::enable_if_t<std::is_integral_v<U>>>
24 explicit ErrorEvent(U val) noexcept
25 : ec{static_cast<int>(val)} {}
26
39 static int translate(int sys) noexcept;
40
48 const char *what() const noexcept;
49
57 const char *name() const noexcept;
58
63 int code() const noexcept;
64
69 explicit operator bool() const noexcept;
70
71private:
72 const int ec;
73};
74
81template<typename T>
82class Emitter {
83 struct BaseHandler {
84 virtual ~BaseHandler() noexcept = default;
85 virtual bool empty() const noexcept = 0;
86 virtual void clear() noexcept = 0;
87 };
88
89 template<typename E>
90 struct Handler final: BaseHandler {
91 using Listener = std::function<void(E &, T &)>;
92 using Element = std::pair<bool, Listener>;
93 using ListenerList = std::list<Element>;
94 using Connection = typename ListenerList::iterator;
95
96 bool empty() const noexcept override {
97 auto pred = [](auto &&element) { return element.first; };
98
99 return std::all_of(onceL.cbegin(), onceL.cend(), pred) && std::all_of(onL.cbegin(), onL.cend(), pred);
100 }
101
102 void clear() noexcept override {
103 if(publishing) {
104 auto func = [](auto &&element) { element.first = true; };
105 std::for_each(onceL.begin(), onceL.end(), func);
106 std::for_each(onL.begin(), onL.end(), func);
107 } else {
108 onceL.clear();
109 onL.clear();
110 }
111 }
112
113 Connection once(Listener f) {
114 return onceL.emplace(onceL.cend(), false, std::move(f));
115 }
116
117 Connection on(Listener f) {
118 return onL.emplace(onL.cend(), false, std::move(f));
119 }
120
121 void erase(Connection conn) noexcept {
122 conn->first = true;
123
124 if(!publishing) {
125 auto pred = [](auto &&element) { return element.first; };
126 onceL.remove_if(pred);
127 onL.remove_if(pred);
128 }
129 }
130
131 void publish(E event, T &ref) {
132 ListenerList currentL;
133 onceL.swap(currentL);
134
135 auto func = [&event, &ref](auto &&element) {
136 return element.first ? void() : element.second(event, ref);
137 };
138
139 publishing = true;
140
141 std::for_each(onL.rbegin(), onL.rend(), func);
142 std::for_each(currentL.rbegin(), currentL.rend(), func);
143
144 publishing = false;
145
146 onL.remove_if([](auto &&element) { return element.first; });
147 }
148
149 private:
150 bool publishing{false};
151 ListenerList onceL{};
152 ListenerList onL{};
153 };
154
155 template<typename E>
156 Handler<E> &handler() noexcept {
157 auto id = type<E>();
158
159 if(!handlers.count(id)) {
160 handlers[id] = std::make_unique<Handler<E>>();
161 }
162
163 return static_cast<Handler<E> &>(*handlers.at(id));
164 }
165
166protected:
167 template<typename E>
168 void publish(E event) {
169 handler<E>().publish(std::move(event), *static_cast<T *>(this));
170 }
171
172public:
173 template<typename E>
174 using Listener = typename Handler<E>::Listener;
175
183 template<typename E>
184 struct Connection: private Handler<E>::Connection {
185 template<typename>
186 friend class Emitter;
187
188 Connection() = default;
189 Connection(const Connection &) = default;
190 Connection(Connection &&) = default;
191
192 Connection(typename Handler<E>::Connection conn)
193 : Handler<E>::Connection{std::move(conn)} {}
194
195 Connection &operator=(const Connection &) = default;
196 Connection &operator=(Connection &&) = default;
197 };
198
199 virtual ~Emitter() noexcept {
200 static_assert(std::is_base_of_v<Emitter<T>, T>);
201 }
202
218 template<typename E>
219 Connection<E> on(Listener<E> f) {
220 return handler<E>().on(std::move(f));
221 }
222
238 template<typename E>
239 Connection<E> once(Listener<E> f) {
240 return handler<E>().once(std::move(f));
241 }
242
247 template<typename E>
248 void erase(Connection<E> conn) noexcept {
249 handler<E>().erase(std::move(conn));
250 }
251
255 template<typename E>
256 void clear() noexcept {
257 handler<E>().clear();
258 }
259
263 void clear() noexcept {
264 std::for_each(handlers.begin(), handlers.end(), [](auto &&hdlr) { if(hdlr.second) { hdlr.second->clear(); } });
265 }
266
272 template<typename E>
273 bool empty() const noexcept {
274 auto id = type<E>();
275
276 return (!handlers.count(id) || static_cast<Handler<E> &>(*handlers.at(id)).empty());
277 }
278
284 bool empty() const noexcept {
285 return std::all_of(handlers.cbegin(), handlers.cend(), [](auto &&hdlr) { return !hdlr.second || hdlr.second->empty(); });
286 }
287
288private:
289 std::unordered_map<std::uint32_t, std::unique_ptr<BaseHandler>> handlers{};
290};
291
292} // namespace uvw
293
294#ifndef UVW_AS_LIB
295# include "emitter.cpp"
296#endif
297
298#endif // UVW_EMITTER_INCLUDE_H
Event emitter base class.
Definition: emitter.h:82
Connection< E > once(Listener< E > f)
Registers a short-lived listener with the event emitter.
Definition: emitter.h:239
bool empty() const noexcept
Checks if there are listeners registered for the specific event.
Definition: emitter.h:273
void clear() noexcept
Disconnects all the listeners for the given event type.
Definition: emitter.h:256
void erase(Connection< E > conn) noexcept
Disconnects a listener from the event emitter.
Definition: emitter.h:248
void clear() noexcept
Disconnects all the listeners.
Definition: emitter.h:263
bool empty() const noexcept
Checks if there are listeners registered with the event emitter.
Definition: emitter.h:284
Connection< E > on(Listener< E > f)
Registers a long-lived listener with the event emitter.
Definition: emitter.h:219
uvw default namespace.
Definition: async.h:8
Connection type for a given event type.
Definition: emitter.h:184
The ErrorEvent event.
Definition: emitter.h:22
const char * what() const noexcept
Returns the error message for the given error code.
int code() const noexcept
Gets the underlying error code, that is an error constant of libuv.
static int translate(int sys) noexcept
Returns the libuv error code equivalent to the given platform dependent error code.
const char * name() const noexcept
Returns the error name for the given error code.