stage2 大量优化代码使其自举编译时间大幅缩短
This commit is contained in:
1 parent
e02b0c633a
commit
846f441e3a
38 files changed
+2418
-835
No files matched your search
+44
-172
@@ -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) {
|
||||
|
||||
Reference in new issue
Block a user