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

privacy