1 // Metamethods for structs
7 #include "metamethods.h"
14 #pragma GCC diagnostic push
15 #pragma GCC diagnostic ignored "-Wstack-protector"
17 PUREFUNC public uint64_t Struct$hash(const void *obj, const TypeInfo_t *type) {
18 if (type->StructInfo.num_fields == 0) return 0;
20 if (type->StructInfo.num_fields == 1) return generic_hash(obj, type->StructInfo.fields[0].type);
22 uint64_t field_hashes[type->StructInfo.num_fields];
23 ptrdiff_t byte_offset = 0;
24 ptrdiff_t bit_offset = 0;
25 for (int i = 0; i < type->StructInfo.num_fields; i++) {
26 NamedType_t field = type->StructInfo.fields[i];
27 if (field.type == &Bool$info) {
28 bool b = ((*(char *)(obj + byte_offset)) >> bit_offset) & 0x1;
29 field_hashes[i] = (uint32_t)b;
31 if (bit_offset >= 8) {
40 if (field.type->align && byte_offset % field.type->align > 0)
41 byte_offset += field.type->align - (byte_offset % field.type->align);
42 field_hashes[i] = generic_hash(obj + byte_offset, field.type);
43 byte_offset += field.type->size;
46 return siphash24((void *)field_hashes, sizeof(field_hashes));
49 #pragma GCC diagnostic pop
52 PUREFUNC public uint64_t PackedData$hash(const void *obj, const TypeInfo_t *type) {
53 if (type->StructInfo.num_fields == 0) return 0;
55 return siphash24(obj, (size_t)type->size);
58 PUREFUNC public int32_t Struct$compare(const void *x, const void *y, const TypeInfo_t *type) {
61 ptrdiff_t byte_offset = 0;
62 ptrdiff_t bit_offset = 0;
63 for (int i = 0; i < type->StructInfo.num_fields; i++) {
64 NamedType_t field = type->StructInfo.fields[i];
65 if (field.type == &Bool$info) {
66 bool bx = ((*(char *)(x + byte_offset)) >> bit_offset) & 0x1;
67 bool by = ((*(char *)(y + byte_offset)) >> bit_offset) & 0x1;
68 if (bx != by) return (int32_t)bx - (int32_t)by;
70 if (bit_offset >= 8) {
79 if (field.type->align && byte_offset % field.type->align > 0)
80 byte_offset += field.type->align - (byte_offset % field.type->align);
81 int32_t cmp = generic_compare(x + byte_offset, y + byte_offset, field.type);
82 if (cmp != 0) return cmp;
83 byte_offset += field.type->size;
89 PUREFUNC public bool Struct$equal(const void *x, const void *y, const TypeInfo_t *type) {
90 if (x == y) return true;
92 ptrdiff_t byte_offset = 0;
93 ptrdiff_t bit_offset = 0;
94 for (int i = 0; i < type->StructInfo.num_fields; i++) {
95 NamedType_t field = type->StructInfo.fields[i];
96 if (field.type == &Bool$info) {
97 bool bx = ((*(char *)(x + byte_offset)) >> bit_offset) & 0x1;
98 bool by = ((*(char *)(y + byte_offset)) >> bit_offset) & 0x1;
99 if (bx != by) return false;
101 if (bit_offset >= 8) {
106 if (bit_offset > 0) {
110 if (field.type->align && byte_offset % field.type->align > 0)
111 byte_offset += field.type->align - (byte_offset % field.type->align);
112 if (!generic_equal(x + byte_offset, y + byte_offset, field.type)) return false;
113 byte_offset += field.type->size;
119 PUREFUNC public bool PackedData$equal(const void *x, const void *y, const TypeInfo_t *type) {
120 if (x == y) return true;
121 return (memcmp(x, y, (size_t)type->size) == 0);
124 PUREFUNC public Text_t Struct$as_text(const void *obj, bool colorize, const TypeInfo_t *type) {
125 if (!obj) return Text$from_str(type->StructInfo.name);
127 Text_t name = Text$from_str(type->StructInfo.name);
128 if (type->StructInfo.is_secret || type->StructInfo.is_opaque) {
129 return colorize ? Text$concat(Text("\x1b[0;1m"), name, Text("\x1b[m(...)")) : Text$concat(name, Text("(...)"));
132 Text_t text = colorize ? Text$concat(Text("\x1b[0;1m"), name, Text("\x1b[m(")) : Text$concat(name, Text("("));
133 ptrdiff_t byte_offset = 0;
134 ptrdiff_t bit_offset = 0;
135 for (int i = 0; i < type->StructInfo.num_fields; i++) {
136 NamedType_t field = type->StructInfo.fields[i];
137 if (i > 0) text = Text$concat(text, Text(", "));
139 if (type->StructInfo.num_fields > 1) text = Text$concat(text, Text$from_str(field.name), Text("="));
141 if (field.type == &Bool$info) {
142 bool b = ((*(char *)(obj + byte_offset)) >> bit_offset) & 0x1;
144 text, Text$from_str(colorize ? (b ? "\x1b[35myes\x1b[m" : "\x1b[35mno\x1b[m") : (b ? "yes" : "no")));
146 if (bit_offset >= 8) {
151 if (bit_offset > 0) {
155 if (field.type->align && byte_offset % field.type->align > 0)
156 byte_offset += field.type->align - (byte_offset % field.type->align);
157 text = Text$concat(text, generic_as_text(obj + byte_offset, colorize, field.type));
158 byte_offset += field.type->size;
161 return Text$concat(text, Text(")"));
166 void Struct$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type) {
167 ptrdiff_t byte_offset = 0;
168 ptrdiff_t bit_offset = 0;
169 for (int i = 0; i < type->StructInfo.num_fields; i++) {
170 NamedType_t field = type->StructInfo.fields[i];
171 if (field.type == &Bool$info) {
172 bool b = ((*(char *)(obj + byte_offset)) >> bit_offset) & 0x1;
175 if (bit_offset >= 8) {
180 if (bit_offset > 0) {
184 if (field.type->align && byte_offset % field.type->align > 0)
185 byte_offset += field.type->align - (byte_offset % field.type->align);
186 _serialize(obj + byte_offset, out, pointers, field.type);
187 byte_offset += field.type->size;
193 void Struct$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_t *type) {
194 ptrdiff_t byte_offset = 0;
195 ptrdiff_t bit_offset = 0;
196 for (int i = 0; i < type->StructInfo.num_fields; i++) {
197 NamedType_t field = type->StructInfo.fields[i];
198 if (field.type == &Bool$info) {
199 bool b = (bool)fgetc(in);
200 *(char *)(outval + byte_offset) |= (b << bit_offset);
202 if (bit_offset >= 8) {
207 if (bit_offset > 0) {
211 if (field.type->align && byte_offset % field.type->align > 0)
212 byte_offset += field.type->align - (byte_offset % field.type->align);
213 _deserialize(in, outval + byte_offset, pointers, field.type);
214 byte_offset += field.type->size;