diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2024-11-29 12:55:14 -0500 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2024-11-29 12:55:14 -0500 |
| commit | 4b5e4cd1f21582f5e5fa682ab4e4bff252963468 (patch) | |
| tree | e8fecb01f444c1d392c09255adba5cf6b312b326 /stdlib/metamethods.c | |
| parent | 0b0e0a0a1d41e9574de8dc17c688a4894c5e7f92 (diff) | |
Change how types handle metamethods
Diffstat (limited to 'stdlib/metamethods.c')
| -rw-r--r-- | stdlib/metamethods.c | 234 |
1 files changed, 13 insertions, 221 deletions
diff --git a/stdlib/metamethods.c b/stdlib/metamethods.c index 6c8583f3..28d97730 100644 --- a/stdlib/metamethods.c +++ b/stdlib/metamethods.c @@ -15,247 +15,40 @@ #include "text.h" #include "util.h" - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wstack-protector" PUREFUNC public uint64_t generic_hash(const void *obj, const TypeInfo_t *type) { - switch (type->tag) { - case TextInfo: return Text$hash((void*)obj); - case ArrayInfo: return Array$hash(obj, type); - case ChannelInfo: return Channel$hash((Channel_t**)obj, type); - case TableInfo: return Table$hash(obj, type); - case OptionalInfo: return is_null(obj, type->OptionalInfo.type) ? 0 : generic_hash(obj, type->OptionalInfo.type); - case StructInfo: { - if (type->StructInfo.num_fields == 0) { - return 0; - } else if (type->StructInfo.num_fields == 1) { - return generic_hash(obj, type->StructInfo.fields[0].type); - } else { - uint32_t field_hashes[type->StructInfo.num_fields] = {}; - ptrdiff_t byte_offset = 0; - ptrdiff_t bit_offset = 0; - for (int i = 0; i < type->StructInfo.num_fields; i++) { - NamedType_t field = type->StructInfo.fields[i]; - if (field.type == &Bool$info) { - bool b = ((*(char*)(obj + byte_offset)) >> bit_offset) & 0x1; - field_hashes[i] = (uint32_t)b; - bit_offset += 1; - if (bit_offset >= 8) { - byte_offset += 1; - bit_offset = 0; - } - } else { - if (bit_offset > 0) { - byte_offset += 1; - bit_offset = 0; - } - if (field.type->align && byte_offset % field.type->align > 0) - byte_offset += field.type->align - (byte_offset % field.type->align); - field_hashes[i] = generic_hash(obj + byte_offset, field.type); - byte_offset += field.type->size; - } - } - return siphash24((void*)field_hashes, sizeof(field_hashes)); - } - } - case EnumInfo: { - int32_t tag = *(int32_t*)obj; - uint32_t components[2] = {(uint32_t)tag, 0}; - - const TypeInfo_t *value = type->EnumInfo.tags[tag-1].type; - if (value && value->size > 0) { - ptrdiff_t byte_offset = sizeof(int32_t); - if (value->align && byte_offset % value->align > 0) - byte_offset += value->align - (byte_offset % value->align); - components[1] = generic_hash(obj + byte_offset, value); - } - return siphash24((void*)components, sizeof(components)); + if (type->metamethods.hash) + return type->metamethods.hash(obj, type); - } - case CustomInfo: case CStringInfo: // These all share the same info - if (!type->CustomInfo.hash) - goto hash_data; - return type->CustomInfo.hash(obj, type); - case PointerInfo: case FunctionInfo: case TypeInfoInfo: case OpaqueInfo: default: { - hash_data:; - return siphash24((void*)obj, (size_t)(type->size)); - } - } + return siphash24((void*)obj, (size_t)(type->size)); } -#pragma GCC diagnostic pop PUREFUNC public int32_t generic_compare(const void *x, const void *y, const TypeInfo_t *type) { if (x == y) return 0; - switch (type->tag) { - case PointerInfo: case FunctionInfo: return Pointer$compare(x, y, type); - case TextInfo: return Text$compare(x, y); - case ArrayInfo: return Array$compare(x, y, type); - case ChannelInfo: return Channel$compare((Channel_t**)x, (Channel_t**)y, type); - case TableInfo: return Table$compare(x, y, type); - case OptionalInfo: { - bool x_is_null = is_null(x, type->OptionalInfo.type); - bool y_is_null = is_null(y, type->OptionalInfo.type); - if (x_is_null && y_is_null) return 0; - else if (x_is_null != y_is_null) return (int32_t)y_is_null - (int32_t)x_is_null; - else return generic_compare(x, y, type->OptionalInfo.type); - } - case StructInfo: { - ptrdiff_t byte_offset = 0; - ptrdiff_t bit_offset = 0; - for (int i = 0; i < type->StructInfo.num_fields; i++) { - NamedType_t field = type->StructInfo.fields[i]; - if (field.type == &Bool$info) { - bool bx = ((*(char*)(x + byte_offset)) >> bit_offset) & 0x1; - bool by = ((*(char*)(y + byte_offset)) >> bit_offset) & 0x1; - if (bx != by) - return (int32_t)bx - (int32_t)by; - bit_offset += 1; - if (bit_offset >= 8) { - byte_offset += 1; - bit_offset = 0; - } - } else { - if (bit_offset > 0) { - byte_offset += 1; - bit_offset = 0; - } - if (field.type->align && byte_offset % field.type->align > 0) - byte_offset += field.type->align - (byte_offset % field.type->align); - int32_t cmp = generic_compare(x + byte_offset, y + byte_offset, field.type); - if (cmp != 0) - return cmp; - byte_offset += field.type->size; - } - } - return 0; - } - case EnumInfo: { - int32_t x_tag = *(int32_t*)x; - int32_t y_tag = *(int32_t*)y; - if (x_tag != y_tag) - return x_tag > y_tag ? 1 : -1; + if (type->metamethods.compare) + return type->metamethods.compare(x, y, type); - const TypeInfo_t *value = type->EnumInfo.tags[x_tag-1].type; - if (value && value->size > 0) { - ptrdiff_t byte_offset = sizeof(int32_t); - if (value->align && byte_offset % value->align > 0) - byte_offset += value->align - (byte_offset % value->align); - return generic_compare(x + byte_offset, y + byte_offset, value); - } - return 0; - } - case CustomInfo: case CStringInfo: // These all share the same info - if (!type->CustomInfo.compare) - goto compare_data; - return type->CustomInfo.compare(x, y, type); - case TypeInfoInfo: case OpaqueInfo: default: - compare_data: - return (int32_t)memcmp((void*)x, (void*)y, (size_t)(type->size)); - } + return (int32_t)memcmp((void*)x, (void*)y, (size_t)(type->size)); } PUREFUNC public bool generic_equal(const void *x, const void *y, const TypeInfo_t *type) { if (x == y) return true; - switch (type->tag) { - case PointerInfo: case FunctionInfo: return Pointer$equal(x, y, type); - case TextInfo: return Text$equal(x, y); - case ArrayInfo: return Array$equal(x, y, type); - case ChannelInfo: return Channel$equal((Channel_t**)x, (Channel_t**)y, type); - case TableInfo: return Table$equal(x, y, type); - case OptionalInfo: { - bool x_is_null = is_null(x, type->OptionalInfo.type); - bool y_is_null = is_null(y, type->OptionalInfo.type); - if (x_is_null && y_is_null) return true; - else if (x_is_null != y_is_null) return false; - else return generic_equal(x, y, type->OptionalInfo.type); - } - case StructInfo: case EnumInfo: - return (generic_compare(x, y, type) == 0); - case CustomInfo: case CStringInfo: // These all share the same info - if (!type->CustomInfo.equal) - goto use_generic_compare; - return type->CustomInfo.equal(x, y, type); - case TypeInfoInfo: case OpaqueInfo: default: - use_generic_compare: - return (generic_compare(x, y, type) == 0); - } + if (type->metamethods.equal) + return type->metamethods.equal(x, y, type); + + return (generic_compare(x, y, type) == 0); } public Text_t generic_as_text(const void *obj, bool colorize, const TypeInfo_t *type) { - switch (type->tag) { - case PointerInfo: return Pointer$as_text(obj, colorize, type); - case FunctionInfo: return Func$as_text(obj, colorize, type); - case TextInfo: return Text$as_text(obj, colorize, type); - case ArrayInfo: return Array$as_text(obj, colorize, type); - case ChannelInfo: return Channel$as_text((Channel_t**)obj, colorize, type); - case TableInfo: return Table$as_text(obj, colorize, type); - case TypeInfoInfo: return Type$as_text(obj, colorize, type); - case OptionalInfo: return Optional$as_text(obj, colorize, type); - case StructInfo: { - if (!obj) return Text$from_str(type->StructInfo.name); - - if (type->StructInfo.is_secret) - return Text$format(colorize ? "\x1b[0;1m%s\x1b[m(...)" : "%s(...)", type->StructInfo.name); - - Text_t text = Text$format(colorize ? "\x1b[0;1m%s\x1b[m(" : "%s(", type->StructInfo.name); - ptrdiff_t byte_offset = 0; - ptrdiff_t bit_offset = 0; - for (int i = 0; i < type->StructInfo.num_fields; i++) { - NamedType_t field = type->StructInfo.fields[i]; - if (i > 0) - text = Text$concat(text, Text(", ")); + if (!type->metamethods.as_text) + fail("No text metamethod provided for type!"); - if (type->StructInfo.num_fields > 1) - text = Text$concat(text, Text$from_str(field.name), Text("=")); - - if (field.type == &Bool$info) { - bool b = ((*(char*)(obj + byte_offset)) >> bit_offset) & 0x1; - text = Text$concat(text, Text$from_str(colorize ? (b ? "\x1b[35myes\x1b[m" : "\x1b[35mno\x1b[m") : (b ? "yes" : "no"))); - bit_offset += 1; - if (bit_offset >= 8) { - byte_offset += 1; - bit_offset = 0; - } - } else { - if (bit_offset > 0) { - byte_offset += 1; - bit_offset = 0; - } - if (field.type->align && byte_offset % field.type->align > 0) - byte_offset += field.type->align - (byte_offset % field.type->align); - text = Text$concat(text, generic_as_text(obj + byte_offset, colorize, field.type)); - byte_offset += field.type->size; - } - } - return Text$concat(text, Text(")")); - } - case EnumInfo: { - if (!obj) return Text$from_str(type->EnumInfo.name); - - int32_t tag = *(int32_t*)obj; - NamedType_t value = type->EnumInfo.tags[tag-1]; - if (!value.type || value.type->size == 0) - return Text$format(colorize ? "\x1b[36;1m%s\x1b[m.\x1b[1m%s\x1b[m" : "%s.%s", type->EnumInfo.name, value.name); - - ptrdiff_t byte_offset = sizeof(int32_t); - if (value.type->align && byte_offset % value.type->align > 0) - byte_offset += value.type->align - (byte_offset % value.type->align); - return Text$concat(Text$format(colorize ? "\x1b[36;1m%s\x1b[m." : "%s.", type->EnumInfo.name), - generic_as_text(obj + byte_offset, colorize, value.type)); - } - case CustomInfo: case CStringInfo: // These all share the same info - if (!type->CustomInfo.as_text) - fail("No text function provided for type!\n"); - return type->CustomInfo.as_text(obj, colorize, type); - case OpaqueInfo: return Text("???"); - default: fail("Invalid type tag: %d", type->tag); - } + return type->metamethods.as_text(obj, colorize, type); } public int generic_print(const void *obj, bool colorize, const TypeInfo_t *type) @@ -264,5 +57,4 @@ public int generic_print(const void *obj, bool colorize, const TypeInfo_t *type) return Text$print(stdout, text) + printf("\n"); } - // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 |
