1 #pragma once
2 
3 
4 #include <type_traits>
5 #include <functional>
6 #include <algorithm>
7 #include <utility>
8 #include <cstddef>
9 #include <vector>
10 #include <memory>
11 #include <list>
12 #include <uv.h>
13 
14 
15 namespace uvw {
16 
17 
18 /**
19  * @brief The ErrorEvent event.
20  *
21  * Custom wrapper around error constants of `libuv`.
22  */
23 struct ErrorEvent {
24     template<typename U, typename = std::enable_if_t<std::is_integral<U>::value>>
ErrorEventuvw::ErrorEvent25     explicit ErrorEvent(U val) noexcept
26         : ec{static_cast<int>(val)}
27     {}
28 
29     /**
30      * @brief Returns the `libuv` error code equivalent to the given platform dependent error code.
31      *
32      * It returns:
33      * * POSIX error codes on Unix (the ones stored in errno).
34      * * Win32 error codes on Windows (those returned by GetLastError() or WSAGetLastError()).
35      *
36      * If `sys` is already a `libuv` error code, it is simply returned.
37      *
38      * @param sys A platform dependent error code.
39      * @return The `libuv` error code equivalent to the given platform dependent error code.
40      */
translateuvw::ErrorEvent41     static int translate(int sys) noexcept {
42         return uv_translate_sys_error(sys);
43     }
44 
45     /**
46      * @brief Returns the error message for the given error code.
47      *
48      * Leaks a few bytes of memory when you call it with an unknown error code.
49      *
50      * @return The error message for the given error code.
51      */
whatuvw::ErrorEvent52     const char * what() const noexcept { return uv_strerror(ec); }
53 
54     /**
55      * @brief Returns the error name for the given error code.
56      *
57      * Leaks a few bytes of memory when you call it with an unknown error code.
58      *
59      * @return The error name for the given error code.
60      */
nameuvw::ErrorEvent61     const char * name() const noexcept { return uv_err_name(ec); }
62 
63     /**
64      * @brief Gets the underlying error code, that is an error constant of `libuv`.
65      * @return The underlying error code.
66      */
codeuvw::ErrorEvent67     int code() const noexcept { return ec; }
68 
69     /**
70      * @brief Checks if the event contains a valid error code.
71      * @return True in case of success, false otherwise.
72      */
operator booluvw::ErrorEvent73     explicit operator bool() const noexcept { return ec < 0; }
74 
75 private:
76     const int ec;
77 };
78 
79 
80 /**
81  * @brief Event emitter base class.
82  *
83  * Almost everything in `uvw` is an event emitter.<br/>
84  * This is the base class from which resources and loops inherit.
85  */
86 template<typename T>
87 class Emitter {
88     struct BaseHandler {
89         virtual ~BaseHandler() noexcept = default;
90         virtual bool empty() const noexcept = 0;
91         virtual void clear() noexcept = 0;
92     };
93 
94     template<typename E>
95     struct Handler final: BaseHandler {
96         using Listener = std::function<void(E &, T &)>;
97         using Element = std::pair<bool, Listener>;
98         using ListenerList = std::list<Element>;
99         using Connection = typename ListenerList::iterator;
100 
emptyuvw::Emitter::Handler101         bool empty() const noexcept override {
102             auto pred = [](auto &&element){ return element.first; };
103 
104             return std::all_of(onceL.cbegin(), onceL.cend(), pred) &&
105                     std::all_of(onL.cbegin(), onL.cend(), pred);
106         }
107 
clearuvw::Emitter::Handler108         void clear() noexcept override {
109             if(publishing) {
110                 auto func = [](auto &&element){ element.first = true; };
111                 std::for_each(onceL.begin(), onceL.end(), func);
112                 std::for_each(onL.begin(), onL.end(), func);
113             } else {
114                 onceL.clear();
115                 onL.clear();
116             }
117         }
118 
onceuvw::Emitter::Handler119         Connection once(Listener f) {
120             return onceL.emplace(onceL.cend(), false, std::move(f));
121         }
122 
onuvw::Emitter::Handler123         Connection on(Listener f) {
124             return onL.emplace(onL.cend(), false, std::move(f));
125         }
126 
eraseuvw::Emitter::Handler127         void erase(Connection conn) noexcept {
128             conn->first = true;
129 
130             if(!publishing) {
131                 auto pred = [](auto &&element){ return element.first; };
132                 onceL.remove_if(pred);
133                 onL.remove_if(pred);
134             }
135         }
136 
publishuvw::Emitter::Handler137         void publish(E event, T &ref) {
138             ListenerList currentL;
139             onceL.swap(currentL);
140 
141             auto func = [&event, &ref](auto &&element) {
142                 return element.first ? void() : element.second(event, ref);
143             };
144 
145             publishing = true;
146 
147             std::for_each(onL.rbegin(), onL.rend(), func);
148             std::for_each(currentL.rbegin(), currentL.rend(), func);
149 
150             publishing = false;
151 
152             onL.remove_if([](auto &&element){ return element.first; });
153         }
154 
155     private:
156         bool publishing{false};
157         ListenerList onceL{};
158         ListenerList onL{};
159     };
160 
next_type()161     static std::size_t next_type() noexcept {
162         static std::size_t counter = 0;
163         return counter++;
164     }
165 
166     template<typename>
event_type()167     static std::size_t event_type() noexcept {
168         static std::size_t value = next_type();
169         return value;
170     }
171 
172     template<typename E>
handler()173     Handler<E> & handler() noexcept {
174         std::size_t type = event_type<E>();
175 
176         if(!(type < handlers.size())) {
177             handlers.resize(type+1);
178         }
179 
180         if(!handlers[type]) {
181            handlers[type] = std::make_unique<Handler<E>>();
182         }
183 
184         return static_cast<Handler<E>&>(*handlers[type]);
185     }
186 
187 protected:
188     template<typename E>
publish(E event)189     void publish(E event) {
190         handler<E>().publish(std::move(event), *static_cast<T*>(this));
191     }
192 
193 public:
194     template<typename E>
195     using Listener = typename Handler<E>::Listener;
196 
197     /**
198      * @brief Connection type for a given event type.
199      *
200      * Given an event type `E`, `Connection<E>` is the type of the connection
201      * object returned by the event emitter whenever a listener for the given
202      * type is registered.
203      */
204     template<typename E>
205     struct Connection: private Handler<E>::Connection {
206         template<typename> friend class Emitter;
207 
208         Connection() = default;
209         Connection(const Connection &) = default;
210         Connection(Connection &&) = default;
211 
Connectionuvw::Emitter::Connection212         Connection(typename Handler<E>::Connection conn)
213             : Handler<E>::Connection{std::move(conn)}
214         {}
215 
216         Connection & operator=(const Connection &) = default;
217         Connection & operator=(Connection &&) = default;
218     };
219 
~Emitter()220     virtual ~Emitter() noexcept {
221         static_assert(std::is_base_of<Emitter<T>, T>::value, "!");
222     }
223 
224     /**
225      * @brief Registers a long-lived listener with the event emitter.
226      *
227      * This method can be used to register a listener that is meant to be
228      * invoked more than once for the given event type.<br/>
229      * The Connection object returned by the method can be freely discarded. It
230      * can be used later to disconnect the listener, if needed.
231      *
232      * Listener is usually defined as a callable object assignable to a
233      * `std::function<void(const E &, T &)`, where `E` is the type of the event
234      * and `T` is the type of the resource.
235      *
236      * @param f A valid listener to be registered.
237      * @return Connection object to be used later to disconnect the listener.
238      */
239     template<typename E>
on(Listener<E> f)240     Connection<E> on(Listener<E> f) {
241         return handler<E>().on(std::move(f));
242     }
243 
244     /**
245      * @brief Registers a short-lived listener with the event emitter.
246      *
247      * This method can be used to register a listener that is meant to be
248      * invoked only once for the given event type.<br/>
249      * The Connection object returned by the method can be freely discarded. It
250      * can be used later to disconnect the listener, if needed.
251      *
252      * Listener is usually defined as a callable object assignable to a
253      * `std::function<void(const E &, T &)`, where `E` is the type of the event
254      * and `T` is the type of the resource.
255      *
256      * @param f A valid listener to be registered.
257      * @return Connection object to be used later to disconnect the listener.
258      */
259     template<typename E>
once(Listener<E> f)260     Connection<E> once(Listener<E> f) {
261         return handler<E>().once(std::move(f));
262     }
263 
264     /**
265      * @brief Disconnects a listener from the event emitter.
266      * @param conn A valid Connection object
267      */
268     template<typename E>
erase(Connection<E> conn)269     void erase(Connection<E> conn) noexcept {
270         handler<E>().erase(std::move(conn));
271     }
272 
273     /**
274      * @brief Disconnects all the listeners for the given event type.
275      */
276     template<typename E>
clear()277     void clear() noexcept {
278         handler<E>().clear();
279     }
280 
281     /**
282      * @brief Disconnects all the listeners.
283      */
clear()284     void clear() noexcept {
285         std::for_each(handlers.begin(), handlers.end(),
286                       [](auto &&hdlr){ if(hdlr) { hdlr->clear(); } });
287     }
288 
289     /**
290      * @brief Checks if there are listeners registered for the specific event.
291      * @return True if there are no listeners registered for the specific event,
292      * false otherwise.
293      */
294     template<typename E>
empty() const295     bool empty() const noexcept {
296         std::size_t type = event_type<E>();
297 
298         return (!(type < handlers.size()) ||
299                 !handlers[type] ||
300                 static_cast<Handler<E>&>(*handlers[type]).empty());
301     }
302 
303     /**
304      * @brief Checks if there are listeners registered with the event emitter.
305      * @return True if there are no listeners registered with the event emitter,
306      * false otherwise.
307      */
empty() const308     bool empty() const noexcept {
309         return std::all_of(handlers.cbegin(), handlers.cend(),
310                            [](auto &&hdlr){ return !hdlr || hdlr->empty(); });
311     }
312 
313 private:
314     std::vector<std::unique_ptr<BaseHandler>> handlers{};
315 };
316 
317 
318 }
319