Gazebo Sim

API Reference

8.14.0
EventManager.hh
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2018 Open Source Robotics Foundation
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 GZ_SIM_EVENTMANAGER_HH_
18 #define GZ_SIM_EVENTMANAGER_HH_
19 
20 #include <cstring>
21 #include <functional>
22 #include <memory>
23 #include <string>
24 #include <typeinfo>
25 #include <unordered_map>
26 #include <utility>
27 
28 #include <gz/common/Console.hh>
29 #include <gz/common/Event.hh>
30 
31 #include <gz/sim/config.hh>
32 #include <gz/sim/Export.hh>
33 #include <gz/sim/Types.hh>
34 
35 namespace gz
36 {
37  namespace sim
38  {
39  // Inline bracket to help doxygen filtering.
40  inline namespace GZ_SIM_VERSION_NAMESPACE {
41  // Forward declarations.
42  class GZ_SIM_HIDDEN EventManagerPrivate;
43 
52 
57  {
59  public: EventManager() = default;
60 
61  public: EventManager(const EventManager &) = delete;
62  public: EventManager &operator=(const EventManager &) = delete;
63 
65  public: ~EventManager() = default;
66 
72  public: template <typename E>
74  Connect(const typename E::CallbackT &_subscriber)
75  {
76  if (this->events.find(typeid(E)) == this->events.end()) {
77  this->events[typeid(E)] = std::make_unique<E>();
78  }
79 
80  // static_cast is used instead of dynamic_cast because
81  // dynamic_cast fails across shared-library boundaries when
82  // plugins are loaded with RTLD_LOCAL and hidden visibility
83  // (the RTTI type_info pointers differ per dylib on macOS).
84  // The map key guarantees the correct type by construction.
85  E *eventPtr = static_cast<E *>(this->events[typeid(E)].get());
86  return eventPtr->Connect(_subscriber);
87  }
88 
92  public: template <typename E, typename ... Args>
93  void Emit(Args && ... _args)
94  {
95  if (this->events.find(typeid(E)) == this->events.end())
96  {
97  // If there are no events of type E in the map, create it.
98  // But it also means there is nothing to signal.
99  //
100  // This is also needed to suppress unused function warnings
101  // for Events that are purely emitted, with no connections.
102  this->events[typeid(E)] = std::make_unique<E>();
103  return;
104  }
105 
106  // static_cast: see Connect() comment on RTTI across dylibs.
107  E *eventPtr = static_cast<E *>(this->events[typeid(E)].get());
108  eventPtr->Signal(std::forward<Args>(_args) ...);
109  }
110 
113  public: template <typename E>
114  unsigned int
116  {
117  if (this->events.find(typeid(E)) == this->events.end())
118  {
119  return 0u;
120  }
121 
122  // static_cast: see Connect() comment on RTTI across dylibs.
123  E *eventPtr = static_cast<E *>(this->events[typeid(E)].get());
124  return eventPtr->ConnectionCount();
125  }
126 
128  private: using TypeInfoRef = std::reference_wrapper<const std::type_info>;
129 
134  private: struct Hasher
135  {
136  std::size_t operator()(TypeInfoRef _code) const
137  {
138  return std::hash<std::string>{}(_code.get().name());
139  }
140  };
141 
143  private: struct EqualTo
144  {
145  bool operator()(TypeInfoRef _lhs, TypeInfoRef _rhs) const
146  {
147  return _lhs.get() == _rhs.get() ||
148  std::strcmp(_lhs.get().name(),
149  _rhs.get().name()) == 0;
150  }
151  };
152 
154  private: std::unordered_map<TypeInfoRef,
156  Hasher, EqualTo> events;
157  };
158  }
159  }
160 }
161 
162 #endif // GZ_SIM_EVENTMANAGER_HH_