Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 76 additions & 7 deletions distr/flecs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1605,6 +1605,7 @@ typedef struct {
int32_t cur;
int32_t block_index;
ecs_flags64_t block;
ecs_flags64_t or_fields;
ecs_termset_t prev_set_fields;
bool optional_not;
bool has_bitset;
Expand Down Expand Up @@ -80012,13 +80013,15 @@ int flecs_query_insert_toggle(
continue;
}

const ecs_flags64_t field_bit = 1llu << term->field_index;

/* Source matches, set flag */
if (term->oper == EcsNot) {
not_toggles |= (1llu << j);
not_toggles |= field_bit;
} else if (term->oper == EcsOptional) {
optional_toggles |= (1llu << j);
optional_toggles |= field_bit;
} else {
and_toggles |= (1llu << j);
and_toggles |= field_bit;
}

fields_done |= (1llu << j);
Expand Down Expand Up @@ -80051,18 +80054,24 @@ int flecs_query_insert_toggle(
* set, separate instructions let the query engine backtrack to get
* the right results. */
if (optional_toggles) {
ecs_flags64_t optional_fields_processed = 0;
for (j = i; j < term_count; j ++) {
uint64_t field_bit = 1ull << j;
const uint64_t field_bit = 1ull << terms[j].field_index;
if (!(optional_toggles & field_bit)) {
continue;
}
if (optional_fields_processed & field_bit) {
continue;
}

ecs_query_op_t op = {0};
op.kind = EcsQueryToggleOption;
op.src = cur.src;
op.first.entity = field_bit;
op.flags = cur.flags;
flecs_query_op_insert(&op, ctx);

optional_fields_processed |= field_bit;
}
}
}
Expand Down Expand Up @@ -85225,13 +85234,54 @@ static inline int32_t flecs_ctz64(uint64_t v) {
#endif
}

static inline
void flecs_query_apply_or_mask(
const ecs_query_t *query,
ecs_table_t *table,
int32_t block_index,
int32_t field_index,
ecs_flags64_t *mask,
bool *has_bitset)
{
const ecs_term_t *terms = query->terms;
const int32_t term_count = query->term_count;
ecs_flags64_t block = 0;
bool chain_has_bitset = false;

for (int32_t i = 0; i < term_count; i ++) {
if (terms[i].field_index != field_index) {
continue;
}

ecs_id_t id = terms[i].id;
ecs_bitset_t *bs = flecs_table_get_toggle(table, id);
if (bs) {
ecs_assert((64 * block_index) < bs->size, ECS_INTERNAL_ERROR, NULL);
block |= bs->data[block_index];
chain_has_bitset = true;
} else if (ecs_table_has_id(query->world, table, id)) {
/* If a non-toggle component is present, it is always enabled
* for all entities in the table. */
block = UINT64_MAX;
break;
}
}

if (chain_has_bitset || block == UINT64_MAX) {
*mask &= block;
*has_bitset |= chain_has_bitset;
}
}

static
flecs_query_row_mask_t flecs_query_get_row_mask(
ecs_iter_t *it,
const ecs_query_t *query,
ecs_table_t *table,
int32_t block_index,
ecs_flags64_t and_fields,
ecs_flags64_t not_fields,
ecs_flags64_t or_fields,
ecs_query_toggle_ctx_t *op_ctx)
{
ecs_flags64_t mask = UINT64_MAX;
Expand All @@ -85253,6 +85303,12 @@ flecs_query_row_mask_t flecs_query_get_row_mask(
ecs_abort(ECS_INTERNAL_ERROR, NULL);
}

if ((or_fields & field_bit)) {
flecs_query_apply_or_mask(query, table, block_index,
i, &mask, &has_bitset);
continue;
}

ecs_id_t id = it->ids[i];
ecs_bitset_t *bs = flecs_table_get_toggle(table, id);
if (!bs) {
Expand Down Expand Up @@ -85288,7 +85344,7 @@ bool flecs_query_toggle_for_up(
ecs_flags64_t fields = (and_fields | not_fields) & it->up_fields;

for (i = 0; i < field_count; i ++) {
uint64_t field_bit = 1llu << i;
const uint64_t field_bit = 1llu << i;
if (!(fields & field_bit)) {
continue;
}
Expand Down Expand Up @@ -85402,7 +85458,8 @@ bool flecs_query_toggle_cmp(
block_index = op_ctx->block_index = new_block_index;

flecs_query_row_mask_t row_mask = flecs_query_get_row_mask(
it, table, block_index, and_fields, not_fields, op_ctx);
it, &ctx->query->pub, table, block_index,
and_fields, not_fields, op_ctx->or_fields, op_ctx);

/* If table doesn't have bitset columns, all columns match */
if (!(op_ctx->has_bitset = row_mask.has_bitset)) {
Expand Down Expand Up @@ -85494,6 +85551,18 @@ bool flecs_query_toggle(
ecs_query_toggle_ctx_t *op_ctx = flecs_op_ctx(ctx, toggle);
if (!redo) {
op_ctx->prev_set_fields = it->set_fields;

/* Precompute which fields have OR toggle terms */
const ecs_query_t *q = &ctx->query->pub;
ecs_flags64_t or_fields = 0;
for (int32_t i = 0; i < q->term_count; i ++) {
if (q->terms[i].oper == EcsOr &&
(q->terms[i].flags_ & EcsTermIsToggle))
{
or_fields |= (1llu << q->terms[i].field_index);
}
}
op_ctx->or_fields = or_fields;
}

ecs_flags64_t and_fields = op->first.entity;
Expand All @@ -85514,6 +85583,7 @@ bool flecs_query_toggle_option(
op_ctx->prev_set_fields = it->set_fields;
op_ctx->optional_not = false;
op_ctx->has_bitset = false;
op_ctx->or_fields = 0;
}

repeat: {}
Expand All @@ -85539,7 +85609,6 @@ repeat: {}
return result;
}


/**
* @file query/engine/eval_trav.c
* @brief Transitive/reflexive relationship traversal.
Expand Down
16 changes: 12 additions & 4 deletions src/query/compiler/compiler.c
Original file line number Diff line number Diff line change
Expand Up @@ -770,13 +770,15 @@ int flecs_query_insert_toggle(
continue;
}

const ecs_flags64_t field_bit = 1llu << term->field_index;

/* Source matches, set flag */
if (term->oper == EcsNot) {
not_toggles |= (1llu << j);
not_toggles |= field_bit;
} else if (term->oper == EcsOptional) {
optional_toggles |= (1llu << j);
optional_toggles |= field_bit;
} else {
and_toggles |= (1llu << j);
and_toggles |= field_bit;
}

fields_done |= (1llu << j);
Expand Down Expand Up @@ -809,18 +811,24 @@ int flecs_query_insert_toggle(
* set, separate instructions let the query engine backtrack to get
* the right results. */
if (optional_toggles) {
ecs_flags64_t optional_fields_processed = 0;
for (j = i; j < term_count; j ++) {
uint64_t field_bit = 1ull << j;
const uint64_t field_bit = 1ull << terms[j].field_index;
if (!(optional_toggles & field_bit)) {
continue;
}
if (optional_fields_processed & field_bit) {
continue;
}

ecs_query_op_t op = {0};
op.kind = EcsQueryToggleOption;
op.src = cur.src;
op.first.entity = field_bit;
op.flags = cur.flags;
flecs_query_op_insert(&op, ctx);

optional_fields_processed |= field_bit;
}
}
}
Expand Down
66 changes: 63 additions & 3 deletions src/query/engine/eval_toggle.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,54 @@ static inline int32_t flecs_ctz64(uint64_t v) {
#endif
}

static inline
void flecs_query_apply_or_mask(
const ecs_query_t *query,
ecs_table_t *table,
int32_t block_index,
int32_t field_index,
ecs_flags64_t *mask,
bool *has_bitset)
{
const ecs_term_t *terms = query->terms;
const int32_t term_count = query->term_count;
ecs_flags64_t block = 0;
bool chain_has_bitset = false;

for (int32_t i = 0; i < term_count; i ++) {
if (terms[i].field_index != field_index) {
continue;
}

ecs_id_t id = terms[i].id;
ecs_bitset_t *bs = flecs_table_get_toggle(table, id);
if (bs) {
ecs_assert((64 * block_index) < bs->size, ECS_INTERNAL_ERROR, NULL);
block |= bs->data[block_index];
chain_has_bitset = true;
} else if (ecs_table_has_id(query->world, table, id)) {
/* If a non-toggle component is present, it is always enabled
* for all entities in the table. */
block = UINT64_MAX;
break;
}
}

if (chain_has_bitset || block == UINT64_MAX) {
*mask &= block;
*has_bitset |= chain_has_bitset;
}
}

static
flecs_query_row_mask_t flecs_query_get_row_mask(
ecs_iter_t *it,
const ecs_query_t *query,
ecs_table_t *table,
int32_t block_index,
ecs_flags64_t and_fields,
ecs_flags64_t not_fields,
ecs_flags64_t or_fields,
ecs_query_toggle_ctx_t *op_ctx)
{
ecs_flags64_t mask = UINT64_MAX;
Expand All @@ -56,6 +97,12 @@ flecs_query_row_mask_t flecs_query_get_row_mask(
ecs_abort(ECS_INTERNAL_ERROR, NULL);
}

if ((or_fields & field_bit)) {
flecs_query_apply_or_mask(query, table, block_index,
i, &mask, &has_bitset);
continue;
}

ecs_id_t id = it->ids[i];
ecs_bitset_t *bs = flecs_table_get_toggle(table, id);
if (!bs) {
Expand Down Expand Up @@ -91,7 +138,7 @@ bool flecs_query_toggle_for_up(
ecs_flags64_t fields = (and_fields | not_fields) & it->up_fields;

for (i = 0; i < field_count; i ++) {
uint64_t field_bit = 1llu << i;
const uint64_t field_bit = 1llu << i;
if (!(fields & field_bit)) {
continue;
}
Expand Down Expand Up @@ -205,7 +252,8 @@ bool flecs_query_toggle_cmp(
block_index = op_ctx->block_index = new_block_index;

flecs_query_row_mask_t row_mask = flecs_query_get_row_mask(
it, table, block_index, and_fields, not_fields, op_ctx);
it, &ctx->query->pub, table, block_index,
and_fields, not_fields, op_ctx->or_fields, op_ctx);

/* If table doesn't have bitset columns, all columns match */
if (!(op_ctx->has_bitset = row_mask.has_bitset)) {
Expand Down Expand Up @@ -297,6 +345,18 @@ bool flecs_query_toggle(
ecs_query_toggle_ctx_t *op_ctx = flecs_op_ctx(ctx, toggle);
if (!redo) {
op_ctx->prev_set_fields = it->set_fields;

/* Precompute which fields have OR toggle terms */
const ecs_query_t *q = &ctx->query->pub;
ecs_flags64_t or_fields = 0;
for (int32_t i = 0; i < q->term_count; i ++) {
if (q->terms[i].oper == EcsOr &&
(q->terms[i].flags_ & EcsTermIsToggle))
{
or_fields |= (1llu << q->terms[i].field_index);
}
}
op_ctx->or_fields = or_fields;
}

ecs_flags64_t and_fields = op->first.entity;
Expand All @@ -317,6 +377,7 @@ bool flecs_query_toggle_option(
op_ctx->prev_set_fields = it->set_fields;
op_ctx->optional_not = false;
op_ctx->has_bitset = false;
op_ctx->or_fields = 0;
}

repeat: {}
Expand All @@ -341,4 +402,3 @@ repeat: {}

return result;
}

1 change: 1 addition & 0 deletions src/query/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,7 @@ typedef struct {
int32_t cur;
int32_t block_index;
ecs_flags64_t block;
ecs_flags64_t or_fields;
ecs_termset_t prev_set_fields;
bool optional_not;
bool has_bitset;
Expand Down
2 changes: 2 additions & 0 deletions test/query/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -2077,6 +2077,8 @@
"fixed_2_src_w_toggle",
"this_w_fixed_src_w_toggle",
"fixed_src_w_this_w_toggle",
"or_chain_3_toggleable_tags",
"or_chain_3_toggleable_components",
"this_from_nothing",
"this",
"this_skip_initial",
Expand Down
Loading
Loading