From abc8cf2b480aa7e56fc6dee65f4412c42a2472a4 Mon Sep 17 00:00:00 2001 From: Klemen Plestenjak Date: Sun, 3 Dec 2023 08:29:00 +0100 Subject: [PATCH] Add ecs defer test --- engine/tests/CMakeLists.txt | 3 ++ engine/tests/ecs_defer_test.c | 93 +++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 engine/tests/ecs_defer_test.c diff --git a/engine/tests/CMakeLists.txt b/engine/tests/CMakeLists.txt index 58d6b16..4e7b52c 100644 --- a/engine/tests/CMakeLists.txt +++ b/engine/tests/CMakeLists.txt @@ -8,6 +8,9 @@ target_link_libraries(window_test LINK_PRIVATE Breeze) add_executable(cute_tiled_test cute_tiled_test.c) target_link_libraries(cute_tiled_test LINK_PRIVATE Breeze) +add_executable(ecs_defer_test ecs_defer_test.c) +target_link_libraries(ecs_defer_test LINK_PRIVATE Breeze) + add_executable(heap_test heap_test.c) target_link_libraries(heap_test LINK_PRIVATE Breeze) diff --git a/engine/tests/ecs_defer_test.c b/engine/tests/ecs_defer_test.c new file mode 100644 index 0000000..757b135 --- /dev/null +++ b/engine/tests/ecs_defer_test.c @@ -0,0 +1,93 @@ +#include +#include + +typedef struct Data { + int x; +} Data; + +typedef struct Test { + Data* ptr; +} Test; + +ECS_COMPONENT_DECLARE(Test); + +ECS_CTOR(Test, ptr, { + ptr->ptr = ecs_os_malloc(sizeof(Data)); + ptr->ptr->x = 0; // Default value + printf("ctor: %d\n", ptr->ptr->x); +}) +ECS_DTOR(Test, ptr, { + printf("dtor: %d\n", ptr->ptr->x); + ecs_os_free(ptr->ptr); +}) +ECS_MOVE(Test, dst, src, { + printf("move: %d->%d\n", src->ptr->x, dst->ptr->x); + dst->ptr = src->ptr; + // Clear the pointer in src since it's been moved tp dst and we + // don't want to free it when `src` ges destroyed + src->ptr = NULL; +}) + +void testRemoved(ecs_iter_t *it) { + Test *test = ecs_field(it, Test, 1); + for (int i = 0; i < it->count; i++) { + printf("on_remove: %d\n", test[i].ptr->x); + } +} +void testSet(ecs_iter_t *it) { + Test *test = ecs_field(it, Test, 1); + for (int i = 0; i < it->count; i++) { + printf("on_set: %d\n", test[i].ptr->x); + } +} + +void ecs_copy_illegal(void *dst, const void *src, int32_t c, const ecs_type_info_t *ti) { + ecs_abort(ECS_INVALID_OPERATION, "invalid copy assignment for %s", ti->name); +} + +int main(int argc, char *argv[]) { + ecs_world_t *ecs = ecs_init(); + ECS_COMPONENT_DEFINE(ecs, Test); + + ecs_set_hooks(ecs, Test, { + .ctor = ecs_ctor(Test), + .dtor = ecs_dtor(Test), + .move = ecs_move(Test), + .copy = ecs_copy_illegal, // Prevent Test from being copied so that they never share the same pointer + + .on_remove = testRemoved, + .on_set = testSet + }); + + ecs_entity_t entity = ecs_new_id(ecs); + Test* test = ecs_emplace(ecs, entity, Test); // Emplace the component, this doesn't call the ctor allowing us to initialize the data in the table directly + Data* ptr = ecs_os_malloc(sizeof(Data)); + ptr->x = 1; + test->ptr = ptr; + ecs_modified(ecs, entity, Test); // Tell the ECS that we are done with modifying the component + + // Modify the data in the component without doing any copy/move + test = ecs_get_mut(ecs, entity, Test); + test->ptr->x = 2; + ecs_modified(ecs, entity, Test); + + ecs_remove(ecs, entity, Test); // testRemoved called for {2} + + // Since the component was previously removed this will call the constructor to initialize the + // default value in the table, and then return that. + test = ecs_get_mut(ecs, entity, Test); + test->ptr->x = 3; + ecs_modified(ecs, entity, Test); + + ecs_defer_begin(ecs); + ecs_remove(ecs, entity, Test); + + test = ecs_get_mut(ecs, entity, Test); + test->ptr->x = 4; + ecs_modified(ecs, entity, Test); + + ecs_defer_end(ecs); + + ecs_fini(ecs); // testRemoved called for {4} +} +