Gazebo Sim

API Reference

10.0.0~pre1
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
217 public: template <typename ComponentTypeT>
218 void Register(const char *_type, ComponentDescriptorBase *_compDesc,
219 RegistrationObjectId _regObjId)
220 {
221 auto typeHash = gz::common::hash64(_type);
222
223 // Initialize static member variable - we need to set these
224 // static members for every shared lib that uses the component, but we
225 // only add them to the maps below once.
226 ComponentTypeT::typeId = typeHash;
227 ComponentTypeT::typeName = _type;
228
229 // Check if component has already been registered by another library
230 auto runtimeName = typeid(ComponentTypeT).name();
231 auto runtimeNameIt = this->runtimeNamesById.find(typeHash);
232 if (runtimeNameIt != this->runtimeNamesById.end())
233 {
234 // Warn user if type was previously registered with a different name.
235 // We're leaving the ID set in case this is a false difference across
236 // libraries.
237 if (runtimeNameIt->second != runtimeName)
238 {
240 << "Registered components of different types with same name: type ["
241 << runtimeNameIt->second << "] and type [" << runtimeName
242 << "] with name [" << _type << "]. Second type will not work."
243 << std::endl;
244 return;
245 }
246 }
247
248 // This happens at static initialization time, so we can't use common
249 // console
250 std::string debugEnv;
251 gz::common::env("GZ_DEBUG_COMPONENT_FACTORY", debugEnv);
252
253 if (debugEnv == "true")
254 {
255 std::cout << "Registering [" << ComponentTypeT::typeName << "]"
256 << std::endl;
257 }
258
259 // Keep track of all types
260 this->compsById[ComponentTypeT::typeId].Add(_regObjId, _compDesc);
261 namesById[ComponentTypeT::typeId] = ComponentTypeT::typeName;
262 runtimeNamesById[ComponentTypeT::typeId] = runtimeName;
263 }
264
271 public: template<typename ComponentTypeT>
273 {
274 this->Unregister(ComponentTypeT::typeId, _regObjId);
275 }
276
286 public: void Unregister(ComponentTypeId _typeId,
287 RegistrationObjectId _regObjId)
288 {
289 auto it = this->compsById.find(_typeId);
290 if (it != this->compsById.end())
291 {
292 it->second.Remove(_regObjId);
293
294 if (it->second.Empty())
295 {
296 this->compsById.erase(it);
297 }
298 }
299 }
300
305 public: template<typename ComponentTypeT>
307 {
308 return std::unique_ptr<ComponentTypeT>(static_cast<ComponentTypeT *>(
309 this->New(ComponentTypeT::typeId).release()));
310 }
311
317 const ComponentTypeId &_type)
318 {
319 // Create a new component if a FactoryFn has been assigned to this type.
321 auto it = this->compsById.find(_type);
322 if (it != this->compsById.end())
323 {
324 comp = it->second.Create();
325 }
326 return comp;
327 }
328
336 const ComponentTypeId &_type, const components::BaseComponent *_data)
337 {
339
340 if (nullptr == _data)
341 {
342 gzerr << "Requested to create a new component instance with null "
343 << "data." << std::endl;
344 }
345 else if (_type != _data->TypeId())
346 {
347 gzerr << "The typeID of _type [" << _type << "] does not match the "
348 << "typeID of _data [" << _data->TypeId() << "]." << std::endl;
349 }
350 else
351 {
352 auto it = this->compsById.find(_type);
353 if (it != this->compsById.end())
354 {
355 comp = it->second.Create(_data);
356 }
357 }
358
359 return comp;
360 }
361
365 {
367
368 // Return the list of all known component types.
369 for (const auto &comp : this->compsById)
370 types.push_back(comp.first);
371
372 return types;
373 }
374
377 public: bool HasType(ComponentTypeId _typeId)
378 {
379 return this->compsById.find(_typeId) != this->compsById.end();
380 }
381
384 public: std::string Name(ComponentTypeId _typeId) const
385 {
386 if (this->namesById.find(_typeId) != this->namesById.end())
387 return namesById.at(_typeId);
388
389 return "";
390 }
391
392 // Since the copy constructors are deleted, we need to explicitly declare a
393 // default constructor.
394 private: Factory() = default;
395 friend gz::utils::NeverDestroyed<Factory>;
398
401
406 };
407
416 #define GZ_SIM_REGISTER_COMPONENT(_compType, _classname) \
417 class GzSimComponents##_classname \
418 { \
419 public: GzSimComponents##_classname() \
420 { \
421 using namespace gz;\
422 using Desc = sim::components::ComponentDescriptor<_classname>; \
423 sim::components::Factory::Instance()->Register<_classname>(\
424 _compType, new Desc(), sim::components::RegistrationObjectId(this));\
425 } \
426 public: GzSimComponents##_classname( \
427 const GzSimComponents##_classname&) = delete; \
428 public: GzSimComponents##_classname( \
429 GzSimComponents##_classname&) = delete; \
430 public: ~GzSimComponents##_classname() \
431 { \
432 using namespace gz; \
433 sim::components::Factory::Instance()->Unregister<_classname>( \
434 sim::components::RegistrationObjectId(this)); \
435 } \
436 }; \
437 static GzSimComponents##_classname\
438 GzSimComponentsInitializer##_classname;
439}
440}
441}
442}
443
444#endif