18 void *on_add =
nullptr;
19 void *on_remove =
nullptr;
20 void *on_set =
nullptr;
21 void *on_replace =
nullptr;
28 if (on_add && free_on_add) {
31 if (on_remove && free_on_remove) {
32 free_on_remove(on_remove);
34 if (on_set && free_on_set) {
37 if (on_replace && free_on_replace) {
38 free_on_replace(on_replace);
51template <
typename ... Components>
56 populate_impl(
iter, std::index_sequence_for<Components...>{});
60 populate_self_impl(
iter, std::index_sequence_for<Components...>{});
68 using A = remove_pointer_t<actual_type_t<T>>;
69 if constexpr (!is_empty_v<A>) {
70 if (
iter->row_fields & (1llu << index)) {
72 fields_[index].is_row =
true;
73 fields_[index].is_ref =
true;
74 fields_[index].index =
static_cast<int8_t
>(index);
77 static_cast<int8_t
>(index));
78 fields_[index].is_ref =
iter->sources[index] != 0;
85 (void)
iter; (void)index;
87 using A = remove_pointer_t<actual_type_t<T>>;
88 if constexpr (!is_empty_v<A>) {
90 static_cast<int8_t
>(index));
91 fields_[index].is_ref =
false;
95 template <
size_t... Is>
96 void populate_impl(
const ecs_iter_t *
iter, std::index_sequence<Is...>) {
98 (populate_field<Components>(
iter, Is), ...);
101 template <
size_t... Is>
102 void populate_self_impl(
const ecs_iter_t *
iter, std::index_sequence<Is...>) {
104 (populate_self_field<Components>(
iter, Is), ...);
112template <
typename T,
typename =
int>
118 : field_(
field), row_(row) {
129 !is_empty<actual_type_t<T>>::value &&
is_actual<T>::value > >
136 return static_cast<T*
>(this->field_.ptr)[this->row_];
145 !is_empty<actual_type_t<T>>::value && !
is_actual<T>::value> >
152 return static_cast<actual_type_t<T>*
>(this->field_.ptr)[this->row_];
159struct each_field<T, if_t< is_empty<actual_type_t<T>>::value &&
160 !is_pointer<T>::value > >
167 return actual_type_t<T>();
175 !is_empty<actual_type_t<T>>::value > >
181 actual_type_t<T> get_row() {
182 if (this->field_.ptr) {
183 return &
static_cast<actual_type_t<T>
>(this->field_.ptr)[this->row_];
193template <
typename T,
typename =
int>
195 using A = remove_pointer_t<actual_type_t<T>>;
213 static_cast<int32_t
>(row));
219template <
typename Func,
typename ... Components>
221 using Terms =
typename field_ptrs<Components ...>::array;
223 template < if_not_t< is_same< decay_t<Func>, decay_t<Func>& >::value > = 0>
225 : func_(FLECS_MOV(func)) { }
236 iter->flags |= EcsIterCppEach;
238 if (
iter->ref_fields |
iter->up_fields) {
239 terms.populate(
iter);
240 invoke_unpack< each_ref_field >(
iter, func_, 0, terms.fields_);
242 terms.populate_self(
iter);
243 invoke_unpack< each_field >(
iter, func_, 0, terms.fields_);
250 ecs_assert(self !=
nullptr, ECS_INTERNAL_ERROR, NULL);
258 ecs_assert(self !=
nullptr, ECS_INTERNAL_ERROR, NULL);
270 static void destruct(
void *obj) {
271 _::free_obj<each_delegate>(obj);
278 iter->callback_ctx = ctx->on_add;
286 iter->callback_ctx = ctx->on_remove;
294 iter->callback_ctx = ctx->on_set;
302 iter->callback_ctx = ctx->on_replace;
308 template <
template<
typename X,
typename =
int>
class ColumnType,
311 decltype(std::declval<const Fn&>()(
312 std::declval<flecs::entity>(),
313 std::declval<ColumnType< remove_reference_t<Components> > >().get_row()...), 0) = 0>
314 static void invoke_callback(
318 "query does not return entities ($this variable is not populated)");
320 (ColumnType< remove_reference_t<Components> >(
iter, comps, i)
325 template <
template<
typename X,
typename =
int>
class ColumnType,
328 decltype(std::declval<const Fn&>()(
329 std::declval<flecs::iter&>(),
330 std::declval<size_t&>(),
331 std::declval<ColumnType< remove_reference_t<Components> > >().get_row()...), 0) = 0>
332 static void invoke_callback(
336 func(it, i, (ColumnType< remove_reference_t<Components> >(
iter, comps, i)
341 template <
template<
typename X,
typename =
int>
class ColumnType,
344 decltype(std::declval<const Fn&>()(
345 std::declval<ColumnType< remove_reference_t<Components> > >().get_row()...), 0) = 0>
346 static void invoke_callback(
349 func((ColumnType< remove_reference_t<Components> >(
iter, comps, i)
353 template <
template<
typename X,
typename =
int>
class ColumnType,
354 typename... Args, if_t<
355 sizeof...(Components) ==
sizeof...(Args)> = 0>
356 static void invoke_unpack(
357 ecs_iter_t *
iter,
const Func& func,
size_t, Terms&, Args... comps)
359 ECS_TABLE_LOCK(
iter->world,
iter->table);
361 size_t count =
static_cast<size_t>(
iter->count);
362 if (count == 0 && !
iter->table) {
368 for (
size_t i = 0; i < count; i ++) {
369 invoke_callback<ColumnType>(
iter, func, i, comps...);
372 ECS_TABLE_UNLOCK(
iter->world,
iter->table);
375 template <
template<
typename X,
typename =
int>
class ColumnType,
376 typename... Args, if_t<
sizeof...(Components) !=
sizeof...(Args) > = 0>
378 size_t index, Terms& columns, Args... comps)
380 invoke_unpack<ColumnType>(
381 iter, func, index + 1, columns, comps..., columns[index]);
388template <
typename Func,
typename ... Components>
390 using Terms =
typename field_ptrs<Components ...>::array;
392 template < if_not_t< is_same< decay_t<Func>, decay_t<Func>& >::value > = 0>
394 : func_(FLECS_MOV(func)) { }
405 iter->flags |= EcsIterCppEach;
407 if (
iter->ref_fields |
iter->up_fields) {
408 terms.populate(
iter);
409 return invoke_callback< each_ref_field >(
iter, func_, 0, terms.fields_);
411 terms.populate_self(
iter);
412 return invoke_callback< each_field >(
iter, func_, 0, terms.fields_);
419 template <
template<
typename X,
typename =
int>
class ColumnType,
422 if_t<
sizeof...(Components) ==
sizeof...(Args)> = 0,
423 decltype(bool(std::declval<const Fn&>()(
424 std::declval<flecs::entity>(),
425 std::declval<ColumnType< remove_reference_t<Components> > >().get_row()...))) =
true>
427 ecs_iter_t *
iter,
const Func& func,
size_t, Terms&, Args... comps)
429 ECS_TABLE_LOCK(
iter->world,
iter->table);
432 size_t count =
static_cast<size_t>(
iter->count);
435 for (
size_t i = 0; i < count; i ++) {
437 (ColumnType< remove_reference_t<Components> >(
iter, comps, i)
445 ECS_TABLE_UNLOCK(
iter->world,
iter->table);
452 template <
template<
typename X,
typename =
int>
class ColumnType,
455 if_t<
sizeof...(Components) ==
sizeof...(Args)> = 0,
456 decltype(bool(std::declval<const Fn&>()(
457 std::declval<flecs::iter&>(),
458 std::declval<size_t&>(),
459 std::declval<ColumnType< remove_reference_t<Components> > >().get_row()...))) =
true>
461 ecs_iter_t *
iter,
const Func& func,
size_t, Terms&, Args... comps)
463 size_t count =
static_cast<size_t>(
iter->count);
473 ECS_TABLE_LOCK(
iter->world,
iter->table);
475 for (
size_t i = 0; i < count; i ++) {
477 (ColumnType< remove_reference_t<Components> >(
iter, comps, i)
485 ECS_TABLE_UNLOCK(
iter->world,
iter->table);
491 template <
template<
typename X,
typename =
int>
class ColumnType,
494 if_t<
sizeof...(Components) ==
sizeof...(Args)> = 0,
495 decltype(bool(std::declval<const Fn&>()(
496 std::declval<ColumnType< remove_reference_t<Components> > >().get_row()...))) =
true>
498 ecs_iter_t *
iter,
const Func& func,
size_t, Terms&, Args... comps)
500 size_t count =
static_cast<size_t>(
iter->count);
510 ECS_TABLE_LOCK(
iter->world,
iter->table);
512 for (
size_t i = 0; i < count; i ++) {
514 (ColumnType< remove_reference_t<Components> >(
iter, comps, i)
522 ECS_TABLE_UNLOCK(
iter->world,
iter->table);
527 template <
template<
typename X,
typename =
int>
class ColumnType,
528 typename... Args, if_t<
sizeof...(Components) !=
sizeof...(Args) > = 0>
530 size_t index, Terms& columns, Args... comps)
532 return invoke_callback<ColumnType>(
533 iter, func, index + 1, columns, comps..., columns[index]);
543template <
typename Func>
545 template < if_not_t< is_same< decay_t<Func>, decay_t<Func>& >::value > = 0>
547 : func_(FLECS_MOV(func)) { }
557 iter->flags &= ~EcsIterIsValid;
564 ecs_assert(self !=
nullptr, ECS_INTERNAL_ERROR, NULL);
576template <
typename Func>
579 : func_(FLECS_MOV(func)) { }
587 template <
typename F,
588 decltype(std::declval<const F&>()(std::declval<flecs::entity>()), 0) = 0>
591 ecs_assert(self !=
nullptr, ECS_INTERNAL_ERROR, NULL);
595 template <
typename F,
596 decltype(std::declval<const F&>()(), 0) = 0>
599 ecs_assert(self !=
nullptr, ECS_INTERNAL_ERROR, NULL);
606template <
typename Func,
typename Event>
609 : func_(FLECS_MOV(func)) { }
617 template <
typename F,
618 decltype(std::declval<const F&>()(
619 std::declval<Event&>()), 0) = 0>
623 ecs_assert(self !=
nullptr, ECS_INTERNAL_ERROR, NULL);
625 "entity observer invoked without payload");
627 Event *data =
static_cast<Event*
>(
iter->
param);
631 template <
typename F,
632 decltype(std::declval<const F&>()(
633 std::declval<flecs::entity>(),
634 std::declval<Event&>()), 0) = 0>
638 ecs_assert(self !=
nullptr, ECS_INTERNAL_ERROR, NULL);
640 "entity observer invoked without payload");
642 Event *data =
static_cast<Event*
>(
iter->
param);
654template<
typename ... Args>
657template<
typename ... Args>
664 static constexpr bool const_args() {
665 return (is_const_v<remove_reference_t<Args>> && ...);
689 for (int32_t column : columns) {
701 ptrs[i ++] = ecs_record_get_by_column(r, column, 0);
718 template <
typename Func>
719 static bool invoke_read(world_t *
world, entity_t e,
const Func& func) {
731 bool has_components = get_ptrs(
world, e, r,
table, ptrs);
732 if (has_components) {
733 invoke_callback(func, 0, ptrs);
738 return has_components;
741 template <
typename Func>
742 static bool invoke_write(world_t *
world, entity_t e,
const Func& func) {
754 bool has_components = get_ptrs(
world, e, r,
table, ptrs);
755 if (has_components) {
756 invoke_callback(func, 0, ptrs);
761 return has_components;
764 template <
typename Func>
765 static bool invoke_get(world_t *
world, entity_t e,
const Func& func) {
766 if constexpr (const_args()) {
767 return invoke_read(
world, e, func);
769 return invoke_write(
world, e, func);
787 InvokeCtx(flecs::table_t *table_arg) :
table(table_arg) { }
788 flecs::table_t *
table;
789 size_t component_count = 0;
793 static int invoke_add(
796 flecs::id_t component_id,
799 ecs_table_diff_t diff;
800 flecs::table_t *next = flecs_table_traverse_add(
801 w, ctx.table, &component_id, &diff);
802 if (next != ctx.table) {
803 ctx.added[ctx.component_count] = component_id;
804 ctx.component_count ++;
806 if (diff.added_flags & EcsTableHasDontFragment) {
809 ctx.added[ctx.component_count] = component_id;
810 ctx.component_count ++;
819 template <
typename Func>
820 static bool invoke_ensure(
847 InvokeCtx ctx(table);
848 DummyArray dummy_before ({ (
849 invoke_add(w,
id, w.
id<Args>(), ctx)
855 if (table != ctx.table) {
857 ids.
array = ctx.added.ptr();
858 ids.
count =
static_cast<ecs_size_t
>(ctx.component_count);
859 ecs_commit(world,
id, r, ctx.table, &ids, NULL);
863 if (!get_ptrs(w,
id, r, table, ptrs)) {
867 ECS_TABLE_LOCK(world, table);
871 ensure_ptrs(world,
id, ptrs);
874 invoke_callback(func, 0, ptrs);
877 ECS_TABLE_UNLOCK(world, table);
881 DummyArray dummy_after ({
890 template <
typename Func,
typename ... TArgs,
891 if_t<
sizeof...(TArgs) ==
sizeof...(Args)> = 0>
892 static void invoke_callback(
893 const Func& f,
size_t, ArrayType&, TArgs&& ... comps)
895 f(*
static_cast<typename base_arg_type<Args>::type*
>(comps)...);
898 template <
typename Func,
typename ... TArgs,
899 if_t<
sizeof...(TArgs) !=
sizeof...(Args)> = 0>
900 static void invoke_callback(
const Func& f,
size_t arg, ArrayType& ptrs,
903 invoke_callback(f, arg + 1, ptrs, comps..., ptrs[arg]);
907template <
typename Func,
typename U =
int>
912template <
typename Func>
917 "function must have at least one argument");
923template <
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_modified_id(ecs_world_t *world, ecs_entity_t entity, ecs_id_t component)
Signal that a component has been modified.
void * ecs_get_mut_id(const ecs_world_t *world, ecs_entity_t entity, ecs_id_t component)
Get a mutable pointer to a component.
void * ecs_ensure_id(ecs_world_t *world, ecs_entity_t entity, ecs_id_t component, size_t size)
Ensure entity has component, return pointer.
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.
int32_t ecs_table_get_column_index(const ecs_world_t *world, const ecs_table_t *table, ecs_id_t component)
Get column index for component.
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.
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.