diff --git a/flecs.c b/flecs.c index 07aa38f202..1bfb810ddc 100644 --- a/flecs.c +++ b/flecs.c @@ -649,6 +649,7 @@ typedef enum ecs_defer_op_kind_t { EcsOpAdd, EcsOpRemove, EcsOpSet, + EcsOpEmplace, EcsOpMut, EcsOpModified, EcsOpDelete, @@ -1618,7 +1619,8 @@ bool flecs_defer_set( ecs_entity_t component, ecs_size_t size, const void *value, - void **value_out); + void **value_out, + bool emplace); bool flecs_defer_end( ecs_world_t *world, @@ -8138,7 +8140,7 @@ void* ecs_get_mut_id( void *result; if (flecs_defer_set( - world, stage, EcsOpMut, entity, id, 0, NULL, &result)) + world, stage, EcsOpMut, entity, id, 0, NULL, &result, false)) { return result; } @@ -8324,7 +8326,9 @@ void* ecs_emplace_id( ecs_stage_t *stage = flecs_stage_from_world(&world); void *result; - if (flecs_defer_set(world, stage, EcsOpMut, entity, id, 0, NULL, &result)) { + if (flecs_defer_set(world, stage, EcsOpEmplace, entity, id, 0, NULL, + &result, true)) + { return result; } @@ -8394,7 +8398,7 @@ ecs_entity_t set_ptr_w_id( } if (flecs_defer_set(world, stage, EcsOpSet, entity, id, - flecs_utosize(size), ptr, NULL)) + flecs_utosize(size), ptr, NULL, false)) { return entity; } @@ -9510,6 +9514,12 @@ bool flecs_defer_end( op->id, flecs_itosize(op->is._1.size), op->is._1.value, true, true); break; + case EcsOpEmplace: + ecs_emplace_id(world, e, op->id); + set_ptr_w_id(world, e, + op->id, flecs_itosize(op->is._1.size), + op->is._1.value, true, false); + break; case EcsOpMut: set_ptr_w_id(world, e, op->id, flecs_itosize(op->is._1.size), @@ -9903,7 +9913,8 @@ bool flecs_defer_set( ecs_id_t id, ecs_size_t size, const void *value, - void **value_out) + void **value_out, + bool emplace) { if (flecs_defer_op(world, stage)) { world->info.set_count ++; @@ -9960,7 +9971,7 @@ bool flecs_defer_set( } else { ecs_os_memcpy(op->is._1.value, value, size); } - } else { + } else if (!emplace) { ecs_xtor_t ctor; if ((ctor = ti->hooks.ctor)) { ctor(op->is._1.value, 1, ti); diff --git a/flecs.h b/flecs.h index 148c19aec1..af2e74d584 100644 --- a/flecs.h +++ b/flecs.h @@ -17,7 +17,7 @@ /* Customizable precision for floating point operations (such as time ops) */ #ifndef ecs_float_t -#define ecs_float_t int +#define ecs_float_t float #endif /* Customizable precision for time scalar values */ diff --git a/src/entity.c b/src/entity.c index 3238c3ba14..7c8022b487 100644 --- a/src/entity.c +++ b/src/entity.c @@ -2911,7 +2911,7 @@ void* ecs_get_mut_id( void *result; if (flecs_defer_set( - world, stage, EcsOpMut, entity, id, 0, NULL, &result)) + world, stage, EcsOpMut, entity, id, 0, NULL, &result, false)) { return result; } @@ -3097,7 +3097,9 @@ void* ecs_emplace_id( ecs_stage_t *stage = flecs_stage_from_world(&world); void *result; - if (flecs_defer_set(world, stage, EcsOpMut, entity, id, 0, NULL, &result)) { + if (flecs_defer_set(world, stage, EcsOpEmplace, entity, id, 0, NULL, + &result, true)) + { return result; } @@ -3167,7 +3169,7 @@ ecs_entity_t set_ptr_w_id( } if (flecs_defer_set(world, stage, EcsOpSet, entity, id, - flecs_utosize(size), ptr, NULL)) + flecs_utosize(size), ptr, NULL, false)) { return entity; } @@ -4283,6 +4285,12 @@ bool flecs_defer_end( op->id, flecs_itosize(op->is._1.size), op->is._1.value, true, true); break; + case EcsOpEmplace: + ecs_emplace_id(world, e, op->id); + set_ptr_w_id(world, e, + op->id, flecs_itosize(op->is._1.size), + op->is._1.value, true, false); + break; case EcsOpMut: set_ptr_w_id(world, e, op->id, flecs_itosize(op->is._1.size), diff --git a/src/private_types.h b/src/private_types.h index 21b3b1e37e..6878d37343 100644 --- a/src/private_types.h +++ b/src/private_types.h @@ -369,6 +369,7 @@ typedef enum ecs_defer_op_kind_t { EcsOpAdd, EcsOpRemove, EcsOpSet, + EcsOpEmplace, EcsOpMut, EcsOpModified, EcsOpDelete, diff --git a/src/stage.c b/src/stage.c index 9dcdc9af2f..714f5b976b 100644 --- a/src/stage.c +++ b/src/stage.c @@ -299,7 +299,8 @@ bool flecs_defer_set( ecs_id_t id, ecs_size_t size, const void *value, - void **value_out) + void **value_out, + bool emplace) { if (flecs_defer_op(world, stage)) { world->info.set_count ++; @@ -356,7 +357,7 @@ bool flecs_defer_set( } else { ecs_os_memcpy(op->is._1.value, value, size); } - } else { + } else if (!emplace) { ecs_xtor_t ctor; if ((ctor = ti->hooks.ctor)) { ctor(op->is._1.value, 1, ti); diff --git a/src/stage.h b/src/stage.h index 690341b0af..224f51767d 100644 --- a/src/stage.h +++ b/src/stage.h @@ -94,7 +94,8 @@ bool flecs_defer_set( ecs_entity_t component, ecs_size_t size, const void *value, - void **value_out); + void **value_out, + bool emplace); bool flecs_defer_end( ecs_world_t *world, diff --git a/test/api/project.json b/test/api/project.json index 085406ce31..bc7a68c79e 100644 --- a/test/api/project.json +++ b/test/api/project.json @@ -815,6 +815,7 @@ "set_lifecycle_after_trigger", "valid_entity_in_dtor_after_delete", "ctor_w_emplace", + "ctor_w_emplace_defer", "dtor_on_fini", "valid_type_in_dtor_on_fini", "valid_other_type_of_entity_in_dtor_on_fini", diff --git a/test/api/src/ComponentLifecycle.c b/test/api/src/ComponentLifecycle.c index 421fad810d..94ed454fc0 100644 --- a/test/api/src/ComponentLifecycle.c +++ b/test/api/src/ComponentLifecycle.c @@ -1293,6 +1293,40 @@ void ComponentLifecycle_ctor_w_emplace() { ecs_fini(world); } +void ComponentLifecycle_ctor_w_emplace_defer() { + ecs_world_t* world = ecs_mini(); + + ECS_COMPONENT(world, Position); + + ecs_set_hooks(world, Position, { + .ctor = ecs_ctor(Position) + }); + + test_int(ctor_position, 0); + + ecs_entity_t e = ecs_new_id(world); + test_assert(e != 0); + + ecs_defer_begin(world); + Position *ptr = ecs_emplace(world, e, Position); + test_assert(ptr != NULL); + test_int(ctor_position, 0); + ptr->x = 10; + ptr->y = 20; + test_assert(!ecs_has(world, e, Position)); + test_int(ctor_position, 0); + ecs_defer_end(world); + + test_assert(ecs_has(world, e, Position)); + test_int(ctor_position, 0); + const Position *p = ecs_get(world, e, Position); + test_assert(p != NULL); + test_int(p->x, 10); + test_int(p->y, 20); + + ecs_fini(world); +} + void ComponentLifecycle_dtor_on_fini() { ecs_world_t *world = ecs_mini(); diff --git a/test/api/src/main.c b/test/api/src/main.c index 4e8e728ad0..3a673188c1 100644 --- a/test/api/src/main.c +++ b/test/api/src/main.c @@ -764,6 +764,7 @@ void ComponentLifecycle_allow_lifecycle_overwrite_equal_callbacks(void); void ComponentLifecycle_set_lifecycle_after_trigger(void); void ComponentLifecycle_valid_entity_in_dtor_after_delete(void); void ComponentLifecycle_ctor_w_emplace(void); +void ComponentLifecycle_ctor_w_emplace_defer(void); void ComponentLifecycle_dtor_on_fini(void); void ComponentLifecycle_valid_type_in_dtor_on_fini(void); void ComponentLifecycle_valid_other_type_of_entity_in_dtor_on_fini(void); @@ -5040,6 +5041,10 @@ bake_test_case ComponentLifecycle_testcases[] = { "ctor_w_emplace", ComponentLifecycle_ctor_w_emplace }, + { + "ctor_w_emplace_defer", + ComponentLifecycle_ctor_w_emplace_defer + }, { "dtor_on_fini", ComponentLifecycle_dtor_on_fini @@ -10644,7 +10649,7 @@ static bake_test_suite suites[] = { "ComponentLifecycle", ComponentLifecycle_setup, NULL, - 68, + 69, ComponentLifecycle_testcases }, { diff --git a/test/cpp_api/project.json b/test/cpp_api/project.json index 7333369c1c..cfd675d654 100644 --- a/test/cpp_api/project.json +++ b/test/cpp_api/project.json @@ -815,7 +815,8 @@ "on_set_hook_w_entity", "chained_hooks", "ctor_w_2_worlds", - "ctor_w_2_worlds_explicit_registration" + "ctor_w_2_worlds_explicit_registration", + "defer_emplace" ] }, { "id": "Refs", diff --git a/test/cpp_api/src/ComponentLifecycle.cpp b/test/cpp_api/src/ComponentLifecycle.cpp index 3c0b8d87b3..db736438d8 100644 --- a/test/cpp_api/src/ComponentLifecycle.cpp +++ b/test/cpp_api/src/ComponentLifecycle.cpp @@ -1273,3 +1273,29 @@ void ComponentLifecycle_ctor_w_2_worlds_explicit_registration() { test_int(Pod::ctor_invoked, 1); } } + +struct DeferEmplaceTest { + double x, y; + + DeferEmplaceTest(double x_, double y_) { + x = x_; + y = y_; + } +}; + +void ComponentLifecycle_defer_emplace() { + flecs::world ecs; + + flecs::entity e = ecs.entity(); + + ecs.defer_begin(); + e.emplace(10.0, 20.0); + test_assert(!e.has()); + ecs.defer_end(); + test_assert(e.has()); + + const DeferEmplaceTest *p = e.get(); + test_assert(p != NULL); + test_int(p->x, 10); + test_int(p->y, 20); +} diff --git a/test/cpp_api/src/main.cpp b/test/cpp_api/src/main.cpp index 1621c62d27..2c782c6f79 100644 --- a/test/cpp_api/src/main.cpp +++ b/test/cpp_api/src/main.cpp @@ -780,6 +780,7 @@ void ComponentLifecycle_on_set_hook_w_entity(void); void ComponentLifecycle_chained_hooks(void); void ComponentLifecycle_ctor_w_2_worlds(void); void ComponentLifecycle_ctor_w_2_worlds_explicit_registration(void); +void ComponentLifecycle_defer_emplace(void); // Testsuite 'Refs' void Refs_get_ref_by_ptr(void); @@ -4004,6 +4005,10 @@ bake_test_case ComponentLifecycle_testcases[] = { { "ctor_w_2_worlds_explicit_registration", ComponentLifecycle_ctor_w_2_worlds_explicit_registration + }, + { + "defer_emplace", + ComponentLifecycle_defer_emplace } }; @@ -4914,7 +4919,7 @@ static bake_test_suite suites[] = { "ComponentLifecycle", NULL, NULL, - 49, + 50, ComponentLifecycle_testcases }, {