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