FairMQ  1.4.33
C++ Message Queuing Library and Framework
EventManager.h
1 /********************************************************************************
2  * Copyright (C) 2014-2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
3  * *
4  * This software is distributed under the terms of the *
5  * GNU Lesser General Public Licence (LGPL) version 3, *
6  * copied verbatim in the file "LICENSE" *
7  ********************************************************************************/
8 
9 #ifndef FAIR_MQ_EVENTMANAGER_H
10 #define FAIR_MQ_EVENTMANAGER_H
11 
12 #include <memory>
13 #include <mutex>
14 #include <string>
15 #include <typeindex>
16 #include <unordered_map>
17 #include <utility>
18 #include <functional>
19 
20 #include <boost/any.hpp>
21 #include <boost/functional/hash.hpp>
22 #include <boost/signals2.hpp>
23 
24 namespace fair::mq
25 {
26 
27 // Inherit from this base event type to create custom event types
28 template<typename K>
29 struct Event
30 {
31  using KeyType = K;
32 };
33 
49 class EventManager
50 {
51  public:
52  // Clang 3.4-3.8 has a bug and cannot properly deal with the following template alias.
53  // Therefore, we leave them here commented out for now.
54  // template<typename E, typename ...Args>
55  // using Callback = std::function<void(typename E::KeyType, Args...)>;
56 
57  template<typename E, typename ...Args>
58  using Signal = boost::signals2::signal<void(typename E::KeyType, Args...)>;
59 
60  template<typename E, typename ...Args>
61  auto Subscribe(const std::string& subscriber, std::function<void(typename E::KeyType, Args...)> callback) -> void
62  {
63  const std::type_index event_type_index{typeid(E)};
64  const std::type_index callback_type_index{typeid(std::function<void(typename E::KeyType, Args...)>)};
65  const auto signalsKey = std::make_pair(event_type_index, callback_type_index);
66  const auto connectionsKey = std::make_pair(subscriber, signalsKey);
67 
68  const auto connection = GetSignal<E, Args...>(signalsKey)->connect(callback);
69 
70  {
71  std::lock_guard<std::mutex> lock{fMutex};
72 
73  if (fConnections.find(connectionsKey) != fConnections.end())
74  {
75  fConnections.at(connectionsKey).disconnect();
76  fConnections.erase(connectionsKey);
77  }
78  fConnections.insert({connectionsKey, connection});
79  }
80  }
81 
82  template<typename E, typename ...Args>
83  auto Unsubscribe(const std::string& subscriber) -> void
84  {
85  const std::type_index event_type_index{typeid(E)};
86  const std::type_index callback_type_index{typeid(std::function<void(typename E::KeyType, Args...)>)};
87  const auto signalsKey = std::make_pair(event_type_index, callback_type_index);
88  const auto connectionsKey = std::make_pair(subscriber, signalsKey);
89 
90  std::lock_guard<std::mutex> lock{fMutex};
91 
92  fConnections.at(connectionsKey).disconnect();
93  fConnections.erase(connectionsKey);
94  }
95 
96  template<typename E, typename ...Args>
97  auto Emit(typename E::KeyType key, Args... args) const -> void
98  {
99  const std::type_index event_type_index{typeid(E)};
100  const std::type_index callback_type_index{typeid(std::function<void(typename E::KeyType, Args...)>)};
101  const auto signalsKey = std::make_pair(event_type_index, callback_type_index);
102 
103  (*GetSignal<E, Args...>(signalsKey))(key, std::forward<Args>(args)...);
104  }
105 
106  private:
107  using SignalsKey = std::pair<std::type_index, std::type_index>;
108  // event , callback
109  using SignalsValue = boost::any;
110  using SignalsMap = std::unordered_map<SignalsKey, SignalsValue, boost::hash<SignalsKey>>;
111  mutable SignalsMap fSignals;
112 
113  using ConnectionsKey = std::pair<std::string, SignalsKey>;
114  // subscriber , event/callback
115  using ConnectionsValue = boost::signals2::connection;
116  using ConnectionsMap = std::unordered_map<ConnectionsKey, ConnectionsValue, boost::hash<ConnectionsKey>>;
117  ConnectionsMap fConnections;
118 
119  mutable std::mutex fMutex;
120 
121  template<typename E, typename ...Args>
122  auto GetSignal(const SignalsKey& key) const -> std::shared_ptr<Signal<E, Args...>>
123  {
124  std::lock_guard<std::mutex> lock{fMutex};
125 
126  if (fSignals.find(key) == fSignals.end())
127  {
128  // wrapper is needed because boost::signals2::signal is neither copyable nor movable
129  // and I don't know how else to insert it into the map
130  auto signal = std::make_shared<Signal<E, Args...>>();
131  fSignals.insert(std::make_pair(key, signal));
132  }
133 
134  return boost::any_cast<std::shared_ptr<Signal<E, Args...>>>(fSignals.at(key));
135  }
136 }; /* class EventManager */
137 
138 } // namespace fair::mq
139 
140 #endif /* FAIR_MQ_EVENTMANAGER_H */
fair::mq
Tools for interfacing containers to the transport via polymorphic allocators.
Definition: DeviceRunner.h:23

privacy