Skip to content

Commit

Permalink
#1021 Add member function overload that takes pointer to member
Browse files Browse the repository at this point in the history
- Added new pointer-to-member member function overload to untyped_component.
- Added support for packed structs in flecs meta.
- Removed unused size and alignment from EcsMetaType.
- Fixed bug where member count was ignored if an explicit offset was provided.
  • Loading branch information
ZeroErrors committed Aug 7, 2023
1 parent f3424e4 commit c27c1da
Show file tree
Hide file tree
Showing 10 changed files with 289 additions and 90 deletions.
52 changes: 37 additions & 15 deletions flecs.c
Original file line number Diff line number Diff line change
Expand Up @@ -55556,19 +55556,13 @@ int flecs_init_type(
ecs_err("computed size for '%s' matches with actual type but "
"alignment is different (%d vs. %d)", ecs_get_name(world, type),
alignment, comp->alignment);
} else {
/* If this is an existing type, the alignment can be larger but
* not smaller than the computed alignment. */
alignment = comp->alignment;
}
}

meta_type->partial = comp->size != size;
}

meta_type->kind = kind;
meta_type->size = size;
meta_type->alignment = alignment;
ecs_modified(world, type, EcsMetaType);

return 0;
Expand Down Expand Up @@ -55714,7 +55708,7 @@ int flecs_add_member_to_struct(
/* Get component of member type to get its size & alignment */
const EcsComponent *mbr_comp = ecs_get(world, elem->type, EcsComponent);
if (!mbr_comp) {
char *path = ecs_get_fullpath(world, member);
char *path = ecs_get_fullpath(world, elem->type);
ecs_err("member '%s' is not a type", path);
ecs_os_free(path);
return -1;
Expand All @@ -55724,7 +55718,7 @@ int flecs_add_member_to_struct(
ecs_size_t member_alignment = mbr_comp->alignment;

if (!member_size || !member_alignment) {
char *path = ecs_get_fullpath(world, member);
char *path = ecs_get_fullpath(world, elem->type);
ecs_err("member '%s' has 0 size/alignment");
ecs_os_free(path);
return -1;
Expand All @@ -55751,14 +55745,42 @@ int flecs_add_member_to_struct(
}
} else {
/* If members have explicit offsets, we can't rely on computed
* size/alignment values. Grab size of just added member instead. It
* doesn't matter if the size doesn't correspond to the actual struct
* size. The flecs_init_type function compares computed size with actual
* size/alignment values. Calculate size as if this is the last member
* instead, since this will validate if the member fits in the struct.
* It doesn't matter if the size is smaller than the actual struct size
* because flecs_init_type function compares computed size with actual
* (component) size to determine if the type is partial. */
const EcsComponent *cptr = ecs_get(world, m->type, EcsComponent);
ecs_assert(cptr != NULL, ECS_INTERNAL_ERROR, NULL);
size = cptr->size;
alignment = cptr->alignment;
ecs_member_t *elem = &members[i];

ecs_assert(elem->name != NULL, ECS_INTERNAL_ERROR, NULL);
ecs_assert(elem->type != 0, ECS_INTERNAL_ERROR, NULL);

/* Get component of member type to get its size & alignment */
const EcsComponent *mbr_comp = ecs_get(world, elem->type, EcsComponent);
if (!mbr_comp) {
char *path = ecs_get_fullpath(world, elem->type);
ecs_err("member '%s' is not a type", path);
ecs_os_free(path);
return -1;
}

ecs_size_t member_size = mbr_comp->size;
ecs_size_t member_alignment = mbr_comp->alignment;

if (!member_size || !member_alignment) {
char *path = ecs_get_fullpath(world, elem->type);
ecs_err("member '%s' has 0 size/alignment");
ecs_os_free(path);
return -1;
}

member_size *= elem->count;
elem->size = member_size;

size = elem->offset + member_size;

const EcsComponent* comp = ecs_get(world, type, EcsComponent);
alignment = comp->alignment;
}

if (size == 0) {
Expand Down
55 changes: 32 additions & 23 deletions flecs.h
Original file line number Diff line number Diff line change
Expand Up @@ -13042,8 +13042,6 @@ typedef struct EcsMetaType {
ecs_type_kind_t kind;
bool existing; /**< Did the type exist or is it populated from reflection */
bool partial; /**< Is the reflection data a partial type description */
ecs_size_t size; /**< Computed size */
ecs_size_t alignment; /**< Computed alignment */
} EcsMetaType;

/** Primitive type kinds supported by meta addon */
Expand Down Expand Up @@ -15864,7 +15862,7 @@ struct string {
return m_const_str;
}

std::size_t length() {
std::size_t length() const {
return static_cast<std::size_t>(m_length);
}

Expand All @@ -15873,7 +15871,7 @@ struct string {
return N - 1;
}

std::size_t size() {
std::size_t size() const {
return length();
}

Expand Down Expand Up @@ -24733,25 +24731,6 @@ struct untyped_component : entity {
* @{
*/

/** Add member. */
untyped_component& member(flecs::entity_t type_id, const char *name, int32_t count = 0, size_t offset = 0) {
ecs_entity_desc_t desc = {};
desc.name = name;
desc.add[0] = ecs_pair(flecs::ChildOf, m_id);
ecs_entity_t eid = ecs_entity_init(m_world, &desc);
ecs_assert(eid != 0, ECS_INTERNAL_ERROR, NULL);

flecs::entity e(m_world, eid);

Member m = {};
m.type = type_id;
m.count = count;
m.offset = static_cast<int32_t>(offset);
e.set<Member>(m);

return *this;
}

/** Add member with unit. */
untyped_component& member(flecs::entity_t type_id, flecs::entity_t unit, const char *name, int32_t count = 0, size_t offset = 0) {
ecs_entity_desc_t desc = {};
Expand All @@ -24772,6 +24751,11 @@ untyped_component& member(flecs::entity_t type_id, flecs::entity_t unit, const c
return *this;
}

/** Add member. */
untyped_component& member(flecs::entity_t type_id, const char* name, int32_t count = 0, size_t offset = 0) {
return member(type_id, 0, name, count, offset);
}

/** Add member. */
template <typename MemberType>
untyped_component& member(const char *name, int32_t count = 0, size_t offset = 0) {
Expand All @@ -24794,6 +24778,31 @@ untyped_component& member(const char *name, int32_t count = 0, size_t offset = 0
return member(type_id, unit_id, name, count, offset);
}

/** Add member using pointer-to-member. */
template <typename MemberType, typename ComponentType, typename RealType = typename std::remove_extent<MemberType>::type>
untyped_component& member(const char* name, const MemberType ComponentType::* ptr) {
flecs::entity_t type_id = _::cpp_type<RealType>::id(m_world);
size_t offset = reinterpret_cast<size_t>(&(static_cast<ComponentType*>(nullptr)->*ptr));
return member(type_id, name, std::extent<MemberType>::value, offset);
}

/** Add member with unit using pointer-to-member. */
template <typename MemberType, typename ComponentType, typename RealType = typename std::remove_extent<MemberType>::type>
untyped_component& member(flecs::entity_t unit, const char* name, const MemberType ComponentType::* ptr) {
flecs::entity_t type_id = _::cpp_type<RealType>::id(m_world);
size_t offset = reinterpret_cast<size_t>(&(static_cast<ComponentType*>(nullptr)->*ptr));
return member(type_id, unit, name, std::extent<MemberType>::value, offset);
}

/** Add member with unit using pointer-to-member. */
template <typename UnitType, typename MemberType, typename ComponentType, typename RealType = typename std::remove_extent<MemberType>::type>
untyped_component& member(const char* name, const MemberType ComponentType::* ptr) {
flecs::entity_t type_id = _::cpp_type<RealType>::id(m_world);
flecs::entity_t unit_id = _::cpp_type<UnitType>::id(m_world);
size_t offset = reinterpret_cast<size_t>(&(static_cast<ComponentType*>(nullptr)->*ptr));
return member(type_id, unit_id, name, std::extent<MemberType>::value, offset);
}

/** Add constant. */
untyped_component& constant(const char *name, int32_t value) {
ecs_add_id(m_world, m_id, _::cpp_type<flecs::Enum>::id(m_world));
Expand Down
49 changes: 30 additions & 19 deletions include/flecs/addons/cpp/mixins/meta/untyped_component.inl
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,6 @@
* @{
*/

/** Add member. */
untyped_component& member(flecs::entity_t type_id, const char *name, int32_t count = 0, size_t offset = 0) {
ecs_entity_desc_t desc = {};
desc.name = name;
desc.add[0] = ecs_pair(flecs::ChildOf, m_id);
ecs_entity_t eid = ecs_entity_init(m_world, &desc);
ecs_assert(eid != 0, ECS_INTERNAL_ERROR, NULL);

flecs::entity e(m_world, eid);

Member m = {};
m.type = type_id;
m.count = count;
m.offset = static_cast<int32_t>(offset);
e.set<Member>(m);

return *this;
}

/** Add member with unit. */
untyped_component& member(flecs::entity_t type_id, flecs::entity_t unit, const char *name, int32_t count = 0, size_t offset = 0) {
ecs_entity_desc_t desc = {};
Expand All @@ -49,6 +30,11 @@ untyped_component& member(flecs::entity_t type_id, flecs::entity_t unit, const c
return *this;
}

/** Add member. */
untyped_component& member(flecs::entity_t type_id, const char* name, int32_t count = 0, size_t offset = 0) {
return member(type_id, 0, name, count, offset);
}

/** Add member. */
template <typename MemberType>
untyped_component& member(const char *name, int32_t count = 0, size_t offset = 0) {
Expand All @@ -71,6 +57,31 @@ untyped_component& member(const char *name, int32_t count = 0, size_t offset = 0
return member(type_id, unit_id, name, count, offset);
}

/** Add member using pointer-to-member. */
template <typename MemberType, typename ComponentType, typename RealType = typename std::remove_extent<MemberType>::type>
untyped_component& member(const char* name, const MemberType ComponentType::* ptr) {
flecs::entity_t type_id = _::cpp_type<RealType>::id(m_world);
size_t offset = reinterpret_cast<size_t>(&(static_cast<ComponentType*>(nullptr)->*ptr));
return member(type_id, name, std::extent<MemberType>::value, offset);
}

/** Add member with unit using pointer-to-member. */
template <typename MemberType, typename ComponentType, typename RealType = typename std::remove_extent<MemberType>::type>
untyped_component& member(flecs::entity_t unit, const char* name, const MemberType ComponentType::* ptr) {
flecs::entity_t type_id = _::cpp_type<RealType>::id(m_world);
size_t offset = reinterpret_cast<size_t>(&(static_cast<ComponentType*>(nullptr)->*ptr));
return member(type_id, unit, name, std::extent<MemberType>::value, offset);
}

/** Add member with unit using pointer-to-member. */
template <typename UnitType, typename MemberType, typename ComponentType, typename RealType = typename std::remove_extent<MemberType>::type>
untyped_component& member(const char* name, const MemberType ComponentType::* ptr) {
flecs::entity_t type_id = _::cpp_type<RealType>::id(m_world);
flecs::entity_t unit_id = _::cpp_type<UnitType>::id(m_world);
size_t offset = reinterpret_cast<size_t>(&(static_cast<ComponentType*>(nullptr)->*ptr));
return member(type_id, unit_id, name, std::extent<MemberType>::value, offset);
}

/** Add constant. */
untyped_component& constant(const char *name, int32_t value) {
ecs_add_id(m_world, m_id, _::cpp_type<flecs::Enum>::id(m_world));
Expand Down
2 changes: 0 additions & 2 deletions include/flecs/addons/meta.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,6 @@ typedef struct EcsMetaType {
ecs_type_kind_t kind;
bool existing; /**< Did the type exist or is it populated from reflection */
bool partial; /**< Is the reflection data a partial type description */
ecs_size_t size; /**< Computed size */
ecs_size_t alignment; /**< Computed alignment */
} EcsMetaType;

/** Primitive type kinds supported by meta addon */
Expand Down
52 changes: 37 additions & 15 deletions src/addons/meta/meta.c
Original file line number Diff line number Diff line change
Expand Up @@ -299,19 +299,13 @@ int flecs_init_type(
ecs_err("computed size for '%s' matches with actual type but "
"alignment is different (%d vs. %d)", ecs_get_name(world, type),
alignment, comp->alignment);
} else {
/* If this is an existing type, the alignment can be larger but
* not smaller than the computed alignment. */
alignment = comp->alignment;
}
}

meta_type->partial = comp->size != size;
}

meta_type->kind = kind;
meta_type->size = size;
meta_type->alignment = alignment;
ecs_modified(world, type, EcsMetaType);

return 0;
Expand Down Expand Up @@ -457,7 +451,7 @@ int flecs_add_member_to_struct(
/* Get component of member type to get its size & alignment */
const EcsComponent *mbr_comp = ecs_get(world, elem->type, EcsComponent);
if (!mbr_comp) {
char *path = ecs_get_fullpath(world, member);
char *path = ecs_get_fullpath(world, elem->type);
ecs_err("member '%s' is not a type", path);
ecs_os_free(path);
return -1;
Expand All @@ -467,7 +461,7 @@ int flecs_add_member_to_struct(
ecs_size_t member_alignment = mbr_comp->alignment;

if (!member_size || !member_alignment) {
char *path = ecs_get_fullpath(world, member);
char *path = ecs_get_fullpath(world, elem->type);
ecs_err("member '%s' has 0 size/alignment");
ecs_os_free(path);
return -1;
Expand All @@ -494,14 +488,42 @@ int flecs_add_member_to_struct(
}
} else {
/* If members have explicit offsets, we can't rely on computed
* size/alignment values. Grab size of just added member instead. It
* doesn't matter if the size doesn't correspond to the actual struct
* size. The flecs_init_type function compares computed size with actual
* size/alignment values. Calculate size as if this is the last member
* instead, since this will validate if the member fits in the struct.
* It doesn't matter if the size is smaller than the actual struct size
* because flecs_init_type function compares computed size with actual
* (component) size to determine if the type is partial. */
const EcsComponent *cptr = ecs_get(world, m->type, EcsComponent);
ecs_assert(cptr != NULL, ECS_INTERNAL_ERROR, NULL);
size = cptr->size;
alignment = cptr->alignment;
ecs_member_t *elem = &members[i];

ecs_assert(elem->name != NULL, ECS_INTERNAL_ERROR, NULL);
ecs_assert(elem->type != 0, ECS_INTERNAL_ERROR, NULL);

/* Get component of member type to get its size & alignment */
const EcsComponent *mbr_comp = ecs_get(world, elem->type, EcsComponent);
if (!mbr_comp) {
char *path = ecs_get_fullpath(world, elem->type);
ecs_err("member '%s' is not a type", path);
ecs_os_free(path);
return -1;
}

ecs_size_t member_size = mbr_comp->size;
ecs_size_t member_alignment = mbr_comp->alignment;

if (!member_size || !member_alignment) {
char *path = ecs_get_fullpath(world, elem->type);
ecs_err("member '%s' has 0 size/alignment");
ecs_os_free(path);
return -1;
}

member_size *= elem->count;
elem->size = member_size;

size = elem->offset + member_size;

const EcsComponent* comp = ecs_get(world, type, EcsComponent);
alignment = comp->alignment;
}

if (size == 0) {
Expand Down
4 changes: 3 additions & 1 deletion test/cpp_api/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -1267,7 +1267,9 @@
"enum_w_bits",
"value_range",
"warning_range",
"error_range"
"error_range",
"struct_member_ptr",
"struct_member_ptr_packed_struct"
]
}, {
"id": "Table",
Expand Down
Loading

0 comments on commit c27c1da

Please sign in to comment.