Skip to content

Commit

Permalink
#1384 Enforce correct type when using *_second operations
Browse files Browse the repository at this point in the history
  • Loading branch information
SanderMertens authored Oct 31, 2024
1 parent 2d80124 commit 002b372
Show file tree
Hide file tree
Showing 7 changed files with 173 additions and 30 deletions.
57 changes: 43 additions & 14 deletions distr/flecs.h
Original file line number Diff line number Diff line change
Expand Up @@ -23286,11 +23286,11 @@ struct entity_view : public id {
*/
template<typename First, typename Second, if_not_t< is_enum<Second>::value> = 0>
const First* get(Second second) const {
auto comp_id = _::type<First>::id(world_);
auto first = _::type<First>::id(world_);
ecs_assert(_::type<First>::size() != 0, ECS_INVALID_PARAMETER,
"operation invalid for empty type");
return static_cast<const First*>(
ecs_get_id(world_, id_, ecs_pair(comp_id, second)));
ecs_get_id(world_, id_, ecs_pair(first, second)));
}

/** Get a pair.
Expand Down Expand Up @@ -23383,6 +23383,10 @@ struct entity_view : public id {
template<typename Second>
const Second* get_second(flecs::entity_t first) const {
auto second = _::type<Second>::id(world_);
ecs_assert( ecs_get_type_info(world_, ecs_pair(first, second)) != NULL,
ECS_INVALID_PARAMETER, "pair is not a component");
ecs_assert( ecs_get_type_info(world_, ecs_pair(first, second))->component == second,
ECS_INVALID_PARAMETER, "type of pair is not Second");
ecs_assert(_::type<Second>::size() != 0, ECS_INVALID_PARAMETER,
"operation invalid for empty type");
return static_cast<const Second*>(
Expand Down Expand Up @@ -23452,11 +23456,11 @@ struct entity_view : public id {
*/
template<typename First, typename Second, if_not_t< is_enum<Second>::value> = 0>
First* get_mut(Second second) const {
auto comp_id = _::type<First>::id(world_);
auto first = _::type<First>::id(world_);
ecs_assert(_::type<First>::size() != 0, ECS_INVALID_PARAMETER,
"operation invalid for empty type");
return static_cast<First*>(
ecs_get_mut_id(world_, id_, ecs_pair(comp_id, second)));
ecs_get_mut_id(world_, id_, ecs_pair(first, second)));
}

/** Get a mutable pair.
Expand Down Expand Up @@ -23504,6 +23508,10 @@ struct entity_view : public id {
template<typename Second>
Second* get_mut_second(flecs::entity_t first) const {
auto second = _::type<Second>::id(world_);
ecs_assert( ecs_get_type_info(world_, ecs_pair(first, second)) != NULL,
ECS_INVALID_PARAMETER, "pair is not a component");
ecs_assert( ecs_get_type_info(world_, ecs_pair(first, second))->component == second,
ECS_INVALID_PARAMETER, "type of pair is not Second");
ecs_assert(_::type<Second>::size() != 0, ECS_INVALID_PARAMETER,
"operation invalid for empty type");
return static_cast<Second*>(
Expand Down Expand Up @@ -24909,6 +24917,10 @@ struct entity_builder : entity_view {
template <typename Second>
const Self& set_second(entity_t first, const Second& value) const {
auto second = _::type<Second>::id(this->world_);
ecs_assert( ecs_get_type_info(world_, ecs_pair(first, second)) != NULL,
ECS_INVALID_PARAMETER, "pair is not a component");
ecs_assert( ecs_get_type_info(world_, ecs_pair(first, second))->component == second,
ECS_INVALID_PARAMETER, "type of pair is not Second");
flecs::set(this->world_, this->id_, value,
ecs_pair(first, second));
return to_base();
Expand All @@ -24925,6 +24937,10 @@ struct entity_builder : entity_view {
template <typename Second>
const Self& set_second(entity_t first, Second&& value) const {
auto second = _::type<Second>::id(this->world_);
ecs_assert( ecs_get_type_info(world_, ecs_pair(first, second)) != NULL,
ECS_INVALID_PARAMETER, "pair is not a component");
ecs_assert( ecs_get_type_info(world_, ecs_pair(first, second))->component == second,
ECS_INVALID_PARAMETER, "type of pair is not Second");
flecs::set(this->world_, this->id_, FLECS_FWD(value),
ecs_pair(first, second));
return to_base();
Expand Down Expand Up @@ -24994,16 +25010,22 @@ struct entity_builder : entity_view {

template <typename First, typename ... Args>
const Self& emplace_first(flecs::entity_t second, Args&&... args) const {
auto first = _::type<First>::id(this->world_);
flecs::emplace<First>(this->world_, this->id_,
ecs_pair(_::type<First>::id(this->world_), second),
ecs_pair(first, second),
FLECS_FWD(args)...);
return to_base();
}

template <typename Second, typename ... Args>
const Self& emplace_second(flecs::entity_t first, Args&&... args) const {
auto second = _::type<Second>::id(this->world_);
ecs_assert( ecs_get_type_info(world_, ecs_pair(first, second)) != NULL,
ECS_INVALID_PARAMETER, "pair is not a component");
ecs_assert( ecs_get_type_info(world_, ecs_pair(first, second))->component == second,
ECS_INVALID_PARAMETER, "type of pair is not Second");
flecs::emplace<Second>(this->world_, this->id_,
ecs_pair(first, _::type<Second>::id(this->world_)),
ecs_pair(first, second),
FLECS_FWD(args)...);
return to_base();
}
Expand Down Expand Up @@ -25551,11 +25573,11 @@ struct entity : entity_builder<entity>
*/
template <typename First>
First& ensure(entity_t second) const {
auto comp_id = _::type<First>::id(world_);
auto first = _::type<First>::id(world_);
ecs_assert(_::type<First>::size() != 0, ECS_INVALID_PARAMETER,
"operation invalid for empty type");
return *static_cast<First*>(
ecs_ensure_id(world_, id_, ecs_pair(comp_id, second)));
ecs_ensure_id(world_, id_, ecs_pair(first, second)));
}

/** Get mutable pointer for a pair (untyped).
Expand All @@ -25579,6 +25601,10 @@ struct entity : entity_builder<entity>
template <typename Second>
Second& ensure_second(entity_t first) const {
auto second = _::type<Second>::id(world_);
ecs_assert( ecs_get_type_info(world_, ecs_pair(first, second)) != NULL,
ECS_INVALID_PARAMETER, "pair is not a component");
ecs_assert( ecs_get_type_info(world_, ecs_pair(first, second))->component == second,
ECS_INVALID_PARAMETER, "type of pair is not Second");
ecs_assert(_::type<Second>::size() != 0, ECS_INVALID_PARAMETER,
"operation invalid for empty type");
return *static_cast<Second*>(
Expand Down Expand Up @@ -25678,20 +25704,23 @@ struct entity : entity_builder<entity>
typename A = actual_type_t<P>>
ref<A> get_ref() const {
return ref<A>(world_, id_,
ecs_pair(_::type<First>::id(world_),
_::type<Second>::id(world_)));
ecs_pair(_::type<First>::id(world_), _::type<Second>::id(world_)));
}

template <typename First>
ref<First> get_ref(flecs::entity_t second) const {
return ref<First>(world_, id_,
ecs_pair(_::type<First>::id(world_), second));
auto first = _::type<First>::id(world_);
return ref<First>(world_, id_, ecs_pair(first, second));
}

template <typename Second>
ref<Second> get_ref_second(flecs::entity_t first) const {
return ref<Second>(world_, id_,
ecs_pair(first, _::type<Second>::id(world_)));
auto second = _::type<Second>::id(world_);
ecs_assert( ecs_get_type_info(world_, ecs_pair(first, second)) != NULL,
ECS_INVALID_PARAMETER, "pair is not a component");
ecs_assert( ecs_get_type_info(world_, ecs_pair(first, second))->component == second,
ECS_INVALID_PARAMETER, "type of pair is not Second");
return ref<Second>(world_, id_, ecs_pair(first, second));
}

/** Clear an entity.
Expand Down
23 changes: 15 additions & 8 deletions include/flecs/addons/cpp/entity.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,11 @@ struct entity : entity_builder<entity>
*/
template <typename First>
First& ensure(entity_t second) const {
auto comp_id = _::type<First>::id(world_);
auto first = _::type<First>::id(world_);
ecs_assert(_::type<First>::size() != 0, ECS_INVALID_PARAMETER,
"operation invalid for empty type");
return *static_cast<First*>(
ecs_ensure_id(world_, id_, ecs_pair(comp_id, second)));
ecs_ensure_id(world_, id_, ecs_pair(first, second)));
}

/** Get mutable pointer for a pair (untyped).
Expand All @@ -166,6 +166,10 @@ struct entity : entity_builder<entity>
template <typename Second>
Second& ensure_second(entity_t first) const {
auto second = _::type<Second>::id(world_);
ecs_assert( ecs_get_type_info(world_, ecs_pair(first, second)) != NULL,
ECS_INVALID_PARAMETER, "pair is not a component");
ecs_assert( ecs_get_type_info(world_, ecs_pair(first, second))->component == second,
ECS_INVALID_PARAMETER, "type of pair is not Second");
ecs_assert(_::type<Second>::size() != 0, ECS_INVALID_PARAMETER,
"operation invalid for empty type");
return *static_cast<Second*>(
Expand Down Expand Up @@ -265,20 +269,23 @@ struct entity : entity_builder<entity>
typename A = actual_type_t<P>>
ref<A> get_ref() const {
return ref<A>(world_, id_,
ecs_pair(_::type<First>::id(world_),
_::type<Second>::id(world_)));
ecs_pair(_::type<First>::id(world_), _::type<Second>::id(world_)));
}

template <typename First>
ref<First> get_ref(flecs::entity_t second) const {
return ref<First>(world_, id_,
ecs_pair(_::type<First>::id(world_), second));
auto first = _::type<First>::id(world_);
return ref<First>(world_, id_, ecs_pair(first, second));
}

template <typename Second>
ref<Second> get_ref_second(flecs::entity_t first) const {
return ref<Second>(world_, id_,
ecs_pair(first, _::type<Second>::id(world_)));
auto second = _::type<Second>::id(world_);
ecs_assert( ecs_get_type_info(world_, ecs_pair(first, second)) != NULL,
ECS_INVALID_PARAMETER, "pair is not a component");
ecs_assert( ecs_get_type_info(world_, ecs_pair(first, second))->component == second,
ECS_INVALID_PARAMETER, "type of pair is not Second");
return ref<Second>(world_, id_, ecs_pair(first, second));
}

/** Clear an entity.
Expand Down
16 changes: 12 additions & 4 deletions include/flecs/addons/cpp/entity_view.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -300,11 +300,11 @@ struct entity_view : public id {
*/
template<typename First, typename Second, if_not_t< is_enum<Second>::value> = 0>
const First* get(Second second) const {
auto comp_id = _::type<First>::id(world_);
auto first = _::type<First>::id(world_);
ecs_assert(_::type<First>::size() != 0, ECS_INVALID_PARAMETER,
"operation invalid for empty type");
return static_cast<const First*>(
ecs_get_id(world_, id_, ecs_pair(comp_id, second)));
ecs_get_id(world_, id_, ecs_pair(first, second)));
}

/** Get a pair.
Expand Down Expand Up @@ -397,6 +397,10 @@ struct entity_view : public id {
template<typename Second>
const Second* get_second(flecs::entity_t first) const {
auto second = _::type<Second>::id(world_);
ecs_assert( ecs_get_type_info(world_, ecs_pair(first, second)) != NULL,
ECS_INVALID_PARAMETER, "pair is not a component");
ecs_assert( ecs_get_type_info(world_, ecs_pair(first, second))->component == second,
ECS_INVALID_PARAMETER, "type of pair is not Second");
ecs_assert(_::type<Second>::size() != 0, ECS_INVALID_PARAMETER,
"operation invalid for empty type");
return static_cast<const Second*>(
Expand Down Expand Up @@ -466,11 +470,11 @@ struct entity_view : public id {
*/
template<typename First, typename Second, if_not_t< is_enum<Second>::value> = 0>
First* get_mut(Second second) const {
auto comp_id = _::type<First>::id(world_);
auto first = _::type<First>::id(world_);
ecs_assert(_::type<First>::size() != 0, ECS_INVALID_PARAMETER,
"operation invalid for empty type");
return static_cast<First*>(
ecs_get_mut_id(world_, id_, ecs_pair(comp_id, second)));
ecs_get_mut_id(world_, id_, ecs_pair(first, second)));
}

/** Get a mutable pair.
Expand Down Expand Up @@ -518,6 +522,10 @@ struct entity_view : public id {
template<typename Second>
Second* get_mut_second(flecs::entity_t first) const {
auto second = _::type<Second>::id(world_);
ecs_assert( ecs_get_type_info(world_, ecs_pair(first, second)) != NULL,
ECS_INVALID_PARAMETER, "pair is not a component");
ecs_assert( ecs_get_type_info(world_, ecs_pair(first, second))->component == second,
ECS_INVALID_PARAMETER, "type of pair is not Second");
ecs_assert(_::type<Second>::size() != 0, ECS_INVALID_PARAMETER,
"operation invalid for empty type");
return static_cast<Second*>(
Expand Down
18 changes: 16 additions & 2 deletions include/flecs/addons/cpp/mixins/entity/builder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -808,6 +808,10 @@ struct entity_builder : entity_view {
template <typename Second>
const Self& set_second(entity_t first, const Second& value) const {
auto second = _::type<Second>::id(this->world_);
ecs_assert( ecs_get_type_info(world_, ecs_pair(first, second)) != NULL,
ECS_INVALID_PARAMETER, "pair is not a component");
ecs_assert( ecs_get_type_info(world_, ecs_pair(first, second))->component == second,
ECS_INVALID_PARAMETER, "type of pair is not Second");
flecs::set(this->world_, this->id_, value,
ecs_pair(first, second));
return to_base();
Expand All @@ -824,6 +828,10 @@ struct entity_builder : entity_view {
template <typename Second>
const Self& set_second(entity_t first, Second&& value) const {
auto second = _::type<Second>::id(this->world_);
ecs_assert( ecs_get_type_info(world_, ecs_pair(first, second)) != NULL,
ECS_INVALID_PARAMETER, "pair is not a component");
ecs_assert( ecs_get_type_info(world_, ecs_pair(first, second))->component == second,
ECS_INVALID_PARAMETER, "type of pair is not Second");
flecs::set(this->world_, this->id_, FLECS_FWD(value),
ecs_pair(first, second));
return to_base();
Expand Down Expand Up @@ -893,16 +901,22 @@ struct entity_builder : entity_view {

template <typename First, typename ... Args>
const Self& emplace_first(flecs::entity_t second, Args&&... args) const {
auto first = _::type<First>::id(this->world_);
flecs::emplace<First>(this->world_, this->id_,
ecs_pair(_::type<First>::id(this->world_), second),
ecs_pair(first, second),
FLECS_FWD(args)...);
return to_base();
}

template <typename Second, typename ... Args>
const Self& emplace_second(flecs::entity_t first, Args&&... args) const {
auto second = _::type<Second>::id(this->world_);
ecs_assert( ecs_get_type_info(world_, ecs_pair(first, second)) != NULL,
ECS_INVALID_PARAMETER, "pair is not a component");
ecs_assert( ecs_get_type_info(world_, ecs_pair(first, second))->component == second,
ECS_INVALID_PARAMETER, "type of pair is not Second");
flecs::emplace<Second>(this->world_, this->id_,
ecs_pair(first, _::type<Second>::id(this->world_)),
ecs_pair(first, second),
FLECS_FWD(args)...);
return to_base();
}
Expand Down
7 changes: 6 additions & 1 deletion test/cpp/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,12 @@
"insert_2_w_1_sparse",
"emplace_sparse",
"override_sparse",
"delete_w_override_sparse"
"delete_w_override_sparse",
"get_pair_second_invalid_type",
"get_mut_pair_second_invalid_type",
"ensure_pair_second_invalid_type",
"set_pair_second_invalid_type",
"get_ref_pair_second_invalid_type"
]
}, {
"id": "Pairs",
Expand Down
55 changes: 55 additions & 0 deletions test/cpp/src/Entity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4808,3 +4808,58 @@ void Entity_delete_w_override_sparse(void) {

e.destruct();
}

void Entity_get_pair_second_invalid_type(void) {
install_test_abort();

flecs::world world;

auto v = world.component<Velocity>();

test_expect_abort();
world.entity().get_second<Position>(v);
}

void Entity_get_mut_pair_second_invalid_type(void) {
install_test_abort();

flecs::world world;

auto v = world.component<Velocity>();

test_expect_abort();
world.entity().get_mut_second<Position>(v);
}

void Entity_ensure_pair_second_invalid_type(void) {
install_test_abort();

flecs::world world;

auto v = world.component<Velocity>();

test_expect_abort();
world.entity().ensure_second<Position>(v);
}

void Entity_set_pair_second_invalid_type(void) {
install_test_abort();

flecs::world world;

auto v = world.component<Velocity>();

test_expect_abort();
world.entity().set_second<Position>(v, {0});
}

void Entity_get_ref_pair_second_invalid_type(void) {
install_test_abort();

flecs::world world;

auto v = world.component<Velocity>();

test_expect_abort();
world.entity().get_ref_second<Position>(v);
}
Loading

0 comments on commit 002b372

Please sign in to comment.