Gazebo Sim

API Reference

9.0.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
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
38namespace gz
39{
40namespace sim
41{
42// Inline bracket to help doxygen filtering.
43inline namespace GZ_SIM_VERSION_NAMESPACE {
44namespace 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
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
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
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 {
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 std::cout << "Registering [" << ComponentTypeT::typeName << "]"
289 << std::endl;
290 }
291
292 // Keep track of all types
293 this->compsById[ComponentTypeT::typeId].Add(_regObjId, _compDesc);
294 namesById[ComponentTypeT::typeId] = ComponentTypeT::typeName;
295 runtimeNamesById[ComponentTypeT::typeId] = runtimeName;
296 }
297
301 // Deprecated in favor of overload that takes _regObjId
302 public: template <typename ComponentTypeT>
303 void GZ_DEPRECATED(8) Unregister()
304 {
305 this->Unregister<ComponentTypeT>(RegistrationObjectId{nullptr});
306 }
307
314 public: template<typename ComponentTypeT>
316 {
317 this->Unregister(ComponentTypeT::typeId, _regObjId);
318 }
319
326 // Deprecated in favor of overload that takes _regObjId
327 public: void GZ_DEPRECATED(8) Unregister(ComponentTypeId _typeId)
328 {
329 this->Unregister(_typeId, RegistrationObjectId{nullptr});
330 }
331
341 public: void Unregister(ComponentTypeId _typeId,
342 RegistrationObjectId _regObjId)
343 {
344 auto it = this->compsById.find(_typeId);
345 if (it != this->compsById.end())
346 {
347 it->second.Remove(_regObjId);
348
349 if (it->second.Empty())
350 {
351 this->compsById.erase(it);
352 }
353 }
354 }
355
360 public: template<typename ComponentTypeT>
362 {
363 return std::unique_ptr<ComponentTypeT>(static_cast<ComponentTypeT *>(
364 this->New(ComponentTypeT::typeId).release()));
365 }
366
372 const ComponentTypeId &_type)
373 {
374 // Create a new component if a FactoryFn has been assigned to this type.
376 auto it = this->compsById.find(_type);
377 if (it != this->compsById.end())
378 {
379 comp = it->second.Create();
380 }
381 return comp;
382 }
383
391 const ComponentTypeId &_type, const components::BaseComponent *_data)
392 {
394
395 if (nullptr == _data)
396 {
397 gzerr << "Requested to create a new component instance with null "
398 << "data." << std::endl;
399 }
400 else if (_type != _data->TypeId())
401 {
402 gzerr << "The typeID of _type [" << _type << "] does not match the "
403 << "typeID of _data [" << _data->TypeId() << "]." << std::endl;
404 }
405 else
406 {
407 auto it = this->compsById.find(_type);
408 if (it != this->compsById.end())
409 {
410 comp = it->second.Create(_data);
411 }
412 }
413
414 return comp;
415 }
416
420 {
422
423 // Return the list of all known component types.
424 for (const auto &comp : this->compsById)
425 types.push_back(comp.first);
426
427 return types;
428 }
429
432 public: bool HasType(ComponentTypeId _typeId)
433 {
434 return this->compsById.find(_typeId) != this->compsById.end();
435 }
436
439 public: std::string Name(ComponentTypeId _typeId) const
440 {
441 if (this->namesById.find(_typeId) != this->namesById.end())
442 return namesById.at(_typeId);
443
444 return "";
445 }
446
447 // Since the copy constructors are deleted, we need to explicitly declare a
448 // default constructor.
449 private: Factory() = default;
450 friend gz::utils::NeverDestroyed<Factory>;
453
456
461 };
462
471 #define GZ_SIM_REGISTER_COMPONENT(_compType, _classname) \
472 class GzSimComponents##_classname \
473 { \
474 public: GzSimComponents##_classname() \
475 { \
476 using namespace gz;\
477 using Desc = sim::components::ComponentDescriptor<_classname>; \
478 sim::components::Factory::Instance()->Register<_classname>(\
479 _compType, new Desc(), sim::components::RegistrationObjectId(this));\
480 } \
481 public: GzSimComponents##_classname( \
482 const GzSimComponents##_classname&) = delete; \
483 public: GzSimComponents##_classname( \
484 GzSimComponents##_classname&) = delete; \
485 public: ~GzSimComponents##_classname() \
486 { \
487 using namespace gz; \
488 sim::components::Factory::Instance()->Unregister<_classname>( \
489 sim::components::RegistrationObjectId(this)); \
490 } \
491 }; \
492 static GzSimComponents##_classname\
493 GzSimComponentsInitializer##_classname;
494}
495}
496}
497}
498
499#endif