#include #include #include "macros.h" #include "rt_struct.h" static int is_root_type(rts_type_tag tag) { return tag != TAG_STRUCT && tag != TAG_UNION; } static int member_is_ptr(rts_member_type type) { return type >= MBR_PTR && type <= MBR_PTR_ARRAY_NULL; } static int member_is_fixed_array(rts_member_type type) { return type == MBR_ARRAY || type == MBR_PTR_ARRAY; } static size_t member_size(rts_member *member) { const rts_type *type = (member_is_ptr(member->mbr_type)) ? &RTS_TYPE_POINTER : member->type; size_t size = type->size; if (member_is_fixed_array(member->mbr_type)) { for (int i = 0; i < member->dim_count && member->dim_sizes[i]; ++i) { size *= member->dim_sizes[i]; } } return size; } static int member_count(rts_type *type) { if (type == NULL || type->members == NULL) { return -1; } else { int i; for (i = 0; type->members[i] != NULL; ++i); return i; } } int create_rts(rts_type *type) { if (type == NULL) { return 1; } if (is_root_type(type->tag)) { return 0; } if (type->members == NULL || type->members[0] == NULL) { return 1; } else { size_t offset = 0; size_t max_align = 0; const int num_members = member_count(type); rts_member **members = type->members; if (type->offsets == NULL) { type->offsets = calloc(num_members+1, sizeof(size_t)); type->offsets[num_members] = -1; } for (int i = 0; members[i] != NULL; ++i) { if (create_rts(members[i]->type)) { return 1; } else { const rts_type *member_type = (member_is_ptr(members[i]->mbr_type)) ? &RTS_TYPE_POINTER : members[i]->type; const size_t align = member_type->alignment; max_align = max(max_align, align); if (type->tag == TAG_STRUCT) { if (!type->is_packed) { const size_t remainder = offset % align; const size_t padding = (remainder) ? align - remainder : 0; offset += padding; } type->offsets[i] = offset; offset += member_size(members[i]); } } } if (!type->is_packed) { const size_t remainder = offset % max_align; const size_t padding = (remainder) ? max_align - remainder : 0; offset += padding; } type->alignment = (!type->is_packed) ? max_align : 0; type->size = offset; return 0; } }