Skip to content

Commit

Permalink
Implement flecs::ref::component() for getting ref's component id
Browse files Browse the repository at this point in the history
  • Loading branch information
SanderMertens committed Jan 9, 2025
1 parent 8a1e9ab commit a20baf3
Show file tree
Hide file tree
Showing 7 changed files with 164 additions and 8 deletions.
46 changes: 43 additions & 3 deletions distr/flecs.h
Original file line number Diff line number Diff line change
Expand Up @@ -26205,6 +26205,34 @@ struct entity : entity_builder<entity>
ecs_modified_id(world_, id_, comp);
}

/** Get reference to component specified by id.
* A reference allows for quick and safe access to a component value, and is
* a faster alternative to repeatedly calling 'get' for the same component.
*
* The method accepts an optional component id argument, which can be used
* to create a ref to a component that is different from the provided type.
* This allows for creating a base type ref that points to a derived type:
*
* @code
* flecs::ref<Base> r = e.get_ref<Base>(world.id<Derived>());
* @endcode
*
* If the provided component id is not binary compatible with the specified
* type, the behavior is undefined.
*
* @tparam T component for which to get a reference.
* @return The reference.
*/
template <typename T, if_t< is_actual<T>::value > = 0>
ref<T> get_ref_w_id(flecs::id_t component) const {
if (component) {
_::type<T>::id(world_); // ensure type is registered
return ref<T>(world_, id_, component);
} else {
return ref<T>(world_, id_, _::type<T>::id(world_));
}
}

/** Get reference to component.
* A reference allows for quick and safe access to a component value, and is
* a faster alternative to repeatedly calling 'get' for the same component.
Expand Down Expand Up @@ -28120,9 +28148,12 @@ struct ref {
id = _::type<T>::id(world);
}

ecs_assert(_::type<T>::size() != 0, ECS_INVALID_PARAMETER,
"operation invalid for empty type");

#ifdef FLECS_DEBUG
flecs::entity_t type = ecs_get_typeid(world, id);
const flecs::type_info_t *ti = ecs_get_type_info(world, type);
ecs_assert(ti && ti->size != 0, ECS_INVALID_PARAMETER,
"cannot create ref to empty type");
#endif
ref_ = ecs_ref_init_id(world_, entity, id);
}

Expand Down Expand Up @@ -28161,8 +28192,12 @@ struct ref {
return has();
}

/** Return entity associated with reference. */
flecs::entity entity() const;

/** Return component associated with reference. */
flecs::id component() const;

private:
world_t *world_;
flecs::ref_t ref_;
Expand Down Expand Up @@ -29106,6 +29141,11 @@ flecs::entity ref<T>::entity() const {
return flecs::entity(world_, ref_.entity);
}

template <typename T>
flecs::id ref<T>::component() const {
return flecs::id(world_, ref_.id);
}

template <typename Self>
template <typename Func>
inline const Self& entity_builder<Self>::insert(const Func& func) const {
Expand Down
28 changes: 28 additions & 0 deletions include/flecs/addons/cpp/entity.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,34 @@ struct entity : entity_builder<entity>
ecs_modified_id(world_, id_, comp);
}

/** Get reference to component specified by id.
* A reference allows for quick and safe access to a component value, and is
* a faster alternative to repeatedly calling 'get' for the same component.
*
* The method accepts an optional component id argument, which can be used
* to create a ref to a component that is different from the provided type.
* This allows for creating a base type ref that points to a derived type:
*
* @code
* flecs::ref<Base> r = e.get_ref<Base>(world.id<Derived>());
* @endcode
*
* If the provided component id is not binary compatible with the specified
* type, the behavior is undefined.
*
* @tparam T component for which to get a reference.
* @return The reference.
*/
template <typename T, if_t< is_actual<T>::value > = 0>
ref<T> get_ref_w_id(flecs::id_t component) const {
if (component) {
_::type<T>::id(world_); // ensure type is registered
return ref<T>(world_, id_, component);
} else {
return ref<T>(world_, id_, _::type<T>::id(world_));
}
}

/** Get reference to component.
* A reference allows for quick and safe access to a component value, and is
* a faster alternative to repeatedly calling 'get' for the same component.
Expand Down
5 changes: 5 additions & 0 deletions include/flecs/addons/cpp/mixins/entity/impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ flecs::entity ref<T>::entity() const {
return flecs::entity(world_, ref_.entity);
}

template <typename T>
flecs::id ref<T>::component() const {
return flecs::id(world_, ref_.id);
}

template <typename Self>
template <typename Func>
inline const Self& entity_builder<Self>::insert(const Func& func) const {
Expand Down
13 changes: 10 additions & 3 deletions include/flecs/addons/cpp/ref.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,12 @@ struct ref {
id = _::type<T>::id(world);
}

ecs_assert(_::type<T>::size() != 0, ECS_INVALID_PARAMETER,
"operation invalid for empty type");

#ifdef FLECS_DEBUG
flecs::entity_t type = ecs_get_typeid(world, id);
const flecs::type_info_t *ti = ecs_get_type_info(world, type);
ecs_assert(ti && ti->size != 0, ECS_INVALID_PARAMETER,
"cannot create ref to empty type");
#endif
ref_ = ecs_ref_init_id(world_, entity, id);
}

Expand Down Expand Up @@ -75,8 +78,12 @@ struct ref {
return has();
}

/** Return entity associated with reference. */
flecs::entity entity() const;

/** Return component associated with reference. */
flecs::id component() const;

private:
world_t *world_;
flecs::ref_t ref_;
Expand Down
5 changes: 4 additions & 1 deletion test/cpp/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -1095,7 +1095,10 @@
"implicit_operator_bool",
"try_get",
"has",
"bool_operator"
"bool_operator",
"base_type",
"empty_base_type",
"get_component"
]
}, {
"id": "Module",
Expand Down
58 changes: 58 additions & 0 deletions test/cpp/src/Refs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,3 +226,61 @@ void Refs_bool_operator(void) {
test_assert(p);
}
}

struct Base {
int x;
};

struct Derived : public Base {
Derived() { }

Derived(int x_, int y_) {
x = x_;
y = y_;
}

int y;
};

void Refs_base_type(void) {
flecs::world world;

flecs::entity e = world.entity().set(Derived{10, 20});

flecs::ref<Base> r = e.get_ref_w_id<Base>(world.id<Derived>());
test_int(r->x, 10);
}

struct BaseEmpty { };

struct DerivedFromEmpty : public BaseEmpty {
DerivedFromEmpty() { }

DerivedFromEmpty(int y_) {
y = y_;
}

int y;
};

void Refs_empty_base_type(void) {
flecs::world world;

flecs::entity e = world.entity().set(DerivedFromEmpty{20});

flecs::ref<BaseEmpty> r = e.get_ref_w_id<BaseEmpty>(world.id<DerivedFromEmpty>());

BaseEmpty *b = r.get();
DerivedFromEmpty *d = static_cast<DerivedFromEmpty*>(b);
test_int(d->y, 20);
}

void Refs_get_component(void) {
flecs::world world;

auto e = flecs::entity(world)
.set<Position>({10, 20});

auto ref = e.get_ref<Position>();
test_assert(ref.component() == world.id<Position>());
}
17 changes: 16 additions & 1 deletion test/cpp/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1059,6 +1059,9 @@ void Refs_implicit_operator_bool(void);
void Refs_try_get(void);
void Refs_has(void);
void Refs_bool_operator(void);
void Refs_base_type(void);
void Refs_empty_base_type(void);
void Refs_get_component(void);

// Testsuite 'Module'
void Module_import(void);
Expand Down Expand Up @@ -5554,6 +5557,18 @@ bake_test_case Refs_testcases[] = {
{
"bool_operator",
Refs_bool_operator
},
{
"base_type",
Refs_base_type
},
{
"empty_base_type",
Refs_empty_base_type
},
{
"get_component",
Refs_get_component
}
};

Expand Down Expand Up @@ -7090,7 +7105,7 @@ static bake_test_suite suites[] = {
"Refs",
NULL,
NULL,
17,
20,
Refs_testcases
},
{
Expand Down

0 comments on commit a20baf3

Please sign in to comment.