Skip to content

Commit

Permalink
SanderMertens#1451 Add type flags for checking valid lifecycle hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
SanderMertens authored Nov 28, 2024
1 parent 9eca2ca commit 3ae6926
Show file tree
Hide file tree
Showing 12 changed files with 964 additions and 291 deletions.
169 changes: 88 additions & 81 deletions distr/flecs.c
Original file line number Diff line number Diff line change
Expand Up @@ -18955,19 +18955,8 @@ void flecs_default_move_w_dtor(void *dst_ptr, void *src_ptr,
cl->dtor(src_ptr, count, ti);
}

/* Define noreturn attribute only for GCC or Clang.
* Certain builds in Windows require this for functions that abort
* (-Wmissing-noreturn)
*/
#if defined(__GNUC__) || defined(__clang__)
#define NORETURN __attribute__((noreturn))
#else
#define NORETURN
#endif

NORETURN
static
void ecs_ctor_illegal(
ECS_NORETURN static
void flecs_ctor_illegal(
void * dst,
int32_t count,
const ecs_type_info_t *ti) {
Expand All @@ -18976,9 +18965,8 @@ void ecs_ctor_illegal(
ecs_abort(ECS_INVALID_OPERATION, "invalid constructor for %s", ti->name);
}

NORETURN
static
void ecs_dtor_illegal(
ECS_NORETURN static
void flecs_dtor_illegal(
void *dst,
int32_t count,
const ecs_type_info_t *ti) {
Expand All @@ -18987,9 +18975,8 @@ void ecs_dtor_illegal(
ecs_abort(ECS_INVALID_OPERATION, "invalid destructor for %s", ti->name);
}

NORETURN
static
void ecs_copy_illegal(
ECS_NORETURN static
void flecs_copy_illegal(
void *dst,
const void *src,
int32_t count,
Expand All @@ -19001,9 +18988,8 @@ void ecs_copy_illegal(
ecs_abort(ECS_INVALID_OPERATION, "invalid copy assignment for %s", ti->name);
}

NORETURN
static
void ecs_move_illegal(
ECS_NORETURN static
void flecs_move_illegal(
void * dst,
void * src,
int32_t count,
Expand All @@ -19014,9 +19000,8 @@ void ecs_move_illegal(
ecs_abort(ECS_INVALID_OPERATION, "invalid move assignment for %s", ti->name);
}

NORETURN
static
void ecs_copy_ctor_illegal(
ECS_NORETURN static
void flecs_copy_ctor_illegal(
void *dst,
const void *src,
int32_t count,
Expand All @@ -19028,9 +19013,8 @@ void ecs_copy_ctor_illegal(
ecs_abort(ECS_INVALID_OPERATION, "invalid copy construct for %s", ti->name);
}

NORETURN
static
void ecs_move_ctor_illegal(
ECS_NORETURN static
void flecs_move_ctor_illegal(
void *dst,
void *src,
int32_t count,
Expand All @@ -19042,20 +19026,44 @@ void ecs_move_ctor_illegal(
ecs_abort(ECS_INVALID_OPERATION, "invalid move construct for %s", ti->name);
}


void ecs_set_hooks_id(
ecs_world_t *world,
ecs_entity_t component,
const ecs_type_hooks_t *h)
{
ecs_check(world != NULL, ECS_INVALID_PARAMETER, NULL);

ecs_check(!(h->flags & ECS_TYPE_HOOKS), ECS_INVALID_PARAMETER,
"hooks flags are derived");

/* TODO: enable asserts once RTT API is updated */
/*
ecs_check(!(h->flags & ECS_TYPE_HOOK_CTOR_ILLEGAL) || !h->ctor,
ECS_INVALID_PARAMETER, "cannot specify both hook and illegal flag");
ecs_check(!(h->flags & ECS_TYPE_HOOK_DTOR_ILLEGAL) || !h->dtor,
ECS_INVALID_PARAMETER, "cannot specify both hook and illegal flag");
ecs_check(!(h->flags & ECS_TYPE_HOOK_COPY_ILLEGAL) || !h->copy,
ECS_INVALID_PARAMETER, "cannot specify both hook and illegal flag");
ecs_check(!(h->flags & ECS_TYPE_HOOK_MOVE_ILLEGAL) || !h->move,
ECS_INVALID_PARAMETER, "cannot specify both hook and illegal flag");
ecs_check(!(h->flags & ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL) || !h->copy_ctor,
ECS_INVALID_PARAMETER,
"cannot specify both hook and illegal flag");
ecs_check(!(h->flags & ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL) || !h->move_ctor,
ECS_INVALID_PARAMETER, "cannot specify both hook and illegal flag");
ecs_check(!(h->flags & ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL) ||
!h->ctor_move_dtor, ECS_INVALID_PARAMETER,
"cannot specify both hook and illegal flag");
ecs_check(!(h->flags & ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL) || !h->move_dtor,
ECS_INVALID_PARAMETER, "cannot specify both hook and illegal flag");
*/

flecs_stage_from_world(&world);

/* Ensure that no tables have yet been created for the component */
ecs_assert( ecs_id_in_use(world, component) == false,
ecs_check( ecs_id_in_use(world, component) == false,
ECS_ALREADY_IN_USE, ecs_get_name(world, component));
ecs_assert( ecs_id_in_use(world, ecs_pair(component, EcsWildcard)) == false,
ecs_check( ecs_id_in_use(world, ecs_pair(component, EcsWildcard)) == false,
ECS_ALREADY_IN_USE, ecs_get_name(world, component));

ecs_type_info_t *ti = flecs_type_info_ensure(world, component);
Expand Down Expand Up @@ -19107,118 +19115,116 @@ void ecs_set_hooks_id(
}

/* Set default copy ctor, move ctor and merge */
ecs_type_hooks_flags_t flags = h->flags;
ecs_flags32_t flags = h->flags;
if (!h->copy_ctor) {
if(flags & ECS_COPY_ILLEGAL || flags & ECS_CTOR_ILLEGAL) {
flags |= ECS_COPY_CTOR_ILLEGAL;
if(flags & ECS_TYPE_HOOK_COPY_ILLEGAL || flags & ECS_TYPE_HOOK_CTOR_ILLEGAL) {
flags |= ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL;
} else if(h->copy) {
ti->hooks.copy_ctor = flecs_default_copy_ctor;
}
}

if (!h->move_ctor) {
if(flags & ECS_MOVE_ILLEGAL || flags & ECS_CTOR_ILLEGAL) {
flags |= ECS_MOVE_CTOR_ILLEGAL;
if(flags & ECS_TYPE_HOOK_MOVE_ILLEGAL || flags & ECS_TYPE_HOOK_CTOR_ILLEGAL) {
flags |= ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL;
} else if (h->move) {
ti->hooks.move_ctor = flecs_default_move_ctor;
}
}

if (!h->ctor_move_dtor) {
ecs_type_hooks_flags_t illegal_check = 0;
ecs_flags32_t illegal_check = 0;
if (h->move) {
illegal_check |= ECS_MOVE_ILLEGAL;
illegal_check |= ECS_TYPE_HOOK_MOVE_ILLEGAL;
if (h->dtor) {
illegal_check |= ECS_DTOR_ILLEGAL;
illegal_check |= ECS_TYPE_HOOK_DTOR_ILLEGAL;
if (h->move_ctor) {
illegal_check |= ECS_MOVE_CTOR_ILLEGAL;
illegal_check |= ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL;
/* If an explicit move ctor has been set, use callback
* that uses the move ctor vs. using a ctor+move */
ti->hooks.ctor_move_dtor = flecs_default_move_ctor_w_dtor;
} else {
illegal_check |= ECS_CTOR_ILLEGAL;
illegal_check |= ECS_TYPE_HOOK_CTOR_ILLEGAL;
/* If no explicit move_ctor has been set, use
* combination of ctor + move + dtor */
ti->hooks.ctor_move_dtor = flecs_default_ctor_w_move_w_dtor;
}
} else {
illegal_check |= ECS_MOVE_CTOR_ILLEGAL;
illegal_check |= ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL;
/* If no dtor has been set, this is just a move ctor */
ti->hooks.ctor_move_dtor = ti->hooks.move_ctor;
}
} else {
/* If move is not set but move_ctor and dtor is, we can still set
* ctor_move_dtor. */
if (h->move_ctor) {
illegal_check |= ECS_MOVE_CTOR_ILLEGAL;
illegal_check |= ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL;
if (h->dtor) {
illegal_check |= ECS_DTOR_ILLEGAL;
illegal_check |= ECS_TYPE_HOOK_DTOR_ILLEGAL;
ti->hooks.ctor_move_dtor = flecs_default_move_ctor_w_dtor;
} else {
ti->hooks.ctor_move_dtor = ti->hooks.move_ctor;
}
}
}
if(flags & illegal_check) {
flags |= ECS_CTOR_MOVE_DTOR_ILLEGAL;
flags |= ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL;
}
}

if (!h->move_dtor) {
ecs_type_hooks_flags_t illegal_check = 0;
ecs_flags32_t illegal_check = 0;
if (h->move) {
illegal_check |= ECS_MOVE_ILLEGAL;
illegal_check |= ECS_TYPE_HOOK_MOVE_ILLEGAL;
if (h->dtor) {
illegal_check |= ECS_DTOR_ILLEGAL;
illegal_check |= ECS_TYPE_HOOK_DTOR_ILLEGAL;
ti->hooks.move_dtor = flecs_default_move_w_dtor;
} else {
ti->hooks.move_dtor = flecs_default_move;
}
} else {
if (h->dtor) {
illegal_check |= ECS_DTOR_ILLEGAL;
illegal_check |= ECS_TYPE_HOOK_DTOR_ILLEGAL;
ti->hooks.move_dtor = flecs_default_dtor;
}
}
if(flags & illegal_check) {
flags |= ECS_MOVE_DTOR_ILLEGAL;
flags |= ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL;
}
}

if(flags & ECS_CTOR_ILLEGAL) {
ti->hooks.ctor = ecs_ctor_illegal;
}

if(flags & ECS_DTOR_ILLEGAL) {
ti->hooks.dtor = ecs_dtor_illegal;
}
ti->hooks.flags = flags;

if(flags & ECS_COPY_ILLEGAL) {
ti->hooks.copy = ecs_copy_illegal;
}
if (ti->hooks.ctor) ti->hooks.flags |= ECS_TYPE_HOOK_CTOR;
if (ti->hooks.dtor) ti->hooks.flags |= ECS_TYPE_HOOK_DTOR;
if (ti->hooks.move) ti->hooks.flags |= ECS_TYPE_HOOK_MOVE;
if (ti->hooks.move_ctor) ti->hooks.flags |= ECS_TYPE_HOOK_MOVE_CTOR;
if (ti->hooks.ctor_move_dtor) ti->hooks.flags |= ECS_TYPE_HOOK_CTOR_MOVE_DTOR;
if (ti->hooks.move_dtor) ti->hooks.flags |= ECS_TYPE_HOOK_MOVE_DTOR;
if (ti->hooks.copy) ti->hooks.flags |= ECS_TYPE_HOOK_COPY;
if (ti->hooks.copy_ctor) ti->hooks.flags |= ECS_TYPE_HOOK_COPY_CTOR;

if(flags & ECS_MOVE_ILLEGAL) {
ti->hooks.move = ecs_move_illegal;
}
if(flags & ECS_TYPE_HOOK_CTOR_ILLEGAL) ti->hooks.ctor = flecs_ctor_illegal;
if(flags & ECS_TYPE_HOOK_DTOR_ILLEGAL) ti->hooks.dtor = flecs_dtor_illegal;
if(flags & ECS_TYPE_HOOK_COPY_ILLEGAL) ti->hooks.copy = flecs_copy_illegal;
if(flags & ECS_TYPE_HOOK_MOVE_ILLEGAL) ti->hooks.move = flecs_move_illegal;

if(flags & ECS_COPY_CTOR_ILLEGAL) {
ti->hooks.copy_ctor = ecs_copy_ctor_illegal;
if(flags & ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL) {
ti->hooks.copy_ctor = flecs_copy_ctor_illegal;
}

if(ti->hooks.flags & ECS_MOVE_CTOR_ILLEGAL) {
ti->hooks.move_ctor = ecs_move_ctor_illegal;
if(ti->hooks.flags & ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL) {
ti->hooks.move_ctor = flecs_move_ctor_illegal;
}

if(ti->hooks.flags & ECS_CTOR_MOVE_DTOR_ILLEGAL) {
ti->hooks.ctor_move_dtor = ecs_move_ctor_illegal;
if(ti->hooks.flags & ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL) {
ti->hooks.ctor_move_dtor = flecs_move_ctor_illegal;
}

if(ti->hooks.flags & ECS_MOVE_DTOR_ILLEGAL) {
ti->hooks.ctor_move_dtor = ecs_move_ctor_illegal;
if(ti->hooks.flags & ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL) {
ti->hooks.ctor_move_dtor = flecs_move_ctor_illegal;
}

ti->hooks.flags = flags;

error:
return;
}
Expand Down Expand Up @@ -51561,7 +51567,7 @@ static
ecs_rtt_struct_ctx_t * flecs_rtt_configure_struct_hooks(
ecs_world_t *world,
const ecs_type_info_t *ti,
ecs_type_hooks_flags_t flags,
ecs_flags32_t flags,
bool ctor,
bool dtor,
bool move,
Expand Down Expand Up @@ -51599,6 +51605,7 @@ ecs_rtt_struct_ctx_t * flecs_rtt_configure_struct_hooks(
hooks.lifecycle_ctx_free = NULL;
}
hooks.flags |= flags;
hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL;
ecs_set_hooks_id(world, ti->component, &hooks);
return rtt_ctx;
}
Expand Down Expand Up @@ -51627,7 +51634,7 @@ void flecs_rtt_init_default_hooks_struct(
* the struct itself will need to have that hook: */
int i, member_count = ecs_vec_count(&struct_info->members);
ecs_member_t *members = ecs_vec_first(&struct_info->members);
ecs_type_hooks_flags_t flags = 0;
ecs_flags32_t flags = 0;
for (i = 0; i < member_count; i++) {
ecs_member_t *m = &members[i];
const ecs_type_info_t *member_ti = ecs_get_type_info(world, m->type);
Expand Down Expand Up @@ -51817,7 +51824,7 @@ void flecs_rtt_init_default_hooks_array(
bool dtor_hook_required = array_ti->hooks.dtor != NULL;
bool move_hook_required = array_ti->hooks.move != NULL;
bool copy_hook_required = array_ti->hooks.copy != NULL;
ecs_type_hooks_flags_t flags = array_ti->hooks.flags;
ecs_flags32_t flags = array_ti->hooks.flags;

ecs_type_hooks_t hooks = *ecs_get_hooks_id(world, component);

Expand Down Expand Up @@ -51856,7 +51863,7 @@ void flecs_rtt_init_default_hooks_array(
}

hooks.flags |= flags;

hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL;
ecs_set_hooks_id(world, component, &hooks);
}

Expand Down Expand Up @@ -51994,6 +52001,7 @@ void flecs_rtt_init_default_hooks_vector(
hooks.dtor = flecs_rtt_vector_dtor;
hooks.move = flecs_rtt_vector_move;
hooks.copy = flecs_rtt_vector_copy;
hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL;
ecs_set_hooks_id(world, component, &hooks);
}

Expand Down Expand Up @@ -52040,10 +52048,9 @@ void flecs_rtt_init_default_hooks(
* could cause serializers to crash when for example inspecting string
* fields. */
if (!ti || !ti->hooks.ctor) {
ecs_set_hooks_id(
world,
component,
&(ecs_type_hooks_t){.ctor = flecs_default_ctor});
ecs_set_hooks_id(world, component, &(ecs_type_hooks_t){
.ctor = flecs_default_ctor
});
}
}
}
Expand Down
Loading

0 comments on commit 3ae6926

Please sign in to comment.