// Expect retcode = 0 // 类型擦除的动态数组。元素按值复制,数组只释放自身存储,不释放元素内部资源。 // Vec 拥有 raw 指向的分配;普通赋值会复制所有权,所有权转移必须使用 take。 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, data: *u8, len: usize, cap: usize, elem_size: usize, elem_align: usize, type VecResult = enum { Ok: Vec, Err: Error, } type PtrResult = enum { Ok: *u8, Err: Error, } fn blank(elem_size: usize, elem_align: usize): Vec { ret Vec { .raw = null, .data = null, .len = 0, .cap = 0, .elem_size = elem_size, .elem_align = elem_align, }; } fn valid_alignment(alignment: usize): bool { ret alignment != 0 && (alignment & (alignment - 1)) == 0; } fn new(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)); } ret .Ok(blank(elem_size, elem_align)); } // 按指针接收,避免每次调用复制整个 Vec;内联对齐检查,省一次函数调用。 fn valid(self: *Vec): bool { 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 { 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 { ret status_from_code(vm_vec_reserve_raw(self as *any, need)); } // 保证至少可容纳 need 个元素(外部入口,含校验)。 fn reserve(self: *Vec, need: usize): Status { if !valid(self) { ret status_error(.InvalidArgument); } ret reserve_raw(self, need); } // 预分配恰好 capacity 个元素(等价“with_capacity”)。 fn with_capacity(elem_size: usize, elem_align: usize, capacity: usize): VecResult { ret allocate(capacity, elem_size, elem_align); } fn get(self: *Vec, index: usize): PtrResult { 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 { 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 { ret status_from_code(vm_vec_append(self as *any, elems as *any, count)); } fn push(self: *Vec, elem: *u8): Status { ret status_from_code(vm_vec_push(self as *any, elem as *any)); } // 热路径:假定 self 有效且已有容量时直接写入;容量不足才回退到 append。 fn push_raw(self: *Vec, elem: *u8): bool { 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; }, } ret false; } // 将末元素复制到 out,然后缩短数组。out 可以与元素区重叠。 fn pop(self: *Vec, out: *u8): Status { ret status_from_code(vm_vec_pop(self as *any, out as *any)); } fn clear(self: *Vec) { self.len = 0; } // 成功时先释放 out 原有存储再提交副本;失败保持 out 不变。 // out 与 src 指向同一个 Vec 也允许。 fn clone(out: *Vec, src: Vec): Status { ret status_from_code(vm_vec_clone(out as *any, &src as *any)); } // 显式转移所有权,返回值必须由接收方最终 drop。 fn take(source: *Vec): Vec { var result = source.*; source.* = blank(result.elem_size, result.elem_align); ret result; } fn drop(self: *Vec) { vm_vec_drop(self as *any); } fn expect_ok(result: Status) { match result { .Ok => {}, .Err(error) => { @assert(false, "unexpected Vec error"); }, } } fn expect_error(result: Status, overflow: bool) { match result { .Ok => { @assert(false, "expected Vec error"); }, .Err(error) => { match error.kind { .Overflow => { @assert(overflow, "unexpected overflow"); }, .OutOfRange => { @assert(!overflow, "unexpected range error"); }, _ => { @assert(false, "unexpected Vec error kind"); }, } }, } } fn make_vec(elem_size: usize, elem_align: usize): Vec { match new(elem_size, elem_align) { .Ok(value) => { ret value; }, .Err(error) => { @assert(false, "Vec construction"); }, } ret blank(1, 1); } fn expect_i32(self: *Vec, index: usize, expected: i32) { match get(self, index) { .Ok(ptr) => { @assert((ptr as *i32).* == expected, "Vec element value"); }, .Err(error) => { @assert(false, "Vec element access"); }, } } fn test_construction_and_alignment() { match new(0, 1) { .Ok(value) => { @assert(false, "zero element size"); }, .Err(error) => { match error.kind { .InvalidArgument => {}, _ => { @assert(false); }, } }, } match new(1, 3) { .Ok(value) => { @assert(false, "invalid element alignment"); }, .Err(error) => { match error.kind { .InvalidAlignment => {}, _ => { @assert(false); }, } }, } var alignment: usize = 1; while alignment <= 64 { var v = make_vec(3, alignment); expect_ok(reserve(&v, 9)); @assert((v.data as usize & (alignment - 1)) == 0, "requested alignment"); @assert(v.cap >= 9 && v.len == 0); drop(&v); @assert(v.raw == null && v.data == null && v.cap == 0); alignment = alignment * 2; } } fn test_growth_and_access() { var v = make_vec(@sizeof(i32), @alignof(i32)); defer { drop(&v); } var i: i32 = 0; while i < 1000 { var value = i * 3 - 7; expect_ok(push(&v, &value as *u8)); i = i + 1; } @assert(v.len == 1000 && v.cap >= v.len); i = 0; while i < 1000 { expect_i32(&v, i as usize, i * 3 - 7); i = i + 1; } var replacement: i32 = 123456; expect_ok(set(&v, 500, &replacement as *u8)); expect_i32(&v, 500, replacement); expect_error(set(&v, 1000, &replacement as *u8), false); var popped: i32 = 0; expect_ok(pop(&v, &popped as *u8)); @assert(popped == 2990 && v.len == 999, "pop copies then removes"); } fn test_self_reference() { var v = make_vec(@sizeof(i32), @alignof(i32)); defer { drop(&v); } var i: i32 = 0; while i < 8 { expect_ok(push(&v, &i as *u8)); i = i + 1; } @assert(v.len == 8 && v.cap == 8, "prepare growth boundary"); // 源指向旧分配,append 必须在扩容后重新定位它。 expect_ok(append(&v, v.data, v.len)); @assert(v.len == 16); i = 0; while i < 16 { expect_i32(&v, i as usize, i % 8); i = i + 1; } var preserved_len = v.len; expect_error(append(&v, v.data + (v.len - 1) * v.elem_size, 2), false); @assert(v.len == preserved_len, "invalid self range preserves Vec"); expect_i32(&v, 15, 7); var last_ptr: *u8 = null; match get(&v, 15) { .Ok(ptr) => { last_ptr = ptr; }, .Err(error) => { @assert(false); }, } expect_ok(set(&v, 0, last_ptr)); expect_i32(&v, 0, 7); } fn test_clone_take_and_failures() { var source = make_vec(@sizeof(i32), @alignof(i32)); defer { drop(&source); } var one: i32 = 1; var two: i32 = 2; expect_ok(push(&source, &one as *u8)); expect_ok(push(&source, &two as *u8)); var copy = make_vec(@sizeof(i32), @alignof(i32)); defer { drop(©); } expect_ok(clone(©, source)); expect_i32(©, 0, 1); one = 99; expect_ok(set(&source, 0, &one as *u8)); expect_i32(©, 0, 1); // out 与 src 为同一对象仍产生内容相同的新分配。 var old_data = copy.data; expect_ok(clone(©, copy)); @assert(copy.data != old_data, "self clone replaces allocation"); expect_i32(©, 1, 2); var moved = take(©); defer { drop(&moved); } @assert(copy.raw == null && copy.data == null && copy.len == 0 && copy.cap == 0); expect_i32(&moved, 0, 1); var old_raw = moved.raw; var old_len = moved.len; var old_cap = moved.cap; expect_error(reserve(&moved, (~(0 as usize)) / moved.elem_size + 1), true); @assert(moved.raw == old_raw && moved.len == old_len && moved.cap == old_cap, "reserve failure preserves Vec"); clear(&moved); @assert(moved.len == 0 && moved.cap == old_cap, "clear retains capacity"); var output: i32 = 55; expect_error(pop(&moved, &output as *u8), false); @assert(output == 55, "failed pop preserves output"); } fn main() { test_construction_and_alignment(); test_growth_and_access(); test_self_reference(); test_clone_take_and_failures(); }