@@ -163,6 +163,10 @@ int32_t flecs_entity_index_not_alive_count(
163163void flecs_entity_index_clear(
164164 ecs_entity_index_t *index);
165165
166+ /* Shrink entity index */
167+ void flecs_entity_index_shrink(
168+ ecs_entity_index_t *index);
169+
166170/* Return number of alive entities in index */
167171const uint64_t* flecs_entity_index_ids(
168172 const ecs_entity_index_t *index);
@@ -19760,6 +19764,28 @@ void flecs_component_ids_set(
1976019764 ecs_vec_get_t(&world->component_ids, ecs_entity_t, index)[0] = component;
1976119765}
1976219766
19767+ void ecs_shrink(
19768+ ecs_world_t *world)
19769+ {
19770+ flecs_entity_index_shrink(&world->store.entity_index);
19771+
19772+ ecs_sparse_t *tables = &world->store.tables;
19773+ int32_t i, count = flecs_sparse_count(tables);
19774+
19775+ for (i = count - 1; i > 0; i --) {
19776+ ecs_table_t *table = flecs_sparse_get_dense_t(tables, ecs_table_t, i);
19777+ if (ecs_table_count(table)) {
19778+ flecs_table_shrink(world, table);
19779+ } else {
19780+ flecs_table_fini(world, table);
19781+ }
19782+ }
19783+
19784+ flecs_table_shrink(world, &world->store.root);
19785+
19786+ flecs_sparse_shrink(&world->store.tables);
19787+ }
19788+
1976319789/**
1976419790 * @file addons/alerts.c
1976519791 * @brief Alerts addon.
@@ -29026,7 +29052,7 @@ void* flecs_brealloc_w_dbg_info(
2902629052}
2902729053
2902829054void* flecs_bdup(
29029- ecs_block_allocator_t *ba,
29055+ ecs_block_allocator_t *ba,
2903029056 void *memory)
2903129057{
2903229058#ifdef FLECS_USE_OS_ALLOC
@@ -30144,33 +30170,33 @@ void flecs_name_index_ensure(
3014430170/* Utility to get a pointer to the payload */
3014530171#define DATA(array, size, offset) (ECS_OFFSET(array, size * offset))
3014630172
30147- typedef struct ecs_page_t {
30173+ typedef struct ecs_sparse_page_t {
3014830174 int32_t *sparse; /* Sparse array with indices to dense array */
3014930175 void *data; /* Store data in sparse array to reduce
3015030176 * indirection and provide stable pointers. */
30151- } ecs_page_t ;
30177+ } ecs_sparse_page_t ;
3015230178
3015330179static
30154- ecs_page_t * flecs_sparse_page_new(
30180+ ecs_sparse_page_t * flecs_sparse_page_new(
3015530181 ecs_sparse_t *sparse,
3015630182 int32_t page_index)
3015730183{
3015830184 ecs_allocator_t *a = sparse->allocator;
3015930185 ecs_block_allocator_t *ca = sparse->page_allocator;
3016030186 int32_t count = ecs_vec_count(&sparse->pages);
30161- ecs_page_t *pages;
30187+ ecs_sparse_page_t *pages;
3016230188
3016330189 if (count <= page_index) {
30164- ecs_vec_set_count_t(a, &sparse->pages, ecs_page_t , page_index + 1);
30165- pages = ecs_vec_first_t(&sparse->pages, ecs_page_t );
30166- ecs_os_memset_n(&pages[count], 0, ecs_page_t , (1 + page_index - count));
30190+ ecs_vec_set_count_t(a, &sparse->pages, ecs_sparse_page_t , page_index + 1);
30191+ pages = ecs_vec_first_t(&sparse->pages, ecs_sparse_page_t );
30192+ ecs_os_memset_n(&pages[count], 0, ecs_sparse_page_t , (1 + page_index - count));
3016730193 } else {
30168- pages = ecs_vec_first_t(&sparse->pages, ecs_page_t );
30194+ pages = ecs_vec_first_t(&sparse->pages, ecs_sparse_page_t );
3016930195 }
3017030196
3017130197 ecs_assert(pages != NULL, ECS_INTERNAL_ERROR, NULL);
3017230198
30173- ecs_page_t *result = &pages[page_index];
30199+ ecs_sparse_page_t *result = &pages[page_index];
3017430200 ecs_assert(result->sparse == NULL, ECS_INTERNAL_ERROR, NULL);
3017530201 ecs_assert(result->data == NULL, ECS_INTERNAL_ERROR, NULL);
3017630202
@@ -30196,7 +30222,7 @@ ecs_page_t* flecs_sparse_page_new(
3019630222static
3019730223void flecs_sparse_page_free(
3019830224 ecs_sparse_t *sparse,
30199- ecs_page_t *page)
30225+ ecs_sparse_page_t *page)
3020030226{
3020130227 ecs_allocator_t *a = sparse->allocator;
3020230228 ecs_block_allocator_t *ca = sparse->page_allocator;
@@ -30214,24 +30240,25 @@ void flecs_sparse_page_free(
3021430240}
3021530241
3021630242static
30217- ecs_page_t * flecs_sparse_get_page(
30243+ ecs_sparse_page_t * flecs_sparse_get_page(
3021830244 const ecs_sparse_t *sparse,
3021930245 int32_t page_index)
3022030246{
3022130247 ecs_assert(page_index >= 0, ECS_INVALID_PARAMETER, NULL);
3022230248 if (page_index >= ecs_vec_count(&sparse->pages)) {
3022330249 return NULL;
3022430250 }
30225- return ecs_vec_get_t(&sparse->pages, ecs_page_t , page_index);
30251+ return ecs_vec_get_t(&sparse->pages, ecs_sparse_page_t , page_index);
3022630252}
3022730253
3022830254static
30229- ecs_page_t * flecs_sparse_get_or_create_page(
30255+ ecs_sparse_page_t * flecs_sparse_get_or_create_page(
3023030256 ecs_sparse_t *sparse,
3023130257 int32_t page_index)
3023230258{
30233- ecs_page_t *page = flecs_sparse_get_page(sparse, page_index);
30259+ ecs_sparse_page_t *page = flecs_sparse_get_page(sparse, page_index);
3023430260 if (page && page->sparse) {
30261+ ecs_assert(page->data != NULL, ECS_INTERNAL_ERROR, NULL);
3023530262 return page;
3023630263 }
3023730264
@@ -30260,7 +30287,7 @@ uint64_t flecs_sparse_strip_generation(
3026030287
3026130288static
3026230289void flecs_sparse_assign_index(
30263- ecs_page_t * page,
30290+ ecs_sparse_page_t * page,
3026430291 uint64_t * dense_array,
3026530292 uint64_t index,
3026630293 int32_t dense)
@@ -30318,7 +30345,7 @@ uint64_t flecs_sparse_create_id(
3031830345 uint64_t index = flecs_sparse_inc_id(sparse);
3031930346 flecs_sparse_grow_dense(sparse);
3032030347
30321- ecs_page_t *page = flecs_sparse_get_or_create_page(sparse, FLECS_SPARSE_PAGE(index));
30348+ ecs_sparse_page_t *page = flecs_sparse_get_or_create_page(sparse, FLECS_SPARSE_PAGE(index));
3032230349 ecs_assert(page->sparse[FLECS_SPARSE_OFFSET(index)] == 0, ECS_INTERNAL_ERROR, NULL);
3032330350
3032430351 uint64_t *dense_array = ecs_vec_first_t(&sparse->dense, uint64_t);
@@ -30354,7 +30381,7 @@ void* flecs_sparse_get_sparse(
3035430381 uint64_t index)
3035530382{
3035630383 flecs_sparse_strip_generation(&index);
30357- ecs_page_t *page = flecs_sparse_get_page(sparse, FLECS_SPARSE_PAGE(index));
30384+ ecs_sparse_page_t *page = flecs_sparse_get_page(sparse, FLECS_SPARSE_PAGE(index));
3035830385 if (!page || !page->sparse) {
3035930386 return NULL;
3036030387 }
@@ -30372,15 +30399,15 @@ void* flecs_sparse_get_sparse(
3037230399static
3037330400void flecs_sparse_swap_dense(
3037430401 ecs_sparse_t * sparse,
30375- ecs_page_t * page_a,
30402+ ecs_sparse_page_t * page_a,
3037630403 int32_t a,
3037730404 int32_t b)
3037830405{
3037930406 uint64_t *dense_array = ecs_vec_first_t(&sparse->dense, uint64_t);
3038030407 uint64_t index_a = dense_array[a];
3038130408 uint64_t index_b = dense_array[b];
3038230409
30383- ecs_page_t *page_b = flecs_sparse_get_or_create_page(sparse, FLECS_SPARSE_PAGE(index_b));
30410+ ecs_sparse_page_t *page_b = flecs_sparse_get_or_create_page(sparse, FLECS_SPARSE_PAGE(index_b));
3038430411 flecs_sparse_assign_index(page_a, dense_array, index_a, b);
3038530412 flecs_sparse_assign_index(page_b, dense_array, index_b, a);
3038630413}
@@ -30397,7 +30424,7 @@ void flecs_sparse_init(
3039730424 result->allocator = allocator;
3039830425 result->page_allocator = page_allocator;
3039930426
30400- ecs_vec_init_t(allocator, &result->pages, ecs_page_t , 0);
30427+ ecs_vec_init_t(allocator, &result->pages, ecs_sparse_page_t , 0);
3040130428 ecs_vec_init_t(allocator, &result->dense, uint64_t, 1);
3040230429 result->dense.count = 1;
3040330430
@@ -30414,7 +30441,7 @@ void flecs_sparse_clear(
3041430441 ecs_assert(sparse != NULL, ECS_INVALID_PARAMETER, NULL);
3041530442
3041630443 int32_t i, count = ecs_vec_count(&sparse->pages);
30417- ecs_page_t *pages = ecs_vec_first_t(&sparse->pages, ecs_page_t );
30444+ ecs_sparse_page_t *pages = ecs_vec_first_t(&sparse->pages, ecs_sparse_page_t );
3041830445 for (i = 0; i < count; i ++) {
3041930446 int32_t *indices = pages[i].sparse;
3042030447 if (indices) {
@@ -30434,12 +30461,12 @@ void flecs_sparse_fini(
3043430461 ecs_assert(sparse != NULL, ECS_INTERNAL_ERROR, NULL);
3043530462
3043630463 int32_t i, count = ecs_vec_count(&sparse->pages);
30437- ecs_page_t *pages = ecs_vec_first_t(&sparse->pages, ecs_page_t );
30464+ ecs_sparse_page_t *pages = ecs_vec_first_t(&sparse->pages, ecs_sparse_page_t );
3043830465 for (i = 0; i < count; i ++) {
3043930466 flecs_sparse_page_free(sparse, &pages[i]);
3044030467 }
3044130468
30442- ecs_vec_fini_t(sparse->allocator, &sparse->pages, ecs_page_t );
30469+ ecs_vec_fini_t(sparse->allocator, &sparse->pages, ecs_sparse_page_t );
3044330470 ecs_vec_fini_t(sparse->allocator, &sparse->dense, uint64_t);
3044430471}
3044530472
@@ -30457,8 +30484,9 @@ void* flecs_sparse_add(
3045730484 ecs_assert(sparse != NULL, ECS_INVALID_PARAMETER, NULL);
3045830485 ecs_assert(!size || size == sparse->size, ECS_INVALID_PARAMETER, NULL);
3045930486 uint64_t index = flecs_sparse_new_index(sparse);
30460- ecs_page_t *page = flecs_sparse_get_page(sparse, FLECS_SPARSE_PAGE(index));
30487+ ecs_sparse_page_t *page = flecs_sparse_get_page(sparse, FLECS_SPARSE_PAGE(index));
3046130488 ecs_assert(page != NULL, ECS_INTERNAL_ERROR, NULL);
30489+ ecs_assert(page->data != NULL, ECS_INTERNAL_ERROR, NULL);
3046230490 return DATA(page->data, size, FLECS_SPARSE_OFFSET(index));
3046330491}
3046430492
@@ -30481,7 +30509,7 @@ void* flecs_sparse_ensure(
3048130509 (void)size;
3048230510
3048330511 uint64_t gen = flecs_sparse_strip_generation(&index);
30484- ecs_page_t *page = flecs_sparse_get_or_create_page(sparse, FLECS_SPARSE_PAGE(index));
30512+ ecs_sparse_page_t *page = flecs_sparse_get_or_create_page(sparse, FLECS_SPARSE_PAGE(index));
3048530513 int32_t offset = FLECS_SPARSE_OFFSET(index);
3048630514 int32_t dense = page->sparse[offset];
3048730515
@@ -30528,7 +30556,7 @@ void* flecs_sparse_ensure(
3052830556 /* If there are unused elements in the list, move the first unused
3052930557 * element to the end of the list */
3053030558 uint64_t unused = dense_array[count];
30531- ecs_page_t *unused_page = flecs_sparse_get_or_create_page(sparse, FLECS_SPARSE_PAGE(unused));
30559+ ecs_sparse_page_t *unused_page = flecs_sparse_get_or_create_page(sparse, FLECS_SPARSE_PAGE(unused));
3053230560 flecs_sparse_assign_index(unused_page, dense_array, unused, dense_count);
3053330561 }
3053430562
@@ -30550,7 +30578,7 @@ void* flecs_sparse_ensure_fast(
3055030578 (void)size;
3055130579
3055230580 uint32_t index = (uint32_t)index_long;
30553- ecs_page_t *page = flecs_sparse_get_or_create_page(sparse, FLECS_SPARSE_PAGE(index));
30581+ ecs_sparse_page_t *page = flecs_sparse_get_or_create_page(sparse, FLECS_SPARSE_PAGE(index));
3055430582 int32_t offset = FLECS_SPARSE_OFFSET(index);
3055530583 int32_t dense = page->sparse[offset];
3055630584 int32_t count = sparse->count;
@@ -30578,7 +30606,7 @@ void* flecs_sparse_remove_fast(
3057830606 ecs_assert(!size || size == sparse->size, ECS_INVALID_PARAMETER, NULL);
3057930607 (void)size;
3058030608
30581- ecs_page_t *page = flecs_sparse_get_page(sparse, FLECS_SPARSE_PAGE(index));
30609+ ecs_sparse_page_t *page = flecs_sparse_get_page(sparse, FLECS_SPARSE_PAGE(index));
3058230610 if (!page || !page->sparse) {
3058330611 return NULL;
3058430612 }
@@ -30616,7 +30644,7 @@ void flecs_sparse_remove(
3061630644 ecs_assert(!size || size == sparse->size, ECS_INVALID_PARAMETER, NULL);
3061730645 (void)size;
3061830646
30619- ecs_page_t *page = flecs_sparse_get_page(sparse, FLECS_SPARSE_PAGE(index));
30647+ ecs_sparse_page_t *page = flecs_sparse_get_page(sparse, FLECS_SPARSE_PAGE(index));
3062030648 if (!page || !page->sparse) {
3062130649 return;
3062230650 }
@@ -30680,7 +30708,7 @@ bool flecs_sparse_is_alive(
3068030708 const ecs_sparse_t *sparse,
3068130709 uint64_t index)
3068230710{
30683- ecs_page_t *page = flecs_sparse_get_page(sparse, FLECS_SPARSE_PAGE(index));
30711+ ecs_sparse_page_t *page = flecs_sparse_get_page(sparse, FLECS_SPARSE_PAGE(index));
3068430712 if (!page || !page->sparse) {
3068530713 return false;
3068630714 }
@@ -30711,7 +30739,7 @@ void* flecs_sparse_try(
3071130739 ecs_assert(sparse != NULL, ECS_INVALID_PARAMETER, NULL);
3071230740 ecs_assert(!size || size == sparse->size, ECS_INVALID_PARAMETER, NULL);
3071330741 (void)size;
30714- ecs_page_t *page = flecs_sparse_get_page(sparse, FLECS_SPARSE_PAGE(index));
30742+ ecs_sparse_page_t *page = flecs_sparse_get_page(sparse, FLECS_SPARSE_PAGE(index));
3071530743 if (!page || !page->sparse) {
3071630744 return NULL;
3071730745 }
@@ -30742,7 +30770,7 @@ void* flecs_sparse_get(
3074230770 ecs_assert(!size || size == sparse->size, ECS_INVALID_PARAMETER, NULL);
3074330771 (void)size;
3074430772
30745- ecs_page_t *page = ecs_vec_get_t(&sparse->pages, ecs_page_t , FLECS_SPARSE_PAGE(index));
30773+ ecs_sparse_page_t *page = ecs_vec_get_t(&sparse->pages, ecs_sparse_page_t , FLECS_SPARSE_PAGE(index));
3074630774 int32_t offset = FLECS_SPARSE_OFFSET(index);
3074730775 int32_t dense = page->sparse[offset];
3074830776 ecs_assert(dense != 0, ECS_INTERNAL_ERROR, NULL);
@@ -30768,7 +30796,7 @@ void* flecs_sparse_get_any(
3076830796 (void)size;
3076930797
3077030798 flecs_sparse_strip_generation(&index);
30771- ecs_page_t *page = flecs_sparse_get_page(sparse, FLECS_SPARSE_PAGE(index));
30799+ ecs_sparse_page_t *page = flecs_sparse_get_page(sparse, FLECS_SPARSE_PAGE(index));
3077230800 if (!page || !page->sparse) {
3077330801 return NULL;
3077430802 }
@@ -30805,6 +30833,43 @@ const uint64_t* flecs_sparse_ids(
3080530833 }
3080630834}
3080730835
30836+ void flecs_sparse_shrink(
30837+ ecs_sparse_t *sparse)
30838+ {
30839+ int32_t i, e, max_page_index = 0, count = ecs_vec_count(&sparse->pages);
30840+ ecs_sparse_page_t *pages = ecs_vec_first_t(&sparse->pages,
30841+ ecs_sparse_page_t);
30842+ for (i = 0; i < count; i ++) {
30843+ ecs_sparse_page_t *page = &pages[i];
30844+ if (!page->sparse) {
30845+ ecs_assert(page->data == NULL, ECS_INTERNAL_ERROR, NULL);
30846+ continue;
30847+ }
30848+
30849+ bool has_alive = false;
30850+ for (e = 0; e < FLECS_SPARSE_PAGE_SIZE; e ++) {
30851+ uint64_t index =
30852+ flecs_ito(uint64_t, (i * FLECS_SPARSE_PAGE_SIZE) + e);
30853+
30854+ if (flecs_sparse_is_alive(sparse, index)) {
30855+ has_alive = true;
30856+ break;
30857+ }
30858+ }
30859+
30860+ if (!has_alive) {
30861+ flecs_sparse_page_free(sparse, page);
30862+ } else {
30863+ max_page_index = i;
30864+ }
30865+ }
30866+
30867+ ecs_vec_set_count_t(
30868+ sparse->allocator, &sparse->pages, ecs_sparse_page_t,
30869+ max_page_index + 1);
30870+ ecs_vec_reclaim_t(sparse->allocator, &sparse->pages, ecs_sparse_page_t);
30871+ }
30872+
3080830873void ecs_sparse_init(
3080930874 ecs_sparse_t *sparse,
3081030875 ecs_size_t elem_size)
@@ -35705,6 +35770,54 @@ void flecs_entity_index_clear(
3570535770 index->max_id = 0;
3570635771}
3570735772
35773+ void flecs_entity_index_shrink(
35774+ ecs_entity_index_t *index)
35775+ {
35776+ ecs_vec_set_count_t(
35777+ index->allocator, &index->dense, uint64_t, index->alive_count);
35778+ ecs_vec_reclaim_t(index->allocator, &index->dense, uint64_t);
35779+
35780+ int32_t i, e, max_page_index = 0, count = ecs_vec_count(&index->pages);
35781+ ecs_entity_index_page_t **pages = ecs_vec_first_t(&index->pages,
35782+ ecs_entity_index_page_t*);
35783+ for (i = 0; i < count; i ++) {
35784+ ecs_entity_index_page_t *page = pages[i];
35785+ if (!page) {
35786+ continue;
35787+ }
35788+
35789+ bool has_alive = false;
35790+ for (e = 0; e < FLECS_ENTITY_PAGE_SIZE; e ++) {
35791+ ecs_record_t *r = &page->records[e];
35792+ ecs_entity_t entity = flecs_ito(uint64_t, (i * 4096) + e);
35793+
35794+ if (r->dense) {
35795+ ecs_assert(flecs_entity_index_get_any(index, entity) == r,
35796+ ECS_INTERNAL_ERROR, NULL);
35797+
35798+ if (flecs_entity_index_is_alive(index, entity)) {
35799+ ecs_assert(flecs_entity_index_is_alive(index, entity),
35800+ ECS_INTERNAL_ERROR, NULL);
35801+ has_alive = true;
35802+ break;
35803+ }
35804+ }
35805+ }
35806+
35807+ if (!has_alive) {
35808+ flecs_bfree(&index->page_allocator, page);
35809+ pages[i] = NULL;
35810+ } else {
35811+ max_page_index = i;
35812+ }
35813+ }
35814+
35815+ ecs_vec_set_count_t(
35816+ index->allocator, &index->pages, ecs_entity_index_page_t*,
35817+ max_page_index + 1);
35818+ ecs_vec_reclaim_t(index->allocator, &index->pages, ecs_entity_index_page_t*);
35819+ }
35820+
3570835821const uint64_t* flecs_entity_index_ids(
3570935822 const ecs_entity_index_t *index)
3571035823{
0 commit comments