Add optimized metamethods for enums and structs that hold packed data

This commit is contained in:
Bruce Hill 2024-12-22 15:53:26 -05:00
parent cdda494fe5
commit 3dd7854076
7 changed files with 78 additions and 5 deletions

View File

@ -46,9 +46,10 @@ void compile_enum_def(env_t *env, ast_t *ast)
num_tags += 1;
type_t *t = Table$str_get(*env->types, def->name);
CORD typeinfo = CORD_asprintf("public const TypeInfo_t %r = {%zu, %zu, .metamethods=Enum$metamethods, {.tag=EnumInfo, .EnumInfo={.name=\"%s\", "
const char *metamethods = is_packed_data(t) ? "PackedDataEnum$metamethods" : "Enum$metamethods";
CORD typeinfo = CORD_asprintf("public const TypeInfo_t %r = {%zu, %zu, .metamethods=%s, {.tag=EnumInfo, .EnumInfo={.name=\"%s\", "
".num_tags=%d, .tags=(NamedType_t[]){",
full_name, type_size(t), type_align(t), def->name, num_tags);
full_name, type_size(t), type_align(t), metamethods, def->name, num_tags);
for (tag_ast_t *tag = def->tags; tag; tag = tag->next) {
const char *tag_type_name = heap_strf("%s$%s", def->name, tag->name);

View File

@ -25,4 +25,14 @@ void Enum$deserialize(FILE *in, void *outval, Array_t *pointers, const TypeInfo_
.deserialize=Enum$deserialize, \
})
#define PackedDataEnum$metamethods ((metamethods_t){ \
.hash=PackedData$hash, \
.compare=Enum$compare, \
.equal=PackedData$equal, \
.as_text=Enum$as_text, \
.is_none=Enum$is_none, \
.serialize=Enum$serialize, \
.deserialize=Enum$deserialize, \
})
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0

View File

@ -53,6 +53,14 @@ PUREFUNC public uint64_t Struct$hash(const void *obj, const TypeInfo_t *type)
}
#pragma GCC diagnostic pop
PUREFUNC public uint64_t PackedData$hash(const void *obj, const TypeInfo_t *type)
{
if (type->StructInfo.num_fields == 0)
return 0;
return siphash24(obj, (size_t)type->size);
}
PUREFUNC public int32_t Struct$compare(const void *x, const void *y, const TypeInfo_t *type)
{
if (x == y)
@ -122,6 +130,12 @@ PUREFUNC public bool Struct$equal(const void *x, const void *y, const TypeInfo_t
return true;
}
PUREFUNC public bool PackedData$equal(const void *x, const void *y, const TypeInfo_t *type)
{
if (x == y) return true;
return (memcmp(x, y, (size_t)type->size) == 0);
}
PUREFUNC public Text_t Struct$as_text(const void *obj, bool colorize, const TypeInfo_t *type)
{
if (!obj) return Text$from_str(type->StructInfo.name);

View File

@ -8,8 +8,10 @@
#include "util.h"
PUREFUNC uint64_t Struct$hash(const void *obj, const TypeInfo_t *type);
PUREFUNC uint64_t PackedData$hash(const void *obj, const TypeInfo_t *type);
PUREFUNC int32_t Struct$compare(const void *x, const void *y, const TypeInfo_t *type);
PUREFUNC bool Struct$equal(const void *x, const void *y, const TypeInfo_t *type);
PUREFUNC bool PackedData$equal(const void *x, const void *y, const TypeInfo_t *type);
PUREFUNC Text_t Struct$as_text(const void *obj, bool colorize, const TypeInfo_t *type);
PUREFUNC bool Struct$is_none(const void *obj, const TypeInfo_t *type);
void Struct$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type);
@ -25,4 +27,14 @@ void Struct$deserialize(FILE *in, void *outval, Array_t *pointers, const TypeInf
.deserialize=Struct$deserialize, \
})
#define PackedData$metamethods ((metamethods_t){ \
.hash=PackedData$hash, \
.compare=Struct$compare, \
.equal=PackedData$equal, \
.as_text=Struct$as_text, \
.is_none=Struct$is_none, \
.serialize=Struct$serialize, \
.deserialize=Struct$deserialize, \
})
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0

View File

@ -27,10 +27,11 @@ void compile_struct_def(env_t *env, ast_t *ast)
short_name = strrchr(short_name, '$') + 1;
env->code->typeinfos = CORD_all("public const TypeInfo_t ", full_name, ";\n", env->code->typeinfos);
CORD typeinfo = CORD_asprintf("public const TypeInfo_t %r = {.size=%zu, .align=%zu, .metamethods=Struct$metamethods, "
const char *metamethods = is_packed_data(t) ? "PackedData$metamethods" : "Struct$metamethods";
CORD typeinfo = CORD_asprintf("public const TypeInfo_t %r = {.size=%zu, .align=%zu, .metamethods=%s, "
".tag=StructInfo, .StructInfo.name=\"%s\"%s, "
".StructInfo.num_fields=%ld",
full_name, type_size(t), type_align(t), short_name, def->secret ? ", .StructInfo.is_secret=true" : "",
full_name, type_size(t), type_align(t), metamethods, short_name, def->secret ? ", .StructInfo.is_secret=true" : "",
num_fields);
if (def->fields) {
typeinfo = CORD_asprintf("%r, .StructInfo.fields=(NamedType_t[%d]){", typeinfo, num_fields);

36
types.c
View File

@ -444,21 +444,55 @@ PUREFUNC bool is_numeric_type(type_t *t)
return t->tag == IntType || t->tag == BigIntType || t->tag == NumType || t->tag == ByteType;
}
PUREFUNC bool is_packed_data(type_t *t)
{
if (t->tag == IntType || t->tag == NumType || t->tag == ByteType || t->tag == PointerType || t->tag == BoolType || t->tag == FunctionType) {
return true;
} else if (t->tag == StructType) {
for (arg_t *field = Match(t, StructType)->fields; field; field = field->next) {
if (!is_packed_data(field->type))
return false;
}
return true;
} else if (t->tag == EnumType) {
for (tag_t *tag = Match(t, EnumType)->tags; tag; tag = tag->next) {
if (!is_packed_data(tag->type))
return false;
}
return true;
} else {
return false;
}
}
PUREFUNC size_t unpadded_struct_size(type_t *t)
{
arg_t *fields = Match(t, StructType)->fields;
size_t size = 0;
size_t bit_offset = 0;
for (arg_t *field = fields; field; field = field->next) {
type_t *field_type = field->type;
if (field_type->tag == BoolType) {
size += 1; // Bit packing
bit_offset += 1;
if (bit_offset >= 8) {
size += 1;
bit_offset = 0;
}
} else {
if (bit_offset > 0) {
size += 1;
bit_offset = 0;
}
size_t align = type_align(field_type);
if (align > 1 && size % align > 0)
size += align - (size % align); // Padding
size += type_size(field_type);
}
}
if (bit_offset > 0) {
size += 1;
bit_offset = 0;
}
return size;
}

View File

@ -150,6 +150,7 @@ PUREFUNC bool can_promote(type_t *actual, type_t *needed);
PUREFUNC const char *enum_single_value_tag(type_t *enum_type, type_t *t);
PUREFUNC bool is_int_type(type_t *t);
PUREFUNC bool is_numeric_type(type_t *t);
PUREFUNC bool is_packed_data(type_t *t);
PUREFUNC size_t type_size(type_t *t);
PUREFUNC size_t type_align(type_t *t);
PUREFUNC size_t unpadded_struct_size(type_t *t);