296 lines
7.4 KiB
C
296 lines
7.4 KiB
C
/**
|
|
* @file meta/serialized.c
|
|
* @brief Serialize type into flat operations array to speed up deserialization.
|
|
*/
|
|
|
|
#include "meta.h"
|
|
|
|
#ifdef FLECS_META
|
|
|
|
static
|
|
int flecs_meta_serialize_type(
|
|
ecs_world_t *world,
|
|
ecs_entity_t type,
|
|
ecs_size_t offset,
|
|
ecs_vec_t *ops);
|
|
|
|
ecs_meta_type_op_kind_t flecs_meta_primitive_to_op_kind(ecs_primitive_kind_t kind) {
|
|
return EcsOpPrimitive + kind;
|
|
}
|
|
|
|
static
|
|
ecs_size_t flecs_meta_type_size(ecs_world_t *world, ecs_entity_t type) {
|
|
const EcsComponent *comp = ecs_get(world, type, EcsComponent);
|
|
ecs_assert(comp != NULL, ECS_INTERNAL_ERROR, NULL);
|
|
return comp->size;
|
|
}
|
|
|
|
static
|
|
ecs_meta_type_op_t* flecs_meta_ops_add(ecs_vec_t *ops, ecs_meta_type_op_kind_t kind) {
|
|
ecs_meta_type_op_t *op = ecs_vec_append_t(NULL, ops, ecs_meta_type_op_t);
|
|
op->kind = kind;
|
|
op->offset = 0;
|
|
op->count = 1;
|
|
op->op_count = 1;
|
|
op->size = 0;
|
|
op->name = NULL;
|
|
op->members = NULL;
|
|
op->type = 0;
|
|
op->member_index = 0;
|
|
return op;
|
|
}
|
|
|
|
static
|
|
ecs_meta_type_op_t* flecs_meta_ops_get(ecs_vec_t *ops, int32_t index) {
|
|
ecs_meta_type_op_t* op = ecs_vec_get_t(ops, ecs_meta_type_op_t, index);
|
|
ecs_assert(op != NULL, ECS_INTERNAL_ERROR, NULL);
|
|
return op;
|
|
}
|
|
|
|
static
|
|
int flecs_meta_serialize_primitive(
|
|
ecs_world_t *world,
|
|
ecs_entity_t type,
|
|
ecs_size_t offset,
|
|
ecs_vec_t *ops)
|
|
{
|
|
const EcsPrimitive *ptr = ecs_get(world, type, EcsPrimitive);
|
|
if (!ptr) {
|
|
char *name = ecs_get_fullpath(world, type);
|
|
ecs_err("entity '%s' is not a primitive type", name);
|
|
ecs_os_free(name);
|
|
return -1;
|
|
}
|
|
|
|
ecs_meta_type_op_t *op = flecs_meta_ops_add(ops, flecs_meta_primitive_to_op_kind(ptr->kind));
|
|
op->offset = offset;
|
|
op->type = type;
|
|
op->size = flecs_meta_type_size(world, type);
|
|
return 0;
|
|
}
|
|
|
|
static
|
|
int flecs_meta_serialize_enum(
|
|
ecs_world_t *world,
|
|
ecs_entity_t type,
|
|
ecs_size_t offset,
|
|
ecs_vec_t *ops)
|
|
{
|
|
(void)world;
|
|
|
|
ecs_meta_type_op_t *op = flecs_meta_ops_add(ops, EcsOpEnum);
|
|
op->offset = offset;
|
|
op->type = type;
|
|
op->size = ECS_SIZEOF(ecs_i32_t);
|
|
return 0;
|
|
}
|
|
|
|
static
|
|
int flecs_meta_serialize_bitmask(
|
|
ecs_world_t *world,
|
|
ecs_entity_t type,
|
|
ecs_size_t offset,
|
|
ecs_vec_t *ops)
|
|
{
|
|
(void)world;
|
|
|
|
ecs_meta_type_op_t *op = flecs_meta_ops_add(ops, EcsOpBitmask);
|
|
op->offset = offset;
|
|
op->type = type;
|
|
op->size = ECS_SIZEOF(ecs_u32_t);
|
|
return 0;
|
|
}
|
|
|
|
static
|
|
int flecs_meta_serialize_array(
|
|
ecs_world_t *world,
|
|
ecs_entity_t type,
|
|
ecs_size_t offset,
|
|
ecs_vec_t *ops)
|
|
{
|
|
(void)world;
|
|
|
|
ecs_meta_type_op_t *op = flecs_meta_ops_add(ops, EcsOpArray);
|
|
op->offset = offset;
|
|
op->type = type;
|
|
op->size = flecs_meta_type_size(world, type);
|
|
return 0;
|
|
}
|
|
|
|
static
|
|
int flecs_meta_serialize_array_component(
|
|
ecs_world_t *world,
|
|
ecs_entity_t type,
|
|
ecs_vec_t *ops)
|
|
{
|
|
const EcsArray *ptr = ecs_get(world, type, EcsArray);
|
|
if (!ptr) {
|
|
return -1; /* Should never happen, will trigger internal error */
|
|
}
|
|
|
|
flecs_meta_serialize_type(world, ptr->type, 0, ops);
|
|
|
|
ecs_meta_type_op_t *first = ecs_vec_first(ops);
|
|
first->count = ptr->count;
|
|
return 0;
|
|
}
|
|
|
|
static
|
|
int flecs_meta_serialize_vector(
|
|
ecs_world_t *world,
|
|
ecs_entity_t type,
|
|
ecs_size_t offset,
|
|
ecs_vec_t *ops)
|
|
{
|
|
(void)world;
|
|
ecs_meta_type_op_t *op = flecs_meta_ops_add(ops, EcsOpVector);
|
|
op->offset = offset;
|
|
op->type = type;
|
|
op->size = flecs_meta_type_size(world, type);
|
|
return 0;
|
|
}
|
|
|
|
static
|
|
int flecs_meta_serialize_custom_type(
|
|
ecs_world_t *world,
|
|
ecs_entity_t type,
|
|
ecs_size_t offset,
|
|
ecs_vec_t *ops)
|
|
{
|
|
(void)world;
|
|
ecs_meta_type_op_t *op = flecs_meta_ops_add(ops, EcsOpOpaque);
|
|
op->offset = offset;
|
|
op->type = type;
|
|
op->size = flecs_meta_type_size(world, type);
|
|
return 0;
|
|
}
|
|
|
|
static
|
|
int flecs_meta_serialize_struct(
|
|
ecs_world_t *world,
|
|
ecs_entity_t type,
|
|
ecs_size_t offset,
|
|
ecs_vec_t *ops)
|
|
{
|
|
const EcsStruct *ptr = ecs_get(world, type, EcsStruct);
|
|
ecs_assert(ptr != NULL, ECS_INTERNAL_ERROR, NULL);
|
|
|
|
int32_t cur, first = ecs_vec_count(ops);
|
|
ecs_meta_type_op_t *op = flecs_meta_ops_add(ops, EcsOpPush);
|
|
op->offset = offset;
|
|
op->type = type;
|
|
op->size = flecs_meta_type_size(world, type);
|
|
|
|
ecs_member_t *members = ecs_vec_first(&ptr->members);
|
|
int32_t i, count = ecs_vec_count(&ptr->members);
|
|
|
|
ecs_hashmap_t *member_index = NULL;
|
|
if (count) {
|
|
op->members = member_index = flecs_name_index_new(
|
|
world, &world->allocator);
|
|
}
|
|
|
|
for (i = 0; i < count; i ++) {
|
|
ecs_member_t *member = &members[i];
|
|
|
|
cur = ecs_vec_count(ops);
|
|
flecs_meta_serialize_type(world,
|
|
member->type, offset + member->offset, ops);
|
|
|
|
op = flecs_meta_ops_get(ops, cur);
|
|
if (!op->type) {
|
|
op->type = member->type;
|
|
}
|
|
|
|
if (op->count <= 1) {
|
|
op->count = member->count;
|
|
}
|
|
|
|
const char *member_name = member->name;
|
|
op->name = member_name;
|
|
op->op_count = ecs_vec_count(ops) - cur;
|
|
op->member_index = i;
|
|
|
|
flecs_name_index_ensure(
|
|
member_index, flecs_ito(uint64_t, cur - first - 1),
|
|
member_name, 0, 0);
|
|
}
|
|
|
|
flecs_meta_ops_add(ops, EcsOpPop);
|
|
flecs_meta_ops_get(ops, first)->op_count = ecs_vec_count(ops) - first;
|
|
return 0;
|
|
}
|
|
|
|
static
|
|
int flecs_meta_serialize_type(
|
|
ecs_world_t *world,
|
|
ecs_entity_t type,
|
|
ecs_size_t offset,
|
|
ecs_vec_t *ops)
|
|
{
|
|
const EcsMetaType *ptr = ecs_get(world, type, EcsMetaType);
|
|
if (!ptr) {
|
|
char *path = ecs_get_fullpath(world, type);
|
|
ecs_err("missing EcsMetaType for type %s'", path);
|
|
ecs_os_free(path);
|
|
return -1;
|
|
}
|
|
|
|
switch(ptr->kind) {
|
|
case EcsPrimitiveType: return flecs_meta_serialize_primitive(world, type, offset, ops);
|
|
case EcsEnumType: return flecs_meta_serialize_enum(world, type, offset, ops);
|
|
case EcsBitmaskType: return flecs_meta_serialize_bitmask(world, type, offset, ops);
|
|
case EcsStructType: return flecs_meta_serialize_struct(world, type, offset, ops);
|
|
case EcsArrayType: return flecs_meta_serialize_array(world, type, offset, ops);
|
|
case EcsVectorType: return flecs_meta_serialize_vector(world, type, offset, ops);
|
|
case EcsOpaqueType: return flecs_meta_serialize_custom_type(world, type, offset, ops);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static
|
|
int flecs_meta_serialize_component(
|
|
ecs_world_t *world,
|
|
ecs_entity_t type,
|
|
ecs_vec_t *ops)
|
|
{
|
|
const EcsMetaType *ptr = ecs_get(world, type, EcsMetaType);
|
|
if (!ptr) {
|
|
char *path = ecs_get_fullpath(world, type);
|
|
ecs_err("missing EcsMetaType for type %s'", path);
|
|
ecs_os_free(path);
|
|
return -1;
|
|
}
|
|
|
|
if (ptr->kind == EcsArrayType) {
|
|
return flecs_meta_serialize_array_component(world, type, ops);
|
|
} else {
|
|
return flecs_meta_serialize_type(world, type, 0, ops);
|
|
}
|
|
}
|
|
|
|
void ecs_meta_type_serialized_init(
|
|
ecs_iter_t *it)
|
|
{
|
|
ecs_world_t *world = it->world;
|
|
|
|
int i, count = it->count;
|
|
for (i = 0; i < count; i ++) {
|
|
ecs_entity_t e = it->entities[i];
|
|
ecs_vec_t ops;
|
|
ecs_vec_init_t(NULL, &ops, ecs_meta_type_op_t, 0);
|
|
flecs_meta_serialize_component(world, e, &ops);
|
|
|
|
EcsMetaTypeSerialized *ptr = ecs_get_mut(
|
|
world, e, EcsMetaTypeSerialized);
|
|
if (ptr->ops.array) {
|
|
ecs_meta_dtor_serialized(ptr);
|
|
}
|
|
|
|
ptr->ops = ops;
|
|
}
|
|
}
|
|
|
|
#endif
|