uvw  1.4.0
emitter.hpp
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 
23 struct ErrorEvent {
24  template<typename U, typename = std::enable_if_t<std::is_integral<U>::value>>
25  explicit ErrorEvent(U val) noexcept
26  : ec{static_cast<int>(val)}
27  {}
28 
41  static int translate(int sys) noexcept {
42  return uv_translate_sys_error(sys);
43  }
44 
52  const char * what() const noexcept { return uv_strerror(ec); }
53 
61  const char * name() const noexcept { return uv_err_name(ec); }
62 
67  int code() const noexcept { return ec; }
68 
73  explicit operator bool() const noexcept { return ec < 0; }
74 
75 private:
76  const int ec;
77 };
78 
79 
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 
101  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 
108  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 
119  Connection once(Listener f) {
120  return onceL.emplace(onceL.cend(), false, std::move(f));
121  }
122 
123  Connection on(Listener f) {
124  return onL.emplace(onL.cend(), false, std::move(f));
125  }
126 
127  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 
137  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 
161  static std::size_t next_type() noexcept {
162  static std::size_t counter = 0;
163  return counter++;
164  }
165 
166  template<typename>
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>
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>
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 
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 
212  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 
220  virtual ~Emitter() noexcept {
221  static_assert(std::is_base_of<Emitter<T>, T>::value, "!");
222  }
223 
239  template<typename E>
240  Connection<E> on(Listener<E> f) {
241  return handler<E>().on(std::move(f));
242  }
243 
259  template<typename E>
260  Connection<E> once(Listener<E> f) {
261  return handler<E>().once(std::move(f));
262  }
263 
268  template<typename E>
269  void erase(Connection<E> conn) noexcept {
270  handler<E>().erase(std::move(conn));
271  }
272 
276  template<typename E>
277  void clear() noexcept {
278  handler<E>().clear();
279  }
280 
284  void clear() noexcept {
285  std::for_each(handlers.begin(), handlers.end(),
286  [](auto &&hdlr){ if(hdlr) { hdlr->clear(); } });
287  }
288 
294  template<typename E>
295  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 
308  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 }
Event emitter base class.
Definition: emitter.hpp:87
Connection type for a given event type.
Definition: emitter.hpp:205
static int translate(int sys) noexcept
Returns the libuv error code equivalent to the given platform dependent error code.
Definition: emitter.hpp:41
bool empty() const noexcept
Checks if there are listeners registered for the specific event.
Definition: emitter.hpp:295
Connection< E > once(Listener< E > f)
Registers a short-lived listener with the event emitter.
Definition: emitter.hpp:260
const char * what() const noexcept
Returns the error message for the given error code.
Definition: emitter.hpp:52
bool empty() const noexcept
Checks if there are listeners registered with the event emitter.
Definition: emitter.hpp:308
void clear() noexcept
Disconnects all the listeners for the given event type.
Definition: emitter.hpp:277
void erase(Connection< E > conn) noexcept
Disconnects a listener from the event emitter.
Definition: emitter.hpp:269
void clear() noexcept
Disconnects all the listeners.
Definition: emitter.hpp:284
const char * name() const noexcept
Returns the error name for the given error code.
Definition: emitter.hpp:61
The ErrorEvent event.
Definition: emitter.hpp:23
Connection< E > on(Listener< E > f)
Registers a long-lived listener with the event emitter.
Definition: emitter.hpp:240
int code() const noexcept
Gets the underlying error code, that is an error constant of libuv.
Definition: emitter.hpp:67
uvw default namespace.
Definition: async.hpp:11