Skip to content

Commit

Permalink
Add yield_existing flags for customizing observer create/delete behavior
Browse files Browse the repository at this point in the history
  • Loading branch information
SanderMertens committed Sep 26, 2024
1 parent f6201fa commit 3986f4e
Show file tree
Hide file tree
Showing 7 changed files with 185 additions and 11 deletions.
11 changes: 7 additions & 4 deletions distr/flecs.c
Original file line number Diff line number Diff line change
Expand Up @@ -14977,7 +14977,10 @@ ecs_observer_t* flecs_observer_init(
impl->term_index = desc->term_index_;
impl->flags = desc->flags_;

bool yield_on_create = false;
ecs_check(!(desc->yield_existing &&
(desc->flags_ & (EcsObserverYieldOnCreate|EcsObserverYieldOnDelete))),
ECS_INVALID_PARAMETER,
"cannot set yield_existing and YieldOn* flags at the same time");

/* Check if observer is monitor. Monitors are created as multi observers
* since they require pre/post checking of the filter to test if the
Expand All @@ -14998,16 +15001,16 @@ ecs_observer_t* flecs_observer_init(
o->event_count ++;
impl->flags |= EcsObserverIsMonitor;
if (desc->yield_existing) {
impl->flags |= EcsObserverYieldOnCreate;
impl->flags |= EcsObserverYieldOnDelete;
yield_on_create = true;
}
} else {
o->events[i] = event;
if (desc->yield_existing) {
if (event == EcsOnRemove) {
impl->flags |= EcsObserverYieldOnDelete;
} else {
yield_on_create = true;
impl->flags |= EcsObserverYieldOnCreate;
}
}
}
Expand Down Expand Up @@ -15043,7 +15046,7 @@ ecs_observer_t* flecs_observer_init(
}
}

if (yield_on_create) {
if (impl->flags & EcsObserverYieldOnCreate) {
flecs_observer_yield_existing(world, o, false);
}

Expand Down
5 changes: 4 additions & 1 deletion distr/flecs.h
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,7 @@ extern "C" {
#define EcsQueryHasTableThisVar (1u << 26u) /* Does query have $this table var */
#define EcsQueryCacheYieldEmptyTables (1u << 27u) /* Does query cache empty tables */


////////////////////////////////////////////////////////////////////////////////
//// Term flags (used by ecs_term_t::flags_)
////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -511,7 +512,9 @@ extern "C" {
#define EcsObserverIsDisabled (1u << 3u) /* Is observer entity disabled */
#define EcsObserverIsParentDisabled (1u << 4u) /* Is module parent of observer disabled */
#define EcsObserverBypassQuery (1u << 5u) /* Don't evaluate query for multi-component observer*/
#define EcsObserverYieldOnDelete (1u << 6u) /* Yield matching entities when deleting observer */
#define EcsObserverYieldOnCreate (1u << 6u) /* Yield matching entities when creating observer */
#define EcsObserverYieldOnDelete (1u << 7u) /* Yield matching entities when deleting observer */


////////////////////////////////////////////////////////////////////////////////
//// Table flags (used by ecs_table_t::flags)
Expand Down
5 changes: 4 additions & 1 deletion include/flecs/private/api_flags.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ extern "C" {
#define EcsQueryHasTableThisVar (1u << 26u) /* Does query have $this table var */
#define EcsQueryCacheYieldEmptyTables (1u << 27u) /* Does query cache empty tables */


////////////////////////////////////////////////////////////////////////////////
//// Term flags (used by ecs_term_t::flags_)
////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -189,7 +190,9 @@ extern "C" {
#define EcsObserverIsDisabled (1u << 3u) /* Is observer entity disabled */
#define EcsObserverIsParentDisabled (1u << 4u) /* Is module parent of observer disabled */
#define EcsObserverBypassQuery (1u << 5u) /* Don't evaluate query for multi-component observer*/
#define EcsObserverYieldOnDelete (1u << 6u) /* Yield matching entities when deleting observer */
#define EcsObserverYieldOnCreate (1u << 6u) /* Yield matching entities when creating observer */
#define EcsObserverYieldOnDelete (1u << 7u) /* Yield matching entities when deleting observer */


////////////////////////////////////////////////////////////////////////////////
//// Table flags (used by ecs_table_t::flags)
Expand Down
11 changes: 7 additions & 4 deletions src/observer.c
Original file line number Diff line number Diff line change
Expand Up @@ -961,7 +961,10 @@ ecs_observer_t* flecs_observer_init(
impl->term_index = desc->term_index_;
impl->flags = desc->flags_;

bool yield_on_create = false;
ecs_check(!(desc->yield_existing &&
(desc->flags_ & (EcsObserverYieldOnCreate|EcsObserverYieldOnDelete))),
ECS_INVALID_PARAMETER,
"cannot set yield_existing and YieldOn* flags at the same time");

/* Check if observer is monitor. Monitors are created as multi observers
* since they require pre/post checking of the filter to test if the
Expand All @@ -982,16 +985,16 @@ ecs_observer_t* flecs_observer_init(
o->event_count ++;
impl->flags |= EcsObserverIsMonitor;
if (desc->yield_existing) {
impl->flags |= EcsObserverYieldOnCreate;
impl->flags |= EcsObserverYieldOnDelete;
yield_on_create = true;
}
} else {
o->events[i] = event;
if (desc->yield_existing) {
if (event == EcsOnRemove) {
impl->flags |= EcsObserverYieldOnDelete;
} else {
yield_on_create = true;
impl->flags |= EcsObserverYieldOnCreate;
}
}
}
Expand Down Expand Up @@ -1027,7 +1030,7 @@ ecs_observer_t* flecs_observer_init(
}
}

if (yield_on_create) {
if (impl->flags & EcsObserverYieldOnCreate) {
flecs_observer_yield_existing(world, o, false);
}

Expand Down
3 changes: 3 additions & 0 deletions test/core/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -1531,6 +1531,9 @@
"on_remove_yield_existing_wildcard_multi",
"on_remove_yield_existing_wildcard_multi_w_wildcard_pivot",
"on_add_remove_yield_existing",
"on_add_remove_yield_existing_flags",
"on_add_remove_no_on_add_yield_existing",
"on_add_remove_no_on_remove_yield_existing",
"observer_superset_wildcard",
"observer_superset_wildcard_add_isa",
"observer_superset_wildcard_add_isa_at_offset",
Expand Down
144 changes: 144 additions & 0 deletions test/core/src/Observer.c
Original file line number Diff line number Diff line change
Expand Up @@ -4187,6 +4187,150 @@ void Observer_on_add_remove_yield_existing(void) {
ecs_fini(world);
}

void Observer_on_add_remove_yield_existing_flags(void) {
ecs_world_t *world = ecs_mini();

ECS_TAG(world, Tag);

/* Create entities before trigger */
ecs_entity_t e1 = ecs_new_w(world, Tag);
ecs_entity_t e2 = ecs_new_w(world, Tag);
ecs_entity_t e3 = ecs_new_w(world, Tag);

test_assert(e1 != 0);
test_assert(e2 != 0);
test_assert(e3 != 0);

Probe ctx = {0};
ecs_entity_t t = ecs_observer_init(world, &(ecs_observer_desc_t){
.query.terms = {{ Tag }},
.events = {EcsOnAdd, EcsOnRemove},
.callback = Observer,
.ctx = &ctx,
.flags_ = EcsObserverYieldOnCreate|EcsObserverYieldOnDelete
});

test_int(ctx.invoked, 1);
test_int(ctx.count, 3);
test_int(ctx.system, t);
test_int(ctx.event, EcsOnAdd);
test_int(ctx.event_id, Tag);
test_int(ctx.term_count, 1);
test_null(ctx.param);

test_int(ctx.e[0], e1);
test_int(ctx.e[1], e2);
test_int(ctx.e[2], e3);
test_int(ctx.c[0][0], Tag);

ecs_os_zeromem(&ctx);

ecs_delete(world, t);

test_int(ctx.invoked, 1);
test_int(ctx.count, 3);
test_int(ctx.system, t);
test_int(ctx.event, EcsOnRemove);
test_int(ctx.event_id, Tag);
test_int(ctx.term_count, 1);
test_null(ctx.param);

test_int(ctx.e[0], e1);
test_int(ctx.e[1], e2);
test_int(ctx.e[2], e3);
test_int(ctx.c[0][0], Tag);

ecs_fini(world);
}

void Observer_on_add_remove_no_on_add_yield_existing(void) {
ecs_world_t *world = ecs_mini();

ECS_TAG(world, Tag);

/* Create entities before trigger */
ecs_entity_t e1 = ecs_new_w(world, Tag);
ecs_entity_t e2 = ecs_new_w(world, Tag);
ecs_entity_t e3 = ecs_new_w(world, Tag);

test_assert(e1 != 0);
test_assert(e2 != 0);
test_assert(e3 != 0);

Probe ctx = {0};
ecs_entity_t t = ecs_observer_init(world, &(ecs_observer_desc_t){
.query.terms = {{ Tag }},
.events = {EcsOnAdd, EcsOnRemove},
.callback = Observer,
.ctx = &ctx,
.flags_ = EcsObserverYieldOnDelete
});

test_int(ctx.invoked, 0);

ecs_delete(world, t);

test_int(ctx.invoked, 1);
test_int(ctx.count, 3);
test_int(ctx.system, t);
test_int(ctx.event, EcsOnRemove);
test_int(ctx.event_id, Tag);
test_int(ctx.term_count, 1);
test_null(ctx.param);

test_int(ctx.e[0], e1);
test_int(ctx.e[1], e2);
test_int(ctx.e[2], e3);
test_int(ctx.c[0][0], Tag);

ecs_fini(world);
}

void Observer_on_add_remove_no_on_remove_yield_existing(void) {
ecs_world_t *world = ecs_mini();

ECS_TAG(world, Tag);

/* Create entities before trigger */
ecs_entity_t e1 = ecs_new_w(world, Tag);
ecs_entity_t e2 = ecs_new_w(world, Tag);
ecs_entity_t e3 = ecs_new_w(world, Tag);

test_assert(e1 != 0);
test_assert(e2 != 0);
test_assert(e3 != 0);

Probe ctx = {0};
ecs_entity_t t = ecs_observer_init(world, &(ecs_observer_desc_t){
.query.terms = {{ Tag }},
.events = {EcsOnAdd, EcsOnRemove},
.callback = Observer,
.ctx = &ctx,
.flags_ = EcsObserverYieldOnCreate
});

test_int(ctx.invoked, 1);
test_int(ctx.count, 3);
test_int(ctx.system, t);
test_int(ctx.event, EcsOnAdd);
test_int(ctx.event_id, Tag);
test_int(ctx.term_count, 1);
test_null(ctx.param);

test_int(ctx.e[0], e1);
test_int(ctx.e[1], e2);
test_int(ctx.e[2], e3);
test_int(ctx.c[0][0], Tag);

ecs_os_zeromem(&ctx);

ecs_delete(world, t);

test_int(ctx.invoked, 0);

ecs_fini(world);
}

void Observer_observer_superset_wildcard(void) {
ecs_world_t *world = ecs_mini();

Expand Down
17 changes: 16 additions & 1 deletion test/core/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1470,6 +1470,9 @@ void Observer_on_remove_yield_existing_wildcard(void);
void Observer_on_remove_yield_existing_wildcard_multi(void);
void Observer_on_remove_yield_existing_wildcard_multi_w_wildcard_pivot(void);
void Observer_on_add_remove_yield_existing(void);
void Observer_on_add_remove_yield_existing_flags(void);
void Observer_on_add_remove_no_on_add_yield_existing(void);
void Observer_on_add_remove_no_on_remove_yield_existing(void);
void Observer_observer_superset_wildcard(void);
void Observer_observer_superset_wildcard_add_isa(void);
void Observer_observer_superset_wildcard_add_isa_at_offset(void);
Expand Down Expand Up @@ -7934,6 +7937,18 @@ bake_test_case Observer_testcases[] = {
"on_add_remove_yield_existing",
Observer_on_add_remove_yield_existing
},
{
"on_add_remove_yield_existing_flags",
Observer_on_add_remove_yield_existing_flags
},
{
"on_add_remove_no_on_add_yield_existing",
Observer_on_add_remove_no_on_add_yield_existing
},
{
"on_add_remove_no_on_remove_yield_existing",
Observer_on_add_remove_no_on_remove_yield_existing
},
{
"observer_superset_wildcard",
Observer_observer_superset_wildcard
Expand Down Expand Up @@ -11165,7 +11180,7 @@ static bake_test_suite suites[] = {
"Observer",
NULL,
NULL,
216,
219,
Observer_testcases
},
{
Expand Down

0 comments on commit 3986f4e

Please sign in to comment.