From a13cbd06d2db542ab2874d45428ef8b3e1b98780 Mon Sep 17 00:00:00 2001 From: Sander Mertens Date: Thu, 11 May 2023 11:41:36 -0700 Subject: [PATCH] Free system/observer ctx/binding_ctx before updating it --- flecs.c | 48 ++++++++++++++++++++++-- src/addons/system/system.c | 18 +++++++++ src/observer.c | 30 +++++++++++++-- test/addons/project.json | 1 + test/addons/src/SystemMisc.c | 69 +++++++++++++++++++++++++++++++++++ test/addons/src/main.c | 7 +++- test/api/project.json | 1 + test/api/src/Observer.c | 71 ++++++++++++++++++++++++++++++++++++ test/api/src/main.c | 7 +++- 9 files changed, 242 insertions(+), 10 deletions(-) diff --git a/flecs.c b/flecs.c index baeffdf8d..60e933102 100644 --- a/flecs.c +++ b/flecs.c @@ -31387,12 +31387,30 @@ ecs_entity_t ecs_system_init( if (desc->callback) { system->action = desc->callback; } + + if (system->ctx_free) { + if (system->ctx && system->ctx != desc->ctx) { + system->ctx_free(system->ctx); + } + } + if (system->binding_ctx_free) { + if (system->binding_ctx && system->binding_ctx != desc->binding_ctx) { + system->binding_ctx_free(system->binding_ctx); + } + } + if (desc->ctx) { system->ctx = desc->ctx; } if (desc->binding_ctx) { system->binding_ctx = desc->binding_ctx; } + if (desc->ctx_free) { + system->ctx_free = desc->ctx_free; + } + if (desc->binding_ctx_free) { + system->binding_ctx_free = desc->binding_ctx_free; + } if (desc->query.filter.instanced) { ECS_BIT_SET(system->query->filter.flags, EcsFilterIsInstanced); } @@ -52217,15 +52235,37 @@ ecs_entity_t ecs_observer_init( ecs_get_name(world, entity)); } } else { - /* If existing entity handle was provided, override existing params */ + ecs_observer_t *observer = ecs_poly(poly->poly, ecs_observer_t); + + if (desc->run) { + observer->run = desc->run; + } if (desc->callback) { - ecs_poly(poly->poly, ecs_observer_t)->callback = desc->callback; + observer->callback = desc->callback; } + + if (observer->ctx_free) { + if (observer->ctx && observer->ctx != desc->ctx) { + observer->ctx_free(observer->ctx); + } + } + if (observer->binding_ctx_free) { + if (observer->binding_ctx && observer->binding_ctx != desc->binding_ctx) { + observer->binding_ctx_free(observer->binding_ctx); + } + } + if (desc->ctx) { - ecs_poly(poly->poly, ecs_observer_t)->ctx = desc->ctx; + observer->ctx = desc->ctx; } if (desc->binding_ctx) { - ecs_poly(poly->poly, ecs_observer_t)->binding_ctx = desc->binding_ctx; + observer->binding_ctx = desc->binding_ctx; + } + if (desc->ctx_free) { + observer->ctx_free = desc->ctx_free; + } + if (desc->binding_ctx_free) { + observer->binding_ctx_free = desc->binding_ctx_free; } } diff --git a/src/addons/system/system.c b/src/addons/system/system.c index d8f071c58..b2e3fc2c9 100644 --- a/src/addons/system/system.c +++ b/src/addons/system/system.c @@ -314,12 +314,30 @@ ecs_entity_t ecs_system_init( if (desc->callback) { system->action = desc->callback; } + + if (system->ctx_free) { + if (system->ctx && system->ctx != desc->ctx) { + system->ctx_free(system->ctx); + } + } + if (system->binding_ctx_free) { + if (system->binding_ctx && system->binding_ctx != desc->binding_ctx) { + system->binding_ctx_free(system->binding_ctx); + } + } + if (desc->ctx) { system->ctx = desc->ctx; } if (desc->binding_ctx) { system->binding_ctx = desc->binding_ctx; } + if (desc->ctx_free) { + system->ctx_free = desc->ctx_free; + } + if (desc->binding_ctx_free) { + system->binding_ctx_free = desc->binding_ctx_free; + } if (desc->query.filter.instanced) { ECS_BIT_SET(system->query->filter.flags, EcsFilterIsInstanced); } diff --git a/src/observer.c b/src/observer.c index afeeb298a..b3d3124bd 100644 --- a/src/observer.c +++ b/src/observer.c @@ -907,15 +907,37 @@ ecs_entity_t ecs_observer_init( ecs_get_name(world, entity)); } } else { - /* If existing entity handle was provided, override existing params */ + ecs_observer_t *observer = ecs_poly(poly->poly, ecs_observer_t); + + if (desc->run) { + observer->run = desc->run; + } if (desc->callback) { - ecs_poly(poly->poly, ecs_observer_t)->callback = desc->callback; + observer->callback = desc->callback; + } + + if (observer->ctx_free) { + if (observer->ctx && observer->ctx != desc->ctx) { + observer->ctx_free(observer->ctx); + } } + if (observer->binding_ctx_free) { + if (observer->binding_ctx && observer->binding_ctx != desc->binding_ctx) { + observer->binding_ctx_free(observer->binding_ctx); + } + } + if (desc->ctx) { - ecs_poly(poly->poly, ecs_observer_t)->ctx = desc->ctx; + observer->ctx = desc->ctx; } if (desc->binding_ctx) { - ecs_poly(poly->poly, ecs_observer_t)->binding_ctx = desc->binding_ctx; + observer->binding_ctx = desc->binding_ctx; + } + if (desc->ctx_free) { + observer->ctx_free = desc->ctx_free; + } + if (desc->binding_ctx_free) { + observer->binding_ctx_free = desc->binding_ctx_free; } } diff --git a/test/addons/project.json b/test/addons/project.json index d781dfa5e..d87536f4d 100644 --- a/test/addons/project.json +++ b/test/addons/project.json @@ -595,6 +595,7 @@ "delete_system", "delete_pipeline_system", "delete_system_w_ctx", + "update_ctx", "run_custom_run_action", "run_w_offset_limit_custom_run_action", "pipeline_custom_run_action", diff --git a/test/addons/src/SystemMisc.c b/test/addons/src/SystemMisc.c index 6522b0afc..fc878c2aa 100644 --- a/test/addons/src/SystemMisc.c +++ b/test/addons/src/SystemMisc.c @@ -1312,6 +1312,20 @@ void binding_ctx_free(void *ctx) { binding_ctx_value ++; } +static int ctx_value_2; +static +void ctx_free_2(void *ctx) { + test_assert(&ctx_value_2 == ctx); + ctx_value_2 ++; +} + +static int binding_ctx_value_2; +static +void binding_ctx_free_2(void *ctx) { + test_assert(&binding_ctx_value_2 == ctx); + binding_ctx_value_2 ++; +} + void SystemMisc_delete_system_w_ctx() { ecs_world_t *world = ecs_init(); @@ -1347,6 +1361,61 @@ void SystemMisc_delete_system_w_ctx() { ecs_fini(world); } +void SystemMisc_update_ctx() { + ecs_world_t *world = ecs_init(); + + ECS_TAG(world, Tag); + + ecs_entity_t system = ecs_system_init(world, &(ecs_system_desc_t){ + .query.filter.terms = {{.id = Tag}}, + .callback = Dummy, + .ctx = &ctx_value, + .ctx_free = ctx_free, + .binding_ctx = &binding_ctx_value, + .binding_ctx_free = binding_ctx_free + }); + test_assert(system != 0); + + test_assert(ecs_get_system_ctx(world, system) == &ctx_value); + test_assert(ecs_get_system_binding_ctx(world, system) + == &binding_ctx_value); + + ecs_system(world, { + .entity = system, + .ctx = &ctx_value, + .ctx_free = ctx_free, + .binding_ctx = &binding_ctx_value, + .binding_ctx_free = binding_ctx_free + }); + + test_int(ctx_value, 0); + test_int(binding_ctx_value, 0); + test_int(ctx_value_2, 0); + test_int(binding_ctx_value_2, 0); + + ecs_system(world, { + .entity = system, + .ctx = &ctx_value_2, + .ctx_free = ctx_free_2, + .binding_ctx = &binding_ctx_value_2, + .binding_ctx_free = binding_ctx_free_2 + }); + + test_int(ctx_value, 1); + test_int(binding_ctx_value, 1); + test_int(ctx_value_2, 0); + test_int(binding_ctx_value_2, 0); + + ecs_delete(world, system); + + test_int(ctx_value, 1); + test_int(binding_ctx_value, 1); + test_int(ctx_value_2, 1); + test_int(binding_ctx_value_2, 1); + + ecs_fini(world); +} + static int run_invoked = 0; static void Run(ecs_iter_t *it) { diff --git a/test/addons/src/main.c b/test/addons/src/main.c index 5a18bf71c..d6ea9d735 100644 --- a/test/addons/src/main.c +++ b/test/addons/src/main.c @@ -582,6 +582,7 @@ void SystemMisc_deactivate_after_disable(void); void SystemMisc_delete_system(void); void SystemMisc_delete_pipeline_system(void); void SystemMisc_delete_system_w_ctx(void); +void SystemMisc_update_ctx(void); void SystemMisc_run_custom_run_action(void); void SystemMisc_run_w_offset_limit_custom_run_action(void); void SystemMisc_pipeline_custom_run_action(void); @@ -3639,6 +3640,10 @@ bake_test_case SystemMisc_testcases[] = { "delete_system_w_ctx", SystemMisc_delete_system_w_ctx }, + { + "update_ctx", + SystemMisc_update_ctx + }, { "run_custom_run_action", SystemMisc_run_custom_run_action @@ -6652,7 +6657,7 @@ static bake_test_suite suites[] = { "SystemMisc", NULL, NULL, - 62, + 63, SystemMisc_testcases }, { diff --git a/test/api/project.json b/test/api/project.json index 9077013d8..5d0178b1d 100644 --- a/test/api/project.json +++ b/test/api/project.json @@ -1927,6 +1927,7 @@ "add_after_delete_observer", "remove_after_delete_observer", "delete_observer_w_ctx", + "update_ctx", "filter_w_strings", "iter_type_set", "readonly_term", diff --git a/test/api/src/Observer.c b/test/api/src/Observer.c index 6cad13939..b0a0a93aa 100644 --- a/test/api/src/Observer.c +++ b/test/api/src/Observer.c @@ -1239,6 +1239,20 @@ void binding_ctx_free(void *ctx) { binding_ctx_value ++; } +static int ctx_value_2; +static +void ctx_free_2(void *ctx) { + test_assert(&ctx_value_2 == ctx); + ctx_value_2 ++; +} + +static int binding_ctx_value_2; +static +void binding_ctx_free_2(void *ctx) { + test_assert(&binding_ctx_value_2 == ctx); + binding_ctx_value_2 ++; +} + void Observer_delete_observer_w_ctx() { ecs_world_t *world = ecs_mini(); @@ -1266,6 +1280,62 @@ void Observer_delete_observer_w_ctx() { ecs_fini(world); } +void Observer_update_ctx() { + ecs_world_t *world = ecs_init(); + + ECS_TAG(world, Tag); + + ecs_entity_t system = ecs_observer(world, { + .filter.terms = {{.id = Tag}}, + .callback = Dummy, + .events = {EcsOnAdd}, + .ctx = &ctx_value, + .ctx_free = ctx_free, + .binding_ctx = &binding_ctx_value, + .binding_ctx_free = binding_ctx_free + }); + test_assert(system != 0); + + test_assert(ecs_get_observer_ctx(world, system) == &ctx_value); + test_assert(ecs_get_observer_binding_ctx(world, system) + == &binding_ctx_value); + + ecs_observer(world, { + .entity = system, + .ctx = &ctx_value, + .ctx_free = ctx_free, + .binding_ctx = &binding_ctx_value, + .binding_ctx_free = binding_ctx_free + }); + + test_int(ctx_value, 0); + test_int(binding_ctx_value, 0); + test_int(ctx_value_2, 0); + test_int(binding_ctx_value_2, 0); + + ecs_observer(world, { + .entity = system, + .ctx = &ctx_value_2, + .ctx_free = ctx_free_2, + .binding_ctx = &binding_ctx_value_2, + .binding_ctx_free = binding_ctx_free_2 + }); + + test_int(ctx_value, 1); + test_int(binding_ctx_value, 1); + test_int(ctx_value_2, 0); + test_int(binding_ctx_value_2, 0); + + ecs_delete(world, system); + + test_int(ctx_value, 1); + test_int(binding_ctx_value, 1); + test_int(ctx_value_2, 1); + test_int(binding_ctx_value_2, 1); + + ecs_fini(world); +} + void Observer_filter_w_strings() { ecs_world_t *world = ecs_mini(); @@ -4735,3 +4805,4 @@ void Observer_notify_after_defer_batched_2_entities_in_table_w_tgt() { ecs_fini(world); } + diff --git a/test/api/src/main.c b/test/api/src/main.c index 515c0909a..fb0b75c49 100644 --- a/test/api/src/main.c +++ b/test/api/src/main.c @@ -1856,6 +1856,7 @@ void Observer_2_terms_on_remove_on_delete(void); void Observer_add_after_delete_observer(void); void Observer_remove_after_delete_observer(void); void Observer_delete_observer_w_ctx(void); +void Observer_update_ctx(void); void Observer_filter_w_strings(void); void Observer_iter_type_set(void); void Observer_readonly_term(void); @@ -9739,6 +9740,10 @@ bake_test_case Observer_testcases[] = { "delete_observer_w_ctx", Observer_delete_observer_w_ctx }, + { + "update_ctx", + Observer_update_ctx + }, { "filter_w_strings", Observer_filter_w_strings @@ -12609,7 +12614,7 @@ static bake_test_suite suites[] = { "Observer", NULL, NULL, - 109, + 110, Observer_testcases }, {