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 <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 
16 namespace uvw {
17 
23 struct 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 
72 private:
73  const int ec;
74 };
75 
82 template<typename T>
83 class 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 
167 protected:
168  template<typename E>
169  void publish(E event) {
170  handler<E>().publish(std::move(event), *static_cast<T *>(this));
171  }
172 
173 public:
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 
289 private:
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
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
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 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
Connection type for a given event type.
Definition: emitter.h:185
The ErrorEvent event.
Definition: emitter.h:23
const char * name() const noexcept
Returns the error name for the given error code.
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.