Flecs v3.2
A fast entity component system (ECS) for C & C++
Loading...
Searching...
No Matches
invoker.hpp
Go to the documentation of this file.
1
6#pragma once
7
8namespace flecs
9{
10
11namespace _
12{
13
14// Binding ctx for component hooks
16 void *on_add = nullptr;
17 void *on_remove = nullptr;
18 void *on_set = nullptr;
19 ecs_ctx_free_t free_on_add = nullptr;
20 ecs_ctx_free_t free_on_remove = nullptr;
21 ecs_ctx_free_t free_on_set = nullptr;
22
24 if (on_add && free_on_add) {
25 free_on_add(on_add);
26 }
27 if (on_remove && free_on_remove) {
28 free_on_remove(on_remove);
29 }
30 if (on_set && free_on_set) {
31 free_on_set(on_set);
32 }
33 }
34};
35
36// Utility to convert template argument pack to array of term ptrs
37struct term_ptr {
38 void *ptr;
39 bool is_ref;
40};
41
42template <typename ... Components>
43struct term_ptrs {
44 using array = flecs::array<_::term_ptr, sizeof...(Components)>;
45
46 bool populate(const ecs_iter_t *iter) {
47 return populate(iter, 0, static_cast<
48 remove_reference_t<
49 remove_pointer_t<Components>>
50 *>(nullptr)...);
51 }
52
53 array m_terms;
54
55private:
56 /* Populate terms array without checking for references */
57 bool populate(const ecs_iter_t*, size_t) { return false; }
58
59 template <typename T, typename... Targs>
60 bool populate(const ecs_iter_t *iter, size_t index, T, Targs... comps) {
61 m_terms[index].ptr = iter->ptrs[index];
62 bool is_ref = iter->sources && iter->sources[index] != 0;
63 m_terms[index].is_ref = is_ref;
64 is_ref |= populate(iter, index + 1, comps ...);
65 return is_ref;
66 }
67};
68
69struct invoker { };
70
71// Template that figures out from the template parameters of a query/system
72// how to pass the value to the each callback
73template <typename T, typename = int>
74struct each_column { };
75
76// Base class
78 each_column_base(const _::term_ptr& term, size_t row)
79 : m_term(term), m_row(row) { }
80
81protected:
82 const _::term_ptr& m_term;
83 size_t m_row;
84};
85
86// If type is not a pointer, return a reference to the type (default case)
87template <typename T>
88struct each_column<T, if_t< !is_pointer<T>::value &&
89 !is_empty<actual_type_t<T>>::value && is_actual<T>::value > >
91{
92 each_column(const _::term_ptr& term, size_t row)
93 : each_column_base(term, row) { }
94
95 T& get_row() {
96 return static_cast<T*>(this->m_term.ptr)[this->m_row];
97 }
98};
99
100// If argument type is not the same as actual component type, return by value.
101// This requires that the actual type can be converted to the type.
102// A typical scenario where this happens is when using flecs::pair types.
103template <typename T>
104struct each_column<T, if_t< !is_pointer<T>::value &&
105 !is_empty<actual_type_t<T>>::value && !is_actual<T>::value> >
107{
108 each_column(const _::term_ptr& term, size_t row)
109 : each_column_base(term, row) { }
110
111 T get_row() {
112 return static_cast<actual_type_t<T>*>(this->m_term.ptr)[this->m_row];
113 }
114};
115
116
117// If type is empty (indicating a tag) the query will pass a nullptr. To avoid
118// returning nullptr to reference arguments, return a temporary value.
119template <typename T>
120struct each_column<T, if_t< is_empty<actual_type_t<T>>::value &&
121 !is_pointer<T>::value > >
123{
124 each_column(const _::term_ptr& term, size_t row)
125 : each_column_base(term, row) { }
126
127 T get_row() {
128 return actual_type_t<T>();
129 }
130};
131
132
133// If type is a pointer (indicating an optional value) return the type as is
134template <typename T>
135struct each_column<T, if_t< is_pointer<T>::value &&
136 !is_empty<actual_type_t<T>>::value > >
138{
139 each_column(const _::term_ptr& term, size_t row)
140 : each_column_base(term, row) { }
141
142 T get_row() {
143 if (this->m_term.ptr) {
144 return &static_cast<actual_type_t<T>>(this->m_term.ptr)[this->m_row];
145 } else {
146 // optional argument doesn't hava a value
147 return nullptr;
148 }
149 }
150};
151
152// If the query contains component references to other entities, check if the
153// current argument is one.
154template <typename T, typename = int>
155struct each_ref_column : public each_column<T> {
156 each_ref_column(const _::term_ptr& term, size_t row)
157 : each_column<T>(term, row) {
158
159 if (term.is_ref) {
160 // If this is a reference, set the row to 0 as a ref always is a
161 // single value, not an array. This prevents the application from
162 // having to do an if-check on whether the column is owned.
163 //
164 // This check only happens when the current table being iterated
165 // over caused the query to match a reference. The check is
166 // performed once per iterated table.
167 this->m_row = 0;
168 }
169 }
170};
171
172template <typename Func, typename ... Components>
173struct each_invoker : public invoker {
174 // If the number of arguments in the function signature is one more than the
175 // number of components in the query, an extra entity arg is required.
176 static constexpr bool PassEntity =
177 (sizeof...(Components) + 1) == (arity<Func>::value);
178
179 // If the number of arguments in the function is two more than the number of
180 // components in the query, extra iter + index arguments are required.
181 static constexpr bool PassIter =
182 (sizeof...(Components) + 2) == (arity<Func>::value);
183
184 static_assert(arity<Func>::value > 0,
185 "each() must have at least one argument");
186
187 using Terms = typename term_ptrs<Components ...>::array;
188
189 template < if_not_t< is_same< decay_t<Func>, decay_t<Func>& >::value > = 0>
190 explicit each_invoker(Func&& func) noexcept
191 : m_func(FLECS_MOV(func)) { }
192
193 explicit each_invoker(const Func& func) noexcept
194 : m_func(func) { }
195
196 // Invoke object directly. This operation is useful when the calling
197 // function has just constructed the invoker, such as what happens when
198 // iterating a query.
199 void invoke(ecs_iter_t *iter) const {
200 term_ptrs<Components...> terms;
201
202 if (terms.populate(iter)) {
203 invoke_callback< each_ref_column >(iter, m_func, 0, terms.m_terms);
204 } else {
205 invoke_callback< each_column >(iter, m_func, 0, terms.m_terms);
206 }
207 }
208
209 // Static function that can be used as callback for systems/triggers
210 static void run(ecs_iter_t *iter) {
211 auto self = static_cast<const each_invoker*>(iter->binding_ctx);
212 ecs_assert(self != nullptr, ECS_INTERNAL_ERROR, NULL);
213 self->invoke(iter);
214 }
215
216 // Static function to call for component on_add hook
217 static void run_add(ecs_iter_t *iter) {
218 component_binding_ctx *ctx = reinterpret_cast<component_binding_ctx*>(
219 iter->binding_ctx);
220 iter->binding_ctx = ctx->on_add;
221 run(iter);
222 }
223
224 // Static function to call for component on_remove hook
225 static void run_remove(ecs_iter_t *iter) {
226 component_binding_ctx *ctx = reinterpret_cast<component_binding_ctx*>(
227 iter->binding_ctx);
228 iter->binding_ctx = ctx->on_remove;
229 run(iter);
230 }
231
232 // Static function to call for component on_set hook
233 static void run_set(ecs_iter_t *iter) {
234 component_binding_ctx *ctx = reinterpret_cast<component_binding_ctx*>(
235 iter->binding_ctx);
236 iter->binding_ctx = ctx->on_set;
237 run(iter);
238 }
239
240 // Each invokers always use instanced iterators
241 static bool instanced() {
242 return true;
243 }
244
245private:
246 // Number of function arguments is one more than number of components, pass
247 // entity as argument.
248 template <template<typename X, typename = int> class ColumnType,
249 typename... Args, if_t<
250 sizeof...(Components) == sizeof...(Args) && PassEntity> = 0>
251 static void invoke_callback(
252 ecs_iter_t *iter, const Func& func, size_t, Terms&, Args... comps)
253 {
254 ECS_TABLE_LOCK(iter->world, iter->table);
255
256 ecs_world_t *world = iter->world;
257 size_t count = static_cast<size_t>(iter->count);
258
259 ecs_assert(count > 0, ECS_INVALID_OPERATION,
260 "no entities returned, use each() without flecs::entity argument");
261
262 for (size_t i = 0; i < count; i ++) {
263 func(flecs::entity(world, iter->entities[i]),
264 (ColumnType< remove_reference_t<Components> >(comps, i)
265 .get_row())...);
266 }
267
268 ECS_TABLE_UNLOCK(iter->world, iter->table);
269 }
270
271 // Number of function arguments is two more than number of components, pass
272 // iter + index as argument.
273 template <template<typename X, typename = int> class ColumnType,
274 typename... Args, int Enabled = PassIter, if_t<
275 sizeof...(Components) == sizeof...(Args) && Enabled> = 0>
276 static void invoke_callback(
277 ecs_iter_t *iter, const Func& func, size_t, Terms&, Args... comps)
278 {
279 size_t count = static_cast<size_t>(iter->count);
280 if (count == 0) {
281 // If query has no This terms, count can be 0. Since each does not
282 // have an entity parameter, just pass through components
283 count = 1;
284 }
285
286 flecs::iter it(iter);
287
288 ECS_TABLE_LOCK(iter->world, iter->table);
289
290 for (size_t i = 0; i < count; i ++) {
291 func(it, i, (ColumnType< remove_reference_t<Components> >(comps, i)
292 .get_row())...);
293 }
294
295 ECS_TABLE_UNLOCK(iter->world, iter->table);
296 }
297
298 // Number of function arguments is equal to number of components, no entity
299 template <template<typename X, typename = int> class ColumnType,
300 typename... Args, if_t<
301 sizeof...(Components) == sizeof...(Args) && !PassEntity && !PassIter> = 0>
302 static void invoke_callback(
303 ecs_iter_t *iter, const Func& func, size_t, Terms&, Args... comps)
304 {
305 size_t count = static_cast<size_t>(iter->count);
306 if (count == 0) {
307 // If query has no This terms, count can be 0. Since each does not
308 // have an entity parameter, just pass through components
309 count = 1;
310 }
311
312 flecs::iter it(iter);
313
314 ECS_TABLE_LOCK(iter->world, iter->table);
315
316 for (size_t i = 0; i < count; i ++) {
317 func( (ColumnType< remove_reference_t<Components> >(comps, i)
318 .get_row())...);
319 }
320
321 ECS_TABLE_UNLOCK(iter->world, iter->table);
322 }
323
324 template <template<typename X, typename = int> class ColumnType,
325 typename... Args, if_t< sizeof...(Components) != sizeof...(Args) > = 0>
326 static void invoke_callback(ecs_iter_t *iter, const Func& func,
327 size_t index, Terms& columns, Args... comps)
328 {
329 invoke_callback<ColumnType>(
330 iter, func, index + 1, columns, comps..., columns[index]);
331 }
332
333 Func m_func;
334};
335
336template <typename Func, typename ... Components>
337struct find_invoker : public invoker {
338 // If the number of arguments in the function signature is one more than the
339 // number of components in the query, an extra entity arg is required.
340 static constexpr bool PassEntity =
341 (sizeof...(Components) + 1) == (arity<Func>::value);
342
343 // If the number of arguments in the function is two more than the number of
344 // components in the query, extra iter + index arguments are required.
345 static constexpr bool PassIter =
346 (sizeof...(Components) + 2) == (arity<Func>::value);
347
348 static_assert(arity<Func>::value > 0,
349 "each() must have at least one argument");
350
351 using Terms = typename term_ptrs<Components ...>::array;
352
353 template < if_not_t< is_same< decay_t<Func>, decay_t<Func>& >::value > = 0>
354 explicit find_invoker(Func&& func) noexcept
355 : m_func(FLECS_MOV(func)) { }
356
357 explicit find_invoker(const Func& func) noexcept
358 : m_func(func) { }
359
360 // Invoke object directly. This operation is useful when the calling
361 // function has just constructed the invoker, such as what happens when
362 // iterating a query.
363 flecs::entity invoke(ecs_iter_t *iter) const {
364 term_ptrs<Components...> terms;
365
366 if (terms.populate(iter)) {
367 return invoke_callback< each_ref_column >(iter, m_func, 0, terms.m_terms);
368 } else {
369 return invoke_callback< each_column >(iter, m_func, 0, terms.m_terms);
370 }
371 }
372
373 // Find invokers always use instanced iterators
374 static bool instanced() {
375 return true;
376 }
377
378private:
379 // Number of function arguments is one more than number of components, pass
380 // entity as argument.
381 template <template<typename X, typename = int> class ColumnType,
382 typename... Args, if_t<
383 sizeof...(Components) == sizeof...(Args) && PassEntity> = 0>
384 static flecs::entity invoke_callback(
385 ecs_iter_t *iter, const Func& func, size_t, Terms&, Args... comps)
386 {
387 ECS_TABLE_LOCK(iter->world, iter->table);
388
389 ecs_world_t *world = iter->world;
390 size_t count = static_cast<size_t>(iter->count);
391 flecs::entity result;
392
393 ecs_assert(count > 0, ECS_INVALID_OPERATION,
394 "no entities returned, use find() without flecs::entity argument");
395
396 for (size_t i = 0; i < count; i ++) {
397 if (func(flecs::entity(world, iter->entities[i]),
398 (ColumnType< remove_reference_t<Components> >(comps, i)
399 .get_row())...))
400 {
401 result = flecs::entity(world, iter->entities[i]);
402 break;
403 }
404 }
405
406 ECS_TABLE_UNLOCK(iter->world, iter->table);
407
408 return result;
409 }
410
411 // Number of function arguments is two more than number of components, pass
412 // iter + index as argument.
413 template <template<typename X, typename = int> class ColumnType,
414 typename... Args, int Enabled = PassIter, if_t<
415 sizeof...(Components) == sizeof...(Args) && Enabled> = 0>
416 static flecs::entity invoke_callback(
417 ecs_iter_t *iter, const Func& func, size_t, Terms&, Args... comps)
418 {
419 size_t count = static_cast<size_t>(iter->count);
420 if (count == 0) {
421 // If query has no This terms, count can be 0. Since each does not
422 // have an entity parameter, just pass through components
423 count = 1;
424 }
425
426 flecs::iter it(iter);
427 flecs::entity result;
428
429 ECS_TABLE_LOCK(iter->world, iter->table);
430
431 for (size_t i = 0; i < count; i ++) {
432 if (func(it, i, (ColumnType< remove_reference_t<Components> >(comps, i)
433 .get_row())...))
434 {
435 result = flecs::entity(iter->world, iter->entities[i]);
436 break;
437 }
438 }
439
440 ECS_TABLE_UNLOCK(iter->world, iter->table);
441
442 return result;
443 }
444
445 // Number of function arguments is equal to number of components, no entity
446 template <template<typename X, typename = int> class ColumnType,
447 typename... Args, if_t<
448 sizeof...(Components) == sizeof...(Args) && !PassEntity && !PassIter> = 0>
449 static flecs::entity invoke_callback(
450 ecs_iter_t *iter, const Func& func, size_t, Terms&, Args... comps)
451 {
452 size_t count = static_cast<size_t>(iter->count);
453 if (count == 0) {
454 // If query has no This terms, count can be 0. Since each does not
455 // have an entity parameter, just pass through components
456 count = 1;
457 }
458
459 flecs::iter it(iter);
460 flecs::entity result;
461
462 ECS_TABLE_LOCK(iter->world, iter->table);
463
464 for (size_t i = 0; i < count; i ++) {
465 if (func( (ColumnType< remove_reference_t<Components> >(comps, i)
466 .get_row())...))
467 {
468 result = flecs::entity(iter->world, iter->entities[i]);
469 break;
470 }
471 }
472
473 ECS_TABLE_UNLOCK(iter->world, iter->table);
474
475 return result;
476 }
477
478 template <template<typename X, typename = int> class ColumnType,
479 typename... Args, if_t< sizeof...(Components) != sizeof...(Args) > = 0>
480 static flecs::entity invoke_callback(ecs_iter_t *iter, const Func& func,
481 size_t index, Terms& columns, Args... comps)
482 {
483 return invoke_callback<ColumnType>(
484 iter, func, index + 1, columns, comps..., columns[index]);
485 }
486
487 Func m_func;
488};
489
493
494template <typename Func, typename ... Components>
496private:
497 static constexpr bool IterOnly = arity<Func>::value == 1;
498
499 using Terms = typename term_ptrs<Components ...>::array;
500
501public:
502 template < if_not_t< is_same< decay_t<Func>, decay_t<Func>& >::value > = 0>
503 explicit iter_invoker(Func&& func) noexcept
504 : m_func(FLECS_MOV(func)) { }
505
506 explicit iter_invoker(const Func& func) noexcept
507 : m_func(func) { }
508
509 // Invoke object directly. This operation is useful when the calling
510 // function has just constructed the invoker, such as what happens when
511 // iterating a query.
512 void invoke(ecs_iter_t *iter) const {
513 term_ptrs<Components...> terms;
514 terms.populate(iter);
515 invoke_callback(iter, m_func, 0, terms.m_terms);
516 }
517
518 // Static function that can be used as callback for systems/triggers
519 static void run(ecs_iter_t *iter) {
520 auto self = static_cast<const iter_invoker*>(iter->binding_ctx);
521 ecs_assert(self != nullptr, ECS_INTERNAL_ERROR, NULL);
522 self->invoke(iter);
523 }
524
525 // Instancing needs to be enabled explicitly for iter invokers
526 static bool instanced() {
527 return false;
528 }
529
530private:
531 template <typename... Args, if_t<!sizeof...(Args) && IterOnly> = 0>
532 static void invoke_callback(ecs_iter_t *iter, const Func& func,
533 size_t, Terms&, Args...)
534 {
535 flecs::iter it(iter);
536
537 ECS_TABLE_LOCK(iter->world, iter->table);
538
539 func(it);
540
541 ECS_TABLE_UNLOCK(iter->world, iter->table);
542 }
543
544 template <typename... Targs, if_t<!IterOnly &&
545 (sizeof...(Targs) == sizeof...(Components))> = 0>
546 static void invoke_callback(ecs_iter_t *iter, const Func& func, size_t,
547 Terms&, Targs... comps)
548 {
549 flecs::iter it(iter);
550
551 ECS_TABLE_LOCK(iter->world, iter->table);
552
553 func(it, ( static_cast<
554 remove_reference_t<
555 remove_pointer_t<
556 actual_type_t<Components> > >* >
557 (comps.ptr))...);
558
559 ECS_TABLE_UNLOCK(iter->world, iter->table);
560 }
561
562 template <typename... Targs, if_t<!IterOnly &&
563 (sizeof...(Targs) != sizeof...(Components)) > = 0>
564 static void invoke_callback(ecs_iter_t *iter, const Func& func,
565 size_t index, Terms& columns, Targs... comps)
566 {
567 invoke_callback(iter, func, index + 1, columns, comps...,
568 columns[index]);
569 }
570
571 Func m_func;
572};
573
574
578
579template<typename ... Args>
581
582template<typename ... Args>
584 using ColumnArray = flecs::array<int32_t, sizeof...(Args)>;
585 using ArrayType = flecs::array<void*, sizeof...(Args)>;
586 using DummyArray = flecs::array<int, sizeof...(Args)>;
587 using IdArray = flecs::array<id_t, sizeof...(Args)>;
588
589 static bool const_args() {
590 static flecs::array<bool, sizeof...(Args)> is_const_args ({
591 flecs::is_const<flecs::remove_reference_t<Args>>::value...
592 });
593
594 for (auto is_const : is_const_args) {
595 if (!is_const) {
596 return false;
597 }
598 }
599 return true;
600 }
601
602 static
603 bool get_ptrs(world_t *world, const ecs_record_t *r, ecs_table_t *table,
604 ArrayType& ptrs)
605 {
606 ecs_assert(table != NULL, ECS_INTERNAL_ERROR, NULL);
608 return false;
609 }
610
611 /* table_index_of needs real world */
612 const flecs::world_t *real_world = ecs_get_world(world);
613
614 /* Get column indices for components */
615 ColumnArray columns ({
617 _::cpp_type<Args>().id(world))...
618 });
619
620 /* Get pointers for columns for entity */
621 size_t i = 0;
622 for (int32_t column : columns) {
623 if (column == -1) {
624 return false;
625 }
626
627 ptrs[i ++] = ecs_record_get_column(r, column, 0);
628 }
629
630 return true;
631 }
632
633 static bool get_mut_ptrs(world_t *world, ecs_entity_t e, ArrayType& ptrs) {
634 /* Get pointers w/get_mut */
635 size_t i = 0;
636 DummyArray dummy ({
637 (ptrs[i ++] = ecs_get_mut_id(world, e,
638 _::cpp_type<Args>().id(world)), 0)...
639 });
640
641 return true;
642 }
643
644 template <typename Func>
645 static bool invoke_read(world_t *world, entity_t e, const Func& func) {
646 const ecs_record_t *r = ecs_read_begin(world, e);
647 if (!r) {
648 return false;
649 }
650
651 ecs_table_t *table = r->table;
652 if (!table) {
653 return false;
654 }
655
656 ArrayType ptrs;
657 bool has_components;
658 if ((has_components = get_ptrs(world, r, table, ptrs))) {
659 invoke_callback(func, 0, ptrs);
660 }
661
662 ecs_read_end(r);
663
664 return has_components;
665 }
666
667 template <typename Func>
668 static bool invoke_write(world_t *world, entity_t e, const Func& func) {
670 if (!r) {
671 return false;
672 }
673
674 ecs_table_t *table = r->table;
675 if (!table) {
676 return false;
677 }
678
679 ArrayType ptrs;
680 bool has_components;
681 if ((has_components = get_ptrs(world, r, table, ptrs))) {
682 invoke_callback(func, 0, ptrs);
683 }
684
685 ecs_write_end(r);
686
687 return has_components;
688 }
689
690 template <typename Func>
691 static bool invoke_get(world_t *world, entity_t e, const Func& func) {
692 if (const_args()) {
693 return invoke_read(world, e, func);
694 } else {
695 return invoke_write(world, e, func);
696 }
697 }
698
699 // Utility for storing id in array in pack expansion
700 static size_t store_added(IdArray& added, size_t elem, ecs_table_t *prev,
701 ecs_table_t *next, id_t id)
702 {
703 // Array should only contain ids for components that are actually added,
704 // so check if the prev and next tables are different.
705 if (prev != next) {
706 added[elem] = id;
707 elem ++;
708 }
709 return elem;
710 }
711
712 template <typename Func>
713 static bool invoke_get_mut(world_t *world, entity_t id, const Func& func) {
715
716 ArrayType ptrs;
717 ecs_table_t *table = NULL;
718
719 // When not deferred take the fast path.
720 if (!w.is_deferred()) {
721 // Bit of low level code so we only do at most one table move & one
722 // entity lookup for the entire operation.
723
724 // Make sure the object is not a stage. Operations on a stage are
725 // only allowed when the stage is in deferred mode, which is when
726 // the world is in readonly mode.
727 ecs_assert(!w.is_stage(), ECS_INVALID_PARAMETER, NULL);
728
729 // Find table for entity
731 if (r) {
732 table = r->table;
733 }
734
735 // Find destination table that has all components
736 ecs_table_t *prev = table, *next;
737 size_t elem = 0;
738 IdArray added;
739
740 // Iterate components, only store added component ids in added array
741 DummyArray dummy_before ({ (
742 next = ecs_table_add_id(world, prev, w.id<Args>()),
743 elem = store_added(added, elem, prev, next, w.id<Args>()),
744 prev = next, 0
745 )... });
746 (void)dummy_before;
747
748 // If table is different, move entity straight to it
749 if (table != next) {
750 ecs_type_t ids;
751 ids.array = added.ptr();
752 ids.count = static_cast<ecs_size_t>(elem);
753 ecs_commit(world, id, r, next, &ids, NULL);
754 table = next;
755 }
756
757 if (!get_ptrs(w, r, table, ptrs)) {
758 ecs_abort(ECS_INTERNAL_ERROR, NULL);
759 }
760
761 ECS_TABLE_LOCK(world, table);
762
763 // When deferred, obtain pointers with regular get_mut
764 } else {
765 get_mut_ptrs(world, id, ptrs);
766 }
767
768 invoke_callback(func, 0, ptrs);
769
770 if (!w.is_deferred()) {
771 ECS_TABLE_UNLOCK(world, table);
772 }
773
774 // Call modified on each component
775 DummyArray dummy_after ({
776 ( ecs_modified_id(world, id, w.id<Args>()), 0)...
777 });
778 (void)dummy_after;
779
780 return true;
781 }
782
783private:
784 template <typename Func, typename ... TArgs,
785 if_t<sizeof...(TArgs) == sizeof...(Args)> = 0>
786 static void invoke_callback(
787 const Func& f, size_t, ArrayType&, TArgs&& ... comps)
788 {
789 f(*static_cast<typename base_arg_type<Args>::type*>(comps)...);
790 }
791
792 template <typename Func, typename ... TArgs,
793 if_t<sizeof...(TArgs) != sizeof...(Args)> = 0>
794 static void invoke_callback(const Func& f, size_t arg, ArrayType& ptrs,
795 TArgs&& ... comps)
796 {
797 invoke_callback(f, arg + 1, ptrs, comps..., ptrs[arg]);
798 }
799};
800
801template <typename Func, typename U = int>
803 static_assert(function_traits<Func>::value, "type is not callable");
804};
805
806template <typename Func>
807struct entity_with_invoker<Func, if_t< is_callable<Func>::value > >
808 : entity_with_invoker_impl< arg_list_t<Func> >
809{
810 static_assert(function_traits<Func>::arity > 0,
811 "function must have at least one argument");
812};
813
814} // namespace _
815
816} // namespace flecs
#define ecs_assert(condition, error_code,...)
Assert.
Definition log.h:352
#define ecs_abort(error_code,...)
Abort.
Definition log.h:343
ecs_id_t ecs_entity_t
An entity identifier.
Definition flecs.h:286
struct ecs_world_t ecs_world_t
A world is the container for all ECS data and supporting features.
Definition flecs.h:330
struct ecs_record_t ecs_record_t
Information about an entity, like its table and row.
Definition flecs.h:436
struct ecs_table_t ecs_table_t
A table stores entities and components for a specific type.
Definition flecs.h:333
flecs::id id(E value) const
Convert enum constant to entity.
void(* ecs_ctx_free_t)(void *ctx)
Function to cleanup context data.
Definition flecs.h:590
void ecs_read_end(const ecs_record_t *record)
End read access to entity.
void ecs_write_end(ecs_record_t *record)
End exclusive write access to entity.
ecs_record_t * ecs_write_begin(ecs_world_t *world, ecs_entity_t entity)
Begin exclusive write access to entity.
void ecs_modified_id(ecs_world_t *world, ecs_entity_t entity, ecs_id_t id)
Signal that a component has been modified.
const ecs_record_t * ecs_read_begin(ecs_world_t *world, ecs_entity_t entity)
Begin read access to entity.
void * ecs_get_mut_id(ecs_world_t *world, ecs_entity_t entity, ecs_id_t id)
Get a mutable pointer to a component.
ecs_table_t * ecs_table_add_id(ecs_world_t *world, ecs_table_t *table, ecs_id_t id)
Get table that has all components of current table plus the specified id.
int32_t ecs_table_column_count(const ecs_table_t *table)
Return number of columns in table.
bool ecs_commit(ecs_world_t *world, ecs_entity_t entity, ecs_record_t *record, ecs_table_t *table, const ecs_type_t *added, const ecs_type_t *removed)
Commit (move) entity to a table.
int32_t ecs_table_get_column_index(const ecs_world_t *world, const ecs_table_t *table, ecs_id_t id)
Get column index for id.
void * ecs_record_get_column(const ecs_record_t *r, int32_t column, size_t c_size)
Get component pointer from column/record.
ecs_record_t * ecs_record_find(const ecs_world_t *world, ecs_entity_t entity)
Find record for entity.
const ecs_world_t * ecs_get_world(const ecs_poly_t *poly)
Get world from poly.
A type is a list of (component) ids.
Definition flecs.h:303
Wrapper class around a column.
Definition iter.hpp:58
Entity.
Definition entity.hpp:30
Class that wraps around a flecs::id_t.
Definition decl.hpp:27
Class that describes a term.
Definition impl.hpp:16
The world.
Definition world.hpp:132
bool is_stage() const
Test if is a stage.
Definition world.hpp:354
bool is_deferred() const
Test whether deferring is enabled.
Definition world.hpp:309
world()
Create world.
Definition world.hpp:135