Gazebo Sim

API Reference

8.7.0
Factory.hh
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2019 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_COMPONENTS_FACTORY_HH_
18 #define GZ_SIM_COMPONENTS_FACTORY_HH_
19 
20 #include <algorithm>
21 #include <cstdint>
22 #include <cstring>
23 #include <deque>
24 #include <map>
25 #include <memory>
26 #include <string>
27 #include <utility>
28 #include <vector>
29 
30 #include <gz/common/SingletonT.hh>
31 #include <gz/common/Util.hh>
33 #include <gz/sim/config.hh>
34 #include <gz/sim/Export.hh>
35 #include <gz/sim/Types.hh>
36 #include <gz/utils/NeverDestroyed.hh>
37 
38 namespace gz
39 {
40 namespace sim
41 {
42 // Inline bracket to help doxygen filtering.
43 inline namespace GZ_SIM_VERSION_NAMESPACE {
44 namespace components
45 {
48  {
50  public: virtual ~ComponentDescriptorBase() = default;
51 
54  public: virtual std::unique_ptr<BaseComponent> Create() const = 0;
55 
60  const components::BaseComponent *_data) const = 0;
61  };
62 
65  template <typename ComponentTypeT>
68  {
70  public: std::unique_ptr<BaseComponent> Create() const override
71  {
72  return std::make_unique<ComponentTypeT>();
73  }
74 
77  const components::BaseComponent *_data) const override
78  {
79  ComponentTypeT comp(*static_cast<const ComponentTypeT *>(_data));
80  return std::make_unique<ComponentTypeT>(comp);
81  }
82  };
83 
86  {
89  explicit RegistrationObjectId(void *_ptr)
90  : id(reinterpret_cast<std::uintptr_t>(_ptr))
91  {
92  }
93 
96  explicit RegistrationObjectId(std::uintptr_t _ptrAddress)
97  : id(_ptrAddress)
98  {
99  }
100 
103  bool operator==(const RegistrationObjectId &_other) const
104  {
105  return this->id == _other.id;
106  }
107 
110  };
111 
112 
128  {
130  public: bool GZ_SIM_HIDDEN Empty()
131  {
132  return this->queue.empty();
133  }
134 
140  public: void GZ_SIM_HIDDEN Add(RegistrationObjectId _regObjId,
142  {
143  this->queue.push_front({_regObjId, _comp});
144  }
145 
152  public: void GZ_SIM_HIDDEN Remove(RegistrationObjectId _regObjId)
153  {
154  auto compIt = std::find_if(this->queue.rbegin(), this->queue.rend(),
155  [&](const auto &_item)
156  { return _item.first == _regObjId; });
157 
158  if (compIt != this->queue.rend())
159  {
160  ComponentDescriptorBase *compDesc = compIt->second;
161  this->queue.erase(std::prev(compIt.base()));
162  delete compDesc;
163  }
164  }
165 
169  public: GZ_SIM_HIDDEN std::unique_ptr<BaseComponent> Create() const
170  {
171  if (!this->queue.empty())
172  {
173  return this->queue.front().second->Create();
174  }
175  return {};
176  }
177 
181  public: GZ_SIM_HIDDEN std::unique_ptr<BaseComponent> Create(
182  const components::BaseComponent *_data) const
183  {
184  if (!this->queue.empty())
185  {
186  return this->queue.front().second->Create(_data);
187  }
188  return {};
189  }
190 
194  ComponentDescriptorBase *>> queue;
195  };
196 
198  class Factory
199  {
200  public: Factory(Factory &) = delete;
201  public: Factory(const Factory &) = delete;
202  public: void operator=(const Factory &) = delete;
203  public: void operator=(Factory &&) = delete;
204 
206  public: GZ_SIM_VISIBLE static Factory *Instance();
207 
214  // Deprecated in favor of overload that takes _regObjId
215  public: template <typename ComponentTypeT>
216  void GZ_DEPRECATED(8) Register(const std::string &_type,
217  ComponentDescriptorBase *_compDesc)
218  {
219  const char* typeDup = strdup(_type.c_str());
220  this->Register<ComponentTypeT>(typeDup, _compDesc,
221  RegistrationObjectId{nullptr});
222  }
232  // Deprecated in favor of overload that takes `const char *_type`
233  public: template <typename ComponentTypeT>
234  void GZ_DEPRECATED(8) Register(const std::string &_type,
235  ComponentDescriptorBase *_compDesc, RegistrationObjectId _regObjId)
236  {
237  const char* typeDup = strdup(_type.c_str());
238  this->Register<ComponentTypeT>(typeDup, _compDesc, _regObjId);
239  }
240 
250  public: template <typename ComponentTypeT>
251  void Register(const char *_type, ComponentDescriptorBase *_compDesc,
252  RegistrationObjectId _regObjId)
253  {
254  auto typeHash = gz::common::hash64(_type);
255 
256  // Initialize static member variable - we need to set these
257  // static members for every shared lib that uses the component, but we
258  // only add them to the maps below once.
259  ComponentTypeT::typeId = typeHash;
260  ComponentTypeT::typeName = _type;
261 
262  // Check if component has already been registered by another library
263  auto runtimeName = typeid(ComponentTypeT).name();
264  auto runtimeNameIt = this->runtimeNamesById.find(typeHash);
265  if (runtimeNameIt != this->runtimeNamesById.end())
266  {
267  // Warn user if type was previously registered with a different name.
268  // We're leaving the ID set in case this is a false difference across
269  // libraries.
270  if (runtimeNameIt->second != runtimeName)
271  {
272  std::cerr
273  << "Registered components of different types with same name: type ["
274  << runtimeNameIt->second << "] and type [" << runtimeName
275  << "] with name [" << _type << "]. Second type will not work."
276  << std::endl;
277  return;
278  }
279  }
280 
281  // This happens at static initialization time, so we can't use common
282  // console
283  std::string debugEnv;
284  gz::common::env("GZ_DEBUG_COMPONENT_FACTORY", debugEnv);
285 
286  if (debugEnv != "true")
287  {
288  gz::common::env("IGN_DEBUG_COMPONENT_FACTORY", debugEnv);
289  if (debugEnv == "true")
290  {
291  std::cerr << "Environment variable [IGN_DEBUG_COMPONENT_FACTORY] "
292  << "is deprecated! Please use [GZ_DEBUG_COMPONENT_FACTORY]"
293  << "instead." << std::endl;
294  }
295  }
296 
297  if (debugEnv == "true")
298  {
299  std::cout << "Registering [" << ComponentTypeT::typeName << "]"
300  << std::endl;
301  }
302 
303  // Keep track of all types
304  this->compsById[ComponentTypeT::typeId].Add(_regObjId, _compDesc);
305  namesById[ComponentTypeT::typeId] = ComponentTypeT::typeName;
306  runtimeNamesById[ComponentTypeT::typeId] = runtimeName;
307  }
308 
312  // Deprecated in favor of overload that takes _regObjId
313  public: template <typename ComponentTypeT>
314  void GZ_DEPRECATED(8) Unregister()
315  {
316  this->Unregister<ComponentTypeT>(RegistrationObjectId{nullptr});
317  }
318 
325  public: template<typename ComponentTypeT>
327  {
328  this->Unregister(ComponentTypeT::typeId, _regObjId);
329  }
330 
337  // Deprecated in favor of overload that takes _regObjId
338  public: void GZ_DEPRECATED(8) Unregister(ComponentTypeId _typeId)
339  {
340  this->Unregister(_typeId, RegistrationObjectId{nullptr});
341  }
342 
352  public: void Unregister(ComponentTypeId _typeId,
353  RegistrationObjectId _regObjId)
354  {
355  auto it = this->compsById.find(_typeId);
356  if (it != this->compsById.end())
357  {
358  it->second.Remove(_regObjId);
359 
360  if (it->second.Empty())
361  {
362  this->compsById.erase(it);
363  }
364  }
365  }
366 
371  public: template<typename ComponentTypeT>
373  {
374  return std::unique_ptr<ComponentTypeT>(static_cast<ComponentTypeT *>(
375  this->New(ComponentTypeT::typeId).release()));
376  }
377 
383  const ComponentTypeId &_type)
384  {
385  // Create a new component if a FactoryFn has been assigned to this type.
387  auto it = this->compsById.find(_type);
388  if (it != this->compsById.end())
389  {
390  comp = it->second.Create();
391  }
392  return comp;
393  }
394 
402  const ComponentTypeId &_type, const components::BaseComponent *_data)
403  {
405 
406  if (nullptr == _data)
407  {
408  gzerr << "Requested to create a new component instance with null "
409  << "data." << std::endl;
410  }
411  else if (_type != _data->TypeId())
412  {
413  gzerr << "The typeID of _type [" << _type << "] does not match the "
414  << "typeID of _data [" << _data->TypeId() << "]." << std::endl;
415  }
416  else
417  {
418  auto it = this->compsById.find(_type);
419  if (it != this->compsById.end())
420  {
421  comp = it->second.Create(_data);
422  }
423  }
424 
425  return comp;
426  }
427 
431  {
433 
434  // Return the list of all known component types.
435  for (const auto &comp : this->compsById)
436  types.push_back(comp.first);
437 
438  return types;
439  }
440 
443  public: bool HasType(ComponentTypeId _typeId)
444  {
445  return this->compsById.find(_typeId) != this->compsById.end();
446  }
447 
450  public: std::string Name(ComponentTypeId _typeId) const
451  {
452  if (this->namesById.find(_typeId) != this->namesById.end())
453  return namesById.at(_typeId);
454 
455  return "";
456  }
457 
458  // Since the copy constructors are deleted, we need to explicitly declare a
459  // default constructor.
460  private: Factory() = default;
461  friend gz::utils::NeverDestroyed<Factory>;
464 
467 
472  };
473 
482  #define GZ_SIM_REGISTER_COMPONENT(_compType, _classname) \
483  class GzSimComponents##_classname \
484  { \
485  public: GzSimComponents##_classname() \
486  { \
487  using namespace gz;\
488  using Desc = sim::components::ComponentDescriptor<_classname>; \
489  sim::components::Factory::Instance()->Register<_classname>(\
490  _compType, new Desc(), sim::components::RegistrationObjectId(this));\
491  } \
492  public: GzSimComponents##_classname( \
493  const GzSimComponents##_classname&) = delete; \
494  public: GzSimComponents##_classname( \
495  GzSimComponents##_classname&) = delete; \
496  public: ~GzSimComponents##_classname() \
497  { \
498  using namespace gz; \
499  sim::components::Factory::Instance()->Unregister<_classname>( \
500  sim::components::RegistrationObjectId(this)); \
501  } \
502  }; \
503  static GzSimComponents##_classname\
504  GzSimComponentsInitializer##_classname;
505 }
506 }
507 }
508 }
509 
510 #endif