Skip to content

Commit

Permalink
Make it possible to create metrics for nested members
Browse files Browse the repository at this point in the history
  • Loading branch information
SanderMertens committed Oct 3, 2023
1 parent 7e05ef3 commit 3a9d67c
Show file tree
Hide file tree
Showing 17 changed files with 397 additions and 57 deletions.
113 changes: 87 additions & 26 deletions flecs.c
Original file line number Diff line number Diff line change
Expand Up @@ -28952,18 +28952,74 @@ int flecs_member_metric_init(
ecs_entity_t metric,
const ecs_metric_desc_t *desc)
{
const EcsMember *m = ecs_get(world, desc->member, EcsMember);
if (!m) {
char *metric_name = ecs_get_fullpath(world, metric);
char *member_name = ecs_get_fullpath(world, desc->member);
ecs_err("entity '%s' provided for metric '%s' is not a member",
member_name, metric_name);
ecs_os_free(member_name);
ecs_os_free(metric_name);
goto error;
ecs_entity_t type = 0, member_type = 0, member = 0;
uintptr_t offset = 0;

if (desc->dotmember) {
if (!desc->id) {
char *metric_name = ecs_get_fullpath(world, metric);
ecs_err("missing id for metric '%s' with member '%s",
metric_name, desc->dotmember);
ecs_os_free(metric_name);
goto error;
}

if (desc->member) {
char *metric_name = ecs_get_fullpath(world, metric);
ecs_err("cannot set both member and dotmember for metric '%s'",
metric_name);
ecs_os_free(metric_name);
goto error;
}

ecs_meta_cursor_t cur = ecs_meta_cursor(world, desc->id, NULL);
if (ecs_meta_push(&cur)) {
char *metric_name = ecs_get_fullpath(world, metric);
ecs_err("invalid type for metric '%s'", metric_name);
ecs_os_free(metric_name);
goto error;
}
if (ecs_meta_dotmember(&cur, desc->dotmember)) {
char *metric_name = ecs_get_fullpath(world, metric);
ecs_err("invalid dotmember '%s' for metric '%s'",
desc->dotmember, metric_name);
ecs_os_free(metric_name);
goto error;
}

type = desc->id;
member_type = ecs_meta_get_type(&cur);
offset = (uintptr_t)ecs_meta_get_ptr(&cur);
member = ecs_meta_get_member_id(&cur);
} else {
const EcsMember *m = ecs_get(world, desc->member, EcsMember);
if (!m) {
char *metric_name = ecs_get_fullpath(world, metric);
char *member_name = ecs_get_fullpath(world, desc->member);
ecs_err("entity '%s' provided for metric '%s' is not a member",
member_name, metric_name);
ecs_os_free(member_name);
ecs_os_free(metric_name);
goto error;
}

type = ecs_get_parent(world, desc->member);
if (!type) {
char *metric_name = ecs_get_fullpath(world, metric);
char *member_name = ecs_get_fullpath(world, desc->member);
ecs_err("member '%s' provided for metric '%s' is not part of a type",
member_name, metric_name);
ecs_os_free(member_name);
ecs_os_free(metric_name);
goto error;
}

member = desc->member;
member_type = m->type;
offset = flecs_ito(uintptr_t, m->offset);
}

const EcsPrimitive *p = ecs_get(world, m->type, EcsPrimitive);
const EcsPrimitive *p = ecs_get(world, member_type, EcsPrimitive);
if (!p) {
char *metric_name = ecs_get_fullpath(world, metric);
char *member_name = ecs_get_fullpath(world, desc->member);
Expand All @@ -28974,17 +29030,6 @@ int flecs_member_metric_init(
goto error;
}

ecs_entity_t type = ecs_get_parent(world, desc->member);
if (!type) {
char *metric_name = ecs_get_fullpath(world, metric);
char *member_name = ecs_get_fullpath(world, desc->member);
ecs_err("member '%s' provided for metric '%s' is not part of a type",
member_name, metric_name);
ecs_os_free(member_name);
ecs_os_free(metric_name);
goto error;
}

const EcsMetaType *mt = ecs_get(world, type, EcsMetaType);
if (!mt) {
char *metric_name = ecs_get_fullpath(world, metric);
Expand All @@ -29010,7 +29055,7 @@ int flecs_member_metric_init(
ctx->metric.metric = metric;
ctx->metric.kind = desc->kind;
ctx->type_kind = p->kind;
ctx->offset = flecs_ito(uint16_t, m->offset);
ctx->offset = flecs_uto(uint16_t, offset);

ecs_observer(world, {
.entity = metric,
Expand All @@ -29025,7 +29070,7 @@ int flecs_member_metric_init(
.ctx = ctx
});

ecs_set_pair(world, metric, EcsMetricMember, desc->member, { .ctx = ctx });
ecs_set_pair(world, metric, EcsMetricMember, member, { .ctx = ctx });
ecs_add_pair(world, metric, EcsMetric, desc->kind);
ecs_add_id(world, metric, EcsMetric);

Expand Down Expand Up @@ -29223,8 +29268,8 @@ ecs_entity_t ecs_metric_init(
#endif
}

if (desc->member) {
if (desc->id) {
if (desc->member || desc->dotmember) {
if (desc->id && desc->member) {
ecs_err("cannot specify both member and id for metric");
goto error;
}
Expand Down Expand Up @@ -54046,7 +54091,6 @@ ecs_meta_cursor_t ecs_meta_cursor(
{
ecs_check(world != NULL, ECS_INVALID_PARAMETER, NULL);
ecs_check(type != 0, ECS_INVALID_PARAMETER, NULL);
ecs_check(ptr != NULL, ECS_INVALID_PARAMETER, NULL);

ecs_meta_cursor_t result = {
.world = world,
Expand Down Expand Up @@ -54560,6 +54604,23 @@ const char* ecs_meta_get_member(
return op->name;
}

ecs_entity_t ecs_meta_get_member_id(
const ecs_meta_cursor_t *cursor)
{
ecs_meta_scope_t *scope = flecs_meta_cursor_get_scope(cursor);
ecs_entity_t type = scope->type;
const EcsStruct *st = ecs_get(cursor->world, type, EcsStruct);
if (!st) {
return 0;
}

ecs_meta_type_op_t *op = flecs_meta_cursor_get_op(scope);
ecs_member_t *m = ecs_vec_get_t(
&st->members, ecs_member_t, op->member_index);

return m->member;
}

/* Utilities for type conversions and bounds checking */
static struct {
int64_t min, max;
Expand Down
27 changes: 27 additions & 0 deletions flecs.h
Original file line number Diff line number Diff line change
Expand Up @@ -11866,6 +11866,11 @@ typedef struct ecs_metric_desc_t {
* at the same time as id. Cannot be combined with EcsCounterId. */
ecs_entity_t member;

/* Member dot expression. Can be used instead of member and supports nested
* members. Must be set together with id and should not be set at the same
* time as member. */
const char *dotmember;

/** Tracks whether entities have the specified component id. Must not be set
* at the same time as member. */
ecs_id_t id;
Expand Down Expand Up @@ -13847,6 +13852,11 @@ FLECS_API
const char* ecs_meta_get_member(
const ecs_meta_cursor_t *cursor);

/** Get member entity of current member */
FLECS_API
ecs_entity_t ecs_meta_get_member_id(
const ecs_meta_cursor_t *cursor);

/* The set functions assign the field with the specified value. If the value
* does not have the same type as the field, it will be cased to the field type.
* If no valid conversion is available, the operation will fail. */
Expand Down Expand Up @@ -18287,6 +18297,11 @@ struct metric_builder {
template <typename T>
metric_builder& member(const char *name);

metric_builder& dotmember(const char *name);

template <typename T>
metric_builder& dotmember(const char *name);

metric_builder& id(flecs::id_t the_id) {
m_desc.id = the_id;
return *this;
Expand Down Expand Up @@ -30061,6 +30076,18 @@ inline metric_builder& metric_builder::member(const char *name) {
return member(m);
}

inline metric_builder& metric_builder::dotmember(const char *expr) {
m_desc.dotmember = expr;
return *this;
}

template <typename T>
inline metric_builder& metric_builder::dotmember(const char *expr) {
m_desc.dotmember = expr;
m_desc.id = _::cpp_type<T>::id(m_world);
return *this;
}

inline metric_builder::operator flecs::entity() {
if (!m_created) {
m_created = true;
Expand Down
5 changes: 5 additions & 0 deletions include/flecs/addons/cpp/mixins/metrics/builder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ struct metric_builder {
template <typename T>
metric_builder& member(const char *name);

metric_builder& dotmember(const char *name);

template <typename T>
metric_builder& dotmember(const char *name);

metric_builder& id(flecs::id_t the_id) {
m_desc.id = the_id;
return *this;
Expand Down
12 changes: 12 additions & 0 deletions include/flecs/addons/cpp/mixins/metrics/impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,18 @@ inline metric_builder& metric_builder::member(const char *name) {
return member(m);
}

inline metric_builder& metric_builder::dotmember(const char *expr) {
m_desc.dotmember = expr;
return *this;
}

template <typename T>
inline metric_builder& metric_builder::dotmember(const char *expr) {
m_desc.dotmember = expr;
m_desc.id = _::cpp_type<T>::id(m_world);
return *this;
}

inline metric_builder::operator flecs::entity() {
if (!m_created) {
m_created = true;
Expand Down
5 changes: 5 additions & 0 deletions include/flecs/addons/meta.h
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,11 @@ FLECS_API
const char* ecs_meta_get_member(
const ecs_meta_cursor_t *cursor);

/** Get member entity of current member */
FLECS_API
ecs_entity_t ecs_meta_get_member_id(
const ecs_meta_cursor_t *cursor);

/* The set functions assign the field with the specified value. If the value
* does not have the same type as the field, it will be cased to the field type.
* If no valid conversion is available, the operation will fail. */
Expand Down
5 changes: 5 additions & 0 deletions include/flecs/addons/metrics.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ typedef struct ecs_metric_desc_t {
* at the same time as id. Cannot be combined with EcsCounterId. */
ecs_entity_t member;

/* Member dot expression. Can be used instead of member and supports nested
* members. Must be set together with id and should not be set at the same
* time as member. */
const char *dotmember;

/** Tracks whether entities have the specified component id. Must not be set
* at the same time as member. */
ecs_id_t id;
Expand Down
18 changes: 17 additions & 1 deletion src/addons/meta/cursor.c
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,6 @@ ecs_meta_cursor_t ecs_meta_cursor(
{
ecs_check(world != NULL, ECS_INVALID_PARAMETER, NULL);
ecs_check(type != 0, ECS_INVALID_PARAMETER, NULL);
ecs_check(ptr != NULL, ECS_INVALID_PARAMETER, NULL);

ecs_meta_cursor_t result = {
.world = world,
Expand Down Expand Up @@ -711,6 +710,23 @@ const char* ecs_meta_get_member(
return op->name;
}

ecs_entity_t ecs_meta_get_member_id(
const ecs_meta_cursor_t *cursor)
{
ecs_meta_scope_t *scope = flecs_meta_cursor_get_scope(cursor);
ecs_entity_t type = scope->type;
const EcsStruct *st = ecs_get(cursor->world, type, EcsStruct);
if (!st) {
return 0;
}

ecs_meta_type_op_t *op = flecs_meta_cursor_get_op(scope);
ecs_member_t *m = ecs_vec_get_t(
&st->members, ecs_member_t, op->member_index);

return m->member;
}

/* Utilities for type conversions and bounds checking */
static struct {
int64_t min, max;
Expand Down
Loading

0 comments on commit 3a9d67c

Please sign in to comment.