Gazebo Sim

API Reference

7.7.0
gz/sim/components/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 <cstdint>
21 #include <cstring>
22 #include <deque>
23 #include <map>
24 #include <memory>
25 #include <string>
26 #include <utility>
27 #include <vector>
28 
29 #include <gz/common/SingletonT.hh>
30 #include <gz/common/Util.hh>
32 #include <gz/sim/config.hh>
33 #include <gz/sim/Export.hh>
34 #include <gz/sim/Types.hh>
35 
36 namespace gz
37 {
38 namespace sim
39 {
40 // Inline bracket to help doxygen filtering.
41 inline namespace GZ_SIM_VERSION_NAMESPACE {
42 namespace components
43 {
46  {
48  public: virtual ~ComponentDescriptorBase() = default;
49 
52  public: virtual std::unique_ptr<BaseComponent> Create() const = 0;
53 
57  public: virtual std::unique_ptr<BaseComponent> Create(
58  const components::BaseComponent *_data) const = 0;
59  };
60 
63  template <typename ComponentTypeT>
66  {
68  public: std::unique_ptr<BaseComponent> Create() const override
69  {
70  return std::make_unique<ComponentTypeT>();
71  }
72 
75  const components::BaseComponent *_data) const override
76  {
77  ComponentTypeT comp(*static_cast<const ComponentTypeT *>(_data));
78  return std::make_unique<ComponentTypeT>(comp);
79  }
80  };
81 
84  {
87  explicit RegistrationObjectId(void *_ptr)
88  : id(reinterpret_cast<std::uintptr_t>(_ptr))
89  {
90  }
91 
94  explicit RegistrationObjectId(std::uintptr_t _ptrAddress)
95  : id(_ptrAddress)
96  {
97  }
98 
101  bool operator==(const RegistrationObjectId &_other) const
102  {
103  return this->id == _other.id;
104  }
105 
108  };
109 
110 
126  {
128  public: bool GZ_SIM_HIDDEN Empty()
129  {
130  return this->queue.empty();
131  }
132 
138  public: void GZ_SIM_HIDDEN Add(RegistrationObjectId _regObjId,
140  {
141  this->queue.push_front({_regObjId, _comp});
142  }
143 
150  public: void GZ_SIM_HIDDEN Remove(RegistrationObjectId _regObjId)
151  {
152  auto compIt = std::find_if(this->queue.rbegin(), this->queue.rend(),
153  [&](const auto &_item)
154  { return _item.first == _regObjId; });
155 
156  if (compIt != this->queue.rend())
157  {
158  ComponentDescriptorBase *compDesc = compIt->second;
159  this->queue.erase(std::prev(compIt.base()));
160  delete compDesc;
161  }
162  }
163 
167  public: GZ_SIM_HIDDEN std::unique_ptr<BaseComponent> Create() const
168  {
169  if (!this->queue.empty())
170  {
171  return this->queue.front().second->Create();
172  }
173  return {};
174  }
175 
179  public: GZ_SIM_HIDDEN std::unique_ptr<BaseComponent> Create(
180  const components::BaseComponent *_data) const
181  {
182  if (!this->queue.empty())
183  {
184  return this->queue.front().second->Create(_data);
185  }
186  return {};
187  }
188 
192  ComponentDescriptorBase *>> queue;
193  };
194 
196  // TODO(azeey) Do not inherit from common::SingletonT in Harmonic
197  class Factory
198  : public gz::common::SingletonT<Factory>
199  {
200  // Deleted copy constructors to make the ABI checker happy
201  public: Factory(Factory &) = delete;
202  public: Factory(const Factory &) = delete;
203  // Since the copy constructors are deleted, we need to explicitly declare a
204  // default constructor.
205  // TODO(azeey) Make this private in Harmonic
206  public: Factory() = default;
207 
209  public: GZ_SIM_VISIBLE static Factory *Instance();
210 
217  // TODO(azeey) Deprecate in favor of overload that takes _regObjId
218  public: template <typename ComponentTypeT>
219  void Register(const std::string &_type, ComponentDescriptorBase *_compDesc)
220  {
221  this->Register<ComponentTypeT>(_type, _compDesc,
222  RegistrationObjectId{nullptr});
223  }
224 
234  public: template <typename ComponentTypeT>
235  void Register(const std::string &_type, ComponentDescriptorBase *_compDesc,
236  RegistrationObjectId _regObjId)
237  {
238  auto typeHash = gz::common::hash64(_type);
239 
240  // Initialize static member variable - we need to set these
241  // static members for every shared lib that uses the component, but we
242  // only add them to the maps below once.
243  ComponentTypeT::typeId = typeHash;
244  ComponentTypeT::typeName = _type;
245 
246  // Check if component has already been registered by another library
247  auto runtimeName = typeid(ComponentTypeT).name();
248  auto runtimeNameIt = this->runtimeNamesById.find(typeHash);
249  if (runtimeNameIt != this->runtimeNamesById.end())
250  {
251  // Warn user if type was previously registered with a different name.
252  // We're leaving the ID set in case this is a false difference across
253  // libraries.
254  if (runtimeNameIt->second != runtimeName)
255  {
256  std::cerr
257  << "Registered components of different types with same name: type ["
258  << runtimeNameIt->second << "] and type [" << runtimeName
259  << "] with name [" << _type << "]. Second type will not work."
260  << std::endl;
261  return;
262  }
263  }
264 
265  // This happens at static initialization time, so we can't use common
266  // console
267  std::string debugEnv;
268  gz::common::env("GZ_DEBUG_COMPONENT_FACTORY", debugEnv);
269 
270  if (debugEnv != "true")
271  {
272  gz::common::env("IGN_DEBUG_COMPONENT_FACTORY", debugEnv);
273  if (debugEnv == "true")
274  {
275  std::cerr << "Environment variable [IGN_DEBUG_COMPONENT_FACTORY] "
276  << "is deprecated! Please use [GZ_DEBUG_COMPONENT_FACTORY]"
277  << "instead." << std::endl;
278  }
279  }
280 
281  if (debugEnv == "true")
282  {
283  std::cout << "Registering [" << ComponentTypeT::typeName << "]"
284  << std::endl;
285  }
286 
287  // Keep track of all types
288  this->compsById[ComponentTypeT::typeId].Add(_regObjId, _compDesc);
289  namesById[ComponentTypeT::typeId] = ComponentTypeT::typeName;
290  runtimeNamesById[ComponentTypeT::typeId] = runtimeName;
291  }
292 
296  // TODO(azeey) Deprecate in favor of overload that takes _regObjId
297  public: template <typename ComponentTypeT>
298  void Unregister()
299  {
300  this->Unregister<ComponentTypeT>(RegistrationObjectId{nullptr});
301  }
302 
309  public: template<typename ComponentTypeT>
311  {
312  this->Unregister(ComponentTypeT::typeId, _regObjId);
313  }
314 
321  // TODO(azeey) Deprecate in favor of overload that takes _regObjId
322  public: void Unregister(ComponentTypeId _typeId)
323  {
324  this->Unregister(_typeId, RegistrationObjectId{nullptr});
325  }
326 
336  public: void Unregister(ComponentTypeId _typeId,
337  RegistrationObjectId _regObjId)
338  {
339  auto it = this->compsById.find(_typeId);
340  if (it != this->compsById.end())
341  {
342  it->second.Remove(_regObjId);
343 
344  if (it->second.Empty())
345  {
346  this->compsById.erase(it);
347  }
348  }
349  }
350 
355  public: template<typename ComponentTypeT>
357  {
358  return std::unique_ptr<ComponentTypeT>(static_cast<ComponentTypeT *>(
359  this->New(ComponentTypeT::typeId).release()));
360  }
361 
367  const ComponentTypeId &_type)
368  {
369  // Create a new component if a FactoryFn has been assigned to this type.
371  auto it = this->compsById.find(_type);
372  if (it != this->compsById.end())
373  {
374  comp = it->second.Create();
375  }
376  return comp;
377  }
378 
386  const ComponentTypeId &_type, const components::BaseComponent *_data)
387  {
389 
390  if (nullptr == _data)
391  {
392  gzerr << "Requested to create a new component instance with null "
393  << "data." << std::endl;
394  }
395  else if (_type != _data->TypeId())
396  {
397  gzerr << "The typeID of _type [" << _type << "] does not match the "
398  << "typeID of _data [" << _data->TypeId() << "]." << std::endl;
399  }
400  else
401  {
402  auto it = this->compsById.find(_type);
403  if (it != this->compsById.end())
404  {
405  comp = it->second.Create(_data);
406  }
407  }
408 
409  return comp;
410  }
411 
415  {
417 
418  // Return the list of all known component types.
419  for (const auto &comp : this->compsById)
420  types.push_back(comp.first);
421 
422  return types;
423  }
424 
427  public: bool HasType(ComponentTypeId _typeId)
428  {
429  return this->compsById.find(_typeId) != this->compsById.end();
430  }
431 
434  public: std::string Name(ComponentTypeId _typeId) const
435  {
436  if (this->namesById.find(_typeId) != this->namesById.end())
437  return namesById.at(_typeId);
438 
439  return "";
440  }
441 
444 
447 
452  };
453 
462  #define GZ_SIM_REGISTER_COMPONENT(_compType, _classname) \
463  class GzSimComponents##_classname \
464  { \
465  public: GzSimComponents##_classname() \
466  { \
467  using namespace gz;\
468  using Desc = sim::components::ComponentDescriptor<_classname>; \
469  sim::components::Factory::Instance()->Register<_classname>(\
470  _compType, new Desc(), sim::components::RegistrationObjectId(this));\
471  } \
472  public: GzSimComponents##_classname( \
473  const GzSimComponents##_classname&) = delete; \
474  public: GzSimComponents##_classname( \
475  GzSimComponents##_classname&) = delete; \
476  public: ~GzSimComponents##_classname() \
477  { \
478  using namespace gz; \
479  sim::components::Factory::Instance()->Unregister<_classname>( \
480  sim::components::RegistrationObjectId(this)); \
481  } \
482  }; \
483  static GzSimComponents##_classname\
484  GzSimComponentsInitializer##_classname;
485 }
486 }
487 }
488 }
489 
490 #endif