uvw  2.11.0
emitter.h
1 #ifndef UVW_EMITTER_INCLUDE_H
2 #define UVW_EMITTER_INCLUDE_H
3 
4 
5 #include <type_traits>
6 #include <functional>
7 #include <algorithm>
8 #include <utility>
9 #include <cstddef>
10 #include <unordered_map>
11 #include <memory>
12 #include <list>
13 #include <uv.h>
14 #include "type_info.hpp"
15 
16 
17 namespace uvw {
18 
19 
25 struct ErrorEvent {
26  template<typename U, typename = std::enable_if_t<std::is_integral_v<U>>>
27  explicit ErrorEvent(U val) noexcept
28  : ec{static_cast<int>(val)}
29  {}
30 
43  static int translate(int sys) noexcept;
44 
52  const char * what() const noexcept;
53 
61  const char * name() const noexcept;
62 
67  int code() const noexcept;
68 
73  explicit operator bool() const noexcept;
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  template<typename E>
162  Handler<E> & handler() noexcept {
163  auto id = type<E>();
164 
165  if(!handlers.count(id)) {
166  handlers[id] = std::make_unique<Handler<E>>();
167  }
168 
169  return static_cast<Handler<E>&>(*handlers.at(id));
170  }
171 
172 protected:
173  template<typename E>
174  void publish(E event) {
175  handler<E>().publish(std::move(event), *static_cast<T*>(this));
176  }
177 
178 public:
179  template<typename E>
180  using Listener = typename Handler<E>::Listener;
181 
189  template<typename E>
190  struct Connection: private Handler<E>::Connection {
191  template<typename> friend class Emitter;
192 
193  Connection() = default;
194  Connection(const Connection &) = default;
195  Connection(Connection &&) = default;
196 
197  Connection(typename Handler<E>::Connection conn)
198  : Handler<E>::Connection{std::move(conn)}
199  {}
200 
201  Connection & operator=(const Connection &) = default;
202  Connection & operator=(Connection &&) = default;
203  };
204 
205  virtual ~Emitter() noexcept {
206  static_assert(std::is_base_of_v<Emitter<T>, T>);
207  }
208 
224  template<typename E>
225  Connection<E> on(Listener<E> f) {
226  return handler<E>().on(std::move(f));
227  }
228 
244  template<typename E>
245  Connection<E> once(Listener<E> f) {
246  return handler<E>().once(std::move(f));
247  }
248 
253  template<typename E>
254  void erase(Connection<E> conn) noexcept {
255  handler<E>().erase(std::move(conn));
256  }
257 
261  template<typename E>
262  void clear() noexcept {
263  handler<E>().clear();
264  }
265 
269  void clear() noexcept {
270  std::for_each(handlers.begin(), handlers.end(),
271  [](auto &&hdlr){ if(hdlr.second) { hdlr.second->clear(); } });
272  }
273 
279  template<typename E>
280  bool empty() const noexcept {
281  auto id = type<E>();
282 
283  return (!handlers.count(id) ||
284  static_cast<Handler<E>&>(*handlers.at(id)).empty());
285  }
286 
292  bool empty() const noexcept {
293  return std::all_of(handlers.cbegin(), handlers.cend(),
294  [](auto &&hdlr){ return !hdlr.second || hdlr.second->empty(); });
295  }
296 
297 private:
298  std::unordered_map<std::uint32_t, std::unique_ptr<BaseHandler>> handlers{};
299 };
300 
301 
302 }
303 
304 
305 #ifndef UVW_AS_LIB
306 #include "emitter.cpp"
307 #endif
308 
309 #endif // UVW_EMITTER_INCLUDE_H
Event emitter base class.
Definition: emitter.h:87
bool empty() const noexcept
Checks if there are listeners registered for the specific event.
Definition: emitter.h:280
void clear() noexcept
Disconnects all the listeners for the given event type.
Definition: emitter.h:262
void erase(Connection< E > conn) noexcept
Disconnects a listener from the event emitter.
Definition: emitter.h:254
void clear() noexcept
Disconnects all the listeners.
Definition: emitter.h:269
Connection< E > once(Listener< E > f)
Registers a short-lived listener with the event emitter.
Definition: emitter.h:245
bool empty() const noexcept
Checks if there are listeners registered with the event emitter.
Definition: emitter.h:292
Connection< E > on(Listener< E > f)
Registers a long-lived listener with the event emitter.
Definition: emitter.h:225
uvw default namespace.
Definition: async.h:10
Connection type for a given event type.
Definition: emitter.h:190
The ErrorEvent event.
Definition: emitter.h:25
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.