Radium Engine  1.5.0
ComponentMessenger.hpp
1 #pragma once
2 
3 #include <Core/Utils/Singleton.hpp>
4 #include <Core/Utils/StdUtils.hpp>
5 #include <Engine/RaEngine.hpp>
6 #include <Engine/Scene/Component.hpp>
7 
8 #include <functional>
9 #include <iostream>
10 #include <memory>
11 #include <typeindex>
12 #include <unordered_map>
13 #include <vector>
14 
15 namespace Ra {
16 namespace Engine {
17 namespace Scene {
18 
19 class Entity;
20 class Component;
21 
39 class RA_ENGINE_API ComponentMessenger
40 {
41  RA_SINGLETON_INTERFACE( ComponentMessenger );
42 
43  public:
45  template <typename T>
46  struct CallbackTypes {
48  using Getter = std::function<const T*( void )>;
50  using Setter = std::function<void( const T* )>;
51 
53  using ReadWrite = std::function<T*( void )>;
54 
56  static const T& getHelper( const Getter& g ) { return *( g() ); }
57  };
58 
59  template <typename T>
60  struct CallbackTypes<std::shared_ptr<T>> {
61  using Getter = std::function<std::shared_ptr<const T>( void )>;
62  using Setter = std::function<void( std::shared_ptr<const T> )>;
63  using ReadWrite = std::function<std::shared_ptr<T>( void )>;
64 
65  static const std::shared_ptr<const T>& getHelper( const Getter& g ) { return ( g() ); }
66  };
67 
68  private:
70  using Key = std::pair<std::string, std::type_index>;
71 
72  // Unfortunately there is no standard hash functions for std::pair.
73  // so we have to provide one (which justs xors the two hashes)
74  // We could use a proper hash combination function like this one :
75  // http://www.boost.org/doc/libs/1_46_1/doc/html/hash/reference.html#boost.hash_combine
76 
78  struct HashFunc {
79  inline std::size_t operator()( const Key& k ) const;
80  };
81 
83  struct CallbackBase {};
84  template <typename T>
85  struct GetterCallback : public CallbackBase {
86  typename CallbackTypes<T>::Getter m_cb;
87  };
88  template <typename T>
89  struct SetterCallback : public CallbackBase {
90  typename CallbackTypes<T>::Setter m_cb;
91  };
92  template <typename T>
93  struct RwCallback : public CallbackBase {
94  typename CallbackTypes<T>::ReadWrite m_cb;
95  };
96 
98  using CallbackMap = std::unordered_map<Key, std::unique_ptr<CallbackBase>, HashFunc>;
99 
100  public:
101  ComponentMessenger() = default;
102 
103  //
104  // Direct access to function pointers
105  //
106 
107  template <typename ReturnType>
108  inline typename CallbackTypes<ReturnType>::Getter getterCallback( const Entity* entity,
109  const std::string& id );
110 
111  template <typename ReturnType>
112  inline typename CallbackTypes<ReturnType>::ReadWrite rwCallback( const Entity* entity,
113  const std::string& id );
114 
115  template <typename ReturnType>
116  inline typename CallbackTypes<ReturnType>::Setter setterCallback( const Entity* entity,
117  const std::string& id );
118 
119  //
120  // Access the exported data.
121  //
122 
123  // Note : all functions assert when the data is not available.
124  // e.g. get() assert if canGet() is false.
125 
126  template <typename ReturnType>
127  inline const ReturnType& get( const Entity* entity, const std::string& id );
128 
129  //
130  // Query if a given key has registered data.
131  //
132 
133  template <typename ReturnType>
134  inline bool canGet( const Entity* entity, const std::string& id );
135 
136  template <typename ReturnType>
137  inline bool canSet( const Entity* entity, const std::string& id );
138 
139  template <typename ReturnType>
140  inline bool canRw( const Entity* entity, const std::string& id );
141 
142  //
143  // Register callbacks
144  //
145 
146  template <typename ReturnType>
147  inline void registerOutput( const Entity* entity,
148  Component* comp,
149  const std::string& id,
150  const typename CallbackTypes<ReturnType>::Getter& cb );
151 
152  template <typename ReturnType>
153  inline void registerReadWrite( const Entity* entity,
154  Component* comp,
155  const std::string& id,
156  const typename CallbackTypes<ReturnType>::ReadWrite& cb );
157 
158  template <typename ReturnType>
159  inline void registerInput( const Entity* entity,
160  Component* comp,
161  const std::string& id,
162  const typename CallbackTypes<ReturnType>::Setter& cb );
163 
165  void unregisterAll( const Entity* entity, Component* component );
166 
167  private:
168  using EntityMap = std::unordered_map<const Entity*, CallbackMap>;
169  EntityMap m_entityGetLists;
170  EntityMap m_entitySetLists;
171  EntityMap m_entityRwLists;
172 };
173 
174 inline std::size_t ComponentMessenger::HashFunc::operator()( const Key& k ) const {
175  return Core::Utils::hash( k );
176 }
177 
178 template <typename ReturnType>
180 ComponentMessenger::getterCallback( const Entity* entity, const std::string& id ) {
181  CORE_ASSERT( canGet<ReturnType>( entity, id ), "Unregistered callback" );
182  return static_cast<GetterCallback<ReturnType>*>(
183  m_entityGetLists[entity][Key( id, std::type_index( typeid( ReturnType ) ) )].get() )
184  ->m_cb;
185 }
186 
187 template <typename ReturnType>
189 ComponentMessenger::rwCallback( const Entity* entity, const std::string& id ) {
190  CORE_ASSERT( canRw<ReturnType>( entity, id ), "Unregistered callback" );
191  return static_cast<RwCallback<ReturnType>*>(
192  m_entityRwLists[entity][Key( id, std::type_index( typeid( ReturnType ) ) )].get() )
193  ->m_cb;
194 }
195 
196 template <typename ReturnType>
198 ComponentMessenger::setterCallback( const Entity* entity, const std::string& id ) {
199  CORE_ASSERT( canSet<ReturnType>( entity, id ), "Unregistered callback" );
200  return static_cast<SetterCallback<ReturnType>*>(
201  m_entitySetLists[entity][Key( id, std::type_index( typeid( ReturnType ) ) )].get() )
202  ->m_cb;
203 }
204 
205 template <typename ReturnType>
206 inline const ReturnType& ComponentMessenger::get( const Entity* entity, const std::string& id ) {
207  return CallbackTypes<ReturnType>::getHelper( getterCallback<ReturnType>( entity, id ) );
208 }
209 /*
210  template<typename ReturnType>
211  inline void ComponentMessenger::set(const Entity* entity, const std::string& id, const
212  ReturnType& x)
213  {
214  return setterCallback<ReturnType>(entity, id)(x);
215  }
216 */
217 template <typename ReturnType>
218 inline bool ComponentMessenger::canGet( const Entity* entity, const std::string& id ) {
219  // Attempt to find the given entity list.
220  const auto& entityListPos = m_entityGetLists.find( entity );
221  if ( entityListPos == m_entityGetLists.end() )
222  return false; // Entity has no registered component
223 
224  Key key( id, std::type_index( typeid( ReturnType ) ) );
225  const CallbackMap& entityList = entityListPos->second;
226 
227  // Check if there are components exporting the given type,
228  // so let's try to find if there is one with the requested id.
229  const auto& callbackEntry = entityList.find( key );
230  const bool found = ( callbackEntry != entityList.end() );
231  return found;
232 }
233 
234 template <typename ReturnType>
235 inline bool ComponentMessenger::canSet( const Entity* entity, const std::string& id ) {
236  // Attempt to find the given entity list.
237  auto entityListPos = m_entitySetLists.find( entity );
238  if ( entityListPos == m_entitySetLists.end() )
239  return false; // Entity has no registered component
240 
241  Key key( id, std::type_index( typeid( ReturnType ) ) );
242  const CallbackMap& entityList = entityListPos->second;
243 
244  // Check if there are components exporting the given type,
245  // so let's try to find if there is one with the requested id.
246  const auto& callbackEntry = entityList.find( key );
247  const bool found = ( callbackEntry != entityList.end() );
248  return found;
249 }
250 
251 template <typename ReturnType>
252 inline bool ComponentMessenger::canRw( const Entity* entity, const std::string& id ) {
253  // Attempt to find the given entity list.
254  const auto& entityListPos = m_entityRwLists.find( entity );
255  if ( entityListPos == m_entityRwLists.end() )
256  return false; // Entity has no registered component
257 
258  Key key( id, std::type_index( typeid( ReturnType ) ) );
259  const CallbackMap& entityList = entityListPos->second;
260 
261  // Check if there are components exporting the given type,
262  // so let's try to find if there is one with the requested id.
263  const auto& callbackEntry = entityList.find( key );
264  const bool found = ( callbackEntry != entityList.end() );
265  return found;
266 }
267 
268 template <typename ReturnType>
269 inline void
270 ComponentMessenger::registerOutput( const Entity* entity,
271  Component* comp,
272  const std::string& id,
273  const typename CallbackTypes<ReturnType>::Getter& cb ) {
274  CORE_ASSERT( entity && comp->getEntity() == entity, "Component not added to entity" );
275  CORE_UNUSED( comp );
276  // Will insert a new entity entry if it doesn't exist.
277  CallbackMap& entityList = m_entityGetLists[entity];
278 
279  Key key( id, std::type_index( typeid( ReturnType ) ) );
280  CORE_ASSERT( entityList.find( key ) == entityList.end(),
281  "Output function already registered for " + id );
282 
283  GetterCallback<ReturnType>* getter = new GetterCallback<ReturnType>();
284  getter->m_cb = cb;
285  entityList[key].reset( getter );
286 }
287 
288 template <typename ReturnType>
289 inline void
290 ComponentMessenger::registerReadWrite( const Entity* entity,
291  Component* comp,
292  const std::string& id,
293  const typename CallbackTypes<ReturnType>::ReadWrite& cb ) {
294  CORE_ASSERT( entity && comp->getEntity() == entity, "Component not added to entity" );
295  CORE_UNUSED( comp );
296  // Will insert a new entity entry if it doesn't exist.
297  CallbackMap& entityList = m_entityRwLists[entity];
298 
299  Key key( id, std::type_index( typeid( ReturnType ) ) );
300  CORE_ASSERT( entityList.find( key ) == entityList.end(),
301  "Rw function already registered for " + id );
302 
303  RwCallback<ReturnType>* rw = new RwCallback<ReturnType>();
304  rw->m_cb = cb;
305  entityList[key].reset( rw );
306 }
307 
308 template <typename ReturnType>
309 inline void
310 ComponentMessenger::registerInput( const Entity* entity,
311  Component* comp,
312  const std::string& id,
313  const typename CallbackTypes<ReturnType>::Setter& cb ) {
314  CORE_ASSERT( entity && comp->getEntity() == entity, "Component not added to entity" );
315  CORE_UNUSED( comp );
316  // Will insert a new entity entry if it doesn't exist.
317  CallbackMap& entityList = m_entitySetLists[entity];
318 
319  Key key( id, std::type_index( typeid( ReturnType ) ) );
320  CORE_ASSERT( entityList.find( key ) == entityList.end(),
321  "Input function already registered for " + id );
322 
323  SetterCallback<ReturnType>* setter = new SetterCallback<ReturnType>();
324  setter->m_cb = cb;
325  entityList[key].reset( setter );
326 }
327 
328 } // namespace Scene
329 } // namespace Engine
330 } // namespace Ra
Definition: Cage.cpp:3
This describes the function pointers accepted for each type.
static const T & getHelper(const Getter &g)
Calls the callback and retrieves the object.
std::function< void(const T *)> Setter
Function pointer for a setter function.
std::function< T *(void)> ReadWrite
Function pointer for a read/write getter.
std::function< const T *(void)> Getter
Function pointer for a getter function.