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