@@ -113,6 +113,14 @@ void register_lifecycle_actions(
113
113
ecs_set_hooks_id ( world, component, &cl);
114
114
}
115
115
116
+ // Instantiates a per-instance global component cache index
117
+ struct cpp_type_component_cache_index {
118
+ cpp_type_component_cache_index ()
119
+ : index(ecs_cpp_component_id_storage_add()) {}
120
+
121
+ ecs_component_cache_index_t const index;
122
+ };
123
+
116
124
// Class that manages component ids across worlds & binaries.
117
125
// The cpp_type class stores the component id for a C++ type in a static global
118
126
// variable that is shared between worlds. Whenever a component is used this
@@ -125,61 +133,20 @@ void register_lifecycle_actions(
125
133
// will register it as a component, and verify whether the input is consistent.
126
134
template <typename T>
127
135
struct cpp_type_impl {
128
- // Initialize component identifier
129
- static void init (
130
- entity_t entity,
131
- bool allow_tag = true )
132
- {
133
- if (s_reset_count != ecs_cpp_reset_count_get ()) {
134
- reset ();
135
- }
136
-
137
- // If an identifier was already set, check for consistency
138
- if (s_id) {
139
- ecs_assert (s_id == entity, ECS_INCONSISTENT_COMPONENT_ID,
140
- type_name<T>());
141
- ecs_assert (allow_tag == s_allow_tag, ECS_INVALID_PARAMETER, NULL );
142
-
143
- // Component was already registered and data is consistent with new
144
- // identifier, so nothing else to be done.
145
- return ;
146
- }
147
-
148
- // Component wasn't registered yet, set the values. Register component
149
- // name as the fully qualified flecs path.
150
- s_id = entity;
151
- s_allow_tag = allow_tag;
152
- s_size = sizeof (T);
153
- s_alignment = alignof (T);
154
- if (is_empty<T>::value && allow_tag) {
155
- s_size = 0 ;
156
- s_alignment = 0 ;
157
- }
158
-
159
- s_reset_count = ecs_cpp_reset_count_get ();
160
- }
161
-
162
136
// Obtain a component identifier for explicit component registration.
163
- static entity_t id_explicit (world_t *world = nullptr ,
137
+ static entity_t id_explicit (world_t *world,
164
138
const char *name = nullptr , bool allow_tag = true , flecs::id_t id = 0 ,
165
139
bool is_component = true , bool *existing = nullptr )
166
140
{
167
- if (!s_id) {
168
- // If no world was provided the component cannot be registered
169
- ecs_assert (world != nullptr , ECS_COMPONENT_NOT_REGISTERED, name);
170
- } else {
171
- ecs_assert (!id || s_id == id, ECS_INCONSISTENT_COMPONENT_ID, NULL );
172
- }
173
-
174
- // If no id has been registered yet for the component (indicating the
175
- // component has not yet been registered, or the component is used
176
- // across more than one binary), or if the id does not exists in the
177
- // world (indicating a multi-world application), register it. */
178
- if (!s_id || (world && !ecs_exists (world, s_id))) {
179
- init (s_id ? s_id : id, allow_tag);
180
-
181
- ecs_assert (!id || s_id == id, ECS_INTERNAL_ERROR, NULL );
141
+ ecs_assert (world != nullptr , ECS_INTERNAL_ERROR, name);
182
142
143
+ if (const ecs_cached_component_info_t * info = ecs_lookup_cached_component_info (world, cached_component_index.index )) {
144
+ return info->component ;
145
+ } else {
146
+ // If no id has been registered yet for the component (indicating the
147
+ // component has not yet been registered), or if the id does not
148
+ // exists in the world (indicating a multi-world application),
149
+ // register it. */
183
150
const char *symbol = nullptr ;
184
151
if (id) {
185
152
symbol = ecs_get_symbol (world, id);
@@ -188,23 +155,37 @@ struct cpp_type_impl {
188
155
symbol = symbol_name<T>();
189
156
}
190
157
191
- entity_t entity = ecs_cpp_component_register_explicit (
192
- world, s_id, id, name, type_name<T>(), symbol,
193
- s_size, s_alignment, is_component, existing);
158
+ const bool is_tag = is_empty<T>::value && allow_tag;
194
159
195
- s_id = entity;
160
+ const size_t component_size = is_tag ? 0U : size ();
161
+ const size_t component_alignment = is_tag ? 0U : alignment ();
162
+
163
+ const entity_t entity = ecs_cpp_component_register_explicit (
164
+ world, id, name, type_name<T>(), symbol,
165
+ component_size, component_alignment, is_component, existing);
166
+
167
+ // Component wasn't registered yet, set the values. Register component
168
+ // name as the fully qualified flecs path.
169
+ ecs_cached_component_info_t * inserted =
170
+ ecs_get_or_create_cached_component_info (world, cached_component_index.index );
171
+
172
+ ecs_assert (!!inserted, ECS_INTERNAL_ERROR, NULL );
173
+ ecs_assert (!ecs_is_cached_component_info_valid (inserted), ECS_INTERNAL_ERROR,
174
+ NULL );
175
+
176
+ inserted->component = entity;
177
+ inserted->size = static_cast <ecs_size_t >(component_size);
178
+ inserted->alignment = static_cast <ecs_size_t >(component_alignment);
179
+
180
+ ecs_assert (ecs_is_cached_component_info_valid (inserted), ECS_INTERNAL_ERROR, NULL );
196
181
197
182
// If component is enum type, register constants
198
183
#if FLECS_CPP_ENUM_REFLECTION_SUPPORT
199
184
_::init_enum<T>(world, entity);
200
185
#endif
201
- }
202
186
203
- // By now the identifier must be valid and known with the world.
204
- ecs_assert (s_id != 0 && ecs_exists (world, s_id),
205
- ECS_INTERNAL_ERROR, NULL );
206
-
207
- return s_id;
187
+ return entity;
188
+ }
208
189
}
209
190
210
191
// Obtain a component identifier for implicit component registration. This
@@ -213,29 +194,28 @@ struct cpp_type_impl {
213
194
// Additionally, implicit registration temporarily resets the scope & with
214
195
// state of the world, so that the component is not implicitly created with
215
196
// the scope/with of the code it happens to be first used by.
216
- static id_t id (world_t *world = nullptr , const char *name = nullptr ,
197
+ static id_t id (world_t *world, const char *name = nullptr ,
217
198
bool allow_tag = true )
218
199
{
219
- // If no id has been registered yet, do it now.
220
- if (!registered (world)) {
221
- ecs_entity_t prev_scope = 0 ;
222
- ecs_id_t prev_with = 0 ;
223
-
224
- if (world) {
225
- prev_scope = ecs_set_scope (world, 0 );
226
- prev_with = ecs_set_with (world, 0 );
227
- }
200
+ ecs_assert (world != nullptr , ECS_INTERNAL_ERROR, name);
201
+
202
+ if (const ecs_cached_component_info_t * info = ecs_lookup_cached_component_info (world, cached_component_index.index )) {
203
+ return info->component ;
204
+ } else {
205
+ // If no id has been registered yet, do it now.
206
+ const ecs_entity_t prev_scope = ecs_set_scope (world, 0 );
207
+ const ecs_id_t prev_with = ecs_set_with (world, 0 );
228
208
229
209
// This will register a component id, but will not register
230
210
// lifecycle callbacks.
231
211
bool existing;
232
- id_explicit (world, name, allow_tag, 0 , true , &existing);
212
+ const entity_t id = id_explicit (world, name, allow_tag, 0 , true , &existing);
233
213
234
214
// Register lifecycle callbacks, but only if the component has a
235
215
// size. Components that don't have a size are tags, and tags don't
236
216
// require construction/destruction/copy/move's. */
237
217
if (size () && !existing) {
238
- register_lifecycle_actions<T>(world, s_id );
218
+ register_lifecycle_actions<T>(world, id );
239
219
}
240
220
241
221
if (prev_with) {
@@ -244,62 +224,40 @@ struct cpp_type_impl {
244
224
if (prev_scope) {
245
225
ecs_set_scope (world, prev_scope);
246
226
}
247
- }
248
227
249
- // By now we should have a valid identifier
250
- ecs_assert (s_id != 0 , ECS_INTERNAL_ERROR, NULL );
251
-
252
- return s_id;
228
+ return id;
229
+ }
253
230
}
254
231
255
- // Return the size of a component.
256
- static size_t size () {
257
- ecs_assert (s_id != 0 , ECS_INTERNAL_ERROR, NULL );
258
- return s_size;
232
+ // / Looks the assigned component up in the provided world.
233
+ // / It can happen that the component has not been initialized yet.
234
+ static entity_t lookup (const world_t * world) {
235
+ const ecs_cached_component_info_t * info = ecs_lookup_cached_component_info (world, cached_component_index.index );
236
+ return info ? info->component : 0 ;
259
237
}
260
238
261
- // Return the alignment of a component.
262
- static size_t alignment () {
263
- ecs_assert (s_id != 0 , ECS_INTERNAL_ERROR, NULL );
264
- return s_alignment;
239
+ // Was the component already registered.
240
+ static bool registered (const world_t * world) {
241
+ return !!lookup (world);
265
242
}
266
243
267
- // Was the component already registered.
268
- static bool registered (flecs::world_t *world) {
269
- if (s_reset_count != ecs_cpp_reset_count_get ()) {
270
- reset ();
271
- }
272
- if (s_id == 0 ) {
273
- return false ;
274
- }
275
- if (world && !ecs_exists (world, s_id)) {
276
- return false ;
277
- }
278
- return true ;
244
+ // Return the size of this component.
245
+ static size_t size () {
246
+ return sizeof (T);
279
247
}
280
248
281
- // This function is only used to test cross-translation unit features. No
282
- // code other than test cases should invoke this function.
283
- static void reset () {
284
- s_id = 0 ;
285
- s_size = 0 ;
286
- s_alignment = 0 ;
287
- s_allow_tag = true ;
249
+ // Return the alignment of this component.
250
+ static size_t alignment () {
251
+ return alignof (T);
288
252
}
289
253
290
- static entity_t s_id;
291
- static size_t s_size;
292
- static size_t s_alignment;
293
- static bool s_allow_tag;
294
- static int32_t s_reset_count;
254
+ // Acquire a per instance incremental index for a world-local component index cache.
255
+ static cpp_type_component_cache_index cached_component_index;
295
256
};
296
257
297
258
// Global templated variables that hold component identifier and other info
298
- template <typename T> entity_t cpp_type_impl<T>::s_id;
299
- template <typename T> size_t cpp_type_impl<T>::s_size;
300
- template <typename T> size_t cpp_type_impl<T>::s_alignment;
301
- template <typename T> bool cpp_type_impl<T>::s_allow_tag( true );
302
- template <typename T> int32_t cpp_type_impl<T>::s_reset_count;
259
+ template <typename T>
260
+ cpp_type_component_cache_index cpp_type_impl<T>::cached_component_index;
303
261
304
262
// Front facing class for implicitly registering a component & obtaining
305
263
// static component data
@@ -375,10 +333,9 @@ struct component : untyped_component {
375
333
implicit_name = true ;
376
334
}
377
335
378
- if (_::cpp_type<T>::registered (world)) {
379
- /* Obtain component id. Because the component is already registered,
380
- * this operation does nothing besides returning the existing id */
381
- id = _::cpp_type<T>::id_explicit (world, name, allow_tag, id);
336
+ /* Obtain a registered component id. */
337
+ if (const entity_t registered = _::cpp_type<T>::lookup (world)) {
338
+ id = registered;
382
339
383
340
ecs_cpp_component_validate (world, id, n, _::symbol_name<T>(),
384
341
_::cpp_type<T>::size (),
@@ -504,17 +461,6 @@ struct component : untyped_component {
504
461
}
505
462
};
506
463
507
- /* * Get id currently assigned to component. If no world has registered the
508
- * component yet, this operation will return 0. */
509
- template <typename T>
510
- flecs::entity_t type_id () {
511
- if (_::cpp_type<T>::s_reset_count == ecs_cpp_reset_count_get ()) {
512
- return _::cpp_type<T>::s_id;
513
- } else {
514
- return 0 ;
515
- }
516
- }
517
-
518
464
/* * Reset static component ids.
519
465
* When components are registered their component ids are stored in a static
520
466
* type specific variable. This stored id is passed into component registration
@@ -537,9 +483,9 @@ flecs::entity_t type_id() {
537
483
*
538
484
* \ingroup cpp_components
539
485
*/
540
- inline void reset () {
541
- ecs_cpp_reset_count_inc ();
542
- }
486
+ ECS_DEPRECATED ( " reset was deprecated, world-local component ids "
487
+ " are supported by default now. " )
488
+ inline void reset () { }
543
489
544
490
}
545
491
0 commit comments