Skip to content

Commit e3f4d11

Browse files
committed
[queries] Skip down-traversal leaf check for non-traversable tables
Fix CI errors
1 parent d00804d commit e3f4d11

7 files changed

Lines changed: 48 additions & 80 deletions

File tree

distr/flecs.c

Lines changed: 24 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1483,9 +1483,9 @@ typedef enum {
14831483
} ecs_trav_direction_t;
14841484

14851485
typedef struct {
1486-
ecs_map_t src; /* map<table_id, trav_up_t> (up direction) */
1487-
ecs_trav_down_t down; /* reused buffer (down direction) */
1488-
ecs_trav_up_t up; /* reused buffer for top-level up result */
1486+
ecs_map_t src;
1487+
ecs_trav_down_t down;
1488+
ecs_trav_up_t up;
14891489
ecs_id_t with;
14901490
ecs_trav_direction_t dir;
14911491
} ecs_trav_up_cache_t;
@@ -2658,10 +2658,6 @@ ecs_iter_t flecs_query_iter(
26582658
const ecs_world_t *world,
26592659
const ecs_query_t *q);
26602660

2661-
/* Fast path for testing a trivial query against a table range, used by
2662-
* observers. Avoids creating a full query iterator. Returns 1 on match, 0 on no
2663-
* match, and -1 if the query is not eligible for this path (caller must fall
2664-
* back to ecs_query_has_range). On a match, populates 'it'. */
26652661
int flecs_query_trivial_has_range(
26662662
const ecs_query_t *q,
26672663
ecs_iter_t *it,
@@ -13395,11 +13391,12 @@ void flecs_iter_init(
1339513391
char *buf = flecs_stack_alloc(stack, wide + cols,
1339613392
ECS_ALIGNOF(ecs_id_t));
1339713393

13398-
it->ids = (ecs_id_t*)buf;
13399-
it->sources = (ecs_entity_t*)(buf + (ecs_size_t)sizeof(ecs_id_t) * fc);
13400-
it->trs = (const ecs_table_record_t**)(buf +
13394+
it->ids = (ecs_id_t*)(void*)buf;
13395+
it->sources = (ecs_entity_t*)(void*)(buf +
13396+
(ecs_size_t)sizeof(ecs_id_t) * fc);
13397+
it->trs = (const ecs_table_record_t**)(void*)(buf +
1340113398
(ecs_size_t)(sizeof(ecs_id_t) + sizeof(ecs_entity_t)) * fc);
13402-
int16_t *columns = (int16_t*)(buf + wide);
13399+
int16_t *columns = (int16_t*)(void*)(buf + wide);
1340313400

1340413401
ecs_os_memset(buf, 0, wide);
1340513402
ecs_os_memset(columns, 0xFF, cols);
@@ -17122,6 +17119,7 @@ void flecs_multi_observer_invoke(
1712217119
}
1712317120

1712417121
ecs_table_t *lock_table = table;
17122+
(void)lock_table;
1712517123
table = table ? table : &world->store.root;
1712617124
prev_table = prev_table ? prev_table : &world->store.root;
1712717125

@@ -17147,9 +17145,6 @@ void flecs_multi_observer_invoke(
1714717145
ecs_assert(match, ECS_INTERNAL_ERROR, NULL);
1714817146
}
1714917147
} else {
17150-
/* Fast path: for trivial observer queries we can test the table
17151-
* directly without creating a full query iterator. Monitors are handled
17152-
* by the regular path as they require an additional check. */
1715317148
int trivial = -1;
1715417149
if (!(impl->flags & EcsObserverIsMonitor)) {
1715517150
trivial = flecs_query_trivial_has_range(o->query, &user_it,
@@ -17249,7 +17244,6 @@ void flecs_multi_observer_invoke_no_query(
1724917244
flecs_poly_assert(o, ecs_observer_t);
1725017245

1725117246
ecs_world_t *world = it->real_world;
17252-
ecs_table_t *table = it->table;
1725317247
ecs_iter_t user_it = *it;
1725417248

1725517249
user_it.ctx = o->ctx;
@@ -17262,7 +17256,7 @@ void flecs_multi_observer_invoke_no_query(
1726217256

1726317257
ecs_entity_t old_system = flecs_stage_set_system(
1726417258
world->stages[0], o->entity);
17265-
ECS_TABLE_LOCK(it->world, table);
17259+
ECS_TABLE_LOCK(it->world, it->table);
1726617260

1726717261
if (o->run) {
1726817262
user_it.next = flecs_default_next_callback;
@@ -17271,7 +17265,7 @@ void flecs_multi_observer_invoke_no_query(
1727117265
user_it.callback(&user_it);
1727217266
}
1727317267

17274-
ECS_TABLE_UNLOCK(it->world, table);
17268+
ECS_TABLE_UNLOCK(it->world, it->table);
1727517269
flecs_stage_set_system(world->stages[0], old_system);
1727617270
}
1727717271

@@ -86019,10 +86013,6 @@ int flecs_query_trivial_has_range(
8601986013
ecs_flags32_t flags = q->flags;
8602086014
ecs_flags32_t trivial_flags = EcsQueryIsTrivial|EcsQueryMatchOnlySelf;
8602186015

86022-
/* Only handle the case where the constrained query would take the trivial
86023-
* test code path. This mirrors the conditions in
86024-
* flecs_query_apply_iter_flags. For anything else, signal the caller to use
86025-
* the regular (full iterator) path. */
8602686016
if (impl->cache ||
8602786017
((flags & trivial_flags) != trivial_flags) ||
8602886018
(flags & EcsQueryMatchWildcards) ||
@@ -86031,8 +86021,6 @@ int flecs_query_trivial_has_range(
8603186021
return -1;
8603286022
}
8603386023

86034-
/* Eval count is incremented unconditionally, matching ecs_query_iter and
86035-
* the bloom filter reject path in ecs_query_has_range. */
8603686024
ECS_CONST_CAST(ecs_query_t*, q)->eval_count ++;
8603786025

8603886026
if (table && ((offset + count) > ecs_table_count(table))) {
@@ -86043,9 +86031,6 @@ int flecs_query_trivial_has_range(
8604386031
return 0;
8604486032
}
8604586033

86046-
/* Build a minimal iterator for the trivial test. Unlike flecs_query_iter
86047-
* this skips the var/written/op_ctx allocations and the query VM, which the
86048-
* trivial test never uses. */
8604986034
ecs_iter_t lit = {0};
8605086035
lit.world = ECS_CONST_CAST(ecs_world_t*, world);
8605186036
lit.real_world = q->real_world;
@@ -86058,8 +86043,6 @@ int flecs_query_trivial_has_range(
8605886043
lit.offset = offset;
8605986044
lit.count = count;
8606086045

86061-
/* flecs_iter_init asserts that EcsIterIsValid is not set on entry, so only
86062-
* mark the iterator valid after initialization. */
8606386046
flecs_iter_init(lit.world, &lit, true);
8606486047
lit.flags |= EcsIterIsValid;
8606586048

@@ -89912,15 +89895,14 @@ void flecs_trav_entity_down_iter_children(
8991289895
bool leaf = false;
8991389896

8991489897
/* Check if table has the component */
89915-
if (flecs_component_get_table(cr_with, r->table) != NULL) {
89916-
if (self) {
89917-
/* If matching self and the table has the component, entity
89918-
* shouldn't be matched through traversal and will instead
89919-
* be matched directly. */
89920-
continue;
89921-
}
89898+
if (self || r->table->_->traversable_count) {
89899+
if (flecs_component_get_table(cr_with, r->table) != NULL) {
89900+
if (self) {
89901+
continue;
89902+
}
8992289903

89923-
leaf = true;
89904+
leaf = true;
89905+
}
8992489906
}
8992589907

8992689908
/* Add element to the cache for a single child */
@@ -89962,11 +89944,13 @@ void flecs_trav_entity_down_iter_tables(
8996289944
ecs_table_t *table = tr->hdr.table;
8996389945
bool leaf = false;
8996489946

89965-
if (flecs_component_get_table(cr_with, table) != NULL) {
89966-
if (self) {
89967-
continue;
89947+
if (self || table->_->traversable_count) {
89948+
if (flecs_component_get_table(cr_with, table) != NULL) {
89949+
if (self) {
89950+
continue;
89951+
}
89952+
leaf = true;
8996889953
}
89969-
leaf = true;
8997089954
}
8997189955

8997289956
/* If record is not the first instance of (trav, *), don't add it

src/iter.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,12 @@ void flecs_iter_init(
6060
char *buf = flecs_stack_alloc(stack, wide + cols,
6161
ECS_ALIGNOF(ecs_id_t));
6262

63-
it->ids = (ecs_id_t*)buf;
64-
it->sources = (ecs_entity_t*)(buf + (ecs_size_t)sizeof(ecs_id_t) * fc);
65-
it->trs = (const ecs_table_record_t**)(buf +
63+
it->ids = (ecs_id_t*)(void*)buf;
64+
it->sources = (ecs_entity_t*)(void*)(buf +
65+
(ecs_size_t)sizeof(ecs_id_t) * fc);
66+
it->trs = (const ecs_table_record_t**)(void*)(buf +
6667
(ecs_size_t)(sizeof(ecs_id_t) + sizeof(ecs_entity_t)) * fc);
67-
int16_t *columns = (int16_t*)(buf + wide);
68+
int16_t *columns = (int16_t*)(void*)(buf + wide);
6869

6970
ecs_os_memset(buf, 0, wide);
7071
ecs_os_memset(columns, 0xFF, cols);

src/observer.c

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,7 @@ void flecs_multi_observer_invoke(
589589
}
590590

591591
ecs_table_t *lock_table = table;
592+
(void)lock_table;
592593
table = table ? table : &world->store.root;
593594
prev_table = prev_table ? prev_table : &world->store.root;
594595

@@ -614,9 +615,6 @@ void flecs_multi_observer_invoke(
614615
ecs_assert(match, ECS_INTERNAL_ERROR, NULL);
615616
}
616617
} else {
617-
/* Fast path: for trivial observer queries we can test the table
618-
* directly without creating a full query iterator. Monitors are handled
619-
* by the regular path as they require an additional check. */
620618
int trivial = -1;
621619
if (!(impl->flags & EcsObserverIsMonitor)) {
622620
trivial = flecs_query_trivial_has_range(o->query, &user_it,
@@ -716,7 +714,6 @@ void flecs_multi_observer_invoke_no_query(
716714
flecs_poly_assert(o, ecs_observer_t);
717715

718716
ecs_world_t *world = it->real_world;
719-
ecs_table_t *table = it->table;
720717
ecs_iter_t user_it = *it;
721718

722719
user_it.ctx = o->ctx;
@@ -729,7 +726,7 @@ void flecs_multi_observer_invoke_no_query(
729726

730727
ecs_entity_t old_system = flecs_stage_set_system(
731728
world->stages[0], o->entity);
732-
ECS_TABLE_LOCK(it->world, table);
729+
ECS_TABLE_LOCK(it->world, it->table);
733730

734731
if (o->run) {
735732
user_it.next = flecs_default_next_callback;
@@ -738,7 +735,7 @@ void flecs_multi_observer_invoke_no_query(
738735
user_it.callback(&user_it);
739736
}
740737

741-
ECS_TABLE_UNLOCK(it->world, table);
738+
ECS_TABLE_UNLOCK(it->world, it->table);
742739
flecs_stage_set_system(world->stages[0], old_system);
743740
}
744741

src/query/engine/eval_iter.c

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -579,10 +579,6 @@ int flecs_query_trivial_has_range(
579579
ecs_flags32_t flags = q->flags;
580580
ecs_flags32_t trivial_flags = EcsQueryIsTrivial|EcsQueryMatchOnlySelf;
581581

582-
/* Only handle the case where the constrained query would take the trivial
583-
* test code path. This mirrors the conditions in
584-
* flecs_query_apply_iter_flags. For anything else, signal the caller to use
585-
* the regular (full iterator) path. */
586582
if (impl->cache ||
587583
((flags & trivial_flags) != trivial_flags) ||
588584
(flags & EcsQueryMatchWildcards) ||
@@ -591,8 +587,6 @@ int flecs_query_trivial_has_range(
591587
return -1;
592588
}
593589

594-
/* Eval count is incremented unconditionally, matching ecs_query_iter and
595-
* the bloom filter reject path in ecs_query_has_range. */
596590
ECS_CONST_CAST(ecs_query_t*, q)->eval_count ++;
597591

598592
if (table && ((offset + count) > ecs_table_count(table))) {
@@ -603,9 +597,6 @@ int flecs_query_trivial_has_range(
603597
return 0;
604598
}
605599

606-
/* Build a minimal iterator for the trivial test. Unlike flecs_query_iter
607-
* this skips the var/written/op_ctx allocations and the query VM, which the
608-
* trivial test never uses. */
609600
ecs_iter_t lit = {0};
610601
lit.world = ECS_CONST_CAST(ecs_world_t*, world);
611602
lit.real_world = q->real_world;
@@ -618,8 +609,6 @@ int flecs_query_trivial_has_range(
618609
lit.offset = offset;
619610
lit.count = count;
620611

621-
/* flecs_iter_init asserts that EcsIterIsValid is not set on entry, so only
622-
* mark the iterator valid after initialization. */
623612
flecs_iter_init(lit.world, &lit, true);
624613
lit.flags |= EcsIterIsValid;
625614

src/query/engine/trav_down_cache.c

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -163,15 +163,14 @@ void flecs_trav_entity_down_iter_children(
163163
bool leaf = false;
164164

165165
/* Check if table has the component */
166-
if (flecs_component_get_table(cr_with, r->table) != NULL) {
167-
if (self) {
168-
/* If matching self and the table has the component, entity
169-
* shouldn't be matched through traversal and will instead
170-
* be matched directly. */
171-
continue;
172-
}
166+
if (self || r->table->_->traversable_count) {
167+
if (flecs_component_get_table(cr_with, r->table) != NULL) {
168+
if (self) {
169+
continue;
170+
}
173171

174-
leaf = true;
172+
leaf = true;
173+
}
175174
}
176175

177176
/* Add element to the cache for a single child */
@@ -213,11 +212,13 @@ void flecs_trav_entity_down_iter_tables(
213212
ecs_table_t *table = tr->hdr.table;
214213
bool leaf = false;
215214

216-
if (flecs_component_get_table(cr_with, table) != NULL) {
217-
if (self) {
218-
continue;
215+
if (self || table->_->traversable_count) {
216+
if (flecs_component_get_table(cr_with, table) != NULL) {
217+
if (self) {
218+
continue;
219+
}
220+
leaf = true;
219221
}
220-
leaf = true;
221222
}
222223

223224
/* If record is not the first instance of (trav, *), don't add it

src/query/query.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,6 @@ ecs_iter_t flecs_query_iter(
3838
const ecs_world_t *world,
3939
const ecs_query_t *q);
4040

41-
/* Fast path for testing a trivial query against a table range, used by
42-
* observers. Avoids creating a full query iterator. Returns 1 on match, 0 on no
43-
* match, and -1 if the query is not eligible for this path (caller must fall
44-
* back to ecs_query_has_range). On a match, populates 'it'. */
4541
int flecs_query_trivial_has_range(
4642
const ecs_query_t *q,
4743
ecs_iter_t *it,

src/query/types.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -221,9 +221,9 @@ typedef enum {
221221
} ecs_trav_direction_t;
222222

223223
typedef struct {
224-
ecs_map_t src; /* map<table_id, trav_up_t> (up direction) */
225-
ecs_trav_down_t down; /* reused buffer (down direction) */
226-
ecs_trav_up_t up; /* reused buffer for top-level up result */
224+
ecs_map_t src;
225+
ecs_trav_down_t down;
226+
ecs_trav_up_t up;
227227
ecs_id_t with;
228228
ecs_trav_direction_t dir;
229229
} ecs_trav_up_cache_t;

0 commit comments

Comments
 (0)