feat: update to Zig v0.12.0-dev.2063+804cee3b
This commit is contained in:
		
							
								
								
									
										180
									
								
								src/lib.zig
									
									
									
									
									
								
							
							
						
						
									
										180
									
								
								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();
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user