Skip to content

Commit 4bac4d4

Browse files
committed
Implement non-fragmenting component storage
1 parent 2a337a6 commit 4bac4d4

File tree

12 files changed

+351
-12
lines changed

12 files changed

+351
-12
lines changed

distr/flecs.c

Lines changed: 121 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -965,6 +965,9 @@ struct ecs_world_t {
965965
ecs_id_record_t *idr_childof_wildcard;
966966
ecs_id_record_t *idr_identifier_name;
967967

968+
/* Head of list that points to all non-fragmenting component ids */
969+
ecs_id_record_t *idr_non_fragmenting_head;
970+
968971
/* -- Mixins -- */
969972
ecs_world_t *self;
970973
ecs_observable_t observable;
@@ -1164,6 +1167,7 @@ struct ecs_id_record_t {
11641167
ecs_id_record_elem_t first; /* (R, *) */
11651168
ecs_id_record_elem_t second; /* (*, O) */
11661169
ecs_id_record_elem_t trav; /* (*, O) with only traversable relationships */
1170+
ecs_id_record_elem_t non_fragmenting; /* All non-fragmenting ids */
11671171

11681172
/* Parent id record. For pair records the parent is the (R, *) record. */
11691173
ecs_id_record_t *parent;
@@ -1241,6 +1245,11 @@ void flecs_id_record_init_sparse(
12411245
ecs_world_t *world,
12421246
ecs_id_record_t *idr);
12431247

1248+
/* Init non-fragmenting component id */
1249+
void flecs_id_record_init_dont_fragment(
1250+
ecs_world_t *world,
1251+
ecs_id_record_t *idr);
1252+
12441253
/* Bootstrap cached id records */
12451254
void flecs_init_id_records(
12461255
ecs_world_t *world);
@@ -3103,6 +3112,11 @@ void flecs_add_ids(
31033112
ecs_id_t *ids,
31043113
int32_t count);
31053114

3115+
void flecs_entity_remove_non_fragmenting(
3116+
ecs_world_t *world,
3117+
ecs_entity_t e,
3118+
ecs_record_t *r);
3119+
31063120
////////////////////////////////////////////////////////////////////////////////
31073121
//// Query API
31083122
////////////////////////////////////////////////////////////////////////////////
@@ -3464,6 +3478,9 @@ bool flecs_set_id_flag(
34643478
if (flag == EcsIdIsSparse) {
34653479
flecs_id_record_init_sparse(world, idr);
34663480
}
3481+
if (flag == EcsIdDontFragment) {
3482+
flecs_id_record_init_dont_fragment(world, idr);
3483+
}
34673484
return true;
34683485
}
34693486
return false;
@@ -5147,6 +5164,45 @@ void flecs_sparse_on_remove(
51475164
}
51485165
}
51495166

5167+
void flecs_entity_remove_non_fragmenting(
5168+
ecs_world_t *world,
5169+
ecs_entity_t e,
5170+
ecs_record_t *r)
5171+
{
5172+
if (!r) {
5173+
r = flecs_entities_get(world, e);
5174+
}
5175+
5176+
if (!r || !(r->row & EcsEntityHasDontFragment)) {
5177+
return;
5178+
}
5179+
5180+
ecs_id_record_t *cur = world->idr_non_fragmenting_head;
5181+
while (cur) {
5182+
ecs_assert(cur->flags & EcsIdIsSparse, ECS_INTERNAL_ERROR, NULL);
5183+
if (cur->sparse) {
5184+
void *ptr = flecs_sparse_get_any(cur->sparse, 0, e);
5185+
if (ptr) {
5186+
const ecs_type_info_t *ti = cur->type_info;
5187+
ecs_xtor_t dtor = ti->hooks.dtor;
5188+
ecs_iter_action_t on_remove = ti->hooks.on_remove;
5189+
if (on_remove) {
5190+
flecs_invoke_hook(world, NULL, NULL, 1, 0,
5191+
&e, cur->id, ti, EcsOnRemove, on_remove);
5192+
}
5193+
if (dtor) {
5194+
dtor(ptr, 1, ti);
5195+
}
5196+
flecs_sparse_remove_fast(cur->sparse, 0, e);
5197+
}
5198+
}
5199+
5200+
cur = cur->non_fragmenting.next;
5201+
}
5202+
5203+
r->row &= ~EcsEntityHasDontFragment;
5204+
}
5205+
51505206
static
51515207
void flecs_union_on_add(
51525208
ecs_world_t *world,
@@ -5223,6 +5279,14 @@ void flecs_notify_on_add(
52235279

52245280
if (sparse && (diff_flags & EcsTableHasSparse)) {
52255281
flecs_sparse_on_add(world, table, row, count, added, construct);
5282+
if (diff_flags & EcsTableHasDontFragment) {
5283+
int32_t i;
5284+
const ecs_entity_t *entities = ecs_table_entities(table);
5285+
for (i = row; i < (row + count); i ++) {
5286+
ecs_record_t *r = flecs_entities_get(world, entities[i]);
5287+
r->row |= EcsEntityHasDontFragment;
5288+
}
5289+
}
52265290
}
52275291

52285292
if (diff_flags & EcsTableHasUnion) {
@@ -5487,8 +5551,10 @@ void flecs_commit(
54875551
/* If source and destination table are the same no action is needed *
54885552
* However, if a component was added in the process of traversing a
54895553
* table, this suggests that a union relationship could have changed. */
5490-
if (src_table && src_table->flags & EcsTableHasUnion) {
5491-
diff->added_flags |= EcsIdIsUnion;
5554+
ecs_flags32_t non_fragment_flags =
5555+
src_table->flags & (EcsTableHasUnion|EcsTableHasDontFragment);
5556+
if (src_table && non_fragment_flags) {
5557+
diff->added_flags |= non_fragment_flags;
54925558
flecs_notify_on_add(world, src_table, src_table,
54935559
ECS_RECORD_TO_ROW(record->row), 1, diff, evt_flags, 0,
54945560
construct, true);
@@ -6883,6 +6949,8 @@ void ecs_clear(
68836949
if (r->row & EcsEntityIsTraversable) {
68846950
flecs_table_traversable_add(table, -1);
68856951
}
6952+
6953+
flecs_entity_remove_non_fragmenting(world, entity, NULL);
68866954
}
68876955

68886956
flecs_defer_end(world, stage);
@@ -7444,6 +7512,9 @@ void ecs_delete(
74447512
flecs_table_traversable_add(table, -1);
74457513
}
74467514
}
7515+
7516+
flecs_entity_remove_non_fragmenting(world, entity, r);
7517+
74477518
/* Merge operations before deleting entity */
74487519
flecs_defer_end(world, stage);
74497520
flecs_defer_begin(world, stage);
@@ -35737,6 +35808,17 @@ void flecs_id_record_init_sparse(
3573735808
}
3573835809
}
3573935810

35811+
void flecs_id_record_init_dont_fragment(
35812+
ecs_world_t *world,
35813+
ecs_id_record_t *idr)
35814+
{
35815+
if (world->idr_non_fragmenting_head) {
35816+
world->idr_non_fragmenting_head->non_fragmenting.prev = idr;
35817+
}
35818+
idr->non_fragmenting.next = world->idr_non_fragmenting_head;
35819+
world->idr_non_fragmenting_head = idr;
35820+
}
35821+
3574035822
static
3574135823
void flecs_id_record_fini_sparse(
3574235824
ecs_world_t *world,
@@ -35960,6 +36042,9 @@ ecs_id_record_t* flecs_id_record_new(
3596036042
if (ecs_has_id(world, tgt, EcsSparse)) {
3596136043
idr->flags |= EcsIdIsSparse;
3596236044
}
36045+
if (ecs_has_id(world, tgt, EcsDontFragment)) {
36046+
idr->flags |= EcsIdDontFragment;
36047+
}
3596336048
}
3596436049
}
3596536050

@@ -35973,6 +36058,10 @@ ecs_id_record_t* flecs_id_record_new(
3597336058
}
3597436059
}
3597536060

36061+
if (idr->flags & EcsIdDontFragment) {
36062+
flecs_id_record_init_dont_fragment(world, idr);
36063+
}
36064+
3597636065
if (ecs_should_log_1()) {
3597736066
char *id_str = ecs_id_str(world, id);
3597836067
ecs_dbg_1("#[green]id#[normal] %s #[green]created", id_str);
@@ -37217,6 +37306,8 @@ void flecs_table_dtor_all(
3721737306
ecs_assert(!e || ecs_is_valid(world, e),
3721837307
ECS_INTERNAL_ERROR, NULL);
3721937308

37309+
flecs_entity_remove_non_fragmenting(world, e, NULL);
37310+
3722037311
if (is_delete) {
3722137312
flecs_entities_remove(world, e);
3722237313
ecs_assert(ecs_is_valid(world, e) == false,
@@ -37237,6 +37328,7 @@ void flecs_table_dtor_all(
3723737328
for (i = row; i < end; i ++) {
3723837329
ecs_entity_t e = entities[i];
3723937330
ecs_assert(!e || ecs_is_valid(world, e), ECS_INTERNAL_ERROR, NULL);
37331+
flecs_entity_remove_non_fragmenting(world, e, NULL);
3724037332
flecs_entities_remove(world, e);
3724137333
ecs_assert(!ecs_is_valid(world, e), ECS_INTERNAL_ERROR, NULL);
3724237334
}
@@ -37245,6 +37337,7 @@ void flecs_table_dtor_all(
3724537337
ecs_entity_t e = entities[i];
3724637338
ecs_assert(!e || ecs_is_valid(world, e), ECS_INTERNAL_ERROR, NULL);
3724737339
ecs_record_t *record = flecs_entities_get(world, e);
37340+
flecs_entity_remove_non_fragmenting(world, e, record);
3724837341
record->table = NULL;
3724937342
record->row = record->row & ECS_ROW_FLAGS_MASK;
3725037343
(void)e;
@@ -39795,6 +39888,17 @@ void flecs_compute_table_diff(
3979539888
return;
3979639889
}
3979739890
}
39891+
} else {
39892+
ecs_id_record_t *idr = flecs_id_record_get(world, id);
39893+
if (idr->flags & EcsIdDontFragment) {
39894+
ecs_table_diff_t *diff = flecs_bcalloc(
39895+
&world->allocators.table_diff);
39896+
diff->added.count = 1;
39897+
diff->added.array = flecs_wdup_n(world, ecs_id_t, 1, &id);
39898+
diff->added_flags = EcsTableHasDontFragment|EcsTableHasSparse;
39899+
edge->diff = diff;
39900+
return;
39901+
}
3979839902
}
3979939903

3980039904
ecs_id_t *ids_node = node_type.array;
@@ -39990,7 +40094,6 @@ void flecs_add_with_property(
3999040094
flecs_add_with_property(world, idr_with_wildcard, dst_type, ra, o);
3999140095
}
3999240096
}
39993-
3999440097
}
3999540098

3999640099
static
@@ -40027,6 +40130,12 @@ ecs_table_t* flecs_find_table_with(
4002740130
r = with;
4002840131
}
4002940132

40133+
if (idr->flags & EcsIdDontFragment) {
40134+
/* Component doesn't fragment tables */
40135+
node->flags |= EcsTableHasDontFragment;
40136+
return node;
40137+
}
40138+
4003040139
/* Create sequence with new id */
4003140140
ecs_type_t dst_type;
4003240141
int res = flecs_type_new_with(world, &dst_type, &node->type, with);
@@ -40060,14 +40169,21 @@ ecs_table_t* flecs_find_table_without(
4006040169
ecs_table_t *node,
4006140170
ecs_id_t without)
4006240171
{
40172+
ecs_id_record_t *idr = NULL;
40173+
4006340174
if (ECS_IS_PAIR(without)) {
4006440175
ecs_entity_t r = 0;
40065-
ecs_id_record_t *idr = NULL;
4006640176
r = ECS_PAIR_FIRST(without);
4006740177
idr = flecs_id_record_get(world, ecs_pair(r, EcsWildcard));
4006840178
if (idr && idr->flags & EcsIdIsUnion) {
4006940179
without = ecs_pair(r, EcsUnion);
4007040180
}
40181+
} else {
40182+
idr = flecs_id_record_get(world, without);
40183+
if (idr && idr->flags & EcsIdDontFragment) {
40184+
/* Component doesn't fragment tables */
40185+
return node;
40186+
}
4007140187
}
4007240188

4007340189
/* Create sequence with new id */
@@ -40110,7 +40226,7 @@ void flecs_init_edge_for_add(
4011040226

4011140227
flecs_table_ensure_hi_edge(world, &table->node.add, id);
4011240228

40113-
if ((table != to) || (table->flags & EcsTableHasUnion)) {
40229+
if ((table != to) || (table->flags & (EcsTableHasUnion|EcsTableHasDontFragment))) {
4011440230
/* Add edges are appended to refs.next */
4011540231
ecs_graph_edge_hdr_t *to_refs = &to->node.refs;
4011640232
ecs_graph_edge_hdr_t *next = to_refs->next;

distr/flecs.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,7 @@ extern "C" {
392392
#define EcsEntityIsId (1u << 31)
393393
#define EcsEntityIsTarget (1u << 30)
394394
#define EcsEntityIsTraversable (1u << 29)
395+
#define EcsEntityHasDontFragment (1u << 28)
395396

396397

397398
////////////////////////////////////////////////////////////////////////////////
@@ -571,7 +572,7 @@ extern "C" {
571572
#define EcsTableHasOnTableCreate (1u << 21u)
572573
#define EcsTableHasOnTableDelete (1u << 22u)
573574
#define EcsTableHasSparse (1u << 23u)
574-
// #define EcsTableHasDontFragment (1u << 24u) /* Can't happen */
575+
#define EcsTableHasDontFragment (1u << 24u)
575576
#define EcsTableHasUnion (1u << 25u)
576577

577578
#define EcsTableHasTraversable (1u << 26u)

include/flecs/private/api_flags.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ extern "C" {
4242
#define EcsEntityIsId (1u << 31)
4343
#define EcsEntityIsTarget (1u << 30)
4444
#define EcsEntityIsTraversable (1u << 29)
45+
#define EcsEntityHasDontFragment (1u << 28)
4546

4647

4748
////////////////////////////////////////////////////////////////////////////////
@@ -221,7 +222,7 @@ extern "C" {
221222
#define EcsTableHasOnTableCreate (1u << 21u)
222223
#define EcsTableHasOnTableDelete (1u << 22u)
223224
#define EcsTableHasSparse (1u << 23u)
224-
// #define EcsTableHasDontFragment (1u << 24u) /* Can't happen */
225+
#define EcsTableHasDontFragment (1u << 24u)
225226
#define EcsTableHasUnion (1u << 25u)
226227

227228
#define EcsTableHasTraversable (1u << 26u)

src/bootstrap.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,9 @@ bool flecs_set_id_flag(
208208
if (flag == EcsIdIsSparse) {
209209
flecs_id_record_init_sparse(world, idr);
210210
}
211+
if (flag == EcsIdDontFragment) {
212+
flecs_id_record_init_dont_fragment(world, idr);
213+
}
211214
return true;
212215
}
213216
return false;

0 commit comments

Comments
 (0)