18 void *on_add =
nullptr;
19 void *on_remove =
nullptr;
20 void *on_set =
nullptr;
26 if (on_add && free_on_add) {
29 if (on_remove && free_on_remove) {
30 free_on_remove(on_remove);
32 if (on_set && free_on_set) {
46template <
typename ... Components>
51 populate(
iter, 0,
static_cast<
53 remove_pointer_t<Components>
>
58 populate_self(
iter, 0,
static_cast<
60 remove_pointer_t<Components>
>
69 template <
typename T,
typename... Targs,
70 typename A = remove_pointer_t<actual_type_t<T>>,
71 if_not_t< is_empty<A>::value > = 0>
72 void populate(
const ecs_iter_t *
iter,
size_t index, T, Targs... comps) {
73 if (
iter->row_fields & (1llu << index)) {
75 fields_[index].is_row =
true;
76 fields_[index].is_ref =
true;
77 fields_[index].index =
static_cast<int8_t
>(index);
80 static_cast<int8_t
>(index));
81 fields_[index].is_ref =
iter->sources[index] != 0;
84 populate(
iter, index + 1, comps ...);
87 template <
typename T,
typename... Targs,
88 typename A = remove_pointer_t<actual_type_t<T>>,
89 if_t< is_empty<A>::value > = 0>
90 void populate(
const ecs_iter_t *
iter,
size_t index, T, Targs... comps) {
91 populate(
iter, index + 1, comps ...);
94 void populate_self(
const ecs_iter_t*,
size_t) { }
96 template <
typename T,
typename... Targs,
97 typename A = remove_pointer_t<actual_type_t<T>>,
98 if_not_t< is_empty<A>::value > = 0>
99 void populate_self(
const ecs_iter_t *
iter,
size_t index, T, Targs... comps) {
101 static_cast<int8_t
>(index));
102 fields_[index].is_ref =
false;
104 populate_self(
iter, index + 1, comps ...);
107 template <
typename T,
typename... Targs,
108 typename A = remove_pointer_t<actual_type_t<T>>,
109 if_t< is_empty<A>::value > = 0>
110 void populate_self(
const ecs_iter_t *
iter,
size_t index, T, Targs... comps) {
111 populate(
iter, index + 1, comps ...);
119template <
typename T,
typename =
int>
125 : field_(
field), row_(row) {
136 !is_empty<actual_type_t<T>>::value &&
is_actual<T>::value > >
143 return static_cast<T*
>(this->field_.ptr)[this->row_];
152 !is_empty<actual_type_t<T>>::value && !
is_actual<T>::value> >
159 return static_cast<actual_type_t<T>*
>(this->field_.ptr)[this->row_];
166struct each_field<T, if_t< is_empty<actual_type_t<T>>::value &&
167 !is_pointer<T>::value > >
174 return actual_type_t<T>();
182 !is_empty<actual_type_t<T>>::value > >
188 actual_type_t<T> get_row() {
189 if (this->field_.ptr) {
190 return &
static_cast<actual_type_t<T>
>(this->field_.ptr)[this->row_];
200template <
typename T,
typename =
int>
218 static_cast<int32_t
>(row));
224template <
typename Func,
typename ... Components>
226 using Terms =
typename field_ptrs<Components ...>::array;
228 template < if_not_t< is_same< decay_t<Func>, decay_t<Func>& >::value > = 0>
230 : func_(FLECS_MOV(func)) { }
241 iter->flags |= EcsIterCppEach;
243 if (
iter->ref_fields |
iter->up_fields) {
244 terms.populate(
iter);
245 invoke_unpack< each_ref_field >(
iter, func_, 0, terms.fields_);
247 terms.populate_self(
iter);
248 invoke_unpack< each_field >(
iter, func_, 0, terms.fields_);
255 ecs_assert(self !=
nullptr, ECS_INTERNAL_ERROR, NULL);
263 ecs_assert(self !=
nullptr, ECS_INTERNAL_ERROR, NULL);
275 static void destruct(
void *obj) {
276 _::free_obj<each_delegate>(obj);
283 iter->callback_ctx = ctx->on_add;
291 iter->callback_ctx = ctx->on_remove;
299 iter->callback_ctx = ctx->on_set;
305 template <
template<
typename X,
typename =
int>
class ColumnType,
308 decltype(std::declval<const Fn&>()(
309 std::declval<flecs::entity>(),
310 std::declval<ColumnType< remove_reference_t<Components> > >().get_row()...), 0) = 0>
311 static void invoke_callback(
315 "query does not return entities ($this variable is not populated)");
317 (ColumnType< remove_reference_t<Components> >(
iter, comps, i)
322 template <
template<
typename X,
typename =
int>
class ColumnType,
325 decltype(std::declval<const Fn&>()(
326 std::declval<flecs::iter&>(),
327 std::declval<size_t&>(),
328 std::declval<ColumnType< remove_reference_t<Components> > >().get_row()...), 0) = 0>
329 static void invoke_callback(
333 func(it, i, (ColumnType< remove_reference_t<Components> >(
iter, comps, i)
338 template <
template<
typename X,
typename =
int>
class ColumnType,
341 decltype(std::declval<const Fn&>()(
342 std::declval<ColumnType< remove_reference_t<Components> > >().get_row()...), 0) = 0>
343 static void invoke_callback(
346 func((ColumnType< remove_reference_t<Components> >(
iter, comps, i)
350 template <
template<
typename X,
typename =
int>
class ColumnType,
351 typename... Args, if_t<
352 sizeof...(Components) ==
sizeof...(Args)> = 0>
353 static void invoke_unpack(
354 ecs_iter_t *
iter,
const Func& func,
size_t, Terms&, Args... comps)
356 ECS_TABLE_LOCK(
iter->world,
iter->table);
358 size_t count =
static_cast<size_t>(
iter->count);
359 if (count == 0 && !
iter->table) {
365 for (
size_t i = 0; i < count; i ++) {
366 invoke_callback<ColumnType>(
iter, func, i, comps...);
369 ECS_TABLE_UNLOCK(
iter->world,
iter->table);
372 template <
template<
typename X,
typename =
int>
class ColumnType,
373 typename... Args, if_t<
sizeof...(Components) !=
sizeof...(Args) > = 0>
375 size_t index, Terms& columns, Args... comps)
377 invoke_unpack<ColumnType>(
378 iter, func, index + 1, columns, comps..., columns[index]);
385template <
typename Func,
typename ... Components>
387 using Terms =
typename field_ptrs<Components ...>::array;
389 template < if_not_t< is_same< decay_t<Func>, decay_t<Func>& >::value > = 0>
391 : func_(FLECS_MOV(func)) { }
402 iter->flags |= EcsIterCppEach;
404 if (
iter->ref_fields |
iter->up_fields) {
405 terms.populate(
iter);
406 return invoke_callback< each_ref_field >(
iter, func_, 0, terms.fields_);
408 terms.populate_self(
iter);
409 return invoke_callback< each_field >(
iter, func_, 0, terms.fields_);
416 template <
template<
typename X,
typename =
int>
class ColumnType,
419 if_t<
sizeof...(Components) ==
sizeof...(Args)> = 0,
420 decltype(bool(std::declval<const Fn&>()(
421 std::declval<flecs::entity>(),
422 std::declval<ColumnType< remove_reference_t<Components> > >().get_row()...))) =
true>
424 ecs_iter_t *
iter,
const Func& func,
size_t, Terms&, Args... comps)
426 ECS_TABLE_LOCK(
iter->world,
iter->table);
429 size_t count =
static_cast<size_t>(
iter->count);
432 for (
size_t i = 0; i < count; i ++) {
434 (ColumnType< remove_reference_t<Components> >(
iter, comps, i)
442 ECS_TABLE_UNLOCK(
iter->world,
iter->table);
449 template <
template<
typename X,
typename =
int>
class ColumnType,
452 if_t<
sizeof...(Components) ==
sizeof...(Args)> = 0,
453 decltype(bool(std::declval<const Fn&>()(
454 std::declval<flecs::iter&>(),
455 std::declval<size_t&>(),
456 std::declval<ColumnType< remove_reference_t<Components> > >().get_row()...))) =
true>
458 ecs_iter_t *
iter,
const Func& func,
size_t, Terms&, Args... comps)
460 size_t count =
static_cast<size_t>(
iter->count);
470 ECS_TABLE_LOCK(
iter->world,
iter->table);
472 for (
size_t i = 0; i < count; i ++) {
474 (ColumnType< remove_reference_t<Components> >(
iter, comps, i)
482 ECS_TABLE_UNLOCK(
iter->world,
iter->table);
488 template <
template<
typename X,
typename =
int>
class ColumnType,
491 if_t<
sizeof...(Components) ==
sizeof...(Args)> = 0,
492 decltype(bool(std::declval<const Fn&>()(
493 std::declval<ColumnType< remove_reference_t<Components> > >().get_row()...))) =
true>
495 ecs_iter_t *
iter,
const Func& func,
size_t, Terms&, Args... comps)
497 size_t count =
static_cast<size_t>(
iter->count);
507 ECS_TABLE_LOCK(
iter->world,
iter->table);
509 for (
size_t i = 0; i < count; i ++) {
511 (ColumnType< remove_reference_t<Components> >(
iter, comps, i)
519 ECS_TABLE_UNLOCK(
iter->world,
iter->table);
524 template <
template<
typename X,
typename =
int>
class ColumnType,
525 typename... Args, if_t<
sizeof...(Components) !=
sizeof...(Args) > = 0>
527 size_t index, Terms& columns, Args... comps)
529 return invoke_callback<ColumnType>(
530 iter, func, index + 1, columns, comps..., columns[index]);
540template <
typename Func>
542 template < if_not_t< is_same< decay_t<Func>, decay_t<Func>& >::value > = 0>
544 : func_(FLECS_MOV(func)) { }
554 iter->flags &= ~EcsIterIsValid;
561 ecs_assert(self !=
nullptr, ECS_INTERNAL_ERROR, NULL);
573template <
typename Func>
576 : func_(FLECS_MOV(func)) { }
584 template <
typename F,
585 decltype(std::declval<const F&>()(std::declval<flecs::entity>()), 0) = 0>
588 ecs_assert(self !=
nullptr, ECS_INTERNAL_ERROR, NULL);
592 template <
typename F,
593 decltype(std::declval<const F&>()(), 0) = 0>
596 ecs_assert(self !=
nullptr, ECS_INTERNAL_ERROR, NULL);
603template <
typename Func,
typename Event>
606 : func_(FLECS_MOV(func)) { }
614 template <
typename F,
615 decltype(std::declval<const F&>()(
616 std::declval<Event&>()), 0) = 0>
620 ecs_assert(self !=
nullptr, ECS_INTERNAL_ERROR, NULL);
622 "entity observer invoked without payload");
624 Event *data =
static_cast<Event*
>(
iter->
param);
628 template <
typename F,
629 decltype(std::declval<const F&>()(
630 std::declval<flecs::entity>(),
631 std::declval<Event&>()), 0) = 0>
635 ecs_assert(self !=
nullptr, ECS_INTERNAL_ERROR, NULL);
637 "entity observer invoked without payload");
639 Event *data =
static_cast<Event*
>(
iter->
param);
651template<
typename ... Args>
654template<
typename ... Args>
661 static bool const_args() {
662 static flecs::array<bool,
sizeof...(Args)> is_const_args ({
663 flecs::is_const<flecs::remove_reference_t<Args>>::value...
666 for (
auto is_const : is_const_args) {
695 for (int32_t column : columns) {
707 ptrs[i ++] = ecs_record_get_by_column(r, column, 0);
724 template <
typename Func>
725 static bool invoke_read(world_t *
world, entity_t e,
const Func& func) {
737 bool has_components = get_ptrs(
world, e, r,
table, ptrs);
738 if (has_components) {
739 invoke_callback(func, 0, ptrs);
744 return has_components;
747 template <
typename Func>
748 static bool invoke_write(world_t *
world, entity_t e,
const Func& func) {
760 bool has_components = get_ptrs(
world, e, r,
table, ptrs);
761 if (has_components) {
762 invoke_callback(func, 0, ptrs);
767 return has_components;
770 template <
typename Func>
771 static bool invoke_get(world_t *
world, entity_t e,
const Func& func) {
773 return invoke_read(
world, e, func);
775 return invoke_write(
world, e, func);
793 InvokeCtx(flecs::table_t *table_arg) :
table(table_arg) { }
794 flecs::table_t *
table;
795 size_t component_count = 0;
799 static int invoke_add(
802 flecs::id_t component_id,
805 ecs_table_diff_t diff;
806 flecs::table_t *next = flecs_table_traverse_add(
807 w, ctx.table, &component_id, &diff);
808 if (next != ctx.table) {
809 ctx.added[ctx.component_count] = component_id;
810 ctx.component_count ++;
812 if (diff.added_flags & EcsTableHasDontFragment) {
815 ctx.added[ctx.component_count] = component_id;
816 ctx.component_count ++;
825 template <
typename Func>
826 static bool invoke_ensure(
853 InvokeCtx ctx(table);
854 DummyArray dummy_before ({ (
855 invoke_add(w,
id, w.
id<Args>(), ctx)
861 if (table != ctx.table) {
863 ids.
array = ctx.added.ptr();
864 ids.
count =
static_cast<ecs_size_t
>(ctx.component_count);
865 ecs_commit(world,
id, r, ctx.table, &ids, NULL);
869 if (!get_ptrs(w,
id, r, table, ptrs)) {
873 ECS_TABLE_LOCK(world, table);
877 ensure_ptrs(world,
id, ptrs);
880 invoke_callback(func, 0, ptrs);
883 ECS_TABLE_UNLOCK(world, table);
887 DummyArray dummy_after ({
896 template <
typename Func,
typename ... TArgs,
897 if_t<
sizeof...(TArgs) ==
sizeof...(Args)> = 0>
898 static void invoke_callback(
899 const Func& f,
size_t, ArrayType&, TArgs&& ... comps)
901 f(*
static_cast<typename base_arg_type<Args>::type*
>(comps)...);
904 template <
typename Func,
typename ... TArgs,
905 if_t<
sizeof...(TArgs) !=
sizeof...(Args)> = 0>
906 static void invoke_callback(
const Func& f,
size_t arg, ArrayType& ptrs,
909 invoke_callback(f, arg + 1, ptrs, comps..., ptrs[arg]);
913template <
typename Func,
typename U =
int>
918template <
typename Func>
923 "function must have at least one argument");
929template <
typename Func,
typename ... Args>
#define ecs_assert(condition, error_code,...)
Assert.
#define ecs_abort(error_code,...)
Abort.
ecs_id_t ecs_entity_t
An entity identifier.
struct ecs_world_t ecs_world_t
A world is the container for all ECS data and supporting features.
struct ecs_record_t ecs_record_t
Information about an entity, like its table and row.
struct ecs_table_t ecs_table_t
A table stores entities and components for a specific type.
flecs::entity entity(Args &&... args) const
Create an entity.
flecs::id id(E value) const
Convert enum constant to entity.
void(* ecs_ctx_free_t)(void *ctx)
Function to cleanup context data.
void * ecs_get_mut_id(const ecs_world_t *world, ecs_entity_t entity, ecs_id_t id)
Get a mutable pointer to a component.
void * ecs_ensure_id(ecs_world_t *world, ecs_entity_t entity, ecs_id_t id)
Get a mutable pointer to a component.
void ecs_modified_id(ecs_world_t *world, ecs_entity_t entity, ecs_id_t id)
Signal that a component has been modified.
ecs_entity_t ecs_field_src(const ecs_iter_t *it, int8_t index)
Return field source.
void * ecs_field_at_w_size(const ecs_iter_t *it, size_t size, int8_t index, int32_t row)
Get data for field at specified row.
void * ecs_field_w_size(const ecs_iter_t *it, size_t size, int8_t index)
Get data for field.
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.
const ecs_world_t * ecs_get_world(const ecs_poly_t *poly)
Get world from poly.
A type is a list of (component) ids.
ecs_id_t * array
Array with ids.
int32_t count
Number of elements in array.
const Self & add() const
Add a component to an entity.
Wrapper class around a field.
Class that wraps around a flecs::id_t.
Class for iterating over query results.
void * param()
Access param.
flecs::field< const flecs::entity_t > entities() const
Get readonly access to entity ids.
bool next()
Progress iterator.
bool is_stage() const
Test if is a stage.
bool is_deferred() const
Test whether deferring is enabled.