Add optimized metamethods for enums and structs that hold packed data
This commit is contained in:
parent
cdda494fe5
commit
3dd7854076
5
enums.c
5
enums.c
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
36
types.c
@ -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;
|
||||
}
|
||||
|
||||
|
1
types.h
1
types.h
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user