cpp-mate  0.7
Helpful library for C++.
Signal.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_SIGNAL_HPP
18 #define CPP_MATE_SIGNAL_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 S>
32 class Signal final
33 {
34 public:
35 
39  using Function = void(*)(const S&);
40 
44  using Lambda = std::function<void(const S& sender)>;
45 
50  Signal(const S& sender): _sender(sender) {}
51 
58  template<typename T>
59  inline void subscribe(const T& instance, void (T::* method)(const S&)) 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 {
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 {
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 {
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 {
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 {
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 
167  void emit() {
168  for (auto it = std::begin(_receivers); it != std::end(_receivers);) {
169  const auto& receiver = *it;
170  receiver(_sender) ? ++it : it = _receivers.erase(it);
171  }
172  }
173 
177  void unsubscribeAll() { _receivers.clear(); }
178 
179 private:
180  class Receiver;
181 
182  using Method = void(*)(const void*, const S&);
183 
184  struct ReceiverHasher {
185  size_t operator()(const Receiver& receiver) const { return receiver.getHash(); }
186  };
187 
188  template<typename... T>
189  inline bool hasReceiver(T&&... args) const {
190  return _receivers.find(Receiver(std::forward<T>(args)...)) != _receivers.end();
191  }
192 
193  template<typename... T>
194  inline void addReceiver(T&&... args) const {
195  _receivers.emplace(std::forward<T>(args)...);
196  }
197 
198  template<typename... T>
199  inline bool removeReceiver(T&&... args) const {
200  return _receivers.erase(Receiver(std::forward<T>(args)...)) > 0;
201  }
202 
203  const S& _sender;
204  mutable std::unordered_set<Receiver, ReceiverHasher> _receivers;
205 };
206 
207 template<typename S>
208 class Signal<S>::Receiver final
209 {
210 public:
211  Receiver(const void* instance, Method method):
212  _type(Type::Method),
213  _instance(instance),
214  _method(reinterpret_cast<decltype(_method)>(method)) {}
215 
216  Receiver(const std::weak_ptr<void>&& instance, Method method):
217  _type(Type::Method),
218  _instance(nullptr),
219  _method(reinterpret_cast<decltype(_method)>(method)),
220  _instancePtr(std::move(instance)) {}
221 
222  Receiver(Function receiver):
223  _type(Type::Function),
224  _instance(nullptr),
225  _method(reinterpret_cast<decltype(_method)>(receiver))
226  {
227  checkArg(receiver);
228  }
229 
230  Receiver(Lambda receiver):
231  _type(Type::Lambda),
232  _instance(nullptr),
233  _method(nullptr),
234  _lambda(std::move(receiver)) {}
235 
236  bool operator==(const Receiver& other) const {
237  return _type == other._type
238  && _method == other._method
239  && getInstance() == other.getInstance();
240  }
241 
242  bool operator!=(const Receiver& other) const { return !(*this == other); }
243 
244  bool operator()(const S& sender) const {
245  switch (_type) {
246  case Receiver::Type::Method:
247  return callMethod(sender);
248  case Receiver::Type::Function:
249  return callFunction(sender);
250  case Receiver::Type::Lambda:
251  return callLambda(sender);
252  }
253  return false;
254  }
255 
256  size_t getHash() const {
257  return std::hash<decltype(_type)>{}(_type) ^ std::hash<decltype(_method)>{}(_method) ^ std::hash<decltype(_instance)>{}(getInstance());
258  }
259 
260 private:
261  enum class Type: uint8_t {
262  Method,
263  Function,
264  Lambda
265  };
266 
267  const void* getInstance() const {
268  return _instance ? _instance : _instancePtr.lock().get();
269  }
270 
271  bool callMethod(const S& sender) const {
272  const auto* instance = getInstance();
273  if (!instance) {
274  return false;
275  }
276  reinterpret_cast<Method>(_method)(instance, sender);
277  return true;
278  }
279 
280  bool callFunction(const S& sender) const {
281  reinterpret_cast<Function>(_method)(sender);
282  return true;
283  }
284 
285  bool callLambda(const S& sender) const {
286  _lambda(sender);
287  return true;
288  }
289 
290  Type _type;
291  const void* _instance;
292  std::weak_ptr<void> _instancePtr;
293  void* _method;
294  Lambda _lambda;
295 };
296 
297 } // namespace CppMate
298 
299 #endif // CPP_MATE_SIGNAL_HPP
Definition: Signal.hpp:209
bool operator==(const Receiver &other) const
Definition: Signal.hpp:236
Receiver(const void *instance, Method method)
Definition: Signal.hpp:211
size_t getHash() const
Definition: Signal.hpp:256
bool operator()(const S &sender) const
Definition: Signal.hpp:244
Receiver(Function receiver)
Definition: Signal.hpp:222
Receiver(Lambda receiver)
Definition: Signal.hpp:230
bool operator!=(const Receiver &other) const
Definition: Signal.hpp:242
Receiver(const std::weak_ptr< void > &&instance, Method method)
Definition: Signal.hpp:216
Represents signal.
Definition: Signal.hpp:33
Signal(const S &sender)
Constructor.
Definition: Signal.hpp:50
void emit()
Emits signal.
Definition: Signal.hpp:167
void unsubscribeAll()
Clear all subscribers.
Definition: Signal.hpp:177
bool unsubscribe(const T &instance, void(T::*method)(const S &)) const
Unsubscribes from the signal.
Definition: Signal.hpp:96
bool unsubscribe(Function subscriber) const
Unsubscribes function from the signal.
Definition: Signal.hpp:119
bool hasSubscriber(std::shared_ptr< T > instance, void(T::*method)(const S &)) const
Indicates that the receiver is already subscribed to the signal.
Definition: Signal.hpp:139
void subscribe(std::shared_ptr< T > instance, void(T::*method)(const S &)) const
Subscribes method of instance to the signal. The subscription is unique.
Definition: Signal.hpp:71
void subscribe(const T &instance, void(T::*method)(const S &)) const
Subscribes method of instance to the signal. The subscription is unique.
Definition: Signal.hpp:59
size_t getSubscribersCount() const
Returns number of recveivers.
Definition: Signal.hpp:162
std::function< void(const S &sender)> Lambda
Definition: Signal.hpp:44
bool unsubscribe(std::shared_ptr< T > instance, void(T::*method)(const S &)) const
Unsubscribes from the signal.
Definition: Signal.hpp:108
bool isEmpty() const
Indicates that subsciprion is empty.
Definition: Signal.hpp:156
bool hasSubscriber(Function subscriber) const
Indicates that the receiver is already subscribed to the signal.
Definition: Signal.hpp:148
bool hasSubscriber(const T &instance, void(T::*method)(const S &)) const
Indicates that the receiver is already subscribed to the signal.
Definition: Signal.hpp:128
void(*)(const S &) Function
Definition: Signal.hpp:39
void subscribe(Function subscriber) const
Subscribes function to the signal.
Definition: Signal.hpp:81
void subscribe(Lambda subscriber) const
Subscribes lambda expression to the signal.
Definition: Signal.hpp:87
Definition: BinaryData.hpp:28