chore: move Channel, Ringbuffer, rotr, sext impls to lib
This commit is contained in:
		
							
								
								
									
										97
									
								
								src/lib.zig
									
									
									
									
									
								
							
							
						
						
									
										97
									
								
								src/lib.zig
									
									
									
									
									
								
							@@ -1,6 +1,8 @@
 | 
			
		||||
const std = @import("std");
 | 
			
		||||
 | 
			
		||||
pub fn RingBuffer(comptime T: type) type {
 | 
			
		||||
const Log2Int = std.math.Log2Int;
 | 
			
		||||
 | 
			
		||||
pub fn Channel(comptime T: type) type {
 | 
			
		||||
    return struct {
 | 
			
		||||
        const Self = @This();
 | 
			
		||||
        const Index = usize;
 | 
			
		||||
@@ -8,7 +10,7 @@ pub fn RingBuffer(comptime T: type) type {
 | 
			
		||||
        const Atomic = std.atomic.Atomic;
 | 
			
		||||
 | 
			
		||||
        const max_capacity = (@as(Index, 1) << @typeInfo(Index).Int.bits - 1) - 1; // half the range of index type
 | 
			
		||||
        const log = std.log.scoped(.RingBuffer);
 | 
			
		||||
        const log = std.log.scoped(.Channel);
 | 
			
		||||
 | 
			
		||||
        read: Atomic(Index),
 | 
			
		||||
        write: Atomic(Index),
 | 
			
		||||
@@ -67,3 +69,94 @@ pub fn RingBuffer(comptime T: type) type {
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn RingBuffer(comptime T: type) type {
 | 
			
		||||
    return struct {
 | 
			
		||||
        const Self = @This();
 | 
			
		||||
        const Index = usize;
 | 
			
		||||
        const max_capacity = (@as(Index, 1) << @typeInfo(Index).Int.bits - 1) - 1; // half the range of index type
 | 
			
		||||
 | 
			
		||||
        const log = std.log.scoped(.RingBuffer);
 | 
			
		||||
 | 
			
		||||
        read: Index,
 | 
			
		||||
        write: Index,
 | 
			
		||||
        buf: []T,
 | 
			
		||||
 | 
			
		||||
        const Error = error{buffer_full};
 | 
			
		||||
 | 
			
		||||
        pub fn init(buf: []T) Self {
 | 
			
		||||
            std.debug.assert(std.math.isPowerOfTwo(buf.len)); // capacity must be a power of two
 | 
			
		||||
            std.debug.assert(buf.len <= max_capacity);
 | 
			
		||||
 | 
			
		||||
            std.mem.set(T, buf, 0);
 | 
			
		||||
 | 
			
		||||
            return .{ .read = 0, .write = 0, .buf = buf };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        pub fn push(self: *Self, value: T) Error!void {
 | 
			
		||||
            if (self.isFull()) return error.buffer_full;
 | 
			
		||||
            defer self.write += 1;
 | 
			
		||||
 | 
			
		||||
            self.buf[self.mask(self.write)] = value;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        pub fn pop(self: *Self) ?T {
 | 
			
		||||
            if (self.isEmpty()) return null;
 | 
			
		||||
            defer self.read += 1;
 | 
			
		||||
 | 
			
		||||
            return self.buf[self.mask(self.read)];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// Returns the number of entries read
 | 
			
		||||
        pub fn copy(self: *const Self, cpy: []T) Index {
 | 
			
		||||
            const count = std.math.min(self.len(), cpy.len);
 | 
			
		||||
            var start: Index = self.read;
 | 
			
		||||
 | 
			
		||||
            for (cpy, 0..) |*v, i| {
 | 
			
		||||
                if (i >= count) break;
 | 
			
		||||
 | 
			
		||||
                v.* = self.buf[self.mask(start)];
 | 
			
		||||
                start += 1;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return count;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fn len(self: *const Self) Index {
 | 
			
		||||
            return self.write - self.read;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fn isFull(self: *const Self) bool {
 | 
			
		||||
            return self.len() == self.buf.len;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fn isEmpty(self: *const Self) bool {
 | 
			
		||||
            return self.read == self.write;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fn mask(self: *const Self, idx: Index) Index {
 | 
			
		||||
            return idx & (self.buf.len - 1);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Sign-Extend value of type `T` to type `U`
 | 
			
		||||
pub fn sext(comptime T: type, comptime U: type, value: T) T {
 | 
			
		||||
    // U must have less bits than T
 | 
			
		||||
    comptime std.debug.assert(@typeInfo(U).Int.bits <= @typeInfo(T).Int.bits);
 | 
			
		||||
 | 
			
		||||
    const iT = std.meta.Int(.signed, @typeInfo(T).Int.bits);
 | 
			
		||||
    const ExtU = if (@typeInfo(U).Int.signedness == .unsigned) T else iT;
 | 
			
		||||
    const shift_amt = @intCast(Log2Int(T), @typeInfo(T).Int.bits - @typeInfo(U).Int.bits);
 | 
			
		||||
 | 
			
		||||
    return @bitCast(T, @bitCast(iT, @as(ExtU, @truncate(U, value)) << shift_amt) >> shift_amt);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// See https://godbolt.org/z/W3en9Eche
 | 
			
		||||
pub inline fn rotr(comptime T: type, x: T, r: anytype) T {
 | 
			
		||||
    if (@typeInfo(T).Int.signedness == .signed)
 | 
			
		||||
        @compileError("cannot rotate signed integer");
 | 
			
		||||
 | 
			
		||||
    const ar = @intCast(Log2Int(T), @mod(r, @typeInfo(T).Int.bits));
 | 
			
		||||
    return x >> ar | x << (1 +% ~ar);
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user