/** * @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