19
19
20
20
#include < cstdint>
21
21
#include < cstring>
22
+ #include < deque>
22
23
#include < map>
23
24
#include < memory>
24
25
#include < string>
@@ -114,6 +115,9 @@ namespace components
114
115
class Factory
115
116
: public ignition::common::SingletonT<Factory>
116
117
{
118
+ // / \brief Get an instance of the singleton
119
+ public: static Factory *Instance ();
120
+
117
121
// / \brief Register a component so that the factory can create instances
118
122
// / of the component and its storage based on an ID.
119
123
// / \param[in] _type Type of component to register.
@@ -139,13 +143,6 @@ namespace components
139
143
public: template <typename ComponentTypeT>
140
144
void Register (const std::string &_type, ComponentDescriptorBase *_compDesc)
141
145
{
142
- // Every time a plugin which uses a component type is loaded, it attempts
143
- // to register it again, so we skip it.
144
- if (ComponentTypeT::typeId != 0 )
145
- {
146
- return ;
147
- }
148
-
149
146
auto typeHash = ignition::common::hash64 (_type);
150
147
151
148
// Initialize static member variable - we need to set these
@@ -169,8 +166,8 @@ namespace components
169
166
<< runtimeNameIt->second << " ] and type [" << runtimeName
170
167
<< " ] with name [" << _type << " ]. Second type will not work."
171
168
<< std::endl;
169
+ return ;
172
170
}
173
- return ;
174
171
}
175
172
176
173
// This happens at static initialization time, so we can't use common
@@ -184,7 +181,7 @@ namespace components
184
181
}
185
182
186
183
// Keep track of all types
187
- this ->compsById [ComponentTypeT::typeId] = _compDesc;
184
+ this ->compsById [ComponentTypeT::typeId]. push_front ( _compDesc) ;
188
185
namesById[ComponentTypeT::typeId] = ComponentTypeT::typeName;
189
186
runtimeNamesById[ComponentTypeT::typeId] = runtimeName;
190
187
}
@@ -193,11 +190,9 @@ namespace components
193
190
// / of the component anymore.
194
191
// / \tparam ComponentTypeT Type of component to unregister.
195
192
public: template <typename ComponentTypeT>
196
- void Unregister ()
193
+ void Unregister (ComponentDescriptorBase *_compDesc = nullptr )
197
194
{
198
- this ->Unregister (ComponentTypeT::typeId);
199
-
200
- ComponentTypeT::typeId = 0 ;
195
+ this ->Unregister (ComponentTypeT::typeId, _compDesc);
201
196
}
202
197
203
198
// / \brief Unregister a component so that the factory can't create instances
@@ -206,7 +201,8 @@ namespace components
206
201
// / within the component type itself. Prefer using the templated
207
202
// / `Unregister` function when possible.
208
203
// / \param[in] _typeId Type of component to unregister.
209
- public: void Unregister (ComponentTypeId _typeId)
204
+ public: void Unregister (ComponentTypeId _typeId,
205
+ ComponentDescriptorBase *_compDesc = nullptr )
210
206
{
211
207
// Not registered
212
208
if (_typeId == 0 )
@@ -216,26 +212,30 @@ namespace components
216
212
217
213
{
218
214
auto it = this ->compsById .find (_typeId);
219
- if (it != this ->compsById .end ())
215
+ if (it != this ->compsById .end () && !it-> second . empty () )
220
216
{
221
- delete it->second ;
222
- this ->compsById .erase (it);
217
+ if (nullptr == _compDesc)
218
+ {
219
+ ComponentDescriptorBase *compDesc = it->second .back ();
220
+ it->second .pop_back ();
221
+ delete compDesc;
222
+ }
223
+ else
224
+ {
225
+ auto compIt =
226
+ std::find (it->second .begin (), it->second .end (), _compDesc);
227
+ if (compIt != it->second .end ())
228
+ {
229
+ ComponentDescriptorBase* compDesc = *compIt;
230
+ it->second .erase (compIt);
231
+ delete compDesc;
232
+ }
233
+ }
223
234
}
224
- }
225
-
226
- {
227
- auto it = namesById.find (_typeId);
228
- if (it != namesById.end ())
235
+ // Check again since we may have updated the list
236
+ if (it->second .empty ())
229
237
{
230
- namesById.erase (it);
231
- }
232
- }
233
-
234
- {
235
- auto it = runtimeNamesById.find (_typeId);
236
- if (it != runtimeNamesById.end ())
237
- {
238
- runtimeNamesById.erase (it);
238
+ this ->compsById .erase (it);
239
239
}
240
240
}
241
241
}
@@ -261,9 +261,15 @@ namespace components
261
261
// Create a new component if a FactoryFn has been assigned to this type.
262
262
std::unique_ptr<components::BaseComponent> comp;
263
263
auto it = this ->compsById .find (_type);
264
- if (it != this ->compsById .end () && nullptr != it->second )
265
- comp = it->second ->Create ();
266
-
264
+ if (it != this ->compsById .end () && !it->second .empty ()){
265
+ comp = it->second .front ()->Create ();
266
+ }
267
+ else
268
+ {
269
+ ignerr << " New(no data) Error: (it, empty)"
270
+ << (it != this ->compsById .end ()) << " "
271
+ << (it->second .size ()) << std::endl;
272
+ }
267
273
return comp;
268
274
}
269
275
@@ -291,8 +297,16 @@ namespace components
291
297
else
292
298
{
293
299
auto it = this ->compsById .find (_type);
294
- if (it != this ->compsById .end () && nullptr != it->second )
295
- comp = it->second ->Create (_data);
300
+ if (it != this ->compsById .end () && !it->second .empty ())
301
+ {
302
+ comp = it->second .front ()->Create (_data);
303
+ }
304
+ else
305
+ {
306
+ ignerr << " New(data) Error: (it, empty)"
307
+ << (it != this ->compsById .end ()) << " "
308
+ << (it->second .size ()) << std::endl;
309
+ }
296
310
}
297
311
298
312
return comp;
@@ -339,19 +353,8 @@ namespace components
339
353
}
340
354
341
355
// / \brief A list of registered components where the key is its id.
342
- // /
343
- // / Note about compsByName and compsById. The maps store pointers as the
344
- // / values, but never cleans them up, which may (at first glance) seem like
345
- // / incorrect behavior. This is not a mistake. Since ComponentDescriptors
346
- // / are created at the point in the code where components are defined, this
347
- // / generally ends up in a shared library that will be loaded at runtime.
348
- // /
349
- // / Because this and the plugin loader both use static variables, and the
350
- // / order of static initialization and destruction are not guaranteed, this
351
- // / can lead to a scenario where the shared library is unloaded (with the
352
- // / ComponentDescriptor), but the Factory still exists. For this reason,
353
- // / we just keep a pointer, which will dangle until the program is shutdown.
354
- private: std::map<ComponentTypeId, ComponentDescriptorBase *> compsById;
356
+ private: std::map<ComponentTypeId, std::deque<ComponentDescriptorBase *>>
357
+ compsById;
355
358
356
359
// / \brief A list of IDs and their equivalent names.
357
360
public: std::map<ComponentTypeId, std::string> namesById;
@@ -375,13 +378,19 @@ namespace components
375
378
{ \
376
379
public: IgnGazeboComponents##_classname() \
377
380
{ \
378
- if (_classname::typeId != 0 ) \
379
- return ; \
380
- using namespace ignition ; \
381
- using Desc = gazebo::components::ComponentDescriptor<_classname>; \
381
+ using namespace ignition ; \
382
+ this ->desc = new Desc (); \
382
383
gazebo::components::Factory::Instance ()->Register <_classname>(\
383
- _compType, new Desc ());\
384
+ _compType, this ->desc );\
385
+ } \
386
+ public: ~IgnGazeboComponents##_classname() \
387
+ { \
388
+ using namespace ignition ; \
389
+ using namespace gazebo ; \
390
+ components::Factory::Instance ()->Unregister <_classname>(this ->desc ); \
384
391
} \
392
+ using Desc = ignition::gazebo::components::ComponentDescriptor<_classname>;\
393
+ private: Desc *desc; \
385
394
}; \
386
395
static IgnGazeboComponents##_classname\
387
396
IgnitionGazeboComponentsInitializer##_classname;
0 commit comments