diff --git a/distr/flecs.c b/distr/flecs.c index 604ece7aa..5ea554ff3 100644 --- a/distr/flecs.c +++ b/distr/flecs.c @@ -34254,6 +34254,12 @@ int flecs_query_finalize_terms( ECS_TERMSET_SET(q->fixed_fields, 1u << term->field_index); } + if ((term->src.id & EcsIsVariable) && + (ECS_TERM_REF_ID(&term->src) != EcsThis)) + { + ECS_TERMSET_SET(q->var_fields, 1u << term->field_index); + } + ecs_id_record_t *idr = flecs_id_record_get(world, term->id); if (idr) { if (ecs_os_has_threading()) { @@ -69940,7 +69946,7 @@ ecs_iter_t flecs_query_iter( it.field_count = q->field_count; it.sizes = q->sizes; it.set_fields = q->set_fields; - it.ref_fields = q->fixed_fields | q->row_fields; + it.ref_fields = q->fixed_fields | q->row_fields | q->var_fields; it.row_fields = q->row_fields; it.up_fields = 0; flecs_query_apply_iter_flags(&it, q); diff --git a/distr/flecs.h b/distr/flecs.h index fdca87e3c..c79064403 100644 --- a/distr/flecs.h +++ b/distr/flecs.h @@ -3425,6 +3425,7 @@ struct ecs_query_t { /* Bitmasks for quick field information lookups */ ecs_termset_t fixed_fields; /**< Fields with a fixed source */ + ecs_termset_t var_fields; /**< Fields with non-$this variable source */ ecs_termset_t static_id_fields; /**< Fields with a static (component) id */ ecs_termset_t data_fields; /**< Fields that have data */ ecs_termset_t write_fields; /**< Fields that write data */ @@ -25719,17 +25720,6 @@ struct each_field { }; struct each_column_base { each_column_base(const _::field_ptr& field, size_t row) : field_(field), row_(row) { - - if (field.is_ref) { - // If this is a reference, set the row to 0 as a ref always is a - // single value, not an array. This prevents the application from - // having to do an if-check on whether the column is owned. - // - // This check only happens when the current table being iterated - // over caused the query to match a reference. The check is - // performed once per iterated table. - this->row_ = 0; - } } protected: @@ -25809,6 +25799,17 @@ struct each_ref_field : public each_field { each_ref_field(const flecs::iter_t *iter, _::field_ptr& field, size_t row) : each_field(iter, field, row) { + if (field.is_ref) { + // If this is a reference, set the row to 0 as a ref always is a + // single value, not an array. This prevents the application from + // having to do an if-check on whether the column is owned. + // + // This check only happens when the current table being iterated + // over caused the query to match a reference. The check is + // performed once per iterated table. + this->row_ = 0; + } + if (field.is_row) { field.ptr = ecs_field_at_w_size(iter, sizeof(T), field.index, static_cast(row)); @@ -25816,7 +25817,6 @@ struct each_ref_field : public each_field { } }; - // Type that handles passing components to each callbacks template struct each_delegate : public delegate { diff --git a/include/flecs.h b/include/flecs.h index 2b401fff3..6780cc7b6 100644 --- a/include/flecs.h +++ b/include/flecs.h @@ -796,6 +796,7 @@ struct ecs_query_t { /* Bitmasks for quick field information lookups */ ecs_termset_t fixed_fields; /**< Fields with a fixed source */ + ecs_termset_t var_fields; /**< Fields with non-$this variable source */ ecs_termset_t static_id_fields; /**< Fields with a static (component) id */ ecs_termset_t data_fields; /**< Fields that have data */ ecs_termset_t write_fields; /**< Fields that write data */ diff --git a/include/flecs/addons/cpp/delegate.hpp b/include/flecs/addons/cpp/delegate.hpp index fdc9c0f73..c13ca8836 100644 --- a/include/flecs/addons/cpp/delegate.hpp +++ b/include/flecs/addons/cpp/delegate.hpp @@ -122,17 +122,6 @@ struct each_field { }; struct each_column_base { each_column_base(const _::field_ptr& field, size_t row) : field_(field), row_(row) { - - if (field.is_ref) { - // If this is a reference, set the row to 0 as a ref always is a - // single value, not an array. This prevents the application from - // having to do an if-check on whether the column is owned. - // - // This check only happens when the current table being iterated - // over caused the query to match a reference. The check is - // performed once per iterated table. - this->row_ = 0; - } } protected: @@ -212,6 +201,17 @@ struct each_ref_field : public each_field { each_ref_field(const flecs::iter_t *iter, _::field_ptr& field, size_t row) : each_field(iter, field, row) { + if (field.is_ref) { + // If this is a reference, set the row to 0 as a ref always is a + // single value, not an array. This prevents the application from + // having to do an if-check on whether the column is owned. + // + // This check only happens when the current table being iterated + // over caused the query to match a reference. The check is + // performed once per iterated table. + this->row_ = 0; + } + if (field.is_row) { field.ptr = ecs_field_at_w_size(iter, sizeof(T), field.index, static_cast(row)); @@ -219,7 +219,6 @@ struct each_ref_field : public each_field { } }; - // Type that handles passing components to each callbacks template struct each_delegate : public delegate { diff --git a/src/query/engine/eval_iter.c b/src/query/engine/eval_iter.c index 452c65bc7..1c128fe93 100644 --- a/src/query/engine/eval_iter.c +++ b/src/query/engine/eval_iter.c @@ -302,7 +302,7 @@ ecs_iter_t flecs_query_iter( it.field_count = q->field_count; it.sizes = q->sizes; it.set_fields = q->set_fields; - it.ref_fields = q->fixed_fields | q->row_fields; + it.ref_fields = q->fixed_fields | q->row_fields | q->var_fields; it.row_fields = q->row_fields; it.up_fields = 0; flecs_query_apply_iter_flags(&it, q); diff --git a/src/query/validator.c b/src/query/validator.c index 718f39ab7..18fca9036 100644 --- a/src/query/validator.c +++ b/src/query/validator.c @@ -1269,6 +1269,12 @@ int flecs_query_finalize_terms( ECS_TERMSET_SET(q->fixed_fields, 1u << term->field_index); } + if ((term->src.id & EcsIsVariable) && + (ECS_TERM_REF_ID(&term->src) != EcsThis)) + { + ECS_TERMSET_SET(q->var_fields, 1u << term->field_index); + } + ecs_id_record_t *idr = flecs_id_record_get(world, term->id); if (idr) { if (ecs_os_has_threading()) { diff --git a/test/cpp/src/Query.cpp b/test/cpp/src/Query.cpp index 0d6d37479..410663de4 100644 --- a/test/cpp/src/Query.cpp +++ b/test/cpp/src/Query.cpp @@ -605,7 +605,7 @@ void Query_run(void) { world.component(); world.component(); - auto entity = flecs::entity(world) + auto entity = world.entity() .set({10, 20}) .set({1, 2}); @@ -634,7 +634,7 @@ void Query_run_const(void) { world.component(); world.component(); - auto entity = flecs::entity(world) + auto entity = world.entity() .set({10, 20}) .set({1, 2}); @@ -663,14 +663,14 @@ void Query_run_shared(void) { world.component().add(flecs::OnInstantiate, flecs::Inherit); world.component().add(flecs::OnInstantiate, flecs::Inherit); - auto base = flecs::entity(world) + auto base = world.entity() .set({1, 2}); - auto e1 = flecs::entity(world) + auto e1 = world.entity() .set({10, 20}) .add(flecs::IsA, base); - auto e2 = flecs::entity(world) + auto e2 = world.entity() .set({10, 20}) .set({3, 4}); @@ -713,20 +713,20 @@ void Query_run_optional(void) { world.component(); flecs::component(world, "Mass"); - auto e1 = flecs::entity(world) + auto e1 = world.entity() .set({10, 20}) .set({1, 2}) .set({1}); - auto e2 = flecs::entity(world) + auto e2 = world.entity() .set({30, 40}) .set({3, 4}) .set({1}); - auto e3 = flecs::entity(world) + auto e3 = world.entity() .set({50, 60}); - auto e4 = flecs::entity(world) + auto e4 = world.entity() .set({70, 80}); auto q = world.query(); @@ -774,7 +774,7 @@ void Query_run_sparse(void) { world.component().add(flecs::Sparse); world.component(); - auto entity = flecs::entity(world) + auto entity = world.entity() .set({10, 20}) .set({1, 2}); @@ -803,7 +803,7 @@ void Query_each(void) { world.component(); world.component(); - auto entity = flecs::entity(world) + auto entity = world.entity() .set({10, 20}) .set({1, 2}); @@ -825,7 +825,7 @@ void Query_each_const(void) { world.component(); world.component(); - auto entity = flecs::entity(world) + auto entity = world.entity() .set({10, 20}) .set({1, 2}); @@ -847,18 +847,18 @@ void Query_each_shared(void) { world.component(); world.component(); - auto base = flecs::entity(world) + auto base = world.entity() .set({1, 2}); - auto e1 = flecs::entity(world) + auto e1 = world.entity() .set({10, 20}) .add(flecs::IsA, base); - auto e2 = flecs::entity(world) + auto e2 = world.entity() .set({20, 30}) .add(flecs::IsA, base); - auto e3 = flecs::entity(world) + auto e3 = world.entity() .set({10, 20}) .set({3, 4}); @@ -889,20 +889,20 @@ void Query_each_optional(void) { world.component(); flecs::component(world, "Mass"); - auto e1 = flecs::entity(world) + auto e1 = world.entity() .set({10, 20}) .set({1, 2}) .set({1}); - auto e2 = flecs::entity(world) + auto e2 = world.entity() .set({30, 40}) .set({3, 4}) .set({1}); - auto e3 = flecs::entity(world) + auto e3 = world.entity() .set({50, 60}); - auto e4 = flecs::entity(world) + auto e4 = world.entity() .set({70, 80}); auto q = world.query(); @@ -940,7 +940,7 @@ void Query_each_sparse(void) { world.component().add(flecs::Sparse); world.component(); - auto entity = flecs::entity(world) + auto entity = world.entity() .set({10, 20}) .set({1, 2}); @@ -1004,7 +1004,7 @@ void Query_signature(void) { world.component(); world.component(); - auto entity = flecs::entity(world) + auto entity = world.entity() .set({10, 20}) .set({1, 2}); @@ -1033,7 +1033,7 @@ void Query_signature_const(void) { world.component(); world.component(); - auto entity = flecs::entity(world) + auto entity = world.entity() .set({10, 20}) .set({1, 2}); @@ -1062,14 +1062,14 @@ void Query_signature_shared(void) { world.component().add(flecs::OnInstantiate, flecs::Inherit); world.component().add(flecs::OnInstantiate, flecs::Inherit); - auto base = flecs::entity(world) + auto base = world.entity() .set({1, 2}); - auto e1 = flecs::entity(world) + auto e1 = world.entity() .set({10, 20}) .add(flecs::IsA, base); - auto e2 = flecs::entity(world) + auto e2 = world.entity() .set({10, 20}) .set({3, 4}); @@ -1112,20 +1112,20 @@ void Query_signature_optional(void) { world.component(); flecs::component(world, "Mass"); - auto e1 = flecs::entity(world) + auto e1 = world.entity() .set({10, 20}) .set({1, 2}) .set({1}); - auto e2 = flecs::entity(world) + auto e2 = world.entity() .set({30, 40}) .set({3, 4}) .set({1}); - auto e3 = flecs::entity(world) + auto e3 = world.entity() .set({50, 60}); - auto e4 = flecs::entity(world) + auto e4 = world.entity() .set({70, 80}); auto q = world.query_builder<>().expr("Position, ?Velocity, ?Mass").build(); @@ -1170,8 +1170,8 @@ void Query_signature_optional(void) { void Query_query_single_pair(void) { flecs::world world; - flecs::entity(world).add(); - auto e2 = flecs::entity(world).add(); + world.entity().add(); + auto e2 = world.entity().add(); auto q = world.query_builder<>() .expr("(Pair, Velocity)") @@ -2944,11 +2944,11 @@ void Query_empty_tables_each(void) { world.component(); world.component(); - auto e1 = flecs::entity(world) + auto e1 = world.entity() .set({10, 20}) .set({1, 2}); - auto e2 = flecs::entity(world) + auto e2 = world.entity() .set({20, 30}) .set({2, 3}); @@ -2983,11 +2983,11 @@ void Query_empty_tables_each_w_entity(void) { world.component(); world.component(); - auto e1 = flecs::entity(world) + auto e1 = world.entity() .set({10, 20}) .set({1, 2}); - auto e2 = flecs::entity(world) + auto e2 = world.entity() .set({20, 30}) .set({2, 3}); @@ -3022,11 +3022,11 @@ void Query_empty_tables_each_w_iter(void) { world.component(); world.component(); - auto e1 = flecs::entity(world) + auto e1 = world.entity() .set({10, 20}) .set({1, 2}); - auto e2 = flecs::entity(world) + auto e2 = world.entity() .set({20, 30}) .set({2, 3}); @@ -3065,32 +3065,27 @@ void Query_pair_with_variable_src(void) { world.component(); world.component(); - auto other = flecs::entity(world) - .set(OtherComp{0}); - - // Guaranty we don't lukily hit zero if we read the the wrong component - flecs::entity(world) - .set(OtherComp{1}); + auto other = world.entity() + .set(OtherComp{10}); - for (int i = 0; i < 3; ++i) - flecs::entity(world) + for (int i = 0; i < 3; ++i) { + world.entity() .set(ThisComp{i}) .add(other); + } - { - auto q = world.query_builder() - .term_at(0).second("$other") - .term_at(2).src("$other") - .build(); - - size_t isPresentBitField = 0; - q.each([&isPresentBitField](Rel const &rel, ThisComp const &thisComp, OtherComp const &otherComp) { - isPresentBitField |= (1 << thisComp.x); - test_int(otherComp.x, 0); - }); + auto q = world.query_builder() + .term_at(0).second("$other") + .term_at(2).src("$other") + .build(); - test_int(isPresentBitField, 7); - } + size_t isPresent = 0; + q.each([&isPresent](const Rel& rel, const ThisComp& thisComp, const OtherComp& otherComp) { + isPresent |= (1 << thisComp.x); + test_int(otherComp.x, 10); + }); + + test_int(isPresent, 7); } void Query_pair_with_variable_src_no_row_fields(void) { @@ -3104,30 +3099,29 @@ void Query_pair_with_variable_src_no_row_fields(void) { world.component(); world.component(); - auto other = flecs::entity(world) + auto other = world.entity() .set(OtherComp{0}); - // Guaranty we don't lukily hit zero if we read the the wrong component - flecs::entity(world) + // Guarantee we don't luckily hit zero if we read the the wrong component + world.entity() .set(OtherComp{1}); - for (int i = 0; i < 3; ++i) - flecs::entity(world) + for (int i = 0; i < 3; ++i) { + world.entity() .set(ThisComp{i}) .add(other); + } - { - auto q = world.query_builder() - .term_at(0).second("$other") - .term_at(2).src("$other") - .build(); - - size_t isPresentBitField = 0; - q.each([&isPresentBitField](Rel const &rel, ThisComp const &thisComp, OtherComp const &otherComp) { - isPresentBitField |= (1 << thisComp.x); - test_int(otherComp.x, 0); - }); + auto q = world.query_builder() + .term_at(0).second("$other") + .term_at(2).src("$other") + .build(); - test_int(isPresentBitField, 7); - } + size_t isPresent = 0; + q.each([&isPresent](const Rel& rel, const ThisComp& thisComp, const OtherComp& otherComp) { + isPresent |= (1 << thisComp.x); + test_int(otherComp.x, 0); + }); + + test_int(isPresent, 7); } diff --git a/test/query/project.json b/test/query/project.json index 8c6720fad..d44e6547d 100644 --- a/test/query/project.json +++ b/test/query/project.json @@ -674,7 +674,12 @@ "match_empty_w_order_by", "match_new_empty_w_order_by", "match_empty_w_bitset", - "default_query_flags" + "default_query_flags", + "ref_fields_this", + "ref_fields_static_src", + "ref_fields_variable_src", + "ref_fields_up_src", + "ref_fields_self_up_src" ] }, { "id": "Combinations", diff --git a/test/query/src/Basic.c b/test/query/src/Basic.c index 089dd97a8..9c27ca05b 100644 --- a/test/query/src/Basic.c +++ b/test/query/src/Basic.c @@ -10512,3 +10512,232 @@ void Basic_default_query_flags(void) { ecs_fini(world); } + +void Basic_ref_fields_this(void) { + ecs_world_t *world = ecs_mini(); + + ECS_COMPONENT(world, Position); + + ecs_entity_t e1 = ecs_insert(world, ecs_value(Position, {10, 20})); + ecs_entity_t e2 = ecs_insert(world, ecs_value(Position, {30, 40})); + ecs_entity_t e3 = ecs_insert(world, ecs_value(Position, {50, 60})); + + ecs_query_t *q = ecs_query(world, { + .terms = {{ .id = ecs_id(Position) }}, + .cache_kind = cache_kind + }); + + test_assert(q != NULL); + + ecs_iter_t it = ecs_query_iter(world, q); + test_bool(true, ecs_query_next(&it)); + test_int(it.count, 3); + test_uint(it.entities[0], e1); + test_uint(it.entities[1], e2); + test_uint(it.entities[2], e3); + test_uint(ecs_id(Position), ecs_field_id(&it, 0)); + test_uint(0, ecs_field_src(&it, 0)); + test_uint(0, it.ref_fields); + test_uint(0, it.row_fields); + test_uint(0, it.up_fields); + const Position *p = ecs_field(&it, Position, 0); + test_assert(p != NULL); + test_int(p[0].x, 10); test_int(p[0].y, 20); + test_int(p[1].x, 30); test_int(p[1].y, 40); + test_int(p[2].x, 50); test_int(p[2].y, 60); + + test_bool(false, ecs_query_next(&it)); + + ecs_query_fini(q); + + ecs_fini(world); +} + +void Basic_ref_fields_static_src(void) { + ecs_world_t *world = ecs_mini(); + + ECS_COMPONENT(world, Position); + + /* ecs_entity_t e1 = */ ecs_insert(world, ecs_value(Position, {10, 20})); + /* ecs_entity_t e2 = */ ecs_insert(world, ecs_value(Position, {30, 40})); + ecs_entity_t e3 = ecs_insert(world, ecs_value(Position, {50, 60})); + + ecs_query_t *q = ecs_query(world, { + .terms = {{ .id = ecs_id(Position), .src.id = e3 }}, + .cache_kind = cache_kind + }); + + test_assert(q != NULL); + + ecs_iter_t it = ecs_query_iter(world, q); + test_bool(true, ecs_query_next(&it)); + test_int(it.count, 0); + test_uint(ecs_id(Position), ecs_field_id(&it, 0)); + test_uint(e3, ecs_field_src(&it, 0)); + test_uint(1, it.ref_fields); + test_uint(0, it.row_fields); + test_uint(0, it.up_fields); + const Position *p = ecs_field(&it, Position, 0); + test_assert(p != NULL); + test_int(p[0].x, 50); test_int(p[0].y, 60); + + test_bool(false, ecs_query_next(&it)); + + ecs_query_fini(q); + + ecs_fini(world); +} + +void Basic_ref_fields_variable_src(void) { + ecs_world_t *world = ecs_mini(); + + ECS_COMPONENT(world, Position); + + ecs_entity_t e1 = ecs_insert(world, ecs_value(Position, {10, 20})); + ecs_entity_t e2 = ecs_insert(world, ecs_value(Position, {30, 40})); + ecs_entity_t e3 = ecs_insert(world, ecs_value(Position, {50, 60})); + + ecs_query_t *q = ecs_query(world, { + .terms = {{ .id = ecs_id(Position), .src.name = "$x" }}, + .cache_kind = cache_kind + }); + + test_assert(q != NULL); + int x_var = ecs_query_find_var(q, "x"); + test_assert(x_var != -1); + + ecs_iter_t it = ecs_query_iter(world, q); + test_bool(true, ecs_query_next(&it)); + test_int(it.count, 0); + test_uint(ecs_id(Position), ecs_field_id(&it, 0)); + test_uint(e1, ecs_field_src(&it, 0)); + test_uint(e1, ecs_iter_get_var(&it, x_var)); + test_uint(1, it.ref_fields); + test_uint(0, it.row_fields); + test_uint(0, it.up_fields); + { const Position *p = ecs_field(&it, Position, 0); + test_assert(p != NULL); + test_int(p[0].x, 10); test_int(p[0].y, 20); } + + test_bool(true, ecs_query_next(&it)); + test_int(it.count, 0); + test_uint(ecs_id(Position), ecs_field_id(&it, 0)); + test_uint(e2, ecs_field_src(&it, 0)); + test_uint(e2, ecs_iter_get_var(&it, x_var)); + test_uint(1, it.ref_fields); + test_uint(0, it.row_fields); + test_uint(0, it.up_fields); + { const Position *p = ecs_field(&it, Position, 0); + test_assert(p != NULL); + test_int(p[0].x, 30); test_int(p[0].y, 40); } + + test_bool(true, ecs_query_next(&it)); + test_int(it.count, 0); + test_uint(ecs_id(Position), ecs_field_id(&it, 0)); + test_uint(e3, ecs_field_src(&it, 0)); + test_uint(e3, ecs_iter_get_var(&it, x_var)); + test_uint(1, it.ref_fields); + test_uint(0, it.row_fields); + test_uint(0, it.up_fields); + { const Position *p = ecs_field(&it, Position, 0); + test_assert(p != NULL); + test_int(p[0].x, 50); test_int(p[0].y, 60); } + + test_bool(false, ecs_query_next(&it)); + + ecs_query_fini(q); + + ecs_fini(world); +} + +void Basic_ref_fields_up_src(void) { + ecs_world_t *world = ecs_mini(); + + ECS_COMPONENT(world, Position); + + /* ecs_entity_t e1 = */ ecs_insert(world, ecs_value(Position, {10, 20})); + /* ecs_entity_t e2 = */ ecs_insert(world, ecs_value(Position, {30, 40})); + ecs_entity_t e3 = ecs_insert(world, ecs_value(Position, {50, 60})); + + ecs_entity_t child = ecs_new_w_pair(world, EcsChildOf, e3); + + ecs_query_t *q = ecs_query(world, { + .terms = {{ .id = ecs_id(Position), .src.id = EcsUp }}, + .cache_kind = cache_kind + }); + + test_assert(q != NULL); + + ecs_iter_t it = ecs_query_iter(world, q); + test_bool(true, ecs_query_next(&it)); + test_int(it.count, 1); + test_uint(it.entities[0], child); + test_uint(ecs_id(Position), ecs_field_id(&it, 0)); + test_uint(e3, ecs_field_src(&it, 0)); + test_uint(0, it.ref_fields); + test_uint(0, it.row_fields); + test_uint(1, it.up_fields); + const Position *p = ecs_field(&it, Position, 0); + test_assert(p != NULL); + test_int(p[0].x, 50); test_int(p[0].y, 60); + + test_bool(false, ecs_query_next(&it)); + + ecs_query_fini(q); + + ecs_fini(world); +} + +void Basic_ref_fields_self_up_src(void) { + ecs_world_t *world = ecs_mini(); + + ECS_COMPONENT(world, Position); + + ecs_entity_t e1 = ecs_insert(world, ecs_value(Position, {10, 20})); + ecs_entity_t e2 = ecs_insert(world, ecs_value(Position, {30, 40})); + ecs_entity_t e3 = ecs_insert(world, ecs_value(Position, {50, 60})); + + ecs_entity_t child = ecs_new_w_pair(world, EcsChildOf, e3); + + ecs_query_t *q = ecs_query(world, { + .terms = {{ .id = ecs_id(Position), .src.id = EcsSelf|EcsUp }}, + .cache_kind = cache_kind + }); + + test_assert(q != NULL); + + ecs_iter_t it = ecs_query_iter(world, q); + test_bool(true, ecs_query_next(&it)); + test_int(it.count, 3); + test_uint(it.entities[0], e1); + test_uint(it.entities[1], e2); + test_uint(it.entities[2], e3); + test_uint(ecs_id(Position), ecs_field_id(&it, 0)); + test_uint(0, ecs_field_src(&it, 0)); + test_uint(0, it.ref_fields); + test_uint(0, it.row_fields); + test_uint(0, it.up_fields); + { const Position *p = ecs_field(&it, Position, 0); + test_assert(p != NULL); + test_int(p[0].x, 10); test_int(p[0].y, 20); + test_int(p[1].x, 30); test_int(p[1].y, 40); + test_int(p[2].x, 50); test_int(p[2].y, 60); } + + test_bool(true, ecs_query_next(&it)); + test_int(it.count, 1); + test_uint(it.entities[0], child); + test_uint(ecs_id(Position), ecs_field_id(&it, 0)); + test_uint(e3, ecs_field_src(&it, 0)); + test_uint(0, it.ref_fields); + test_uint(0, it.row_fields); + test_uint(1, it.up_fields); + { const Position *p = ecs_field(&it, Position, 0); + test_assert(p != NULL); + test_int(p[0].x, 50); test_int(p[0].y, 60); } + + test_bool(false, ecs_query_next(&it)); + + ecs_query_fini(q); + + ecs_fini(world); +} diff --git a/test/query/src/main.c b/test/query/src/main.c index 48915173a..aeec6141d 100644 --- a/test/query/src/main.c +++ b/test/query/src/main.c @@ -663,6 +663,11 @@ void Basic_match_empty_w_order_by(void); void Basic_match_new_empty_w_order_by(void); void Basic_match_empty_w_bitset(void); void Basic_default_query_flags(void); +void Basic_ref_fields_this(void); +void Basic_ref_fields_static_src(void); +void Basic_ref_fields_variable_src(void); +void Basic_ref_fields_up_src(void); +void Basic_ref_fields_self_up_src(void); // Testsuite 'Combinations' void Combinations_setup(void); @@ -4653,6 +4658,26 @@ bake_test_case Basic_testcases[] = { { "default_query_flags", Basic_default_query_flags + }, + { + "ref_fields_this", + Basic_ref_fields_this + }, + { + "ref_fields_static_src", + Basic_ref_fields_static_src + }, + { + "ref_fields_variable_src", + Basic_ref_fields_variable_src + }, + { + "ref_fields_up_src", + Basic_ref_fields_up_src + }, + { + "ref_fields_self_up_src", + Basic_ref_fields_self_up_src } }; @@ -10127,7 +10152,7 @@ static bake_test_suite suites[] = { "Basic", Basic_setup, NULL, - 207, + 212, Basic_testcases, 1, Basic_params