From fb0ff9b663d0a311b13dc15ebb49690673cc9154 Mon Sep 17 00:00:00 2001 From: zzy <2450266535@qq.com> Date: Thu, 17 Sep 2026 20:55:21 +0800 Subject: [PATCH] =?UTF-8?q?stage1=20=E8=A7=A3=E5=86=B3=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E5=93=88=E5=B8=8C=20nob=E4=BC=98=E5=8C=96=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E5=A4=B4=E6=96=87=E4=BB=B6=E7=BC=93=E5=AD=98=E4=BB=A5=E5=8F=8A?= =?UTF-8?q?win=E4=B8=8Bexe=E7=BC=93=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nob.c | 64 ++++++++++++++++++++++++++++----- stage0/include/core_map.h | 27 -------------- stage1/spl_fold.c | 34 ++++++++++++++++++ stage1/spl_fold.h | 36 +++++++++++++++++++ stage1/spl_lang_type.c | 66 ++++++++++++++++++++-------------- stage1/spl_lang_type.h | 6 ++-- stage1/spl_type.c | 75 +++++++++++++++++++++++---------------- stage1/spl_type.h | 26 ++++++++++++-- 8 files changed, 236 insertions(+), 98 deletions(-) create mode 100644 stage1/spl_fold.c create mode 100644 stage1/spl_fold.h diff --git a/nob.c b/nob.c index 0ee9404..1783d27 100644 --- a/nob.c +++ b/nob.c @@ -30,6 +30,7 @@ static const char *splc0_srcs[] = { "stage1/spl_parser.c", "stage1/spl_dumptree.c", "stage1/spl_type.c", + "stage1/spl_fold.c", "stage1/spl_lang_type.c", "stage1/spl_attr.c", "stage1/spl_scope.c", @@ -78,6 +79,16 @@ static const char *obj_path(const char *src) { return out; } +// Windows 上 clang/gcc 会输出 build/foo.exe;这里统一带上后缀, +// 否则 nob_needs_rebuild 找不到输出会每次重新链接。 +static const char *exe_path(const char *name) { +#ifdef _WIN32 + return nob_temp_sprintf(BUILD_FOLDER "%s.exe", name); +#else + return nob_temp_sprintf(BUILD_FOLDER "%s", name); +#endif +} + static bool sync_cflags_stamp(void) { Nob_String_View cflags = nob_sv_from_cstr(CFLAGS_STR); Nob_String_Builder old = {0}; @@ -95,10 +106,39 @@ static bool sync_cflags_stamp(void) { return true; } +// 头文件依赖:收集 stage0/stage1 下的所有 .h,作为每个 object 的输入。 +// nob 不解析 #include,这里用“任一头文件变化则重建全部 object”的保守策略, +// 避免头文件改动后各 .o 结构体布局/常量不一致导致的隐蔽错误。 +static Nob_Files g_headers = {0}; + +static bool collect_header_entry(Nob_Walk_Entry entry) { + if (entry.type != NOB_FILE_REGULAR) + return true; + const char *dot = strrchr(entry.path, '.'); + if (!dot || strcmp(dot, ".h") != 0) + return true; + if (strstr(entry.path, ".old") != NULL) + return true; + da_append(&g_headers, nob_temp_strdup(entry.path)); + return true; +} + +static bool collect_headers(void) { + if (g_headers.count > 0) + return true; + if (!nob_walk_dir("stage0", collect_header_entry)) + return false; + if (!nob_walk_dir("stage1", collect_header_entry)) + return false; + return true; +} + static bool prepare_build(void) { if (!nob_mkdir_if_not_exists(BUILD_FOLDER)) return false; - return sync_cflags_stamp(); + if (!sync_cflags_stamp()) + return false; + return collect_headers(); } static bool build_object(const char *src) { @@ -108,8 +148,16 @@ static bool build_object(const char *src) { return false; } - const char *inputs[] = {src, CFLAGS_STAMP}; - int needs = nob_needs_rebuild(obj, inputs, NOB_ARRAY_LEN(inputs)); + // 依赖:源文件 + 所有头文件 + cflags 戳。 + size_t ninputs = g_headers.count + 2; + const char **inputs = (const char **)nob_temp_alloc(sizeof(const char *) * ninputs); + inputs[0] = src; + for (size_t i = 0; i < g_headers.count; ++i) { + inputs[i + 1] = g_headers.items[i]; + } + inputs[ninputs - 1] = CFLAGS_STAMP; + + int needs = nob_needs_rebuild(obj, inputs, ninputs); if (needs < 0) return false; if (needs == 0) @@ -125,7 +173,7 @@ static bool build_object(const char *src) { } static bool link_exe(const target_t *target) { - const char *exe = nob_temp_sprintf(BUILD_FOLDER "%s", target->name); + const char *exe = exe_path(target->name); const char **objs = (const char **)nob_temp_alloc(sizeof(const char *) * target->srcs_count); for (size_t i = 0; i < target->srcs_count; ++i) { objs[i] = obj_path(target->srcs[i]); @@ -225,7 +273,7 @@ static bool test_once(const char *fname, void *user_data) { } cmd.count = 0; - nob_cmd_append(&cmd, nob_temp_sprintf(BUILD_FOLDER "%s", compiler_path)); + nob_cmd_append(&cmd, exe_path(compiler_path)); nob_cmd_append(&cmd, fname, target_sir); if (!nob_cmd_run(&cmd)) { return false; @@ -235,7 +283,7 @@ static bool test_once(const char *fname, void *user_data) { return 1; } cmd.count = 0; - nob_cmd_append(&cmd, nob_temp_sprintf(BUILD_FOLDER "%s", cli_path)); + nob_cmd_append(&cmd, exe_path(cli_path)); nob_cmd_append(&cmd, target_sir); // nob_cmd_run(&cmd); @@ -267,7 +315,7 @@ static bool test_once_with_dump(const char *fname, void *user_data) { if (!build_target(target_name)) return 1; Nob_Cmd cmd = {0}; - nob_cmd_append(&cmd, nob_temp_sprintf(BUILD_FOLDER "%s", target_name)); + nob_cmd_append(&cmd, exe_path(target_name)); nob_cmd_append(&cmd, "--dump", (char *)user_data, fname, BUILD_FOLDER "t.sir"); return nob_cmd_run(&cmd); } @@ -402,7 +450,7 @@ int main(int argc, char **argv) { if (!build_target(target_name)) return 1; Nob_Cmd cmd = {0}; - nob_cmd_append(&cmd, nob_temp_sprintf(BUILD_FOLDER "%s", target_name)); + nob_cmd_append(&cmd, exe_path(target_name)); while (argc > 0) { nob_cmd_append(&cmd, nob_shift(argv, argc)); } diff --git a/stage0/include/core_map.h b/stage0/include/core_map.h index 938591d..bb42b76 100644 --- a/stage0/include/core_map.h +++ b/stage0/include/core_map.h @@ -202,33 +202,6 @@ static inline usize map_hash_str(const char *s) { _found; \ })) -/** - * 查询(续探):首次调用前将 *in_out_idx 置为 (usize)-1, - * 则从键自身的 hash 桶开始查找;命中后 *out_val 被赋值、返回 1, - * 且 *in_out_idx 更新为命中槽位,下次调用从该槽的下一个继续探测(碰撞续探)。 - * 扫描到空槽返回 0。用于 key 碰撞后需要回表二次比较的场景。 - */ -#define map_get_continue(map, _key, out_val, in_out_idx) \ - (({ \ - int _found = 0; \ - if ((map).cap > 0) { \ - usize _mask = (map).cap - 1; \ - usize _idx = (*(in_out_idx) == (usize) - 1) ? (map).hash(_key) & _mask \ - : (*(in_out_idx) + 1) & _mask; \ - while ((map).data[_idx].state != __MAP_SLOT_EMPTY) { \ - if ((map).data[_idx].state == __MAP_SLOT_OCCUPIED && \ - (map).cmp((map).data[_idx].key, _key) == 0) { \ - *out_val = (map).data[_idx].val; \ - *(in_out_idx) = _idx; \ - _found = 1; \ - break; \ - } \ - _idx = (_idx + 1) & _mask; \ - } \ - } \ - _found; \ - })) - /** * 删除指定键 */ diff --git a/stage1/spl_fold.c b/stage1/spl_fold.c new file mode 100644 index 0000000..de0674b --- /dev/null +++ b/stage1/spl_fold.c @@ -0,0 +1,34 @@ +#include "spl_fold.h" + +static usize spl_fold_bucket_hash(usize k) { return MAP_HASH_INT(k); } +static int spl_fold_bucket_cmp(usize a, usize b) { return MAP_CMP_INT(a, b); } + +void spl_fold_init(spl_fold_t *fold, void *ctx, spl_fold_eq_fn eq, spl_fold_next_fn next, + spl_fold_set_next_fn set_next) { + map_init(fold->buckets, spl_fold_bucket_hash, spl_fold_bucket_cmp); + fold->ctx = ctx; + fold->eq = eq; + fold->next = next; + fold->set_next = set_next; +} + +void spl_fold_drop(spl_fold_t *fold) { map_free(fold->buckets); } + +spl_fold_id_t spl_fold_find(const spl_fold_t *fold, usize hash, const void *probe) { + spl_fold_id_t cur = 0; + if (!map_get(fold->buckets, hash, &cur)) + return 0; + while (cur) { + if (fold->eq(fold->ctx, cur, probe)) + return cur; + cur = fold->next(fold->ctx, cur); + } + return 0; +} + +void spl_fold_insert(spl_fold_t *fold, usize hash, spl_fold_id_t id) { + spl_fold_id_t head = 0; + map_get(fold->buckets, hash, &head); + fold->set_next(fold->ctx, id, head); + map_put(fold->buckets, hash, id); +} diff --git a/stage1/spl_fold.h b/stage1/spl_fold.h new file mode 100644 index 0000000..95f554b --- /dev/null +++ b/stage1/spl_fold.h @@ -0,0 +1,36 @@ +#ifndef __SPL_FOLD_H__ +#define __SPL_FOLD_H__ + +#include "../stage0/include/utils.h" + +/* 通用 intrusive 哈希集合,对应 LLVM FoldingSet 的桶链部分。 + - 节点表由调用方持有,节点自带 next 字段; + - hash 只用于选择桶(本实现以完整 hash 值作桶 map 的 key), + 相等始终由 eq 回调做结构比较; + - 只增不删,适合类型 intern。 */ +typedef usize spl_fold_id_t; + +/* 相等返回非零;probe 指向调用方的临时(尚未入表)节点。 */ +typedef int (*spl_fold_eq_fn)(void *ctx, spl_fold_id_t node, const void *probe); +typedef spl_fold_id_t (*spl_fold_next_fn)(void *ctx, spl_fold_id_t node); +typedef void (*spl_fold_set_next_fn)(void *ctx, spl_fold_id_t node, spl_fold_id_t next); + +typedef struct { + MAP(usize, spl_fold_id_t) buckets; + void *ctx; + spl_fold_eq_fn eq; + spl_fold_next_fn next; + spl_fold_set_next_fn set_next; +} spl_fold_t; + +void spl_fold_init(spl_fold_t *fold, void *ctx, spl_fold_eq_fn eq, spl_fold_next_fn next, + spl_fold_set_next_fn set_next); +void spl_fold_drop(spl_fold_t *fold); + +/* 命中返回已存在的 id,否则返回 0。 */ +spl_fold_id_t spl_fold_find(const spl_fold_t *fold, usize hash, const void *probe); + +/* 把已分配 id 的节点挂到对应桶头。 */ +void spl_fold_insert(spl_fold_t *fold, usize hash, spl_fold_id_t id); + +#endif /* __SPL_FOLD_H__ */ diff --git a/stage1/spl_lang_type.c b/stage1/spl_lang_type.c index 24ef851..183c714 100644 --- a/stage1/spl_lang_type.c +++ b/stage1/spl_lang_type.c @@ -1,36 +1,37 @@ #include "spl_lang_type.h" static usize spl_lang_type_hash(spl_lang_type_node_t n) { - usize hash = (usize)n.kind * 131 + n.ir_type_id; + usize hash = spl_hash_seed(); + hash = spl_hash_mix(hash, (usize)n.kind); + hash = spl_hash_mix(hash, n.ir_type_id); switch (n.kind) { case SPL_LANG_TYPE_PTR: case SPL_LANG_TYPE_SLICE: case SPL_LANG_TYPE_RANGE: - hash += n.extra.elem; + hash = spl_hash_mix(hash, n.extra.elem); break; case SPL_LANG_TYPE_TUPLE: + hash = spl_hash_mix(hash, vec_size(n.extra.elems)); for (usize i = 0; i < vec_size(n.extra.elems); i++) { - hash += vec_at(n.extra.elems, i); + hash = spl_hash_mix(hash, vec_at(n.extra.elems, i)); } break; case SPL_LANG_TYPE_FN: - hash += n.extra.fn.ret; + hash = spl_hash_mix(hash, n.extra.fn.ret); + hash = spl_hash_mix(hash, vec_size(n.extra.fn.params)); for (usize i = 0; i < vec_size(n.extra.fn.params); i++) { - hash += vec_at(n.extra.fn.params, i); + hash = spl_hash_mix(hash, vec_at(n.extra.fn.params, i)); } break; case SPL_LANG_TYPE_STRUCT: case SPL_LANG_TYPE_UNION: case SPL_LANG_TYPE_ENUM: case SPL_LANG_TYPE_SHAPE: + hash = spl_hash_mix(hash, vec_size(n.methods)); for (usize i = 0; i < vec_size(n.methods); i++) { spl_lang_method_t *m = &vec_at(n.methods, i); - hash += m->def_id * 31; - if (m->name) { - const char *s = m->name; - while (*s) - hash = hash * 31 + (usize)(*s++); - } + hash = spl_hash_mix(hash, m->def_id); + hash = spl_hash_mix_str(hash, m->name); } break; default: @@ -87,9 +88,6 @@ static int spl_lang_type_eq(spl_lang_type_node_t n1, spl_lang_type_node_t n2) { } } -static usize spl_lang_map_hash(usize k) { return MAP_HASH_INT(k); } -static int spl_lang_map_cmp(usize a, usize b) { return MAP_CMP_INT(a, b); } - static void spl_lang_node_free_extra(spl_lang_type_node_t *n) { switch (n->kind) { case SPL_LANG_TYPE_TUPLE: @@ -109,20 +107,35 @@ static void spl_lang_node_free_extra(spl_lang_type_node_t *n) { } } +/* spl_fold 回调:只在链内做结构比较(同桶已保证 hash 相同)。 */ +static int spl_lang_fold_eq(void *ctx, spl_fold_id_t node, const void *probe) { + spl_lang_type_t *type = (spl_lang_type_t *)ctx; + return spl_lang_type_eq(vec_at(type->lang_table, node), + *(const spl_lang_type_node_t *)probe) == 0; +} + +static spl_fold_id_t spl_lang_fold_next(void *ctx, spl_fold_id_t node) { + spl_lang_type_t *type = (spl_lang_type_t *)ctx; + return vec_at(type->lang_table, node).hash_next; +} + +static void spl_lang_fold_set_next(void *ctx, spl_fold_id_t node, spl_fold_id_t next) { + spl_lang_type_t *type = (spl_lang_type_t *)ctx; + vec_at(type->lang_table, node).hash_next = next; +} + spl_lang_type_id_t spl_lang_node_push(spl_lang_type_t *type, spl_lang_type_node_t *node) { usize hash = spl_lang_type_hash(*node); - usize idx = (usize)-1; - spl_lang_type_id_t cand = 0; - while (map_get_continue(type->lang_map, hash, &cand, &idx)) { - spl_lang_type_node_t *existing = &vec_at(type->lang_table, cand); - if (spl_lang_type_eq(*existing, *node) == 0) { - spl_lang_node_free_extra(node); - return cand; - } + + spl_lang_type_id_t existing = spl_fold_find(&type->lang_fold, hash, node); + if (existing) { + spl_lang_node_free_extra(node); + return existing; } + spl_lang_type_id_t id = vec_size(type->lang_table); vec_push(type->lang_table, *node); - map_put_new(type->lang_map, hash, id); + spl_fold_insert(&type->lang_fold, hash, id); node->kind = SPL_LANG_TYPE_ERROR; return id; } @@ -133,7 +146,8 @@ void spl_lang_type_init(spl_lang_type_t *type) { vec_init(type->lang_table); spl_lang_type_node_t lang_node = {0}; vec_push(type->lang_table, lang_node); - map_init(type->lang_map, spl_lang_map_hash, spl_lang_map_cmp); + spl_fold_init(&type->lang_fold, type, spl_lang_fold_eq, spl_lang_fold_next, + spl_lang_fold_set_next); vec_init(type->def_table); vec_push(type->def_table, (spl_def_node_t){0}); @@ -144,7 +158,7 @@ void spl_lang_type_drop(spl_lang_type_t *type) { spl_lang_type_node_t *n = &vec_at(type->lang_table, i); spl_lang_node_free_extra(n); } - map_free(type->lang_map); + spl_fold_drop(&type->lang_fold); vec_free(type->lang_table); vec_free(type->def_table); @@ -182,7 +196,7 @@ void spl_lang_define_ir(spl_lang_type_t *type, spl_type_id_t id, spl_type_node_t return; spl_type_node_t *slot = &vec_at(type->ir.type_table, id); /* slot 原是空 ERROR 节点,无 vec 字段可释放。node 的 vec 字段 move 进 slot。 - 占位 id 不写 type_map,不参与 hash-consing。 */ + 占位 id 不写 type_fold,不参与 hash-consing。 */ *slot = *node; node->kind = SPL_TYPE_ERROR; } diff --git a/stage1/spl_lang_type.h b/stage1/spl_lang_type.h index f96f4c5..12dd5dd 100644 --- a/stage1/spl_lang_type.h +++ b/stage1/spl_lang_type.h @@ -51,9 +51,9 @@ typedef struct { spl_lang_type_id_t ret; } fn; } extra; + usize hash_next; /* 同 hash 桶内下一个类型 id;0 表示链尾。不参与相等比较。 */ } spl_lang_type_node_t; typedef VEC(spl_lang_type_node_t) spl_lang_type_vec_t; -typedef MAP(usize, spl_lang_type_id_t) spl_lang_type_map_t; typedef enum { SPL_DEF_ERROR, @@ -91,7 +91,7 @@ typedef VEC(spl_def_node_t) spl_def_node_vec_t; typedef struct { spl_type_t ir; spl_lang_type_vec_t lang_table; - spl_lang_type_map_t lang_map; + spl_fold_t lang_fold; spl_def_node_vec_t def_table; } spl_lang_type_t; @@ -105,7 +105,7 @@ spl_type_id_t spl_lang_type_get_ir_type(spl_lang_type_t *type, spl_lang_type_id_ /* 前向引用支持:reserve 一个 type_table 空槽位(kind=ERROR)作为身份锚点, 让 *Node / []Node 这类成员能拿到稳定 pointee;成员解析完后再调 define - 把真实内容填进去。占位槽位**不写 type_map**,不参与 hash-consing—— + 把真实内容填进去。占位槽位**不写 type_fold**,不参与 hash-consing—— 后续相同形状的类型走 spl_type_node_push 会生成独立 id,语义等价。 */ spl_type_id_t spl_lang_reserve_ir(spl_lang_type_t *type); void spl_lang_define_ir(spl_lang_type_t *type, spl_type_id_t id, spl_type_node_t *node); diff --git a/stage1/spl_type.c b/stage1/spl_type.c index 5dceb29..b18f7a9 100644 --- a/stage1/spl_type.c +++ b/stage1/spl_type.c @@ -1,7 +1,8 @@ #include "spl_type.h" static usize spl_type_hash(spl_type_node_t n) { - usize hash = (usize)n.kind * 131; + usize hash = spl_hash_seed(); + hash = spl_hash_mix(hash, (usize)n.kind); switch (n.kind) { case SPL_TYPE_ERROR: case SPL_TYPE_UNIT: @@ -13,38 +14,38 @@ static usize spl_type_hash(spl_type_node_t n) { case SPL_TYPE_BOOL: break; case SPL_TYPE_INT: - hash += n.int_type.bits + (usize)n.int_type.is_signed; + hash = spl_hash_mix(hash, n.int_type.bits); + hash = spl_hash_mix(hash, (usize)n.int_type.is_signed); break; case SPL_TYPE_FLOAT: - hash += n.float_type.bits; + hash = spl_hash_mix(hash, n.float_type.bits); break; case SPL_TYPE_PTR: - hash += n.ptr_type.pointee; + hash = spl_hash_mix(hash, n.ptr_type.pointee); break; case SPL_TYPE_ARRAY: - hash += n.array_type.element + n.array_type.len; + hash = spl_hash_mix(hash, n.array_type.element); + hash = spl_hash_mix(hash, n.array_type.len); break; case SPL_TYPE_STRUCT: case SPL_TYPE_UNION: case SPL_TYPE_ENUM: case SPL_TYPE_SHAPE: - hash += (usize)n.layout.mode * 31 + n.layout.fixed_align_bits; - hash += n.agg_type.tag_type; + hash = spl_hash_mix(hash, (usize)n.layout.mode); + hash = spl_hash_mix(hash, n.layout.fixed_align_bits); + hash = spl_hash_mix(hash, n.agg_type.tag_type); + hash = spl_hash_mix(hash, vec_size(n.agg_type.variants)); for (usize i = 0; i < vec_size(n.agg_type.variants); i++) { - spl_type_member_t *m = &n.agg_type.variants.data[i]; - hash += m->type_id; - if (m->name) { - const char *s = m->name; - while (*s) { - hash = hash * 31 + (usize)(*s++); - } - } + spl_type_member_t *m = &vec_at(n.agg_type.variants, i); + hash = spl_hash_mix(hash, m->type_id); + hash = spl_hash_mix_str(hash, m->name); } break; case SPL_TYPE_FN: - hash += n.fn_type.ret; + hash = spl_hash_mix(hash, n.fn_type.ret); + hash = spl_hash_mix(hash, vec_size(n.fn_type.params)); for (usize i = 0; i < vec_size(n.fn_type.params); i++) { - hash += vec_at(n.fn_type.params, i); + hash = spl_hash_mix(hash, vec_at(n.fn_type.params, i)); } break; } @@ -110,9 +111,6 @@ static int spl_type_eq(spl_type_node_t n1, spl_type_node_t n2) { return 1; } -static usize spl_type_map_hash(usize k) { return MAP_HASH_INT(k); } -static int spl_type_map_cmp(usize a, usize b) { return MAP_CMP_INT(a, b); } - static void spl_type_node_free_vecs(spl_type_node_t *tn) { switch (tn->kind) { case SPL_TYPE_STRUCT: @@ -129,20 +127,34 @@ static void spl_type_node_free_vecs(spl_type_node_t *tn) { } } +/* spl_fold 回调:只在链内做结构比较(同桶已保证 hash 相同)。 */ +static int spl_type_fold_eq(void *ctx, spl_fold_id_t node, const void *probe) { + spl_type_t *type = (spl_type_t *)ctx; + return spl_type_eq(vec_at(type->type_table, node), *(const spl_type_node_t *)probe) == 0; +} + +static spl_fold_id_t spl_type_fold_next(void *ctx, spl_fold_id_t node) { + spl_type_t *type = (spl_type_t *)ctx; + return vec_at(type->type_table, node).hash_next; +} + +static void spl_type_fold_set_next(void *ctx, spl_fold_id_t node, spl_fold_id_t next) { + spl_type_t *type = (spl_type_t *)ctx; + vec_at(type->type_table, node).hash_next = next; +} + spl_type_id_t spl_type_node_push(spl_type_t *type, spl_type_node_t *tn) { usize hash = spl_type_hash(*tn); - usize idx = (usize)-1; - spl_type_id_t cand = 0; - while (map_get_continue(type->type_map, hash, &cand, &idx)) { - spl_type_node_t *existing = &vec_at(type->type_table, cand); - if (spl_type_eq(*existing, *tn) == 0) { - spl_type_node_free_vecs(tn); - return cand; - } + + spl_type_id_t existing = spl_fold_find(&type->type_fold, hash, tn); + if (existing) { + spl_type_node_free_vecs(tn); + return existing; } + spl_type_id_t id = vec_size(type->type_table); vec_push(type->type_table, *tn); - map_put_new(type->type_map, hash, id); + spl_fold_insert(&type->type_fold, hash, id); tn->kind = SPL_TYPE_ERROR; return id; } @@ -151,7 +163,8 @@ void spl_type_init(spl_type_t *type) { vec_init(type->type_table); spl_type_node_t type_node = {0}; vec_push(type->type_table, type_node); - map_init(type->type_map, spl_type_map_hash, spl_type_map_cmp); + spl_fold_init(&type->type_fold, type, spl_type_fold_eq, spl_type_fold_next, + spl_type_fold_set_next); } void spl_type_drop(spl_type_t *type) { @@ -159,7 +172,7 @@ void spl_type_drop(spl_type_t *type) { spl_type_node_t *n = &vec_at(type->type_table, i); spl_type_node_free_vecs(n); } - map_free(type->type_map); + spl_fold_drop(&type->type_fold); vec_free(type->type_table); } diff --git a/stage1/spl_type.h b/stage1/spl_type.h index 15f6be8..b5f285a 100644 --- a/stage1/spl_type.h +++ b/stage1/spl_type.h @@ -2,6 +2,27 @@ #define __SPL_TYPE_H__ #include "../stage0/include/utils.h" +#include "spl_fold.h" + +/* 类型 intern 用的哈希混合(FNV-1a 风格,顺序敏感)。 + hash 只用于选择桶;相等判定始终由结构比较完成。 */ +static inline usize spl_hash_mix(usize h, usize x) { + h ^= x; + h *= (usize)1099511628211ULL; + return h; +} + +static inline usize spl_hash_mix_str(usize h, const char *s) { + if (!s) + return spl_hash_mix(h, 0); + while (*s) { + h = spl_hash_mix(h, (usize)(unsigned char)*s); + s++; + } + return spl_hash_mix(h, 0); /* 终止符参与混合,避免名称拼接歧义 */ +} + +static inline usize spl_hash_seed(void) { return (usize)14695981039346656037ULL; } typedef usize spl_type_id_t; typedef VEC(spl_type_id_t) spl_type_id_vec_t; @@ -73,14 +94,13 @@ typedef struct { struct { } shape_type; }; + usize hash_next; /* 同 hash 桶内下一个类型 id;0 表示链尾。不参与相等比较。 */ } spl_type_node_t; typedef VEC(spl_type_node_t) spl_type_node_vec_t; -typedef MAP(usize, spl_type_id_t) spl_type_node_map_t; - typedef struct { spl_type_node_vec_t type_table; - spl_type_node_map_t type_map; + spl_fold_t type_fold; } spl_type_t; void spl_type_init(spl_type_t *type);