| ... | @@ -1,5 +1,4 @@ | ... | @@ -1,5 +1,4 @@ |
| 1 | // FIFO of fixed size items | 1 | //! Deprecated. Stop using this API |
| 2 | // Usually used for e.g. byte buffers | | |
| 3 | | 2 | |
| 4 | const std = @import("std"); | 3 | const std = @import("std"); |
| 5 | const math = std.math; | 4 | const math = std.math; |
| ... | @@ -8,70 +7,16 @@ const Allocator = mem.Allocator; | ... | @@ -8,70 +7,16 @@ const Allocator = mem.Allocator; |
| 8 | const assert = std.debug.assert; | 7 | const assert = std.debug.assert; |
| 9 | const testing = std.testing; | 8 | const testing = std.testing; |
| 10 | | 9 | |
| 11 | pub const LinearFifoBufferType = union(enum) { | 10 | pub fn LinearFifo(comptime T: type) type { |
| 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 | | | |
| 34 | return struct { | 11 | return struct { |
| 35 | allocator: if (buffer_type == .Dynamic) Allocator else void, | 12 | allocator: Allocator, |
| 36 | buf: if (buffer_type == .Static) [buffer_type.Static]T else []T, | 13 | buf: []T, |
| 37 | head: usize, | 14 | head: usize, |
| 38 | count: usize, | 15 | count: usize, |
| 39 | | 16 | |
| 40 | const Self = @This(); | 17 | const Self = @This(); |
| 41 | | 18 | |
| 42 | // Type of Self argument for slice operations. | 19 | pub fn init(allocator: Allocator) Self { |
| 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); | | |
| 75 | return .{ | 20 | return .{ |
| 76 | .allocator = allocator, | 21 | .allocator = allocator, |
| 77 | .buf = &.{}, | 22 | .buf = &.{}, |
| ... | @@ -80,8 +25,9 @@ pub fn LinearFifo( | ... | @@ -80,8 +25,9 @@ pub fn LinearFifo( |
| 80 | }; | 25 | }; |
| 81 | } | 26 | } |
| 82 | | 27 | |
| 83 | pub fn deinit(self: Self) void { | 28 | pub fn deinit(self: *Self) void { |
| 84 | if (buffer_type == .Dynamic) self.allocator.free(self.buf); | 29 | self.allocator.free(self.buf); |
| | 30 | self.* = undefined; |
| 85 | } | 31 | } |
| 86 | | 32 | |
| 87 | pub fn realign(self: *Self) void { | 33 | pub fn realign(self: *Self) void { |
| ... | @@ -109,24 +55,18 @@ pub fn LinearFifo( | ... | @@ -109,24 +55,18 @@ pub fn LinearFifo( |
| 109 | /// Reduce allocated capacity to `size`. | 55 | /// Reduce allocated capacity to `size`. |
| 110 | pub fn shrink(self: *Self, size: usize) void { | 56 | pub fn shrink(self: *Self, size: usize) void { |
| 111 | assert(size >= self.count); | 57 | assert(size >= self.count); |
| 112 | if (buffer_type == .Dynamic) { | 58 | self.realign(); |
| 113 | self.realign(); | 59 | self.buf = self.allocator.realloc(self.buf, size) catch |e| switch (e) { |
| 114 | self.buf = self.allocator.realloc(self.buf, size) catch |e| switch (e) { | 60 | error.OutOfMemory => return, // no problem, capacity is still correct then. |
| 115 | error.OutOfMemory => return, // no problem, capacity is still correct then. | 61 | }; |
| 116 | }; | | |
| 117 | } | | |
| 118 | } | 62 | } |
| 119 | | 63 | |
| 120 | /// Ensure that the buffer can fit at least `size` items | 64 | /// Ensure that the buffer can fit at least `size` items |
| 121 | pub fn ensureTotalCapacity(self: *Self, size: usize) !void { | 65 | pub fn ensureTotalCapacity(self: *Self, size: usize) !void { |
| 122 | if (self.buf.len >= size) return; | 66 | if (self.buf.len >= size) return; |
| 123 | if (buffer_type == .Dynamic) { | 67 | self.realign(); |
| 124 | self.realign(); | 68 | const new_size = if (true) math.ceilPowerOfTwo(usize, size) catch return error.OutOfMemory else size; |
| 125 | const new_size = if (powers_of_two) math.ceilPowerOfTwo(usize, size) catch return error.OutOfMemory else size; | 69 | self.buf = try self.allocator.realloc(self.buf, new_size); |
| 126 | self.buf = try self.allocator.realloc(self.buf, new_size); | | |
| 127 | } else { | | |
| 128 | return error.OutOfMemory; | | |
| 129 | } | | |
| 130 | } | 70 | } |
| 131 | | 71 | |
| 132 | /// Makes sure at least `size` items are unused | 72 | /// Makes sure at least `size` items are unused |
| ... | @@ -142,7 +82,7 @@ pub fn LinearFifo( | ... | @@ -142,7 +82,7 @@ pub fn LinearFifo( |
| 142 | } | 82 | } |
| 143 | | 83 | |
| 144 | /// Returns a writable slice from the 'read' end of the fifo | 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 | if (offset > self.count) return &[_]T{}; | 86 | if (offset > self.count) return &[_]T{}; |
| 147 | | 87 | |
| 148 | var start = self.head + offset; | 88 | var start = self.head + offset; |
| ... | @@ -156,7 +96,7 @@ pub fn LinearFifo( | ... | @@ -156,7 +96,7 @@ pub fn LinearFifo( |
| 156 | } | 96 | } |
| 157 | | 97 | |
| 158 | /// Returns a readable slice from `offset` | 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 | return self.readableSliceMut(offset); | 100 | return self.readableSliceMut(offset); |
| 161 | } | 101 | } |
| 162 | | 102 | |
| ... | @@ -186,12 +126,12 @@ pub fn LinearFifo( | ... | @@ -186,12 +126,12 @@ pub fn LinearFifo( |
| 186 | @memset(unused2, undefined); | 126 | @memset(unused2, undefined); |
| 187 | } | 127 | } |
| 188 | } | 128 | } |
| 189 | if (autoalign and self.count == count) { | 129 | if (false and self.count == count) { |
| 190 | self.head = 0; | 130 | self.head = 0; |
| 191 | self.count = 0; | 131 | self.count = 0; |
| 192 | } else { | 132 | } else { |
| 193 | var head = self.head + count; | 133 | var head = self.head + count; |
| 194 | if (powers_of_two) { | 134 | if (true) { |
| 195 | // Note it is safe to do a wrapping subtract as | 135 | // Note it is safe to do a wrapping subtract as |
| 196 | // bitwise & with all 1s is a noop | 136 | // bitwise & with all 1s is a noop |
| 197 | head &= self.buf.len -% 1; | 137 | head &= self.buf.len -% 1; |
| ... | @@ -275,7 +215,7 @@ pub fn LinearFifo( | ... | @@ -275,7 +215,7 @@ pub fn LinearFifo( |
| 275 | | 215 | |
| 276 | /// Returns the first section of writable buffer. | 216 | /// Returns the first section of writable buffer. |
| 277 | /// Note that this may be of length 0 | 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 | if (offset > self.buf.len) return &[_]T{}; | 219 | if (offset > self.buf.len) return &[_]T{}; |
| 280 | | 220 | |
| 281 | const tail = self.head + offset + self.count; | 221 | const tail = self.head + offset + self.count; |
| ... | @@ -330,7 +270,7 @@ pub fn LinearFifo( | ... | @@ -330,7 +270,7 @@ pub fn LinearFifo( |
| 330 | | 270 | |
| 331 | pub fn writeItemAssumeCapacity(self: *Self, item: T) void { | 271 | pub fn writeItemAssumeCapacity(self: *Self, item: T) void { |
| 332 | var tail = self.head + self.count; | 272 | var tail = self.head + self.count; |
| 333 | if (powers_of_two) { | 273 | if (true) { |
| 334 | tail &= self.buf.len - 1; | 274 | tail &= self.buf.len - 1; |
| 335 | } else { | 275 | } else { |
| 336 | tail %= self.buf.len; | 276 | tail %= self.buf.len; |
| ... | @@ -393,7 +333,7 @@ pub fn LinearFifo( | ... | @@ -393,7 +333,7 @@ pub fn LinearFifo( |
| 393 | assert(self.writableLength() >= count); | 333 | assert(self.writableLength() >= count); |
| 394 | | 334 | |
| 395 | var head = self.head + (self.buf.len - count); | 335 | var head = self.head + (self.buf.len - count); |
| 396 | if (powers_of_two) { | 336 | if (true) { |
| 397 | head &= self.buf.len - 1; | 337 | head &= self.buf.len - 1; |
| 398 | } else { | 338 | } else { |
| 399 | head %= self.buf.len; | 339 | head %= self.buf.len; |
| ... | @@ -424,7 +364,7 @@ pub fn LinearFifo( | ... | @@ -424,7 +364,7 @@ pub fn LinearFifo( |
| 424 | assert(offset < self.count); | 364 | assert(offset < self.count); |
| 425 | | 365 | |
| 426 | var index = self.head + offset; | 366 | var index = self.head + offset; |
| 427 | if (powers_of_two) { | 367 | if (true) { |
| 428 | index &= self.buf.len - 1; | 368 | index &= self.buf.len - 1; |
| 429 | } else { | 369 | } else { |
| 430 | index %= self.buf.len; | 370 | index %= self.buf.len; |
| ... | @@ -548,40 +488,33 @@ test "LinearFifo(u8, .Dynamic)" { | ... | @@ -548,40 +488,33 @@ test "LinearFifo(u8, .Dynamic)" { |
| 548 | | 488 | |
| 549 | test LinearFifo { | 489 | test LinearFifo { |
| 550 | inline for ([_]type{ u1, u8, u16, u64 }) |T| { | 490 | inline for ([_]type{ u1, u8, u16, u64 }) |T| { |
| 551 | inline for ([_]LinearFifoBufferType{ LinearFifoBufferType{ .Static = 32 }, .Slice, .Dynamic }) |bt| { | 491 | const FifoType = LinearFifo(T); |
| 552 | const FifoType = LinearFifo(T, bt); | 492 | var fifo: FifoType = .init(testing.allocator); |
| 553 | var buf: if (bt == .Slice) [32]T else void = undefined; | 493 | defer fifo.deinit(); |
| 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 | } | | |
| 572 | | 494 | |
| 573 | { | 495 | try fifo.write(&[_]T{ 0, 1, 1, 0, 1 }); |
| 574 | try fifo.writeItem(1); | 496 | try testing.expectEqual(@as(usize, 5), fifo.readableLength()); |
| 575 | try fifo.writeItem(1); | | |
| 576 | try fifo.writeItem(1); | | |
| 577 | try testing.expectEqual(@as(usize, 3), fifo.readableLength()); | | |
| 578 | } | | |
| 579 | | 497 | |
| 580 | { | 498 | { |
| 581 | var readBuf: [3]T = undefined; | 499 | try testing.expectEqual(@as(T, 0), fifo.readItem().?); |
| 582 | const n = fifo.read(&readBuf); | 500 | try testing.expectEqual(@as(T, 1), fifo.readItem().?); |
| 583 | try testing.expectEqual(@as(usize, 3), n); // NOTE: It should be the number of items. | 501 | try testing.expectEqual(@as(T, 1), fifo.readItem().?); |
| 584 | } | 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 | } |