stage2 大量优化代码使其自举编译时间大幅缩短

This commit is contained in:
zzy committed 2026-09-20 09:33:20 +08:00
1 parent e02b0c633a
commit 846f441e3a
38 files changed
+2418 -835

No files matched your search

+2 -5
View File
@@ -272,11 +272,8 @@ fn drop(self: *Ast) {
}
fn node(self: *Ast, ref: usize): *Node {
match Vec.get(&self.nodes, ref) {
.Ok(ptr) => { ret ptr as *Node; },
.Err(error) => { ret null; },
}
ret null;
if ref >= self.nodes.len { ret null; }
ret (self.nodes.data as *Node) + ref;
}
// 追加节点,返回其引用(失败返回 0)。
+4 -4
View File
@@ -6,7 +6,7 @@
type .{ .Error } = @import("utils/error.spl");
type .{ .Vec } = @import("utils/vec.spl");
type .{ .Map } = @import("utils/map.spl");
type .{ .Map, .hash_kind_usize } = @import("utils/map.spl");
type .{ .ByteView } = @import("utils/byte_view.spl");
type .{ .ByteBuffer } = @import("utils/byte_buffer.spl");
type .{ .hash_usize, .eq_usize } = @import("utils/hash.spl");
@@ -54,8 +54,8 @@ owned: Vec, // ByteBuffer:为 dbg.panic 消息提供稳定存储
// ---- 小工具 ----
fn list_at(v: Vec, i: usize): usize {
match Vec.get(&v, i) { .Ok(p) => { ret (p as *usize).*; }, .Err(e) => { ret 0; } }
ret 0;
if i >= v.len { ret 0; }
ret ((v.data as *usize) + i).*;
}
fn push_u(v: *Vec, x: usize) {
@@ -2069,7 +2069,7 @@ fn new(builder: *IrBuilder, sema: *Sema, diag: *Diag): Ast2Ir {
.ir = builder,
.ast = sema.ast,
.def2ir_map = Map.new(@sizeof(usize), @alignof(usize), @sizeof(usize), @alignof(usize),
hash_usize, eq_usize),
hash_kind_usize()),
.loop_stack = Vec.blank(@sizeof(LoopCtx), @alignof(LoopCtx)),
.defer_stack = Vec.blank(@sizeof(usize), @alignof(usize)),
.cur_ret_lang = 0,
+1 -5
View File
@@ -132,11 +132,7 @@ fn drop(self: *Attr) {
fn node(self: *Attr, id: usize): *AttrNode {
if id == 0 || id >= self.table.len { ret null; }
match Vec.get(&self.table, id) {
.Ok(ptr) => { ret ptr as *AttrNode; },
.Err(error) => { ret null; },
}
ret null;
ret (self.table.data as *AttrNode) + id;
}
fn info_at(self: *Attr, index: usize): *AttrInfo {
+1 -5
View File
@@ -87,11 +87,7 @@ fn drop(self: *DefTable) {
// id 0 与越界均返回 null(对应 stage1 spl_def_node)。
fn node(self: *DefTable, id: usize): *DefNode {
if id == 0 || id >= self.table.len { ret null; }
match Vec.get(&self.table, id) {
.Ok(ptr) => { ret ptr as *DefNode; },
.Err(error) => { ret null; },
}
ret null;
ret (self.table.data as *DefNode) + id;
}
fn count(self: *DefTable): usize {
+1 -4
View File
@@ -161,10 +161,7 @@ fn table_count(): usize {
fn strip_at(name: ByteView): ByteView {
if name.len > 0 && name.ptr[0] == '@' {
match ByteView.slice(name, 1, name.len) {
.Ok(rest) => { ret rest; },
.Err(error) => { ret name; },
}
ret ByteView { .ptr = name.ptr + 1, .len = name.len - 1 };
}
ret name;
}
+17 -41
View File
@@ -167,26 +167,16 @@ fn drop_body(body: IrBody) {
fn drop(self: *Ir) {
var i: usize = 0;
while i < self.funcs.len {
match Vec.get(&self.funcs, i) {
.Ok(ptr) => {
var f = ptr as *IrFunc;
var j: usize = 0;
while j < f.nodes.len {
match Vec.get(&f.nodes, j) {
.Ok(np) => {
var e = np as *IrEntry;
Vec.drop(&e.attrs);
drop_body(e.body);
},
.Err(error) => {},
}
j = j + 1;
}
Vec.drop(&f.attrs);
Vec.drop(&f.nodes);
},
.Err(error) => {},
var f = (self.funcs.data as *IrFunc) + i;
var j: usize = 0;
while j < f.nodes.len {
var e = (f.nodes.data as *IrEntry) + j;
Vec.drop(&e.attrs);
drop_body(e.body);
j = j + 1;
}
Vec.drop(&f.attrs);
Vec.drop(&f.nodes);
i = i + 1;
}
Vec.drop(&self.funcs);
@@ -207,36 +197,22 @@ fn alloc_fn(self: *Ir): usize {
fn alloc_node(self: *Ir, fn_id: usize): usize {
if fn_id == 0 || fn_id >= self.funcs.len { ret 0; }
match Vec.get(&self.funcs, fn_id) {
.Ok(ptr) => {
var f = ptr as *IrFunc;
var n = new_entry();
match Vec.push(&f.nodes, &n as *u8) { .Ok => {}, .Err(error) => { ret 0; } }
ret f.nodes.len - 1;
},
.Err(error) => {},
}
ret 0;
var f = (self.funcs.data as *IrFunc) + fn_id;
var n = new_entry();
match Vec.push(&f.nodes, &n as *u8) { .Ok => {}, .Err(error) => { ret 0; } }
ret f.nodes.len - 1;
}
fn func(self: *Ir, fn_id: usize): *IrFunc {
if fn_id == 0 || fn_id >= self.funcs.len { ret null; }
match Vec.get(&self.funcs, fn_id) {
.Ok(ptr) => { ret ptr as *IrFunc; },
.Err(error) => { ret null; },
}
ret null;
ret (self.funcs.data as *IrFunc) + fn_id;
}
fn node(self: *Ir, fn_id: usize, node_id: usize): *IrEntry {
var f = func(self, fn_id);
if f == null { ret null; }
if node_id == 0 || node_id >= f.nodes.len { ret null; }
match Vec.get(&f.nodes, node_id) {
.Ok(ptr) => { ret ptr as *IrEntry; },
.Err(error) => { ret null; },
}
ret null;
ret (f.nodes.data as *IrEntry) + node_id;
}
fn kind_name(kind: IrKind): []u8 {
@@ -345,8 +321,8 @@ fn dump_attrs(out: *ByteBuffer, attr: *Attr, ids: Vec): bool {
}
fn list_at(v: Vec, i: usize): usize {
match Vec.get(&v, i) { .Ok(p) => { ret (p as *usize).*; }, .Err(e) => { ret 0; } }
ret 0;
if i >= v.len { ret 0; }
ret ((v.data as *usize) + i).*;
}
fn dump_body(out: *ByteBuffer, ty: *TypeTable, e: *IrEntry): bool {
+12 -2
View File
@@ -362,7 +362,7 @@ fn frame_build(fl: *FrameLayout, ctx: *Ir2Vm, fid: usize) {
var i: usize = 0;
while i < n {
var blank: Slot = .{ .result_off = 0, .data_off = 0 };
match Vec.push(&fl.slots, &blank as *u8) { .Ok => {}, .Err(error) => {} }
ignore_bool(Vec.push_raw(&fl.slots, &blank as *u8));
i = i + 1;
}
@@ -421,7 +421,17 @@ fixups: *Vec,
terminated: bool,
fn emit(cg: *Cgen, op: Op, ty: VmKind, imm: usize) {
ignore_usize(Mcode.add_instr(&cg.ctx.prog, op, ty, imm));
var prog = &cg.ctx.prog;
var i = prog.insns.len;
if i < prog.insns.cap {
var p = (prog.insns.data as *VmIns) + i;
p.opcode = op;
p.ty = ty;
p.imm = imm;
prog.insns.len = i + 1;
ret;
}
ignore_usize(Mcode.add_instr(prog, op, ty, imm));
}
fn ip_of(cg: *Cgen): usize {
+2 -2
View File
@@ -14,8 +14,8 @@ type Ir = @import("./ir.spl");
type .{ .IrKind, .ConstLit, .IrEntry, .IrFunc, .IrBody } = @import("./ir.spl");
fn list_at(v: Vec, i: usize): usize {
match Vec.get(&v, i) { .Ok(p) => { ret (p as *usize).*; }, .Err(e) => { ret 0; } }
ret 0;
if i >= v.len { ret 0; }
ret ((v.data as *usize) + i).*;
}
// ---- builder ----
+3 -7
View File
@@ -9,7 +9,7 @@
type .{ .Error } = @import("utils/error.spl");
type .{ .Vec } = @import("utils/vec.spl");
type .{ .Map } = @import("utils/map.spl");
type .{ .Map, .hash_kind_usize } = @import("utils/map.spl");
type .{ .ByteView } = @import("utils/byte_view.spl");
type .{ .ByteBuffer } = @import("utils/byte_buffer.spl");
type .{ .append_usize } = @import("utils/fmt.spl");
@@ -183,7 +183,7 @@ fn new(): LangTypeResult {
.ir = ir,
.lang_table = lang_table,
.fold = Map.new(@sizeof(usize), @alignof(usize), @sizeof(usize), @alignof(usize),
hash_usize, eq_usize),
hash_kind_usize()),
.defs = defs,
.owned_names = Vec.blank(@sizeof(ByteBuffer), @alignof(ByteBuffer)),
};
@@ -218,11 +218,7 @@ fn drop(self: *LangType) {
// id 0 与越界返回 null(对应 stage1 spl_lang_type_node)。
fn lang_node(self: *LangType, id: usize): *LangEntry {
if id == 0 || id >= self.lang_table.len { ret null; }
match Vec.get(&self.lang_table, id) {
.Ok(ptr) => { ret ptr as *LangEntry; },
.Err(error) => { ret null; },
}
ret null;
ret (self.lang_table.data as *LangEntry) + id;
}
fn ir_type(self: *LangType, lang_id: usize): usize {
+1 -5
View File
@@ -44,11 +44,7 @@ fn new(): LayoutResult {
fn info_at(self: *Layout, id: usize): *LayoutInfo {
if id == 0 || id >= self.infos.len { ret null; }
match Vec.get(&self.infos, id) {
.Ok(ptr) => { ret ptr as *LayoutInfo; },
.Err(error) => { ret null; },
}
ret null;
ret (self.infos.data as *LayoutInfo) + id;
}
// 未解析或越界返回 null(对应 stage1 spl_layout_info_of)。
+2 -5
View File
@@ -92,11 +92,8 @@ fn has3(self: *Lexer, ch1: u8, ch2: u8): bool {
}
fn sub(self: *Lexer, start: usize, end: usize): ByteView {
match ByteView.slice(self.src, start, end) {
.Ok(v) => { ret v; },
.Err(error) => { ret ByteView.empty(); },
}
ret ByteView.empty();
if start >= end { ret ByteView.empty(); }
ret ByteView { .ptr = self.src.ptr + start, .len = end - start };
}
// 产出 token 并把 pos/col 推进到 end。Vec.push 失败视为致命(同 vec.make_vec 风格)。
+71 -26
View File
@@ -265,6 +265,15 @@ fn drop(self: *Prog) {
// ---- 构建 ----
fn add_instr(self: *Prog, op: Op, ty: VmKind, imm: usize): usize {
var i = self.insns.len;
if i < self.insns.cap {
var p = (self.insns.data as *VmIns) + i;
p.opcode = op;
p.ty = ty;
p.imm = imm;
self.insns.len = i + 1;
ret i + 1;
}
var ins = VmIns { .opcode = op, .ty = ty, .imm = imm };
if !Vec.push_raw(&self.insns, &ins as *u8) { ret 0; }
ret self.insns.len;
@@ -462,11 +471,8 @@ fn dump(self: *Prog, out: *ByteBuffer): bool {
}
fn ins_at(self: *Prog, i: usize): VmIns {
match Vec.get(&self.insns, i) {
.Ok(ptr) => { ret (ptr as *VmIns).*; },
.Err(error) => { ret VmIns { .opcode = .Error, .ty = .Void, .imm = 0 }; },
}
ret VmIns { .opcode = .Error, .ty = .Void, .imm = 0 };
if i >= self.insns.len { ret VmIns { .opcode = .Error, .ty = .Void, .imm = 0 }; }
ret ((self.insns.data as *VmIns) + i).*;
}
fn func_at(self: *Prog, i: usize): *VmFunc {
@@ -491,41 +497,43 @@ fn align8(n: usize): usize {
ret (n + 7) & (~(7 as usize));
}
// 说明:以下 put_* 直接写入已预留容量的 ByteBuffer 存储(store 已按精确总大小 reserve),
// 跳过 ByteBuffer.append → Vec.append 的校验/拷贝路径。若容量不足会越界,故 store 先校验容量。
fn put_u8(out: *ByteBuffer, b: u8): bool {
match ByteBuffer.append_byte(out, b) { .Ok => { ret true; }, .Err(error) => { ret false; } }
ret false;
out.storage.data[out.storage.len] = b;
out.storage.len = out.storage.len + 1;
ret true;
}
// 直接按小端整型写(x86 小端;VM 的 STORE 用 memcpy,未对齐也安全)。
fn put_u16(out: *ByteBuffer, v: usize): bool {
if !put_u8(out, (v & 255) as u8) { ret false; }
ret put_u8(out, ((v >> 8) & 255) as u8);
var d = out.storage.data + out.storage.len;
(d as *u16).* = v as u16;
out.storage.len = out.storage.len + 2;
ret true;
}
fn put_u64(out: *ByteBuffer, v: usize): bool {
var i: usize = 0;
while i < 8 {
if !put_u8(out, ((v >> (i * 8)) & 255) as u8) { ret false; }
i = i + 1;
}
var d = out.storage.data + out.storage.len;
(d as *u64).* = v as u64;
out.storage.len = out.storage.len + 8;
ret true;
}
fn put_zeros(out: *ByteBuffer, n: usize): bool {
var i: usize = 0;
while i < n {
if !put_u8(out, 0) { ret false; }
i = i + 1;
if n != 0 {
ignore_ptr(Mem.set((out.storage.data + out.storage.len) as *any, 0, n));
out.storage.len = out.storage.len + n;
}
ret true;
}
fn put_view(out: *ByteBuffer, v: ByteView): bool {
if v.len == 0 { ret true; }
match ByteBuffer.append(out, ByteView.as_slice(v)) {
.Ok => { ret true; },
.Err(error) => { ret false; },
}
ret false;
Mem.copy((out.storage.data + out.storage.len) as *any, v.ptr as *any, v.len);
out.storage.len = out.storage.len + v.len;
ret true;
}
// 写入「带结尾 NUL、再按 8 对齐」的名称字段(对应 C 侧 nlen = strlen+1)。
@@ -541,6 +549,41 @@ fn store(self: *Prog, path: ByteView): Status {
var out = ByteBuffer.new();
defer { ByteBuffer.drop(&out); }
// 精确预估输出大小并一次性预留,避免大文件逐字节增长导致的重复拷贝。
var total: usize = 48;
var fi: usize = 0;
while fi < self.funcs.len {
var f = func_at(self, fi);
if f != null {
var nlen = f.name.len + 1;
total = total + 8 + align8(nlen) + 32;
}
fi = fi + 1;
}
total = total + self.insns.len * 12;
fi = 0;
while fi < self.natives.len {
var n = native_at(self, fi);
if n != null {
var nlen = n.name.len + 1;
total = total + 8 + align8(nlen) + 8;
}
fi = fi + 1;
}
fi = 0;
while fi < self.strtab.len {
total = total + 8 + align8(str_at(self, fi).len);
fi = fi + 1;
}
fi = 1;
while fi < self.gdata.len {
var e = gdata_at(self, fi);
if e != null { total = total + 8 + align8(e.storage.len); }
fi = fi + 1;
}
match ByteBuffer.reserve(&out, total) { .Ok => {}, .Err(error) => {} }
if out.storage.cap < total || out.storage.data == null { ret .Err(make(.Io)); }
if !put_view(&out, ByteView.from_slice("SPLBIN")) { ret .Err(make(.Io)); }
if !put_zeros(&out, 2) { ret .Err(make(.Io)); }
@@ -572,9 +615,11 @@ fn store(self: *Prog, path: ByteView): Status {
i = 0;
while i < ninsns {
var ins = ins_at(self, i);
if !put_u16(&out, @enum2int(ins.opcode) as usize) { ret .Err(make(.Io)); }
if !put_u16(&out, @enum2int(ins.ty) as usize) { ret .Err(make(.Io)); }
if !put_u64(&out, ins.imm) { ret .Err(make(.Io)); }
var d = out.storage.data + out.storage.len;
(d as *u16).* = @enum2int(ins.opcode) as u16;
((d + 2) as *u16).* = @enum2int(ins.ty) as u16;
((d + 4) as *u64).* = ins.imm as u64;
out.storage.len = out.storage.len + 12;
i = i + 1;
}
+7 -9
View File
@@ -42,11 +42,8 @@ fn new(ast: *Ast, toks: Vec, diag: *Diag): Parser {
// ---- token 访问 ----
fn token_ptr(self: *Parser, index: usize): *Token {
match Vec.get(&self.toks, index) {
.Ok(ptr) => { ret ptr as *Token; },
.Err(error) => { ret null; },
}
ret null;
if index >= self.toks.len { ret null; }
ret (self.toks.data as *Token) + index;
}
fn is_trivia(kind: TokenKind): bool {
@@ -61,16 +58,17 @@ fn is_trivia(kind: TokenKind): bool {
// 跳过 trivia;返回当前 token(含 EOF)。越界返回 null。
fn peek(self: *Parser): *Token {
var n = self.toks.len;
var base = self.toks.data as *Token;
var i = self.pos;
while i < n {
var t = token_ptr(self, i);
if t == null { break; }
if base == null { break; }
var t = base + i;
if !is_trivia(t.kind) { break; }
i = i + 1;
}
self.pos = i;
if i >= n { ret null; }
ret token_ptr(self, i);
if i >= n || base == null { ret null; }
ret base + i;
}
fn advance(self: *Parser): *Token {
+3 -7
View File
@@ -7,7 +7,7 @@
type .{ .Error } = @import("utils/error.spl");
type .{ .Vec } = @import("utils/vec.spl");
type .{ .Map } = @import("utils/map.spl");
type .{ .Map, .hash_kind_view } = @import("utils/map.spl");
type .{ .ByteView } = @import("utils/byte_view.spl");
type .{ .hash_view, .eq_view } = @import("utils/hash.spl");
@@ -43,7 +43,7 @@ type ScopeResult = enum {
fn new_map(): Map {
ret Map.new(@sizeof(ByteView), @alignof(ByteView), @sizeof(Symbol), @alignof(Symbol),
hash_view, eq_view);
hash_kind_view());
}
fn new(): ScopeResult {
@@ -81,11 +81,7 @@ fn drop(self: *Scope) {
// id 0 与越界返回 null。
fn node(self: *Scope, id: usize): *ScopeNode {
if id == 0 || id >= self.scopes.len { ret null; }
match Vec.get(&self.scopes, id) {
.Ok(ptr) => { ret ptr as *ScopeNode; },
.Err(error) => { ret null; },
}
ret null;
ret (self.scopes.data as *ScopeNode) + id;
}
// 新作用域 parent = 当前作用域;不自动切换 current(调用方负责,见 sema)。
+4 -7
View File
@@ -9,7 +9,7 @@
type .{ .Error, .Status } = @import("utils/error.spl");
type .{ .Vec } = @import("utils/vec.spl");
type .{ .Map } = @import("utils/map.spl");
type .{ .Map, .hash_kind_usize } = @import("utils/map.spl");
type .{ .ByteView } = @import("utils/byte_view.spl");
type .{ .ByteBuffer } = @import("utils/byte_buffer.spl");
type .{ .append_usize } = @import("utils/fmt.spl");
@@ -69,11 +69,8 @@ type SemaResult = enum {
// ---- 小工具 ----
fn list_at(v: Vec, i: usize): usize {
match Vec.get(&v, i) {
.Ok(ptr) => { ret (ptr as *usize).*; },
.Err(error) => { ret 0; },
}
ret 0;
if i >= v.len { ret 0; }
ret ((v.data as *usize) + i).*;
}
fn push_u(v: *Vec, x: usize) {
@@ -234,7 +231,7 @@ fn new(ast: *Ast, diag: *Diag): SemaResult {
.current_loop_break_tid = 0,
.label_stack = Vec.blank(@sizeof(ByteView), @alignof(ByteView)),
.ir_to_lang = Map.new(@sizeof(usize), @alignof(usize), @sizeof(usize), @alignof(usize),
hash_usize, eq_usize),
hash_kind_usize()),
};
ret .Ok(s);
}
+4
View File
@@ -25,6 +25,10 @@ fn steps(): usize {
ret vm_timestamp(3);
}
fn calls(): usize {
ret vm_timestamp(5);
}
fn now_ns(): usize {
ret vm_timestamp(4);
}
+58 -30
View File
@@ -66,37 +66,65 @@ fn is_trivia(kind: TokenKind): bool {
}
}
// 先按长度与首字节分派,再做完整比较,避免对每个标识符做全表串比较。
fn keyword_of(text: ByteView): KeywordResult {
if is(text, "any") { ret .Yes(.Any); }
if is(text, "as") { ret .Yes(.As); }
if is(text, "bool") { ret .Yes(.Bool); }
if is(text, "break") { ret .Yes(.Break); }
if is(text, "catch") { ret .Yes(.Catch); }
if is(text, "comptime") { ret .Yes(.Comptime); }
if is(text, "const") { ret .Yes(.Const); }
if is(text, "continue") { ret .Yes(.Continue); }
if is(text, "defer") { ret .Yes(.Defer); }
if is(text, "else") { ret .Yes(.Else); }
if is(text, "enum") { ret .Yes(.Enum); }
if is(text, "errdefer") { ret .Yes(.Errdefer); }
if is(text, "false") { ret .Yes(.False); }
if is(text, "fn") { ret .Yes(.Fn); }
if is(text, "for") { ret .Yes(.For); }
if is(text, "if") { ret .Yes(.If); }
if is(text, "loop") { ret .Yes(.Loop); }
if is(text, "match") { ret .Yes(.Match); }
if is(text, "null") { ret .Yes(.Null); }
if is(text, "ret") { ret .Yes(.Ret); }
if is(text, "shape") { ret .Yes(.Shape); }
if is(text, "struct") { ret .Yes(.Struct); }
if is(text, "true") { ret .Yes(.True); }
if is(text, "try") { ret .Yes(.Try); }
if is(text, "type") { ret .Yes(.Type); }
if is(text, "undefined") { ret .Yes(.Undefined); }
if is(text, "union") { ret .Yes(.Union); }
if is(text, "var") { ret .Yes(.Var); }
if is(text, "while") { ret .Yes(.While); }
if is(text, "_") { ret .Yes(.Underscore); }
var n = text.len;
if n == 0 { ret .No; }
var c0 = text.ptr[0];
if n == 2 {
if c0 == 'a' && is(text, "as") { ret .Yes(.As); }
if c0 == 'f' && is(text, "fn") { ret .Yes(.Fn); }
if c0 == 'i' && is(text, "if") { ret .Yes(.If); }
ret .No;
}
if n == 3 {
if c0 == 'a' && is(text, "any") { ret .Yes(.Any); }
if c0 == 'f' && is(text, "for") { ret .Yes(.For); }
if c0 == 'r' && is(text, "ret") { ret .Yes(.Ret); }
if c0 == 't' && is(text, "try") { ret .Yes(.Try); }
if c0 == 'v' && is(text, "var") { ret .Yes(.Var); }
ret .No;
}
if n == 4 {
if c0 == 'b' && is(text, "bool") { ret .Yes(.Bool); }
if c0 == 'e' && is(text, "else") { ret .Yes(.Else); }
if c0 == 'e' && is(text, "enum") { ret .Yes(.Enum); }
if c0 == 'l' && is(text, "loop") { ret .Yes(.Loop); }
if c0 == 'n' && is(text, "null") { ret .Yes(.Null); }
if c0 == 't' && is(text, "true") { ret .Yes(.True); }
if c0 == 't' && is(text, "type") { ret .Yes(.Type); }
ret .No;
}
if n == 5 {
if c0 == 'b' && is(text, "break") { ret .Yes(.Break); }
if c0 == 'c' && is(text, "catch") { ret .Yes(.Catch); }
if c0 == 'c' && is(text, "const") { ret .Yes(.Const); }
if c0 == 'd' && is(text, "defer") { ret .Yes(.Defer); }
if c0 == 'f' && is(text, "false") { ret .Yes(.False); }
if c0 == 'm' && is(text, "match") { ret .Yes(.Match); }
if c0 == 's' && is(text, "shape") { ret .Yes(.Shape); }
if c0 == 'u' && is(text, "union") { ret .Yes(.Union); }
if c0 == 'w' && is(text, "while") { ret .Yes(.While); }
ret .No;
}
if n == 6 {
if c0 == 's' && is(text, "struct") { ret .Yes(.Struct); }
ret .No;
}
if n == 8 {
if c0 == 'c' && is(text, "comptime") { ret .Yes(.Comptime); }
if c0 == 'c' && is(text, "continue") { ret .Yes(.Continue); }
if c0 == 'e' && is(text, "errdefer") { ret .Yes(.Errdefer); }
ret .No;
}
if n == 9 {
if c0 == 'u' && is(text, "undefined") { ret .Yes(.Undefined); }
ret .No;
}
if n == 1 {
if c0 == '_' && is(text, "_") { ret .Yes(.Underscore); }
ret .No;
}
ret .No;
}
+5 -12
View File
@@ -9,7 +9,7 @@
type .{ .Error } = @import("utils/error.spl");
type .{ .Vec } = @import("utils/vec.spl");
type .{ .Map } = @import("utils/map.spl");
type .{ .Map, .hash_kind_usize } = @import("utils/map.spl");
type .{ .ByteView } = @import("utils/byte_view.spl");
type .{ .ByteBuffer } = @import("utils/byte_buffer.spl");
type .{ .append_usize } = @import("utils/fmt.spl");
@@ -301,11 +301,8 @@ fn usize_at(v: Vec, i: usize): usize {
}
fn member_at(v: *Vec, i: usize): *Member {
match Vec.get(v, i) {
.Ok(ptr) => { ret ptr as *Member; },
.Err(error) => { ret null; },
}
ret null;
if i >= v.len { ret null; }
ret (v.data as *Member) + i;
}
fn push_member(v: *Vec, name: []u8, type_id: usize) {
@@ -323,11 +320,7 @@ fn push_member(v: *Vec, name: []u8, type_id: usize) {
// id 0 与越界均返回 null(对应 stage1 spl_type_node)。
fn node(self: *TypeTable, id: usize): *TypeEntry {
if id == 0 || id >= self.table.len { ret null; }
match Vec.get(&self.table, id) {
.Ok(ptr) => { ret ptr as *TypeEntry; },
.Err(error) => { ret null; },
}
ret null;
ret (self.table.data as *TypeEntry) + id;
}
// ---- 生命周期 ----
@@ -336,7 +329,7 @@ fn new(): TypeTableResult {
var tt = TypeTable {
.table = Vec.blank(@sizeof(TypeEntry), @alignof(TypeEntry)),
.fold = Map.new(@sizeof(usize), @alignof(usize), @sizeof(usize), @alignof(usize),
hash_usize, eq_usize),
hash_kind_usize()),
};
var sentinel = TypeEntry { .hash_next = 0, .node = .Error };
match Vec.push(&tt.table, &sentinel as *u8) {
+3 -7
View File
@@ -5,6 +5,8 @@
type .{ .Error, .make } = @import("error.spl");
#extern(vm) fn vm_bytes_eq(a: *any, alen: usize, b: *any, blen: usize): i32;
type ByteView = @self;
ptr: *u8,
@@ -62,13 +64,7 @@ fn byte_at(self: ByteView, index: usize): ByteResult {
}
fn eq(a: ByteView, b: ByteView): bool {
if a.len != b.len { ret false; }
var i: usize = 0;
while i < a.len {
if a.ptr[i] != b.ptr[i] { ret false; }
i = i + 1;
}
ret true;
ret vm_bytes_eq(a.ptr as *any, a.len, b.ptr as *any, b.len) != 0;
}
// 按无符号字节进行字典序比较,结果只承诺小于、等于或大于零。
+45 -190
View File
@@ -7,9 +7,14 @@
type .{ .Error, .Status, .make } = @import("error.spl");
type .{ .Vec } = @import("vec.spl");
type .{ .ByteView } = @import("byte_view.spl");
type .{ .hash_usize, .eq_usize, .hash_view, .eq_view } = @import("hash.spl");
type .{ .checked_add, .checked_mul, .grow_capacity } = @import("memory.spl");
type .{ .copy } = @import("../sys/mem.spl");
#extern(vm) fn vm_map_valid(m: *any): i32;
#extern(vm) fn vm_map_reserve(m: *any, need: usize): i32;
#extern(vm) fn vm_map_put(m: *any, key: *any, val: *any): i32;
#extern(vm) fn vm_map_get(m: *any, key: *any, out: *any): i32;
#extern(vm) fn vm_map_del(m: *any, key: *any): i32;
#extern(vm) fn vm_map_clear(m: *any): void;
#extern(vm) fn vm_map_drop(m: *any): void;
// 槽位状态:Empty/Occupied/Deleted(墓碑,仅在扩容重哈希时清除)。
// 负载因子 70/128。
@@ -20,11 +25,6 @@ type SlotState = enum {
Deleted,
}
fn state_code(state: SlotState): u8 {
var s: SlotState = state;
ret @enum2int(s) as u8;
}
// 查找/删除结果:显式区分命中与缺失,替代 bool 哨兵。
type LookupResult = enum {
Found,
@@ -39,11 +39,15 @@ states: Vec,
size: usize,
key_size: usize,
val_size: usize,
hash_fn: fn(*u8): usize,
eq_fn: fn(*u8, *u8): bool,
hash_kind: usize,
// 键解释:0 = usize;1 = ByteView(按内容哈希/比较)。
fn hash_kind_usize(): usize { ret 0; }
fn hash_kind_view(): usize { ret 1; }
fn hash_kind_constant(): usize { ret 2; }
fn blank(key_size: usize, key_align: usize, val_size: usize, val_align: usize,
hash_fn: fn(*u8): usize, eq_fn: fn(*u8, *u8): bool): Map {
hash_kind: usize): Map {
ret Map {
.keys = Vec.blank(key_size, key_align),
.vals = Vec.blank(val_size, val_align),
@@ -51,23 +55,30 @@ fn blank(key_size: usize, key_align: usize, val_size: usize, val_align: usize,
.size = 0,
.key_size = key_size,
.val_size = val_size,
.hash_fn = hash_fn,
.eq_fn = eq_fn,
.hash_kind = hash_kind,
};
}
fn new(key_size: usize, key_align: usize, val_size: usize, val_align: usize,
hash_fn: fn(*u8): usize, eq_fn: fn(*u8, *u8): bool): Map {
ret blank(key_size, key_align, val_size, val_align, hash_fn, eq_fn);
hash_kind: usize): Map {
ret blank(key_size, key_align, val_size, val_align, hash_kind);
}
fn valid(self: Map): bool {
if self.key_size == 0 || self.val_size == 0 { ret false; }
if self.states.len != self.keys.len || self.states.len != self.vals.len {
ret false;
}
if self.size > self.states.len { ret false; }
ret true;
fn status_from_code(code: i32): Status {
if code == 0 { ret .Ok; }
if code == 2 { ret .Err(make(.OutOfRange)); }
if code == 3 { ret .Err(make(.Overflow)); }
if code == 4 { ret .Err(make(.InvalidAlignment)); }
ret .Err(make(.InvalidArgument));
}
fn lookup_from_code(code: i32): LookupResult {
if code == 0 { ret .Found; }
ret .NotFound;
}
fn valid(self: *Map): bool {
ret vm_map_valid(self as *any) != 0;
}
fn size(self: Map): usize {
@@ -85,10 +96,8 @@ fn slot_count(self: Map): usize {
fn slot_state(self: Map, index: usize): SlotState {
var code = self.states.data[index];
var occupied: SlotState = .Occupied;
var deleted_state: SlotState = .Deleted;
if code == state_code(occupied) { ret .Occupied; }
if code == state_code(deleted_state) { ret .Deleted; }
if code == 1 { ret .Occupied; }
if code == 2 { ret .Deleted; }
ret .Empty;
}
@@ -109,186 +118,32 @@ fn val_at(self: *Map, index: usize): *u8 {
ret self.vals.data + index * self.val_size;
}
// 返回占用键的槽位;未找到返回 ~0。容量为 0 时直接未找到。
fn find_slot(self: *Map, key: *u8): usize {
if self.states.cap == 0 { ret ~(0 as usize); }
var mask = self.states.cap - 1;
var i = self.hash_fn(key) & mask;
var empty: SlotState = .Empty;
var occupied: SlotState = .Occupied;
var probes: usize = 0;
while probes < self.states.cap && self.states.data[i] != state_code(empty) {
if self.states.data[i] == state_code(occupied) &&
self.eq_fn(self.keys.data + i * self.key_size, key) {
ret i;
}
i = (i + 1) & mask;
probes = probes + 1;
}
ret ~(0 as usize);
}
// 要求容量非零且键不存在。优先复用探测链中的第一个墓碑。
fn place(self: *Map, key: *u8, val: *u8) {
var mask = self.states.cap - 1;
var i = self.hash_fn(key) & mask;
var empty: SlotState = .Empty;
var deleted: SlotState = .Deleted;
var occupied: SlotState = .Occupied;
var first_deleted = ~(0 as usize);
var probes: usize = 0;
while probes < self.states.cap && self.states.data[i] != state_code(empty) {
if self.states.data[i] == state_code(deleted) && first_deleted == ~(0 as usize) {
first_deleted = i;
}
i = (i + 1) & mask;
probes = probes + 1;
}
if first_deleted != ~(0 as usize) {
i = first_deleted;
}
copy((self.keys.data + i * self.key_size) as *any, key as *any, self.key_size);
copy((self.vals.data + i * self.val_size) as *any, val as *any, self.val_size);
self.states.data[i] = state_code(occupied);
self.size = self.size + 1;
}
// 保证至少 need 个槽位。所有检查在旧表改动前完成,失败保持原表不变。
fn reserve(self: *Map, need: usize): Status {
if !valid(self.*) { ret .Err(make(.InvalidArgument)); }
if need <= self.states.cap { ret .Ok; }
var new_cap = grow_capacity(self.states.cap, 8, need);
var fresh = self.*;
fresh.keys = Vec.blank(self.key_size, self.keys.elem_align);
fresh.vals = Vec.blank(self.val_size, self.vals.elem_align);
fresh.states = Vec.blank(1, 1);
fresh.size = 0;
match Vec.reserve(&fresh.keys, new_cap) {
.Ok => {},
.Err(error) => { drop(&fresh); ret .Err(error); },
}
match Vec.reserve(&fresh.vals, new_cap) {
.Ok => {},
.Err(error) => { drop(&fresh); ret .Err(error); },
}
match Vec.reserve(&fresh.states, new_cap) {
.Ok => {},
.Err(error) => { drop(&fresh); ret .Err(error); },
}
fresh.keys.len = new_cap;
fresh.vals.len = new_cap;
fresh.states.len = new_cap;
var i: usize = 0;
var empty: SlotState = .Empty;
var occupied: SlotState = .Occupied;
while i < new_cap {
fresh.states.data[i] = state_code(empty);
i = i + 1;
}
i = 0;
while i < self.states.len {
if self.states.data[i] == state_code(occupied) {
place(&fresh, self.keys.data + i * self.key_size,
self.vals.data + i * self.val_size);
}
i = i + 1;
}
var old_keys = self.keys;
var old_vals = self.vals;
var old_states = self.states;
self.* = fresh;
Vec.drop(&old_keys);
Vec.drop(&old_vals);
Vec.drop(&old_states);
ret .Ok;
ret status_from_code(vm_map_reserve(self as *any, need));
}
// 覆盖已存在的键;否则插入并可能扩容。
fn put(self: *Map, key: *u8, val: *u8): Status {
if !valid(self.*) || key == null || val == null {
ret .Err(make(.InvalidArgument));
}
var existing = find_slot(self, key);
if existing != ~(0 as usize) {
copy((self.vals.data + existing * self.val_size) as *any, val as *any, self.val_size);
ret .Ok;
}
if self.states.cap == 0 {
match reserve(self, 8) {
.Ok => {},
.Err(error) => { ret .Err(error); },
}
} else {
var next_size: usize = 0;
match checked_add(self.size, 1) {
.Ok(value) => { next_size = value; },
.Err(error) => { ret .Err(error); },
}
var scaled: usize = 0;
match checked_mul(next_size, 128) {
.Ok(value) => { scaled = value; },
.Err(error) => { ret .Err(error); },
}
if scaled / self.states.cap >= 70 {
var need: usize = 0;
match checked_mul(self.states.cap, 2) {
.Ok(value) => { need = value; },
.Err(error) => { ret .Err(error); },
}
match reserve(self, need) {
.Ok => {},
.Err(error) => { ret .Err(error); },
}
}
}
place(self, key, val);
ret .Ok;
ret status_from_code(vm_map_put(self as *any, key as *any, val as *any));
}
// 找到键则把值复制到 out 并返回 Found;否则 out 不变并返回 NotFound。
fn get(self: *Map, key: *u8, out: *u8): LookupResult {
if !valid(self.*) || key == null || out == null { ret .NotFound; }
var i = find_slot(self, key);
if i == ~(0 as usize) { ret .NotFound; }
copy(out as *any, (self.vals.data + i * self.val_size) as *any, self.val_size);
ret .Found;
ret lookup_from_code(vm_map_get(self as *any, key as *any, out as *any));
}
fn del(self: *Map, key: *u8): LookupResult {
if !valid(self.*) || key == null { ret .NotFound; }
var i = find_slot(self, key);
if i == ~(0 as usize) { ret .NotFound; }
var deleted_state: SlotState = .Deleted;
self.states.data[i] = state_code(deleted_state);
self.size = self.size - 1;
ret .Found;
ret lookup_from_code(vm_map_del(self as *any, key as *any));
}
// 清空内容但保留容量。墓碑与负载计数一并复位。
fn clear(self: *Map) {
var i: usize = 0;
var empty: SlotState = .Empty;
while i < self.states.len {
self.states.data[i] = state_code(empty);
i = i + 1;
}
self.size = 0;
vm_map_clear(self as *any);
}
fn drop(self: *Map) {
Vec.drop(&self.keys);
Vec.drop(&self.vals);
Vec.drop(&self.states);
self.size = 0;
vm_map_drop(self as *any);
}
fn take(source: *Map): Map {
@@ -348,13 +203,13 @@ fn deleted(m: *Map, key: *u8): bool {
}
fn make_int_map(): Map {
ret new(@sizeof(usize), @alignof(usize), @sizeof(i32), @alignof(i32), hash_usize, eq_usize);
ret new(@sizeof(usize), @alignof(usize), @sizeof(i32), @alignof(i32), hash_kind_usize());
}
fn test_put_get_update() {
var m = make_int_map();
@assert(size(m) == 0 && capacity(m) == 0, "empty map");
@assert(valid(m));
@assert(valid(&m));
var key: usize = 0;
var value: i32 = 0;
@@ -367,7 +222,7 @@ fn test_put_get_update() {
key = 7;
value = 70;
expect_ok(put(&m, &key as *u8, &value as *u8));
@assert(size(m) == 1 && valid(m));
@assert(size(m) == 1 && valid(&m));
out = -1;
@assert(found(&m, &key as *u8, &out as *u8) && out == 70, "insert then get");
@@ -463,7 +318,7 @@ fn test_take_and_self_put() {
fn test_byte_view_keys() {
var m = new(@sizeof(ByteView), @alignof(ByteView), @sizeof(i32), @alignof(i32),
hash_view, eq_view);
hash_kind_view());
defer { drop(&m); }
var alpha = ByteView.from_slice("alpha");
+3 -25
View File
@@ -5,6 +5,7 @@
type .{ .Error, .Status, .make } = @import("error.spl");
#extern(vm) fn vm_memcpy(dst: *any, src: *any, n: usize): *any;
#extern(vm) fn vm_memmove(dst: *any, src: *any, n: usize): *any;
fn ignore_ptr(p: *any) {}
@@ -73,31 +74,8 @@ fn move(dst: []u8, src: []u8): Status {
}
if dst_addr == src_addr { ret .Ok; }
// 非重叠且较大时走原生 memcpy(Vec 扩容复制是常见场景)。
var non_overlap = false;
if dst_addr < src_addr {
if src_addr - dst_addr >= count { non_overlap = true; }
} else {
if dst_addr - src_addr >= count { non_overlap = true; }
}
if non_overlap && count >= 16 {
ignore_ptr(vm_memcpy(dst.ptr as *any, src.ptr as *any, count));
ret .Ok;
}
if dst_addr < src_addr {
var i: usize = 0;
while i < count {
dst.ptr[i] = src.ptr[i];
i = i + 1;
}
} else {
var i = count;
while i > 0 {
i = i - 1;
dst.ptr[i] = src.ptr[i];
}
}
// 重叠安全,统一走原生 memmove。
ignore_ptr(vm_memmove(dst.ptr as *any, src.ptr as *any, count));
ret .Ok;
}
+8 -8
View File
@@ -3,7 +3,8 @@
// 开放寻址集合。键按字节复制到集合自己的存储中;集合只释放自身存储,
// 不释放键值内部引用的资源。哈希与相等回调的约定和 Map 一致。
type .{ .Status } = @import("error.spl");
type .{ .Map, .LookupResult } = @import("map.spl");
type .{ .Map, .LookupResult, .hash_kind_usize, .hash_kind_view, .hash_kind_constant } =
@import("map.spl");
type .{ .ByteView } = @import("byte_view.spl");
type .{ .hash_usize, .eq_usize, .hash_view, .eq_view } = @import("hash.spl");
@@ -11,15 +12,14 @@ type Set = @self;
map: Map,
fn new(key_size: usize, key_align: usize,
hash_fn: fn(*u8): usize, eq_fn: fn(*u8, *u8): bool): Set {
fn new(key_size: usize, key_align: usize, hash_kind: usize): Set {
ret Set {
.map = Map.new(key_size, key_align, 1, 1, hash_fn, eq_fn),
.map = Map.new(key_size, key_align, 1, 1, hash_kind),
};
}
fn valid(self: Set): bool {
ret Map.valid(self.map) && self.map.val_size == 1;
ret Map.valid(&self.map) && self.map.val_size == 1;
}
fn size(self: Set): usize {
@@ -104,7 +104,7 @@ fn constant_hash(key: *u8): usize {
}
fn test_insert_find_remove() {
var set = new(@sizeof(usize), @alignof(usize), hash_usize, eq_usize);
var set = new(@sizeof(usize), @alignof(usize), hash_kind_usize());
defer { drop(&set); }
@assert(valid(set));
@assert(size(set) == 0 && capacity(set) == 0);
@@ -169,7 +169,7 @@ fn test_insert_find_remove() {
}
fn test_collisions_and_take() {
var set = new(@sizeof(usize), @alignof(usize), constant_hash, eq_usize);
var set = new(@sizeof(usize), @alignof(usize), hash_kind_constant());
defer { drop(&set); }
var i: usize = 0;
@@ -213,7 +213,7 @@ fn test_collisions_and_take() {
}
fn test_byte_view_keys() {
var set = new(@sizeof(ByteView), @alignof(ByteView), hash_view, eq_view);
var set = new(@sizeof(ByteView), @alignof(ByteView), hash_kind_view());
defer { drop(&set); }
var alpha = ByteView.from_slice("alpha");
+2 -2
View File
@@ -6,7 +6,7 @@
type .{ .Error, .Status, .make } = @import("error.spl");
type .{ .ByteView, .FindResult } = @import("byte_view.spl");
type .{ .Vec } = @import("vec.spl");
type .{ .Map } = @import("map.spl");
type .{ .Map, .hash_kind_view } = @import("map.spl");
type .{ .hash_view, .eq_view } = @import("hash.spl");
type Position = struct {
@@ -134,7 +134,7 @@ fn set_new(): Sources {
ret Sources {
.items = Vec.blank(@sizeof(Source), 8),
.by_name = Map.blank(@sizeof(ByteView), @alignof(ByteView), @sizeof(usize),
@alignof(usize), hash_view, eq_view),
@alignof(usize), hash_kind_view()),
};
}
+44 -172
View File
@@ -7,6 +7,18 @@ type .{ .Error, .Kind, .Status } = @import("error.spl");
type .{ .SizeResult, .checked_add, .checked_mul, .grow_capacity, .move } = @import("memory.spl");
type .{ .alloc, .copy, .free } = @import("../sys/mem.spl");
#extern(vm) fn vm_vec_valid(v: *any): i32;
#extern(vm) fn vm_vec_push_raw(v: *any, elem: *any): i32;
#extern(vm) fn vm_vec_push(v: *any, elem: *any): i32;
#extern(vm) fn vm_vec_get(v: *any, index: usize, out: *any): i32;
#extern(vm) fn vm_vec_allocate(out: *any, capacity: usize, elem_size: usize, elem_align: usize): i32;
#extern(vm) fn vm_vec_reserve_raw(v: *any, need: usize): i32;
#extern(vm) fn vm_vec_append(v: *any, elems: *any, count: usize): i32;
#extern(vm) fn vm_vec_set(v: *any, index: usize, elem: *any): i32;
#extern(vm) fn vm_vec_pop(v: *any, out: *any): i32;
#extern(vm) fn vm_vec_clone(out: *any, src: *any): i32;
#extern(vm) fn vm_vec_drop(v: *any): void;
type Vec = @self;
raw: *u8,
@@ -51,95 +63,41 @@ fn new(elem_size: usize, elem_align: usize): VecResult {
// 按指针接收,避免每次调用复制整个 Vec;内联对齐检查,省一次函数调用。
fn valid(self: *Vec): bool {
if self.elem_size == 0 { ret false; }
var a = self.elem_align;
if a == 0 || (a & (a - 1)) != 0 { ret false; }
if self.len > self.cap { ret false; }
if self.cap == 0 {
ret self.raw == null && self.data == null && self.len == 0;
}
if self.raw == null || self.data == null { ret false; }
ret (self.data as usize & (a - 1)) == 0;
ret vm_vec_valid(self as *any) != 0;
}
fn status_error(kind: Kind): Status {
ret .Err(Error.make(kind));
}
// native 错误码 -> Error.Kind(0 ok / 1 InvalidArgument / 2 OutOfRange / 3 Overflow / 4 InvalidAlignment)
fn kind_from_code(code: i32): Kind {
if code == 2 { ret .OutOfRange; }
if code == 3 { ret .Overflow; }
if code == 4 { ret .InvalidAlignment; }
ret .InvalidArgument;
}
fn status_from_code(code: i32): Status {
if code == 0 { ret .Ok; }
ret status_error(kind_from_code(code));
}
// 计算元素区字节数。错误时不修改任何 Vec。
fn byte_count(count: usize, elem_size: usize): SizeResult {
ret checked_mul(count, elem_size);
}
fn allocate(capacity: usize, elem_size: usize, elem_align: usize): VecResult {
if elem_size == 0 { ret .Err(Error.make(.InvalidArgument)); }
if !valid_alignment(elem_align) {
ret .Err(Error.make(.InvalidAlignment));
}
if capacity == 0 { ret .Ok(blank(elem_size, elem_align)); }
var bytes: usize = 0;
match byte_count(capacity, elem_size) {
.Ok(value) => { bytes = value; },
.Err(error) => { ret .Err(error); },
}
var total: usize = 0;
match checked_add(bytes, elem_align - 1) {
.Ok(value) => { total = value; },
.Err(error) => { ret .Err(error); },
}
var raw = alloc(total) as *u8;
if raw == null {
ret .Err(Error.make(.Overflow));
}
var address = raw as usize;
var mask = elem_align - 1;
if address > (~(0 as usize)) - mask {
free(raw as *any);
ret .Err(Error.make(.Overflow));
}
var aligned = (address + mask) & ~mask;
ret .Ok(Vec {
.raw = raw,
.data = aligned as *u8,
.len = 0,
.cap = capacity,
.elem_size = elem_size,
.elem_align = elem_align,
});
var v: Vec = undefined;
var rc = vm_vec_allocate(&v as *any, capacity, elem_size, elem_align);
if rc == 0 { ret .Ok(v); }
ret .Err(Error.make(kind_from_code(rc)));
}
// 与 reserve 相同,但假定调用方已校验 self(内部热路径用,省去重复 valid)。
fn reserve_raw(self: *Vec, need: usize): Status {
if need <= self.cap { ret .Ok; }
var new_cap = grow_capacity(self.cap, 8, need);
var fresh: Vec = undefined;
match allocate(new_cap, self.elem_size, self.elem_align) {
.Ok(value) => { fresh = value; },
.Err(error) => { ret .Err(error); },
}
var used_bytes: usize = 0;
match byte_count(self.len, self.elem_size) {
.Ok(value) => { used_bytes = value; },
.Err(error) => {
drop(&fresh);
ret .Err(error);
},
}
if used_bytes != 0 {
copy(fresh.data as *any, self.data as *any, used_bytes);
}
fresh.len = self.len;
var old_raw = self.raw;
self.* = fresh;
free(old_raw as *any);
ret .Ok;
ret status_from_code(vm_vec_reserve_raw(self as *any, need));
}
// 保证至少可容纳 need 个元素(外部入口,含校验)。
@@ -154,81 +112,30 @@ fn with_capacity(elem_size: usize, elem_align: usize, capacity: usize): VecResul
}
fn get(self: *Vec, index: usize): PtrResult {
if !valid(self) { ret .Err(Error.make(.InvalidArgument)); }
if index >= self.len { ret .Err(Error.make(.OutOfRange)); }
ret .Ok(self.data + index * self.elem_size);
var out: *u8 = null;
var rc = vm_vec_get(self as *any, index, &out as *any);
if rc == 0 { ret .Ok(out); }
if rc == 2 { ret .Err(Error.make(.OutOfRange)); }
ret .Err(Error.make(.InvalidArgument));
}
fn set(self: *Vec, index: usize, elem: *u8): Status {
if !valid(self) || elem == null { ret status_error(.InvalidArgument); }
if index >= self.len { ret status_error(.OutOfRange); }
var dst = self.data + index * self.elem_size;
ret move(dst[0..self.elem_size], elem[0..self.elem_size]);
ret status_from_code(vm_vec_set(self as *any, index, elem as *any));
}
// 追加 count 个连续元素。elems 可以指向 self 当前已初始化的元素区。
fn append(self: *Vec, elems: *u8, count: usize): Status {
if !valid(self) { ret status_error(.InvalidArgument); }
if count == 0 { ret .Ok; }
if elems == null { ret status_error(.InvalidArgument); }
var copy_bytes: usize = 0;
match byte_count(count, self.elem_size) {
.Ok(value) => { copy_bytes = value; },
.Err(error) => { ret .Err(error); },
}
var new_len: usize = 0;
match checked_add(self.len, count) {
.Ok(value) => { new_len = value; },
.Err(error) => { ret .Err(error); },
}
var used_bytes: usize = 0;
match byte_count(self.len, self.elem_size) {
.Ok(value) => { used_bytes = value; },
.Err(error) => { ret .Err(error); },
}
var source_inside = false;
var source_offset: usize = 0;
if used_bytes != 0 {
var base = self.data as usize;
var source = elems as usize;
if source >= base && source - base < used_bytes {
source_offset = source - base;
if copy_bytes > used_bytes - source_offset {
ret status_error(.OutOfRange);
}
source_inside = true;
}
}
match reserve_raw(self, new_len) {
.Ok => {},
.Err(error) => { ret .Err(error); },
}
if source_inside { elems = self.data + source_offset; }
var dst = self.data + used_bytes;
match move(dst[0..copy_bytes], elems[0..copy_bytes]) {
.Ok => {},
.Err(error) => { ret .Err(error); },
}
self.len = new_len;
ret .Ok;
ret status_from_code(vm_vec_append(self as *any, elems as *any, count));
}
fn push(self: *Vec, elem: *u8): Status {
ret append(self, elem, 1);
ret status_from_code(vm_vec_push(self as *any, elem as *any));
}
// 热路径:假定 self 有效且已有容量时直接写入;容量不足才回退到 append。
fn push_raw(self: *Vec, elem: *u8): bool {
if self.len < self.cap {
copy(self.data + self.len * self.elem_size, elem, self.elem_size);
self.len = self.len + 1;
ret true;
}
if elem == null { ret false; }
if vm_vec_push_raw(self as *any, elem as *any) != 0 { ret true; }
match append(self, elem, 1) {
.Ok => { ret true; },
.Err(error) => { ret false; },
@@ -238,15 +145,7 @@ fn push_raw(self: *Vec, elem: *u8): bool {
// 将末元素复制到 out,然后缩短数组。out 可以与元素区重叠。
fn pop(self: *Vec, out: *u8): Status {
if !valid(self) || out == null { ret status_error(.InvalidArgument); }
if self.len == 0 { ret status_error(.OutOfRange); }
var source = self.data + (self.len - 1) * self.elem_size;
match move(out[0..self.elem_size], source[0..self.elem_size]) {
.Ok => {},
.Err(error) => { ret .Err(error); },
}
self.len = self.len - 1;
ret .Ok;
ret status_from_code(vm_vec_pop(self as *any, out as *any));
}
fn clear(self: *Vec) {
@@ -256,31 +155,7 @@ fn clear(self: *Vec) {
// 成功时先释放 out 原有存储再提交副本;失败保持 out 不变。
// out 与 src 指向同一个 Vec 也允许。
fn clone(out: *Vec, src: Vec): Status {
if !valid(out) || !valid(&src) { ret status_error(.InvalidArgument); }
if out.elem_size != src.elem_size || out.elem_align != src.elem_align {
ret status_error(.InvalidArgument);
}
var fresh = blank(src.elem_size, src.elem_align);
match reserve(&fresh, src.len) {
.Ok => {},
.Err(error) => { ret .Err(error); },
}
var bytes: usize = 0;
match byte_count(src.len, src.elem_size) {
.Ok(value) => { bytes = value; },
.Err(error) => {
drop(&fresh);
ret .Err(error);
},
}
if bytes != 0 {
copy(fresh.data as *any, src.data as *any, bytes);
}
fresh.len = src.len;
drop(out);
out.* = fresh;
ret .Ok;
ret status_from_code(vm_vec_clone(out as *any, &src as *any));
}
// 显式转移所有权,返回值必须由接收方最终 drop。
@@ -291,10 +166,7 @@ fn take(source: *Vec): Vec {
}
fn drop(self: *Vec) {
var elem_size = self.elem_size;
var elem_align = self.elem_align;
free(self.raw as *any);
self.* = blank(elem_size, elem_align);
vm_vec_drop(self as *any);
}
fn expect_ok(result: Status) {