From 505b85ead546a093a94b157889fbfe83731a55c2 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sun, 2 Nov 2025 07:45:40 +0100 Subject: Add #subtype using to name canonicalization --- src/name_canonicalization.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/name_canonicalization.cpp') diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp index 8bacfabc6..88235484a 100644 --- a/src/name_canonicalization.cpp +++ b/src/name_canonicalization.cpp @@ -756,6 +756,14 @@ gb_internal void write_type_to_canonical_string(TypeWriter *w, Type *type) { if (i > 0) { type_writer_appendc(w, CANONICAL_FIELD_SEPARATOR); } + + if (f->flags & EntityFlags_IsSubtype) { + type_writer_appendc(w, "#subtype"); + } + + if (f->flags & EntityFlag_Using) { + type_writer_appendc(w, "using"); + } type_writer_append(w, f->token.string.text, f->token.string.len); type_writer_appendc(w, CANONICAL_TYPE_SEPARATOR); write_type_to_canonical_string(w, f->type); -- cgit v1.2.3 From b6181a768e368536819621b145ceaa5bb05d60ac Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sun, 2 Nov 2025 13:28:34 +0100 Subject: Add space --- src/name_canonicalization.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/name_canonicalization.cpp') diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp index 88235484a..edadde35e 100644 --- a/src/name_canonicalization.cpp +++ b/src/name_canonicalization.cpp @@ -758,11 +758,11 @@ gb_internal void write_type_to_canonical_string(TypeWriter *w, Type *type) { } if (f->flags & EntityFlags_IsSubtype) { - type_writer_appendc(w, "#subtype"); + type_writer_appendc(w, "#subtype "); } if (f->flags & EntityFlag_Using) { - type_writer_appendc(w, "using"); + type_writer_appendc(w, "using "); } type_writer_append(w, f->token.string.text, f->token.string.len); type_writer_appendc(w, CANONICAL_TYPE_SEPARATOR); -- cgit v1.2.3 From 3731cf4e08eaf5b2c91f3f64e1eab0b20efdd51e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 4 Nov 2025 10:42:24 +0000 Subject: Fix #5176 --- src/name_canonicalization.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/name_canonicalization.cpp') diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp index edadde35e..c2acf83f5 100644 --- a/src/name_canonicalization.cpp +++ b/src/name_canonicalization.cpp @@ -417,7 +417,7 @@ gb_internal gbString string_canonical_entity_name(gbAllocator allocator, Entity gb_internal void write_canonical_parent_prefix(TypeWriter *w, Entity *e) { GB_ASSERT(e != nullptr); - if (e->kind == Entity_Procedure || e->kind == Entity_TypeName) { + if (e->kind == Entity_Procedure || e->kind == Entity_TypeName || e->kind == Entity_Variable) { if (e->kind == Entity_Procedure && (e->Procedure.is_export || e->Procedure.is_foreign)) { // no prefix return; -- cgit v1.2.3 From ea5db0e04864f7e453a5b5faa305df22543c4b75 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 5 Nov 2025 10:06:40 +0000 Subject: Fix type name name canonicalization within an anonymously nested procedure in a struct. --- src/name_canonicalization.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/name_canonicalization.cpp') diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp index c2acf83f5..87d7a8522 100644 --- a/src/name_canonicalization.cpp +++ b/src/name_canonicalization.cpp @@ -527,6 +527,11 @@ gb_internal void write_canonical_entity_name(TypeWriter *w, Entity *e) { } else if (s->flags & (ScopeFlag_Builtin)) { goto write_base_name; } + + if (e->kind == Entity_TypeName) { + goto write_base_name; + } + gb_printf_err("%s WEIRD ENTITY TYPE %s %u %p\n", token_pos_to_string(e->token.pos), type_to_string(e->type), s->flags, s->decl_info); auto const print_scope_flags = [](Scope *s) { @@ -543,7 +548,7 @@ gb_internal void write_canonical_entity_name(TypeWriter *w, Entity *e) { }; print_scope_flags(s); - GB_PANIC("weird entity %.*s", LIT(e->token.string)); + GB_PANIC("weird entity %.*s (%.*s)", LIT(e->token.string), LIT(entity_strings[e->kind])); } if (e->pkg != nullptr) { type_writer_append(w, e->pkg->name.text, e->pkg->name.len); -- cgit v1.2.3 From 593d2e6daa1f0dd9c24c7fb8704463c8db757af0 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 5 Nov 2025 13:30:40 +0000 Subject: Add `#all_or_none` --- base/runtime/core.odin | 8 +++---- base/runtime/print.odin | 6 ++--- core/odin/ast/ast.odin | 1 + core/odin/doc-format/doc_format.odin | 1 + core/odin/parser/parser.odin | 44 ++++++++++++++++++++++------------- core/reflect/types.odin | 6 ++--- src/check_expr.cpp | 45 ++++++++++++++++++++++++++++++++++++ src/check_type.cpp | 7 +++--- src/llvm_backend_type.cpp | 8 +++---- src/name_canonicalization.cpp | 5 ++-- src/parser.cpp | 18 +++++++++++++-- src/parser.hpp | 1 + src/types.cpp | 8 ++++--- 13 files changed, 118 insertions(+), 40 deletions(-) (limited to 'src/name_canonicalization.cpp') diff --git a/base/runtime/core.odin b/base/runtime/core.odin index 2e70147db..58a0b8ad1 100644 --- a/base/runtime/core.odin +++ b/base/runtime/core.odin @@ -118,10 +118,10 @@ Type_Info_Parameters :: struct { // Only used for procedures parameters and resu Type_Info_Struct_Flags :: distinct bit_set[Type_Info_Struct_Flag; u8] Type_Info_Struct_Flag :: enum u8 { - packed = 0, - raw_union = 1, - _ = 2, - align = 3, + packed = 0, + raw_union = 1, + all_or_none = 2, + align = 3, } Type_Info_Struct :: struct { diff --git a/base/runtime/print.odin b/base/runtime/print.odin index 2cfb6661b..90119c699 100644 --- a/base/runtime/print.odin +++ b/base/runtime/print.odin @@ -408,9 +408,9 @@ print_type :: #force_no_inline proc "contextless" (ti: ^Type_Info) { } print_string("struct ") - if .packed in info.flags { print_string("#packed ") } - if .raw_union in info.flags { print_string("#raw_union ") } - // if .no_copy in info.flags { print_string("#no_copy ") } + if .packed in info.flags { print_string("#packed ") } + if .raw_union in info.flags { print_string("#raw_union ") } + if .all_or_none in info.flags { print_string("#all_or_none ") } if .align in info.flags { print_string("#align(") print_u64(u64(ti.align)) diff --git a/core/odin/ast/ast.odin b/core/odin/ast/ast.odin index 4dcc1f215..a8c198476 100644 --- a/core/odin/ast/ast.odin +++ b/core/odin/ast/ast.odin @@ -790,6 +790,7 @@ Struct_Type :: struct { is_packed: bool, is_raw_union: bool, is_no_copy: bool, + is_all_or_none: bool, fields: ^Field_List, name_count: int, } diff --git a/core/odin/doc-format/doc_format.odin b/core/odin/doc-format/doc_format.odin index e37092948..a60768931 100644 --- a/core/odin/doc-format/doc_format.odin +++ b/core/odin/doc-format/doc_format.odin @@ -281,6 +281,7 @@ Type_Flag_Struct :: enum u32le { Polymorphic = 0, Packed = 1, Raw_Union = 2, + All_Or_None = 3, } Type_Flags_Union :: distinct bit_set[Type_Flag_Union; u32le] diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index 9ce484a10..ce088fc64 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -2658,11 +2658,12 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { align: ^ast.Expr min_field_align: ^ast.Expr max_field_align: ^ast.Expr - is_packed: bool - is_raw_union: bool - is_no_copy: bool - fields: ^ast.Field_List - name_count: int + is_packed: bool + is_raw_union: bool + is_no_copy: bool + is_all_or_none: bool + fields: ^ast.Field_List + name_count: int if allow_token(p, .Open_Paren) { param_count: int @@ -2684,6 +2685,11 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { error(p, tag.pos, "duplicate struct tag '#%s'", tag.text) } is_packed = true + case "all_or_none": + if is_all_or_none { + error(p, tag.pos, "duplicate struct tag '#%s'", tag.text) + } + is_all_or_none = true case "align": if align != nil { error(p, tag.pos, "duplicate struct tag '#%s'", tag.text) @@ -2726,6 +2732,11 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { error(p, tok.pos, "'#raw_union' cannot also be '#packed") } + if is_raw_union && is_all_or_none { + is_all_or_none = false + error(p, tok.pos, "'#raw_union' cannot also be '#all_or_none") + } + where_token: tokenizer.Token where_clauses: []^ast.Expr @@ -2745,17 +2756,18 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { close := expect_closing_brace_of_field_list(p) st := ast.new(ast.Struct_Type, tok.pos, end_pos(close)) - st.poly_params = poly_params - st.align = align - st.min_field_align = min_field_align - st.max_field_align = max_field_align - st.is_packed = is_packed - st.is_raw_union = is_raw_union - st.is_no_copy = is_no_copy - st.fields = fields - st.name_count = name_count - st.where_token = where_token - st.where_clauses = where_clauses + st.poly_params = poly_params + st.align = align + st.min_field_align = min_field_align + st.max_field_align = max_field_align + st.is_packed = is_packed + st.is_raw_union = is_raw_union + st.is_no_copy = is_no_copy + st.is_all_or_none = is_all_or_none + st.fields = fields + st.name_count = name_count + st.where_token = where_token + st.where_clauses = where_clauses return st case .Union: diff --git a/core/reflect/types.odin b/core/reflect/types.odin index 2e82e29b1..f71395298 100644 --- a/core/reflect/types.odin +++ b/core/reflect/types.odin @@ -696,9 +696,9 @@ write_type_writer :: #force_no_inline proc(w: io.Writer, ti: ^Type_Info, n_writt } io.write_string(w, "struct ", &n) or_return - if .packed in info.flags { io.write_string(w, "#packed ", &n) or_return } - if .raw_union in info.flags { io.write_string(w, "#raw_union ", &n) or_return } - // if .no_copy in info.flags { io.write_string(w, "#no_copy ", &n) or_return } + if .packed in info.flags { io.write_string(w, "#packed ", &n) or_return } + if .raw_union in info.flags { io.write_string(w, "#raw_union ", &n) or_return } + if .all_or_none in info.flags { io.write_string(w, "#all_or_none ", &n) or_return } if .align in info.flags { io.write_string(w, "#align(", &n) or_return io.write_i64(w, i64(ti.align), 10, &n) or_return diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 8ac277917..677735c44 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -9838,6 +9838,51 @@ gb_internal void check_compound_literal_field_values(CheckerContext *c, Slicebit_field_bit_size = prev_bit_field_bit_size; } + + if (bt->kind == Type_Struct && bt->Struct.is_all_or_none && elems.count > 0 && bt->Struct.fields.count > 0) { + PtrSet missing_fields = {}; + defer (ptr_set_destroy(&missing_fields)); + + for_array(i, bt->Struct.fields) { + Entity *field = bt->Struct.fields[i]; + String name = field->token.string; + if (is_blank_ident(name) || name == "") { + continue; + } + bool found = string_set_exists(&fields_visited, name); + String *raw_union = string_map_get(&fields_visited_through_raw_union, name); + if (!found && raw_union == nullptr) { + ptr_set_add(&missing_fields, field); + } + } + + if (missing_fields.count > 0) { + ERROR_BLOCK(); + + if (build_context.terse_errors) { + gbString fields_string = gb_string_make(heap_allocator(), ""); + defer (gb_string_free(fields_string)); + isize i = 0; + FOR_PTR_SET(field, missing_fields) { + if (i > 0) { + fields_string = gb_string_appendc(fields_string, ", "); + } + String name = field->token.string; + fields_string = gb_string_append_length(fields_string, name.text, name.len); + i += 1; + } + + error(o->expr, "All or none of the fields must be assigned to a struct with '#all_or_none' applied, missing fields: %s", fields_string); + } else { + error(o->expr, "All or none of the fields must be assigned to a struct with '#all_or_none' applied, missing fields:"); + FOR_PTR_SET(field, missing_fields) { + gbString s = type_to_string(field->type); + error_line("\t%.*s: %s\n", LIT(field->token.string), s); + gb_string_free(s); + } + } + } + } } gb_internal bool is_expr_inferred_fixed_array(Ast *type_expr) { diff --git a/src/check_type.cpp b/src/check_type.cpp index 5accfbd9f..af07efd8f 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -654,9 +654,10 @@ gb_internal void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast * context = str_lit("struct #raw_union"); } - struct_type->Struct.node = node; - struct_type->Struct.scope = ctx->scope; - struct_type->Struct.is_packed = st->is_packed; + struct_type->Struct.node = node; + struct_type->Struct.scope = ctx->scope; + struct_type->Struct.is_packed = st->is_packed; + struct_type->Struct.is_all_or_none = st->is_all_or_none; struct_type->Struct.polymorphic_params = check_record_polymorphic_params( ctx, st->polymorphic_params, &struct_type->Struct.is_polymorphic, diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index 474999191..382304a4e 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -817,10 +817,10 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ { u8 flags = 0; - if (t->Struct.is_packed) flags |= 1<<0; - if (t->Struct.is_raw_union) flags |= 1<<1; - // - if (t->Struct.custom_align) flags |= 1<<3; + if (t->Struct.is_packed) flags |= 1<<0; + if (t->Struct.is_raw_union) flags |= 1<<1; + if (t->Struct.is_all_or_none) flags |= 1<<2; + if (t->Struct.custom_align) flags |= 1<<3; vals[6] = lb_const_int(m, t_u8, flags).value; if (is_type_comparable(t) && !is_type_simple_compare(t)) { diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp index 87d7a8522..7cc4ad893 100644 --- a/src/name_canonicalization.cpp +++ b/src/name_canonicalization.cpp @@ -749,8 +749,9 @@ gb_internal void write_type_to_canonical_string(TypeWriter *w, Type *type) { write_canonical_params(w, type->Struct.polymorphic_params); } - if (type->Struct.is_packed) type_writer_appendc(w, "#packed"); - if (type->Struct.is_raw_union) type_writer_appendc(w, "#raw_union"); + if (type->Struct.is_packed) type_writer_appendc(w, "#packed"); + if (type->Struct.is_raw_union) type_writer_appendc(w, "#raw_union"); + if (type->Struct.is_all_or_none) type_writer_appendc(w, "#all_or_none"); if (type->Struct.custom_min_field_align != 0) type_writer_append_fmt(w, "#min_field_align(%lld)", cast(long long)type->Struct.custom_min_field_align); if (type->Struct.custom_max_field_align != 0) type_writer_append_fmt(w, "#max_field_align(%lld)", cast(long long)type->Struct.custom_max_field_align); if (type->Struct.custom_align != 0) type_writer_append_fmt(w, "#align(%lld)", cast(long long)type->Struct.custom_align); diff --git a/src/parser.cpp b/src/parser.cpp index 152e55f8b..d3b35f3f4 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1230,7 +1230,7 @@ gb_internal Ast *ast_dynamic_array_type(AstFile *f, Token token, Ast *elem) { } gb_internal Ast *ast_struct_type(AstFile *f, Token token, Slice fields, isize field_count, - Ast *polymorphic_params, bool is_packed, bool is_raw_union, bool is_no_copy, + Ast *polymorphic_params, bool is_packed, bool is_raw_union, bool is_no_copy, bool is_all_or_none, Ast *align, Ast *min_field_align, Ast *max_field_align, Token where_token, Array const &where_clauses) { Ast *result = alloc_ast_node(f, Ast_StructType); @@ -1241,6 +1241,7 @@ gb_internal Ast *ast_struct_type(AstFile *f, Token token, Slice fields, i result->StructType.is_packed = is_packed; result->StructType.is_raw_union = is_raw_union; result->StructType.is_no_copy = is_no_copy; + result->StructType.is_all_or_none = is_all_or_none; result->StructType.align = align; result->StructType.min_field_align = min_field_align; result->StructType.max_field_align = max_field_align; @@ -2773,6 +2774,7 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) { Token token = expect_token(f, Token_struct); Ast *polymorphic_params = nullptr; bool is_packed = false; + bool is_all_or_none = false; bool is_raw_union = false; bool no_copy = false; Ast *align = nullptr; @@ -2802,6 +2804,11 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) { syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string)); } is_packed = true; + } else if (tag.string == "all_or_none") { + if (is_packed) { + syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string)); + } + is_all_or_none = true; } else if (tag.string == "align") { if (align) { syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string)); @@ -2872,6 +2879,10 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) { is_packed = false; syntax_error(token, "'#raw_union' cannot also be '#packed'"); } + if (is_raw_union && is_all_or_none) { + is_all_or_none = false; + syntax_error(token, "'#raw_union' cannot also be '#all_or_none'"); + } Token where_token = {}; Array where_clauses = {}; @@ -2901,7 +2912,10 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) { parser_check_polymorphic_record_parameters(f, polymorphic_params); - return ast_struct_type(f, token, decls, name_count, polymorphic_params, is_packed, is_raw_union, no_copy, align, min_field_align, max_field_align, where_token, where_clauses); + return ast_struct_type(f, token, decls, name_count, + polymorphic_params, is_packed, is_raw_union, no_copy, is_all_or_none, + align, min_field_align, max_field_align, + where_token, where_clauses); } break; case Token_union: { diff --git a/src/parser.hpp b/src/parser.hpp index 6127468d4..71b61d95f 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -766,6 +766,7 @@ AST_KIND(_TypeBegin, "", bool) \ bool is_packed; \ bool is_raw_union; \ bool is_no_copy; \ + bool is_all_or_none; \ }) \ AST_KIND(UnionType, "union type", struct { \ Scope *scope; \ diff --git a/src/types.cpp b/src/types.cpp index b9089b9fc..eb20b8edf 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -162,6 +162,7 @@ struct TypeStruct { bool are_offsets_set : 1; bool is_packed : 1; bool is_raw_union : 1; + bool is_all_or_none : 1; bool is_poly_specialized : 1; std::atomic are_offsets_being_processed; @@ -3084,9 +3085,10 @@ gb_internal bool are_types_identical_internal(Type *x, Type *y, bool check_tuple break; case Type_Struct: - if (x->Struct.is_raw_union == y->Struct.is_raw_union && - x->Struct.fields.count == y->Struct.fields.count && - x->Struct.is_packed == y->Struct.is_packed && + if (x->Struct.is_raw_union == y->Struct.is_raw_union && + x->Struct.fields.count == y->Struct.fields.count && + x->Struct.is_packed == y->Struct.is_packed && + x->Struct.is_all_or_none == y->Struct.is_all_or_none && x->Struct.soa_kind == y->Struct.soa_kind && x->Struct.soa_count == y->Struct.soa_count && are_types_identical(x->Struct.soa_elem, y->Struct.soa_elem)) { -- cgit v1.2.3 From 21116a7b477b2c72e4ecc1b7ab39df33cbc0712c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 18 Nov 2025 12:33:48 +0000 Subject: Use SIP hash as name canonicalization hash Replaces fnv64a --- src/name_canonicalization.cpp | 155 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 146 insertions(+), 9 deletions(-) (limited to 'src/name_canonicalization.cpp') diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp index 7cc4ad893..f1dccb182 100644 --- a/src/name_canonicalization.cpp +++ b/src/name_canonicalization.cpp @@ -242,9 +242,146 @@ gb_internal gb_inline void type_set_clear(TypeSet *s) { typedef TYPE_WRITER_PROC(TypeWriterProc); +enum { SIP_BLOCK_SIZE = 8 }; + +struct SipHashContext { + u64 v0, v1, v2, v3; // State values + u64 k0, k1; // Split key + isize c_rounds; // Number of message rounds + isize d_rounds; // Number of finalization rounds + u8 buf[SIP_BLOCK_SIZE]; // Provided data + isize last_block; // offset from last block + isize total_length; + bool is_initialized; +}; + +struct TypeidHashContext { + SipHashContext sip; +}; + + +void typeid_hash_context_init(TypeidHashContext *hash_ctx) { + SipHashContext *sip = &hash_ctx->sip; + sip->c_rounds = 2; + sip->d_rounds = 4; + + // some random numbers to act as the seed + sip->k0 = 0xa6592ea25e04ac3cull; + sip->k1 = 0xba3cba04ed28a9aeull; + + // + sip->v0 = 0x736f6d6570736575 ^ sip->k0; + sip->v1 = 0x646f72616e646f6d ^ sip->k1; + sip->v2 = 0x6c7967656e657261 ^ sip->k0; + sip->v3 = 0x7465646279746573 ^ sip->k1; + + sip->last_block = 0; + sip->total_length = 0; + + sip->is_initialized = true; +} + +u64 rotate_left64(u64 x, u64 k) { + static u64 const n = 64; + u64 s = k & (n-1); + return (x<>(n-2)); +} + +void sip_compress(SipHashContext *sip) { + sip->v0 += sip->v1; + sip->v1 = rotate_left64(sip->v1, 13); + sip->v1 ^= sip->v0; + sip->v0 = rotate_left64(sip->v0, 32); + sip->v2 += sip->v3; + sip->v3 = rotate_left64(sip->v3, 16); + sip->v3 ^= sip->v2; + sip->v0 += sip->v3; + sip->v3 = rotate_left64(sip->v3, 21); + sip->v3 ^= sip->v0; + sip->v2 += sip->v1; + sip->v1 = rotate_left64(sip->v1, 17); + sip->v1 ^= sip->v2; + sip->v2 = rotate_left64(sip->v2, 32); +} + +void sip_block(SipHashContext *sip, void const *ptr, isize len) { + u8 const *data = cast(u8 const *)ptr; + while (len >= SIP_BLOCK_SIZE) { + u64 m = 0; + gb_memcopy(&m, data, 8); + + sip->v3 ^= m; + + for (isize i = 0; i < sip->c_rounds; i++) { + sip_compress(sip); + } + + sip->v0 ^= m; + + data += SIP_BLOCK_SIZE; + len -= SIP_BLOCK_SIZE; + } +} + +void typeid_hash_context_update(TypeidHashContext *ctx, void const *ptr, isize len) { + GB_ASSERT(ctx->sip.is_initialized); + SipHashContext *sip = &ctx->sip; + + u8 const *data = cast(u8 const *)ptr; + sip->total_length += len; + if (sip->last_block > 0) { + isize n = gb_min(SIP_BLOCK_SIZE - sip->last_block, len); + gb_memcopy(sip->buf + sip->last_block, data, n); + sip->last_block += n; + if (sip->last_block == SIP_BLOCK_SIZE) { + sip_block(sip, sip->buf, SIP_BLOCK_SIZE); + sip->last_block = 0; + } + data += n; + len -= n; + } + + if (len >= SIP_BLOCK_SIZE) { + isize n = len & ~(SIP_BLOCK_SIZE-1); + sip_block(sip, data, n); + data += n; + len -= n; + } + if (len > 0) { + isize n = gb_min(SIP_BLOCK_SIZE, len); + gb_memcopy(sip->buf, data, n); + sip->last_block = n; + } +} + +u64 typeid_hash_context_fini(TypeidHashContext *ctx) { + GB_ASSERT(ctx->sip.is_initialized); + SipHashContext *sip = &ctx->sip; + + u8 tmp[SIP_BLOCK_SIZE] = {}; + gb_memcopy(tmp, sip->buf, gb_min(sip->last_block, SIP_BLOCK_SIZE)); + tmp[7] = u8(sip->total_length & 0xff); + sip_block(sip, tmp, SIP_BLOCK_SIZE); + + sip->v2 ^= 0xff; + + for (isize i = 0; i < sip->d_rounds; i++) { + sip_compress(sip); + } + + u64 res = sip->v0 ^ sip->v1 ^ sip->v2 ^ sip->v3; + + *sip = {}; + + return res ? res : 1; +} + + + struct TypeWriter { - TypeWriterProc *proc; - void *user_data; + TypeWriterProc * proc; + void * user_data; + TypeidHashContext hash_ctx; }; bool type_writer_append(TypeWriter *w, void const *ptr, isize len) { @@ -289,13 +426,14 @@ void type_writer_destroy_string(TypeWriter *w) { TYPE_WRITER_PROC(type_writer_hasher_writer_proc) { - u64 *seed = cast(u64 *)w->user_data; - *seed = fnv64a(ptr, len, *seed); + TypeidHashContext *ctx = cast(TypeidHashContext *)w->user_data; + typeid_hash_context_update(ctx, ptr, len); return true; } -void type_writer_make_hasher(TypeWriter *w, u64 *hash) { - w->user_data = hash; +void type_writer_make_hasher(TypeWriter *w, TypeidHashContext *ctx) { + typeid_hash_context_init(ctx); + w->user_data = ctx; w->proc = type_writer_hasher_writer_proc; } @@ -378,11 +516,10 @@ gb_internal u64 type_hash_canonical_type(Type *type) { return prev_hash; } - u64 hash = fnv64a(nullptr, 0); TypeWriter w = {}; - type_writer_make_hasher(&w, &hash); + type_writer_make_hasher(&w, &w.hash_ctx); write_type_to_canonical_string(&w, type); - hash = hash ? hash : 1; + u64 hash = typeid_hash_context_fini(&w.hash_ctx); type->canonical_hash.store(hash, std::memory_order_relaxed); -- cgit v1.2.3