FairMQ  1.2.3
C++ Message Passing 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 <tuple>
16 #include <typeindex>
17 #include <typeinfo>
18 #include <unordered_map>
19 #include <utility>
20 #include <vector>
21 
22 #include <boost/any.hpp>
23 #include <boost/functional/hash.hpp>
24 #include <boost/signals2.hpp>
25 
26 namespace fair
27 {
28 namespace mq
29 {
30 
31 // Inherit from this base event type to create custom event types
32 template<typename K>
33 struct Event
34 {
35  using KeyType = K;
36 };
37 
54 {
55  public:
56  // Clang 3.4-3.8 has a bug and cannot properly deal with the following template alias.
57  // Therefore, we leave them here commented out for now.
58  // template<typename E, typename ...Args>
59  // using Callback = std::function<void(typename E::KeyType, Args...)>;
60 
61  template<typename E, typename ...Args>
62  using Signal = boost::signals2::signal<void(typename E::KeyType, Args...)>;
63 
64  template<typename E, typename ...Args>
65  auto Subscribe(const std::string& subscriber, std::function<void(typename E::KeyType, Args...)> callback) -> void
66  {
67  const std::type_index event_type_index{typeid(E)};
68  const std::type_index callback_type_index{typeid(std::function<void(typename E::KeyType, Args...)>)};
69  const auto signalsKey = std::make_pair(event_type_index, callback_type_index);
70  const auto connectionsKey = std::make_pair(subscriber, signalsKey);
71 
72  const auto connection = GetSignal<E, Args...>(signalsKey)->connect(callback);
73 
74  {
75  std::lock_guard<std::mutex> lock{fMutex};
76 
77  if (fConnections.find(connectionsKey) != fConnections.end())
78  {
79  fConnections.at(connectionsKey).disconnect();
80  fConnections.erase(connectionsKey);
81  }
82  fConnections.insert({connectionsKey, connection});
83  }
84  }
85 
86  template<typename E, typename ...Args>
87  auto Unsubscribe(const std::string& subscriber) -> void
88  {
89  const std::type_index event_type_index{typeid(E)};
90  const std::type_index callback_type_index{typeid(std::function<void(typename E::KeyType, Args...)>)};
91  const auto signalsKey = std::make_pair(event_type_index, callback_type_index);
92  const auto connectionsKey = std::make_pair(subscriber, signalsKey);
93 
94  std::lock_guard<std::mutex> lock{fMutex};
95 
96  fConnections.at(connectionsKey).disconnect();
97  fConnections.erase(connectionsKey);
98  }
99 
100  template<typename E, typename ...Args>
101  auto Emit(typename E::KeyType key, Args... args) const -> void
102  {
103  const std::type_index event_type_index{typeid(E)};
104  const std::type_index callback_type_index{typeid(std::function<void(typename E::KeyType, Args...)>)};
105  const auto signalsKey = std::make_pair(event_type_index, callback_type_index);
106 
107  (*GetSignal<E, Args...>(signalsKey))(key, std::forward<Args>(args)...);
108  }
109 
110  private:
111  using SignalsKey = std::pair<std::type_index, std::type_index>;
112  // event , callback
113  using SignalsValue = boost::any;
114  using SignalsMap = std::unordered_map<SignalsKey, SignalsValue, boost::hash<SignalsKey>>;
115  mutable SignalsMap fSignals;
116 
117  using ConnectionsKey = std::pair<std::string, SignalsKey>;
118  // subscriber , event/callback
119  using ConnectionsValue = boost::signals2::connection;
120  using ConnectionsMap = std::unordered_map<ConnectionsKey, ConnectionsValue, boost::hash<ConnectionsKey>>;
121  ConnectionsMap fConnections;
122 
123  mutable std::mutex fMutex;
124 
125  template<typename E, typename ...Args>
126  auto GetSignal(const SignalsKey& key) const -> std::shared_ptr<Signal<E, Args...>>
127  {
128  std::lock_guard<std::mutex> lock{fMutex};
129 
130  if (fSignals.find(key) == fSignals.end())
131  {
132  // wrapper is needed because boost::signals2::signal is neither copyable nor movable
133  // and I don't know how else to insert it into the map
134  auto signal = std::make_shared<Signal<E, Args...>>();
135  fSignals.insert(std::make_pair(key, signal));
136  }
137 
138  return boost::any_cast<std::shared_ptr<Signal<E, Args...>>>(fSignals.at(key));
139  }
140 }; /* class EventManager */
141 
142 } /* namespace mq */
143 } /* namespace fair */
144 
145 #endif /* FAIR_MQ_EVENTMANAGER_H */
Definition: EventManager.h:33
Manages event callbacks from different subscribers.
Definition: EventManager.h:53
Definition: DeviceRunner.h:23