From ac73c715d4dd437666404f2e69cd4e936b1e491f Mon Sep 17 00:00:00 2001 From: Tomas Slusny Date: Sun, 13 Oct 2024 07:23:44 +0200 Subject: [PATCH] Add support for type checked term_at and term_at(i) First method is simple loop over terms to find term for T. Its slower than using index directly, but sometimes type safety is more preferred and when the cost is only on initialization. Second method is same as term_at(i) but with type checked assert. For middle ground to still keep the safety but also performance. This is mostly to mirror the C# binding PR where this is slightly more useful but maybe cpp would benefit too: https://github.com/BeanCheeseBurrito/Flecs.NET/pull/52 Signed-off-by: Tomas Slusny --- distr/flecs.h | 31 ++++++++++++ .../addons/cpp/mixins/query/builder_i.hpp | 31 ++++++++++++ test/cpp/project.json | 2 + test/cpp/src/QueryBuilder.cpp | 48 +++++++++++++++++++ test/cpp/src/main.cpp | 12 ++++- 5 files changed, 123 insertions(+), 1 deletion(-) diff --git a/distr/flecs.h b/distr/flecs.h index d36f391ee..b81cfdbad 100644 --- a/distr/flecs.h +++ b/distr/flecs.h @@ -29759,6 +29759,37 @@ struct query_builder_i : term_builder_i { return *this; } + /** Sets the current term to the one with the provided type. + * This loops over all terms to find the one with the provided type. + * For performance-critical paths, use term_at(int32_t) instead. + */ + template + Base& term_at() { + flecs::id_t term_id = _::type::id(this->world_v()); + + for (int i = 0; i < term_index_; i ++) { + if (desc_->terms[i].first.id == term_id) { + return term_at(i); + } + } + + ecs_assert(ecs_term_is_initialized(this->term_), + ECS_INVALID_PARAMETER, NULL); + ecs_assert(this->term_->first.id == term_id, + ECS_INVALID_PARAMETER, "term not found"); + return *this; + } + + /** Sets the current term to the one at the provided index and asserts that the type matches. + */ + template + Base& term_at(int32_t term_index) { + this->term_at(term_index); + ecs_assert(this->term_->first.id == _::type::id(this->world_v()), + ECS_INVALID_PARAMETER, "term type mismatch"); + return *this; + } + /** Sort the output of a query. * This enables sorting of entities across matched tables. As a result of this * operation, the order of entities in the matched tables may be changed. diff --git a/include/flecs/addons/cpp/mixins/query/builder_i.hpp b/include/flecs/addons/cpp/mixins/query/builder_i.hpp index c5e7258e2..4e2476eb7 100644 --- a/include/flecs/addons/cpp/mixins/query/builder_i.hpp +++ b/include/flecs/addons/cpp/mixins/query/builder_i.hpp @@ -246,6 +246,37 @@ struct query_builder_i : term_builder_i { return *this; } + /** Sets the current term to the one with the provided type. + * This loops over all terms to find the one with the provided type. + * For performance-critical paths, use term_at(int32_t) instead. + */ + template + Base& term_at() { + flecs::id_t term_id = _::type::id(this->world_v()); + + for (int i = 0; i < term_index_; i ++) { + if (desc_->terms[i].first.id == term_id) { + return term_at(i); + } + } + + ecs_assert(ecs_term_is_initialized(this->term_), + ECS_INVALID_PARAMETER, NULL); + ecs_assert(this->term_->first.id == term_id, + ECS_INVALID_PARAMETER, "term not found"); + return *this; + } + + /** Sets the current term to the one at the provided index and asserts that the type matches. + */ + template + Base& term_at(int32_t term_index) { + this->term_at(term_index); + ecs_assert(this->term_->first.id == _::type::id(this->world_v()), + ECS_INVALID_PARAMETER, "term type mismatch"); + return *this; + } + /** Sort the output of a query. * This enables sorting of entities across matched tables. As a result of this * operation, the order of entities in the matched tables may be changed. diff --git a/test/cpp/project.json b/test/cpp/project.json index 7d35c391a..ca6ba09d9 100644 --- a/test/cpp/project.json +++ b/test/cpp/project.json @@ -747,6 +747,8 @@ "relation_w_predicate_wildcard", "add_pair_w_rel_type", "template_term", + "template_term_at", + "template_term_at_index", "explicit_subject_w_id", "explicit_subject_w_type", "explicit_object_w_id", diff --git a/test/cpp/src/QueryBuilder.cpp b/test/cpp/src/QueryBuilder.cpp index c540008f3..a466aed83 100644 --- a/test/cpp/src/QueryBuilder.cpp +++ b/test/cpp/src/QueryBuilder.cpp @@ -1592,6 +1592,54 @@ void QueryBuilder_template_term(void) { test_int(count, 1); } +void QueryBuilder_template_term_at(void) { + flecs::world ecs; + + struct Rel { int foo; }; + + int32_t count = 0; + + auto s = ecs.system() + .term_at().singleton() + .term_at().second(flecs::Wildcard) + .run([&](flecs::iter it){ + while (it.next()) { + count += it.count(); + } + }); + + ecs.entity().add(); + ecs.set({}); + + s.run(); + + test_int(count, 1); +} + +void QueryBuilder_template_term_at_index(void) { + flecs::world ecs; + + struct Rel { int foo; }; + + int32_t count = 0; + + auto s = ecs.system() + .term_at(1).singleton() + .term_at(0).second(flecs::Wildcard) + .run([&](flecs::iter it){ + while (it.next()) { + count += it.count(); + } + }); + + ecs.entity().add(); + ecs.set({}); + + s.run(); + + test_int(count, 1); +} + void QueryBuilder_explicit_subject_w_id(void) { flecs::world ecs; diff --git a/test/cpp/src/main.cpp b/test/cpp/src/main.cpp index d1fdaf7e5..2c443b1dc 100644 --- a/test/cpp/src/main.cpp +++ b/test/cpp/src/main.cpp @@ -718,6 +718,8 @@ void QueryBuilder_relation_w_object_wildcard(void); void QueryBuilder_relation_w_predicate_wildcard(void); void QueryBuilder_add_pair_w_rel_type(void); void QueryBuilder_template_term(void); +void QueryBuilder_template_term_at(void); +void QueryBuilder_template_term_at_index(void); void QueryBuilder_explicit_subject_w_id(void); void QueryBuilder_explicit_subject_w_type(void); void QueryBuilder_explicit_object_w_id(void); @@ -4160,6 +4162,14 @@ bake_test_case QueryBuilder_testcases[] = { "template_term", QueryBuilder_template_term }, + { + "template_term_at", + QueryBuilder_template_term_at + }, + { + "template_term_at_index", + QueryBuilder_template_term_at_index + }, { "explicit_subject_w_id", QueryBuilder_explicit_subject_w_id @@ -6805,7 +6815,7 @@ static bake_test_suite suites[] = { "QueryBuilder", QueryBuilder_setup, NULL, - 166, + 168, QueryBuilder_testcases, 1, QueryBuilder_params