From b1b43463c8cde01444cf1fc60fafb7d898f1e7f6 Mon Sep 17 00:00:00 2001 From: Sander Mertens Date: Fri, 25 Aug 2023 17:01:18 -0700 Subject: [PATCH] Cleanup internal table APIs --- flecs.c | 917 +++++++++++++++++------------------- flecs.h | 10 + include/flecs/private/vec.h | 10 + src/datastructures/vec.c | 25 + src/entity.c | 9 +- src/storage/table.c | 191 ++------ src/storage/table.h | 119 ++--- src/storage/table_graph.c | 247 ---------- src/storage/table_graph.h | 7 + src/storage/type.c | 226 +++++++++ src/storage/type.h | 63 +++ src/world.c | 30 +- 12 files changed, 872 insertions(+), 982 deletions(-) create mode 100644 src/storage/type.c create mode 100644 src/storage/type.h diff --git a/flecs.c b/flecs.c index 15a1b5ba4..31bfa2e27 100644 --- a/flecs.c +++ b/flecs.c @@ -380,6 +380,71 @@ void flecs_bitset_swap( #ifndef FLECS_TABLE_GRAPH_H #define FLECS_TABLE_GRAPH_H +/** + * @file type.h + * @brief Type utilities + */ + +#ifndef FLECS_TYPE_H +#define FLECS_TYPE_H + +int flecs_type_find_insert( + const ecs_type_t *type, + int32_t offset, + ecs_id_t to_add); + +/* Find location of id in type */ +int flecs_type_find( + const ecs_type_t *type, + ecs_id_t id); + +/* Count number of matching ids */ +int flecs_type_count_matches( + const ecs_type_t *type, + ecs_id_t wildcard, + int32_t offset); + +/* Create type from source type with id */ +int flecs_type_new_with( + ecs_world_t *world, + ecs_type_t *dst, + const ecs_type_t *src, + ecs_id_t with); + +/* Copy type */ +ecs_type_t flecs_type_copy( + ecs_world_t *world, + const ecs_type_t *src); + +/* Create type from source type without ids matching wildcard */ +int flecs_type_new_filtered( + ecs_world_t *world, + ecs_type_t *dst, + const ecs_type_t *src, + ecs_id_t wildcard, + int32_t at); + +/* Create type from source type without id */ +int flecs_type_new_without( + ecs_world_t *world, + ecs_type_t *dst, + const ecs_type_t *src, + ecs_id_t without); + +/* Free type */ +void flecs_type_free( + ecs_world_t *world, + ecs_type_t *type); + +/* Add to type */ +void flecs_type_add( + ecs_world_t *world, + ecs_type_t *type, + ecs_id_t add); + +#endif + + /** Cache of added/removed components for non-trivial edges between tables */ #define ECS_TABLE_DIFF_INIT { .added = {0}} @@ -441,6 +506,11 @@ ecs_table_t *flecs_table_traverse_remove( ecs_id_t *id_ptr, ecs_table_diff_t *diff); +/** Find or create table for a set of components */ +ecs_table_t* flecs_table_find_or_create( + ecs_world_t *world, + ecs_type_t *type); + /* Cleanup incoming and outgoing edges for table */ void flecs_table_clear_edges( ecs_world_t *world, @@ -555,12 +625,6 @@ struct ecs_table_t { ecs_table__t *_; /* Infrequently accessed table metadata */ }; -/* Init table */ -void flecs_table_init( - ecs_world_t *world, - ecs_table_t *table, - ecs_table_t *from); - /* Get table data */ ecs_data_t* flecs_table_data( const ecs_table_t *table); @@ -590,42 +654,11 @@ ecs_entity_t* flecs_table_entities_array( ecs_record_t** flecs_table_records_array( const ecs_table_t *table); -/** Copy type. */ -ecs_type_t flecs_type_copy( - ecs_world_t *world, - const ecs_type_t *src); - -/** Free type. */ -void flecs_type_free( - ecs_world_t *world, - ecs_type_t *type); - -/** Find or create table for a set of components */ -ecs_table_t* flecs_table_find_or_create( - ecs_world_t *world, - ecs_type_t *type); - -/* Initialize columns for data */ -void flecs_table_init_data( - ecs_world_t *world, - ecs_table_t *table, - int32_t column_count); - -/* Clear all entities from a table. */ -void flecs_table_clear_entities( - ecs_world_t *world, - ecs_table_t *table); - -/* Reset a table to its initial state */ -void flecs_table_reset( - ecs_world_t *world, - ecs_table_t *table); - -/* Clear table data. Don't call OnRemove handlers. */ -void flecs_table_clear_data( +/* Init table */ +void flecs_table_init( ecs_world_t *world, ecs_table_t *table, - ecs_data_t *data); + ecs_table_t *from); /* Add a new entry to the table for the specified entity */ int32_t flecs_table_append( @@ -643,10 +676,6 @@ void flecs_table_delete( int32_t index, bool destruct); -/* Make sure table records are in correct table cache list */ -bool flecs_table_records_update_empty( - ecs_table_t *table); - /* Move a row from one table to another */ void flecs_table_move( ecs_world_t *world, @@ -658,21 +687,31 @@ void flecs_table_move( int32_t old_index, bool construct); +/* Merge data of one table into another table */ +void flecs_table_merge( + ecs_world_t *world, + ecs_table_t *new_table, + ecs_table_t *old_table); + +/* Swap rows in table */ +void flecs_table_swap( + ecs_world_t *world, + ecs_table_t *table, + int32_t row_1, + int32_t row_2); + /* Grow table with specified number of records. Populate table with entities, * starting from specified entity id. */ int32_t flecs_table_appendn( ecs_world_t *world, ecs_table_t *table, - ecs_data_t *data, int32_t count, const ecs_entity_t *ids); -/* Set table to a fixed size. Useful for preallocating memory in advance. */ -void flecs_table_set_size( +/* Reset a table to its initial state */ +void flecs_table_reset( ecs_world_t *world, - ecs_table_t *table, - ecs_data_t *data, - int32_t count); + ecs_table_t *table); /* Shrink table to contents */ bool flecs_table_shrink( @@ -688,53 +727,37 @@ int32_t* flecs_table_get_dirty_state( void flecs_init_root_table( ecs_world_t *world); -/* Unset components in table */ -void flecs_table_remove_actions( - ecs_world_t *world, - ecs_table_t *table); - -/* Free table */ -void flecs_table_free( - ecs_world_t *world, - ecs_table_t *table); - -/* Free table */ -void flecs_table_free_type( - ecs_world_t *world, - ecs_table_t *table); - -/* Merge data of one table into another table */ -void flecs_table_merge( - ecs_world_t *world, - ecs_table_t *new_table, - ecs_table_t *old_table, - ecs_data_t *new_data, - ecs_data_t *old_data); - -void flecs_table_swap( - ecs_world_t *world, - ecs_table_t *table, - int32_t row_1, - int32_t row_2); - +/* Mark component column dirty */ void flecs_table_mark_dirty( ecs_world_t *world, ecs_table_t *table, ecs_entity_t component); +/* Keep track of number of traversable entities in table */ +void flecs_table_traversable_add( + ecs_table_t *table, + int32_t value); + +/* Notify table of event (used for propagating observer related flags) */ void flecs_table_notify( ecs_world_t *world, ecs_table_t *table, ecs_table_event_t *event); +/* Clear entities from a table. */ +void flecs_table_clear_entities( + ecs_world_t *world, + ecs_table_t *table); + +/* Clear entities from a table, delete entities from entity index. */ void flecs_table_delete_entities( ecs_world_t *world, ecs_table_t *table); -/* Increase observer count of table */ -void flecs_table_traversable_add( - ecs_table_t *table, - int32_t value); +/* Free table */ +void flecs_table_free( + ecs_world_t *world, + ecs_table_t *table); #endif @@ -3859,7 +3882,7 @@ void flecs_commit( ecs_world_t *world, ecs_entity_t entity, ecs_record_t *record, - ecs_table_t *dst_table, + ecs_table_t *dst_table, ecs_table_diff_t *diff, bool construct, ecs_flags32_t evt_flags) @@ -3961,7 +3984,7 @@ const ecs_entity_t* flecs_bulk_new( } ecs_data_t *data = flecs_table_data(table); - int32_t row = flecs_table_appendn(world, table, data, count, entities); + int32_t row = flecs_table_appendn(world, table, count, entities); /* Update entity index. */ int i; @@ -5455,8 +5478,7 @@ void flecs_remove_from_table( ecs_log_pop_3(); } - flecs_table_merge(world, dst_table, table, - flecs_table_data(dst_table), flecs_table_data(table)); + flecs_table_merge(world, dst_table, table); } } @@ -6711,7 +6733,7 @@ void flecs_flatten( ecs_table_diff_t td; flecs_table_diff_build_noalloc(&diff, &td); flecs_notify_on_remove(world, table, NULL, 0, count, &td.removed); - flecs_table_merge(world, dst, table, dst->data, table->data); + flecs_table_merge(world, dst, table); flecs_notify_on_add(world, dst, NULL, dst_count, count, &td.added, 0); flecs_table_diff_builder_fini(world, &diff); @@ -21364,14 +21386,6 @@ void flecs_clean_tables( flecs_table_free(world, t); } - /* Free table types separately so that if application destructors rely on - * a type it's still valid. */ - for (i = 1; i < count; i ++) { - ecs_table_t *t = flecs_sparse_get_dense_t(&world->store.tables, - ecs_table_t, i); - flecs_table_free_type(world, t); - } - /* Clear the root table */ if (count) { flecs_table_reset(world, &world->store.root); @@ -22074,7 +22088,10 @@ void flecs_fini_unset_tables( for (i = 1; i < count; i ++) { ecs_table_t *table = flecs_sparse_get_dense_t(tables, ecs_table_t, i); - flecs_table_remove_actions(world, table); + int32_t count = ecs_table_count(table); + if (count) { + flecs_notify_on_remove(world, table, NULL, 0, count, &table->type); + } } } @@ -22713,6 +22730,23 @@ void flecs_process_empty_queries( flecs_defer_end(world, &world->stages[0]); } +static +bool flecs_table_records_update_empty( + ecs_table_t *table) +{ + bool result = false; + bool is_empty = ecs_table_count(table) == 0; + + int32_t i, count = table->_->record_count; + for (i = 0; i < count; i ++) { + ecs_table_record_t *tr = &table->_->records[i]; + ecs_table_cache_t *cache = tr->hdr.cache; + result |= ecs_table_cache_set_empty(cache, table, is_empty); + } + + return result; +} + /** Walk over tables that had a state change which requires bookkeeping */ void flecs_process_pending_tables( const ecs_world_t *world_r) @@ -39583,6 +39617,31 @@ void* ecs_vec_grow( return ECS_ELEM(v->array, size, count); } +void ecs_vec_merge( + struct ecs_allocator_t *allocator, + ecs_vec_t *dst, + ecs_vec_t *src, + ecs_size_t size) +{ + int32_t dst_count = dst->count; + + if (!dst_count) { + ecs_vec_fini(allocator, dst, size); + *dst = *src; + src->array = NULL; + src->count = 0; + src->size = 0; + } else { + int32_t src_count = src->count; + ecs_vec_set_count(allocator, dst, size, dst_count + src_count); + + void *dst_ptr = ECS_ELEM(dst->array, size, dst_count); + void *src_ptr = src->array; + ecs_os_memcpy(dst_ptr, src_ptr, size * src_count); + ecs_vec_fini(allocator, src, size); + } +} + void* ecs_vec_append( ecs_allocator_t *allocator, ecs_vec_t *v, @@ -40804,6 +40863,7 @@ void flecs_table_init_columns( } /* Initialize table storage */ +static void flecs_table_init_data( ecs_world_t *world, ecs_table_t *table, @@ -41230,6 +41290,7 @@ void flecs_table_init( table->column_map = flecs_walloc_n(world, int32_t, dst_count + column_count); } + flecs_table_init_data(world, table, column_count); if (table->flags & EcsTableHasName) { @@ -41302,22 +41363,6 @@ void flecs_table_add_trigger_flags( } } -/* Invoke OnRemove observers for all entities in table. Useful during table - * deletion or when clearing entities from a table. */ -static -void flecs_table_notify_on_remove( - ecs_world_t *world, - ecs_table_t *table, - ecs_data_t *data) -{ - ecs_assert(table != NULL, ECS_INTERNAL_ERROR, NULL); - ecs_assert(data != NULL, ECS_INTERNAL_ERROR, NULL); - int32_t count = data->entities.count; - if (count) { - flecs_notify_on_remove(world, table, NULL, 0, count, &table->type); - } -} - /* Invoke type hook for entities in table */ static void flecs_table_invoke_hook( @@ -41422,7 +41467,6 @@ static void flecs_table_dtor_all( ecs_world_t *world, ecs_table_t *table, - ecs_data_t *data, int32_t row, int32_t count, bool update_entity_index, @@ -41431,7 +41475,8 @@ void flecs_table_dtor_all( /* Can't delete and not update the entity index */ ecs_assert(!is_delete || update_entity_index, ECS_INTERNAL_ERROR, NULL); - int32_t ids_count = table->data->column_count; + ecs_data_t *data = flecs_table_data(table); + int32_t ids_count = data->column_count; ecs_record_t **records = data->records.array; ecs_entity_t *entities = data->entities.array; int32_t i, c, end = row + count; @@ -41531,25 +41576,23 @@ static void flecs_table_fini_data( ecs_world_t *world, ecs_table_t *table, - ecs_data_t *data, bool do_on_remove, bool update_entity_index, bool is_delete, bool deactivate) { ecs_assert(!table->_->lock, ECS_LOCKED_STORAGE, NULL); - - if (!data) { - return; - } - - if (do_on_remove) { - flecs_table_notify_on_remove(world, table, data); - } + ecs_assert(table != NULL, ECS_INTERNAL_ERROR, NULL); + ecs_data_t *data = table->data; + ecs_assert(data != NULL, ECS_INTERNAL_ERROR, NULL); int32_t count = ecs_table_count(table); if (count) { - flecs_table_dtor_all(world, table, data, 0, count, + if (do_on_remove) { + flecs_notify_on_remove(world, table, NULL, 0, count, &table->type); + } + + flecs_table_dtor_all(world, table, 0, count, update_entity_index, is_delete); } @@ -41593,20 +41636,20 @@ void flecs_table_fini_data( } /* Cleanup, no OnRemove, don't update entity index, don't deactivate table */ +static void flecs_table_clear_data( ecs_world_t *world, - ecs_table_t *table, - ecs_data_t *data) + ecs_table_t *table) { - flecs_table_fini_data(world, table, data, false, false, false, false); + flecs_table_fini_data(world, table, false, false, false, false); } -/* Cleanup, run OnRemove, clear entity index, deactivate table */ +/* Cleanup, run OnRemove, clear entity index (don't delete), deactivate table */ void flecs_table_clear_entities( ecs_world_t *world, ecs_table_t *table) { - flecs_table_fini_data(world, table, table->data, true, true, false, true); + flecs_table_fini_data(world, table, true, true, false, true); } /* Cleanup, run OnRemove, delete from entity index, deactivate table */ @@ -41614,17 +41657,7 @@ void flecs_table_delete_entities( ecs_world_t *world, ecs_table_t *table) { - flecs_table_fini_data(world, table, table->data, true, true, true, true); -} - -/* Unset all components in table. This function is called before a table is - * deleted, and invokes all UnSet handlers, if any */ -void flecs_table_remove_actions( - ecs_world_t *world, - ecs_table_t *table) -{ - (void)world; - flecs_table_notify_on_remove(world, table, table->data); + flecs_table_fini_data(world, table, true, true, true, true); } /* Free table resources. */ @@ -41632,6 +41665,7 @@ void flecs_table_free( ecs_world_t *world, ecs_table_t *table) { + ecs_allocator_t *a = &world->allocator; bool is_root = table == &world->store.root; ecs_assert(!table->_->lock, ECS_LOCKED_STORAGE, NULL); ecs_assert(is_root || table->id != 0, ECS_INTERNAL_ERROR, NULL); @@ -41663,7 +41697,7 @@ void flecs_table_free( world->info.empty_table_count -= (ecs_table_count(table) == 0); /* Cleanup data, no OnRemove, delete from entity index, don't deactivate */ - flecs_table_fini_data(world, table, table->data, false, true, true, false); + flecs_table_fini_data(world, table, false, true, true, false); flecs_table_clear_edges(world, table); if (!is_root) { @@ -41693,26 +41727,17 @@ void flecs_table_free( world->info.trivial_table_count -= !(table->flags & EcsTableIsComplex); } - flecs_free_t(&world->allocator, ecs_table__t, table->_); + flecs_free_t(a, ecs_table__t, table->_); + flecs_wfree_n(world, ecs_id_t, table->type.count, table->type.array); if (!(world->flags & EcsWorldFini)) { ecs_assert(!is_root, ECS_INTERNAL_ERROR, NULL); - flecs_table_free_type(world, table); flecs_sparse_remove_t(&world->store.tables, ecs_table_t, table->id); } ecs_log_pop_2(); } -/* Free table type. Do this separately from freeing the table as types can be - * in use by application destructors. */ -void flecs_table_free_type( - ecs_world_t *world, - ecs_table_t *table) -{ - flecs_wfree_n(world, ecs_id_t, table->type.count, table->type.array); -} - /* Reset a table to its initial state. */ void flecs_table_reset( ecs_world_t *world, @@ -41945,19 +41970,21 @@ void* flecs_table_grow_column( } /* Grow all data structures in a table */ -static -int32_t flecs_table_grow_data( +int32_t flecs_table_appendn( ecs_world_t *world, ecs_table_t *table, - ecs_data_t *data, int32_t to_add, - int32_t size, const ecs_entity_t *ids) { ecs_assert(table != NULL, ECS_INTERNAL_ERROR, NULL); + ecs_assert(!table->_->lock, ECS_LOCKED_STORAGE, NULL); + ecs_data_t *data = table->data; ecs_assert(data != NULL, ECS_INTERNAL_ERROR, NULL); + flecs_table_check_sanity(table); + int32_t cur_count = ecs_table_count(table); + int32_t size = to_add + cur_count; int32_t column_count = table->data->column_count; /* Add record to record ptr array */ @@ -42008,6 +42035,8 @@ int32_t flecs_table_grow_data( flecs_table_set_empty(world, table); } + flecs_table_check_sanity(table); + /* Return index of first added entity */ return cur_count; } @@ -42417,45 +42446,6 @@ void flecs_table_move( flecs_table_check_sanity(src_table); } -/* Append n entities to table */ -int32_t flecs_table_appendn( - ecs_world_t *world, - ecs_table_t *table, - ecs_data_t *data, - int32_t to_add, - const ecs_entity_t *ids) -{ - ecs_assert(!table->_->lock, ECS_LOCKED_STORAGE, NULL); - - flecs_table_check_sanity(table); - int32_t cur_count = ecs_table_count(table); - int32_t result = flecs_table_grow_data( - world, table, data, to_add, cur_count + to_add, ids); - flecs_table_check_sanity(table); - - return result; -} - -/* Set allocated table size */ -void flecs_table_set_size( - ecs_world_t *world, - ecs_table_t *table, - ecs_data_t *data, - int32_t size) -{ - ecs_assert(table != NULL, ECS_LOCKED_STORAGE, NULL); - ecs_assert(!table->_->lock, ECS_LOCKED_STORAGE, NULL); - - flecs_table_check_sanity(table); - - int32_t cur_count = ecs_table_count(table); - - if (cur_count < size) { - flecs_table_grow_data(world, table, data, 0, size, NULL); - flecs_table_check_sanity(table); - } -} - /* Shrink table storage to fit number of entities */ bool flecs_table_shrink( ecs_world_t *world, @@ -42579,40 +42569,6 @@ void flecs_table_swap( flecs_table_check_sanity(table); } -static -void flecs_table_merge_vec( - ecs_world_t *world, - ecs_vec_t *dst, - ecs_vec_t *src, - int32_t size, - int32_t elem_size) -{ - int32_t dst_count = dst->count; - - if (!dst_count) { - ecs_vec_fini(&world->allocator, dst, size); - *dst = *src; - src->array = NULL; - src->count = 0; - src->size = 0; - } else { - int32_t src_count = src->count; - - if (elem_size) { - ecs_vec_set_size(&world->allocator, - dst, size, elem_size); - } - ecs_vec_set_count(&world->allocator, - dst, size, dst_count + src_count); - - void *dst_ptr = ECS_ELEM(dst->array, size, dst_count); - void *src_ptr = src->array; - ecs_os_memcpy(dst_ptr, src_ptr, size * src_count); - - ecs_vec_fini(&world->allocator, src, size); - } -} - /* Merge data from one table column into other table column */ static void flecs_table_merge_column( @@ -42676,18 +42632,14 @@ void flecs_table_merge_data( return; } - /* Merge entities */ - flecs_table_merge_vec(world, &dst_data->entities, &src_data->entities, - ECS_SIZEOF(ecs_entity_t), 0); + /* Merge entities & records vectors */ + ecs_allocator_t *a = &world->allocator; + ecs_vec_merge_t(a, &dst_data->entities, &src_data->entities, ecs_entity_t); ecs_assert(dst_data->entities.count == src_count + dst_count, ECS_INTERNAL_ERROR, NULL); - int32_t column_size = dst_data->entities.size; - ecs_allocator_t *a = &world->allocator; - - /* Merge record pointers */ - flecs_table_merge_vec(world, &dst_data->records, &src_data->records, - ECS_SIZEOF(ecs_record_t*), 0); + ecs_vec_merge_t(a, &dst_data->records, &src_data->records, ecs_record_t*); + int32_t column_size = dst_data->entities.size; for (; (i_new < dst_column_count) && (i_old < src_column_count); ) { ecs_column_t *dst_column = &dst_columns[i_new]; ecs_column_t *src_column = &src_columns[i_old]; @@ -42714,7 +42666,8 @@ void flecs_table_merge_data( } } - flecs_table_move_bitset_columns(dst_table, dst_count, src_table, 0, src_count, true); + flecs_table_move_bitset_columns( + dst_table, dst_count, src_table, 0, src_count, true); /* Initialize remaining columns */ for (; i_new < dst_column_count; i_new ++) { @@ -42743,9 +42696,7 @@ void flecs_table_merge_data( void flecs_table_merge( ecs_world_t *world, ecs_table_t *dst_table, - ecs_table_t *src_table, - ecs_data_t *dst_data, - ecs_data_t *src_data) + ecs_table_t *src_table) { ecs_assert(src_table != NULL, ECS_INTERNAL_ERROR, NULL); ecs_assert(!src_table->_->lock, ECS_LOCKED_STORAGE, NULL); @@ -42754,10 +42705,15 @@ void flecs_table_merge( flecs_table_check_sanity(dst_table); bool move_data = false; + + ecs_data_t *dst_data = dst_table->data; + ecs_data_t *src_data = src_table->data; + ecs_assert(dst_data != NULL, ECS_INTERNAL_ERROR, NULL); + ecs_assert(src_data != NULL, ECS_INTERNAL_ERROR, NULL); /* If there is nothing to merge to, just clear the old table */ if (!dst_table) { - flecs_table_clear_data(world, src_table, src_data); + flecs_table_clear_data(world, src_table); flecs_table_check_sanity(src_table); return; } else { @@ -43439,237 +43395,6 @@ void flecs_table_hashmap_init( flecs_type_hash, flecs_type_compare, &world->allocator); } -/* Find location where to insert id into type */ -static -int flecs_type_find_insert( - const ecs_type_t *type, - int32_t offset, - ecs_id_t to_add) -{ - ecs_id_t *array = type->array; - int32_t i, count = type->count; - - for (i = offset; i < count; i ++) { - ecs_id_t id = array[i]; - if (id == to_add) { - return -1; - } - if (id > to_add) { - return i; - } - } - return i; -} - -/* Find location of id in type */ -static -int flecs_type_find( - const ecs_type_t *type, - ecs_id_t id) -{ - ecs_id_t *array = type->array; - int32_t i, count = type->count; - - for (i = 0; i < count; i ++) { - ecs_id_t cur = array[i]; - if (ecs_id_match(cur, id)) { - return i; - } - if (cur > id) { - return -1; - } - } - - return -1; -} - -/* Count number of matching ids */ -static -int flecs_type_count_matches( - const ecs_type_t *type, - ecs_id_t wildcard, - int32_t offset) -{ - ecs_id_t *array = type->array; - int32_t i = offset, count = type->count; - - for (; i < count; i ++) { - ecs_id_t cur = array[i]; - if (!ecs_id_match(cur, wildcard)) { - break; - } - } - - return i - offset; -} - -/* Create type from source type with id */ -static -int flecs_type_new_with( - ecs_world_t *world, - ecs_type_t *dst, - const ecs_type_t *src, - ecs_id_t with) -{ - ecs_id_t *src_array = src->array; - int32_t at = flecs_type_find_insert(src, 0, with); - if (at == -1) { - return -1; - } - - int32_t dst_count = src->count + 1; - ecs_id_t *dst_array = flecs_walloc_n(world, ecs_id_t, dst_count); - dst->count = dst_count; - dst->array = dst_array; - - if (at) { - ecs_os_memcpy_n(dst_array, src_array, ecs_id_t, at); - } - - int32_t remain = src->count - at; - if (remain) { - ecs_os_memcpy_n(&dst_array[at + 1], &src_array[at], ecs_id_t, remain); - } - - dst_array[at] = with; - - return 0; -} - -/* Create type from source type without ids matching wildcard */ -static -int flecs_type_new_filtered( - ecs_world_t *world, - ecs_type_t *dst, - const ecs_type_t *src, - ecs_id_t wildcard, - int32_t at) -{ - *dst = flecs_type_copy(world, src); - ecs_id_t *dst_array = dst->array; - ecs_id_t *src_array = src->array; - if (at) { - ecs_assert(dst_array != NULL, ECS_INTERNAL_ERROR, NULL); - ecs_os_memcpy_n(dst_array, src_array, ecs_id_t, at); - } - - int32_t i = at + 1, w = at, count = src->count; - for (; i < count; i ++) { - ecs_id_t id = src_array[i]; - if (!ecs_id_match(id, wildcard)) { - dst_array[w] = id; - w ++; - } - } - - dst->count = w; - if (w != count) { - dst->array = flecs_wrealloc_n(world, ecs_id_t, w, count, dst->array); - } - - return 0; -} - -/* Create type from source type without id */ -static -int flecs_type_new_without( - ecs_world_t *world, - ecs_type_t *dst, - const ecs_type_t *src, - ecs_id_t without) -{ - ecs_id_t *src_array = src->array; - int32_t count = 1, at = flecs_type_find(src, without); - if (at == -1) { - return -1; - } - - int32_t src_count = src->count; - if (src_count == 1) { - dst->array = NULL; - dst->count = 0; - return 0; - } - - if (ecs_id_is_wildcard(without)) { - if (ECS_IS_PAIR(without)) { - ecs_entity_t r = ECS_PAIR_FIRST(without); - ecs_entity_t o = ECS_PAIR_SECOND(without); - if (r == EcsWildcard && o != EcsWildcard) { - return flecs_type_new_filtered(world, dst, src, without, at); - } - } - count += flecs_type_count_matches(src, without, at + 1); - } - - int32_t dst_count = src_count - count; - dst->count = dst_count; - if (!dst_count) { - dst->array = NULL; - return 0; - } - - ecs_id_t *dst_array = flecs_walloc_n(world, ecs_id_t, dst_count); - dst->array = dst_array; - - if (at) { - ecs_os_memcpy_n(dst_array, src_array, ecs_id_t, at); - } - - int32_t remain = dst_count - at; - if (remain) { - ecs_os_memcpy_n( - &dst_array[at], &src_array[at + count], ecs_id_t, remain); - } - - return 0; -} - -/* Copy type */ -ecs_type_t flecs_type_copy( - ecs_world_t *world, - const ecs_type_t *src) -{ - int32_t src_count = src->count; - if (!src_count) { - return (ecs_type_t){ 0 }; - } - - ecs_id_t *ids = flecs_walloc_n(world, ecs_id_t, src_count); - ecs_os_memcpy_n(ids, src->array, ecs_id_t, src_count); - return (ecs_type_t) { - .array = ids, - .count = src_count - }; -} - -/* Free type */ -void flecs_type_free( - ecs_world_t *world, - ecs_type_t *type) -{ - int32_t count = type->count; - if (count) { - flecs_wfree_n(world, ecs_id_t, type->count, type->array); - } -} - -/* Add to type */ -static -void flecs_type_add( - ecs_world_t *world, - ecs_type_t *type, - ecs_id_t add) -{ - ecs_type_t new_type; - int res = flecs_type_new_with(world, &new_type, type, add); - if (res != -1) { - flecs_type_free(world, type); - type->array = new_type.array; - type->count = new_type.count; - } -} - /* Graph edge utilities */ void flecs_table_diff_builder_init( @@ -43883,22 +43608,6 @@ void flecs_table_init_node( flecs_table_init_edges(&node->remove); } -bool flecs_table_records_update_empty( - ecs_table_t *table) -{ - bool result = false; - bool is_empty = ecs_table_count(table) == 0; - - int32_t i, count = table->_->record_count; - for (i = 0; i < count; i ++) { - ecs_table_record_t *tr = &table->_->records[i]; - ecs_table_cache_t *cache = tr->hdr.cache; - result |= ecs_table_cache_set_empty(cache, table, is_empty); - } - - return result; -} - static void flecs_init_table( ecs_world_t *world, @@ -44565,6 +44274,232 @@ ecs_table_t* ecs_table_find( return flecs_table_ensure(world, &type, false, NULL); } + + +/* Find location where to insert id into type */ +int flecs_type_find_insert( + const ecs_type_t *type, + int32_t offset, + ecs_id_t to_add) +{ + ecs_id_t *array = type->array; + int32_t i, count = type->count; + + for (i = offset; i < count; i ++) { + ecs_id_t id = array[i]; + if (id == to_add) { + return -1; + } + if (id > to_add) { + return i; + } + } + return i; +} + +/* Find location of id in type */ +int flecs_type_find( + const ecs_type_t *type, + ecs_id_t id) +{ + ecs_id_t *array = type->array; + int32_t i, count = type->count; + + for (i = 0; i < count; i ++) { + ecs_id_t cur = array[i]; + if (ecs_id_match(cur, id)) { + return i; + } + if (cur > id) { + return -1; + } + } + + return -1; +} + +/* Count number of matching ids */ +int flecs_type_count_matches( + const ecs_type_t *type, + ecs_id_t wildcard, + int32_t offset) +{ + ecs_id_t *array = type->array; + int32_t i = offset, count = type->count; + + for (; i < count; i ++) { + ecs_id_t cur = array[i]; + if (!ecs_id_match(cur, wildcard)) { + break; + } + } + + return i - offset; +} + +/* Create type from source type with id */ +int flecs_type_new_with( + ecs_world_t *world, + ecs_type_t *dst, + const ecs_type_t *src, + ecs_id_t with) +{ + ecs_id_t *src_array = src->array; + int32_t at = flecs_type_find_insert(src, 0, with); + if (at == -1) { + return -1; + } + + int32_t dst_count = src->count + 1; + ecs_id_t *dst_array = flecs_walloc_n(world, ecs_id_t, dst_count); + dst->count = dst_count; + dst->array = dst_array; + + if (at) { + ecs_os_memcpy_n(dst_array, src_array, ecs_id_t, at); + } + + int32_t remain = src->count - at; + if (remain) { + ecs_os_memcpy_n(&dst_array[at + 1], &src_array[at], ecs_id_t, remain); + } + + dst_array[at] = with; + + return 0; +} + +/* Copy type */ +ecs_type_t flecs_type_copy( + ecs_world_t *world, + const ecs_type_t *src) +{ + int32_t src_count = src->count; + if (!src_count) { + return (ecs_type_t){ 0 }; + } + + ecs_id_t *ids = flecs_walloc_n(world, ecs_id_t, src_count); + ecs_os_memcpy_n(ids, src->array, ecs_id_t, src_count); + return (ecs_type_t) { + .array = ids, + .count = src_count + }; +} + +/* Create type from source type without ids matching wildcard */ +int flecs_type_new_filtered( + ecs_world_t *world, + ecs_type_t *dst, + const ecs_type_t *src, + ecs_id_t wildcard, + int32_t at) +{ + *dst = flecs_type_copy(world, src); + ecs_id_t *dst_array = dst->array; + ecs_id_t *src_array = src->array; + if (at) { + ecs_assert(dst_array != NULL, ECS_INTERNAL_ERROR, NULL); + ecs_os_memcpy_n(dst_array, src_array, ecs_id_t, at); + } + + int32_t i = at + 1, w = at, count = src->count; + for (; i < count; i ++) { + ecs_id_t id = src_array[i]; + if (!ecs_id_match(id, wildcard)) { + dst_array[w] = id; + w ++; + } + } + + dst->count = w; + if (w != count) { + dst->array = flecs_wrealloc_n(world, ecs_id_t, w, count, dst->array); + } + + return 0; +} + +/* Create type from source type without id */ +int flecs_type_new_without( + ecs_world_t *world, + ecs_type_t *dst, + const ecs_type_t *src, + ecs_id_t without) +{ + ecs_id_t *src_array = src->array; + int32_t count = 1, at = flecs_type_find(src, without); + if (at == -1) { + return -1; + } + + int32_t src_count = src->count; + if (src_count == 1) { + dst->array = NULL; + dst->count = 0; + return 0; + } + + if (ecs_id_is_wildcard(without)) { + if (ECS_IS_PAIR(without)) { + ecs_entity_t r = ECS_PAIR_FIRST(without); + ecs_entity_t o = ECS_PAIR_SECOND(without); + if (r == EcsWildcard && o != EcsWildcard) { + return flecs_type_new_filtered(world, dst, src, without, at); + } + } + count += flecs_type_count_matches(src, without, at + 1); + } + + int32_t dst_count = src_count - count; + dst->count = dst_count; + if (!dst_count) { + dst->array = NULL; + return 0; + } + + ecs_id_t *dst_array = flecs_walloc_n(world, ecs_id_t, dst_count); + dst->array = dst_array; + + if (at) { + ecs_os_memcpy_n(dst_array, src_array, ecs_id_t, at); + } + + int32_t remain = dst_count - at; + if (remain) { + ecs_os_memcpy_n( + &dst_array[at], &src_array[at + count], ecs_id_t, remain); + } + + return 0; +} + +/* Free type */ +void flecs_type_free( + ecs_world_t *world, + ecs_type_t *type) +{ + int32_t count = type->count; + if (count) { + flecs_wfree_n(world, ecs_id_t, type->count, type->array); + } +} + +/* Add to type */ +void flecs_type_add( + ecs_world_t *world, + ecs_type_t *type, + ecs_id_t add) +{ + ecs_type_t new_type; + int res = flecs_type_new_with(world, &new_type, type, add); + if (res != -1) { + flecs_type_free(world, type); + type->array = new_type.array; + type->count = new_type.count; + } +} + /** * @file expr/deserialize.c * @brief Deserialize flecs string format into (component) values. diff --git a/flecs.h b/flecs.h index c80fc37d1..055a3c163 100644 --- a/flecs.h +++ b/flecs.h @@ -1063,6 +1063,16 @@ void* ecs_vec_grow( #define ecs_vec_grow_t(allocator, vec, T, elem_count) \ ecs_vec_grow(allocator, vec, ECS_SIZEOF(T), elem_count) +FLECS_API +void ecs_vec_merge( + struct ecs_allocator_t *allocator, + ecs_vec_t *dst, + ecs_vec_t *src, + ecs_size_t size); + +#define ecs_vec_merge_t(allocator, dst, src, T) \ + ecs_vec_merge(allocator, dst, src, ECS_SIZEOF(T)) + FLECS_API int32_t ecs_vec_count( const ecs_vec_t *vec); diff --git a/include/flecs/private/vec.h b/include/flecs/private/vec.h index 27842d930..e91cb32da 100644 --- a/include/flecs/private/vec.h +++ b/include/flecs/private/vec.h @@ -160,6 +160,16 @@ void* ecs_vec_grow( #define ecs_vec_grow_t(allocator, vec, T, elem_count) \ ecs_vec_grow(allocator, vec, ECS_SIZEOF(T), elem_count) +FLECS_API +void ecs_vec_merge( + struct ecs_allocator_t *allocator, + ecs_vec_t *dst, + ecs_vec_t *src, + ecs_size_t size); + +#define ecs_vec_merge_t(allocator, dst, src, T) \ + ecs_vec_merge(allocator, dst, src, ECS_SIZEOF(T)) + FLECS_API int32_t ecs_vec_count( const ecs_vec_t *vec); diff --git a/src/datastructures/vec.c b/src/datastructures/vec.c index 2458a1cec..4c78c72a9 100644 --- a/src/datastructures/vec.c +++ b/src/datastructures/vec.c @@ -221,6 +221,31 @@ void* ecs_vec_grow( return ECS_ELEM(v->array, size, count); } +void ecs_vec_merge( + struct ecs_allocator_t *allocator, + ecs_vec_t *dst, + ecs_vec_t *src, + ecs_size_t size) +{ + int32_t dst_count = dst->count; + + if (!dst_count) { + ecs_vec_fini(allocator, dst, size); + *dst = *src; + src->array = NULL; + src->count = 0; + src->size = 0; + } else { + int32_t src_count = src->count; + ecs_vec_set_count(allocator, dst, size, dst_count + src_count); + + void *dst_ptr = ECS_ELEM(dst->array, size, dst_count); + void *src_ptr = src->array; + ecs_os_memcpy(dst_ptr, src_ptr, size * src_count); + ecs_vec_fini(allocator, src, size); + } +} + void* ecs_vec_append( ecs_allocator_t *allocator, ecs_vec_t *v, diff --git a/src/entity.c b/src/entity.c index ca85c1e08..eccf1182c 100644 --- a/src/entity.c +++ b/src/entity.c @@ -664,7 +664,7 @@ void flecs_commit( ecs_world_t *world, ecs_entity_t entity, ecs_record_t *record, - ecs_table_t *dst_table, + ecs_table_t *dst_table, ecs_table_diff_t *diff, bool construct, ecs_flags32_t evt_flags) @@ -766,7 +766,7 @@ const ecs_entity_t* flecs_bulk_new( } ecs_data_t *data = flecs_table_data(table); - int32_t row = flecs_table_appendn(world, table, data, count, entities); + int32_t row = flecs_table_appendn(world, table, count, entities); /* Update entity index. */ int i; @@ -2260,8 +2260,7 @@ void flecs_remove_from_table( ecs_log_pop_3(); } - flecs_table_merge(world, dst_table, table, - flecs_table_data(dst_table), flecs_table_data(table)); + flecs_table_merge(world, dst_table, table); } } @@ -3516,7 +3515,7 @@ void flecs_flatten( ecs_table_diff_t td; flecs_table_diff_build_noalloc(&diff, &td); flecs_notify_on_remove(world, table, NULL, 0, count, &td.removed); - flecs_table_merge(world, dst, table, dst->data, table->data); + flecs_table_merge(world, dst, table); flecs_notify_on_add(world, dst, NULL, dst_count, count, &td.added, 0); flecs_table_diff_builder_fini(world, &diff); diff --git a/src/storage/table.c b/src/storage/table.c index d3570e59b..520c1f2fe 100644 --- a/src/storage/table.c +++ b/src/storage/table.c @@ -171,6 +171,7 @@ void flecs_table_init_columns( } /* Initialize table storage */ +static void flecs_table_init_data( ecs_world_t *world, ecs_table_t *table, @@ -597,6 +598,7 @@ void flecs_table_init( table->column_map = flecs_walloc_n(world, int32_t, dst_count + column_count); } + flecs_table_init_data(world, table, column_count); if (table->flags & EcsTableHasName) { @@ -669,22 +671,6 @@ void flecs_table_add_trigger_flags( } } -/* Invoke OnRemove observers for all entities in table. Useful during table - * deletion or when clearing entities from a table. */ -static -void flecs_table_notify_on_remove( - ecs_world_t *world, - ecs_table_t *table, - ecs_data_t *data) -{ - ecs_assert(table != NULL, ECS_INTERNAL_ERROR, NULL); - ecs_assert(data != NULL, ECS_INTERNAL_ERROR, NULL); - int32_t count = data->entities.count; - if (count) { - flecs_notify_on_remove(world, table, NULL, 0, count, &table->type); - } -} - /* Invoke type hook for entities in table */ static void flecs_table_invoke_hook( @@ -789,7 +775,6 @@ static void flecs_table_dtor_all( ecs_world_t *world, ecs_table_t *table, - ecs_data_t *data, int32_t row, int32_t count, bool update_entity_index, @@ -798,7 +783,8 @@ void flecs_table_dtor_all( /* Can't delete and not update the entity index */ ecs_assert(!is_delete || update_entity_index, ECS_INTERNAL_ERROR, NULL); - int32_t ids_count = table->data->column_count; + ecs_data_t *data = flecs_table_data(table); + int32_t ids_count = data->column_count; ecs_record_t **records = data->records.array; ecs_entity_t *entities = data->entities.array; int32_t i, c, end = row + count; @@ -898,25 +884,23 @@ static void flecs_table_fini_data( ecs_world_t *world, ecs_table_t *table, - ecs_data_t *data, bool do_on_remove, bool update_entity_index, bool is_delete, bool deactivate) { ecs_assert(!table->_->lock, ECS_LOCKED_STORAGE, NULL); - - if (!data) { - return; - } - - if (do_on_remove) { - flecs_table_notify_on_remove(world, table, data); - } + ecs_assert(table != NULL, ECS_INTERNAL_ERROR, NULL); + ecs_data_t *data = table->data; + ecs_assert(data != NULL, ECS_INTERNAL_ERROR, NULL); int32_t count = ecs_table_count(table); if (count) { - flecs_table_dtor_all(world, table, data, 0, count, + if (do_on_remove) { + flecs_notify_on_remove(world, table, NULL, 0, count, &table->type); + } + + flecs_table_dtor_all(world, table, 0, count, update_entity_index, is_delete); } @@ -960,20 +944,20 @@ void flecs_table_fini_data( } /* Cleanup, no OnRemove, don't update entity index, don't deactivate table */ +static void flecs_table_clear_data( ecs_world_t *world, - ecs_table_t *table, - ecs_data_t *data) + ecs_table_t *table) { - flecs_table_fini_data(world, table, data, false, false, false, false); + flecs_table_fini_data(world, table, false, false, false, false); } -/* Cleanup, run OnRemove, clear entity index, deactivate table */ +/* Cleanup, run OnRemove, clear entity index (don't delete), deactivate table */ void flecs_table_clear_entities( ecs_world_t *world, ecs_table_t *table) { - flecs_table_fini_data(world, table, table->data, true, true, false, true); + flecs_table_fini_data(world, table, true, true, false, true); } /* Cleanup, run OnRemove, delete from entity index, deactivate table */ @@ -981,17 +965,7 @@ void flecs_table_delete_entities( ecs_world_t *world, ecs_table_t *table) { - flecs_table_fini_data(world, table, table->data, true, true, true, true); -} - -/* Unset all components in table. This function is called before a table is - * deleted, and invokes all UnSet handlers, if any */ -void flecs_table_remove_actions( - ecs_world_t *world, - ecs_table_t *table) -{ - (void)world; - flecs_table_notify_on_remove(world, table, table->data); + flecs_table_fini_data(world, table, true, true, true, true); } /* Free table resources. */ @@ -999,6 +973,7 @@ void flecs_table_free( ecs_world_t *world, ecs_table_t *table) { + ecs_allocator_t *a = &world->allocator; bool is_root = table == &world->store.root; ecs_assert(!table->_->lock, ECS_LOCKED_STORAGE, NULL); ecs_assert(is_root || table->id != 0, ECS_INTERNAL_ERROR, NULL); @@ -1030,7 +1005,7 @@ void flecs_table_free( world->info.empty_table_count -= (ecs_table_count(table) == 0); /* Cleanup data, no OnRemove, delete from entity index, don't deactivate */ - flecs_table_fini_data(world, table, table->data, false, true, true, false); + flecs_table_fini_data(world, table, false, true, true, false); flecs_table_clear_edges(world, table); if (!is_root) { @@ -1060,26 +1035,17 @@ void flecs_table_free( world->info.trivial_table_count -= !(table->flags & EcsTableIsComplex); } - flecs_free_t(&world->allocator, ecs_table__t, table->_); + flecs_free_t(a, ecs_table__t, table->_); + flecs_wfree_n(world, ecs_id_t, table->type.count, table->type.array); if (!(world->flags & EcsWorldFini)) { ecs_assert(!is_root, ECS_INTERNAL_ERROR, NULL); - flecs_table_free_type(world, table); flecs_sparse_remove_t(&world->store.tables, ecs_table_t, table->id); } ecs_log_pop_2(); } -/* Free table type. Do this separately from freeing the table as types can be - * in use by application destructors. */ -void flecs_table_free_type( - ecs_world_t *world, - ecs_table_t *table) -{ - flecs_wfree_n(world, ecs_id_t, table->type.count, table->type.array); -} - /* Reset a table to its initial state. */ void flecs_table_reset( ecs_world_t *world, @@ -1312,19 +1278,21 @@ void* flecs_table_grow_column( } /* Grow all data structures in a table */ -static -int32_t flecs_table_grow_data( +int32_t flecs_table_appendn( ecs_world_t *world, ecs_table_t *table, - ecs_data_t *data, int32_t to_add, - int32_t size, const ecs_entity_t *ids) { ecs_assert(table != NULL, ECS_INTERNAL_ERROR, NULL); + ecs_assert(!table->_->lock, ECS_LOCKED_STORAGE, NULL); + ecs_data_t *data = table->data; ecs_assert(data != NULL, ECS_INTERNAL_ERROR, NULL); + flecs_table_check_sanity(table); + int32_t cur_count = ecs_table_count(table); + int32_t size = to_add + cur_count; int32_t column_count = table->data->column_count; /* Add record to record ptr array */ @@ -1375,6 +1343,8 @@ int32_t flecs_table_grow_data( flecs_table_set_empty(world, table); } + flecs_table_check_sanity(table); + /* Return index of first added entity */ return cur_count; } @@ -1784,45 +1754,6 @@ void flecs_table_move( flecs_table_check_sanity(src_table); } -/* Append n entities to table */ -int32_t flecs_table_appendn( - ecs_world_t *world, - ecs_table_t *table, - ecs_data_t *data, - int32_t to_add, - const ecs_entity_t *ids) -{ - ecs_assert(!table->_->lock, ECS_LOCKED_STORAGE, NULL); - - flecs_table_check_sanity(table); - int32_t cur_count = ecs_table_count(table); - int32_t result = flecs_table_grow_data( - world, table, data, to_add, cur_count + to_add, ids); - flecs_table_check_sanity(table); - - return result; -} - -/* Set allocated table size */ -void flecs_table_set_size( - ecs_world_t *world, - ecs_table_t *table, - ecs_data_t *data, - int32_t size) -{ - ecs_assert(table != NULL, ECS_LOCKED_STORAGE, NULL); - ecs_assert(!table->_->lock, ECS_LOCKED_STORAGE, NULL); - - flecs_table_check_sanity(table); - - int32_t cur_count = ecs_table_count(table); - - if (cur_count < size) { - flecs_table_grow_data(world, table, data, 0, size, NULL); - flecs_table_check_sanity(table); - } -} - /* Shrink table storage to fit number of entities */ bool flecs_table_shrink( ecs_world_t *world, @@ -1946,40 +1877,6 @@ void flecs_table_swap( flecs_table_check_sanity(table); } -static -void flecs_table_merge_vec( - ecs_world_t *world, - ecs_vec_t *dst, - ecs_vec_t *src, - int32_t size, - int32_t elem_size) -{ - int32_t dst_count = dst->count; - - if (!dst_count) { - ecs_vec_fini(&world->allocator, dst, size); - *dst = *src; - src->array = NULL; - src->count = 0; - src->size = 0; - } else { - int32_t src_count = src->count; - - if (elem_size) { - ecs_vec_set_size(&world->allocator, - dst, size, elem_size); - } - ecs_vec_set_count(&world->allocator, - dst, size, dst_count + src_count); - - void *dst_ptr = ECS_ELEM(dst->array, size, dst_count); - void *src_ptr = src->array; - ecs_os_memcpy(dst_ptr, src_ptr, size * src_count); - - ecs_vec_fini(&world->allocator, src, size); - } -} - /* Merge data from one table column into other table column */ static void flecs_table_merge_column( @@ -2043,18 +1940,14 @@ void flecs_table_merge_data( return; } - /* Merge entities */ - flecs_table_merge_vec(world, &dst_data->entities, &src_data->entities, - ECS_SIZEOF(ecs_entity_t), 0); + /* Merge entities & records vectors */ + ecs_allocator_t *a = &world->allocator; + ecs_vec_merge_t(a, &dst_data->entities, &src_data->entities, ecs_entity_t); ecs_assert(dst_data->entities.count == src_count + dst_count, ECS_INTERNAL_ERROR, NULL); - int32_t column_size = dst_data->entities.size; - ecs_allocator_t *a = &world->allocator; - - /* Merge record pointers */ - flecs_table_merge_vec(world, &dst_data->records, &src_data->records, - ECS_SIZEOF(ecs_record_t*), 0); + ecs_vec_merge_t(a, &dst_data->records, &src_data->records, ecs_record_t*); + int32_t column_size = dst_data->entities.size; for (; (i_new < dst_column_count) && (i_old < src_column_count); ) { ecs_column_t *dst_column = &dst_columns[i_new]; ecs_column_t *src_column = &src_columns[i_old]; @@ -2081,7 +1974,8 @@ void flecs_table_merge_data( } } - flecs_table_move_bitset_columns(dst_table, dst_count, src_table, 0, src_count, true); + flecs_table_move_bitset_columns( + dst_table, dst_count, src_table, 0, src_count, true); /* Initialize remaining columns */ for (; i_new < dst_column_count; i_new ++) { @@ -2110,9 +2004,7 @@ void flecs_table_merge_data( void flecs_table_merge( ecs_world_t *world, ecs_table_t *dst_table, - ecs_table_t *src_table, - ecs_data_t *dst_data, - ecs_data_t *src_data) + ecs_table_t *src_table) { ecs_assert(src_table != NULL, ECS_INTERNAL_ERROR, NULL); ecs_assert(!src_table->_->lock, ECS_LOCKED_STORAGE, NULL); @@ -2121,10 +2013,15 @@ void flecs_table_merge( flecs_table_check_sanity(dst_table); bool move_data = false; + + ecs_data_t *dst_data = dst_table->data; + ecs_data_t *src_data = src_table->data; + ecs_assert(dst_data != NULL, ECS_INTERNAL_ERROR, NULL); + ecs_assert(src_data != NULL, ECS_INTERNAL_ERROR, NULL); /* If there is nothing to merge to, just clear the old table */ if (!dst_table) { - flecs_table_clear_data(world, src_table, src_data); + flecs_table_clear_data(world, src_table); flecs_table_check_sanity(src_table); return; } else { diff --git a/src/storage/table.h b/src/storage/table.h index 121bf2e46..711446c96 100644 --- a/src/storage/table.h +++ b/src/storage/table.h @@ -85,12 +85,6 @@ struct ecs_table_t { ecs_table__t *_; /* Infrequently accessed table metadata */ }; -/* Init table */ -void flecs_table_init( - ecs_world_t *world, - ecs_table_t *table, - ecs_table_t *from); - /* Get table data */ ecs_data_t* flecs_table_data( const ecs_table_t *table); @@ -120,42 +114,11 @@ ecs_entity_t* flecs_table_entities_array( ecs_record_t** flecs_table_records_array( const ecs_table_t *table); -/** Copy type. */ -ecs_type_t flecs_type_copy( - ecs_world_t *world, - const ecs_type_t *src); - -/** Free type. */ -void flecs_type_free( - ecs_world_t *world, - ecs_type_t *type); - -/** Find or create table for a set of components */ -ecs_table_t* flecs_table_find_or_create( - ecs_world_t *world, - ecs_type_t *type); - -/* Initialize columns for data */ -void flecs_table_init_data( - ecs_world_t *world, - ecs_table_t *table, - int32_t column_count); - -/* Clear all entities from a table. */ -void flecs_table_clear_entities( - ecs_world_t *world, - ecs_table_t *table); - -/* Reset a table to its initial state */ -void flecs_table_reset( - ecs_world_t *world, - ecs_table_t *table); - -/* Clear table data. Don't call OnRemove handlers. */ -void flecs_table_clear_data( +/* Init table */ +void flecs_table_init( ecs_world_t *world, ecs_table_t *table, - ecs_data_t *data); + ecs_table_t *from); /* Add a new entry to the table for the specified entity */ int32_t flecs_table_append( @@ -173,10 +136,6 @@ void flecs_table_delete( int32_t index, bool destruct); -/* Make sure table records are in correct table cache list */ -bool flecs_table_records_update_empty( - ecs_table_t *table); - /* Move a row from one table to another */ void flecs_table_move( ecs_world_t *world, @@ -188,21 +147,31 @@ void flecs_table_move( int32_t old_index, bool construct); +/* Merge data of one table into another table */ +void flecs_table_merge( + ecs_world_t *world, + ecs_table_t *new_table, + ecs_table_t *old_table); + +/* Swap rows in table */ +void flecs_table_swap( + ecs_world_t *world, + ecs_table_t *table, + int32_t row_1, + int32_t row_2); + /* Grow table with specified number of records. Populate table with entities, * starting from specified entity id. */ int32_t flecs_table_appendn( ecs_world_t *world, ecs_table_t *table, - ecs_data_t *data, int32_t count, const ecs_entity_t *ids); -/* Set table to a fixed size. Useful for preallocating memory in advance. */ -void flecs_table_set_size( +/* Reset a table to its initial state */ +void flecs_table_reset( ecs_world_t *world, - ecs_table_t *table, - ecs_data_t *data, - int32_t count); + ecs_table_t *table); /* Shrink table to contents */ bool flecs_table_shrink( @@ -218,52 +187,36 @@ int32_t* flecs_table_get_dirty_state( void flecs_init_root_table( ecs_world_t *world); -/* Unset components in table */ -void flecs_table_remove_actions( - ecs_world_t *world, - ecs_table_t *table); - -/* Free table */ -void flecs_table_free( - ecs_world_t *world, - ecs_table_t *table); - -/* Free table */ -void flecs_table_free_type( - ecs_world_t *world, - ecs_table_t *table); - -/* Merge data of one table into another table */ -void flecs_table_merge( - ecs_world_t *world, - ecs_table_t *new_table, - ecs_table_t *old_table, - ecs_data_t *new_data, - ecs_data_t *old_data); - -void flecs_table_swap( - ecs_world_t *world, - ecs_table_t *table, - int32_t row_1, - int32_t row_2); - +/* Mark component column dirty */ void flecs_table_mark_dirty( ecs_world_t *world, ecs_table_t *table, ecs_entity_t component); +/* Keep track of number of traversable entities in table */ +void flecs_table_traversable_add( + ecs_table_t *table, + int32_t value); + +/* Notify table of event (used for propagating observer related flags) */ void flecs_table_notify( ecs_world_t *world, ecs_table_t *table, ecs_table_event_t *event); +/* Clear entities from a table. */ +void flecs_table_clear_entities( + ecs_world_t *world, + ecs_table_t *table); + +/* Clear entities from a table, delete entities from entity index. */ void flecs_table_delete_entities( ecs_world_t *world, ecs_table_t *table); -/* Increase observer count of table */ -void flecs_table_traversable_add( - ecs_table_t *table, - int32_t value); +/* Free table */ +void flecs_table_free( + ecs_world_t *world, + ecs_table_t *table); #endif diff --git a/src/storage/table_graph.c b/src/storage/table_graph.c index 018a175b6..0a189c046 100644 --- a/src/storage/table_graph.c +++ b/src/storage/table_graph.c @@ -54,237 +54,6 @@ void flecs_table_hashmap_init( flecs_type_hash, flecs_type_compare, &world->allocator); } -/* Find location where to insert id into type */ -static -int flecs_type_find_insert( - const ecs_type_t *type, - int32_t offset, - ecs_id_t to_add) -{ - ecs_id_t *array = type->array; - int32_t i, count = type->count; - - for (i = offset; i < count; i ++) { - ecs_id_t id = array[i]; - if (id == to_add) { - return -1; - } - if (id > to_add) { - return i; - } - } - return i; -} - -/* Find location of id in type */ -static -int flecs_type_find( - const ecs_type_t *type, - ecs_id_t id) -{ - ecs_id_t *array = type->array; - int32_t i, count = type->count; - - for (i = 0; i < count; i ++) { - ecs_id_t cur = array[i]; - if (ecs_id_match(cur, id)) { - return i; - } - if (cur > id) { - return -1; - } - } - - return -1; -} - -/* Count number of matching ids */ -static -int flecs_type_count_matches( - const ecs_type_t *type, - ecs_id_t wildcard, - int32_t offset) -{ - ecs_id_t *array = type->array; - int32_t i = offset, count = type->count; - - for (; i < count; i ++) { - ecs_id_t cur = array[i]; - if (!ecs_id_match(cur, wildcard)) { - break; - } - } - - return i - offset; -} - -/* Create type from source type with id */ -static -int flecs_type_new_with( - ecs_world_t *world, - ecs_type_t *dst, - const ecs_type_t *src, - ecs_id_t with) -{ - ecs_id_t *src_array = src->array; - int32_t at = flecs_type_find_insert(src, 0, with); - if (at == -1) { - return -1; - } - - int32_t dst_count = src->count + 1; - ecs_id_t *dst_array = flecs_walloc_n(world, ecs_id_t, dst_count); - dst->count = dst_count; - dst->array = dst_array; - - if (at) { - ecs_os_memcpy_n(dst_array, src_array, ecs_id_t, at); - } - - int32_t remain = src->count - at; - if (remain) { - ecs_os_memcpy_n(&dst_array[at + 1], &src_array[at], ecs_id_t, remain); - } - - dst_array[at] = with; - - return 0; -} - -/* Create type from source type without ids matching wildcard */ -static -int flecs_type_new_filtered( - ecs_world_t *world, - ecs_type_t *dst, - const ecs_type_t *src, - ecs_id_t wildcard, - int32_t at) -{ - *dst = flecs_type_copy(world, src); - ecs_id_t *dst_array = dst->array; - ecs_id_t *src_array = src->array; - if (at) { - ecs_assert(dst_array != NULL, ECS_INTERNAL_ERROR, NULL); - ecs_os_memcpy_n(dst_array, src_array, ecs_id_t, at); - } - - int32_t i = at + 1, w = at, count = src->count; - for (; i < count; i ++) { - ecs_id_t id = src_array[i]; - if (!ecs_id_match(id, wildcard)) { - dst_array[w] = id; - w ++; - } - } - - dst->count = w; - if (w != count) { - dst->array = flecs_wrealloc_n(world, ecs_id_t, w, count, dst->array); - } - - return 0; -} - -/* Create type from source type without id */ -static -int flecs_type_new_without( - ecs_world_t *world, - ecs_type_t *dst, - const ecs_type_t *src, - ecs_id_t without) -{ - ecs_id_t *src_array = src->array; - int32_t count = 1, at = flecs_type_find(src, without); - if (at == -1) { - return -1; - } - - int32_t src_count = src->count; - if (src_count == 1) { - dst->array = NULL; - dst->count = 0; - return 0; - } - - if (ecs_id_is_wildcard(without)) { - if (ECS_IS_PAIR(without)) { - ecs_entity_t r = ECS_PAIR_FIRST(without); - ecs_entity_t o = ECS_PAIR_SECOND(without); - if (r == EcsWildcard && o != EcsWildcard) { - return flecs_type_new_filtered(world, dst, src, without, at); - } - } - count += flecs_type_count_matches(src, without, at + 1); - } - - int32_t dst_count = src_count - count; - dst->count = dst_count; - if (!dst_count) { - dst->array = NULL; - return 0; - } - - ecs_id_t *dst_array = flecs_walloc_n(world, ecs_id_t, dst_count); - dst->array = dst_array; - - if (at) { - ecs_os_memcpy_n(dst_array, src_array, ecs_id_t, at); - } - - int32_t remain = dst_count - at; - if (remain) { - ecs_os_memcpy_n( - &dst_array[at], &src_array[at + count], ecs_id_t, remain); - } - - return 0; -} - -/* Copy type */ -ecs_type_t flecs_type_copy( - ecs_world_t *world, - const ecs_type_t *src) -{ - int32_t src_count = src->count; - if (!src_count) { - return (ecs_type_t){ 0 }; - } - - ecs_id_t *ids = flecs_walloc_n(world, ecs_id_t, src_count); - ecs_os_memcpy_n(ids, src->array, ecs_id_t, src_count); - return (ecs_type_t) { - .array = ids, - .count = src_count - }; -} - -/* Free type */ -void flecs_type_free( - ecs_world_t *world, - ecs_type_t *type) -{ - int32_t count = type->count; - if (count) { - flecs_wfree_n(world, ecs_id_t, type->count, type->array); - } -} - -/* Add to type */ -static -void flecs_type_add( - ecs_world_t *world, - ecs_type_t *type, - ecs_id_t add) -{ - ecs_type_t new_type; - int res = flecs_type_new_with(world, &new_type, type, add); - if (res != -1) { - flecs_type_free(world, type); - type->array = new_type.array; - type->count = new_type.count; - } -} - /* Graph edge utilities */ void flecs_table_diff_builder_init( @@ -498,22 +267,6 @@ void flecs_table_init_node( flecs_table_init_edges(&node->remove); } -bool flecs_table_records_update_empty( - ecs_table_t *table) -{ - bool result = false; - bool is_empty = ecs_table_count(table) == 0; - - int32_t i, count = table->_->record_count; - for (i = 0; i < count; i ++) { - ecs_table_record_t *tr = &table->_->records[i]; - ecs_table_cache_t *cache = tr->hdr.cache; - result |= ecs_table_cache_set_empty(cache, table, is_empty); - } - - return result; -} - static void flecs_init_table( ecs_world_t *world, diff --git a/src/storage/table_graph.h b/src/storage/table_graph.h index 18fcf0a34..71b6bb169 100644 --- a/src/storage/table_graph.h +++ b/src/storage/table_graph.h @@ -6,6 +6,8 @@ #ifndef FLECS_TABLE_GRAPH_H #define FLECS_TABLE_GRAPH_H +#include "type.h" + /** Cache of added/removed components for non-trivial edges between tables */ #define ECS_TABLE_DIFF_INIT { .added = {0}} @@ -67,6 +69,11 @@ ecs_table_t *flecs_table_traverse_remove( ecs_id_t *id_ptr, ecs_table_diff_t *diff); +/** Find or create table for a set of components */ +ecs_table_t* flecs_table_find_or_create( + ecs_world_t *world, + ecs_type_t *type); + /* Cleanup incoming and outgoing edges for table */ void flecs_table_clear_edges( ecs_world_t *world, diff --git a/src/storage/type.c b/src/storage/type.c new file mode 100644 index 000000000..30823e195 --- /dev/null +++ b/src/storage/type.c @@ -0,0 +1,226 @@ + +#include "../private_api.h" + +/* Find location where to insert id into type */ +int flecs_type_find_insert( + const ecs_type_t *type, + int32_t offset, + ecs_id_t to_add) +{ + ecs_id_t *array = type->array; + int32_t i, count = type->count; + + for (i = offset; i < count; i ++) { + ecs_id_t id = array[i]; + if (id == to_add) { + return -1; + } + if (id > to_add) { + return i; + } + } + return i; +} + +/* Find location of id in type */ +int flecs_type_find( + const ecs_type_t *type, + ecs_id_t id) +{ + ecs_id_t *array = type->array; + int32_t i, count = type->count; + + for (i = 0; i < count; i ++) { + ecs_id_t cur = array[i]; + if (ecs_id_match(cur, id)) { + return i; + } + if (cur > id) { + return -1; + } + } + + return -1; +} + +/* Count number of matching ids */ +int flecs_type_count_matches( + const ecs_type_t *type, + ecs_id_t wildcard, + int32_t offset) +{ + ecs_id_t *array = type->array; + int32_t i = offset, count = type->count; + + for (; i < count; i ++) { + ecs_id_t cur = array[i]; + if (!ecs_id_match(cur, wildcard)) { + break; + } + } + + return i - offset; +} + +/* Create type from source type with id */ +int flecs_type_new_with( + ecs_world_t *world, + ecs_type_t *dst, + const ecs_type_t *src, + ecs_id_t with) +{ + ecs_id_t *src_array = src->array; + int32_t at = flecs_type_find_insert(src, 0, with); + if (at == -1) { + return -1; + } + + int32_t dst_count = src->count + 1; + ecs_id_t *dst_array = flecs_walloc_n(world, ecs_id_t, dst_count); + dst->count = dst_count; + dst->array = dst_array; + + if (at) { + ecs_os_memcpy_n(dst_array, src_array, ecs_id_t, at); + } + + int32_t remain = src->count - at; + if (remain) { + ecs_os_memcpy_n(&dst_array[at + 1], &src_array[at], ecs_id_t, remain); + } + + dst_array[at] = with; + + return 0; +} + +/* Copy type */ +ecs_type_t flecs_type_copy( + ecs_world_t *world, + const ecs_type_t *src) +{ + int32_t src_count = src->count; + if (!src_count) { + return (ecs_type_t){ 0 }; + } + + ecs_id_t *ids = flecs_walloc_n(world, ecs_id_t, src_count); + ecs_os_memcpy_n(ids, src->array, ecs_id_t, src_count); + return (ecs_type_t) { + .array = ids, + .count = src_count + }; +} + +/* Create type from source type without ids matching wildcard */ +int flecs_type_new_filtered( + ecs_world_t *world, + ecs_type_t *dst, + const ecs_type_t *src, + ecs_id_t wildcard, + int32_t at) +{ + *dst = flecs_type_copy(world, src); + ecs_id_t *dst_array = dst->array; + ecs_id_t *src_array = src->array; + if (at) { + ecs_assert(dst_array != NULL, ECS_INTERNAL_ERROR, NULL); + ecs_os_memcpy_n(dst_array, src_array, ecs_id_t, at); + } + + int32_t i = at + 1, w = at, count = src->count; + for (; i < count; i ++) { + ecs_id_t id = src_array[i]; + if (!ecs_id_match(id, wildcard)) { + dst_array[w] = id; + w ++; + } + } + + dst->count = w; + if (w != count) { + dst->array = flecs_wrealloc_n(world, ecs_id_t, w, count, dst->array); + } + + return 0; +} + +/* Create type from source type without id */ +int flecs_type_new_without( + ecs_world_t *world, + ecs_type_t *dst, + const ecs_type_t *src, + ecs_id_t without) +{ + ecs_id_t *src_array = src->array; + int32_t count = 1, at = flecs_type_find(src, without); + if (at == -1) { + return -1; + } + + int32_t src_count = src->count; + if (src_count == 1) { + dst->array = NULL; + dst->count = 0; + return 0; + } + + if (ecs_id_is_wildcard(without)) { + if (ECS_IS_PAIR(without)) { + ecs_entity_t r = ECS_PAIR_FIRST(without); + ecs_entity_t o = ECS_PAIR_SECOND(without); + if (r == EcsWildcard && o != EcsWildcard) { + return flecs_type_new_filtered(world, dst, src, without, at); + } + } + count += flecs_type_count_matches(src, without, at + 1); + } + + int32_t dst_count = src_count - count; + dst->count = dst_count; + if (!dst_count) { + dst->array = NULL; + return 0; + } + + ecs_id_t *dst_array = flecs_walloc_n(world, ecs_id_t, dst_count); + dst->array = dst_array; + + if (at) { + ecs_os_memcpy_n(dst_array, src_array, ecs_id_t, at); + } + + int32_t remain = dst_count - at; + if (remain) { + ecs_os_memcpy_n( + &dst_array[at], &src_array[at + count], ecs_id_t, remain); + } + + return 0; +} + +/* Free type */ +void flecs_type_free( + ecs_world_t *world, + ecs_type_t *type) +{ + int32_t count = type->count; + if (count) { + flecs_wfree_n(world, ecs_id_t, type->count, type->array); + } +} + +/* Add to type */ +void flecs_type_add( + ecs_world_t *world, + ecs_type_t *type, + ecs_id_t add) +{ + ecs_type_t new_type; + int res = flecs_type_new_with(world, &new_type, type, add); + if (res != -1) { + flecs_type_free(world, type); + type->array = new_type.array; + type->count = new_type.count; + } +} diff --git a/src/storage/type.h b/src/storage/type.h new file mode 100644 index 000000000..945cd0a38 --- /dev/null +++ b/src/storage/type.h @@ -0,0 +1,63 @@ +/** + * @file type.h + * @brief Type utilities + */ + +#ifndef FLECS_TYPE_H +#define FLECS_TYPE_H + +int flecs_type_find_insert( + const ecs_type_t *type, + int32_t offset, + ecs_id_t to_add); + +/* Find location of id in type */ +int flecs_type_find( + const ecs_type_t *type, + ecs_id_t id); + +/* Count number of matching ids */ +int flecs_type_count_matches( + const ecs_type_t *type, + ecs_id_t wildcard, + int32_t offset); + +/* Create type from source type with id */ +int flecs_type_new_with( + ecs_world_t *world, + ecs_type_t *dst, + const ecs_type_t *src, + ecs_id_t with); + +/* Copy type */ +ecs_type_t flecs_type_copy( + ecs_world_t *world, + const ecs_type_t *src); + +/* Create type from source type without ids matching wildcard */ +int flecs_type_new_filtered( + ecs_world_t *world, + ecs_type_t *dst, + const ecs_type_t *src, + ecs_id_t wildcard, + int32_t at); + +/* Create type from source type without id */ +int flecs_type_new_without( + ecs_world_t *world, + ecs_type_t *dst, + const ecs_type_t *src, + ecs_id_t without); + +/* Free type */ +void flecs_type_free( + ecs_world_t *world, + ecs_type_t *type); + +/* Add to type */ +void flecs_type_add( + ecs_world_t *world, + ecs_type_t *type, + ecs_id_t add); + +#endif diff --git a/src/world.c b/src/world.c index bcd67cc3d..785c2693b 100644 --- a/src/world.c +++ b/src/world.c @@ -576,14 +576,6 @@ void flecs_clean_tables( flecs_table_free(world, t); } - /* Free table types separately so that if application destructors rely on - * a type it's still valid. */ - for (i = 1; i < count; i ++) { - ecs_table_t *t = flecs_sparse_get_dense_t(&world->store.tables, - ecs_table_t, i); - flecs_table_free_type(world, t); - } - /* Clear the root table */ if (count) { flecs_table_reset(world, &world->store.root); @@ -1286,7 +1278,10 @@ void flecs_fini_unset_tables( for (i = 1; i < count; i ++) { ecs_table_t *table = flecs_sparse_get_dense_t(tables, ecs_table_t, i); - flecs_table_remove_actions(world, table); + int32_t count = ecs_table_count(table); + if (count) { + flecs_notify_on_remove(world, table, NULL, 0, count, &table->type); + } } } @@ -1925,6 +1920,23 @@ void flecs_process_empty_queries( flecs_defer_end(world, &world->stages[0]); } +static +bool flecs_table_records_update_empty( + ecs_table_t *table) +{ + bool result = false; + bool is_empty = ecs_table_count(table) == 0; + + int32_t i, count = table->_->record_count; + for (i = 0; i < count; i ++) { + ecs_table_record_t *tr = &table->_->records[i]; + ecs_table_cache_t *cache = tr->hdr.cache; + result |= ecs_table_cache_set_empty(cache, table, is_empty); + } + + return result; +} + /** Walk over tables that had a state change which requires bookkeeping */ void flecs_process_pending_tables( const ecs_world_t *world_r)