| ... | ... | @@ -1,5 +1,4 @@ |
| 1 | | // FIFO of fixed size items |
| 2 | | // Usually used for e.g. byte buffers |
| 1 | //! Deprecated. Stop using this API |
| 3 | 2 | |
| 4 | 3 | const std = @import("std"); |
| 5 | 4 | const math = std.math; |
| ... | ... | @@ -8,70 +7,16 @@ const Allocator = mem.Allocator; |
| 8 | 7 | const assert = std.debug.assert; |
| 9 | 8 | const testing = std.testing; |
| 10 | 9 | |
| 11 | | pub const LinearFifoBufferType = union(enum) { |
| 12 | | /// The buffer is internal to the fifo; it is of the specified size. |
| 13 | | Static: usize, |
| 14 | | |
| 15 | | /// The buffer is passed as a slice to the initialiser. |
| 16 | | Slice, |
| 17 | | |
| 18 | | /// The buffer is managed dynamically using a `mem.Allocator`. |
| 19 | | Dynamic, |
| 20 | | }; |
| 21 | | |
| 22 | | pub fn LinearFifo( |
| 23 | | comptime T: type, |
| 24 | | comptime buffer_type: LinearFifoBufferType, |
| 25 | | ) type { |
| 26 | | const autoalign = false; |
| 27 | | |
| 28 | | const powers_of_two = switch (buffer_type) { |
| 29 | | .Static => std.math.isPowerOfTwo(buffer_type.Static), |
| 30 | | .Slice => false, // Any size slice could be passed in |
| 31 | | .Dynamic => true, // This could be configurable in future |
| 32 | | }; |
| 33 | | |
| 10 | pub fn LinearFifo(comptime T: type) type { |
| 34 | 11 | return struct { |
| 35 | | allocator: if (buffer_type == .Dynamic) Allocator else void, |
| 36 | | buf: if (buffer_type == .Static) [buffer_type.Static]T else []T, |
| 12 | allocator: Allocator, |
| 13 | buf: []T, |
| 37 | 14 | head: usize, |
| 38 | 15 | count: usize, |
| 39 | 16 | |
| 40 | 17 | const Self = @This(); |
| 41 | 18 | |
| 42 | | // Type of Self argument for slice operations. |
| 43 | | // If buffer is inline (Static) then we need to ensure we haven't |
| 44 | | // returned a slice into a copy on the stack |
| 45 | | const SliceSelfArg = if (buffer_type == .Static) *Self else Self; |
| 46 | | |
| 47 | | pub const init = switch (buffer_type) { |
| 48 | | .Static => initStatic, |
| 49 | | .Slice => initSlice, |
| 50 | | .Dynamic => initDynamic, |
| 51 | | }; |
| 52 | | |
| 53 | | fn initStatic() Self { |
| 54 | | comptime assert(buffer_type == .Static); |
| 55 | | return .{ |
| 56 | | .allocator = {}, |
| 57 | | .buf = undefined, |
| 58 | | .head = 0, |
| 59 | | .count = 0, |
| 60 | | }; |
| 61 | | } |
| 62 | | |
| 63 | | fn initSlice(buf: []T) Self { |
| 64 | | comptime assert(buffer_type == .Slice); |
| 65 | | return .{ |
| 66 | | .allocator = {}, |
| 67 | | .buf = buf, |
| 68 | | .head = 0, |
| 69 | | .count = 0, |
| 70 | | }; |
| 71 | | } |
| 72 | | |
| 73 | | fn initDynamic(allocator: Allocator) Self { |
| 74 | | comptime assert(buffer_type == .Dynamic); |
| 19 | pub fn init(allocator: Allocator) Self { |
| 75 | 20 | return .{ |
| 76 | 21 | .allocator = allocator, |
| 77 | 22 | .buf = &.{}, |
| ... | ... | @@ -80,8 +25,9 @@ pub fn LinearFifo( |
| 80 | 25 | }; |
| 81 | 26 | } |
| 82 | 27 | |
| 83 | | pub fn deinit(self: Self) void { |
| 84 | | if (buffer_type == .Dynamic) self.allocator.free(self.buf); |
| 28 | pub fn deinit(self: *Self) void { |
| 29 | self.allocator.free(self.buf); |
| 30 | self.* = undefined; |
| 85 | 31 | } |
| 86 | 32 | |
| 87 | 33 | pub fn realign(self: *Self) void { |
| ... | ... | @@ -109,24 +55,18 @@ pub fn LinearFifo( |
| 109 | 55 | /// Reduce allocated capacity to `size`. |
| 110 | 56 | pub fn shrink(self: *Self, size: usize) void { |
| 111 | 57 | assert(size >= self.count); |
| 112 | | if (buffer_type == .Dynamic) { |
| 113 | | self.realign(); |
| 114 | | self.buf = self.allocator.realloc(self.buf, size) catch |e| switch (e) { |
| 115 | | error.OutOfMemory => return, // no problem, capacity is still correct then. |
| 116 | | }; |
| 117 | | } |
| 58 | self.realign(); |
| 59 | self.buf = self.allocator.realloc(self.buf, size) catch |e| switch (e) { |
| 60 | error.OutOfMemory => return, // no problem, capacity is still correct then. |
| 61 | }; |
| 118 | 62 | } |
| 119 | 63 | |
| 120 | 64 | /// Ensure that the buffer can fit at least `size` items |
| 121 | 65 | pub fn ensureTotalCapacity(self: *Self, size: usize) !void { |
| 122 | 66 | if (self.buf.len >= size) return; |
| 123 | | if (buffer_type == .Dynamic) { |
| 124 | | self.realign(); |
| 125 | | const new_size = if (powers_of_two) math.ceilPowerOfTwo(usize, size) catch return error.OutOfMemory else size; |
| 126 | | self.buf = try self.allocator.realloc(self.buf, new_size); |
| 127 | | } else { |
| 128 | | return error.OutOfMemory; |
| 129 | | } |
| 67 | self.realign(); |
| 68 | const new_size = if (true) math.ceilPowerOfTwo(usize, size) catch return error.OutOfMemory else size; |
| 69 | self.buf = try self.allocator.realloc(self.buf, new_size); |
| 130 | 70 | } |
| 131 | 71 | |
| 132 | 72 | /// Makes sure at least `size` items are unused |
| ... | ... | @@ -142,7 +82,7 @@ pub fn LinearFifo( |
| 142 | 82 | } |
| 143 | 83 | |
| 144 | 84 | /// Returns a writable slice from the 'read' end of the fifo |
| 145 | | fn readableSliceMut(self: SliceSelfArg, offset: usize) []T { |
| 85 | fn readableSliceMut(self: Self, offset: usize) []T { |
| 146 | 86 | if (offset > self.count) return &[_]T{}; |
| 147 | 87 | |
| 148 | 88 | var start = self.head + offset; |
| ... | ... | @@ -156,7 +96,7 @@ pub fn LinearFifo( |
| 156 | 96 | } |
| 157 | 97 | |
| 158 | 98 | /// Returns a readable slice from `offset` |
| 159 | | pub fn readableSlice(self: SliceSelfArg, offset: usize) []const T { |
| 99 | pub fn readableSlice(self: Self, offset: usize) []const T { |
| 160 | 100 | return self.readableSliceMut(offset); |
| 161 | 101 | } |
| 162 | 102 | |
| ... | ... | @@ -186,12 +126,12 @@ pub fn LinearFifo( |
| 186 | 126 | @memset(unused2, undefined); |
| 187 | 127 | } |
| 188 | 128 | } |
| 189 | | if (autoalign and self.count == count) { |
| 129 | if (false and self.count == count) { |
| 190 | 130 | self.head = 0; |
| 191 | 131 | self.count = 0; |
| 192 | 132 | } else { |
| 193 | 133 | var head = self.head + count; |
| 194 | | if (powers_of_two) { |
| 134 | if (true) { |
| 195 | 135 | // Note it is safe to do a wrapping subtract as |
| 196 | 136 | // bitwise & with all 1s is a noop |
| 197 | 137 | head &= self.buf.len -% 1; |
| ... | ... | @@ -275,7 +215,7 @@ pub fn LinearFifo( |
| 275 | 215 | |
| 276 | 216 | /// Returns the first section of writable buffer. |
| 277 | 217 | /// Note that this may be of length 0 |
| 278 | | pub fn writableSlice(self: SliceSelfArg, offset: usize) []T { |
| 218 | pub fn writableSlice(self: Self, offset: usize) []T { |
| 279 | 219 | if (offset > self.buf.len) return &[_]T{}; |
| 280 | 220 | |
| 281 | 221 | const tail = self.head + offset + self.count; |
| ... | ... | @@ -330,7 +270,7 @@ pub fn LinearFifo( |
| 330 | 270 | |
| 331 | 271 | pub fn writeItemAssumeCapacity(self: *Self, item: T) void { |
| 332 | 272 | var tail = self.head + self.count; |
| 333 | | if (powers_of_two) { |
| 273 | if (true) { |
| 334 | 274 | tail &= self.buf.len - 1; |
| 335 | 275 | } else { |
| 336 | 276 | tail %= self.buf.len; |
| ... | ... | @@ -393,7 +333,7 @@ pub fn LinearFifo( |
| 393 | 333 | assert(self.writableLength() >= count); |
| 394 | 334 | |
| 395 | 335 | var head = self.head + (self.buf.len - count); |
| 396 | | if (powers_of_two) { |
| 336 | if (true) { |
| 397 | 337 | head &= self.buf.len - 1; |
| 398 | 338 | } else { |
| 399 | 339 | head %= self.buf.len; |
| ... | ... | @@ -424,7 +364,7 @@ pub fn LinearFifo( |
| 424 | 364 | assert(offset < self.count); |
| 425 | 365 | |
| 426 | 366 | var index = self.head + offset; |
| 427 | | if (powers_of_two) { |
| 367 | if (true) { |
| 428 | 368 | index &= self.buf.len - 1; |
| 429 | 369 | } else { |
| 430 | 370 | index %= self.buf.len; |
| ... | ... | @@ -548,40 +488,33 @@ test "LinearFifo(u8, .Dynamic)" { |
| 548 | 488 | |
| 549 | 489 | test LinearFifo { |
| 550 | 490 | inline for ([_]type{ u1, u8, u16, u64 }) |T| { |
| 551 | | inline for ([_]LinearFifoBufferType{ LinearFifoBufferType{ .Static = 32 }, .Slice, .Dynamic }) |bt| { |
| 552 | | const FifoType = LinearFifo(T, bt); |
| 553 | | var buf: if (bt == .Slice) [32]T else void = undefined; |
| 554 | | var fifo = switch (bt) { |
| 555 | | .Static => FifoType.init(), |
| 556 | | .Slice => FifoType.init(buf[0..]), |
| 557 | | .Dynamic => FifoType.init(testing.allocator), |
| 558 | | }; |
| 559 | | defer fifo.deinit(); |
| 560 | | |
| 561 | | try fifo.write(&[_]T{ 0, 1, 1, 0, 1 }); |
| 562 | | try testing.expectEqual(@as(usize, 5), fifo.readableLength()); |
| 563 | | |
| 564 | | { |
| 565 | | try testing.expectEqual(@as(T, 0), fifo.readItem().?); |
| 566 | | try testing.expectEqual(@as(T, 1), fifo.readItem().?); |
| 567 | | try testing.expectEqual(@as(T, 1), fifo.readItem().?); |
| 568 | | try testing.expectEqual(@as(T, 0), fifo.readItem().?); |
| 569 | | try testing.expectEqual(@as(T, 1), fifo.readItem().?); |
| 570 | | try testing.expectEqual(@as(usize, 0), fifo.readableLength()); |
| 571 | | } |
| 491 | const FifoType = LinearFifo(T); |
| 492 | var fifo: FifoType = .init(testing.allocator); |
| 493 | defer fifo.deinit(); |
| 572 | 494 | |
| 573 | | { |
| 574 | | try fifo.writeItem(1); |
| 575 | | try fifo.writeItem(1); |
| 576 | | try fifo.writeItem(1); |
| 577 | | try testing.expectEqual(@as(usize, 3), fifo.readableLength()); |
| 578 | | } |
| 495 | try fifo.write(&[_]T{ 0, 1, 1, 0, 1 }); |
| 496 | try testing.expectEqual(@as(usize, 5), fifo.readableLength()); |
| 579 | 497 | |
| 580 | | { |
| 581 | | var readBuf: [3]T = undefined; |
| 582 | | const n = fifo.read(&readBuf); |
| 583 | | try testing.expectEqual(@as(usize, 3), n); // NOTE: It should be the number of items. |
| 584 | | } |
| 498 | { |
| 499 | try testing.expectEqual(@as(T, 0), fifo.readItem().?); |
| 500 | try testing.expectEqual(@as(T, 1), fifo.readItem().?); |
| 501 | try testing.expectEqual(@as(T, 1), fifo.readItem().?); |
| 502 | try testing.expectEqual(@as(T, 0), fifo.readItem().?); |
| 503 | try testing.expectEqual(@as(T, 1), fifo.readItem().?); |
| 504 | try testing.expectEqual(@as(usize, 0), fifo.readableLength()); |
| 505 | } |
| 506 | |
| 507 | { |
| 508 | try fifo.writeItem(1); |
| 509 | try fifo.writeItem(1); |
| 510 | try fifo.writeItem(1); |
| 511 | try testing.expectEqual(@as(usize, 3), fifo.readableLength()); |
| 512 | } |
| 513 | |
| 514 | { |
| 515 | var readBuf: [3]T = undefined; |
| 516 | const n = fifo.read(&readBuf); |
| 517 | try testing.expectEqual(@as(usize, 3), n); // NOTE: It should be the number of items. |
| 585 | 518 | } |
| 586 | 519 | } |
| 587 | 520 | } |