aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--enums.c5
-rw-r--r--stdlib/enums.h10
-rw-r--r--stdlib/structs.c14
-rw-r--r--stdlib/structs.h12
-rw-r--r--structs.c5
-rw-r--r--types.c36
-rw-r--r--types.h1
7 files changed, 78 insertions, 5 deletions
diff --git a/enums.c b/enums.c
index 2dcb7148..354d9752 100644
--- a/enums.c
+++ b/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);
diff --git a/stdlib/enums.h b/stdlib/enums.h
index 35c3a22a..a61daacc 100644
--- a/stdlib/enums.h
+++ b/stdlib/enums.h
@@ -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
diff --git a/stdlib/structs.c b/stdlib/structs.c
index 010b49f7..1ff5a918 100644
--- a/stdlib/structs.c
+++ b/stdlib/structs.c
@@ -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);
diff --git a/stdlib/structs.h b/stdlib/structs.h
index 6553cc86..b027a01e 100644
--- a/stdlib/structs.h
+++ b/stdlib/structs.h
@@ -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
diff --git a/structs.c b/structs.c
index ce5116e0..8e184266 100644
--- a/structs.c
+++ b/structs.c
@@ -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);
diff --git a/types.c b/types.c
index 2b421b40..5c37a686 100644
--- a/types.c
+++ b/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;
}
diff --git a/types.h b/types.h
index 0163c4dc..29098835 100644
--- a/types.h
+++ b/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);