From 28608e24e47a9eddeb1b191a31258392578939f8 Mon Sep 17 00:00:00 2001 From: Jeremia Dominguez Date: Thu, 3 Apr 2025 09:46:17 -0500 Subject: [PATCH 1/4] Update to Zig 0.14.0 --- .github/workflows/ci.yml | 2 +- .gitignore | 2 +- build.zig.zon | 3 ++- stable_array.zig | 35 ++++++++++++++++++----------------- 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dc84a6d..1a2aa87 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,5 +16,5 @@ jobs: - uses: actions/checkout@v2 - uses: goto-bus-stop/setup-zig@v2 with: - version: 0.12.0 + version: 0.14.0 - run: zig build test diff --git a/.gitignore b/.gitignore index 3cef7be..1dfcbd2 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -zig-cache/ +.zig-cache/ diff --git a/build.zig.zon b/build.zig.zon index 8e0d453..3e05ef3 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -1,6 +1,7 @@ .{ - .name = "zig-stable-array", + .name = .stable_array, .version = "0.1.0", + .fingerprint = 0xee760748bd6028de, .dependencies = .{}, .paths = .{ "build.zig", diff --git a/stable_array.zig b/stable_array.zig index 39d3e0d..fbb114e 100644 --- a/stable_array.zig +++ b/stable_array.zig @@ -3,12 +3,13 @@ const builtin = @import("builtin"); const os = std.os; const posix = std.posix; const mem = std.mem; +const heap = std.heap; const assert = std.debug.assert; const AllocError = std.mem.Allocator.Error; const darwin = struct { - extern "c" fn madvise(ptr: [*]align(mem.page_size) u8, length: usize, advice: c_int) c_int; + extern "c" fn madvise(ptr: [*]align(heap.page_size_min) u8, length: usize, advice: c_int) c_int; }; pub fn StableArray(comptime T: type) type { @@ -33,7 +34,7 @@ pub fn StableArrayAligned(comptime T: type, comptime alignment: u29) type { max_virtual_alloc_bytes: usize, pub fn init(max_virtual_alloc_bytes: usize) Self { - assert(@mod(max_virtual_alloc_bytes, mem.page_size) == 0); // max_virtual_alloc_bytes must be a multiple of mem.page_size + assert(@mod(max_virtual_alloc_bytes, heap.page_size_min) == 0); // max_virtual_alloc_bytes must be a multiple of heap.page_size_min return Self{ .items = &[_]T{}, .capacity = 0, @@ -208,8 +209,8 @@ pub fn StableArrayAligned(comptime T: type, comptime alignment: u29) type { } else { const base_addr: usize = @intFromPtr(self.items.ptr); const offset_addr: usize = base_addr + new_capacity_bytes; - const addr: [*]align(mem.page_size) u8 = @ptrFromInt(offset_addr); - if (comptime builtin.target.isDarwin()) { + const addr: [*]align(heap.page_size_min) u8 = @ptrFromInt(offset_addr); + if (comptime builtin.os.tag.isDarwin()) { const MADV_DONTNEED = 4; const err: c_int = darwin.madvise(addr, bytes_to_free, MADV_DONTNEED); switch (@as(posix.E, @enumFromInt(err))) { @@ -243,7 +244,7 @@ pub fn StableArrayAligned(comptime T: type, comptime alignment: u29) type { const w = os.windows; w.VirtualFree(@as(*anyopaque, @ptrCast(self.items.ptr)), 0, w.MEM_RELEASE); } else { - var slice: []align(mem.page_size) const u8 = undefined; + var slice: []align(heap.page_size_min) const u8 = undefined; slice.ptr = @alignCast(@as([*]u8, @ptrCast(self.items.ptr))); slice.len = self.max_virtual_alloc_bytes; posix.munmap(slice); @@ -340,7 +341,7 @@ pub fn StableArrayAligned(comptime T: type, comptime alignment: u29) type { } fn calcBytesUsedForCapacity(capacity: usize) usize { - return mem.alignForward(usize, k_sizeof * capacity, mem.page_size); + return mem.alignForward(usize, k_sizeof * capacity, heap.page_size_min); } }; } @@ -364,15 +365,15 @@ test "init" { test "append" { var a = StableArray(u8).init(TEST_VIRTUAL_ALLOC_SIZE); try a.appendSlice(&[_]u8{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }); - assert(a.calcTotalUsedBytes() == mem.page_size); + assert(a.calcTotalUsedBytes() == heap.page_size_min); for (a.items, 0..) |v, i| { assert(v == i); } a.deinit(); - var b = StableArrayAligned(u8, mem.page_size).init(TEST_VIRTUAL_ALLOC_SIZE); + var b = StableArrayAligned(u8, heap.page_size_min).init(TEST_VIRTUAL_ALLOC_SIZE); try b.appendSlice(&[_]u8{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }); - assert(b.calcTotalUsedBytes() == mem.page_size * 10); + assert(b.calcTotalUsedBytes() == heap.page_size_min * 10); for (b.items, 0..) |v, i| { assert(v == i); } @@ -384,17 +385,17 @@ test "shrinkAndFree" { try a.appendSlice(&[_]u8{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }); a.shrinkAndFree(5); - assert(a.calcTotalUsedBytes() == mem.page_size); + assert(a.calcTotalUsedBytes() == heap.page_size_min); assert(a.items.len == 5); for (a.items, 0..) |v, i| { assert(v == i); } a.deinit(); - var b = StableArrayAligned(u8, mem.page_size).init(TEST_VIRTUAL_ALLOC_SIZE); + var b = StableArrayAligned(u8, heap.page_size_min).init(TEST_VIRTUAL_ALLOC_SIZE); try b.appendSlice(&[_]u8{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }); b.shrinkAndFree(5); - assert(b.calcTotalUsedBytes() == mem.page_size * 5); + assert(b.calcTotalUsedBytes() == heap.page_size_min * 5); assert(b.items.len == 5); for (b.items, 0..) |v, i| { assert(v == i); @@ -404,7 +405,7 @@ test "shrinkAndFree" { var c = StableArrayAligned(u8, 2048).init(TEST_VIRTUAL_ALLOC_SIZE); try c.appendSlice(&[_]u8{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }); c.shrinkAndFree(5); - assert(c.calcTotalUsedBytes() == mem.page_size * 3); + assert(c.calcTotalUsedBytes() == heap.page_size_min * 3); assert(c.capacity == 6); assert(c.items.len == 5); for (c.items, 0..) |v, i| { @@ -426,10 +427,10 @@ test "resize" { } test "out of memory" { - var a = StableArrayAligned(u8, mem.page_size).init(TEST_VIRTUAL_ALLOC_SIZE); + var a = StableArrayAligned(u8, heap.page_size_min).init(TEST_VIRTUAL_ALLOC_SIZE); defer a.deinit(); - const max_capacity: usize = TEST_VIRTUAL_ALLOC_SIZE / mem.page_size; + const max_capacity: usize = TEST_VIRTUAL_ALLOC_SIZE / heap.page_size_min; try a.appendNTimes(0xFF, max_capacity); for (a.items) |v| { assert(v == 0xFF); @@ -464,8 +465,8 @@ test "growing retains values" { var a = StableArray(u8).init(TEST_VIRTUAL_ALLOC_SIZE); defer a.deinit(); - try a.resize(mem.page_size); + try a.resize(heap.page_size_min); a.items[0] = 0xFF; - try a.resize(mem.page_size * 2); + try a.resize(heap.page_size_min * 2); assert(a.items[0] == 0xFF); } From 08145b207eaaee7b24155c62cb7b36b848d527c2 Mon Sep 17 00:00:00 2001 From: Reuben Dunnington Date: Sun, 6 Apr 2025 19:41:15 -0700 Subject: [PATCH 2/4] use heap.pageSize() when actually calculating array size/capacity --- stable_array.zig | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/stable_array.zig b/stable_array.zig index fbb114e..b198e54 100644 --- a/stable_array.zig +++ b/stable_array.zig @@ -28,13 +28,19 @@ pub fn StableArrayAligned(comptime T: type, comptime alignment: u29) type { pub const VariableSlice = [*]align(alignment) T; pub const k_sizeof: usize = if (alignment > @sizeOf(T)) alignment else @sizeOf(T); + pub const page_size: usize = heap.pageSize(); items: Slice, capacity: usize, max_virtual_alloc_bytes: usize, + pub fn pageSize(self: *Self) usize { + _ = self; + return Self.page_size; + } + pub fn init(max_virtual_alloc_bytes: usize) Self { - assert(@mod(max_virtual_alloc_bytes, heap.page_size_min) == 0); // max_virtual_alloc_bytes must be a multiple of heap.page_size_min + assert(@mod(max_virtual_alloc_bytes, page_size) == 0); // max_virtual_alloc_bytes must be a multiple of page_size return Self{ .items = &[_]T{}, .capacity = 0, @@ -341,7 +347,7 @@ pub fn StableArrayAligned(comptime T: type, comptime alignment: u29) type { } fn calcBytesUsedForCapacity(capacity: usize) usize { - return mem.alignForward(usize, k_sizeof * capacity, heap.page_size_min); + return mem.alignForward(usize, k_sizeof * capacity, page_size); } }; } @@ -360,20 +366,22 @@ test "init" { assert(b.capacity == 0); assert(b.max_virtual_alloc_bytes == TEST_VIRTUAL_ALLOC_SIZE); b.deinit(); + + assert(a.pageSize() == b.pageSize()); } test "append" { var a = StableArray(u8).init(TEST_VIRTUAL_ALLOC_SIZE); try a.appendSlice(&[_]u8{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }); - assert(a.calcTotalUsedBytes() == heap.page_size_min); + assert(a.calcTotalUsedBytes() == a.pageSize()); for (a.items, 0..) |v, i| { assert(v == i); } a.deinit(); - var b = StableArrayAligned(u8, heap.page_size_min).init(TEST_VIRTUAL_ALLOC_SIZE); + var b = StableArrayAligned(u8, heap.pageSize()).init(TEST_VIRTUAL_ALLOC_SIZE); try b.appendSlice(&[_]u8{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }); - assert(b.calcTotalUsedBytes() == heap.page_size_min * 10); + assert(b.calcTotalUsedBytes() == a.pageSize() * 10); for (b.items, 0..) |v, i| { assert(v == i); } @@ -385,17 +393,17 @@ test "shrinkAndFree" { try a.appendSlice(&[_]u8{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }); a.shrinkAndFree(5); - assert(a.calcTotalUsedBytes() == heap.page_size_min); + assert(a.calcTotalUsedBytes() == a.pageSize()); assert(a.items.len == 5); for (a.items, 0..) |v, i| { assert(v == i); } a.deinit(); - var b = StableArrayAligned(u8, heap.page_size_min).init(TEST_VIRTUAL_ALLOC_SIZE); + var b = StableArrayAligned(u8, heap.pageSize()).init(TEST_VIRTUAL_ALLOC_SIZE); try b.appendSlice(&[_]u8{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }); b.shrinkAndFree(5); - assert(b.calcTotalUsedBytes() == heap.page_size_min * 5); + assert(b.calcTotalUsedBytes() == a.pageSize() * 5); assert(b.items.len == 5); for (b.items, 0..) |v, i| { assert(v == i); @@ -405,7 +413,7 @@ test "shrinkAndFree" { var c = StableArrayAligned(u8, 2048).init(TEST_VIRTUAL_ALLOC_SIZE); try c.appendSlice(&[_]u8{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }); c.shrinkAndFree(5); - assert(c.calcTotalUsedBytes() == heap.page_size_min * 3); + assert(c.calcTotalUsedBytes() == a.pageSize() * 3); assert(c.capacity == 6); assert(c.items.len == 5); for (c.items, 0..) |v, i| { @@ -427,10 +435,10 @@ test "resize" { } test "out of memory" { - var a = StableArrayAligned(u8, heap.page_size_min).init(TEST_VIRTUAL_ALLOC_SIZE); + var a = StableArrayAligned(u8, heap.pageSize()).init(TEST_VIRTUAL_ALLOC_SIZE); defer a.deinit(); - const max_capacity: usize = TEST_VIRTUAL_ALLOC_SIZE / heap.page_size_min; + const max_capacity: usize = TEST_VIRTUAL_ALLOC_SIZE / a.pageSize(); try a.appendNTimes(0xFF, max_capacity); for (a.items) |v| { assert(v == 0xFF); @@ -465,8 +473,8 @@ test "growing retains values" { var a = StableArray(u8).init(TEST_VIRTUAL_ALLOC_SIZE); defer a.deinit(); - try a.resize(heap.page_size_min); + try a.resize(a.pageSize()); a.items[0] = 0xFF; - try a.resize(heap.page_size_min * 2); + try a.resize(a.pageSize() * 2); assert(a.items[0] == 0xFF); } From dd988801a3f1a4ccd97ffe388e6cf5cb2e41b474 Mon Sep 17 00:00:00 2001 From: Reuben Dunnington Date: Sun, 6 Apr 2025 19:42:18 -0700 Subject: [PATCH 3/4] use mlugg's setup-zig instead of goto-bus-stop --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1a2aa87..52f8a02 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: runs-on: ${{matrix.os}} steps: - uses: actions/checkout@v2 - - uses: goto-bus-stop/setup-zig@v2 + - uses: mlugg/setup-zig@v1 with: version: 0.14.0 - run: zig build test From 53458d7108dbbff2d91ac4d1db1dd3a15f45bc41 Mon Sep 17 00:00:00 2001 From: Reuben Dunnington Date: Sun, 6 Apr 2025 20:38:19 -0700 Subject: [PATCH 4/4] avoid hardcoding shrinkAndFree test page sizes, alignment getter --- stable_array.zig | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/stable_array.zig b/stable_array.zig index b198e54..ee6f744 100644 --- a/stable_array.zig +++ b/stable_array.zig @@ -16,7 +16,7 @@ pub fn StableArray(comptime T: type) type { return StableArrayAligned(T, @alignOf(T)); } -pub fn StableArrayAligned(comptime T: type, comptime alignment: u29) type { +pub fn StableArrayAligned(comptime T: type, comptime _alignment: u29) type { if (@sizeOf(T) == 0) { @compileError("StableArray does not support types of size 0. Use ArrayList instead."); } @@ -29,16 +29,22 @@ pub fn StableArrayAligned(comptime T: type, comptime alignment: u29) type { pub const k_sizeof: usize = if (alignment > @sizeOf(T)) alignment else @sizeOf(T); pub const page_size: usize = heap.pageSize(); + pub const alignment = _alignment; items: Slice, capacity: usize, max_virtual_alloc_bytes: usize, - pub fn pageSize(self: *Self) usize { + pub fn getPageSize(self: *Self) usize { _ = self; return Self.page_size; } + pub fn getAlignment(self: *Self) usize { + _ = self; + return Self.alignment; + } + pub fn init(max_virtual_alloc_bytes: usize) Self { assert(@mod(max_virtual_alloc_bytes, page_size) == 0); // max_virtual_alloc_bytes must be a multiple of page_size return Self{ @@ -362,18 +368,19 @@ test "init" { a.deinit(); var b = StableArrayAligned(u8, 16).init(TEST_VIRTUAL_ALLOC_SIZE); + assert(b.getAlignment() == 16); assert(b.items.len == 0); assert(b.capacity == 0); assert(b.max_virtual_alloc_bytes == TEST_VIRTUAL_ALLOC_SIZE); b.deinit(); - assert(a.pageSize() == b.pageSize()); + assert(a.getPageSize() == b.getPageSize()); } test "append" { var a = StableArray(u8).init(TEST_VIRTUAL_ALLOC_SIZE); try a.appendSlice(&[_]u8{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }); - assert(a.calcTotalUsedBytes() == a.pageSize()); + assert(a.calcTotalUsedBytes() == a.getPageSize()); for (a.items, 0..) |v, i| { assert(v == i); } @@ -381,7 +388,7 @@ test "append" { var b = StableArrayAligned(u8, heap.pageSize()).init(TEST_VIRTUAL_ALLOC_SIZE); try b.appendSlice(&[_]u8{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }); - assert(b.calcTotalUsedBytes() == a.pageSize() * 10); + assert(b.calcTotalUsedBytes() == a.getPageSize() * 10); for (b.items, 0..) |v, i| { assert(v == i); } @@ -389,11 +396,12 @@ test "append" { } test "shrinkAndFree" { + const page_size = heap.pageSize(); + var a = StableArray(u8).init(TEST_VIRTUAL_ALLOC_SIZE); try a.appendSlice(&[_]u8{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }); a.shrinkAndFree(5); - - assert(a.calcTotalUsedBytes() == a.pageSize()); + assert(a.calcTotalUsedBytes() == page_size); // still using only a page assert(a.items.len == 5); for (a.items, 0..) |v, i| { assert(v == i); @@ -403,17 +411,18 @@ test "shrinkAndFree" { var b = StableArrayAligned(u8, heap.pageSize()).init(TEST_VIRTUAL_ALLOC_SIZE); try b.appendSlice(&[_]u8{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }); b.shrinkAndFree(5); - assert(b.calcTotalUsedBytes() == a.pageSize() * 5); + assert(b.calcTotalUsedBytes() == page_size * 5); // alignment of each item is 1 page assert(b.items.len == 5); for (b.items, 0..) |v, i| { assert(v == i); } b.deinit(); - var c = StableArrayAligned(u8, 2048).init(TEST_VIRTUAL_ALLOC_SIZE); + var c = StableArrayAligned(u8, page_size / 2).init(TEST_VIRTUAL_ALLOC_SIZE); + assert(c.getAlignment() == page_size / 2); try c.appendSlice(&[_]u8{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }); c.shrinkAndFree(5); - assert(c.calcTotalUsedBytes() == a.pageSize() * 3); + assert(c.calcTotalUsedBytes() == page_size * 3); assert(c.capacity == 6); assert(c.items.len == 5); for (c.items, 0..) |v, i| { @@ -438,7 +447,7 @@ test "out of memory" { var a = StableArrayAligned(u8, heap.pageSize()).init(TEST_VIRTUAL_ALLOC_SIZE); defer a.deinit(); - const max_capacity: usize = TEST_VIRTUAL_ALLOC_SIZE / a.pageSize(); + const max_capacity: usize = TEST_VIRTUAL_ALLOC_SIZE / a.getPageSize(); try a.appendNTimes(0xFF, max_capacity); for (a.items) |v| { assert(v == 0xFF); @@ -473,8 +482,8 @@ test "growing retains values" { var a = StableArray(u8).init(TEST_VIRTUAL_ALLOC_SIZE); defer a.deinit(); - try a.resize(a.pageSize()); + try a.resize(a.getPageSize()); a.items[0] = 0xFF; - try a.resize(a.pageSize() * 2); + try a.resize(a.getPageSize() * 2); assert(a.items[0] == 0xFF); }