Skip to content
Flecs v4.1
sparse_query.hpp
Go to the documentation of this file.
1/** @file addons/cpp/mixins/query/sparse_query.hpp
2 * @brief Direct iteration of sparse component storages. */
3
4#pragma once
5
6namespace flecs {
7
8/** @defgroup cpp_queries Sparse queries
9 * @ingroup cpp_core
10 * Direct iteration of sparse component storages. @{ */
11
12/** Query that iterates sparse component storages directly.
13 * Returned by world::query() when all components have the dont_fragment
14 * trait and don't declare the on_instantiate::inherit policy. */
15template <typename ... Components>
16struct sparse_query {
17 static_assert(_::is_sparse_query<Components...>::value,
18 "all sparse_query components must have the dont_fragment trait and "
19 "must not declare the on_instantiate::inherit policy");
20
21 explicit sparse_query(flecs::world_t *world)
22 : world_(ECS_CONST_CAST(flecs::world_t*, ecs_get_world(world)))
23 , ids_{ _::type<Components>::id(world)... }
24 {
25 assert_policies();
26 }
27
28 /** Iterate the query.
29 * The function signature must match func(flecs::entity e, Components&...)
30 * or func(Components&...). */
31 template <typename Func>
32 void each(Func&& func) const {
33 each_impl(std::index_sequence_for<Components...>{}, func);
34 }
35
36 /** Return the number of entities matched by the query. */
37 int32_t count() const {
38 int32_t result = 0;
39 each([&](Components&...) { result ++; });
40 return result;
41 }
42
43 /** Convert to a regular flecs::query for the same components. */
44 operator flecs::query<Components...>() const;
45
46private:
47 template <size_t ... Is, typename Func>
48 void each_impl(std::index_sequence<Is...>, const Func& func) const {
49 constexpr size_t n = sizeof...(Components);
50
51 ecs_sparse_t *sparse[n] = { storage(ids_[Is])... };
52 for (size_t f = 0; f < n; f ++) {
53 if (!sparse[f]) {
54 return;
55 }
56 }
57
58 size_t lead = 0;
59 for (size_t f = 1; f < n; f ++) {
60 if (sparse[f]->count < sparse[lead]->count) {
61 lead = f;
62 }
63 }
64
65 const uint64_t *entities = flecs_sparse_ids(sparse[lead]);
66 int32_t count = sparse[lead]->count - 1;
67
68 for (int32_t i = 0; i < count; i ++) {
69 uint64_t e = entities[i];
70 void *ptrs[n];
71 if (!(... && (ptrs[Is] = flecs_sparse_get_w_check(
72 sparse[Is], ECS_SIZEOF(remove_reference_t<Components>), e,
73 Is != lead))))
74 {
75 continue;
76 }
77
78 const ecs_record_t *r = ecs_record_find(world_, e);
79 if (flecs_table_flags(r->table) &
80 (EcsTableNotQueryable|EcsTableIsPrefab|EcsTableIsDisabled))
81 {
82 continue;
83 }
84
85 if constexpr (std::is_invocable<
86 Func, flecs::entity, Components&...>::value)
87 {
88 func(flecs::entity(world_, e),
89 (*static_cast<remove_reference_t<Components>*>(
90 ptrs[Is]))...);
91 } else {
92 func((*static_cast<remove_reference_t<Components>*>(
93 ptrs[Is]))...);
94 }
95 }
96 }
97
98 ecs_sparse_t* storage(flecs::id_t id) const {
99 ecs_component_record_t *cr = flecs_components_get(world_, id);
100 return cr ? flecs_component_get_sparse(cr) : nullptr;
101 }
102
103 void assert_policies() const {
104#ifdef FLECS_PREFAB
105 for (flecs::id_t id : ids_) {
106 (void)id;
107 ecs_assert(ecs_get_target(world_, id, flecs::OnInstantiate, 0) !=
108 flecs::Inherit, ECS_INVALID_OPERATION,
109 "sparse_query component has the OnInstantiate Inherit trait, "
110 "which sparse queries cannot match; add the on_instantiate "
111 "trait at compile time instead");
112 }
113#endif
114 }
115
116 flecs::world_t *world_;
117 flecs::id_t ids_[sizeof...(Components)];
118};
119
120/** @} */
121
122}
#define ecs_assert(condition, error_code,...)
Assert.
Definition log.h:473
#define ECS_INVALID_OPERATION
Invalid operation error code.
Definition log.h:669
struct ecs_component_record_t ecs_component_record_t
Information about a (component) ID, such as type info and tables with the ID.
Definition flecs.h:507
struct ecs_record_t ecs_record_t
Information about an entity, like its table and row.
Definition flecs.h:504
ecs_id_t id_t
ID type.
Definition c_types.hpp:20
ecs_world_t world_t
World type.
Definition c_types.hpp:18
ecs_entity_t ecs_get_target(const ecs_world_t *world, ecs_entity_t entity, ecs_entity_t rel, int32_t index)
Get the target of a relationship.
const ecs_world_t * ecs_get_world(const ecs_poly_t *poly)
Get the world from a poly.
Typed query.
Definition impl.hpp:266
int32_t count() const
Return the number of entities matched by the query.
void each(Func &&func) const
Iterate the query.
Trait that marks a component as Sparse at compile time.
Definition utils.hpp:187
The world.
Definition world.hpp:129
flecs::entity entity(Args &&... args) const
Create an entity.