#include typedef struct Pair { float value; } Pair; void Pairs_add_component_pair(void) { flecs::world ecs; auto entity = ecs.entity() .add(); test_assert(entity.id() != 0); test_assert((entity.has())); test_assert((!entity.has())); test_str(entity.type().str().c_str(), "(Pair,Position)"); } void Pairs_add_tag_pair(void) { flecs::world ecs; ecs.component(); auto Pair = ecs.entity("Pair"); auto entity = ecs.entity() .add_second(Pair); test_assert(entity.id() != 0); test_assert(entity.has_second(Pair)); test_assert(!entity.has(Pair)); test_str(entity.type().str().c_str(), "(Pair,Position)"); } void Pairs_add_tag_pair_to_tag(void) { flecs::world ecs; auto Tag = ecs.entity("Tag"); auto Pair = ecs.entity("Pair"); auto entity = ecs.entity() .add(Pair, Tag); test_assert(entity.id() != 0); test_assert(entity.has(Pair, Tag)); test_str(entity.type().str().c_str(), "(Pair,Tag)"); } void Pairs_remove_component_pair(void) { flecs::world ecs; ecs.component(); ecs.component(); auto entity = ecs.entity() .add(); test_assert(entity.id() != 0); test_assert((entity.has())); test_assert((!entity.has())); test_str(entity.type().str().c_str(), "(Pair,Position)"); entity.remove(); test_assert(!(entity.has())); } void Pairs_remove_tag_pair(void) { flecs::world ecs; ecs.component(); auto Pair = ecs.entity("Pair"); auto entity = ecs.entity() .add_second(Pair); test_assert(entity.id() != 0); test_assert(entity.has_second(Pair)); test_assert(!entity.has(Pair)); test_str(entity.type().str().c_str(), "(Pair,Position)"); entity.remove(Pair); test_assert(!entity.has(Pair)); } void Pairs_remove_tag_pair_to_tag(void) { flecs::world ecs; auto Tag = ecs.entity("Tag"); auto Pair = ecs.entity("Pair"); auto entity = ecs.entity() .add(Pair, Tag); test_assert(entity.id() != 0); test_assert(entity.has(Pair, Tag)); test_str(entity.type().str().c_str(), "(Pair,Tag)"); entity.remove(Tag, Pair); test_assert(!entity.has(Tag, Pair)); } void Pairs_set_component_pair(void) { flecs::world ecs; auto entity = ecs.entity() .set({10}); test_assert(entity.id() != 0); test_assert((entity.has())); test_assert((!entity.has())); test_str(entity.type().str().c_str(), "(Pair,Position)"); const Pair *t = entity.get(); test_int(t->value, 10); } void Pairs_set_tag_pair(void) { flecs::world ecs; auto Pair = ecs.entity("Pair"); auto entity = ecs.entity() .set_second(Pair, {10, 20}); test_assert(entity.id() != 0); test_assert(entity.has_second(Pair)); test_str(entity.type().str().c_str(), "(Pair,Position)"); const Position *p = entity.get_second(Pair); test_assert(p != NULL); test_int(p->x, 10); test_int(p->y, 20); } void Pairs_system_1_pair_instance(void) { flecs::world ecs; ecs.entity() .set({10}); int invoke_count = 0; int entity_count = 0; int trait_value = 0; ecs.system<>() .expr("(Pair, *)") .iter([&](flecs::iter it) { flecs::column tr(it, 1); invoke_count ++; for (auto i : it) { entity_count ++; trait_value = tr[i].value; } }); ecs.progress(); test_int(invoke_count, 1); test_int(entity_count, 1); test_int(trait_value, 10); } void Pairs_system_2_pair_instances(void) { flecs::world ecs; ecs.entity() .set({10}) .set({20}); int invoke_count = 0; int entity_count = 0; int trait_value = 0; ecs.system<>() .expr("(Pair, *)") .iter([&](flecs::iter it) { flecs::column tr(it, 1); invoke_count ++; for (auto i : it) { entity_count ++; trait_value += tr[i].value; } }); ecs.progress(); test_int(invoke_count, 2); test_int(entity_count, 2); test_int(trait_value, 30); } void Pairs_override_pair(void) { flecs::world ecs; auto base = ecs.entity() .set({10}); auto instance = ecs.entity() .add(flecs::IsA, base); test_assert((instance.has())); const Pair *t = instance.get(); test_int(t->value, 10); const Pair *t_2 = base.get(); test_assert(t == t_2); instance.add(); t = instance.get(); test_int(t->value, 10); test_assert(t != t_2); instance.remove(); t = instance.get(); test_int(t->value, 10); test_assert(t == t_2); } void Pairs_override_tag_pair(void) { flecs::world ecs; auto Pair = ecs.entity(); auto base = ecs.entity() .set_second(Pair, {10, 20}); auto instance = ecs.entity() .add(flecs::IsA, base); test_assert((instance.has_second(Pair))); const Position *t = instance.get_second(Pair); test_int(t->x, 10); test_int(t->y, 20); const Position *t_2 = base.get_second(Pair); test_assert(t == t_2); instance.add_second(Pair); t = instance.get_second(Pair); test_int(t->x, 10); test_int(t->y, 20); test_assert(t != t_2); instance.remove_second(Pair); t = instance.get_second(Pair); test_int(t->x, 10); test_int(t->y, 20); test_assert(t == t_2); } void Pairs_get_mut_pair(void) { flecs::world ecs; auto e = ecs.entity(); Pair *t = e.get_mut(); test_assert(t != NULL); t->value = 10; const Pair *t_2 = e.get(); test_assert(t == t_2); test_int(t->value, 10); } void Pairs_get_mut_pair_existing(void) { flecs::world ecs; auto e = ecs.entity() .set({20}); Pair *t = e.get_mut(); test_assert(t != NULL); test_int(t->value, 20); t->value = 10; const Pair *t_2 = e.get(); test_assert(t == t_2); test_int(t->value, 10); } void Pairs_get_mut_pair_tag(void) { flecs::world ecs; auto Pair = ecs.entity(); auto e = ecs.entity(); Position *p = e.get_mut_second(Pair); test_assert(p != NULL); p->x = 10; p->y = 20; const Position *p_2 = e.get_second(Pair); test_assert(p == p_2); test_int(p->x, 10); test_int(p->y, 20); } void Pairs_get_mut_pair_tag_existing(void) { flecs::world ecs; auto Pair = ecs.entity(); auto e = ecs.entity() .set_second(Pair, {10, 20}); Position *p = e.get_mut_second(Pair); test_assert(p != NULL); test_int(p->x, 10); test_int(p->y, 20); const Position *p_2 = e.get_second(Pair); test_assert(p == p_2); test_int(p->x, 10); test_int(p->y, 20); } void Pairs_get_mut_R_tag_O(void) { flecs::world ecs; auto e = ecs.entity() .set({10, 20}); Position *t = e.get_mut(); test_assert(t != NULL); test_int(t->x, 10); test_int(t->y, 20); t->x = 30; t->y = 40; const Position *t_2 = e.get(); test_assert(t == t_2); test_int(t->x, 30); test_int(t->y, 40); } void Pairs_get_relation_from_id(void) { flecs::world ecs; auto rel = ecs.entity(); auto obj = ecs.entity(); flecs::id pair(rel, obj); test_assert(pair.first() == rel); test_assert(pair.second() != rel); test_assert(pair.first().is_alive()); test_assert(pair.first().is_valid()); } void Pairs_get_second_from_id(void) { flecs::world ecs; auto rel = ecs.entity(); auto obj = ecs.entity(); flecs::id pair(rel, obj); test_assert(pair.first() != obj); test_assert(pair.second() == obj); test_assert(pair.second().is_alive()); test_assert(pair.second().is_valid()); } void Pairs_get_recycled_relation_from_id(void) { flecs::world ecs; auto rel = ecs.entity(); auto obj = ecs.entity(); rel.destruct(); obj.destruct(); rel = ecs.entity(); obj = ecs.entity(); // Make sure ids are recycled test_assert((uint32_t)rel.id() != rel.id()); test_assert((uint32_t)obj.id() != obj.id()); flecs::id pair(rel, obj); test_assert(pair.first() == rel); test_assert(pair.second() != rel); test_assert(pair.first().is_alive()); test_assert(pair.first().is_valid()); } void Pairs_get_recycled_object_from_id(void) { flecs::world ecs; auto rel = ecs.entity(); auto obj = ecs.entity(); rel.destruct(); obj.destruct(); rel = ecs.entity(); obj = ecs.entity(); // Make sure ids are recycled test_assert((uint32_t)rel.id() != rel.id()); test_assert((uint32_t)obj.id() != obj.id()); flecs::id pair(rel, obj); test_assert(pair.first() == rel); test_assert(pair.second() != rel); test_assert(pair.second().is_alive()); test_assert(pair.second().is_valid()); } void Pairs_get_rel_obj(void) { flecs::world ecs; auto rel = ecs.component(); auto obj = ecs.entity(); auto e = ecs.entity() .set(obj, {10, 20}); test_assert(e.has(obj)); test_assert(e.has(rel, obj)); const void *ptr = e.get(rel, obj); test_assert(ptr != nullptr); test_int(static_cast(ptr)->x, 10); test_int(static_cast(ptr)->y, 20); } void Pairs_get_rel_obj_id(void) { flecs::world ecs; flecs::id rel = ecs.component(); flecs::id obj = ecs.entity(); auto e = ecs.entity() .set(obj, {10, 20}); test_assert(e.has(obj)); test_assert(e.has(rel, obj)); const void *ptr = e.get(rel, obj); test_assert(ptr != nullptr); test_int(static_cast(ptr)->x, 10); test_int(static_cast(ptr)->y, 20); } void Pairs_get_rel_obj_id_t(void) { flecs::world ecs; flecs::id_t rel = ecs.component(); flecs::id_t obj = ecs.entity(); auto e = ecs.entity() .set(obj, {10, 20}); test_assert(e.has(obj)); test_assert(e.has(rel, obj)); const void *ptr = e.get(rel, obj); test_assert(ptr != nullptr); test_int(static_cast(ptr)->x, 10); test_int(static_cast(ptr)->y, 20); } void Pairs_get_R_obj(void) { flecs::world ecs; auto obj = ecs.entity(); auto e = ecs.entity() .set(obj, {10, 20}); test_assert(e.has(obj)); const Position *ptr = e.get(obj); test_assert(ptr != nullptr); test_int(ptr->x, 10); test_int(ptr->y, 20); } void Pairs_get_R_obj_id(void) { flecs::world ecs; flecs::id obj = ecs.entity(); auto e = ecs.entity() .set(obj, {10, 20}); test_assert(e.has(obj)); const Position *ptr = e.get(obj); test_assert(ptr != nullptr); test_int(ptr->x, 10); test_int(ptr->y, 20); } void Pairs_get_R_obj_id_t(void) { flecs::world ecs; flecs::id_t obj = ecs.entity(); auto e = ecs.entity() .set(obj, {10, 20}); test_assert(e.has(obj)); const Position *ptr = e.get(obj); test_assert(ptr != nullptr); test_int(ptr->x, 10); test_int(ptr->y, 20); } void Pairs_get_R_O(void) { flecs::world ecs; auto e = ecs.entity().set({10, 20}); test_assert((e.has())); const Position *ptr = e.get(); test_assert(ptr != nullptr); test_int(ptr->x, 10); test_int(ptr->y, 20); } void Pairs_get_R_tag_O(void) { flecs::world ecs; auto e = ecs.entity().set({10, 20}); test_assert((e.has())); const Position *ptr = e.get(); test_assert(ptr != nullptr); test_int(ptr->x, 10); test_int(ptr->y, 20); } void Pairs_get_second(void) { flecs::world ecs; auto rel = ecs.entity(); auto e = ecs.entity() .set_second(rel, {10, 20}); test_assert(e.has_second(rel)); const Position *ptr = e.get_second(rel); test_assert(ptr != nullptr); test_int(ptr->x, 10); test_int(ptr->y, 20); } void Pairs_get_second_id(void) { flecs::world ecs; flecs::id rel = ecs.entity(); auto e = ecs.entity() .set_second(rel, {10, 20}); test_assert(e.has_second(rel)); const Position *ptr = e.get_second(rel); test_assert(ptr != nullptr); test_int(ptr->x, 10); test_int(ptr->y, 20); } void Pairs_get_second_id_t(void) { flecs::world ecs; flecs::id_t rel = ecs.entity(); auto e = ecs.entity() .set_second(rel, {10, 20}); test_assert(e.has_second(rel)); const Position *ptr = e.get_second(rel); test_assert(ptr != nullptr); test_int(ptr->x, 10); test_int(ptr->y, 20); } void Pairs_each(void) { flecs::world ecs; auto p_1 = ecs.entity(); auto p_2 = ecs.entity(); auto e = ecs.entity() .add(p_1) .add(p_2); int32_t count = 0; e.each([&](flecs::id e) { if (count == 0) { test_assert(e == p_1); } else if (count == 1) { test_assert(e == p_2); } else { test_assert(false); } count ++; }); test_int(count, 2); } void Pairs_each_pair(void) { flecs::world ecs; auto pair = ecs.component(); auto pos = ecs.component(); auto vel = ecs.component(); auto e = ecs.entity() .add() .add(); int32_t count = 0; e.each(pair, [&](flecs::entity object) { if (count == 0) { test_assert(object == pos); } else if (count == 1) { test_assert(object == vel); } else { test_assert(false); } count ++; }); test_int(count, 2); } void Pairs_each_pair_by_type(void) { flecs::world ecs; auto pos = ecs.component(); auto vel = ecs.component(); auto e = ecs.entity() .add() .add(); int32_t count = 0; e.each([&](flecs::entity object) { if (count == 0) { test_assert(object == pos); } else if (count == 1) { test_assert(object == vel); } else { test_assert(false); } count ++; }); test_int(count, 2); } void Pairs_each_pair_w_isa(void) { flecs::world ecs; auto p_1 = ecs.entity(); auto p_2 = ecs.entity(); auto e = ecs.entity() .is_a(p_1) .is_a(p_2); int32_t count = 0; e.each(flecs::IsA, [&](flecs::entity object) { if (count == 0) { test_assert(object == p_1); } else if (count == 1) { test_assert(object == p_2); } else { test_assert(false); } count ++; }); test_int(count, 2); } void Pairs_each_pair_w_recycled_rel(void) { flecs::world ecs; auto e_1 = ecs.entity(); auto e_2 = ecs.entity(); ecs.entity().destruct(); // force recycling auto pair = ecs.entity(); test_assert((uint32_t)pair.id() != pair.id()); // ensure recycled auto e = ecs.entity() .add(pair, e_1) .add(pair, e_2); int32_t count = 0; // should work correctly e.each(pair, [&](flecs::entity object) { if (count == 0) { test_assert(object == e_1); } else if (count == 1) { test_assert(object == e_2); } else { test_assert(false); } count ++; }); test_int(count, 2); } void Pairs_each_pair_w_recycled_obj(void) { flecs::world ecs; auto pair = ecs.component(); ecs.entity().destruct(); // force recycling auto e_1 = ecs.entity(); test_assert((uint32_t)e_1.id() != e_1.id()); // ensure recycled ecs.entity().destruct(); auto e_2 = ecs.entity(); test_assert((uint32_t)e_2.id() != e_2.id()); auto e = ecs.entity() .add(e_1) .add(e_2); int32_t count = 0; // should work correctly e.each(pair, [&](flecs::entity object) { if (count == 0) { test_assert(object == e_1); } else if (count == 1) { test_assert(object == e_2); } else { test_assert(false); } count ++; }); test_int(count, 2); } void Pairs_match_pair(void) { flecs::world ecs; auto Eats = ecs.entity(); auto Dislikes = ecs.entity(); auto Apples = ecs.entity(); auto Pears = ecs.entity(); auto Bananas = ecs.entity(); auto e = ecs.entity() .set({10, 20}) // should not be matched .add(Eats, Apples) .add(Eats, Pears) .add(Dislikes, Bananas); int32_t count = 0; e.each(Eats, Apples, [&](flecs::id id) { test_assert(id.first() == Eats); test_assert(id.second() == Apples); count ++; }); test_int(count, 1); } void Pairs_match_pair_obj_wildcard(void) { flecs::world ecs; auto Eats = ecs.entity(); auto Dislikes = ecs.entity(); auto Apples = ecs.entity(); auto Pears = ecs.entity(); auto Bananas = ecs.entity(); auto e = ecs.entity() .set({10, 20}) // should not be matched .add(Eats, Apples) .add(Eats, Pears) .add(Dislikes, Bananas); int32_t count = 0; e.each(Eats, flecs::Wildcard, [&](flecs::id id) { test_assert(id.first() == Eats); test_assert(id.second() == Apples || id.second() == Pears); count ++; }); test_int(count, 2); } void Pairs_match_pair_rel_wildcard(void) { flecs::world ecs; auto Eats = ecs.entity(); auto Dislikes = ecs.entity(); auto Apples = ecs.entity(); auto Pears = ecs.entity(); auto Bananas = ecs.entity(); auto e = ecs.entity() .set({10, 20}) // should not be matched .add(Eats, Apples) .add(Eats, Pears) .add(Dislikes, Bananas); int32_t count = 0; e.each(flecs::Wildcard, Pears, [&](flecs::id id) { test_assert(id.first() == Eats); test_assert(id.second() == Pears); count ++; }); test_int(count, 1); } void Pairs_match_pair_both_wildcard(void) { flecs::world ecs; auto Eats = ecs.entity(); auto Dislikes = ecs.entity(); auto Apples = ecs.entity(); auto Pears = ecs.entity(); auto Bananas = ecs.entity(); auto e = ecs.entity() .set({10, 20}) // should not be matched .add(Eats, Apples) .add(Eats, Pears) .add(Dislikes, Bananas); int32_t count = 0; e.each(flecs::Wildcard, flecs::Wildcard, [&](flecs::id id) { count ++; }); test_int(count, 3); } void Pairs_has_tag_w_object(void) { flecs::world ecs; struct Likes { }; auto Bob = ecs.entity(); auto e = ecs.entity().add(Bob); test_assert(e.has(Bob)); } void Pairs_has_second_tag(void) { flecs::world ecs; struct Bob { }; auto Likes = ecs.entity(); auto e = ecs.entity().add_second(Likes); test_assert(e.has_second(Likes)); } struct Eats { int amount; }; struct Apples { }; struct Pears { }; using EatsApples = flecs::pair; using EatsPears = flecs::pair; void Pairs_add_pair_type(void) { flecs::world ecs; auto e = ecs.entity().add(); test_assert((e.has())); test_assert((e.has())); } void Pairs_remove_pair_type(void) { flecs::world ecs; auto e = ecs.entity().add(); test_assert((e.has())); test_assert((e.has())); e.remove(); test_assert(!(e.has())); test_assert(!(e.has())); } void Pairs_set_pair_type(void) { flecs::world ecs; auto e = ecs.entity().set({10}); test_assert((e.has())); test_assert((e.has())); const Eats *ptr = e.get(); test_int(ptr->amount, 10); test_assert((ptr == e.get())); } void Pairs_has_pair_type(void) { flecs::world ecs; auto e = ecs.entity().add(); test_assert((e.has())); test_assert((e.has())); } void Pairs_get_1_pair_arg(void) { flecs::world ecs; auto e = ecs.entity().set({10}); test_assert((e.has())); test_assert((e.has())); test_bool(e.get([](const EatsApples& a) { test_int(a->amount, 10); }), true); } void Pairs_get_2_pair_arg(void) { flecs::world ecs; auto e = ecs.entity() .set({10}) .set({20}); test_assert((e.has())); test_assert((e.has())); test_assert((e.has())); test_assert((e.has())); test_bool(e.get([](const EatsApples& a, const EatsPears& p) { test_int(a->amount, 10); test_int(p->amount, 20); }), true); } void Pairs_set_1_pair_arg(void) { flecs::world ecs; auto e = ecs.entity() .set([](EatsApples&& a) { a->amount = 10; }); auto eats = e.get(); test_int(eats->amount, 10); } void Pairs_set_2_pair_arg(void) { flecs::world ecs; auto e = ecs.entity() .set([](EatsApples&& a, EatsPears&& p) { a->amount = 10; p->amount = 20; }); auto eats = e.get(); test_int(eats->amount, 10); eats = e.get(); test_int(eats->amount, 20); } void Pairs_get_inline_pair_type(void) { flecs::world ecs; auto e = ecs.entity().set({10}); test_assert((e.has())); test_assert((e.has())); test_bool(e.get([](const flecs::pair& a) { test_int(a->amount, 10); }), true); } void Pairs_set_inline_pair_type(void) { flecs::world ecs; auto e = ecs.entity() .set([](flecs::pair&& a) { a->amount = 10; }); auto eats = e.get(); test_int(eats->amount, 10); } void Pairs_get_pair_type_object(void) { flecs::world ecs; auto e = ecs.entity().set_second({10}); test_assert((e.has())); test_bool(e.get([](const flecs::pair_object& a) { test_int(a->amount, 10); }), true); } void Pairs_set_pair_type_object(void) { flecs::world ecs; auto e = ecs.entity() .set([](flecs::pair_object&& a) { a->amount = 10; }); auto eats = e.get_second(); test_int(eats->amount, 10); } struct Event { const char *value; }; struct Begin { }; struct End { }; using BeginEvent = flecs::pair; using EndEvent = flecs::pair; void Pairs_set_get_second_variants(void) { flecs::world ecs; auto e1 = ecs.entity().set_second({"Big Bang"}); test_assert((e1.has())); const Event* v = e1.get_second(); test_assert(v != NULL); test_str(v->value, "Big Bang"); auto e2 = ecs.entity().set({"Big Bang"}); test_assert((e2.has())); v = e2.get(); test_assert(v != NULL); test_str(v->value, "Big Bang"); auto e3 = ecs.entity().set>({"Big Bang"}); test_assert((e3.has>())); v = e3.get>(); test_assert(v != NULL); test_str(v->value, "Big Bang"); auto e4 = ecs.entity().set({"Big Bang"}); test_assert((e4.has())); v = e4.get(); test_assert(v != NULL); test_str(v->value, "Big Bang"); } void Pairs_get_object_for_type_self(void) { flecs::world ecs; auto base = ecs.entity().add(); auto self = ecs.entity().is_a(base).add(); auto obj = self.target_for(flecs::IsA); test_assert(obj != 0); test_assert(obj == self); } void Pairs_get_object_for_type_base(void) { flecs::world ecs; auto base = ecs.entity().add(); auto self = ecs.entity().is_a(base); auto obj = self.target_for(flecs::IsA); test_assert(obj != 0); test_assert(obj == base); } void Pairs_get_object_for_id_self(void) { flecs::world ecs; auto tag = ecs.entity(); auto base = ecs.entity().add(tag); auto self = ecs.entity().is_a(base).add(tag); auto obj = self.target_for(flecs::IsA, tag); test_assert(obj != 0); test_assert(obj == self); } void Pairs_get_object_for_id_base(void) { flecs::world ecs; auto tag = ecs.entity(); auto base = ecs.entity().add(tag); auto self = ecs.entity().is_a(base); auto obj = self.target_for(flecs::IsA, tag); test_assert(obj != 0); test_assert(obj == base); } void Pairs_get_object_for_id_not_found(void) { flecs::world ecs; auto tag = ecs.entity(); auto base = ecs.entity(); auto self = ecs.entity().is_a(base); auto obj = self.target_for(flecs::IsA, tag); test_assert(obj == 0); } void Pairs_deref_pair(void) { flecs::world ecs; Position v = {10, 20}; flecs::pair p(v); test_int(p->x, 10); test_int(p->y, 20); Position pos = *p; test_int(pos.x, 10); test_int(pos.y, 20); } void Pairs_deref_const_pair(void) { flecs::world ecs; Position v = {10, 20}; const flecs::pair p(v); test_int(p->x, 10); test_int(p->y, 20); Position pos = *p; test_int(pos.x, 10); test_int(pos.y, 20); } void Pairs_deref_pair_obj(void) { flecs::world ecs; Position v = {10, 20}; flecs::pair p(v); test_int(p->x, 10); test_int(p->y, 20); Position pos = *p; test_int(pos.x, 10); test_int(pos.y, 20); } void Pairs_deref_const_pair_obj(void) { flecs::world ecs; Position v = {10, 20}; const flecs::pair p(v); test_int(p->x, 10); test_int(p->y, 20); Position pos = *p; test_int(pos.x, 10); test_int(pos.y, 20); } void Pairs_set_R_existing_value(void) { flecs::world ecs; Position p{10, 20}; flecs::entity e = ecs.entity().set(p); const Position *ptr = e.get(); test_assert(ptr != nullptr); test_int(ptr->x, 10); test_int(ptr->y, 20); }