@@ -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,22 @@ 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
- bool is_component = true , bool *existing = nullptr )
139
+ bool is_component = true , bool *existing = nullptr , flecs:: id_t s_id = 0 )
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
- }
141
+ ecs_assert (world != nullptr , ECS_INTERNAL_ERROR, name);
173
142
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 );
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
+ ecs_assert (!ecs_stage_is_readonly (ecs_get_world (world)), ECS_INVALID_WHILE_READONLY, name);
182
147
148
+ // If no id has been registered yet for the component (indicating the
149
+ // component has not yet been registered), or if the id does not
150
+ // exists in the world (indicating a multi-world application),
151
+ // register it. */
183
152
const char *symbol = nullptr ;
184
153
if (id) {
185
154
symbol = ecs_get_symbol (world, id);
@@ -188,23 +157,37 @@ struct cpp_type_impl {
188
157
symbol = symbol_name<T>();
189
158
}
190
159
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);
160
+ const bool is_tag = is_empty<T>::value && allow_tag;
161
+
162
+ const size_t component_size = is_tag ? 0U : size ();
163
+ const size_t component_alignment = is_tag ? 0U : alignment ();
194
164
195
- s_id = entity;
165
+ const entity_t entity = ecs_cpp_component_register_explicit (
166
+ world, s_id, id, name, type_name<T>(), symbol,
167
+ component_size, component_alignment, is_component, existing);
168
+
169
+ // Component wasn't registered yet, set the values. Register component
170
+ // name as the fully qualified flecs path.
171
+ ecs_cached_component_info_t * inserted =
172
+ ecs_get_or_create_cached_component_info (world, cached_component_index.index );
173
+
174
+ ecs_assert (!!inserted, ECS_INTERNAL_ERROR, NULL );
175
+ ecs_assert (!ecs_is_cached_component_info_valid (inserted), ECS_INTERNAL_ERROR,
176
+ NULL );
177
+
178
+ inserted->component = entity;
179
+ inserted->size = static_cast <ecs_size_t >(component_size);
180
+ inserted->alignment = static_cast <ecs_size_t >(component_alignment);
181
+
182
+ ecs_assert (ecs_is_cached_component_info_valid (inserted), ECS_INTERNAL_ERROR, NULL );
196
183
197
184
// If component is enum type, register constants
198
185
#if FLECS_CPP_ENUM_REFLECTION_SUPPORT
199
186
_::init_enum<T>(world, entity);
200
187
#endif
201
- }
202
-
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
188
207
- return s_id;
189
+ return entity;
190
+ }
208
191
}
209
192
210
193
// Obtain a component identifier for implicit component registration. This
@@ -213,29 +196,31 @@ struct cpp_type_impl {
213
196
// Additionally, implicit registration temporarily resets the scope & with
214
197
// state of the world, so that the component is not implicitly created with
215
198
// 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 ,
199
+ static id_t id (world_t *world, const char *name = nullptr ,
217
200
bool allow_tag = true )
218
201
{
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
- }
202
+ ecs_assert (world != nullptr , ECS_INTERNAL_ERROR, name);
203
+
204
+ if (const ecs_cached_component_info_t * info = ecs_lookup_cached_component_info (world, cached_component_index.index )) {
205
+ return info->component ;
206
+ } else {
207
+ // If no id has been registered yet, do it now.
208
+ const ecs_entity_t prev_scope = ecs_set_scope (world, 0 );
209
+ const ecs_id_t prev_with = ecs_set_with (world, 0 );
228
210
229
211
// This will register a component id, but will not register
230
212
// lifecycle callbacks.
231
213
bool existing;
232
- id_explicit (world, name, allow_tag, 0 , true , &existing);
214
+ const entity_t id = id_explicit (world, name, allow_tag, 0 , true , &existing);
215
+ ecs_assert (id != 0 , ECS_INTERNAL_ERROR, NULL );
216
+ ecs_assert (ecs_lookup_cached_component_info (world, cached_component_index.index ) != NULL ,
217
+ ECS_INTERNAL_ERROR, NULL );
233
218
234
219
// Register lifecycle callbacks, but only if the component has a
235
220
// size. Components that don't have a size are tags, and tags don't
236
221
// require construction/destruction/copy/move's. */
237
222
if (size () && !existing) {
238
- register_lifecycle_actions<T>(world, s_id );
223
+ register_lifecycle_actions<T>(world, id );
239
224
}
240
225
241
226
if (prev_with) {
@@ -244,62 +229,40 @@ struct cpp_type_impl {
244
229
if (prev_scope) {
245
230
ecs_set_scope (world, prev_scope);
246
231
}
247
- }
248
-
249
- // By now we should have a valid identifier
250
- ecs_assert (s_id != 0 , ECS_INTERNAL_ERROR, NULL );
251
232
252
- return s_id;
233
+ return id;
234
+ }
253
235
}
254
236
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;
237
+ // / Looks the assigned component up in the provided world.
238
+ // / It can happen that the component has not been initialized yet.
239
+ static entity_t lookup (const world_t * world) {
240
+ const ecs_cached_component_info_t * info = ecs_lookup_cached_component_info (world, cached_component_index.index );
241
+ return info ? info->component : 0 ;
259
242
}
260
243
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;
244
+ // Was the component already registered.
245
+ static bool registered (const world_t * world) {
246
+ return !!lookup (world);
265
247
}
266
248
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 ;
249
+ // Return the size of this component.
250
+ static size_t size () {
251
+ return sizeof (T);
279
252
}
280
253
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 ;
254
+ // Return the alignment of this component.
255
+ static size_t alignment () {
256
+ return alignof (T);
288
257
}
289
258
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;
259
+ // Acquire a per instance incremental index for a world-local component index cache.
260
+ static cpp_type_component_cache_index cached_component_index;
295
261
};
296
262
297
263
// 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;
264
+ template <typename T>
265
+ cpp_type_component_cache_index cpp_type_impl<T>::cached_component_index;
303
266
304
267
// Front facing class for implicitly registering a component & obtaining
305
268
// static component data
@@ -375,10 +338,9 @@ struct component : untyped_component {
375
338
implicit_name = true ;
376
339
}
377
340
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);
341
+ /* Obtain a registered component id. */
342
+ if (const entity_t registered = _::cpp_type<T>::lookup (world)) {
343
+ id = registered;
382
344
383
345
ecs_cpp_component_validate (world, id, n, _::symbol_name<T>(),
384
346
_::cpp_type<T>::size (),
@@ -412,8 +374,12 @@ struct component : untyped_component {
412
374
id = ecs_cpp_component_register (world, id, n, _::symbol_name<T>(),
413
375
ECS_SIZEOF (T), ECS_ALIGNOF (T), implicit_name, &existing);
414
376
415
- /* Initialize static component data */
416
- id = _::cpp_type<T>::id_explicit (world, name, allow_tag, id);
377
+ if (!existing) {
378
+ /* Initialize static component data */
379
+ id = _::cpp_type<T>::id_explicit (world, name, allow_tag, id);
380
+ } else {
381
+ ecs_assert (ecs_is_valid (world, id), ECS_INTERNAL_ERROR, NULL );
382
+ }
417
383
418
384
/* Initialize lifecycle actions (ctor, dtor, copy, move) */
419
385
if (_::cpp_type<T>::size () && !existing) {
@@ -504,17 +470,6 @@ struct component : untyped_component {
504
470
}
505
471
};
506
472
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
473
/* * Reset static component ids.
519
474
* When components are registered their component ids are stored in a static
520
475
* type specific variable. This stored id is passed into component registration
@@ -537,9 +492,9 @@ flecs::entity_t type_id() {
537
492
*
538
493
* \ingroup cpp_components
539
494
*/
540
- inline void reset () {
541
- ecs_cpp_reset_count_inc ();
542
- }
495
+ ECS_DEPRECATED ( " reset was deprecated, world-local component ids "
496
+ " are supported by default now. " )
497
+ inline void reset () { }
543
498
544
499
}
545
500
0 commit comments