cpp-mate  0.7
Helpful library for C++.
Event.hpp
1 /*
2  * Copyright (C) 2020 Alexander Kornilov (akornilov.82@gmail.com)
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef CPP_MATE_EVENT_HPP
18 #define CPP_MATE_EVENT_HPP
19 
20 #include <CppMate/Checkers.hpp>
21 
22 #include <unordered_set>
23 #include <memory>
24 #include <functional>
25 
26 namespace CppMate {
27 
31 template<typename E, typename S>
32 class Event final
33 {
34 public:
35 
39  using Function = void(*)(const S&, const E&);
40 
44  using Lambda = std::function<void(const S& sender, const E& event)>;
45 
50  Event(const S& sender): _sender(sender) {}
51 
58  template<typename T>
59  inline void subscribe(const T& instance, void (T::* method)(const S&, const E&)) const {
60  addReceiver(&instance, *reinterpret_cast<Method*>(&method));
61  }
62 
70  template<typename T>
71  inline void subscribe(std::shared_ptr<T> instance, void (T::* method)(const S&, const E&)) const {
72  checkArg(instance.get());
73  addReceiver(std::weak_ptr<void>(instance), *reinterpret_cast<Method*>(&method));
74  }
75 
81  void subscribe(Function subscriber) const { addReceiver(subscriber); }
82 
87  void subscribe(Lambda subscriber) const { addReceiver(subscriber); }
88 
95  template<typename T>
96  inline bool unsubscribe(const T& instance, void (T::* method)(const S&, const E&)) const {
97  return removeReceiver(&instance, *reinterpret_cast<Method*>(&method));
98  }
99 
107  template<typename T>
108  inline bool unsubscribe(std::shared_ptr<T> instance, void (T::* method)(const S&, const E&)) const {
109  checkArg(instance.get());
110  return removeReceiver(std::weak_ptr<void>(instance), *reinterpret_cast<Method*>(&method));
111  }
112 
119  bool unsubscribe(Function subscriber) const { return removeReceiver(subscriber); }
120 
127  template<typename T>
128  inline bool hasSubscriber(const T& instance, void (T::* method)(const S&, const E&)) const {
129  return hasReceiver(&instance, *reinterpret_cast<Method*>(&method));
130  }
131 
138  template<typename T>
139  inline bool hasSubscriber(std::shared_ptr<T> instance, void (T::* method)(const S&, const E&)) const {
140  return instance.get() && hasReceiver(std::weak_ptr<void>(instance), *reinterpret_cast<Method*>(&method));
141  }
142 
148  bool hasSubscriber(Function subscriber) const {
149  return subscriber && hasReceiver(subscriber);
150  }
151 
156  bool isEmpty() const { return _receivers.empty(); }
157 
162  size_t getSubscribersCount() const { return _receivers.size(); }
163 
168  void emit(const E& event) {
169  for (auto it = std::begin(_receivers); it != std::end(_receivers);) {
170  const auto& receiver = *it;
171  receiver(_sender, event) ? ++it : it = _receivers.erase(it);
172  }
173  }
174 
178  void unsubscribeAll() { _receivers.clear(); }
179 
180 private:
181  class Receiver;
182 
183  using Method = void(*)(const void*, const S&, const E&);
184 
185  struct ReceiverHasher {
186  size_t operator()(const Receiver& receiver) const { return receiver.getHash(); }
187  };
188 
189  template<typename... T>
190  inline bool hasReceiver(T&&... args) const {
191  return _receivers.find(Receiver(std::forward<T>(args)...)) != _receivers.end();
192  }
193 
194  template<typename... T>
195  inline void addReceiver(T&&... args) const {
196  _receivers.emplace(std::forward<T>(args)...);
197  }
198 
199  template<typename... T>
200  inline bool removeReceiver(T&&... args) const {
201  return _receivers.erase(Receiver(std::forward<T>(args)...)) > 0;
202  }
203 
204  const S& _sender;
205  mutable std::unordered_set<Receiver, ReceiverHasher> _receivers;
206 };
207 
208 template<typename E, typename S>
209 class Event<E, S>::Receiver final
210 {
211 public:
212  Receiver(const void* instance, Method method):
213  _type(Type::Method),
214  _instance(instance),
215  _method(reinterpret_cast<decltype(_method)>(method)) {}
216 
217  Receiver(const std::weak_ptr<void>&& instance, Method method):
218  _type(Type::Method),
219  _instance(nullptr),
220  _method(reinterpret_cast<decltype(_method)>(method)),
221  _instancePtr(std::move(instance)) {}
222 
223  Receiver(Function receiver):
224  _type(Type::Function),
225  _instance(nullptr),
226  _method(reinterpret_cast<decltype(_method)>(receiver))
227  {
228  checkArg(receiver);
229  }
230 
231  Receiver(Lambda receiver):
232  _type(Type::Lambda),
233  _instance(nullptr),
234  _method(nullptr),
235  _lambda(std::move(receiver)) {}
236 
237  bool operator==(const Receiver& other) const {
238  return _type == other._type
239  && _method == other._method
240  && getInstance() == other.getInstance();
241  }
242 
243  bool operator!=(const Receiver& other) const { return !(*this == other); }
244 
245  bool operator()(const S& sender, const E& event) const {
246  switch (_type) {
247  case Receiver::Type::Method:
248  return callMethod(sender, event);
249  case Receiver::Type::Function:
250  return callFunction(sender, event);
251  case Receiver::Type::Lambda:
252  return callLambda(sender, event);
253  }
254  return false;
255  }
256 
257  size_t getHash() const {
258  return std::hash<decltype(_type)>{}(_type) ^ std::hash<decltype(_method)>{}(_method) ^ std::hash<decltype(_instance)>{}(getInstance());
259  }
260 
261 private:
262  enum class Type: uint8_t {
263  Method,
264  Function,
265  Lambda
266  };
267 
268  const void* getInstance() const {
269  return _instance ? _instance : _instancePtr.lock().get();
270  }
271 
272  bool callMethod(const S& sender, const E& event) const {
273  const auto* instance = getInstance();
274  if (!instance) {
275  return false;
276  }
277  reinterpret_cast<Method>(_method)(instance, sender, event);
278  return true;
279  }
280 
281  bool callFunction(const S& sender, const E& event) const {
282  reinterpret_cast<Function>(_method)(sender, event);
283  return true;
284  }
285 
286  bool callLambda(const S& sender, const E& event) const {
287  _lambda(sender, event);
288  return true;
289  }
290 
291  Type _type;
292  const void* _instance;
293  std::weak_ptr<void> _instancePtr;
294  void* _method;
295  Lambda _lambda;
296 };
297 
298 } // namespace CppMate
299 
300 #endif // CPP_MATE_EVENT_HPP
Definition: Event.hpp:210
bool operator==(const Receiver &other) const
Definition: Event.hpp:237
Receiver(Lambda receiver)
Definition: Event.hpp:231
size_t getHash() const
Definition: Event.hpp:257
Receiver(const std::weak_ptr< void > &&instance, Method method)
Definition: Event.hpp:217
bool operator!=(const Receiver &other) const
Definition: Event.hpp:243
Receiver(Function receiver)
Definition: Event.hpp:223
bool operator()(const S &sender, const E &event) const
Definition: Event.hpp:245
Receiver(const void *instance, Method method)
Definition: Event.hpp:212
Represents signal emitter with a specified event type.
Definition: Event.hpp:33
std::function< void(const S &sender, const E &event)> Lambda
Definition: Event.hpp:44
bool hasSubscriber(const T &instance, void(T::*method)(const S &, const E &)) const
Indicates that the receiver is already subscribed to the event.
Definition: Event.hpp:128
bool hasSubscriber(Function subscriber) const
Indicates that the receiver is already subscribed to the event.
Definition: Event.hpp:148
Event(const S &sender)
Constructor.
Definition: Event.hpp:50
bool unsubscribe(const T &instance, void(T::*method)(const S &, const E &)) const
Unsubscribes from the event.
Definition: Event.hpp:96
void subscribe(Lambda subscriber) const
Subscribes lambda expression to the event.
Definition: Event.hpp:87
void(*)(const S &, const E &) Function
Definition: Event.hpp:39
size_t getSubscribersCount() const
Returns number of recveivers.
Definition: Event.hpp:162
bool unsubscribe(std::shared_ptr< T > instance, void(T::*method)(const S &, const E &)) const
Unsubscribes from the event.
Definition: Event.hpp:108
void subscribe(std::shared_ptr< T > instance, void(T::*method)(const S &, const E &)) const
Subscribes method of instance to the event passed by constant reference. The subscription is unique.
Definition: Event.hpp:71
void subscribe(Function subscriber) const
Subscribes function to the event.
Definition: Event.hpp:81
bool isEmpty() const
Indicates that subsciprion is empty.
Definition: Event.hpp:156
void unsubscribeAll()
Clear all subscribers.
Definition: Event.hpp:178
bool unsubscribe(Function subscriber) const
Unsubscribes from the event.
Definition: Event.hpp:119
void subscribe(const T &instance, void(T::*method)(const S &, const E &)) const
Subscribes method of instance to the event passed by constant reference. The subscription is unique.
Definition: Event.hpp:59
void emit(const E &event)
Emits event.
Definition: Event.hpp:168
bool hasSubscriber(std::shared_ptr< T > instance, void(T::*method)(const S &, const E &)) const
Indicates that the receiver is already subscribed to the event.
Definition: Event.hpp:139
Definition: BinaryData.hpp:28