Skip to content

Commit

Permalink
Fix issue with query change detection for terms with static sources
Browse files Browse the repository at this point in the history
  • Loading branch information
SanderMertens committed Jul 20, 2023
1 parent 0c68408 commit f9c7c3d
Show file tree
Hide file tree
Showing 5 changed files with 175 additions and 59 deletions.
87 changes: 58 additions & 29 deletions flecs.c
Original file line number Diff line number Diff line change
Expand Up @@ -56099,21 +56099,26 @@ void flecs_query_get_dirty_state(
table_dirty_state_t *out)
{
ecs_world_t *world = query->filter.world;
ecs_entity_t subject = match->sources[term];
ecs_entity_t src = match->sources[term];
ecs_table_t *table;
int32_t column = -1;

if (!subject) {
if (!src) {
table = match->table;
column = match->storage_columns[term];
} else {
table = ecs_get_table(world, subject);
int32_t ref_index = -match->columns[term] - 1;
ecs_ref_t *ref = ecs_vec_get_t(&match->refs, ecs_ref_t, ref_index);
if (ref->id != 0) {
ecs_ref_update(world, ref);
column = ref->tr->column;
column = ecs_table_type_to_storage_index(table, column);
const ecs_filter_t *filter = &query->filter;
table = ecs_get_table(world, src);
if (ecs_term_match_this(&filter->terms[term])) {
int32_t ref_index = -match->columns[term] - 1;
ecs_ref_t *ref = ecs_vec_get_t(&match->refs, ecs_ref_t, ref_index);
if (ref->id != 0) {
ecs_ref_update(world, ref);
column = ref->tr->column;
column = ecs_table_type_to_storage_index(table, column);
}
} else {
column = match->columns[term];
}
}

Expand Down Expand Up @@ -56158,11 +56163,6 @@ bool flecs_query_get_match_monitor(
continue; /* If term isn't read, don't monitor */
}

/* If term is not matched on this, don't track */
if (!ecs_term_match_this(&f->terms[i])) {
continue;
}

int32_t column = match->columns[t];
if (column == 0) {
continue; /* Don't track terms that aren't matched */
Expand Down Expand Up @@ -56226,10 +56226,11 @@ void flecs_query_sync_match_monitor(
if (monitor[t + 1] == -1) {
continue;
}

flecs_query_get_dirty_state(query, match, t, &cur);
if (cur.column < 0) {
continue;
// continue;
cur.column = -(cur.column + 1);
}

monitor[t + 1] = cur.dirty_state[cur.column + 1];
Expand Down Expand Up @@ -56315,9 +56316,10 @@ bool flecs_query_check_match_monitor(
}
}

bool has_flat = false;
ecs_world_t *world = query->filter.world;
int32_t i, field_count = query->filter.field_count;
bool has_flat = false, is_this = false;
const ecs_filter_t *filter = &query->filter;
ecs_world_t *world = filter->world;
int32_t i, j, field_count = filter->field_count;
int32_t *storage_columns = match->storage_columns;
int32_t *columns = it ? it->columns : NULL;
if (!columns) {
Expand All @@ -56331,7 +56333,7 @@ bool flecs_query_check_match_monitor(
}

int32_t column = storage_columns[i];
if (column >= 0) {
if (columns[i] >= 0) {
/* owned component */
ecs_assert(dirty_state != NULL, ECS_INTERNAL_ERROR, NULL);
if (mon != dirty_state[column + 1]) {
Expand All @@ -56351,19 +56353,46 @@ bool flecs_query_check_match_monitor(
ecs_assert(column < 0, ECS_INTERNAL_ERROR, NULL);
column = -column;

/* Find term index from field index, which differ when using || */
int32_t term_index = i;
if (filter->terms[i].field_index != i) {
for (j = i; j < filter->term_count; j ++) {
if (filter->terms[j].field_index == i) {
term_index = j;
break;
}
}
}

is_this = ecs_term_match_this(&filter->terms[term_index]);

/* Flattened fields are encoded by adding field_count to the column
* index of the parent component. */
if (it && (column > field_count)) {
if (is_this && it && (column > field_count)) {
has_flat = true;
} else {
int32_t ref_index = column - 1;
ecs_ref_t *ref = ecs_vec_get_t(refs, ecs_ref_t, ref_index);
if (ref->id != 0) {
ecs_ref_update(world, ref);
ecs_table_record_t *tr = ref->tr;
ecs_table_t *src_table = tr->hdr.table;
column = tr->column;
column = ecs_table_type_to_storage_index(src_table, column);
if (is_this) {
/* Component reached through traversal from this */
int32_t ref_index = column - 1;
ecs_ref_t *ref = ecs_vec_get_t(refs, ecs_ref_t, ref_index);
if (ref->id != 0) {
ecs_ref_update(world, ref);
ecs_table_record_t *tr = ref->tr;
ecs_table_t *src_table = tr->hdr.table;
column = tr->column;
column = ecs_table_type_to_storage_index(src_table, column);
int32_t *src_dirty_state = flecs_table_get_dirty_state(
world, src_table);
if (mon != src_dirty_state[column + 1]) {
return true;
}
}
} else {
/* Component from static source */
ecs_entity_t src = match->sources[i];
ecs_table_t *src_table = ecs_get_table(world, src);
ecs_assert(src_table != NULL, ECS_INTERNAL_ERROR, NULL);
column = ecs_table_type_to_storage_index(src_table, column - 1);
int32_t *src_dirty_state = flecs_table_get_dirty_state(
world, src_table);
if (mon != src_dirty_state[column + 1]) {
Expand Down
87 changes: 58 additions & 29 deletions src/query.c
Original file line number Diff line number Diff line change
Expand Up @@ -418,21 +418,26 @@ void flecs_query_get_dirty_state(
table_dirty_state_t *out)
{
ecs_world_t *world = query->filter.world;
ecs_entity_t subject = match->sources[term];
ecs_entity_t src = match->sources[term];
ecs_table_t *table;
int32_t column = -1;

if (!subject) {
if (!src) {
table = match->table;
column = match->storage_columns[term];
} else {
table = ecs_get_table(world, subject);
int32_t ref_index = -match->columns[term] - 1;
ecs_ref_t *ref = ecs_vec_get_t(&match->refs, ecs_ref_t, ref_index);
if (ref->id != 0) {
ecs_ref_update(world, ref);
column = ref->tr->column;
column = ecs_table_type_to_storage_index(table, column);
const ecs_filter_t *filter = &query->filter;
table = ecs_get_table(world, src);
if (ecs_term_match_this(&filter->terms[term])) {
int32_t ref_index = -match->columns[term] - 1;
ecs_ref_t *ref = ecs_vec_get_t(&match->refs, ecs_ref_t, ref_index);
if (ref->id != 0) {
ecs_ref_update(world, ref);
column = ref->tr->column;
column = ecs_table_type_to_storage_index(table, column);
}
} else {
column = match->columns[term];
}
}

Expand Down Expand Up @@ -477,11 +482,6 @@ bool flecs_query_get_match_monitor(
continue; /* If term isn't read, don't monitor */
}

/* If term is not matched on this, don't track */
if (!ecs_term_match_this(&f->terms[i])) {
continue;
}

int32_t column = match->columns[t];
if (column == 0) {
continue; /* Don't track terms that aren't matched */
Expand Down Expand Up @@ -545,10 +545,11 @@ void flecs_query_sync_match_monitor(
if (monitor[t + 1] == -1) {
continue;
}

flecs_query_get_dirty_state(query, match, t, &cur);
if (cur.column < 0) {
continue;
// continue;
cur.column = -(cur.column + 1);
}

monitor[t + 1] = cur.dirty_state[cur.column + 1];
Expand Down Expand Up @@ -634,9 +635,10 @@ bool flecs_query_check_match_monitor(
}
}

bool has_flat = false;
ecs_world_t *world = query->filter.world;
int32_t i, field_count = query->filter.field_count;
bool has_flat = false, is_this = false;
const ecs_filter_t *filter = &query->filter;
ecs_world_t *world = filter->world;
int32_t i, j, field_count = filter->field_count;
int32_t *storage_columns = match->storage_columns;
int32_t *columns = it ? it->columns : NULL;
if (!columns) {
Expand All @@ -650,7 +652,7 @@ bool flecs_query_check_match_monitor(
}

int32_t column = storage_columns[i];
if (column >= 0) {
if (columns[i] >= 0) {
/* owned component */
ecs_assert(dirty_state != NULL, ECS_INTERNAL_ERROR, NULL);
if (mon != dirty_state[column + 1]) {
Expand All @@ -670,19 +672,46 @@ bool flecs_query_check_match_monitor(
ecs_assert(column < 0, ECS_INTERNAL_ERROR, NULL);
column = -column;

/* Find term index from field index, which differ when using || */
int32_t term_index = i;
if (filter->terms[i].field_index != i) {
for (j = i; j < filter->term_count; j ++) {
if (filter->terms[j].field_index == i) {
term_index = j;
break;
}
}
}

is_this = ecs_term_match_this(&filter->terms[term_index]);

/* Flattened fields are encoded by adding field_count to the column
* index of the parent component. */
if (it && (column > field_count)) {
if (is_this && it && (column > field_count)) {
has_flat = true;
} else {
int32_t ref_index = column - 1;
ecs_ref_t *ref = ecs_vec_get_t(refs, ecs_ref_t, ref_index);
if (ref->id != 0) {
ecs_ref_update(world, ref);
ecs_table_record_t *tr = ref->tr;
ecs_table_t *src_table = tr->hdr.table;
column = tr->column;
column = ecs_table_type_to_storage_index(src_table, column);
if (is_this) {
/* Component reached through traversal from this */
int32_t ref_index = column - 1;
ecs_ref_t *ref = ecs_vec_get_t(refs, ecs_ref_t, ref_index);
if (ref->id != 0) {
ecs_ref_update(world, ref);
ecs_table_record_t *tr = ref->tr;
ecs_table_t *src_table = tr->hdr.table;
column = tr->column;
column = ecs_table_type_to_storage_index(src_table, column);
int32_t *src_dirty_state = flecs_table_get_dirty_state(
world, src_table);
if (mon != src_dirty_state[column + 1]) {
return true;
}
}
} else {
/* Component from static source */
ecs_entity_t src = match->sources[i];
ecs_table_t *src_table = ecs_get_table(world, src);
ecs_assert(src_table != NULL, ECS_INTERNAL_ERROR, NULL);
column = ecs_table_type_to_storage_index(src_table, column - 1);
int32_t *src_dirty_state = flecs_table_get_dirty_state(
world, src_table);
if (mon != src_dirty_state[column + 1]) {
Expand Down
1 change: 1 addition & 0 deletions test/api/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -1501,6 +1501,7 @@
"query_changed_or",
"query_changed_w_singleton",
"query_changed_w_only_singleton",
"query_changed_w_only_singleton_after_set",
"subquery_match_existing",
"subquery_match_new",
"subquery_inactive",
Expand Down
52 changes: 52 additions & 0 deletions test/api/src/Query.c
Original file line number Diff line number Diff line change
Expand Up @@ -3148,6 +3148,58 @@ void Query_query_changed_w_only_singleton() {
ecs_fini(world);
}

void Query_query_changed_w_only_singleton_after_set() {
ecs_world_t *world = ecs_mini();

ECS_COMPONENT(world, Position);

ecs_singleton_set(world, Position, {1, 2});

ecs_query_t *q = ecs_query(world, {
.filter.terms = {{
.id = ecs_id(Position),
.src.id = ecs_id(Position)
}}
});

{
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_bool(true, ecs_query_changed(NULL, &it));
test_int(0, it.count);
Position *p = ecs_field(&it, Position, 1);
test_int(p->x, 1);
test_int(p->y, 2);
test_bool(false, ecs_query_next(&it));
}

{
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_bool(false, ecs_query_changed(NULL, &it));
test_int(0, it.count);
Position *p = ecs_field(&it, Position, 1);
test_int(p->x, 1);
test_int(p->y, 2);
test_bool(false, ecs_query_next(&it));
}

ecs_singleton_set(world, Position, {3, 4});

{
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_bool(true, ecs_query_changed(NULL, &it));
test_int(0, it.count);
Position *p = ecs_field(&it, Position, 1);
test_int(p->x, 3);
test_int(p->y, 4);
test_bool(false, ecs_query_next(&it));
}

ecs_fini(world);
}

void Query_subquery_match_existing() {
ecs_world_t *world = ecs_mini();

Expand Down
7 changes: 6 additions & 1 deletion test/api/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1438,6 +1438,7 @@ void Query_query_changed_w_or(void);
void Query_query_changed_or(void);
void Query_query_changed_w_singleton(void);
void Query_query_changed_w_only_singleton(void);
void Query_query_changed_w_only_singleton_after_set(void);
void Query_subquery_match_existing(void);
void Query_subquery_match_new(void);
void Query_subquery_inactive(void);
Expand Down Expand Up @@ -8103,6 +8104,10 @@ bake_test_case Query_testcases[] = {
"query_changed_w_only_singleton",
Query_query_changed_w_only_singleton
},
{
"query_changed_w_only_singleton_after_set",
Query_query_changed_w_only_singleton_after_set
},
{
"subquery_match_existing",
Query_subquery_match_existing
Expand Down Expand Up @@ -12661,7 +12666,7 @@ static bake_test_suite suites[] = {
"Query",
NULL,
NULL,
208,
209,
Query_testcases
},
{
Expand Down

0 comments on commit f9c7c3d

Please sign in to comment.