Flecs v4.0
A fast entity component system (ECS) for C & C++
Loading...
Searching...
No Matches
builder_i.hpp
Go to the documentation of this file.
1
6#pragma once
7
9
10namespace flecs
11{
12
20template<typename Base>
22 term_ref_builder_i() : term_ref_(nullptr) { }
23
24 virtual ~term_ref_builder_i() { }
25
26 /* The self flag indicates the term identifier itself is used */
27 Base& self() {
28 this->assert_term_ref();
29 term_ref_->id |= flecs::Self;
30 return *this;
31 }
32
33 /* Specify value of identifier by id */
34 Base& id(flecs::entity_t id) {
35 this->assert_term_ref();
36 term_ref_->id = id;
37 return *this;
38 }
39
40 /* Specify value of identifier by id. Almost the same as id(entity), but this
41 * operation explicitly sets the flecs::IsEntity flag. This forces the id to
42 * be interpreted as entity, whereas not setting the flag would implicitly
43 * convert ids for builtin variables such as flecs::This to a variable.
44 *
45 * This function can also be used to disambiguate id(0), which would match
46 * both id(entity_t) and id(const char*).
47 */
48 Base& entity(flecs::entity_t entity) {
49 this->assert_term_ref();
50 term_ref_->id = entity | flecs::IsEntity;
51 return *this;
52 }
53
54 /* Specify value of identifier by name */
55 Base& name(const char *name) {
56 this->assert_term_ref();
57 term_ref_->id |= flecs::IsEntity;
58 term_ref_->name = const_cast<char*>(name);
59 return *this;
60 }
61
62 /* Specify identifier is a variable (resolved at query evaluation time) */
63 Base& var(const char *var_name) {
64 this->assert_term_ref();
65 term_ref_->id |= flecs::IsVariable;
66 term_ref_->name = const_cast<char*>(var_name);
67 return *this;
68 }
69
70 /* Override term id flags */
71 Base& flags(flecs::flags32_t flags) {
72 this->assert_term_ref();
73 term_ref_->id = flags;
74 return *this;
75 }
76
77 ecs_term_ref_t *term_ref_;
78
79protected:
80 virtual flecs::world_t* world_v() = 0;
81
82 void assert_term_ref() {
83 ecs_assert(term_ref_ != NULL, ECS_INVALID_PARAMETER,
84 "no active term (call .with() first)");
85 }
86
87private:
88 operator Base&() {
89 return *static_cast<Base*>(this);
90 }
91};
92
98template<typename Base>
100 term_builder_i() : term_(nullptr) { }
101
102 term_builder_i(ecs_term_t *term_ptr) {
103 set_term(term_ptr);
104 }
105
106 Base& term(id_t id) {
107 return this->id(id);
108 }
109
110 /* Call prior to setting values for src identifier */
111 Base& src() {
112 this->assert_term();
113 this->term_ref_ = &term_->src;
114 return *this;
115 }
116
117 /* Call prior to setting values for first identifier. This is either the
118 * component identifier, or first element of a pair (in case second is
119 * populated as well). */
120 Base& first() {
121 this->assert_term();
122 this->term_ref_ = &term_->first;
123 return *this;
124 }
125
126 /* Call prior to setting values for second identifier. This is the second
127 * element of a pair. Requires that first() is populated as well. */
128 Base& second() {
129 this->assert_term();
130 this->term_ref_ = &term_->second;
131 return *this;
132 }
133
134 /* Select src identifier, initialize it with entity id */
135 Base& src(flecs::entity_t id) {
136 this->src();
137 this->id(id);
138 return *this;
139 }
140
141 /* Select src identifier, initialize it with id associated with type */
142 template<typename T>
143 Base& src() {
144 this->src(_::type<T>::id(this->world_v()));
145 return *this;
146 }
147
148 /* Select src identifier, initialize it with name. If name starts with a $
149 * the name is interpreted as a variable. */
150 Base& src(const char *name) {
151 ecs_assert(name != NULL, ECS_INVALID_PARAMETER, NULL);
152 this->src();
153 if (name[0] == '$') {
154 this->var(&name[1]);
155 } else {
156 this->name(name);
157 }
158 return *this;
159 }
160
161 /* Select first identifier, initialize it with entity id */
162 Base& first(flecs::entity_t id) {
163 this->first();
164 this->id(id);
165 return *this;
166 }
167
168 /* Select first identifier, initialize it with id associated with type */
169 template<typename T>
170 Base& first() {
171 this->first(_::type<T>::id(this->world_v()));
172 return *this;
173 }
174
175 /* Select first identifier, initialize it with name. If name starts with a $
176 * the name is interpreted as a variable. */
177 Base& first(const char *name) {
178 ecs_assert(name != NULL, ECS_INVALID_PARAMETER, NULL);
179 this->first();
180 if (name[0] == '$') {
181 this->var(&name[1]);
182 } else {
183 this->name(name);
184 }
185 return *this;
186 }
187
188 /* Select second identifier, initialize it with entity id */
189 Base& second(flecs::entity_t id) {
190 this->second();
191 this->id(id);
192 return *this;
193 }
194
195 /* Select second identifier, initialize it with id associated with type */
196 template<typename T>
197 Base& second() {
198 this->second(_::type<T>::id(this->world_v()));
199 return *this;
200 }
201
202 /* Select second identifier, initialize it with name. If name starts with a $
203 * the name is interpreted as a variable. */
204 Base& second(const char *name) {
205 ecs_assert(name != NULL, ECS_INVALID_PARAMETER, NULL);
206 this->second();
207 if (name[0] == '$') {
208 this->var(&name[1]);
209 } else {
210 this->name(name);
211 }
212 return *this;
213 }
214
215 /* The up flag indicates that the term identifier may be substituted by
216 * traversing a relationship upwards. For example: substitute the identifier
217 * with its parent by traversing the ChildOf relationship. */
218 Base& up(flecs::entity_t trav = 0) {
219 this->assert_term_ref();
220 ecs_check(this->term_ref_ != &term_->first, ECS_INVALID_PARAMETER,
221 "up traversal can only be applied to term source");
222 ecs_check(this->term_ref_ != &term_->second, ECS_INVALID_PARAMETER,
223 "up traversal can only be applied to term source");
224 this->term_ref_->id |= flecs::Up;
225 if (trav) {
226 term_->trav = trav;
227 }
228 error:
229 return *this;
230 }
231
232 template <typename Trav>
233 Base& up() {
234 return this->up(_::type<Trav>::id(this->world_v()));
235 }
236
237 /* The cascade flag is like up, but returns results in breadth-first order.
238 * Only supported for flecs::query */
239 Base& cascade(flecs::entity_t trav = 0) {
240 this->assert_term_ref();
241 this->up();
242 this->term_ref_->id |= flecs::Cascade;
243 if (trav) {
244 term_->trav = trav;
245 }
246 return *this;
247 }
248
249 template <typename Trav>
250 Base& cascade() {
251 return this->cascade(_::type<Trav>::id(this->world_v()));
252 }
253
254 /* Use with cascade to iterate results in descending (bottom -> top) order */
255 Base& desc() {
256 this->assert_term_ref();
257 this->term_ref_->id |= flecs::Desc;
258 return *this;
259 }
260
261 /* Same as up(), exists for backwards compatibility */
262 Base& parent() {
263 return this->up();
264 }
265
266 /* Specify relationship to traverse, and flags to indicate direction */
267 Base& trav(flecs::entity_t trav, flecs::flags32_t flags = 0) {
268 this->assert_term_ref();
269 term_->trav = trav;
270 this->term_ref_->id |= flags;
271 return *this;
272 }
273
275 Base& id_flags(id_t flags) {
276 this->assert_term();
277 term_->id |= flags;
278 return *this;
279 }
280
282 Base& inout(flecs::inout_kind_t inout) {
283 this->assert_term();
284 term_->inout = static_cast<ecs_inout_kind_t>(inout);
285 return *this;
286 }
287
296 Base& inout_stage(flecs::inout_kind_t inout) {
297 this->assert_term();
298 term_->inout = static_cast<ecs_inout_kind_t>(inout);
299 if (term_->oper != EcsNot) {
300 this->src().entity(0);
301 }
302 return *this;
303 }
304
308 Base& write() {
309 return this->inout_stage(flecs::Out);
310 }
311
315 Base& read() {
316 return this->inout_stage(flecs::In);
317 }
318
322 Base& read_write() {
323 return this->inout_stage(flecs::InOut);
324 }
325
327 Base& in() {
328 return this->inout(flecs::In);
329 }
330
332 Base& out() {
333 return this->inout(flecs::Out);
334 }
335
337 Base& inout() {
338 return this->inout(flecs::InOut);
339 }
340
342 Base& inout_none() {
343 return this->inout(flecs::InOutNone);
344 }
345
347 Base& oper(flecs::oper_kind_t oper) {
348 this->assert_term();
349 term_->oper = static_cast<ecs_oper_kind_t>(oper);
350 return *this;
351 }
352
353 /* Short for oper(flecs::And) */
354 Base& and_() {
355 return this->oper(flecs::And);
356 }
357
358 /* Short for oper(flecs::Or) */
359 Base& or_() {
360 return this->oper(flecs::Or);
361 }
362
363 /* Short for oper(flecs::Or) */
364 Base& not_() {
365 return this->oper(flecs::Not);
366 }
367
368 /* Short for oper(flecs::Or) */
369 Base& optional() {
370 return this->oper(flecs::Optional);
371 }
372
373 /* Short for oper(flecs::AndFrom) */
374 Base& and_from() {
375 return this->oper(flecs::AndFrom);
376 }
377
378 /* Short for oper(flecs::OrFrom) */
379 Base& or_from() {
380 return this->oper(flecs::OrFrom);
381 }
382
383 /* Short for oper(flecs::NotFrom) */
384 Base& not_from() {
385 return this->oper(flecs::NotFrom);
386 }
387
389 Base& singleton() {
390 this->assert_term();
391 ecs_assert(term_->id || term_->first.id, ECS_INVALID_PARAMETER,
392 "no component specified for singleton");
393
394 flecs::id_t sid = term_->id;
395 if (!sid) {
396 sid = term_->first.id;
397 }
398
399 ecs_assert(sid != 0, ECS_INVALID_PARAMETER, NULL);
400
401 if (!ECS_IS_PAIR(sid)) {
402 term_->src.id = sid;
403 } else {
404 term_->src.id = ecs_pair_first(world(), sid);
405 }
406 return *this;
407 }
408
409 /* Query terms are not triggered on by observers */
410 Base& filter() {
411 term_->inout = EcsInOutFilter;
412 return *this;
413 }
414
415 ecs_term_t *term_;
416
417protected:
418 virtual flecs::world_t* world_v() override = 0;
419
420 void set_term(ecs_term_t *term) {
421 term_ = term;
422 if (term) {
423 this->term_ref_ = &term_->src; // default to subject
424 } else {
425 this->term_ref_ = nullptr;
426 }
427 }
428
429private:
430 void assert_term() {
431 ecs_assert(term_ != NULL, ECS_INVALID_PARAMETER,
432 "no active term (call .with() first)");
433 }
434
435 operator Base&() {
436 return *static_cast<Base*>(this);
437 }
438};
439
440}
#define ecs_assert(condition, error_code,...)
Assert.
Definition log.h:352
#define ecs_check(condition, error_code,...)
Check.
Definition log.h:399
ecs_inout_kind_t
Specify read/write access for term.
Definition flecs.h:662
ecs_oper_kind_t
Specify operator for term.
Definition flecs.h:672
@ EcsInOutFilter
Same as InOutNone + prevents term from triggering observers.
Definition flecs.h:665
@ EcsNot
The term must not match.
Definition flecs.h:675
Compile time utilities for deriving query attributes from param pack.
Type that describes a reference to an entity or variable in a term.
Definition flecs.h:753
const char * name
Name.
Definition flecs.h:760
ecs_entity_t id
Entity id.
Definition flecs.h:754
Type that describes a term (single element in a query).
Definition flecs.h:768
ecs_term_ref_t src
Source of term.
Definition flecs.h:774
ecs_id_t id
Component id to be matched by term.
Definition flecs.h:769
int16_t oper
Operator of term.
Definition flecs.h:783
ecs_term_ref_t second
Second element of pair.
Definition flecs.h:776
ecs_entity_t trav
Relationship to traverse when looking for the component.
Definition flecs.h:778
int16_t inout
Access to contents matched by term.
Definition flecs.h:782
ecs_term_ref_t first
Component or first element of pair.
Definition flecs.h:775
Entity.
Definition entity.hpp:30
Class that wraps around a flecs::id_t.
Definition decl.hpp:27
Term builder interface.
Definition builder_i.hpp:99
Base & inout(flecs::inout_kind_t inout)
Set read/write access of term.
Base & singleton()
Match singleton.
Base & oper(flecs::oper_kind_t oper)
Set operator of term.
Base & read_write()
Short for inout_stage(flecs::InOut).
Base & inout()
Short for inout(flecs::InOut)
Base & in()
Short for inout(flecs::In)
Base & inout_stage(flecs::inout_kind_t inout)
Set read/write access for stage.
Base & out()
Short for inout(flecs::Out)
Base & read()
Short for inout_stage(flecs::In).
Base & inout_none()
Short for inout(flecs::In)
Base & id_flags(id_t flags)
Set id flags for term.
Base & write()
Short for inout_stage(flecs::Out).
Term identifier builder.
Definition builder_i.hpp:21
Class that describes a term.
Definition impl.hpp:16
The world.
Definition world.hpp:137