From 78b944a98f18592512241f71ca2267ef951c82e1 Mon Sep 17 00:00:00 2001 From: paoda Date: Thu, 8 Feb 2024 17:50:00 -0600 Subject: [PATCH] feat: update to Zig v0.12.0-dev.2063+804cee3b --- build.zig | 5 +- src/lib.zig | 180 ---------------------------------------------------- 2 files changed, 1 insertion(+), 184 deletions(-) diff --git a/build.zig b/build.zig index b0195c9..8000fc3 100644 --- a/build.zig +++ b/build.zig @@ -15,10 +15,7 @@ pub fn build(b: *std.Build) void { // set a preferred release mode, allowing the user to decide how to optimize. const optimize = b.standardOptimizeOption(.{}); - _ = b.addModule("zba-util", .{ - .source_file = .{ .path = "src/lib.zig" }, - .dependencies = &.{}, - }); + _ = b.addModule("zba-util", .{ .root_source_file = .{ .path = "src/lib.zig" } }); // Creates a step for unit testing. This only builds the test executable // but does not run it. diff --git a/src/lib.zig b/src/lib.zig index b99a8f8..686543a 100644 --- a/src/lib.zig +++ b/src/lib.zig @@ -2,186 +2,6 @@ const std = @import("std"); const Log2Int = std.math.Log2Int; const Allocator = std.mem.Allocator; -// TODO: Rewrite -// pub const TwoWayChannel = struct { -// const Self = @This(); - -// emu: Channel(EmuMessage), -// gui: Channel(GuiMessage), - -// pub fn init(items: []u8) Self { -// comptime std.debug.assert(@sizeOf(EmuMessage) == @sizeOf(GuiMessage)); -// comptime std.debug.assert(@sizeOf(@typeInfo([]u8).Pointer.child) == @sizeOf(EmuMessage)); - -// std.debug.assert(items.len % 2 == 0); - -// const left = @ptrCast([*]EmuMessage, items)[0 .. items.len / 2]; -// const right = @ptrCast([*]GuiMessage, items)[items.len / 2 .. items.len]; - -// return .{ .emu = Channel(EmuMessage).init(left), .gui = Channel(GuiMessage).init(right) }; -// } -// }; - -pub fn Channel(comptime T: type, comptime N: usize) type { - return struct { - const Index = usize; - const capacity_limit = (@as(Index, 1) << @typeInfo(Index).Int.bits - 1) - 1; // half the range of index type - - tx: Sender, - rx: Receiver, - - pub const Sender = struct { - const Self = @This(); - - read: *Index, - write: *Index, - ptr: *[N]T, - - const Error = error{buffer_full}; - - pub fn send(self: Self, value: T) void { - const idx_r = @atomicLoad(Index, self.read, .Acquire); - const idx_w = @atomicLoad(Index, self.write, .Acquire); - - // Check to see if Queue is full - if (idx_w - idx_r == N) @panic("Channel: Buffer is full"); - - self.ptr[mask(idx_w)] = value; - - std.atomic.fence(.Release); - @atomicStore(Index, self.write, idx_w + 1, .Release); - } - - pub fn len(self: Self) Index { - const idx_r = @atomicLoad(Index, self.read, .Acquire); - const idx_w = @atomicLoad(Index, self.write, .Acquire); - - return idx_w - idx_r; - } - }; - - pub const Receiver = struct { - const Self = @This(); - - read: *Index, - write: *Index, - ptr: *[N]T, - - pub fn recv(self: Self) ?T { - const idx_r = @atomicLoad(Index, self.read, .Acquire); - const idx_w = @atomicLoad(Index, self.write, .Acquire); - - if (idx_r == idx_w) return null; - - std.atomic.fence(.Acquire); - const value = self.ptr[mask(idx_r)]; - - std.atomic.fence(.Release); - @atomicStore(Index, self.read, idx_r + 1, .Release); - - return value; - } - - pub fn peek(self: Self) ?T { - const idx_r = @atomicLoad(Index, self.read, .Acquire); - const idx_w = @atomicLoad(Index, self.write, .Acquire); - - if (idx_r == idx_w) return null; - - std.atomic.fence(.Acquire); - return self.ptr[mask(idx_r)]; - } - - pub fn len(self: Self) Index { - const idx_r = @atomicLoad(Index, self.read, .Acquire); - const idx_w = @atomicLoad(Index, self.write, .Acquire); - - return idx_w - idx_r; - } - }; - - fn mask(idx: Index) Index { - return idx & (@as(Index, @intCast(N)) - 1); - } - - pub fn init(allocator: Allocator) !Channel(T, N) { - const buf = try allocator.alloc(T, N); - const indicies = try allocator.alloc(Index, 2); - - return .{ - .tx = Sender{ - .ptr = buf[0..N], - .read = &indicies[0], - .write = &indicies[1], - }, - .rx = Receiver{ - .ptr = buf[0..N], - .read = &indicies[0], - .write = &indicies[1], - }, - }; - } - - pub fn deinit(self: *Channel(T, N), allocator: Allocator) void { - const indicies: [*]Index = @ptrCast(self.tx.read); - - allocator.free(indicies[0..2]); - allocator.free(self.tx.ptr); - - self.* = undefined; - } - - comptime { - std.debug.assert(std.math.isPowerOfTwo(N)); - std.debug.assert(N <= capacity_limit); - } - }; -} - -test "Channel init + deinit" { - var ch = try Channel(u8, 64).init(std.testing.allocator); - defer ch.deinit(std.testing.allocator); -} - -test "Channel basic queue" { - var ch = try Channel(u8, 64).init(std.testing.allocator); - defer ch.deinit(std.testing.allocator); - - ch.tx.send(128); - - try std.testing.expectEqual(@as(?u8, 128), ch.rx.recv()); -} - -test "Channel basic multithreaded" { - const builtin = @import("builtin"); - - if (builtin.single_threaded) - return error.SkipZigTest; - - const run_tx = struct { - fn run(tx: anytype) void { - tx.send(128); - } - }.run; - - const run_rx = struct { - fn run(rx: anytype) !void { - while (rx.recv()) |value| { - try std.testing.expectEqual(@as(?u8, 128), value); - } - } - }.run; - - var ch = try Channel(u8, 64).init(std.testing.allocator); - defer ch.deinit(std.testing.allocator); - - const tx_handle = try std.Thread.spawn(.{}, run_tx, .{&ch.tx}); - defer tx_handle.join(); - - const rx_handle = try std.Thread.spawn(.{}, run_rx, .{&ch.rx}); - defer rx_handle.join(); -} - pub fn RingBuffer(comptime T: type) type { return struct { const Self = @This();