From 8286539540fa4a54c11aca2229e91ab3b684351e Mon Sep 17 00:00:00 2001 From: Javier Peletier Date: Thu, 28 Nov 2024 09:35:27 +0100 Subject: [PATCH 01/23] restored ComponentLifecycle tests first version, pending tests and cpp change default compare behavior remove flag fix clang operator== warning. always set default hook. fix wfloat-equal warning fix string comparer refactor rtt tests fix (const char *const *) add compare test file --- distr/flecs.c | 512 ++++- distr/flecs.h | 180 +- include/flecs.h | 9 + include/flecs/addons/cpp/component.hpp | 18 +- include/flecs/addons/cpp/lifecycle_traits.hpp | 147 ++ include/flecs/private/api_support.h | 6 + src/addons/meta/definitions.c | 5 +- src/addons/meta/meta.c | 231 +- src/addons/meta/meta.h | 5 + src/addons/meta/rtt_lifecycle.c | 257 ++- src/world.c | 16 +- test/cpp/project.json | 9 +- test/cpp/src/ComponentLifecycle.cpp | 176 ++ test/cpp/src/main.cpp | 39 +- test/meta/project.json | 5 + test/meta/src/Compare.c | 44 + test/meta/src/RuntimeTypes.c | 1942 ++++++++--------- test/meta/src/main.c | 19 +- 18 files changed, 2520 insertions(+), 1100 deletions(-) create mode 100644 test/meta/src/Compare.c diff --git a/distr/flecs.c b/distr/flecs.c index e6cfaa71f..126a80b22 100644 --- a/distr/flecs.c +++ b/distr/flecs.c @@ -18942,7 +18942,17 @@ void flecs_default_move_w_dtor(void *dst_ptr, void *src_ptr, cl->dtor(src_ptr, count, ti); } -ECS_NORETURN static +int flecs_default_comp( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + (void)ti; + return a_ptr == b_ptr ? 0 : (a_ptr < b_ptr) ? -1 : 1; +} + +ECS_NORETURN +static void flecs_ctor_illegal( void * dst, int32_t count, @@ -19082,6 +19092,7 @@ void ecs_set_hooks_id( if (h->move_ctor) ti->hooks.move_ctor = h->move_ctor; if (h->ctor_move_dtor) ti->hooks.ctor_move_dtor = h->ctor_move_dtor; if (h->move_dtor) ti->hooks.move_dtor = h->move_dtor; + if (h->comp) ti->hooks.comp = h->comp; if (h->on_add) ti->hooks.on_add = h->on_add; if (h->on_remove) ti->hooks.on_remove = h->on_remove; @@ -19212,6 +19223,9 @@ void ecs_set_hooks_id( ti->hooks.ctor_move_dtor = flecs_move_ctor_illegal; } + if(ti->hooks.comp == NULL) { + ti->hooks.comp = flecs_default_comp; + } error: return; } @@ -42776,6 +42790,11 @@ int flecs_expr_ser_primitive( void flecs_rtt_init_default_hooks( ecs_iter_t *it); +int ecs_compare_string( + const void *str_a, + const void *str_b, + const ecs_type_info_t *ti); + #endif #endif @@ -49650,7 +49669,10 @@ void flecs_meta_import_core_definitions( }), .type = { .size = ECS_SIZEOF(const char*), - .alignment = ECS_ALIGNOF(const char*) + .alignment = ECS_ALIGNOF(const char*), + .hooks = { + .comp = ecs_compare_string, + } } }), .type = { @@ -49924,6 +49946,223 @@ static ECS_DTOR(ecs_string_t, ptr, { *(ecs_string_t*)ptr = NULL; }) +/* Primitive comparers */ + +static +int ecs_compare_bool( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + (void)ti; + return (int)(*((const ecs_bool_t*)a_ptr)) - (int)(*((const ecs_bool_t*)b_ptr)); +} + +static +int ecs_compare_char( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + (void)ti; + return (int)(*((const ecs_char_t*)a_ptr)) - (int)(*((const ecs_char_t*)b_ptr)); +} + +static +int ecs_compare_byte( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + (void)ti; + return (int)(*((const ecs_byte_t*)a_ptr)) - (int)(*((const ecs_byte_t*)b_ptr)); +} + +static +int ecs_compare_u8( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + (void)ti; + return (int)(*((const ecs_u8_t*)a_ptr)) - (int)(*((const ecs_u8_t*)b_ptr)); +} + +static +int ecs_compare_u16( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + (void)ti; + return (int)(*((const ecs_u16_t*)a_ptr)) - (int)(*((const ecs_u16_t*)b_ptr)); +} + +static +int ecs_compare_u32( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + (void)ti; + ecs_u32_t a = *((const ecs_u32_t*)a_ptr); + ecs_u32_t b = *((const ecs_u32_t*)b_ptr); + return (a > b) - (a < b); +} + +static +int ecs_compare_u64( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + (void)ti; + ecs_u64_t a = *((const ecs_u64_t*)a_ptr); + ecs_u64_t b = *((const ecs_u64_t*)b_ptr); + return (a > b) - (a < b); +} + +static +int ecs_compare_uptr( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + (void)ti; + ecs_uptr_t a = *((const ecs_uptr_t*)a_ptr); + ecs_uptr_t b = *((const ecs_uptr_t*)b_ptr); + return (a > b) - (a < b); +} + +static +int ecs_compare_i8( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + (void)ti; + return (int)(*((const ecs_i8_t*)a_ptr)) - + (int)(*((const ecs_i8_t*)b_ptr)); +} + +static +int ecs_compare_i16( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + (void)ti; + return (int)(*((const ecs_i16_t*)a_ptr)) - + (int)(*((const ecs_i16_t*)b_ptr)); +} + +static +int ecs_compare_i32( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + (void)ti; + ecs_i32_t a = *((const ecs_i32_t*)a_ptr); + ecs_i32_t b = *((const ecs_i32_t*)b_ptr); + return (a > b) - (a < b); +} + +static +int ecs_compare_i64( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + (void)ti; + ecs_i64_t a = *((const ecs_i64_t*)a_ptr); + ecs_i64_t b = *((const ecs_i64_t*)b_ptr); + return (a > b) - (a < b); +} + +static +int ecs_compare_iptr( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + (void)ti; + ecs_iptr_t a = *((const ecs_iptr_t*)a_ptr); + ecs_iptr_t b = *((const ecs_iptr_t*)b_ptr); + return (a > b) - (a < b); +} + +static +int ecs_compare_f32( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + (void)ti; + ecs_f32_t a = *((const ecs_f32_t*)a_ptr); + ecs_f32_t b = *((const ecs_f32_t*)b_ptr); + if (a < b) return -1; + if (a > b) return 1; + return 0; +} + +static +int ecs_compare_f64( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + (void)ti; + ecs_f64_t a = *((const ecs_f64_t*)a_ptr); + ecs_f64_t b = *((const ecs_f64_t*)b_ptr); + if (a < b) return -1; + if (a > b) return 1; + return 0; +} + +static +int ecs_compare_entity( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + (void)ti; + ecs_entity_t a = *((const ecs_entity_t*)a_ptr); + ecs_entity_t b = *((const ecs_entity_t*)b_ptr); + return (a > b) - (a < b); +} + +static +int ecs_compare_id( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + (void)ti; + ecs_id_t a = *((const ecs_id_t*)a_ptr); + ecs_id_t b = *((const ecs_id_t*)b_ptr); + return (a > b) - (a < b); +} + + +int ecs_compare_string( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) { + (void)ti; + const char* str_a = *((const char *const *) a_ptr); + const char* str_b = *((const char *const *) b_ptr); + if(str_a == str_b) { + return 0; + } + if(str_a == NULL) { + return -1; + } + if(str_b == NULL) { + return 1; + } + return ecs_os_strcmp(str_a, str_b); +} /* EcsTypeSerializer lifecycle */ @@ -50165,8 +50404,13 @@ int flecs_init_type( * serializers on uninitialized values. For runtime types (rtt), the default hooks are set by flecs_meta_rtt_init_default_hooks */ ecs_type_info_t *ti = flecs_type_info_ensure(world, type); - if (meta_type->existing && !ti->hooks.ctor) { + if (meta_type->existing) { + if (!ti->hooks.ctor) { ti->hooks.ctor = flecs_default_ctor; + } + if (!ti->hooks.comp) { + ti->hooks.comp = flecs_default_comp; + } } } else { if (meta_type->kind != kind) { @@ -51301,7 +51545,10 @@ void FlecsMetaImport( .symbol = #type });\ ecs_set(world, ecs_id(ecs_##type##_t), EcsPrimitive, {\ .kind = primitive_kind\ - }); + });\ + ecs_set_hooks(world, ecs_##type##_t, { \ + .comp = ecs_compare_##type \ + }) ECS_PRIMITIVE(world, bool, EcsBool); ECS_PRIMITIVE(world, char, EcsChar); @@ -51328,7 +51575,7 @@ void FlecsMetaImport( .ctor = flecs_default_ctor, .copy = ecs_copy(ecs_string_t), .move = ecs_move(ecs_string_t), - .dtor = ecs_dtor(ecs_string_t) + .dtor = ecs_dtor(ecs_string_t), }); /* Set default child components */ @@ -51362,6 +51609,7 @@ typedef struct ecs_rtt_call_data_t { ecs_xtor_t xtor; ecs_move_t move; ecs_copy_t copy; + ecs_comp_t comp; } hook; const ecs_type_info_t *type_info; int32_t offset; @@ -51370,10 +51618,11 @@ typedef struct ecs_rtt_call_data_t { /* Lifecycle context for runtime structs */ typedef struct ecs_rtt_struct_ctx_t { - ecs_vec_t vctor; /* vector */ + ecs_vec_t vctor; /* vector */ ecs_vec_t vdtor; /* vector */ ecs_vec_t vmove; /* vector */ ecs_vec_t vcopy; /* vector */ + ecs_vec_t vcomp; /* vector */ } ecs_rtt_struct_ctx_t; /* Lifecycle context for runtime arrays */ @@ -51529,6 +51778,45 @@ void flecs_rtt_struct_copy( } } +/* Generic compare hook. It will read hook information call data from the + * structs's lifecycle context and call the compare hooks configured when + * the type was created. */ +static +int flecs_rtt_struct_comp( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *type_info) +{ + if(a_ptr == b_ptr) { + return 0; + } + + ecs_rtt_struct_ctx_t *rtt_ctx = type_info->hooks.lifecycle_ctx; + ecs_assert(rtt_ctx != NULL, ECS_INTERNAL_ERROR, NULL); + + int cb_count = ecs_vec_count(&rtt_ctx->vcomp); + int i; + for (i = 0; i < cb_count; i++) { + ecs_rtt_call_data_t *comp_data = + ecs_vec_get_t(&rtt_ctx->vcomp, ecs_rtt_call_data_t, i); + int c = comp_data->hook.comp( + ECS_OFFSET(a_ptr, comp_data->offset), + ECS_OFFSET(b_ptr, comp_data->offset), + comp_data->type_info); + if (c != 0) { + return c; + } + } + return 0; +} + +static +void flecs_rtt_free_lifecycle_nop( + void *ctx) +{ + (void)ctx; +} + static void flecs_rtt_free_lifecycle_struct_ctx( void *ctx) @@ -51543,6 +51831,7 @@ void flecs_rtt_free_lifecycle_struct_ctx( ecs_vec_fini_t(NULL, &lifecycle_ctx->vdtor, ecs_rtt_call_data_t); ecs_vec_fini_t(NULL, &lifecycle_ctx->vmove, ecs_rtt_call_data_t); ecs_vec_fini_t(NULL, &lifecycle_ctx->vcopy, ecs_rtt_call_data_t); + ecs_vec_fini_t(NULL, &lifecycle_ctx->vcomp, ecs_rtt_call_data_t); ecs_os_free(ctx); } @@ -51552,10 +51841,11 @@ ecs_rtt_struct_ctx_t * flecs_rtt_configure_struct_hooks( ecs_world_t *world, const ecs_type_info_t *ti, ecs_flags32_t flags, - bool ctor, - bool dtor, - bool move, - bool copy) + ecs_xtor_t ctor, + ecs_xtor_t dtor, + ecs_move_t move, + ecs_copy_t copy, + ecs_comp_t comp) { ecs_type_hooks_t hooks = ti->hooks; if (hooks.lifecycle_ctx_free) { @@ -51563,31 +51853,38 @@ ecs_rtt_struct_ctx_t * flecs_rtt_configure_struct_hooks( } ecs_rtt_struct_ctx_t *rtt_ctx = NULL; - if (ctor || dtor || move || copy) { + if (ctor || dtor || move || copy || comp == flecs_rtt_struct_comp) { rtt_ctx = ecs_os_malloc_t(ecs_rtt_struct_ctx_t); ecs_vec_init_t(NULL, &rtt_ctx->vctor, ecs_rtt_call_data_t, 0); ecs_vec_init_t(NULL, &rtt_ctx->vdtor, ecs_rtt_call_data_t, 0); ecs_vec_init_t(NULL, &rtt_ctx->vmove, ecs_rtt_call_data_t, 0); ecs_vec_init_t(NULL, &rtt_ctx->vcopy, ecs_rtt_call_data_t, 0); + ecs_vec_init_t(NULL, &rtt_ctx->vcomp, ecs_rtt_call_data_t, 0); hooks.lifecycle_ctx = rtt_ctx; hooks.lifecycle_ctx_free = flecs_rtt_free_lifecycle_struct_ctx; if (ctor) { - hooks.ctor = flecs_rtt_struct_ctor; + hooks.ctor = ctor; } if (dtor) { - hooks.dtor = flecs_rtt_struct_dtor; + hooks.dtor = dtor; } if (move) { - hooks.move = flecs_rtt_struct_move; + hooks.move = move; } if (copy) { - hooks.copy = flecs_rtt_struct_copy; + hooks.copy = copy; } } else { hooks.lifecycle_ctx = NULL; - hooks.lifecycle_ctx_free = NULL; + hooks.lifecycle_ctx_free = flecs_rtt_free_lifecycle_nop; } + if(comp) { + hooks.comp = comp; + } else { + hooks.comp = flecs_default_comp; + } + hooks.flags |= flags; hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id(world, ti->component, &hooks); @@ -51613,6 +51910,7 @@ void flecs_rtt_init_default_hooks_struct( bool dtor_hook_required = false; bool move_hook_required = false; bool copy_hook_required = false; + bool default_comparable = true; /* Iterate all struct members and see if any member type has hooks. If so, * the struct itself will need to have that hook: */ @@ -51627,6 +51925,12 @@ void flecs_rtt_init_default_hooks_struct( dtor_hook_required |= member_ti->hooks.dtor != NULL; move_hook_required |= member_ti->hooks.move != NULL; copy_hook_required |= member_ti->hooks.copy != NULL; + + /* A struct is default-comparable if all its members + * are default-comparable */ + default_comparable &= member_ti->hooks.comp == NULL || + member_ti->hooks.comp == flecs_default_comp; + flags |= member_ti->hooks.flags; } @@ -51636,13 +51940,15 @@ void flecs_rtt_init_default_hooks_struct( world, ti, flags, - ctor_hook_required, - dtor_hook_required, - move_hook_required, - copy_hook_required); + ctor_hook_required ? flecs_rtt_struct_ctor : NULL, + dtor_hook_required ? flecs_rtt_struct_dtor : NULL, + move_hook_required ? flecs_rtt_struct_move : NULL, + copy_hook_required ? flecs_rtt_struct_copy : NULL, + default_comparable ? NULL : flecs_rtt_struct_comp + ); if (!rtt_ctx) { - return; /* no hooks required */ + return; /* no hook forwarding required */ } /* At least a hook was configured, therefore examine each struct member to @@ -51695,6 +52001,18 @@ void flecs_rtt_init_default_hooks_struct( copy_data->hook.copy = flecs_rtt_default_copy; } } + if (!default_comparable) { + ecs_rtt_call_data_t *comp_data = + ecs_vec_append_t(NULL, &rtt_ctx->vcomp, ecs_rtt_call_data_t); + comp_data->offset = m->offset; + comp_data->type_info = member_ti; + comp_data->count = 1; + if(member_ti->hooks.comp) { + comp_data->hook.comp = member_ti->hooks.comp; + } else { + comp_data->hook.comp = flecs_default_comp; + } + } } } @@ -51791,6 +52109,34 @@ void flecs_rtt_array_copy( } } +/* Generic array compare hook. It will invoke the compare hook of the underlying + * type for each element */ +static +int flecs_rtt_array_comp( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *type_info) +{ + if(a_ptr == b_ptr) { + return 0; + } + + ecs_rtt_array_ctx_t *rtt_ctx = type_info->hooks.lifecycle_ctx; + ecs_comp_t comp = rtt_ctx->type_info->hooks.comp; + ecs_assert(comp, ECS_INVALID_PARAMETER, NULL); + ecs_size_t element_size = rtt_ctx->type_info->size; + int i; + for (i = 0; i < rtt_ctx->elem_count; i++) { + const void *a_element = ECS_ELEM(a_ptr, element_size, i); + const void *b_element = ECS_ELEM(b_ptr, element_size, i); + int c = comp(a_element, b_element, rtt_ctx->type_info); + if(c != 0) { + return c; + } + } + return 0; +} + /* Checks if an array's underlying type has hooks installed. If so, it generates * and installs required hooks for the array type itself. These hooks will * invoke the underlying type's hook for each element in the array. */ @@ -51801,26 +52147,34 @@ void flecs_rtt_init_default_hooks_array( { const EcsArray *array_info = ecs_get(world, component, EcsArray); ecs_assert(array_info != NULL, ECS_INTERNAL_ERROR, NULL); - const ecs_type_info_t *array_ti = + const ecs_type_info_t *element_ti = ecs_get_type_info(world, array_info->type); bool ctor_hook_required = - array_ti->hooks.ctor && array_ti->hooks.ctor != flecs_default_ctor; - 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_flags32_t flags = array_ti->hooks.flags; + element_ti->hooks.ctor && element_ti->hooks.ctor != flecs_default_ctor; + bool dtor_hook_required = element_ti->hooks.dtor != NULL; + bool move_hook_required = element_ti->hooks.move != NULL; + bool copy_hook_required = element_ti->hooks.copy != NULL; + + ecs_flags32_t flags = element_ti->hooks.flags; ecs_type_hooks_t hooks = *ecs_get_hooks_id(world, component); + + if(element_ti->hooks.comp == NULL || + element_ti->hooks.comp == flecs_default_comp) { + hooks.comp = flecs_default_comp; + } else { + hooks.comp = flecs_rtt_array_comp; + } if (hooks.lifecycle_ctx_free) { hooks.lifecycle_ctx_free(hooks.lifecycle_ctx); - hooks.lifecycle_ctx_free = NULL; + hooks.lifecycle_ctx_free = flecs_rtt_free_lifecycle_nop; } if (ctor_hook_required || dtor_hook_required || move_hook_required || - copy_hook_required) { + copy_hook_required || hooks.comp == flecs_rtt_array_comp) { ecs_rtt_array_ctx_t *rtt_ctx = ecs_os_malloc_t(ecs_rtt_array_ctx_t); - rtt_ctx->type_info = array_ti; + rtt_ctx->type_info = element_ti; rtt_ctx->elem_count = array_info->count; if (hooks.lifecycle_ctx_free) { hooks.lifecycle_ctx_free(hooks.lifecycle_ctx); @@ -51960,6 +52314,49 @@ void flecs_rtt_vector_copy( } } +/* Generic vector compare hook. */ +static +int flecs_rtt_vector_comp( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *type_info) +{ + if(a_ptr == b_ptr) { + return 0; + } + + const ecs_vec_t *vec_a = a_ptr; + const ecs_vec_t *vec_b = b_ptr; + + ecs_size_t count_a = ecs_vec_count(vec_a); + ecs_size_t count_b = ecs_vec_count(vec_b); + { + int c = count_a - count_b; + if(c != 0) { + return c; + } + } + + ecs_rtt_vector_ctx_t *rtt_ctx = type_info->hooks.lifecycle_ctx; + ecs_comp_t comp = rtt_ctx->type_info->hooks.comp; + ecs_assert(comp, ECS_INVALID_PARAMETER, NULL); + + ecs_size_t element_size = rtt_ctx->type_info->size; + const void *a = ecs_vec_first(vec_a); + const void *b = ecs_vec_first(vec_b); + + int i; + for (i = 0; i < count_a; i++) { + const void *a_element = ECS_ELEM(a, element_size, i); + const void *b_element = ECS_ELEM(b, element_size, i); + int c = comp(a_element, b_element, rtt_ctx->type_info); + if(c != 0) { + return c; + } + } + return 0; +} + /* Generates and installs required hooks for managing the vector and underlying * type lifecycle. Vectors always have hooks because at the very least the * vector structure itself must be initialized/destroyed/copied/moved, even if @@ -51971,21 +52368,31 @@ void flecs_rtt_init_default_hooks_vector( { const EcsVector *vector_info = ecs_get(world, component, EcsVector); ecs_assert(vector_info != NULL, ECS_INTERNAL_ERROR, NULL); - const ecs_type_info_t *vector_ti = + const ecs_type_info_t *element_ti = ecs_get_type_info(world, vector_info->type); ecs_rtt_vector_ctx_t *rtt_ctx = ecs_os_malloc_t(ecs_rtt_vector_ctx_t); - rtt_ctx->type_info = vector_ti; + rtt_ctx->type_info = element_ti; + ecs_type_hooks_t hooks = *ecs_get_hooks_id(world, component); + if (hooks.lifecycle_ctx_free) { hooks.lifecycle_ctx_free(hooks.lifecycle_ctx); } hooks.lifecycle_ctx = rtt_ctx; hooks.lifecycle_ctx_free = flecs_rtt_free_lifecycle_vector_ctx; + hooks.ctor = flecs_rtt_vector_ctor; hooks.dtor = flecs_rtt_vector_dtor; hooks.move = flecs_rtt_vector_move; hooks.copy = flecs_rtt_vector_copy; - hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; + + if(element_ti->hooks.comp == NULL || + element_ti->hooks.comp == flecs_default_comp) { + hooks.comp = flecs_default_comp; + } else { + hooks.comp = flecs_rtt_vector_comp; + } + ecs_set_hooks_id(world, component, &hooks); } @@ -52015,27 +52422,42 @@ void flecs_rtt_init_default_hooks( * */ ecs_entity_t component = it->entities[i]; + + /* Skip configuring hooks for ids already in use */ + const ecs_world_t* w = ecs_get_world(world); + if(ecs_id_in_use(w, component) || + ecs_id_in_use(w, ecs_pair(component, EcsWildcard))) { + continue; + } + const ecs_type_info_t *ti = ecs_get_type_info(world, component); + ecs_assert(ti,ECS_INTERNAL_ERROR,NULL); - if (ti) { - if (type->kind == EcsStructType) { - flecs_rtt_init_default_hooks_struct(world, component, ti); - } else if (type->kind == EcsArrayType) { - flecs_rtt_init_default_hooks_array(world, component); - } else if (type->kind == EcsVectorType) { - flecs_rtt_init_default_hooks_vector(world, component); - } + if (type->kind == EcsStructType) { + flecs_rtt_init_default_hooks_struct(world, component, ti); + } else if (type->kind == EcsArrayType) { + flecs_rtt_init_default_hooks_array(world, component); + } else if (type->kind == EcsVectorType) { + flecs_rtt_init_default_hooks_vector(world, component); } + ecs_type_hooks_t hooks = ti->hooks; /* Make sure there is at least a default constructor. This ensures that * a new component value does not contain uninitialized memory, which * 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 - }); + if(!ti->hooks.ctor) { + hooks.ctor = flecs_default_ctor; } + + if(!ti->hooks.comp) { + hooks.comp = flecs_default_comp; + } + + ecs_set_hooks_id( + world, + component, + &hooks); } } diff --git a/distr/flecs.h b/distr/flecs.h index 708b49e54..42bf28b29 100644 --- a/distr/flecs.h +++ b/distr/flecs.h @@ -3313,6 +3313,12 @@ typedef void (*ecs_move_t)( int32_t count, const ecs_type_info_t *type_info); +/** Compare hook to compare component instances */ +typedef int (*ecs_comp_t)( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *type_info); + /** Destructor function for poly objects. */ typedef void (*flecs_poly_dtor_t)( ecs_poly_t *poly); @@ -3587,11 +3593,14 @@ struct ecs_type_hooks_t { * not set explicitly it will be derived from other callbacks. */ ecs_move_t move_dtor; + ecs_comp_t comp; + /** Hook flags. * Indicates which hooks are set for the type, and which hooks are illegal. * When an ILLEGAL flag is set when calling ecs_set_hooks() a hook callback * will be set that panics when called. */ ecs_flags32_t flags; + /** Callback that is invoked when an instance of a component is added. This * callback is invoked before triggers are invoked. */ @@ -3838,6 +3847,12 @@ void flecs_default_ctor( int32_t count, const ecs_type_info_t *ctx); +/* Default compare function */ +int flecs_default_comp( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti); + /* Create allocated string from format */ FLECS_DBG_API char* flecs_vasprintf( @@ -20500,6 +20515,153 @@ ecs_move_t move_dtor(ecs_flags32_t &) { return move_dtor_impl; } + +// Traits to check for operator<, operator>, and operator== +template +using void_t = void; + + +// Trait to check for operator< +template +struct has_operator_less : std::false_type {}; + +// Only enable if T has an operator< that takes T as the right-hand side (no implicit conversion) +template +struct has_operator_less() < std::declval())>> : + std::is_same() < std::declval()), bool> {}; + +// Trait to check for operator> +template +struct has_operator_greater : std::false_type {}; + +// Only enable if T has an operator> that takes T as the right-hand side (no implicit conversion) +template +struct has_operator_greater() > std::declval())>> : + std::is_same() > std::declval()), bool> {}; + + + +// Trait to check for operator== +// This trait causes a "float comparison warning" in some compilers +// when `T` is float or double. +// Disable this warning with the following pragmas: +#if defined(__clang__) + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wfloat-equal" +#elif defined(__GNUC__) && !defined(__clang__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + +template +struct has_operator_equal : std::false_type {}; + +// Only enable if T has an operator== that takes T as the right-hand side (no implicit conversion) +template +struct has_operator_equal() == std::declval())>> : + std::is_same() == std::declval()), bool> {}; + + +// re-enable the warning: +#if defined(__clang__) + #pragma clang diagnostic pop +#elif defined(__GNUC__) && !defined(__clang__) + #pragma GCC diagnostic pop +#endif + +// 1. Compare function if `<`, `>`, are defined +template ::value && + has_operator_greater::value > = 0> +int compare_impl(const void *a, const void *b, const ecs_type_info_t *) { + const T& lhs = *static_cast(a); + const T& rhs = *static_cast(b); + if (lhs < rhs) return -1; + if (lhs > rhs) return 1; + return 0; +} + +// 2. Compare function if `<` and `==` are defined, deducing `>` +template ::value && + has_operator_equal::value && + !has_operator_greater::value > = 0> +int compare_impl(const void *a, const void *b, const ecs_type_info_t *) { + const T& lhs = *static_cast(a); + const T& rhs = *static_cast(b); + if (lhs == rhs) return 0; + if (lhs < rhs) return -1; + return 1; // If not less and not equal, must be greater +} + +// 3. Compare function if `>` and `==` are defined, deducing `<` +template ::value && + has_operator_equal::value && + !has_operator_less::value > = 0> +int compare_impl(const void *a, const void *b, const ecs_type_info_t *) { + const T& lhs = *static_cast(a); + const T& rhs = *static_cast(b); + if (lhs == rhs) return 0; + if (lhs > rhs) return 1; + return -1; // If not greater and not equal, must be less +} + +// 4. Compare function if only `<` is defined, deducing the rest +template ::value && + !has_operator_greater::value && + !has_operator_equal::value > = 0> +int compare_impl(const void *a, const void *b, const ecs_type_info_t *) { + const T& lhs = *static_cast(a); + const T& rhs = *static_cast(b); + if (lhs < rhs) return -1; + if (rhs < lhs) return 1; + return 0; // If neither is less, they must be equal +} + +// 5. Compare function if only `>` is defined, deducing the rest +template ::value && + !has_operator_less::value && + !has_operator_equal::value > = 0> +int compare_impl(const void *a, const void *b, const ecs_type_info_t *) { + const T& lhs = *static_cast(a); + const T& rhs = *static_cast(b); + if (lhs > rhs) return 1; + if (rhs > lhs) return -1; + return 0; // If neither is greater, they must be equal +} + +// 6. Compare function if only `==` is defined, compare pointers to decide greater or smaller +template ::value && + !has_operator_less::value && + !has_operator_greater::value > = 0> +int compare_impl(const void *a, const void *b, const ecs_type_info_t *) { + const T& lhs = *static_cast(a); + const T& rhs = *static_cast(b); + if (lhs == rhs) return 0; + return (a < b) ? -1 : 1; // Use pointer comparison to decide order +} + +template ::value || + has_operator_greater::value || + has_operator_equal::value > = 0> +ecs_comp_t compare() { + return compare_impl; +} + +template ::value && + !has_operator_greater::value && + !has_operator_equal::value > = 0> +ecs_comp_t compare() { + return NULL; +} + + } // _ } // flecs @@ -26828,7 +26990,21 @@ template <> inline const char* symbol_name() { template::value == true >* = nullptr> -void register_lifecycle_actions(ecs_world_t*, ecs_entity_t) { } +void register_lifecycle_actions( + ecs_world_t *world, + ecs_entity_t component) { + + const ecs_world_t* w = ecs_get_world(world); + + if(ecs_id_in_use(w, component) || + ecs_id_in_use(w, ecs_pair(component, EcsWildcard))) { + return; + } + + ecs_type_hooks_t cl{}; + cl.comp = compare(); + ecs_set_hooks_id(world, component, &cl); +} // If the component is non-trivial, register component lifecycle actions. // Depending on the type not all callbacks may be available. @@ -26851,6 +27027,8 @@ void register_lifecycle_actions( cl.ctor_move_dtor = ctor_move_dtor(cl.flags); cl.move_dtor = move_dtor(cl.flags); + cl.comp = compare(); + ecs_set_hooks_id(world, component, &cl); if (cl.flags & (ECS_TYPE_HOOK_MOVE_ILLEGAL|ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL)) diff --git a/include/flecs.h b/include/flecs.h index 8dde6591f..1058aeb92 100644 --- a/include/flecs.h +++ b/include/flecs.h @@ -645,6 +645,12 @@ typedef void (*ecs_move_t)( int32_t count, const ecs_type_info_t *type_info); +/** Compare hook to compare component instances */ +typedef int (*ecs_comp_t)( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *type_info); + /** Destructor function for poly objects. */ typedef void (*flecs_poly_dtor_t)( ecs_poly_t *poly); @@ -919,11 +925,14 @@ struct ecs_type_hooks_t { * not set explicitly it will be derived from other callbacks. */ ecs_move_t move_dtor; + ecs_comp_t comp; + /** Hook flags. * Indicates which hooks are set for the type, and which hooks are illegal. * When an ILLEGAL flag is set when calling ecs_set_hooks() a hook callback * will be set that panics when called. */ ecs_flags32_t flags; + /** Callback that is invoked when an instance of a component is added. This * callback is invoked before triggers are invoked. */ diff --git a/include/flecs/addons/cpp/component.hpp b/include/flecs/addons/cpp/component.hpp index f4702128f..751f9e78e 100644 --- a/include/flecs/addons/cpp/component.hpp +++ b/include/flecs/addons/cpp/component.hpp @@ -89,7 +89,21 @@ template <> inline const char* symbol_name() { template::value == true >* = nullptr> -void register_lifecycle_actions(ecs_world_t*, ecs_entity_t) { } +void register_lifecycle_actions( + ecs_world_t *world, + ecs_entity_t component) { + + const ecs_world_t* w = ecs_get_world(world); + + if(ecs_id_in_use(w, component) || + ecs_id_in_use(w, ecs_pair(component, EcsWildcard))) { + return; + } + + ecs_type_hooks_t cl{}; + cl.comp = compare(); + ecs_set_hooks_id(world, component, &cl); +} // If the component is non-trivial, register component lifecycle actions. // Depending on the type not all callbacks may be available. @@ -112,6 +126,8 @@ void register_lifecycle_actions( cl.ctor_move_dtor = ctor_move_dtor(cl.flags); cl.move_dtor = move_dtor(cl.flags); + cl.comp = compare(); + ecs_set_hooks_id(world, component, &cl); if (cl.flags & (ECS_TYPE_HOOK_MOVE_ILLEGAL|ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL)) diff --git a/include/flecs/addons/cpp/lifecycle_traits.hpp b/include/flecs/addons/cpp/lifecycle_traits.hpp index 425d28290..73efe673e 100644 --- a/include/flecs/addons/cpp/lifecycle_traits.hpp +++ b/include/flecs/addons/cpp/lifecycle_traits.hpp @@ -348,5 +348,152 @@ ecs_move_t move_dtor(ecs_flags32_t &) { return move_dtor_impl; } + +// Traits to check for operator<, operator>, and operator== +template +using void_t = void; + + +// Trait to check for operator< +template +struct has_operator_less : std::false_type {}; + +// Only enable if T has an operator< that takes T as the right-hand side (no implicit conversion) +template +struct has_operator_less() < std::declval())>> : + std::is_same() < std::declval()), bool> {}; + +// Trait to check for operator> +template +struct has_operator_greater : std::false_type {}; + +// Only enable if T has an operator> that takes T as the right-hand side (no implicit conversion) +template +struct has_operator_greater() > std::declval())>> : + std::is_same() > std::declval()), bool> {}; + + + +// Trait to check for operator== +// This trait causes a "float comparison warning" in some compilers +// when `T` is float or double. +// Disable this warning with the following pragmas: +#if defined(__clang__) + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wfloat-equal" +#elif defined(__GNUC__) && !defined(__clang__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + +template +struct has_operator_equal : std::false_type {}; + +// Only enable if T has an operator== that takes T as the right-hand side (no implicit conversion) +template +struct has_operator_equal() == std::declval())>> : + std::is_same() == std::declval()), bool> {}; + + +// re-enable the warning: +#if defined(__clang__) + #pragma clang diagnostic pop +#elif defined(__GNUC__) && !defined(__clang__) + #pragma GCC diagnostic pop +#endif + +// 1. Compare function if `<`, `>`, are defined +template ::value && + has_operator_greater::value > = 0> +int compare_impl(const void *a, const void *b, const ecs_type_info_t *) { + const T& lhs = *static_cast(a); + const T& rhs = *static_cast(b); + if (lhs < rhs) return -1; + if (lhs > rhs) return 1; + return 0; +} + +// 2. Compare function if `<` and `==` are defined, deducing `>` +template ::value && + has_operator_equal::value && + !has_operator_greater::value > = 0> +int compare_impl(const void *a, const void *b, const ecs_type_info_t *) { + const T& lhs = *static_cast(a); + const T& rhs = *static_cast(b); + if (lhs == rhs) return 0; + if (lhs < rhs) return -1; + return 1; // If not less and not equal, must be greater +} + +// 3. Compare function if `>` and `==` are defined, deducing `<` +template ::value && + has_operator_equal::value && + !has_operator_less::value > = 0> +int compare_impl(const void *a, const void *b, const ecs_type_info_t *) { + const T& lhs = *static_cast(a); + const T& rhs = *static_cast(b); + if (lhs == rhs) return 0; + if (lhs > rhs) return 1; + return -1; // If not greater and not equal, must be less +} + +// 4. Compare function if only `<` is defined, deducing the rest +template ::value && + !has_operator_greater::value && + !has_operator_equal::value > = 0> +int compare_impl(const void *a, const void *b, const ecs_type_info_t *) { + const T& lhs = *static_cast(a); + const T& rhs = *static_cast(b); + if (lhs < rhs) return -1; + if (rhs < lhs) return 1; + return 0; // If neither is less, they must be equal +} + +// 5. Compare function if only `>` is defined, deducing the rest +template ::value && + !has_operator_less::value && + !has_operator_equal::value > = 0> +int compare_impl(const void *a, const void *b, const ecs_type_info_t *) { + const T& lhs = *static_cast(a); + const T& rhs = *static_cast(b); + if (lhs > rhs) return 1; + if (rhs > lhs) return -1; + return 0; // If neither is greater, they must be equal +} + +// 6. Compare function if only `==` is defined, compare pointers to decide greater or smaller +template ::value && + !has_operator_less::value && + !has_operator_greater::value > = 0> +int compare_impl(const void *a, const void *b, const ecs_type_info_t *) { + const T& lhs = *static_cast(a); + const T& rhs = *static_cast(b); + if (lhs == rhs) return 0; + return (a < b) ? -1 : 1; // Use pointer comparison to decide order +} + +template ::value || + has_operator_greater::value || + has_operator_equal::value > = 0> +ecs_comp_t compare() { + return compare_impl; +} + +template ::value && + !has_operator_greater::value && + !has_operator_equal::value > = 0> +ecs_comp_t compare() { + return NULL; +} + + } // _ } // flecs diff --git a/include/flecs/private/api_support.h b/include/flecs/private/api_support.h index 5c9ce00fd..11ea8feb8 100644 --- a/include/flecs/private/api_support.h +++ b/include/flecs/private/api_support.h @@ -42,6 +42,12 @@ void flecs_default_ctor( int32_t count, const ecs_type_info_t *ctx); +/* Default compare function */ +int flecs_default_comp( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti); + /* Create allocated string from format */ FLECS_DBG_API char* flecs_vasprintf( diff --git a/src/addons/meta/definitions.c b/src/addons/meta/definitions.c index f22a7ef98..d237bb21a 100644 --- a/src/addons/meta/definitions.c +++ b/src/addons/meta/definitions.c @@ -71,7 +71,10 @@ void flecs_meta_import_core_definitions( }), .type = { .size = ECS_SIZEOF(const char*), - .alignment = ECS_ALIGNOF(const char*) + .alignment = ECS_ALIGNOF(const char*), + .hooks = { + .comp = ecs_compare_string, + } } }), .type = { diff --git a/src/addons/meta/meta.c b/src/addons/meta/meta.c index eff54d968..6147dfb1a 100644 --- a/src/addons/meta/meta.c +++ b/src/addons/meta/meta.c @@ -25,6 +25,223 @@ static ECS_DTOR(ecs_string_t, ptr, { *(ecs_string_t*)ptr = NULL; }) +/* Primitive comparers */ + +static +int ecs_compare_bool( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + (void)ti; + return (int)(*((const ecs_bool_t*)a_ptr)) - (int)(*((const ecs_bool_t*)b_ptr)); +} + +static +int ecs_compare_char( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + (void)ti; + return (int)(*((const ecs_char_t*)a_ptr)) - (int)(*((const ecs_char_t*)b_ptr)); +} + +static +int ecs_compare_byte( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + (void)ti; + return (int)(*((const ecs_byte_t*)a_ptr)) - (int)(*((const ecs_byte_t*)b_ptr)); +} + +static +int ecs_compare_u8( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + (void)ti; + return (int)(*((const ecs_u8_t*)a_ptr)) - (int)(*((const ecs_u8_t*)b_ptr)); +} + +static +int ecs_compare_u16( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + (void)ti; + return (int)(*((const ecs_u16_t*)a_ptr)) - (int)(*((const ecs_u16_t*)b_ptr)); +} + +static +int ecs_compare_u32( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + (void)ti; + ecs_u32_t a = *((const ecs_u32_t*)a_ptr); + ecs_u32_t b = *((const ecs_u32_t*)b_ptr); + return (a > b) - (a < b); +} + +static +int ecs_compare_u64( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + (void)ti; + ecs_u64_t a = *((const ecs_u64_t*)a_ptr); + ecs_u64_t b = *((const ecs_u64_t*)b_ptr); + return (a > b) - (a < b); +} + +static +int ecs_compare_uptr( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + (void)ti; + ecs_uptr_t a = *((const ecs_uptr_t*)a_ptr); + ecs_uptr_t b = *((const ecs_uptr_t*)b_ptr); + return (a > b) - (a < b); +} + +static +int ecs_compare_i8( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + (void)ti; + return (int)(*((const ecs_i8_t*)a_ptr)) - + (int)(*((const ecs_i8_t*)b_ptr)); +} + +static +int ecs_compare_i16( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + (void)ti; + return (int)(*((const ecs_i16_t*)a_ptr)) - + (int)(*((const ecs_i16_t*)b_ptr)); +} + +static +int ecs_compare_i32( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + (void)ti; + ecs_i32_t a = *((const ecs_i32_t*)a_ptr); + ecs_i32_t b = *((const ecs_i32_t*)b_ptr); + return (a > b) - (a < b); +} + +static +int ecs_compare_i64( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + (void)ti; + ecs_i64_t a = *((const ecs_i64_t*)a_ptr); + ecs_i64_t b = *((const ecs_i64_t*)b_ptr); + return (a > b) - (a < b); +} + +static +int ecs_compare_iptr( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + (void)ti; + ecs_iptr_t a = *((const ecs_iptr_t*)a_ptr); + ecs_iptr_t b = *((const ecs_iptr_t*)b_ptr); + return (a > b) - (a < b); +} + +static +int ecs_compare_f32( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + (void)ti; + ecs_f32_t a = *((const ecs_f32_t*)a_ptr); + ecs_f32_t b = *((const ecs_f32_t*)b_ptr); + if (a < b) return -1; + if (a > b) return 1; + return 0; +} + +static +int ecs_compare_f64( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + (void)ti; + ecs_f64_t a = *((const ecs_f64_t*)a_ptr); + ecs_f64_t b = *((const ecs_f64_t*)b_ptr); + if (a < b) return -1; + if (a > b) return 1; + return 0; +} + +static +int ecs_compare_entity( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + (void)ti; + ecs_entity_t a = *((const ecs_entity_t*)a_ptr); + ecs_entity_t b = *((const ecs_entity_t*)b_ptr); + return (a > b) - (a < b); +} + +static +int ecs_compare_id( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + (void)ti; + ecs_id_t a = *((const ecs_id_t*)a_ptr); + ecs_id_t b = *((const ecs_id_t*)b_ptr); + return (a > b) - (a < b); +} + + +int ecs_compare_string( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) { + (void)ti; + const char* str_a = *((const char *const *) a_ptr); + const char* str_b = *((const char *const *) b_ptr); + if(str_a == str_b) { + return 0; + } + if(str_a == NULL) { + return -1; + } + if(str_b == NULL) { + return 1; + } + return ecs_os_strcmp(str_a, str_b); +} /* EcsTypeSerializer lifecycle */ @@ -266,8 +483,13 @@ int flecs_init_type( * serializers on uninitialized values. For runtime types (rtt), the default hooks are set by flecs_meta_rtt_init_default_hooks */ ecs_type_info_t *ti = flecs_type_info_ensure(world, type); - if (meta_type->existing && !ti->hooks.ctor) { + if (meta_type->existing) { + if (!ti->hooks.ctor) { ti->hooks.ctor = flecs_default_ctor; + } + if (!ti->hooks.comp) { + ti->hooks.comp = flecs_default_comp; + } } } else { if (meta_type->kind != kind) { @@ -1402,7 +1624,10 @@ void FlecsMetaImport( .symbol = #type });\ ecs_set(world, ecs_id(ecs_##type##_t), EcsPrimitive, {\ .kind = primitive_kind\ - }); + });\ + ecs_set_hooks(world, ecs_##type##_t, { \ + .comp = ecs_compare_##type \ + }) ECS_PRIMITIVE(world, bool, EcsBool); ECS_PRIMITIVE(world, char, EcsChar); @@ -1429,7 +1654,7 @@ void FlecsMetaImport( .ctor = flecs_default_ctor, .copy = ecs_copy(ecs_string_t), .move = ecs_move(ecs_string_t), - .dtor = ecs_dtor(ecs_string_t) + .dtor = ecs_dtor(ecs_string_t), }); /* Set default child components */ diff --git a/src/addons/meta/meta.h b/src/addons/meta/meta.h index 0f2d401c8..c62934438 100644 --- a/src/addons/meta/meta.h +++ b/src/addons/meta/meta.h @@ -37,6 +37,11 @@ int flecs_expr_ser_primitive( void flecs_rtt_init_default_hooks( ecs_iter_t *it); +int ecs_compare_string( + const void *str_a, + const void *str_b, + const ecs_type_info_t *ti); + #endif #endif diff --git a/src/addons/meta/rtt_lifecycle.c b/src/addons/meta/rtt_lifecycle.c index 172079128..4b09c923e 100644 --- a/src/addons/meta/rtt_lifecycle.c +++ b/src/addons/meta/rtt_lifecycle.c @@ -15,6 +15,7 @@ typedef struct ecs_rtt_call_data_t { ecs_xtor_t xtor; ecs_move_t move; ecs_copy_t copy; + ecs_comp_t comp; } hook; const ecs_type_info_t *type_info; int32_t offset; @@ -23,10 +24,11 @@ typedef struct ecs_rtt_call_data_t { /* Lifecycle context for runtime structs */ typedef struct ecs_rtt_struct_ctx_t { - ecs_vec_t vctor; /* vector */ + ecs_vec_t vctor; /* vector */ ecs_vec_t vdtor; /* vector */ ecs_vec_t vmove; /* vector */ ecs_vec_t vcopy; /* vector */ + ecs_vec_t vcomp; /* vector */ } ecs_rtt_struct_ctx_t; /* Lifecycle context for runtime arrays */ @@ -182,6 +184,45 @@ void flecs_rtt_struct_copy( } } +/* Generic compare hook. It will read hook information call data from the + * structs's lifecycle context and call the compare hooks configured when + * the type was created. */ +static +int flecs_rtt_struct_comp( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *type_info) +{ + if(a_ptr == b_ptr) { + return 0; + } + + ecs_rtt_struct_ctx_t *rtt_ctx = type_info->hooks.lifecycle_ctx; + ecs_assert(rtt_ctx != NULL, ECS_INTERNAL_ERROR, NULL); + + int cb_count = ecs_vec_count(&rtt_ctx->vcomp); + int i; + for (i = 0; i < cb_count; i++) { + ecs_rtt_call_data_t *comp_data = + ecs_vec_get_t(&rtt_ctx->vcomp, ecs_rtt_call_data_t, i); + int c = comp_data->hook.comp( + ECS_OFFSET(a_ptr, comp_data->offset), + ECS_OFFSET(b_ptr, comp_data->offset), + comp_data->type_info); + if (c != 0) { + return c; + } + } + return 0; +} + +static +void flecs_rtt_free_lifecycle_nop( + void *ctx) +{ + (void)ctx; +} + static void flecs_rtt_free_lifecycle_struct_ctx( void *ctx) @@ -196,6 +237,7 @@ void flecs_rtt_free_lifecycle_struct_ctx( ecs_vec_fini_t(NULL, &lifecycle_ctx->vdtor, ecs_rtt_call_data_t); ecs_vec_fini_t(NULL, &lifecycle_ctx->vmove, ecs_rtt_call_data_t); ecs_vec_fini_t(NULL, &lifecycle_ctx->vcopy, ecs_rtt_call_data_t); + ecs_vec_fini_t(NULL, &lifecycle_ctx->vcomp, ecs_rtt_call_data_t); ecs_os_free(ctx); } @@ -205,10 +247,11 @@ ecs_rtt_struct_ctx_t * flecs_rtt_configure_struct_hooks( ecs_world_t *world, const ecs_type_info_t *ti, ecs_flags32_t flags, - bool ctor, - bool dtor, - bool move, - bool copy) + ecs_xtor_t ctor, + ecs_xtor_t dtor, + ecs_move_t move, + ecs_copy_t copy, + ecs_comp_t comp) { ecs_type_hooks_t hooks = ti->hooks; if (hooks.lifecycle_ctx_free) { @@ -216,31 +259,38 @@ ecs_rtt_struct_ctx_t * flecs_rtt_configure_struct_hooks( } ecs_rtt_struct_ctx_t *rtt_ctx = NULL; - if (ctor || dtor || move || copy) { + if (ctor || dtor || move || copy || comp == flecs_rtt_struct_comp) { rtt_ctx = ecs_os_malloc_t(ecs_rtt_struct_ctx_t); ecs_vec_init_t(NULL, &rtt_ctx->vctor, ecs_rtt_call_data_t, 0); ecs_vec_init_t(NULL, &rtt_ctx->vdtor, ecs_rtt_call_data_t, 0); ecs_vec_init_t(NULL, &rtt_ctx->vmove, ecs_rtt_call_data_t, 0); ecs_vec_init_t(NULL, &rtt_ctx->vcopy, ecs_rtt_call_data_t, 0); + ecs_vec_init_t(NULL, &rtt_ctx->vcomp, ecs_rtt_call_data_t, 0); hooks.lifecycle_ctx = rtt_ctx; hooks.lifecycle_ctx_free = flecs_rtt_free_lifecycle_struct_ctx; if (ctor) { - hooks.ctor = flecs_rtt_struct_ctor; + hooks.ctor = ctor; } if (dtor) { - hooks.dtor = flecs_rtt_struct_dtor; + hooks.dtor = dtor; } if (move) { - hooks.move = flecs_rtt_struct_move; + hooks.move = move; } if (copy) { - hooks.copy = flecs_rtt_struct_copy; + hooks.copy = copy; } } else { hooks.lifecycle_ctx = NULL; - hooks.lifecycle_ctx_free = NULL; + hooks.lifecycle_ctx_free = flecs_rtt_free_lifecycle_nop; + } + if(comp) { + hooks.comp = comp; + } else { + hooks.comp = flecs_default_comp; } + hooks.flags |= flags; hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id(world, ti->component, &hooks); @@ -266,6 +316,7 @@ void flecs_rtt_init_default_hooks_struct( bool dtor_hook_required = false; bool move_hook_required = false; bool copy_hook_required = false; + bool default_comparable = true; /* Iterate all struct members and see if any member type has hooks. If so, * the struct itself will need to have that hook: */ @@ -280,6 +331,12 @@ void flecs_rtt_init_default_hooks_struct( dtor_hook_required |= member_ti->hooks.dtor != NULL; move_hook_required |= member_ti->hooks.move != NULL; copy_hook_required |= member_ti->hooks.copy != NULL; + + /* A struct is default-comparable if all its members + * are default-comparable */ + default_comparable &= member_ti->hooks.comp == NULL || + member_ti->hooks.comp == flecs_default_comp; + flags |= member_ti->hooks.flags; } @@ -289,13 +346,15 @@ void flecs_rtt_init_default_hooks_struct( world, ti, flags, - ctor_hook_required, - dtor_hook_required, - move_hook_required, - copy_hook_required); + ctor_hook_required ? flecs_rtt_struct_ctor : NULL, + dtor_hook_required ? flecs_rtt_struct_dtor : NULL, + move_hook_required ? flecs_rtt_struct_move : NULL, + copy_hook_required ? flecs_rtt_struct_copy : NULL, + default_comparable ? NULL : flecs_rtt_struct_comp + ); if (!rtt_ctx) { - return; /* no hooks required */ + return; /* no hook forwarding required */ } /* At least a hook was configured, therefore examine each struct member to @@ -348,6 +407,18 @@ void flecs_rtt_init_default_hooks_struct( copy_data->hook.copy = flecs_rtt_default_copy; } } + if (!default_comparable) { + ecs_rtt_call_data_t *comp_data = + ecs_vec_append_t(NULL, &rtt_ctx->vcomp, ecs_rtt_call_data_t); + comp_data->offset = m->offset; + comp_data->type_info = member_ti; + comp_data->count = 1; + if(member_ti->hooks.comp) { + comp_data->hook.comp = member_ti->hooks.comp; + } else { + comp_data->hook.comp = flecs_default_comp; + } + } } } @@ -444,6 +515,34 @@ void flecs_rtt_array_copy( } } +/* Generic array compare hook. It will invoke the compare hook of the underlying + * type for each element */ +static +int flecs_rtt_array_comp( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *type_info) +{ + if(a_ptr == b_ptr) { + return 0; + } + + ecs_rtt_array_ctx_t *rtt_ctx = type_info->hooks.lifecycle_ctx; + ecs_comp_t comp = rtt_ctx->type_info->hooks.comp; + ecs_assert(comp, ECS_INVALID_PARAMETER, NULL); + ecs_size_t element_size = rtt_ctx->type_info->size; + int i; + for (i = 0; i < rtt_ctx->elem_count; i++) { + const void *a_element = ECS_ELEM(a_ptr, element_size, i); + const void *b_element = ECS_ELEM(b_ptr, element_size, i); + int c = comp(a_element, b_element, rtt_ctx->type_info); + if(c != 0) { + return c; + } + } + return 0; +} + /* Checks if an array's underlying type has hooks installed. If so, it generates * and installs required hooks for the array type itself. These hooks will * invoke the underlying type's hook for each element in the array. */ @@ -454,26 +553,34 @@ void flecs_rtt_init_default_hooks_array( { const EcsArray *array_info = ecs_get(world, component, EcsArray); ecs_assert(array_info != NULL, ECS_INTERNAL_ERROR, NULL); - const ecs_type_info_t *array_ti = + const ecs_type_info_t *element_ti = ecs_get_type_info(world, array_info->type); bool ctor_hook_required = - array_ti->hooks.ctor && array_ti->hooks.ctor != flecs_default_ctor; - 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_flags32_t flags = array_ti->hooks.flags; + element_ti->hooks.ctor && element_ti->hooks.ctor != flecs_default_ctor; + bool dtor_hook_required = element_ti->hooks.dtor != NULL; + bool move_hook_required = element_ti->hooks.move != NULL; + bool copy_hook_required = element_ti->hooks.copy != NULL; + + ecs_flags32_t flags = element_ti->hooks.flags; ecs_type_hooks_t hooks = *ecs_get_hooks_id(world, component); + + if(element_ti->hooks.comp == NULL || + element_ti->hooks.comp == flecs_default_comp) { + hooks.comp = flecs_default_comp; + } else { + hooks.comp = flecs_rtt_array_comp; + } if (hooks.lifecycle_ctx_free) { hooks.lifecycle_ctx_free(hooks.lifecycle_ctx); - hooks.lifecycle_ctx_free = NULL; + hooks.lifecycle_ctx_free = flecs_rtt_free_lifecycle_nop; } if (ctor_hook_required || dtor_hook_required || move_hook_required || - copy_hook_required) { + copy_hook_required || hooks.comp == flecs_rtt_array_comp) { ecs_rtt_array_ctx_t *rtt_ctx = ecs_os_malloc_t(ecs_rtt_array_ctx_t); - rtt_ctx->type_info = array_ti; + rtt_ctx->type_info = element_ti; rtt_ctx->elem_count = array_info->count; if (hooks.lifecycle_ctx_free) { hooks.lifecycle_ctx_free(hooks.lifecycle_ctx); @@ -613,6 +720,49 @@ void flecs_rtt_vector_copy( } } +/* Generic vector compare hook. */ +static +int flecs_rtt_vector_comp( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *type_info) +{ + if(a_ptr == b_ptr) { + return 0; + } + + const ecs_vec_t *vec_a = a_ptr; + const ecs_vec_t *vec_b = b_ptr; + + ecs_size_t count_a = ecs_vec_count(vec_a); + ecs_size_t count_b = ecs_vec_count(vec_b); + { + int c = count_a - count_b; + if(c != 0) { + return c; + } + } + + ecs_rtt_vector_ctx_t *rtt_ctx = type_info->hooks.lifecycle_ctx; + ecs_comp_t comp = rtt_ctx->type_info->hooks.comp; + ecs_assert(comp, ECS_INVALID_PARAMETER, NULL); + + ecs_size_t element_size = rtt_ctx->type_info->size; + const void *a = ecs_vec_first(vec_a); + const void *b = ecs_vec_first(vec_b); + + int i; + for (i = 0; i < count_a; i++) { + const void *a_element = ECS_ELEM(a, element_size, i); + const void *b_element = ECS_ELEM(b, element_size, i); + int c = comp(a_element, b_element, rtt_ctx->type_info); + if(c != 0) { + return c; + } + } + return 0; +} + /* Generates and installs required hooks for managing the vector and underlying * type lifecycle. Vectors always have hooks because at the very least the * vector structure itself must be initialized/destroyed/copied/moved, even if @@ -624,21 +774,31 @@ void flecs_rtt_init_default_hooks_vector( { const EcsVector *vector_info = ecs_get(world, component, EcsVector); ecs_assert(vector_info != NULL, ECS_INTERNAL_ERROR, NULL); - const ecs_type_info_t *vector_ti = + const ecs_type_info_t *element_ti = ecs_get_type_info(world, vector_info->type); ecs_rtt_vector_ctx_t *rtt_ctx = ecs_os_malloc_t(ecs_rtt_vector_ctx_t); - rtt_ctx->type_info = vector_ti; + rtt_ctx->type_info = element_ti; + ecs_type_hooks_t hooks = *ecs_get_hooks_id(world, component); + if (hooks.lifecycle_ctx_free) { hooks.lifecycle_ctx_free(hooks.lifecycle_ctx); } hooks.lifecycle_ctx = rtt_ctx; hooks.lifecycle_ctx_free = flecs_rtt_free_lifecycle_vector_ctx; + hooks.ctor = flecs_rtt_vector_ctor; hooks.dtor = flecs_rtt_vector_dtor; hooks.move = flecs_rtt_vector_move; hooks.copy = flecs_rtt_vector_copy; - hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; + + if(element_ti->hooks.comp == NULL || + element_ti->hooks.comp == flecs_default_comp) { + hooks.comp = flecs_default_comp; + } else { + hooks.comp = flecs_rtt_vector_comp; + } + ecs_set_hooks_id(world, component, &hooks); } @@ -668,27 +828,42 @@ void flecs_rtt_init_default_hooks( * */ ecs_entity_t component = it->entities[i]; - const ecs_type_info_t *ti = ecs_get_type_info(world, component); - if (ti) { - if (type->kind == EcsStructType) { - flecs_rtt_init_default_hooks_struct(world, component, ti); - } else if (type->kind == EcsArrayType) { - flecs_rtt_init_default_hooks_array(world, component); - } else if (type->kind == EcsVectorType) { - flecs_rtt_init_default_hooks_vector(world, component); - } + /* Skip configuring hooks for ids already in use */ + const ecs_world_t* w = ecs_get_world(world); + if(ecs_id_in_use(w, component) || + ecs_id_in_use(w, ecs_pair(component, EcsWildcard))) { + continue; + } + + const ecs_type_info_t *ti = ecs_get_type_info(world, component); + ecs_assert(ti,ECS_INTERNAL_ERROR,NULL); + + if (type->kind == EcsStructType) { + flecs_rtt_init_default_hooks_struct(world, component, ti); + } else if (type->kind == EcsArrayType) { + flecs_rtt_init_default_hooks_array(world, component); + } else if (type->kind == EcsVectorType) { + flecs_rtt_init_default_hooks_vector(world, component); } + ecs_type_hooks_t hooks = ti->hooks; /* Make sure there is at least a default constructor. This ensures that * a new component value does not contain uninitialized memory, which * 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 - }); + if(!ti->hooks.ctor) { + hooks.ctor = flecs_default_ctor; + } + + if(!ti->hooks.comp) { + hooks.comp = flecs_default_comp; } + + ecs_set_hooks_id( + world, + component, + &hooks); } } diff --git a/src/world.c b/src/world.c index cbe66941c..32a0d6832 100644 --- a/src/world.c +++ b/src/world.c @@ -1182,7 +1182,17 @@ void flecs_default_move_w_dtor(void *dst_ptr, void *src_ptr, cl->dtor(src_ptr, count, ti); } -ECS_NORETURN static +int flecs_default_comp( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + (void)ti; + return a_ptr == b_ptr ? 0 : (a_ptr < b_ptr) ? -1 : 1; +} + +ECS_NORETURN +static void flecs_ctor_illegal( void * dst, int32_t count, @@ -1322,6 +1332,7 @@ void ecs_set_hooks_id( if (h->move_ctor) ti->hooks.move_ctor = h->move_ctor; if (h->ctor_move_dtor) ti->hooks.ctor_move_dtor = h->ctor_move_dtor; if (h->move_dtor) ti->hooks.move_dtor = h->move_dtor; + if (h->comp) ti->hooks.comp = h->comp; if (h->on_add) ti->hooks.on_add = h->on_add; if (h->on_remove) ti->hooks.on_remove = h->on_remove; @@ -1452,6 +1463,9 @@ void ecs_set_hooks_id( ti->hooks.ctor_move_dtor = flecs_move_ctor_illegal; } + if(ti->hooks.comp == NULL) { + ti->hooks.comp = flecs_default_comp; + } error: return; } diff --git a/test/cpp/project.json b/test/cpp/project.json index 73579eb99..0c9bb867a 100644 --- a/test/cpp/project.json +++ b/test/cpp/project.json @@ -1053,7 +1053,14 @@ "sparse_component", "count_in_add_hook", "count_in_remove_hook", - "set_multiple_hooks" + "set_multiple_hooks", + "compare_WithGreaterThan", + "compare_WithLessThan", + "compare_WithLessAndGreaterThan", + "compare_WithEqualsAndGreaterThan", + "compare_WithEqualsAndLessThan", + "compare_WithEqualsOnly", + "compare_WithoutOperators" ] }, { "id": "Refs", diff --git a/test/cpp/src/ComponentLifecycle.cpp b/test/cpp/src/ComponentLifecycle.cpp index 258be5020..2212dd0f8 100644 --- a/test/cpp/src/ComponentLifecycle.cpp +++ b/test/cpp/src/ComponentLifecycle.cpp @@ -2279,4 +2279,180 @@ void ComponentLifecycle_set_multiple_hooks(void) { ecs.release(); /* destroys world */ test_int(removes, 2); /* two instances of `Pod` removed */ + +int compare(flecs::world& ecs, flecs::entity_t id, const void *a, const void *b) { + const ecs_type_info_t* ti = ecs_get_type_info(ecs, id); + return ti->hooks.comp(a, b, ti); +} + +struct WithGreaterThan { + int value; + bool operator>(const WithGreaterThan &other) const { + return value > other.value; + } +}; + +struct WithLessThan { + int value; + bool operator<(const WithLessThan &other) const { + return value < other.value; + } +}; + +struct WithLessAndGreaterThan { + int value; + bool operator<(const WithLessAndGreaterThan &other) const { + return value < other.value; + } + bool operator>(const WithLessAndGreaterThan &other) const { + return value > other.value; + } +}; + + +struct WithEqualsAndGreaterThan { + int value; + bool operator==(const WithEqualsAndGreaterThan &other) const { + return value == other.value; + } + bool operator>(const WithEqualsAndGreaterThan &other) const { + return value > other.value; + } +}; + +struct WithEqualsAndLessThan { + int value; + bool operator==(const WithEqualsAndLessThan &other) const { + return value == other.value; + } + bool operator<(const WithEqualsAndLessThan &other) const { + return value < other.value; + } +}; + +struct WithEqualsOnly { + int value; + bool operator==(const WithEqualsOnly &other) const { + return value == other.value; + } +}; + +struct WithoutOperators { + int value; +}; + +void ComponentLifecycle_compare_WithGreaterThan(void) { + flecs::world ecs; + + auto component = ecs.component(); + + WithGreaterThan c[] = {5, 7, 7, 5}; + + test_assert(compare(ecs, component, &c[0], &c[1]) < 0); + test_assert(compare(ecs, component, &c[1], &c[0]) > 0); + test_assert(compare(ecs, component, &c[1], &c[2]) == 0); + test_assert(compare(ecs, component, &c[2], &c[3]) > 0); + test_assert(compare(ecs, component, &c[3], &c[2]) < 0); + test_assert(compare(ecs, component, &c[1], &c[1]) == 0); +} + +void ComponentLifecycle_compare_WithLessThan(void) { + flecs::world ecs; + + auto component = ecs.component(); + + WithLessThan c[] = {5, 7, 7, 5}; + + test_assert(compare(ecs, component, &c[0], &c[1]) < 0); + test_assert(compare(ecs, component, &c[1], &c[0]) > 0); + test_assert(compare(ecs, component, &c[1], &c[2]) == 0); + test_assert(compare(ecs, component, &c[2], &c[3]) > 0); + test_assert(compare(ecs, component, &c[3], &c[2]) < 0); + test_assert(compare(ecs, component, &c[1], &c[1]) == 0); +} + +void ComponentLifecycle_compare_WithLessAndGreaterThan(void) { + flecs::world ecs; + + auto component = ecs.component(); + + WithLessAndGreaterThan c[] = {5, 7, 7, 5}; + + test_assert(compare(ecs, component, &c[0], &c[1]) < 0); + test_assert(compare(ecs, component, &c[1], &c[0]) > 0); + test_assert(compare(ecs, component, &c[1], &c[2]) == 0); + test_assert(compare(ecs, component, &c[2], &c[3]) > 0); + test_assert(compare(ecs, component, &c[3], &c[2]) < 0); + test_assert(compare(ecs, component, &c[1], &c[1]) == 0); +} + + +void ComponentLifecycle_compare_WithEqualsAndGreaterThan(void) { + flecs::world ecs; + + auto component = ecs.component(); + + WithEqualsAndGreaterThan c[] = {5, 7, 7, 5}; + + test_assert(compare(ecs, component, &c[0], &c[1]) < 0); + test_assert(compare(ecs, component, &c[1], &c[0]) > 0); + test_assert(compare(ecs, component, &c[1], &c[2]) == 0); + test_assert(compare(ecs, component, &c[2], &c[3]) > 0); + test_assert(compare(ecs, component, &c[3], &c[2]) < 0); + test_assert(compare(ecs, component, &c[1], &c[1]) == 0); +} + +void ComponentLifecycle_compare_WithEqualsAndLessThan(void) { + flecs::world ecs; + + auto component = ecs.component(); + + WithEqualsAndLessThan c[] = {5, 7, 7, 5}; + + test_assert(compare(ecs, component, &c[0], &c[1]) < 0); + test_assert(compare(ecs, component, &c[1], &c[0]) > 0); + test_assert(compare(ecs, component, &c[1], &c[2]) == 0); + test_assert(compare(ecs, component, &c[2], &c[3]) > 0); + test_assert(compare(ecs, component, &c[3], &c[2]) < 0); + test_assert(compare(ecs, component, &c[1], &c[1]) == 0); +} + +void ComponentLifecycle_compare_WithEqualsOnly(void) { + flecs::world ecs; + + auto component = ecs.component(); + + WithEqualsOnly c[] = {5, 7, 7, 5}; + + /* With only a == operator, we can only test equality */ + test_assert(compare(ecs, component, &c[1], &c[2]) == 0); + test_assert(compare(ecs, component, &c[1], &c[1]) == 0); + + /* If values are different, compare returns greater/less than 0 depending + * on memory location (position in the array) */ + test_assert(compare(ecs, component, &c[0], &c[1]) < 0); + test_assert(compare(ecs, component, &c[1], &c[0]) > 0); + test_assert(compare(ecs, component, &c[2], &c[3]) < 0); + test_assert(compare(ecs, component, &c[3], &c[2]) > 0); +} + +void ComponentLifecycle_compare_WithoutOperators(void) { + flecs::world ecs; + + auto component = ecs.component(); + + WithoutOperators c[] = {5, 7, 7, 5}; + + /* Without any operator defined, we can only test equality one element + * with itself */ + test_assert(compare(ecs, component, &c[1], &c[1]) == 0); + test_assert(compare(ecs, component, &c[3], &c[3]) == 0); + + /* Other comparisons return greater/less than 0 depending + * on memory location (position in the array) */ + test_assert(compare(ecs, component, &c[0], &c[1]) < 0); + test_assert(compare(ecs, component, &c[1], &c[0]) > 0); + test_assert(compare(ecs, component, &c[1], &c[2]) < 0); + test_assert(compare(ecs, component, &c[2], &c[3]) < 0); + test_assert(compare(ecs, component, &c[3], &c[2]) > 0); } diff --git a/test/cpp/src/main.cpp b/test/cpp/src/main.cpp index 7a5c45ac9..4458b5360 100644 --- a/test/cpp/src/main.cpp +++ b/test/cpp/src/main.cpp @@ -1019,6 +1019,13 @@ void ComponentLifecycle_sparse_component(void); void ComponentLifecycle_count_in_add_hook(void); void ComponentLifecycle_count_in_remove_hook(void); void ComponentLifecycle_set_multiple_hooks(void); +void ComponentLifecycle_compare_WithGreaterThan(void); +void ComponentLifecycle_compare_WithLessThan(void); +void ComponentLifecycle_compare_WithLessAndGreaterThan(void); +void ComponentLifecycle_compare_WithEqualsAndGreaterThan(void); +void ComponentLifecycle_compare_WithEqualsAndLessThan(void); +void ComponentLifecycle_compare_WithEqualsOnly(void); +void ComponentLifecycle_compare_WithoutOperators(void); // Testsuite 'Refs' void Refs_get_ref_by_ptr(void); @@ -5375,7 +5382,35 @@ bake_test_case ComponentLifecycle_testcases[] = { }, { "set_multiple_hooks", - ComponentLifecycle_set_multiple_hooks + ComponentLifecycle_set_multiple_hooks, + }, + { + "compare_WithGreaterThan", + ComponentLifecycle_compare_WithGreaterThan + }, + { + "compare_WithLessThan", + ComponentLifecycle_compare_WithLessThan + }, + { + "compare_WithLessAndGreaterThan", + ComponentLifecycle_compare_WithLessAndGreaterThan + }, + { + "compare_WithEqualsAndGreaterThan", + ComponentLifecycle_compare_WithEqualsAndGreaterThan + }, + { + "compare_WithEqualsAndLessThan", + ComponentLifecycle_compare_WithEqualsAndLessThan + }, + { + "compare_WithEqualsOnly", + ComponentLifecycle_compare_WithEqualsOnly + }, + { + "compare_WithoutOperators", + ComponentLifecycle_compare_WithoutOperators } }; @@ -6968,7 +7003,7 @@ static bake_test_suite suites[] = { "ComponentLifecycle", NULL, NULL, - 89, + 96, ComponentLifecycle_testcases }, { diff --git a/test/meta/project.json b/test/meta/project.json index d736524f2..b3762f828 100644 --- a/test/meta/project.json +++ b/test/meta/project.json @@ -1055,6 +1055,11 @@ "unit_prefix_from_suspend_defer", "quantity_from_suspend_defer" ] + },{ + "id": "Compare", + "testcases": [ + "u8" + ] }] } } diff --git a/test/meta/src/Compare.c b/test/meta/src/Compare.c new file mode 100644 index 000000000..f933c3522 --- /dev/null +++ b/test/meta/src/Compare.c @@ -0,0 +1,44 @@ +#include "flecs.h" +#include +#include +#include + + + + +const ecs_type_info_t *sort_ti = NULL; + +int compare_element(const void *a, const void *b) { + return sort_ti->hooks.comp(a, b, sort_ti); +} + +int compare_array(const void *a, const void *b, ecs_size_t num_elements) { + int i; + for(i = 0; isize, i); + const void *el_b = ECS_ELEM(b, sort_ti->size, i); + int c = compare_element(el_a, el_b); + if(c != 0) { + return c; + } + } + return 0; +} + +void sort_array(const ecs_world_t* world, ecs_entity_t component, void *arr, ecs_size_t num_elements) { + sort_ti = ecs_get_type_info(world, component); + qsort(arr, num_elements, sort_ti->size, compare_element); +} + +void Compare_u8(void) { + ecs_world_t *world = ecs_init(); + + ecs_u8_t arr[] = {1, 79, 12, 3, 255, 79, 0, 14 }; + ecs_u8_t expected[] = {0, 1, 3, 12, 14, 79, 79, 255 }; + + sort_array(world, ecs_id(ecs_u8_t), arr, 8); + + test_assert(compare_array(arr, expected, 8) == 0); + + ecs_fini(world); +} \ No newline at end of file diff --git a/test/meta/src/RuntimeTypes.c b/test/meta/src/RuntimeTypes.c index 6a789450c..a5539179b 100644 --- a/test/meta/src/RuntimeTypes.c +++ b/test/meta/src/RuntimeTypes.c @@ -215,6 +215,12 @@ const ecs_type_info_t *define_test_struct( return ecs_get_type_info(world, test_struct); } +/* Compares two instances of the given type */ +int compare(const ecs_world_t* world, ecs_entity_t id, const void *a, const void *b) { + const ecs_type_info_t* ti = ecs_get_type_info(world, id); + return ti->hooks.comp(a, b, ti); +} + /* Tests that a constructor is generated for a struct if at least a member has * itself a constructor Also tests if the generated constructor works. */ void RuntimeTypes_ctor(void) { @@ -695,6 +701,18 @@ void ResourceHandle_copy( } } +/* compares two resource handles */ +static +int ResourceHandle_comp( + const void *a, + const void *b, + const ecs_type_info_t *ti) +{ + int va = ((const ResourceHandle*)a)->value; + int vb = ((const ResourceHandle*)b)->value; + return (va > vb) - (va < vb); +} + /* Defines a struct in Flecs to model the ResourceHandle struct * For different tests, it can set specific hooks or not. */ static ecs_entity_t resource_handle; @@ -728,6 +746,8 @@ void define_resource_handle( hooks.copy = ResourceHandle_copy; hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; + hooks.comp = ResourceHandle_comp; + ecs_set_hooks_id(world, resource_handle, &hooks); } @@ -938,27 +958,6 @@ void RuntimeTypes_array_dtor_illegal(void) { ecs_fini(world); } -/* compares two resource handles */ -static -bool resource_handle_compare( - ecs_world_t *world, - void *a, - void *b, - int32_t count, - const ecs_type_info_t *ti) -{ - for (int j = 0; j < count; j++) { - const ResourceHandle *ra = - (const ResourceHandle *) ECS_ELEM(a, ti->size, j); - const ResourceHandle *rb = - (const ResourceHandle *) ECS_ELEM(b, ti->size, j); - if (ra->value != rb->value) { - return false; - } - } - return true; -} - /* Tests that if on the array's underlying type only a move hook is defined, * only a move hook is defined for the array itself. Tests that the specified * move hook is called for each array element. */ @@ -1010,17 +1009,13 @@ void RuntimeTypes_array_move(void) { ecs_add_id(world, e, ecs_new(world)); handles = (ResourceHandle *) ecs_get_mut_id(world, e, arr_of_resources); - const ecs_type_info_t *rh_ti = ecs_get_type_info(world, resource_handle); /* we should retrieve the same values: */ - test_assert(resource_handle_compare( - world, &(ResourceHandle){.id = 100, .value = 111}, &handles[0], 1, - rh_ti)); - test_assert(resource_handle_compare( - world, &(ResourceHandle){.id = 200, .value = 222}, &handles[1], 1, - rh_ti)); - test_assert(resource_handle_compare( - world, &(ResourceHandle){.id = 300, .value = 333}, &handles[2], 1, - rh_ti)); + test_assert(0 == compare( + world, resource_handle, &(ResourceHandle){.id = 100, .value = 111}, &handles[0])); + test_assert(0 == compare( + world, resource_handle, &(ResourceHandle){.id = 200, .value = 222}, &handles[1])); + test_assert(0 == compare( + world, resource_handle, &(ResourceHandle){.id = 300, .value = 333}, &handles[2])); test_int(10, resources_left()); /* pool stays the same */ @@ -1126,13 +1121,12 @@ void RuntimeTypes_array_copy(void) { ResourceHandle *handles = (ResourceHandle *) ecs_get_mut_id(world, e, arr_of_resources); - const ecs_type_info_t *rh_ti = ecs_get_type_info(world, resource_handle); - test_assert(resource_handle_compare(world, &prefab_handles[0], &handles[0], - 1, rh_ti)); - test_assert(resource_handle_compare(world, &prefab_handles[1], &handles[1], - 1, rh_ti)); - test_assert(resource_handle_compare(world, &prefab_handles[2], &handles[2], - 1, rh_ti)); + test_assert(0 == compare( + world, resource_handle, &prefab_handles[0], &handles[0])); + test_assert(0 == compare( + world, resource_handle, &prefab_handles[1], &handles[1])); + test_assert(0 == compare( + world, resource_handle, &prefab_handles[2], &handles[2])); ecs_delete(world, e); test_int(7, resources_left()); /* resources not returned since we @@ -1317,6 +1311,8 @@ ecs_entity_t define_ResourceHandle_opaque( hooks.move = ResourceHandle_move; hooks.copy = ResourceHandle_copy; hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; + hooks.comp = ResourceHandle_comp; + ecs_set_hooks_id(world, ecs_id(ResourceHandle), &hooks); /* Create struct type that describes the structure of ResourceHandle */ @@ -1388,32 +1384,30 @@ void RuntimeTypes_struct_with_ints(void) { /* Test constructor: */ ecs_entity_t e = ecs_new(world); - { - StructWithInts *ptr = ecs_ensure_id(world, e, struct_with_ints); - test_memory_zero(ptr, sizeof(StructWithInts)); - ptr->a = 100; - ptr->b = 101; - } + StructWithInts *ptr1 = ecs_ensure_id(world, e, struct_with_ints); + test_memory_zero(ptr1, sizeof(StructWithInts)); + ptr1->a = 100; + ptr1->b = 101; /* Test copying: */ ecs_entity_t instance = ecs_clone(world, 0, e, true); - { - const StructWithInts *ptr = - ecs_get_id(world, instance, struct_with_ints); - test_int(100, ptr->a); - test_int(101, ptr->b); - } + const StructWithInts *ptr2 = + ecs_get_id(world, instance, struct_with_ints); + test_int(100, ptr2->a); + test_int(101, ptr2->b); + + test_assert(compare(world, struct_with_ints, ptr1, ptr2) == 0); /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); ecs_add(world, e, MakeMeMove); - { - const StructWithInts *ptr = - ecs_get_id(world, instance, struct_with_ints); - test_int(100, ptr->a); - test_int(101, ptr->b); - } + const StructWithInts *ptr3 = + ecs_get_id(world, instance, struct_with_ints); + test_int(100, ptr3->a); + test_int(101, ptr3->b); + + test_assert(compare(world, struct_with_ints, ptr1, ptr3) == 0); /* Test deleting: */ ecs_delete(world, e); @@ -1441,34 +1435,33 @@ void RuntimeTypes_struct_with_strings(void) { /* Test constructor: */ ecs_entity_t e = ecs_new(world); - { - StructWithStrings *ptr = ecs_ensure_id(world, e, struct_with_strings); - test_memory_zero(ptr, sizeof(StructWithStrings)); - ptr->a = ecs_os_strdup("String100"); - ptr->b = 101; - ptr->c = ecs_os_strdup("String102"); - } + StructWithStrings *ptr1 = ecs_ensure_id(world, e, struct_with_strings); + test_memory_zero(ptr1, sizeof(StructWithStrings)); + ptr1->a = ecs_os_strdup("String100"); + ptr1->b = 101; + ptr1->c = ecs_os_strdup("String102"); + /* Test copying: */ ecs_entity_t instance = ecs_clone(world, 0, e, true); - { - const StructWithStrings *ptr = - ecs_get_id(world, instance, struct_with_strings); - test_str("String100", ptr->a); - test_int(101, ptr->b); - test_str("String102", ptr->c); - } + const StructWithStrings *ptr2 = + ecs_get_id(world, instance, struct_with_strings); + test_str("String100", ptr2->a); + test_int(101, ptr2->b); + test_str("String102", ptr2->c); + + test_assert(compare(world, struct_with_strings, ptr1, ptr2) == 0); /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); ecs_add(world, e, MakeMeMove); - { - const StructWithStrings *ptr = - ecs_get_id(world, instance, struct_with_strings); - test_str("String100", ptr->a); - test_int(101, ptr->b); - test_str("String102", ptr->c); - } + const StructWithStrings *ptr3 = + ecs_get_id(world, instance, struct_with_strings); + test_str("String100", ptr3->a); + test_int(101, ptr3->b); + test_str("String102", ptr3->c); + + test_assert(compare(world, struct_with_strings, ptr1, ptr3) == 0); /* Test deleting: */ ecs_delete(world, e); @@ -1498,33 +1491,34 @@ void RuntimeTypes_struct_with_opaque(void) { /* Test constructor: */ ecs_entity_t e = ecs_new(world); - { - StructWithOpaque *ptr = ecs_ensure_id(world, e, struct_with_opaque); - test_assert(ptr->a.id != 0); - test_int(0, ptr->a.value); - ptr->a.value = 100; - } + StructWithOpaque *ptr1 = ecs_ensure_id(world, e, struct_with_opaque); + test_assert(ptr1->a.id != 0); + test_int(0, ptr1->a.value); + ptr1->a.value = 100; + /* 1 resource(s) should have been used */ test_int(1, initial_resources - resources_left()); /* Test copying: */ ecs_entity_t instance = ecs_clone(world, 0, e, true); - { - const StructWithOpaque *ptr = - ecs_get_id(world, instance, struct_with_opaque); - test_int(100, ptr->a.value); - } + const StructWithOpaque *ptr2 = + ecs_get_id(world, instance, struct_with_opaque); + test_int(100, ptr2->a.value); + + test_assert(compare(world, struct_with_opaque, ptr1, ptr2) == 0); + /* 2 resource(s) should be in use now */ test_int(2, initial_resources - resources_left()); /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); ecs_add(world, e, MakeMeMove); - { - const StructWithOpaque *ptr = - ecs_get_id(world, instance, struct_with_opaque); - test_int(100, ptr->a.value); - } + const StructWithOpaque *ptr3 = + ecs_get_id(world, instance, struct_with_opaque); + test_int(100, ptr3->a.value); + + test_assert(compare(world, struct_with_opaque, ptr1, ptr3) == 0); + /* 2 resource(s) should still be in use after a move */ test_int(2, initial_resources - resources_left()); @@ -1580,47 +1574,45 @@ void RuntimeTypes_nested_struct_with_strings(void) { /* Test constructor: */ ecs_entity_t e = ecs_new(world); - { - NestedStructWithStrings *ptr = - ecs_ensure_id(world, e, nested_struct_with_strings); - test_memory_zero(ptr, sizeof(NestedStructWithStrings)); - ptr->a.a = ecs_os_strdup("String100"); - ptr->a.b = 101; - ptr->a.c = ecs_os_strdup("String102"); - ptr->b = 103; - ptr->c.a = ecs_os_strdup("String104"); - ptr->c.b = 105; - ptr->c.c = ecs_os_strdup("String106"); - } + NestedStructWithStrings *ptr1 = + ecs_ensure_id(world, e, nested_struct_with_strings); + test_memory_zero(ptr1, sizeof(NestedStructWithStrings)); + ptr1->a.a = ecs_os_strdup("String100"); + ptr1->a.b = 101; + ptr1->a.c = ecs_os_strdup("String102"); + ptr1->b = 103; + ptr1->c.a = ecs_os_strdup("String104"); + ptr1->c.b = 105; + ptr1->c.c = ecs_os_strdup("String106"); /* Test copying: */ ecs_entity_t instance = ecs_clone(world, 0, e, true); - { - const NestedStructWithStrings *ptr = - ecs_get_id(world, instance, nested_struct_with_strings); - test_str("String100", ptr->a.a); - test_int(101, ptr->a.b); - test_str("String102", ptr->a.c); - test_int(103, ptr->b); - test_str("String104", ptr->c.a); - test_int(105, ptr->c.b); - test_str("String106", ptr->c.c); - } + const NestedStructWithStrings *ptr2 = + ecs_get_id(world, instance, nested_struct_with_strings); + test_str("String100", ptr2->a.a); + test_int(101, ptr2->a.b); + test_str("String102", ptr2->a.c); + test_int(103, ptr2->b); + test_str("String104", ptr2->c.a); + test_int(105, ptr2->c.b); + test_str("String106", ptr2->c.c); + + test_assert(compare(world, nested_struct_with_strings, ptr1, ptr2) == 0); /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); ecs_add(world, e, MakeMeMove); - { - const NestedStructWithStrings *ptr = - ecs_get_id(world, instance, nested_struct_with_strings); - test_str("String100", ptr->a.a); - test_int(101, ptr->a.b); - test_str("String102", ptr->a.c); - test_int(103, ptr->b); - test_str("String104", ptr->c.a); - test_int(105, ptr->c.b); - test_str("String106", ptr->c.c); - } + const NestedStructWithStrings *ptr3 = + ecs_get_id(world, instance, nested_struct_with_strings); + test_str("String100", ptr3->a.a); + test_int(101, ptr3->a.b); + test_str("String102", ptr3->a.c); + test_int(103, ptr3->b); + test_str("String104", ptr3->c.a); + test_int(105, ptr3->c.b); + test_str("String106", ptr3->c.c); + + test_assert(compare(world, nested_struct_with_strings, ptr1, ptr3) == 0); /* Test deleting: */ ecs_delete(world, e); @@ -1649,38 +1641,36 @@ void RuntimeTypes_struct_with_array_of_strings(void) { /* Test constructor: */ ecs_entity_t e = ecs_new(world); - { - StructWithArrayOfStrings *ptr = - ecs_ensure_id(world, e, struct_with_array_of_strings); - test_memory_zero(ptr, sizeof(StructWithArrayOfStrings)); - ptr->a[0] = ecs_os_strdup("String100"); - ptr->a[1] = ecs_os_strdup("String101"); - ptr->a[2] = ecs_os_strdup("String102"); - ptr->b = 103; - } + StructWithArrayOfStrings *ptr1 = + ecs_ensure_id(world, e, struct_with_array_of_strings); + test_memory_zero(ptr1, sizeof(StructWithArrayOfStrings)); + ptr1->a[0] = ecs_os_strdup("String100"); + ptr1->a[1] = ecs_os_strdup("String101"); + ptr1->a[2] = ecs_os_strdup("String102"); + ptr1->b = 103; /* Test copying: */ ecs_entity_t instance = ecs_clone(world, 0, e, true); - { - const StructWithArrayOfStrings *ptr = - ecs_get_id(world, instance, struct_with_array_of_strings); - test_str("String100", ptr->a[0]); - test_str("String101", ptr->a[1]); - test_str("String102", ptr->a[2]); - test_int(103, ptr->b); - } + const StructWithArrayOfStrings *ptr2 = + ecs_get_id(world, instance, struct_with_array_of_strings); + test_str("String100", ptr2->a[0]); + test_str("String101", ptr2->a[1]); + test_str("String102", ptr2->a[2]); + test_int(103, ptr2->b); + + test_assert(compare(world, struct_with_array_of_strings, ptr1, ptr2) == 0); /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); ecs_add(world, e, MakeMeMove); - { - const StructWithArrayOfStrings *ptr = - ecs_get_id(world, instance, struct_with_array_of_strings); - test_str("String100", ptr->a[0]); - test_str("String101", ptr->a[1]); - test_str("String102", ptr->a[2]); - test_int(103, ptr->b); - } + const StructWithArrayOfStrings *ptr3 = + ecs_get_id(world, instance, struct_with_array_of_strings); + test_str("String100", ptr3->a[0]); + test_str("String101", ptr3->a[1]); + test_str("String102", ptr3->a[2]); + test_int(103, ptr3->b); + + test_assert(compare(world, struct_with_array_of_strings, ptr1, ptr3) == 0); /* Test deleting: */ ecs_delete(world, e); @@ -1712,47 +1702,43 @@ void RuntimeTypes_struct_with_array_of_array_of_strings(void) { /* Test constructor: */ ecs_entity_t e = ecs_new(world); - { - StructWithArrayOfArrayOfStrings *ptr = - ecs_ensure_id(world, e, struct_with_array_of_array_of_strings); - test_memory_zero(ptr, sizeof(StructWithArrayOfArrayOfStrings)); - int i; - for (i = 0; i < 3; i++) { - ptr->a[i][0] = ecs_os_strdup("String100"); - ptr->a[i][1] = ecs_os_strdup("String101"); - ptr->a[i][2] = ecs_os_strdup("String102"); - } - ptr->b = ecs_os_strdup("String103"); + StructWithArrayOfArrayOfStrings *ptr1 = + ecs_ensure_id(world, e, struct_with_array_of_array_of_strings); + test_memory_zero(ptr1, sizeof(StructWithArrayOfArrayOfStrings)); + int i; + for (i = 0; i < 3; i++) { + ptr1->a[i][0] = ecs_os_strdup("String100"); + ptr1->a[i][1] = ecs_os_strdup("String101"); + ptr1->a[i][2] = ecs_os_strdup("String102"); } + ptr1->b = ecs_os_strdup("String103"); /* Test copying: */ ecs_entity_t instance = ecs_clone(world, 0, e, true); - { - const StructWithArrayOfArrayOfStrings *ptr = - ecs_get_id(world, instance, struct_with_array_of_array_of_strings); - int i; - for (i = 0; i < 3; i++) { - test_str("String100", ptr->a[i][0]); - test_str("String101", ptr->a[i][1]); - test_str("String102", ptr->a[i][2]); - } - test_str("String103", ptr->b); + const StructWithArrayOfArrayOfStrings *ptr2 = + ecs_get_id(world, instance, struct_with_array_of_array_of_strings); + for (i = 0; i < 3; i++) { + test_str("String100", ptr2->a[i][0]); + test_str("String101", ptr2->a[i][1]); + test_str("String102", ptr2->a[i][2]); } + test_str("String103", ptr2->b); + + test_assert(compare(world, struct_with_array_of_array_of_strings, ptr1, ptr2) == 0); /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); ecs_add(world, e, MakeMeMove); - { - const StructWithArrayOfArrayOfStrings *ptr = - ecs_get_id(world, instance, struct_with_array_of_array_of_strings); - int i; - for (i = 0; i < 3; i++) { - test_str("String100", ptr->a[i][0]); - test_str("String101", ptr->a[i][1]); - test_str("String102", ptr->a[i][2]); - } - test_str("String103", ptr->b); + const StructWithArrayOfArrayOfStrings *ptr3 = + ecs_get_id(world, instance, struct_with_array_of_array_of_strings); + for (i = 0; i < 3; i++) { + test_str("String100", ptr3->a[i][0]); + test_str("String101", ptr3->a[i][1]); + test_str("String102", ptr3->a[i][2]); } + test_str("String103", ptr3->b); + + test_assert(compare(world, struct_with_array_of_array_of_strings, ptr1, ptr3) == 0); /* Test deleting: */ ecs_delete(world, e); @@ -1779,51 +1765,40 @@ void RuntimeTypes_struct_with_vector_of_ints(void) { /* Test constructor: */ ecs_entity_t e = ecs_new(world); - { - StructWithVectorOfInts *ptr = - ecs_ensure_id(world, e, struct_with_vector_of_ints); - { - test_int(0, ecs_vec_count(&ptr->a)); - ecs_vec_set_count(NULL, &ptr->a, sizeof(ecs_i32_t), 3); - ecs_i32_t *va = ecs_vec_first(&ptr->a); - invoke_type_ctor(world, va, 3, ecs_id(ecs_i32_t)); - test_memory_zero(va, sizeof(ecs_i32_t) * 3); - va[0] = 100; - va[1] = 101; - va[2] = 102; - } - } + StructWithVectorOfInts *ptr1 = ecs_ensure_id(world, e, struct_with_vector_of_ints); + test_int(0, ecs_vec_count(&ptr1->a)); + ecs_vec_set_count(NULL, &ptr1->a, sizeof(ecs_i32_t), 3); + ecs_i32_t *va1 = ecs_vec_first(&ptr1->a); + invoke_type_ctor(world, va1, 3, ecs_id(ecs_i32_t)); + test_memory_zero(va1, sizeof(ecs_i32_t) * 3); + va1[0] = 100; + va1[1] = 101; + va1[2] = 102; /* Test copying: */ ecs_entity_t instance = ecs_clone(world, 0, e, true); - { - const StructWithVectorOfInts *ptr = - ecs_get_id(world, instance, struct_with_vector_of_ints); - { - test_int(3, ecs_vec_count(&ptr->a)); - const ecs_i32_t *va = ecs_vec_first(&ptr->a); - test_assert(va != NULL); - test_int(100, va[0]); - test_int(101, va[1]); - test_int(102, va[2]); - } - } + const StructWithVectorOfInts *ptr2 = ecs_get_id(world, instance, struct_with_vector_of_ints); + test_int(3, ecs_vec_count(&ptr2->a)); + const ecs_i32_t *va2 = ecs_vec_first(&ptr2->a); + test_assert(va2 != NULL); + test_int(100, va2[0]); + test_int(101, va2[1]); + test_int(102, va2[2]); + + test_assert(compare(world, struct_with_vector_of_ints, ptr1, ptr2) == 0); /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); ecs_add(world, e, MakeMeMove); - { - const StructWithVectorOfInts *ptr = - ecs_get_id(world, instance, struct_with_vector_of_ints); - { - test_int(3, ecs_vec_count(&ptr->a)); - const ecs_i32_t *va = ecs_vec_first(&ptr->a); - test_assert(va != NULL); - test_int(100, va[0]); - test_int(101, va[1]); - test_int(102, va[2]); - } - } + const StructWithVectorOfInts *ptr3 = ecs_get_id(world, instance, struct_with_vector_of_ints); + test_int(3, ecs_vec_count(&ptr3->a)); + const ecs_i32_t *va3 = ecs_vec_first(&ptr3->a); + test_assert(va3 != NULL); + test_int(100, va3[0]); + test_int(101, va3[1]); + test_int(102, va3[2]); + + test_assert(compare(world, struct_with_vector_of_ints, ptr1, ptr3) == 0); /* Test deleting: */ ecs_delete(world, e); @@ -1850,51 +1825,43 @@ void RuntimeTypes_struct_with_vector_of_strings(void) { /* Test constructor: */ ecs_entity_t e = ecs_new(world); - { - StructWithVectorOfStrings *ptr = - ecs_ensure_id(world, e, struct_with_vector_of_strings); - { - test_int(0, ecs_vec_count(&ptr->a)); - ecs_vec_set_count(NULL, &ptr->a, sizeof(ecs_string_t), 3); - ecs_string_t *va = ecs_vec_first(&ptr->a); - invoke_type_ctor(world, va, 3, ecs_id(ecs_string_t)); - test_memory_zero(va, sizeof(ecs_string_t) * 3); - va[0] = ecs_os_strdup("String100"); - va[1] = ecs_os_strdup("String101"); - va[2] = ecs_os_strdup("String102"); - } - } + StructWithVectorOfStrings *ptr1 = + ecs_ensure_id(world, e, struct_with_vector_of_strings); + test_int(0, ecs_vec_count(&ptr1->a)); + ecs_vec_set_count(NULL, &ptr1->a, sizeof(ecs_string_t), 3); + ecs_string_t *va1 = ecs_vec_first(&ptr1->a); + invoke_type_ctor(world, va1, 3, ecs_id(ecs_string_t)); + test_memory_zero(va1, sizeof(ecs_string_t) * 3); + va1[0] = ecs_os_strdup("String100"); + va1[1] = ecs_os_strdup("String101"); + va1[2] = ecs_os_strdup("String102"); /* Test copying: */ ecs_entity_t instance = ecs_clone(world, 0, e, true); - { - const StructWithVectorOfStrings *ptr = - ecs_get_id(world, instance, struct_with_vector_of_strings); - { - test_int(3, ecs_vec_count(&ptr->a)); - const ecs_string_t *va = ecs_vec_first(&ptr->a); - test_assert(va != NULL); - test_str("String100", va[0]); - test_str("String101", va[1]); - test_str("String102", va[2]); - } - } + const StructWithVectorOfStrings *ptr2 = + ecs_get_id(world, instance, struct_with_vector_of_strings); + test_int(3, ecs_vec_count(&ptr2->a)); + const ecs_string_t *va2 = ecs_vec_first(&ptr2->a); + test_assert(va2 != NULL); + test_str("String100", va2[0]); + test_str("String101", va2[1]); + test_str("String102", va2[2]); + + test_assert(compare(world, struct_with_vector_of_strings, ptr1, ptr2) == 0); /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); ecs_add(world, e, MakeMeMove); - { - const StructWithVectorOfStrings *ptr = - ecs_get_id(world, instance, struct_with_vector_of_strings); - { - test_int(3, ecs_vec_count(&ptr->a)); - const ecs_string_t *va = ecs_vec_first(&ptr->a); - test_assert(va != NULL); - test_str("String100", va[0]); - test_str("String101", va[1]); - test_str("String102", va[2]); - } - } + const StructWithVectorOfStrings *ptr3 = + ecs_get_id(world, instance, struct_with_vector_of_strings); + test_int(3, ecs_vec_count(&ptr3->a)); + const ecs_string_t *va3 = ecs_vec_first(&ptr3->a); + test_assert(va3 != NULL); + test_str("String100", va3[0]); + test_str("String101", va3[1]); + test_str("String102", va3[2]); + + test_assert(compare(world, struct_with_vector_of_strings, ptr1, ptr3) == 0); /* Test deleting: */ ecs_delete(world, e); @@ -1939,111 +1906,109 @@ void RuntimeTypes_nested_struct_with_vector_of_ints(void) { /* Test constructor: */ ecs_entity_t e = ecs_new(world); - { - NestedStructWithVectorOfInts *ptr = - ecs_ensure_id(world, e, nested_struct_with_vector_of_ints); - { - test_int(0, ecs_vec_count(&ptr->a)); - ecs_vec_set_count(NULL, &ptr->a, sizeof(ecs_i32_t), 3); - ecs_i32_t *va = ecs_vec_first(&ptr->a); - invoke_type_ctor(world, va, 3, ecs_id(ecs_i32_t)); - test_memory_zero(va, sizeof(ecs_i32_t) * 3); - va[0] = 100; - va[1] = 101; - va[2] = 102; - } - test_int(0, ptr->b); - ptr->b = 103; - { - test_int(0, ecs_vec_count(&ptr->c.a)); - ecs_vec_set_count(NULL, &ptr->c.a, sizeof(ecs_i32_t), 3); - ecs_i32_t *vca = ecs_vec_first(&ptr->c.a); - invoke_type_ctor(world, vca, 3, ecs_id(ecs_i32_t)); - test_memory_zero(vca, sizeof(ecs_i32_t) * 3); - vca[0] = 104; - vca[1] = 105; - vca[2] = 106; - } - test_int(0, ptr->c.b); - ptr->c.b = 107; - { - test_int(0, ecs_vec_count(&ptr->c.c)); - ecs_vec_set_count(NULL, &ptr->c.c, sizeof(ecs_i32_t), 3); - ecs_i32_t *vcc = ecs_vec_first(&ptr->c.c); - invoke_type_ctor(world, vcc, 3, ecs_id(ecs_i32_t)); - test_memory_zero(vcc, sizeof(ecs_i32_t) * 3); - vcc[0] = 108; - vcc[1] = 109; - vcc[2] = 110; - } + NestedStructWithVectorOfInts *ptr1 = + ecs_ensure_id(world, e, nested_struct_with_vector_of_ints); + { + test_int(0, ecs_vec_count(&ptr1->a)); + ecs_vec_set_count(NULL, &ptr1->a, sizeof(ecs_i32_t), 3); + ecs_i32_t *va = ecs_vec_first(&ptr1->a); + invoke_type_ctor(world, va, 3, ecs_id(ecs_i32_t)); + test_memory_zero(va, sizeof(ecs_i32_t) * 3); + va[0] = 100; + va[1] = 101; + va[2] = 102; + } + test_int(0, ptr1->b); + ptr1->b = 103; + { + test_int(0, ecs_vec_count(&ptr1->c.a)); + ecs_vec_set_count(NULL, &ptr1->c.a, sizeof(ecs_i32_t), 3); + ecs_i32_t *vca = ecs_vec_first(&ptr1->c.a); + invoke_type_ctor(world, vca, 3, ecs_id(ecs_i32_t)); + test_memory_zero(vca, sizeof(ecs_i32_t) * 3); + vca[0] = 104; + vca[1] = 105; + vca[2] = 106; + } + test_int(0, ptr1->c.b); + ptr1->c.b = 107; + { + test_int(0, ecs_vec_count(&ptr1->c.c)); + ecs_vec_set_count(NULL, &ptr1->c.c, sizeof(ecs_i32_t), 3); + ecs_i32_t *vcc = ecs_vec_first(&ptr1->c.c); + invoke_type_ctor(world, vcc, 3, ecs_id(ecs_i32_t)); + test_memory_zero(vcc, sizeof(ecs_i32_t) * 3); + vcc[0] = 108; + vcc[1] = 109; + vcc[2] = 110; } /* Test copying: */ ecs_entity_t instance = ecs_clone(world, 0, e, true); + const NestedStructWithVectorOfInts *ptr2 = + ecs_get_id(world, instance, nested_struct_with_vector_of_ints); { - const NestedStructWithVectorOfInts *ptr = - ecs_get_id(world, instance, nested_struct_with_vector_of_ints); - { - test_int(3, ecs_vec_count(&ptr->a)); - const ecs_i32_t *va = ecs_vec_first(&ptr->a); - test_assert(va != NULL); - test_int(100, va[0]); - test_int(101, va[1]); - test_int(102, va[2]); - } - test_int(103, ptr->b); - { - test_int(3, ecs_vec_count(&ptr->c.a)); - const ecs_i32_t *vca = ecs_vec_first(&ptr->c.a); - test_assert(vca != NULL); - test_int(104, vca[0]); - test_int(105, vca[1]); - test_int(106, vca[2]); - } - test_int(107, ptr->c.b); - { - test_int(3, ecs_vec_count(&ptr->c.c)); - const ecs_i32_t *vcc = ecs_vec_first(&ptr->c.c); - test_assert(vcc != NULL); - test_int(108, vcc[0]); - test_int(109, vcc[1]); - test_int(110, vcc[2]); - } + test_int(3, ecs_vec_count(&ptr2->a)); + const ecs_i32_t *va = ecs_vec_first(&ptr2->a); + test_assert(va != NULL); + test_int(100, va[0]); + test_int(101, va[1]); + test_int(102, va[2]); + } + test_int(103, ptr2->b); + { + test_int(3, ecs_vec_count(&ptr2->c.a)); + const ecs_i32_t *vca = ecs_vec_first(&ptr2->c.a); + test_assert(vca != NULL); + test_int(104, vca[0]); + test_int(105, vca[1]); + test_int(106, vca[2]); + } + test_int(107, ptr2->c.b); + { + test_int(3, ecs_vec_count(&ptr2->c.c)); + const ecs_i32_t *vcc = ecs_vec_first(&ptr2->c.c); + test_assert(vcc != NULL); + test_int(108, vcc[0]); + test_int(109, vcc[1]); + test_int(110, vcc[2]); } + test_assert(compare(world, nested_struct_with_vector_of_ints, ptr1, ptr2) == 0); + /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); ecs_add(world, e, MakeMeMove); + const NestedStructWithVectorOfInts *ptr3 = + ecs_get_id(world, instance, nested_struct_with_vector_of_ints); { - const NestedStructWithVectorOfInts *ptr = - ecs_get_id(world, instance, nested_struct_with_vector_of_ints); - { - test_int(3, ecs_vec_count(&ptr->a)); - const ecs_i32_t *va = ecs_vec_first(&ptr->a); - test_assert(va != NULL); - test_int(100, va[0]); - test_int(101, va[1]); - test_int(102, va[2]); - } - test_int(103, ptr->b); - { - test_int(3, ecs_vec_count(&ptr->c.a)); - const ecs_i32_t *vca = ecs_vec_first(&ptr->c.a); - test_assert(vca != NULL); - test_int(104, vca[0]); - test_int(105, vca[1]); - test_int(106, vca[2]); - } - test_int(107, ptr->c.b); - { - test_int(3, ecs_vec_count(&ptr->c.c)); - const ecs_i32_t *vcc = ecs_vec_first(&ptr->c.c); - test_assert(vcc != NULL); - test_int(108, vcc[0]); - test_int(109, vcc[1]); - test_int(110, vcc[2]); - } + test_int(3, ecs_vec_count(&ptr3->a)); + const ecs_i32_t *va = ecs_vec_first(&ptr3->a); + test_assert(va != NULL); + test_int(100, va[0]); + test_int(101, va[1]); + test_int(102, va[2]); } + test_int(103, ptr3->b); + { + test_int(3, ecs_vec_count(&ptr3->c.a)); + const ecs_i32_t *vca = ecs_vec_first(&ptr3->c.a); + test_assert(vca != NULL); + test_int(104, vca[0]); + test_int(105, vca[1]); + test_int(106, vca[2]); + } + test_int(107, ptr3->c.b); + { + test_int(3, ecs_vec_count(&ptr3->c.c)); + const ecs_i32_t *vcc = ecs_vec_first(&ptr3->c.c); + test_assert(vcc != NULL); + test_int(108, vcc[0]); + test_int(109, vcc[1]); + test_int(110, vcc[2]); + } + + test_assert(compare(world, nested_struct_with_vector_of_ints, ptr1, ptr3) == 0); /* Test deleting: */ ecs_delete(world, e); @@ -2088,112 +2053,110 @@ void RuntimeTypes_nested_struct_with_vector_of_strings(void) { /* Test constructor: */ ecs_entity_t e = ecs_new(world); - { - NestedStructWithVectorOfStrings *ptr = - ecs_ensure_id(world, e, nested_struct_with_vector_of_strings); - { - test_int(0, ecs_vec_count(&ptr->a)); - ecs_vec_set_count(NULL, &ptr->a, sizeof(ecs_string_t), 3); - ecs_string_t *va = ecs_vec_first(&ptr->a); - invoke_type_ctor(world, va, 3, ecs_id(ecs_string_t)); - test_memory_zero(va, sizeof(ecs_string_t) * 3); - va[0] = ecs_os_strdup("String100"); - va[1] = ecs_os_strdup("String101"); - va[2] = ecs_os_strdup("String102"); - } - test_int(0, ptr->b); - ptr->b = 103; - { - test_int(0, ecs_vec_count(&ptr->c.a)); - ecs_vec_set_count(NULL, &ptr->c.a, sizeof(ecs_string_t), 3); - ecs_string_t *vca = ecs_vec_first(&ptr->c.a); - invoke_type_ctor(world, vca, 3, ecs_id(ecs_string_t)); - test_memory_zero(vca, sizeof(ecs_string_t) * 3); - vca[0] = ecs_os_strdup("String104"); - vca[1] = ecs_os_strdup("String105"); - vca[2] = ecs_os_strdup("String106"); - } - test_int(0, ptr->c.b); - ptr->c.b = 107; - { - test_int(0, ecs_vec_count(&ptr->c.c)); - ecs_vec_set_count(NULL, &ptr->c.c, sizeof(ecs_string_t), 3); - ecs_string_t *vcc = ecs_vec_first(&ptr->c.c); - invoke_type_ctor(world, vcc, 3, ecs_id(ecs_string_t)); - test_memory_zero(vcc, sizeof(ecs_string_t) * 3); - vcc[0] = ecs_os_strdup("String108"); - vcc[1] = ecs_os_strdup("String109"); - vcc[2] = ecs_os_strdup("String110"); - } + NestedStructWithVectorOfStrings *ptr1 = + ecs_ensure_id(world, e, nested_struct_with_vector_of_strings); + { + test_int(0, ecs_vec_count(&ptr1->a)); + ecs_vec_set_count(NULL, &ptr1->a, sizeof(ecs_string_t), 3); + ecs_string_t *va = ecs_vec_first(&ptr1->a); + invoke_type_ctor(world, va, 3, ecs_id(ecs_string_t)); + test_memory_zero(va, sizeof(ecs_string_t) * 3); + va[0] = ecs_os_strdup("String100"); + va[1] = ecs_os_strdup("String101"); + va[2] = ecs_os_strdup("String102"); + } + test_int(0, ptr1->b); + ptr1->b = 103; + { + test_int(0, ecs_vec_count(&ptr1->c.a)); + ecs_vec_set_count(NULL, &ptr1->c.a, sizeof(ecs_string_t), 3); + ecs_string_t *vca = ecs_vec_first(&ptr1->c.a); + invoke_type_ctor(world, vca, 3, ecs_id(ecs_string_t)); + test_memory_zero(vca, sizeof(ecs_string_t) * 3); + vca[0] = ecs_os_strdup("String104"); + vca[1] = ecs_os_strdup("String105"); + vca[2] = ecs_os_strdup("String106"); + } + test_int(0, ptr1->c.b); + ptr1->c.b = 107; + { + test_int(0, ecs_vec_count(&ptr1->c.c)); + ecs_vec_set_count(NULL, &ptr1->c.c, sizeof(ecs_string_t), 3); + ecs_string_t *vcc = ecs_vec_first(&ptr1->c.c); + invoke_type_ctor(world, vcc, 3, ecs_id(ecs_string_t)); + test_memory_zero(vcc, sizeof(ecs_string_t) * 3); + vcc[0] = ecs_os_strdup("String108"); + vcc[1] = ecs_os_strdup("String109"); + vcc[2] = ecs_os_strdup("String110"); } /* Test copying: */ ecs_entity_t instance = ecs_clone(world, 0, e, true); + const NestedStructWithVectorOfStrings *ptr2 = + ecs_get_id(world, instance, nested_struct_with_vector_of_strings); { - const NestedStructWithVectorOfStrings *ptr = - ecs_get_id(world, instance, nested_struct_with_vector_of_strings); - { - test_int(3, ecs_vec_count(&ptr->a)); - const ecs_string_t *va = ecs_vec_first(&ptr->a); - test_assert(va != NULL); - test_str("String100", va[0]); - test_str("String101", va[1]); - test_str("String102", va[2]); - } - test_int(103, ptr->b); - { - test_int(3, ecs_vec_count(&ptr->c.a)); - const ecs_string_t *vca = ecs_vec_first(&ptr->c.a); - test_assert(vca != NULL); - test_str("String104", vca[0]); - test_str("String105", vca[1]); - test_str("String106", vca[2]); - } - test_int(107, ptr->c.b); - { - test_int(3, ecs_vec_count(&ptr->c.c)); - const ecs_string_t *vcc = ecs_vec_first(&ptr->c.c); - test_assert(vcc != NULL); - test_str("String108", vcc[0]); - test_str("String109", vcc[1]); - test_str("String110", vcc[2]); - } + test_int(3, ecs_vec_count(&ptr2->a)); + const ecs_string_t *va = ecs_vec_first(&ptr2->a); + test_assert(va != NULL); + test_str("String100", va[0]); + test_str("String101", va[1]); + test_str("String102", va[2]); } + test_int(103, ptr2->b); + { + test_int(3, ecs_vec_count(&ptr2->c.a)); + const ecs_string_t *vca = ecs_vec_first(&ptr2->c.a); + test_assert(vca != NULL); + test_str("String104", vca[0]); + test_str("String105", vca[1]); + test_str("String106", vca[2]); + } + test_int(107, ptr2->c.b); + { + test_int(3, ecs_vec_count(&ptr2->c.c)); + const ecs_string_t *vcc = ecs_vec_first(&ptr2->c.c); + test_assert(vcc != NULL); + test_str("String108", vcc[0]); + test_str("String109", vcc[1]); + test_str("String110", vcc[2]); + } + + test_assert(compare(world, nested_struct_with_vector_of_strings, ptr1, ptr2) == 0); /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); ecs_add(world, e, MakeMeMove); + const NestedStructWithVectorOfStrings *ptr3 = + ecs_get_id(world, instance, nested_struct_with_vector_of_strings); { - const NestedStructWithVectorOfStrings *ptr = - ecs_get_id(world, instance, nested_struct_with_vector_of_strings); - { - test_int(3, ecs_vec_count(&ptr->a)); - const ecs_string_t *va = ecs_vec_first(&ptr->a); - test_assert(va != NULL); - test_str("String100", va[0]); - test_str("String101", va[1]); - test_str("String102", va[2]); - } - test_int(103, ptr->b); - { - test_int(3, ecs_vec_count(&ptr->c.a)); - const ecs_string_t *vca = ecs_vec_first(&ptr->c.a); - test_assert(vca != NULL); - test_str("String104", vca[0]); - test_str("String105", vca[1]); - test_str("String106", vca[2]); - } - test_int(107, ptr->c.b); - { - test_int(3, ecs_vec_count(&ptr->c.c)); - const ecs_string_t *vcc = ecs_vec_first(&ptr->c.c); - test_assert(vcc != NULL); - test_str("String108", vcc[0]); - test_str("String109", vcc[1]); - test_str("String110", vcc[2]); - } + test_int(3, ecs_vec_count(&ptr3->a)); + const ecs_string_t *va = ecs_vec_first(&ptr3->a); + test_assert(va != NULL); + test_str("String100", va[0]); + test_str("String101", va[1]); + test_str("String102", va[2]); + } + test_int(103, ptr3->b); + { + test_int(3, ecs_vec_count(&ptr3->c.a)); + const ecs_string_t *vca = ecs_vec_first(&ptr3->c.a); + test_assert(vca != NULL); + test_str("String104", vca[0]); + test_str("String105", vca[1]); + test_str("String106", vca[2]); + } + test_int(107, ptr3->c.b); + { + test_int(3, ecs_vec_count(&ptr3->c.c)); + const ecs_string_t *vcc = ecs_vec_first(&ptr3->c.c); + test_assert(vcc != NULL); + test_str("String108", vcc[0]); + test_str("String109", vcc[1]); + test_str("String110", vcc[2]); } + test_assert(compare(world, nested_struct_with_vector_of_strings, ptr1, ptr3) == 0); + /* Test deleting: */ ecs_delete(world, e); ecs_delete(world, instance); @@ -2209,32 +2172,30 @@ void RuntimeTypes_array_of_ints(void) { /* Test constructor: */ ecs_entity_t e = ecs_new(world); - { - ecs_i32_t *arr = ecs_ensure_id(world, e, array_of_ints); - test_memory_zero(arr, sizeof(ecs_i32_t[3])); - arr[0] = 100; - arr[1] = 101; - arr[2] = 102; - } + ecs_i32_t *arr1 = ecs_ensure_id(world, e, array_of_ints); + test_memory_zero(arr1, sizeof(ecs_i32_t[3])); + arr1[0] = 100; + arr1[1] = 101; + arr1[2] = 102; /* Test copying: */ ecs_entity_t instance = ecs_clone(world, 0, e, true); - { - const ecs_i32_t *arr = ecs_get_id(world, e, array_of_ints); - test_int(100, arr[0]); - test_int(101, arr[1]); - test_int(102, arr[2]); - } + const ecs_i32_t *arr2 = ecs_get_id(world, e, array_of_ints); + test_int(100, arr2[0]); + test_int(101, arr2[1]); + test_int(102, arr2[2]); + + test_assert(compare(world, array_of_ints, arr1, arr2) == 0); /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); ecs_add(world, e, MakeMeMove); - { - const ecs_i32_t *arr = ecs_get_id(world, e, array_of_ints); - test_int(100, arr[0]); - test_int(101, arr[1]); - test_int(102, arr[2]); - } + const ecs_i32_t *arr3 = ecs_get_id(world, e, array_of_ints); + test_int(100, arr3[0]); + test_int(101, arr3[1]); + test_int(102, arr3[2]); + + test_assert(compare(world, array_of_ints, arr1, arr3) == 0); /* Test deleting: */ ecs_delete(world, e); @@ -2251,32 +2212,30 @@ void RuntimeTypes_array_of_strings(void) { /* Test constructor: */ ecs_entity_t e = ecs_new(world); - { - ecs_string_t *arr = ecs_ensure_id(world, e, array_of_strings); - test_memory_zero(arr, sizeof(ecs_string_t[3])); - arr[0] = ecs_os_strdup("String100"); - arr[1] = ecs_os_strdup("String101"); - arr[2] = ecs_os_strdup("String102"); - } + ecs_string_t *arr1 = ecs_ensure_id(world, e, array_of_strings); + test_memory_zero(arr1, sizeof(ecs_string_t[3])); + arr1[0] = ecs_os_strdup("String100"); + arr1[1] = ecs_os_strdup("String101"); + arr1[2] = ecs_os_strdup("String102"); /* Test copying: */ ecs_entity_t instance = ecs_clone(world, 0, e, true); - { - const ecs_string_t *arr = ecs_get_id(world, e, array_of_strings); - test_str("String100", arr[0]); - test_str("String101", arr[1]); - test_str("String102", arr[2]); - } + const ecs_string_t *arr2 = ecs_get_id(world, e, array_of_strings); + test_str("String100", arr2[0]); + test_str("String101", arr2[1]); + test_str("String102", arr2[2]); + + test_assert(compare(world, array_of_strings, arr1, arr2) == 0); /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); ecs_add(world, e, MakeMeMove); - { - const ecs_string_t *arr = ecs_get_id(world, e, array_of_strings); - test_str("String100", arr[0]); - test_str("String101", arr[1]); - test_str("String102", arr[2]); - } + const ecs_string_t *arr3 = ecs_get_id(world, e, array_of_strings); + test_str("String100", arr3[0]); + test_str("String101", arr3[1]); + test_str("String102", arr3[2]); + + test_assert(compare(world, array_of_strings, arr1, arr3) == 0); /* Test deleting: */ ecs_delete(world, e); @@ -2305,44 +2264,42 @@ void RuntimeTypes_array_of_struct_with_ints(void) { /* Test constructor: */ ecs_entity_t e = ecs_new(world); - { - StructWithInts *arr = - ecs_ensure_id(world, e, array_of_struct_with_ints); - test_memory_zero(arr, sizeof(StructWithInts[3])); - arr[0].a = 100; - arr[0].b = 101; - arr[1].a = 102; - arr[1].b = 103; - arr[2].a = 104; - arr[2].b = 105; - } + StructWithInts *arr1 = + ecs_ensure_id(world, e, array_of_struct_with_ints); + test_memory_zero(arr1, sizeof(StructWithInts[3])); + arr1[0].a = 100; + arr1[0].b = 101; + arr1[1].a = 102; + arr1[1].b = 103; + arr1[2].a = 104; + arr1[2].b = 105; /* Test copying: */ ecs_entity_t instance = ecs_clone(world, 0, e, true); - { - const StructWithInts *arr = - ecs_get_id(world, e, array_of_struct_with_ints); - test_int(100, arr[0].a); - test_int(101, arr[0].b); - test_int(102, arr[1].a); - test_int(103, arr[1].b); - test_int(104, arr[2].a); - test_int(105, arr[2].b); - } + const StructWithInts *arr2 = + ecs_get_id(world, e, array_of_struct_with_ints); + test_int(100, arr2[0].a); + test_int(101, arr2[0].b); + test_int(102, arr2[1].a); + test_int(103, arr2[1].b); + test_int(104, arr2[2].a); + test_int(105, arr2[2].b); + + test_assert(compare(world, array_of_struct_with_ints, arr1, arr2) == 0); /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); ecs_add(world, e, MakeMeMove); - { - const StructWithInts *arr = - ecs_get_id(world, e, array_of_struct_with_ints); - test_int(100, arr[0].a); - test_int(101, arr[0].b); - test_int(102, arr[1].a); - test_int(103, arr[1].b); - test_int(104, arr[2].a); - test_int(105, arr[2].b); - } + const StructWithInts *arr3 = + ecs_get_id(world, e, array_of_struct_with_ints); + test_int(100, arr3[0].a); + test_int(101, arr3[0].b); + test_int(102, arr3[1].a); + test_int(103, arr3[1].b); + test_int(104, arr3[2].a); + test_int(105, arr3[2].b); + + test_assert(compare(world, array_of_struct_with_ints, arr1, arr3) == 0); /* Test deleting: */ ecs_delete(world, e); @@ -2373,53 +2330,51 @@ void RuntimeTypes_array_of_struct_with_strings(void) { /* Test constructor: */ ecs_entity_t e = ecs_new(world); - { - StructWithStrings *arr = - ecs_ensure_id(world, e, array_of_struct_with_strings); - test_memory_zero(arr, sizeof(StructWithStrings[3])); - arr[0].a = ecs_os_strdup("String100"); - arr[0].b = 101; - arr[0].c = ecs_os_strdup("String102"); - arr[1].a = ecs_os_strdup("String103"); - arr[1].b = 104; - arr[1].c = ecs_os_strdup("String105"); - arr[2].a = ecs_os_strdup("String106"); - arr[2].b = 107; - arr[2].c = ecs_os_strdup("String108"); - } + StructWithStrings *arr1 = + ecs_ensure_id(world, e, array_of_struct_with_strings); + test_memory_zero(arr1, sizeof(StructWithStrings[3])); + arr1[0].a = ecs_os_strdup("String100"); + arr1[0].b = 101; + arr1[0].c = ecs_os_strdup("String102"); + arr1[1].a = ecs_os_strdup("String103"); + arr1[1].b = 104; + arr1[1].c = ecs_os_strdup("String105"); + arr1[2].a = ecs_os_strdup("String106"); + arr1[2].b = 107; + arr1[2].c = ecs_os_strdup("String108"); /* Test copying: */ ecs_entity_t instance = ecs_clone(world, 0, e, true); - { - const StructWithStrings *arr = - ecs_get_id(world, e, array_of_struct_with_strings); - test_str("String100", arr[0].a); - test_int(101, arr[0].b); - test_str("String102", arr[0].c); - test_str("String103", arr[1].a); - test_int(104, arr[1].b); - test_str("String105", arr[1].c); - test_str("String106", arr[2].a); - test_int(107, arr[2].b); - test_str("String108", arr[2].c); - } + const StructWithStrings *arr2 = + ecs_get_id(world, e, array_of_struct_with_strings); + test_str("String100", arr2[0].a); + test_int(101, arr2[0].b); + test_str("String102", arr2[0].c); + test_str("String103", arr2[1].a); + test_int(104, arr2[1].b); + test_str("String105", arr2[1].c); + test_str("String106", arr2[2].a); + test_int(107, arr2[2].b); + test_str("String108", arr2[2].c); + + test_assert(compare(world, array_of_struct_with_strings, arr1, arr2) == 0); /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); ecs_add(world, e, MakeMeMove); - { - const StructWithStrings *arr = - ecs_get_id(world, e, array_of_struct_with_strings); - test_str("String100", arr[0].a); - test_int(101, arr[0].b); - test_str("String102", arr[0].c); - test_str("String103", arr[1].a); - test_int(104, arr[1].b); - test_str("String105", arr[1].c); - test_str("String106", arr[2].a); - test_int(107, arr[2].b); - test_str("String108", arr[2].c); - } + const StructWithStrings *arr3 = + ecs_get_id(world, e, array_of_struct_with_strings); + test_str("String100", arr3[0].a); + test_int(101, arr3[0].b); + test_str("String102", arr3[0].c); + test_str("String103", arr3[1].a); + test_int(104, arr3[1].b); + test_str("String105", arr3[1].c); + test_str("String106", arr3[2].a); + test_int(107, arr3[2].b); + test_str("String108", arr3[2].c); + + test_assert(compare(world, array_of_struct_with_strings, arr1, arr3) == 0); /* Test deleting: */ ecs_delete(world, e); @@ -2452,44 +2407,45 @@ void RuntimeTypes_array_of_struct_with_opaques(void) { /* Test constructor: */ ecs_entity_t e = ecs_new(world); - { - StructWithOpaque *arr = - ecs_ensure_id(world, e, array_of_struct_with_opaques); - test_assert(arr[0].a.id != 0); - test_int(0, arr[0].a.value); - arr[0].a.value = 100; - test_assert(arr[1].a.id != 0); - test_int(0, arr[1].a.value); - arr[1].a.value = 101; - test_assert(arr[2].a.id != 0); - test_int(0, arr[2].a.value); - arr[2].a.value = 102; - } + StructWithOpaque *arr1 = + ecs_ensure_id(world, e, array_of_struct_with_opaques); + test_assert(arr1[0].a.id != 0); + test_int(0, arr1[0].a.value); + arr1[0].a.value = 100; + test_assert(arr1[1].a.id != 0); + test_int(0, arr1[1].a.value); + arr1[1].a.value = 101; + test_assert(arr1[2].a.id != 0); + test_int(0, arr1[2].a.value); + arr1[2].a.value = 102; + /* 3 resource(s) should have been used */ test_int(3, initial_resources - resources_left()); /* Test copying: */ ecs_entity_t instance = ecs_clone(world, 0, e, true); - { - const StructWithOpaque *arr = - ecs_get_id(world, e, array_of_struct_with_opaques); - test_int(100, arr[0].a.value); - test_int(101, arr[1].a.value); - test_int(102, arr[2].a.value); - } + const StructWithOpaque *arr2 = + ecs_get_id(world, e, array_of_struct_with_opaques); + test_int(100, arr2[0].a.value); + test_int(101, arr2[1].a.value); + test_int(102, arr2[2].a.value); + + test_assert(compare(world, array_of_struct_with_opaques, arr1, arr2) == 0); + /* 6 resource(s) should be in use now */ test_int(6, initial_resources - resources_left()); /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); ecs_add(world, e, MakeMeMove); - { - const StructWithOpaque *arr = - ecs_get_id(world, e, array_of_struct_with_opaques); - test_int(100, arr[0].a.value); - test_int(101, arr[1].a.value); - test_int(102, arr[2].a.value); - } + const StructWithOpaque *arr3 = + ecs_get_id(world, e, array_of_struct_with_opaques); + test_int(100, arr3[0].a.value); + test_int(101, arr3[1].a.value); + test_int(102, arr3[2].a.value); + + test_assert(compare(world, array_of_struct_with_opaques, arr1, arr3) == 0); + /* 6 resource(s) should still be in use after a move */ test_int(6, initial_resources - resources_left()); @@ -2524,45 +2480,41 @@ void RuntimeTypes_array_of_array_of_strings(void) { /* Test constructor: */ ecs_entity_t e = ecs_new(world); - { - ecs_string_t(*arr)[3] = - ecs_ensure_id(world, e, array_of_array_of_strings); - test_memory_zero(arr, sizeof(ecs_string_t[3][3])); - int i; - for (i = 0; i < 3; i++) { - arr[i][0] = ecs_os_strdup("String100"); - arr[i][1] = ecs_os_strdup("String101"); - arr[i][2] = ecs_os_strdup("String102"); - } + ecs_string_t(*arr1)[3] = + ecs_ensure_id(world, e, array_of_array_of_strings); + test_memory_zero(arr1, sizeof(ecs_string_t[3][3])); + int i; + for (i = 0; i < 3; i++) { + arr1[i][0] = ecs_os_strdup("String100"); + arr1[i][1] = ecs_os_strdup("String101"); + arr1[i][2] = ecs_os_strdup("String102"); } /* Test copying: */ ecs_entity_t instance = ecs_clone(world, 0, e, true); - { - const ecs_string_t(*arr)[3] = (const ecs_string_t(*)[3]) ecs_get_id( - world, e, array_of_array_of_strings); - int i; - for (i = 0; i < 3; i++) { - test_str("String100", arr[i][0]); - test_str("String101", arr[i][1]); - test_str("String102", arr[i][2]); - } + const ecs_string_t(*arr2)[3] = (const ecs_string_t(*)[3]) ecs_get_id( + world, e, array_of_array_of_strings); + for (i = 0; i < 3; i++) { + test_str("String100", arr2[i][0]); + test_str("String101", arr2[i][1]); + test_str("String102", arr2[i][2]); } + test_assert(compare(world, array_of_array_of_strings, arr1, arr2) == 0); + /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); ecs_add(world, e, MakeMeMove); - { - const ecs_string_t(*arr)[3] = (const ecs_string_t(*)[3]) ecs_get_id( - world, e, array_of_array_of_strings); - int i; - for (i = 0; i < 3; i++) { - test_str("String100", arr[i][0]); - test_str("String101", arr[i][1]); - test_str("String102", arr[i][2]); - } + const ecs_string_t(*arr3)[3] = (const ecs_string_t(*)[3]) ecs_get_id( + world, e, array_of_array_of_strings); + for (i = 0; i < 3; i++) { + test_str("String100", arr3[i][0]); + test_str("String101", arr3[i][1]); + test_str("String102", arr3[i][2]); } + test_assert(compare(world, array_of_array_of_strings, arr1, arr3) == 0); + /* Test deleting: */ ecs_delete(world, e); ecs_delete(world, instance); @@ -2596,64 +2548,60 @@ void RuntimeTypes_array_of_array_of_struct_with_strings(void) { /* Test constructor: */ ecs_entity_t e = ecs_new(world); - { - StructWithStrings(*arr)[3] = - ecs_ensure_id(world, e, array_of_array_of_struct_with_strings); - test_memory_zero(arr, sizeof(StructWithStrings[3][3])); - int i; - for (i = 0; i < 3; i++) { - arr[i][0].a = ecs_os_strdup("String100"); - arr[i][0].b = 101; - arr[i][0].c = ecs_os_strdup("String102"); - arr[i][1].a = ecs_os_strdup("String103"); - arr[i][1].b = 104; - arr[i][1].c = ecs_os_strdup("String105"); - arr[i][2].a = ecs_os_strdup("String106"); - arr[i][2].b = 107; - arr[i][2].c = ecs_os_strdup("String108"); - } + StructWithStrings(*arr1)[3] = + ecs_ensure_id(world, e, array_of_array_of_struct_with_strings); + test_memory_zero(arr1, sizeof(StructWithStrings[3][3])); + int i; + for (i = 0; i < 3; i++) { + arr1[i][0].a = ecs_os_strdup("String100"); + arr1[i][0].b = 101; + arr1[i][0].c = ecs_os_strdup("String102"); + arr1[i][1].a = ecs_os_strdup("String103"); + arr1[i][1].b = 104; + arr1[i][1].c = ecs_os_strdup("String105"); + arr1[i][2].a = ecs_os_strdup("String106"); + arr1[i][2].b = 107; + arr1[i][2].c = ecs_os_strdup("String108"); } /* Test copying: */ ecs_entity_t instance = ecs_clone(world, 0, e, true); - { - const StructWithStrings(*arr)[3] = - (const StructWithStrings(*)[3]) ecs_get_id( - world, e, array_of_array_of_struct_with_strings); - int i; - for (i = 0; i < 3; i++) { - test_str("String100", arr[i][0].a); - test_int(101, arr[i][0].b); - test_str("String102", arr[i][0].c); - test_str("String103", arr[i][1].a); - test_int(104, arr[i][1].b); - test_str("String105", arr[i][1].c); - test_str("String106", arr[i][2].a); - test_int(107, arr[i][2].b); - test_str("String108", arr[i][2].c); - } - } + const StructWithStrings(*arr2)[3] = + (const StructWithStrings(*)[3]) ecs_get_id( + world, e, array_of_array_of_struct_with_strings); + for (i = 0; i < 3; i++) { + test_str("String100", arr2[i][0].a); + test_int(101, arr2[i][0].b); + test_str("String102", arr2[i][0].c); + test_str("String103", arr2[i][1].a); + test_int(104, arr2[i][1].b); + test_str("String105", arr2[i][1].c); + test_str("String106", arr2[i][2].a); + test_int(107, arr2[i][2].b); + test_str("String108", arr2[i][2].c); + } + + test_assert(compare(world, array_of_array_of_struct_with_strings, arr1, arr2) == 0); /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); ecs_add(world, e, MakeMeMove); - { - const StructWithStrings(*arr)[3] = - (const StructWithStrings(*)[3]) ecs_get_id( - world, e, array_of_array_of_struct_with_strings); - int i; - for (i = 0; i < 3; i++) { - test_str("String100", arr[i][0].a); - test_int(101, arr[i][0].b); - test_str("String102", arr[i][0].c); - test_str("String103", arr[i][1].a); - test_int(104, arr[i][1].b); - test_str("String105", arr[i][1].c); - test_str("String106", arr[i][2].a); - test_int(107, arr[i][2].b); - test_str("String108", arr[i][2].c); - } - } + const StructWithStrings(*arr3)[3] = + (const StructWithStrings(*)[3]) ecs_get_id( + world, e, array_of_array_of_struct_with_strings); + for (i = 0; i < 3; i++) { + test_str("String100", arr3[i][0].a); + test_int(101, arr3[i][0].b); + test_str("String102", arr3[i][0].c); + test_str("String103", arr3[i][1].a); + test_int(104, arr3[i][1].b); + test_str("String105", arr3[i][1].c); + test_str("String106", arr3[i][2].a); + test_int(107, arr3[i][2].b); + test_str("String108", arr3[i][2].c); + } + + test_assert(compare(world, array_of_array_of_struct_with_strings, arr1, arr3) == 0); /* Test deleting: */ ecs_delete(world, e); @@ -2673,101 +2621,99 @@ void RuntimeTypes_array_of_vectors_of_ints(void) { /* Test constructor: */ ecs_entity_t e = ecs_new(world); - { - ecs_vec_t *arr = ecs_ensure_id(world, e, array_of_vectors_of_ints); - { - test_int(0, ecs_vec_count(&arr[0])); - ecs_vec_set_count(NULL, &arr[0], sizeof(ecs_i32_t), 3); - ecs_i32_t *v = ecs_vec_first(&arr[0]); - invoke_type_ctor(world, v, 3, ecs_id(ecs_i32_t)); - test_memory_zero(v, sizeof(ecs_i32_t) * 3); - v[0] = 100; - v[1] = 101; - v[2] = 102; - } - { - test_int(0, ecs_vec_count(&arr[1])); - ecs_vec_set_count(NULL, &arr[1], sizeof(ecs_i32_t), 3); - ecs_i32_t *v = ecs_vec_first(&arr[1]); - invoke_type_ctor(world, v, 3, ecs_id(ecs_i32_t)); - test_memory_zero(v, sizeof(ecs_i32_t) * 3); - v[0] = 103; - v[1] = 104; - v[2] = 105; - } - { - test_int(0, ecs_vec_count(&arr[2])); - ecs_vec_set_count(NULL, &arr[2], sizeof(ecs_i32_t), 3); - ecs_i32_t *v = ecs_vec_first(&arr[2]); - invoke_type_ctor(world, v, 3, ecs_id(ecs_i32_t)); - test_memory_zero(v, sizeof(ecs_i32_t) * 3); - v[0] = 106; - v[1] = 107; - v[2] = 108; - } + ecs_vec_t *arr1 = ecs_ensure_id(world, e, array_of_vectors_of_ints); + { + test_int(0, ecs_vec_count(&arr1[0])); + ecs_vec_set_count(NULL, &arr1[0], sizeof(ecs_i32_t), 3); + ecs_i32_t *v = ecs_vec_first(&arr1[0]); + invoke_type_ctor(world, v, 3, ecs_id(ecs_i32_t)); + test_memory_zero(v, sizeof(ecs_i32_t) * 3); + v[0] = 100; + v[1] = 101; + v[2] = 102; + } + { + test_int(0, ecs_vec_count(&arr1[1])); + ecs_vec_set_count(NULL, &arr1[1], sizeof(ecs_i32_t), 3); + ecs_i32_t *v = ecs_vec_first(&arr1[1]); + invoke_type_ctor(world, v, 3, ecs_id(ecs_i32_t)); + test_memory_zero(v, sizeof(ecs_i32_t) * 3); + v[0] = 103; + v[1] = 104; + v[2] = 105; + } + { + test_int(0, ecs_vec_count(&arr1[2])); + ecs_vec_set_count(NULL, &arr1[2], sizeof(ecs_i32_t), 3); + ecs_i32_t *v = ecs_vec_first(&arr1[2]); + invoke_type_ctor(world, v, 3, ecs_id(ecs_i32_t)); + test_memory_zero(v, sizeof(ecs_i32_t) * 3); + v[0] = 106; + v[1] = 107; + v[2] = 108; } /* Test copying: */ ecs_entity_t instance = ecs_clone(world, 0, e, true); + const ecs_vec_t *arr2 = ecs_get_id(world, e, array_of_vectors_of_ints); { - const ecs_vec_t *arr = ecs_get_id(world, e, array_of_vectors_of_ints); - { - test_int(3, ecs_vec_count(&arr[0])); - const ecs_i32_t *v = ecs_vec_first(&arr[0]); - test_assert(v != NULL); - test_int(100, v[0]); - test_int(101, v[1]); - test_int(102, v[2]); - } - { - test_int(3, ecs_vec_count(&arr[1])); - const ecs_i32_t *v = ecs_vec_first(&arr[1]); - test_assert(v != NULL); - test_int(103, v[0]); - test_int(104, v[1]); - test_int(105, v[2]); - } - { - test_int(3, ecs_vec_count(&arr[2])); - const ecs_i32_t *v = ecs_vec_first(&arr[2]); - test_assert(v != NULL); - test_int(106, v[0]); - test_int(107, v[1]); - test_int(108, v[2]); - } + test_int(3, ecs_vec_count(&arr2[0])); + const ecs_i32_t *v = ecs_vec_first(&arr2[0]); + test_assert(v != NULL); + test_int(100, v[0]); + test_int(101, v[1]); + test_int(102, v[2]); + } + { + test_int(3, ecs_vec_count(&arr2[1])); + const ecs_i32_t *v = ecs_vec_first(&arr2[1]); + test_assert(v != NULL); + test_int(103, v[0]); + test_int(104, v[1]); + test_int(105, v[2]); + } + { + test_int(3, ecs_vec_count(&arr2[2])); + const ecs_i32_t *v = ecs_vec_first(&arr2[2]); + test_assert(v != NULL); + test_int(106, v[0]); + test_int(107, v[1]); + test_int(108, v[2]); } + test_assert(compare(world, array_of_vectors_of_ints, arr1, arr2) == 0); + /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); ecs_add(world, e, MakeMeMove); + const ecs_vec_t *arr3 = ecs_get_id(world, e, array_of_vectors_of_ints); { - const ecs_vec_t *arr = ecs_get_id(world, e, array_of_vectors_of_ints); - { - test_int(3, ecs_vec_count(&arr[0])); - const ecs_i32_t *v = ecs_vec_first(&arr[0]); - test_assert(v != NULL); - test_int(100, v[0]); - test_int(101, v[1]); - test_int(102, v[2]); - } - { - test_int(3, ecs_vec_count(&arr[1])); - const ecs_i32_t *v = ecs_vec_first(&arr[1]); - test_assert(v != NULL); - test_int(103, v[0]); - test_int(104, v[1]); - test_int(105, v[2]); - } - { - test_int(3, ecs_vec_count(&arr[2])); - const ecs_i32_t *v = ecs_vec_first(&arr[2]); - test_assert(v != NULL); - test_int(106, v[0]); - test_int(107, v[1]); - test_int(108, v[2]); - } + test_int(3, ecs_vec_count(&arr3[0])); + const ecs_i32_t *v = ecs_vec_first(&arr3[0]); + test_assert(v != NULL); + test_int(100, v[0]); + test_int(101, v[1]); + test_int(102, v[2]); + } + { + test_int(3, ecs_vec_count(&arr3[1])); + const ecs_i32_t *v = ecs_vec_first(&arr3[1]); + test_assert(v != NULL); + test_int(103, v[0]); + test_int(104, v[1]); + test_int(105, v[2]); + } + { + test_int(3, ecs_vec_count(&arr3[2])); + const ecs_i32_t *v = ecs_vec_first(&arr3[2]); + test_assert(v != NULL); + test_int(106, v[0]); + test_int(107, v[1]); + test_int(108, v[2]); } + test_assert(compare(world, array_of_vectors_of_ints, arr1, arr3) == 0); + /* Test deleting: */ ecs_delete(world, e); ecs_delete(world, instance); @@ -2786,102 +2732,100 @@ void RuntimeTypes_array_of_vectors_of_strings(void) { /* Test constructor: */ ecs_entity_t e = ecs_new(world); - { - ecs_vec_t *arr = ecs_ensure_id(world, e, array_of_vectors_of_strings); - { - test_int(0, ecs_vec_count(&arr[0])); - ecs_vec_set_count(NULL, &arr[0], sizeof(ecs_string_t), 3); - ecs_string_t *v = ecs_vec_first(&arr[0]); - invoke_type_ctor(world, v, 3, ecs_id(ecs_string_t)); - test_memory_zero(v, sizeof(ecs_string_t) * 3); - v[0] = ecs_os_strdup("String100"); - v[1] = ecs_os_strdup("String101"); - v[2] = ecs_os_strdup("String102"); - } - { - test_int(0, ecs_vec_count(&arr[1])); - ecs_vec_set_count(NULL, &arr[1], sizeof(ecs_string_t), 3); - ecs_string_t *v = ecs_vec_first(&arr[1]); - invoke_type_ctor(world, v, 3, ecs_id(ecs_string_t)); - test_memory_zero(v, sizeof(ecs_string_t) * 3); - v[0] = ecs_os_strdup("String103"); - v[1] = ecs_os_strdup("String104"); - v[2] = ecs_os_strdup("String105"); - } - { - test_int(0, ecs_vec_count(&arr[2])); - ecs_vec_set_count(NULL, &arr[2], sizeof(ecs_string_t), 3); - ecs_string_t *v = ecs_vec_first(&arr[2]); - invoke_type_ctor(world, v, 3, ecs_id(ecs_string_t)); - test_memory_zero(v, sizeof(ecs_string_t) * 3); - v[0] = ecs_os_strdup("String106"); - v[1] = ecs_os_strdup("String107"); - v[2] = ecs_os_strdup("String108"); - } + ecs_vec_t *arr1 = ecs_ensure_id(world, e, array_of_vectors_of_strings); + { + test_int(0, ecs_vec_count(&arr1[0])); + ecs_vec_set_count(NULL, &arr1[0], sizeof(ecs_string_t), 3); + ecs_string_t *v = ecs_vec_first(&arr1[0]); + invoke_type_ctor(world, v, 3, ecs_id(ecs_string_t)); + test_memory_zero(v, sizeof(ecs_string_t) * 3); + v[0] = ecs_os_strdup("String100"); + v[1] = ecs_os_strdup("String101"); + v[2] = ecs_os_strdup("String102"); + } + { + test_int(0, ecs_vec_count(&arr1[1])); + ecs_vec_set_count(NULL, &arr1[1], sizeof(ecs_string_t), 3); + ecs_string_t *v = ecs_vec_first(&arr1[1]); + invoke_type_ctor(world, v, 3, ecs_id(ecs_string_t)); + test_memory_zero(v, sizeof(ecs_string_t) * 3); + v[0] = ecs_os_strdup("String103"); + v[1] = ecs_os_strdup("String104"); + v[2] = ecs_os_strdup("String105"); + } + { + test_int(0, ecs_vec_count(&arr1[2])); + ecs_vec_set_count(NULL, &arr1[2], sizeof(ecs_string_t), 3); + ecs_string_t *v = ecs_vec_first(&arr1[2]); + invoke_type_ctor(world, v, 3, ecs_id(ecs_string_t)); + test_memory_zero(v, sizeof(ecs_string_t) * 3); + v[0] = ecs_os_strdup("String106"); + v[1] = ecs_os_strdup("String107"); + v[2] = ecs_os_strdup("String108"); } /* Test copying: */ ecs_entity_t instance = ecs_clone(world, 0, e, true); + const ecs_vec_t *arr2 = + ecs_get_id(world, e, array_of_vectors_of_strings); { - const ecs_vec_t *arr = - ecs_get_id(world, e, array_of_vectors_of_strings); - { - test_int(3, ecs_vec_count(&arr[0])); - const ecs_string_t *v = ecs_vec_first(&arr[0]); - test_assert(v != NULL); - test_str("String100", v[0]); - test_str("String101", v[1]); - test_str("String102", v[2]); - } - { - test_int(3, ecs_vec_count(&arr[1])); - const ecs_string_t *v = ecs_vec_first(&arr[1]); - test_assert(v != NULL); - test_str("String103", v[0]); - test_str("String104", v[1]); - test_str("String105", v[2]); - } - { - test_int(3, ecs_vec_count(&arr[2])); - const ecs_string_t *v = ecs_vec_first(&arr[2]); - test_assert(v != NULL); - test_str("String106", v[0]); - test_str("String107", v[1]); - test_str("String108", v[2]); - } + test_int(3, ecs_vec_count(&arr2[0])); + const ecs_string_t *v = ecs_vec_first(&arr2[0]); + test_assert(v != NULL); + test_str("String100", v[0]); + test_str("String101", v[1]); + test_str("String102", v[2]); + } + { + test_int(3, ecs_vec_count(&arr2[1])); + const ecs_string_t *v = ecs_vec_first(&arr2[1]); + test_assert(v != NULL); + test_str("String103", v[0]); + test_str("String104", v[1]); + test_str("String105", v[2]); + } + { + test_int(3, ecs_vec_count(&arr2[2])); + const ecs_string_t *v = ecs_vec_first(&arr2[2]); + test_assert(v != NULL); + test_str("String106", v[0]); + test_str("String107", v[1]); + test_str("String108", v[2]); } + test_assert(compare(world, array_of_vectors_of_strings, arr1, arr2) == 0); + /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); ecs_add(world, e, MakeMeMove); + const ecs_vec_t *arr3 = + ecs_get_id(world, e, array_of_vectors_of_strings); { - const ecs_vec_t *arr = - ecs_get_id(world, e, array_of_vectors_of_strings); - { - test_int(3, ecs_vec_count(&arr[0])); - const ecs_string_t *v = ecs_vec_first(&arr[0]); - test_assert(v != NULL); - test_str("String100", v[0]); - test_str("String101", v[1]); - test_str("String102", v[2]); - } - { - test_int(3, ecs_vec_count(&arr[1])); - const ecs_string_t *v = ecs_vec_first(&arr[1]); - test_assert(v != NULL); - test_str("String103", v[0]); - test_str("String104", v[1]); - test_str("String105", v[2]); - } - { - test_int(3, ecs_vec_count(&arr[2])); - const ecs_string_t *v = ecs_vec_first(&arr[2]); - test_assert(v != NULL); - test_str("String106", v[0]); - test_str("String107", v[1]); - test_str("String108", v[2]); - } + test_int(3, ecs_vec_count(&arr3[0])); + const ecs_string_t *v = ecs_vec_first(&arr3[0]); + test_assert(v != NULL); + test_str("String100", v[0]); + test_str("String101", v[1]); + test_str("String102", v[2]); } + { + test_int(3, ecs_vec_count(&arr3[1])); + const ecs_string_t *v = ecs_vec_first(&arr3[1]); + test_assert(v != NULL); + test_str("String103", v[0]); + test_str("String104", v[1]); + test_str("String105", v[2]); + } + { + test_int(3, ecs_vec_count(&arr3[2])); + const ecs_string_t *v = ecs_vec_first(&arr3[2]); + test_assert(v != NULL); + test_str("String106", v[0]); + test_str("String107", v[1]); + test_str("String108", v[2]); + } + + test_assert(compare(world, array_of_vectors_of_strings, arr1, arr3) == 0); /* Test deleting: */ ecs_delete(world, e); @@ -2904,41 +2848,42 @@ void RuntimeTypes_array_of_opaque(void) { /* Test constructor: */ ecs_entity_t e = ecs_new(world); - { - ResourceHandle *arr = ecs_ensure_id(world, e, array_of_opaque); - test_assert(arr[0].id != 0); - test_int(0, arr[0].value); - arr[0].value = 100; - test_assert(arr[1].id != 0); - test_int(0, arr[1].value); - arr[1].value = 101; - test_assert(arr[2].id != 0); - test_int(0, arr[2].value); - arr[2].value = 102; - } + ResourceHandle *arr1 = ecs_ensure_id(world, e, array_of_opaque); + test_assert(arr1[0].id != 0); + test_int(0, arr1[0].value); + arr1[0].value = 100; + test_assert(arr1[1].id != 0); + test_int(0, arr1[1].value); + arr1[1].value = 101; + test_assert(arr1[2].id != 0); + test_int(0, arr1[2].value); + arr1[2].value = 102; + /* 3 resource(s) should have been used */ test_int(3, initial_resources - resources_left()); /* Test copying: */ ecs_entity_t instance = ecs_clone(world, 0, e, true); - { - const ResourceHandle *arr = ecs_get_id(world, e, array_of_opaque); - test_int(100, arr[0].value); - test_int(101, arr[1].value); - test_int(102, arr[2].value); - } + const ResourceHandle *arr2 = ecs_get_id(world, e, array_of_opaque); + test_int(100, arr2[0].value); + test_int(101, arr2[1].value); + test_int(102, arr2[2].value); + + test_assert(compare(world, array_of_opaque, arr1, arr2) == 0); + /* 6 resource(s) should be in use now */ test_int(6, initial_resources - resources_left()); /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); ecs_add(world, e, MakeMeMove); - { - const ResourceHandle *arr = ecs_get_id(world, e, array_of_opaque); - test_int(100, arr[0].value); - test_int(101, arr[1].value); - test_int(102, arr[2].value); - } + const ResourceHandle *arr3 = ecs_get_id(world, e, array_of_opaque); + test_int(100, arr3[0].value); + test_int(101, arr3[1].value); + test_int(102, arr3[2].value); + + test_assert(compare(world, array_of_opaque, arr1, arr3) == 0); + /* 6 resource(s) should still be in use after a move */ test_int(6, initial_resources - resources_left()); @@ -2970,49 +2915,47 @@ void RuntimeTypes_vector_of_ints(void) { /* Test constructor: */ ecs_entity_t e = ecs_new(world); + ecs_vec_t *vec1 = ecs_ensure_id(world, e, vector_of_ints); { - ecs_vec_t *vec = ecs_ensure_id(world, e, vector_of_ints); - { - test_int(0, ecs_vec_count(vec)); - ecs_vec_set_count(NULL, vec, sizeof(ecs_i32_t), 3); - ecs_i32_t *v = ecs_vec_first(vec); - invoke_type_ctor(world, v, 3, ecs_id(ecs_i32_t)); - test_memory_zero(v, sizeof(ecs_i32_t) * 3); - v[0] = 100; - v[1] = 101; - v[2] = 102; - } + test_int(0, ecs_vec_count(vec1)); + ecs_vec_set_count(NULL, vec1, sizeof(ecs_i32_t), 3); + ecs_i32_t *v = ecs_vec_first(vec1); + invoke_type_ctor(world, v, 3, ecs_id(ecs_i32_t)); + test_memory_zero(v, sizeof(ecs_i32_t) * 3); + v[0] = 100; + v[1] = 101; + v[2] = 102; } /* Test copying: */ ecs_entity_t instance = ecs_clone(world, 0, e, true); + const ecs_vec_t *vec2 = ecs_get_id(world, e, vector_of_ints); { - const ecs_vec_t *vec = ecs_get_id(world, e, vector_of_ints); - { - test_int(3, ecs_vec_count(vec)); - const ecs_i32_t *v = ecs_vec_first(vec); - test_assert(v != NULL); - test_int(100, v[0]); - test_int(101, v[1]); - test_int(102, v[2]); - } + test_int(3, ecs_vec_count(vec2)); + const ecs_i32_t *v = ecs_vec_first(vec2); + test_assert(v != NULL); + test_int(100, v[0]); + test_int(101, v[1]); + test_int(102, v[2]); } + test_assert(compare(world, vector_of_ints, vec1, vec2) == 0); + /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); ecs_add(world, e, MakeMeMove); + const ecs_vec_t *vec3 = ecs_get_id(world, e, vector_of_ints); { - const ecs_vec_t *vec = ecs_get_id(world, e, vector_of_ints); - { - test_int(3, ecs_vec_count(vec)); - const ecs_i32_t *v = ecs_vec_first(vec); - test_assert(v != NULL); - test_int(100, v[0]); - test_int(101, v[1]); - test_int(102, v[2]); - } + test_int(3, ecs_vec_count(vec3)); + const ecs_i32_t *v = ecs_vec_first(vec3); + test_assert(v != NULL); + test_int(100, v[0]); + test_int(101, v[1]); + test_int(102, v[2]); } + test_assert(compare(world, vector_of_ints, vec1, vec3) == 0); + /* Test deleting: */ ecs_delete(world, e); ecs_delete(world, instance); @@ -3028,49 +2971,47 @@ void RuntimeTypes_vector_of_strings(void) { /* Test constructor: */ ecs_entity_t e = ecs_new(world); + ecs_vec_t *vec1 = ecs_ensure_id(world, e, vector_of_strings); { - ecs_vec_t *vec = ecs_ensure_id(world, e, vector_of_strings); - { - test_int(0, ecs_vec_count(vec)); - ecs_vec_set_count(NULL, vec, sizeof(ecs_string_t), 3); - ecs_string_t *v = ecs_vec_first(vec); - invoke_type_ctor(world, v, 3, ecs_id(ecs_string_t)); - test_memory_zero(v, sizeof(ecs_string_t) * 3); - v[0] = ecs_os_strdup("String100"); - v[1] = ecs_os_strdup("String101"); - v[2] = ecs_os_strdup("String102"); - } + test_int(0, ecs_vec_count(vec1)); + ecs_vec_set_count(NULL, vec1, sizeof(ecs_string_t), 3); + ecs_string_t *v = ecs_vec_first(vec1); + invoke_type_ctor(world, v, 3, ecs_id(ecs_string_t)); + test_memory_zero(v, sizeof(ecs_string_t) * 3); + v[0] = ecs_os_strdup("String100"); + v[1] = ecs_os_strdup("String101"); + v[2] = ecs_os_strdup("String102"); } /* Test copying: */ ecs_entity_t instance = ecs_clone(world, 0, e, true); + const ecs_vec_t *vec2 = ecs_get_id(world, e, vector_of_strings); { - const ecs_vec_t *vec = ecs_get_id(world, e, vector_of_strings); - { - test_int(3, ecs_vec_count(vec)); - const ecs_string_t *v = ecs_vec_first(vec); - test_assert(v != NULL); - test_str("String100", v[0]); - test_str("String101", v[1]); - test_str("String102", v[2]); - } + test_int(3, ecs_vec_count(vec2)); + const ecs_string_t *v = ecs_vec_first(vec2); + test_assert(v != NULL); + test_str("String100", v[0]); + test_str("String101", v[1]); + test_str("String102", v[2]); } + test_assert(compare(world, vector_of_strings, vec1, vec2) == 0); + /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); ecs_add(world, e, MakeMeMove); + const ecs_vec_t *vec3 = ecs_get_id(world, e, vector_of_strings); { - const ecs_vec_t *vec = ecs_get_id(world, e, vector_of_strings); - { - test_int(3, ecs_vec_count(vec)); - const ecs_string_t *v = ecs_vec_first(vec); - test_assert(v != NULL); - test_str("String100", v[0]); - test_str("String101", v[1]); - test_str("String102", v[2]); - } + test_int(3, ecs_vec_count(vec3)); + const ecs_string_t *v = ecs_vec_first(vec3); + test_assert(v != NULL); + test_str("String100", v[0]); + test_str("String101", v[1]); + test_str("String102", v[2]); } + test_assert(compare(world, vector_of_strings, vec1, vec3) == 0); + /* Test deleting: */ ecs_delete(world, e); ecs_delete(world, instance); @@ -3098,11 +3039,11 @@ void RuntimeTypes_vector_of_struct_with_ints(void) { /* Test constructor: */ ecs_entity_t e = ecs_new(world); + ecs_vec_t *vec1 = ecs_ensure_id(world, e, vector_of_struct_with_ints); { - ecs_vec_t *vec = ecs_ensure_id(world, e, vector_of_struct_with_ints); - test_int(0, ecs_vec_count(vec)); - ecs_vec_set_count(NULL, vec, sizeof(StructWithInts), 3); - StructWithInts *v = ecs_vec_first(vec); + test_int(0, ecs_vec_count(vec1)); + ecs_vec_set_count(NULL, vec1, sizeof(StructWithInts), 3); + StructWithInts *v = ecs_vec_first(vec1); invoke_type_ctor(world, v, 3, struct_with_ints); test_memory_zero(v, sizeof(StructWithInts) * 3); v[0].a = 100; @@ -3115,10 +3056,10 @@ void RuntimeTypes_vector_of_struct_with_ints(void) { /* Test copying: */ ecs_entity_t instance = ecs_clone(world, 0, e, true); + const ecs_vec_t *vec2 = ecs_get_id(world, e, vector_of_struct_with_ints); { - const ecs_vec_t *vec = ecs_get_id(world, e, vector_of_struct_with_ints); - test_int(3, ecs_vec_count(vec)); - const StructWithInts *v = ecs_vec_first(vec); + test_int(3, ecs_vec_count(vec2)); + const StructWithInts *v = ecs_vec_first(vec2); test_assert(v != NULL); test_int(100, v[0].a); test_int(101, v[0].b); @@ -3127,14 +3068,16 @@ void RuntimeTypes_vector_of_struct_with_ints(void) { test_int(104, v[2].a); test_int(105, v[2].b); } + test_assert(compare(world, vector_of_struct_with_ints, vec1, vec2) == 0); + /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); ecs_add(world, e, MakeMeMove); + const ecs_vec_t *vec3 = ecs_get_id(world, e, vector_of_struct_with_ints); { - const ecs_vec_t *vec = ecs_get_id(world, e, vector_of_struct_with_ints); - test_int(3, ecs_vec_count(vec)); - const StructWithInts *v = ecs_vec_first(vec); + test_int(3, ecs_vec_count(vec3)); + const StructWithInts *v = ecs_vec_first(vec2); test_assert(v != NULL); test_int(100, v[0].a); test_int(101, v[0].b); @@ -3143,6 +3086,7 @@ void RuntimeTypes_vector_of_struct_with_ints(void) { test_int(104, v[2].a); test_int(105, v[2].b); } + test_assert(compare(world, vector_of_struct_with_ints, vec1, vec3) == 0); /* Test deleting: */ ecs_delete(world, e); @@ -3173,11 +3117,11 @@ void RuntimeTypes_vector_of_struct_with_strings(void) { /* Test constructor: */ ecs_entity_t e = ecs_new(world); + ecs_vec_t *vec1 = ecs_ensure_id(world, e, vector_of_struct_with_strings); { - ecs_vec_t *vec = ecs_ensure_id(world, e, vector_of_struct_with_strings); - test_int(0, ecs_vec_count(vec)); - ecs_vec_set_count(NULL, vec, sizeof(StructWithStrings), 3); - StructWithStrings *v = ecs_vec_first(vec); + test_int(0, ecs_vec_count(vec1)); + ecs_vec_set_count(NULL, vec1, sizeof(StructWithStrings), 3); + StructWithStrings *v = ecs_vec_first(vec1); invoke_type_ctor(world, v, 3, struct_with_strings); test_memory_zero(v, sizeof(StructWithStrings) * 3); v[0].a = ecs_os_strdup("String100"); @@ -3193,11 +3137,10 @@ void RuntimeTypes_vector_of_struct_with_strings(void) { /* Test copying: */ ecs_entity_t instance = ecs_clone(world, 0, e, true); + const ecs_vec_t *vec2 = ecs_get_id(world, e, vector_of_struct_with_strings); { - const ecs_vec_t *vec = - ecs_get_id(world, e, vector_of_struct_with_strings); - test_int(3, ecs_vec_count(vec)); - const StructWithStrings *v = ecs_vec_first(vec); + test_int(3, ecs_vec_count(vec2)); + const StructWithStrings *v = ecs_vec_first(vec2); test_assert(v != NULL); test_str("String100", v[0].a); test_int(101, v[0].b); @@ -3209,15 +3152,15 @@ void RuntimeTypes_vector_of_struct_with_strings(void) { test_int(107, v[2].b); test_str("String108", v[2].c); } + test_assert(compare(world, vector_of_struct_with_strings, vec1, vec2) == 0); /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); ecs_add(world, e, MakeMeMove); + const ecs_vec_t *vec3 = ecs_get_id(world, e, vector_of_struct_with_strings); { - const ecs_vec_t *vec = - ecs_get_id(world, e, vector_of_struct_with_strings); - test_int(3, ecs_vec_count(vec)); - const StructWithStrings *v = ecs_vec_first(vec); + test_int(3, ecs_vec_count(vec3)); + const StructWithStrings *v = ecs_vec_first(vec3); test_assert(v != NULL); test_str("String100", v[0].a); test_int(101, v[0].b); @@ -3229,6 +3172,7 @@ void RuntimeTypes_vector_of_struct_with_strings(void) { test_int(107, v[2].b); test_str("String108", v[2].c); } + test_assert(compare(world, vector_of_struct_with_strings, vec1, vec3) == 0); /* Test deleting: */ ecs_delete(world, e); @@ -3248,61 +3192,55 @@ void RuntimeTypes_vector_of_arrays_of_strings(void) { /* Test constructor: */ ecs_entity_t e = ecs_new(world); + ecs_vec_t *vec1 = ecs_ensure_id(world, e, vector_of_arrays_of_strings); { - ecs_vec_t *vec = ecs_ensure_id(world, e, vector_of_arrays_of_strings); - { - test_int(0, ecs_vec_count(vec)); - ecs_vec_set_count(NULL, vec, sizeof(ecs_string_t[3]), 3); - ecs_string_t(*v)[3] = ecs_vec_first(vec); - invoke_type_ctor(world, v, 3, array_of_strings); - test_memory_zero(v, sizeof(ecs_string_t[3]) * 3); - int i; - for (i = 0; i < 3; i++) { - v[i][0] = ecs_os_strdup("String100"); - v[i][1] = ecs_os_strdup("String101"); - v[i][2] = ecs_os_strdup("String102"); - } + test_int(0, ecs_vec_count(vec1)); + ecs_vec_set_count(NULL, vec1, sizeof(ecs_string_t[3]), 3); + ecs_string_t(*v)[3] = ecs_vec_first(vec1); + invoke_type_ctor(world, v, 3, array_of_strings); + test_memory_zero(v, sizeof(ecs_string_t[3]) * 3); + int i; + for (i = 0; i < 3; i++) { + v[i][0] = ecs_os_strdup("String100"); + v[i][1] = ecs_os_strdup("String101"); + v[i][2] = ecs_os_strdup("String102"); } } /* Test copying: */ ecs_entity_t instance = ecs_clone(world, 0, e, true); + const ecs_vec_t *vec2 = ecs_get_id(world, e, vector_of_arrays_of_strings); { - const ecs_vec_t *vec = - ecs_get_id(world, e, vector_of_arrays_of_strings); - { - test_int(3, ecs_vec_count(vec)); - const ecs_string_t(*v)[3] = - (const ecs_string_t(*)[3]) ecs_vec_first(vec); - test_assert(v != NULL); - int i; - for (i = 0; i < 3; i++) { - test_str("String100", v[i][0]); - test_str("String101", v[i][1]); - test_str("String102", v[i][2]); - } + test_int(3, ecs_vec_count(vec2)); + const ecs_string_t(*v)[3] = + (const ecs_string_t(*)[3]) ecs_vec_first(vec2); + test_assert(v != NULL); + int i; + for (i = 0; i < 3; i++) { + test_str("String100", v[i][0]); + test_str("String101", v[i][1]); + test_str("String102", v[i][2]); } } + test_assert(compare(world, vector_of_arrays_of_strings, vec1, vec2) == 0); /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); ecs_add(world, e, MakeMeMove); + const ecs_vec_t *vec3 = ecs_get_id(world, e, vector_of_arrays_of_strings); { - const ecs_vec_t *vec = - ecs_get_id(world, e, vector_of_arrays_of_strings); - { - test_int(3, ecs_vec_count(vec)); - const ecs_string_t(*v)[3] = - (const ecs_string_t(*)[3]) ecs_vec_first(vec); - test_assert(v != NULL); - int i; - for (i = 0; i < 3; i++) { - test_str("String100", v[i][0]); - test_str("String101", v[i][1]); - test_str("String102", v[i][2]); - } + test_int(3, ecs_vec_count(vec3)); + const ecs_string_t(*v)[3] = + (const ecs_string_t(*)[3]) ecs_vec_first(vec3); + test_assert(v != NULL); + int i; + for (i = 0; i < 3; i++) { + test_str("String100", v[i][0]); + test_str("String101", v[i][1]); + test_str("String102", v[i][2]); } } + test_assert(compare(world, vector_of_arrays_of_strings, vec1, vec3) == 0); /* Test deleting: */ ecs_delete(world, e); @@ -3325,57 +3263,55 @@ void RuntimeTypes_vector_of_opaque(void) { /* Test constructor: */ ecs_entity_t e = ecs_new(world); - { - ecs_vec_t *vec = ecs_ensure_id(world, e, vector_of_opaque); - { - test_int(0, ecs_vec_count(vec)); - ecs_vec_set_count(NULL, vec, sizeof(ResourceHandle), 3); - ResourceHandle *v = ecs_vec_first(vec); - invoke_type_ctor(world, v, 3, resource_handle_opaque); - test_assert(v[0].id != 0); - test_int(0, v[0].value); - v[0].value = 100; - test_assert(v[1].id != 0); - test_int(0, v[1].value); - v[1].value = 101; - test_assert(v[2].id != 0); - test_int(0, v[2].value); - v[2].value = 102; - } + ecs_vec_t *vec1 = ecs_ensure_id(world, e, vector_of_opaque); + { + test_int(0, ecs_vec_count(vec1)); + ecs_vec_set_count(NULL, vec1, sizeof(ResourceHandle), 3); + ResourceHandle *v = ecs_vec_first(vec1); + invoke_type_ctor(world, v, 3, resource_handle_opaque); + test_assert(v[0].id != 0); + test_int(0, v[0].value); + v[0].value = 100; + test_assert(v[1].id != 0); + test_int(0, v[1].value); + v[1].value = 101; + test_assert(v[2].id != 0); + test_int(0, v[2].value); + v[2].value = 102; } /* 3 resource(s) should have been used */ test_int(3, initial_resources - resources_left()); /* Test copying: */ ecs_entity_t instance = ecs_clone(world, 0, e, true); + const ecs_vec_t *vec2 = ecs_get_id(world, e, vector_of_opaque); { - const ecs_vec_t *vec = ecs_get_id(world, e, vector_of_opaque); - { - test_int(3, ecs_vec_count(vec)); - const ResourceHandle *v = ecs_vec_first(vec); - test_assert(v != NULL); - test_int(100, v[0].value); - test_int(101, v[1].value); - test_int(102, v[2].value); - } + test_int(3, ecs_vec_count(vec2)); + const ResourceHandle *v = ecs_vec_first(vec2); + test_assert(v != NULL); + test_int(100, v[0].value); + test_int(101, v[1].value); + test_int(102, v[2].value); } + test_assert(compare(world, vector_of_opaque, vec1, vec2) == 0); + /* 6 resource(s) should be in use now */ test_int(6, initial_resources - resources_left()); /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); ecs_add(world, e, MakeMeMove); + const ecs_vec_t *vec3 = ecs_get_id(world, e, vector_of_opaque); { - const ecs_vec_t *vec = ecs_get_id(world, e, vector_of_opaque); - { - test_int(3, ecs_vec_count(vec)); - const ResourceHandle *v = ecs_vec_first(vec); - test_assert(v != NULL); - test_int(100, v[0].value); - test_int(101, v[1].value); - test_int(102, v[2].value); - } + test_int(3, ecs_vec_count(vec3)); + const ResourceHandle *v = ecs_vec_first(vec3); + test_assert(v != NULL); + test_int(100, v[0].value); + test_int(101, v[1].value); + test_int(102, v[2].value); } + test_assert(compare(world, vector_of_opaque, vec1, vec3) == 0); + /* 6 resource(s) should still be in use after a move */ test_int(6, initial_resources - resources_left()); diff --git a/test/meta/src/main.c b/test/meta/src/main.c index 4845f069e..f59263395 100644 --- a/test/meta/src/main.c +++ b/test/meta/src/main.c @@ -1010,6 +1010,9 @@ void Misc_unit_from_suspend_defer(void); void Misc_unit_prefix_from_suspend_defer(void); void Misc_quantity_from_suspend_defer(void); +// Testsuite 'Compare' +void Compare_u8(void); + bake_test_case PrimitiveTypes_testcases[] = { { "bool", @@ -4913,6 +4916,13 @@ bake_test_case Misc_testcases[] = { } }; +bake_test_case Compare_testcases[] = { + { + "u8", + Compare_u8 + } +}; + static bake_test_suite suites[] = { { @@ -5061,9 +5071,16 @@ static bake_test_suite suites[] = { NULL, 40, Misc_testcases + }, + { + "Compare", + NULL, + NULL, + 1, + Compare_testcases } }; int main(int argc, char *argv[]) { - return bake_test_run("meta", argc, argv, suites, 21); + return bake_test_run("meta", argc, argv, suites, 22); } From 7a943b540f5dd823e18323f62d1b594b8a044e99 Mon Sep 17 00:00:00 2001 From: Javier Peletier Date: Thu, 28 Nov 2024 12:29:53 +0100 Subject: [PATCH 02/23] make compare == NULL mean illegal --- distr/flecs.c | 172 ++++++++---------- distr/flecs.h | 58 +++--- include/flecs.h | 23 ++- include/flecs/addons/cpp/lifecycle_traits.hpp | 29 +-- include/flecs/private/api_support.h | 6 - src/addons/meta/meta.c | 3 - src/addons/meta/rtt_lifecycle.c | 122 ++++++------- src/world.c | 47 ++--- test/meta/src/RuntimeTypes.c | 16 ++ 9 files changed, 220 insertions(+), 256 deletions(-) diff --git a/distr/flecs.c b/distr/flecs.c index 126a80b22..e451a11e3 100644 --- a/distr/flecs.c +++ b/distr/flecs.c @@ -18942,15 +18942,6 @@ void flecs_default_move_w_dtor(void *dst_ptr, void *src_ptr, cl->dtor(src_ptr, count, ti); } -int flecs_default_comp( - const void *a_ptr, - const void *b_ptr, - const ecs_type_info_t *ti) -{ - (void)ti; - return a_ptr == b_ptr ? 0 : (a_ptr < b_ptr) ? -1 : 1; -} - ECS_NORETURN static void flecs_ctor_illegal( @@ -19023,6 +19014,17 @@ void flecs_move_ctor_illegal( ecs_abort(ECS_INVALID_OPERATION, "invalid move construct for %s", ti->name); } +ECS_NORETURN static +int flecs_comp_illegal( + const void *dst, + const void *src, + const ecs_type_info_t *ti) +{ + (void)dst; /* silence unused warning */ + (void)src; + ecs_abort(ECS_INVALID_OPERATION, "invalid compare hook for %s", ti->name); +} + void ecs_set_hooks_id( ecs_world_t *world, ecs_entity_t component, @@ -19035,26 +19037,25 @@ void ecs_set_hooks_id( flags &= ~((ecs_flags32_t)ECS_TYPE_HOOKS); /* TODO: enable asserts once RTT API is updated */ - /* - ecs_check(!(h->flags & ECS_TYPE_HOOK_CTOR_ILLEGAL) || !h->ctor, + + ecs_check(!(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_check(!(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_check(!(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_check(!(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_check(!(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_check(!(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) || + ecs_check(!(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_check(!(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); @@ -19092,7 +19093,7 @@ void ecs_set_hooks_id( if (h->move_ctor) ti->hooks.move_ctor = h->move_ctor; if (h->ctor_move_dtor) ti->hooks.ctor_move_dtor = h->ctor_move_dtor; if (h->move_dtor) ti->hooks.move_dtor = h->move_dtor; - if (h->comp) ti->hooks.comp = h->comp; + if (h->comp || flags & ECS_TYPE_HOOK_COMP_ILLEGAL) ti->hooks.comp = h->comp; if (h->on_add) ti->hooks.on_add = h->on_add; if (h->on_remove) ti->hooks.on_remove = h->on_remove; @@ -19201,11 +19202,13 @@ void ecs_set_hooks_id( 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 (ti->hooks.comp) ti->hooks.flags |= ECS_TYPE_HOOK_COMP; 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_TYPE_HOOK_COMP_ILLEGAL) ti->hooks.comp = flecs_comp_illegal; if(flags & ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL) { ti->hooks.copy_ctor = flecs_copy_ctor_illegal; @@ -19223,9 +19226,7 @@ void ecs_set_hooks_id( ti->hooks.ctor_move_dtor = flecs_move_ctor_illegal; } - if(ti->hooks.comp == NULL) { - ti->hooks.comp = flecs_default_comp; - } + error: return; } @@ -50408,9 +50409,6 @@ int flecs_init_type( if (!ti->hooks.ctor) { ti->hooks.ctor = flecs_default_ctor; } - if (!ti->hooks.comp) { - ti->hooks.comp = flecs_default_comp; - } } } else { if (meta_type->kind != kind) { @@ -51852,8 +51850,24 @@ ecs_rtt_struct_ctx_t * flecs_rtt_configure_struct_hooks( hooks.lifecycle_ctx_free(hooks.lifecycle_ctx); } + if(flags & ECS_TYPE_HOOK_CTOR_ILLEGAL) { + ctor = NULL; + } + if(flags & ECS_TYPE_HOOK_DTOR_ILLEGAL) { + dtor = NULL; + } + if(flags & ECS_TYPE_HOOK_MOVE_ILLEGAL) { + move = NULL; + } + if(flags & ECS_TYPE_HOOK_COPY_ILLEGAL) { + copy = NULL; + } + if(flags & ECS_TYPE_HOOK_COMP_ILLEGAL) { + comp = NULL; + } + ecs_rtt_struct_ctx_t *rtt_ctx = NULL; - if (ctor || dtor || move || copy || comp == flecs_rtt_struct_comp) { + if (ctor || dtor || move || copy || comp) { rtt_ctx = ecs_os_malloc_t(ecs_rtt_struct_ctx_t); ecs_vec_init_t(NULL, &rtt_ctx->vctor, ecs_rtt_call_data_t, 0); ecs_vec_init_t(NULL, &rtt_ctx->vdtor, ecs_rtt_call_data_t, 0); @@ -51863,29 +51877,17 @@ ecs_rtt_struct_ctx_t * flecs_rtt_configure_struct_hooks( hooks.lifecycle_ctx = rtt_ctx; hooks.lifecycle_ctx_free = flecs_rtt_free_lifecycle_struct_ctx; - if (ctor) { - hooks.ctor = ctor; - } - if (dtor) { - hooks.dtor = dtor; - } - if (move) { - hooks.move = move; - } - if (copy) { - hooks.copy = copy; - } + hooks.ctor = ctor; + hooks.dtor = dtor; + hooks.move = move; + hooks.copy = copy; + hooks.comp = comp; } else { hooks.lifecycle_ctx = NULL; hooks.lifecycle_ctx_free = flecs_rtt_free_lifecycle_nop; - } - if(comp) { - hooks.comp = comp; - } else { - hooks.comp = flecs_default_comp; - } + } - hooks.flags |= flags; + hooks.flags = flags; hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id(world, ti->component, &hooks); return rtt_ctx; @@ -51910,7 +51912,7 @@ void flecs_rtt_init_default_hooks_struct( bool dtor_hook_required = false; bool move_hook_required = false; bool copy_hook_required = false; - bool default_comparable = true; + bool comparable = true; /* Iterate all struct members and see if any member type has hooks. If so, * the struct itself will need to have that hook: */ @@ -51926,10 +51928,9 @@ void flecs_rtt_init_default_hooks_struct( move_hook_required |= member_ti->hooks.move != NULL; copy_hook_required |= member_ti->hooks.copy != NULL; - /* A struct is default-comparable if all its members - * are default-comparable */ - default_comparable &= member_ti->hooks.comp == NULL || - member_ti->hooks.comp == flecs_default_comp; + /* A struct is comparable if all its members + * are comparable */ + comparable &= member_ti->hooks.comp != NULL; flags |= member_ti->hooks.flags; } @@ -51944,7 +51945,7 @@ void flecs_rtt_init_default_hooks_struct( dtor_hook_required ? flecs_rtt_struct_dtor : NULL, move_hook_required ? flecs_rtt_struct_move : NULL, copy_hook_required ? flecs_rtt_struct_copy : NULL, - default_comparable ? NULL : flecs_rtt_struct_comp + comparable ? flecs_rtt_struct_comp : NULL ); if (!rtt_ctx) { @@ -52001,17 +52002,14 @@ void flecs_rtt_init_default_hooks_struct( copy_data->hook.copy = flecs_rtt_default_copy; } } - if (!default_comparable) { + if (comparable) { ecs_rtt_call_data_t *comp_data = ecs_vec_append_t(NULL, &rtt_ctx->vcomp, ecs_rtt_call_data_t); comp_data->offset = m->offset; comp_data->type_info = member_ti; comp_data->count = 1; - if(member_ti->hooks.comp) { - comp_data->hook.comp = member_ti->hooks.comp; - } else { - comp_data->hook.comp = flecs_default_comp; - } + ecs_assert(member_ti->hooks.comp, ECS_INTERNAL_ERROR, NULL); + comp_data->hook.comp = member_ti->hooks.comp; } } } @@ -52154,25 +52152,31 @@ void flecs_rtt_init_default_hooks_array( bool dtor_hook_required = element_ti->hooks.dtor != NULL; bool move_hook_required = element_ti->hooks.move != NULL; bool copy_hook_required = element_ti->hooks.copy != NULL; + bool comparable = element_ti->hooks.comp != NULL; ecs_flags32_t flags = element_ti->hooks.flags; ecs_type_hooks_t hooks = *ecs_get_hooks_id(world, component); - if(element_ti->hooks.comp == NULL || - element_ti->hooks.comp == flecs_default_comp) { - hooks.comp = flecs_default_comp; - } else { - hooks.comp = flecs_rtt_array_comp; - } + hooks.ctor = ctor_hook_required && !(flags & ECS_TYPE_HOOK_CTOR_ILLEGAL) ? + flecs_rtt_array_ctor : NULL; + hooks.dtor = dtor_hook_required && !(flags & ECS_TYPE_HOOK_DTOR_ILLEGAL) ? + flecs_rtt_array_dtor : NULL; + hooks.move = move_hook_required && !(flags & ECS_TYPE_HOOK_MOVE_ILLEGAL) ? + flecs_rtt_array_move : NULL; + hooks.copy = copy_hook_required && !(flags & ECS_TYPE_HOOK_COPY_ILLEGAL) ? + flecs_rtt_array_copy : NULL; + hooks.comp = comparable && !(flags & ECS_TYPE_HOOK_COMP_ILLEGAL) ? + flecs_rtt_array_comp : NULL; if (hooks.lifecycle_ctx_free) { hooks.lifecycle_ctx_free(hooks.lifecycle_ctx); hooks.lifecycle_ctx_free = flecs_rtt_free_lifecycle_nop; } - if (ctor_hook_required || dtor_hook_required || move_hook_required || - copy_hook_required || hooks.comp == flecs_rtt_array_comp) { + if (hooks.ctor || hooks.dtor || hooks.move || + hooks.copy || hooks.comp) + { ecs_rtt_array_ctx_t *rtt_ctx = ecs_os_malloc_t(ecs_rtt_array_ctx_t); rtt_ctx->type_info = element_ti; rtt_ctx->elem_count = array_info->count; @@ -52184,23 +52188,7 @@ void flecs_rtt_init_default_hooks_array( hooks.lifecycle_ctx_free = flecs_rtt_free_lifecycle_array_ctx; } - if (ctor_hook_required) { - hooks.ctor = flecs_rtt_array_ctor; - } - - if (dtor_hook_required) { - hooks.dtor = flecs_rtt_array_dtor; - } - - if (move_hook_required) { - hooks.move = flecs_rtt_array_move; - } - - if (copy_hook_required) { - hooks.copy = flecs_rtt_array_copy; - } - - hooks.flags |= flags; + hooks.flags = flags; hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id(world, component, &hooks); } @@ -52372,6 +52360,7 @@ void flecs_rtt_init_default_hooks_vector( ecs_get_type_info(world, vector_info->type); ecs_rtt_vector_ctx_t *rtt_ctx = ecs_os_malloc_t(ecs_rtt_vector_ctx_t); rtt_ctx->type_info = element_ti; + ecs_flags32_t flags = element_ti->hooks.flags; ecs_type_hooks_t hooks = *ecs_get_hooks_id(world, component); @@ -52385,14 +52374,17 @@ 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; - - if(element_ti->hooks.comp == NULL || - element_ti->hooks.comp == flecs_default_comp) { - hooks.comp = flecs_default_comp; - } else { + + if (element_ti->hooks.comp != NULL && !(flags & ECS_TYPE_HOOK_COMP_ILLEGAL)) { hooks.comp = flecs_rtt_vector_comp; + } else { + hooks.comp = NULL; } + + /* propagate only the compare hook illegal flag, if set */ + hooks.flags |= flags & ECS_TYPE_HOOK_COMP_ILLEGAL; + hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id(world, component, &hooks); } @@ -52450,10 +52442,6 @@ void flecs_rtt_init_default_hooks( hooks.ctor = flecs_default_ctor; } - if(!ti->hooks.comp) { - hooks.comp = flecs_default_comp; - } - ecs_set_hooks_id( world, component, diff --git a/distr/flecs.h b/distr/flecs.h index 42bf28b29..326e770f1 100644 --- a/distr/flecs.h +++ b/distr/flecs.h @@ -3545,29 +3545,32 @@ struct ecs_observer_t { #define ECS_TYPE_HOOK_MOVE_CTOR (1 << 5) #define ECS_TYPE_HOOK_CTOR_MOVE_DTOR (1 << 6) #define ECS_TYPE_HOOK_MOVE_DTOR (1 << 7) +#define ECS_TYPE_HOOK_COMP (1 << 8) + /* Flags that can be used to set/check which hooks of a type are invalid */ -#define ECS_TYPE_HOOK_CTOR_ILLEGAL (1 << 8) -#define ECS_TYPE_HOOK_DTOR_ILLEGAL (1 << 9) -#define ECS_TYPE_HOOK_COPY_ILLEGAL (1 << 10) -#define ECS_TYPE_HOOK_MOVE_ILLEGAL (1 << 11) -#define ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL (1 << 12) -#define ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL (1 << 13) -#define ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL (1 << 14) -#define ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL (1 << 15) +#define ECS_TYPE_HOOK_CTOR_ILLEGAL (1 << 9) +#define ECS_TYPE_HOOK_DTOR_ILLEGAL (1 << 10) +#define ECS_TYPE_HOOK_COPY_ILLEGAL (1 << 11) +#define ECS_TYPE_HOOK_MOVE_ILLEGAL (1 << 12) +#define ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL (1 << 13) +#define ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL (1 << 14) +#define ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL (1 << 15) +#define ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL (1 << 16) +#define ECS_TYPE_HOOK_COMP_ILLEGAL (1 << 17) /* All valid hook flags */ #define ECS_TYPE_HOOKS (ECS_TYPE_HOOK_CTOR|ECS_TYPE_HOOK_DTOR|\ ECS_TYPE_HOOK_COPY|ECS_TYPE_HOOK_MOVE|ECS_TYPE_HOOK_COPY_CTOR|\ ECS_TYPE_HOOK_MOVE_CTOR|ECS_TYPE_HOOK_CTOR_MOVE_DTOR|\ - ECS_TYPE_HOOK_MOVE_DTOR) + ECS_TYPE_HOOK_MOVE_DTOR|ECS_TYPE_HOOK_COMP) /* All invalid hook flags */ #define ECS_TYPE_HOOKS_ILLEGAL (ECS_TYPE_HOOK_CTOR_ILLEGAL|\ ECS_TYPE_HOOK_DTOR_ILLEGAL|ECS_TYPE_HOOK_COPY_ILLEGAL|\ ECS_TYPE_HOOK_MOVE_ILLEGAL|ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL|\ ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL|ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL|\ - ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL) + ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL|ECS_TYPE_HOOK_COMP_ILLEGAL) struct ecs_type_hooks_t { ecs_xtor_t ctor; /**< ctor */ @@ -3847,12 +3850,6 @@ void flecs_default_ctor( int32_t count, const ecs_type_info_t *ctx); -/* Default compare function */ -int flecs_default_comp( - const void *a_ptr, - const void *b_ptr, - const ecs_type_info_t *ti); - /* Create allocated string from format */ FLECS_DBG_API char* flecs_vasprintf( @@ -20572,7 +20569,8 @@ struct has_operator_equal() == std::de // 1. Compare function if `<`, `>`, are defined template ::value && - has_operator_greater::value > = 0> + has_operator_greater::value > && + !has_operator_equal::value = 0> int compare_impl(const void *a, const void *b, const ecs_type_info_t *) { const T& lhs = *static_cast(a); const T& rhs = *static_cast(b); @@ -20581,11 +20579,11 @@ int compare_impl(const void *a, const void *b, const ecs_type_info_t *) { return 0; } -// 2. Compare function if `<` and `==` are defined, deducing `>` +// 2. Compare function if `<` and `==` are defined, ignoring `>` +// if defined. template ::value && - has_operator_equal::value && - !has_operator_greater::value > = 0> + has_operator_equal::value > = 0> int compare_impl(const void *a, const void *b, const ecs_type_info_t *) { const T& lhs = *static_cast(a); const T& rhs = *static_cast(b); @@ -20633,30 +20631,18 @@ int compare_impl(const void *a, const void *b, const ecs_type_info_t *) { return 0; // If neither is greater, they must be equal } -// 6. Compare function if only `==` is defined, compare pointers to decide greater or smaller -template ::value && - !has_operator_less::value && - !has_operator_greater::value > = 0> -int compare_impl(const void *a, const void *b, const ecs_type_info_t *) { - const T& lhs = *static_cast(a); - const T& rhs = *static_cast(b); - if (lhs == rhs) return 0; - return (a < b) ? -1 : 1; // Use pointer comparison to decide order -} - +// In order to have a generated compare hook, at least +// operator> or operator< must be defined: template ::value || - has_operator_greater::value || - has_operator_equal::value > = 0> + has_operator_greater::value > = 0> ecs_comp_t compare() { return compare_impl; } template ::value && - !has_operator_greater::value && - !has_operator_equal::value > = 0> + !has_operator_greater::value > = 0> ecs_comp_t compare() { return NULL; } diff --git a/include/flecs.h b/include/flecs.h index 1058aeb92..acceada2c 100644 --- a/include/flecs.h +++ b/include/flecs.h @@ -877,29 +877,32 @@ struct ecs_observer_t { #define ECS_TYPE_HOOK_MOVE_CTOR (1 << 5) #define ECS_TYPE_HOOK_CTOR_MOVE_DTOR (1 << 6) #define ECS_TYPE_HOOK_MOVE_DTOR (1 << 7) +#define ECS_TYPE_HOOK_COMP (1 << 8) + /* Flags that can be used to set/check which hooks of a type are invalid */ -#define ECS_TYPE_HOOK_CTOR_ILLEGAL (1 << 8) -#define ECS_TYPE_HOOK_DTOR_ILLEGAL (1 << 9) -#define ECS_TYPE_HOOK_COPY_ILLEGAL (1 << 10) -#define ECS_TYPE_HOOK_MOVE_ILLEGAL (1 << 11) -#define ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL (1 << 12) -#define ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL (1 << 13) -#define ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL (1 << 14) -#define ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL (1 << 15) +#define ECS_TYPE_HOOK_CTOR_ILLEGAL (1 << 9) +#define ECS_TYPE_HOOK_DTOR_ILLEGAL (1 << 10) +#define ECS_TYPE_HOOK_COPY_ILLEGAL (1 << 11) +#define ECS_TYPE_HOOK_MOVE_ILLEGAL (1 << 12) +#define ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL (1 << 13) +#define ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL (1 << 14) +#define ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL (1 << 15) +#define ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL (1 << 16) +#define ECS_TYPE_HOOK_COMP_ILLEGAL (1 << 17) /* All valid hook flags */ #define ECS_TYPE_HOOKS (ECS_TYPE_HOOK_CTOR|ECS_TYPE_HOOK_DTOR|\ ECS_TYPE_HOOK_COPY|ECS_TYPE_HOOK_MOVE|ECS_TYPE_HOOK_COPY_CTOR|\ ECS_TYPE_HOOK_MOVE_CTOR|ECS_TYPE_HOOK_CTOR_MOVE_DTOR|\ - ECS_TYPE_HOOK_MOVE_DTOR) + ECS_TYPE_HOOK_MOVE_DTOR|ECS_TYPE_HOOK_COMP) /* All invalid hook flags */ #define ECS_TYPE_HOOKS_ILLEGAL (ECS_TYPE_HOOK_CTOR_ILLEGAL|\ ECS_TYPE_HOOK_DTOR_ILLEGAL|ECS_TYPE_HOOK_COPY_ILLEGAL|\ ECS_TYPE_HOOK_MOVE_ILLEGAL|ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL|\ ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL|ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL|\ - ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL) + ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL|ECS_TYPE_HOOK_COMP_ILLEGAL) struct ecs_type_hooks_t { ecs_xtor_t ctor; /**< ctor */ diff --git a/include/flecs/addons/cpp/lifecycle_traits.hpp b/include/flecs/addons/cpp/lifecycle_traits.hpp index 73efe673e..3ee35fe1d 100644 --- a/include/flecs/addons/cpp/lifecycle_traits.hpp +++ b/include/flecs/addons/cpp/lifecycle_traits.hpp @@ -405,7 +405,8 @@ struct has_operator_equal() == std::de // 1. Compare function if `<`, `>`, are defined template ::value && - has_operator_greater::value > = 0> + has_operator_greater::value > && + !has_operator_equal::value = 0> int compare_impl(const void *a, const void *b, const ecs_type_info_t *) { const T& lhs = *static_cast(a); const T& rhs = *static_cast(b); @@ -414,11 +415,11 @@ int compare_impl(const void *a, const void *b, const ecs_type_info_t *) { return 0; } -// 2. Compare function if `<` and `==` are defined, deducing `>` +// 2. Compare function if `<` and `==` are defined, ignoring `>` +// if defined. template ::value && - has_operator_equal::value && - !has_operator_greater::value > = 0> + has_operator_equal::value > = 0> int compare_impl(const void *a, const void *b, const ecs_type_info_t *) { const T& lhs = *static_cast(a); const T& rhs = *static_cast(b); @@ -466,30 +467,18 @@ int compare_impl(const void *a, const void *b, const ecs_type_info_t *) { return 0; // If neither is greater, they must be equal } -// 6. Compare function if only `==` is defined, compare pointers to decide greater or smaller -template ::value && - !has_operator_less::value && - !has_operator_greater::value > = 0> -int compare_impl(const void *a, const void *b, const ecs_type_info_t *) { - const T& lhs = *static_cast(a); - const T& rhs = *static_cast(b); - if (lhs == rhs) return 0; - return (a < b) ? -1 : 1; // Use pointer comparison to decide order -} - +// In order to have a generated compare hook, at least +// operator> or operator< must be defined: template ::value || - has_operator_greater::value || - has_operator_equal::value > = 0> + has_operator_greater::value > = 0> ecs_comp_t compare() { return compare_impl; } template ::value && - !has_operator_greater::value && - !has_operator_equal::value > = 0> + !has_operator_greater::value > = 0> ecs_comp_t compare() { return NULL; } diff --git a/include/flecs/private/api_support.h b/include/flecs/private/api_support.h index 11ea8feb8..5c9ce00fd 100644 --- a/include/flecs/private/api_support.h +++ b/include/flecs/private/api_support.h @@ -42,12 +42,6 @@ void flecs_default_ctor( int32_t count, const ecs_type_info_t *ctx); -/* Default compare function */ -int flecs_default_comp( - const void *a_ptr, - const void *b_ptr, - const ecs_type_info_t *ti); - /* Create allocated string from format */ FLECS_DBG_API char* flecs_vasprintf( diff --git a/src/addons/meta/meta.c b/src/addons/meta/meta.c index 6147dfb1a..97d34dd92 100644 --- a/src/addons/meta/meta.c +++ b/src/addons/meta/meta.c @@ -487,9 +487,6 @@ int flecs_init_type( if (!ti->hooks.ctor) { ti->hooks.ctor = flecs_default_ctor; } - if (!ti->hooks.comp) { - ti->hooks.comp = flecs_default_comp; - } } } else { if (meta_type->kind != kind) { diff --git a/src/addons/meta/rtt_lifecycle.c b/src/addons/meta/rtt_lifecycle.c index 4b09c923e..2a5323103 100644 --- a/src/addons/meta/rtt_lifecycle.c +++ b/src/addons/meta/rtt_lifecycle.c @@ -258,8 +258,24 @@ ecs_rtt_struct_ctx_t * flecs_rtt_configure_struct_hooks( hooks.lifecycle_ctx_free(hooks.lifecycle_ctx); } + if(flags & ECS_TYPE_HOOK_CTOR_ILLEGAL) { + ctor = NULL; + } + if(flags & ECS_TYPE_HOOK_DTOR_ILLEGAL) { + dtor = NULL; + } + if(flags & ECS_TYPE_HOOK_MOVE_ILLEGAL) { + move = NULL; + } + if(flags & ECS_TYPE_HOOK_COPY_ILLEGAL) { + copy = NULL; + } + if(flags & ECS_TYPE_HOOK_COMP_ILLEGAL) { + comp = NULL; + } + ecs_rtt_struct_ctx_t *rtt_ctx = NULL; - if (ctor || dtor || move || copy || comp == flecs_rtt_struct_comp) { + if (ctor || dtor || move || copy || comp) { rtt_ctx = ecs_os_malloc_t(ecs_rtt_struct_ctx_t); ecs_vec_init_t(NULL, &rtt_ctx->vctor, ecs_rtt_call_data_t, 0); ecs_vec_init_t(NULL, &rtt_ctx->vdtor, ecs_rtt_call_data_t, 0); @@ -269,29 +285,17 @@ ecs_rtt_struct_ctx_t * flecs_rtt_configure_struct_hooks( hooks.lifecycle_ctx = rtt_ctx; hooks.lifecycle_ctx_free = flecs_rtt_free_lifecycle_struct_ctx; - if (ctor) { - hooks.ctor = ctor; - } - if (dtor) { - hooks.dtor = dtor; - } - if (move) { - hooks.move = move; - } - if (copy) { - hooks.copy = copy; - } + hooks.ctor = ctor; + hooks.dtor = dtor; + hooks.move = move; + hooks.copy = copy; + hooks.comp = comp; } else { hooks.lifecycle_ctx = NULL; hooks.lifecycle_ctx_free = flecs_rtt_free_lifecycle_nop; - } - if(comp) { - hooks.comp = comp; - } else { - hooks.comp = flecs_default_comp; - } + } - hooks.flags |= flags; + hooks.flags = flags; hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id(world, ti->component, &hooks); return rtt_ctx; @@ -316,7 +320,7 @@ void flecs_rtt_init_default_hooks_struct( bool dtor_hook_required = false; bool move_hook_required = false; bool copy_hook_required = false; - bool default_comparable = true; + bool comparable = true; /* Iterate all struct members and see if any member type has hooks. If so, * the struct itself will need to have that hook: */ @@ -332,10 +336,9 @@ void flecs_rtt_init_default_hooks_struct( move_hook_required |= member_ti->hooks.move != NULL; copy_hook_required |= member_ti->hooks.copy != NULL; - /* A struct is default-comparable if all its members - * are default-comparable */ - default_comparable &= member_ti->hooks.comp == NULL || - member_ti->hooks.comp == flecs_default_comp; + /* A struct is comparable if all its members + * are comparable */ + comparable &= member_ti->hooks.comp != NULL; flags |= member_ti->hooks.flags; } @@ -350,7 +353,7 @@ void flecs_rtt_init_default_hooks_struct( dtor_hook_required ? flecs_rtt_struct_dtor : NULL, move_hook_required ? flecs_rtt_struct_move : NULL, copy_hook_required ? flecs_rtt_struct_copy : NULL, - default_comparable ? NULL : flecs_rtt_struct_comp + comparable ? flecs_rtt_struct_comp : NULL ); if (!rtt_ctx) { @@ -407,17 +410,14 @@ void flecs_rtt_init_default_hooks_struct( copy_data->hook.copy = flecs_rtt_default_copy; } } - if (!default_comparable) { + if (comparable) { ecs_rtt_call_data_t *comp_data = ecs_vec_append_t(NULL, &rtt_ctx->vcomp, ecs_rtt_call_data_t); comp_data->offset = m->offset; comp_data->type_info = member_ti; comp_data->count = 1; - if(member_ti->hooks.comp) { - comp_data->hook.comp = member_ti->hooks.comp; - } else { - comp_data->hook.comp = flecs_default_comp; - } + ecs_assert(member_ti->hooks.comp, ECS_INTERNAL_ERROR, NULL); + comp_data->hook.comp = member_ti->hooks.comp; } } } @@ -560,25 +560,31 @@ void flecs_rtt_init_default_hooks_array( bool dtor_hook_required = element_ti->hooks.dtor != NULL; bool move_hook_required = element_ti->hooks.move != NULL; bool copy_hook_required = element_ti->hooks.copy != NULL; + bool comparable = element_ti->hooks.comp != NULL; ecs_flags32_t flags = element_ti->hooks.flags; ecs_type_hooks_t hooks = *ecs_get_hooks_id(world, component); - if(element_ti->hooks.comp == NULL || - element_ti->hooks.comp == flecs_default_comp) { - hooks.comp = flecs_default_comp; - } else { - hooks.comp = flecs_rtt_array_comp; - } + hooks.ctor = ctor_hook_required && !(flags & ECS_TYPE_HOOK_CTOR_ILLEGAL) ? + flecs_rtt_array_ctor : NULL; + hooks.dtor = dtor_hook_required && !(flags & ECS_TYPE_HOOK_DTOR_ILLEGAL) ? + flecs_rtt_array_dtor : NULL; + hooks.move = move_hook_required && !(flags & ECS_TYPE_HOOK_MOVE_ILLEGAL) ? + flecs_rtt_array_move : NULL; + hooks.copy = copy_hook_required && !(flags & ECS_TYPE_HOOK_COPY_ILLEGAL) ? + flecs_rtt_array_copy : NULL; + hooks.comp = comparable && !(flags & ECS_TYPE_HOOK_COMP_ILLEGAL) ? + flecs_rtt_array_comp : NULL; if (hooks.lifecycle_ctx_free) { hooks.lifecycle_ctx_free(hooks.lifecycle_ctx); hooks.lifecycle_ctx_free = flecs_rtt_free_lifecycle_nop; } - if (ctor_hook_required || dtor_hook_required || move_hook_required || - copy_hook_required || hooks.comp == flecs_rtt_array_comp) { + if (hooks.ctor || hooks.dtor || hooks.move || + hooks.copy || hooks.comp) + { ecs_rtt_array_ctx_t *rtt_ctx = ecs_os_malloc_t(ecs_rtt_array_ctx_t); rtt_ctx->type_info = element_ti; rtt_ctx->elem_count = array_info->count; @@ -590,23 +596,7 @@ void flecs_rtt_init_default_hooks_array( hooks.lifecycle_ctx_free = flecs_rtt_free_lifecycle_array_ctx; } - if (ctor_hook_required) { - hooks.ctor = flecs_rtt_array_ctor; - } - - if (dtor_hook_required) { - hooks.dtor = flecs_rtt_array_dtor; - } - - if (move_hook_required) { - hooks.move = flecs_rtt_array_move; - } - - if (copy_hook_required) { - hooks.copy = flecs_rtt_array_copy; - } - - hooks.flags |= flags; + hooks.flags = flags; hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id(world, component, &hooks); } @@ -778,6 +768,7 @@ void flecs_rtt_init_default_hooks_vector( ecs_get_type_info(world, vector_info->type); ecs_rtt_vector_ctx_t *rtt_ctx = ecs_os_malloc_t(ecs_rtt_vector_ctx_t); rtt_ctx->type_info = element_ti; + ecs_flags32_t flags = element_ti->hooks.flags; ecs_type_hooks_t hooks = *ecs_get_hooks_id(world, component); @@ -791,14 +782,17 @@ 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; - - if(element_ti->hooks.comp == NULL || - element_ti->hooks.comp == flecs_default_comp) { - hooks.comp = flecs_default_comp; - } else { + + if (element_ti->hooks.comp != NULL && !(flags & ECS_TYPE_HOOK_COMP_ILLEGAL)) { hooks.comp = flecs_rtt_vector_comp; + } else { + hooks.comp = NULL; } + + /* propagate only the compare hook illegal flag, if set */ + hooks.flags |= flags & ECS_TYPE_HOOK_COMP_ILLEGAL; + hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id(world, component, &hooks); } @@ -856,10 +850,6 @@ void flecs_rtt_init_default_hooks( hooks.ctor = flecs_default_ctor; } - if(!ti->hooks.comp) { - hooks.comp = flecs_default_comp; - } - ecs_set_hooks_id( world, component, diff --git a/src/world.c b/src/world.c index 32a0d6832..884352d8d 100644 --- a/src/world.c +++ b/src/world.c @@ -1182,15 +1182,6 @@ void flecs_default_move_w_dtor(void *dst_ptr, void *src_ptr, cl->dtor(src_ptr, count, ti); } -int flecs_default_comp( - const void *a_ptr, - const void *b_ptr, - const ecs_type_info_t *ti) -{ - (void)ti; - return a_ptr == b_ptr ? 0 : (a_ptr < b_ptr) ? -1 : 1; -} - ECS_NORETURN static void flecs_ctor_illegal( @@ -1263,6 +1254,17 @@ void flecs_move_ctor_illegal( ecs_abort(ECS_INVALID_OPERATION, "invalid move construct for %s", ti->name); } +ECS_NORETURN static +int flecs_comp_illegal( + const void *dst, + const void *src, + const ecs_type_info_t *ti) +{ + (void)dst; /* silence unused warning */ + (void)src; + ecs_abort(ECS_INVALID_OPERATION, "invalid compare hook for %s", ti->name); +} + void ecs_set_hooks_id( ecs_world_t *world, ecs_entity_t component, @@ -1275,26 +1277,25 @@ void ecs_set_hooks_id( flags &= ~((ecs_flags32_t)ECS_TYPE_HOOKS); /* TODO: enable asserts once RTT API is updated */ - /* - ecs_check(!(h->flags & ECS_TYPE_HOOK_CTOR_ILLEGAL) || !h->ctor, + + ecs_check(!(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_check(!(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_check(!(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_check(!(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_check(!(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_check(!(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) || + ecs_check(!(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_check(!(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); @@ -1332,7 +1333,7 @@ void ecs_set_hooks_id( if (h->move_ctor) ti->hooks.move_ctor = h->move_ctor; if (h->ctor_move_dtor) ti->hooks.ctor_move_dtor = h->ctor_move_dtor; if (h->move_dtor) ti->hooks.move_dtor = h->move_dtor; - if (h->comp) ti->hooks.comp = h->comp; + if (h->comp || flags & ECS_TYPE_HOOK_COMP_ILLEGAL) ti->hooks.comp = h->comp; if (h->on_add) ti->hooks.on_add = h->on_add; if (h->on_remove) ti->hooks.on_remove = h->on_remove; @@ -1441,11 +1442,13 @@ void ecs_set_hooks_id( 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 (ti->hooks.comp) ti->hooks.flags |= ECS_TYPE_HOOK_COMP; 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_TYPE_HOOK_COMP_ILLEGAL) ti->hooks.comp = flecs_comp_illegal; if(flags & ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL) { ti->hooks.copy_ctor = flecs_copy_ctor_illegal; @@ -1463,9 +1466,7 @@ void ecs_set_hooks_id( ti->hooks.ctor_move_dtor = flecs_move_ctor_illegal; } - if(ti->hooks.comp == NULL) { - ti->hooks.comp = flecs_default_comp; - } + error: return; } diff --git a/test/meta/src/RuntimeTypes.c b/test/meta/src/RuntimeTypes.c index a5539179b..99790583c 100644 --- a/test/meta/src/RuntimeTypes.c +++ b/test/meta/src/RuntimeTypes.c @@ -279,6 +279,8 @@ void RuntimeTypes_ctor_illegal(void) { ecs_type_hooks_t hooks = nested_struct_ti->hooks; hooks.flags |= ECS_TYPE_HOOK_CTOR_ILLEGAL; /* mark constructor for "NestedStruct" as illegal */ + hooks.ctor = NULL; + hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id(world, nested_struct, &hooks); @@ -355,6 +357,8 @@ void RuntimeTypes_dtor_illegal(void) { ecs_type_hooks_t hooks = nested_struct_ti->hooks; hooks.flags |= ECS_TYPE_HOOK_DTOR_ILLEGAL; /* mark destructor for "NestedStruct" as illegal */ + hooks.dtor = NULL; + hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id(world, nested_struct, &hooks); @@ -447,6 +451,8 @@ void RuntimeTypes_move_illegal(void) { ecs_type_hooks_t hooks = nested_struct_ti->hooks; hooks.flags |= ECS_TYPE_HOOK_MOVE_ILLEGAL; /* mark move hook for "NestedStruct" as illegal */ + hooks.move = NULL; + hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id(world, nested_struct, &hooks); @@ -536,6 +542,8 @@ void RuntimeTypes_copy_illegal(void) { ecs_type_hooks_t hooks = nested_struct_ti->hooks; hooks.flags |= ECS_TYPE_HOOK_COPY_ILLEGAL; /* mark copy hook for "NestedStruct" as illegal */ + hooks.copy = NULL; + hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id(world, nested_struct, &hooks); @@ -844,6 +852,8 @@ void RuntimeTypes_array_ctor_illegal(void) { ecs_type_hooks_t hooks = nested_struct_ti->hooks; hooks.flags |= ECS_TYPE_HOOK_CTOR_ILLEGAL; /* mark constructor for "NestedStruct" as illegal */ + hooks.ctor = NULL; + hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id(world, nested_struct, &hooks); @@ -937,6 +947,8 @@ void RuntimeTypes_array_dtor_illegal(void) { ecs_type_hooks_t hooks = nested_struct_ti->hooks; hooks.flags |= ECS_TYPE_HOOK_DTOR_ILLEGAL; /* mark destructor for "NestedStruct" as illegal */ + hooks.dtor = NULL; + hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id(world, nested_struct, &hooks); @@ -1043,6 +1055,8 @@ void RuntimeTypes_array_move_illegal(void) { ecs_type_hooks_t hooks = nested_struct_ti->hooks; hooks.flags |= ECS_TYPE_HOOK_MOVE_ILLEGAL; /* mark move hook for "NestedStruct" as illegal */ + hooks.move = NULL; + hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id(world, nested_struct, &hooks); @@ -1147,6 +1161,8 @@ void RuntimeTypes_array_copy_illegal(void) { ecs_type_hooks_t hooks = nested_struct_ti->hooks; hooks.flags |= ECS_TYPE_HOOK_COPY_ILLEGAL; /* mark copy hook for "NestedStruct" as illegal */ + hooks.copy = NULL; + hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id(world, nested_struct, &hooks); From b5a51c702e0bfc37275c3cdd7801c9ec4ee89132 Mon Sep 17 00:00:00 2001 From: Javier Peletier Date: Thu, 28 Nov 2024 14:31:01 +0100 Subject: [PATCH 03/23] Enable ecs_set_hooks_id asserts and unquarantine ComponentLifecycle tests --- distr/flecs.c | 70 +++++++++++++------ distr/flecs.h | 4 +- include/flecs/addons/cpp/lifecycle_traits.hpp | 4 +- src/addons/meta/rtt_lifecycle.c | 2 +- src/world.c | 68 ++++++++++++------ test/core/src/ComponentLifecycle.c | 16 ----- 6 files changed, 100 insertions(+), 64 deletions(-) diff --git a/distr/flecs.c b/distr/flecs.c index e451a11e3..41ec1cc38 100644 --- a/distr/flecs.c +++ b/distr/flecs.c @@ -19036,26 +19036,52 @@ void ecs_set_hooks_id( ecs_flags32_t flags = h->flags; flags &= ~((ecs_flags32_t)ECS_TYPE_HOOKS); - /* TODO: enable asserts once RTT API is updated */ - - ecs_check(!(flags & ECS_TYPE_HOOK_CTOR_ILLEGAL) || !h->ctor, - ECS_INVALID_PARAMETER, "cannot specify both hook and illegal flag"); - ecs_check(!(flags & ECS_TYPE_HOOK_DTOR_ILLEGAL) || !h->dtor, - ECS_INVALID_PARAMETER, "cannot specify both hook and illegal flag"); - ecs_check(!(flags & ECS_TYPE_HOOK_COPY_ILLEGAL) || !h->copy, - ECS_INVALID_PARAMETER, "cannot specify both hook and illegal flag"); - ecs_check(!(flags & ECS_TYPE_HOOK_MOVE_ILLEGAL) || !h->move, - ECS_INVALID_PARAMETER, "cannot specify both hook and illegal flag"); - ecs_check(!(flags & ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL) || !h->copy_ctor, - ECS_INVALID_PARAMETER, - "cannot specify both hook and illegal flag"); - ecs_check(!(flags & ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL) || !h->move_ctor, - ECS_INVALID_PARAMETER, "cannot specify both hook and illegal flag"); - ecs_check(!(flags & ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL) || - !h->ctor_move_dtor, ECS_INVALID_PARAMETER, - "cannot specify both hook and illegal flag"); - ecs_check(!(flags & ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL) || !h->move_dtor, - ECS_INVALID_PARAMETER, "cannot specify both hook and illegal flag"); + ecs_check(!(flags & ECS_TYPE_HOOK_CTOR_ILLEGAL && + h->ctor != NULL && + h->ctor != flecs_ctor_illegal), + ECS_INVALID_PARAMETER, "cannot specify both ctor hook and illegal flag"); + + ecs_check(!(flags & ECS_TYPE_HOOK_DTOR_ILLEGAL && + h->dtor != NULL && + h->dtor != flecs_dtor_illegal), + ECS_INVALID_PARAMETER, "cannot specify both dtor hook and illegal flag"); + + ecs_check(!(flags & ECS_TYPE_HOOK_COPY_ILLEGAL && + h->copy != NULL && + h->copy != flecs_copy_illegal), + ECS_INVALID_PARAMETER, "cannot specify both copy hook and illegal flag"); + + ecs_check(!(flags & ECS_TYPE_HOOK_MOVE_ILLEGAL && + h->move != NULL && + h->move != flecs_move_illegal), + ECS_INVALID_PARAMETER, "cannot specify both move hook and illegal flag"); + + ecs_check(!(flags & ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL && + h->copy_ctor != NULL && + h->copy_ctor != flecs_copy_ctor_illegal), + ECS_INVALID_PARAMETER, "cannot specify both copy ctor hook and illegal flag"); + + ecs_check(!(flags & ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL && + h->move_ctor != NULL && + h->move_ctor != flecs_move_ctor_illegal), + ECS_INVALID_PARAMETER, "cannot specify both move ctor hook and illegal flag"); + + ecs_check(!(flags & ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL && + h->ctor_move_dtor != NULL && + h->ctor_move_dtor != flecs_move_ctor_illegal), + ECS_INVALID_PARAMETER, "cannot specify both ctor move dtor hook and illegal flag"); + + ecs_check(!(flags & ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL && + h->move_dtor != NULL && + h->move_dtor != flecs_move_ctor_illegal), + ECS_INVALID_PARAMETER, "cannot specify both move dtor hook and illegal flag"); + + ecs_check(!(flags & ECS_TYPE_HOOK_COMP_ILLEGAL && + h->comp != NULL && + h->comp != flecs_comp_illegal), + ECS_INVALID_PARAMETER, "cannot specify both compare hook and illegal flag"); + + flecs_stage_from_world(&world); @@ -19223,7 +19249,7 @@ void ecs_set_hooks_id( } if(ti->hooks.flags & ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL) { - ti->hooks.ctor_move_dtor = flecs_move_ctor_illegal; + ti->hooks.move_dtor = flecs_move_ctor_illegal; } @@ -52438,7 +52464,7 @@ void flecs_rtt_init_default_hooks( * a new component value does not contain uninitialized memory, which * could cause serializers to crash when for example inspecting string * fields. */ - if(!ti->hooks.ctor) { + if(!ti->hooks.ctor && !(ti->hooks.flags & ECS_TYPE_HOOK_CTOR_ILLEGAL)) { hooks.ctor = flecs_default_ctor; } diff --git a/distr/flecs.h b/distr/flecs.h index 326e770f1..b1406a78e 100644 --- a/distr/flecs.h +++ b/distr/flecs.h @@ -20569,8 +20569,8 @@ struct has_operator_equal() == std::de // 1. Compare function if `<`, `>`, are defined template ::value && - has_operator_greater::value > && - !has_operator_equal::value = 0> + has_operator_greater::value && + !has_operator_equal::value > = 0> int compare_impl(const void *a, const void *b, const ecs_type_info_t *) { const T& lhs = *static_cast(a); const T& rhs = *static_cast(b); diff --git a/include/flecs/addons/cpp/lifecycle_traits.hpp b/include/flecs/addons/cpp/lifecycle_traits.hpp index 3ee35fe1d..2433fc561 100644 --- a/include/flecs/addons/cpp/lifecycle_traits.hpp +++ b/include/flecs/addons/cpp/lifecycle_traits.hpp @@ -405,8 +405,8 @@ struct has_operator_equal() == std::de // 1. Compare function if `<`, `>`, are defined template ::value && - has_operator_greater::value > && - !has_operator_equal::value = 0> + has_operator_greater::value && + !has_operator_equal::value > = 0> int compare_impl(const void *a, const void *b, const ecs_type_info_t *) { const T& lhs = *static_cast(a); const T& rhs = *static_cast(b); diff --git a/src/addons/meta/rtt_lifecycle.c b/src/addons/meta/rtt_lifecycle.c index 2a5323103..5cb3429ea 100644 --- a/src/addons/meta/rtt_lifecycle.c +++ b/src/addons/meta/rtt_lifecycle.c @@ -846,7 +846,7 @@ void flecs_rtt_init_default_hooks( * a new component value does not contain uninitialized memory, which * could cause serializers to crash when for example inspecting string * fields. */ - if(!ti->hooks.ctor) { + if(!ti->hooks.ctor && !(ti->hooks.flags & ECS_TYPE_HOOK_CTOR_ILLEGAL)) { hooks.ctor = flecs_default_ctor; } diff --git a/src/world.c b/src/world.c index 884352d8d..492617f77 100644 --- a/src/world.c +++ b/src/world.c @@ -1276,26 +1276,52 @@ void ecs_set_hooks_id( ecs_flags32_t flags = h->flags; flags &= ~((ecs_flags32_t)ECS_TYPE_HOOKS); - /* TODO: enable asserts once RTT API is updated */ - - ecs_check(!(flags & ECS_TYPE_HOOK_CTOR_ILLEGAL) || !h->ctor, - ECS_INVALID_PARAMETER, "cannot specify both hook and illegal flag"); - ecs_check(!(flags & ECS_TYPE_HOOK_DTOR_ILLEGAL) || !h->dtor, - ECS_INVALID_PARAMETER, "cannot specify both hook and illegal flag"); - ecs_check(!(flags & ECS_TYPE_HOOK_COPY_ILLEGAL) || !h->copy, - ECS_INVALID_PARAMETER, "cannot specify both hook and illegal flag"); - ecs_check(!(flags & ECS_TYPE_HOOK_MOVE_ILLEGAL) || !h->move, - ECS_INVALID_PARAMETER, "cannot specify both hook and illegal flag"); - ecs_check(!(flags & ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL) || !h->copy_ctor, - ECS_INVALID_PARAMETER, - "cannot specify both hook and illegal flag"); - ecs_check(!(flags & ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL) || !h->move_ctor, - ECS_INVALID_PARAMETER, "cannot specify both hook and illegal flag"); - ecs_check(!(flags & ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL) || - !h->ctor_move_dtor, ECS_INVALID_PARAMETER, - "cannot specify both hook and illegal flag"); - ecs_check(!(flags & ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL) || !h->move_dtor, - ECS_INVALID_PARAMETER, "cannot specify both hook and illegal flag"); + ecs_check(!(flags & ECS_TYPE_HOOK_CTOR_ILLEGAL && + h->ctor != NULL && + h->ctor != flecs_ctor_illegal), + ECS_INVALID_PARAMETER, "cannot specify both ctor hook and illegal flag"); + + ecs_check(!(flags & ECS_TYPE_HOOK_DTOR_ILLEGAL && + h->dtor != NULL && + h->dtor != flecs_dtor_illegal), + ECS_INVALID_PARAMETER, "cannot specify both dtor hook and illegal flag"); + + ecs_check(!(flags & ECS_TYPE_HOOK_COPY_ILLEGAL && + h->copy != NULL && + h->copy != flecs_copy_illegal), + ECS_INVALID_PARAMETER, "cannot specify both copy hook and illegal flag"); + + ecs_check(!(flags & ECS_TYPE_HOOK_MOVE_ILLEGAL && + h->move != NULL && + h->move != flecs_move_illegal), + ECS_INVALID_PARAMETER, "cannot specify both move hook and illegal flag"); + + ecs_check(!(flags & ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL && + h->copy_ctor != NULL && + h->copy_ctor != flecs_copy_ctor_illegal), + ECS_INVALID_PARAMETER, "cannot specify both copy ctor hook and illegal flag"); + + ecs_check(!(flags & ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL && + h->move_ctor != NULL && + h->move_ctor != flecs_move_ctor_illegal), + ECS_INVALID_PARAMETER, "cannot specify both move ctor hook and illegal flag"); + + ecs_check(!(flags & ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL && + h->ctor_move_dtor != NULL && + h->ctor_move_dtor != flecs_move_ctor_illegal), + ECS_INVALID_PARAMETER, "cannot specify both ctor move dtor hook and illegal flag"); + + ecs_check(!(flags & ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL && + h->move_dtor != NULL && + h->move_dtor != flecs_move_ctor_illegal), + ECS_INVALID_PARAMETER, "cannot specify both move dtor hook and illegal flag"); + + ecs_check(!(flags & ECS_TYPE_HOOK_COMP_ILLEGAL && + h->comp != NULL && + h->comp != flecs_comp_illegal), + ECS_INVALID_PARAMETER, "cannot specify both compare hook and illegal flag"); + + flecs_stage_from_world(&world); @@ -1463,7 +1489,7 @@ void ecs_set_hooks_id( } if(ti->hooks.flags & ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL) { - ti->hooks.ctor_move_dtor = flecs_move_ctor_illegal; + ti->hooks.move_dtor = flecs_move_ctor_illegal; } diff --git a/test/core/src/ComponentLifecycle.c b/test/core/src/ComponentLifecycle.c index d6de7d44f..c339877dc 100644 --- a/test/core/src/ComponentLifecycle.c +++ b/test/core/src/ComponentLifecycle.c @@ -3695,8 +3695,6 @@ void ComponentLifecycle_illegal_copy_and_ctor(void) { } void ComponentLifecycle_illegal_ctor_w_ctor(void) { - test_quarantine("27 Nov 2024"); - install_test_abort(); ecs_world_t *world = ecs_mini(); @@ -3712,8 +3710,6 @@ void ComponentLifecycle_illegal_ctor_w_ctor(void) { } void ComponentLifecycle_illegal_dtor_w_dtor(void) { - test_quarantine("27 Nov 2024"); - install_test_abort(); ecs_world_t *world = ecs_mini(); @@ -3729,8 +3725,6 @@ void ComponentLifecycle_illegal_dtor_w_dtor(void) { } void ComponentLifecycle_illegal_move_w_move(void) { - test_quarantine("27 Nov 2024"); - install_test_abort(); ecs_world_t *world = ecs_mini(); @@ -3746,8 +3740,6 @@ void ComponentLifecycle_illegal_move_w_move(void) { } void ComponentLifecycle_illegal_copy_w_copy(void) { - test_quarantine("27 Nov 2024"); - install_test_abort(); ecs_world_t *world = ecs_mini(); @@ -3763,8 +3755,6 @@ void ComponentLifecycle_illegal_copy_w_copy(void) { } void ComponentLifecycle_illegal_move_ctor_w_move_ctor(void) { - test_quarantine("27 Nov 2024"); - install_test_abort(); ecs_world_t *world = ecs_mini(); @@ -3780,8 +3770,6 @@ void ComponentLifecycle_illegal_move_ctor_w_move_ctor(void) { } void ComponentLifecycle_illegal_copy_ctor_w_copy_ctor(void) { - test_quarantine("27 Nov 2024"); - install_test_abort(); ecs_world_t *world = ecs_mini(); @@ -3797,8 +3785,6 @@ void ComponentLifecycle_illegal_copy_ctor_w_copy_ctor(void) { } void ComponentLifecycle_illegal_move_ctor_w_ctor_and_move(void) { - test_quarantine("27 Nov 2024"); - install_test_abort(); ecs_world_t *world = ecs_mini(); @@ -3825,8 +3811,6 @@ void ComponentLifecycle_illegal_move_ctor_w_ctor_and_move(void) { } void ComponentLifecycle_illegal_copy_ctor_w_ctor_and_copy(void) { - test_quarantine("27 Nov 2024"); - install_test_abort(); ecs_world_t *world = ecs_mini(); From dbd7f06ce6d595c0590083abb9efbf8aeb2cc1a9 Mon Sep 17 00:00:00 2001 From: Javier Peletier Date: Thu, 28 Nov 2024 15:43:10 +0100 Subject: [PATCH 04/23] add primitive compare tests --- distr/flecs.c | 4 +- src/addons/meta/meta.c | 4 +- test/meta/project.json | 20 ++- test/meta/src/Compare.c | 298 +++++++++++++++++++++++++++++++++++++--- test/meta/src/main.c | 92 ++++++++++++- 5 files changed, 394 insertions(+), 24 deletions(-) diff --git a/distr/flecs.c b/distr/flecs.c index 41ec1cc38..d3753a517 100644 --- a/distr/flecs.c +++ b/distr/flecs.c @@ -50177,8 +50177,8 @@ int ecs_compare_string( const void *b_ptr, const ecs_type_info_t *ti) { (void)ti; - const char* str_a = *((const char *const *) a_ptr); - const char* str_b = *((const char *const *) b_ptr); + const ecs_string_t str_a = *((const ecs_string_t *) a_ptr); + const ecs_string_t str_b = *((const ecs_string_t *) b_ptr); if(str_a == str_b) { return 0; } diff --git a/src/addons/meta/meta.c b/src/addons/meta/meta.c index 97d34dd92..3c56f2364 100644 --- a/src/addons/meta/meta.c +++ b/src/addons/meta/meta.c @@ -229,8 +229,8 @@ int ecs_compare_string( const void *b_ptr, const ecs_type_info_t *ti) { (void)ti; - const char* str_a = *((const char *const *) a_ptr); - const char* str_b = *((const char *const *) b_ptr); + const ecs_string_t str_a = *((const ecs_string_t *) a_ptr); + const ecs_string_t str_b = *((const ecs_string_t *) b_ptr); if(str_a == str_b) { return 0; } diff --git a/test/meta/project.json b/test/meta/project.json index b3762f828..ad0d4dab8 100644 --- a/test/meta/project.json +++ b/test/meta/project.json @@ -1058,7 +1058,25 @@ },{ "id": "Compare", "testcases": [ - "u8" + "bool", + "char", + "byte", + "u8", + "u16", + "u32", + "u64", + "uptr", + "i8", + "i16", + "i32", + "i64", + "iptr", + "f32", + "f64", + "entity", + "id", + "string", + "const_string" ] }] } diff --git a/test/meta/src/Compare.c b/test/meta/src/Compare.c index f933c3522..1e2774f5b 100644 --- a/test/meta/src/Compare.c +++ b/test/meta/src/Compare.c @@ -1,28 +1,17 @@ -#include "flecs.h" -#include #include #include +#include "flecs.h" +#include +int cmp(const void *a, const void *b, const ecs_type_info_t* ti) { + return ti->hooks.comp(a, b, ti); +} const ecs_type_info_t *sort_ti = NULL; - int compare_element(const void *a, const void *b) { - return sort_ti->hooks.comp(a, b, sort_ti); -} - -int compare_array(const void *a, const void *b, ecs_size_t num_elements) { - int i; - for(i = 0; isize, i); - const void *el_b = ECS_ELEM(b, sort_ti->size, i); - int c = compare_element(el_a, el_b); - if(c != 0) { - return c; - } - } - return 0; + return cmp(a, b, sort_ti); } void sort_array(const ecs_world_t* world, ecs_entity_t component, void *arr, ecs_size_t num_elements) { @@ -30,6 +19,50 @@ void sort_array(const ecs_world_t* world, ecs_entity_t component, void *arr, ecs qsort(arr, num_elements, sort_ti->size, compare_element); } +/* Primitive comparer testing + * Comparer is demonstrated to work if it successfully sorts an array of primitives. +*/ + +void Compare_bool(void) { + ecs_world_t *world = ecs_init(); + + ecs_bool_t arr[] = {true, false, true, false}; + ecs_bool_t expected[] = {false, false, true, true}; + + sort_array(world, ecs_id(ecs_bool_t), arr, 4); + + test_assert(memcmp(arr, expected, sizeof(arr)) == 0); + + ecs_fini(world); +} + +void Compare_char(void) { + ecs_world_t *world = ecs_init(); + + ecs_char_t arr[] = {'z', 'a', 'm', 'a', 'x', 'b'}; + ecs_char_t expected[] = {'a', 'a', 'b', 'm', 'x', 'z'}; + + sort_array(world, ecs_id(ecs_char_t), arr, 6); + + test_assert(memcmp(arr, expected, sizeof(arr)) == 0); + + ecs_fini(world); +} + +void Compare_byte(void) { + ecs_world_t *world = ecs_init(); + + ecs_byte_t arr[] = {0xFF, 0x01, 0x7F, 0x01, 0x00}; + ecs_byte_t expected[] = {0x00, 0x01, 0x01, 0x7F, 0xFF}; + + sort_array(world, ecs_id(ecs_byte_t), arr, 5); + + test_assert(memcmp(arr, expected, sizeof(arr)) == 0); + + ecs_fini(world); +} + + void Compare_u8(void) { ecs_world_t *world = ecs_init(); @@ -38,7 +71,236 @@ void Compare_u8(void) { sort_array(world, ecs_id(ecs_u8_t), arr, 8); - test_assert(compare_array(arr, expected, 8) == 0); + test_assert(memcmp(arr, expected, sizeof(arr)) == 0); + + ecs_fini(world); +} + +void Compare_u16(void) { + ecs_world_t *world = ecs_init(); + + ecs_u16_t arr[] = {1024, 65535, 0, 1, 1024, 256}; + ecs_u16_t expected[] = {0, 1, 256, 1024, 1024, 65535}; + + sort_array(world, ecs_id(ecs_u16_t), arr, 6); + + test_assert(memcmp(arr, expected, sizeof(arr)) == 0); + + ecs_fini(world); +} + +void Compare_u32(void) { + ecs_world_t *world = ecs_init(); + + ecs_u32_t arr[] = {100000, 500, 4294967295, 100000, 0}; + ecs_u32_t expected[] = {0, 500, 100000, 100000, 4294967295}; + + sort_array(world, ecs_id(ecs_u32_t), arr, 5); + + test_assert(memcmp(arr, expected, sizeof(arr)) == 0); + + ecs_fini(world); +} + +void Compare_u64(void) { + ecs_world_t *world = ecs_init(); + + ecs_u64_t arr[] = {18446744073709551615ULL, 0, 1000, 18446744073709551615ULL, 42}; + ecs_u64_t expected[] = {0, 42, 1000, 18446744073709551615ULL, 18446744073709551615ULL}; + + sort_array(world, ecs_id(ecs_u64_t), arr, 5); + + test_assert(memcmp(arr, expected, sizeof(arr)) == 0); + + ecs_fini(world); +} + +void Compare_uptr(void) { + ecs_world_t *world = ecs_init(); + + ecs_uptr_t arr[] = {(ecs_uptr_t)0x1234, (ecs_uptr_t)0x5678, (ecs_uptr_t)0x1234, (ecs_uptr_t)0x9ABC}; + ecs_uptr_t expected[] = {(ecs_uptr_t)0x1234, (ecs_uptr_t)0x1234, (ecs_uptr_t)0x5678, (ecs_uptr_t)0x9ABC}; + + sort_array(world, ecs_id(ecs_uptr_t), arr, 4); + + test_assert(memcmp(arr, expected, sizeof(arr)) == 0); + + ecs_fini(world); +} + +void Compare_i8(void) { + ecs_world_t *world = ecs_init(); + + ecs_i8_t arr[] = {-128, 127, 0, -1, 127, 1}; + ecs_i8_t expected[] = {-128, -1, 0, 1, 127, 127}; + + sort_array(world, ecs_id(ecs_i8_t), arr, 6); + + test_assert(memcmp(arr, expected, sizeof(arr)) == 0); + + ecs_fini(world); +} + +void Compare_i16(void) { + ecs_world_t *world = ecs_init(); + + ecs_i16_t arr[] = {-32768, 32767, 100, -100, 32767}; + ecs_i16_t expected[] = {-32768, -100, 100, 32767, 32767}; + + sort_array(world, ecs_id(ecs_i16_t), arr, 5); + + test_assert(memcmp(arr, expected, sizeof(arr)) == 0); + + ecs_fini(world); +} + +void Compare_i32(void) { + ecs_world_t *world = ecs_init(); + + ecs_i32_t arr[] = {-100000, 50000, 0, -100000, 100000}; + ecs_i32_t expected[] = {-100000, -100000, 0, 50000, 100000}; + + sort_array(world, ecs_id(ecs_i32_t), arr, 5); + + test_assert(memcmp(arr, expected, sizeof(arr)) == 0); + + ecs_fini(world); +} + +void Compare_i64(void) { + ecs_world_t *world = ecs_init(); + + ecs_i64_t arr[] = {-9223372036854775807LL, 9223372036854775807LL, 0, -1000, + 9223372036854775807LL}; + ecs_i64_t expected[] = {-9223372036854775807LL, -1000, 0, + 9223372036854775807LL, 9223372036854775807LL}; + + sort_array(world, ecs_id(ecs_i64_t), arr, 5); + + test_assert(memcmp(arr, expected, sizeof(arr)) == 0); + + ecs_fini(world); +} + +void Compare_iptr(void) { + ecs_world_t *world = ecs_init(); + + ecs_iptr_t arr[] = {(ecs_iptr_t)-1000, (ecs_iptr_t)500, (ecs_iptr_t)0, + (ecs_iptr_t)-1000}; + ecs_iptr_t expected[] = {(ecs_iptr_t)-1000, (ecs_iptr_t)-1000, (ecs_iptr_t)0, + (ecs_iptr_t)500}; + + sort_array(world, ecs_id(ecs_iptr_t), arr, 4); + + test_assert(memcmp(arr, expected, sizeof(arr)) == 0); + + ecs_fini(world); +} + +void Compare_f32(void) { + ecs_world_t *world = ecs_init(); + + ecs_f32_t arr[] = {3.14f, 2.71f, -1.0f, 2.71f, 0.0f}; + ecs_f32_t expected[] = {-1.0f, 0.0f, 2.71f, 2.71f, 3.14f}; + + sort_array(world, ecs_id(ecs_f32_t), arr, 5); + + test_assert(memcmp(arr, expected, sizeof(arr)) == 0); + + ecs_fini(world); +} + +void Compare_f64(void) { + ecs_world_t *world = ecs_init(); + + ecs_f64_t arr[] = {3.14159, 2.71828, -1.0, 2.71828, 0.0}; + ecs_f64_t expected[] = {-1.0, 0.0, 2.71828, 2.71828, 3.14159}; + + sort_array(world, ecs_id(ecs_f64_t), arr, 5); + + test_assert(memcmp(arr, expected, sizeof(arr)) == 0); + + ecs_fini(world); +} + +void Compare_entity(void) { + ecs_world_t *world = ecs_init(); + + ecs_entity_t arr[] = {1000, 42, 1000, 500, 0}; + ecs_entity_t expected[] = {0, 42, 500, 1000, 1000}; + + sort_array(world, ecs_id(ecs_entity_t), arr, 5); + + test_assert(memcmp(arr, expected, sizeof(arr)) == 0); + + ecs_fini(world); +} + +void Compare_id(void) { + ecs_world_t *world = ecs_init(); + + ecs_id_t arr[] = {1000, 42, 1000, 500, 0}; + ecs_id_t expected[] = {0, 42, 500, 1000, 1000}; + + sort_array(world, ecs_id(ecs_id_t), arr, 5); + + test_assert(memcmp(arr, expected, sizeof(arr)) == 0); + + ecs_fini(world); +} + +void Compare_string(void) { + + ecs_world_t *world = ecs_init(); + + const char* const_arr[] = {"world", "hello", NULL, "aa", "zz" ,"aa", "cc", "bb"}; + const char* const_expected[] = {NULL, "aa", "aa", "bb", "cc", "hello", "world", "zz"}; + + ecs_size_t count = sizeof(const_arr) / sizeof(const char*); + test_assert(count == sizeof(const_expected) / sizeof(const char*)); + + ecs_string_t arr[count]; + ecs_string_t expected[count]; + + const ecs_type_info_t *ti = ecs_get_type_info(world, ecs_id(ecs_string_t)); + ti->hooks.copy_ctor(arr, const_arr, count, ti); + ti->hooks.copy_ctor(expected, const_expected,count , ti); + + sort_array(world, ecs_id(ecs_string_t), arr, count); + + int i; + for(i = 0; i < count; i++) { + test_assert((arr[i] == NULL && expected[i] == NULL) || + ecs_os_strcmp(arr[i], expected[i]) == 0); + } + + ti->hooks.dtor(arr, count, ti); + ti->hooks.dtor(expected, count, ti); + + ecs_fini(world); +} + +void Compare_const_string(void) { + + ecs_world_t *world = ecs_init(); + + // Lookup const string type: + ecs_entity_t const_string = ecs_lookup(world, "flecs.core.const_string_t"); + + const char* arr[] = {"world", "hello", NULL, "aa", "zz" ,"aa", "cc", "bb"}; + const char* expected[] = {NULL, "aa", "aa", "bb", "cc", "hello", "world", "zz"}; + + ecs_size_t count = sizeof(arr) / sizeof(const char*); + test_assert(count == sizeof(expected) / sizeof(const char*)); + + sort_array(world, const_string, arr, count); + + int i; + for(i = 0; i < count; i++) { + test_assert((arr[i] == NULL && expected[i] == NULL) || + ecs_os_strcmp(arr[i], expected[i]) == 0); + } + ecs_fini(world); } \ No newline at end of file diff --git a/test/meta/src/main.c b/test/meta/src/main.c index f59263395..4c1a4db3e 100644 --- a/test/meta/src/main.c +++ b/test/meta/src/main.c @@ -1011,7 +1011,25 @@ void Misc_unit_prefix_from_suspend_defer(void); void Misc_quantity_from_suspend_defer(void); // Testsuite 'Compare' +void Compare_bool(void); +void Compare_char(void); +void Compare_byte(void); void Compare_u8(void); +void Compare_u16(void); +void Compare_u32(void); +void Compare_u64(void); +void Compare_uptr(void); +void Compare_i8(void); +void Compare_i16(void); +void Compare_i32(void); +void Compare_i64(void); +void Compare_iptr(void); +void Compare_f32(void); +void Compare_f64(void); +void Compare_entity(void); +void Compare_id(void); +void Compare_string(void); +void Compare_const_string(void); bake_test_case PrimitiveTypes_testcases[] = { { @@ -4917,9 +4935,81 @@ bake_test_case Misc_testcases[] = { }; bake_test_case Compare_testcases[] = { + { + "bool", + Compare_bool + }, + { + "char", + Compare_char + }, + { + "byte", + Compare_byte + }, { "u8", Compare_u8 + }, + { + "u16", + Compare_u16 + }, + { + "u32", + Compare_u32 + }, + { + "u64", + Compare_u64 + }, + { + "uptr", + Compare_uptr + }, + { + "i8", + Compare_i8 + }, + { + "i16", + Compare_i16 + }, + { + "i32", + Compare_i32 + }, + { + "i64", + Compare_i64 + }, + { + "iptr", + Compare_iptr + }, + { + "f32", + Compare_f32 + }, + { + "f64", + Compare_f64 + }, + { + "entity", + Compare_entity + }, + { + "id", + Compare_id + }, + { + "string", + Compare_string + }, + { + "const_string", + Compare_const_string } }; @@ -5076,7 +5166,7 @@ static bake_test_suite suites[] = { "Compare", NULL, NULL, - 1, + 19, Compare_testcases } }; From 57f29d20a39b6e6ad6d5e5e4660acf194ab3a4e6 Mon Sep 17 00:00:00 2001 From: Javier Peletier Date: Thu, 28 Nov 2024 16:17:47 +0100 Subject: [PATCH 05/23] complete tests by adding more basic testing first --- test/meta/src/Compare.c | 314 +++++++++++++++++++++++++++++++++++----- 1 file changed, 274 insertions(+), 40 deletions(-) diff --git a/test/meta/src/Compare.c b/test/meta/src/Compare.c index 1e2774f5b..2009c63bb 100644 --- a/test/meta/src/Compare.c +++ b/test/meta/src/Compare.c @@ -14,11 +14,24 @@ int compare_element(const void *a, const void *b) { return cmp(a, b, sort_ti); } -void sort_array(const ecs_world_t* world, ecs_entity_t component, void *arr, ecs_size_t num_elements) { - sort_ti = ecs_get_type_info(world, component); +void sort_array(const ecs_type_info_t* ti, void *arr, ecs_size_t num_elements) { + sort_ti = ti; qsort(arr, num_elements, sort_ti->size, compare_element); } +bool str_equals(const char* a, const char* b) { + if(a == b) { + return true; + } + if(a == NULL) { + return false; + } + if(b == NULL) { + return false; + } + return ecs_os_strcmp(a,b) == 0; +} + /* Primitive comparer testing * Comparer is demonstrated to work if it successfully sorts an array of primitives. */ @@ -29,7 +42,19 @@ void Compare_bool(void) { ecs_bool_t arr[] = {true, false, true, false}; ecs_bool_t expected[] = {false, false, true, true}; - sort_array(world, ecs_id(ecs_bool_t), arr, 4); + const ecs_type_info_t* ti = ecs_get_type_info(world, ecs_id(ecs_bool_t)); + + /* test "less" */ + test_assert(cmp(&arr[1], &arr[0], ti) < 0); + + /* test "greater" */ + test_assert(cmp(&arr[0], &arr[1], ti) > 0); + + /* test "equal" */ + test_assert(cmp(&arr[0], &arr[0], ti) == 0); + + /* further test by sorting the array */ + sort_array(ti, arr, 4); test_assert(memcmp(arr, expected, sizeof(arr)) == 0); @@ -42,7 +67,19 @@ void Compare_char(void) { ecs_char_t arr[] = {'z', 'a', 'm', 'a', 'x', 'b'}; ecs_char_t expected[] = {'a', 'a', 'b', 'm', 'x', 'z'}; - sort_array(world, ecs_id(ecs_char_t), arr, 6); + const ecs_type_info_t* ti = ecs_get_type_info(world, ecs_id(ecs_char_t)); + + /* test "less" */ + test_assert(cmp(&arr[1], &arr[0], ti) < 0); + + /* test "greater" */ + test_assert(cmp(&arr[0], &arr[1], ti) > 0); + + /* test "equal" */ + test_assert(cmp(&arr[1], &arr[1], ti) == 0); + + /* further test by sorting the array */ + sort_array(ti, arr, 6); test_assert(memcmp(arr, expected, sizeof(arr)) == 0); @@ -55,7 +92,19 @@ void Compare_byte(void) { ecs_byte_t arr[] = {0xFF, 0x01, 0x7F, 0x01, 0x00}; ecs_byte_t expected[] = {0x00, 0x01, 0x01, 0x7F, 0xFF}; - sort_array(world, ecs_id(ecs_byte_t), arr, 5); + const ecs_type_info_t* ti = ecs_get_type_info(world, ecs_id(ecs_byte_t)); + + /* test "less" */ + test_assert(cmp(&arr[1], &arr[0], ti) < 0); + + /* test "greater" */ + test_assert(cmp(&arr[0], &arr[1], ti) > 0); + + /* test "equal" */ + test_assert(cmp(&arr[1], &arr[1], ti) == 0); + + /* further test by sorting the array */ + sort_array(ti, arr, 5); test_assert(memcmp(arr, expected, sizeof(arr)) == 0); @@ -69,7 +118,19 @@ void Compare_u8(void) { ecs_u8_t arr[] = {1, 79, 12, 3, 255, 79, 0, 14 }; ecs_u8_t expected[] = {0, 1, 3, 12, 14, 79, 79, 255 }; - sort_array(world, ecs_id(ecs_u8_t), arr, 8); + const ecs_type_info_t* ti = ecs_get_type_info(world, ecs_id(ecs_u8_t)); + + /* test "less" */ + test_assert(cmp(&arr[0], &arr[1], ti) < 0); + + /* test "greater" */ + test_assert(cmp(&arr[1], &arr[0], ti) > 0); + + /* test "equal" */ + test_assert(cmp(&arr[0], &arr[0], ti) == 0); + + /* further test by sorting the array */ + sort_array(ti, arr, 8); test_assert(memcmp(arr, expected, sizeof(arr)) == 0); @@ -82,7 +143,19 @@ void Compare_u16(void) { ecs_u16_t arr[] = {1024, 65535, 0, 1, 1024, 256}; ecs_u16_t expected[] = {0, 1, 256, 1024, 1024, 65535}; - sort_array(world, ecs_id(ecs_u16_t), arr, 6); + const ecs_type_info_t* ti = ecs_get_type_info(world, ecs_id(ecs_u16_t)); + + /* test "less" */ + test_assert(cmp(&arr[2], &arr[1], ti) < 0); + + /* test "greater" */ + test_assert(cmp(&arr[1], &arr[2], ti) > 0); + + /* test "equal" */ + test_assert(cmp(&arr[0], &arr[4], ti) == 0); + + /* further test by sorting the array */ + sort_array(ti, arr, 6); test_assert(memcmp(arr, expected, sizeof(arr)) == 0); @@ -95,7 +168,19 @@ void Compare_u32(void) { ecs_u32_t arr[] = {100000, 500, 4294967295, 100000, 0}; ecs_u32_t expected[] = {0, 500, 100000, 100000, 4294967295}; - sort_array(world, ecs_id(ecs_u32_t), arr, 5); + const ecs_type_info_t* ti = ecs_get_type_info(world, ecs_id(ecs_u32_t)); + + /* test "less" */ + test_assert(cmp(&arr[4], &arr[1], ti) < 0); + + /* test "greater" */ + test_assert(cmp(&arr[2], &arr[1], ti) > 0); + + /* test "equal" */ + test_assert(cmp(&arr[0], &arr[3], ti) == 0); + + /* further test by sorting the array */ + sort_array(ti, arr, 5); test_assert(memcmp(arr, expected, sizeof(arr)) == 0); @@ -108,7 +193,19 @@ void Compare_u64(void) { ecs_u64_t arr[] = {18446744073709551615ULL, 0, 1000, 18446744073709551615ULL, 42}; ecs_u64_t expected[] = {0, 42, 1000, 18446744073709551615ULL, 18446744073709551615ULL}; - sort_array(world, ecs_id(ecs_u64_t), arr, 5); + const ecs_type_info_t* ti = ecs_get_type_info(world, ecs_id(ecs_u64_t)); + + /* test "less" */ + test_assert(cmp(&arr[1], &arr[0], ti) < 0); + + /* test "greater" */ + test_assert(cmp(&arr[0], &arr[2], ti) > 0); + + /* test "equal" */ + test_assert(cmp(&arr[0], &arr[3], ti) == 0); + + /* further test by sorting the array */ + sort_array(ti, arr, 5); test_assert(memcmp(arr, expected, sizeof(arr)) == 0); @@ -121,7 +218,19 @@ void Compare_uptr(void) { ecs_uptr_t arr[] = {(ecs_uptr_t)0x1234, (ecs_uptr_t)0x5678, (ecs_uptr_t)0x1234, (ecs_uptr_t)0x9ABC}; ecs_uptr_t expected[] = {(ecs_uptr_t)0x1234, (ecs_uptr_t)0x1234, (ecs_uptr_t)0x5678, (ecs_uptr_t)0x9ABC}; - sort_array(world, ecs_id(ecs_uptr_t), arr, 4); + const ecs_type_info_t* ti = ecs_get_type_info(world, ecs_id(ecs_uptr_t)); + + /* test "less" */ + test_assert(cmp(&arr[0], &arr[1], ti) < 0); + + /* test "greater" */ + test_assert(cmp(&arr[3], &arr[1], ti) > 0); + + /* test "equal" */ + test_assert(cmp(&arr[0], &arr[2], ti) == 0); + + /* further test by sorting the array */ + sort_array(ti, arr, 4); test_assert(memcmp(arr, expected, sizeof(arr)) == 0); @@ -134,7 +243,19 @@ void Compare_i8(void) { ecs_i8_t arr[] = {-128, 127, 0, -1, 127, 1}; ecs_i8_t expected[] = {-128, -1, 0, 1, 127, 127}; - sort_array(world, ecs_id(ecs_i8_t), arr, 6); + const ecs_type_info_t* ti = ecs_get_type_info(world, ecs_id(ecs_i8_t)); + + /* test "less" */ + test_assert(cmp(&arr[0], &arr[1], ti) < 0); + + /* test "greater" */ + test_assert(cmp(&arr[1], &arr[2], ti) > 0); + + /* test "equal" */ + test_assert(cmp(&arr[1], &arr[4], ti) == 0); + + /* further test by sorting the array */ + sort_array(ti, arr, 6); test_assert(memcmp(arr, expected, sizeof(arr)) == 0); @@ -147,7 +268,19 @@ void Compare_i16(void) { ecs_i16_t arr[] = {-32768, 32767, 100, -100, 32767}; ecs_i16_t expected[] = {-32768, -100, 100, 32767, 32767}; - sort_array(world, ecs_id(ecs_i16_t), arr, 5); + const ecs_type_info_t* ti = ecs_get_type_info(world, ecs_id(ecs_i16_t)); + + /* test "less" */ + test_assert(cmp(&arr[0], &arr[2], ti) < 0); + + /* test "greater" */ + test_assert(cmp(&arr[1], &arr[2], ti) > 0); + + /* test "equal" */ + test_assert(cmp(&arr[1], &arr[4], ti) == 0); + + /* further test by sorting the array */ + sort_array(ti, arr, 5); test_assert(memcmp(arr, expected, sizeof(arr)) == 0); @@ -160,7 +293,19 @@ void Compare_i32(void) { ecs_i32_t arr[] = {-100000, 50000, 0, -100000, 100000}; ecs_i32_t expected[] = {-100000, -100000, 0, 50000, 100000}; - sort_array(world, ecs_id(ecs_i32_t), arr, 5); + const ecs_type_info_t* ti = ecs_get_type_info(world, ecs_id(ecs_i32_t)); + + /* test "less" */ + test_assert(cmp(&arr[0], &arr[1], ti) < 0); + + /* test "greater" */ + test_assert(cmp(&arr[1], &arr[2], ti) > 0); + + /* test "equal" */ + test_assert(cmp(&arr[0], &arr[3], ti) == 0); + + /* further test by sorting the array */ + sort_array(ti, arr, 5); test_assert(memcmp(arr, expected, sizeof(arr)) == 0); @@ -170,12 +315,22 @@ void Compare_i32(void) { void Compare_i64(void) { ecs_world_t *world = ecs_init(); - ecs_i64_t arr[] = {-9223372036854775807LL, 9223372036854775807LL, 0, -1000, - 9223372036854775807LL}; - ecs_i64_t expected[] = {-9223372036854775807LL, -1000, 0, - 9223372036854775807LL, 9223372036854775807LL}; + ecs_i64_t arr[] = {-9223372036854775807LL, 9223372036854775807LL, 0, -1000, 9223372036854775807LL}; + ecs_i64_t expected[] = {-9223372036854775807LL, -1000, 0, 9223372036854775807LL, 9223372036854775807LL}; + + const ecs_type_info_t* ti = ecs_get_type_info(world, ecs_id(ecs_i64_t)); + + /* test "less" */ + test_assert(cmp(&arr[0], &arr[1], ti) < 0); + + /* test "greater" */ + test_assert(cmp(&arr[1], &arr[2], ti) > 0); + + /* test "equal" */ + test_assert(cmp(&arr[1], &arr[4], ti) == 0); - sort_array(world, ecs_id(ecs_i64_t), arr, 5); + /* further test by sorting the array */ + sort_array(ti, arr, 5); test_assert(memcmp(arr, expected, sizeof(arr)) == 0); @@ -185,12 +340,22 @@ void Compare_i64(void) { void Compare_iptr(void) { ecs_world_t *world = ecs_init(); - ecs_iptr_t arr[] = {(ecs_iptr_t)-1000, (ecs_iptr_t)500, (ecs_iptr_t)0, - (ecs_iptr_t)-1000}; - ecs_iptr_t expected[] = {(ecs_iptr_t)-1000, (ecs_iptr_t)-1000, (ecs_iptr_t)0, - (ecs_iptr_t)500}; + ecs_iptr_t arr[] = {(ecs_iptr_t)-1000, (ecs_iptr_t)500, (ecs_iptr_t)0, (ecs_iptr_t)-1000}; + ecs_iptr_t expected[] = {(ecs_iptr_t)-1000, (ecs_iptr_t)-1000, (ecs_iptr_t)0, (ecs_iptr_t)500}; - sort_array(world, ecs_id(ecs_iptr_t), arr, 4); + const ecs_type_info_t* ti = ecs_get_type_info(world, ecs_id(ecs_iptr_t)); + + /* test "less" */ + test_assert(cmp(&arr[0], &arr[1], ti) < 0); + + /* test "greater" */ + test_assert(cmp(&arr[1], &arr[2], ti) > 0); + + /* test "equal" */ + test_assert(cmp(&arr[0], &arr[3], ti) == 0); + + /* further test by sorting the array */ + sort_array(ti, arr, 4); test_assert(memcmp(arr, expected, sizeof(arr)) == 0); @@ -203,7 +368,19 @@ void Compare_f32(void) { ecs_f32_t arr[] = {3.14f, 2.71f, -1.0f, 2.71f, 0.0f}; ecs_f32_t expected[] = {-1.0f, 0.0f, 2.71f, 2.71f, 3.14f}; - sort_array(world, ecs_id(ecs_f32_t), arr, 5); + const ecs_type_info_t* ti = ecs_get_type_info(world, ecs_id(ecs_f32_t)); + + /* test "less" */ + test_assert(cmp(&arr[2], &arr[0], ti) < 0); + + /* test "greater" */ + test_assert(cmp(&arr[0], &arr[4], ti) > 0); + + /* test "equal" */ + test_assert(cmp(&arr[1], &arr[3], ti) == 0); + + /* further test by sorting the array */ + sort_array(ti, arr, 5); test_assert(memcmp(arr, expected, sizeof(arr)) == 0); @@ -216,7 +393,19 @@ void Compare_f64(void) { ecs_f64_t arr[] = {3.14159, 2.71828, -1.0, 2.71828, 0.0}; ecs_f64_t expected[] = {-1.0, 0.0, 2.71828, 2.71828, 3.14159}; - sort_array(world, ecs_id(ecs_f64_t), arr, 5); + const ecs_type_info_t* ti = ecs_get_type_info(world, ecs_id(ecs_f64_t)); + + /* test "less" */ + test_assert(cmp(&arr[2], &arr[0], ti) < 0); + + /* test "greater" */ + test_assert(cmp(&arr[0], &arr[4], ti) > 0); + + /* test "equal" */ + test_assert(cmp(&arr[1], &arr[3], ti) == 0); + + /* further test by sorting the array */ + sort_array(ti, arr, 5); test_assert(memcmp(arr, expected, sizeof(arr)) == 0); @@ -229,7 +418,19 @@ void Compare_entity(void) { ecs_entity_t arr[] = {1000, 42, 1000, 500, 0}; ecs_entity_t expected[] = {0, 42, 500, 1000, 1000}; - sort_array(world, ecs_id(ecs_entity_t), arr, 5); + const ecs_type_info_t* ti = ecs_get_type_info(world, ecs_id(ecs_entity_t)); + + /* test "less" */ + test_assert(cmp(&arr[4], &arr[1], ti) < 0); + + /* test "greater" */ + test_assert(cmp(&arr[0], &arr[1], ti) > 0); + + /* test "equal" */ + test_assert(cmp(&arr[0], &arr[2], ti) == 0); + + /* further test by sorting the array */ + sort_array(ti, arr, 5); test_assert(memcmp(arr, expected, sizeof(arr)) == 0); @@ -242,18 +443,30 @@ void Compare_id(void) { ecs_id_t arr[] = {1000, 42, 1000, 500, 0}; ecs_id_t expected[] = {0, 42, 500, 1000, 1000}; - sort_array(world, ecs_id(ecs_id_t), arr, 5); + const ecs_type_info_t* ti = ecs_get_type_info(world, ecs_id(ecs_id_t)); + + /* test "less" */ + test_assert(cmp(&arr[4], &arr[1], ti) < 0); + + /* test "greater" */ + test_assert(cmp(&arr[0], &arr[1], ti) > 0); + + /* test "equal" */ + test_assert(cmp(&arr[0], &arr[2], ti) == 0); + + /* further test by sorting the array */ + sort_array(ti, arr, 5); test_assert(memcmp(arr, expected, sizeof(arr)) == 0); ecs_fini(world); } -void Compare_string(void) { +void Compare_string(void) { ecs_world_t *world = ecs_init(); - const char* const_arr[] = {"world", "hello", NULL, "aa", "zz" ,"aa", "cc", "bb"}; + const char* const_arr[] = {"world", "hello", NULL, "aa", "zz", "aa", "cc", "bb"}; const char* const_expected[] = {NULL, "aa", "aa", "bb", "cc", "hello", "world", "zz"}; ecs_size_t count = sizeof(const_arr) / sizeof(const char*); @@ -264,14 +477,25 @@ void Compare_string(void) { const ecs_type_info_t *ti = ecs_get_type_info(world, ecs_id(ecs_string_t)); ti->hooks.copy_ctor(arr, const_arr, count, ti); - ti->hooks.copy_ctor(expected, const_expected,count , ti); + ti->hooks.copy_ctor(expected, const_expected, count, ti); + + /* test "less" */ + test_assert(cmp(&arr[3], &arr[7], ti) < 0); /* "aa < "bb" */ + test_assert(cmp(&arr[2], &arr[5], ti) < 0); /* NULL < "aa" */ + + /* test "greater" */ + test_assert(cmp(&arr[6], &arr[5], ti) > 0); /* "cc" > "aa" */ - sort_array(world, ecs_id(ecs_string_t), arr, count); + /* test "equal" */ + test_assert(cmp(&arr[3], &arr[5], ti) == 0); /* "aa" == "aa" */ + test_assert(cmp(&arr[2], &arr[5], ti) < 0); /* NULL == NULL */ + + /* further test by sorting the array */ + sort_array(ti, arr, count); int i; for(i = 0; i < count; i++) { - test_assert((arr[i] == NULL && expected[i] == NULL) || - ecs_os_strcmp(arr[i], expected[i]) == 0); + test_assert(str_equals(arr[i], expected[i])); } ti->hooks.dtor(arr, count, ti); @@ -281,26 +505,36 @@ void Compare_string(void) { } void Compare_const_string(void) { - ecs_world_t *world = ecs_init(); - // Lookup const string type: ecs_entity_t const_string = ecs_lookup(world, "flecs.core.const_string_t"); - const char* arr[] = {"world", "hello", NULL, "aa", "zz" ,"aa", "cc", "bb"}; + const char* arr[] = {"world", "hello", NULL, "aa", "zz", "aa", "cc", "bb"}; const char* expected[] = {NULL, "aa", "aa", "bb", "cc", "hello", "world", "zz"}; + const ecs_type_info_t *ti = ecs_get_type_info(world, const_string); + ecs_size_t count = sizeof(arr) / sizeof(const char*); test_assert(count == sizeof(expected) / sizeof(const char*)); - sort_array(world, const_string, arr, count); + /* test "less" */ + test_assert(cmp(&arr[3], &arr[7], ti) < 0); /* "aa < "bb" */ + test_assert(cmp(&arr[2], &arr[5], ti) < 0); /* NULL < "aa" */ + + /* test "greater" */ + test_assert(cmp(&arr[6], &arr[5], ti) > 0); /* "cc" > "aa" */ + + /* test "equal" */ + test_assert(cmp(&arr[3], &arr[5], ti) == 0); /* "aa" == "aa" */ + test_assert(cmp(&arr[2], &arr[5], ti) < 0); /* NULL == NULL */ + + /* further test by sorting the array */ + sort_array(ti, arr, count); int i; for(i = 0; i < count; i++) { - test_assert((arr[i] == NULL && expected[i] == NULL) || - ecs_os_strcmp(arr[i], expected[i]) == 0); + test_assert(str_equals(arr[i], expected[i])); } - ecs_fini(world); } \ No newline at end of file From bb5026a06e72e4671146df3438c853bd2b9fae2f Mon Sep 17 00:00:00 2001 From: Javier Peletier Date: Thu, 28 Nov 2024 16:30:22 +0100 Subject: [PATCH 06/23] some comments in primitive comparer tests --- test/meta/src/Compare.c | 126 +++++++++++++++++++++------------------- 1 file changed, 67 insertions(+), 59 deletions(-) diff --git a/test/meta/src/Compare.c b/test/meta/src/Compare.c index 2009c63bb..68222405e 100644 --- a/test/meta/src/Compare.c +++ b/test/meta/src/Compare.c @@ -45,13 +45,13 @@ void Compare_bool(void) { const ecs_type_info_t* ti = ecs_get_type_info(world, ecs_id(ecs_bool_t)); /* test "less" */ - test_assert(cmp(&arr[1], &arr[0], ti) < 0); + test_assert(cmp(&arr[1], &arr[0], ti) < 0); /* false < true */ /* test "greater" */ - test_assert(cmp(&arr[0], &arr[1], ti) > 0); + test_assert(cmp(&arr[0], &arr[1], ti) > 0); /* true > false */ /* test "equal" */ - test_assert(cmp(&arr[0], &arr[0], ti) == 0); + test_assert(cmp(&arr[0], &arr[0], ti) == 0); /* true == true */ /* further test by sorting the array */ sort_array(ti, arr, 4); @@ -70,13 +70,13 @@ void Compare_char(void) { const ecs_type_info_t* ti = ecs_get_type_info(world, ecs_id(ecs_char_t)); /* test "less" */ - test_assert(cmp(&arr[1], &arr[0], ti) < 0); + test_assert(cmp(&arr[1], &arr[0], ti) < 0); /* 'a' < 'z' */ /* test "greater" */ - test_assert(cmp(&arr[0], &arr[1], ti) > 0); + test_assert(cmp(&arr[0], &arr[1], ti) > 0); /* 'z' > 'a' */ /* test "equal" */ - test_assert(cmp(&arr[1], &arr[1], ti) == 0); + test_assert(cmp(&arr[1], &arr[1], ti) == 0); /* 'a' == 'a' */ /* further test by sorting the array */ sort_array(ti, arr, 6); @@ -95,13 +95,13 @@ void Compare_byte(void) { const ecs_type_info_t* ti = ecs_get_type_info(world, ecs_id(ecs_byte_t)); /* test "less" */ - test_assert(cmp(&arr[1], &arr[0], ti) < 0); + test_assert(cmp(&arr[1], &arr[0], ti) < 0); /* 0x01 < 0xFF */ /* test "greater" */ - test_assert(cmp(&arr[0], &arr[1], ti) > 0); + test_assert(cmp(&arr[0], &arr[1], ti) > 0); /* 0xFF > 0x01 */ /* test "equal" */ - test_assert(cmp(&arr[1], &arr[1], ti) == 0); + test_assert(cmp(&arr[1], &arr[1], ti) == 0); /* 0x01 == 0x01 */ /* further test by sorting the array */ sort_array(ti, arr, 5); @@ -111,23 +111,22 @@ void Compare_byte(void) { ecs_fini(world); } - void Compare_u8(void) { ecs_world_t *world = ecs_init(); - - ecs_u8_t arr[] = {1, 79, 12, 3, 255, 79, 0, 14 }; - ecs_u8_t expected[] = {0, 1, 3, 12, 14, 79, 79, 255 }; + + ecs_u8_t arr[] = {1, 79, 12, 3, 255, 79, 0, 14}; + ecs_u8_t expected[] = {0, 1, 3, 12, 14, 79, 79, 255}; const ecs_type_info_t* ti = ecs_get_type_info(world, ecs_id(ecs_u8_t)); /* test "less" */ - test_assert(cmp(&arr[0], &arr[1], ti) < 0); + test_assert(cmp(&arr[0], &arr[1], ti) < 0); /* 1 < 79 */ /* test "greater" */ - test_assert(cmp(&arr[1], &arr[0], ti) > 0); + test_assert(cmp(&arr[1], &arr[0], ti) > 0); /* 79 > 1 */ /* test "equal" */ - test_assert(cmp(&arr[0], &arr[0], ti) == 0); + test_assert(cmp(&arr[5], &arr[1], ti) == 0); /* 79 == 79 */ /* further test by sorting the array */ sort_array(ti, arr, 8); @@ -146,13 +145,13 @@ void Compare_u16(void) { const ecs_type_info_t* ti = ecs_get_type_info(world, ecs_id(ecs_u16_t)); /* test "less" */ - test_assert(cmp(&arr[2], &arr[1], ti) < 0); + test_assert(cmp(&arr[2], &arr[1], ti) < 0); /* 0 < 65535 */ /* test "greater" */ - test_assert(cmp(&arr[1], &arr[2], ti) > 0); + test_assert(cmp(&arr[1], &arr[2], ti) > 0); /* 65535 > 0 */ /* test "equal" */ - test_assert(cmp(&arr[0], &arr[4], ti) == 0); + test_assert(cmp(&arr[0], &arr[4], ti) == 0); /* 1024 == 1024 */ /* further test by sorting the array */ sort_array(ti, arr, 6); @@ -171,13 +170,13 @@ void Compare_u32(void) { const ecs_type_info_t* ti = ecs_get_type_info(world, ecs_id(ecs_u32_t)); /* test "less" */ - test_assert(cmp(&arr[4], &arr[1], ti) < 0); + test_assert(cmp(&arr[4], &arr[1], ti) < 0); /* 0 < 500 */ /* test "greater" */ - test_assert(cmp(&arr[2], &arr[1], ti) > 0); + test_assert(cmp(&arr[2], &arr[1], ti) > 0); /* 4294967295 > 500 */ /* test "equal" */ - test_assert(cmp(&arr[0], &arr[3], ti) == 0); + test_assert(cmp(&arr[0], &arr[3], ti) == 0); /* 100000 == 100000 */ /* further test by sorting the array */ sort_array(ti, arr, 5); @@ -190,19 +189,24 @@ void Compare_u32(void) { void Compare_u64(void) { ecs_world_t *world = ecs_init(); - ecs_u64_t arr[] = {18446744073709551615ULL, 0, 1000, 18446744073709551615ULL, 42}; - ecs_u64_t expected[] = {0, 42, 1000, 18446744073709551615ULL, 18446744073709551615ULL}; + ecs_u64_t arr[] = {18446744073709551615ULL, 0, + 1000, 18446744073709551615ULL, 42}; + ecs_u64_t expected[] = {0, 42, 1000, + 18446744073709551615ULL, 18446744073709551615ULL}; const ecs_type_info_t* ti = ecs_get_type_info(world, ecs_id(ecs_u64_t)); /* test "less" */ - test_assert(cmp(&arr[1], &arr[0], ti) < 0); + /* 0 < 18446744073709551615 */ + test_assert(cmp(&arr[1], &arr[0], ti) < 0); /* test "greater" */ + /* 18446744073709551615 > 1000 */ test_assert(cmp(&arr[0], &arr[2], ti) > 0); /* test "equal" */ - test_assert(cmp(&arr[0], &arr[3], ti) == 0); + /* 18446744073709551615 == 18446744073709551615 */ + test_assert(cmp(&arr[0], &arr[3], ti) == 0); /* further test by sorting the array */ sort_array(ti, arr, 5); @@ -221,13 +225,13 @@ void Compare_uptr(void) { const ecs_type_info_t* ti = ecs_get_type_info(world, ecs_id(ecs_uptr_t)); /* test "less" */ - test_assert(cmp(&arr[0], &arr[1], ti) < 0); + test_assert(cmp(&arr[0], &arr[1], ti) < 0); /* 0x1234 < 0x5678 */ /* test "greater" */ - test_assert(cmp(&arr[3], &arr[1], ti) > 0); + test_assert(cmp(&arr[3], &arr[1], ti) > 0); /* 0x9ABC > 0x5678 */ /* test "equal" */ - test_assert(cmp(&arr[0], &arr[2], ti) == 0); + test_assert(cmp(&arr[0], &arr[2], ti) == 0); /* 0x1234 == 0x1234 */ /* further test by sorting the array */ sort_array(ti, arr, 4); @@ -246,13 +250,13 @@ void Compare_i8(void) { const ecs_type_info_t* ti = ecs_get_type_info(world, ecs_id(ecs_i8_t)); /* test "less" */ - test_assert(cmp(&arr[0], &arr[1], ti) < 0); + test_assert(cmp(&arr[0], &arr[1], ti) < 0); /* -128 < 127 */ /* test "greater" */ - test_assert(cmp(&arr[1], &arr[2], ti) > 0); + test_assert(cmp(&arr[1], &arr[2], ti) > 0); /* 127 > 0 */ /* test "equal" */ - test_assert(cmp(&arr[1], &arr[4], ti) == 0); + test_assert(cmp(&arr[1], &arr[4], ti) == 0); /* 127 == 127 */ /* further test by sorting the array */ sort_array(ti, arr, 6); @@ -271,13 +275,13 @@ void Compare_i16(void) { const ecs_type_info_t* ti = ecs_get_type_info(world, ecs_id(ecs_i16_t)); /* test "less" */ - test_assert(cmp(&arr[0], &arr[2], ti) < 0); + test_assert(cmp(&arr[0], &arr[1], ti) < 0); /* -32768 < 32767 */ /* test "greater" */ - test_assert(cmp(&arr[1], &arr[2], ti) > 0); + test_assert(cmp(&arr[1], &arr[2], ti) > 0); /* 32767 > 100 */ /* test "equal" */ - test_assert(cmp(&arr[1], &arr[4], ti) == 0); + test_assert(cmp(&arr[1], &arr[4], ti) == 0); /* 32767 == 32767 */ /* further test by sorting the array */ sort_array(ti, arr, 5); @@ -296,13 +300,13 @@ void Compare_i32(void) { const ecs_type_info_t* ti = ecs_get_type_info(world, ecs_id(ecs_i32_t)); /* test "less" */ - test_assert(cmp(&arr[0], &arr[1], ti) < 0); + test_assert(cmp(&arr[0], &arr[1], ti) < 0); /* -100000 < 50000 */ /* test "greater" */ - test_assert(cmp(&arr[1], &arr[2], ti) > 0); + test_assert(cmp(&arr[1], &arr[2], ti) > 0); /* 50000 > 0 */ /* test "equal" */ - test_assert(cmp(&arr[0], &arr[3], ti) == 0); + test_assert(cmp(&arr[0], &arr[3], ti) == 0); /* -100000 == -100000 */ /* further test by sorting the array */ sort_array(ti, arr, 5); @@ -315,19 +319,24 @@ void Compare_i32(void) { void Compare_i64(void) { ecs_world_t *world = ecs_init(); - ecs_i64_t arr[] = {-9223372036854775807LL, 9223372036854775807LL, 0, -1000, 9223372036854775807LL}; - ecs_i64_t expected[] = {-9223372036854775807LL, -1000, 0, 9223372036854775807LL, 9223372036854775807LL}; + ecs_i64_t arr[] = {-9223372036854775807LL, 9223372036854775807LL, + 0, -1000, 9223372036854775807LL}; + ecs_i64_t expected[] = {-9223372036854775807LL, -1000, 0, + 9223372036854775807LL, 9223372036854775807LL}; const ecs_type_info_t* ti = ecs_get_type_info(world, ecs_id(ecs_i64_t)); /* test "less" */ - test_assert(cmp(&arr[0], &arr[1], ti) < 0); + /* -9223372036854775807 < 9223372036854775807 */ + test_assert(cmp(&arr[0], &arr[1], ti) < 0); /* test "greater" */ - test_assert(cmp(&arr[1], &arr[2], ti) > 0); + /* 9223372036854775807 > 0 */ + test_assert(cmp(&arr[1], &arr[2], ti) > 0); /* test "equal" */ - test_assert(cmp(&arr[1], &arr[4], ti) == 0); + /* 9223372036854775807 == 9223372036854775807 */ + test_assert(cmp(&arr[1], &arr[4], ti) == 0); /* further test by sorting the array */ sort_array(ti, arr, 5); @@ -346,13 +355,13 @@ void Compare_iptr(void) { const ecs_type_info_t* ti = ecs_get_type_info(world, ecs_id(ecs_iptr_t)); /* test "less" */ - test_assert(cmp(&arr[0], &arr[1], ti) < 0); + test_assert(cmp(&arr[0], &arr[1], ti) < 0); /* -1000 < 500 */ /* test "greater" */ - test_assert(cmp(&arr[1], &arr[2], ti) > 0); + test_assert(cmp(&arr[1], &arr[2], ti) > 0); /* 500 > 0 */ /* test "equal" */ - test_assert(cmp(&arr[0], &arr[3], ti) == 0); + test_assert(cmp(&arr[0], &arr[3], ti) == 0); /* -1000 == -1000 */ /* further test by sorting the array */ sort_array(ti, arr, 4); @@ -371,13 +380,13 @@ void Compare_f32(void) { const ecs_type_info_t* ti = ecs_get_type_info(world, ecs_id(ecs_f32_t)); /* test "less" */ - test_assert(cmp(&arr[2], &arr[0], ti) < 0); + test_assert(cmp(&arr[2], &arr[0], ti) < 0); /* -1.0 < 3.14 */ /* test "greater" */ - test_assert(cmp(&arr[0], &arr[4], ti) > 0); + test_assert(cmp(&arr[0], &arr[4], ti) > 0); /* 3.14 > 0.0 */ /* test "equal" */ - test_assert(cmp(&arr[1], &arr[3], ti) == 0); + test_assert(cmp(&arr[1], &arr[3], ti) == 0); /* 2.71 == 2.71 */ /* further test by sorting the array */ sort_array(ti, arr, 5); @@ -396,13 +405,13 @@ void Compare_f64(void) { const ecs_type_info_t* ti = ecs_get_type_info(world, ecs_id(ecs_f64_t)); /* test "less" */ - test_assert(cmp(&arr[2], &arr[0], ti) < 0); + test_assert(cmp(&arr[2], &arr[0], ti) < 0); /* -1.0 < 3.14159 */ /* test "greater" */ - test_assert(cmp(&arr[0], &arr[4], ti) > 0); + test_assert(cmp(&arr[0], &arr[4], ti) > 0); /* 3.14159 > 0.0 */ /* test "equal" */ - test_assert(cmp(&arr[1], &arr[3], ti) == 0); + test_assert(cmp(&arr[1], &arr[3], ti) == 0); /* 2.71828 == 2.71828 */ /* further test by sorting the array */ sort_array(ti, arr, 5); @@ -421,13 +430,13 @@ void Compare_entity(void) { const ecs_type_info_t* ti = ecs_get_type_info(world, ecs_id(ecs_entity_t)); /* test "less" */ - test_assert(cmp(&arr[4], &arr[1], ti) < 0); + test_assert(cmp(&arr[4], &arr[1], ti) < 0); /* 0 < 42 */ /* test "greater" */ - test_assert(cmp(&arr[0], &arr[1], ti) > 0); + test_assert(cmp(&arr[0], &arr[1], ti) > 0); /* 1000 > 42 */ /* test "equal" */ - test_assert(cmp(&arr[0], &arr[2], ti) == 0); + test_assert(cmp(&arr[0], &arr[2], ti) == 0); /* 1000 == 1000 */ /* further test by sorting the array */ sort_array(ti, arr, 5); @@ -446,13 +455,13 @@ void Compare_id(void) { const ecs_type_info_t* ti = ecs_get_type_info(world, ecs_id(ecs_id_t)); /* test "less" */ - test_assert(cmp(&arr[4], &arr[1], ti) < 0); + test_assert(cmp(&arr[4], &arr[1], ti) < 0); /* 0 < 42 */ /* test "greater" */ - test_assert(cmp(&arr[0], &arr[1], ti) > 0); + test_assert(cmp(&arr[0], &arr[1], ti) > 0); /* 1000 > 42 */ /* test "equal" */ - test_assert(cmp(&arr[0], &arr[2], ti) == 0); + test_assert(cmp(&arr[0], &arr[2], ti) == 0); /* 1000 == 1000 */ /* further test by sorting the array */ sort_array(ti, arr, 5); @@ -462,7 +471,6 @@ void Compare_id(void) { ecs_fini(world); } - void Compare_string(void) { ecs_world_t *world = ecs_init(); From 4224713778ec0db0c9c753782a57133d361be6e2 Mon Sep 17 00:00:00 2001 From: Javier Peletier Date: Thu, 28 Nov 2024 16:36:14 +0100 Subject: [PATCH 07/23] Rename Compare.c to PrimitiveCompare.c --- test/meta/project.json | 2 +- .../src/{Compare.c => PrimitiveCompare.c} | 40 ++++----- test/meta/src/main.c | 84 +++++++++---------- 3 files changed, 63 insertions(+), 63 deletions(-) rename test/meta/src/{Compare.c => PrimitiveCompare.c} (95%) diff --git a/test/meta/project.json b/test/meta/project.json index ad0d4dab8..d8be91be3 100644 --- a/test/meta/project.json +++ b/test/meta/project.json @@ -1056,7 +1056,7 @@ "quantity_from_suspend_defer" ] },{ - "id": "Compare", + "id": "PrimitiveCompare", "testcases": [ "bool", "char", diff --git a/test/meta/src/Compare.c b/test/meta/src/PrimitiveCompare.c similarity index 95% rename from test/meta/src/Compare.c rename to test/meta/src/PrimitiveCompare.c index 68222405e..07f85df04 100644 --- a/test/meta/src/Compare.c +++ b/test/meta/src/PrimitiveCompare.c @@ -36,7 +36,7 @@ bool str_equals(const char* a, const char* b) { * Comparer is demonstrated to work if it successfully sorts an array of primitives. */ -void Compare_bool(void) { +void PrimitiveCompare_bool(void) { ecs_world_t *world = ecs_init(); ecs_bool_t arr[] = {true, false, true, false}; @@ -61,7 +61,7 @@ void Compare_bool(void) { ecs_fini(world); } -void Compare_char(void) { +void PrimitiveCompare_char(void) { ecs_world_t *world = ecs_init(); ecs_char_t arr[] = {'z', 'a', 'm', 'a', 'x', 'b'}; @@ -86,7 +86,7 @@ void Compare_char(void) { ecs_fini(world); } -void Compare_byte(void) { +void PrimitiveCompare_byte(void) { ecs_world_t *world = ecs_init(); ecs_byte_t arr[] = {0xFF, 0x01, 0x7F, 0x01, 0x00}; @@ -111,7 +111,7 @@ void Compare_byte(void) { ecs_fini(world); } -void Compare_u8(void) { +void PrimitiveCompare_u8(void) { ecs_world_t *world = ecs_init(); ecs_u8_t arr[] = {1, 79, 12, 3, 255, 79, 0, 14}; @@ -136,7 +136,7 @@ void Compare_u8(void) { ecs_fini(world); } -void Compare_u16(void) { +void PrimitiveCompare_u16(void) { ecs_world_t *world = ecs_init(); ecs_u16_t arr[] = {1024, 65535, 0, 1, 1024, 256}; @@ -161,7 +161,7 @@ void Compare_u16(void) { ecs_fini(world); } -void Compare_u32(void) { +void PrimitiveCompare_u32(void) { ecs_world_t *world = ecs_init(); ecs_u32_t arr[] = {100000, 500, 4294967295, 100000, 0}; @@ -186,7 +186,7 @@ void Compare_u32(void) { ecs_fini(world); } -void Compare_u64(void) { +void PrimitiveCompare_u64(void) { ecs_world_t *world = ecs_init(); ecs_u64_t arr[] = {18446744073709551615ULL, 0, @@ -216,7 +216,7 @@ void Compare_u64(void) { ecs_fini(world); } -void Compare_uptr(void) { +void PrimitiveCompare_uptr(void) { ecs_world_t *world = ecs_init(); ecs_uptr_t arr[] = {(ecs_uptr_t)0x1234, (ecs_uptr_t)0x5678, (ecs_uptr_t)0x1234, (ecs_uptr_t)0x9ABC}; @@ -241,7 +241,7 @@ void Compare_uptr(void) { ecs_fini(world); } -void Compare_i8(void) { +void PrimitiveCompare_i8(void) { ecs_world_t *world = ecs_init(); ecs_i8_t arr[] = {-128, 127, 0, -1, 127, 1}; @@ -266,7 +266,7 @@ void Compare_i8(void) { ecs_fini(world); } -void Compare_i16(void) { +void PrimitiveCompare_i16(void) { ecs_world_t *world = ecs_init(); ecs_i16_t arr[] = {-32768, 32767, 100, -100, 32767}; @@ -291,7 +291,7 @@ void Compare_i16(void) { ecs_fini(world); } -void Compare_i32(void) { +void PrimitiveCompare_i32(void) { ecs_world_t *world = ecs_init(); ecs_i32_t arr[] = {-100000, 50000, 0, -100000, 100000}; @@ -316,7 +316,7 @@ void Compare_i32(void) { ecs_fini(world); } -void Compare_i64(void) { +void PrimitiveCompare_i64(void) { ecs_world_t *world = ecs_init(); ecs_i64_t arr[] = {-9223372036854775807LL, 9223372036854775807LL, @@ -346,7 +346,7 @@ void Compare_i64(void) { ecs_fini(world); } -void Compare_iptr(void) { +void PrimitiveCompare_iptr(void) { ecs_world_t *world = ecs_init(); ecs_iptr_t arr[] = {(ecs_iptr_t)-1000, (ecs_iptr_t)500, (ecs_iptr_t)0, (ecs_iptr_t)-1000}; @@ -371,7 +371,7 @@ void Compare_iptr(void) { ecs_fini(world); } -void Compare_f32(void) { +void PrimitiveCompare_f32(void) { ecs_world_t *world = ecs_init(); ecs_f32_t arr[] = {3.14f, 2.71f, -1.0f, 2.71f, 0.0f}; @@ -396,7 +396,7 @@ void Compare_f32(void) { ecs_fini(world); } -void Compare_f64(void) { +void PrimitiveCompare_f64(void) { ecs_world_t *world = ecs_init(); ecs_f64_t arr[] = {3.14159, 2.71828, -1.0, 2.71828, 0.0}; @@ -421,7 +421,7 @@ void Compare_f64(void) { ecs_fini(world); } -void Compare_entity(void) { +void PrimitiveCompare_entity(void) { ecs_world_t *world = ecs_init(); ecs_entity_t arr[] = {1000, 42, 1000, 500, 0}; @@ -446,7 +446,7 @@ void Compare_entity(void) { ecs_fini(world); } -void Compare_id(void) { +void PrimitiveCompare_id(void) { ecs_world_t *world = ecs_init(); ecs_id_t arr[] = {1000, 42, 1000, 500, 0}; @@ -471,7 +471,7 @@ void Compare_id(void) { ecs_fini(world); } -void Compare_string(void) { +void PrimitiveCompare_string(void) { ecs_world_t *world = ecs_init(); const char* const_arr[] = {"world", "hello", NULL, "aa", "zz", "aa", "cc", "bb"}; @@ -512,7 +512,7 @@ void Compare_string(void) { ecs_fini(world); } -void Compare_const_string(void) { +void PrimitiveCompare_const_string(void) { ecs_world_t *world = ecs_init(); ecs_entity_t const_string = ecs_lookup(world, "flecs.core.const_string_t"); @@ -545,4 +545,4 @@ void Compare_const_string(void) { } ecs_fini(world); -} \ No newline at end of file +} diff --git a/test/meta/src/main.c b/test/meta/src/main.c index 4c1a4db3e..e30288793 100644 --- a/test/meta/src/main.c +++ b/test/meta/src/main.c @@ -1010,26 +1010,26 @@ void Misc_unit_from_suspend_defer(void); void Misc_unit_prefix_from_suspend_defer(void); void Misc_quantity_from_suspend_defer(void); -// Testsuite 'Compare' -void Compare_bool(void); -void Compare_char(void); -void Compare_byte(void); -void Compare_u8(void); -void Compare_u16(void); -void Compare_u32(void); -void Compare_u64(void); -void Compare_uptr(void); -void Compare_i8(void); -void Compare_i16(void); -void Compare_i32(void); -void Compare_i64(void); -void Compare_iptr(void); -void Compare_f32(void); -void Compare_f64(void); -void Compare_entity(void); -void Compare_id(void); -void Compare_string(void); -void Compare_const_string(void); +// Testsuite 'PrimitiveCompare' +void PrimitiveCompare_bool(void); +void PrimitiveCompare_char(void); +void PrimitiveCompare_byte(void); +void PrimitiveCompare_u8(void); +void PrimitiveCompare_u16(void); +void PrimitiveCompare_u32(void); +void PrimitiveCompare_u64(void); +void PrimitiveCompare_uptr(void); +void PrimitiveCompare_i8(void); +void PrimitiveCompare_i16(void); +void PrimitiveCompare_i32(void); +void PrimitiveCompare_i64(void); +void PrimitiveCompare_iptr(void); +void PrimitiveCompare_f32(void); +void PrimitiveCompare_f64(void); +void PrimitiveCompare_entity(void); +void PrimitiveCompare_id(void); +void PrimitiveCompare_string(void); +void PrimitiveCompare_const_string(void); bake_test_case PrimitiveTypes_testcases[] = { { @@ -4934,82 +4934,82 @@ bake_test_case Misc_testcases[] = { } }; -bake_test_case Compare_testcases[] = { +bake_test_case PrimitiveCompare_testcases[] = { { "bool", - Compare_bool + PrimitiveCompare_bool }, { "char", - Compare_char + PrimitiveCompare_char }, { "byte", - Compare_byte + PrimitiveCompare_byte }, { "u8", - Compare_u8 + PrimitiveCompare_u8 }, { "u16", - Compare_u16 + PrimitiveCompare_u16 }, { "u32", - Compare_u32 + PrimitiveCompare_u32 }, { "u64", - Compare_u64 + PrimitiveCompare_u64 }, { "uptr", - Compare_uptr + PrimitiveCompare_uptr }, { "i8", - Compare_i8 + PrimitiveCompare_i8 }, { "i16", - Compare_i16 + PrimitiveCompare_i16 }, { "i32", - Compare_i32 + PrimitiveCompare_i32 }, { "i64", - Compare_i64 + PrimitiveCompare_i64 }, { "iptr", - Compare_iptr + PrimitiveCompare_iptr }, { "f32", - Compare_f32 + PrimitiveCompare_f32 }, { "f64", - Compare_f64 + PrimitiveCompare_f64 }, { "entity", - Compare_entity + PrimitiveCompare_entity }, { "id", - Compare_id + PrimitiveCompare_id }, { "string", - Compare_string + PrimitiveCompare_string }, { "const_string", - Compare_const_string + PrimitiveCompare_const_string } }; @@ -5163,11 +5163,11 @@ static bake_test_suite suites[] = { Misc_testcases }, { - "Compare", + "PrimitiveCompare", NULL, NULL, 19, - Compare_testcases + PrimitiveCompare_testcases } }; From 9cc1f06f0766dcb715fe1e3b144f2dca3605a22f Mon Sep 17 00:00:00 2001 From: Javier Peletier Date: Thu, 28 Nov 2024 17:00:58 +0100 Subject: [PATCH 08/23] fix cpp compare tests --- distr/flecs.h | 6 ++++++ include/flecs/addons/cpp/component.hpp | 6 ++++++ test/cpp/src/ComponentLifecycle.cpp | 30 ++++++-------------------- test/meta/project.json | 5 +++++ test/meta/src/RttCompare.c | 7 ++++++ test/meta/src/main.c | 19 +++++++++++++++- 6 files changed, 48 insertions(+), 25 deletions(-) create mode 100644 test/meta/src/RttCompare.c diff --git a/distr/flecs.h b/distr/flecs.h index b1406a78e..1188ac602 100644 --- a/distr/flecs.h +++ b/distr/flecs.h @@ -26989,6 +26989,9 @@ void register_lifecycle_actions( ecs_type_hooks_t cl{}; cl.comp = compare(); + if(cl.comp == NULL) { + cl.flags |= ECS_TYPE_HOOK_COMP_ILLEGAL; + } ecs_set_hooks_id(world, component, &cl); } @@ -27014,6 +27017,9 @@ void register_lifecycle_actions( cl.move_dtor = move_dtor(cl.flags); cl.comp = compare(); + if(cl.comp == NULL) { + cl.flags |= ECS_TYPE_HOOK_COMP_ILLEGAL; + } ecs_set_hooks_id(world, component, &cl); diff --git a/include/flecs/addons/cpp/component.hpp b/include/flecs/addons/cpp/component.hpp index 751f9e78e..34b9c689a 100644 --- a/include/flecs/addons/cpp/component.hpp +++ b/include/flecs/addons/cpp/component.hpp @@ -102,6 +102,9 @@ void register_lifecycle_actions( ecs_type_hooks_t cl{}; cl.comp = compare(); + if(cl.comp == NULL) { + cl.flags |= ECS_TYPE_HOOK_COMP_ILLEGAL; + } ecs_set_hooks_id(world, component, &cl); } @@ -127,6 +130,9 @@ void register_lifecycle_actions( cl.move_dtor = move_dtor(cl.flags); cl.comp = compare(); + if(cl.comp == NULL) { + cl.flags |= ECS_TYPE_HOOK_COMP_ILLEGAL; + } ecs_set_hooks_id(world, component, &cl); diff --git a/test/cpp/src/ComponentLifecycle.cpp b/test/cpp/src/ComponentLifecycle.cpp index 2212dd0f8..4aca1f634 100644 --- a/test/cpp/src/ComponentLifecycle.cpp +++ b/test/cpp/src/ComponentLifecycle.cpp @@ -2422,18 +2422,10 @@ void ComponentLifecycle_compare_WithEqualsOnly(void) { auto component = ecs.component(); - WithEqualsOnly c[] = {5, 7, 7, 5}; + const ecs_type_hooks_t* hooks = ecs_get_hooks_id(ecs, component); - /* With only a == operator, we can only test equality */ - test_assert(compare(ecs, component, &c[1], &c[2]) == 0); - test_assert(compare(ecs, component, &c[1], &c[1]) == 0); - - /* If values are different, compare returns greater/less than 0 depending - * on memory location (position in the array) */ - test_assert(compare(ecs, component, &c[0], &c[1]) < 0); - test_assert(compare(ecs, component, &c[1], &c[0]) > 0); - test_assert(compare(ecs, component, &c[2], &c[3]) < 0); - test_assert(compare(ecs, component, &c[3], &c[2]) > 0); + /* can't compare if no < or > operators are defined */ + test_assert(hooks->flags & ECS_TYPE_HOOK_COMP_ILLEGAL); } void ComponentLifecycle_compare_WithoutOperators(void) { @@ -2441,18 +2433,8 @@ void ComponentLifecycle_compare_WithoutOperators(void) { auto component = ecs.component(); - WithoutOperators c[] = {5, 7, 7, 5}; + const ecs_type_hooks_t* hooks = ecs_get_hooks_id(ecs, component); - /* Without any operator defined, we can only test equality one element - * with itself */ - test_assert(compare(ecs, component, &c[1], &c[1]) == 0); - test_assert(compare(ecs, component, &c[3], &c[3]) == 0); - - /* Other comparisons return greater/less than 0 depending - * on memory location (position in the array) */ - test_assert(compare(ecs, component, &c[0], &c[1]) < 0); - test_assert(compare(ecs, component, &c[1], &c[0]) > 0); - test_assert(compare(ecs, component, &c[1], &c[2]) < 0); - test_assert(compare(ecs, component, &c[2], &c[3]) < 0); - test_assert(compare(ecs, component, &c[3], &c[2]) > 0); + /* can't compare if no operators are defined */ + test_assert(hooks->flags & ECS_TYPE_HOOK_COMP_ILLEGAL); } diff --git a/test/meta/project.json b/test/meta/project.json index d8be91be3..fd9cfe5b4 100644 --- a/test/meta/project.json +++ b/test/meta/project.json @@ -1078,6 +1078,11 @@ "string", "const_string" ] + },{ + "id": "RttCompare", + "testcases": [ + "test1" + ] }] } } diff --git a/test/meta/src/RttCompare.c b/test/meta/src/RttCompare.c new file mode 100644 index 000000000..840ed7bee --- /dev/null +++ b/test/meta/src/RttCompare.c @@ -0,0 +1,7 @@ +#include +#include +#include "flecs.h" +#include + + +void RttCompare_test1(void) {} \ No newline at end of file diff --git a/test/meta/src/main.c b/test/meta/src/main.c index e30288793..f021501eb 100644 --- a/test/meta/src/main.c +++ b/test/meta/src/main.c @@ -1031,6 +1031,9 @@ void PrimitiveCompare_id(void); void PrimitiveCompare_string(void); void PrimitiveCompare_const_string(void); +// Testsuite 'RttCompare' +void RttCompare_test1(void); + bake_test_case PrimitiveTypes_testcases[] = { { "bool", @@ -5013,6 +5016,13 @@ bake_test_case PrimitiveCompare_testcases[] = { } }; +bake_test_case RttCompare_testcases[] = { + { + "test1", + RttCompare_test1 + } +}; + static bake_test_suite suites[] = { { @@ -5168,9 +5178,16 @@ static bake_test_suite suites[] = { NULL, 19, PrimitiveCompare_testcases + }, + { + "RttCompare", + NULL, + NULL, + 1, + RttCompare_testcases } }; int main(int argc, char *argv[]) { - return bake_test_run("meta", argc, argv, suites, 22); + return bake_test_run("meta", argc, argv, suites, 23); } From d9d49da961d04161491e980a5884ccea7329b19c Mon Sep 17 00:00:00 2001 From: Javier Peletier Date: Thu, 28 Nov 2024 17:23:16 +0100 Subject: [PATCH 09/23] extend disable float == warning --- distr/flecs.c | 2 +- distr/flecs.h | 34 +++++++++---------- include/flecs/addons/cpp/lifecycle_traits.hpp | 34 +++++++++---------- src/world.c | 2 +- 4 files changed, 34 insertions(+), 38 deletions(-) diff --git a/distr/flecs.c b/distr/flecs.c index d3753a517..ce4374ef2 100644 --- a/distr/flecs.c +++ b/distr/flecs.c @@ -19119,7 +19119,7 @@ void ecs_set_hooks_id( if (h->move_ctor) ti->hooks.move_ctor = h->move_ctor; if (h->ctor_move_dtor) ti->hooks.ctor_move_dtor = h->ctor_move_dtor; if (h->move_dtor) ti->hooks.move_dtor = h->move_dtor; - if (h->comp || flags & ECS_TYPE_HOOK_COMP_ILLEGAL) ti->hooks.comp = h->comp; + if (h->comp) ti->hooks.comp = h->comp; if (h->on_add) ti->hooks.on_add = h->on_add; if (h->on_remove) ti->hooks.on_remove = h->on_remove; diff --git a/distr/flecs.h b/distr/flecs.h index 1188ac602..ae3b2f400 100644 --- a/distr/flecs.h +++ b/distr/flecs.h @@ -20517,6 +20517,16 @@ ecs_move_t move_dtor(ecs_flags32_t &) { template using void_t = void; +// These traits causes a "float comparison warning" in some compilers +// when `T` is float or double. +// Disable this warning with the following pragmas: +#if defined(__clang__) + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wfloat-equal" +#elif defined(__GNUC__) && !defined(__clang__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" +#endif // Trait to check for operator< template @@ -20539,16 +20549,6 @@ struct has_operator_greater() > std::d // Trait to check for operator== -// This trait causes a "float comparison warning" in some compilers -// when `T` is float or double. -// Disable this warning with the following pragmas: -#if defined(__clang__) - #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Wfloat-equal" -#elif defined(__GNUC__) && !defined(__clang__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wfloat-equal" -#endif template struct has_operator_equal : std::false_type {}; @@ -20558,14 +20558,6 @@ template struct has_operator_equal() == std::declval())>> : std::is_same() == std::declval()), bool> {}; - -// re-enable the warning: -#if defined(__clang__) - #pragma clang diagnostic pop -#elif defined(__GNUC__) && !defined(__clang__) - #pragma GCC diagnostic pop -#endif - // 1. Compare function if `<`, `>`, are defined template ::value && @@ -20647,6 +20639,12 @@ ecs_comp_t compare() { return NULL; } +// re-enable the float comparison warning: +#if defined(__clang__) + #pragma clang diagnostic pop +#elif defined(__GNUC__) && !defined(__clang__) + #pragma GCC diagnostic pop +#endif } // _ } // flecs diff --git a/include/flecs/addons/cpp/lifecycle_traits.hpp b/include/flecs/addons/cpp/lifecycle_traits.hpp index 2433fc561..2bfb882f0 100644 --- a/include/flecs/addons/cpp/lifecycle_traits.hpp +++ b/include/flecs/addons/cpp/lifecycle_traits.hpp @@ -353,6 +353,16 @@ ecs_move_t move_dtor(ecs_flags32_t &) { template using void_t = void; +// These traits causes a "float comparison warning" in some compilers +// when `T` is float or double. +// Disable this warning with the following pragmas: +#if defined(__clang__) + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wfloat-equal" +#elif defined(__GNUC__) && !defined(__clang__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" +#endif // Trait to check for operator< template @@ -375,16 +385,6 @@ struct has_operator_greater() > std::d // Trait to check for operator== -// This trait causes a "float comparison warning" in some compilers -// when `T` is float or double. -// Disable this warning with the following pragmas: -#if defined(__clang__) - #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Wfloat-equal" -#elif defined(__GNUC__) && !defined(__clang__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wfloat-equal" -#endif template struct has_operator_equal : std::false_type {}; @@ -394,14 +394,6 @@ template struct has_operator_equal() == std::declval())>> : std::is_same() == std::declval()), bool> {}; - -// re-enable the warning: -#if defined(__clang__) - #pragma clang diagnostic pop -#elif defined(__GNUC__) && !defined(__clang__) - #pragma GCC diagnostic pop -#endif - // 1. Compare function if `<`, `>`, are defined template ::value && @@ -483,6 +475,12 @@ ecs_comp_t compare() { return NULL; } +// re-enable the float comparison warning: +#if defined(__clang__) + #pragma clang diagnostic pop +#elif defined(__GNUC__) && !defined(__clang__) + #pragma GCC diagnostic pop +#endif } // _ } // flecs diff --git a/src/world.c b/src/world.c index 492617f77..9079ab495 100644 --- a/src/world.c +++ b/src/world.c @@ -1359,7 +1359,7 @@ void ecs_set_hooks_id( if (h->move_ctor) ti->hooks.move_ctor = h->move_ctor; if (h->ctor_move_dtor) ti->hooks.ctor_move_dtor = h->ctor_move_dtor; if (h->move_dtor) ti->hooks.move_dtor = h->move_dtor; - if (h->comp || flags & ECS_TYPE_HOOK_COMP_ILLEGAL) ti->hooks.comp = h->comp; + if (h->comp) ti->hooks.comp = h->comp; if (h->on_add) ti->hooks.on_add = h->on_add; if (h->on_remove) ti->hooks.on_remove = h->on_remove; From 00c941b8f819a9e1fbc066aeee118ee35c0c1faa Mon Sep 17 00:00:00 2001 From: Javier Peletier Date: Thu, 28 Nov 2024 21:43:13 +0100 Subject: [PATCH 10/23] more tests --- test/meta/include/meta.h | 2 + test/meta/project.json | 14 +- test/meta/src/RttCompare.c | 1181 +++++++++++++++++++++++++++++++++++- test/meta/src/main.c | 68 ++- 4 files changed, 1259 insertions(+), 6 deletions(-) diff --git a/test/meta/include/meta.h b/test/meta/include/meta.h index ad1befaa1..32cafc427 100644 --- a/test/meta/include/meta.h +++ b/test/meta/include/meta.h @@ -64,6 +64,8 @@ void install_test_abort(void); #define test_json(v1, v2) _test_json(v1, v2, #v1, #v2, __FILE__, __LINE__) void _test_json(const char* str1, const char *str2, const char* vstr1, const char *vstr2, const char *file, int line); +int cmp(const void *a, const void *b, const ecs_type_info_t* ti); + #ifdef __cplusplus } #endif diff --git a/test/meta/project.json b/test/meta/project.json index fd9cfe5b4..b3beef408 100644 --- a/test/meta/project.json +++ b/test/meta/project.json @@ -1081,7 +1081,19 @@ },{ "id": "RttCompare", "testcases": [ - "test1" + "struct_with_ints", + "struct_with_strings", + "struct_with_opaque", + "nested_struct_with_strings", + "struct_with_array_of_strings", + "struct_with_array_of_array_of_strings", + "struct_with_vector_of_ints", + "struct_with_vector_of_strings", + "nested_struct_with_vector_of_ints", + "nested_struct_with_vector_of_strings", + "array_of_ints", + "array_of_strings", + "array_of_struct_with_ints" ] }] } diff --git a/test/meta/src/RttCompare.c b/test/meta/src/RttCompare.c index 840ed7bee..b4d169c99 100644 --- a/test/meta/src/RttCompare.c +++ b/test/meta/src/RttCompare.c @@ -3,5 +3,1184 @@ #include "flecs.h" #include +int cmp_e(const ecs_world_t *world, ecs_entity_t component, ecs_entity_t ea, + ecs_entity_t eb) { + const ecs_type_info_t *ti = ecs_get_type_info(world, component); -void RttCompare_test1(void) {} \ No newline at end of file + const void *a = ecs_get_id(world, ea, component); + const void *b = ecs_get_id(world, eb, component); + + return ti->hooks.comp(a, b, ti); +} + +typedef struct OpaqueType { + int16_t value; +} OpaqueType; + +int opaque_type_compare(const void *a, const void *b, const ecs_type_info_t* ti) { + const OpaqueType* op_a = a; + const OpaqueType* op_b = b; + return op_a->value - op_b->value; +} + +ecs_entity_t define_opaque_type(ecs_world_t *world) { + ECS_COMPONENT(world, OpaqueType); + + ecs_type_hooks_t hooks = *ecs_get_hooks(world, OpaqueType); + hooks.comp = opaque_type_compare; + + ecs_set_hooks_id(world, ecs_id(OpaqueType), &hooks); + + ecs_entity_t descriptor = ecs_struct(world, { + .members = { + {.name = "value", .type = ecs_id(ecs_i16_t)}, + } + }); + + ecs_opaque(world, { + .entity = ecs_id(OpaqueType), + .type = {.as_type = descriptor} + }); + + return ecs_id(OpaqueType); +} + +void RttCompare_struct_with_ints(void) { + ecs_world_t *world = ecs_init(); + + typedef struct { + ecs_i32_t a; + ecs_i32_t b; + } StructWithInts; + + ecs_entity_t struct_with_ints = ecs_struct(world, { + .members = { + {"a", ecs_id(ecs_i32_t)}, + {"b", ecs_id(ecs_i32_t)}, + } + }); + + ecs_entity_t e1 = ecs_new(world); + ecs_entity_t e2 = ecs_new(world); + ecs_entity_t e3 = ecs_new(world); + + StructWithInts *ptr1 = ecs_ensure_id(world, e1, struct_with_ints); + ptr1->a = 10; + ptr1->b = 20; + + StructWithInts *ptr2 = ecs_ensure_id(world, e2, struct_with_ints); + ptr2->a = 10; + ptr2->b = 25; + + StructWithInts *ptr3 = ecs_ensure_id(world, e3, struct_with_ints); + ptr3->a = 10; + ptr3->b = 20; + + /* Test "less" */ + /* {10, 20} < {10, 25} */ + test_assert(cmp_e(world, struct_with_ints, e1, e2) < 0); + + /* Test "greater" */ + /* {10, 25} > {10, 20} */ + test_assert(cmp_e(world, struct_with_ints, e2, e1) > 0); + + /* Test "equal" */ + /* {10, 20} == {10, 20} */ + test_assert(cmp_e(world, struct_with_ints, e1, e3) == 0); + test_assert(cmp_e(world, struct_with_ints, e1, e1) == 0); + + ecs_delete(world, e1); + ecs_delete(world, e2); + ecs_delete(world, e3); + + ecs_fini(world); +} + +void RttCompare_struct_with_strings(void) { + ecs_world_t *world = ecs_init(); + + typedef struct { + ecs_string_t a; + ecs_i32_t b; + ecs_string_t c; + } StructWithStrings; + + ecs_entity_t struct_with_strings = + ecs_struct(world, {.members = { + {"a", ecs_id(ecs_string_t)}, + {"b", ecs_id(ecs_i32_t)}, + {"c", ecs_id(ecs_string_t)}, + }}); + ecs_add_id(world, struct_with_strings, EcsSparse); + + /* Create three entities with StructWithStrings component */ + ecs_entity_t e1 = ecs_new(world); + ecs_entity_t e2 = ecs_new(world); + ecs_entity_t e3 = ecs_new(world); + + StructWithStrings *ptr1 = ecs_ensure_id(world, e1, struct_with_strings); + ptr1->a = ecs_os_strdup("AA"); + ptr1->b = 20; + ptr1->c = ecs_os_strdup("CC"); + + StructWithStrings *ptr2 = ecs_ensure_id(world, e2, struct_with_strings); + ptr2->a = ecs_os_strdup("AA"); + ptr2->b = 25; + ptr2->c = ecs_os_strdup("BB"); + + StructWithStrings *ptr3 = ecs_ensure_id(world, e3, struct_with_strings); + ptr3->a = ecs_os_strdup("AA"); + ptr3->b = 20; + ptr3->c = ecs_os_strdup("CC"); + + /* Test "less" */ + /* {"AA", 20, "CC"} < {"AA", 25, "BB"} */ + test_assert(cmp_e(world, struct_with_strings, e1, e2) < 0); + + /* Test "greater" */ + /* {"AA", 25, "BB"} > {"AA", 20, "CC"} */ + test_assert(cmp_e(world, struct_with_strings, e2, e1) > 0); + + /* Test "equal" */ + /* {"AA", 20, "CC"} == {"AA", 20, "CC"} */ + test_assert(cmp_e(world, struct_with_strings, e1, e3) == 0); + test_assert(cmp_e(world, struct_with_strings, e1, e1) == 0); + + ecs_delete(world, e1); + ecs_delete(world, e2); + ecs_delete(world, e3); + + ecs_fini(world); +} + +void RttCompare_struct_with_opaque(void) { + ecs_world_t *world = ecs_init(); + + typedef struct { + OpaqueType a; + } StructWithOpaque; + + ecs_entity_t opaque = define_opaque_type(world); + + ecs_entity_t struct_with_opaque = ecs_struct(world, { + .members = { + {"a", opaque}, + } + }); + + /* Create three entities with StructWithOpaque component */ + ecs_entity_t e1 = ecs_new(world); + ecs_entity_t e2 = ecs_new(world); + ecs_entity_t e3 = ecs_new(world); + + StructWithOpaque *ptr1 = ecs_ensure_id(world, e1, struct_with_opaque); + ptr1->a.value = 10; + + StructWithOpaque *ptr2 = ecs_ensure_id(world, e2, struct_with_opaque); + ptr2->a.value = 15; + + StructWithOpaque *ptr3 = ecs_ensure_id(world, e3, struct_with_opaque); + ptr3->a.value = 10; + + /* Test "less" */ + /* {10} < {15} */ + test_assert(cmp_e(world, struct_with_opaque, e1, e2) < 0); + + /* Test "greater" */ + /* {15} > {10} */ + test_assert(cmp_e(world, struct_with_opaque, e2, e1) > 0); + + /* Test "equal" */ + /* {10} == {10} */ + test_assert(cmp_e(world, struct_with_opaque, e1, e3) == 0); + test_assert(cmp_e(world, struct_with_opaque, e1, e1) == 0); + + ecs_delete(world, e1); + ecs_delete(world, e2); + ecs_delete(world, e3); + + ecs_fini(world); +} + +void RttCompare_nested_struct_with_strings(void) { + ecs_world_t *world = ecs_init(); + + typedef struct { + ecs_string_t a; + ecs_i32_t b; + ecs_string_t c; + } StructWithStrings; + + ecs_entity_t struct_with_strings = ecs_struct(world, { + .members = { + {"a", ecs_id(ecs_string_t)}, + {"b", ecs_id(ecs_i32_t)}, + {"c", ecs_id(ecs_string_t)}, + } + }); + + typedef struct { + StructWithStrings a; + ecs_i32_t b; + StructWithStrings c; + } NestedStructWithStrings; + + ecs_entity_t nested_struct_with_strings = ecs_struct(world, { + .members = { + {"a", struct_with_strings}, + {"b", ecs_id(ecs_i32_t)}, + {"c", struct_with_strings}, + } + }); + + /* Create three entities with NestedStructWithStrings component */ + ecs_entity_t e1 = ecs_new(world); + ecs_entity_t e2 = ecs_new(world); + ecs_entity_t e3 = ecs_new(world); + + NestedStructWithStrings *ptr1 = ecs_ensure_id(world, e1, nested_struct_with_strings); + ptr1->a.a = ecs_os_strdup("AA"); + ptr1->a.b = 10; + ptr1->a.c = ecs_os_strdup("BB"); + ptr1->b = 20; + ptr1->c.a = ecs_os_strdup("CC"); + ptr1->c.b = 30; + ptr1->c.c = ecs_os_strdup("DD"); + + NestedStructWithStrings *ptr2 = ecs_ensure_id(world, e2, nested_struct_with_strings); + ptr2->a.a = ecs_os_strdup("AA"); + ptr2->a.b = 15; + ptr2->a.c = ecs_os_strdup("BB"); + ptr2->b = 25; + ptr2->c.a = ecs_os_strdup("CC"); + ptr2->c.b = 35; + ptr2->c.c = ecs_os_strdup("DD"); + + NestedStructWithStrings *ptr3 = ecs_ensure_id(world, e3, nested_struct_with_strings); + ptr3->a.a = ecs_os_strdup("AA"); + ptr3->a.b = 10; + ptr3->a.c = ecs_os_strdup("BB"); + ptr3->b = 20; + ptr3->c.a = ecs_os_strdup("CC"); + ptr3->c.b = 30; + ptr3->c.c = ecs_os_strdup("DD"); + + /* Test "less" */ + test_assert(cmp_e(world, nested_struct_with_strings, e1, e2) < 0); + + /* Test "greater" */ + test_assert(cmp_e(world, nested_struct_with_strings, e2, e1) > 0); + + /* Test "equal" */ + test_assert(cmp_e(world, nested_struct_with_strings, e1, e3) == 0); + test_assert(cmp_e(world, nested_struct_with_strings, e1, e1) == 0); + + ecs_delete(world, e1); + ecs_delete(world, e2); + ecs_delete(world, e3); + + ecs_fini(world); +} + +void RttCompare_struct_with_array_of_strings(void) { + ecs_world_t *world = ecs_init(); + + ecs_entity_t /* ecs_string_t[3] */ array_of_strings = + ecs_array(world, {.type = ecs_id(ecs_string_t), .count = 3}); + + typedef struct { + ecs_string_t a[3]; + ecs_i32_t b; + } StructWithArrayOfStrings; + + ecs_entity_t struct_with_array_of_strings = ecs_struct(world, { + .members = { + {"a", array_of_strings}, + {"b", ecs_id(ecs_i32_t)}, + } + }); + + /* Create five entities with StructWithArrayOfStrings component */ + ecs_entity_t e1 = ecs_new(world); + ecs_entity_t e2 = ecs_new(world); + ecs_entity_t e3 = ecs_new(world); + ecs_entity_t e4 = ecs_new(world); + ecs_entity_t e5 = ecs_new(world); + + StructWithArrayOfStrings *ptr1 = ecs_ensure_id(world, e1, + struct_with_array_of_strings); + ptr1->a[0] = ecs_os_strdup("AA"); + ptr1->a[1] = ecs_os_strdup("BB"); + ptr1->a[2] = ecs_os_strdup("CC"); + ptr1->b = 10; + + StructWithArrayOfStrings *ptr2 = ecs_ensure_id(world, e2, + struct_with_array_of_strings); + ptr2->a[0] = ecs_os_strdup("AA"); + ptr2->a[1] = ecs_os_strdup("BB"); + ptr2->a[2] = ecs_os_strdup("CC"); + ptr2->b = 20; + + StructWithArrayOfStrings *ptr3 = ecs_ensure_id(world, e3, + struct_with_array_of_strings); + ptr3->a[0] = ecs_os_strdup("AA"); + ptr3->a[1] = ecs_os_strdup("BB"); + ptr3->a[2] = ecs_os_strdup("CC"); + ptr3->b = 10; + + StructWithArrayOfStrings *ptr4 = ecs_ensure_id(world, e4, + struct_with_array_of_strings); + ptr4->a[0] = ecs_os_strdup("AA"); + ptr4->a[1] = ecs_os_strdup("ZZ"); + ptr4->a[2] = ecs_os_strdup("CC"); + ptr4->b = 10; + + StructWithArrayOfStrings *ptr5 = ecs_ensure_id(world, e5, + struct_with_array_of_strings); + ptr5->a[0] = ecs_os_strdup("AA"); + ptr5->a[1] = ecs_os_strdup("AA"); + ptr5->a[2] = ecs_os_strdup("DD"); + ptr5->b = 15; + + /* Test "less" */ + /* {"AA", "BB", "CC", 10} < {"AA", "BB", "CC", 20} */ + test_assert(cmp_e(world, struct_with_array_of_strings, e1, e2) < 0); + + /* {"AA", "BB", "CC", 10} < {"AA", "ZZ", "CC", 10} */ + test_assert(cmp_e(world, struct_with_array_of_strings, e1, e4) < 0); + + /* {"AA", "AA", "DD", 15} < {"AA", "BB", "CC", 20} */ + test_assert(cmp_e(world, struct_with_array_of_strings, e5, e2) < 0); + + /* Test "greater" */ + /* {"AA", "BB", "CC", 20} > {"AA", "BB", "CC", 10} */ + test_assert(cmp_e(world, struct_with_array_of_strings, e2, e1) > 0); + + /* {"AA", "ZZ", "CC", 10} > {"AA", "BB", "CC", 10} */ + test_assert(cmp_e(world, struct_with_array_of_strings, e4, e1) > 0); + + /* {"AA", "BB", "CC", 20} > {"AA", "AA", "DD", 15} */ + test_assert(cmp_e(world, struct_with_array_of_strings, e2, e5) > 0); + + /* Test "equal" */ + /* {"AA", "BB", "CC", 10} == {"AA", "BB", "CC", 10} */ + test_assert(cmp_e(world, struct_with_array_of_strings, e1, e3) == 0); + test_assert(cmp_e(world, struct_with_array_of_strings, e1, e1) == 0); + + ecs_delete(world, e1); + ecs_delete(world, e2); + ecs_delete(world, e3); + ecs_delete(world, e4); + ecs_delete(world, e5); + + ecs_fini(world); +} + +void RttCompare_struct_with_array_of_array_of_strings(void) { + ecs_world_t *world = ecs_init(); + + ecs_entity_t /* ecs_string_t[3] */ array_of_strings = + ecs_array(world, {.type = ecs_id(ecs_string_t), .count = 3}); + + ecs_entity_t /* ecs_string_t[3][3] */ array_of_array_of_strings = + ecs_array(world, {.type = array_of_strings, .count = 3}); + + typedef struct { + ecs_string_t a[3][3]; + ecs_string_t b; + } StructWithArrayOfArrayOfStrings; + + ecs_entity_t struct_with_array_of_array_of_strings = ecs_struct(world, { + .members = { + {"a", array_of_array_of_strings}, + {"b", ecs_id(ecs_string_t)}, + } + }); + + /* Create five entities with StructWithArrayOfArrayOfStrings component */ + ecs_entity_t e1 = ecs_new(world); + ecs_entity_t e2 = ecs_new(world); + ecs_entity_t e3 = ecs_new(world); + ecs_entity_t e4 = ecs_new(world); + ecs_entity_t e5 = ecs_new(world); + + StructWithArrayOfArrayOfStrings *ptr1 = ecs_ensure_id(world, e1, + struct_with_array_of_array_of_strings); + for (int i = 0; i < 3; i++) { + ptr1->a[i][0] = ecs_os_strdup("AA"); + ptr1->a[i][1] = ecs_os_strdup("BB"); + ptr1->a[i][2] = ecs_os_strdup("CC"); + } + ptr1->b = ecs_os_strdup("DD"); + + StructWithArrayOfArrayOfStrings *ptr2 = ecs_ensure_id(world, e2, + struct_with_array_of_array_of_strings); + for (int i = 0; i < 3; i++) { + ptr2->a[i][0] = ecs_os_strdup("AA"); + ptr2->a[i][1] = ecs_os_strdup("BB"); + ptr2->a[i][2] = ecs_os_strdup("CC"); + } + ptr2->b = ecs_os_strdup("EE"); + + StructWithArrayOfArrayOfStrings *ptr3 = ecs_ensure_id(world, e3, + struct_with_array_of_array_of_strings); + for (int i = 0; i < 3; i++) { + ptr3->a[i][0] = ecs_os_strdup("AA"); + ptr3->a[i][1] = ecs_os_strdup("BB"); + ptr3->a[i][2] = ecs_os_strdup("CC"); + } + ptr3->b = ecs_os_strdup("DD"); + + StructWithArrayOfArrayOfStrings *ptr4 = ecs_ensure_id(world, e4, + struct_with_array_of_array_of_strings); + for (int i = 0; i < 3; i++) { + ptr4->a[i][0] = ecs_os_strdup("AA"); + ptr4->a[i][1] = ecs_os_strdup("ZZ"); + ptr4->a[i][2] = ecs_os_strdup("CC"); + } + ptr4->b = ecs_os_strdup("DD"); + + StructWithArrayOfArrayOfStrings *ptr5 = ecs_ensure_id(world, e5, + struct_with_array_of_array_of_strings); + for (int i = 0; i < 3; i++) { + ptr5->a[i][0] = ecs_os_strdup("XX"); + ptr5->a[i][1] = ecs_os_strdup("BB"); + ptr5->a[i][2] = ecs_os_strdup("YY"); + } + ptr5->b = ecs_os_strdup("FF"); + + /* Test "less" */ + /* {"AA", "BB", "CC", "DD"} < {"AA", "BB", "CC", "EE"} */ + test_assert(cmp_e(world, struct_with_array_of_array_of_strings, e1, e2) < 0); + + /* {"AA", "BB", "CC", "DD"} < {"AA", "ZZ", "CC", "DD"} */ + test_assert(cmp_e(world, struct_with_array_of_array_of_strings, e1, e4) < 0); + + /* {"AA", "BB", "CC", "DD"} < {"XX", "BB", "YY", "FF"} */ + test_assert(cmp_e(world, struct_with_array_of_array_of_strings, e1, e5) < 0); + + /* Test "greater" */ + /* {"AA", "BB", "CC", "EE"} > {"AA", "BB", "CC", "DD"} */ + test_assert(cmp_e(world, struct_with_array_of_array_of_strings, e2, e1) > 0); + + /* {"AA", "ZZ", "CC", "DD"} > {"AA", "BB", "CC", "DD"} */ + test_assert(cmp_e(world, struct_with_array_of_array_of_strings, e4, e1) > 0); + + /* {"XX", "BB", "YY", "FF"} > {"AA", "BB", "CC", "DD"} */ + test_assert(cmp_e(world, struct_with_array_of_array_of_strings, e5, e1) > 0); + + /* Test "equal" */ + /* {"AA", "BB", "CC", "DD"} == {"AA", "BB", "CC", "DD"} */ + test_assert(cmp_e(world, struct_with_array_of_array_of_strings, e1, e3) == 0); + test_assert(cmp_e(world, struct_with_array_of_array_of_strings, e1, e1) == 0); + + ecs_delete(world, e1); + ecs_delete(world, e2); + ecs_delete(world, e3); + ecs_delete(world, e4); + ecs_delete(world, e5); + + ecs_fini(world); +} + +void RttCompare_struct_with_vector_of_ints(void) { + ecs_world_t *world = ecs_init(); + + ecs_entity_t /* vector */ vector_of_ints = + ecs_vector(world, {.type = ecs_id(ecs_i32_t)}); + + typedef struct { + ecs_vec_t a; + } StructWithVectorOfInts; + + ecs_entity_t struct_with_vector_of_ints = ecs_struct(world, { + .members = { + {"a", vector_of_ints}, + } + }); + + /* Create four entities with StructWithVectorOfInts component */ + ecs_entity_t e1 = ecs_new(world); + ecs_entity_t e2 = ecs_new(world); + ecs_entity_t e3 = ecs_new(world); + ecs_entity_t e4 = ecs_new(world); + + StructWithVectorOfInts *ptr1 = ecs_ensure_id(world, e1, struct_with_vector_of_ints); + ecs_vec_set_count(NULL, &ptr1->a, sizeof(ecs_i32_t), 3); + ecs_i32_t *v1 = ecs_vec_first(&ptr1->a); + v1[0] = 10; + v1[1] = 20; + v1[2] = 30; + + StructWithVectorOfInts *ptr2 = ecs_ensure_id(world, e2, struct_with_vector_of_ints); + ecs_vec_set_count(NULL, &ptr2->a, sizeof(ecs_i32_t), 3); + ecs_i32_t *v2 = ecs_vec_first(&ptr2->a); + v2[0] = 15; + v2[1] = 25; + v2[2] = 35; + + StructWithVectorOfInts *ptr3 = ecs_ensure_id(world, e3, struct_with_vector_of_ints); + ecs_vec_set_count(NULL, &ptr3->a, sizeof(ecs_i32_t), 3); + ecs_i32_t *v3 = ecs_vec_first(&ptr3->a); + v3[0] = 10; + v3[1] = 20; + v3[2] = 30; + + StructWithVectorOfInts *ptr4 = ecs_ensure_id(world, e4, struct_with_vector_of_ints); + ecs_vec_set_count(NULL, &ptr4->a, sizeof(ecs_i32_t), 2); + ecs_i32_t *v4 = ecs_vec_first(&ptr4->a); + v4[0] = 10; + v4[1] = 20; + + /* Test "less" */ + /* {10, 20, 30} < {15, 25, 35} */ + test_assert(cmp_e(world, struct_with_vector_of_ints, e1, e2) < 0); + + /* {10, 20} < {10, 20, 30} (because fewer elements) */ + test_assert(cmp_e(world, struct_with_vector_of_ints, e4, e1) < 0); + + /* Test "greater" */ + /* {15, 25, 35} > {10, 20, 30} */ + test_assert(cmp_e(world, struct_with_vector_of_ints, e2, e1) > 0); + + /* {10, 20, 30} > {10, 20} (because more elements) */ + test_assert(cmp_e(world, struct_with_vector_of_ints, e1, e4) > 0); + + /* Test "equal" */ + /* {10, 20, 30} == {10, 20, 30} */ + test_assert(cmp_e(world, struct_with_vector_of_ints, e1, e3) == 0); + test_assert(cmp_e(world, struct_with_vector_of_ints, e1, e1) == 0); + + ecs_delete(world, e1); + ecs_delete(world, e2); + ecs_delete(world, e3); + ecs_delete(world, e4); + + ecs_fini(world); +} + +void RttCompare_struct_with_vector_of_strings(void) { + ecs_world_t *world = ecs_init(); + + ecs_entity_t /* vector */ vector_of_strings = + ecs_vector(world, {.type = ecs_id(ecs_string_t)}); + + typedef struct { + ecs_vec_t a; + } StructWithVectorOfStrings; + + ecs_entity_t struct_with_vector_of_strings = ecs_struct(world, { + .members = { + {"a", vector_of_strings}, + } + }); + + /* Create four entities with StructWithVectorOfStrings component */ + ecs_entity_t e1 = ecs_new(world); + ecs_entity_t e2 = ecs_new(world); + ecs_entity_t e3 = ecs_new(world); + ecs_entity_t e4 = ecs_new(world); + + StructWithVectorOfStrings *ptr1 = ecs_ensure_id(world, e1, struct_with_vector_of_strings); + ecs_vec_set_count(NULL, &ptr1->a, sizeof(ecs_string_t), 3); + ecs_string_t *va1 = ecs_vec_first(&ptr1->a); + va1[0] = ecs_os_strdup("AA"); + va1[1] = ecs_os_strdup("BB"); + va1[2] = ecs_os_strdup("CC"); + + StructWithVectorOfStrings *ptr2 = ecs_ensure_id(world, e2, struct_with_vector_of_strings); + ecs_vec_set_count(NULL, &ptr2->a, sizeof(ecs_string_t), 3); + ecs_string_t *va2 = ecs_vec_first(&ptr2->a); + va2[0] = ecs_os_strdup("AA"); + va2[1] = ecs_os_strdup("BB"); + va2[2] = ecs_os_strdup("DD"); + + StructWithVectorOfStrings *ptr3 = ecs_ensure_id(world, e3, struct_with_vector_of_strings); + ecs_vec_set_count(NULL, &ptr3->a, sizeof(ecs_string_t), 3); + ecs_string_t *va3 = ecs_vec_first(&ptr3->a); + va3[0] = ecs_os_strdup("AA"); + va3[1] = ecs_os_strdup("BB"); + va3[2] = ecs_os_strdup("CC"); + + StructWithVectorOfStrings *ptr4 = ecs_ensure_id(world, e4, struct_with_vector_of_strings); + ecs_vec_set_count(NULL, &ptr4->a, sizeof(ecs_string_t), 2); + ecs_string_t *va4 = ecs_vec_first(&ptr4->a); + va4[0] = ecs_os_strdup("AA"); + va4[1] = ecs_os_strdup("BB"); + + /* Test "less" */ + /* {"AA", "BB", "CC"} < {"AA", "BB", "DD"} */ + test_assert(cmp_e(world, struct_with_vector_of_strings, e1, e2) < 0); + + /* {"AA", "BB"} < {"AA", "BB", "CC"} (because fewer elements) */ + test_assert(cmp_e(world, struct_with_vector_of_strings, e4, e1) < 0); + + /* Test "greater" */ + /* {"AA", "BB", "DD"} > {"AA", "BB", "CC"} */ + test_assert(cmp_e(world, struct_with_vector_of_strings, e2, e1) > 0); + + /* {"AA", "BB", "CC"} > {"AA", "BB"} (because more elements) */ + test_assert(cmp_e(world, struct_with_vector_of_strings, e1, e4) > 0); + + /* Test "equal" */ + /* {"AA", "BB", "CC"} == {"AA", "BB", "CC"} */ + test_assert(cmp_e(world, struct_with_vector_of_strings, e1, e3) == 0); + test_assert(cmp_e(world, struct_with_vector_of_strings, e1, e1) == 0); + + ecs_delete(world, e1); + ecs_delete(world, e2); + ecs_delete(world, e3); + ecs_delete(world, e4); + + ecs_fini(world); +} + +void RttCompare_nested_struct_with_vector_of_ints(void) { + ecs_world_t *world = ecs_init(); + + ecs_entity_t /* vector */ vector_of_ints = + ecs_vector(world, {.type = ecs_id(ecs_i32_t)}); + + typedef struct { + ecs_vec_t a; + ecs_i32_t b; + ecs_vec_t c; + } InnerStruct1; + + ecs_entity_t inner_struct_1 = ecs_struct(world, { + .members = { + {"a", vector_of_ints}, + {"b", ecs_id(ecs_i32_t)}, + {"c", vector_of_ints}, + } + }); + + typedef struct { + ecs_vec_t a; + ecs_i32_t b; + InnerStruct1 c; + } NestedStructWithVectorOfInts; + + ecs_entity_t nested_struct_with_vector_of_ints = ecs_struct(world, { + .members = { + {"a", vector_of_ints}, + {"b", ecs_id(ecs_i32_t)}, + {"c", inner_struct_1}, + } + }); + + /* Create five entities with NestedStructWithVectorOfInts component */ + ecs_entity_t e1 = ecs_new(world); + ecs_entity_t e2 = ecs_new(world); + ecs_entity_t e3 = ecs_new(world); + ecs_entity_t e4 = ecs_new(world); + ecs_entity_t e5 = ecs_new(world); + + /* Entity e1 */ + NestedStructWithVectorOfInts *ptr1 = ecs_ensure_id(world, e1, + nested_struct_with_vector_of_ints); + ecs_vec_set_count(NULL, &ptr1->a, sizeof(ecs_i32_t), 3); + ecs_i32_t *va1 = ecs_vec_first(&ptr1->a); + va1[0] = 1; + va1[1] = 2; + va1[2] = 3; + ptr1->b = 10; + + ecs_vec_set_count(NULL, &ptr1->c.a, sizeof(ecs_i32_t), 2); + ecs_i32_t *vca1 = ecs_vec_first(&ptr1->c.a); + vca1[0] = 4; + vca1[1] = 5; + ptr1->c.b = 15; + + ecs_vec_set_count(NULL, &ptr1->c.c, sizeof(ecs_i32_t), 1); + ecs_i32_t *vcc1 = ecs_vec_first(&ptr1->c.c); + vcc1[0] = 6; + + /* Entity e2 */ + NestedStructWithVectorOfInts *ptr2 = ecs_ensure_id(world, e2, + nested_struct_with_vector_of_ints); + ecs_vec_set_count(NULL, &ptr2->a, sizeof(ecs_i32_t), 3); + ecs_i32_t *va2 = ecs_vec_first(&ptr2->a); + va2[0] = 1; + va2[1] = 2; + va2[2] = 3; + ptr2->b = 20; + + ecs_vec_set_count(NULL, &ptr2->c.a, sizeof(ecs_i32_t), 2); + ecs_i32_t *vca2 = ecs_vec_first(&ptr2->c.a); + vca2[0] = 4; + vca2[1] = 5; + ptr2->c.b = 15; + + ecs_vec_set_count(NULL, &ptr2->c.c, sizeof(ecs_i32_t), 1); + ecs_i32_t *vcc2 = ecs_vec_first(&ptr2->c.c); + vcc2[0] = 6; + + /* Entity e3 */ + NestedStructWithVectorOfInts *ptr3 = ecs_ensure_id(world, e3, + nested_struct_with_vector_of_ints); + ecs_vec_set_count(NULL, &ptr3->a, sizeof(ecs_i32_t), 3); + ecs_i32_t *va3 = ecs_vec_first(&ptr3->a); + va3[0] = 1; + va3[1] = 2; + va3[2] = 3; + ptr3->b = 10; + + ecs_vec_set_count(NULL, &ptr3->c.a, sizeof(ecs_i32_t), 2); + ecs_i32_t *vca3 = ecs_vec_first(&ptr3->c.a); + vca3[0] = 4; + vca3[1] = 5; + ptr3->c.b = 15; + + ecs_vec_set_count(NULL, &ptr3->c.c, sizeof(ecs_i32_t), 1); + ecs_i32_t *vcc3 = ecs_vec_first(&ptr3->c.c); + vcc3[0] = 6; + + /* Entity e4 - different vector values */ + NestedStructWithVectorOfInts *ptr4 = ecs_ensure_id(world, e4, + nested_struct_with_vector_of_ints); + ecs_vec_set_count(NULL, &ptr4->a, sizeof(ecs_i32_t), 3); + ecs_i32_t *va4 = ecs_vec_first(&ptr4->a); + va4[0] = 3; + va4[1] = 2; + va4[2] = 1; + ptr4->b = 10; + + ecs_vec_set_count(NULL, &ptr4->c.a, sizeof(ecs_i32_t), 2); + ecs_i32_t *vca4 = ecs_vec_first(&ptr4->c.a); + vca4[0] = 4; + vca4[1] = 5; + ptr4->c.b = 15; + + ecs_vec_set_count(NULL, &ptr4->c.c, sizeof(ecs_i32_t), 1); + ecs_i32_t *vcc4 = ecs_vec_first(&ptr4->c.c); + vcc4[0] = 6; + + /* Entity e5 - different nested structure values */ + NestedStructWithVectorOfInts *ptr5 = ecs_ensure_id(world, e5, + nested_struct_with_vector_of_ints); + ecs_vec_set_count(NULL, &ptr5->a, sizeof(ecs_i32_t), 3); + ecs_i32_t *va5 = ecs_vec_first(&ptr5->a); + va5[0] = 1; + va5[1] = 2; + va5[2] = 3; + ptr5->b = 30; + + ecs_vec_set_count(NULL, &ptr5->c.a, sizeof(ecs_i32_t), 2); + ecs_i32_t *vca5 = ecs_vec_first(&ptr5->c.a); + vca5[0] = 7; + vca5[1] = 8; + ptr5->c.b = 25; + + ecs_vec_set_count(NULL, &ptr5->c.c, sizeof(ecs_i32_t), 1); + ecs_i32_t *vcc5 = ecs_vec_first(&ptr5->c.c); + vcc5[0] = 9; + + /* Test "less" */ + /* {1, 2, 3, 10, {4, 5, 15, 6}} < {1, 2, 3, 20, {4, 5, 15, 6}} */ + test_assert(cmp_e(world, nested_struct_with_vector_of_ints, e1, e2) < 0); + /* {1, 2, 3, 10, {4, 5, 15, 6}} < {3, 2, 1, 10, {4, 5, 15, 6}} */ + test_assert(cmp_e(world, nested_struct_with_vector_of_ints, e1, e4) < 0); + /* {1, 2, 3, 10, {4, 5, 15, 6}} < {1, 2, 3, 30, {7, 8, 25, 9}} */ + test_assert(cmp_e(world, nested_struct_with_vector_of_ints, e1, e5) < 0); + + /* Test "greater" */ + /* {1, 2, 3, 20, {4, 5, 15, 6}} > {1, 2, 3, 10, {4, 5, 15, 6}} */ + test_assert(cmp_e(world, nested_struct_with_vector_of_ints, e2, e1) > 0); + /* {3, 2, 1, 10, {4, 5, 15, 6}} > {1, 2, 3, 10, {4, 5, 15, 6}} */ + test_assert(cmp_e(world, nested_struct_with_vector_of_ints, e4, e1) > 0); + /* {1, 2, 3, 30, {7, 8, 25, 9}} > {1, 2, 3, 10, {4, 5, 15, 6}} */ + test_assert(cmp_e(world, nested_struct_with_vector_of_ints, e5, e1) > 0); + + /* Test "equal" */ + /* {1, 2, 3, 10, {4, 5, 15, 6}} == {1, 2, 3, 10, {4, 5, 15, 6}} */ + test_assert(cmp_e(world, nested_struct_with_vector_of_ints, e1, e3) == 0); + test_assert(cmp_e(world, nested_struct_with_vector_of_ints, e1, e1) == 0); + + ecs_delete(world, e1); + ecs_delete(world, e2); + ecs_delete(world, e3); + ecs_delete(world, e4); + ecs_delete(world, e5); + + ecs_fini(world); +} + +void RttCompare_nested_struct_with_vector_of_strings(void) { + ecs_world_t *world = ecs_init(); + + ecs_entity_t /* vector */ vector_of_strings = + ecs_vector(world, {.type = ecs_id(ecs_string_t)}); + + typedef struct { + ecs_vec_t a; /* vector */ + ecs_i32_t b; + ecs_vec_t c; /* vector */ + } InnerStruct2; + + ecs_entity_t inner_struct_2 = ecs_struct(world, { + .members = { + {"a", vector_of_strings}, + {"b", ecs_id(ecs_i32_t)}, + {"c", vector_of_strings}, + } + }); + + typedef struct { + ecs_vec_t a; /* vector */ + ecs_i32_t b; + InnerStruct2 c; + } NestedStructWithVectorOfStrings; + + ecs_entity_t nested_struct_with_vector_of_strings = ecs_struct(world, { + .members = { + {"a", vector_of_strings}, + {"b", ecs_id(ecs_i32_t)}, + {"c", inner_struct_2}, + } + }); + + /* Create five entities with NestedStructWithVectorOfStrings component */ + ecs_entity_t e1 = ecs_new(world); + ecs_entity_t e2 = ecs_new(world); + ecs_entity_t e3 = ecs_new(world); + ecs_entity_t e4 = ecs_new(world); + ecs_entity_t e5 = ecs_new(world); + + NestedStructWithVectorOfStrings *ptr1 = ecs_ensure_id(world, e1, + nested_struct_with_vector_of_strings); + ecs_vec_set_count(NULL, &ptr1->a, sizeof(ecs_string_t), 3); + ecs_string_t *a1 = ecs_vec_first(&ptr1->a); + a1[0] = ecs_os_strdup("AA"); + a1[1] = ecs_os_strdup("BB"); + a1[2] = ecs_os_strdup("CC"); + ptr1->b = 10; + ecs_vec_set_count(NULL, &ptr1->c.a, sizeof(ecs_string_t), 2); + ecs_string_t *c_a1 = ecs_vec_first(&ptr1->c.a); + c_a1[0] = ecs_os_strdup("XX"); + c_a1[1] = ecs_os_strdup("YY"); + ptr1->c.b = 5; + ecs_vec_set_count(NULL, &ptr1->c.c, sizeof(ecs_string_t), 1); + ecs_string_t *c_c1 = ecs_vec_first(&ptr1->c.c); + c_c1[0] = ecs_os_strdup("ZZ"); + + NestedStructWithVectorOfStrings *ptr2 = ecs_ensure_id(world, e2, + nested_struct_with_vector_of_strings); + ecs_vec_set_count(NULL, &ptr2->a, sizeof(ecs_string_t), 3); + ecs_string_t *a2 = ecs_vec_first(&ptr2->a); + a2[0] = ecs_os_strdup("AA"); + a2[1] = ecs_os_strdup("BB"); + a2[2] = ecs_os_strdup("CC"); + ptr2->b = 15; + ecs_vec_set_count(NULL, &ptr2->c.a, sizeof(ecs_string_t), 2); + ecs_string_t *c_a2 = ecs_vec_first(&ptr2->c.a); + c_a2[0] = ecs_os_strdup("XX"); + c_a2[1] = ecs_os_strdup("YY"); + ptr2->c.b = 5; + ecs_vec_set_count(NULL, &ptr2->c.c, sizeof(ecs_string_t), 1); + ecs_string_t *c_c2 = ecs_vec_first(&ptr2->c.c); + c_c2[0] = ecs_os_strdup("ZZ"); + + NestedStructWithVectorOfStrings *ptr3 = ecs_ensure_id(world, e3, + nested_struct_with_vector_of_strings); + ecs_vec_set_count(NULL, &ptr3->a, sizeof(ecs_string_t), 3); + ecs_string_t *a3 = ecs_vec_first(&ptr3->a); + a3[0] = ecs_os_strdup("AA"); + a3[1] = ecs_os_strdup("BB"); + a3[2] = ecs_os_strdup("CC"); + ptr3->b = 10; + ecs_vec_set_count(NULL, &ptr3->c.a, sizeof(ecs_string_t), 2); + ecs_string_t *c_a3 = ecs_vec_first(&ptr3->c.a); + c_a3[0] = ecs_os_strdup("XX"); + c_a3[1] = ecs_os_strdup("YY"); + ptr3->c.b = 5; + ecs_vec_set_count(NULL, &ptr3->c.c, sizeof(ecs_string_t), 1); + ecs_string_t *c_c3 = ecs_vec_first(&ptr3->c.c); + c_c3[0] = ecs_os_strdup("ZZ"); + + NestedStructWithVectorOfStrings *ptr4 = ecs_ensure_id(world, e4, + nested_struct_with_vector_of_strings); + ecs_vec_set_count(NULL, &ptr4->a, sizeof(ecs_string_t), 2); + ecs_string_t *a4 = ecs_vec_first(&ptr4->a); + a4[0] = ecs_os_strdup("AA"); + a4[1] = ecs_os_strdup("DD"); + ptr4->b = 20; + ecs_vec_set_count(NULL, &ptr4->c.a, sizeof(ecs_string_t), 3); + ecs_string_t *c_a4 = ecs_vec_first(&ptr4->c.a); + c_a4[0] = ecs_os_strdup("XX"); + c_a4[1] = ecs_os_strdup("YY"); + c_a4[2] = ecs_os_strdup("ZZ"); + ptr4->c.b = 10; + ecs_vec_set_count(NULL, &ptr4->c.c, sizeof(ecs_string_t), 2); + ecs_string_t *c_c4 = ecs_vec_first(&ptr4->c.c); + c_c4[0] = ecs_os_strdup("WW"); + c_c4[1] = ecs_os_strdup("QQ"); + + NestedStructWithVectorOfStrings *ptr5 = ecs_ensure_id(world, e5, + nested_struct_with_vector_of_strings); + ecs_vec_set_count(NULL, &ptr5->a, sizeof(ecs_string_t), 1); + ecs_string_t *a5 = ecs_vec_first(&ptr5->a); + a5[0] = ecs_os_strdup("EE"); + ptr5->b = 5; + ecs_vec_set_count(NULL, &ptr5->c.a, sizeof(ecs_string_t), 2); + ecs_string_t *c_a5 = ecs_vec_first(&ptr5->c.a); + c_a5[0] = ecs_os_strdup("MM"); + c_a5[1] = ecs_os_strdup("NN"); + ptr5->c.b = 8; + ecs_vec_set_count(NULL, &ptr5->c.c, sizeof(ecs_string_t), 3); + ecs_string_t *c_c5 = ecs_vec_first(&ptr5->c.c); + c_c5[0] = ecs_os_strdup("OO"); + c_c5[1] = ecs_os_strdup("PP"); + c_c5[2] = ecs_os_strdup("RR"); + + /* Test "less" */ + /* {{"AA", "BB", "CC"}, 10, {{"XX", "YY"}, 5, {"ZZ"}}} < */ + /* {{"AA", "BB", "CC"}, 15, {{"XX", "YY"}, 5, {"ZZ"}}} */ + test_assert(cmp_e(world, nested_struct_with_vector_of_strings, e1, e2) < 0); + + /* {{"EE"}, 5, {{"MM", "NN"}, 8, {"OO", "PP", "RR"}}} < */ + /* {{"AA", "BB", "CC"}, 15, {{"XX", "YY"}, 5, {"ZZ"}}} */ + test_assert(cmp_e(world, nested_struct_with_vector_of_strings, e5, e2) < 0); + + /* {{"AA", "DD"}, 20, {{"XX", "YY", "ZZ"}, 10, {"WW", "QQ"}}} > */ + /* {{"AA", "BB", "CC"}, 10, {{"XX", "YY"}, 5, {"ZZ"}}} */ + test_assert(cmp_e(world, nested_struct_with_vector_of_strings, e4, e1) < 0); + + /* Test "greater" */ + /* {{"AA", "BB", "CC"}, 15, {{"XX", "YY"}, 5, {"ZZ"}}} > */ + /* {{"AA", "BB", "CC"}, 10, {{"XX", "YY"}, 5, {"ZZ"}}} */ + test_assert(cmp_e(world, nested_struct_with_vector_of_strings, e2, e1) > 0); + + /* {{"AA", "BB", "CC"}, 10, {{"XX", "YY"}, 5, {"ZZ"}}} < */ + /* {{"AA", "DD"}, 20, {{"XX", "YY", "ZZ"}, 10, {"WW", "QQ"}}} */ + test_assert(cmp_e(world, nested_struct_with_vector_of_strings, e1, e4) > 0); + + + /* {{"AA", "BB", "CC"}, 15, {{"XX", "YY"}, 5, {"ZZ"}}} > */ + /* {{"EE"}, 5, {{"MM", "NN"}, 8, {"OO", "PP", "RR"}}} */ + test_assert(cmp_e(world, nested_struct_with_vector_of_strings, e2, e5) > 0); + + /* Test "equal" */ + /* {{"AA", "BB", "CC"}, 10, {{"XX", "YY"}, 5, {"ZZ"}}} == */ + /* {{"AA", "BB", "CC"}, 10, {{"XX", "YY"}, 5, {"ZZ"}}} */ + test_assert(cmp_e(world, nested_struct_with_vector_of_strings, e1, e3) == 0); + test_assert(cmp_e(world, nested_struct_with_vector_of_strings, e1, e1) == 0); + + ecs_delete(world, e1); + ecs_delete(world, e2); + ecs_delete(world, e3); + ecs_delete(world, e4); + ecs_delete(world, e5); + + ecs_fini(world); +} + +void RttCompare_array_of_ints(void) { + ecs_world_t *world = ecs_init(); + + ecs_entity_t /* ecs_i32_t[3] */ array_of_ints = + ecs_array(world, {.type = ecs_id(ecs_i32_t), .count = 3}); + + /* Create five entities, each with an array of integers component */ + ecs_entity_t e1 = ecs_new(world); + ecs_entity_t e2 = ecs_new(world); + ecs_entity_t e3 = ecs_new(world); + ecs_entity_t e4 = ecs_new(world); + ecs_entity_t e5 = ecs_new(world); + + ecs_i32_t *arr1 = ecs_ensure_id(world, e1, array_of_ints); + arr1[0] = 1; + arr1[1] = 2; + arr1[2] = 3; + + ecs_i32_t *arr2 = ecs_ensure_id(world, e2, array_of_ints); + arr2[0] = 1; + arr2[1] = 2; + arr2[2] = 4; + + ecs_i32_t *arr3 = ecs_ensure_id(world, e3, array_of_ints); + arr3[0] = 1; + arr3[1] = 2; + arr3[2] = 3; + + ecs_i32_t *arr4 = ecs_ensure_id(world, e4, array_of_ints); + arr4[0] = 0; + arr4[1] = 5; + arr4[2] = 6; + + ecs_i32_t *arr5 = ecs_ensure_id(world, e5, array_of_ints); + arr5[0] = 1; + arr5[1] = 2; + arr5[2] = 2; + + /* Test "less" */ + /* {1, 2, 3} < {1, 2, 4} */ + test_assert(cmp_e(world, array_of_ints, e1, e2) < 0); + + /* {0, 5, 6} < {1, 2, 3} */ + test_assert(cmp_e(world, array_of_ints, e4, e1) < 0); + + /* Test "greater" */ + /* {1, 2, 4} > {1, 2, 3} */ + test_assert(cmp_e(world, array_of_ints, e2, e1) > 0); + + /* {1, 2, 3} > {1, 2, 2} */ + test_assert(cmp_e(world, array_of_ints, e1, e5) > 0); + + /* Test "equal" */ + /* {1, 2, 3} == {1, 2, 3} */ + test_assert(cmp_e(world, array_of_ints, e1, e3) == 0); + test_assert(cmp_e(world, array_of_ints, e1, e1) == 0); + + ecs_delete(world, e1); + ecs_delete(world, e2); + ecs_delete(world, e3); + ecs_delete(world, e4); + ecs_delete(world, e5); + + ecs_fini(world); +} + +void RttCompare_array_of_strings(void) { + ecs_world_t *world = ecs_init(); + + ecs_entity_t /* ecs_string_t[3] */ array_of_strings = + ecs_array(world, {.type = ecs_id(ecs_string_t), .count = 3}); + + /* Create five entities, each with an array of strings component */ + ecs_entity_t e1 = ecs_new(world); + ecs_entity_t e2 = ecs_new(world); + ecs_entity_t e3 = ecs_new(world); + ecs_entity_t e4 = ecs_new(world); + ecs_entity_t e5 = ecs_new(world); + + ecs_string_t *arr1 = ecs_ensure_id(world, e1, array_of_strings); + arr1[0] = ecs_os_strdup("AA"); + arr1[1] = ecs_os_strdup("BB"); + arr1[2] = ecs_os_strdup("CC"); + + ecs_string_t *arr2 = ecs_ensure_id(world, e2, array_of_strings); + arr2[0] = ecs_os_strdup("AA"); + arr2[1] = ecs_os_strdup("BB"); + arr2[2] = ecs_os_strdup("DD"); + + ecs_string_t *arr3 = ecs_ensure_id(world, e3, array_of_strings); + arr3[0] = ecs_os_strdup("AA"); + arr3[1] = ecs_os_strdup("BB"); + arr3[2] = ecs_os_strdup("CC"); + + ecs_string_t *arr4 = ecs_ensure_id(world, e4, array_of_strings); + arr4[0] = ecs_os_strdup("ZZ"); + arr4[1] = ecs_os_strdup("YY"); + arr4[2] = ecs_os_strdup("XX"); + + ecs_string_t *arr5 = ecs_ensure_id(world, e5, array_of_strings); + arr5[0] = ecs_os_strdup("AA"); + arr5[1] = ecs_os_strdup("AB"); + arr5[2] = ecs_os_strdup("AC"); + + /* Test "less" */ + /* {"AA", "BB", "CC"} < {"AA", "BB", "DD"} */ + test_assert(cmp_e(world, array_of_strings, e1, e2) < 0); + + /* {"AA", "AB", "AC"} < {"AA", "BB", "CC"} */ + test_assert(cmp_e(world, array_of_strings, e5, e1) < 0); + + /* Test "greater" */ + /* {"ZZ", "YY", "XX"} > {"AA", "BB", "CC"} */ + test_assert(cmp_e(world, array_of_strings, e4, e1) > 0); + + /* {"AA", "BB", "DD"} > {"AA", "BB", "CC"} */ + test_assert(cmp_e(world, array_of_strings, e2, e1) > 0); + + /* Test "equal" */ + /* {"AA", "BB", "CC"} == {"AA", "BB", "CC"} */ + test_assert(cmp_e(world, array_of_strings, e1, e3) == 0); + test_assert(cmp_e(world, array_of_strings, e1, e1) == 0); + + ecs_delete(world, e1); + ecs_delete(world, e2); + ecs_delete(world, e3); + ecs_delete(world, e4); + ecs_delete(world, e5); + + ecs_fini(world); +} + +void RttCompare_array_of_struct_with_ints(void) { + ecs_world_t *world = ecs_init(); + + typedef struct { + ecs_i32_t a; + ecs_i32_t b; + } StructWithInts; + + ecs_entity_t struct_with_ints = ecs_struct(world, { + .members = { + {"a", ecs_id(ecs_i32_t)}, + {"b", ecs_id(ecs_i32_t)}, + } + }); + + ecs_entity_t /* StructWithInts[3] */ array_of_struct_with_ints = + ecs_array(world, {.type = struct_with_ints, .count = 3}); + + /* Create five entities with array of StructWithInts component */ + ecs_entity_t e1 = ecs_new(world); + ecs_entity_t e2 = ecs_new(world); + ecs_entity_t e3 = ecs_new(world); + ecs_entity_t e4 = ecs_new(world); + ecs_entity_t e5 = ecs_new(world); + + StructWithInts *arr1 = ecs_ensure_id(world, e1, array_of_struct_with_ints); + arr1[0].a = 1; arr1[0].b = 2; + arr1[1].a = 3; arr1[1].b = 4; + arr1[2].a = 5; arr1[2].b = 6; + + StructWithInts *arr2 = ecs_ensure_id(world, e2, array_of_struct_with_ints); + arr2[0].a = 1; arr2[0].b = 2; + arr2[1].a = 3; arr2[1].b = 4; + arr2[2].a = 5; arr2[2].b = 10; + + StructWithInts *arr3 = ecs_ensure_id(world, e3, array_of_struct_with_ints); + arr3[0].a = 1; arr3[0].b = 2; + arr3[1].a = 3; arr3[1].b = 4; + arr3[2].a = 5; arr3[2].b = 6; + + StructWithInts *arr4 = ecs_ensure_id(world, e4, array_of_struct_with_ints); + arr4[0].a = 0; arr4[0].b = 1; + arr4[1].a = 2; arr4[1].b = 3; + arr4[2].a = 4; arr4[2].b = 5; + + StructWithInts *arr5 = ecs_ensure_id(world, e5, array_of_struct_with_ints); + arr5[0].a = 7; arr5[0].b = 8; + arr5[1].a = 9; arr5[1].b = 10; + arr5[2].a = 11; arr5[2].b = 12; + + /* Test "less" */ + /* {{1, 2}, {3, 4}, {5, 6}} < {{1, 2}, {3, 4}, {5, 10}} */ + test_assert(cmp_e(world, array_of_struct_with_ints, e1, e2) < 0); + + /* {{0, 1}, {2, 3}, {4, 5}} < {{1, 2}, {3, 4}, {5, 6}} */ + test_assert(cmp_e(world, array_of_struct_with_ints, e4, e1) < 0); + + /* Test "greater" */ + /* {{1, 2}, {3, 4}, {5, 10}} > {{1, 2}, {3, 4}, {5, 6}} */ + test_assert(cmp_e(world, array_of_struct_with_ints, e2, e1) > 0); + + /* {{7, 8}, {9, 10}, {11, 12}} > {{1, 2}, {3, 4}, {5, 6}} */ + test_assert(cmp_e(world, array_of_struct_with_ints, e5, e1) > 0); + + /* Test "equal" */ + /* {{1, 2}, {3, 4}, {5, 6}} == {{1, 2}, {3, 4}, {5, 6}} */ + test_assert(cmp_e(world, array_of_struct_with_ints, e1, e3) == 0); + test_assert(cmp_e(world, array_of_struct_with_ints, e1, e1) == 0); + + ecs_delete(world, e1); + ecs_delete(world, e2); + ecs_delete(world, e3); + ecs_delete(world, e4); + ecs_delete(world, e5); + + ecs_fini(world); +} diff --git a/test/meta/src/main.c b/test/meta/src/main.c index f021501eb..a559d417b 100644 --- a/test/meta/src/main.c +++ b/test/meta/src/main.c @@ -1032,7 +1032,19 @@ void PrimitiveCompare_string(void); void PrimitiveCompare_const_string(void); // Testsuite 'RttCompare' -void RttCompare_test1(void); +void RttCompare_struct_with_ints(void); +void RttCompare_struct_with_strings(void); +void RttCompare_struct_with_opaque(void); +void RttCompare_nested_struct_with_strings(void); +void RttCompare_struct_with_array_of_strings(void); +void RttCompare_struct_with_array_of_array_of_strings(void); +void RttCompare_struct_with_vector_of_ints(void); +void RttCompare_struct_with_vector_of_strings(void); +void RttCompare_nested_struct_with_vector_of_ints(void); +void RttCompare_nested_struct_with_vector_of_strings(void); +void RttCompare_array_of_ints(void); +void RttCompare_array_of_strings(void); +void RttCompare_array_of_struct_with_ints(void); bake_test_case PrimitiveTypes_testcases[] = { { @@ -5018,8 +5030,56 @@ bake_test_case PrimitiveCompare_testcases[] = { bake_test_case RttCompare_testcases[] = { { - "test1", - RttCompare_test1 + "struct_with_ints", + RttCompare_struct_with_ints + }, + { + "struct_with_strings", + RttCompare_struct_with_strings + }, + { + "struct_with_opaque", + RttCompare_struct_with_opaque + }, + { + "nested_struct_with_strings", + RttCompare_nested_struct_with_strings + }, + { + "struct_with_array_of_strings", + RttCompare_struct_with_array_of_strings + }, + { + "struct_with_array_of_array_of_strings", + RttCompare_struct_with_array_of_array_of_strings + }, + { + "struct_with_vector_of_ints", + RttCompare_struct_with_vector_of_ints + }, + { + "struct_with_vector_of_strings", + RttCompare_struct_with_vector_of_strings + }, + { + "nested_struct_with_vector_of_ints", + RttCompare_nested_struct_with_vector_of_ints + }, + { + "nested_struct_with_vector_of_strings", + RttCompare_nested_struct_with_vector_of_strings + }, + { + "array_of_ints", + RttCompare_array_of_ints + }, + { + "array_of_strings", + RttCompare_array_of_strings + }, + { + "array_of_struct_with_ints", + RttCompare_array_of_struct_with_ints } }; @@ -5183,7 +5243,7 @@ static bake_test_suite suites[] = { "RttCompare", NULL, NULL, - 1, + 13, RttCompare_testcases } }; From ba83f9bc88052ee3625c2e78bc5efc7975f2820e Mon Sep 17 00:00:00 2001 From: Javier Peletier Date: Thu, 28 Nov 2024 23:55:50 +0100 Subject: [PATCH 11/23] Finish tests --- src/addons/meta/rtt_lifecycle.c | 14 +- test/cpp/src/ComponentLifecycle.cpp | 93 ++- test/cpp/src/main.cpp | 2 +- test/meta/project.json | 18 +- test/meta/src/RttCompare.c | 1141 +++++++++++++++++++++++++++ test/meta/src/RuntimeTypes.c | 93 ++- test/meta/src/main.c | 84 +- 7 files changed, 1391 insertions(+), 54 deletions(-) diff --git a/src/addons/meta/rtt_lifecycle.c b/src/addons/meta/rtt_lifecycle.c index 5cb3429ea..3869a6a21 100644 --- a/src/addons/meta/rtt_lifecycle.c +++ b/src/addons/meta/rtt_lifecycle.c @@ -284,16 +284,16 @@ ecs_rtt_struct_ctx_t * flecs_rtt_configure_struct_hooks( ecs_vec_init_t(NULL, &rtt_ctx->vcomp, ecs_rtt_call_data_t, 0); hooks.lifecycle_ctx = rtt_ctx; hooks.lifecycle_ctx_free = flecs_rtt_free_lifecycle_struct_ctx; - - hooks.ctor = ctor; - hooks.dtor = dtor; - hooks.move = move; - hooks.copy = copy; - hooks.comp = comp; } else { hooks.lifecycle_ctx = NULL; hooks.lifecycle_ctx_free = flecs_rtt_free_lifecycle_nop; - } + } + + hooks.ctor = ctor; + hooks.dtor = dtor; + hooks.move = move; + hooks.copy = copy; + hooks.comp = comp; hooks.flags = flags; hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; diff --git a/test/cpp/src/ComponentLifecycle.cpp b/test/cpp/src/ComponentLifecycle.cpp index 4aca1f634..29f46e8f6 100644 --- a/test/cpp/src/ComponentLifecycle.cpp +++ b/test/cpp/src/ComponentLifecycle.cpp @@ -2279,10 +2279,6 @@ void ComponentLifecycle_set_multiple_hooks(void) { ecs.release(); /* destroys world */ test_int(removes, 2); /* two instances of `Pod` removed */ - -int compare(flecs::world& ecs, flecs::entity_t id, const void *a, const void *b) { - const ecs_type_info_t* ti = ecs_get_type_info(ecs, id); - return ti->hooks.comp(a, b, ti); } struct WithGreaterThan { @@ -2341,19 +2337,26 @@ struct WithoutOperators { int value; }; +int compare(flecs::world& ecs, flecs::entity_t id, const void *a, const void *b) { + const ecs_type_info_t* ti = ecs_get_type_info(ecs, id); + return ti->hooks.comp(a, b, ti); +} + void ComponentLifecycle_compare_WithGreaterThan(void) { flecs::world ecs; auto component = ecs.component(); - WithGreaterThan c[] = {5, 7, 7, 5}; + WithGreaterThan a = {1}; + WithGreaterThan b = {2}; + WithGreaterThan c = {1}; - test_assert(compare(ecs, component, &c[0], &c[1]) < 0); - test_assert(compare(ecs, component, &c[1], &c[0]) > 0); - test_assert(compare(ecs, component, &c[1], &c[2]) == 0); - test_assert(compare(ecs, component, &c[2], &c[3]) > 0); - test_assert(compare(ecs, component, &c[3], &c[2]) < 0); - test_assert(compare(ecs, component, &c[1], &c[1]) == 0); + test_assert(compare(ecs, component, &a, &b) < 0); + test_assert(compare(ecs, component, &b, &a) > 0); + test_assert(compare(ecs, component, &a, &c) == 0); + test_assert(compare(ecs, component, &b, &c) > 0); + test_assert(compare(ecs, component, &c, &b) < 0); + test_assert(compare(ecs, component, &b, &b) == 0); } void ComponentLifecycle_compare_WithLessThan(void) { @@ -2361,14 +2364,16 @@ void ComponentLifecycle_compare_WithLessThan(void) { auto component = ecs.component(); - WithLessThan c[] = {5, 7, 7, 5}; + WithLessThan a = {1}; + WithLessThan b = {2}; + WithLessThan c = {1}; - test_assert(compare(ecs, component, &c[0], &c[1]) < 0); - test_assert(compare(ecs, component, &c[1], &c[0]) > 0); - test_assert(compare(ecs, component, &c[1], &c[2]) == 0); - test_assert(compare(ecs, component, &c[2], &c[3]) > 0); - test_assert(compare(ecs, component, &c[3], &c[2]) < 0); - test_assert(compare(ecs, component, &c[1], &c[1]) == 0); + test_assert(compare(ecs, component, &a, &b) < 0); + test_assert(compare(ecs, component, &b, &a) > 0); + test_assert(compare(ecs, component, &a, &c) == 0); + test_assert(compare(ecs, component, &b, &c) > 0); + test_assert(compare(ecs, component, &c, &b) < 0); + test_assert(compare(ecs, component, &b, &b) == 0); } void ComponentLifecycle_compare_WithLessAndGreaterThan(void) { @@ -2376,30 +2381,33 @@ void ComponentLifecycle_compare_WithLessAndGreaterThan(void) { auto component = ecs.component(); - WithLessAndGreaterThan c[] = {5, 7, 7, 5}; + WithLessAndGreaterThan a = {1}; + WithLessAndGreaterThan b = {2}; + WithLessAndGreaterThan c = {1}; - test_assert(compare(ecs, component, &c[0], &c[1]) < 0); - test_assert(compare(ecs, component, &c[1], &c[0]) > 0); - test_assert(compare(ecs, component, &c[1], &c[2]) == 0); - test_assert(compare(ecs, component, &c[2], &c[3]) > 0); - test_assert(compare(ecs, component, &c[3], &c[2]) < 0); - test_assert(compare(ecs, component, &c[1], &c[1]) == 0); + test_assert(compare(ecs, component, &a, &b) < 0); + test_assert(compare(ecs, component, &b, &a) > 0); + test_assert(compare(ecs, component, &a, &c) == 0); + test_assert(compare(ecs, component, &b, &c) > 0); + test_assert(compare(ecs, component, &c, &b) < 0); + test_assert(compare(ecs, component, &b, &b) == 0); } - void ComponentLifecycle_compare_WithEqualsAndGreaterThan(void) { flecs::world ecs; auto component = ecs.component(); - WithEqualsAndGreaterThan c[] = {5, 7, 7, 5}; + WithEqualsAndGreaterThan a = {1}; + WithEqualsAndGreaterThan b = {2}; + WithEqualsAndGreaterThan c = {1}; - test_assert(compare(ecs, component, &c[0], &c[1]) < 0); - test_assert(compare(ecs, component, &c[1], &c[0]) > 0); - test_assert(compare(ecs, component, &c[1], &c[2]) == 0); - test_assert(compare(ecs, component, &c[2], &c[3]) > 0); - test_assert(compare(ecs, component, &c[3], &c[2]) < 0); - test_assert(compare(ecs, component, &c[1], &c[1]) == 0); + test_assert(compare(ecs, component, &a, &b) < 0); + test_assert(compare(ecs, component, &b, &a) > 0); + test_assert(compare(ecs, component, &a, &c) == 0); + test_assert(compare(ecs, component, &b, &c) > 0); + test_assert(compare(ecs, component, &c, &b) < 0); + test_assert(compare(ecs, component, &b, &b) == 0); } void ComponentLifecycle_compare_WithEqualsAndLessThan(void) { @@ -2407,14 +2415,16 @@ void ComponentLifecycle_compare_WithEqualsAndLessThan(void) { auto component = ecs.component(); - WithEqualsAndLessThan c[] = {5, 7, 7, 5}; + WithEqualsAndLessThan a = {1}; + WithEqualsAndLessThan b = {2}; + WithEqualsAndLessThan c = {1}; - test_assert(compare(ecs, component, &c[0], &c[1]) < 0); - test_assert(compare(ecs, component, &c[1], &c[0]) > 0); - test_assert(compare(ecs, component, &c[1], &c[2]) == 0); - test_assert(compare(ecs, component, &c[2], &c[3]) > 0); - test_assert(compare(ecs, component, &c[3], &c[2]) < 0); - test_assert(compare(ecs, component, &c[1], &c[1]) == 0); + test_assert(compare(ecs, component, &a, &b) < 0); + test_assert(compare(ecs, component, &b, &a) > 0); + test_assert(compare(ecs, component, &a, &c) == 0); + test_assert(compare(ecs, component, &b, &c) > 0); + test_assert(compare(ecs, component, &c, &b) < 0); + test_assert(compare(ecs, component, &b, &b) == 0); } void ComponentLifecycle_compare_WithEqualsOnly(void) { @@ -2435,6 +2445,7 @@ void ComponentLifecycle_compare_WithoutOperators(void) { const ecs_type_hooks_t* hooks = ecs_get_hooks_id(ecs, component); - /* can't compare if no operators are defined */ + /* can't compare if no operators are defined at all */ test_assert(hooks->flags & ECS_TYPE_HOOK_COMP_ILLEGAL); } + diff --git a/test/cpp/src/main.cpp b/test/cpp/src/main.cpp index 4458b5360..4bbdbcb81 100644 --- a/test/cpp/src/main.cpp +++ b/test/cpp/src/main.cpp @@ -5382,7 +5382,7 @@ bake_test_case ComponentLifecycle_testcases[] = { }, { "set_multiple_hooks", - ComponentLifecycle_set_multiple_hooks, + ComponentLifecycle_set_multiple_hooks }, { "compare_WithGreaterThan", diff --git a/test/meta/project.json b/test/meta/project.json index b3beef408..e57e5f821 100644 --- a/test/meta/project.json +++ b/test/meta/project.json @@ -107,6 +107,7 @@ "move_illegal", "copy", "copy_illegal", + "comp_illegal", "trivial_array", "array_ctor", "array_ctor_illegal", @@ -116,8 +117,10 @@ "array_move_illegal", "array_copy", "array_copy_illegal", + "array_comp_illegal", "vector_lifecycle", "vector_lifecycle_trivial_type", + "vector_comp_illegal", "opaque", "struct_with_ints", "struct_with_strings", @@ -1093,7 +1096,20 @@ "nested_struct_with_vector_of_strings", "array_of_ints", "array_of_strings", - "array_of_struct_with_ints" + "array_of_struct_with_ints", + "array_of_struct_with_strings", + "array_of_struct_with_opaques", + "array_of_array_of_strings", + "array_of_array_of_struct_with_strings", + "array_of_vectors_of_ints", + "array_of_vectors_of_strings", + "array_of_opaque", + "vector_of_ints", + "vector_of_strings", + "vector_of_struct_with_ints", + "vector_of_struct_with_strings", + "vector_of_arrays_of_strings", + "vector_of_opaque" ] }] } diff --git a/test/meta/src/RttCompare.c b/test/meta/src/RttCompare.c index b4d169c99..57bfcaac0 100644 --- a/test/meta/src/RttCompare.c +++ b/test/meta/src/RttCompare.c @@ -1184,3 +1184,1144 @@ void RttCompare_array_of_struct_with_ints(void) { ecs_fini(world); } + +void RttCompare_array_of_struct_with_strings(void) { + ecs_world_t *world = ecs_init(); + + typedef struct { + ecs_string_t a; + ecs_i32_t b; + ecs_string_t c; + } StructWithStrings; + + ecs_entity_t struct_with_strings = ecs_struct(world, { + .members = { + {"a", ecs_id(ecs_string_t)}, + {"b", ecs_id(ecs_i32_t)}, + {"c", ecs_id(ecs_string_t)}, + } + }); + + ecs_entity_t /* StructWithStrings[3] */ array_of_struct_with_strings = + ecs_array(world, {.type = struct_with_strings, .count = 3}); + + typedef struct { + StructWithStrings items[3]; + } ArrayOfStructWithStrings; + + ecs_entity_t struct_array_entity = ecs_struct(world, { + .members = { + {"items", array_of_struct_with_strings}, + } + }); + + /* Create five entities with ArrayOfStructWithStrings component */ + ecs_entity_t e1 = ecs_new(world); + ecs_entity_t e2 = ecs_new(world); + ecs_entity_t e3 = ecs_new(world); + ecs_entity_t e4 = ecs_new(world); + ecs_entity_t e5 = ecs_new(world); + + /* Initialize e1 */ + ArrayOfStructWithStrings *ptr1 = ecs_ensure_id(world, e1, struct_array_entity); + ptr1->items[0].a = ecs_os_strdup("AA"); + ptr1->items[0].b = 10; + ptr1->items[0].c = ecs_os_strdup("BB"); + ptr1->items[1].a = ecs_os_strdup("CC"); + ptr1->items[1].b = 15; + ptr1->items[1].c = ecs_os_strdup("DD"); + ptr1->items[2].a = ecs_os_strdup("EE"); + ptr1->items[2].b = 20; + ptr1->items[2].c = ecs_os_strdup("FF"); + + /* Initialize e2 with different value in the second struct */ + ArrayOfStructWithStrings *ptr2 = ecs_ensure_id(world, e2, struct_array_entity); + ptr2->items[0].a = ecs_os_strdup("AA"); + ptr2->items[0].b = 10; + ptr2->items[0].c = ecs_os_strdup("BB"); + ptr2->items[1].a = ecs_os_strdup("CC"); + ptr2->items[1].b = 18; // Different value + ptr2->items[1].c = ecs_os_strdup("DD"); + ptr2->items[2].a = ecs_os_strdup("EE"); + ptr2->items[2].b = 20; + ptr2->items[2].c = ecs_os_strdup("FF"); + + /* Initialize e3 identical to e1 */ + ArrayOfStructWithStrings *ptr3 = ecs_ensure_id(world, e3, struct_array_entity); + ptr3->items[0].a = ecs_os_strdup("AA"); + ptr3->items[0].b = 10; + ptr3->items[0].c = ecs_os_strdup("BB"); + ptr3->items[1].a = ecs_os_strdup("CC"); + ptr3->items[1].b = 15; + ptr3->items[1].c = ecs_os_strdup("DD"); + ptr3->items[2].a = ecs_os_strdup("EE"); + ptr3->items[2].b = 20; + ptr3->items[2].c = ecs_os_strdup("FF"); + + /* Initialize e4 with completely different strings */ + ArrayOfStructWithStrings *ptr4 = ecs_ensure_id(world, e4, struct_array_entity); + ptr4->items[0].a = ecs_os_strdup("XX"); + ptr4->items[0].b = 5; + ptr4->items[0].c = ecs_os_strdup("YY"); + ptr4->items[1].a = ecs_os_strdup("ZZ"); + ptr4->items[1].b = 25; + ptr4->items[1].c = ecs_os_strdup("WW"); + ptr4->items[2].a = ecs_os_strdup("VV"); + ptr4->items[2].b = 30; + ptr4->items[2].c = ecs_os_strdup("UU"); + + /* Initialize e5 with mixture of similar and different values */ + ArrayOfStructWithStrings *ptr5 = ecs_ensure_id(world, e5, struct_array_entity); + ptr5->items[0].a = ecs_os_strdup("AA"); + ptr5->items[0].b = 10; + ptr5->items[0].c = ecs_os_strdup("GG"); // Different from e1 + ptr5->items[1].a = ecs_os_strdup("CC"); + ptr5->items[1].b = 15; + ptr5->items[1].c = ecs_os_strdup("HH"); // Different from e1 + ptr5->items[2].a = ecs_os_strdup("EE"); + ptr5->items[2].b = 20; + ptr5->items[2].c = ecs_os_strdup("FF"); + + /* Test "less" */ + test_assert(cmp_e(world, struct_array_entity, e1, e2) < 0);/*15 < 18 */ + test_assert(cmp_e(world, struct_array_entity, e5, e4) < 0);/*"AA" < "XX" */ + test_assert(cmp_e(world, struct_array_entity, e1, e4) < 0);/*"CC" < "ZZ" */ + + /* Test "greater" */ + /* e2 > e1 because ptr2->items[1].b (18) > ptr1->items[1].b (15) */ + test_assert(cmp_e(world, struct_array_entity, e2, e1) > 0);/* 18 > 15 */ + test_assert(cmp_e(world, struct_array_entity, e5, e1) > 0);/* "GG" > "BB"*/ + + /* e4 > e1 because */ + test_assert(cmp_e(world, struct_array_entity, e4, e1) > 0);/* "XX" > "AA"*/ + + /* Test "equal" */ + test_assert(cmp_e(world, struct_array_entity, e1, e3) == 0); + test_assert(cmp_e(world, struct_array_entity, e1, e1) == 0); + + ecs_delete(world, e1); + ecs_delete(world, e2); + ecs_delete(world, e3); + ecs_delete(world, e4); + ecs_delete(world, e5); + + ecs_fini(world); +} + +void RttCompare_array_of_struct_with_opaques(void) { + ecs_world_t *world = ecs_init(); + + ecs_entity_t opaque = define_opaque_type(world); + + typedef struct { + OpaqueType a; + } StructWithOpaque; + + ecs_entity_t struct_with_opaque = ecs_struct(world, { + .members = { + {"a", opaque}, + } + }); + + ecs_entity_t /* StructWithOpaque[3] */ array_of_struct_with_opaques = + ecs_array(world, {.type = struct_with_opaque, .count = 3}); + + /* Create three entities with array of StructWithOpaque component */ + ecs_entity_t e1 = ecs_new(world); + ecs_entity_t e2 = ecs_new(world); + ecs_entity_t e3 = ecs_new(world); + + StructWithOpaque *arr1 = ecs_ensure_id(world, e1, array_of_struct_with_opaques); + arr1[0].a.value = 5; + arr1[1].a.value = 10; + arr1[2].a.value = 15; + + StructWithOpaque *arr2 = ecs_ensure_id(world, e2, array_of_struct_with_opaques); + arr2[0].a.value = 5; + arr2[1].a.value = 15; + arr2[2].a.value = 20; + + StructWithOpaque *arr3 = ecs_ensure_id(world, e3, array_of_struct_with_opaques); + arr3[0].a.value = 5; + arr3[1].a.value = 10; + arr3[2].a.value = 15; + + /* Test "less" */ + /* {{5}, {10}, {15}} < {{5}, {15}, {20}} */ + test_assert(cmp_e(world, array_of_struct_with_opaques, e1, e2) < 0); + + /* Test "greater" */ + /* {{5}, {15}, {20}} > {{5}, {10}, {15}} */ + test_assert(cmp_e(world, array_of_struct_with_opaques, e2, e1) > 0); + + /* Test "equal" */ + /* {{5}, {10}, {15}} == {{5}, {10}, {15}} */ + test_assert(cmp_e(world, array_of_struct_with_opaques, e1, e3) == 0); + test_assert(cmp_e(world, array_of_struct_with_opaques, e1, e1) == 0); + + ecs_delete(world, e1); + ecs_delete(world, e2); + ecs_delete(world, e3); + + ecs_fini(world); +} + +void RttCompare_array_of_array_of_strings(void) { + ecs_world_t *world = ecs_init(); + + ecs_entity_t /* ecs_string_t[3] */ array_of_strings = + ecs_array(world, {.type = ecs_id(ecs_string_t), .count = 3}); + + ecs_entity_t /* ecs_string_t[3][3] */ array_of_array_of_strings = + ecs_array(world, {.type = array_of_strings, .count = 3}); + + /* Create multiple entities with array of arrays of strings component */ + ecs_entity_t e1 = ecs_new(world); + ecs_entity_t e2 = ecs_new(world); + ecs_entity_t e3 = ecs_new(world); + ecs_entity_t e4 = ecs_new(world); + + ecs_string_t (*arr1)[3] = ecs_ensure_id(world, e1, array_of_array_of_strings); + arr1[0][0] = ecs_os_strdup("AA"); + arr1[0][1] = ecs_os_strdup("BB"); + arr1[0][2] = ecs_os_strdup("CC"); + arr1[1][0] = ecs_os_strdup("AA"); + arr1[1][1] = ecs_os_strdup("BB"); + arr1[1][2] = ecs_os_strdup("CC"); + arr1[2][0] = ecs_os_strdup("AA"); + arr1[2][1] = ecs_os_strdup("BB"); + arr1[2][2] = ecs_os_strdup("CC"); + + ecs_string_t (*arr2)[3] = ecs_ensure_id(world, e2, array_of_array_of_strings); + arr2[0][0] = ecs_os_strdup("AA"); + arr2[0][1] = ecs_os_strdup("BB"); + arr2[0][2] = ecs_os_strdup("CC"); + arr2[1][0] = ecs_os_strdup("AA"); + arr2[1][1] = ecs_os_strdup("ZZ"); + arr2[1][2] = ecs_os_strdup("CC"); + arr2[2][0] = ecs_os_strdup("AA"); + arr2[2][1] = ecs_os_strdup("BB"); + arr2[2][2] = ecs_os_strdup("CC"); + + ecs_string_t (*arr3)[3] = ecs_ensure_id(world, e3, array_of_array_of_strings); + arr3[0][0] = ecs_os_strdup("AA"); + arr3[0][1] = ecs_os_strdup("BB"); + arr3[0][2] = ecs_os_strdup("CC"); + arr3[1][0] = ecs_os_strdup("AA"); + arr3[1][1] = ecs_os_strdup("BB"); + arr3[1][2] = ecs_os_strdup("CC"); + arr3[2][0] = ecs_os_strdup("AA"); + arr3[2][1] = ecs_os_strdup("BB"); + arr3[2][2] = ecs_os_strdup("CC"); + + ecs_string_t (*arr4)[3] = ecs_ensure_id(world, e4, array_of_array_of_strings); + arr4[0][0] = ecs_os_strdup("XX"); + arr4[0][1] = ecs_os_strdup("YY"); + arr4[0][2] = ecs_os_strdup("ZZ"); + arr4[1][0] = ecs_os_strdup("XX"); + arr4[1][1] = ecs_os_strdup("YY"); + arr4[1][2] = ecs_os_strdup("ZZ"); + arr4[2][0] = ecs_os_strdup("XX"); + arr4[2][1] = ecs_os_strdup("YY"); + arr4[2][2] = ecs_os_strdup("ZZ"); + + /* Test "less" */ + /* {"AA", ...} < {"XX", ...} */ + test_assert(cmp_e(world, array_of_array_of_strings, e1, e4) < 0); + /* {"AA", ...} < {"AA", ..., "ZZ"} */ + test_assert(cmp_e(world, array_of_array_of_strings, e1, e2) < 0); + + /* Test "greater" */ + /* {"XX", ...} > {"AA", ...} */ + test_assert(cmp_e(world, array_of_array_of_strings, e4, e1) > 0); + /* {"AA", ..., "ZZ"} > {"AA", ...} */ + test_assert(cmp_e(world, array_of_array_of_strings, e2, e1) > 0); + + /* Test "equal" */ + test_assert(cmp_e(world, array_of_array_of_strings, e1, e3) == 0); + test_assert(cmp_e(world, array_of_array_of_strings, e1, e1) == 0); + + + ecs_delete(world, e1); + ecs_delete(world, e2); + ecs_delete(world, e3); + ecs_delete(world, e4); + + ecs_fini(world); +} + +void RttCompare_array_of_array_of_struct_with_strings(void) { + ecs_world_t *world = ecs_init(); + + typedef struct { + ecs_string_t a; + ecs_i32_t b; + ecs_string_t c; + } StructWithStrings; + + ecs_entity_t struct_with_strings = ecs_struct(world, { + .members = { + {"a", ecs_id(ecs_string_t)}, + {"b", ecs_id(ecs_i32_t)}, + {"c", ecs_id(ecs_string_t)}, + } + }); + + ecs_entity_t /* StructWithStrings[3] */ array_of_struct_with_strings = + ecs_array(world, {.type = struct_with_strings, .count = 3}); + + ecs_entity_t /* StructWithStrings[3][3] */ + array_of_array_of_struct_with_strings = ecs_array( + world, {.type = array_of_struct_with_strings, .count = 3}); + + /* Create five entities with the nested component */ + ecs_entity_t e1 = ecs_new(world); + ecs_entity_t e2 = ecs_new(world); + ecs_entity_t e3 = ecs_new(world); + ecs_entity_t e4 = ecs_new(world); + ecs_entity_t e5 = ecs_new(world); + + StructWithStrings (*ptr1)[3] = + ecs_ensure_id(world, e1, array_of_array_of_struct_with_strings); + ptr1[0][0].a = ecs_os_strdup("AA"); + ptr1[0][0].b = 10; + ptr1[0][0].c = ecs_os_strdup("CC"); + ptr1[1][1].a = ecs_os_strdup("BB"); + ptr1[1][1].b = 20; + ptr1[1][1].c = ecs_os_strdup("DD"); + + StructWithStrings (*ptr2)[3] = + ecs_ensure_id(world, e2, array_of_array_of_struct_with_strings); + ptr2[0][0].a = ecs_os_strdup("AA"); + ptr2[0][0].b = 10; + ptr2[0][0].c = ecs_os_strdup("CC"); + ptr2[1][1].a = ecs_os_strdup("BB"); + ptr2[1][1].b = 25; + ptr2[1][1].c = ecs_os_strdup("DD"); + + StructWithStrings (*ptr3)[3] = + ecs_ensure_id(world, e3, array_of_array_of_struct_with_strings); + ptr3[0][0].a = ecs_os_strdup("AA"); + ptr3[0][0].b = 10; + ptr3[0][0].c = ecs_os_strdup("CC"); + ptr3[1][1].a = ecs_os_strdup("BB"); + ptr3[1][1].b = 20; + ptr3[1][1].c = ecs_os_strdup("DD"); + + StructWithStrings (*ptr4)[3] = + ecs_ensure_id(world, e4, array_of_array_of_struct_with_strings); + ptr4[0][0].a = ecs_os_strdup("AA"); + ptr4[0][0].b = 5; + ptr4[0][0].c = ecs_os_strdup("EE"); + ptr4[1][1].a = ecs_os_strdup("ZZ"); + ptr4[1][1].b = 20; + ptr4[1][1].c = ecs_os_strdup("FF"); + + StructWithStrings (*ptr5)[3] = + ecs_ensure_id(world, e5, array_of_array_of_struct_with_strings); + ptr5[0][0].a = ecs_os_strdup("AA"); + ptr5[0][0].b = 15; + ptr5[0][0].c = ecs_os_strdup("GG"); + ptr5[1][1].a = ecs_os_strdup("BB"); + ptr5[1][1].b = 30; + ptr5[1][1].c = ecs_os_strdup("HH"); + + /* Test "less" */ + /* {{"AA", 10, "CC"}, {"BB", 20, "DD"}} < {{"AA", 10, "CC"}, {"BB", 25, "DD"}} */ + test_assert(cmp_e(world, array_of_array_of_struct_with_strings, e1, e2) < 0); + + /* {{"AA", 5, "EE"}, {"ZZ", 20, "FF"}} < {{"AA", 15, "GG"}, {"BB", 30, "HH"}} */ + test_assert(cmp_e(world, array_of_array_of_struct_with_strings, e4, e5) < 0); + + /* Test "greater" */ + /* {{"AA", 10, "CC"}, {"BB", 25, "DD"}} > {{"AA", 10, "CC"}, {"BB", 20, "DD"}} */ + test_assert(cmp_e(world, array_of_array_of_struct_with_strings, e2, e1) > 0); + + /* {{"AA", 15, "GG"}, {"BB", 30, "HH"}} > {{"AA", 5, "EE"}, {"ZZ", 20, "FF"}} */ + test_assert(cmp_e(world, array_of_array_of_struct_with_strings, e5, e4) > 0); + + /* Test "equal" */ + /* {{"AA", 10, "CC"}, {"BB", 20, "DD"}} == {{"AA", 10, "CC"}, {"BB", 20, "DD"}} */ + test_assert(cmp_e(world, array_of_array_of_struct_with_strings, e1, e3) == 0); + test_assert(cmp_e(world, array_of_array_of_struct_with_strings, e1, e1) == 0); + + ecs_delete(world, e1); + ecs_delete(world, e2); + ecs_delete(world, e3); + ecs_delete(world, e4); + ecs_delete(world, e5); + + ecs_fini(world); +} + +void RttCompare_array_of_vectors_of_ints(void) { + ecs_world_t *world = ecs_init(); + + ecs_entity_t /* vector */ vector_of_ints = + ecs_vector(world, {.type = ecs_id(ecs_i32_t)}); + + ecs_entity_t /* ecs_vec_t[3] */ array_of_vectors_of_ints = + ecs_array(world, {.type = vector_of_ints, .count = 3}); + + /* Create four entities with array of vectors of integers component */ + ecs_entity_t e1 = ecs_new(world); + ecs_entity_t e2 = ecs_new(world); + ecs_entity_t e3 = ecs_new(world); + ecs_entity_t e4 = ecs_new(world); + + ecs_vec_t *arr1 = ecs_ensure_id(world, e1, array_of_vectors_of_ints); + ecs_vec_set_count(NULL, &arr1[0], sizeof(ecs_i32_t), 3); + ecs_i32_t *v1_0 = ecs_vec_first(&arr1[0]); + v1_0[0] = 10; + v1_0[1] = 20; + v1_0[2] = 30; + ecs_vec_set_count(NULL, &arr1[1], sizeof(ecs_i32_t), 2); + ecs_i32_t *v1_1 = ecs_vec_first(&arr1[1]); + v1_1[0] = 5; + v1_1[1] = 15; + ecs_vec_set_count(NULL, &arr1[2], sizeof(ecs_i32_t), 4); + ecs_i32_t *v1_2 = ecs_vec_first(&arr1[2]); + v1_2[0] = 1; + v1_2[1] = 2; + v1_2[2] = 3; + v1_2[3] = 4; + + ecs_vec_t *arr2 = ecs_ensure_id(world, e2, array_of_vectors_of_ints); + ecs_vec_set_count(NULL, &arr2[0], sizeof(ecs_i32_t), 3); + ecs_i32_t *v2_0 = ecs_vec_first(&arr2[0]); + v2_0[0] = 10; + v2_0[1] = 20; + v2_0[2] = 30; + ecs_vec_set_count(NULL, &arr2[1], sizeof(ecs_i32_t), 2); + ecs_i32_t *v2_1 = ecs_vec_first(&arr2[1]); + v2_1[0] = 5; + v2_1[1] = 15; + ecs_vec_set_count(NULL, &arr2[2], sizeof(ecs_i32_t), 4); + ecs_i32_t *v2_2 = ecs_vec_first(&arr2[2]); + v2_2[0] = 1; + v2_2[1] = 2; + v2_2[2] = 3; + v2_2[3] = 4; + + ecs_vec_t *arr3 = ecs_ensure_id(world, e3, array_of_vectors_of_ints); + ecs_vec_set_count(NULL, &arr3[0], sizeof(ecs_i32_t), 3); + ecs_i32_t *v3_0 = ecs_vec_first(&arr3[0]); + v3_0[0] = 10; + v3_0[1] = 20; + v3_0[2] = 31; // Different from arr1 + ecs_vec_set_count(NULL, &arr3[1], sizeof(ecs_i32_t), 2); + ecs_i32_t *v3_1 = ecs_vec_first(&arr3[1]); + v3_1[0] = 5; + v3_1[1] = 15; + ecs_vec_set_count(NULL, &arr3[2], sizeof(ecs_i32_t), 4); + ecs_i32_t *v3_2 = ecs_vec_first(&arr3[2]); + v3_2[0] = 1; + v3_2[1] = 2; + v3_2[2] = 3; + v3_2[3] = 4; + + ecs_vec_t *arr4 = ecs_ensure_id(world, e4, array_of_vectors_of_ints); + ecs_vec_set_count(NULL, &arr4[0], sizeof(ecs_i32_t), 3); + ecs_i32_t *v4_0 = ecs_vec_first(&arr4[0]); + v4_0[0] = 12; // Different from arr1 + v4_0[1] = 22; + v4_0[2] = 32; + ecs_vec_set_count(NULL, &arr4[1], sizeof(ecs_i32_t), 2); + ecs_i32_t *v4_1 = ecs_vec_first(&arr4[1]); + v4_1[0] = 7; // Different from arr1 + v4_1[1] = 17; + ecs_vec_set_count(NULL, &arr4[2], sizeof(ecs_i32_t), 4); + ecs_i32_t *v4_2 = ecs_vec_first(&arr4[2]); + v4_2[0] = 1; + v4_2[1] = 2; + v4_2[2] = 3; + v4_2[3] = 4; + + /* Test "less" */ + test_assert(cmp_e(world, array_of_vectors_of_ints, e1, e3) < 0); + + /* Test "greater" */ + test_assert(cmp_e(world, array_of_vectors_of_ints, e3, e1) > 0); + + /* Test "equal" */ + test_assert(cmp_e(world, array_of_vectors_of_ints, e1, e2) == 0); + test_assert(cmp_e(world, array_of_vectors_of_ints, e1, e1) == 0); + + /* Test when different in multiple fields */ + test_assert(cmp_e(world, array_of_vectors_of_ints, e1, e4) < 0); + test_assert(cmp_e(world, array_of_vectors_of_ints, e4, e1) > 0); + + ecs_delete(world, e1); + ecs_delete(world, e2); + ecs_delete(world, e3); + ecs_delete(world, e4); + + ecs_fini(world); +} + +void RttCompare_array_of_vectors_of_strings(void) { + ecs_world_t *world = ecs_init(); + + ecs_entity_t /* vector */ vector_of_strings = + ecs_vector(world, {.type = ecs_id(ecs_string_t)}); + + ecs_entity_t /* ecs_vec_t[3] */ array_of_vectors_of_strings = + ecs_array(world, {.type = vector_of_strings, .count = 3}); + + /* Create five entities with array of vectors of strings */ + ecs_entity_t e1 = ecs_new(world); + ecs_entity_t e2 = ecs_new(world); + ecs_entity_t e3 = ecs_new(world); + ecs_entity_t e4 = ecs_new(world); + ecs_entity_t e5 = ecs_new(world); + + /* Initialize e1 */ + ecs_vec_t *arr1 = ecs_ensure_id(world, e1, array_of_vectors_of_strings); + ecs_vec_set_count(NULL, &arr1[0], sizeof(ecs_string_t), 3); + ecs_string_t *vec1_0 = ecs_vec_first(&arr1[0]); + vec1_0[0] = ecs_os_strdup("AA"); + vec1_0[1] = ecs_os_strdup("BB"); + vec1_0[2] = ecs_os_strdup("CC"); + + ecs_vec_set_count(NULL, &arr1[1], sizeof(ecs_string_t), 2); + ecs_string_t *vec1_1 = ecs_vec_first(&arr1[1]); + vec1_1[0] = ecs_os_strdup("XX"); + vec1_1[1] = ecs_os_strdup("YY"); + + ecs_vec_set_count(NULL, &arr1[2], sizeof(ecs_string_t), 1); + ecs_string_t *vec1_2 = ecs_vec_first(&arr1[2]); + vec1_2[0] = ecs_os_strdup("ZZ"); + + /* Initialize e2 */ + ecs_vec_t *arr2 = ecs_ensure_id(world, e2, array_of_vectors_of_strings); + ecs_vec_set_count(NULL, &arr2[0], sizeof(ecs_string_t), 3); + ecs_string_t *vec2_0 = ecs_vec_first(&arr2[0]); + vec2_0[0] = ecs_os_strdup("AA"); + vec2_0[1] = ecs_os_strdup("BB"); + vec2_0[2] = ecs_os_strdup("CC"); + + ecs_vec_set_count(NULL, &arr2[1], sizeof(ecs_string_t), 2); + ecs_string_t *vec2_1 = ecs_vec_first(&arr2[1]); + vec2_1[0] = ecs_os_strdup("XX"); + vec2_1[1] = ecs_os_strdup("YY"); + + ecs_vec_set_count(NULL, &arr2[2], sizeof(ecs_string_t), 1); + ecs_string_t *vec2_2 = ecs_vec_first(&arr2[2]); + vec2_2[0] = ecs_os_strdup("AA"); + + /* Initialize e3 */ + ecs_vec_t *arr3 = ecs_ensure_id(world, e3, array_of_vectors_of_strings); + ecs_vec_set_count(NULL, &arr3[0], sizeof(ecs_string_t), 3); + ecs_string_t *vec3_0 = ecs_vec_first(&arr3[0]); + vec3_0[0] = ecs_os_strdup("AA"); + vec3_0[1] = ecs_os_strdup("BB"); + vec3_0[2] = ecs_os_strdup("CC"); + + ecs_vec_set_count(NULL, &arr3[1], sizeof(ecs_string_t), 2); + ecs_string_t *vec3_1 = ecs_vec_first(&arr3[1]); + vec3_1[0] = ecs_os_strdup("XX"); + vec3_1[1] = ecs_os_strdup("YY"); + + ecs_vec_set_count(NULL, &arr3[2], sizeof(ecs_string_t), 1); + ecs_string_t *vec3_2 = ecs_vec_first(&arr3[2]); + vec3_2[0] = ecs_os_strdup("ZZ"); + + /* Initialize e4 with different strings */ + ecs_vec_t *arr4 = ecs_ensure_id(world, e4, array_of_vectors_of_strings); + ecs_vec_set_count(NULL, &arr4[0], sizeof(ecs_string_t), 3); + ecs_string_t *vec4_0 = ecs_vec_first(&arr4[0]); + vec4_0[0] = ecs_os_strdup("AA"); + vec4_0[1] = ecs_os_strdup("BB"); + vec4_0[2] = ecs_os_strdup("CC"); + + ecs_vec_set_count(NULL, &arr4[1], sizeof(ecs_string_t), 2); + ecs_string_t *vec4_1 = ecs_vec_first(&arr4[1]); + vec4_1[0] = ecs_os_strdup("XX"); + vec4_1[1] = ecs_os_strdup("ZZ"); + + ecs_vec_set_count(NULL, &arr4[2], sizeof(ecs_string_t), 1); + ecs_string_t *vec4_2 = ecs_vec_first(&arr4[2]); + vec4_2[0] = ecs_os_strdup("AA"); + + /* Initialize e5 with even more variation */ + ecs_vec_t *arr5 = ecs_ensure_id(world, e5, array_of_vectors_of_strings); + ecs_vec_set_count(NULL, &arr5[0], sizeof(ecs_string_t), 3); + ecs_string_t *vec5_0 = ecs_vec_first(&arr5[0]); + vec5_0[0] = ecs_os_strdup("DD"); + vec5_0[1] = ecs_os_strdup("EE"); + vec5_0[2] = ecs_os_strdup("FF"); + + ecs_vec_set_count(NULL, &arr5[1], sizeof(ecs_string_t), 2); + ecs_string_t *vec5_1 = ecs_vec_first(&arr5[1]); + vec5_1[0] = ecs_os_strdup("GG"); + vec5_1[1] = ecs_os_strdup("HH"); + + ecs_vec_set_count(NULL, &arr5[2], sizeof(ecs_string_t), 1); + ecs_string_t *vec5_2 = ecs_vec_first(&arr5[2]); + vec5_2[0] = ecs_os_strdup("II"); + + /* Test "less" */ + test_assert(cmp_e(world, array_of_vectors_of_strings, e2, e4) < 0); + test_assert(cmp_e(world, array_of_vectors_of_strings, e2, e1) < 0); + test_assert(cmp_e(world, array_of_vectors_of_strings, e1, e5) < 0); + + /* Test "greater" */ + test_assert(cmp_e(world, array_of_vectors_of_strings, e5, e1) > 0); + test_assert(cmp_e(world, array_of_vectors_of_strings, e1, e2) > 0); + test_assert(cmp_e(world, array_of_vectors_of_strings, e4, e2) > 0); + + /* Test "equal" */ + test_assert(cmp_e(world, array_of_vectors_of_strings, e1, e3) == 0); + test_assert(cmp_e(world, array_of_vectors_of_strings, e3, e1) == 0); + + ecs_delete(world, e1); + ecs_delete(world, e2); + ecs_delete(world, e3); + ecs_delete(world, e4); + ecs_delete(world, e5); + + ecs_fini(world); +} + +void RttCompare_array_of_opaque(void) { + ecs_world_t *world = ecs_init(); + + ecs_entity_t opaque_type = define_opaque_type(world); + + /* Define an array of OpaqueType with 3 elements */ + ecs_entity_t array_of_opaque = ecs_array(world, { + .type = opaque_type, .count = 3 + }); + + /* Create five entities with array of OpaqueType component */ + ecs_entity_t e1 = ecs_new(world); + ecs_entity_t e2 = ecs_new(world); + ecs_entity_t e3 = ecs_new(world); + ecs_entity_t e4 = ecs_new(world); + ecs_entity_t e5 = ecs_new(world); + + OpaqueType *ptr1 = ecs_ensure_id(world, e1, array_of_opaque); + ptr1[0].value = 5; + ptr1[1].value = 10; + ptr1[2].value = 15; + + OpaqueType *ptr2 = ecs_ensure_id(world, e2, array_of_opaque); + ptr2[0].value = 5; + ptr2[1].value = 10; + ptr2[2].value = 20; + + OpaqueType *ptr3 = ecs_ensure_id(world, e3, array_of_opaque); + ptr3[0].value = 5; + ptr3[1].value = 10; + ptr3[2].value = 15; + + OpaqueType *ptr4 = ecs_ensure_id(world, e4, array_of_opaque); + ptr4[0].value = 7; + ptr4[1].value = 8; + ptr4[2].value = 9; + + OpaqueType *ptr5 = ecs_ensure_id(world, e5, array_of_opaque); + ptr5[0].value = 3; + ptr5[1].value = 10; + ptr5[2].value = 15; + + /* Test "less" */ + /* {5, 10, 15} < {5, 10, 20} */ + test_assert(cmp_e(world, array_of_opaque, e1, e2) < 0); + + /* {3, 10, 15} < {7, 8, 9} */ + test_assert(cmp_e(world, array_of_opaque, e5, e4) < 0); + + /* Test "greater" */ + /* {5, 10, 20} > {5, 10, 15} */ + test_assert(cmp_e(world, array_of_opaque, e2, e1) > 0); + + /* {7, 8, 9} > {3, 10, 15} */ + test_assert(cmp_e(world, array_of_opaque, e4, e5) > 0); + + /* Test "equal" */ + /* {5, 10, 15} == {5, 10, 15} */ + test_assert(cmp_e(world, array_of_opaque, e1, e3) == 0); + test_assert(cmp_e(world, array_of_opaque, e1, e1) == 0); + + ecs_delete(world, e1); + ecs_delete(world, e2); + ecs_delete(world, e3); + ecs_delete(world, e4); + ecs_delete(world, e5); + + ecs_fini(world); +} + +void RttCompare_vector_of_ints(void) { + ecs_world_t *world = ecs_init(); + + ecs_entity_t /* vector */ vector_of_ints = + ecs_vector(world, {.type = ecs_id(ecs_i32_t)}); + + /* Create five entities with vector_of_ints component */ + ecs_entity_t e1 = ecs_new(world); + ecs_entity_t e2 = ecs_new(world); + ecs_entity_t e3 = ecs_new(world); + ecs_entity_t e4 = ecs_new(world); + ecs_entity_t e5 = ecs_new(world); + + ecs_vec_t *vec1 = ecs_ensure_id(world, e1, vector_of_ints); + ecs_vec_set_count(NULL, vec1, sizeof(ecs_i32_t), 3); + ecs_i32_t *v1_data = ecs_vec_first(vec1); + v1_data[0] = 10; + v1_data[1] = 20; + v1_data[2] = 30; + + ecs_vec_t *vec2 = ecs_ensure_id(world, e2, vector_of_ints); + ecs_vec_set_count(NULL, vec2, sizeof(ecs_i32_t), 3); + ecs_i32_t *v2_data = ecs_vec_first(vec2); + v2_data[0] = 10; + v2_data[1] = 25; + v2_data[2] = 30; + + ecs_vec_t *vec3 = ecs_ensure_id(world, e3, vector_of_ints); + ecs_vec_set_count(NULL, vec3, sizeof(ecs_i32_t), 3); + ecs_i32_t *v3_data = ecs_vec_first(vec3); + v3_data[0] = 10; + v3_data[1] = 20; + v3_data[2] = 30; + + ecs_vec_t *vec4 = ecs_ensure_id(world, e4, vector_of_ints); + ecs_vec_set_count(NULL, vec4, sizeof(ecs_i32_t), 2); + ecs_i32_t *v4_data = ecs_vec_first(vec4); + v4_data[0] = 10; + v4_data[1] = 20; + + ecs_vec_t *vec5 = ecs_ensure_id(world, e5, vector_of_ints); + ecs_vec_set_count(NULL, vec5, sizeof(ecs_i32_t), 3); + ecs_i32_t *v5_data = ecs_vec_first(vec5); + v5_data[0] = 40; + v5_data[1] = 50; + v5_data[2] = 60; + + /* Test "less" */ + /* {10, 20, 30} < {10, 25, 30} */ + test_assert(cmp_e(world, vector_of_ints, e1, e2) < 0); + + /* {10, 20, 30} < {40, 50, 60} */ + test_assert(cmp_e(world, vector_of_ints, e1, e5) < 0); + + /* {10, 20} < {10, 20, 30} */ + test_assert(cmp_e(world, vector_of_ints, e4, e1) < 0); + + /* Test "greater" */ + /* {10, 25, 30} > {10, 20, 30} */ + test_assert(cmp_e(world, vector_of_ints, e2, e1) > 0); + + /* {40, 50, 60} > {10, 20, 30} */ + test_assert(cmp_e(world, vector_of_ints, e5, e1) > 0); + + /* Test "equal" */ + /* {10, 20, 30} == {10, 20, 30} */ + test_assert(cmp_e(world, vector_of_ints, e1, e3) == 0); + test_assert(cmp_e(world, vector_of_ints, e1, e1) == 0); + + ecs_delete(world, e1); + ecs_delete(world, e2); + ecs_delete(world, e3); + ecs_delete(world, e4); + ecs_delete(world, e5); + + ecs_fini(world); +} + +void RttCompare_vector_of_strings(void) { + ecs_world_t *world = ecs_init(); + + ecs_entity_t /* vector */ vector_of_strings = + ecs_vector(world, {.type = ecs_id(ecs_string_t)}); + + /* Create five entities with a vector of strings component */ + ecs_entity_t e1 = ecs_new(world); + ecs_entity_t e2 = ecs_new(world); + ecs_entity_t e3 = ecs_new(world); + ecs_entity_t e4 = ecs_new(world); + ecs_entity_t e5 = ecs_new(world); + + ecs_vec_t *vec1 = ecs_ensure_id(world, e1, vector_of_strings); + ecs_vec_set_count(NULL, vec1, sizeof(ecs_string_t), 3); + ecs_string_t *v1_data = ecs_vec_first(vec1); + v1_data[0] = ecs_os_strdup("AA"); + v1_data[1] = ecs_os_strdup("BB"); + v1_data[2] = ecs_os_strdup("CC"); + + ecs_vec_t *vec2 = ecs_ensure_id(world, e2, vector_of_strings); + ecs_vec_set_count(NULL, vec2, sizeof(ecs_string_t), 3); + ecs_string_t *v2_data = ecs_vec_first(vec2); + v2_data[0] = ecs_os_strdup("AA"); + v2_data[1] = ecs_os_strdup("BB"); + v2_data[2] = ecs_os_strdup("DD"); + + ecs_vec_t *vec3 = ecs_ensure_id(world, e3, vector_of_strings); + ecs_vec_set_count(NULL, vec3, sizeof(ecs_string_t), 3); + ecs_string_t *v3_data = ecs_vec_first(vec3); + v3_data[0] = ecs_os_strdup("AA"); + v3_data[1] = ecs_os_strdup("BB"); + v3_data[2] = ecs_os_strdup("CC"); + + ecs_vec_t *vec4 = ecs_ensure_id(world, e4, vector_of_strings); + ecs_vec_set_count(NULL, vec4, sizeof(ecs_string_t), 3); + ecs_string_t *v4_data = ecs_vec_first(vec4); + v4_data[0] = ecs_os_strdup("ZZ"); + v4_data[1] = ecs_os_strdup("AA"); + v4_data[2] = ecs_os_strdup("DD"); + + ecs_vec_t *vec5 = ecs_ensure_id(world, e5, vector_of_strings); + ecs_vec_set_count(NULL, vec5, sizeof(ecs_string_t), 3); + ecs_string_t *v5_data = ecs_vec_first(vec5); + v5_data[0] = ecs_os_strdup("AA"); + v5_data[1] = ecs_os_strdup("AA"); + v5_data[2] = ecs_os_strdup("BB"); + + /* Test "less" */ + /* {"AA", "BB", "CC"} < {"AA", "BB", "DD"} */ + test_assert(cmp_e(world, vector_of_strings, e1, e2) < 0); + + /* {"AA", "AA", "BB"} < {"AA", "BB", "CC"} */ + test_assert(cmp_e(world, vector_of_strings, e5, e1) < 0); + + /* {"AA", "BB", "DD"} < {"ZZ", "AA", "DD"} */ + test_assert(cmp_e(world, vector_of_strings, e2, e4) < 0); + + /* Test "greater" */ + /* {"AA", "BB", "DD"} > {"AA", "BB", "CC"} */ + test_assert(cmp_e(world, vector_of_strings, e2, e1) > 0); + /* {"ZZ", "AA", "DD"} > {"AA", "BB", "DD"} */ + test_assert(cmp_e(world, vector_of_strings, e4, e2) > 0); + + /* {"AA", "BB", "CC"} > {"AA", "AA", "BB"} */ + test_assert(cmp_e(world, vector_of_strings, e1, e5) > 0); + + + /* Test "equal" */ + /* {"AA", "BB", "CC"} == {"AA", "BB", "CC"} */ + test_assert(cmp_e(world, vector_of_strings, e1, e3) == 0); + test_assert(cmp_e(world, vector_of_strings, e1, e1) == 0); + + ecs_delete(world, e1); + ecs_delete(world, e2); + ecs_delete(world, e3); + ecs_delete(world, e4); + ecs_delete(world, e5); + + ecs_fini(world); +} + +void RttCompare_vector_of_struct_with_ints(void) { + ecs_world_t *world = ecs_init(); + + typedef struct { + ecs_i32_t a; + ecs_i32_t b; + } StructWithInts; + + ecs_entity_t struct_with_ints = ecs_struct(world, { + .members = { + {"a", ecs_id(ecs_i32_t)}, + {"b", ecs_id(ecs_i32_t)}, + } + }); + + ecs_entity_t /* vector */ vector_of_struct_with_ints = + ecs_vector(world, {.type = struct_with_ints}); + + /* Create three entities with a vector of StructWithInts component */ + ecs_entity_t e1 = ecs_new(world); + ecs_entity_t e2 = ecs_new(world); + ecs_entity_t e3 = ecs_new(world); + + ecs_vec_t *vec1 = ecs_ensure_id(world, e1, vector_of_struct_with_ints); + ecs_vec_set_count(NULL, vec1, sizeof(StructWithInts), 3); + StructWithInts *v1 = ecs_vec_first(vec1); + v1[0] = (StructWithInts){.a = 10, .b = 20}; + v1[1] = (StructWithInts){.a = 15, .b = 25}; + v1[2] = (StructWithInts){.a = 20, .b = 30}; + + ecs_vec_t *vec2 = ecs_ensure_id(world, e2, vector_of_struct_with_ints); + ecs_vec_set_count(NULL, vec2, sizeof(StructWithInts), 3); + StructWithInts *v2 = ecs_vec_first(vec2); + v2[0] = (StructWithInts){.a = 10, .b = 20}; + v2[1] = (StructWithInts){.a = 15, .b = 25}; + v2[2] = (StructWithInts){.a = 25, .b = 35}; + + ecs_vec_t *vec3 = ecs_ensure_id(world, e3, vector_of_struct_with_ints); + ecs_vec_set_count(NULL, vec3, sizeof(StructWithInts), 3); + StructWithInts *v3 = ecs_vec_first(vec3); + v3[0] = (StructWithInts){.a = 10, .b = 20}; + v3[1] = (StructWithInts){.a = 15, .b = 25}; + v3[2] = (StructWithInts){.a = 20, .b = 30}; + + /* Test "less" */ + /* vec1 < vec2 because v1[2].a < v2[2].a */ + test_assert(cmp_e(world, vector_of_struct_with_ints, e1, e2) < 0); + + /* Test "greater" */ + /* vec2 > vec1 because v2[2].a > v1[2].a */ + test_assert(cmp_e(world, vector_of_struct_with_ints, e2, e1) > 0); + + /* Test "equal" */ + /* vec1 == vec3 as they have identical values */ + test_assert(cmp_e(world, vector_of_struct_with_ints, e1, e3) == 0); + test_assert(cmp_e(world, vector_of_struct_with_ints, e1, e1) == 0); + + ecs_delete(world, e1); + ecs_delete(world, e2); + ecs_delete(world, e3); + + ecs_fini(world); +} + +void RttCompare_vector_of_struct_with_strings(void) { + ecs_world_t *world = ecs_init(); + + typedef struct { + ecs_string_t a; + ecs_i32_t b; + ecs_string_t c; + } StructWithStrings; + + ecs_entity_t struct_with_strings = ecs_struct(world, { + .members = { + {"a", ecs_id(ecs_string_t)}, + {"b", ecs_id(ecs_i32_t)}, + {"c", ecs_id(ecs_string_t)}, + } + }); + + ecs_entity_t /* vector */ vector_of_struct_with_strings = + ecs_vector(world, {.type = struct_with_strings}); + + /* Create entities with vector component */ + ecs_entity_t e1 = ecs_new(world); + ecs_entity_t e2 = ecs_new(world); + ecs_entity_t e3 = ecs_new(world); + ecs_entity_t e4 = ecs_new(world); + + ecs_vec_t *vec1 = ecs_ensure_id(world, e1, vector_of_struct_with_strings); + ecs_vec_set_count(NULL, vec1, sizeof(StructWithStrings), 2); + StructWithStrings *v1 = ecs_vec_first(vec1); + v1[0].a = ecs_os_strdup("AA"); + v1[0].b = 10; + v1[0].c = ecs_os_strdup("BB"); + v1[1].a = ecs_os_strdup("CC"); + v1[1].b = 15; + v1[1].c = ecs_os_strdup("DD"); + + ecs_vec_t *vec2 = ecs_ensure_id(world, e2, vector_of_struct_with_strings); + ecs_vec_set_count(NULL, vec2, sizeof(StructWithStrings), 2); + StructWithStrings *v2 = ecs_vec_first(vec2); + v2[0].a = ecs_os_strdup("AA"); + v2[0].b = 20; + v2[0].c = ecs_os_strdup("BB"); + v2[1].a = ecs_os_strdup("CC"); + v2[1].b = 15; + v2[1].c = ecs_os_strdup("DD"); + + ecs_vec_t *vec3 = ecs_ensure_id(world, e3, vector_of_struct_with_strings); + ecs_vec_set_count(NULL, vec3, sizeof(StructWithStrings), 2); + StructWithStrings *v3 = ecs_vec_first(vec3); + v3[0].a = ecs_os_strdup("AA"); + v3[0].b = 10; + v3[0].c = ecs_os_strdup("BB"); + v3[1].a = ecs_os_strdup("CC"); + v3[1].b = 15; + v3[1].c = ecs_os_strdup("DD"); + + ecs_vec_t *vec4 = ecs_ensure_id(world, e4, vector_of_struct_with_strings); + ecs_vec_set_count(NULL, vec4, sizeof(StructWithStrings), 1); + StructWithStrings *v4 = ecs_vec_first(vec4); + v4[0].a = ecs_os_strdup("AA"); + v4[0].b = 5; + v4[0].c = ecs_os_strdup("BB"); + + /* Test "less" */ + /* vec1 < vec2, because {10} < {20} */ + test_assert(cmp_e(world, vector_of_struct_with_strings, e1, e2) < 0); + + /* vec4 < vec1, because vec4 has fewer elements */ + test_assert(cmp_e(world, vector_of_struct_with_strings, e4, e1) < 0); + + /* Test "greater" */ + /* vec2 > vec1, because {20} > {10} */ + test_assert(cmp_e(world, vector_of_struct_with_strings, e2, e1) > 0); + + /* vec1 > vec4, because vec1 has more elements */ + test_assert(cmp_e(world, vector_of_struct_with_strings, e1, e4) > 0); + + /* Test "equal" */ + /* vec1 == vec3, all elements are identical */ + test_assert(cmp_e(world, vector_of_struct_with_strings, e1, e3) == 0); + + ecs_delete(world, e1); + ecs_delete(world, e2); + ecs_delete(world, e3); + ecs_delete(world, e4); + + ecs_fini(world); +} + +void RttCompare_vector_of_arrays_of_strings(void) { + ecs_world_t *world = ecs_init(); + + ecs_entity_t /* ecs_string_t[3] */ array_of_strings = + ecs_array(world, {.type = ecs_id(ecs_string_t), .count = 3}); + + ecs_entity_t /* vector */ vector_of_arrays_of_strings = + ecs_vector(world, {.type = array_of_strings}); + + /* Create five entities with vector of arrays of strings component */ + ecs_entity_t e1 = ecs_new(world); + ecs_entity_t e2 = ecs_new(world); + ecs_entity_t e3 = ecs_new(world); + ecs_entity_t e4 = ecs_new(world); + ecs_entity_t e5 = ecs_new(world); + + ecs_vec_t *vec1 = ecs_ensure_id(world, e1, vector_of_arrays_of_strings); + ecs_vec_set_count(NULL, vec1, sizeof(ecs_string_t[3]), 1); + ecs_string_t (*v1)[3] = ecs_vec_first(vec1); + v1[0][0] = ecs_os_strdup("AA"); + v1[0][1] = ecs_os_strdup("BB"); + v1[0][2] = ecs_os_strdup("CC"); + + ecs_vec_t *vec2 = ecs_ensure_id(world, e2, vector_of_arrays_of_strings); + ecs_vec_set_count(NULL, vec2, sizeof(ecs_string_t[3]), 1); + ecs_string_t (*v2)[3] = ecs_vec_first(vec2); + v2[0][0] = ecs_os_strdup("AA"); + v2[0][1] = ecs_os_strdup("BB"); + v2[0][2] = ecs_os_strdup("CC"); + + ecs_vec_t *vec3 = ecs_ensure_id(world, e3, vector_of_arrays_of_strings); + ecs_vec_set_count(NULL, vec3, sizeof(ecs_string_t[3]), 1); + ecs_string_t (*v3)[3] = ecs_vec_first(vec3); + v3[0][0] = ecs_os_strdup("AA"); + v3[0][1] = ecs_os_strdup("ZZ"); + v3[0][2] = ecs_os_strdup("CC"); + + ecs_vec_t *vec4 = ecs_ensure_id(world, e4, vector_of_arrays_of_strings); + ecs_vec_set_count(NULL, vec4, sizeof(ecs_string_t[3]), 1); + ecs_string_t (*v4)[3] = ecs_vec_first(vec4); + v4[0][0] = ecs_os_strdup("ZZ"); + v4[0][1] = ecs_os_strdup("AA"); + v4[0][2] = ecs_os_strdup("DD"); + + ecs_vec_t *vec5 = ecs_ensure_id(world, e5, vector_of_arrays_of_strings); + ecs_vec_set_count(NULL, vec5, sizeof(ecs_string_t[3]), 1); + ecs_string_t (*v5)[3] = ecs_vec_first(vec5); + v5[0][0] = ecs_os_strdup("AA"); + v5[0][1] = ecs_os_strdup("BB"); + v5[0][2] = ecs_os_strdup("DD"); + + /* Test "less" */ + /* {"AA", "BB", "CC"} < {"AA", "ZZ", "CC"} */ + test_assert(cmp_e(world, vector_of_arrays_of_strings, e1, e3) < 0); + + /* {"AA", "BB", "CC"} < {"ZZ", "AA", "DD"} */ + test_assert(cmp_e(world, vector_of_arrays_of_strings, e1, e4) < 0); + + /* {"AA", "BB", "DD"} < {"ZZ", "AA", "DD"} */ + test_assert(cmp_e(world, vector_of_arrays_of_strings, e5, e4) < 0); + + /* Test "greater" */ + /* {"ZZ", "AA", "DD"} > {"AA", "BB", "CC"} */ + test_assert(cmp_e(world, vector_of_arrays_of_strings, e4, e1) > 0); + + /* {"AA", "ZZ", "CC"} > {"AA", "BB", "CC"} */ + test_assert(cmp_e(world, vector_of_arrays_of_strings, e3, e1) > 0); + + /* Test "equal" */ + /* {"AA", "BB", "CC"} == {"AA", "BB", "CC"} */ + test_assert(cmp_e(world, vector_of_arrays_of_strings, e1, e2) == 0); + test_assert(cmp_e(world, vector_of_arrays_of_strings, e1, e1) == 0); + + ecs_delete(world, e1); + ecs_delete(world, e2); + ecs_delete(world, e3); + ecs_delete(world, e4); + ecs_delete(world, e5); + + ecs_fini(world); +} + +void RttCompare_vector_of_opaque(void) { + ecs_world_t *world = ecs_init(); + + ecs_entity_t opaque = define_opaque_type(world); + + ecs_entity_t /* vector */ vector_of_opaque = + ecs_vector(world, {.type = opaque }); + + /* Create five entities with vector_of_opaque component */ + ecs_entity_t e1 = ecs_new(world); + ecs_entity_t e2 = ecs_new(world); + ecs_entity_t e3 = ecs_new(world); + ecs_entity_t e4 = ecs_new(world); + ecs_entity_t e5 = ecs_new(world); + + ecs_vec_t *vec1 = ecs_ensure_id(world, e1, vector_of_opaque); + ecs_vec_set_count(NULL, vec1, sizeof(OpaqueType), 3); + OpaqueType *v1_data = ecs_vec_first(vec1); + v1_data[0].value = 10; + v1_data[1].value = 20; + v1_data[2].value = 30; + + ecs_vec_t *vec2 = ecs_ensure_id(world, e2, vector_of_opaque); + ecs_vec_set_count(NULL, vec2, sizeof(OpaqueType), 3); + OpaqueType *v2_data = ecs_vec_first(vec2); + v2_data[0].value = 10; + v2_data[1].value = 25; + v2_data[2].value = 30; + + ecs_vec_t *vec3 = ecs_ensure_id(world, e3, vector_of_opaque); + ecs_vec_set_count(NULL, vec3, sizeof(OpaqueType), 3); + OpaqueType *v3_data = ecs_vec_first(vec3); + v3_data[0].value = 10; + v3_data[1].value = 20; + v3_data[2].value = 30; + + ecs_vec_t *vec4 = ecs_ensure_id(world, e4, vector_of_opaque); + ecs_vec_set_count(NULL, vec4, sizeof(OpaqueType), 2); + OpaqueType *v4_data = ecs_vec_first(vec4); + v4_data[0].value = 5; + v4_data[1].value = 15; + + ecs_vec_t *vec5 = ecs_ensure_id(world, e5, vector_of_opaque); + ecs_vec_set_count(NULL, vec5, sizeof(OpaqueType), 4); + OpaqueType *v5_data = ecs_vec_first(vec5); + v5_data[0].value = 10; + v5_data[1].value = 20; + v5_data[2].value = 25; + v5_data[3].value = 35; + + /* Test "less" */ + /* {10, 20, 30} < {10, 25, 30} */ + test_assert(cmp_e(world, vector_of_opaque, e1, e2) < 0); + + /* {5, 15} < {10, 20, 30} */ + test_assert(cmp_e(world, vector_of_opaque, e4, e1) < 0); + + /* Test "greater" */ + /* {10, 25, 30} > {10, 20, 30} */ + test_assert(cmp_e(world, vector_of_opaque, e2, e1) > 0); + + /* {10, 20, 30, 35} > {10, 20, 30} */ + test_assert(cmp_e(world, vector_of_opaque, e5, e1) > 0); + + /* Test "equal" */ + /* {10, 20, 30} == {10, 20, 30} */ + test_assert(cmp_e(world, vector_of_opaque, e1, e3) == 0); + test_assert(cmp_e(world, vector_of_opaque, e1, e1) == 0); + + ecs_delete(world, e1); + ecs_delete(world, e2); + ecs_delete(world, e3); + ecs_delete(world, e4); + ecs_delete(world, e5); + + ecs_fini(world); +} diff --git a/test/meta/src/RuntimeTypes.c b/test/meta/src/RuntimeTypes.c index 99790583c..302aea66c 100644 --- a/test/meta/src/RuntimeTypes.c +++ b/test/meta/src/RuntimeTypes.c @@ -548,10 +548,10 @@ void RuntimeTypes_copy_illegal(void) { ecs_set_hooks_id(world, nested_struct, &hooks); /* Define TestStruct, which has two "NestedStruct" members. - * TestStruct's constructor should be set to illegal as well. */ + * TestStruct's copy and copy ctor should be set to illegal as well. */ const ecs_type_info_t *test_struct_ti = define_test_struct(world); - /* TestStruct should have an illegal move hook too: */ + /* TestStruct should have an illegal copy and copy ctor hook too: */ test_assert(test_struct_ti->hooks.flags & ECS_TYPE_HOOK_COPY_ILLEGAL); test_assert(test_struct_ti->hooks.flags & ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL); @@ -563,6 +563,31 @@ void RuntimeTypes_copy_illegal(void) { ecs_fini(world); } +/* Tests that an illegal compare hook is set for a struct if at least a member has + * itself an illegal compare hook */ +void RuntimeTypes_comp_illegal(void) { + ecs_world_t *world = ecs_init(); + + /* Define NestedStruct: */ + const ecs_type_info_t *nested_struct_ti = define_nested_struct(world); + + ecs_type_hooks_t hooks = nested_struct_ti->hooks; + hooks.flags |= ECS_TYPE_HOOK_COMP_ILLEGAL; /* mark copy hook for "NestedStruct" as illegal */ + hooks.comp = NULL; + + hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; + ecs_set_hooks_id(world, nested_struct, &hooks); + + /* Define TestStruct, which has two "NestedStruct" members. + * TestStruct's compare hook should be set to illegal as well. */ + const ecs_type_info_t *test_struct_ti = define_test_struct(world); + + /* TestStruct should have an illegal compare hook too: */ + test_assert(test_struct_ti->hooks.flags & ECS_TYPE_HOOK_COMP_ILLEGAL); + + ecs_fini(world); +} + /* For the following tests, we model a "ResourceHandle" that must allocate an id * from a pool of resource ids. When constructing a handle, it must get a unique * id. When destroying a handle, it must return the id. When copying a handle, @@ -1185,6 +1210,40 @@ void RuntimeTypes_array_copy_illegal(void) { ecs_fini(world); } +/* Tests that an illegal comp hook is set for an array if its underlying type itself + * has an illegal comp hook */ +void RuntimeTypes_array_comp_illegal(void) { + ecs_world_t *world = ecs_init(); + + /* Define NestedStruct: */ + const ecs_type_info_t *nested_struct_ti = define_nested_struct(world); + + ecs_type_hooks_t hooks = nested_struct_ti->hooks; + hooks.flags |= ECS_TYPE_HOOK_COMP_ILLEGAL; /* mark compare hook + for "NestedStruct" as illegal */ + hooks.comp = NULL; + + hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; + ecs_set_hooks_id(world, nested_struct, &hooks); + + /* Define test_arr, as an array of "NestedStruct". + * TestStruct's comp hook should be set to illegal as well. */ + ecs_array_desc_t desc = {.entity = 0, .type = nested_struct, .count = 3}; + ecs_entity_t test_arr = ecs_array_init(world, &desc); + + const ecs_type_info_t* test_arr_ti = ecs_get_type_info(world, test_arr); + + /* test_arr should have an illegal comp hook too: */ + test_assert(test_arr_ti->hooks.flags & ECS_TYPE_HOOK_COMP_ILLEGAL); + + /* No other hooks should've been set: */ + test_assert(test_arr_ti->hooks.ctor != NULL); + test_assert(test_arr_ti->hooks.dtor == NULL); + test_assert(test_arr_ti->hooks.move == NULL); + + ecs_fini(world); +} + /* Test vector types */ void RuntimeTypes_vector_lifecycle(void) { ecs_world_t *world = ecs_init(); @@ -1315,6 +1374,35 @@ void RuntimeTypes_vector_lifecycle_trivial_type(void) { free_resource_ids(); } +/* Tests that an illegal comp hook is set for an array if its underlying type itself + * has an illegal comp hook */ +void RuntimeTypes_vector_comp_illegal(void) { + ecs_world_t *world = ecs_init(); + + /* Define NestedStruct: */ + const ecs_type_info_t *nested_struct_ti = define_nested_struct(world); + + ecs_type_hooks_t hooks = nested_struct_ti->hooks; + hooks.flags |= ECS_TYPE_HOOK_COMP_ILLEGAL; /* mark compare hook + for "NestedStruct" as illegal */ + hooks.comp = NULL; + + hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; + ecs_set_hooks_id(world, nested_struct, &hooks); + + /* Define test_vec, as a vector of "NestedStruct". + * TestStruct's comp hook should be set to illegal as well. */ + ecs_vector_desc_t desc = {.entity = 0, .type = nested_struct}; + ecs_entity_t test_vec = ecs_vector_init(world, &desc); + + const ecs_type_info_t* test_vec_ti = ecs_get_type_info(world, test_vec); + + /* test_vec should have an illegal comp hook too: */ + test_assert(test_vec_ti->hooks.flags & ECS_TYPE_HOOK_COMP_ILLEGAL); + + ecs_fini(world); +} + /* Configure an opaque type that consumes resources */ ecs_entity_t define_ResourceHandle_opaque( ecs_world_t *world) @@ -3350,3 +3438,4 @@ void RuntimeTypes_vector_of_opaque(void) { free_resource_ids(); } + diff --git a/test/meta/src/main.c b/test/meta/src/main.c index a559d417b..f723f3983 100644 --- a/test/meta/src/main.c +++ b/test/meta/src/main.c @@ -96,6 +96,7 @@ void RuntimeTypes_move(void); void RuntimeTypes_move_illegal(void); void RuntimeTypes_copy(void); void RuntimeTypes_copy_illegal(void); +void RuntimeTypes_comp_illegal(void); void RuntimeTypes_trivial_array(void); void RuntimeTypes_array_ctor(void); void RuntimeTypes_array_ctor_illegal(void); @@ -105,8 +106,10 @@ void RuntimeTypes_array_move(void); void RuntimeTypes_array_move_illegal(void); void RuntimeTypes_array_copy(void); void RuntimeTypes_array_copy_illegal(void); +void RuntimeTypes_array_comp_illegal(void); void RuntimeTypes_vector_lifecycle(void); void RuntimeTypes_vector_lifecycle_trivial_type(void); +void RuntimeTypes_vector_comp_illegal(void); void RuntimeTypes_opaque(void); void RuntimeTypes_struct_with_ints(void); void RuntimeTypes_struct_with_strings(void); @@ -1045,6 +1048,19 @@ void RttCompare_nested_struct_with_vector_of_strings(void); void RttCompare_array_of_ints(void); void RttCompare_array_of_strings(void); void RttCompare_array_of_struct_with_ints(void); +void RttCompare_array_of_struct_with_strings(void); +void RttCompare_array_of_struct_with_opaques(void); +void RttCompare_array_of_array_of_strings(void); +void RttCompare_array_of_array_of_struct_with_strings(void); +void RttCompare_array_of_vectors_of_ints(void); +void RttCompare_array_of_vectors_of_strings(void); +void RttCompare_array_of_opaque(void); +void RttCompare_vector_of_ints(void); +void RttCompare_vector_of_strings(void); +void RttCompare_vector_of_struct_with_ints(void); +void RttCompare_vector_of_struct_with_strings(void); +void RttCompare_vector_of_arrays_of_strings(void); +void RttCompare_vector_of_opaque(void); bake_test_case PrimitiveTypes_testcases[] = { { @@ -1380,6 +1396,10 @@ bake_test_case RuntimeTypes_testcases[] = { "copy_illegal", RuntimeTypes_copy_illegal }, + { + "comp_illegal", + RuntimeTypes_comp_illegal + }, { "trivial_array", RuntimeTypes_trivial_array @@ -1416,6 +1436,10 @@ bake_test_case RuntimeTypes_testcases[] = { "array_copy_illegal", RuntimeTypes_array_copy_illegal }, + { + "array_comp_illegal", + RuntimeTypes_array_comp_illegal + }, { "vector_lifecycle", RuntimeTypes_vector_lifecycle @@ -1424,6 +1448,10 @@ bake_test_case RuntimeTypes_testcases[] = { "vector_lifecycle_trivial_type", RuntimeTypes_vector_lifecycle_trivial_type }, + { + "vector_comp_illegal", + RuntimeTypes_vector_comp_illegal + }, { "opaque", RuntimeTypes_opaque @@ -5080,6 +5108,58 @@ bake_test_case RttCompare_testcases[] = { { "array_of_struct_with_ints", RttCompare_array_of_struct_with_ints + }, + { + "array_of_struct_with_strings", + RttCompare_array_of_struct_with_strings + }, + { + "array_of_struct_with_opaques", + RttCompare_array_of_struct_with_opaques + }, + { + "array_of_array_of_strings", + RttCompare_array_of_array_of_strings + }, + { + "array_of_array_of_struct_with_strings", + RttCompare_array_of_array_of_struct_with_strings + }, + { + "array_of_vectors_of_ints", + RttCompare_array_of_vectors_of_ints + }, + { + "array_of_vectors_of_strings", + RttCompare_array_of_vectors_of_strings + }, + { + "array_of_opaque", + RttCompare_array_of_opaque + }, + { + "vector_of_ints", + RttCompare_vector_of_ints + }, + { + "vector_of_strings", + RttCompare_vector_of_strings + }, + { + "vector_of_struct_with_ints", + RttCompare_vector_of_struct_with_ints + }, + { + "vector_of_struct_with_strings", + RttCompare_vector_of_struct_with_strings + }, + { + "vector_of_arrays_of_strings", + RttCompare_vector_of_arrays_of_strings + }, + { + "vector_of_opaque", + RttCompare_vector_of_opaque } }; @@ -5110,7 +5190,7 @@ static bake_test_suite suites[] = { "RuntimeTypes", NULL, NULL, - 47, + 50, RuntimeTypes_testcases }, { @@ -5243,7 +5323,7 @@ static bake_test_suite suites[] = { "RttCompare", NULL, NULL, - 13, + 26, RttCompare_testcases } }; From 0decf95486ce607e8ee2395bc777c565ae86c9de Mon Sep 17 00:00:00 2001 From: Javier Peletier Date: Fri, 29 Nov 2024 09:17:56 +0100 Subject: [PATCH 12/23] fixt test-windows compilation error due to const array size r --- distr/flecs.c | 21 +- distr/flecs.h | 10 +- include/flecs.h | 1 + include/flecs/addons/cpp/component.hpp | 5 +- include/flecs/addons/cpp/lifecycle_traits.hpp | 4 - src/addons/meta/meta.c | 4 +- src/world.c | 3 +- test/meta/include/meta.h | 2 - test/meta/src/PrimitiveCompare.c | 42 ++- test/meta/src/RttCompare.c | 324 +++++++++--------- test/meta/src/RuntimeTypes.c | 1 + 11 files changed, 203 insertions(+), 214 deletions(-) diff --git a/distr/flecs.c b/distr/flecs.c index ce4374ef2..430b6dba1 100644 --- a/distr/flecs.c +++ b/distr/flecs.c @@ -18942,8 +18942,7 @@ void flecs_default_move_w_dtor(void *dst_ptr, void *src_ptr, cl->dtor(src_ptr, count, ti); } -ECS_NORETURN -static +ECS_NORETURN static void flecs_ctor_illegal( void * dst, int32_t count, @@ -50431,10 +50430,8 @@ int flecs_init_type( * serializers on uninitialized values. For runtime types (rtt), the default hooks are set by flecs_meta_rtt_init_default_hooks */ ecs_type_info_t *ti = flecs_type_info_ensure(world, type); - if (meta_type->existing) { - if (!ti->hooks.ctor) { + if (meta_type->existing && !ti->hooks.ctor) { ti->hooks.ctor = flecs_default_ctor; - } } } else { if (meta_type->kind != kind) { @@ -51902,16 +51899,16 @@ ecs_rtt_struct_ctx_t * flecs_rtt_configure_struct_hooks( ecs_vec_init_t(NULL, &rtt_ctx->vcomp, ecs_rtt_call_data_t, 0); hooks.lifecycle_ctx = rtt_ctx; hooks.lifecycle_ctx_free = flecs_rtt_free_lifecycle_struct_ctx; - - hooks.ctor = ctor; - hooks.dtor = dtor; - hooks.move = move; - hooks.copy = copy; - hooks.comp = comp; } else { hooks.lifecycle_ctx = NULL; hooks.lifecycle_ctx_free = flecs_rtt_free_lifecycle_nop; - } + } + + hooks.ctor = ctor; + hooks.dtor = dtor; + hooks.move = move; + hooks.copy = copy; + hooks.comp = comp; hooks.flags = flags; hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; diff --git a/distr/flecs.h b/distr/flecs.h index ae3b2f400..ab6faf413 100644 --- a/distr/flecs.h +++ b/distr/flecs.h @@ -3596,6 +3596,7 @@ struct ecs_type_hooks_t { * not set explicitly it will be derived from other callbacks. */ ecs_move_t move_dtor; + /** Compare hook */ ecs_comp_t comp; /** Hook flags. @@ -20512,7 +20513,6 @@ ecs_move_t move_dtor(ecs_flags32_t &) { return move_dtor_impl; } - // Traits to check for operator<, operator>, and operator== template using void_t = void; @@ -20546,10 +20546,7 @@ template struct has_operator_greater() > std::declval())>> : std::is_same() > std::declval()), bool> {}; - - // Trait to check for operator== - template struct has_operator_equal : std::false_type {}; @@ -26990,6 +26987,8 @@ void register_lifecycle_actions( if(cl.comp == NULL) { cl.flags |= ECS_TYPE_HOOK_COMP_ILLEGAL; } + + cl.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id(world, component, &cl); } @@ -27018,7 +27017,8 @@ void register_lifecycle_actions( if(cl.comp == NULL) { cl.flags |= ECS_TYPE_HOOK_COMP_ILLEGAL; } - + + cl.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id(world, component, &cl); if (cl.flags & (ECS_TYPE_HOOK_MOVE_ILLEGAL|ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL)) diff --git a/include/flecs.h b/include/flecs.h index acceada2c..5e2f218ec 100644 --- a/include/flecs.h +++ b/include/flecs.h @@ -928,6 +928,7 @@ struct ecs_type_hooks_t { * not set explicitly it will be derived from other callbacks. */ ecs_move_t move_dtor; + /** Compare hook */ ecs_comp_t comp; /** Hook flags. diff --git a/include/flecs/addons/cpp/component.hpp b/include/flecs/addons/cpp/component.hpp index 34b9c689a..3bf799c47 100644 --- a/include/flecs/addons/cpp/component.hpp +++ b/include/flecs/addons/cpp/component.hpp @@ -105,6 +105,8 @@ void register_lifecycle_actions( if(cl.comp == NULL) { cl.flags |= ECS_TYPE_HOOK_COMP_ILLEGAL; } + + cl.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id(world, component, &cl); } @@ -133,7 +135,8 @@ void register_lifecycle_actions( if(cl.comp == NULL) { cl.flags |= ECS_TYPE_HOOK_COMP_ILLEGAL; } - + + cl.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id(world, component, &cl); if (cl.flags & (ECS_TYPE_HOOK_MOVE_ILLEGAL|ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL)) diff --git a/include/flecs/addons/cpp/lifecycle_traits.hpp b/include/flecs/addons/cpp/lifecycle_traits.hpp index 2bfb882f0..0d29a8055 100644 --- a/include/flecs/addons/cpp/lifecycle_traits.hpp +++ b/include/flecs/addons/cpp/lifecycle_traits.hpp @@ -348,7 +348,6 @@ ecs_move_t move_dtor(ecs_flags32_t &) { return move_dtor_impl; } - // Traits to check for operator<, operator>, and operator== template using void_t = void; @@ -382,10 +381,7 @@ template struct has_operator_greater() > std::declval())>> : std::is_same() > std::declval()), bool> {}; - - // Trait to check for operator== - template struct has_operator_equal : std::false_type {}; diff --git a/src/addons/meta/meta.c b/src/addons/meta/meta.c index 3c56f2364..e2c871ff1 100644 --- a/src/addons/meta/meta.c +++ b/src/addons/meta/meta.c @@ -483,10 +483,8 @@ int flecs_init_type( * serializers on uninitialized values. For runtime types (rtt), the default hooks are set by flecs_meta_rtt_init_default_hooks */ ecs_type_info_t *ti = flecs_type_info_ensure(world, type); - if (meta_type->existing) { - if (!ti->hooks.ctor) { + if (meta_type->existing && !ti->hooks.ctor) { ti->hooks.ctor = flecs_default_ctor; - } } } else { if (meta_type->kind != kind) { diff --git a/src/world.c b/src/world.c index 9079ab495..63d8fe91b 100644 --- a/src/world.c +++ b/src/world.c @@ -1182,8 +1182,7 @@ void flecs_default_move_w_dtor(void *dst_ptr, void *src_ptr, cl->dtor(src_ptr, count, ti); } -ECS_NORETURN -static +ECS_NORETURN static void flecs_ctor_illegal( void * dst, int32_t count, diff --git a/test/meta/include/meta.h b/test/meta/include/meta.h index 32cafc427..ad1befaa1 100644 --- a/test/meta/include/meta.h +++ b/test/meta/include/meta.h @@ -64,8 +64,6 @@ void install_test_abort(void); #define test_json(v1, v2) _test_json(v1, v2, #v1, #v2, __FILE__, __LINE__) void _test_json(const char* str1, const char *str2, const char* vstr1, const char *vstr2, const char *file, int line); -int cmp(const void *a, const void *b, const ecs_type_info_t* ti); - #ifdef __cplusplus } #endif diff --git a/test/meta/src/PrimitiveCompare.c b/test/meta/src/PrimitiveCompare.c index 07f85df04..30e33f851 100644 --- a/test/meta/src/PrimitiveCompare.c +++ b/test/meta/src/PrimitiveCompare.c @@ -1,24 +1,25 @@ -#include #include -#include "flecs.h" #include - +static int cmp(const void *a, const void *b, const ecs_type_info_t* ti) { return ti->hooks.comp(a, b, ti); } const ecs_type_info_t *sort_ti = NULL; +static int compare_element(const void *a, const void *b) { return cmp(a, b, sort_ti); } +static void sort_array(const ecs_type_info_t* ti, void *arr, ecs_size_t num_elements) { sort_ti = ti; qsort(arr, num_elements, sort_ti->size, compare_element); } +static bool str_equals(const char* a, const char* b) { if(a == b) { return true; @@ -471,21 +472,20 @@ void PrimitiveCompare_id(void) { ecs_fini(world); } + +#define STRING_COUNT 8 void PrimitiveCompare_string(void) { ecs_world_t *world = ecs_init(); - const char* const_arr[] = {"world", "hello", NULL, "aa", "zz", "aa", "cc", "bb"}; - const char* const_expected[] = {NULL, "aa", "aa", "bb", "cc", "hello", "world", "zz"}; - - ecs_size_t count = sizeof(const_arr) / sizeof(const char*); - test_assert(count == sizeof(const_expected) / sizeof(const char*)); + char* const_arr[] = {"world", "hello", NULL, "aa", "zz", "aa", "cc", "bb"}; + char* const_expected[] = {NULL, "aa", "aa", "bb", "cc", "hello", "world", "zz"}; - ecs_string_t arr[count]; - ecs_string_t expected[count]; + ecs_string_t arr[STRING_COUNT]; + ecs_string_t expected[STRING_COUNT]; const ecs_type_info_t *ti = ecs_get_type_info(world, ecs_id(ecs_string_t)); - ti->hooks.copy_ctor(arr, const_arr, count, ti); - ti->hooks.copy_ctor(expected, const_expected, count, ti); + ti->hooks.copy_ctor(arr, const_arr, STRING_COUNT, ti); + ti->hooks.copy_ctor(expected, const_expected, STRING_COUNT, ti); /* test "less" */ test_assert(cmp(&arr[3], &arr[7], ti) < 0); /* "aa < "bb" */ @@ -499,15 +499,15 @@ void PrimitiveCompare_string(void) { test_assert(cmp(&arr[2], &arr[5], ti) < 0); /* NULL == NULL */ /* further test by sorting the array */ - sort_array(ti, arr, count); + sort_array(ti, arr, STRING_COUNT); int i; - for(i = 0; i < count; i++) { + for(i = 0; i < STRING_COUNT; i++) { test_assert(str_equals(arr[i], expected[i])); } - ti->hooks.dtor(arr, count, ti); - ti->hooks.dtor(expected, count, ti); + ti->hooks.dtor(arr, STRING_COUNT, ti); + ti->hooks.dtor(expected, STRING_COUNT, ti); ecs_fini(world); } @@ -517,13 +517,11 @@ void PrimitiveCompare_const_string(void) { ecs_entity_t const_string = ecs_lookup(world, "flecs.core.const_string_t"); - const char* arr[] = {"world", "hello", NULL, "aa", "zz", "aa", "cc", "bb"}; - const char* expected[] = {NULL, "aa", "aa", "bb", "cc", "hello", "world", "zz"}; + char* arr[] = {"world", "hello", NULL, "aa", "zz", "aa", "cc", "bb"}; + char* expected[] = {NULL, "aa", "aa", "bb", "cc", "hello", "world", "zz"}; const ecs_type_info_t *ti = ecs_get_type_info(world, const_string); - ecs_size_t count = sizeof(arr) / sizeof(const char*); - test_assert(count == sizeof(expected) / sizeof(const char*)); /* test "less" */ test_assert(cmp(&arr[3], &arr[7], ti) < 0); /* "aa < "bb" */ @@ -537,10 +535,10 @@ void PrimitiveCompare_const_string(void) { test_assert(cmp(&arr[2], &arr[5], ti) < 0); /* NULL == NULL */ /* further test by sorting the array */ - sort_array(ti, arr, count); + sort_array(ti, arr, STRING_COUNT); int i; - for(i = 0; i < count; i++) { + for(i = 0; i < STRING_COUNT; i++) { test_assert(str_equals(arr[i], expected[i])); } diff --git a/test/meta/src/RttCompare.c b/test/meta/src/RttCompare.c index 57bfcaac0..ade5ab28d 100644 --- a/test/meta/src/RttCompare.c +++ b/test/meta/src/RttCompare.c @@ -1,9 +1,7 @@ -#include -#include -#include "flecs.h" #include -int cmp_e(const ecs_world_t *world, ecs_entity_t component, ecs_entity_t ea, +static +int cmp(const ecs_world_t *world, ecs_entity_t component, ecs_entity_t ea, ecs_entity_t eb) { const ecs_type_info_t *ti = ecs_get_type_info(world, component); @@ -78,16 +76,16 @@ void RttCompare_struct_with_ints(void) { /* Test "less" */ /* {10, 20} < {10, 25} */ - test_assert(cmp_e(world, struct_with_ints, e1, e2) < 0); + test_assert(cmp(world, struct_with_ints, e1, e2) < 0); /* Test "greater" */ /* {10, 25} > {10, 20} */ - test_assert(cmp_e(world, struct_with_ints, e2, e1) > 0); + test_assert(cmp(world, struct_with_ints, e2, e1) > 0); /* Test "equal" */ /* {10, 20} == {10, 20} */ - test_assert(cmp_e(world, struct_with_ints, e1, e3) == 0); - test_assert(cmp_e(world, struct_with_ints, e1, e1) == 0); + test_assert(cmp(world, struct_with_ints, e1, e3) == 0); + test_assert(cmp(world, struct_with_ints, e1, e1) == 0); ecs_delete(world, e1); ecs_delete(world, e2); @@ -135,16 +133,16 @@ void RttCompare_struct_with_strings(void) { /* Test "less" */ /* {"AA", 20, "CC"} < {"AA", 25, "BB"} */ - test_assert(cmp_e(world, struct_with_strings, e1, e2) < 0); + test_assert(cmp(world, struct_with_strings, e1, e2) < 0); /* Test "greater" */ /* {"AA", 25, "BB"} > {"AA", 20, "CC"} */ - test_assert(cmp_e(world, struct_with_strings, e2, e1) > 0); + test_assert(cmp(world, struct_with_strings, e2, e1) > 0); /* Test "equal" */ /* {"AA", 20, "CC"} == {"AA", 20, "CC"} */ - test_assert(cmp_e(world, struct_with_strings, e1, e3) == 0); - test_assert(cmp_e(world, struct_with_strings, e1, e1) == 0); + test_assert(cmp(world, struct_with_strings, e1, e3) == 0); + test_assert(cmp(world, struct_with_strings, e1, e1) == 0); ecs_delete(world, e1); ecs_delete(world, e2); @@ -184,16 +182,16 @@ void RttCompare_struct_with_opaque(void) { /* Test "less" */ /* {10} < {15} */ - test_assert(cmp_e(world, struct_with_opaque, e1, e2) < 0); + test_assert(cmp(world, struct_with_opaque, e1, e2) < 0); /* Test "greater" */ /* {15} > {10} */ - test_assert(cmp_e(world, struct_with_opaque, e2, e1) > 0); + test_assert(cmp(world, struct_with_opaque, e2, e1) > 0); /* Test "equal" */ /* {10} == {10} */ - test_assert(cmp_e(world, struct_with_opaque, e1, e3) == 0); - test_assert(cmp_e(world, struct_with_opaque, e1, e1) == 0); + test_assert(cmp(world, struct_with_opaque, e1, e3) == 0); + test_assert(cmp(world, struct_with_opaque, e1, e1) == 0); ecs_delete(world, e1); ecs_delete(world, e2); @@ -266,14 +264,14 @@ void RttCompare_nested_struct_with_strings(void) { ptr3->c.c = ecs_os_strdup("DD"); /* Test "less" */ - test_assert(cmp_e(world, nested_struct_with_strings, e1, e2) < 0); + test_assert(cmp(world, nested_struct_with_strings, e1, e2) < 0); /* Test "greater" */ - test_assert(cmp_e(world, nested_struct_with_strings, e2, e1) > 0); + test_assert(cmp(world, nested_struct_with_strings, e2, e1) > 0); /* Test "equal" */ - test_assert(cmp_e(world, nested_struct_with_strings, e1, e3) == 0); - test_assert(cmp_e(world, nested_struct_with_strings, e1, e1) == 0); + test_assert(cmp(world, nested_struct_with_strings, e1, e3) == 0); + test_assert(cmp(world, nested_struct_with_strings, e1, e1) == 0); ecs_delete(world, e1); ecs_delete(world, e2); @@ -344,28 +342,28 @@ void RttCompare_struct_with_array_of_strings(void) { /* Test "less" */ /* {"AA", "BB", "CC", 10} < {"AA", "BB", "CC", 20} */ - test_assert(cmp_e(world, struct_with_array_of_strings, e1, e2) < 0); + test_assert(cmp(world, struct_with_array_of_strings, e1, e2) < 0); /* {"AA", "BB", "CC", 10} < {"AA", "ZZ", "CC", 10} */ - test_assert(cmp_e(world, struct_with_array_of_strings, e1, e4) < 0); + test_assert(cmp(world, struct_with_array_of_strings, e1, e4) < 0); /* {"AA", "AA", "DD", 15} < {"AA", "BB", "CC", 20} */ - test_assert(cmp_e(world, struct_with_array_of_strings, e5, e2) < 0); + test_assert(cmp(world, struct_with_array_of_strings, e5, e2) < 0); /* Test "greater" */ /* {"AA", "BB", "CC", 20} > {"AA", "BB", "CC", 10} */ - test_assert(cmp_e(world, struct_with_array_of_strings, e2, e1) > 0); + test_assert(cmp(world, struct_with_array_of_strings, e2, e1) > 0); /* {"AA", "ZZ", "CC", 10} > {"AA", "BB", "CC", 10} */ - test_assert(cmp_e(world, struct_with_array_of_strings, e4, e1) > 0); + test_assert(cmp(world, struct_with_array_of_strings, e4, e1) > 0); /* {"AA", "BB", "CC", 20} > {"AA", "AA", "DD", 15} */ - test_assert(cmp_e(world, struct_with_array_of_strings, e2, e5) > 0); + test_assert(cmp(world, struct_with_array_of_strings, e2, e5) > 0); /* Test "equal" */ /* {"AA", "BB", "CC", 10} == {"AA", "BB", "CC", 10} */ - test_assert(cmp_e(world, struct_with_array_of_strings, e1, e3) == 0); - test_assert(cmp_e(world, struct_with_array_of_strings, e1, e1) == 0); + test_assert(cmp(world, struct_with_array_of_strings, e1, e3) == 0); + test_assert(cmp(world, struct_with_array_of_strings, e1, e1) == 0); ecs_delete(world, e1); ecs_delete(world, e2); @@ -451,28 +449,28 @@ void RttCompare_struct_with_array_of_array_of_strings(void) { /* Test "less" */ /* {"AA", "BB", "CC", "DD"} < {"AA", "BB", "CC", "EE"} */ - test_assert(cmp_e(world, struct_with_array_of_array_of_strings, e1, e2) < 0); + test_assert(cmp(world, struct_with_array_of_array_of_strings, e1, e2) < 0); /* {"AA", "BB", "CC", "DD"} < {"AA", "ZZ", "CC", "DD"} */ - test_assert(cmp_e(world, struct_with_array_of_array_of_strings, e1, e4) < 0); + test_assert(cmp(world, struct_with_array_of_array_of_strings, e1, e4) < 0); /* {"AA", "BB", "CC", "DD"} < {"XX", "BB", "YY", "FF"} */ - test_assert(cmp_e(world, struct_with_array_of_array_of_strings, e1, e5) < 0); + test_assert(cmp(world, struct_with_array_of_array_of_strings, e1, e5) < 0); /* Test "greater" */ /* {"AA", "BB", "CC", "EE"} > {"AA", "BB", "CC", "DD"} */ - test_assert(cmp_e(world, struct_with_array_of_array_of_strings, e2, e1) > 0); + test_assert(cmp(world, struct_with_array_of_array_of_strings, e2, e1) > 0); /* {"AA", "ZZ", "CC", "DD"} > {"AA", "BB", "CC", "DD"} */ - test_assert(cmp_e(world, struct_with_array_of_array_of_strings, e4, e1) > 0); + test_assert(cmp(world, struct_with_array_of_array_of_strings, e4, e1) > 0); /* {"XX", "BB", "YY", "FF"} > {"AA", "BB", "CC", "DD"} */ - test_assert(cmp_e(world, struct_with_array_of_array_of_strings, e5, e1) > 0); + test_assert(cmp(world, struct_with_array_of_array_of_strings, e5, e1) > 0); /* Test "equal" */ /* {"AA", "BB", "CC", "DD"} == {"AA", "BB", "CC", "DD"} */ - test_assert(cmp_e(world, struct_with_array_of_array_of_strings, e1, e3) == 0); - test_assert(cmp_e(world, struct_with_array_of_array_of_strings, e1, e1) == 0); + test_assert(cmp(world, struct_with_array_of_array_of_strings, e1, e3) == 0); + test_assert(cmp(world, struct_with_array_of_array_of_strings, e1, e1) == 0); ecs_delete(world, e1); ecs_delete(world, e2); @@ -534,22 +532,22 @@ void RttCompare_struct_with_vector_of_ints(void) { /* Test "less" */ /* {10, 20, 30} < {15, 25, 35} */ - test_assert(cmp_e(world, struct_with_vector_of_ints, e1, e2) < 0); + test_assert(cmp(world, struct_with_vector_of_ints, e1, e2) < 0); /* {10, 20} < {10, 20, 30} (because fewer elements) */ - test_assert(cmp_e(world, struct_with_vector_of_ints, e4, e1) < 0); + test_assert(cmp(world, struct_with_vector_of_ints, e4, e1) < 0); /* Test "greater" */ /* {15, 25, 35} > {10, 20, 30} */ - test_assert(cmp_e(world, struct_with_vector_of_ints, e2, e1) > 0); + test_assert(cmp(world, struct_with_vector_of_ints, e2, e1) > 0); /* {10, 20, 30} > {10, 20} (because more elements) */ - test_assert(cmp_e(world, struct_with_vector_of_ints, e1, e4) > 0); + test_assert(cmp(world, struct_with_vector_of_ints, e1, e4) > 0); /* Test "equal" */ /* {10, 20, 30} == {10, 20, 30} */ - test_assert(cmp_e(world, struct_with_vector_of_ints, e1, e3) == 0); - test_assert(cmp_e(world, struct_with_vector_of_ints, e1, e1) == 0); + test_assert(cmp(world, struct_with_vector_of_ints, e1, e3) == 0); + test_assert(cmp(world, struct_with_vector_of_ints, e1, e1) == 0); ecs_delete(world, e1); ecs_delete(world, e2); @@ -610,22 +608,22 @@ void RttCompare_struct_with_vector_of_strings(void) { /* Test "less" */ /* {"AA", "BB", "CC"} < {"AA", "BB", "DD"} */ - test_assert(cmp_e(world, struct_with_vector_of_strings, e1, e2) < 0); + test_assert(cmp(world, struct_with_vector_of_strings, e1, e2) < 0); /* {"AA", "BB"} < {"AA", "BB", "CC"} (because fewer elements) */ - test_assert(cmp_e(world, struct_with_vector_of_strings, e4, e1) < 0); + test_assert(cmp(world, struct_with_vector_of_strings, e4, e1) < 0); /* Test "greater" */ /* {"AA", "BB", "DD"} > {"AA", "BB", "CC"} */ - test_assert(cmp_e(world, struct_with_vector_of_strings, e2, e1) > 0); + test_assert(cmp(world, struct_with_vector_of_strings, e2, e1) > 0); /* {"AA", "BB", "CC"} > {"AA", "BB"} (because more elements) */ - test_assert(cmp_e(world, struct_with_vector_of_strings, e1, e4) > 0); + test_assert(cmp(world, struct_with_vector_of_strings, e1, e4) > 0); /* Test "equal" */ /* {"AA", "BB", "CC"} == {"AA", "BB", "CC"} */ - test_assert(cmp_e(world, struct_with_vector_of_strings, e1, e3) == 0); - test_assert(cmp_e(world, struct_with_vector_of_strings, e1, e1) == 0); + test_assert(cmp(world, struct_with_vector_of_strings, e1, e3) == 0); + test_assert(cmp(world, struct_with_vector_of_strings, e1, e1) == 0); ecs_delete(world, e1); ecs_delete(world, e2); @@ -778,24 +776,24 @@ void RttCompare_nested_struct_with_vector_of_ints(void) { /* Test "less" */ /* {1, 2, 3, 10, {4, 5, 15, 6}} < {1, 2, 3, 20, {4, 5, 15, 6}} */ - test_assert(cmp_e(world, nested_struct_with_vector_of_ints, e1, e2) < 0); + test_assert(cmp(world, nested_struct_with_vector_of_ints, e1, e2) < 0); /* {1, 2, 3, 10, {4, 5, 15, 6}} < {3, 2, 1, 10, {4, 5, 15, 6}} */ - test_assert(cmp_e(world, nested_struct_with_vector_of_ints, e1, e4) < 0); + test_assert(cmp(world, nested_struct_with_vector_of_ints, e1, e4) < 0); /* {1, 2, 3, 10, {4, 5, 15, 6}} < {1, 2, 3, 30, {7, 8, 25, 9}} */ - test_assert(cmp_e(world, nested_struct_with_vector_of_ints, e1, e5) < 0); + test_assert(cmp(world, nested_struct_with_vector_of_ints, e1, e5) < 0); /* Test "greater" */ /* {1, 2, 3, 20, {4, 5, 15, 6}} > {1, 2, 3, 10, {4, 5, 15, 6}} */ - test_assert(cmp_e(world, nested_struct_with_vector_of_ints, e2, e1) > 0); + test_assert(cmp(world, nested_struct_with_vector_of_ints, e2, e1) > 0); /* {3, 2, 1, 10, {4, 5, 15, 6}} > {1, 2, 3, 10, {4, 5, 15, 6}} */ - test_assert(cmp_e(world, nested_struct_with_vector_of_ints, e4, e1) > 0); + test_assert(cmp(world, nested_struct_with_vector_of_ints, e4, e1) > 0); /* {1, 2, 3, 30, {7, 8, 25, 9}} > {1, 2, 3, 10, {4, 5, 15, 6}} */ - test_assert(cmp_e(world, nested_struct_with_vector_of_ints, e5, e1) > 0); + test_assert(cmp(world, nested_struct_with_vector_of_ints, e5, e1) > 0); /* Test "equal" */ /* {1, 2, 3, 10, {4, 5, 15, 6}} == {1, 2, 3, 10, {4, 5, 15, 6}} */ - test_assert(cmp_e(world, nested_struct_with_vector_of_ints, e1, e3) == 0); - test_assert(cmp_e(world, nested_struct_with_vector_of_ints, e1, e1) == 0); + test_assert(cmp(world, nested_struct_with_vector_of_ints, e1, e3) == 0); + test_assert(cmp(world, nested_struct_with_vector_of_ints, e1, e1) == 0); ecs_delete(world, e1); ecs_delete(world, e2); @@ -936,35 +934,35 @@ void RttCompare_nested_struct_with_vector_of_strings(void) { /* Test "less" */ /* {{"AA", "BB", "CC"}, 10, {{"XX", "YY"}, 5, {"ZZ"}}} < */ /* {{"AA", "BB", "CC"}, 15, {{"XX", "YY"}, 5, {"ZZ"}}} */ - test_assert(cmp_e(world, nested_struct_with_vector_of_strings, e1, e2) < 0); + test_assert(cmp(world, nested_struct_with_vector_of_strings, e1, e2) < 0); /* {{"EE"}, 5, {{"MM", "NN"}, 8, {"OO", "PP", "RR"}}} < */ /* {{"AA", "BB", "CC"}, 15, {{"XX", "YY"}, 5, {"ZZ"}}} */ - test_assert(cmp_e(world, nested_struct_with_vector_of_strings, e5, e2) < 0); + test_assert(cmp(world, nested_struct_with_vector_of_strings, e5, e2) < 0); /* {{"AA", "DD"}, 20, {{"XX", "YY", "ZZ"}, 10, {"WW", "QQ"}}} > */ /* {{"AA", "BB", "CC"}, 10, {{"XX", "YY"}, 5, {"ZZ"}}} */ - test_assert(cmp_e(world, nested_struct_with_vector_of_strings, e4, e1) < 0); + test_assert(cmp(world, nested_struct_with_vector_of_strings, e4, e1) < 0); /* Test "greater" */ /* {{"AA", "BB", "CC"}, 15, {{"XX", "YY"}, 5, {"ZZ"}}} > */ /* {{"AA", "BB", "CC"}, 10, {{"XX", "YY"}, 5, {"ZZ"}}} */ - test_assert(cmp_e(world, nested_struct_with_vector_of_strings, e2, e1) > 0); + test_assert(cmp(world, nested_struct_with_vector_of_strings, e2, e1) > 0); /* {{"AA", "BB", "CC"}, 10, {{"XX", "YY"}, 5, {"ZZ"}}} < */ /* {{"AA", "DD"}, 20, {{"XX", "YY", "ZZ"}, 10, {"WW", "QQ"}}} */ - test_assert(cmp_e(world, nested_struct_with_vector_of_strings, e1, e4) > 0); + test_assert(cmp(world, nested_struct_with_vector_of_strings, e1, e4) > 0); /* {{"AA", "BB", "CC"}, 15, {{"XX", "YY"}, 5, {"ZZ"}}} > */ /* {{"EE"}, 5, {{"MM", "NN"}, 8, {"OO", "PP", "RR"}}} */ - test_assert(cmp_e(world, nested_struct_with_vector_of_strings, e2, e5) > 0); + test_assert(cmp(world, nested_struct_with_vector_of_strings, e2, e5) > 0); /* Test "equal" */ /* {{"AA", "BB", "CC"}, 10, {{"XX", "YY"}, 5, {"ZZ"}}} == */ /* {{"AA", "BB", "CC"}, 10, {{"XX", "YY"}, 5, {"ZZ"}}} */ - test_assert(cmp_e(world, nested_struct_with_vector_of_strings, e1, e3) == 0); - test_assert(cmp_e(world, nested_struct_with_vector_of_strings, e1, e1) == 0); + test_assert(cmp(world, nested_struct_with_vector_of_strings, e1, e3) == 0); + test_assert(cmp(world, nested_struct_with_vector_of_strings, e1, e1) == 0); ecs_delete(world, e1); ecs_delete(world, e2); @@ -1015,22 +1013,22 @@ void RttCompare_array_of_ints(void) { /* Test "less" */ /* {1, 2, 3} < {1, 2, 4} */ - test_assert(cmp_e(world, array_of_ints, e1, e2) < 0); + test_assert(cmp(world, array_of_ints, e1, e2) < 0); /* {0, 5, 6} < {1, 2, 3} */ - test_assert(cmp_e(world, array_of_ints, e4, e1) < 0); + test_assert(cmp(world, array_of_ints, e4, e1) < 0); /* Test "greater" */ /* {1, 2, 4} > {1, 2, 3} */ - test_assert(cmp_e(world, array_of_ints, e2, e1) > 0); + test_assert(cmp(world, array_of_ints, e2, e1) > 0); /* {1, 2, 3} > {1, 2, 2} */ - test_assert(cmp_e(world, array_of_ints, e1, e5) > 0); + test_assert(cmp(world, array_of_ints, e1, e5) > 0); /* Test "equal" */ /* {1, 2, 3} == {1, 2, 3} */ - test_assert(cmp_e(world, array_of_ints, e1, e3) == 0); - test_assert(cmp_e(world, array_of_ints, e1, e1) == 0); + test_assert(cmp(world, array_of_ints, e1, e3) == 0); + test_assert(cmp(world, array_of_ints, e1, e1) == 0); ecs_delete(world, e1); ecs_delete(world, e2); @@ -1081,22 +1079,22 @@ void RttCompare_array_of_strings(void) { /* Test "less" */ /* {"AA", "BB", "CC"} < {"AA", "BB", "DD"} */ - test_assert(cmp_e(world, array_of_strings, e1, e2) < 0); + test_assert(cmp(world, array_of_strings, e1, e2) < 0); /* {"AA", "AB", "AC"} < {"AA", "BB", "CC"} */ - test_assert(cmp_e(world, array_of_strings, e5, e1) < 0); + test_assert(cmp(world, array_of_strings, e5, e1) < 0); /* Test "greater" */ /* {"ZZ", "YY", "XX"} > {"AA", "BB", "CC"} */ - test_assert(cmp_e(world, array_of_strings, e4, e1) > 0); + test_assert(cmp(world, array_of_strings, e4, e1) > 0); /* {"AA", "BB", "DD"} > {"AA", "BB", "CC"} */ - test_assert(cmp_e(world, array_of_strings, e2, e1) > 0); + test_assert(cmp(world, array_of_strings, e2, e1) > 0); /* Test "equal" */ /* {"AA", "BB", "CC"} == {"AA", "BB", "CC"} */ - test_assert(cmp_e(world, array_of_strings, e1, e3) == 0); - test_assert(cmp_e(world, array_of_strings, e1, e1) == 0); + test_assert(cmp(world, array_of_strings, e1, e3) == 0); + test_assert(cmp(world, array_of_strings, e1, e1) == 0); ecs_delete(world, e1); ecs_delete(world, e2); @@ -1159,22 +1157,22 @@ void RttCompare_array_of_struct_with_ints(void) { /* Test "less" */ /* {{1, 2}, {3, 4}, {5, 6}} < {{1, 2}, {3, 4}, {5, 10}} */ - test_assert(cmp_e(world, array_of_struct_with_ints, e1, e2) < 0); + test_assert(cmp(world, array_of_struct_with_ints, e1, e2) < 0); /* {{0, 1}, {2, 3}, {4, 5}} < {{1, 2}, {3, 4}, {5, 6}} */ - test_assert(cmp_e(world, array_of_struct_with_ints, e4, e1) < 0); + test_assert(cmp(world, array_of_struct_with_ints, e4, e1) < 0); /* Test "greater" */ /* {{1, 2}, {3, 4}, {5, 10}} > {{1, 2}, {3, 4}, {5, 6}} */ - test_assert(cmp_e(world, array_of_struct_with_ints, e2, e1) > 0); + test_assert(cmp(world, array_of_struct_with_ints, e2, e1) > 0); /* {{7, 8}, {9, 10}, {11, 12}} > {{1, 2}, {3, 4}, {5, 6}} */ - test_assert(cmp_e(world, array_of_struct_with_ints, e5, e1) > 0); + test_assert(cmp(world, array_of_struct_with_ints, e5, e1) > 0); /* Test "equal" */ /* {{1, 2}, {3, 4}, {5, 6}} == {{1, 2}, {3, 4}, {5, 6}} */ - test_assert(cmp_e(world, array_of_struct_with_ints, e1, e3) == 0); - test_assert(cmp_e(world, array_of_struct_with_ints, e1, e1) == 0); + test_assert(cmp(world, array_of_struct_with_ints, e1, e3) == 0); + test_assert(cmp(world, array_of_struct_with_ints, e1, e1) == 0); ecs_delete(world, e1); ecs_delete(world, e2); @@ -1283,21 +1281,21 @@ void RttCompare_array_of_struct_with_strings(void) { ptr5->items[2].c = ecs_os_strdup("FF"); /* Test "less" */ - test_assert(cmp_e(world, struct_array_entity, e1, e2) < 0);/*15 < 18 */ - test_assert(cmp_e(world, struct_array_entity, e5, e4) < 0);/*"AA" < "XX" */ - test_assert(cmp_e(world, struct_array_entity, e1, e4) < 0);/*"CC" < "ZZ" */ + test_assert(cmp(world, struct_array_entity, e1, e2) < 0);/*15 < 18 */ + test_assert(cmp(world, struct_array_entity, e5, e4) < 0);/*"AA" < "XX" */ + test_assert(cmp(world, struct_array_entity, e1, e4) < 0);/*"CC" < "ZZ" */ /* Test "greater" */ /* e2 > e1 because ptr2->items[1].b (18) > ptr1->items[1].b (15) */ - test_assert(cmp_e(world, struct_array_entity, e2, e1) > 0);/* 18 > 15 */ - test_assert(cmp_e(world, struct_array_entity, e5, e1) > 0);/* "GG" > "BB"*/ + test_assert(cmp(world, struct_array_entity, e2, e1) > 0);/* 18 > 15 */ + test_assert(cmp(world, struct_array_entity, e5, e1) > 0);/* "GG" > "BB"*/ /* e4 > e1 because */ - test_assert(cmp_e(world, struct_array_entity, e4, e1) > 0);/* "XX" > "AA"*/ + test_assert(cmp(world, struct_array_entity, e4, e1) > 0);/* "XX" > "AA"*/ /* Test "equal" */ - test_assert(cmp_e(world, struct_array_entity, e1, e3) == 0); - test_assert(cmp_e(world, struct_array_entity, e1, e1) == 0); + test_assert(cmp(world, struct_array_entity, e1, e3) == 0); + test_assert(cmp(world, struct_array_entity, e1, e1) == 0); ecs_delete(world, e1); ecs_delete(world, e2); @@ -1348,16 +1346,16 @@ void RttCompare_array_of_struct_with_opaques(void) { /* Test "less" */ /* {{5}, {10}, {15}} < {{5}, {15}, {20}} */ - test_assert(cmp_e(world, array_of_struct_with_opaques, e1, e2) < 0); + test_assert(cmp(world, array_of_struct_with_opaques, e1, e2) < 0); /* Test "greater" */ /* {{5}, {15}, {20}} > {{5}, {10}, {15}} */ - test_assert(cmp_e(world, array_of_struct_with_opaques, e2, e1) > 0); + test_assert(cmp(world, array_of_struct_with_opaques, e2, e1) > 0); /* Test "equal" */ /* {{5}, {10}, {15}} == {{5}, {10}, {15}} */ - test_assert(cmp_e(world, array_of_struct_with_opaques, e1, e3) == 0); - test_assert(cmp_e(world, array_of_struct_with_opaques, e1, e1) == 0); + test_assert(cmp(world, array_of_struct_with_opaques, e1, e3) == 0); + test_assert(cmp(world, array_of_struct_with_opaques, e1, e1) == 0); ecs_delete(world, e1); ecs_delete(world, e2); @@ -1427,19 +1425,19 @@ void RttCompare_array_of_array_of_strings(void) { /* Test "less" */ /* {"AA", ...} < {"XX", ...} */ - test_assert(cmp_e(world, array_of_array_of_strings, e1, e4) < 0); + test_assert(cmp(world, array_of_array_of_strings, e1, e4) < 0); /* {"AA", ...} < {"AA", ..., "ZZ"} */ - test_assert(cmp_e(world, array_of_array_of_strings, e1, e2) < 0); + test_assert(cmp(world, array_of_array_of_strings, e1, e2) < 0); /* Test "greater" */ /* {"XX", ...} > {"AA", ...} */ - test_assert(cmp_e(world, array_of_array_of_strings, e4, e1) > 0); + test_assert(cmp(world, array_of_array_of_strings, e4, e1) > 0); /* {"AA", ..., "ZZ"} > {"AA", ...} */ - test_assert(cmp_e(world, array_of_array_of_strings, e2, e1) > 0); + test_assert(cmp(world, array_of_array_of_strings, e2, e1) > 0); /* Test "equal" */ - test_assert(cmp_e(world, array_of_array_of_strings, e1, e3) == 0); - test_assert(cmp_e(world, array_of_array_of_strings, e1, e1) == 0); + test_assert(cmp(world, array_of_array_of_strings, e1, e3) == 0); + test_assert(cmp(world, array_of_array_of_strings, e1, e1) == 0); ecs_delete(world, e1); @@ -1528,22 +1526,22 @@ void RttCompare_array_of_array_of_struct_with_strings(void) { /* Test "less" */ /* {{"AA", 10, "CC"}, {"BB", 20, "DD"}} < {{"AA", 10, "CC"}, {"BB", 25, "DD"}} */ - test_assert(cmp_e(world, array_of_array_of_struct_with_strings, e1, e2) < 0); + test_assert(cmp(world, array_of_array_of_struct_with_strings, e1, e2) < 0); /* {{"AA", 5, "EE"}, {"ZZ", 20, "FF"}} < {{"AA", 15, "GG"}, {"BB", 30, "HH"}} */ - test_assert(cmp_e(world, array_of_array_of_struct_with_strings, e4, e5) < 0); + test_assert(cmp(world, array_of_array_of_struct_with_strings, e4, e5) < 0); /* Test "greater" */ /* {{"AA", 10, "CC"}, {"BB", 25, "DD"}} > {{"AA", 10, "CC"}, {"BB", 20, "DD"}} */ - test_assert(cmp_e(world, array_of_array_of_struct_with_strings, e2, e1) > 0); + test_assert(cmp(world, array_of_array_of_struct_with_strings, e2, e1) > 0); /* {{"AA", 15, "GG"}, {"BB", 30, "HH"}} > {{"AA", 5, "EE"}, {"ZZ", 20, "FF"}} */ - test_assert(cmp_e(world, array_of_array_of_struct_with_strings, e5, e4) > 0); + test_assert(cmp(world, array_of_array_of_struct_with_strings, e5, e4) > 0); /* Test "equal" */ /* {{"AA", 10, "CC"}, {"BB", 20, "DD"}} == {{"AA", 10, "CC"}, {"BB", 20, "DD"}} */ - test_assert(cmp_e(world, array_of_array_of_struct_with_strings, e1, e3) == 0); - test_assert(cmp_e(world, array_of_array_of_struct_with_strings, e1, e1) == 0); + test_assert(cmp(world, array_of_array_of_struct_with_strings, e1, e3) == 0); + test_assert(cmp(world, array_of_array_of_struct_with_strings, e1, e1) == 0); ecs_delete(world, e1); ecs_delete(world, e2); @@ -1638,18 +1636,18 @@ void RttCompare_array_of_vectors_of_ints(void) { v4_2[3] = 4; /* Test "less" */ - test_assert(cmp_e(world, array_of_vectors_of_ints, e1, e3) < 0); + test_assert(cmp(world, array_of_vectors_of_ints, e1, e3) < 0); /* Test "greater" */ - test_assert(cmp_e(world, array_of_vectors_of_ints, e3, e1) > 0); + test_assert(cmp(world, array_of_vectors_of_ints, e3, e1) > 0); /* Test "equal" */ - test_assert(cmp_e(world, array_of_vectors_of_ints, e1, e2) == 0); - test_assert(cmp_e(world, array_of_vectors_of_ints, e1, e1) == 0); + test_assert(cmp(world, array_of_vectors_of_ints, e1, e2) == 0); + test_assert(cmp(world, array_of_vectors_of_ints, e1, e1) == 0); /* Test when different in multiple fields */ - test_assert(cmp_e(world, array_of_vectors_of_ints, e1, e4) < 0); - test_assert(cmp_e(world, array_of_vectors_of_ints, e4, e1) > 0); + test_assert(cmp(world, array_of_vectors_of_ints, e1, e4) < 0); + test_assert(cmp(world, array_of_vectors_of_ints, e4, e1) > 0); ecs_delete(world, e1); ecs_delete(world, e2); @@ -1761,18 +1759,18 @@ void RttCompare_array_of_vectors_of_strings(void) { vec5_2[0] = ecs_os_strdup("II"); /* Test "less" */ - test_assert(cmp_e(world, array_of_vectors_of_strings, e2, e4) < 0); - test_assert(cmp_e(world, array_of_vectors_of_strings, e2, e1) < 0); - test_assert(cmp_e(world, array_of_vectors_of_strings, e1, e5) < 0); + test_assert(cmp(world, array_of_vectors_of_strings, e2, e4) < 0); + test_assert(cmp(world, array_of_vectors_of_strings, e2, e1) < 0); + test_assert(cmp(world, array_of_vectors_of_strings, e1, e5) < 0); /* Test "greater" */ - test_assert(cmp_e(world, array_of_vectors_of_strings, e5, e1) > 0); - test_assert(cmp_e(world, array_of_vectors_of_strings, e1, e2) > 0); - test_assert(cmp_e(world, array_of_vectors_of_strings, e4, e2) > 0); + test_assert(cmp(world, array_of_vectors_of_strings, e5, e1) > 0); + test_assert(cmp(world, array_of_vectors_of_strings, e1, e2) > 0); + test_assert(cmp(world, array_of_vectors_of_strings, e4, e2) > 0); /* Test "equal" */ - test_assert(cmp_e(world, array_of_vectors_of_strings, e1, e3) == 0); - test_assert(cmp_e(world, array_of_vectors_of_strings, e3, e1) == 0); + test_assert(cmp(world, array_of_vectors_of_strings, e1, e3) == 0); + test_assert(cmp(world, array_of_vectors_of_strings, e3, e1) == 0); ecs_delete(world, e1); ecs_delete(world, e2); @@ -1827,22 +1825,22 @@ void RttCompare_array_of_opaque(void) { /* Test "less" */ /* {5, 10, 15} < {5, 10, 20} */ - test_assert(cmp_e(world, array_of_opaque, e1, e2) < 0); + test_assert(cmp(world, array_of_opaque, e1, e2) < 0); /* {3, 10, 15} < {7, 8, 9} */ - test_assert(cmp_e(world, array_of_opaque, e5, e4) < 0); + test_assert(cmp(world, array_of_opaque, e5, e4) < 0); /* Test "greater" */ /* {5, 10, 20} > {5, 10, 15} */ - test_assert(cmp_e(world, array_of_opaque, e2, e1) > 0); + test_assert(cmp(world, array_of_opaque, e2, e1) > 0); /* {7, 8, 9} > {3, 10, 15} */ - test_assert(cmp_e(world, array_of_opaque, e4, e5) > 0); + test_assert(cmp(world, array_of_opaque, e4, e5) > 0); /* Test "equal" */ /* {5, 10, 15} == {5, 10, 15} */ - test_assert(cmp_e(world, array_of_opaque, e1, e3) == 0); - test_assert(cmp_e(world, array_of_opaque, e1, e1) == 0); + test_assert(cmp(world, array_of_opaque, e1, e3) == 0); + test_assert(cmp(world, array_of_opaque, e1, e1) == 0); ecs_delete(world, e1); ecs_delete(world, e2); @@ -1902,25 +1900,25 @@ void RttCompare_vector_of_ints(void) { /* Test "less" */ /* {10, 20, 30} < {10, 25, 30} */ - test_assert(cmp_e(world, vector_of_ints, e1, e2) < 0); + test_assert(cmp(world, vector_of_ints, e1, e2) < 0); /* {10, 20, 30} < {40, 50, 60} */ - test_assert(cmp_e(world, vector_of_ints, e1, e5) < 0); + test_assert(cmp(world, vector_of_ints, e1, e5) < 0); /* {10, 20} < {10, 20, 30} */ - test_assert(cmp_e(world, vector_of_ints, e4, e1) < 0); + test_assert(cmp(world, vector_of_ints, e4, e1) < 0); /* Test "greater" */ /* {10, 25, 30} > {10, 20, 30} */ - test_assert(cmp_e(world, vector_of_ints, e2, e1) > 0); + test_assert(cmp(world, vector_of_ints, e2, e1) > 0); /* {40, 50, 60} > {10, 20, 30} */ - test_assert(cmp_e(world, vector_of_ints, e5, e1) > 0); + test_assert(cmp(world, vector_of_ints, e5, e1) > 0); /* Test "equal" */ /* {10, 20, 30} == {10, 20, 30} */ - test_assert(cmp_e(world, vector_of_ints, e1, e3) == 0); - test_assert(cmp_e(world, vector_of_ints, e1, e1) == 0); + test_assert(cmp(world, vector_of_ints, e1, e3) == 0); + test_assert(cmp(world, vector_of_ints, e1, e1) == 0); ecs_delete(world, e1); ecs_delete(world, e2); @@ -1981,28 +1979,28 @@ void RttCompare_vector_of_strings(void) { /* Test "less" */ /* {"AA", "BB", "CC"} < {"AA", "BB", "DD"} */ - test_assert(cmp_e(world, vector_of_strings, e1, e2) < 0); + test_assert(cmp(world, vector_of_strings, e1, e2) < 0); /* {"AA", "AA", "BB"} < {"AA", "BB", "CC"} */ - test_assert(cmp_e(world, vector_of_strings, e5, e1) < 0); + test_assert(cmp(world, vector_of_strings, e5, e1) < 0); /* {"AA", "BB", "DD"} < {"ZZ", "AA", "DD"} */ - test_assert(cmp_e(world, vector_of_strings, e2, e4) < 0); + test_assert(cmp(world, vector_of_strings, e2, e4) < 0); /* Test "greater" */ /* {"AA", "BB", "DD"} > {"AA", "BB", "CC"} */ - test_assert(cmp_e(world, vector_of_strings, e2, e1) > 0); + test_assert(cmp(world, vector_of_strings, e2, e1) > 0); /* {"ZZ", "AA", "DD"} > {"AA", "BB", "DD"} */ - test_assert(cmp_e(world, vector_of_strings, e4, e2) > 0); + test_assert(cmp(world, vector_of_strings, e4, e2) > 0); /* {"AA", "BB", "CC"} > {"AA", "AA", "BB"} */ - test_assert(cmp_e(world, vector_of_strings, e1, e5) > 0); + test_assert(cmp(world, vector_of_strings, e1, e5) > 0); /* Test "equal" */ /* {"AA", "BB", "CC"} == {"AA", "BB", "CC"} */ - test_assert(cmp_e(world, vector_of_strings, e1, e3) == 0); - test_assert(cmp_e(world, vector_of_strings, e1, e1) == 0); + test_assert(cmp(world, vector_of_strings, e1, e3) == 0); + test_assert(cmp(world, vector_of_strings, e1, e1) == 0); ecs_delete(world, e1); ecs_delete(world, e2); @@ -2059,16 +2057,16 @@ void RttCompare_vector_of_struct_with_ints(void) { /* Test "less" */ /* vec1 < vec2 because v1[2].a < v2[2].a */ - test_assert(cmp_e(world, vector_of_struct_with_ints, e1, e2) < 0); + test_assert(cmp(world, vector_of_struct_with_ints, e1, e2) < 0); /* Test "greater" */ /* vec2 > vec1 because v2[2].a > v1[2].a */ - test_assert(cmp_e(world, vector_of_struct_with_ints, e2, e1) > 0); + test_assert(cmp(world, vector_of_struct_with_ints, e2, e1) > 0); /* Test "equal" */ /* vec1 == vec3 as they have identical values */ - test_assert(cmp_e(world, vector_of_struct_with_ints, e1, e3) == 0); - test_assert(cmp_e(world, vector_of_struct_with_ints, e1, e1) == 0); + test_assert(cmp(world, vector_of_struct_with_ints, e1, e3) == 0); + test_assert(cmp(world, vector_of_struct_with_ints, e1, e1) == 0); ecs_delete(world, e1); ecs_delete(world, e2); @@ -2142,21 +2140,21 @@ void RttCompare_vector_of_struct_with_strings(void) { /* Test "less" */ /* vec1 < vec2, because {10} < {20} */ - test_assert(cmp_e(world, vector_of_struct_with_strings, e1, e2) < 0); + test_assert(cmp(world, vector_of_struct_with_strings, e1, e2) < 0); /* vec4 < vec1, because vec4 has fewer elements */ - test_assert(cmp_e(world, vector_of_struct_with_strings, e4, e1) < 0); + test_assert(cmp(world, vector_of_struct_with_strings, e4, e1) < 0); /* Test "greater" */ /* vec2 > vec1, because {20} > {10} */ - test_assert(cmp_e(world, vector_of_struct_with_strings, e2, e1) > 0); + test_assert(cmp(world, vector_of_struct_with_strings, e2, e1) > 0); /* vec1 > vec4, because vec1 has more elements */ - test_assert(cmp_e(world, vector_of_struct_with_strings, e1, e4) > 0); + test_assert(cmp(world, vector_of_struct_with_strings, e1, e4) > 0); /* Test "equal" */ /* vec1 == vec3, all elements are identical */ - test_assert(cmp_e(world, vector_of_struct_with_strings, e1, e3) == 0); + test_assert(cmp(world, vector_of_struct_with_strings, e1, e3) == 0); ecs_delete(world, e1); ecs_delete(world, e2); @@ -2219,25 +2217,25 @@ void RttCompare_vector_of_arrays_of_strings(void) { /* Test "less" */ /* {"AA", "BB", "CC"} < {"AA", "ZZ", "CC"} */ - test_assert(cmp_e(world, vector_of_arrays_of_strings, e1, e3) < 0); + test_assert(cmp(world, vector_of_arrays_of_strings, e1, e3) < 0); /* {"AA", "BB", "CC"} < {"ZZ", "AA", "DD"} */ - test_assert(cmp_e(world, vector_of_arrays_of_strings, e1, e4) < 0); + test_assert(cmp(world, vector_of_arrays_of_strings, e1, e4) < 0); /* {"AA", "BB", "DD"} < {"ZZ", "AA", "DD"} */ - test_assert(cmp_e(world, vector_of_arrays_of_strings, e5, e4) < 0); + test_assert(cmp(world, vector_of_arrays_of_strings, e5, e4) < 0); /* Test "greater" */ /* {"ZZ", "AA", "DD"} > {"AA", "BB", "CC"} */ - test_assert(cmp_e(world, vector_of_arrays_of_strings, e4, e1) > 0); + test_assert(cmp(world, vector_of_arrays_of_strings, e4, e1) > 0); /* {"AA", "ZZ", "CC"} > {"AA", "BB", "CC"} */ - test_assert(cmp_e(world, vector_of_arrays_of_strings, e3, e1) > 0); + test_assert(cmp(world, vector_of_arrays_of_strings, e3, e1) > 0); /* Test "equal" */ /* {"AA", "BB", "CC"} == {"AA", "BB", "CC"} */ - test_assert(cmp_e(world, vector_of_arrays_of_strings, e1, e2) == 0); - test_assert(cmp_e(world, vector_of_arrays_of_strings, e1, e1) == 0); + test_assert(cmp(world, vector_of_arrays_of_strings, e1, e2) == 0); + test_assert(cmp(world, vector_of_arrays_of_strings, e1, e1) == 0); ecs_delete(world, e1); ecs_delete(world, e2); @@ -2300,22 +2298,22 @@ void RttCompare_vector_of_opaque(void) { /* Test "less" */ /* {10, 20, 30} < {10, 25, 30} */ - test_assert(cmp_e(world, vector_of_opaque, e1, e2) < 0); + test_assert(cmp(world, vector_of_opaque, e1, e2) < 0); /* {5, 15} < {10, 20, 30} */ - test_assert(cmp_e(world, vector_of_opaque, e4, e1) < 0); + test_assert(cmp(world, vector_of_opaque, e4, e1) < 0); /* Test "greater" */ /* {10, 25, 30} > {10, 20, 30} */ - test_assert(cmp_e(world, vector_of_opaque, e2, e1) > 0); + test_assert(cmp(world, vector_of_opaque, e2, e1) > 0); /* {10, 20, 30, 35} > {10, 20, 30} */ - test_assert(cmp_e(world, vector_of_opaque, e5, e1) > 0); + test_assert(cmp(world, vector_of_opaque, e5, e1) > 0); /* Test "equal" */ /* {10, 20, 30} == {10, 20, 30} */ - test_assert(cmp_e(world, vector_of_opaque, e1, e3) == 0); - test_assert(cmp_e(world, vector_of_opaque, e1, e1) == 0); + test_assert(cmp(world, vector_of_opaque, e1, e3) == 0); + test_assert(cmp(world, vector_of_opaque, e1, e1) == 0); ecs_delete(world, e1); ecs_delete(world, e2); diff --git a/test/meta/src/RuntimeTypes.c b/test/meta/src/RuntimeTypes.c index 302aea66c..314098297 100644 --- a/test/meta/src/RuntimeTypes.c +++ b/test/meta/src/RuntimeTypes.c @@ -216,6 +216,7 @@ const ecs_type_info_t *define_test_struct( } /* Compares two instances of the given type */ +static int compare(const ecs_world_t* world, ecs_entity_t id, const void *a, const void *b) { const ecs_type_info_t* ti = ecs_get_type_info(world, id); return ti->hooks.comp(a, b, ti); From 5339e697576fb27842392216ba1b5e284c3b0d85 Mon Sep 17 00:00:00 2001 From: Javier Peletier Date: Fri, 29 Nov 2024 11:08:35 +0100 Subject: [PATCH 13/23] Rename comp to cmp for clarity --- distr/flecs.c | 62 +++++++++---------- distr/flecs.h | 29 ++++----- include/flecs.h | 14 ++--- include/flecs/addons/cpp/component.hpp | 10 +-- include/flecs/addons/cpp/lifecycle_traits.hpp | 5 +- src/addons/meta/definitions.c | 2 +- src/addons/meta/meta.c | 2 +- src/addons/meta/rtt_lifecycle.c | 46 +++++++------- src/world.c | 12 ++-- test/cpp/src/ComponentLifecycle.cpp | 6 +- test/meta/src/PrimitiveCompare.c | 2 +- test/meta/src/RttCompare.c | 4 +- test/meta/src/RuntimeTypes.c | 40 ++++++------ 13 files changed, 112 insertions(+), 122 deletions(-) diff --git a/distr/flecs.c b/distr/flecs.c index 430b6dba1..4464bdbb6 100644 --- a/distr/flecs.c +++ b/distr/flecs.c @@ -19075,9 +19075,9 @@ void ecs_set_hooks_id( h->move_dtor != flecs_move_ctor_illegal), ECS_INVALID_PARAMETER, "cannot specify both move dtor hook and illegal flag"); - ecs_check(!(flags & ECS_TYPE_HOOK_COMP_ILLEGAL && - h->comp != NULL && - h->comp != flecs_comp_illegal), + ecs_check(!(flags & ECS_TYPE_HOOK_CMP_ILLEGAL && + h->cmp != NULL && + h->cmp != flecs_comp_illegal), ECS_INVALID_PARAMETER, "cannot specify both compare hook and illegal flag"); @@ -19118,7 +19118,7 @@ void ecs_set_hooks_id( if (h->move_ctor) ti->hooks.move_ctor = h->move_ctor; if (h->ctor_move_dtor) ti->hooks.ctor_move_dtor = h->ctor_move_dtor; if (h->move_dtor) ti->hooks.move_dtor = h->move_dtor; - if (h->comp) ti->hooks.comp = h->comp; + if (h->cmp) ti->hooks.cmp = h->cmp; if (h->on_add) ti->hooks.on_add = h->on_add; if (h->on_remove) ti->hooks.on_remove = h->on_remove; @@ -19227,13 +19227,13 @@ void ecs_set_hooks_id( 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 (ti->hooks.comp) ti->hooks.flags |= ECS_TYPE_HOOK_COMP; + if (ti->hooks.cmp) ti->hooks.flags |= ECS_TYPE_HOOK_CMP; 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_TYPE_HOOK_COMP_ILLEGAL) ti->hooks.comp = flecs_comp_illegal; + if(flags & ECS_TYPE_HOOK_CMP_ILLEGAL) ti->hooks.cmp = flecs_comp_illegal; if(flags & ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL) { ti->hooks.copy_ctor = flecs_copy_ctor_illegal; @@ -49697,7 +49697,7 @@ void flecs_meta_import_core_definitions( .size = ECS_SIZEOF(const char*), .alignment = ECS_ALIGNOF(const char*), .hooks = { - .comp = ecs_compare_string, + .cmp = ecs_compare_string, } } }), @@ -51568,7 +51568,7 @@ void FlecsMetaImport( .kind = primitive_kind\ });\ ecs_set_hooks(world, ecs_##type##_t, { \ - .comp = ecs_compare_##type \ + .cmp = ecs_compare_##type \ }) ECS_PRIMITIVE(world, bool, EcsBool); @@ -51630,7 +51630,7 @@ typedef struct ecs_rtt_call_data_t { ecs_xtor_t xtor; ecs_move_t move; ecs_copy_t copy; - ecs_comp_t comp; + ecs_cmp_t cmp; } hook; const ecs_type_info_t *type_info; int32_t offset; @@ -51820,7 +51820,7 @@ int flecs_rtt_struct_comp( for (i = 0; i < cb_count; i++) { ecs_rtt_call_data_t *comp_data = ecs_vec_get_t(&rtt_ctx->vcomp, ecs_rtt_call_data_t, i); - int c = comp_data->hook.comp( + int c = comp_data->hook.cmp( ECS_OFFSET(a_ptr, comp_data->offset), ECS_OFFSET(b_ptr, comp_data->offset), comp_data->type_info); @@ -51866,7 +51866,7 @@ ecs_rtt_struct_ctx_t * flecs_rtt_configure_struct_hooks( ecs_xtor_t dtor, ecs_move_t move, ecs_copy_t copy, - ecs_comp_t comp) + ecs_cmp_t cmp) { ecs_type_hooks_t hooks = ti->hooks; if (hooks.lifecycle_ctx_free) { @@ -51885,12 +51885,12 @@ ecs_rtt_struct_ctx_t * flecs_rtt_configure_struct_hooks( if(flags & ECS_TYPE_HOOK_COPY_ILLEGAL) { copy = NULL; } - if(flags & ECS_TYPE_HOOK_COMP_ILLEGAL) { - comp = NULL; + if(flags & ECS_TYPE_HOOK_CMP_ILLEGAL) { + cmp = NULL; } ecs_rtt_struct_ctx_t *rtt_ctx = NULL; - if (ctor || dtor || move || copy || comp) { + if (ctor || dtor || move || copy || cmp) { rtt_ctx = ecs_os_malloc_t(ecs_rtt_struct_ctx_t); ecs_vec_init_t(NULL, &rtt_ctx->vctor, ecs_rtt_call_data_t, 0); ecs_vec_init_t(NULL, &rtt_ctx->vdtor, ecs_rtt_call_data_t, 0); @@ -51908,7 +51908,7 @@ ecs_rtt_struct_ctx_t * flecs_rtt_configure_struct_hooks( hooks.dtor = dtor; hooks.move = move; hooks.copy = copy; - hooks.comp = comp; + hooks.cmp = cmp; hooks.flags = flags; hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; @@ -51953,7 +51953,7 @@ void flecs_rtt_init_default_hooks_struct( /* A struct is comparable if all its members * are comparable */ - comparable &= member_ti->hooks.comp != NULL; + comparable &= member_ti->hooks.cmp != NULL; flags |= member_ti->hooks.flags; } @@ -52031,8 +52031,8 @@ void flecs_rtt_init_default_hooks_struct( comp_data->offset = m->offset; comp_data->type_info = member_ti; comp_data->count = 1; - ecs_assert(member_ti->hooks.comp, ECS_INTERNAL_ERROR, NULL); - comp_data->hook.comp = member_ti->hooks.comp; + ecs_assert(member_ti->hooks.cmp, ECS_INTERNAL_ERROR, NULL); + comp_data->hook.cmp = member_ti->hooks.cmp; } } } @@ -52143,14 +52143,14 @@ int flecs_rtt_array_comp( } ecs_rtt_array_ctx_t *rtt_ctx = type_info->hooks.lifecycle_ctx; - ecs_comp_t comp = rtt_ctx->type_info->hooks.comp; - ecs_assert(comp, ECS_INVALID_PARAMETER, NULL); + ecs_cmp_t cmp = rtt_ctx->type_info->hooks.cmp; + ecs_assert(cmp, ECS_INVALID_PARAMETER, NULL); ecs_size_t element_size = rtt_ctx->type_info->size; int i; for (i = 0; i < rtt_ctx->elem_count; i++) { const void *a_element = ECS_ELEM(a_ptr, element_size, i); const void *b_element = ECS_ELEM(b_ptr, element_size, i); - int c = comp(a_element, b_element, rtt_ctx->type_info); + int c = cmp(a_element, b_element, rtt_ctx->type_info); if(c != 0) { return c; } @@ -52175,7 +52175,7 @@ void flecs_rtt_init_default_hooks_array( bool dtor_hook_required = element_ti->hooks.dtor != NULL; bool move_hook_required = element_ti->hooks.move != NULL; bool copy_hook_required = element_ti->hooks.copy != NULL; - bool comparable = element_ti->hooks.comp != NULL; + bool comparable = element_ti->hooks.cmp != NULL; ecs_flags32_t flags = element_ti->hooks.flags; @@ -52189,7 +52189,7 @@ void flecs_rtt_init_default_hooks_array( flecs_rtt_array_move : NULL; hooks.copy = copy_hook_required && !(flags & ECS_TYPE_HOOK_COPY_ILLEGAL) ? flecs_rtt_array_copy : NULL; - hooks.comp = comparable && !(flags & ECS_TYPE_HOOK_COMP_ILLEGAL) ? + hooks.cmp = comparable && !(flags & ECS_TYPE_HOOK_CMP_ILLEGAL) ? flecs_rtt_array_comp : NULL; if (hooks.lifecycle_ctx_free) { @@ -52198,7 +52198,7 @@ void flecs_rtt_init_default_hooks_array( } if (hooks.ctor || hooks.dtor || hooks.move || - hooks.copy || hooks.comp) + hooks.copy || hooks.cmp) { ecs_rtt_array_ctx_t *rtt_ctx = ecs_os_malloc_t(ecs_rtt_array_ctx_t); rtt_ctx->type_info = element_ti; @@ -52349,8 +52349,8 @@ int flecs_rtt_vector_comp( } ecs_rtt_vector_ctx_t *rtt_ctx = type_info->hooks.lifecycle_ctx; - ecs_comp_t comp = rtt_ctx->type_info->hooks.comp; - ecs_assert(comp, ECS_INVALID_PARAMETER, NULL); + ecs_cmp_t cmp = rtt_ctx->type_info->hooks.cmp; + ecs_assert(cmp, ECS_INVALID_PARAMETER, NULL); ecs_size_t element_size = rtt_ctx->type_info->size; const void *a = ecs_vec_first(vec_a); @@ -52360,7 +52360,7 @@ int flecs_rtt_vector_comp( for (i = 0; i < count_a; i++) { const void *a_element = ECS_ELEM(a, element_size, i); const void *b_element = ECS_ELEM(b, element_size, i); - int c = comp(a_element, b_element, rtt_ctx->type_info); + int c = cmp(a_element, b_element, rtt_ctx->type_info); if(c != 0) { return c; } @@ -52398,14 +52398,14 @@ void flecs_rtt_init_default_hooks_vector( hooks.move = flecs_rtt_vector_move; hooks.copy = flecs_rtt_vector_copy; - if (element_ti->hooks.comp != NULL && !(flags & ECS_TYPE_HOOK_COMP_ILLEGAL)) { - hooks.comp = flecs_rtt_vector_comp; + if (element_ti->hooks.cmp != NULL && !(flags & ECS_TYPE_HOOK_CMP_ILLEGAL)) { + hooks.cmp = flecs_rtt_vector_comp; } else { - hooks.comp = NULL; + hooks.cmp = NULL; } /* propagate only the compare hook illegal flag, if set */ - hooks.flags |= flags & ECS_TYPE_HOOK_COMP_ILLEGAL; + hooks.flags |= flags & ECS_TYPE_HOOK_CMP_ILLEGAL; hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id(world, component, &hooks); diff --git a/distr/flecs.h b/distr/flecs.h index ab6faf413..05ef7f9ff 100644 --- a/distr/flecs.h +++ b/distr/flecs.h @@ -3314,7 +3314,7 @@ typedef void (*ecs_move_t)( const ecs_type_info_t *type_info); /** Compare hook to compare component instances */ -typedef int (*ecs_comp_t)( +typedef int (*ecs_cmp_t)( const void *a_ptr, const void *b_ptr, const ecs_type_info_t *type_info); @@ -3545,7 +3545,7 @@ struct ecs_observer_t { #define ECS_TYPE_HOOK_MOVE_CTOR (1 << 5) #define ECS_TYPE_HOOK_CTOR_MOVE_DTOR (1 << 6) #define ECS_TYPE_HOOK_MOVE_DTOR (1 << 7) -#define ECS_TYPE_HOOK_COMP (1 << 8) +#define ECS_TYPE_HOOK_CMP (1 << 8) /* Flags that can be used to set/check which hooks of a type are invalid */ @@ -3557,20 +3557,20 @@ struct ecs_observer_t { #define ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL (1 << 14) #define ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL (1 << 15) #define ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL (1 << 16) -#define ECS_TYPE_HOOK_COMP_ILLEGAL (1 << 17) +#define ECS_TYPE_HOOK_CMP_ILLEGAL (1 << 17) /* All valid hook flags */ #define ECS_TYPE_HOOKS (ECS_TYPE_HOOK_CTOR|ECS_TYPE_HOOK_DTOR|\ ECS_TYPE_HOOK_COPY|ECS_TYPE_HOOK_MOVE|ECS_TYPE_HOOK_COPY_CTOR|\ ECS_TYPE_HOOK_MOVE_CTOR|ECS_TYPE_HOOK_CTOR_MOVE_DTOR|\ - ECS_TYPE_HOOK_MOVE_DTOR|ECS_TYPE_HOOK_COMP) + ECS_TYPE_HOOK_MOVE_DTOR|ECS_TYPE_HOOK_CMP) /* All invalid hook flags */ #define ECS_TYPE_HOOKS_ILLEGAL (ECS_TYPE_HOOK_CTOR_ILLEGAL|\ ECS_TYPE_HOOK_DTOR_ILLEGAL|ECS_TYPE_HOOK_COPY_ILLEGAL|\ ECS_TYPE_HOOK_MOVE_ILLEGAL|ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL|\ ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL|ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL|\ - ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL|ECS_TYPE_HOOK_COMP_ILLEGAL) + ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL|ECS_TYPE_HOOK_CMP_ILLEGAL) struct ecs_type_hooks_t { ecs_xtor_t ctor; /**< ctor */ @@ -3597,8 +3597,8 @@ struct ecs_type_hooks_t { ecs_move_t move_dtor; /** Compare hook */ - ecs_comp_t comp; - + ecs_cmp_t cmp; + /** Hook flags. * Indicates which hooks are set for the type, and which hooks are illegal. * When an ILLEGAL flag is set when calling ecs_set_hooks() a hook callback @@ -20625,14 +20625,15 @@ int compare_impl(const void *a, const void *b, const ecs_type_info_t *) { template ::value || has_operator_greater::value > = 0> -ecs_comp_t compare() { +ecs_cmp_t compare(ecs_flags32_t &) { return compare_impl; } template ::value && !has_operator_greater::value > = 0> -ecs_comp_t compare() { +ecs_cmp_t compare(ecs_flags32_t &flags) { + flags |= ECS_TYPE_HOOK_CMP_ILLEGAL; return NULL; } @@ -26983,10 +26984,7 @@ void register_lifecycle_actions( } ecs_type_hooks_t cl{}; - cl.comp = compare(); - if(cl.comp == NULL) { - cl.flags |= ECS_TYPE_HOOK_COMP_ILLEGAL; - } + cl.cmp = compare(cl.flags); cl.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id(world, component, &cl); @@ -27013,10 +27011,7 @@ void register_lifecycle_actions( cl.ctor_move_dtor = ctor_move_dtor(cl.flags); cl.move_dtor = move_dtor(cl.flags); - cl.comp = compare(); - if(cl.comp == NULL) { - cl.flags |= ECS_TYPE_HOOK_COMP_ILLEGAL; - } + cl.cmp = compare(cl.flags); cl.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id(world, component, &cl); diff --git a/include/flecs.h b/include/flecs.h index 5e2f218ec..d92a1ccbb 100644 --- a/include/flecs.h +++ b/include/flecs.h @@ -646,7 +646,7 @@ typedef void (*ecs_move_t)( const ecs_type_info_t *type_info); /** Compare hook to compare component instances */ -typedef int (*ecs_comp_t)( +typedef int (*ecs_cmp_t)( const void *a_ptr, const void *b_ptr, const ecs_type_info_t *type_info); @@ -877,7 +877,7 @@ struct ecs_observer_t { #define ECS_TYPE_HOOK_MOVE_CTOR (1 << 5) #define ECS_TYPE_HOOK_CTOR_MOVE_DTOR (1 << 6) #define ECS_TYPE_HOOK_MOVE_DTOR (1 << 7) -#define ECS_TYPE_HOOK_COMP (1 << 8) +#define ECS_TYPE_HOOK_CMP (1 << 8) /* Flags that can be used to set/check which hooks of a type are invalid */ @@ -889,20 +889,20 @@ struct ecs_observer_t { #define ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL (1 << 14) #define ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL (1 << 15) #define ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL (1 << 16) -#define ECS_TYPE_HOOK_COMP_ILLEGAL (1 << 17) +#define ECS_TYPE_HOOK_CMP_ILLEGAL (1 << 17) /* All valid hook flags */ #define ECS_TYPE_HOOKS (ECS_TYPE_HOOK_CTOR|ECS_TYPE_HOOK_DTOR|\ ECS_TYPE_HOOK_COPY|ECS_TYPE_HOOK_MOVE|ECS_TYPE_HOOK_COPY_CTOR|\ ECS_TYPE_HOOK_MOVE_CTOR|ECS_TYPE_HOOK_CTOR_MOVE_DTOR|\ - ECS_TYPE_HOOK_MOVE_DTOR|ECS_TYPE_HOOK_COMP) + ECS_TYPE_HOOK_MOVE_DTOR|ECS_TYPE_HOOK_CMP) /* All invalid hook flags */ #define ECS_TYPE_HOOKS_ILLEGAL (ECS_TYPE_HOOK_CTOR_ILLEGAL|\ ECS_TYPE_HOOK_DTOR_ILLEGAL|ECS_TYPE_HOOK_COPY_ILLEGAL|\ ECS_TYPE_HOOK_MOVE_ILLEGAL|ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL|\ ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL|ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL|\ - ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL|ECS_TYPE_HOOK_COMP_ILLEGAL) + ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL|ECS_TYPE_HOOK_CMP_ILLEGAL) struct ecs_type_hooks_t { ecs_xtor_t ctor; /**< ctor */ @@ -929,8 +929,8 @@ struct ecs_type_hooks_t { ecs_move_t move_dtor; /** Compare hook */ - ecs_comp_t comp; - + ecs_cmp_t cmp; + /** Hook flags. * Indicates which hooks are set for the type, and which hooks are illegal. * When an ILLEGAL flag is set when calling ecs_set_hooks() a hook callback diff --git a/include/flecs/addons/cpp/component.hpp b/include/flecs/addons/cpp/component.hpp index 3bf799c47..ffa853ed3 100644 --- a/include/flecs/addons/cpp/component.hpp +++ b/include/flecs/addons/cpp/component.hpp @@ -101,10 +101,7 @@ void register_lifecycle_actions( } ecs_type_hooks_t cl{}; - cl.comp = compare(); - if(cl.comp == NULL) { - cl.flags |= ECS_TYPE_HOOK_COMP_ILLEGAL; - } + cl.cmp = compare(cl.flags); cl.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id(world, component, &cl); @@ -131,10 +128,7 @@ void register_lifecycle_actions( cl.ctor_move_dtor = ctor_move_dtor(cl.flags); cl.move_dtor = move_dtor(cl.flags); - cl.comp = compare(); - if(cl.comp == NULL) { - cl.flags |= ECS_TYPE_HOOK_COMP_ILLEGAL; - } + cl.cmp = compare(cl.flags); cl.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id(world, component, &cl); diff --git a/include/flecs/addons/cpp/lifecycle_traits.hpp b/include/flecs/addons/cpp/lifecycle_traits.hpp index 0d29a8055..aa32cd689 100644 --- a/include/flecs/addons/cpp/lifecycle_traits.hpp +++ b/include/flecs/addons/cpp/lifecycle_traits.hpp @@ -460,14 +460,15 @@ int compare_impl(const void *a, const void *b, const ecs_type_info_t *) { template ::value || has_operator_greater::value > = 0> -ecs_comp_t compare() { +ecs_cmp_t compare(ecs_flags32_t &) { return compare_impl; } template ::value && !has_operator_greater::value > = 0> -ecs_comp_t compare() { +ecs_cmp_t compare(ecs_flags32_t &flags) { + flags |= ECS_TYPE_HOOK_CMP_ILLEGAL; return NULL; } diff --git a/src/addons/meta/definitions.c b/src/addons/meta/definitions.c index d237bb21a..c8bb9b5cc 100644 --- a/src/addons/meta/definitions.c +++ b/src/addons/meta/definitions.c @@ -73,7 +73,7 @@ void flecs_meta_import_core_definitions( .size = ECS_SIZEOF(const char*), .alignment = ECS_ALIGNOF(const char*), .hooks = { - .comp = ecs_compare_string, + .cmp = ecs_compare_string, } } }), diff --git a/src/addons/meta/meta.c b/src/addons/meta/meta.c index e2c871ff1..d5f7d34dd 100644 --- a/src/addons/meta/meta.c +++ b/src/addons/meta/meta.c @@ -1621,7 +1621,7 @@ void FlecsMetaImport( .kind = primitive_kind\ });\ ecs_set_hooks(world, ecs_##type##_t, { \ - .comp = ecs_compare_##type \ + .cmp = ecs_compare_##type \ }) ECS_PRIMITIVE(world, bool, EcsBool); diff --git a/src/addons/meta/rtt_lifecycle.c b/src/addons/meta/rtt_lifecycle.c index 3869a6a21..632e40b3e 100644 --- a/src/addons/meta/rtt_lifecycle.c +++ b/src/addons/meta/rtt_lifecycle.c @@ -15,7 +15,7 @@ typedef struct ecs_rtt_call_data_t { ecs_xtor_t xtor; ecs_move_t move; ecs_copy_t copy; - ecs_comp_t comp; + ecs_cmp_t cmp; } hook; const ecs_type_info_t *type_info; int32_t offset; @@ -205,7 +205,7 @@ int flecs_rtt_struct_comp( for (i = 0; i < cb_count; i++) { ecs_rtt_call_data_t *comp_data = ecs_vec_get_t(&rtt_ctx->vcomp, ecs_rtt_call_data_t, i); - int c = comp_data->hook.comp( + int c = comp_data->hook.cmp( ECS_OFFSET(a_ptr, comp_data->offset), ECS_OFFSET(b_ptr, comp_data->offset), comp_data->type_info); @@ -251,7 +251,7 @@ ecs_rtt_struct_ctx_t * flecs_rtt_configure_struct_hooks( ecs_xtor_t dtor, ecs_move_t move, ecs_copy_t copy, - ecs_comp_t comp) + ecs_cmp_t cmp) { ecs_type_hooks_t hooks = ti->hooks; if (hooks.lifecycle_ctx_free) { @@ -270,12 +270,12 @@ ecs_rtt_struct_ctx_t * flecs_rtt_configure_struct_hooks( if(flags & ECS_TYPE_HOOK_COPY_ILLEGAL) { copy = NULL; } - if(flags & ECS_TYPE_HOOK_COMP_ILLEGAL) { - comp = NULL; + if(flags & ECS_TYPE_HOOK_CMP_ILLEGAL) { + cmp = NULL; } ecs_rtt_struct_ctx_t *rtt_ctx = NULL; - if (ctor || dtor || move || copy || comp) { + if (ctor || dtor || move || copy || cmp) { rtt_ctx = ecs_os_malloc_t(ecs_rtt_struct_ctx_t); ecs_vec_init_t(NULL, &rtt_ctx->vctor, ecs_rtt_call_data_t, 0); ecs_vec_init_t(NULL, &rtt_ctx->vdtor, ecs_rtt_call_data_t, 0); @@ -293,7 +293,7 @@ ecs_rtt_struct_ctx_t * flecs_rtt_configure_struct_hooks( hooks.dtor = dtor; hooks.move = move; hooks.copy = copy; - hooks.comp = comp; + hooks.cmp = cmp; hooks.flags = flags; hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; @@ -338,7 +338,7 @@ void flecs_rtt_init_default_hooks_struct( /* A struct is comparable if all its members * are comparable */ - comparable &= member_ti->hooks.comp != NULL; + comparable &= member_ti->hooks.cmp != NULL; flags |= member_ti->hooks.flags; } @@ -416,8 +416,8 @@ void flecs_rtt_init_default_hooks_struct( comp_data->offset = m->offset; comp_data->type_info = member_ti; comp_data->count = 1; - ecs_assert(member_ti->hooks.comp, ECS_INTERNAL_ERROR, NULL); - comp_data->hook.comp = member_ti->hooks.comp; + ecs_assert(member_ti->hooks.cmp, ECS_INTERNAL_ERROR, NULL); + comp_data->hook.cmp = member_ti->hooks.cmp; } } } @@ -528,14 +528,14 @@ int flecs_rtt_array_comp( } ecs_rtt_array_ctx_t *rtt_ctx = type_info->hooks.lifecycle_ctx; - ecs_comp_t comp = rtt_ctx->type_info->hooks.comp; - ecs_assert(comp, ECS_INVALID_PARAMETER, NULL); + ecs_cmp_t cmp = rtt_ctx->type_info->hooks.cmp; + ecs_assert(cmp, ECS_INVALID_PARAMETER, NULL); ecs_size_t element_size = rtt_ctx->type_info->size; int i; for (i = 0; i < rtt_ctx->elem_count; i++) { const void *a_element = ECS_ELEM(a_ptr, element_size, i); const void *b_element = ECS_ELEM(b_ptr, element_size, i); - int c = comp(a_element, b_element, rtt_ctx->type_info); + int c = cmp(a_element, b_element, rtt_ctx->type_info); if(c != 0) { return c; } @@ -560,7 +560,7 @@ void flecs_rtt_init_default_hooks_array( bool dtor_hook_required = element_ti->hooks.dtor != NULL; bool move_hook_required = element_ti->hooks.move != NULL; bool copy_hook_required = element_ti->hooks.copy != NULL; - bool comparable = element_ti->hooks.comp != NULL; + bool comparable = element_ti->hooks.cmp != NULL; ecs_flags32_t flags = element_ti->hooks.flags; @@ -574,7 +574,7 @@ void flecs_rtt_init_default_hooks_array( flecs_rtt_array_move : NULL; hooks.copy = copy_hook_required && !(flags & ECS_TYPE_HOOK_COPY_ILLEGAL) ? flecs_rtt_array_copy : NULL; - hooks.comp = comparable && !(flags & ECS_TYPE_HOOK_COMP_ILLEGAL) ? + hooks.cmp = comparable && !(flags & ECS_TYPE_HOOK_CMP_ILLEGAL) ? flecs_rtt_array_comp : NULL; if (hooks.lifecycle_ctx_free) { @@ -583,7 +583,7 @@ void flecs_rtt_init_default_hooks_array( } if (hooks.ctor || hooks.dtor || hooks.move || - hooks.copy || hooks.comp) + hooks.copy || hooks.cmp) { ecs_rtt_array_ctx_t *rtt_ctx = ecs_os_malloc_t(ecs_rtt_array_ctx_t); rtt_ctx->type_info = element_ti; @@ -734,8 +734,8 @@ int flecs_rtt_vector_comp( } ecs_rtt_vector_ctx_t *rtt_ctx = type_info->hooks.lifecycle_ctx; - ecs_comp_t comp = rtt_ctx->type_info->hooks.comp; - ecs_assert(comp, ECS_INVALID_PARAMETER, NULL); + ecs_cmp_t cmp = rtt_ctx->type_info->hooks.cmp; + ecs_assert(cmp, ECS_INVALID_PARAMETER, NULL); ecs_size_t element_size = rtt_ctx->type_info->size; const void *a = ecs_vec_first(vec_a); @@ -745,7 +745,7 @@ int flecs_rtt_vector_comp( for (i = 0; i < count_a; i++) { const void *a_element = ECS_ELEM(a, element_size, i); const void *b_element = ECS_ELEM(b, element_size, i); - int c = comp(a_element, b_element, rtt_ctx->type_info); + int c = cmp(a_element, b_element, rtt_ctx->type_info); if(c != 0) { return c; } @@ -783,14 +783,14 @@ void flecs_rtt_init_default_hooks_vector( hooks.move = flecs_rtt_vector_move; hooks.copy = flecs_rtt_vector_copy; - if (element_ti->hooks.comp != NULL && !(flags & ECS_TYPE_HOOK_COMP_ILLEGAL)) { - hooks.comp = flecs_rtt_vector_comp; + if (element_ti->hooks.cmp != NULL && !(flags & ECS_TYPE_HOOK_CMP_ILLEGAL)) { + hooks.cmp = flecs_rtt_vector_comp; } else { - hooks.comp = NULL; + hooks.cmp = NULL; } /* propagate only the compare hook illegal flag, if set */ - hooks.flags |= flags & ECS_TYPE_HOOK_COMP_ILLEGAL; + hooks.flags |= flags & ECS_TYPE_HOOK_CMP_ILLEGAL; hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id(world, component, &hooks); diff --git a/src/world.c b/src/world.c index 63d8fe91b..c6a5e4363 100644 --- a/src/world.c +++ b/src/world.c @@ -1315,9 +1315,9 @@ void ecs_set_hooks_id( h->move_dtor != flecs_move_ctor_illegal), ECS_INVALID_PARAMETER, "cannot specify both move dtor hook and illegal flag"); - ecs_check(!(flags & ECS_TYPE_HOOK_COMP_ILLEGAL && - h->comp != NULL && - h->comp != flecs_comp_illegal), + ecs_check(!(flags & ECS_TYPE_HOOK_CMP_ILLEGAL && + h->cmp != NULL && + h->cmp != flecs_comp_illegal), ECS_INVALID_PARAMETER, "cannot specify both compare hook and illegal flag"); @@ -1358,7 +1358,7 @@ void ecs_set_hooks_id( if (h->move_ctor) ti->hooks.move_ctor = h->move_ctor; if (h->ctor_move_dtor) ti->hooks.ctor_move_dtor = h->ctor_move_dtor; if (h->move_dtor) ti->hooks.move_dtor = h->move_dtor; - if (h->comp) ti->hooks.comp = h->comp; + if (h->cmp) ti->hooks.cmp = h->cmp; if (h->on_add) ti->hooks.on_add = h->on_add; if (h->on_remove) ti->hooks.on_remove = h->on_remove; @@ -1467,13 +1467,13 @@ void ecs_set_hooks_id( 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 (ti->hooks.comp) ti->hooks.flags |= ECS_TYPE_HOOK_COMP; + if (ti->hooks.cmp) ti->hooks.flags |= ECS_TYPE_HOOK_CMP; 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_TYPE_HOOK_COMP_ILLEGAL) ti->hooks.comp = flecs_comp_illegal; + if(flags & ECS_TYPE_HOOK_CMP_ILLEGAL) ti->hooks.cmp = flecs_comp_illegal; if(flags & ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL) { ti->hooks.copy_ctor = flecs_copy_ctor_illegal; diff --git a/test/cpp/src/ComponentLifecycle.cpp b/test/cpp/src/ComponentLifecycle.cpp index 29f46e8f6..b653653cc 100644 --- a/test/cpp/src/ComponentLifecycle.cpp +++ b/test/cpp/src/ComponentLifecycle.cpp @@ -2339,7 +2339,7 @@ struct WithoutOperators { int compare(flecs::world& ecs, flecs::entity_t id, const void *a, const void *b) { const ecs_type_info_t* ti = ecs_get_type_info(ecs, id); - return ti->hooks.comp(a, b, ti); + return ti->hooks.cmp(a, b, ti); } void ComponentLifecycle_compare_WithGreaterThan(void) { @@ -2435,7 +2435,7 @@ void ComponentLifecycle_compare_WithEqualsOnly(void) { const ecs_type_hooks_t* hooks = ecs_get_hooks_id(ecs, component); /* can't compare if no < or > operators are defined */ - test_assert(hooks->flags & ECS_TYPE_HOOK_COMP_ILLEGAL); + test_assert(hooks->flags & ECS_TYPE_HOOK_CMP_ILLEGAL); } void ComponentLifecycle_compare_WithoutOperators(void) { @@ -2446,6 +2446,6 @@ void ComponentLifecycle_compare_WithoutOperators(void) { const ecs_type_hooks_t* hooks = ecs_get_hooks_id(ecs, component); /* can't compare if no operators are defined at all */ - test_assert(hooks->flags & ECS_TYPE_HOOK_COMP_ILLEGAL); + test_assert(hooks->flags & ECS_TYPE_HOOK_CMP_ILLEGAL); } diff --git a/test/meta/src/PrimitiveCompare.c b/test/meta/src/PrimitiveCompare.c index 30e33f851..097d848d2 100644 --- a/test/meta/src/PrimitiveCompare.c +++ b/test/meta/src/PrimitiveCompare.c @@ -4,7 +4,7 @@ static int cmp(const void *a, const void *b, const ecs_type_info_t* ti) { - return ti->hooks.comp(a, b, ti); + return ti->hooks.cmp(a, b, ti); } const ecs_type_info_t *sort_ti = NULL; diff --git a/test/meta/src/RttCompare.c b/test/meta/src/RttCompare.c index ade5ab28d..b024da5ce 100644 --- a/test/meta/src/RttCompare.c +++ b/test/meta/src/RttCompare.c @@ -8,7 +8,7 @@ int cmp(const ecs_world_t *world, ecs_entity_t component, ecs_entity_t ea, const void *a = ecs_get_id(world, ea, component); const void *b = ecs_get_id(world, eb, component); - return ti->hooks.comp(a, b, ti); + return ti->hooks.cmp(a, b, ti); } typedef struct OpaqueType { @@ -25,7 +25,7 @@ ecs_entity_t define_opaque_type(ecs_world_t *world) { ECS_COMPONENT(world, OpaqueType); ecs_type_hooks_t hooks = *ecs_get_hooks(world, OpaqueType); - hooks.comp = opaque_type_compare; + hooks.cmp = opaque_type_compare; ecs_set_hooks_id(world, ecs_id(OpaqueType), &hooks); diff --git a/test/meta/src/RuntimeTypes.c b/test/meta/src/RuntimeTypes.c index 314098297..18345103a 100644 --- a/test/meta/src/RuntimeTypes.c +++ b/test/meta/src/RuntimeTypes.c @@ -219,7 +219,7 @@ const ecs_type_info_t *define_test_struct( static int compare(const ecs_world_t* world, ecs_entity_t id, const void *a, const void *b) { const ecs_type_info_t* ti = ecs_get_type_info(world, id); - return ti->hooks.comp(a, b, ti); + return ti->hooks.cmp(a, b, ti); } /* Tests that a constructor is generated for a struct if at least a member has @@ -573,8 +573,8 @@ void RuntimeTypes_comp_illegal(void) { const ecs_type_info_t *nested_struct_ti = define_nested_struct(world); ecs_type_hooks_t hooks = nested_struct_ti->hooks; - hooks.flags |= ECS_TYPE_HOOK_COMP_ILLEGAL; /* mark copy hook for "NestedStruct" as illegal */ - hooks.comp = NULL; + hooks.flags |= ECS_TYPE_HOOK_CMP_ILLEGAL; /* mark copy hook for "NestedStruct" as illegal */ + hooks.cmp = NULL; hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id(world, nested_struct, &hooks); @@ -584,7 +584,7 @@ void RuntimeTypes_comp_illegal(void) { const ecs_type_info_t *test_struct_ti = define_test_struct(world); /* TestStruct should have an illegal compare hook too: */ - test_assert(test_struct_ti->hooks.flags & ECS_TYPE_HOOK_COMP_ILLEGAL); + test_assert(test_struct_ti->hooks.flags & ECS_TYPE_HOOK_CMP_ILLEGAL); ecs_fini(world); } @@ -780,7 +780,7 @@ void define_resource_handle( hooks.copy = ResourceHandle_copy; hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; - hooks.comp = ResourceHandle_comp; + hooks.cmp = ResourceHandle_comp; ecs_set_hooks_id(world, resource_handle, &hooks); } @@ -1211,8 +1211,8 @@ void RuntimeTypes_array_copy_illegal(void) { ecs_fini(world); } -/* Tests that an illegal comp hook is set for an array if its underlying type itself - * has an illegal comp hook */ +/* Tests that an illegal cmp hook is set for an array if its underlying type itself + * has an illegal cmp hook */ void RuntimeTypes_array_comp_illegal(void) { ecs_world_t *world = ecs_init(); @@ -1220,22 +1220,22 @@ void RuntimeTypes_array_comp_illegal(void) { const ecs_type_info_t *nested_struct_ti = define_nested_struct(world); ecs_type_hooks_t hooks = nested_struct_ti->hooks; - hooks.flags |= ECS_TYPE_HOOK_COMP_ILLEGAL; /* mark compare hook + hooks.flags |= ECS_TYPE_HOOK_CMP_ILLEGAL; /* mark compare hook for "NestedStruct" as illegal */ - hooks.comp = NULL; + hooks.cmp = NULL; hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id(world, nested_struct, &hooks); /* Define test_arr, as an array of "NestedStruct". - * TestStruct's comp hook should be set to illegal as well. */ + * TestStruct's cmp hook should be set to illegal as well. */ ecs_array_desc_t desc = {.entity = 0, .type = nested_struct, .count = 3}; ecs_entity_t test_arr = ecs_array_init(world, &desc); const ecs_type_info_t* test_arr_ti = ecs_get_type_info(world, test_arr); - /* test_arr should have an illegal comp hook too: */ - test_assert(test_arr_ti->hooks.flags & ECS_TYPE_HOOK_COMP_ILLEGAL); + /* test_arr should have an illegal cmp hook too: */ + test_assert(test_arr_ti->hooks.flags & ECS_TYPE_HOOK_CMP_ILLEGAL); /* No other hooks should've been set: */ test_assert(test_arr_ti->hooks.ctor != NULL); @@ -1375,8 +1375,8 @@ void RuntimeTypes_vector_lifecycle_trivial_type(void) { free_resource_ids(); } -/* Tests that an illegal comp hook is set for an array if its underlying type itself - * has an illegal comp hook */ +/* Tests that an illegal cmp hook is set for an array if its underlying type itself + * has an illegal cmp hook */ void RuntimeTypes_vector_comp_illegal(void) { ecs_world_t *world = ecs_init(); @@ -1384,22 +1384,22 @@ void RuntimeTypes_vector_comp_illegal(void) { const ecs_type_info_t *nested_struct_ti = define_nested_struct(world); ecs_type_hooks_t hooks = nested_struct_ti->hooks; - hooks.flags |= ECS_TYPE_HOOK_COMP_ILLEGAL; /* mark compare hook + hooks.flags |= ECS_TYPE_HOOK_CMP_ILLEGAL; /* mark compare hook for "NestedStruct" as illegal */ - hooks.comp = NULL; + hooks.cmp = NULL; hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id(world, nested_struct, &hooks); /* Define test_vec, as a vector of "NestedStruct". - * TestStruct's comp hook should be set to illegal as well. */ + * TestStruct's cmp hook should be set to illegal as well. */ ecs_vector_desc_t desc = {.entity = 0, .type = nested_struct}; ecs_entity_t test_vec = ecs_vector_init(world, &desc); const ecs_type_info_t* test_vec_ti = ecs_get_type_info(world, test_vec); - /* test_vec should have an illegal comp hook too: */ - test_assert(test_vec_ti->hooks.flags & ECS_TYPE_HOOK_COMP_ILLEGAL); + /* test_vec should have an illegal cmp hook too: */ + test_assert(test_vec_ti->hooks.flags & ECS_TYPE_HOOK_CMP_ILLEGAL); ecs_fini(world); } @@ -1416,7 +1416,7 @@ ecs_entity_t define_ResourceHandle_opaque( hooks.move = ResourceHandle_move; hooks.copy = ResourceHandle_copy; hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; - hooks.comp = ResourceHandle_comp; + hooks.cmp = ResourceHandle_comp; ecs_set_hooks_id(world, ecs_id(ResourceHandle), &hooks); From 508c08520c260f543741704ce320dc49726fdfaf Mon Sep 17 00:00:00 2001 From: Javier Peletier Date: Fri, 29 Nov 2024 09:33:23 +0100 Subject: [PATCH 14/23] add equals hook type --- distr/flecs.h | 9 +++++++++ include/flecs.h | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/distr/flecs.h b/distr/flecs.h index 05ef7f9ff..d7f6550cc 100644 --- a/distr/flecs.h +++ b/distr/flecs.h @@ -3319,6 +3319,12 @@ typedef int (*ecs_cmp_t)( const void *b_ptr, const ecs_type_info_t *type_info); +/** Equals operator hook */ +typedef bool (*ecs_equals_t)( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *type_info); + /** Destructor function for poly objects. */ typedef void (*flecs_poly_dtor_t)( ecs_poly_t *poly); @@ -3599,6 +3605,9 @@ struct ecs_type_hooks_t { /** Compare hook */ ecs_cmp_t cmp; + /** Equals hook */ + ecs_equals_t equals; + /** Hook flags. * Indicates which hooks are set for the type, and which hooks are illegal. * When an ILLEGAL flag is set when calling ecs_set_hooks() a hook callback diff --git a/include/flecs.h b/include/flecs.h index d92a1ccbb..ae03b235b 100644 --- a/include/flecs.h +++ b/include/flecs.h @@ -651,6 +651,12 @@ typedef int (*ecs_cmp_t)( const void *b_ptr, const ecs_type_info_t *type_info); +/** Equals operator hook */ +typedef bool (*ecs_equals_t)( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *type_info); + /** Destructor function for poly objects. */ typedef void (*flecs_poly_dtor_t)( ecs_poly_t *poly); @@ -931,6 +937,9 @@ struct ecs_type_hooks_t { /** Compare hook */ ecs_cmp_t cmp; + /** Equals hook */ + ecs_equals_t equals; + /** Hook flags. * Indicates which hooks are set for the type, and which hooks are illegal. * When an ILLEGAL flag is set when calling ecs_set_hooks() a hook callback From 0a6c187392737315050cf6ea093cd8cc72913508 Mon Sep 17 00:00:00 2001 From: Javier Peletier Date: Fri, 29 Nov 2024 11:59:12 +0100 Subject: [PATCH 15/23] Implement equals hook. Add tests to PrimitiveCompare --- distr/flecs.c | 390 ++++++++++++++++++++++++++++--- distr/flecs.h | 26 ++- include/flecs.h | 26 ++- src/addons/meta/definitions.c | 1 + src/addons/meta/meta.c | 166 ++++++++++++- src/addons/meta/meta.h | 5 + src/addons/meta/rtt_lifecycle.c | 187 +++++++++++++-- src/world.c | 32 +++ test/meta/project.json | 6 +- test/meta/src/PrimitiveCompare.c | 90 +++++-- test/meta/src/RuntimeTypes.c | 6 +- test/meta/src/main.c | 18 +- 12 files changed, 843 insertions(+), 110 deletions(-) diff --git a/distr/flecs.c b/distr/flecs.c index 4464bdbb6..77a1c1d56 100644 --- a/distr/flecs.c +++ b/distr/flecs.c @@ -18942,6 +18942,11 @@ void flecs_default_move_w_dtor(void *dst_ptr, void *src_ptr, cl->dtor(src_ptr, count, ti); } +static +bool flecs_default_equals(const void *a_ptr, const void *b_ptr, const ecs_type_info_t* ti) { + return ti->hooks.cmp(a_ptr, b_ptr, ti) == 0; +} + ECS_NORETURN static void flecs_ctor_illegal( void * dst, @@ -19024,6 +19029,17 @@ int flecs_comp_illegal( ecs_abort(ECS_INVALID_OPERATION, "invalid compare hook for %s", ti->name); } +ECS_NORETURN static +bool flecs_equals_illegal( + const void *dst, + const void *src, + const ecs_type_info_t *ti) +{ + (void)dst; /* silence unused warning */ + (void)src; + ecs_abort(ECS_INVALID_OPERATION, "invalid compare hook for %s", ti->name); +} + void ecs_set_hooks_id( ecs_world_t *world, ecs_entity_t component, @@ -19080,6 +19096,10 @@ void ecs_set_hooks_id( h->cmp != flecs_comp_illegal), ECS_INVALID_PARAMETER, "cannot specify both compare hook and illegal flag"); + ecs_check(!(flags & ECS_TYPE_HOOK_EQUALS_ILLEGAL && + h->equals != NULL && + h->equals != flecs_equals_illegal), + ECS_INVALID_PARAMETER, "cannot specify both equals hook and illegal flag"); flecs_stage_from_world(&world); @@ -19119,6 +19139,7 @@ void ecs_set_hooks_id( if (h->ctor_move_dtor) ti->hooks.ctor_move_dtor = h->ctor_move_dtor; if (h->move_dtor) ti->hooks.move_dtor = h->move_dtor; if (h->cmp) ti->hooks.cmp = h->cmp; + if (h->equals) ti->hooks.equals = h->equals; if (h->on_add) ti->hooks.on_add = h->on_add; if (h->on_remove) ti->hooks.on_remove = h->on_remove; @@ -19217,6 +19238,14 @@ void ecs_set_hooks_id( } } + if (!h->equals) { + if(flags & ECS_TYPE_HOOK_CMP_ILLEGAL) { + flags |= ECS_TYPE_HOOK_EQUALS_ILLEGAL; + } else if(h->cmp) { + ti->hooks.equals = flecs_default_equals; + } + } + ti->hooks.flags = flags; if (ti->hooks.ctor) ti->hooks.flags |= ECS_TYPE_HOOK_CTOR; @@ -19228,12 +19257,14 @@ void ecs_set_hooks_id( 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 (ti->hooks.cmp) ti->hooks.flags |= ECS_TYPE_HOOK_CMP; + if (ti->hooks.equals) ti->hooks.flags |= ECS_TYPE_HOOK_EQUALS; 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_TYPE_HOOK_CMP_ILLEGAL) ti->hooks.cmp = flecs_comp_illegal; + if(flags & ECS_TYPE_HOOK_EQUALS_ILLEGAL) ti->hooks.equals = flecs_equals_illegal; if(flags & ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL) { ti->hooks.copy_ctor = flecs_copy_ctor_illegal; @@ -42821,6 +42852,11 @@ int ecs_compare_string( const void *str_b, const ecs_type_info_t *ti); +bool ecs_equals_string( + const void *str_a, + const void *str_b, + const ecs_type_info_t *ti); + #endif #endif @@ -49698,6 +49734,7 @@ void flecs_meta_import_core_definitions( .alignment = ECS_ALIGNOF(const char*), .hooks = { .cmp = ecs_compare_string, + .equals = ecs_equals_string } } }), @@ -49984,6 +50021,15 @@ int ecs_compare_bool( return (int)(*((const ecs_bool_t*)a_ptr)) - (int)(*((const ecs_bool_t*)b_ptr)); } +static +bool ecs_equals_bool( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + return ecs_compare_bool(a_ptr, b_ptr, ti) == 0; +} + static int ecs_compare_char( const void *a_ptr, @@ -49994,6 +50040,15 @@ int ecs_compare_char( return (int)(*((const ecs_char_t*)a_ptr)) - (int)(*((const ecs_char_t*)b_ptr)); } +static +bool ecs_equals_char( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + return ecs_compare_char(a_ptr, b_ptr, ti) == 0; +} + static int ecs_compare_byte( const void *a_ptr, @@ -50004,6 +50059,15 @@ int ecs_compare_byte( return (int)(*((const ecs_byte_t*)a_ptr)) - (int)(*((const ecs_byte_t*)b_ptr)); } +static +bool ecs_equals_byte( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + return ecs_compare_byte(a_ptr, b_ptr, ti) == 0; +} + static int ecs_compare_u8( const void *a_ptr, @@ -50014,6 +50078,15 @@ int ecs_compare_u8( return (int)(*((const ecs_u8_t*)a_ptr)) - (int)(*((const ecs_u8_t*)b_ptr)); } +static +bool ecs_equals_u8( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + return ecs_compare_u8(a_ptr, b_ptr, ti) == 0; +} + static int ecs_compare_u16( const void *a_ptr, @@ -50024,6 +50097,15 @@ int ecs_compare_u16( return (int)(*((const ecs_u16_t*)a_ptr)) - (int)(*((const ecs_u16_t*)b_ptr)); } +static +bool ecs_equals_u16( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + return ecs_compare_u16(a_ptr, b_ptr, ti) == 0; +} + static int ecs_compare_u32( const void *a_ptr, @@ -50036,6 +50118,15 @@ int ecs_compare_u32( return (a > b) - (a < b); } +static +bool ecs_equals_u32( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + return ecs_compare_u32(a_ptr, b_ptr, ti) == 0; +} + static int ecs_compare_u64( const void *a_ptr, @@ -50048,6 +50139,15 @@ int ecs_compare_u64( return (a > b) - (a < b); } +static +bool ecs_equals_u64( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + return ecs_compare_u64(a_ptr, b_ptr, ti) == 0; +} + static int ecs_compare_uptr( const void *a_ptr, @@ -50060,6 +50160,15 @@ int ecs_compare_uptr( return (a > b) - (a < b); } +static +bool ecs_equals_uptr( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + return ecs_compare_uptr(a_ptr, b_ptr, ti) == 0; +} + static int ecs_compare_i8( const void *a_ptr, @@ -50071,6 +50180,15 @@ int ecs_compare_i8( (int)(*((const ecs_i8_t*)b_ptr)); } +static +bool ecs_equals_i8( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + return ecs_compare_i8(a_ptr, b_ptr, ti) == 0; +} + static int ecs_compare_i16( const void *a_ptr, @@ -50082,6 +50200,15 @@ int ecs_compare_i16( (int)(*((const ecs_i16_t*)b_ptr)); } +static +bool ecs_equals_i16( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + return ecs_compare_i16(a_ptr, b_ptr, ti) == 0; +} + static int ecs_compare_i32( const void *a_ptr, @@ -50094,6 +50221,15 @@ int ecs_compare_i32( return (a > b) - (a < b); } +static +bool ecs_equals_i32( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + return ecs_compare_i32(a_ptr, b_ptr, ti) == 0; +} + static int ecs_compare_i64( const void *a_ptr, @@ -50106,6 +50242,15 @@ int ecs_compare_i64( return (a > b) - (a < b); } +static +bool ecs_equals_i64( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + return ecs_compare_i64(a_ptr, b_ptr, ti) == 0; +} + static int ecs_compare_iptr( const void *a_ptr, @@ -50118,6 +50263,15 @@ int ecs_compare_iptr( return (a > b) - (a < b); } +static +bool ecs_equals_iptr( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + return ecs_compare_iptr(a_ptr, b_ptr, ti) == 0; +} + static int ecs_compare_f32( const void *a_ptr, @@ -50132,6 +50286,16 @@ int ecs_compare_f32( return 0; } +static +bool ecs_equals_f32( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + /* intentional equal check as if it was an integer */ + return ecs_compare_u32(a_ptr, b_ptr, ti) == 0; +} + static int ecs_compare_f64( const void *a_ptr, @@ -50146,6 +50310,16 @@ int ecs_compare_f64( return 0; } +static +bool ecs_equals_f64( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + /* intentional equal check as if it was an integer */ + return ecs_compare_u64(a_ptr, b_ptr, ti) == 0; +} + static int ecs_compare_entity( const void *a_ptr, @@ -50158,6 +50332,15 @@ int ecs_compare_entity( return (a > b) - (a < b); } +static +bool ecs_equals_entity( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + return ecs_compare_entity(a_ptr, b_ptr, ti) == 0; +} + static int ecs_compare_id( const void *a_ptr, @@ -50170,6 +50353,14 @@ int ecs_compare_id( return (a > b) - (a < b); } +static +bool ecs_equals_id( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + return ecs_compare_id(a_ptr, b_ptr, ti) == 0; +} int ecs_compare_string( const void *a_ptr, @@ -50190,6 +50381,15 @@ int ecs_compare_string( return ecs_os_strcmp(str_a, str_b); } +bool ecs_equals_string( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + return ecs_compare_string(a_ptr, b_ptr, ti) == 0; +} + + /* EcsTypeSerializer lifecycle */ void ecs_meta_dtor_serialized( @@ -51568,7 +51768,8 @@ void FlecsMetaImport( .kind = primitive_kind\ });\ ecs_set_hooks(world, ecs_##type##_t, { \ - .cmp = ecs_compare_##type \ + .cmp = ecs_compare_##type, \ + .equals = ecs_equals_##type \ }) ECS_PRIMITIVE(world, bool, EcsBool); @@ -51631,6 +51832,7 @@ typedef struct ecs_rtt_call_data_t { ecs_move_t move; ecs_copy_t copy; ecs_cmp_t cmp; + ecs_equals_t equals; } hook; const ecs_type_info_t *type_info; int32_t offset; @@ -51639,11 +51841,13 @@ typedef struct ecs_rtt_call_data_t { /* Lifecycle context for runtime structs */ typedef struct ecs_rtt_struct_ctx_t { - ecs_vec_t vctor; /* vector */ - ecs_vec_t vdtor; /* vector */ - ecs_vec_t vmove; /* vector */ - ecs_vec_t vcopy; /* vector */ - ecs_vec_t vcomp; /* vector */ + ecs_vec_t vctor; /* vector */ + ecs_vec_t vdtor; /* vector */ + ecs_vec_t vmove; /* vector */ + ecs_vec_t vcopy; /* vector */ + ecs_vec_t vcomp; /* vector */ + ecs_vec_t vequals; /* vector */ + } ecs_rtt_struct_ctx_t; /* Lifecycle context for runtime arrays */ @@ -51803,7 +52007,7 @@ void flecs_rtt_struct_copy( * structs's lifecycle context and call the compare hooks configured when * the type was created. */ static -int flecs_rtt_struct_comp( +int flecs_rtt_struct_cmp( const void *a_ptr, const void *b_ptr, const ecs_type_info_t *type_info) @@ -51831,6 +52035,38 @@ int flecs_rtt_struct_comp( return 0; } +/* Generic equals hook. It will read hook information call data from the + * structs's lifecycle context and call the equals hooks configured when + * the type was created. */ +static +bool flecs_rtt_struct_equals( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *type_info) +{ + if(a_ptr == b_ptr) { + return 0; + } + + ecs_rtt_struct_ctx_t *rtt_ctx = type_info->hooks.lifecycle_ctx; + ecs_assert(rtt_ctx != NULL, ECS_INTERNAL_ERROR, NULL); + + int cb_count = ecs_vec_count(&rtt_ctx->vcomp); + int i; + for (i = 0; i < cb_count; i++) { + ecs_rtt_call_data_t *comp_data = + ecs_vec_get_t(&rtt_ctx->vcomp, ecs_rtt_call_data_t, i); + bool eq = comp_data->hook.equals( + ECS_OFFSET(a_ptr, comp_data->offset), + ECS_OFFSET(b_ptr, comp_data->offset), + comp_data->type_info); + if (!eq) { + return false; + } + } + return true; +} + static void flecs_rtt_free_lifecycle_nop( void *ctx) @@ -51853,6 +52089,7 @@ void flecs_rtt_free_lifecycle_struct_ctx( ecs_vec_fini_t(NULL, &lifecycle_ctx->vmove, ecs_rtt_call_data_t); ecs_vec_fini_t(NULL, &lifecycle_ctx->vcopy, ecs_rtt_call_data_t); ecs_vec_fini_t(NULL, &lifecycle_ctx->vcomp, ecs_rtt_call_data_t); + ecs_vec_fini_t(NULL, &lifecycle_ctx->vequals, ecs_rtt_call_data_t); ecs_os_free(ctx); } @@ -51866,7 +52103,8 @@ ecs_rtt_struct_ctx_t * flecs_rtt_configure_struct_hooks( ecs_xtor_t dtor, ecs_move_t move, ecs_copy_t copy, - ecs_cmp_t cmp) + ecs_cmp_t cmp, + ecs_equals_t equals) { ecs_type_hooks_t hooks = ti->hooks; if (hooks.lifecycle_ctx_free) { @@ -51888,15 +52126,19 @@ ecs_rtt_struct_ctx_t * flecs_rtt_configure_struct_hooks( if(flags & ECS_TYPE_HOOK_CMP_ILLEGAL) { cmp = NULL; } - + if(flags & ECS_TYPE_HOOK_EQUALS_ILLEGAL) { + equals = NULL; + } ecs_rtt_struct_ctx_t *rtt_ctx = NULL; - if (ctor || dtor || move || copy || cmp) { + if (ctor || dtor || move || copy || cmp || equals) { rtt_ctx = ecs_os_malloc_t(ecs_rtt_struct_ctx_t); ecs_vec_init_t(NULL, &rtt_ctx->vctor, ecs_rtt_call_data_t, 0); ecs_vec_init_t(NULL, &rtt_ctx->vdtor, ecs_rtt_call_data_t, 0); ecs_vec_init_t(NULL, &rtt_ctx->vmove, ecs_rtt_call_data_t, 0); ecs_vec_init_t(NULL, &rtt_ctx->vcopy, ecs_rtt_call_data_t, 0); ecs_vec_init_t(NULL, &rtt_ctx->vcomp, ecs_rtt_call_data_t, 0); + ecs_vec_init_t(NULL, &rtt_ctx->vequals, ecs_rtt_call_data_t, 0); + hooks.lifecycle_ctx = rtt_ctx; hooks.lifecycle_ctx_free = flecs_rtt_free_lifecycle_struct_ctx; } else { @@ -51909,6 +52151,7 @@ ecs_rtt_struct_ctx_t * flecs_rtt_configure_struct_hooks( hooks.move = move; hooks.copy = copy; hooks.cmp = cmp; + hooks.equals = equals; hooks.flags = flags; hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; @@ -51935,7 +52178,8 @@ void flecs_rtt_init_default_hooks_struct( bool dtor_hook_required = false; bool move_hook_required = false; bool copy_hook_required = false; - bool comparable = true; + bool valid_cmp = true; + bool valid_equals = true; /* Iterate all struct members and see if any member type has hooks. If so, * the struct itself will need to have that hook: */ @@ -51951,10 +52195,12 @@ void flecs_rtt_init_default_hooks_struct( move_hook_required |= member_ti->hooks.move != NULL; copy_hook_required |= member_ti->hooks.copy != NULL; - /* A struct is comparable if all its members - * are comparable */ - comparable &= member_ti->hooks.cmp != NULL; - + /* A struct has a valid cmp hook if all its members have it */ + valid_cmp &= member_ti->hooks.cmp != NULL; + + /* A struct has a valid equals hook if all its members have it */ + valid_equals &= member_ti->hooks.equals != NULL; + flags |= member_ti->hooks.flags; } @@ -51968,7 +52214,8 @@ void flecs_rtt_init_default_hooks_struct( dtor_hook_required ? flecs_rtt_struct_dtor : NULL, move_hook_required ? flecs_rtt_struct_move : NULL, copy_hook_required ? flecs_rtt_struct_copy : NULL, - comparable ? flecs_rtt_struct_comp : NULL + valid_cmp ? flecs_rtt_struct_cmp : NULL, + valid_equals ? flecs_rtt_struct_equals : NULL ); if (!rtt_ctx) { @@ -52025,7 +52272,7 @@ void flecs_rtt_init_default_hooks_struct( copy_data->hook.copy = flecs_rtt_default_copy; } } - if (comparable) { + if (valid_cmp) { ecs_rtt_call_data_t *comp_data = ecs_vec_append_t(NULL, &rtt_ctx->vcomp, ecs_rtt_call_data_t); comp_data->offset = m->offset; @@ -52034,6 +52281,15 @@ void flecs_rtt_init_default_hooks_struct( ecs_assert(member_ti->hooks.cmp, ECS_INTERNAL_ERROR, NULL); comp_data->hook.cmp = member_ti->hooks.cmp; } + if (valid_equals) { + ecs_rtt_call_data_t *comp_data = + ecs_vec_append_t(NULL, &rtt_ctx->vequals, ecs_rtt_call_data_t); + comp_data->offset = m->offset; + comp_data->type_info = member_ti; + comp_data->count = 1; + ecs_assert(member_ti->hooks.equals, ECS_INTERNAL_ERROR, NULL); + comp_data->hook.equals = member_ti->hooks.equals; + } } } @@ -52133,7 +52389,7 @@ void flecs_rtt_array_copy( /* Generic array compare hook. It will invoke the compare hook of the underlying * type for each element */ static -int flecs_rtt_array_comp( +int flecs_rtt_array_cmp( const void *a_ptr, const void *b_ptr, const ecs_type_info_t *type_info) @@ -52158,6 +52414,34 @@ int flecs_rtt_array_comp( return 0; } +/* Generic array equals hook. It will invoke the equals hook of the underlying + * type for each element */ +static +bool flecs_rtt_array_equals( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *type_info) +{ + if(a_ptr == b_ptr) { + return 0; + } + + ecs_rtt_array_ctx_t *rtt_ctx = type_info->hooks.lifecycle_ctx; + ecs_equals_t equals = rtt_ctx->type_info->hooks.equals; + ecs_assert(equals, ECS_INVALID_PARAMETER, NULL); + ecs_size_t element_size = rtt_ctx->type_info->size; + int i; + for (i = 0; i < rtt_ctx->elem_count; i++) { + const void *a_element = ECS_ELEM(a_ptr, element_size, i); + const void *b_element = ECS_ELEM(b_ptr, element_size, i); + bool eq = equals(a_element, b_element, rtt_ctx->type_info); + if(!eq) { + return false; + } + } + return true; +} + /* Checks if an array's underlying type has hooks installed. If so, it generates * and installs required hooks for the array type itself. These hooks will * invoke the underlying type's hook for each element in the array. */ @@ -52175,7 +52459,8 @@ void flecs_rtt_init_default_hooks_array( bool dtor_hook_required = element_ti->hooks.dtor != NULL; bool move_hook_required = element_ti->hooks.move != NULL; bool copy_hook_required = element_ti->hooks.copy != NULL; - bool comparable = element_ti->hooks.cmp != NULL; + bool valid_cmp = element_ti->hooks.cmp != NULL; + bool valid_equals = element_ti->hooks.equals != NULL; ecs_flags32_t flags = element_ti->hooks.flags; @@ -52189,8 +52474,11 @@ void flecs_rtt_init_default_hooks_array( flecs_rtt_array_move : NULL; hooks.copy = copy_hook_required && !(flags & ECS_TYPE_HOOK_COPY_ILLEGAL) ? flecs_rtt_array_copy : NULL; - hooks.cmp = comparable && !(flags & ECS_TYPE_HOOK_CMP_ILLEGAL) ? - flecs_rtt_array_comp : NULL; + hooks.cmp = valid_cmp && !(flags & ECS_TYPE_HOOK_CMP_ILLEGAL) ? + flecs_rtt_array_cmp : NULL; + hooks.equals = valid_equals && !(flags & ECS_TYPE_HOOK_EQUALS_ILLEGAL) ? + flecs_rtt_array_equals : NULL; + if (hooks.lifecycle_ctx_free) { hooks.lifecycle_ctx_free(hooks.lifecycle_ctx); @@ -52198,7 +52486,7 @@ void flecs_rtt_init_default_hooks_array( } if (hooks.ctor || hooks.dtor || hooks.move || - hooks.copy || hooks.cmp) + hooks.copy || hooks.cmp || hooks.equals) { ecs_rtt_array_ctx_t *rtt_ctx = ecs_os_malloc_t(ecs_rtt_array_ctx_t); rtt_ctx->type_info = element_ti; @@ -52327,7 +52615,7 @@ void flecs_rtt_vector_copy( /* Generic vector compare hook. */ static -int flecs_rtt_vector_comp( +int flecs_rtt_vector_cmp( const void *a_ptr, const void *b_ptr, const ecs_type_info_t *type_info) @@ -52368,6 +52656,49 @@ int flecs_rtt_vector_comp( return 0; } +/* Generic vector equals hook. */ +static +bool flecs_rtt_vector_equals( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *type_info) +{ + if(a_ptr == b_ptr) { + return 0; + } + + const ecs_vec_t *vec_a = a_ptr; + const ecs_vec_t *vec_b = b_ptr; + + ecs_size_t count_a = ecs_vec_count(vec_a); + ecs_size_t count_b = ecs_vec_count(vec_b); + { + int c = count_a - count_b; + if(c != 0) { + return c; + } + } + + ecs_rtt_vector_ctx_t *rtt_ctx = type_info->hooks.lifecycle_ctx; + ecs_equals_t equals = rtt_ctx->type_info->hooks.equals; + ecs_assert(equals, ECS_INVALID_PARAMETER, NULL); + + ecs_size_t element_size = rtt_ctx->type_info->size; + const void *a = ecs_vec_first(vec_a); + const void *b = ecs_vec_first(vec_b); + + int i; + for (i = 0; i < count_a; i++) { + const void *a_element = ECS_ELEM(a, element_size, i); + const void *b_element = ECS_ELEM(b, element_size, i); + int eq = equals(a_element, b_element, rtt_ctx->type_info); + if(!eq) { + return false; + } + } + return true; +} + /* Generates and installs required hooks for managing the vector and underlying * type lifecycle. Vectors always have hooks because at the very least the * vector structure itself must be initialized/destroyed/copied/moved, even if @@ -52399,13 +52730,20 @@ void flecs_rtt_init_default_hooks_vector( hooks.copy = flecs_rtt_vector_copy; if (element_ti->hooks.cmp != NULL && !(flags & ECS_TYPE_HOOK_CMP_ILLEGAL)) { - hooks.cmp = flecs_rtt_vector_comp; + hooks.cmp = flecs_rtt_vector_cmp; } else { hooks.cmp = NULL; } - /* propagate only the compare hook illegal flag, if set */ - hooks.flags |= flags & ECS_TYPE_HOOK_CMP_ILLEGAL; + if (element_ti->hooks.equals != NULL && !(flags & ECS_TYPE_HOOK_EQUALS_ILLEGAL)) { + hooks.equals = flecs_rtt_vector_equals; + } else { + hooks.equals = NULL; + } + + + /* propagate only the compare/equals hook illegal flag, if set */ + hooks.flags |= flags & (ECS_TYPE_HOOK_CMP_ILLEGAL|ECS_TYPE_HOOK_EQUALS_ILLEGAL); hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id(world, component, &hooks); diff --git a/distr/flecs.h b/distr/flecs.h index d7f6550cc..1c37ab0d8 100644 --- a/distr/flecs.h +++ b/distr/flecs.h @@ -3552,31 +3552,35 @@ struct ecs_observer_t { #define ECS_TYPE_HOOK_CTOR_MOVE_DTOR (1 << 6) #define ECS_TYPE_HOOK_MOVE_DTOR (1 << 7) #define ECS_TYPE_HOOK_CMP (1 << 8) +#define ECS_TYPE_HOOK_EQUALS (1 << 9) /* Flags that can be used to set/check which hooks of a type are invalid */ -#define ECS_TYPE_HOOK_CTOR_ILLEGAL (1 << 9) -#define ECS_TYPE_HOOK_DTOR_ILLEGAL (1 << 10) -#define ECS_TYPE_HOOK_COPY_ILLEGAL (1 << 11) -#define ECS_TYPE_HOOK_MOVE_ILLEGAL (1 << 12) -#define ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL (1 << 13) -#define ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL (1 << 14) -#define ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL (1 << 15) -#define ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL (1 << 16) -#define ECS_TYPE_HOOK_CMP_ILLEGAL (1 << 17) +#define ECS_TYPE_HOOK_CTOR_ILLEGAL (1 << 10) +#define ECS_TYPE_HOOK_DTOR_ILLEGAL (1 << 12) +#define ECS_TYPE_HOOK_COPY_ILLEGAL (1 << 13) +#define ECS_TYPE_HOOK_MOVE_ILLEGAL (1 << 14) +#define ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL (1 << 15) +#define ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL (1 << 16) +#define ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL (1 << 17) +#define ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL (1 << 18) +#define ECS_TYPE_HOOK_CMP_ILLEGAL (1 << 19) +#define ECS_TYPE_HOOK_EQUALS_ILLEGAL (1 << 20) + /* All valid hook flags */ #define ECS_TYPE_HOOKS (ECS_TYPE_HOOK_CTOR|ECS_TYPE_HOOK_DTOR|\ ECS_TYPE_HOOK_COPY|ECS_TYPE_HOOK_MOVE|ECS_TYPE_HOOK_COPY_CTOR|\ ECS_TYPE_HOOK_MOVE_CTOR|ECS_TYPE_HOOK_CTOR_MOVE_DTOR|\ - ECS_TYPE_HOOK_MOVE_DTOR|ECS_TYPE_HOOK_CMP) + ECS_TYPE_HOOK_MOVE_DTOR|ECS_TYPE_HOOK_CMP|ECS_TYPE_HOOK_EQUALS) /* All invalid hook flags */ #define ECS_TYPE_HOOKS_ILLEGAL (ECS_TYPE_HOOK_CTOR_ILLEGAL|\ ECS_TYPE_HOOK_DTOR_ILLEGAL|ECS_TYPE_HOOK_COPY_ILLEGAL|\ ECS_TYPE_HOOK_MOVE_ILLEGAL|ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL|\ ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL|ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL|\ - ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL|ECS_TYPE_HOOK_CMP_ILLEGAL) + ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL|ECS_TYPE_HOOK_CMP_ILLEGAL|\ + ECS_TYPE_HOOK_EQUALS_ILLEGAL) struct ecs_type_hooks_t { ecs_xtor_t ctor; /**< ctor */ diff --git a/include/flecs.h b/include/flecs.h index ae03b235b..d1ce44f87 100644 --- a/include/flecs.h +++ b/include/flecs.h @@ -884,31 +884,35 @@ struct ecs_observer_t { #define ECS_TYPE_HOOK_CTOR_MOVE_DTOR (1 << 6) #define ECS_TYPE_HOOK_MOVE_DTOR (1 << 7) #define ECS_TYPE_HOOK_CMP (1 << 8) +#define ECS_TYPE_HOOK_EQUALS (1 << 9) /* Flags that can be used to set/check which hooks of a type are invalid */ -#define ECS_TYPE_HOOK_CTOR_ILLEGAL (1 << 9) -#define ECS_TYPE_HOOK_DTOR_ILLEGAL (1 << 10) -#define ECS_TYPE_HOOK_COPY_ILLEGAL (1 << 11) -#define ECS_TYPE_HOOK_MOVE_ILLEGAL (1 << 12) -#define ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL (1 << 13) -#define ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL (1 << 14) -#define ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL (1 << 15) -#define ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL (1 << 16) -#define ECS_TYPE_HOOK_CMP_ILLEGAL (1 << 17) +#define ECS_TYPE_HOOK_CTOR_ILLEGAL (1 << 10) +#define ECS_TYPE_HOOK_DTOR_ILLEGAL (1 << 12) +#define ECS_TYPE_HOOK_COPY_ILLEGAL (1 << 13) +#define ECS_TYPE_HOOK_MOVE_ILLEGAL (1 << 14) +#define ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL (1 << 15) +#define ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL (1 << 16) +#define ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL (1 << 17) +#define ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL (1 << 18) +#define ECS_TYPE_HOOK_CMP_ILLEGAL (1 << 19) +#define ECS_TYPE_HOOK_EQUALS_ILLEGAL (1 << 20) + /* All valid hook flags */ #define ECS_TYPE_HOOKS (ECS_TYPE_HOOK_CTOR|ECS_TYPE_HOOK_DTOR|\ ECS_TYPE_HOOK_COPY|ECS_TYPE_HOOK_MOVE|ECS_TYPE_HOOK_COPY_CTOR|\ ECS_TYPE_HOOK_MOVE_CTOR|ECS_TYPE_HOOK_CTOR_MOVE_DTOR|\ - ECS_TYPE_HOOK_MOVE_DTOR|ECS_TYPE_HOOK_CMP) + ECS_TYPE_HOOK_MOVE_DTOR|ECS_TYPE_HOOK_CMP|ECS_TYPE_HOOK_EQUALS) /* All invalid hook flags */ #define ECS_TYPE_HOOKS_ILLEGAL (ECS_TYPE_HOOK_CTOR_ILLEGAL|\ ECS_TYPE_HOOK_DTOR_ILLEGAL|ECS_TYPE_HOOK_COPY_ILLEGAL|\ ECS_TYPE_HOOK_MOVE_ILLEGAL|ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL|\ ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL|ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL|\ - ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL|ECS_TYPE_HOOK_CMP_ILLEGAL) + ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL|ECS_TYPE_HOOK_CMP_ILLEGAL|\ + ECS_TYPE_HOOK_EQUALS_ILLEGAL) struct ecs_type_hooks_t { ecs_xtor_t ctor; /**< ctor */ diff --git a/src/addons/meta/definitions.c b/src/addons/meta/definitions.c index c8bb9b5cc..a96c0051a 100644 --- a/src/addons/meta/definitions.c +++ b/src/addons/meta/definitions.c @@ -74,6 +74,7 @@ void flecs_meta_import_core_definitions( .alignment = ECS_ALIGNOF(const char*), .hooks = { .cmp = ecs_compare_string, + .equals = ecs_equals_string } } }), diff --git a/src/addons/meta/meta.c b/src/addons/meta/meta.c index d5f7d34dd..0db0274bb 100644 --- a/src/addons/meta/meta.c +++ b/src/addons/meta/meta.c @@ -37,6 +37,15 @@ int ecs_compare_bool( return (int)(*((const ecs_bool_t*)a_ptr)) - (int)(*((const ecs_bool_t*)b_ptr)); } +static +bool ecs_equals_bool( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + return ecs_compare_bool(a_ptr, b_ptr, ti) == 0; +} + static int ecs_compare_char( const void *a_ptr, @@ -47,6 +56,15 @@ int ecs_compare_char( return (int)(*((const ecs_char_t*)a_ptr)) - (int)(*((const ecs_char_t*)b_ptr)); } +static +bool ecs_equals_char( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + return ecs_compare_char(a_ptr, b_ptr, ti) == 0; +} + static int ecs_compare_byte( const void *a_ptr, @@ -57,6 +75,15 @@ int ecs_compare_byte( return (int)(*((const ecs_byte_t*)a_ptr)) - (int)(*((const ecs_byte_t*)b_ptr)); } +static +bool ecs_equals_byte( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + return ecs_compare_byte(a_ptr, b_ptr, ti) == 0; +} + static int ecs_compare_u8( const void *a_ptr, @@ -67,6 +94,15 @@ int ecs_compare_u8( return (int)(*((const ecs_u8_t*)a_ptr)) - (int)(*((const ecs_u8_t*)b_ptr)); } +static +bool ecs_equals_u8( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + return ecs_compare_u8(a_ptr, b_ptr, ti) == 0; +} + static int ecs_compare_u16( const void *a_ptr, @@ -77,6 +113,15 @@ int ecs_compare_u16( return (int)(*((const ecs_u16_t*)a_ptr)) - (int)(*((const ecs_u16_t*)b_ptr)); } +static +bool ecs_equals_u16( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + return ecs_compare_u16(a_ptr, b_ptr, ti) == 0; +} + static int ecs_compare_u32( const void *a_ptr, @@ -89,6 +134,15 @@ int ecs_compare_u32( return (a > b) - (a < b); } +static +bool ecs_equals_u32( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + return ecs_compare_u32(a_ptr, b_ptr, ti) == 0; +} + static int ecs_compare_u64( const void *a_ptr, @@ -101,6 +155,15 @@ int ecs_compare_u64( return (a > b) - (a < b); } +static +bool ecs_equals_u64( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + return ecs_compare_u64(a_ptr, b_ptr, ti) == 0; +} + static int ecs_compare_uptr( const void *a_ptr, @@ -113,6 +176,15 @@ int ecs_compare_uptr( return (a > b) - (a < b); } +static +bool ecs_equals_uptr( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + return ecs_compare_uptr(a_ptr, b_ptr, ti) == 0; +} + static int ecs_compare_i8( const void *a_ptr, @@ -124,6 +196,15 @@ int ecs_compare_i8( (int)(*((const ecs_i8_t*)b_ptr)); } +static +bool ecs_equals_i8( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + return ecs_compare_i8(a_ptr, b_ptr, ti) == 0; +} + static int ecs_compare_i16( const void *a_ptr, @@ -135,6 +216,15 @@ int ecs_compare_i16( (int)(*((const ecs_i16_t*)b_ptr)); } +static +bool ecs_equals_i16( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + return ecs_compare_i16(a_ptr, b_ptr, ti) == 0; +} + static int ecs_compare_i32( const void *a_ptr, @@ -147,6 +237,15 @@ int ecs_compare_i32( return (a > b) - (a < b); } +static +bool ecs_equals_i32( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + return ecs_compare_i32(a_ptr, b_ptr, ti) == 0; +} + static int ecs_compare_i64( const void *a_ptr, @@ -159,6 +258,15 @@ int ecs_compare_i64( return (a > b) - (a < b); } +static +bool ecs_equals_i64( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + return ecs_compare_i64(a_ptr, b_ptr, ti) == 0; +} + static int ecs_compare_iptr( const void *a_ptr, @@ -171,6 +279,15 @@ int ecs_compare_iptr( return (a > b) - (a < b); } +static +bool ecs_equals_iptr( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + return ecs_compare_iptr(a_ptr, b_ptr, ti) == 0; +} + static int ecs_compare_f32( const void *a_ptr, @@ -185,6 +302,16 @@ int ecs_compare_f32( return 0; } +static +bool ecs_equals_f32( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + /* intentional equal check as if it was an integer */ + return ecs_compare_u32(a_ptr, b_ptr, ti) == 0; +} + static int ecs_compare_f64( const void *a_ptr, @@ -199,6 +326,16 @@ int ecs_compare_f64( return 0; } +static +bool ecs_equals_f64( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + /* intentional equal check as if it was an integer */ + return ecs_compare_u64(a_ptr, b_ptr, ti) == 0; +} + static int ecs_compare_entity( const void *a_ptr, @@ -211,6 +348,15 @@ int ecs_compare_entity( return (a > b) - (a < b); } +static +bool ecs_equals_entity( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + return ecs_compare_entity(a_ptr, b_ptr, ti) == 0; +} + static int ecs_compare_id( const void *a_ptr, @@ -223,6 +369,14 @@ int ecs_compare_id( return (a > b) - (a < b); } +static +bool ecs_equals_id( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + return ecs_compare_id(a_ptr, b_ptr, ti) == 0; +} int ecs_compare_string( const void *a_ptr, @@ -243,6 +397,15 @@ int ecs_compare_string( return ecs_os_strcmp(str_a, str_b); } +bool ecs_equals_string( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *ti) +{ + return ecs_compare_string(a_ptr, b_ptr, ti) == 0; +} + + /* EcsTypeSerializer lifecycle */ void ecs_meta_dtor_serialized( @@ -1621,7 +1784,8 @@ void FlecsMetaImport( .kind = primitive_kind\ });\ ecs_set_hooks(world, ecs_##type##_t, { \ - .cmp = ecs_compare_##type \ + .cmp = ecs_compare_##type, \ + .equals = ecs_equals_##type \ }) ECS_PRIMITIVE(world, bool, EcsBool); diff --git a/src/addons/meta/meta.h b/src/addons/meta/meta.h index c62934438..8c3d66712 100644 --- a/src/addons/meta/meta.h +++ b/src/addons/meta/meta.h @@ -42,6 +42,11 @@ int ecs_compare_string( const void *str_b, const ecs_type_info_t *ti); +bool ecs_equals_string( + const void *str_a, + const void *str_b, + const ecs_type_info_t *ti); + #endif #endif diff --git a/src/addons/meta/rtt_lifecycle.c b/src/addons/meta/rtt_lifecycle.c index 632e40b3e..c2248d11e 100644 --- a/src/addons/meta/rtt_lifecycle.c +++ b/src/addons/meta/rtt_lifecycle.c @@ -16,6 +16,7 @@ typedef struct ecs_rtt_call_data_t { ecs_move_t move; ecs_copy_t copy; ecs_cmp_t cmp; + ecs_equals_t equals; } hook; const ecs_type_info_t *type_info; int32_t offset; @@ -24,11 +25,13 @@ typedef struct ecs_rtt_call_data_t { /* Lifecycle context for runtime structs */ typedef struct ecs_rtt_struct_ctx_t { - ecs_vec_t vctor; /* vector */ - ecs_vec_t vdtor; /* vector */ - ecs_vec_t vmove; /* vector */ - ecs_vec_t vcopy; /* vector */ - ecs_vec_t vcomp; /* vector */ + ecs_vec_t vctor; /* vector */ + ecs_vec_t vdtor; /* vector */ + ecs_vec_t vmove; /* vector */ + ecs_vec_t vcopy; /* vector */ + ecs_vec_t vcomp; /* vector */ + ecs_vec_t vequals; /* vector */ + } ecs_rtt_struct_ctx_t; /* Lifecycle context for runtime arrays */ @@ -188,7 +191,7 @@ void flecs_rtt_struct_copy( * structs's lifecycle context and call the compare hooks configured when * the type was created. */ static -int flecs_rtt_struct_comp( +int flecs_rtt_struct_cmp( const void *a_ptr, const void *b_ptr, const ecs_type_info_t *type_info) @@ -216,6 +219,38 @@ int flecs_rtt_struct_comp( return 0; } +/* Generic equals hook. It will read hook information call data from the + * structs's lifecycle context and call the equals hooks configured when + * the type was created. */ +static +bool flecs_rtt_struct_equals( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *type_info) +{ + if(a_ptr == b_ptr) { + return 0; + } + + ecs_rtt_struct_ctx_t *rtt_ctx = type_info->hooks.lifecycle_ctx; + ecs_assert(rtt_ctx != NULL, ECS_INTERNAL_ERROR, NULL); + + int cb_count = ecs_vec_count(&rtt_ctx->vcomp); + int i; + for (i = 0; i < cb_count; i++) { + ecs_rtt_call_data_t *comp_data = + ecs_vec_get_t(&rtt_ctx->vcomp, ecs_rtt_call_data_t, i); + bool eq = comp_data->hook.equals( + ECS_OFFSET(a_ptr, comp_data->offset), + ECS_OFFSET(b_ptr, comp_data->offset), + comp_data->type_info); + if (!eq) { + return false; + } + } + return true; +} + static void flecs_rtt_free_lifecycle_nop( void *ctx) @@ -238,6 +273,7 @@ void flecs_rtt_free_lifecycle_struct_ctx( ecs_vec_fini_t(NULL, &lifecycle_ctx->vmove, ecs_rtt_call_data_t); ecs_vec_fini_t(NULL, &lifecycle_ctx->vcopy, ecs_rtt_call_data_t); ecs_vec_fini_t(NULL, &lifecycle_ctx->vcomp, ecs_rtt_call_data_t); + ecs_vec_fini_t(NULL, &lifecycle_ctx->vequals, ecs_rtt_call_data_t); ecs_os_free(ctx); } @@ -251,7 +287,8 @@ ecs_rtt_struct_ctx_t * flecs_rtt_configure_struct_hooks( ecs_xtor_t dtor, ecs_move_t move, ecs_copy_t copy, - ecs_cmp_t cmp) + ecs_cmp_t cmp, + ecs_equals_t equals) { ecs_type_hooks_t hooks = ti->hooks; if (hooks.lifecycle_ctx_free) { @@ -273,15 +310,19 @@ ecs_rtt_struct_ctx_t * flecs_rtt_configure_struct_hooks( if(flags & ECS_TYPE_HOOK_CMP_ILLEGAL) { cmp = NULL; } - + if(flags & ECS_TYPE_HOOK_EQUALS_ILLEGAL) { + equals = NULL; + } ecs_rtt_struct_ctx_t *rtt_ctx = NULL; - if (ctor || dtor || move || copy || cmp) { + if (ctor || dtor || move || copy || cmp || equals) { rtt_ctx = ecs_os_malloc_t(ecs_rtt_struct_ctx_t); ecs_vec_init_t(NULL, &rtt_ctx->vctor, ecs_rtt_call_data_t, 0); ecs_vec_init_t(NULL, &rtt_ctx->vdtor, ecs_rtt_call_data_t, 0); ecs_vec_init_t(NULL, &rtt_ctx->vmove, ecs_rtt_call_data_t, 0); ecs_vec_init_t(NULL, &rtt_ctx->vcopy, ecs_rtt_call_data_t, 0); ecs_vec_init_t(NULL, &rtt_ctx->vcomp, ecs_rtt_call_data_t, 0); + ecs_vec_init_t(NULL, &rtt_ctx->vequals, ecs_rtt_call_data_t, 0); + hooks.lifecycle_ctx = rtt_ctx; hooks.lifecycle_ctx_free = flecs_rtt_free_lifecycle_struct_ctx; } else { @@ -294,6 +335,7 @@ ecs_rtt_struct_ctx_t * flecs_rtt_configure_struct_hooks( hooks.move = move; hooks.copy = copy; hooks.cmp = cmp; + hooks.equals = equals; hooks.flags = flags; hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; @@ -320,7 +362,8 @@ void flecs_rtt_init_default_hooks_struct( bool dtor_hook_required = false; bool move_hook_required = false; bool copy_hook_required = false; - bool comparable = true; + bool valid_cmp = true; + bool valid_equals = true; /* Iterate all struct members and see if any member type has hooks. If so, * the struct itself will need to have that hook: */ @@ -336,10 +379,12 @@ void flecs_rtt_init_default_hooks_struct( move_hook_required |= member_ti->hooks.move != NULL; copy_hook_required |= member_ti->hooks.copy != NULL; - /* A struct is comparable if all its members - * are comparable */ - comparable &= member_ti->hooks.cmp != NULL; - + /* A struct has a valid cmp hook if all its members have it */ + valid_cmp &= member_ti->hooks.cmp != NULL; + + /* A struct has a valid equals hook if all its members have it */ + valid_equals &= member_ti->hooks.equals != NULL; + flags |= member_ti->hooks.flags; } @@ -353,7 +398,8 @@ void flecs_rtt_init_default_hooks_struct( dtor_hook_required ? flecs_rtt_struct_dtor : NULL, move_hook_required ? flecs_rtt_struct_move : NULL, copy_hook_required ? flecs_rtt_struct_copy : NULL, - comparable ? flecs_rtt_struct_comp : NULL + valid_cmp ? flecs_rtt_struct_cmp : NULL, + valid_equals ? flecs_rtt_struct_equals : NULL ); if (!rtt_ctx) { @@ -410,7 +456,7 @@ void flecs_rtt_init_default_hooks_struct( copy_data->hook.copy = flecs_rtt_default_copy; } } - if (comparable) { + if (valid_cmp) { ecs_rtt_call_data_t *comp_data = ecs_vec_append_t(NULL, &rtt_ctx->vcomp, ecs_rtt_call_data_t); comp_data->offset = m->offset; @@ -419,6 +465,15 @@ void flecs_rtt_init_default_hooks_struct( ecs_assert(member_ti->hooks.cmp, ECS_INTERNAL_ERROR, NULL); comp_data->hook.cmp = member_ti->hooks.cmp; } + if (valid_equals) { + ecs_rtt_call_data_t *comp_data = + ecs_vec_append_t(NULL, &rtt_ctx->vequals, ecs_rtt_call_data_t); + comp_data->offset = m->offset; + comp_data->type_info = member_ti; + comp_data->count = 1; + ecs_assert(member_ti->hooks.equals, ECS_INTERNAL_ERROR, NULL); + comp_data->hook.equals = member_ti->hooks.equals; + } } } @@ -518,7 +573,7 @@ void flecs_rtt_array_copy( /* Generic array compare hook. It will invoke the compare hook of the underlying * type for each element */ static -int flecs_rtt_array_comp( +int flecs_rtt_array_cmp( const void *a_ptr, const void *b_ptr, const ecs_type_info_t *type_info) @@ -543,6 +598,34 @@ int flecs_rtt_array_comp( return 0; } +/* Generic array equals hook. It will invoke the equals hook of the underlying + * type for each element */ +static +bool flecs_rtt_array_equals( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *type_info) +{ + if(a_ptr == b_ptr) { + return 0; + } + + ecs_rtt_array_ctx_t *rtt_ctx = type_info->hooks.lifecycle_ctx; + ecs_equals_t equals = rtt_ctx->type_info->hooks.equals; + ecs_assert(equals, ECS_INVALID_PARAMETER, NULL); + ecs_size_t element_size = rtt_ctx->type_info->size; + int i; + for (i = 0; i < rtt_ctx->elem_count; i++) { + const void *a_element = ECS_ELEM(a_ptr, element_size, i); + const void *b_element = ECS_ELEM(b_ptr, element_size, i); + bool eq = equals(a_element, b_element, rtt_ctx->type_info); + if(!eq) { + return false; + } + } + return true; +} + /* Checks if an array's underlying type has hooks installed. If so, it generates * and installs required hooks for the array type itself. These hooks will * invoke the underlying type's hook for each element in the array. */ @@ -560,7 +643,8 @@ void flecs_rtt_init_default_hooks_array( bool dtor_hook_required = element_ti->hooks.dtor != NULL; bool move_hook_required = element_ti->hooks.move != NULL; bool copy_hook_required = element_ti->hooks.copy != NULL; - bool comparable = element_ti->hooks.cmp != NULL; + bool valid_cmp = element_ti->hooks.cmp != NULL; + bool valid_equals = element_ti->hooks.equals != NULL; ecs_flags32_t flags = element_ti->hooks.flags; @@ -574,8 +658,11 @@ void flecs_rtt_init_default_hooks_array( flecs_rtt_array_move : NULL; hooks.copy = copy_hook_required && !(flags & ECS_TYPE_HOOK_COPY_ILLEGAL) ? flecs_rtt_array_copy : NULL; - hooks.cmp = comparable && !(flags & ECS_TYPE_HOOK_CMP_ILLEGAL) ? - flecs_rtt_array_comp : NULL; + hooks.cmp = valid_cmp && !(flags & ECS_TYPE_HOOK_CMP_ILLEGAL) ? + flecs_rtt_array_cmp : NULL; + hooks.equals = valid_equals && !(flags & ECS_TYPE_HOOK_EQUALS_ILLEGAL) ? + flecs_rtt_array_equals : NULL; + if (hooks.lifecycle_ctx_free) { hooks.lifecycle_ctx_free(hooks.lifecycle_ctx); @@ -583,7 +670,7 @@ void flecs_rtt_init_default_hooks_array( } if (hooks.ctor || hooks.dtor || hooks.move || - hooks.copy || hooks.cmp) + hooks.copy || hooks.cmp || hooks.equals) { ecs_rtt_array_ctx_t *rtt_ctx = ecs_os_malloc_t(ecs_rtt_array_ctx_t); rtt_ctx->type_info = element_ti; @@ -712,7 +799,7 @@ void flecs_rtt_vector_copy( /* Generic vector compare hook. */ static -int flecs_rtt_vector_comp( +int flecs_rtt_vector_cmp( const void *a_ptr, const void *b_ptr, const ecs_type_info_t *type_info) @@ -753,6 +840,49 @@ int flecs_rtt_vector_comp( return 0; } +/* Generic vector equals hook. */ +static +bool flecs_rtt_vector_equals( + const void *a_ptr, + const void *b_ptr, + const ecs_type_info_t *type_info) +{ + if(a_ptr == b_ptr) { + return 0; + } + + const ecs_vec_t *vec_a = a_ptr; + const ecs_vec_t *vec_b = b_ptr; + + ecs_size_t count_a = ecs_vec_count(vec_a); + ecs_size_t count_b = ecs_vec_count(vec_b); + { + int c = count_a - count_b; + if(c != 0) { + return c; + } + } + + ecs_rtt_vector_ctx_t *rtt_ctx = type_info->hooks.lifecycle_ctx; + ecs_equals_t equals = rtt_ctx->type_info->hooks.equals; + ecs_assert(equals, ECS_INVALID_PARAMETER, NULL); + + ecs_size_t element_size = rtt_ctx->type_info->size; + const void *a = ecs_vec_first(vec_a); + const void *b = ecs_vec_first(vec_b); + + int i; + for (i = 0; i < count_a; i++) { + const void *a_element = ECS_ELEM(a, element_size, i); + const void *b_element = ECS_ELEM(b, element_size, i); + int eq = equals(a_element, b_element, rtt_ctx->type_info); + if(!eq) { + return false; + } + } + return true; +} + /* Generates and installs required hooks for managing the vector and underlying * type lifecycle. Vectors always have hooks because at the very least the * vector structure itself must be initialized/destroyed/copied/moved, even if @@ -784,13 +914,20 @@ void flecs_rtt_init_default_hooks_vector( hooks.copy = flecs_rtt_vector_copy; if (element_ti->hooks.cmp != NULL && !(flags & ECS_TYPE_HOOK_CMP_ILLEGAL)) { - hooks.cmp = flecs_rtt_vector_comp; + hooks.cmp = flecs_rtt_vector_cmp; } else { hooks.cmp = NULL; } - /* propagate only the compare hook illegal flag, if set */ - hooks.flags |= flags & ECS_TYPE_HOOK_CMP_ILLEGAL; + if (element_ti->hooks.equals != NULL && !(flags & ECS_TYPE_HOOK_EQUALS_ILLEGAL)) { + hooks.equals = flecs_rtt_vector_equals; + } else { + hooks.equals = NULL; + } + + + /* propagate only the compare/equals hook illegal flag, if set */ + hooks.flags |= flags & (ECS_TYPE_HOOK_CMP_ILLEGAL|ECS_TYPE_HOOK_EQUALS_ILLEGAL); hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id(world, component, &hooks); diff --git a/src/world.c b/src/world.c index c6a5e4363..f4ec3bb0a 100644 --- a/src/world.c +++ b/src/world.c @@ -3,6 +3,7 @@ * @brief World-level API. */ +#include "flecs.h" #include "private_api.h" /* Id flags */ @@ -1182,6 +1183,11 @@ void flecs_default_move_w_dtor(void *dst_ptr, void *src_ptr, cl->dtor(src_ptr, count, ti); } +static +bool flecs_default_equals(const void *a_ptr, const void *b_ptr, const ecs_type_info_t* ti) { + return ti->hooks.cmp(a_ptr, b_ptr, ti) == 0; +} + ECS_NORETURN static void flecs_ctor_illegal( void * dst, @@ -1264,6 +1270,17 @@ int flecs_comp_illegal( ecs_abort(ECS_INVALID_OPERATION, "invalid compare hook for %s", ti->name); } +ECS_NORETURN static +bool flecs_equals_illegal( + const void *dst, + const void *src, + const ecs_type_info_t *ti) +{ + (void)dst; /* silence unused warning */ + (void)src; + ecs_abort(ECS_INVALID_OPERATION, "invalid compare hook for %s", ti->name); +} + void ecs_set_hooks_id( ecs_world_t *world, ecs_entity_t component, @@ -1320,6 +1337,10 @@ void ecs_set_hooks_id( h->cmp != flecs_comp_illegal), ECS_INVALID_PARAMETER, "cannot specify both compare hook and illegal flag"); + ecs_check(!(flags & ECS_TYPE_HOOK_EQUALS_ILLEGAL && + h->equals != NULL && + h->equals != flecs_equals_illegal), + ECS_INVALID_PARAMETER, "cannot specify both equals hook and illegal flag"); flecs_stage_from_world(&world); @@ -1359,6 +1380,7 @@ void ecs_set_hooks_id( if (h->ctor_move_dtor) ti->hooks.ctor_move_dtor = h->ctor_move_dtor; if (h->move_dtor) ti->hooks.move_dtor = h->move_dtor; if (h->cmp) ti->hooks.cmp = h->cmp; + if (h->equals) ti->hooks.equals = h->equals; if (h->on_add) ti->hooks.on_add = h->on_add; if (h->on_remove) ti->hooks.on_remove = h->on_remove; @@ -1457,6 +1479,14 @@ void ecs_set_hooks_id( } } + if (!h->equals) { + if(flags & ECS_TYPE_HOOK_CMP_ILLEGAL) { + flags |= ECS_TYPE_HOOK_EQUALS_ILLEGAL; + } else if(h->cmp) { + ti->hooks.equals = flecs_default_equals; + } + } + ti->hooks.flags = flags; if (ti->hooks.ctor) ti->hooks.flags |= ECS_TYPE_HOOK_CTOR; @@ -1468,12 +1498,14 @@ void ecs_set_hooks_id( 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 (ti->hooks.cmp) ti->hooks.flags |= ECS_TYPE_HOOK_CMP; + if (ti->hooks.equals) ti->hooks.flags |= ECS_TYPE_HOOK_EQUALS; 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_TYPE_HOOK_CMP_ILLEGAL) ti->hooks.cmp = flecs_comp_illegal; + if(flags & ECS_TYPE_HOOK_EQUALS_ILLEGAL) ti->hooks.equals = flecs_equals_illegal; if(flags & ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL) { ti->hooks.copy_ctor = flecs_copy_ctor_illegal; diff --git a/test/meta/project.json b/test/meta/project.json index e57e5f821..3ae4865a7 100644 --- a/test/meta/project.json +++ b/test/meta/project.json @@ -107,7 +107,7 @@ "move_illegal", "copy", "copy_illegal", - "comp_illegal", + "cmp_illegal", "trivial_array", "array_ctor", "array_ctor_illegal", @@ -117,10 +117,10 @@ "array_move_illegal", "array_copy", "array_copy_illegal", - "array_comp_illegal", + "array_cmp_illegal", "vector_lifecycle", "vector_lifecycle_trivial_type", - "vector_comp_illegal", + "vector_cmp_illegal", "opaque", "struct_with_ints", "struct_with_strings", diff --git a/test/meta/src/PrimitiveCompare.c b/test/meta/src/PrimitiveCompare.c index 097d848d2..9253e6711 100644 --- a/test/meta/src/PrimitiveCompare.c +++ b/test/meta/src/PrimitiveCompare.c @@ -1,5 +1,6 @@ #include #include +#include "flecs.h" static @@ -7,6 +8,11 @@ int cmp(const void *a, const void *b, const ecs_type_info_t* ti) { return ti->hooks.cmp(a, b, ti); } +static +bool equals(const void *a, const void *b, const ecs_type_info_t* ti) { + return ti->hooks.equals(a, b, ti); +} + const ecs_type_info_t *sort_ti = NULL; static int compare_element(const void *a, const void *b) { @@ -51,8 +57,10 @@ void PrimitiveCompare_bool(void) { /* test "greater" */ test_assert(cmp(&arr[0], &arr[1], ti) > 0); /* true > false */ - /* test "equal" */ + /* test "equal" via cmp hook */ test_assert(cmp(&arr[0], &arr[0], ti) == 0); /* true == true */ + /* test "equal" via equals hook */ + test_assert(equals(&arr[0], &arr[0], ti)); /* true == true */ /* further test by sorting the array */ sort_array(ti, arr, 4); @@ -76,8 +84,10 @@ void PrimitiveCompare_char(void) { /* test "greater" */ test_assert(cmp(&arr[0], &arr[1], ti) > 0); /* 'z' > 'a' */ - /* test "equal" */ + /* test "equal" via cmp hook */ test_assert(cmp(&arr[1], &arr[1], ti) == 0); /* 'a' == 'a' */ + /* test "equal" via equals hook */ + test_assert(equals(&arr[1], &arr[1], ti)); /* 'a' == 'a' */ /* further test by sorting the array */ sort_array(ti, arr, 6); @@ -101,8 +111,10 @@ void PrimitiveCompare_byte(void) { /* test "greater" */ test_assert(cmp(&arr[0], &arr[1], ti) > 0); /* 0xFF > 0x01 */ - /* test "equal" */ + /* test "equal" via cmp hook */ test_assert(cmp(&arr[1], &arr[1], ti) == 0); /* 0x01 == 0x01 */ + /* test "equal" via equals hook */ + test_assert(equals(&arr[1], &arr[1], ti)); /* 0x01 == 0x01 */ /* further test by sorting the array */ sort_array(ti, arr, 5); @@ -126,8 +138,10 @@ void PrimitiveCompare_u8(void) { /* test "greater" */ test_assert(cmp(&arr[1], &arr[0], ti) > 0); /* 79 > 1 */ - /* test "equal" */ + /* test "equal" via cmp hook */ test_assert(cmp(&arr[5], &arr[1], ti) == 0); /* 79 == 79 */ + /* test "equal" via equals hook */ + test_assert(equals(&arr[5], &arr[1], ti)); /* 79 == 79 */ /* further test by sorting the array */ sort_array(ti, arr, 8); @@ -151,8 +165,10 @@ void PrimitiveCompare_u16(void) { /* test "greater" */ test_assert(cmp(&arr[1], &arr[2], ti) > 0); /* 65535 > 0 */ - /* test "equal" */ + /* test "equal" via cmp hook */ test_assert(cmp(&arr[0], &arr[4], ti) == 0); /* 1024 == 1024 */ + /* test "equal" via equals hook */ + test_assert(equals(&arr[0], &arr[4], ti)); /* 1024 == 1024 */ /* further test by sorting the array */ sort_array(ti, arr, 6); @@ -176,8 +192,10 @@ void PrimitiveCompare_u32(void) { /* test "greater" */ test_assert(cmp(&arr[2], &arr[1], ti) > 0); /* 4294967295 > 500 */ - /* test "equal" */ + /* test "equal" via cmp hook */ test_assert(cmp(&arr[0], &arr[3], ti) == 0); /* 100000 == 100000 */ + /* test "equal" via equals hook */ + test_assert(equals(&arr[0], &arr[3], ti)); /* 100000 == 100000 */ /* further test by sorting the array */ sort_array(ti, arr, 5); @@ -205,9 +223,11 @@ void PrimitiveCompare_u64(void) { /* 18446744073709551615 > 1000 */ test_assert(cmp(&arr[0], &arr[2], ti) > 0); - /* test "equal" */ + /* test "equal" via cmp hook */ /* 18446744073709551615 == 18446744073709551615 */ test_assert(cmp(&arr[0], &arr[3], ti) == 0); + /* test "equal" via equals hook */ + test_assert(equals(&arr[0], &arr[3], ti)); /* further test by sorting the array */ sort_array(ti, arr, 5); @@ -231,8 +251,10 @@ void PrimitiveCompare_uptr(void) { /* test "greater" */ test_assert(cmp(&arr[3], &arr[1], ti) > 0); /* 0x9ABC > 0x5678 */ - /* test "equal" */ + /* test "equal" via cmp hook */ test_assert(cmp(&arr[0], &arr[2], ti) == 0); /* 0x1234 == 0x1234 */ + /* test "equal" via equals hook */ + test_assert(equals(&arr[0], &arr[2], ti)); /* 0x1234 == 0x1234 */ /* further test by sorting the array */ sort_array(ti, arr, 4); @@ -256,8 +278,10 @@ void PrimitiveCompare_i8(void) { /* test "greater" */ test_assert(cmp(&arr[1], &arr[2], ti) > 0); /* 127 > 0 */ - /* test "equal" */ + /* test "equal" via cmp hook */ test_assert(cmp(&arr[1], &arr[4], ti) == 0); /* 127 == 127 */ + /* test "equal" via equals hook */ + test_assert(equals(&arr[1], &arr[4], ti)); /* 127 == 127 */ /* further test by sorting the array */ sort_array(ti, arr, 6); @@ -281,8 +305,10 @@ void PrimitiveCompare_i16(void) { /* test "greater" */ test_assert(cmp(&arr[1], &arr[2], ti) > 0); /* 32767 > 100 */ - /* test "equal" */ + /* test "equal" via cmp hook */ test_assert(cmp(&arr[1], &arr[4], ti) == 0); /* 32767 == 32767 */ + /* test "equal" via equals hook */ + test_assert(equals(&arr[1], &arr[4], ti)); /* 32767 == 32767 */ /* further test by sorting the array */ sort_array(ti, arr, 5); @@ -306,8 +332,10 @@ void PrimitiveCompare_i32(void) { /* test "greater" */ test_assert(cmp(&arr[1], &arr[2], ti) > 0); /* 50000 > 0 */ - /* test "equal" */ + /* test "equal" via cmp hook */ test_assert(cmp(&arr[0], &arr[3], ti) == 0); /* -100000 == -100000 */ + /* test "equal" via equals hook */ + test_assert(equals(&arr[0], &arr[3], ti)); /* -100000 == -100000 */ /* further test by sorting the array */ sort_array(ti, arr, 5); @@ -335,9 +363,11 @@ void PrimitiveCompare_i64(void) { /* 9223372036854775807 > 0 */ test_assert(cmp(&arr[1], &arr[2], ti) > 0); - /* test "equal" */ + /* test "equal" via cmp hook */ /* 9223372036854775807 == 9223372036854775807 */ test_assert(cmp(&arr[1], &arr[4], ti) == 0); + /* test "equal" via equals hook */ + test_assert(equals(&arr[1], &arr[4], ti)); /* further test by sorting the array */ sort_array(ti, arr, 5); @@ -361,8 +391,10 @@ void PrimitiveCompare_iptr(void) { /* test "greater" */ test_assert(cmp(&arr[1], &arr[2], ti) > 0); /* 500 > 0 */ - /* test "equal" */ + /* test "equal" via cmp hook */ test_assert(cmp(&arr[0], &arr[3], ti) == 0); /* -1000 == -1000 */ + /* test "equal" via equals hook */ + test_assert(equals(&arr[0], &arr[3], ti)); /* -1000 == -1000 */ /* further test by sorting the array */ sort_array(ti, arr, 4); @@ -386,8 +418,10 @@ void PrimitiveCompare_f32(void) { /* test "greater" */ test_assert(cmp(&arr[0], &arr[4], ti) > 0); /* 3.14 > 0.0 */ - /* test "equal" */ + /* test "equal" via cmp hook */ test_assert(cmp(&arr[1], &arr[3], ti) == 0); /* 2.71 == 2.71 */ + /* test "equal" via equals hook */ + test_assert(equals(&arr[1], &arr[3], ti)); /* 2.71 == 2.71 */ /* further test by sorting the array */ sort_array(ti, arr, 5); @@ -411,8 +445,10 @@ void PrimitiveCompare_f64(void) { /* test "greater" */ test_assert(cmp(&arr[0], &arr[4], ti) > 0); /* 3.14159 > 0.0 */ - /* test "equal" */ + /* test "equal" via cmp hook */ test_assert(cmp(&arr[1], &arr[3], ti) == 0); /* 2.71828 == 2.71828 */ + /* test "equal" via equals hook */ + test_assert(equals(&arr[1], &arr[3], ti)); /* 2.71828 == 2.71828 */ /* further test by sorting the array */ sort_array(ti, arr, 5); @@ -436,8 +472,10 @@ void PrimitiveCompare_entity(void) { /* test "greater" */ test_assert(cmp(&arr[0], &arr[1], ti) > 0); /* 1000 > 42 */ - /* test "equal" */ + /* test "equal" via cmp hook */ test_assert(cmp(&arr[0], &arr[2], ti) == 0); /* 1000 == 1000 */ + /* test "equal" via equals hook */ + test_assert(equals(&arr[0], &arr[2], ti)); /* 1000 == 1000 */ /* further test by sorting the array */ sort_array(ti, arr, 5); @@ -461,8 +499,10 @@ void PrimitiveCompare_id(void) { /* test "greater" */ test_assert(cmp(&arr[0], &arr[1], ti) > 0); /* 1000 > 42 */ - /* test "equal" */ + /* test "equal" via cmp hook */ test_assert(cmp(&arr[0], &arr[2], ti) == 0); /* 1000 == 1000 */ + /* test "equal" via equals hook */ + test_assert(equals(&arr[0], &arr[2], ti)); /* 1000 == 1000 */ /* further test by sorting the array */ sort_array(ti, arr, 5); @@ -494,9 +534,13 @@ void PrimitiveCompare_string(void) { /* test "greater" */ test_assert(cmp(&arr[6], &arr[5], ti) > 0); /* "cc" > "aa" */ - /* test "equal" */ + /* test "equal" via cmp hook */ test_assert(cmp(&arr[3], &arr[5], ti) == 0); /* "aa" == "aa" */ - test_assert(cmp(&arr[2], &arr[5], ti) < 0); /* NULL == NULL */ + test_assert(cmp(&arr[2], &arr[2], ti) == 0); /* NULL == NULL */ + + /* test "equal" via equals hook */ + test_assert(equals(&arr[3], &arr[5], ti)); /* "aa" == "aa" */ + test_assert(equals(&arr[2], &arr[2], ti)); /* NULL == NULL */ /* further test by sorting the array */ sort_array(ti, arr, STRING_COUNT); @@ -530,9 +574,13 @@ void PrimitiveCompare_const_string(void) { /* test "greater" */ test_assert(cmp(&arr[6], &arr[5], ti) > 0); /* "cc" > "aa" */ - /* test "equal" */ + /* test "equal" via cmp hook */ test_assert(cmp(&arr[3], &arr[5], ti) == 0); /* "aa" == "aa" */ - test_assert(cmp(&arr[2], &arr[5], ti) < 0); /* NULL == NULL */ + test_assert(cmp(&arr[2], &arr[2], ti) == 0); /* NULL == NULL */ + + /* test "equal" via equals hook */ + test_assert(equals(&arr[3], &arr[5], ti)); /* "aa" == "aa" */ + test_assert(equals(&arr[2], &arr[2], ti)); /* NULL == NULL */ /* further test by sorting the array */ sort_array(ti, arr, STRING_COUNT); diff --git a/test/meta/src/RuntimeTypes.c b/test/meta/src/RuntimeTypes.c index 18345103a..a33c4259a 100644 --- a/test/meta/src/RuntimeTypes.c +++ b/test/meta/src/RuntimeTypes.c @@ -566,7 +566,7 @@ void RuntimeTypes_copy_illegal(void) { /* Tests that an illegal compare hook is set for a struct if at least a member has * itself an illegal compare hook */ -void RuntimeTypes_comp_illegal(void) { +void RuntimeTypes_cmp_illegal(void) { ecs_world_t *world = ecs_init(); /* Define NestedStruct: */ @@ -1213,7 +1213,7 @@ void RuntimeTypes_array_copy_illegal(void) { /* Tests that an illegal cmp hook is set for an array if its underlying type itself * has an illegal cmp hook */ -void RuntimeTypes_array_comp_illegal(void) { +void RuntimeTypes_array_cmp_illegal(void) { ecs_world_t *world = ecs_init(); /* Define NestedStruct: */ @@ -1377,7 +1377,7 @@ void RuntimeTypes_vector_lifecycle_trivial_type(void) { /* Tests that an illegal cmp hook is set for an array if its underlying type itself * has an illegal cmp hook */ -void RuntimeTypes_vector_comp_illegal(void) { +void RuntimeTypes_vector_cmp_illegal(void) { ecs_world_t *world = ecs_init(); /* Define NestedStruct: */ diff --git a/test/meta/src/main.c b/test/meta/src/main.c index f723f3983..123f91fa4 100644 --- a/test/meta/src/main.c +++ b/test/meta/src/main.c @@ -96,7 +96,7 @@ void RuntimeTypes_move(void); void RuntimeTypes_move_illegal(void); void RuntimeTypes_copy(void); void RuntimeTypes_copy_illegal(void); -void RuntimeTypes_comp_illegal(void); +void RuntimeTypes_cmp_illegal(void); void RuntimeTypes_trivial_array(void); void RuntimeTypes_array_ctor(void); void RuntimeTypes_array_ctor_illegal(void); @@ -106,10 +106,10 @@ void RuntimeTypes_array_move(void); void RuntimeTypes_array_move_illegal(void); void RuntimeTypes_array_copy(void); void RuntimeTypes_array_copy_illegal(void); -void RuntimeTypes_array_comp_illegal(void); +void RuntimeTypes_array_cmp_illegal(void); void RuntimeTypes_vector_lifecycle(void); void RuntimeTypes_vector_lifecycle_trivial_type(void); -void RuntimeTypes_vector_comp_illegal(void); +void RuntimeTypes_vector_cmp_illegal(void); void RuntimeTypes_opaque(void); void RuntimeTypes_struct_with_ints(void); void RuntimeTypes_struct_with_strings(void); @@ -1397,8 +1397,8 @@ bake_test_case RuntimeTypes_testcases[] = { RuntimeTypes_copy_illegal }, { - "comp_illegal", - RuntimeTypes_comp_illegal + "cmp_illegal", + RuntimeTypes_cmp_illegal }, { "trivial_array", @@ -1437,8 +1437,8 @@ bake_test_case RuntimeTypes_testcases[] = { RuntimeTypes_array_copy_illegal }, { - "array_comp_illegal", - RuntimeTypes_array_comp_illegal + "array_cmp_illegal", + RuntimeTypes_array_cmp_illegal }, { "vector_lifecycle", @@ -1449,8 +1449,8 @@ bake_test_case RuntimeTypes_testcases[] = { RuntimeTypes_vector_lifecycle_trivial_type }, { - "vector_comp_illegal", - RuntimeTypes_vector_comp_illegal + "vector_cmp_illegal", + RuntimeTypes_vector_cmp_illegal }, { "opaque", From 63a079323b16cfee9e87dba75483ec3c049b01ab Mon Sep 17 00:00:00 2001 From: Javier Peletier Date: Fri, 29 Nov 2024 12:28:32 +0100 Subject: [PATCH 16/23] Equals hook lifecycle traits --- distr/flecs.c | 3 +- distr/flecs.h | 24 +++++++++++ include/flecs/addons/cpp/component.hpp | 2 + include/flecs/addons/cpp/lifecycle_traits.hpp | 22 ++++++++++ src/world.c | 3 +- test/cpp/src/ComponentLifecycle.cpp | 43 +++++++++++++++++++ 6 files changed, 95 insertions(+), 2 deletions(-) diff --git a/distr/flecs.c b/distr/flecs.c index 77a1c1d56..7f0e189cb 100644 --- a/distr/flecs.c +++ b/distr/flecs.c @@ -19037,7 +19037,7 @@ bool flecs_equals_illegal( { (void)dst; /* silence unused warning */ (void)src; - ecs_abort(ECS_INVALID_OPERATION, "invalid compare hook for %s", ti->name); + ecs_abort(ECS_INVALID_OPERATION, "invalid equals hook for %s", ti->name); } void ecs_set_hooks_id( @@ -19242,6 +19242,7 @@ void ecs_set_hooks_id( if(flags & ECS_TYPE_HOOK_CMP_ILLEGAL) { flags |= ECS_TYPE_HOOK_EQUALS_ILLEGAL; } else if(h->cmp) { + flags &= (ecs_flags32_t)(~ECS_TYPE_HOOK_EQUALS_ILLEGAL); ti->hooks.equals = flecs_default_equals; } } diff --git a/distr/flecs.h b/distr/flecs.h index 1c37ab0d8..bf80ce844 100644 --- a/distr/flecs.h +++ b/distr/flecs.h @@ -20650,6 +20650,28 @@ ecs_cmp_t compare(ecs_flags32_t &flags) { return NULL; } +// Equals function enabled only if `==` is defined +template ::value > = 0> +bool equals_impl(const void *a, const void *b, const ecs_type_info_t *) { + const T& lhs = *static_cast(a); + const T& rhs = *static_cast(b); + return lhs == rhs; +} + +template ::value > = 0> +ecs_equals_t equals(ecs_flags32_t &) { + return equals_impl; +} + +template ::value > = 0> +ecs_equals_t equals(ecs_flags32_t &flags) { + flags |= ECS_TYPE_HOOK_EQUALS_ILLEGAL; + return NULL; +} + // re-enable the float comparison warning: #if defined(__clang__) #pragma clang diagnostic pop @@ -26998,6 +27020,7 @@ void register_lifecycle_actions( ecs_type_hooks_t cl{}; cl.cmp = compare(cl.flags); + cl.equals = equals(cl.flags); cl.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id(world, component, &cl); @@ -27025,6 +27048,7 @@ void register_lifecycle_actions( cl.move_dtor = move_dtor(cl.flags); cl.cmp = compare(cl.flags); + cl.equals = equals(cl.flags); cl.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id(world, component, &cl); diff --git a/include/flecs/addons/cpp/component.hpp b/include/flecs/addons/cpp/component.hpp index ffa853ed3..c7c113266 100644 --- a/include/flecs/addons/cpp/component.hpp +++ b/include/flecs/addons/cpp/component.hpp @@ -102,6 +102,7 @@ void register_lifecycle_actions( ecs_type_hooks_t cl{}; cl.cmp = compare(cl.flags); + cl.equals = equals(cl.flags); cl.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id(world, component, &cl); @@ -129,6 +130,7 @@ void register_lifecycle_actions( cl.move_dtor = move_dtor(cl.flags); cl.cmp = compare(cl.flags); + cl.equals = equals(cl.flags); cl.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id(world, component, &cl); diff --git a/include/flecs/addons/cpp/lifecycle_traits.hpp b/include/flecs/addons/cpp/lifecycle_traits.hpp index aa32cd689..80b611089 100644 --- a/include/flecs/addons/cpp/lifecycle_traits.hpp +++ b/include/flecs/addons/cpp/lifecycle_traits.hpp @@ -472,6 +472,28 @@ ecs_cmp_t compare(ecs_flags32_t &flags) { return NULL; } +// Equals function enabled only if `==` is defined +template ::value > = 0> +bool equals_impl(const void *a, const void *b, const ecs_type_info_t *) { + const T& lhs = *static_cast(a); + const T& rhs = *static_cast(b); + return lhs == rhs; +} + +template ::value > = 0> +ecs_equals_t equals(ecs_flags32_t &) { + return equals_impl; +} + +template ::value > = 0> +ecs_equals_t equals(ecs_flags32_t &flags) { + flags |= ECS_TYPE_HOOK_EQUALS_ILLEGAL; + return NULL; +} + // re-enable the float comparison warning: #if defined(__clang__) #pragma clang diagnostic pop diff --git a/src/world.c b/src/world.c index f4ec3bb0a..9ebbb48ba 100644 --- a/src/world.c +++ b/src/world.c @@ -1278,7 +1278,7 @@ bool flecs_equals_illegal( { (void)dst; /* silence unused warning */ (void)src; - ecs_abort(ECS_INVALID_OPERATION, "invalid compare hook for %s", ti->name); + ecs_abort(ECS_INVALID_OPERATION, "invalid equals hook for %s", ti->name); } void ecs_set_hooks_id( @@ -1483,6 +1483,7 @@ void ecs_set_hooks_id( if(flags & ECS_TYPE_HOOK_CMP_ILLEGAL) { flags |= ECS_TYPE_HOOK_EQUALS_ILLEGAL; } else if(h->cmp) { + flags &= (ecs_flags32_t)(~ECS_TYPE_HOOK_EQUALS_ILLEGAL); ti->hooks.equals = flecs_default_equals; } } diff --git a/test/cpp/src/ComponentLifecycle.cpp b/test/cpp/src/ComponentLifecycle.cpp index b653653cc..58b3eed89 100644 --- a/test/cpp/src/ComponentLifecycle.cpp +++ b/test/cpp/src/ComponentLifecycle.cpp @@ -2342,6 +2342,11 @@ int compare(flecs::world& ecs, flecs::entity_t id, const void *a, const void *b) return ti->hooks.cmp(a, b, ti); } +bool equals(flecs::world& ecs, flecs::entity_t id, const void *a, const void *b) { + const ecs_type_info_t* ti = ecs_get_type_info(ecs, id); + return ti->hooks.equals(a, b, ti); +} + void ComponentLifecycle_compare_WithGreaterThan(void) { flecs::world ecs; @@ -2357,6 +2362,11 @@ void ComponentLifecycle_compare_WithGreaterThan(void) { test_assert(compare(ecs, component, &b, &c) > 0); test_assert(compare(ecs, component, &c, &b) < 0); test_assert(compare(ecs, component, &b, &b) == 0); + + /* test using autogenerated equals operator: */ + test_assert(equals(ecs, component, &a, &b) == false); + test_assert(equals(ecs, component, &a, &c) == true); + test_assert(equals(ecs, component, &a, &a) == true); } void ComponentLifecycle_compare_WithLessThan(void) { @@ -2374,6 +2384,11 @@ void ComponentLifecycle_compare_WithLessThan(void) { test_assert(compare(ecs, component, &b, &c) > 0); test_assert(compare(ecs, component, &c, &b) < 0); test_assert(compare(ecs, component, &b, &b) == 0); + + /* test using autogenerated equals operator: */ + test_assert(equals(ecs, component, &a, &b) == false); + test_assert(equals(ecs, component, &a, &c) == true); + test_assert(equals(ecs, component, &a, &a) == true); } void ComponentLifecycle_compare_WithLessAndGreaterThan(void) { @@ -2391,6 +2406,11 @@ void ComponentLifecycle_compare_WithLessAndGreaterThan(void) { test_assert(compare(ecs, component, &b, &c) > 0); test_assert(compare(ecs, component, &c, &b) < 0); test_assert(compare(ecs, component, &b, &b) == 0); + + /* test using autogenerated equals operator: */ + test_assert(equals(ecs, component, &a, &b) == false); + test_assert(equals(ecs, component, &a, &c) == true); + test_assert(equals(ecs, component, &a, &a) == true); } void ComponentLifecycle_compare_WithEqualsAndGreaterThan(void) { @@ -2408,6 +2428,11 @@ void ComponentLifecycle_compare_WithEqualsAndGreaterThan(void) { test_assert(compare(ecs, component, &b, &c) > 0); test_assert(compare(ecs, component, &c, &b) < 0); test_assert(compare(ecs, component, &b, &b) == 0); + + /* test using equals operator: */ + test_assert(equals(ecs, component, &a, &b) == false); + test_assert(equals(ecs, component, &a, &c) == true); + test_assert(equals(ecs, component, &a, &a) == true); } void ComponentLifecycle_compare_WithEqualsAndLessThan(void) { @@ -2425,6 +2450,13 @@ void ComponentLifecycle_compare_WithEqualsAndLessThan(void) { test_assert(compare(ecs, component, &b, &c) > 0); test_assert(compare(ecs, component, &c, &b) < 0); test_assert(compare(ecs, component, &b, &b) == 0); + + /* test using equals operator: */ + test_assert(equals(ecs, component, &a, &b) == false); + test_assert(equals(ecs, component, &a, &c) == true); + test_assert(equals(ecs, component, &a, &a) == true); + + } void ComponentLifecycle_compare_WithEqualsOnly(void) { @@ -2436,6 +2468,15 @@ void ComponentLifecycle_compare_WithEqualsOnly(void) { /* can't compare if no < or > operators are defined */ test_assert(hooks->flags & ECS_TYPE_HOOK_CMP_ILLEGAL); + + WithEqualsOnly a = {1}; + WithEqualsOnly b = {2}; + WithEqualsOnly c = {1}; + + test_assert(equals(ecs, component, &a, &b) == false); + test_assert(equals(ecs, component, &a, &c) == true); + test_assert(equals(ecs, component, &a, &a) == true); + } void ComponentLifecycle_compare_WithoutOperators(void) { @@ -2447,5 +2488,7 @@ void ComponentLifecycle_compare_WithoutOperators(void) { /* can't compare if no operators are defined at all */ test_assert(hooks->flags & ECS_TYPE_HOOK_CMP_ILLEGAL); + test_assert(hooks->flags & ECS_TYPE_HOOK_EQUALS_ILLEGAL); + } From 368d63ce6701764ed10d71d1c47ca2b819e23474 Mon Sep 17 00:00:00 2001 From: Javier Peletier Date: Fri, 29 Nov 2024 12:45:54 +0100 Subject: [PATCH 17/23] Added equals test to RttCompare --- distr/flecs.c | 22 ++++++------ src/addons/meta/rtt_lifecycle.c | 22 ++++++------ test/meta/src/RttCompare.c | 63 +++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 22 deletions(-) diff --git a/distr/flecs.c b/distr/flecs.c index 7f0e189cb..477725829 100644 --- a/distr/flecs.c +++ b/distr/flecs.c @@ -51846,7 +51846,7 @@ typedef struct ecs_rtt_struct_ctx_t { ecs_vec_t vdtor; /* vector */ ecs_vec_t vmove; /* vector */ ecs_vec_t vcopy; /* vector */ - ecs_vec_t vcomp; /* vector */ + ecs_vec_t vcmp; /* vector */ ecs_vec_t vequals; /* vector */ } ecs_rtt_struct_ctx_t; @@ -52020,11 +52020,11 @@ int flecs_rtt_struct_cmp( ecs_rtt_struct_ctx_t *rtt_ctx = type_info->hooks.lifecycle_ctx; ecs_assert(rtt_ctx != NULL, ECS_INTERNAL_ERROR, NULL); - int cb_count = ecs_vec_count(&rtt_ctx->vcomp); + int cb_count = ecs_vec_count(&rtt_ctx->vcmp); int i; for (i = 0; i < cb_count; i++) { ecs_rtt_call_data_t *comp_data = - ecs_vec_get_t(&rtt_ctx->vcomp, ecs_rtt_call_data_t, i); + ecs_vec_get_t(&rtt_ctx->vcmp, ecs_rtt_call_data_t, i); int c = comp_data->hook.cmp( ECS_OFFSET(a_ptr, comp_data->offset), ECS_OFFSET(b_ptr, comp_data->offset), @@ -52046,17 +52046,17 @@ bool flecs_rtt_struct_equals( const ecs_type_info_t *type_info) { if(a_ptr == b_ptr) { - return 0; + return true; } ecs_rtt_struct_ctx_t *rtt_ctx = type_info->hooks.lifecycle_ctx; ecs_assert(rtt_ctx != NULL, ECS_INTERNAL_ERROR, NULL); - int cb_count = ecs_vec_count(&rtt_ctx->vcomp); + int cb_count = ecs_vec_count(&rtt_ctx->vequals); int i; for (i = 0; i < cb_count; i++) { ecs_rtt_call_data_t *comp_data = - ecs_vec_get_t(&rtt_ctx->vcomp, ecs_rtt_call_data_t, i); + ecs_vec_get_t(&rtt_ctx->vequals, ecs_rtt_call_data_t, i); bool eq = comp_data->hook.equals( ECS_OFFSET(a_ptr, comp_data->offset), ECS_OFFSET(b_ptr, comp_data->offset), @@ -52089,7 +52089,7 @@ void flecs_rtt_free_lifecycle_struct_ctx( ecs_vec_fini_t(NULL, &lifecycle_ctx->vdtor, ecs_rtt_call_data_t); ecs_vec_fini_t(NULL, &lifecycle_ctx->vmove, ecs_rtt_call_data_t); ecs_vec_fini_t(NULL, &lifecycle_ctx->vcopy, ecs_rtt_call_data_t); - ecs_vec_fini_t(NULL, &lifecycle_ctx->vcomp, ecs_rtt_call_data_t); + ecs_vec_fini_t(NULL, &lifecycle_ctx->vcmp, ecs_rtt_call_data_t); ecs_vec_fini_t(NULL, &lifecycle_ctx->vequals, ecs_rtt_call_data_t); ecs_os_free(ctx); @@ -52137,7 +52137,7 @@ ecs_rtt_struct_ctx_t * flecs_rtt_configure_struct_hooks( ecs_vec_init_t(NULL, &rtt_ctx->vdtor, ecs_rtt_call_data_t, 0); ecs_vec_init_t(NULL, &rtt_ctx->vmove, ecs_rtt_call_data_t, 0); ecs_vec_init_t(NULL, &rtt_ctx->vcopy, ecs_rtt_call_data_t, 0); - ecs_vec_init_t(NULL, &rtt_ctx->vcomp, ecs_rtt_call_data_t, 0); + ecs_vec_init_t(NULL, &rtt_ctx->vcmp, ecs_rtt_call_data_t, 0); ecs_vec_init_t(NULL, &rtt_ctx->vequals, ecs_rtt_call_data_t, 0); hooks.lifecycle_ctx = rtt_ctx; @@ -52275,7 +52275,7 @@ void flecs_rtt_init_default_hooks_struct( } if (valid_cmp) { ecs_rtt_call_data_t *comp_data = - ecs_vec_append_t(NULL, &rtt_ctx->vcomp, ecs_rtt_call_data_t); + ecs_vec_append_t(NULL, &rtt_ctx->vcmp, ecs_rtt_call_data_t); comp_data->offset = m->offset; comp_data->type_info = member_ti; comp_data->count = 1; @@ -52424,7 +52424,7 @@ bool flecs_rtt_array_equals( const ecs_type_info_t *type_info) { if(a_ptr == b_ptr) { - return 0; + return true; } ecs_rtt_array_ctx_t *rtt_ctx = type_info->hooks.lifecycle_ctx; @@ -52665,7 +52665,7 @@ bool flecs_rtt_vector_equals( const ecs_type_info_t *type_info) { if(a_ptr == b_ptr) { - return 0; + return true; } const ecs_vec_t *vec_a = a_ptr; diff --git a/src/addons/meta/rtt_lifecycle.c b/src/addons/meta/rtt_lifecycle.c index c2248d11e..4af8250d3 100644 --- a/src/addons/meta/rtt_lifecycle.c +++ b/src/addons/meta/rtt_lifecycle.c @@ -29,7 +29,7 @@ typedef struct ecs_rtt_struct_ctx_t { ecs_vec_t vdtor; /* vector */ ecs_vec_t vmove; /* vector */ ecs_vec_t vcopy; /* vector */ - ecs_vec_t vcomp; /* vector */ + ecs_vec_t vcmp; /* vector */ ecs_vec_t vequals; /* vector */ } ecs_rtt_struct_ctx_t; @@ -203,11 +203,11 @@ int flecs_rtt_struct_cmp( ecs_rtt_struct_ctx_t *rtt_ctx = type_info->hooks.lifecycle_ctx; ecs_assert(rtt_ctx != NULL, ECS_INTERNAL_ERROR, NULL); - int cb_count = ecs_vec_count(&rtt_ctx->vcomp); + int cb_count = ecs_vec_count(&rtt_ctx->vcmp); int i; for (i = 0; i < cb_count; i++) { ecs_rtt_call_data_t *comp_data = - ecs_vec_get_t(&rtt_ctx->vcomp, ecs_rtt_call_data_t, i); + ecs_vec_get_t(&rtt_ctx->vcmp, ecs_rtt_call_data_t, i); int c = comp_data->hook.cmp( ECS_OFFSET(a_ptr, comp_data->offset), ECS_OFFSET(b_ptr, comp_data->offset), @@ -229,17 +229,17 @@ bool flecs_rtt_struct_equals( const ecs_type_info_t *type_info) { if(a_ptr == b_ptr) { - return 0; + return true; } ecs_rtt_struct_ctx_t *rtt_ctx = type_info->hooks.lifecycle_ctx; ecs_assert(rtt_ctx != NULL, ECS_INTERNAL_ERROR, NULL); - int cb_count = ecs_vec_count(&rtt_ctx->vcomp); + int cb_count = ecs_vec_count(&rtt_ctx->vequals); int i; for (i = 0; i < cb_count; i++) { ecs_rtt_call_data_t *comp_data = - ecs_vec_get_t(&rtt_ctx->vcomp, ecs_rtt_call_data_t, i); + ecs_vec_get_t(&rtt_ctx->vequals, ecs_rtt_call_data_t, i); bool eq = comp_data->hook.equals( ECS_OFFSET(a_ptr, comp_data->offset), ECS_OFFSET(b_ptr, comp_data->offset), @@ -272,7 +272,7 @@ void flecs_rtt_free_lifecycle_struct_ctx( ecs_vec_fini_t(NULL, &lifecycle_ctx->vdtor, ecs_rtt_call_data_t); ecs_vec_fini_t(NULL, &lifecycle_ctx->vmove, ecs_rtt_call_data_t); ecs_vec_fini_t(NULL, &lifecycle_ctx->vcopy, ecs_rtt_call_data_t); - ecs_vec_fini_t(NULL, &lifecycle_ctx->vcomp, ecs_rtt_call_data_t); + ecs_vec_fini_t(NULL, &lifecycle_ctx->vcmp, ecs_rtt_call_data_t); ecs_vec_fini_t(NULL, &lifecycle_ctx->vequals, ecs_rtt_call_data_t); ecs_os_free(ctx); @@ -320,7 +320,7 @@ ecs_rtt_struct_ctx_t * flecs_rtt_configure_struct_hooks( ecs_vec_init_t(NULL, &rtt_ctx->vdtor, ecs_rtt_call_data_t, 0); ecs_vec_init_t(NULL, &rtt_ctx->vmove, ecs_rtt_call_data_t, 0); ecs_vec_init_t(NULL, &rtt_ctx->vcopy, ecs_rtt_call_data_t, 0); - ecs_vec_init_t(NULL, &rtt_ctx->vcomp, ecs_rtt_call_data_t, 0); + ecs_vec_init_t(NULL, &rtt_ctx->vcmp, ecs_rtt_call_data_t, 0); ecs_vec_init_t(NULL, &rtt_ctx->vequals, ecs_rtt_call_data_t, 0); hooks.lifecycle_ctx = rtt_ctx; @@ -458,7 +458,7 @@ void flecs_rtt_init_default_hooks_struct( } if (valid_cmp) { ecs_rtt_call_data_t *comp_data = - ecs_vec_append_t(NULL, &rtt_ctx->vcomp, ecs_rtt_call_data_t); + ecs_vec_append_t(NULL, &rtt_ctx->vcmp, ecs_rtt_call_data_t); comp_data->offset = m->offset; comp_data->type_info = member_ti; comp_data->count = 1; @@ -607,7 +607,7 @@ bool flecs_rtt_array_equals( const ecs_type_info_t *type_info) { if(a_ptr == b_ptr) { - return 0; + return true; } ecs_rtt_array_ctx_t *rtt_ctx = type_info->hooks.lifecycle_ctx; @@ -848,7 +848,7 @@ bool flecs_rtt_vector_equals( const ecs_type_info_t *type_info) { if(a_ptr == b_ptr) { - return 0; + return true; } const ecs_vec_t *vec_a = a_ptr; diff --git a/test/meta/src/RttCompare.c b/test/meta/src/RttCompare.c index b024da5ce..bb2b45075 100644 --- a/test/meta/src/RttCompare.c +++ b/test/meta/src/RttCompare.c @@ -1,4 +1,5 @@ #include +#include "flecs.h" static int cmp(const ecs_world_t *world, ecs_entity_t component, ecs_entity_t ea, @@ -11,6 +12,17 @@ int cmp(const ecs_world_t *world, ecs_entity_t component, ecs_entity_t ea, return ti->hooks.cmp(a, b, ti); } +static +bool equals(const ecs_world_t *world, ecs_entity_t component, ecs_entity_t ea, + ecs_entity_t eb) { + const ecs_type_info_t *ti = ecs_get_type_info(world, component); + + const void *a = ecs_get_id(world, ea, component); + const void *b = ecs_get_id(world, eb, component); + + return ti->hooks.equals(a, b, ti); +} + typedef struct OpaqueType { int16_t value; } OpaqueType; @@ -85,7 +97,9 @@ void RttCompare_struct_with_ints(void) { /* Test "equal" */ /* {10, 20} == {10, 20} */ test_assert(cmp(world, struct_with_ints, e1, e3) == 0); + test_assert(equals(world, struct_with_ints, e1, e3) == true); test_assert(cmp(world, struct_with_ints, e1, e1) == 0); + test_assert(equals(world, struct_with_ints, e1, e1) == true); ecs_delete(world, e1); ecs_delete(world, e2); @@ -142,7 +156,9 @@ void RttCompare_struct_with_strings(void) { /* Test "equal" */ /* {"AA", 20, "CC"} == {"AA", 20, "CC"} */ test_assert(cmp(world, struct_with_strings, e1, e3) == 0); + test_assert(equals(world, struct_with_strings, e1, e3) == true); test_assert(cmp(world, struct_with_strings, e1, e1) == 0); + test_assert(equals(world, struct_with_strings, e1, e1) == true); ecs_delete(world, e1); ecs_delete(world, e2); @@ -191,7 +207,9 @@ void RttCompare_struct_with_opaque(void) { /* Test "equal" */ /* {10} == {10} */ test_assert(cmp(world, struct_with_opaque, e1, e3) == 0); + test_assert(equals(world, struct_with_opaque, e1, e3) == true); test_assert(cmp(world, struct_with_opaque, e1, e1) == 0); + test_assert(equals(world, struct_with_opaque, e1, e1) == true); ecs_delete(world, e1); ecs_delete(world, e2); @@ -271,7 +289,9 @@ void RttCompare_nested_struct_with_strings(void) { /* Test "equal" */ test_assert(cmp(world, nested_struct_with_strings, e1, e3) == 0); + test_assert(equals(world, nested_struct_with_strings, e1, e3) == true); test_assert(cmp(world, nested_struct_with_strings, e1, e1) == 0); + test_assert(equals(world, nested_struct_with_strings, e1, e1) == true); ecs_delete(world, e1); ecs_delete(world, e2); @@ -363,7 +383,9 @@ void RttCompare_struct_with_array_of_strings(void) { /* Test "equal" */ /* {"AA", "BB", "CC", 10} == {"AA", "BB", "CC", 10} */ test_assert(cmp(world, struct_with_array_of_strings, e1, e3) == 0); + test_assert(equals(world, struct_with_array_of_strings, e1, e3) == true); test_assert(cmp(world, struct_with_array_of_strings, e1, e1) == 0); + test_assert(equals(world, struct_with_array_of_strings, e1, e1) == true); ecs_delete(world, e1); ecs_delete(world, e2); @@ -470,7 +492,9 @@ void RttCompare_struct_with_array_of_array_of_strings(void) { /* Test "equal" */ /* {"AA", "BB", "CC", "DD"} == {"AA", "BB", "CC", "DD"} */ test_assert(cmp(world, struct_with_array_of_array_of_strings, e1, e3) == 0); + test_assert(equals(world, struct_with_array_of_array_of_strings, e1, e3) == true); test_assert(cmp(world, struct_with_array_of_array_of_strings, e1, e1) == 0); + test_assert(equals(world, struct_with_array_of_array_of_strings, e1, e1) == true); ecs_delete(world, e1); ecs_delete(world, e2); @@ -547,7 +571,9 @@ void RttCompare_struct_with_vector_of_ints(void) { /* Test "equal" */ /* {10, 20, 30} == {10, 20, 30} */ test_assert(cmp(world, struct_with_vector_of_ints, e1, e3) == 0); + test_assert(equals(world, struct_with_vector_of_ints, e1, e3) == true); test_assert(cmp(world, struct_with_vector_of_ints, e1, e1) == 0); + test_assert(equals(world, struct_with_vector_of_ints, e1, e1) == true); ecs_delete(world, e1); ecs_delete(world, e2); @@ -623,7 +649,9 @@ void RttCompare_struct_with_vector_of_strings(void) { /* Test "equal" */ /* {"AA", "BB", "CC"} == {"AA", "BB", "CC"} */ test_assert(cmp(world, struct_with_vector_of_strings, e1, e3) == 0); + test_assert(equals(world, struct_with_vector_of_strings, e1, e3) == true); test_assert(cmp(world, struct_with_vector_of_strings, e1, e1) == 0); + test_assert(equals(world, struct_with_vector_of_strings, e1, e1) == true); ecs_delete(world, e1); ecs_delete(world, e2); @@ -793,7 +821,9 @@ void RttCompare_nested_struct_with_vector_of_ints(void) { /* Test "equal" */ /* {1, 2, 3, 10, {4, 5, 15, 6}} == {1, 2, 3, 10, {4, 5, 15, 6}} */ test_assert(cmp(world, nested_struct_with_vector_of_ints, e1, e3) == 0); + test_assert(equals(world, nested_struct_with_vector_of_ints, e1, e3) == true); test_assert(cmp(world, nested_struct_with_vector_of_ints, e1, e1) == 0); + test_assert(equals(world, nested_struct_with_vector_of_ints, e1, e1) == true); ecs_delete(world, e1); ecs_delete(world, e2); @@ -962,7 +992,9 @@ void RttCompare_nested_struct_with_vector_of_strings(void) { /* {{"AA", "BB", "CC"}, 10, {{"XX", "YY"}, 5, {"ZZ"}}} == */ /* {{"AA", "BB", "CC"}, 10, {{"XX", "YY"}, 5, {"ZZ"}}} */ test_assert(cmp(world, nested_struct_with_vector_of_strings, e1, e3) == 0); + test_assert(equals(world, nested_struct_with_vector_of_strings, e1, e3) == true); test_assert(cmp(world, nested_struct_with_vector_of_strings, e1, e1) == 0); + test_assert(equals(world, nested_struct_with_vector_of_strings, e1, e1) == true); ecs_delete(world, e1); ecs_delete(world, e2); @@ -1028,7 +1060,9 @@ void RttCompare_array_of_ints(void) { /* Test "equal" */ /* {1, 2, 3} == {1, 2, 3} */ test_assert(cmp(world, array_of_ints, e1, e3) == 0); + test_assert(equals(world, array_of_ints, e1, e3) == true); test_assert(cmp(world, array_of_ints, e1, e1) == 0); + test_assert(equals(world, array_of_ints, e1, e1) == true); ecs_delete(world, e1); ecs_delete(world, e2); @@ -1094,7 +1128,9 @@ void RttCompare_array_of_strings(void) { /* Test "equal" */ /* {"AA", "BB", "CC"} == {"AA", "BB", "CC"} */ test_assert(cmp(world, array_of_strings, e1, e3) == 0); + test_assert(equals(world, array_of_strings, e1, e3) == true); test_assert(cmp(world, array_of_strings, e1, e1) == 0); + test_assert(equals(world, array_of_strings, e1, e1) == true); ecs_delete(world, e1); ecs_delete(world, e2); @@ -1172,7 +1208,9 @@ void RttCompare_array_of_struct_with_ints(void) { /* Test "equal" */ /* {{1, 2}, {3, 4}, {5, 6}} == {{1, 2}, {3, 4}, {5, 6}} */ test_assert(cmp(world, array_of_struct_with_ints, e1, e3) == 0); + test_assert(equals(world, array_of_struct_with_ints, e1, e3) == true); test_assert(cmp(world, array_of_struct_with_ints, e1, e1) == 0); + test_assert(equals(world, array_of_struct_with_ints, e1, e1) == true); ecs_delete(world, e1); ecs_delete(world, e2); @@ -1295,7 +1333,9 @@ void RttCompare_array_of_struct_with_strings(void) { /* Test "equal" */ test_assert(cmp(world, struct_array_entity, e1, e3) == 0); + test_assert(equals(world, struct_array_entity, e1, e3) == true); test_assert(cmp(world, struct_array_entity, e1, e1) == 0); + test_assert(equals(world, struct_array_entity, e1, e1) == true); ecs_delete(world, e1); ecs_delete(world, e2); @@ -1355,7 +1395,9 @@ void RttCompare_array_of_struct_with_opaques(void) { /* Test "equal" */ /* {{5}, {10}, {15}} == {{5}, {10}, {15}} */ test_assert(cmp(world, array_of_struct_with_opaques, e1, e3) == 0); + test_assert(equals(world, array_of_struct_with_opaques, e1, e3) == true); test_assert(cmp(world, array_of_struct_with_opaques, e1, e1) == 0); + test_assert(equals(world, array_of_struct_with_opaques, e1, e1) == true); ecs_delete(world, e1); ecs_delete(world, e2); @@ -1437,7 +1479,9 @@ void RttCompare_array_of_array_of_strings(void) { /* Test "equal" */ test_assert(cmp(world, array_of_array_of_strings, e1, e3) == 0); + test_assert(equals(world, array_of_array_of_strings, e1, e3) == true); test_assert(cmp(world, array_of_array_of_strings, e1, e1) == 0); + test_assert(equals(world, array_of_array_of_strings, e1, e1) == true); ecs_delete(world, e1); @@ -1541,7 +1585,9 @@ void RttCompare_array_of_array_of_struct_with_strings(void) { /* Test "equal" */ /* {{"AA", 10, "CC"}, {"BB", 20, "DD"}} == {{"AA", 10, "CC"}, {"BB", 20, "DD"}} */ test_assert(cmp(world, array_of_array_of_struct_with_strings, e1, e3) == 0); + test_assert(equals(world, array_of_array_of_struct_with_strings, e1, e3) == true); test_assert(cmp(world, array_of_array_of_struct_with_strings, e1, e1) == 0); + test_assert(equals(world, array_of_array_of_struct_with_strings, e1, e1) == true); ecs_delete(world, e1); ecs_delete(world, e2); @@ -1643,7 +1689,9 @@ void RttCompare_array_of_vectors_of_ints(void) { /* Test "equal" */ test_assert(cmp(world, array_of_vectors_of_ints, e1, e2) == 0); + test_assert(equals(world, array_of_vectors_of_ints, e1, e2) == true); test_assert(cmp(world, array_of_vectors_of_ints, e1, e1) == 0); + test_assert(equals(world, array_of_vectors_of_ints, e1, e1) == true); /* Test when different in multiple fields */ test_assert(cmp(world, array_of_vectors_of_ints, e1, e4) < 0); @@ -1770,7 +1818,9 @@ void RttCompare_array_of_vectors_of_strings(void) { /* Test "equal" */ test_assert(cmp(world, array_of_vectors_of_strings, e1, e3) == 0); + test_assert(equals(world, array_of_vectors_of_strings, e1, e3) == true); test_assert(cmp(world, array_of_vectors_of_strings, e3, e1) == 0); + test_assert(equals(world, array_of_vectors_of_strings, e3, e1) == true); ecs_delete(world, e1); ecs_delete(world, e2); @@ -1840,7 +1890,9 @@ void RttCompare_array_of_opaque(void) { /* Test "equal" */ /* {5, 10, 15} == {5, 10, 15} */ test_assert(cmp(world, array_of_opaque, e1, e3) == 0); + test_assert(equals(world, array_of_opaque, e1, e3) == true); test_assert(cmp(world, array_of_opaque, e1, e1) == 0); + test_assert(equals(world, array_of_opaque, e1, e1) == true); ecs_delete(world, e1); ecs_delete(world, e2); @@ -1918,7 +1970,9 @@ void RttCompare_vector_of_ints(void) { /* Test "equal" */ /* {10, 20, 30} == {10, 20, 30} */ test_assert(cmp(world, vector_of_ints, e1, e3) == 0); + test_assert(equals(world, vector_of_ints, e1, e3) == true); test_assert(cmp(world, vector_of_ints, e1, e1) == 0); + test_assert(equals(world, vector_of_ints, e1, e1) == true); ecs_delete(world, e1); ecs_delete(world, e2); @@ -2000,7 +2054,9 @@ void RttCompare_vector_of_strings(void) { /* Test "equal" */ /* {"AA", "BB", "CC"} == {"AA", "BB", "CC"} */ test_assert(cmp(world, vector_of_strings, e1, e3) == 0); + test_assert(equals(world, vector_of_strings, e1, e3) == true); test_assert(cmp(world, vector_of_strings, e1, e1) == 0); + test_assert(equals(world, vector_of_strings, e1, e1) == true); ecs_delete(world, e1); ecs_delete(world, e2); @@ -2066,7 +2122,9 @@ void RttCompare_vector_of_struct_with_ints(void) { /* Test "equal" */ /* vec1 == vec3 as they have identical values */ test_assert(cmp(world, vector_of_struct_with_ints, e1, e3) == 0); + test_assert(equals(world, vector_of_struct_with_ints, e1, e3) == true); test_assert(cmp(world, vector_of_struct_with_ints, e1, e1) == 0); + test_assert(equals(world, vector_of_struct_with_ints, e1, e1) == true); ecs_delete(world, e1); ecs_delete(world, e2); @@ -2155,6 +2213,7 @@ void RttCompare_vector_of_struct_with_strings(void) { /* Test "equal" */ /* vec1 == vec3, all elements are identical */ test_assert(cmp(world, vector_of_struct_with_strings, e1, e3) == 0); + test_assert(equals(world, vector_of_struct_with_strings, e1, e3) == true); ecs_delete(world, e1); ecs_delete(world, e2); @@ -2235,7 +2294,9 @@ void RttCompare_vector_of_arrays_of_strings(void) { /* Test "equal" */ /* {"AA", "BB", "CC"} == {"AA", "BB", "CC"} */ test_assert(cmp(world, vector_of_arrays_of_strings, e1, e2) == 0); + test_assert(equals(world, vector_of_arrays_of_strings, e1, e2) == true); test_assert(cmp(world, vector_of_arrays_of_strings, e1, e1) == 0); + test_assert(equals(world, vector_of_arrays_of_strings, e1, e1) == true); ecs_delete(world, e1); ecs_delete(world, e2); @@ -2313,7 +2374,9 @@ void RttCompare_vector_of_opaque(void) { /* Test "equal" */ /* {10, 20, 30} == {10, 20, 30} */ test_assert(cmp(world, vector_of_opaque, e1, e3) == 0); + test_assert(equals(world, vector_of_opaque, e1, e3) == true); test_assert(cmp(world, vector_of_opaque, e1, e1) == 0); + test_assert(equals(world, vector_of_opaque, e1, e1) == true); ecs_delete(world, e1); ecs_delete(world, e2); From 094fba0a3499f0dd57d604bc2a1f58173083a541 Mon Sep 17 00:00:00 2001 From: Javier Peletier Date: Fri, 29 Nov 2024 12:53:56 +0100 Subject: [PATCH 18/23] renamed function in RuntimeTypes test --- test/meta/src/RuntimeTypes.c | 125 ++++++++++++++++++----------------- 1 file changed, 66 insertions(+), 59 deletions(-) diff --git a/test/meta/src/RuntimeTypes.c b/test/meta/src/RuntimeTypes.c index a33c4259a..01ef855f3 100644 --- a/test/meta/src/RuntimeTypes.c +++ b/test/meta/src/RuntimeTypes.c @@ -217,11 +217,18 @@ const ecs_type_info_t *define_test_struct( /* Compares two instances of the given type */ static -int compare(const ecs_world_t* world, ecs_entity_t id, const void *a, const void *b) { +int cmp(const ecs_world_t* world, ecs_entity_t id, const void *a, const void *b) { const ecs_type_info_t* ti = ecs_get_type_info(world, id); return ti->hooks.cmp(a, b, ti); } +/* Tests equality of two instances of the given type */ +static +bool equals(const ecs_world_t* world, ecs_entity_t id, const void *a, const void *b) { + const ecs_type_info_t* ti = ecs_get_type_info(world, id); + return ti->hooks.equals(a, b, ti); +} + /* Tests that a constructor is generated for a struct if at least a member has * itself a constructor Also tests if the generated constructor works. */ void RuntimeTypes_ctor(void) { @@ -1048,11 +1055,11 @@ void RuntimeTypes_array_move(void) { handles = (ResourceHandle *) ecs_get_mut_id(world, e, arr_of_resources); /* we should retrieve the same values: */ - test_assert(0 == compare( + test_assert(0 == cmp( world, resource_handle, &(ResourceHandle){.id = 100, .value = 111}, &handles[0])); - test_assert(0 == compare( + test_assert(0 == cmp( world, resource_handle, &(ResourceHandle){.id = 200, .value = 222}, &handles[1])); - test_assert(0 == compare( + test_assert(0 == cmp( world, resource_handle, &(ResourceHandle){.id = 300, .value = 333}, &handles[2])); test_int(10, resources_left()); /* pool stays the same */ @@ -1161,11 +1168,11 @@ void RuntimeTypes_array_copy(void) { ResourceHandle *handles = (ResourceHandle *) ecs_get_mut_id(world, e, arr_of_resources); - test_assert(0 == compare( + test_assert(0 == cmp( world, resource_handle, &prefab_handles[0], &handles[0])); - test_assert(0 == compare( + test_assert(0 == cmp( world, resource_handle, &prefab_handles[1], &handles[1])); - test_assert(0 == compare( + test_assert(0 == cmp( world, resource_handle, &prefab_handles[2], &handles[2])); ecs_delete(world, e); @@ -1501,7 +1508,7 @@ void RuntimeTypes_struct_with_ints(void) { test_int(100, ptr2->a); test_int(101, ptr2->b); - test_assert(compare(world, struct_with_ints, ptr1, ptr2) == 0); + test_assert(cmp(world, struct_with_ints, ptr1, ptr2) == 0); /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); @@ -1512,7 +1519,7 @@ void RuntimeTypes_struct_with_ints(void) { test_int(100, ptr3->a); test_int(101, ptr3->b); - test_assert(compare(world, struct_with_ints, ptr1, ptr3) == 0); + test_assert(cmp(world, struct_with_ints, ptr1, ptr3) == 0); /* Test deleting: */ ecs_delete(world, e); @@ -1555,7 +1562,7 @@ void RuntimeTypes_struct_with_strings(void) { test_int(101, ptr2->b); test_str("String102", ptr2->c); - test_assert(compare(world, struct_with_strings, ptr1, ptr2) == 0); + test_assert(cmp(world, struct_with_strings, ptr1, ptr2) == 0); /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); @@ -1566,7 +1573,7 @@ void RuntimeTypes_struct_with_strings(void) { test_int(101, ptr3->b); test_str("String102", ptr3->c); - test_assert(compare(world, struct_with_strings, ptr1, ptr3) == 0); + test_assert(cmp(world, struct_with_strings, ptr1, ptr3) == 0); /* Test deleting: */ ecs_delete(world, e); @@ -1610,7 +1617,7 @@ void RuntimeTypes_struct_with_opaque(void) { ecs_get_id(world, instance, struct_with_opaque); test_int(100, ptr2->a.value); - test_assert(compare(world, struct_with_opaque, ptr1, ptr2) == 0); + test_assert(cmp(world, struct_with_opaque, ptr1, ptr2) == 0); /* 2 resource(s) should be in use now */ test_int(2, initial_resources - resources_left()); @@ -1622,7 +1629,7 @@ void RuntimeTypes_struct_with_opaque(void) { ecs_get_id(world, instance, struct_with_opaque); test_int(100, ptr3->a.value); - test_assert(compare(world, struct_with_opaque, ptr1, ptr3) == 0); + test_assert(cmp(world, struct_with_opaque, ptr1, ptr3) == 0); /* 2 resource(s) should still be in use after a move */ test_int(2, initial_resources - resources_left()); @@ -1702,7 +1709,7 @@ void RuntimeTypes_nested_struct_with_strings(void) { test_int(105, ptr2->c.b); test_str("String106", ptr2->c.c); - test_assert(compare(world, nested_struct_with_strings, ptr1, ptr2) == 0); + test_assert(cmp(world, nested_struct_with_strings, ptr1, ptr2) == 0); /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); @@ -1717,7 +1724,7 @@ void RuntimeTypes_nested_struct_with_strings(void) { test_int(105, ptr3->c.b); test_str("String106", ptr3->c.c); - test_assert(compare(world, nested_struct_with_strings, ptr1, ptr3) == 0); + test_assert(cmp(world, nested_struct_with_strings, ptr1, ptr3) == 0); /* Test deleting: */ ecs_delete(world, e); @@ -1763,7 +1770,7 @@ void RuntimeTypes_struct_with_array_of_strings(void) { test_str("String102", ptr2->a[2]); test_int(103, ptr2->b); - test_assert(compare(world, struct_with_array_of_strings, ptr1, ptr2) == 0); + test_assert(cmp(world, struct_with_array_of_strings, ptr1, ptr2) == 0); /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); @@ -1775,7 +1782,7 @@ void RuntimeTypes_struct_with_array_of_strings(void) { test_str("String102", ptr3->a[2]); test_int(103, ptr3->b); - test_assert(compare(world, struct_with_array_of_strings, ptr1, ptr3) == 0); + test_assert(cmp(world, struct_with_array_of_strings, ptr1, ptr3) == 0); /* Test deleting: */ ecs_delete(world, e); @@ -1829,7 +1836,7 @@ void RuntimeTypes_struct_with_array_of_array_of_strings(void) { } test_str("String103", ptr2->b); - test_assert(compare(world, struct_with_array_of_array_of_strings, ptr1, ptr2) == 0); + test_assert(cmp(world, struct_with_array_of_array_of_strings, ptr1, ptr2) == 0); /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); @@ -1843,7 +1850,7 @@ void RuntimeTypes_struct_with_array_of_array_of_strings(void) { } test_str("String103", ptr3->b); - test_assert(compare(world, struct_with_array_of_array_of_strings, ptr1, ptr3) == 0); + test_assert(cmp(world, struct_with_array_of_array_of_strings, ptr1, ptr3) == 0); /* Test deleting: */ ecs_delete(world, e); @@ -1890,7 +1897,7 @@ void RuntimeTypes_struct_with_vector_of_ints(void) { test_int(101, va2[1]); test_int(102, va2[2]); - test_assert(compare(world, struct_with_vector_of_ints, ptr1, ptr2) == 0); + test_assert(cmp(world, struct_with_vector_of_ints, ptr1, ptr2) == 0); /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); @@ -1903,7 +1910,7 @@ void RuntimeTypes_struct_with_vector_of_ints(void) { test_int(101, va3[1]); test_int(102, va3[2]); - test_assert(compare(world, struct_with_vector_of_ints, ptr1, ptr3) == 0); + test_assert(cmp(world, struct_with_vector_of_ints, ptr1, ptr3) == 0); /* Test deleting: */ ecs_delete(world, e); @@ -1952,7 +1959,7 @@ void RuntimeTypes_struct_with_vector_of_strings(void) { test_str("String101", va2[1]); test_str("String102", va2[2]); - test_assert(compare(world, struct_with_vector_of_strings, ptr1, ptr2) == 0); + test_assert(cmp(world, struct_with_vector_of_strings, ptr1, ptr2) == 0); /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); @@ -1966,7 +1973,7 @@ void RuntimeTypes_struct_with_vector_of_strings(void) { test_str("String101", va3[1]); test_str("String102", va3[2]); - test_assert(compare(world, struct_with_vector_of_strings, ptr1, ptr3) == 0); + test_assert(cmp(world, struct_with_vector_of_strings, ptr1, ptr3) == 0); /* Test deleting: */ ecs_delete(world, e); @@ -2079,7 +2086,7 @@ void RuntimeTypes_nested_struct_with_vector_of_ints(void) { test_int(110, vcc[2]); } - test_assert(compare(world, nested_struct_with_vector_of_ints, ptr1, ptr2) == 0); + test_assert(cmp(world, nested_struct_with_vector_of_ints, ptr1, ptr2) == 0); /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); @@ -2113,7 +2120,7 @@ void RuntimeTypes_nested_struct_with_vector_of_ints(void) { test_int(110, vcc[2]); } - test_assert(compare(world, nested_struct_with_vector_of_ints, ptr1, ptr3) == 0); + test_assert(cmp(world, nested_struct_with_vector_of_ints, ptr1, ptr3) == 0); /* Test deleting: */ ecs_delete(world, e); @@ -2226,7 +2233,7 @@ void RuntimeTypes_nested_struct_with_vector_of_strings(void) { test_str("String110", vcc[2]); } - test_assert(compare(world, nested_struct_with_vector_of_strings, ptr1, ptr2) == 0); + test_assert(cmp(world, nested_struct_with_vector_of_strings, ptr1, ptr2) == 0); /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); @@ -2260,7 +2267,7 @@ void RuntimeTypes_nested_struct_with_vector_of_strings(void) { test_str("String110", vcc[2]); } - test_assert(compare(world, nested_struct_with_vector_of_strings, ptr1, ptr3) == 0); + test_assert(cmp(world, nested_struct_with_vector_of_strings, ptr1, ptr3) == 0); /* Test deleting: */ ecs_delete(world, e); @@ -2290,7 +2297,7 @@ void RuntimeTypes_array_of_ints(void) { test_int(101, arr2[1]); test_int(102, arr2[2]); - test_assert(compare(world, array_of_ints, arr1, arr2) == 0); + test_assert(cmp(world, array_of_ints, arr1, arr2) == 0); /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); @@ -2300,7 +2307,7 @@ void RuntimeTypes_array_of_ints(void) { test_int(101, arr3[1]); test_int(102, arr3[2]); - test_assert(compare(world, array_of_ints, arr1, arr3) == 0); + test_assert(cmp(world, array_of_ints, arr1, arr3) == 0); /* Test deleting: */ ecs_delete(world, e); @@ -2330,7 +2337,7 @@ void RuntimeTypes_array_of_strings(void) { test_str("String101", arr2[1]); test_str("String102", arr2[2]); - test_assert(compare(world, array_of_strings, arr1, arr2) == 0); + test_assert(cmp(world, array_of_strings, arr1, arr2) == 0); /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); @@ -2340,7 +2347,7 @@ void RuntimeTypes_array_of_strings(void) { test_str("String101", arr3[1]); test_str("String102", arr3[2]); - test_assert(compare(world, array_of_strings, arr1, arr3) == 0); + test_assert(cmp(world, array_of_strings, arr1, arr3) == 0); /* Test deleting: */ ecs_delete(world, e); @@ -2390,7 +2397,7 @@ void RuntimeTypes_array_of_struct_with_ints(void) { test_int(104, arr2[2].a); test_int(105, arr2[2].b); - test_assert(compare(world, array_of_struct_with_ints, arr1, arr2) == 0); + test_assert(cmp(world, array_of_struct_with_ints, arr1, arr2) == 0); /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); @@ -2404,7 +2411,7 @@ void RuntimeTypes_array_of_struct_with_ints(void) { test_int(104, arr3[2].a); test_int(105, arr3[2].b); - test_assert(compare(world, array_of_struct_with_ints, arr1, arr3) == 0); + test_assert(cmp(world, array_of_struct_with_ints, arr1, arr3) == 0); /* Test deleting: */ ecs_delete(world, e); @@ -2462,7 +2469,7 @@ void RuntimeTypes_array_of_struct_with_strings(void) { test_int(107, arr2[2].b); test_str("String108", arr2[2].c); - test_assert(compare(world, array_of_struct_with_strings, arr1, arr2) == 0); + test_assert(cmp(world, array_of_struct_with_strings, arr1, arr2) == 0); /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); @@ -2479,7 +2486,7 @@ void RuntimeTypes_array_of_struct_with_strings(void) { test_int(107, arr3[2].b); test_str("String108", arr3[2].c); - test_assert(compare(world, array_of_struct_with_strings, arr1, arr3) == 0); + test_assert(cmp(world, array_of_struct_with_strings, arr1, arr3) == 0); /* Test deleting: */ ecs_delete(world, e); @@ -2535,7 +2542,7 @@ void RuntimeTypes_array_of_struct_with_opaques(void) { test_int(101, arr2[1].a.value); test_int(102, arr2[2].a.value); - test_assert(compare(world, array_of_struct_with_opaques, arr1, arr2) == 0); + test_assert(cmp(world, array_of_struct_with_opaques, arr1, arr2) == 0); /* 6 resource(s) should be in use now */ test_int(6, initial_resources - resources_left()); @@ -2549,7 +2556,7 @@ void RuntimeTypes_array_of_struct_with_opaques(void) { test_int(101, arr3[1].a.value); test_int(102, arr3[2].a.value); - test_assert(compare(world, array_of_struct_with_opaques, arr1, arr3) == 0); + test_assert(cmp(world, array_of_struct_with_opaques, arr1, arr3) == 0); /* 6 resource(s) should still be in use after a move */ test_int(6, initial_resources - resources_left()); @@ -2605,7 +2612,7 @@ void RuntimeTypes_array_of_array_of_strings(void) { test_str("String102", arr2[i][2]); } - test_assert(compare(world, array_of_array_of_strings, arr1, arr2) == 0); + test_assert(cmp(world, array_of_array_of_strings, arr1, arr2) == 0); /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); @@ -2618,7 +2625,7 @@ void RuntimeTypes_array_of_array_of_strings(void) { test_str("String102", arr3[i][2]); } - test_assert(compare(world, array_of_array_of_strings, arr1, arr3) == 0); + test_assert(cmp(world, array_of_array_of_strings, arr1, arr3) == 0); /* Test deleting: */ ecs_delete(world, e); @@ -2686,7 +2693,7 @@ void RuntimeTypes_array_of_array_of_struct_with_strings(void) { test_str("String108", arr2[i][2].c); } - test_assert(compare(world, array_of_array_of_struct_with_strings, arr1, arr2) == 0); + test_assert(cmp(world, array_of_array_of_struct_with_strings, arr1, arr2) == 0); /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); @@ -2706,7 +2713,7 @@ void RuntimeTypes_array_of_array_of_struct_with_strings(void) { test_str("String108", arr3[i][2].c); } - test_assert(compare(world, array_of_array_of_struct_with_strings, arr1, arr3) == 0); + test_assert(cmp(world, array_of_array_of_struct_with_strings, arr1, arr3) == 0); /* Test deleting: */ ecs_delete(world, e); @@ -2786,7 +2793,7 @@ void RuntimeTypes_array_of_vectors_of_ints(void) { test_int(108, v[2]); } - test_assert(compare(world, array_of_vectors_of_ints, arr1, arr2) == 0); + test_assert(cmp(world, array_of_vectors_of_ints, arr1, arr2) == 0); /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); @@ -2817,7 +2824,7 @@ void RuntimeTypes_array_of_vectors_of_ints(void) { test_int(108, v[2]); } - test_assert(compare(world, array_of_vectors_of_ints, arr1, arr3) == 0); + test_assert(cmp(world, array_of_vectors_of_ints, arr1, arr3) == 0); /* Test deleting: */ ecs_delete(world, e); @@ -2898,7 +2905,7 @@ void RuntimeTypes_array_of_vectors_of_strings(void) { test_str("String108", v[2]); } - test_assert(compare(world, array_of_vectors_of_strings, arr1, arr2) == 0); + test_assert(cmp(world, array_of_vectors_of_strings, arr1, arr2) == 0); /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); @@ -2930,7 +2937,7 @@ void RuntimeTypes_array_of_vectors_of_strings(void) { test_str("String108", v[2]); } - test_assert(compare(world, array_of_vectors_of_strings, arr1, arr3) == 0); + test_assert(cmp(world, array_of_vectors_of_strings, arr1, arr3) == 0); /* Test deleting: */ ecs_delete(world, e); @@ -2974,7 +2981,7 @@ void RuntimeTypes_array_of_opaque(void) { test_int(101, arr2[1].value); test_int(102, arr2[2].value); - test_assert(compare(world, array_of_opaque, arr1, arr2) == 0); + test_assert(cmp(world, array_of_opaque, arr1, arr2) == 0); /* 6 resource(s) should be in use now */ test_int(6, initial_resources - resources_left()); @@ -2987,7 +2994,7 @@ void RuntimeTypes_array_of_opaque(void) { test_int(101, arr3[1].value); test_int(102, arr3[2].value); - test_assert(compare(world, array_of_opaque, arr1, arr3) == 0); + test_assert(cmp(world, array_of_opaque, arr1, arr3) == 0); /* 6 resource(s) should still be in use after a move */ test_int(6, initial_resources - resources_left()); @@ -3044,7 +3051,7 @@ void RuntimeTypes_vector_of_ints(void) { test_int(102, v[2]); } - test_assert(compare(world, vector_of_ints, vec1, vec2) == 0); + test_assert(cmp(world, vector_of_ints, vec1, vec2) == 0); /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); @@ -3059,7 +3066,7 @@ void RuntimeTypes_vector_of_ints(void) { test_int(102, v[2]); } - test_assert(compare(world, vector_of_ints, vec1, vec3) == 0); + test_assert(cmp(world, vector_of_ints, vec1, vec3) == 0); /* Test deleting: */ ecs_delete(world, e); @@ -3100,7 +3107,7 @@ void RuntimeTypes_vector_of_strings(void) { test_str("String102", v[2]); } - test_assert(compare(world, vector_of_strings, vec1, vec2) == 0); + test_assert(cmp(world, vector_of_strings, vec1, vec2) == 0); /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); @@ -3115,7 +3122,7 @@ void RuntimeTypes_vector_of_strings(void) { test_str("String102", v[2]); } - test_assert(compare(world, vector_of_strings, vec1, vec3) == 0); + test_assert(cmp(world, vector_of_strings, vec1, vec3) == 0); /* Test deleting: */ ecs_delete(world, e); @@ -3173,7 +3180,7 @@ void RuntimeTypes_vector_of_struct_with_ints(void) { test_int(104, v[2].a); test_int(105, v[2].b); } - test_assert(compare(world, vector_of_struct_with_ints, vec1, vec2) == 0); + test_assert(cmp(world, vector_of_struct_with_ints, vec1, vec2) == 0); /* Test moving by forcing an archetype change: */ @@ -3191,7 +3198,7 @@ void RuntimeTypes_vector_of_struct_with_ints(void) { test_int(104, v[2].a); test_int(105, v[2].b); } - test_assert(compare(world, vector_of_struct_with_ints, vec1, vec3) == 0); + test_assert(cmp(world, vector_of_struct_with_ints, vec1, vec3) == 0); /* Test deleting: */ ecs_delete(world, e); @@ -3257,7 +3264,7 @@ void RuntimeTypes_vector_of_struct_with_strings(void) { test_int(107, v[2].b); test_str("String108", v[2].c); } - test_assert(compare(world, vector_of_struct_with_strings, vec1, vec2) == 0); + test_assert(cmp(world, vector_of_struct_with_strings, vec1, vec2) == 0); /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); @@ -3277,7 +3284,7 @@ void RuntimeTypes_vector_of_struct_with_strings(void) { test_int(107, v[2].b); test_str("String108", v[2].c); } - test_assert(compare(world, vector_of_struct_with_strings, vec1, vec3) == 0); + test_assert(cmp(world, vector_of_struct_with_strings, vec1, vec3) == 0); /* Test deleting: */ ecs_delete(world, e); @@ -3327,7 +3334,7 @@ void RuntimeTypes_vector_of_arrays_of_strings(void) { test_str("String102", v[i][2]); } } - test_assert(compare(world, vector_of_arrays_of_strings, vec1, vec2) == 0); + test_assert(cmp(world, vector_of_arrays_of_strings, vec1, vec2) == 0); /* Test moving by forcing an archetype change: */ ECS_TAG(world, MakeMeMove); @@ -3345,7 +3352,7 @@ void RuntimeTypes_vector_of_arrays_of_strings(void) { test_str("String102", v[i][2]); } } - test_assert(compare(world, vector_of_arrays_of_strings, vec1, vec3) == 0); + test_assert(cmp(world, vector_of_arrays_of_strings, vec1, vec3) == 0); /* Test deleting: */ ecs_delete(world, e); @@ -3398,7 +3405,7 @@ void RuntimeTypes_vector_of_opaque(void) { test_int(101, v[1].value); test_int(102, v[2].value); } - test_assert(compare(world, vector_of_opaque, vec1, vec2) == 0); + test_assert(cmp(world, vector_of_opaque, vec1, vec2) == 0); /* 6 resource(s) should be in use now */ test_int(6, initial_resources - resources_left()); @@ -3415,7 +3422,7 @@ void RuntimeTypes_vector_of_opaque(void) { test_int(101, v[1].value); test_int(102, v[2].value); } - test_assert(compare(world, vector_of_opaque, vec1, vec3) == 0); + test_assert(cmp(world, vector_of_opaque, vec1, vec3) == 0); /* 6 resource(s) should still be in use after a move */ test_int(6, initial_resources - resources_left()); From 68cac3755921cee8eb3b9887c27156dbb3b1b051 Mon Sep 17 00:00:00 2001 From: Javier Peletier Date: Fri, 29 Nov 2024 14:22:01 +0100 Subject: [PATCH 19/23] Add equals hook illegal test. Allow in cpp to generate equals hook from compare hook --- distr/flecs.c | 3 +- distr/flecs.h | 7 +++- include/flecs/addons/cpp/lifecycle_traits.hpp | 7 +++- src/world.c | 3 +- test/meta/project.json | 1 + test/meta/src/RuntimeTypes.c | 34 ++++++++++++++----- test/meta/src/main.c | 7 +++- 7 files changed, 47 insertions(+), 15 deletions(-) diff --git a/distr/flecs.c b/distr/flecs.c index 477725829..3cf115f3a 100644 --- a/distr/flecs.c +++ b/distr/flecs.c @@ -19239,10 +19239,9 @@ void ecs_set_hooks_id( } if (!h->equals) { - if(flags & ECS_TYPE_HOOK_CMP_ILLEGAL) { + if(flags & (ECS_TYPE_HOOK_CMP_ILLEGAL|ECS_TYPE_HOOK_EQUALS_ILLEGAL)) { flags |= ECS_TYPE_HOOK_EQUALS_ILLEGAL; } else if(h->cmp) { - flags &= (ecs_flags32_t)(~ECS_TYPE_HOOK_EQUALS_ILLEGAL); ti->hooks.equals = flecs_default_equals; } } diff --git a/distr/flecs.h b/distr/flecs.h index bf80ce844..5910795ac 100644 --- a/distr/flecs.h +++ b/distr/flecs.h @@ -20668,7 +20668,12 @@ ecs_equals_t equals(ecs_flags32_t &) { template ::value > = 0> ecs_equals_t equals(ecs_flags32_t &flags) { - flags |= ECS_TYPE_HOOK_EQUALS_ILLEGAL; + if(flags & ECS_TYPE_HOOK_CMP_ILLEGAL) { + /* Only mark equals hook as illegal if compare is also illegal + * this way we let Flecs generate an equals hook + * from the compare hook automatically */ + flags |= ECS_TYPE_HOOK_EQUALS_ILLEGAL; + } return NULL; } diff --git a/include/flecs/addons/cpp/lifecycle_traits.hpp b/include/flecs/addons/cpp/lifecycle_traits.hpp index 80b611089..68def8bbf 100644 --- a/include/flecs/addons/cpp/lifecycle_traits.hpp +++ b/include/flecs/addons/cpp/lifecycle_traits.hpp @@ -490,7 +490,12 @@ ecs_equals_t equals(ecs_flags32_t &) { template ::value > = 0> ecs_equals_t equals(ecs_flags32_t &flags) { - flags |= ECS_TYPE_HOOK_EQUALS_ILLEGAL; + if(flags & ECS_TYPE_HOOK_CMP_ILLEGAL) { + /* Only mark equals hook as illegal if compare is also illegal + * this way we let Flecs generate an equals hook + * from the compare hook automatically */ + flags |= ECS_TYPE_HOOK_EQUALS_ILLEGAL; + } return NULL; } diff --git a/src/world.c b/src/world.c index 9ebbb48ba..8ee9369a3 100644 --- a/src/world.c +++ b/src/world.c @@ -1480,10 +1480,9 @@ void ecs_set_hooks_id( } if (!h->equals) { - if(flags & ECS_TYPE_HOOK_CMP_ILLEGAL) { + if(flags & (ECS_TYPE_HOOK_CMP_ILLEGAL|ECS_TYPE_HOOK_EQUALS_ILLEGAL)) { flags |= ECS_TYPE_HOOK_EQUALS_ILLEGAL; } else if(h->cmp) { - flags &= (ecs_flags32_t)(~ECS_TYPE_HOOK_EQUALS_ILLEGAL); ti->hooks.equals = flecs_default_equals; } } diff --git a/test/meta/project.json b/test/meta/project.json index 3ae4865a7..269d0db86 100644 --- a/test/meta/project.json +++ b/test/meta/project.json @@ -108,6 +108,7 @@ "copy", "copy_illegal", "cmp_illegal", + "equals_illegal", "trivial_array", "array_ctor", "array_ctor_illegal", diff --git a/test/meta/src/RuntimeTypes.c b/test/meta/src/RuntimeTypes.c index 01ef855f3..c1fe13ffa 100644 --- a/test/meta/src/RuntimeTypes.c +++ b/test/meta/src/RuntimeTypes.c @@ -222,13 +222,6 @@ int cmp(const ecs_world_t* world, ecs_entity_t id, const void *a, const void *b) return ti->hooks.cmp(a, b, ti); } -/* Tests equality of two instances of the given type */ -static -bool equals(const ecs_world_t* world, ecs_entity_t id, const void *a, const void *b) { - const ecs_type_info_t* ti = ecs_get_type_info(world, id); - return ti->hooks.equals(a, b, ti); -} - /* Tests that a constructor is generated for a struct if at least a member has * itself a constructor Also tests if the generated constructor works. */ void RuntimeTypes_ctor(void) { @@ -580,7 +573,7 @@ void RuntimeTypes_cmp_illegal(void) { const ecs_type_info_t *nested_struct_ti = define_nested_struct(world); ecs_type_hooks_t hooks = nested_struct_ti->hooks; - hooks.flags |= ECS_TYPE_HOOK_CMP_ILLEGAL; /* mark copy hook for "NestedStruct" as illegal */ + hooks.flags |= ECS_TYPE_HOOK_CMP_ILLEGAL; /* mark cmp hook for "NestedStruct" as illegal */ hooks.cmp = NULL; hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; @@ -596,6 +589,31 @@ void RuntimeTypes_cmp_illegal(void) { ecs_fini(world); } +/* Tests that an illegal equals hook is set for a struct if at least a member has + * itself an illegal equals hook */ +void RuntimeTypes_equals_illegal(void) { + ecs_world_t *world = ecs_init(); + + /* Define NestedStruct: */ + const ecs_type_info_t *nested_struct_ti = define_nested_struct(world); + + ecs_type_hooks_t hooks = nested_struct_ti->hooks; + hooks.flags |= ECS_TYPE_HOOK_EQUALS_ILLEGAL; /* mark equals hook for "NestedStruct" as illegal */ + hooks.equals = NULL; + + hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; + ecs_set_hooks_id(world, nested_struct, &hooks); + + /* Define TestStruct, which has two "NestedStruct" members. + * TestStruct's equals hook should be set to illegal as well. */ + const ecs_type_info_t *test_struct_ti = define_test_struct(world); + + /* TestStruct should have an illegal equals hook too: */ + test_assert(test_struct_ti->hooks.flags & ECS_TYPE_HOOK_EQUALS_ILLEGAL); + + ecs_fini(world); +} + /* For the following tests, we model a "ResourceHandle" that must allocate an id * from a pool of resource ids. When constructing a handle, it must get a unique * id. When destroying a handle, it must return the id. When copying a handle, diff --git a/test/meta/src/main.c b/test/meta/src/main.c index 123f91fa4..3640c1143 100644 --- a/test/meta/src/main.c +++ b/test/meta/src/main.c @@ -97,6 +97,7 @@ void RuntimeTypes_move_illegal(void); void RuntimeTypes_copy(void); void RuntimeTypes_copy_illegal(void); void RuntimeTypes_cmp_illegal(void); +void RuntimeTypes_equals_illegal(void); void RuntimeTypes_trivial_array(void); void RuntimeTypes_array_ctor(void); void RuntimeTypes_array_ctor_illegal(void); @@ -1400,6 +1401,10 @@ bake_test_case RuntimeTypes_testcases[] = { "cmp_illegal", RuntimeTypes_cmp_illegal }, + { + "equals_illegal", + RuntimeTypes_equals_illegal + }, { "trivial_array", RuntimeTypes_trivial_array @@ -5190,7 +5195,7 @@ static bake_test_suite suites[] = { "RuntimeTypes", NULL, NULL, - 50, + 51, RuntimeTypes_testcases }, { From 8bde6d4e0a8efe94ecf21e5b123f60909ad01af8 Mon Sep 17 00:00:00 2001 From: Javier Peletier Date: Wed, 4 Dec 2024 01:20:20 +0100 Subject: [PATCH 20/23] added op_equals, op_compare. Tests. --- distr/flecs.c | 42 ++-- distr/flecs.h | 194 +++++++++++------- include/flecs.h | 61 +++--- include/flecs/addons/cpp/component.hpp | 75 ++++--- include/flecs/addons/cpp/lifecycle_traits.hpp | 15 +- .../cpp/mixins/meta/untyped_component.inl | 43 ++++ src/addons/meta/meta.c | 14 +- src/addons/meta/rtt_lifecycle.c | 17 +- src/world.c | 11 +- test/core/project.json | 4 +- test/core/src/ComponentLifecycle.c | 81 +++++++- test/core/src/main.c | 12 +- test/cpp/src/ComponentLifecycle.cpp | 114 +++++++++- test/meta/src/RttCompare.c | 3 +- test/meta/src/RuntimeTypes.c | 7 +- 15 files changed, 498 insertions(+), 195 deletions(-) diff --git a/distr/flecs.c b/distr/flecs.c index 3cf115f3a..7e682e525 100644 --- a/distr/flecs.c +++ b/distr/flecs.c @@ -19238,11 +19238,16 @@ void ecs_set_hooks_id( } } - if (!h->equals) { - if(flags & (ECS_TYPE_HOOK_CMP_ILLEGAL|ECS_TYPE_HOOK_EQUALS_ILLEGAL)) { + if(!h->cmp) { + flags |= ECS_TYPE_HOOK_CMP_ILLEGAL; + } + + if (!h->equals || h->equals == flecs_equals_illegal) { + if(flags & ECS_TYPE_HOOK_CMP_ILLEGAL) { flags |= ECS_TYPE_HOOK_EQUALS_ILLEGAL; - } else if(h->cmp) { + } else { ti->hooks.equals = flecs_default_equals; + flags &= ~ECS_TYPE_HOOK_EQUALS_ILLEGAL; } } @@ -51793,12 +51798,14 @@ void FlecsMetaImport( #undef ECS_PRIMITIVE - ecs_set_hooks(world, ecs_string_t, { - .ctor = flecs_default_ctor, - .copy = ecs_copy(ecs_string_t), - .move = ecs_move(ecs_string_t), - .dtor = ecs_dtor(ecs_string_t), - }); + ecs_type_hooks_t string_hooks = *ecs_get_hooks(world, ecs_string_t); + string_hooks.ctor = flecs_default_ctor; + string_hooks.copy = ecs_copy(ecs_string_t); + string_hooks.move = ecs_move(ecs_string_t); + string_hooks.dtor = ecs_dtor(ecs_string_t); + string_hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; + ecs_set_hooks_id(world, ecs_id(ecs_string_t), &string_hooks); + /* Set default child components */ ecs_set(world, ecs_id(EcsStruct), EcsDefaultChildComponent, {ecs_id(EcsMember)}); @@ -52194,13 +52201,9 @@ void flecs_rtt_init_default_hooks_struct( dtor_hook_required |= member_ti->hooks.dtor != NULL; move_hook_required |= member_ti->hooks.move != NULL; copy_hook_required |= member_ti->hooks.copy != NULL; - - /* A struct has a valid cmp hook if all its members have it */ - valid_cmp &= member_ti->hooks.cmp != NULL; - - /* A struct has a valid equals hook if all its members have it */ + /* A struct has a valid cmp/equals hook if all its members have it: */ + valid_cmp &= member_ti->hooks.cmp != NULL; valid_equals &= member_ti->hooks.equals != NULL; - flags |= member_ti->hooks.flags; } @@ -52214,7 +52217,7 @@ void flecs_rtt_init_default_hooks_struct( dtor_hook_required ? flecs_rtt_struct_dtor : NULL, move_hook_required ? flecs_rtt_struct_move : NULL, copy_hook_required ? flecs_rtt_struct_copy : NULL, - valid_cmp ? flecs_rtt_struct_cmp : NULL, + valid_cmp ? flecs_rtt_struct_cmp : NULL, valid_equals ? flecs_rtt_struct_equals : NULL ); @@ -52454,15 +52457,15 @@ void flecs_rtt_init_default_hooks_array( ecs_assert(array_info != NULL, ECS_INTERNAL_ERROR, NULL); const ecs_type_info_t *element_ti = ecs_get_type_info(world, array_info->type); + ecs_flags32_t flags = element_ti->hooks.flags; bool ctor_hook_required = element_ti->hooks.ctor && element_ti->hooks.ctor != flecs_default_ctor; bool dtor_hook_required = element_ti->hooks.dtor != NULL; bool move_hook_required = element_ti->hooks.move != NULL; bool copy_hook_required = element_ti->hooks.copy != NULL; - bool valid_cmp = element_ti->hooks.cmp != NULL; - bool valid_equals = element_ti->hooks.equals != NULL; + bool valid_cmp = element_ti->hooks.cmp != NULL && !(flags & ECS_TYPE_HOOK_CMP_ILLEGAL); + bool valid_equals = element_ti->hooks.equals != NULL && !(flags & ECS_TYPE_HOOK_CMP_ILLEGAL); - ecs_flags32_t flags = element_ti->hooks.flags; ecs_type_hooks_t hooks = *ecs_get_hooks_id(world, component); @@ -52803,6 +52806,7 @@ void flecs_rtt_init_default_hooks( hooks.ctor = flecs_default_ctor; } + hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id( world, component, diff --git a/distr/flecs.h b/distr/flecs.h index 5910795ac..abfa6317b 100644 --- a/distr/flecs.h +++ b/distr/flecs.h @@ -3543,44 +3543,43 @@ struct ecs_observer_t { */ /* Flags that can be used to check which hooks a type has set */ -#define ECS_TYPE_HOOK_CTOR (1 << 0) -#define ECS_TYPE_HOOK_DTOR (1 << 1) -#define ECS_TYPE_HOOK_COPY (1 << 2) -#define ECS_TYPE_HOOK_MOVE (1 << 3) -#define ECS_TYPE_HOOK_COPY_CTOR (1 << 4) -#define ECS_TYPE_HOOK_MOVE_CTOR (1 << 5) -#define ECS_TYPE_HOOK_CTOR_MOVE_DTOR (1 << 6) -#define ECS_TYPE_HOOK_MOVE_DTOR (1 << 7) -#define ECS_TYPE_HOOK_CMP (1 << 8) -#define ECS_TYPE_HOOK_EQUALS (1 << 9) +static const ecs_flags32_t ECS_TYPE_HOOK_CTOR = (1 << 0); +static const ecs_flags32_t ECS_TYPE_HOOK_DTOR = (1 << 1); +static const ecs_flags32_t ECS_TYPE_HOOK_COPY = (1 << 2); +static const ecs_flags32_t ECS_TYPE_HOOK_MOVE = (1 << 3); +static const ecs_flags32_t ECS_TYPE_HOOK_COPY_CTOR = (1 << 4); +static const ecs_flags32_t ECS_TYPE_HOOK_MOVE_CTOR = (1 << 5); +static const ecs_flags32_t ECS_TYPE_HOOK_CTOR_MOVE_DTOR = (1 << 6); +static const ecs_flags32_t ECS_TYPE_HOOK_MOVE_DTOR = (1 << 7); +static const ecs_flags32_t ECS_TYPE_HOOK_CMP = (1 << 8); +static const ecs_flags32_t ECS_TYPE_HOOK_EQUALS = (1 << 9); /* Flags that can be used to set/check which hooks of a type are invalid */ -#define ECS_TYPE_HOOK_CTOR_ILLEGAL (1 << 10) -#define ECS_TYPE_HOOK_DTOR_ILLEGAL (1 << 12) -#define ECS_TYPE_HOOK_COPY_ILLEGAL (1 << 13) -#define ECS_TYPE_HOOK_MOVE_ILLEGAL (1 << 14) -#define ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL (1 << 15) -#define ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL (1 << 16) -#define ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL (1 << 17) -#define ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL (1 << 18) -#define ECS_TYPE_HOOK_CMP_ILLEGAL (1 << 19) -#define ECS_TYPE_HOOK_EQUALS_ILLEGAL (1 << 20) +static const ecs_flags32_t ECS_TYPE_HOOK_CTOR_ILLEGAL = (1 << 10); +static const ecs_flags32_t ECS_TYPE_HOOK_DTOR_ILLEGAL = (1 << 12); +static const ecs_flags32_t ECS_TYPE_HOOK_COPY_ILLEGAL = (1 << 13); +static const ecs_flags32_t ECS_TYPE_HOOK_MOVE_ILLEGAL = (1 << 14); +static const ecs_flags32_t ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL = (1 << 15); +static const ecs_flags32_t ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL = (1 << 16); +static const ecs_flags32_t ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL= (1 << 17); +static const ecs_flags32_t ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL = (1 << 18); +static const ecs_flags32_t ECS_TYPE_HOOK_CMP_ILLEGAL = (1 << 19); +static const ecs_flags32_t ECS_TYPE_HOOK_EQUALS_ILLEGAL = (1 << 20); /* All valid hook flags */ -#define ECS_TYPE_HOOKS (ECS_TYPE_HOOK_CTOR|ECS_TYPE_HOOK_DTOR|\ - ECS_TYPE_HOOK_COPY|ECS_TYPE_HOOK_MOVE|ECS_TYPE_HOOK_COPY_CTOR|\ - ECS_TYPE_HOOK_MOVE_CTOR|ECS_TYPE_HOOK_CTOR_MOVE_DTOR|\ - ECS_TYPE_HOOK_MOVE_DTOR|ECS_TYPE_HOOK_CMP|ECS_TYPE_HOOK_EQUALS) - +static const ecs_flags32_t ECS_TYPE_HOOKS = (ECS_TYPE_HOOK_CTOR|ECS_TYPE_HOOK_DTOR| + ECS_TYPE_HOOK_COPY|ECS_TYPE_HOOK_MOVE|ECS_TYPE_HOOK_COPY_CTOR| + ECS_TYPE_HOOK_MOVE_CTOR|ECS_TYPE_HOOK_CTOR_MOVE_DTOR| + ECS_TYPE_HOOK_MOVE_DTOR|ECS_TYPE_HOOK_CMP|ECS_TYPE_HOOK_EQUALS); /* All invalid hook flags */ -#define ECS_TYPE_HOOKS_ILLEGAL (ECS_TYPE_HOOK_CTOR_ILLEGAL|\ - ECS_TYPE_HOOK_DTOR_ILLEGAL|ECS_TYPE_HOOK_COPY_ILLEGAL|\ - ECS_TYPE_HOOK_MOVE_ILLEGAL|ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL|\ - ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL|ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL|\ - ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL|ECS_TYPE_HOOK_CMP_ILLEGAL|\ - ECS_TYPE_HOOK_EQUALS_ILLEGAL) +static const ecs_flags32_t ECS_TYPE_HOOKS_ILLEGAL = (ECS_TYPE_HOOK_CTOR_ILLEGAL| + ECS_TYPE_HOOK_DTOR_ILLEGAL|ECS_TYPE_HOOK_COPY_ILLEGAL| + ECS_TYPE_HOOK_MOVE_ILLEGAL|ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL| + ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL|ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL| + ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL|ECS_TYPE_HOOK_CMP_ILLEGAL | + ECS_TYPE_HOOK_EQUALS_ILLEGAL); struct ecs_type_hooks_t { ecs_xtor_t ctor; /**< ctor */ @@ -20638,15 +20637,14 @@ int compare_impl(const void *a, const void *b, const ecs_type_info_t *) { template ::value || has_operator_greater::value > = 0> -ecs_cmp_t compare(ecs_flags32_t &) { +ecs_cmp_t compare() { return compare_impl; } template ::value && !has_operator_greater::value > = 0> -ecs_cmp_t compare(ecs_flags32_t &flags) { - flags |= ECS_TYPE_HOOK_CMP_ILLEGAL; +ecs_cmp_t compare() { return NULL; } @@ -20661,19 +20659,13 @@ bool equals_impl(const void *a, const void *b, const ecs_type_info_t *) { template ::value > = 0> -ecs_equals_t equals(ecs_flags32_t &) { +ecs_equals_t equals() { return equals_impl; } template ::value > = 0> -ecs_equals_t equals(ecs_flags32_t &flags) { - if(flags & ECS_TYPE_HOOK_CMP_ILLEGAL) { - /* Only mark equals hook as illegal if compare is also illegal - * this way we let Flecs generate an equals hook - * from the compare hook automatically */ - flags |= ECS_TYPE_HOOK_EQUALS_ILLEGAL; - } +ecs_equals_t equals() { return NULL; } @@ -27014,22 +27006,7 @@ template* = nullptr> void register_lifecycle_actions( ecs_world_t *world, - ecs_entity_t component) { - - const ecs_world_t* w = ecs_get_world(world); - - if(ecs_id_in_use(w, component) || - ecs_id_in_use(w, ecs_pair(component, EcsWildcard))) { - return; - } - - ecs_type_hooks_t cl{}; - cl.cmp = compare(cl.flags); - cl.equals = equals(cl.flags); - - cl.flags &= ECS_TYPE_HOOKS_ILLEGAL; - ecs_set_hooks_id(world, component, &cl); -} + ecs_entity_t component) {} // If the component is non-trivial, register component lifecycle actions. // Depending on the type not all callbacks may be available. @@ -27052,9 +27029,6 @@ void register_lifecycle_actions( cl.ctor_move_dtor = ctor_move_dtor(cl.flags); cl.move_dtor = move_dtor(cl.flags); - cl.cmp = compare(cl.flags); - cl.equals = equals(cl.flags); - cl.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id(world, component, &cl); @@ -27338,6 +27312,22 @@ untyped_component& internal_member( return *this; } +protected: + +flecs::type_hooks_t get_hooks() const { + const flecs::type_hooks_t* h = ecs_get_hooks_id(world_, id_); + if (h) { + return *h; + } else { + return {}; + } +} + +void set_hooks(flecs::type_hooks_t &h) { + h.flags &= ECS_TYPE_HOOKS_ILLEGAL; + ecs_set_hooks_id(world_, id_, &h); +} + public: /** Add member with unit. */ @@ -27604,6 +27594,33 @@ untyped_component& error_range( return *this; } +untyped_component& op_compare( + ecs_cmp_t compare_callback) +{ + ecs_assert(compare_callback, ECS_INVALID_PARAMETER, NULL); + flecs::type_hooks_t h = get_hooks(); + h.cmp = compare_callback; + h.flags &= ~ECS_TYPE_HOOK_CMP_ILLEGAL; + if(h.flags & ECS_TYPE_HOOK_EQUALS_ILLEGAL) { + h.flags &= ~(ECS_TYPE_HOOK_EQUALS_ILLEGAL); + h.equals = NULL; + } + set_hooks(h); + return *this; +} + +untyped_component& op_equals( + ecs_equals_t equals_callback) +{ + ecs_assert(equals_callback, ECS_INVALID_PARAMETER, NULL); + flecs::type_hooks_t h = get_hooks(); + h.equals = equals_callback; + h.flags &= ~ECS_TYPE_HOOK_EQUALS_ILLEGAL; + set_hooks(h); + return *this; +} + + /** @} */ # endif @@ -27650,6 +27667,12 @@ untyped_component& metric( * * @ingroup cpp_components */ + +template +int ttest() { + return 7; +} + template struct component : untyped_component { /** Register a component. @@ -27741,7 +27764,7 @@ struct component : untyped_component { h.on_add = Delegate::run_add; ctx->on_add = FLECS_NEW(Delegate)(FLECS_FWD(func)); ctx->free_on_add = _::free_obj; - ecs_set_hooks_id(world_, id_, &h); + set_hooks(h); return *this; } @@ -27757,7 +27780,7 @@ struct component : untyped_component { h.on_remove = Delegate::run_remove; ctx->on_remove = FLECS_NEW(Delegate)(FLECS_FWD(func)); ctx->free_on_remove = _::free_obj; - ecs_set_hooks_id(world_, id_, &h); + set_hooks(h); return *this; } @@ -27773,7 +27796,41 @@ struct component : untyped_component { h.on_set = Delegate::run_set; ctx->on_set = FLECS_NEW(Delegate)(FLECS_FWD(func)); ctx->free_on_set = _::free_obj; - ecs_set_hooks_id(world_, id_, &h); + set_hooks(h); + return *this; + } + + /** Register operator compare hook. */ + using untyped_component::op_compare; + component& op_compare() { + ecs_cmp_t handler = _::compare(); + ecs_assert(handler != NULL, ECS_INVALID_OPERATION, + "Type does not have operator> or operator< const or is inaccessible"); + op_compare(handler); + return *this; + } + + /** Type safe variant of compare op function */ + using cmp_hook = int(*)(const T* a, const T* b, const ecs_type_info_t *ti); + component& op_compare(cmp_hook callback) { + op_compare(reinterpret_cast(callback)); + return *this; + } + + /** Register operator equals hook. */ + using untyped_component::op_equals; + component& op_equals() { + ecs_equals_t handler = _::equals(); + ecs_assert(handler != NULL, ECS_INVALID_OPERATION, + "Type does not have operator== const or is inaccessible"); + op_equals(handler); + return *this; + } + + /** Type safe variant of equals op function */ + using equals_hook = bool(*)(const T* a, const T* b, const ecs_type_info_t *ti); + component& op_equals(equals_hook callback) { + op_equals(reinterpret_cast(callback)); return *this; } @@ -27828,15 +27885,6 @@ component& constant(const char *name, T value) { } return result; } - - flecs::type_hooks_t get_hooks() { - const flecs::type_hooks_t* h = ecs_get_hooks_id(world_, id_); - if (h) { - return *h; - } else { - return {}; - } - } }; /** Get id currently assigned to component. If no world has registered the diff --git a/include/flecs.h b/include/flecs.h index d1ce44f87..a56b5216f 100644 --- a/include/flecs.h +++ b/include/flecs.h @@ -875,44 +875,43 @@ struct ecs_observer_t { */ /* Flags that can be used to check which hooks a type has set */ -#define ECS_TYPE_HOOK_CTOR (1 << 0) -#define ECS_TYPE_HOOK_DTOR (1 << 1) -#define ECS_TYPE_HOOK_COPY (1 << 2) -#define ECS_TYPE_HOOK_MOVE (1 << 3) -#define ECS_TYPE_HOOK_COPY_CTOR (1 << 4) -#define ECS_TYPE_HOOK_MOVE_CTOR (1 << 5) -#define ECS_TYPE_HOOK_CTOR_MOVE_DTOR (1 << 6) -#define ECS_TYPE_HOOK_MOVE_DTOR (1 << 7) -#define ECS_TYPE_HOOK_CMP (1 << 8) -#define ECS_TYPE_HOOK_EQUALS (1 << 9) +static const ecs_flags32_t ECS_TYPE_HOOK_CTOR = (1 << 0); +static const ecs_flags32_t ECS_TYPE_HOOK_DTOR = (1 << 1); +static const ecs_flags32_t ECS_TYPE_HOOK_COPY = (1 << 2); +static const ecs_flags32_t ECS_TYPE_HOOK_MOVE = (1 << 3); +static const ecs_flags32_t ECS_TYPE_HOOK_COPY_CTOR = (1 << 4); +static const ecs_flags32_t ECS_TYPE_HOOK_MOVE_CTOR = (1 << 5); +static const ecs_flags32_t ECS_TYPE_HOOK_CTOR_MOVE_DTOR = (1 << 6); +static const ecs_flags32_t ECS_TYPE_HOOK_MOVE_DTOR = (1 << 7); +static const ecs_flags32_t ECS_TYPE_HOOK_CMP = (1 << 8); +static const ecs_flags32_t ECS_TYPE_HOOK_EQUALS = (1 << 9); /* Flags that can be used to set/check which hooks of a type are invalid */ -#define ECS_TYPE_HOOK_CTOR_ILLEGAL (1 << 10) -#define ECS_TYPE_HOOK_DTOR_ILLEGAL (1 << 12) -#define ECS_TYPE_HOOK_COPY_ILLEGAL (1 << 13) -#define ECS_TYPE_HOOK_MOVE_ILLEGAL (1 << 14) -#define ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL (1 << 15) -#define ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL (1 << 16) -#define ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL (1 << 17) -#define ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL (1 << 18) -#define ECS_TYPE_HOOK_CMP_ILLEGAL (1 << 19) -#define ECS_TYPE_HOOK_EQUALS_ILLEGAL (1 << 20) +static const ecs_flags32_t ECS_TYPE_HOOK_CTOR_ILLEGAL = (1 << 10); +static const ecs_flags32_t ECS_TYPE_HOOK_DTOR_ILLEGAL = (1 << 12); +static const ecs_flags32_t ECS_TYPE_HOOK_COPY_ILLEGAL = (1 << 13); +static const ecs_flags32_t ECS_TYPE_HOOK_MOVE_ILLEGAL = (1 << 14); +static const ecs_flags32_t ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL = (1 << 15); +static const ecs_flags32_t ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL = (1 << 16); +static const ecs_flags32_t ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL= (1 << 17); +static const ecs_flags32_t ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL = (1 << 18); +static const ecs_flags32_t ECS_TYPE_HOOK_CMP_ILLEGAL = (1 << 19); +static const ecs_flags32_t ECS_TYPE_HOOK_EQUALS_ILLEGAL = (1 << 20); /* All valid hook flags */ -#define ECS_TYPE_HOOKS (ECS_TYPE_HOOK_CTOR|ECS_TYPE_HOOK_DTOR|\ - ECS_TYPE_HOOK_COPY|ECS_TYPE_HOOK_MOVE|ECS_TYPE_HOOK_COPY_CTOR|\ - ECS_TYPE_HOOK_MOVE_CTOR|ECS_TYPE_HOOK_CTOR_MOVE_DTOR|\ - ECS_TYPE_HOOK_MOVE_DTOR|ECS_TYPE_HOOK_CMP|ECS_TYPE_HOOK_EQUALS) - +static const ecs_flags32_t ECS_TYPE_HOOKS = (ECS_TYPE_HOOK_CTOR|ECS_TYPE_HOOK_DTOR| + ECS_TYPE_HOOK_COPY|ECS_TYPE_HOOK_MOVE|ECS_TYPE_HOOK_COPY_CTOR| + ECS_TYPE_HOOK_MOVE_CTOR|ECS_TYPE_HOOK_CTOR_MOVE_DTOR| + ECS_TYPE_HOOK_MOVE_DTOR|ECS_TYPE_HOOK_CMP|ECS_TYPE_HOOK_EQUALS); /* All invalid hook flags */ -#define ECS_TYPE_HOOKS_ILLEGAL (ECS_TYPE_HOOK_CTOR_ILLEGAL|\ - ECS_TYPE_HOOK_DTOR_ILLEGAL|ECS_TYPE_HOOK_COPY_ILLEGAL|\ - ECS_TYPE_HOOK_MOVE_ILLEGAL|ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL|\ - ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL|ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL|\ - ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL|ECS_TYPE_HOOK_CMP_ILLEGAL|\ - ECS_TYPE_HOOK_EQUALS_ILLEGAL) +static const ecs_flags32_t ECS_TYPE_HOOKS_ILLEGAL = (ECS_TYPE_HOOK_CTOR_ILLEGAL| + ECS_TYPE_HOOK_DTOR_ILLEGAL|ECS_TYPE_HOOK_COPY_ILLEGAL| + ECS_TYPE_HOOK_MOVE_ILLEGAL|ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL| + ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL|ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL| + ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL|ECS_TYPE_HOOK_CMP_ILLEGAL | + ECS_TYPE_HOOK_EQUALS_ILLEGAL); struct ecs_type_hooks_t { ecs_xtor_t ctor; /**< ctor */ diff --git a/include/flecs/addons/cpp/component.hpp b/include/flecs/addons/cpp/component.hpp index c7c113266..bc4edcb33 100644 --- a/include/flecs/addons/cpp/component.hpp +++ b/include/flecs/addons/cpp/component.hpp @@ -91,22 +91,7 @@ template* = nullptr> void register_lifecycle_actions( ecs_world_t *world, - ecs_entity_t component) { - - const ecs_world_t* w = ecs_get_world(world); - - if(ecs_id_in_use(w, component) || - ecs_id_in_use(w, ecs_pair(component, EcsWildcard))) { - return; - } - - ecs_type_hooks_t cl{}; - cl.cmp = compare(cl.flags); - cl.equals = equals(cl.flags); - - cl.flags &= ECS_TYPE_HOOKS_ILLEGAL; - ecs_set_hooks_id(world, component, &cl); -} + ecs_entity_t component) {} // If the component is non-trivial, register component lifecycle actions. // Depending on the type not all callbacks may be available. @@ -129,9 +114,6 @@ void register_lifecycle_actions( cl.ctor_move_dtor = ctor_move_dtor(cl.flags); cl.move_dtor = move_dtor(cl.flags); - cl.cmp = compare(cl.flags); - cl.equals = equals(cl.flags); - cl.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id(world, component, &cl); @@ -385,6 +367,12 @@ struct untyped_component : entity { * * @ingroup cpp_components */ + +template +int ttest() { + return 7; +} + template struct component : untyped_component { /** Register a component. @@ -476,7 +464,7 @@ struct component : untyped_component { h.on_add = Delegate::run_add; ctx->on_add = FLECS_NEW(Delegate)(FLECS_FWD(func)); ctx->free_on_add = _::free_obj; - ecs_set_hooks_id(world_, id_, &h); + set_hooks(h); return *this; } @@ -492,7 +480,7 @@ struct component : untyped_component { h.on_remove = Delegate::run_remove; ctx->on_remove = FLECS_NEW(Delegate)(FLECS_FWD(func)); ctx->free_on_remove = _::free_obj; - ecs_set_hooks_id(world_, id_, &h); + set_hooks(h); return *this; } @@ -508,7 +496,41 @@ struct component : untyped_component { h.on_set = Delegate::run_set; ctx->on_set = FLECS_NEW(Delegate)(FLECS_FWD(func)); ctx->free_on_set = _::free_obj; - ecs_set_hooks_id(world_, id_, &h); + set_hooks(h); + return *this; + } + + /** Register operator compare hook. */ + using untyped_component::op_compare; + component& op_compare() { + ecs_cmp_t handler = _::compare(); + ecs_assert(handler != NULL, ECS_INVALID_OPERATION, + "Type does not have operator> or operator< const or is inaccessible"); + op_compare(handler); + return *this; + } + + /** Type safe variant of compare op function */ + using cmp_hook = int(*)(const T* a, const T* b, const ecs_type_info_t *ti); + component& op_compare(cmp_hook callback) { + op_compare(reinterpret_cast(callback)); + return *this; + } + + /** Register operator equals hook. */ + using untyped_component::op_equals; + component& op_equals() { + ecs_equals_t handler = _::equals(); + ecs_assert(handler != NULL, ECS_INVALID_OPERATION, + "Type does not have operator== const or is inaccessible"); + op_equals(handler); + return *this; + } + + /** Type safe variant of equals op function */ + using equals_hook = bool(*)(const T* a, const T* b, const ecs_type_info_t *ti); + component& op_equals(equals_hook callback) { + op_equals(reinterpret_cast(callback)); return *this; } @@ -528,15 +550,6 @@ struct component : untyped_component { } return result; } - - flecs::type_hooks_t get_hooks() { - const flecs::type_hooks_t* h = ecs_get_hooks_id(world_, id_); - if (h) { - return *h; - } else { - return {}; - } - } }; /** Get id currently assigned to component. If no world has registered the diff --git a/include/flecs/addons/cpp/lifecycle_traits.hpp b/include/flecs/addons/cpp/lifecycle_traits.hpp index 68def8bbf..45a0b6a19 100644 --- a/include/flecs/addons/cpp/lifecycle_traits.hpp +++ b/include/flecs/addons/cpp/lifecycle_traits.hpp @@ -460,15 +460,14 @@ int compare_impl(const void *a, const void *b, const ecs_type_info_t *) { template ::value || has_operator_greater::value > = 0> -ecs_cmp_t compare(ecs_flags32_t &) { +ecs_cmp_t compare() { return compare_impl; } template ::value && !has_operator_greater::value > = 0> -ecs_cmp_t compare(ecs_flags32_t &flags) { - flags |= ECS_TYPE_HOOK_CMP_ILLEGAL; +ecs_cmp_t compare() { return NULL; } @@ -483,19 +482,13 @@ bool equals_impl(const void *a, const void *b, const ecs_type_info_t *) { template ::value > = 0> -ecs_equals_t equals(ecs_flags32_t &) { +ecs_equals_t equals() { return equals_impl; } template ::value > = 0> -ecs_equals_t equals(ecs_flags32_t &flags) { - if(flags & ECS_TYPE_HOOK_CMP_ILLEGAL) { - /* Only mark equals hook as illegal if compare is also illegal - * this way we let Flecs generate an equals hook - * from the compare hook automatically */ - flags |= ECS_TYPE_HOOK_EQUALS_ILLEGAL; - } +ecs_equals_t equals() { return NULL; } diff --git a/include/flecs/addons/cpp/mixins/meta/untyped_component.inl b/include/flecs/addons/cpp/mixins/meta/untyped_component.inl index 6c1df49db..1cb75e61d 100644 --- a/include/flecs/addons/cpp/mixins/meta/untyped_component.inl +++ b/include/flecs/addons/cpp/mixins/meta/untyped_component.inl @@ -40,6 +40,22 @@ untyped_component& internal_member( return *this; } +protected: + +flecs::type_hooks_t get_hooks() const { + const flecs::type_hooks_t* h = ecs_get_hooks_id(world_, id_); + if (h) { + return *h; + } else { + return {}; + } +} + +void set_hooks(flecs::type_hooks_t &h) { + h.flags &= ECS_TYPE_HOOKS_ILLEGAL; + ecs_set_hooks_id(world_, id_, &h); +} + public: /** Add member with unit. */ @@ -306,4 +322,31 @@ untyped_component& error_range( return *this; } +untyped_component& op_compare( + ecs_cmp_t compare_callback) +{ + ecs_assert(compare_callback, ECS_INVALID_PARAMETER, NULL); + flecs::type_hooks_t h = get_hooks(); + h.cmp = compare_callback; + h.flags &= ~ECS_TYPE_HOOK_CMP_ILLEGAL; + if(h.flags & ECS_TYPE_HOOK_EQUALS_ILLEGAL) { + h.flags &= ~(ECS_TYPE_HOOK_EQUALS_ILLEGAL); + h.equals = NULL; + } + set_hooks(h); + return *this; +} + +untyped_component& op_equals( + ecs_equals_t equals_callback) +{ + ecs_assert(equals_callback, ECS_INVALID_PARAMETER, NULL); + flecs::type_hooks_t h = get_hooks(); + h.equals = equals_callback; + h.flags &= ~ECS_TYPE_HOOK_EQUALS_ILLEGAL; + set_hooks(h); + return *this; +} + + /** @} */ diff --git a/src/addons/meta/meta.c b/src/addons/meta/meta.c index 0db0274bb..780debf1f 100644 --- a/src/addons/meta/meta.c +++ b/src/addons/meta/meta.c @@ -1809,12 +1809,14 @@ void FlecsMetaImport( #undef ECS_PRIMITIVE - ecs_set_hooks(world, ecs_string_t, { - .ctor = flecs_default_ctor, - .copy = ecs_copy(ecs_string_t), - .move = ecs_move(ecs_string_t), - .dtor = ecs_dtor(ecs_string_t), - }); + ecs_type_hooks_t string_hooks = *ecs_get_hooks(world, ecs_string_t); + string_hooks.ctor = flecs_default_ctor; + string_hooks.copy = ecs_copy(ecs_string_t); + string_hooks.move = ecs_move(ecs_string_t); + string_hooks.dtor = ecs_dtor(ecs_string_t); + string_hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; + ecs_set_hooks_id(world, ecs_id(ecs_string_t), &string_hooks); + /* Set default child components */ ecs_set(world, ecs_id(EcsStruct), EcsDefaultChildComponent, {ecs_id(EcsMember)}); diff --git a/src/addons/meta/rtt_lifecycle.c b/src/addons/meta/rtt_lifecycle.c index 4af8250d3..c197490d5 100644 --- a/src/addons/meta/rtt_lifecycle.c +++ b/src/addons/meta/rtt_lifecycle.c @@ -378,13 +378,9 @@ void flecs_rtt_init_default_hooks_struct( dtor_hook_required |= member_ti->hooks.dtor != NULL; move_hook_required |= member_ti->hooks.move != NULL; copy_hook_required |= member_ti->hooks.copy != NULL; - - /* A struct has a valid cmp hook if all its members have it */ - valid_cmp &= member_ti->hooks.cmp != NULL; - - /* A struct has a valid equals hook if all its members have it */ + /* A struct has a valid cmp/equals hook if all its members have it: */ + valid_cmp &= member_ti->hooks.cmp != NULL; valid_equals &= member_ti->hooks.equals != NULL; - flags |= member_ti->hooks.flags; } @@ -398,7 +394,7 @@ void flecs_rtt_init_default_hooks_struct( dtor_hook_required ? flecs_rtt_struct_dtor : NULL, move_hook_required ? flecs_rtt_struct_move : NULL, copy_hook_required ? flecs_rtt_struct_copy : NULL, - valid_cmp ? flecs_rtt_struct_cmp : NULL, + valid_cmp ? flecs_rtt_struct_cmp : NULL, valid_equals ? flecs_rtt_struct_equals : NULL ); @@ -638,15 +634,15 @@ void flecs_rtt_init_default_hooks_array( ecs_assert(array_info != NULL, ECS_INTERNAL_ERROR, NULL); const ecs_type_info_t *element_ti = ecs_get_type_info(world, array_info->type); + ecs_flags32_t flags = element_ti->hooks.flags; bool ctor_hook_required = element_ti->hooks.ctor && element_ti->hooks.ctor != flecs_default_ctor; bool dtor_hook_required = element_ti->hooks.dtor != NULL; bool move_hook_required = element_ti->hooks.move != NULL; bool copy_hook_required = element_ti->hooks.copy != NULL; - bool valid_cmp = element_ti->hooks.cmp != NULL; - bool valid_equals = element_ti->hooks.equals != NULL; + bool valid_cmp = element_ti->hooks.cmp != NULL && !(flags & ECS_TYPE_HOOK_CMP_ILLEGAL); + bool valid_equals = element_ti->hooks.equals != NULL && !(flags & ECS_TYPE_HOOK_CMP_ILLEGAL); - ecs_flags32_t flags = element_ti->hooks.flags; ecs_type_hooks_t hooks = *ecs_get_hooks_id(world, component); @@ -987,6 +983,7 @@ void flecs_rtt_init_default_hooks( hooks.ctor = flecs_default_ctor; } + hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id( world, component, diff --git a/src/world.c b/src/world.c index 8ee9369a3..6fea55d30 100644 --- a/src/world.c +++ b/src/world.c @@ -1479,11 +1479,16 @@ void ecs_set_hooks_id( } } - if (!h->equals) { - if(flags & (ECS_TYPE_HOOK_CMP_ILLEGAL|ECS_TYPE_HOOK_EQUALS_ILLEGAL)) { + if(!h->cmp) { + flags |= ECS_TYPE_HOOK_CMP_ILLEGAL; + } + + if (!h->equals || h->equals == flecs_equals_illegal) { + if(flags & ECS_TYPE_HOOK_CMP_ILLEGAL) { flags |= ECS_TYPE_HOOK_EQUALS_ILLEGAL; - } else if(h->cmp) { + } else { ti->hooks.equals = flecs_default_equals; + flags &= ~ECS_TYPE_HOOK_EQUALS_ILLEGAL; } } diff --git a/test/core/project.json b/test/core/project.json index 3b2436d1e..058317cf2 100644 --- a/test/core/project.json +++ b/test/core/project.json @@ -1219,7 +1219,9 @@ "move_flags", "copy_flags", "ctor_move_dtor_flags", - "move_dtor_flags" + "move_dtor_flags", + "cmp_flags", + "equals_flags" ] }, { "id": "Pairs", diff --git a/test/core/src/ComponentLifecycle.c b/test/core/src/ComponentLifecycle.c index c339877dc..42f69bfca 100644 --- a/test/core/src/ComponentLifecycle.c +++ b/test/core/src/ComponentLifecycle.c @@ -3848,7 +3848,9 @@ void ComponentLifecycle_ctor_flags(void) { const ecs_type_info_t *ti = ecs_get_type_info(world, ecs_id(Position)); test_assert(ti != NULL); test_assert(ti->hooks.ctor != NULL); - test_assert(ti->hooks.flags == ECS_TYPE_HOOK_CTOR); + test_assert(ti->hooks.flags == (ECS_TYPE_HOOK_CTOR| + ECS_TYPE_HOOK_CMP|ECS_TYPE_HOOK_EQUALS| + ECS_TYPE_HOOK_CMP_ILLEGAL|ECS_TYPE_HOOK_EQUALS_ILLEGAL)); ecs_fini(world); } @@ -3868,7 +3870,9 @@ void ComponentLifecycle_dtor_flags(void) { test_assert(ti->hooks.dtor != NULL); test_assert(ti->hooks.move_dtor != NULL); test_assert(ti->hooks.flags == - (ECS_TYPE_HOOK_CTOR|ECS_TYPE_HOOK_DTOR|ECS_TYPE_HOOK_MOVE_DTOR)); + (ECS_TYPE_HOOK_CTOR|ECS_TYPE_HOOK_DTOR|ECS_TYPE_HOOK_MOVE_DTOR| + ECS_TYPE_HOOK_CMP|ECS_TYPE_HOOK_EQUALS| + ECS_TYPE_HOOK_CMP_ILLEGAL|ECS_TYPE_HOOK_EQUALS_ILLEGAL)); ecs_fini(world); } @@ -3887,7 +3891,9 @@ void ComponentLifecycle_move_flags(void) { test_assert(ti->hooks.move != NULL); test_assert(ti->hooks.flags == (ECS_TYPE_HOOK_CTOR|ECS_TYPE_HOOK_MOVE|ECS_TYPE_HOOK_MOVE_CTOR| - ECS_TYPE_HOOK_CTOR_MOVE_DTOR|ECS_TYPE_HOOK_MOVE_DTOR)); + ECS_TYPE_HOOK_CTOR_MOVE_DTOR|ECS_TYPE_HOOK_MOVE_DTOR| + ECS_TYPE_HOOK_CMP|ECS_TYPE_HOOK_EQUALS| + ECS_TYPE_HOOK_CMP_ILLEGAL|ECS_TYPE_HOOK_EQUALS_ILLEGAL)); ecs_fini(world); } @@ -3905,7 +3911,9 @@ void ComponentLifecycle_copy_flags(void) { test_assert(ti != NULL); test_assert(ti->hooks.copy != NULL); test_assert(ti->hooks.flags == - (ECS_TYPE_HOOK_CTOR|ECS_TYPE_HOOK_COPY|ECS_TYPE_HOOK_COPY_CTOR)); + (ECS_TYPE_HOOK_CTOR|ECS_TYPE_HOOK_COPY|ECS_TYPE_HOOK_COPY_CTOR| + ECS_TYPE_HOOK_CMP|ECS_TYPE_HOOK_EQUALS| + ECS_TYPE_HOOK_CMP_ILLEGAL|ECS_TYPE_HOOK_EQUALS_ILLEGAL)); ecs_fini(world); } @@ -3931,7 +3939,9 @@ void ComponentLifecycle_ctor_move_dtor_flags(void) { test_assert(ti->hooks.move_dtor != NULL); test_assert(ti->hooks.flags == (ECS_TYPE_HOOK_CTOR|ECS_TYPE_HOOK_DTOR|ECS_TYPE_HOOK_MOVE| - ECS_TYPE_HOOK_MOVE_CTOR|ECS_TYPE_HOOK_CTOR_MOVE_DTOR|ECS_TYPE_HOOK_MOVE_DTOR)); + ECS_TYPE_HOOK_MOVE_CTOR|ECS_TYPE_HOOK_CTOR_MOVE_DTOR|ECS_TYPE_HOOK_MOVE_DTOR| + ECS_TYPE_HOOK_CMP|ECS_TYPE_HOOK_EQUALS| + ECS_TYPE_HOOK_CMP_ILLEGAL|ECS_TYPE_HOOK_EQUALS_ILLEGAL)); ecs_fini(world); } @@ -3953,7 +3963,66 @@ void ComponentLifecycle_move_dtor_flags(void) { test_assert(ti->hooks.move_dtor != NULL); test_assert(ti->hooks.flags == (ECS_TYPE_HOOK_CTOR|ECS_TYPE_HOOK_MOVE_CTOR|ECS_TYPE_HOOK_CTOR_MOVE_DTOR| - ECS_TYPE_HOOK_DTOR|ECS_TYPE_HOOK_MOVE|ECS_TYPE_HOOK_MOVE_DTOR)); + ECS_TYPE_HOOK_DTOR|ECS_TYPE_HOOK_MOVE|ECS_TYPE_HOOK_MOVE_DTOR| + ECS_TYPE_HOOK_CMP|ECS_TYPE_HOOK_EQUALS| + ECS_TYPE_HOOK_CMP_ILLEGAL|ECS_TYPE_HOOK_EQUALS_ILLEGAL)); ecs_fini(world); } + +int compare_Position(const void *a, const void *b, const ecs_type_info_t *ti) { + Position *pa = (Position*) a; + Position *pb = (Position*) b; + double ma = (pa->x) * (pa->x) + (pa->y) * (pa->y); + double mb = (pb->x) * (pb->x) + (pb->y) * (pb->y); + return mamb ? 1 : 0; +} + +bool equals_Position(const void *a, const void *b, const ecs_type_info_t *ti) { + Position *pa = (Position*) a; + Position *pb = (Position*) b; + return (pa->x == pb->x) && (pa->y == pb->y); +} + +void ComponentLifecycle_cmp_flags(void) { + ecs_world_t *world = ecs_mini(); + + ECS_COMPONENT(world, Position); + + ecs_set_hooks(world, Position, { + .cmp = compare_Position, + }); + + const ecs_type_info_t *ti = ecs_get_type_info(world, ecs_id(Position)); + test_assert(ti != NULL); + test_assert(ti->hooks.cmp != NULL); + + /* equals is autogenerated from valid cmp */ + test_assert(ti->hooks.equals != NULL); + + test_assert(ti->hooks.flags == (ECS_TYPE_HOOK_CMP|ECS_TYPE_HOOK_EQUALS)); + + ecs_fini(world); +} + +void ComponentLifecycle_equals_flags(void) { + ecs_world_t *world = ecs_mini(); + + ECS_COMPONENT(world, Position); + + ecs_set_hooks(world, Position, { + .equals = equals_Position, + }); + + const ecs_type_info_t *ti = ecs_get_type_info(world, ecs_id(Position)); + test_assert(ti != NULL); + test_assert(ti->hooks.equals != NULL); + + test_assert(ti->hooks.flags == ( + ECS_TYPE_HOOK_CMP| + ECS_TYPE_HOOK_EQUALS| + ECS_TYPE_HOOK_CMP_ILLEGAL + )); + + ecs_fini(world); +} \ No newline at end of file diff --git a/test/core/src/main.c b/test/core/src/main.c index 956cb0439..608d6ec7b 100644 --- a/test/core/src/main.c +++ b/test/core/src/main.c @@ -1165,6 +1165,8 @@ void ComponentLifecycle_move_flags(void); void ComponentLifecycle_copy_flags(void); void ComponentLifecycle_ctor_move_dtor_flags(void); void ComponentLifecycle_move_dtor_flags(void); +void ComponentLifecycle_cmp_flags(void); +void ComponentLifecycle_equals_flags(void); // Testsuite 'Pairs' void Pairs_type_w_one_pair(void); @@ -6801,6 +6803,14 @@ bake_test_case ComponentLifecycle_testcases[] = { { "move_dtor_flags", ComponentLifecycle_move_dtor_flags + }, + { + "cmp_flags", + ComponentLifecycle_cmp_flags + }, + { + "equals_flags", + ComponentLifecycle_equals_flags } }; @@ -11509,7 +11519,7 @@ static bake_test_suite suites[] = { "ComponentLifecycle", ComponentLifecycle_setup, NULL, - 120, + 122, ComponentLifecycle_testcases }, { diff --git a/test/cpp/src/ComponentLifecycle.cpp b/test/cpp/src/ComponentLifecycle.cpp index 58b3eed89..5bc9053e9 100644 --- a/test/cpp/src/ComponentLifecycle.cpp +++ b/test/cpp/src/ComponentLifecycle.cpp @@ -2334,7 +2334,7 @@ struct WithEqualsOnly { }; struct WithoutOperators { - int value; + int16_t value; }; int compare(flecs::world& ecs, flecs::entity_t id, const void *a, const void *b) { @@ -2352,6 +2352,18 @@ void ComponentLifecycle_compare_WithGreaterThan(void) { auto component = ecs.component(); + const ecs_type_hooks_t* hooks = ecs_get_hooks_id(ecs, component); + test_assert(hooks->flags & ECS_TYPE_HOOK_CMP_ILLEGAL); + test_assert(hooks->flags & ECS_TYPE_HOOK_EQUALS_ILLEGAL); + + /* generate cmp operator from C++ operator> */ + component.op_compare(); + + hooks = ecs_get_hooks_id(ecs, component); + test_assert(!(hooks->flags & ECS_TYPE_HOOK_CMP_ILLEGAL)); + /* `equals` is automatically generated: */ + test_assert(!(hooks->flags & ECS_TYPE_HOOK_EQUALS_ILLEGAL)); + WithGreaterThan a = {1}; WithGreaterThan b = {2}; WithGreaterThan c = {1}; @@ -2374,6 +2386,20 @@ void ComponentLifecycle_compare_WithLessThan(void) { auto component = ecs.component(); + const ecs_type_hooks_t* hooks = ecs_get_hooks_id(ecs, component); + + test_assert(hooks->flags & ECS_TYPE_HOOK_CMP_ILLEGAL); + test_assert(hooks->flags & ECS_TYPE_HOOK_EQUALS_ILLEGAL); + + /* generate cmp operator from C++ operator< */ + component.op_compare(); + + hooks = ecs_get_hooks_id(ecs, component); + test_assert(!(hooks->flags & ECS_TYPE_HOOK_CMP_ILLEGAL)); + /* `equals` is automatically generated: */ + test_assert(!(hooks->flags & ECS_TYPE_HOOK_EQUALS_ILLEGAL)); + + WithLessThan a = {1}; WithLessThan b = {2}; WithLessThan c = {1}; @@ -2396,6 +2422,18 @@ void ComponentLifecycle_compare_WithLessAndGreaterThan(void) { auto component = ecs.component(); + const ecs_type_hooks_t* hooks = ecs_get_hooks_id(ecs, component); + test_assert(hooks->flags & ECS_TYPE_HOOK_CMP_ILLEGAL); + test_assert(hooks->flags & ECS_TYPE_HOOK_EQUALS_ILLEGAL); + + /* generate cmp operator from C++ operator> and operator< */ + component.op_compare(); + + hooks = ecs_get_hooks_id(ecs, component); + test_assert(!(hooks->flags & ECS_TYPE_HOOK_CMP_ILLEGAL)); + /* `equals` is automatically generated: */ + test_assert(!(hooks->flags & ECS_TYPE_HOOK_EQUALS_ILLEGAL)); + WithLessAndGreaterThan a = {1}; WithLessAndGreaterThan b = {2}; WithLessAndGreaterThan c = {1}; @@ -2418,6 +2456,18 @@ void ComponentLifecycle_compare_WithEqualsAndGreaterThan(void) { auto component = ecs.component(); + const ecs_type_hooks_t* hooks = ecs_get_hooks_id(ecs, component); + test_assert(hooks->flags & ECS_TYPE_HOOK_CMP_ILLEGAL); + test_assert(hooks->flags & ECS_TYPE_HOOK_EQUALS_ILLEGAL); + + /* generate cmp operator from C++ operator> and operator== */ + component.op_compare(); + + hooks = ecs_get_hooks_id(ecs, component); + test_assert(!(hooks->flags & ECS_TYPE_HOOK_CMP_ILLEGAL)); + /* `equals` is automatically generated: */ + test_assert(!(hooks->flags & ECS_TYPE_HOOK_EQUALS_ILLEGAL)); + WithEqualsAndGreaterThan a = {1}; WithEqualsAndGreaterThan b = {2}; WithEqualsAndGreaterThan c = {1}; @@ -2440,6 +2490,19 @@ void ComponentLifecycle_compare_WithEqualsAndLessThan(void) { auto component = ecs.component(); + const ecs_type_hooks_t* hooks = ecs_get_hooks_id(ecs, component); + test_assert(hooks->flags & ECS_TYPE_HOOK_CMP_ILLEGAL); + test_assert(hooks->flags & ECS_TYPE_HOOK_EQUALS_ILLEGAL); + + /* generate cmp operator from C++ operator< and operator== */ + component.op_compare(); + + hooks = ecs_get_hooks_id(ecs, component); + test_assert(!(hooks->flags & ECS_TYPE_HOOK_CMP_ILLEGAL)); + /* `equals` is automatically generated: */ + test_assert(!(hooks->flags & ECS_TYPE_HOOK_EQUALS_ILLEGAL)); + + WithEqualsAndLessThan a = {1}; WithEqualsAndLessThan b = {2}; WithEqualsAndLessThan c = {1}; @@ -2465,10 +2528,20 @@ void ComponentLifecycle_compare_WithEqualsOnly(void) { auto component = ecs.component(); const ecs_type_hooks_t* hooks = ecs_get_hooks_id(ecs, component); + test_assert(hooks->flags & ECS_TYPE_HOOK_CMP_ILLEGAL); + test_assert(hooks->flags & ECS_TYPE_HOOK_EQUALS_ILLEGAL); + + /* generate equals operator from C++ operator== */ + component.op_equals(); + + hooks = ecs_get_hooks_id(ecs, component); /* can't compare if no < or > operators are defined */ test_assert(hooks->flags & ECS_TYPE_HOOK_CMP_ILLEGAL); + /* operator equals is defined: */ + test_assert(!(hooks->flags & ECS_TYPE_HOOK_EQUALS_ILLEGAL)); + WithEqualsOnly a = {1}; WithEqualsOnly b = {2}; WithEqualsOnly c = {1}; @@ -2490,5 +2563,44 @@ void ComponentLifecycle_compare_WithoutOperators(void) { test_assert(hooks->flags & ECS_TYPE_HOOK_CMP_ILLEGAL); test_assert(hooks->flags & ECS_TYPE_HOOK_EQUALS_ILLEGAL); + /* define operator equals via a explicit callback: */ + component.op_equals([]( + const WithoutOperators *a, + const WithoutOperators *b, + const ecs_type_info_t* ti) -> bool { + return a->value == b->value; + }); + + hooks = ecs_get_hooks_id(ecs, component); + + test_assert(hooks->flags & ECS_TYPE_HOOK_CMP_ILLEGAL); + test_assert(!(hooks->flags & ECS_TYPE_HOOK_EQUALS_ILLEGAL)); + + WithoutOperators a = {1}; + WithoutOperators b = {2}; + WithoutOperators c = {1}; + + test_assert(equals(ecs, component, &a, &b) == false); + test_assert(equals(ecs, component, &a, &c) == true); + test_assert(equals(ecs, component, &a, &a) == true); + + component.op_compare([]( + const WithoutOperators *a, + const WithoutOperators *b, + const ecs_type_info_t *ti) -> int { + return a->value - b->value; + }); + + hooks = ecs_get_hooks_id(ecs, component); + + test_assert(!(hooks->flags & ECS_TYPE_HOOK_CMP_ILLEGAL)); + test_assert(!(hooks->flags & ECS_TYPE_HOOK_EQUALS_ILLEGAL)); + + test_assert(compare(ecs, component, &a, &b) < 0); + test_assert(compare(ecs, component, &b, &a) > 0); + test_assert(compare(ecs, component, &a, &c) == 0); + test_assert(compare(ecs, component, &b, &c) > 0); + test_assert(compare(ecs, component, &c, &b) < 0); + test_assert(compare(ecs, component, &b, &b) == 0); } diff --git a/test/meta/src/RttCompare.c b/test/meta/src/RttCompare.c index bb2b45075..f62544a9e 100644 --- a/test/meta/src/RttCompare.c +++ b/test/meta/src/RttCompare.c @@ -38,7 +38,8 @@ ecs_entity_t define_opaque_type(ecs_world_t *world) { ecs_type_hooks_t hooks = *ecs_get_hooks(world, OpaqueType); hooks.cmp = opaque_type_compare; - + hooks.flags &= ~ECS_TYPE_HOOK_CMP_ILLEGAL; + hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id(world, ecs_id(OpaqueType), &hooks); ecs_entity_t descriptor = ecs_struct(world, { diff --git a/test/meta/src/RuntimeTypes.c b/test/meta/src/RuntimeTypes.c index c1fe13ffa..6b83bda09 100644 --- a/test/meta/src/RuntimeTypes.c +++ b/test/meta/src/RuntimeTypes.c @@ -600,6 +600,10 @@ void RuntimeTypes_equals_illegal(void) { ecs_type_hooks_t hooks = nested_struct_ti->hooks; hooks.flags |= ECS_TYPE_HOOK_EQUALS_ILLEGAL; /* mark equals hook for "NestedStruct" as illegal */ hooks.equals = NULL; + + /* must mark cmp illegal too, otherwise equals would be autogenerated from cmp */ + hooks.flags |= ECS_TYPE_HOOK_CMP_ILLEGAL; + hooks.cmp = NULL; hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id(world, nested_struct, &hooks); @@ -1440,8 +1444,9 @@ ecs_entity_t define_ResourceHandle_opaque( hooks.dtor = ResourceHandle_dtor; hooks.move = ResourceHandle_move; hooks.copy = ResourceHandle_copy; - hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; hooks.cmp = ResourceHandle_comp; + hooks.flags &= ~ECS_TYPE_HOOK_CMP_ILLEGAL; + hooks.flags &= ECS_TYPE_HOOKS_ILLEGAL; ecs_set_hooks_id(world, ecs_id(ResourceHandle), &hooks); From bfce29b8ca86f77d10a197b498d90382bb4e7fdf Mon Sep 17 00:00:00 2001 From: Javier Peletier Date: Wed, 4 Dec 2024 22:57:32 +0100 Subject: [PATCH 21/23] fix quirks (1) --- distr/flecs.h | 159 +++++++++--------- include/flecs.h | 62 +++---- include/flecs/addons/cpp/component.hpp | 54 +++++- .../cpp/mixins/meta/untyped_component.inl | 43 ----- 4 files changed, 160 insertions(+), 158 deletions(-) diff --git a/distr/flecs.h b/distr/flecs.h index abfa6317b..3ee48e776 100644 --- a/distr/flecs.h +++ b/distr/flecs.h @@ -3543,44 +3543,44 @@ struct ecs_observer_t { */ /* Flags that can be used to check which hooks a type has set */ -static const ecs_flags32_t ECS_TYPE_HOOK_CTOR = (1 << 0); -static const ecs_flags32_t ECS_TYPE_HOOK_DTOR = (1 << 1); -static const ecs_flags32_t ECS_TYPE_HOOK_COPY = (1 << 2); -static const ecs_flags32_t ECS_TYPE_HOOK_MOVE = (1 << 3); -static const ecs_flags32_t ECS_TYPE_HOOK_COPY_CTOR = (1 << 4); -static const ecs_flags32_t ECS_TYPE_HOOK_MOVE_CTOR = (1 << 5); -static const ecs_flags32_t ECS_TYPE_HOOK_CTOR_MOVE_DTOR = (1 << 6); -static const ecs_flags32_t ECS_TYPE_HOOK_MOVE_DTOR = (1 << 7); -static const ecs_flags32_t ECS_TYPE_HOOK_CMP = (1 << 8); -static const ecs_flags32_t ECS_TYPE_HOOK_EQUALS = (1 << 9); +#define ECS_TYPE_HOOK_CTOR ((ecs_flags32_t)(1 << 0)) +#define ECS_TYPE_HOOK_DTOR ((ecs_flags32_t)(1 << 1)) +#define ECS_TYPE_HOOK_COPY ((ecs_flags32_t)(1 << 2)) +#define ECS_TYPE_HOOK_MOVE ((ecs_flags32_t)(1 << 3)) +#define ECS_TYPE_HOOK_COPY_CTOR ((ecs_flags32_t)(1 << 4)) +#define ECS_TYPE_HOOK_MOVE_CTOR ((ecs_flags32_t)(1 << 5)) +#define ECS_TYPE_HOOK_CTOR_MOVE_DTOR ((ecs_flags32_t)(1 << 6)) +#define ECS_TYPE_HOOK_MOVE_DTOR ((ecs_flags32_t)(1 << 7)) +#define ECS_TYPE_HOOK_CMP ((ecs_flags32_t)(1 << 8)) +#define ECS_TYPE_HOOK_EQUALS ((ecs_flags32_t)(1 << 9)) /* Flags that can be used to set/check which hooks of a type are invalid */ -static const ecs_flags32_t ECS_TYPE_HOOK_CTOR_ILLEGAL = (1 << 10); -static const ecs_flags32_t ECS_TYPE_HOOK_DTOR_ILLEGAL = (1 << 12); -static const ecs_flags32_t ECS_TYPE_HOOK_COPY_ILLEGAL = (1 << 13); -static const ecs_flags32_t ECS_TYPE_HOOK_MOVE_ILLEGAL = (1 << 14); -static const ecs_flags32_t ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL = (1 << 15); -static const ecs_flags32_t ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL = (1 << 16); -static const ecs_flags32_t ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL= (1 << 17); -static const ecs_flags32_t ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL = (1 << 18); -static const ecs_flags32_t ECS_TYPE_HOOK_CMP_ILLEGAL = (1 << 19); -static const ecs_flags32_t ECS_TYPE_HOOK_EQUALS_ILLEGAL = (1 << 20); +#define ECS_TYPE_HOOK_CTOR_ILLEGAL ((ecs_flags32_t)(1 << 10)) +#define ECS_TYPE_HOOK_DTOR_ILLEGAL ((ecs_flags32_t)(1 << 12)) +#define ECS_TYPE_HOOK_COPY_ILLEGAL ((ecs_flags32_t)(1 << 13)) +#define ECS_TYPE_HOOK_MOVE_ILLEGAL ((ecs_flags32_t)(1 << 14)) +#define ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL ((ecs_flags32_t)(1 << 15)) +#define ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL ((ecs_flags32_t)(1 << 16)) +#define ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL ((ecs_flags32_t)(1 << 17)) +#define ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL ((ecs_flags32_t)(1 << 18)) +#define ECS_TYPE_HOOK_CMP_ILLEGAL ((ecs_flags32_t)(1 << 19)) +#define ECS_TYPE_HOOK_EQUALS_ILLEGAL ((ecs_flags32_t)(1 << 20)) /* All valid hook flags */ -static const ecs_flags32_t ECS_TYPE_HOOKS = (ECS_TYPE_HOOK_CTOR|ECS_TYPE_HOOK_DTOR| - ECS_TYPE_HOOK_COPY|ECS_TYPE_HOOK_MOVE|ECS_TYPE_HOOK_COPY_CTOR| - ECS_TYPE_HOOK_MOVE_CTOR|ECS_TYPE_HOOK_CTOR_MOVE_DTOR| - ECS_TYPE_HOOK_MOVE_DTOR|ECS_TYPE_HOOK_CMP|ECS_TYPE_HOOK_EQUALS); -/* All invalid hook flags */ -static const ecs_flags32_t ECS_TYPE_HOOKS_ILLEGAL = (ECS_TYPE_HOOK_CTOR_ILLEGAL| - ECS_TYPE_HOOK_DTOR_ILLEGAL|ECS_TYPE_HOOK_COPY_ILLEGAL| - ECS_TYPE_HOOK_MOVE_ILLEGAL|ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL| - ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL|ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL| - ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL|ECS_TYPE_HOOK_CMP_ILLEGAL | - ECS_TYPE_HOOK_EQUALS_ILLEGAL); +#define ECS_TYPE_HOOKS (ECS_TYPE_HOOK_CTOR|ECS_TYPE_HOOK_DTOR|\ + ECS_TYPE_HOOK_COPY|ECS_TYPE_HOOK_MOVE|ECS_TYPE_HOOK_COPY_CTOR|\ + ECS_TYPE_HOOK_MOVE_CTOR|ECS_TYPE_HOOK_CTOR_MOVE_DTOR|\ + ECS_TYPE_HOOK_MOVE_DTOR|ECS_TYPE_HOOK_CMP|ECS_TYPE_HOOK_EQUALS) +/* All invalid hook flags */ +#define ECS_TYPE_HOOKS_ILLEGAL (ECS_TYPE_HOOK_CTOR_ILLEGAL|\ + ECS_TYPE_HOOK_DTOR_ILLEGAL|ECS_TYPE_HOOK_COPY_ILLEGAL|\ + ECS_TYPE_HOOK_MOVE_ILLEGAL|ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL|\ + ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL|ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL|\ + ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL|ECS_TYPE_HOOK_CMP_ILLEGAL|\ + ECS_TYPE_HOOK_EQUALS_ILLEGAL) struct ecs_type_hooks_t { ecs_xtor_t ctor; /**< ctor */ ecs_xtor_t dtor; /**< dtor */ @@ -27005,8 +27005,8 @@ template::value == true >* = nullptr> void register_lifecycle_actions( - ecs_world_t *world, - ecs_entity_t component) {} + ecs_world_t*, + ecs_entity_t) {} // If the component is non-trivial, register component lifecycle actions. // Depending on the type not all callbacks may be available. @@ -27269,6 +27269,50 @@ struct type::value >> struct untyped_component : entity { using entity::entity; +protected: + +flecs::type_hooks_t get_hooks() const { + const flecs::type_hooks_t* h = ecs_get_hooks_id(world_, id_); + if (h) { + return *h; + } else { + return {}; + } +} + +void set_hooks(flecs::type_hooks_t &h) { + h.flags &= ECS_TYPE_HOOKS_ILLEGAL; + ecs_set_hooks_id(world_, id_, &h); +} + +public: + +untyped_component& op_compare( + ecs_cmp_t compare_callback) +{ + ecs_assert(compare_callback, ECS_INVALID_PARAMETER, NULL); + flecs::type_hooks_t h = get_hooks(); + h.cmp = compare_callback; + h.flags &= ~ECS_TYPE_HOOK_CMP_ILLEGAL; + if(h.flags & ECS_TYPE_HOOK_EQUALS_ILLEGAL) { + h.flags &= ~(ECS_TYPE_HOOK_EQUALS_ILLEGAL); + h.equals = NULL; + } + set_hooks(h); + return *this; +} + +untyped_component& op_equals( + ecs_equals_t equals_callback) +{ + ecs_assert(equals_callback, ECS_INVALID_PARAMETER, NULL); + flecs::type_hooks_t h = get_hooks(); + h.equals = equals_callback; + h.flags &= ~ECS_TYPE_HOOK_EQUALS_ILLEGAL; + set_hooks(h); + return *this; +} + # ifdef FLECS_META /** * @file addons/cpp/mixins/meta/untyped_component.inl @@ -27312,22 +27356,6 @@ untyped_component& internal_member( return *this; } -protected: - -flecs::type_hooks_t get_hooks() const { - const flecs::type_hooks_t* h = ecs_get_hooks_id(world_, id_); - if (h) { - return *h; - } else { - return {}; - } -} - -void set_hooks(flecs::type_hooks_t &h) { - h.flags &= ECS_TYPE_HOOKS_ILLEGAL; - ecs_set_hooks_id(world_, id_, &h); -} - public: /** Add member with unit. */ @@ -27594,33 +27622,6 @@ untyped_component& error_range( return *this; } -untyped_component& op_compare( - ecs_cmp_t compare_callback) -{ - ecs_assert(compare_callback, ECS_INVALID_PARAMETER, NULL); - flecs::type_hooks_t h = get_hooks(); - h.cmp = compare_callback; - h.flags &= ~ECS_TYPE_HOOK_CMP_ILLEGAL; - if(h.flags & ECS_TYPE_HOOK_EQUALS_ILLEGAL) { - h.flags &= ~(ECS_TYPE_HOOK_EQUALS_ILLEGAL); - h.equals = NULL; - } - set_hooks(h); - return *this; -} - -untyped_component& op_equals( - ecs_equals_t equals_callback) -{ - ecs_assert(equals_callback, ECS_INVALID_PARAMETER, NULL); - flecs::type_hooks_t h = get_hooks(); - h.equals = equals_callback; - h.flags &= ~ECS_TYPE_HOOK_EQUALS_ILLEGAL; - set_hooks(h); - return *this; -} - - /** @} */ # endif @@ -27757,7 +27758,7 @@ struct component : untyped_component { template component& on_add(Func&& func) { using Delegate = typename _::each_delegate::type, T>; - flecs::type_hooks_t h = get_hooks(); + flecs::type_hooks_t h = this->get_hooks(); ecs_assert(h.on_add == nullptr, ECS_INVALID_OPERATION, "on_add hook is already set"); BindingCtx *ctx = get_binding_ctx(h); @@ -27773,7 +27774,7 @@ struct component : untyped_component { component& on_remove(Func&& func) { using Delegate = typename _::each_delegate< typename std::decay::type, T>; - flecs::type_hooks_t h = get_hooks(); + flecs::type_hooks_t h = this->get_hooks(); ecs_assert(h.on_remove == nullptr, ECS_INVALID_OPERATION, "on_remove hook is already set"); BindingCtx *ctx = get_binding_ctx(h); @@ -27789,7 +27790,7 @@ struct component : untyped_component { component& on_set(Func&& func) { using Delegate = typename _::each_delegate< typename std::decay::type, T>; - flecs::type_hooks_t h = get_hooks(); + flecs::type_hooks_t h = this->get_hooks(); ecs_assert(h.on_set == nullptr, ECS_INVALID_OPERATION, "on_set hook is already set"); BindingCtx *ctx = get_binding_ctx(h); diff --git a/include/flecs.h b/include/flecs.h index a56b5216f..25e755a22 100644 --- a/include/flecs.h +++ b/include/flecs.h @@ -875,44 +875,44 @@ struct ecs_observer_t { */ /* Flags that can be used to check which hooks a type has set */ -static const ecs_flags32_t ECS_TYPE_HOOK_CTOR = (1 << 0); -static const ecs_flags32_t ECS_TYPE_HOOK_DTOR = (1 << 1); -static const ecs_flags32_t ECS_TYPE_HOOK_COPY = (1 << 2); -static const ecs_flags32_t ECS_TYPE_HOOK_MOVE = (1 << 3); -static const ecs_flags32_t ECS_TYPE_HOOK_COPY_CTOR = (1 << 4); -static const ecs_flags32_t ECS_TYPE_HOOK_MOVE_CTOR = (1 << 5); -static const ecs_flags32_t ECS_TYPE_HOOK_CTOR_MOVE_DTOR = (1 << 6); -static const ecs_flags32_t ECS_TYPE_HOOK_MOVE_DTOR = (1 << 7); -static const ecs_flags32_t ECS_TYPE_HOOK_CMP = (1 << 8); -static const ecs_flags32_t ECS_TYPE_HOOK_EQUALS = (1 << 9); +#define ECS_TYPE_HOOK_CTOR ((ecs_flags32_t)(1 << 0)) +#define ECS_TYPE_HOOK_DTOR ((ecs_flags32_t)(1 << 1)) +#define ECS_TYPE_HOOK_COPY ((ecs_flags32_t)(1 << 2)) +#define ECS_TYPE_HOOK_MOVE ((ecs_flags32_t)(1 << 3)) +#define ECS_TYPE_HOOK_COPY_CTOR ((ecs_flags32_t)(1 << 4)) +#define ECS_TYPE_HOOK_MOVE_CTOR ((ecs_flags32_t)(1 << 5)) +#define ECS_TYPE_HOOK_CTOR_MOVE_DTOR ((ecs_flags32_t)(1 << 6)) +#define ECS_TYPE_HOOK_MOVE_DTOR ((ecs_flags32_t)(1 << 7)) +#define ECS_TYPE_HOOK_CMP ((ecs_flags32_t)(1 << 8)) +#define ECS_TYPE_HOOK_EQUALS ((ecs_flags32_t)(1 << 9)) /* Flags that can be used to set/check which hooks of a type are invalid */ -static const ecs_flags32_t ECS_TYPE_HOOK_CTOR_ILLEGAL = (1 << 10); -static const ecs_flags32_t ECS_TYPE_HOOK_DTOR_ILLEGAL = (1 << 12); -static const ecs_flags32_t ECS_TYPE_HOOK_COPY_ILLEGAL = (1 << 13); -static const ecs_flags32_t ECS_TYPE_HOOK_MOVE_ILLEGAL = (1 << 14); -static const ecs_flags32_t ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL = (1 << 15); -static const ecs_flags32_t ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL = (1 << 16); -static const ecs_flags32_t ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL= (1 << 17); -static const ecs_flags32_t ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL = (1 << 18); -static const ecs_flags32_t ECS_TYPE_HOOK_CMP_ILLEGAL = (1 << 19); -static const ecs_flags32_t ECS_TYPE_HOOK_EQUALS_ILLEGAL = (1 << 20); +#define ECS_TYPE_HOOK_CTOR_ILLEGAL ((ecs_flags32_t)(1 << 10)) +#define ECS_TYPE_HOOK_DTOR_ILLEGAL ((ecs_flags32_t)(1 << 12)) +#define ECS_TYPE_HOOK_COPY_ILLEGAL ((ecs_flags32_t)(1 << 13)) +#define ECS_TYPE_HOOK_MOVE_ILLEGAL ((ecs_flags32_t)(1 << 14)) +#define ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL ((ecs_flags32_t)(1 << 15)) +#define ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL ((ecs_flags32_t)(1 << 16)) +#define ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL ((ecs_flags32_t)(1 << 17)) +#define ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL ((ecs_flags32_t)(1 << 18)) +#define ECS_TYPE_HOOK_CMP_ILLEGAL ((ecs_flags32_t)(1 << 19)) +#define ECS_TYPE_HOOK_EQUALS_ILLEGAL ((ecs_flags32_t)(1 << 20)) /* All valid hook flags */ -static const ecs_flags32_t ECS_TYPE_HOOKS = (ECS_TYPE_HOOK_CTOR|ECS_TYPE_HOOK_DTOR| - ECS_TYPE_HOOK_COPY|ECS_TYPE_HOOK_MOVE|ECS_TYPE_HOOK_COPY_CTOR| - ECS_TYPE_HOOK_MOVE_CTOR|ECS_TYPE_HOOK_CTOR_MOVE_DTOR| - ECS_TYPE_HOOK_MOVE_DTOR|ECS_TYPE_HOOK_CMP|ECS_TYPE_HOOK_EQUALS); -/* All invalid hook flags */ -static const ecs_flags32_t ECS_TYPE_HOOKS_ILLEGAL = (ECS_TYPE_HOOK_CTOR_ILLEGAL| - ECS_TYPE_HOOK_DTOR_ILLEGAL|ECS_TYPE_HOOK_COPY_ILLEGAL| - ECS_TYPE_HOOK_MOVE_ILLEGAL|ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL| - ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL|ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL| - ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL|ECS_TYPE_HOOK_CMP_ILLEGAL | - ECS_TYPE_HOOK_EQUALS_ILLEGAL); +#define ECS_TYPE_HOOKS (ECS_TYPE_HOOK_CTOR|ECS_TYPE_HOOK_DTOR|\ + ECS_TYPE_HOOK_COPY|ECS_TYPE_HOOK_MOVE|ECS_TYPE_HOOK_COPY_CTOR|\ + ECS_TYPE_HOOK_MOVE_CTOR|ECS_TYPE_HOOK_CTOR_MOVE_DTOR|\ + ECS_TYPE_HOOK_MOVE_DTOR|ECS_TYPE_HOOK_CMP|ECS_TYPE_HOOK_EQUALS) +/* All invalid hook flags */ +#define ECS_TYPE_HOOKS_ILLEGAL (ECS_TYPE_HOOK_CTOR_ILLEGAL|\ + ECS_TYPE_HOOK_DTOR_ILLEGAL|ECS_TYPE_HOOK_COPY_ILLEGAL|\ + ECS_TYPE_HOOK_MOVE_ILLEGAL|ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL|\ + ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL|ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL|\ + ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL|ECS_TYPE_HOOK_CMP_ILLEGAL|\ + ECS_TYPE_HOOK_EQUALS_ILLEGAL) struct ecs_type_hooks_t { ecs_xtor_t ctor; /**< ctor */ ecs_xtor_t dtor; /**< dtor */ diff --git a/include/flecs/addons/cpp/component.hpp b/include/flecs/addons/cpp/component.hpp index bc4edcb33..1ecf630ab 100644 --- a/include/flecs/addons/cpp/component.hpp +++ b/include/flecs/addons/cpp/component.hpp @@ -90,8 +90,8 @@ template::value == true >* = nullptr> void register_lifecycle_actions( - ecs_world_t *world, - ecs_entity_t component) {} + ecs_world_t*, + ecs_entity_t) {} // If the component is non-trivial, register component lifecycle actions. // Depending on the type not all callbacks may be available. @@ -354,6 +354,50 @@ struct type::value >> struct untyped_component : entity { using entity::entity; +protected: + +flecs::type_hooks_t get_hooks() const { + const flecs::type_hooks_t* h = ecs_get_hooks_id(world_, id_); + if (h) { + return *h; + } else { + return {}; + } +} + +void set_hooks(flecs::type_hooks_t &h) { + h.flags &= ECS_TYPE_HOOKS_ILLEGAL; + ecs_set_hooks_id(world_, id_, &h); +} + +public: + +untyped_component& op_compare( + ecs_cmp_t compare_callback) +{ + ecs_assert(compare_callback, ECS_INVALID_PARAMETER, NULL); + flecs::type_hooks_t h = get_hooks(); + h.cmp = compare_callback; + h.flags &= ~ECS_TYPE_HOOK_CMP_ILLEGAL; + if(h.flags & ECS_TYPE_HOOK_EQUALS_ILLEGAL) { + h.flags &= ~(ECS_TYPE_HOOK_EQUALS_ILLEGAL); + h.equals = NULL; + } + set_hooks(h); + return *this; +} + +untyped_component& op_equals( + ecs_equals_t equals_callback) +{ + ecs_assert(equals_callback, ECS_INVALID_PARAMETER, NULL); + flecs::type_hooks_t h = get_hooks(); + h.equals = equals_callback; + h.flags &= ~ECS_TYPE_HOOK_EQUALS_ILLEGAL; + set_hooks(h); + return *this; +} + # ifdef FLECS_META # include "mixins/meta/untyped_component.inl" # endif @@ -457,7 +501,7 @@ struct component : untyped_component { template component& on_add(Func&& func) { using Delegate = typename _::each_delegate::type, T>; - flecs::type_hooks_t h = get_hooks(); + flecs::type_hooks_t h = this->get_hooks(); ecs_assert(h.on_add == nullptr, ECS_INVALID_OPERATION, "on_add hook is already set"); BindingCtx *ctx = get_binding_ctx(h); @@ -473,7 +517,7 @@ struct component : untyped_component { component& on_remove(Func&& func) { using Delegate = typename _::each_delegate< typename std::decay::type, T>; - flecs::type_hooks_t h = get_hooks(); + flecs::type_hooks_t h = this->get_hooks(); ecs_assert(h.on_remove == nullptr, ECS_INVALID_OPERATION, "on_remove hook is already set"); BindingCtx *ctx = get_binding_ctx(h); @@ -489,7 +533,7 @@ struct component : untyped_component { component& on_set(Func&& func) { using Delegate = typename _::each_delegate< typename std::decay::type, T>; - flecs::type_hooks_t h = get_hooks(); + flecs::type_hooks_t h = this->get_hooks(); ecs_assert(h.on_set == nullptr, ECS_INVALID_OPERATION, "on_set hook is already set"); BindingCtx *ctx = get_binding_ctx(h); diff --git a/include/flecs/addons/cpp/mixins/meta/untyped_component.inl b/include/flecs/addons/cpp/mixins/meta/untyped_component.inl index 1cb75e61d..6c1df49db 100644 --- a/include/flecs/addons/cpp/mixins/meta/untyped_component.inl +++ b/include/flecs/addons/cpp/mixins/meta/untyped_component.inl @@ -40,22 +40,6 @@ untyped_component& internal_member( return *this; } -protected: - -flecs::type_hooks_t get_hooks() const { - const flecs::type_hooks_t* h = ecs_get_hooks_id(world_, id_); - if (h) { - return *h; - } else { - return {}; - } -} - -void set_hooks(flecs::type_hooks_t &h) { - h.flags &= ECS_TYPE_HOOKS_ILLEGAL; - ecs_set_hooks_id(world_, id_, &h); -} - public: /** Add member with unit. */ @@ -322,31 +306,4 @@ untyped_component& error_range( return *this; } -untyped_component& op_compare( - ecs_cmp_t compare_callback) -{ - ecs_assert(compare_callback, ECS_INVALID_PARAMETER, NULL); - flecs::type_hooks_t h = get_hooks(); - h.cmp = compare_callback; - h.flags &= ~ECS_TYPE_HOOK_CMP_ILLEGAL; - if(h.flags & ECS_TYPE_HOOK_EQUALS_ILLEGAL) { - h.flags &= ~(ECS_TYPE_HOOK_EQUALS_ILLEGAL); - h.equals = NULL; - } - set_hooks(h); - return *this; -} - -untyped_component& op_equals( - ecs_equals_t equals_callback) -{ - ecs_assert(equals_callback, ECS_INVALID_PARAMETER, NULL); - flecs::type_hooks_t h = get_hooks(); - h.equals = equals_callback; - h.flags &= ~ECS_TYPE_HOOK_EQUALS_ILLEGAL; - set_hooks(h); - return *this; -} - - /** @} */ From f0f65f2d29ab85d8791ac16da8615a45c3b71438 Mon Sep 17 00:00:00 2001 From: Javier Peletier Date: Wed, 4 Dec 2024 23:42:53 +0100 Subject: [PATCH 22/23] fix cast error c/c++ --- distr/flecs.h | 52 +++++++++++--------------- include/flecs.h | 40 ++++++++++---------- include/flecs/addons/cpp/component.hpp | 12 +----- src/world.c | 1 - 4 files changed, 44 insertions(+), 61 deletions(-) diff --git a/distr/flecs.h b/distr/flecs.h index 3ee48e776..4c8d69a6b 100644 --- a/distr/flecs.h +++ b/distr/flecs.h @@ -3543,29 +3543,29 @@ struct ecs_observer_t { */ /* Flags that can be used to check which hooks a type has set */ -#define ECS_TYPE_HOOK_CTOR ((ecs_flags32_t)(1 << 0)) -#define ECS_TYPE_HOOK_DTOR ((ecs_flags32_t)(1 << 1)) -#define ECS_TYPE_HOOK_COPY ((ecs_flags32_t)(1 << 2)) -#define ECS_TYPE_HOOK_MOVE ((ecs_flags32_t)(1 << 3)) -#define ECS_TYPE_HOOK_COPY_CTOR ((ecs_flags32_t)(1 << 4)) -#define ECS_TYPE_HOOK_MOVE_CTOR ((ecs_flags32_t)(1 << 5)) -#define ECS_TYPE_HOOK_CTOR_MOVE_DTOR ((ecs_flags32_t)(1 << 6)) -#define ECS_TYPE_HOOK_MOVE_DTOR ((ecs_flags32_t)(1 << 7)) -#define ECS_TYPE_HOOK_CMP ((ecs_flags32_t)(1 << 8)) -#define ECS_TYPE_HOOK_EQUALS ((ecs_flags32_t)(1 << 9)) +#define ECS_TYPE_HOOK_CTOR ECS_CAST(ecs_flags32_t, 1 << 0) +#define ECS_TYPE_HOOK_DTOR ECS_CAST(ecs_flags32_t, 1 << 1) +#define ECS_TYPE_HOOK_COPY ECS_CAST(ecs_flags32_t, 1 << 2) +#define ECS_TYPE_HOOK_MOVE ECS_CAST(ecs_flags32_t, 1 << 3) +#define ECS_TYPE_HOOK_COPY_CTOR ECS_CAST(ecs_flags32_t, 1 << 4) +#define ECS_TYPE_HOOK_MOVE_CTOR ECS_CAST(ecs_flags32_t, 1 << 5) +#define ECS_TYPE_HOOK_CTOR_MOVE_DTOR ECS_CAST(ecs_flags32_t, 1 << 6) +#define ECS_TYPE_HOOK_MOVE_DTOR ECS_CAST(ecs_flags32_t, 1 << 7) +#define ECS_TYPE_HOOK_CMP ECS_CAST(ecs_flags32_t, 1 << 8) +#define ECS_TYPE_HOOK_EQUALS ECS_CAST(ecs_flags32_t, 1 << 9) /* Flags that can be used to set/check which hooks of a type are invalid */ -#define ECS_TYPE_HOOK_CTOR_ILLEGAL ((ecs_flags32_t)(1 << 10)) -#define ECS_TYPE_HOOK_DTOR_ILLEGAL ((ecs_flags32_t)(1 << 12)) -#define ECS_TYPE_HOOK_COPY_ILLEGAL ((ecs_flags32_t)(1 << 13)) -#define ECS_TYPE_HOOK_MOVE_ILLEGAL ((ecs_flags32_t)(1 << 14)) -#define ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL ((ecs_flags32_t)(1 << 15)) -#define ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL ((ecs_flags32_t)(1 << 16)) -#define ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL ((ecs_flags32_t)(1 << 17)) -#define ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL ((ecs_flags32_t)(1 << 18)) -#define ECS_TYPE_HOOK_CMP_ILLEGAL ((ecs_flags32_t)(1 << 19)) -#define ECS_TYPE_HOOK_EQUALS_ILLEGAL ((ecs_flags32_t)(1 << 20)) +#define ECS_TYPE_HOOK_CTOR_ILLEGAL ECS_CAST(ecs_flags32_t, 1 << 10) +#define ECS_TYPE_HOOK_DTOR_ILLEGAL ECS_CAST(ecs_flags32_t, 1 << 12) +#define ECS_TYPE_HOOK_COPY_ILLEGAL ECS_CAST(ecs_flags32_t, 1 << 13) +#define ECS_TYPE_HOOK_MOVE_ILLEGAL ECS_CAST(ecs_flags32_t, 1 << 14) +#define ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL ECS_CAST(ecs_flags32_t, 1 << 15) +#define ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL ECS_CAST(ecs_flags32_t, 1 << 16) +#define ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL ECS_CAST(ecs_flags32_t, 1 << 17) +#define ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL ECS_CAST(ecs_flags32_t, 1 << 18) +#define ECS_TYPE_HOOK_CMP_ILLEGAL ECS_CAST(ecs_flags32_t, 1 << 19) +#define ECS_TYPE_HOOK_EQUALS_ILLEGAL ECS_CAST(ecs_flags32_t, 1 << 20) /* All valid hook flags */ @@ -27004,9 +27004,7 @@ template <> inline const char* symbol_name() { template::value == true >* = nullptr> -void register_lifecycle_actions( - ecs_world_t*, - ecs_entity_t) {} +void register_lifecycle_actions(ecs_world_t*, ecs_entity_t) { } // If the component is non-trivial, register component lifecycle actions. // Depending on the type not all callbacks may be available. @@ -27295,7 +27293,7 @@ untyped_component& op_compare( h.cmp = compare_callback; h.flags &= ~ECS_TYPE_HOOK_CMP_ILLEGAL; if(h.flags & ECS_TYPE_HOOK_EQUALS_ILLEGAL) { - h.flags &= ~(ECS_TYPE_HOOK_EQUALS_ILLEGAL); + h.flags &= ~ECS_TYPE_HOOK_EQUALS_ILLEGAL; h.equals = NULL; } set_hooks(h); @@ -27668,12 +27666,6 @@ untyped_component& metric( * * @ingroup cpp_components */ - -template -int ttest() { - return 7; -} - template struct component : untyped_component { /** Register a component. diff --git a/include/flecs.h b/include/flecs.h index 25e755a22..07b52df85 100644 --- a/include/flecs.h +++ b/include/flecs.h @@ -875,29 +875,29 @@ struct ecs_observer_t { */ /* Flags that can be used to check which hooks a type has set */ -#define ECS_TYPE_HOOK_CTOR ((ecs_flags32_t)(1 << 0)) -#define ECS_TYPE_HOOK_DTOR ((ecs_flags32_t)(1 << 1)) -#define ECS_TYPE_HOOK_COPY ((ecs_flags32_t)(1 << 2)) -#define ECS_TYPE_HOOK_MOVE ((ecs_flags32_t)(1 << 3)) -#define ECS_TYPE_HOOK_COPY_CTOR ((ecs_flags32_t)(1 << 4)) -#define ECS_TYPE_HOOK_MOVE_CTOR ((ecs_flags32_t)(1 << 5)) -#define ECS_TYPE_HOOK_CTOR_MOVE_DTOR ((ecs_flags32_t)(1 << 6)) -#define ECS_TYPE_HOOK_MOVE_DTOR ((ecs_flags32_t)(1 << 7)) -#define ECS_TYPE_HOOK_CMP ((ecs_flags32_t)(1 << 8)) -#define ECS_TYPE_HOOK_EQUALS ((ecs_flags32_t)(1 << 9)) +#define ECS_TYPE_HOOK_CTOR ECS_CAST(ecs_flags32_t, 1 << 0) +#define ECS_TYPE_HOOK_DTOR ECS_CAST(ecs_flags32_t, 1 << 1) +#define ECS_TYPE_HOOK_COPY ECS_CAST(ecs_flags32_t, 1 << 2) +#define ECS_TYPE_HOOK_MOVE ECS_CAST(ecs_flags32_t, 1 << 3) +#define ECS_TYPE_HOOK_COPY_CTOR ECS_CAST(ecs_flags32_t, 1 << 4) +#define ECS_TYPE_HOOK_MOVE_CTOR ECS_CAST(ecs_flags32_t, 1 << 5) +#define ECS_TYPE_HOOK_CTOR_MOVE_DTOR ECS_CAST(ecs_flags32_t, 1 << 6) +#define ECS_TYPE_HOOK_MOVE_DTOR ECS_CAST(ecs_flags32_t, 1 << 7) +#define ECS_TYPE_HOOK_CMP ECS_CAST(ecs_flags32_t, 1 << 8) +#define ECS_TYPE_HOOK_EQUALS ECS_CAST(ecs_flags32_t, 1 << 9) /* Flags that can be used to set/check which hooks of a type are invalid */ -#define ECS_TYPE_HOOK_CTOR_ILLEGAL ((ecs_flags32_t)(1 << 10)) -#define ECS_TYPE_HOOK_DTOR_ILLEGAL ((ecs_flags32_t)(1 << 12)) -#define ECS_TYPE_HOOK_COPY_ILLEGAL ((ecs_flags32_t)(1 << 13)) -#define ECS_TYPE_HOOK_MOVE_ILLEGAL ((ecs_flags32_t)(1 << 14)) -#define ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL ((ecs_flags32_t)(1 << 15)) -#define ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL ((ecs_flags32_t)(1 << 16)) -#define ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL ((ecs_flags32_t)(1 << 17)) -#define ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL ((ecs_flags32_t)(1 << 18)) -#define ECS_TYPE_HOOK_CMP_ILLEGAL ((ecs_flags32_t)(1 << 19)) -#define ECS_TYPE_HOOK_EQUALS_ILLEGAL ((ecs_flags32_t)(1 << 20)) +#define ECS_TYPE_HOOK_CTOR_ILLEGAL ECS_CAST(ecs_flags32_t, 1 << 10) +#define ECS_TYPE_HOOK_DTOR_ILLEGAL ECS_CAST(ecs_flags32_t, 1 << 12) +#define ECS_TYPE_HOOK_COPY_ILLEGAL ECS_CAST(ecs_flags32_t, 1 << 13) +#define ECS_TYPE_HOOK_MOVE_ILLEGAL ECS_CAST(ecs_flags32_t, 1 << 14) +#define ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL ECS_CAST(ecs_flags32_t, 1 << 15) +#define ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL ECS_CAST(ecs_flags32_t, 1 << 16) +#define ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL ECS_CAST(ecs_flags32_t, 1 << 17) +#define ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL ECS_CAST(ecs_flags32_t, 1 << 18) +#define ECS_TYPE_HOOK_CMP_ILLEGAL ECS_CAST(ecs_flags32_t, 1 << 19) +#define ECS_TYPE_HOOK_EQUALS_ILLEGAL ECS_CAST(ecs_flags32_t, 1 << 20) /* All valid hook flags */ diff --git a/include/flecs/addons/cpp/component.hpp b/include/flecs/addons/cpp/component.hpp index 1ecf630ab..cef10bac4 100644 --- a/include/flecs/addons/cpp/component.hpp +++ b/include/flecs/addons/cpp/component.hpp @@ -89,9 +89,7 @@ template <> inline const char* symbol_name() { template::value == true >* = nullptr> -void register_lifecycle_actions( - ecs_world_t*, - ecs_entity_t) {} +void register_lifecycle_actions(ecs_world_t*, ecs_entity_t) { } // If the component is non-trivial, register component lifecycle actions. // Depending on the type not all callbacks may be available. @@ -380,7 +378,7 @@ untyped_component& op_compare( h.cmp = compare_callback; h.flags &= ~ECS_TYPE_HOOK_CMP_ILLEGAL; if(h.flags & ECS_TYPE_HOOK_EQUALS_ILLEGAL) { - h.flags &= ~(ECS_TYPE_HOOK_EQUALS_ILLEGAL); + h.flags &= ~ECS_TYPE_HOOK_EQUALS_ILLEGAL; h.equals = NULL; } set_hooks(h); @@ -411,12 +409,6 @@ untyped_component& op_equals( * * @ingroup cpp_components */ - -template -int ttest() { - return 7; -} - template struct component : untyped_component { /** Register a component. diff --git a/src/world.c b/src/world.c index 6fea55d30..41485f179 100644 --- a/src/world.c +++ b/src/world.c @@ -3,7 +3,6 @@ * @brief World-level API. */ -#include "flecs.h" #include "private_api.h" /* Id flags */ From 2c416eaec28e43660e4eac14bd603f0869695bcb Mon Sep 17 00:00:00 2001 From: Javier Peletier Date: Thu, 5 Dec 2024 18:01:29 +0100 Subject: [PATCH 23/23] support enums --- distr/flecs.c | 12 ++++++++++-- src/addons/meta/meta.c | 12 ++++++++++-- test/cpp/project.json | 3 ++- test/cpp/src/ComponentLifecycle.cpp | 29 +++++++++++++++++++++++++++++ test/cpp/src/main.cpp | 7 ++++++- 5 files changed, 57 insertions(+), 6 deletions(-) diff --git a/distr/flecs.c b/distr/flecs.c index 7e682e525..b367560ce 100644 --- a/distr/flecs.c +++ b/distr/flecs.c @@ -50635,8 +50635,16 @@ int flecs_init_type( * serializers on uninitialized values. For runtime types (rtt), the default hooks are set by flecs_meta_rtt_init_default_hooks */ ecs_type_info_t *ti = flecs_type_info_ensure(world, type); - if (meta_type->existing && !ti->hooks.ctor) { - ti->hooks.ctor = flecs_default_ctor; + if (meta_type->existing) { + if(!ti->hooks.ctor) { + ti->hooks.ctor = flecs_default_ctor; + } + if(kind == EcsEnumType) { + ti->hooks.cmp = ecs_compare_i32; + ti->hooks.equals = ecs_equals_i32; + ti->hooks.flags &= ~(ECS_TYPE_HOOK_CMP_ILLEGAL|ECS_TYPE_HOOK_EQUALS_ILLEGAL); + ti->hooks.flags |= ECS_TYPE_HOOK_CMP|ECS_TYPE_HOOK_EQUALS; + } } } else { if (meta_type->kind != kind) { diff --git a/src/addons/meta/meta.c b/src/addons/meta/meta.c index 780debf1f..d38bb6306 100644 --- a/src/addons/meta/meta.c +++ b/src/addons/meta/meta.c @@ -646,8 +646,16 @@ int flecs_init_type( * serializers on uninitialized values. For runtime types (rtt), the default hooks are set by flecs_meta_rtt_init_default_hooks */ ecs_type_info_t *ti = flecs_type_info_ensure(world, type); - if (meta_type->existing && !ti->hooks.ctor) { - ti->hooks.ctor = flecs_default_ctor; + if (meta_type->existing) { + if(!ti->hooks.ctor) { + ti->hooks.ctor = flecs_default_ctor; + } + if(kind == EcsEnumType) { + ti->hooks.cmp = ecs_compare_i32; + ti->hooks.equals = ecs_equals_i32; + ti->hooks.flags &= ~(ECS_TYPE_HOOK_CMP_ILLEGAL|ECS_TYPE_HOOK_EQUALS_ILLEGAL); + ti->hooks.flags |= ECS_TYPE_HOOK_CMP|ECS_TYPE_HOOK_EQUALS; + } } } else { if (meta_type->kind != kind) { diff --git a/test/cpp/project.json b/test/cpp/project.json index 0c9bb867a..a569010b6 100644 --- a/test/cpp/project.json +++ b/test/cpp/project.json @@ -1060,7 +1060,8 @@ "compare_WithEqualsAndGreaterThan", "compare_WithEqualsAndLessThan", "compare_WithEqualsOnly", - "compare_WithoutOperators" + "compare_WithoutOperators", + "compare_Enum" ] }, { "id": "Refs", diff --git a/test/cpp/src/ComponentLifecycle.cpp b/test/cpp/src/ComponentLifecycle.cpp index 5bc9053e9..e84d41b4d 100644 --- a/test/cpp/src/ComponentLifecycle.cpp +++ b/test/cpp/src/ComponentLifecycle.cpp @@ -2604,3 +2604,32 @@ void ComponentLifecycle_compare_WithoutOperators(void) { test_assert(compare(ecs, component, &b, &b) == 0); } + +enum TestColorEnum { + Red = 1, + Yellow = 2, + Blue = 3 +}; + +void ComponentLifecycle_compare_Enum(void) { + + flecs::world ecs; + + auto component = ecs.component(); + + const ecs_type_hooks_t* hooks = ecs_get_hooks_id(ecs, component); + + test_assert(!(hooks->flags & ECS_TYPE_HOOK_CMP_ILLEGAL)); + test_assert(!(hooks->flags & ECS_TYPE_HOOK_EQUALS_ILLEGAL)); + + TestColorEnum a = TestColorEnum::Red; + TestColorEnum b = TestColorEnum::Yellow; + TestColorEnum c = TestColorEnum::Red; + + test_assert(compare(ecs, component, &a, &b) < 0); + test_assert(compare(ecs, component, &b, &a) > 0); + test_assert(compare(ecs, component, &a, &c) == 0); + test_assert(compare(ecs, component, &b, &c) > 0); + test_assert(compare(ecs, component, &c, &b) < 0); + test_assert(compare(ecs, component, &b, &b) == 0); +} diff --git a/test/cpp/src/main.cpp b/test/cpp/src/main.cpp index 4bbdbcb81..78107acf5 100644 --- a/test/cpp/src/main.cpp +++ b/test/cpp/src/main.cpp @@ -1026,6 +1026,7 @@ void ComponentLifecycle_compare_WithEqualsAndGreaterThan(void); void ComponentLifecycle_compare_WithEqualsAndLessThan(void); void ComponentLifecycle_compare_WithEqualsOnly(void); void ComponentLifecycle_compare_WithoutOperators(void); +void ComponentLifecycle_compare_Enum(void); // Testsuite 'Refs' void Refs_get_ref_by_ptr(void); @@ -5411,6 +5412,10 @@ bake_test_case ComponentLifecycle_testcases[] = { { "compare_WithoutOperators", ComponentLifecycle_compare_WithoutOperators + }, + { + "compare_Enum", + ComponentLifecycle_compare_Enum } }; @@ -7003,7 +7008,7 @@ static bake_test_suite suites[] = { "ComponentLifecycle", NULL, NULL, - 96, + 97, ComponentLifecycle_testcases }, {