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"); | 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 { |     return struct { | ||||||
|         const Self = @This(); |         const Self = @This(); | ||||||
|         const Index = usize; |         const Index = usize; | ||||||
| @@ -8,7 +10,7 @@ pub fn RingBuffer(comptime T: type) type { | |||||||
|         const Atomic = std.atomic.Atomic; |         const Atomic = std.atomic.Atomic; | ||||||
|  |  | ||||||
|         const max_capacity = (@as(Index, 1) << @typeInfo(Index).Int.bits - 1) - 1; // half the range of index type |         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), |         read: Atomic(Index), | ||||||
|         write: 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