feat: update to Zig v0.12.0-dev.2063+804cee3b
This commit is contained in:
parent
14ea006f4f
commit
78b944a98f
|
@ -15,10 +15,7 @@ pub fn build(b: *std.Build) void {
|
||||||
// set a preferred release mode, allowing the user to decide how to optimize.
|
// set a preferred release mode, allowing the user to decide how to optimize.
|
||||||
const optimize = b.standardOptimizeOption(.{});
|
const optimize = b.standardOptimizeOption(.{});
|
||||||
|
|
||||||
_ = b.addModule("zba-util", .{
|
_ = b.addModule("zba-util", .{ .root_source_file = .{ .path = "src/lib.zig" } });
|
||||||
.source_file = .{ .path = "src/lib.zig" },
|
|
||||||
.dependencies = &.{},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Creates a step for unit testing. This only builds the test executable
|
// Creates a step for unit testing. This only builds the test executable
|
||||||
// but does not run it.
|
// but does not run it.
|
||||||
|
|
180
src/lib.zig
180
src/lib.zig
|
@ -2,186 +2,6 @@ const std = @import("std");
|
||||||
const Log2Int = std.math.Log2Int;
|
const Log2Int = std.math.Log2Int;
|
||||||
const Allocator = std.mem.Allocator;
|
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 {
|
pub fn RingBuffer(comptime T: type) type {
|
||||||
return struct {
|
return struct {
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
Loading…
Reference in New Issue