17 enum Hook { OnAdd, OnRemove, OnSet, OnReplace, OnValidate, Count };
18 void *callbacks[Count] = {};
22 for (
size_t i = 0; i < Count; i ++) {
23 if (callbacks[i] && free[i]) {
24 free[i](callbacks[i]);
39template <
typename ... Components>
44 populate_impl(
iter, std::index_sequence_for<Components...>{});
48 populate_self_impl(
iter, std::index_sequence_for<Components...>{});
56 using A = remove_pointer_t<actual_type_t<T>>;
57 if constexpr (!is_empty_v<A>) {
58 if (
iter->row_fields & (1llu << index)) {
60 fields_[index].is_row =
true;
61 fields_[index].is_ref =
true;
62 fields_[index].index =
static_cast<int8_t
>(index);
67 static_cast<int8_t
>(index));
68 fields_[index].is_ref =
iter->sources[index] != 0;
71 fields_[index].stride =
static_cast<int32_t
>(
78 (void)
iter; (void)index;
80 using A = remove_pointer_t<actual_type_t<T>>;
81 if constexpr (!is_empty_v<A>) {
83 static_cast<int8_t
>(index));
84 fields_[index].is_ref =
false;
88 template <
size_t... Is>
89 void populate_impl(
const ecs_iter_t *
iter, std::index_sequence<Is...>) {
91 (populate_field<Components>(
iter, Is), ...);
94 template <
size_t... Is>
95 void populate_self_impl(
const ecs_iter_t *
iter, std::index_sequence<Is...>) {
97 (populate_self_field<Components>(
iter, Is), ...);
103template <
typename T,
bool Ref = false>
110 : iter_(
iter), field_(
field), row_(row) { }
112 decltype(
auto) get_row() {
113 using A = actual_type_t<T>;
114 if constexpr (is_empty<A>::value && !is_pointer<T>::value) {
117 using E = remove_pointer_t<A>;
125 field_.index,
static_cast<int32_t
>(row_));
129 if constexpr (is_pointer<T>::value) {
131 return static_cast<A
>(
nullptr);
139 elem =
static_cast<E*
>(ECS_OFFSET(field_.ptr,
140 row *
static_cast<size_t>(field_.stride)));
142 elem = &
static_cast<E*
>(field_.ptr)[row];
145 if constexpr (is_pointer<T>::value) {
147 }
else if constexpr (is_actual<T>::value) {
157template <
typename Func,
typename ... Components>
161 template < if_not_t< is_same< decay_t<Func>, decay_t<Func>& >::value > = 0>
162 explicit each_delegate(Func&& func) noexcept
163 : func_(FLECS_MOV(func)) { }
165 explicit each_delegate(
const Func& func) noexcept
172 invoke_until<false>(
iter);
177 auto self =
static_cast<const each_delegate*
>(
iter->callback_ctx);
185 auto self =
static_cast<const each_delegate*
>(
iter->run_ctx);
193 static each_delegate* make(
const Func& func) {
194 return FLECS_NEW(each_delegate)(func);
198 static void destruct(
void *obj) {
199 _::free_obj<each_delegate>(obj);
202 template <component_binding_ctx::Hook Hook>
205 auto self =
static_cast<const each_delegate*
>(ctx->callbacks[Hook]);
207 iter->callback_ctx = ctx->callbacks[Hook];
208 self->template invoke_until<
false,
209 Hook != component_binding_ctx::OnReplace>(
iter);
213 template <
bool Find,
bool Shared = true>
216 iter->flags |= EcsIterCppEach;
217 if (Shared && (
iter->ref_fields |
iter->up_fields |
218 (
iter->flags & EcsIterComponentInheritance)))
220 terms.populate(
iter);
221 return invoke_rows<Find, true>(
iter, terms.fields_,
222 std::index_sequence_for<Components...>{});
224 terms.populate_self(
iter);
225 return invoke_rows<Find, false>(
iter, terms.fields_,
226 std::index_sequence_for<Components...>{});
231 template <
typename... Args>
232 static decltype(
auto) invoke_callback(
235 if constexpr (std::is_invocable_v<
const Func&,
flecs::entity, Args...>) {
237 "query does not return entities ($this variable is not populated)");
240 }
else if constexpr (std::is_invocable_v<
244 return func(it, i, FLECS_FWD(args)...);
246 return func(FLECS_FWD(args)...);
250 template <
bool Find,
bool Ref,
size_t... I>
252 std::index_sequence<I...>)
const
255 size_t count =
static_cast<size_t>(
iter->
count);
256 if constexpr (Find) {
257 if constexpr (!std::is_invocable_v<
const Func&,
flecs::entity,
259 remove_reference_t<Components>, Ref>>().get_row())...>)
270 for (
size_t i = 0; i < count; i ++) {
271 if constexpr (Find) {
272 if (invoke_callback(
iter, func_, i,
273 each_field<remove_reference_t<Components>, Ref>(
274 iter, terms[I], i).get_row()...))
280 invoke_callback(
iter, func_, i,
281 each_field<remove_reference_t<Components>, Ref>(
282 iter, terms[I], i).get_row()...);
293template <
typename Func,
typename T>
295 template < if_not_t< is_same< decay_t<Func>, decay_t<Func>& >::value > = 0>
296 explicit validate_delegate(Func&& func) noexcept
297 : func_(FLECS_MOV(func)) { }
299 explicit validate_delegate(
const Func& func) noexcept
308 auto self =
static_cast<const validate_delegate*
>(ctx->callbacks[component_binding_ctx::OnValidate]);
317template <
typename Func,
typename ... Components>
319 using each_delegate<Func, Components...>::each_delegate;
322 return this->
template invoke_until<true>(
iter);
330template <
typename Func>
332 template < if_not_t< is_same< decay_t<Func>, decay_t<Func>& >::value > = 0>
333 explicit run_delegate(Func&& func) noexcept
334 : func_(FLECS_MOV(func)) { }
336 explicit run_delegate(
const Func& func) noexcept
344 iter->flags &= ~EcsIterIsValid;
350 auto self =
static_cast<const run_delegate*
>(
iter->run_ctx);
363template <
typename Func,
typename Event =
void>
365 template <
typename F>
366 explicit entity_observer_delegate(F&& func) noexcept
367 : func_(FLECS_FWD(func)) { }
370 auto self =
static_cast<const entity_observer_delegate*
>(
iter->callback_ctx);
372 if constexpr (std::is_void_v<Event> || is_empty_v<Event>) {
376 "entity observer invoked without payload");
382 template <
typename... Args>
384 if constexpr (std::is_invocable_v<
const Func&,
flecs::entity, Args&...>) {
398template <
typename ArgList>
401template <
typename... Args>
412 for (
auto id : ids) {
415 flecs_entity_get_column(record, column, 0);
424 template <
typename Func>
427 if (!record || !record->table) {
436 invoke_callback(func, ptrs, std::index_sequence_for<Args...>{});
442 template <
typename Func>
451 flecs_add_ids(
world,
entity, ids.ptr(),
static_cast<int32_t
>(
sizeof...(Args)));
461 invoke_callback(func, ptrs, std::index_sequence_for<Args...>{});
465 for (
auto id : ids) {
472 template <
typename Func,
size_t... I>
473 static void invoke_callback(
const Func& func, ArrayType& ptrs, std::index_sequence<I...>) {
478template <
typename Func,
typename =
int>
480 static_assert(arity<Func>::value > 0,
"function must have at least one argument");
484template <
typename ArgList,
bool Normalize>
487template <
bool Normalize,
typename ... Args>
489 using type = arg_list<conditional_t<Normalize, remove_reference_t<Args>, Args>...>;
494template <
typename ArgList,
typename =
int,
bool Normalize = true>
499template <
bool Normalize,
typename First,
typename ... Args>
505template <
bool Normalize,
typename First,
typename Second,
typename ... Args>
512 typename Desc,
typename Func>
513void set_callback(Desc& desc, Func&& func) {
514 (Run ? desc.run : desc.callback) = Action;
515 (Run ? desc.run_ctx : desc.callback_ctx) = FLECS_NEW(Delegate)(FLECS_FWD(func));
516 (Run ? desc.run_ctx_free : desc.callback_ctx_free) = free_obj<Delegate>;
519template <
bool Run,
typename Desc,
typename Func,
typename... Components>
520void set_each_callback(Desc& desc, Func&& func, arg_list<Components...>) {
521 using Delegate = each_delegate<decay_t<Func>, Components...>;
522 set_callback<Delegate, Run ? Delegate::run_each : Delegate::run, Run>(
523 desc, FLECS_FWD(func));
534template <
typename Func,
typename ... Args>
_::each_delegate< typename std::decay< Func >::type, Args... > delegate
Delegate type for each callbacks.
#define ecs_assert(condition, error_code,...)
Assert.
#define ECS_INVALID_OPERATION
Invalid operation error code.
#define ECS_INVALID_PARAMETER
Invalid parameter error code.
#define ECS_INTERNAL_ERROR
Internal error code.
#define ecs_abort(error_code,...)
Abort.
bool ecs_is_stage(const ecs_world_t *world)
Test whether a world object is a stage.
const ecs_type_hooks_t * ecs_get_hooks_id(const ecs_world_t *world, ecs_entity_t component)
Get hooks for a component.
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.
ecs_iter_t iter_t
Iterator type.
ecs_entity_t entity_t
Entity type.
ecs_world_t world_t
World type.
typename base_arg_type< T >::type base_arg_type_t
Convenience alias for base_arg_type.
void(*) ecs_ctx_free_t(void *ctx)
Function to clean up context data.
void(*) ecs_iter_action_t(ecs_iter_t *it)
Function prototype for iterables.
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 an entity has a component and return a pointer.
ecs_entity_t ecs_field_src(const ecs_iter_t *it, int8_t index)
Return the field source.
size_t ecs_field_stride(const ecs_iter_t *it, int8_t index)
Return the field storage stride.
void * ecs_field_at_w_size(const ecs_iter_t *it, size_t size, int8_t index, int32_t row)
Get data for a field at a specified row.
void * ecs_base_field_w_size(const ecs_iter_t *it, size_t size, int8_t index)
Get data for a field matched through component inheritance.
void * ecs_field_w_size(const ecs_iter_t *it, size_t size, int8_t index)
Get data for a field.
int32_t ecs_table_get_column_index(const ecs_world_t *world, const ecs_table_t *table, ecs_id_t component)
Get the column index for a component.
const ecs_world_t * ecs_get_world(const ecs_poly_t *poly)
Get the world from a poly.
#define flecs_poly_is(object, type)
Test if a pointer is of the specified type.
void * binding_ctx
Language binding context.
Extract the component argument list from an each-callback signature.
Strip references from each-callback argument types.
Array class (primary template, disabled).
Wrapper class around a field.
Class for iterating over query results.
flecs::table table() const
Get the table for the current iterator result.
void * param()
Access param.
size_t count() const
Get the number of entities to iterate over.
flecs::field< const flecs::entity_t > entities() const
Get read-only access to entity IDs.
bool next()
Progress iterator.
table()
Default constructor.
enable_if_t< V, int > if_t
Convenience enable_if alias using int as default type.