Skip to content
Flecs v4.1
impl.hpp
Go to the documentation of this file.
1/**
2 * @file addons/cpp/mixins/query/impl.hpp
3 * @brief Query implementation.
4 */
5
6#pragma once
7
8#include "builder.hpp"
9
10namespace flecs
11{
13/** Base class for queries.
14 *
15 * @ingroup cpp_core_queries
16 */
17struct query_base {
18 /** Default constructor. */
20
21 /** Construct from a mutable query pointer. */
23 : query_(q) {
24 flecs_poly_claim(q);
25 }
26
27 /** Construct from a const query pointer. */
29 : query_(ECS_CONST_CAST(query_t*, q)) {
30 flecs_poly_claim(q);
31 }
32
33 /** Construct from a world and a query descriptor. */
35 if (desc->entity && desc->terms[0].id == 0) {
36 const flecs::Poly *query_poly = ecs_get_pair(
37 world, desc->entity, EcsPoly, EcsQuery);
38 if (query_poly) {
39 query_ = static_cast<flecs::query_t*>(query_poly->poly);
40 flecs_poly_claim(query_);
41 return;
42 }
43 }
44
45 query_ = ecs_query_init(world, desc);
46 }
47
48 /** Copy constructor. */
49 query_base(const query_base& obj) {
50 this->query_ = obj.query_;
51 if (this->query_)
52 {
53 flecs_poly_claim(this->query_);
54 }
55 }
56
57 /** Copy assignment operator. */
59 if (this != &obj) {
60 this->~query_base();
61 this->query_ = obj.query_;
62 if (this->query_)
63 {
64 flecs_poly_claim(this->query_);
65 }
66 }
67 return *this;
68 }
69
70 /** Move constructor. */
71 query_base(query_base&& obj) noexcept {
72 this->query_ = obj.query_;
73 obj.query_ = nullptr;
74 }
75
76 /** Move assignment operator. */
77 query_base& operator=(query_base&& obj) noexcept {
78 if (this != &obj) {
79 this->~query_base();
80 this->query_ = obj.query_;
81 obj.query_ = nullptr;
82 }
83 return *this;
84 }
85
86 /** Get the entity associated with the query. */
88 return flecs::entity(query_->stage, query_->entity);
89 }
90
91 /** Get a pointer to the underlying C query. */
92 const flecs::query_t* c_ptr() const {
93 return query_;
94 }
95
96 /** Convert to a const query pointer. */
97 operator const flecs::query_t*() const {
98 return query_;
99 }
100
101 /** Check if the query is valid. */
102 operator bool() const {
103 return query_ != nullptr;
104 }
105
106 /** Free a persistent query.
107 * A persistent query is a query that is associated with an entity, such as
108 * system queries and named queries. Persistent queries must be deleted with
109 * destruct(), or will be deleted automatically at world cleanup.
110 */
111 void destruct() {
112 ecs_assert(query_->entity != 0, ECS_INVALID_OPERATION, "destruct() "
113 "should only be called on queries associated with entities");
114 ecs_query_fini(query_);
115 query_ = nullptr;
116 }
117
118 /** Destructor. Only frees the query if it is not associated with an entity. */
120 if (query_ && !query_->entity) {
121 if (!flecs_poly_release(query_)) {
122 ecs_query_fini(query_);
123 query_ = nullptr;
124 }
125 }
126 }
127
128#ifdef FLECS_CACHED_QUERIES
129 /** Return whether the query data changed since the last iteration.
130 * This operation must be invoked before obtaining the iterator, as this will
131 * reset the changed state. The operation will return true after:
132 * - new entities have been matched with
133 * - matched entities were deleted
134 * - matched components were changed
135 *
136 * @return true if entities changed, otherwise false.
137 */
138 bool changed() const {
139 return ecs_query_changed(query_);
140 }
141
142 /** Get info for a group.
143 *
144 * @param group_id The group ID for which to retrieve the info.
145 * @return The group info.
146 */
147 const flecs::query_group_info_t* group_info(uint64_t group_id) const {
148 return ecs_query_get_group_info(query_, group_id);
149 }
150
151 /** Iterate the active groups of a grouped query.
152 * Returns a range over (group_id, value) entries from the query's group
153 * map. The map value type is currently opaque, so V is exposed as void*.
154 *
155 * @return A flecs::map range over the query's active groups.
156 */
159 }
160
161 /** Get context for a group.
162 *
163 * @param group_id The group ID for which to retrieve the context.
164 * @return The group context.
165 */
166 void* group_ctx(uint64_t group_id) const {
167 const flecs::query_group_info_t *gi = group_info(group_id);
168 if (gi) {
169 return gi->ctx;
170 } else {
171 return nullptr;
172 }
173 }
174#endif
175
176 /** Iterate each term in the query, invoking a callback for each. */
177 template <typename Func>
178 void each_term(const Func& func) {
179 for (int i = 0; i < query_->term_count; i ++) {
180 flecs::term t(query_->stage, query_->terms[i]);
181 func(t);
182 t.reset(); // prevent freeing resources
183 }
184 }
185
186 /** Get term at the specified index. */
187 flecs::term term(int32_t index) const {
188 return flecs::term(query_->stage, query_->terms[index]);
189 }
190
191 /** Get the number of terms in the query. */
192 int32_t term_count() const {
193 return query_->term_count;
194 }
195
196 /** Get the number of fields in the query. */
197 int32_t field_count() const {
198 return query_->field_count;
199 }
200
201#ifdef FLECS_QUERY_PLANS
202 /** Find a variable by name. */
203 int32_t find_var(const char *name) const {
204 return ecs_query_find_var(query_, name);
205 }
206
207 /** Return a string representing the query plan.
208 * This can be used to analyze the behavior and performance of the query.
209 * @see ecs_query_plan()
210 */
212 char *result = ecs_query_plan(query_);
213 return flecs::string(result);
214 }
215#endif
216
217 bool has(flecs::entity_t e) const {
218 ecs_iter_t it;
219 bool result = ecs_query_has(query_, e, &it);
220 if (result) {
221 ecs_iter_fini(&it);
222 }
223 return result;
224 }
225
226 bool has(const flecs::table& t) const {
227 ecs_iter_t it;
228 bool result = ecs_query_has_table(query_, t.get_table(), &it);
229 if (result) {
230 ecs_iter_fini(&it);
231 }
232 return result;
233 }
234
235 bool has(const flecs::table_range& range) const {
236 ecs_table_range_t r = {
237 range.get_table(),
238 range.offset(),
239 range.count()
240 };
241 ecs_iter_t it;
242 bool result = ecs_query_has_range(query_, &r, &it);
243 if (result) {
244 ecs_iter_fini(&it);
245 }
246 return result;
247 }
248
249 /** Convert the query to a string expression. */
251 char *result = ecs_query_str(query_);
252 return flecs::string(result);
253 }
254
255 /** Convert to a typed query. */
256 operator query<>() const;
257
258# ifdef FLECS_JSON
259# include "../json/query.inl"
260# endif
261
262protected:
263 query_t *query_ = nullptr;
264};
265
266/** Typed query.
267 *
268 * @ingroup cpp_core_queries
269 */
270template<typename ... Components>
271struct query : query_base, iterable<Components...> {
272private:
273 using Fields = typename _::field_ptrs<Components...>::array;
274
275public:
277
278 /** Default constructor. */
279 query() : query_base() { } // necessary not to confuse MSVC
280
281 /** Copy constructor. */
282 query(const query& obj) : query_base(obj) { }
283
284 /** Copy assignment operator. */
285 query& operator=(const query& obj) {
287 return *this;
288 }
289
290 /** Move constructor. */
291 query(query&& obj) noexcept : query_base(FLECS_MOV(obj)) { }
292
293 /** Move assignment operator. */
294 query& operator=(query&& obj) noexcept {
295 query_base::operator=(FLECS_FWD(obj));
296 return *this;
297 }
298
299#ifdef FLECS_CACHED_QUERIES
300 /** Get the cache query, if any. */
302 const flecs::query_t *q = ecs_query_get_cache_query(query_);
303 return flecs::query<>(q);
304 }
305#endif
306
307private:
308 ecs_iter_t get_iter(flecs::world_t *world) const override {
309 ecs_assert(query_ != nullptr, ECS_INVALID_PARAMETER,
310 "cannot iterate invalid query");
311 if (!world) {
312 world = query_->stage;
313 }
314 return ecs_query_iter(world, query_);
315 }
316
317 ecs_iter_next_action_t next_action() const override {
318 return ecs_query_next;
319 }
320};
321
322// World mixin implementation
323template <typename... Comps, typename... Args>
324inline conditional_t<sizeof...(Args) == 0 && _::is_sparse_query<Comps...>::value,
325 flecs::sparse_query<Comps...>, flecs::query<Comps...>>
326world::query(Args &&... args) const {
327 if constexpr (sizeof...(Args) == 0 && _::is_sparse_query<Comps...>::value) {
328 return flecs::sparse_query<Comps...>(world_);
329 } else {
330 return flecs::query_builder<Comps...>(world_, FLECS_FWD(args)...)
331 .build();
332 }
333}
334
335inline flecs::query<> world::query(flecs::entity query_entity) const {
336 ecs_query_desc_t desc = {};
337 desc.entity = query_entity;
338 return flecs::query<>(world_, &desc);
339}
340
341template <typename... Comps, typename... Args>
342inline flecs::query_builder<Comps...> world::query_builder(Args &&... args) const {
343 return flecs::query_builder<Comps...>(world_, FLECS_FWD(args)...);
344}
345
346template <typename ... Components>
347inline sparse_query<Components...>::operator flecs::query<Components...>() const {
348 return flecs::query_builder<Components...>(world_).build();
349}
350
351namespace _ {
352
353template <typename Func, typename... Components>
354void world_each(const flecs::world& world, Func&& func, arg_list<Components...>) {
355 if constexpr (sizeof...(Components) == 0) {
357 for (int32_t i = 0; i < entities.alive_count; i ++) {
358 func(flecs::entity(world, entities.ids[i]));
359 }
360 } else {
361 world.query<Components...>().each(FLECS_FWD(func));
362 }
363}
364
365}
366
367template <typename Func>
368inline void world::each(Func&& func) const {
369 using Components = typename _::each_callback_args<arg_list_t<Func>, int, false>::type;
370 _::world_each(*this, FLECS_FWD(func), Components{});
371}
372
373template <typename T, typename Func>
374inline void world::each(Func&& func) const {
376
377 while (ecs_each_next(&it)) {
378 _::each_delegate<Func, T>(func).invoke(&it);
379 }
380}
381
382template <typename Func>
383inline void world::each(flecs::id_t each_id, Func&& func) const {
384 ecs_iter_t it = ecs_each_id(world_, each_id);
385
386 while (ecs_each_next(&it)) {
387 _::each_delegate<Func>(func).invoke(&it);
388 }
389}
390
391// query_base implementation
392inline query_base::operator flecs::query<> () const {
393 return flecs::query<>(query_);
394}
395
396}
const ecs_entity_t EcsQuery
Tag added to queries.
#define ecs_assert(condition, error_code,...)
Assert.
Definition log.h:473
#define ECS_INVALID_OPERATION
Invalid operation error code.
Definition log.h:696
#define ECS_INVALID_PARAMETER
Invalid parameter error code.
Definition log.h:698
struct ecs_iter_t ecs_iter_t
Type used for iterating iterable objects.
Definition flecs.h:482
conditional_t< sizeof...(Args)==0 &&_::is_sparse_query< Comps... >::value, flecs::sparse_query< Comps... >, flecs::query< Comps... > > query(Args &&... args) const
Create a query.
Definition impl.hpp:326
flecs::query_builder< Comps... > query_builder(Args &&... args) const
Create a query builder.
Definition impl.hpp:342
void each(Func &&func) const
Iterate over all entities with components in the argument list of the function.
Definition impl.hpp:368
ecs_query_t query_t
Query type.
Definition c_types.hpp:25
ecs_id_t id_t
ID type.
Definition c_types.hpp:20
ecs_entity_t entity_t
Entity type.
Definition c_types.hpp:21
ecs_query_group_info_t query_group_info_t
Query group info type.
Definition c_types.hpp:26
EcsPoly Poly
Built-in EcsPoly type.
Definition c_types.hpp:84
ecs_world_t world_t
World type.
Definition c_types.hpp:18
ecs_iter_t ecs_each_id(const ecs_world_t *world, ecs_id_t component)
Iterate all entities with a specified (component ID).
bool ecs_each_next(ecs_iter_t *it)
Progress an iterator created with ecs_each_id().
#define ecs_get_pair(world, subject, First, second)
Get the first element of a pair.
Definition flecs_c.h:346
bool(*) ecs_iter_next_action_t(ecs_iter_t *it)
Function prototype for iterating an iterator.
Definition flecs.h:602
void ecs_iter_fini(ecs_iter_t *it)
Clean up iterator resources.
bool ecs_query_has_table(const ecs_query_t *query, ecs_table_t *table, ecs_iter_t *it)
Match a table with a query.
bool ecs_query_next(ecs_iter_t *it)
Progress a query iterator.
const ecs_query_group_info_t * ecs_query_get_group_info(const ecs_query_t *query, uint64_t group_id)
Get information about a query group.
bool ecs_query_has_range(const ecs_query_t *query, ecs_table_range_t *range, ecs_iter_t *it)
Match a range with a query.
int32_t ecs_query_find_var(const ecs_query_t *query, const char *name)
Find a variable index.
void ecs_query_fini(ecs_query_t *query)
Delete a query.
bool ecs_query_has(const ecs_query_t *query, ecs_entity_t entity, ecs_iter_t *it)
Match an entity with a query.
char * ecs_query_plan(const ecs_query_t *query)
Convert a query to a string.
ecs_iter_t ecs_query_iter(const ecs_world_t *world, const ecs_query_t *query)
Create a query iterator.
char * ecs_query_str(const ecs_query_t *query)
Convert a query to a string expression.
ecs_query_t * ecs_query_init(ecs_world_t *world, const ecs_query_desc_t *desc)
Create a query.
bool ecs_query_changed(ecs_query_t *query)
Return whether the query data changed since the last iteration.
const ecs_map_t * ecs_query_get_groups(const ecs_query_t *query)
Return the map with query groups.
const ecs_query_t * ecs_query_get_cache_query(const ecs_query_t *query)
Get the query used to populate the cache.
ecs_entities_t ecs_get_entities(const ecs_world_t *world)
Return entity identifiers in the world.
const ecs_world_t * ecs_get_world(const ecs_poly_t *poly)
Get the world from a poly.
Query builder.
Int to enum.
Definition component.hpp:18
JSON query mixin.
Component for storing a poly object.
Definition flecs.h:1617
ecs_poly_t * poly
Pointer to poly object.
Definition flecs.h:1618
Type returned by ecs_get_entities().
Definition flecs.h:2052
int32_t alive_count
Number of alive entity IDs.
Definition flecs.h:2055
const ecs_entity_t * ids
Array with all entity IDs in the world.
Definition flecs.h:2053
Iterator.
Definition flecs.h:1184
Used with ecs_query_init().
Definition flecs.h:1316
ecs_term_t terms[32]
Query terms.
Definition flecs.h:1321
ecs_entity_t entity
Entity associated with query (optional).
Definition flecs.h:1383
void * ctx
Group context, returned by on_group_create.
Definition flecs.h:1589
ecs_world_t * stage
World or stage the query was created with.
Definition flecs.h:895
ecs_id_t id
Component ID to be matched by term.
Definition flecs.h:836
Extract the component argument list from an each-callback signature.
Definition delegate.hpp:495
Array class (primary template, disabled).
Definition array.hpp:47
Entity.
Definition entity.hpp:30
Base class for iterable query objects.
Definition iterable.hpp:25
const flecs::query_t * c_ptr() const
Get a pointer to the underlying C query.
Definition impl.hpp:92
bool changed() const
Return whether the query data changed since the last iteration.
Definition impl.hpp:138
query_base & operator=(const query_base &obj)
Copy assignment operator.
Definition impl.hpp:58
flecs::entity entity() const
Get the entity associated with the query.
Definition impl.hpp:87
void each_term(const Func &func)
Iterate each term in the query, invoking a callback for each.
Definition impl.hpp:178
query_base(query_base &&obj) noexcept
Move constructor.
Definition impl.hpp:71
query_base()
Default constructor.
Definition impl.hpp:19
flecs::map< uint64_t, void * > groups() const
Iterate the active groups of a grouped query.
Definition impl.hpp:157
void * group_ctx(uint64_t group_id) const
Get context for a group.
Definition impl.hpp:166
query_base(const query_t *q)
Construct from a const query pointer.
Definition impl.hpp:28
flecs::string plan() const
Return a string representing the query plan.
Definition impl.hpp:211
flecs::term term(int32_t index) const
Get term at the specified index.
Definition impl.hpp:187
query_base(query_t *q)
Construct from a mutable query pointer.
Definition impl.hpp:22
query_base(world_t *world, const ecs_query_desc_t *desc)
Construct from a world and a query descriptor.
Definition impl.hpp:34
query_base & operator=(query_base &&obj) noexcept
Move assignment operator.
Definition impl.hpp:77
query_base(const query_base &obj)
Copy constructor.
Definition impl.hpp:49
~query_base()
Destructor.
Definition impl.hpp:119
int32_t term_count() const
Get the number of terms in the query.
Definition impl.hpp:192
const flecs::query_group_info_t * group_info(uint64_t group_id) const
Get info for a group.
Definition impl.hpp:147
flecs::string str() const
Convert the query to a string expression.
Definition impl.hpp:250
void destruct()
Free a persistent query.
Definition impl.hpp:111
int32_t find_var(const char *name) const
Find a variable by name.
Definition impl.hpp:203
int32_t field_count() const
Get the number of fields in the query.
Definition impl.hpp:197
Query builder.
Definition builder.hpp:24
Typed query.
Definition impl.hpp:271
query_base()
Default constructor.
Definition impl.hpp:19
query()
Default constructor.
Definition impl.hpp:279
query(const query &obj)
Copy constructor.
Definition impl.hpp:282
flecs::query cache_query() const
Get the cache query, if any.
Definition impl.hpp:301
query & operator=(query &&obj) noexcept
Move assignment operator.
Definition impl.hpp:294
query & operator=(const query &obj)
Copy assignment operator.
Definition impl.hpp:285
query(query &&obj) noexcept
Move constructor.
Definition impl.hpp:291
Query that iterates sparse component storages directly.
Owned string wrapper.
Definition string.hpp:15
table_t * get_table() const
Get the table.
Definition table.hpp:171
Class that describes a term.
Definition impl.hpp:16
void reset()
Reset the term to its default state.
Definition impl.hpp:45
Type class.
Definition type.hpp:21
The world.
Definition world.hpp:129
world_t * world_
Pointer to the underlying C world.
Definition world.hpp:892
void each(Func &&func) const
Iterate over all entities with components in the argument list of the function.