| author | |
| committer | |
| log | c7c35bf9e61035ead3098d109dc894b285373622 |
| tree | b70c5924b82efb6f44d8ec74e524fc5a86b3755a |
| parent | 1c518bd993b159d80a24925dc09ae7da5035ee05 |
6 files changed, 140 insertions(+), 128 deletions(-)
lib/std/RingBuffer.zig created+136| ... | ... | @@ -0,0 +1,136 @@ |
| 1 | //! This ring buffer stores read and write indices while being able to utilise | |
| 2 | //! the full backing slice by incrementing the indices modulo twice the slice's | |
| 3 | //! length and reducing indices modulo the slice's length on slice access. This | |
| 4 | //! means that whether the ring buffer if full or empty can be distinguished by | |
| 5 | //! looking at the difference between the read and write indices without adding | |
| 6 | //! an extra boolean flag or having to reserve a slot in the buffer. | |
| 7 | //! | |
| 8 | //! This ring buffer has not been implemented with thread safety in mind, and | |
| 9 | //! therefore should not be assumed to be suitable for use cases involving | |
| 10 | //! separate reader and writer threads. | |
| 11 | ||
| 12 | const Allocator = @import("std").mem.Allocator; | |
| 13 | const assert = @import("std").debug.assert; | |
| 14 | ||
| 15 | const RingBuffer = @This(); | |
| 16 | ||
| 17 | data: []u8, | |
| 18 | read_index: usize, | |
| 19 | write_index: usize, | |
| 20 | ||
| 21 | pub const Error = error{Full}; | |
| 22 | ||
| 23 | /// Allocate a new `RingBuffer`; `deinit()` should be called to free the buffer. | |
| 24 | pub fn init(allocator: Allocator, capacity: usize) Allocator.Error!RingBuffer { | |
| 25 | const bytes = try allocator.alloc(u8, capacity); | |
| 26 | return RingBuffer{ | |
| 27 | .data = bytes, | |
| 28 | .write_index = 0, | |
| 29 | .read_index = 0, | |
| 30 | }; | |
| 31 | } | |
| 32 | ||
| 33 | /// Free the data backing a `RingBuffer`; must be passed the same `Allocator` as | |
| 34 | /// `init()`. | |
| 35 | pub fn deinit(self: *RingBuffer, allocator: Allocator) void { | |
| 36 | allocator.free(self.data); | |
| 37 | self.* = undefined; | |
| 38 | } | |
| 39 | ||
| 40 | /// Returns `index` modulo the length of the backing slice. | |
| 41 | pub fn mask(self: RingBuffer, index: usize) usize { | |
| 42 | return index % self.data.len; | |
| 43 | } | |
| 44 | ||
| 45 | /// Returns `index` modulo twice the length of the backing slice. | |
| 46 | pub fn mask2(self: RingBuffer, index: usize) usize { | |
| 47 | return index % (2 * self.data.len); | |
| 48 | } | |
| 49 | ||
| 50 | /// Write `byte` into the ring buffer. Returns `error.Full` if the ring | |
| 51 | /// buffer is full. | |
| 52 | pub fn write(self: *RingBuffer, byte: u8) Error!void { | |
| 53 | if (self.isFull()) return error.Full; | |
| 54 | self.writeAssumeCapacity(byte); | |
| 55 | } | |
| 56 | ||
| 57 | /// Write `byte` into the ring buffer. If the ring buffer is full, the | |
| 58 | /// oldest byte is overwritten. | |
| 59 | pub fn writeAssumeCapacity(self: *RingBuffer, byte: u8) void { | |
| 60 | self.data[self.mask(self.write_index)] = byte; | |
| 61 | self.write_index = self.mask2(self.write_index + 1); | |
| 62 | } | |
| 63 | ||
| 64 | /// Write `bytes` into the ring buffer. Returns `error.Full` if the ring | |
| 65 | /// buffer does not have enough space, without writing any data. | |
| 66 | pub fn writeSlice(self: *RingBuffer, bytes: []const u8) Error!void { | |
| 67 | if (self.len() + bytes.len > self.data.len) return error.Full; | |
| 68 | self.writeSliceAssumeCapacity(bytes); | |
| 69 | } | |
| 70 | ||
| 71 | /// Write `bytes` into the ring buffer. If there is not enough space, older | |
| 72 | /// bytes will be overwritten. | |
| 73 | pub fn writeSliceAssumeCapacity(self: *RingBuffer, bytes: []const u8) void { | |
| 74 | for (bytes) |b| self.writeAssumeCapacity(b); | |
| 75 | } | |
| 76 | ||
| 77 | /// Consume a byte from the ring buffer and return it. Returns `null` if the | |
| 78 | /// ring buffer is empty. | |
| 79 | pub fn read(self: *RingBuffer) ?u8 { | |
| 80 | if (self.isEmpty()) return null; | |
| 81 | return self.readAssumeLength(); | |
| 82 | } | |
| 83 | ||
| 84 | /// Consume a byte from the ring buffer and return it; asserts that the buffer | |
| 85 | /// is not empty. | |
| 86 | pub fn readAssumeLength(self: *RingBuffer) u8 { | |
| 87 | assert(!self.isEmpty()); | |
| 88 | const byte = self.data[self.mask(self.read_index)]; | |
| 89 | self.read_index = self.mask2(self.read_index + 1); | |
| 90 | return byte; | |
| 91 | } | |
| 92 | ||
| 93 | /// Returns `true` if the ring buffer is empty and `false` otherwise. | |
| 94 | pub fn isEmpty(self: RingBuffer) bool { | |
| 95 | return self.write_index == self.read_index; | |
| 96 | } | |
| 97 | ||
| 98 | /// Returns `true` if the ring buffer is full and `false` otherwise. | |
| 99 | pub fn isFull(self: RingBuffer) bool { | |
| 100 | return self.mask2(self.write_index + self.data.len) == self.read_index; | |
| 101 | } | |
| 102 | ||
| 103 | /// Returns the length | |
| 104 | pub fn len(self: RingBuffer) usize { | |
| 105 | const wrap_offset = 2 * self.data.len * @boolToInt(self.write_index < self.read_index); | |
| 106 | const adjusted_write_index = self.write_index + wrap_offset; | |
| 107 | return adjusted_write_index - self.read_index; | |
| 108 | } | |
| 109 | ||
| 110 | /// A `Slice` represents a region of a ring buffer. The region is split into two | |
| 111 | /// sections as the ring buffer data will not be contiguous if the desired | |
| 112 | /// region wraps to the start of the backing slice. | |
| 113 | pub const Slice = struct { | |
| 114 | first: []u8, | |
| 115 | second: []u8, | |
| 116 | }; | |
| 117 | ||
| 118 | /// Returns a `Slice` for the region of the ring buffer starting at | |
| 119 | /// `self.mask(start_unmasked)` with the specified length. | |
| 120 | pub fn sliceAt(self: RingBuffer, start_unmasked: usize, length: usize) Slice { | |
| 121 | assert(length <= self.data.len); | |
| 122 | const slice1_start = self.mask(start_unmasked); | |
| 123 | const slice1_end = @min(self.data.len, slice1_start + length); | |
| 124 | const slice1 = self.data[slice1_start..slice1_end]; | |
| 125 | const slice2 = self.data[0 .. length - slice1.len]; | |
| 126 | return Slice{ | |
| 127 | .first = slice1, | |
| 128 | .second = slice2, | |
| 129 | }; | |
| 130 | } | |
| 131 | ||
| 132 | /// Returns a `Slice` for the last `length` bytes written to the ring buffer. | |
| 133 | /// Does not check that any bytes have been written into the region. | |
| 134 | pub fn sliceLast(self: RingBuffer, length: usize) Slice { | |
| 135 | return self.sliceAt(self.write_index + self.data.len - length, length); | |
| 136 | } |
lib/std/compress/zstandard.zig+1-1| ... | ... | @@ -1,11 +1,11 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | const Allocator = std.mem.Allocator; |
| 3 | const RingBuffer = std.RingBuffer; | |
| 3 | 4 | |
| 4 | 5 | const types = @import("zstandard/types.zig"); |
| 5 | 6 | pub const frame = types.frame; |
| 6 | 7 | pub const compressed_block = types.compressed_block; |
| 7 | 8 | |
| 8 | const RingBuffer = @import("zstandard/RingBuffer.zig"); | |
| 9 | 9 | pub const decompress = @import("zstandard/decompress.zig"); |
| 10 | 10 | |
| 11 | 11 | pub fn DecompressStream( |
lib/std/compress/zstandard/RingBuffer.zig deleted-122| ... | ... | @@ -1,122 +0,0 @@ |
| 1 | //! This ring buffer stores read and write indices while being able to utilise the full | |
| 2 | //! backing slice by incrementing the indices modulo twice the slice's length and reducing | |
| 3 | //! indices modulo the slice's length on slice access. This means that whether the ring buffer | |
| 4 | //! if full or empty can be distinguised by looking at the different between the read and write | |
| 5 | //! indices without adding an extra boolean flag or having to reserve a slot in the buffer. | |
| 6 | ||
| 7 | const Allocator = @import("std").mem.Allocator; | |
| 8 | const assert = @import("std").debug.assert; | |
| 9 | ||
| 10 | const RingBuffer = @This(); | |
| 11 | ||
| 12 | data: []u8, | |
| 13 | read_index: usize, | |
| 14 | write_index: usize, | |
| 15 | ||
| 16 | pub const Error = error{Full}; | |
| 17 | ||
| 18 | /// Allocate a new `RingBuffer` | |
| 19 | pub fn init(allocator: Allocator, capacity: usize) Allocator.Error!RingBuffer { | |
| 20 | const bytes = try allocator.alloc(u8, capacity); | |
| 21 | return RingBuffer{ | |
| 22 | .data = bytes, | |
| 23 | .write_index = 0, | |
| 24 | .read_index = 0, | |
| 25 | }; | |
| 26 | } | |
| 27 | ||
| 28 | /// Free a `RingBuffer` | |
| 29 | pub fn deinit(self: *RingBuffer, allocator: Allocator) void { | |
| 30 | allocator.free(self.data); | |
| 31 | self.* = undefined; | |
| 32 | } | |
| 33 | ||
| 34 | /// Returns `index` modulo the length of the backing slice. | |
| 35 | pub fn mask(self: RingBuffer, index: usize) usize { | |
| 36 | return index % self.data.len; | |
| 37 | } | |
| 38 | ||
| 39 | /// Returns `index` module twice the length of the backing slice. | |
| 40 | pub fn mask2(self: RingBuffer, index: usize) usize { | |
| 41 | return index % (2 * self.data.len); | |
| 42 | } | |
| 43 | ||
| 44 | /// Write `byte` into the ring buffer. Returns `error.Full` if the ring | |
| 45 | /// buffer is full. | |
| 46 | pub fn write(self: *RingBuffer, byte: u8) Error!void { | |
| 47 | if (self.isFull()) return error.Full; | |
| 48 | self.writeAssumeCapacity(byte); | |
| 49 | } | |
| 50 | ||
| 51 | /// Write `byte` into the ring buffer. If the ring buffer is full, the | |
| 52 | /// oldest byte is overwritten. | |
| 53 | pub fn writeAssumeCapacity(self: *RingBuffer, byte: u8) void { | |
| 54 | self.data[self.mask(self.write_index)] = byte; | |
| 55 | self.write_index = self.mask2(self.write_index + 1); | |
| 56 | } | |
| 57 | ||
| 58 | /// Write `bytes` into the ring bufffer. Returns `error.Full` if the ring | |
| 59 | /// buffer does not have enough space, without writing any data. | |
| 60 | pub fn writeSlice(self: *RingBuffer, bytes: []const u8) Error!void { | |
| 61 | if (self.len() + bytes.len > self.data.len) return error.Full; | |
| 62 | self.writeSliceAssumeCapacity(bytes); | |
| 63 | } | |
| 64 | ||
| 65 | /// Write `bytes` into the ring buffer. If there is not enough space, older | |
| 66 | /// bytes will be overwritten. | |
| 67 | pub fn writeSliceAssumeCapacity(self: *RingBuffer, bytes: []const u8) void { | |
| 68 | for (bytes) |b| self.writeAssumeCapacity(b); | |
| 69 | } | |
| 70 | ||
| 71 | /// Consume a byte from the ring buffer and return it. Returns `null` if the | |
| 72 | /// ring buffer is empty. | |
| 73 | pub fn read(self: *RingBuffer) ?u8 { | |
| 74 | if (self.isEmpty()) return null; | |
| 75 | const byte = self.data[self.mask(self.read_index)]; | |
| 76 | self.read_index = self.mask2(self.read_index + 1); | |
| 77 | return byte; | |
| 78 | } | |
| 79 | ||
| 80 | /// Returns `true` if the ring buffer is empty and `false` otherwise. | |
| 81 | pub fn isEmpty(self: RingBuffer) bool { | |
| 82 | return self.write_index == self.read_index; | |
| 83 | } | |
| 84 | ||
| 85 | /// Returns `true` if the ring buffer is full and `false` otherwise. | |
| 86 | pub fn isFull(self: RingBuffer) bool { | |
| 87 | return self.mask2(self.write_index + self.data.len) == self.read_index; | |
| 88 | } | |
| 89 | ||
| 90 | /// Returns the length | |
| 91 | pub fn len(self: RingBuffer) usize { | |
| 92 | const wrap_offset = 2 * self.data.len * @boolToInt(self.write_index < self.read_index); | |
| 93 | const adjusted_write_index = self.write_index + wrap_offset; | |
| 94 | return adjusted_write_index - self.read_index; | |
| 95 | } | |
| 96 | ||
| 97 | /// A `Slice` represents a region of a ring buffer. The region is split into two | |
| 98 | /// sections as the ring buffer data will not be contiguous if the desired region | |
| 99 | /// wraps to the start of the backing slice. | |
| 100 | pub const Slice = struct { | |
| 101 | first: []u8, | |
| 102 | second: []u8, | |
| 103 | }; | |
| 104 | ||
| 105 | /// Returns a `Slice` for the region of the ring buffer staring at `self.mask(start_unmasked)` | |
| 106 | /// with the specified length. | |
| 107 | pub fn sliceAt(self: RingBuffer, start_unmasked: usize, length: usize) Slice { | |
| 108 | assert(length <= self.data.len); | |
| 109 | const slice1_start = self.mask(start_unmasked); | |
| 110 | const slice1_end = @min(self.data.len, slice1_start + length); | |
| 111 | const slice1 = self.data[slice1_start..slice1_end]; | |
| 112 | const slice2 = self.data[0 .. length - slice1.len]; | |
| 113 | return Slice{ | |
| 114 | .first = slice1, | |
| 115 | .second = slice2, | |
| 116 | }; | |
| 117 | } | |
| 118 | ||
| 119 | /// Returns a `Slice` for the last `length` bytes written to the ring buffer. | |
| 120 | pub fn sliceLast(self: RingBuffer, length: usize) Slice { | |
| 121 | return self.sliceAt(self.write_index + self.data.len - length, length); | |
| 122 | } |
lib/std/compress/zstandard/decode/block.zig+1-3| ... | ... | @@ -1,5 +1,6 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | const assert = std.debug.assert; |
| 3 | const RingBuffer = std.RingBuffer; | |
| 3 | 4 | |
| 4 | 5 | const types = @import("../types.zig"); |
| 5 | 6 | const frame = types.frame; |
| ... | ... | @@ -8,9 +9,6 @@ const LiteralsSection = types.compressed_block.LiteralsSection; |
| 8 | 9 | const SequencesSection = types.compressed_block.SequencesSection; |
| 9 | 10 | |
| 10 | 11 | const huffman = @import("huffman.zig"); |
| 11 | ||
| 12 | const RingBuffer = @import("../RingBuffer.zig"); | |
| 13 | ||
| 14 | 12 | const readers = @import("../readers.zig"); |
| 15 | 13 | |
| 16 | 14 | const decodeFseTable = @import("fse.zig").decodeFseTable; |
lib/std/compress/zstandard/decompress.zig+1-2| ... | ... | @@ -1,6 +1,7 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | const assert = std.debug.assert; |
| 3 | 3 | const Allocator = std.mem.Allocator; |
| 4 | const RingBuffer = std.RingBuffer; | |
| 4 | 5 | |
| 5 | 6 | const types = @import("types.zig"); |
| 6 | 7 | const frame = types.frame; |
| ... | ... | @@ -12,8 +13,6 @@ const Table = types.compressed_block.Table; |
| 12 | 13 | |
| 13 | 14 | pub const block = @import("decode/block.zig"); |
| 14 | 15 | |
| 15 | pub const RingBuffer = @import("RingBuffer.zig"); | |
| 16 | ||
| 17 | 16 | const readers = @import("readers.zig"); |
| 18 | 17 | |
| 19 | 18 | const readInt = std.mem.readIntLittle; |
lib/std/std.zig+1| ... | ... | @@ -31,6 +31,7 @@ pub const PackedIntSliceEndian = @import("packed_int_array.zig").PackedIntSliceE |
| 31 | 31 | pub const PriorityQueue = @import("priority_queue.zig").PriorityQueue; |
| 32 | 32 | pub const PriorityDequeue = @import("priority_dequeue.zig").PriorityDequeue; |
| 33 | 33 | pub const Progress = @import("Progress.zig"); |
| 34 | pub const RingBuffer = @import("RingBuffer.zig"); | |
| 34 | 35 | pub const SegmentedList = @import("segmented_list.zig").SegmentedList; |
| 35 | 36 | pub const SemanticVersion = @import("SemanticVersion.zig"); |
| 36 | 37 | pub const SinglyLinkedList = @import("linked_list.zig").SinglyLinkedList; |