authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-08-04 23:59:48-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-08-05 09:56:02-07:00
log8c11ada66caa011523e5c1019f9bb23c2db89231
tree8d9e96bad570e6094ae15c74979a6f072c12d642
parentb6f84c47c4144827ebf96617dbe40aeacd8cc34f

std: delete RingBuffer

Progress towards #19231

2 files changed, 0 insertions(+), 231 deletions(-)

lib/std/RingBuffer.zig deleted-230
......@@ -1,230 +0,0 @@
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 is 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
12const Allocator = @import("std").mem.Allocator;
13const assert = @import("std").debug.assert;
14const copyForwards = @import("std").mem.copyForwards;
15
16const RingBuffer = @This();
17
18data: []u8,
19read_index: usize,
20write_index: usize,
21
22pub const Error = error{ Full, ReadLengthInvalid };
23
24/// Allocate a new `RingBuffer`; `deinit()` should be called to free the buffer.
25pub fn init(allocator: Allocator, capacity: usize) Allocator.Error!RingBuffer {
26 const bytes = try allocator.alloc(u8, capacity);
27 return RingBuffer{
28 .data = bytes,
29 .write_index = 0,
30 .read_index = 0,
31 };
32}
33
34/// Free the data backing a `RingBuffer`; must be passed the same `Allocator` as
35/// `init()`.
36pub fn deinit(self: *RingBuffer, allocator: Allocator) void {
37 allocator.free(self.data);
38 self.* = undefined;
39}
40
41/// Returns `index` modulo the length of the backing slice.
42pub fn mask(self: RingBuffer, index: usize) usize {
43 return index % self.data.len;
44}
45
46/// Returns `index` modulo twice the length of the backing slice.
47pub fn mask2(self: RingBuffer, index: usize) usize {
48 return index % (2 * self.data.len);
49}
50
51/// Write `byte` into the ring buffer. Returns `error.Full` if the ring
52/// buffer is full.
53pub fn write(self: *RingBuffer, byte: u8) Error!void {
54 if (self.isFull()) return error.Full;
55 self.writeAssumeCapacity(byte);
56}
57
58/// Write `byte` into the ring buffer. If the ring buffer is full, the
59/// oldest byte is overwritten.
60pub fn writeAssumeCapacity(self: *RingBuffer, byte: u8) void {
61 self.data[self.mask(self.write_index)] = byte;
62 self.write_index = self.mask2(self.write_index + 1);
63}
64
65/// Write `bytes` into the ring buffer. Returns `error.Full` if the ring
66/// buffer does not have enough space, without writing any data.
67/// Uses memcpy and so `bytes` must not overlap ring buffer data.
68pub fn writeSlice(self: *RingBuffer, bytes: []const u8) Error!void {
69 if (self.len() + bytes.len > self.data.len) return error.Full;
70 self.writeSliceAssumeCapacity(bytes);
71}
72
73/// Write `bytes` into the ring buffer. If there is not enough space, older
74/// bytes will be overwritten.
75/// Uses memcpy and so `bytes` must not overlap ring buffer data.
76pub fn writeSliceAssumeCapacity(self: *RingBuffer, bytes: []const u8) void {
77 assert(bytes.len <= self.data.len);
78 const data_start = self.mask(self.write_index);
79 const part1_data_end = @min(data_start + bytes.len, self.data.len);
80 const part1_len = part1_data_end - data_start;
81 @memcpy(self.data[data_start..part1_data_end], bytes[0..part1_len]);
82
83 const remaining = bytes.len - part1_len;
84 const to_write = @min(remaining, remaining % self.data.len + self.data.len);
85 const part2_bytes_start = bytes.len - to_write;
86 const part2_bytes_end = @min(part2_bytes_start + self.data.len, bytes.len);
87 const part2_len = part2_bytes_end - part2_bytes_start;
88 @memcpy(self.data[0..part2_len], bytes[part2_bytes_start..part2_bytes_end]);
89 if (part2_bytes_end != bytes.len) {
90 const part3_len = bytes.len - part2_bytes_end;
91 @memcpy(self.data[0..part3_len], bytes[part2_bytes_end..bytes.len]);
92 }
93 self.write_index = self.mask2(self.write_index + bytes.len);
94}
95
96/// Write `bytes` into the ring buffer. Returns `error.Full` if the ring
97/// buffer does not have enough space, without writing any data.
98/// Uses copyForwards and can write slices from this RingBuffer into itself.
99pub fn writeSliceForwards(self: *RingBuffer, bytes: []const u8) Error!void {
100 if (self.len() + bytes.len > self.data.len) return error.Full;
101 self.writeSliceForwardsAssumeCapacity(bytes);
102}
103
104/// Write `bytes` into the ring buffer. If there is not enough space, older
105/// bytes will be overwritten.
106/// Uses copyForwards and can write slices from this RingBuffer into itself.
107pub fn writeSliceForwardsAssumeCapacity(self: *RingBuffer, bytes: []const u8) void {
108 assert(bytes.len <= self.data.len);
109 const data_start = self.mask(self.write_index);
110 const part1_data_end = @min(data_start + bytes.len, self.data.len);
111 const part1_len = part1_data_end - data_start;
112 copyForwards(u8, self.data[data_start..], bytes[0..part1_len]);
113
114 const remaining = bytes.len - part1_len;
115 const to_write = @min(remaining, remaining % self.data.len + self.data.len);
116 const part2_bytes_start = bytes.len - to_write;
117 const part2_bytes_end = @min(part2_bytes_start + self.data.len, bytes.len);
118 copyForwards(u8, self.data[0..], bytes[part2_bytes_start..part2_bytes_end]);
119 if (part2_bytes_end != bytes.len)
120 copyForwards(u8, self.data[0..], bytes[part2_bytes_end..bytes.len]);
121 self.write_index = self.mask2(self.write_index + bytes.len);
122}
123
124/// Consume a byte from the ring buffer and return it. Returns `null` if the
125/// ring buffer is empty.
126pub fn read(self: *RingBuffer) ?u8 {
127 if (self.isEmpty()) return null;
128 return self.readAssumeLength();
129}
130
131/// Consume a byte from the ring buffer and return it; asserts that the buffer
132/// is not empty.
133pub fn readAssumeLength(self: *RingBuffer) u8 {
134 assert(!self.isEmpty());
135 const byte = self.data[self.mask(self.read_index)];
136 self.read_index = self.mask2(self.read_index + 1);
137 return byte;
138}
139
140/// Reads first `length` bytes written to the ring buffer into `dest`; Returns
141/// Error.ReadLengthInvalid if length greater than ring or dest length
142/// Uses memcpy and so `dest` must not overlap ring buffer data.
143pub fn readFirst(self: *RingBuffer, dest: []u8, length: usize) Error!void {
144 if (length > self.len() or length > dest.len) return error.ReadLengthInvalid;
145 self.readFirstAssumeLength(dest, length);
146}
147
148/// Reads first `length` bytes written to the ring buffer into `dest`;
149/// Asserts that length not greater than ring buffer or dest length
150/// Uses memcpy and so `dest` must not overlap ring buffer data.
151pub fn readFirstAssumeLength(self: *RingBuffer, dest: []u8, length: usize) void {
152 assert(length <= self.len() and length <= dest.len);
153 const slice = self.sliceAt(self.read_index, length);
154 slice.copyTo(dest);
155 self.read_index = self.mask2(self.read_index + length);
156}
157
158/// Reads last `length` bytes written to the ring buffer into `dest`; Returns
159/// Error.ReadLengthInvalid if length greater than ring or dest length
160/// Uses memcpy and so `dest` must not overlap ring buffer data.
161/// Reduces write index by `length`.
162pub fn readLast(self: *RingBuffer, dest: []u8, length: usize) Error!void {
163 if (length > self.len() or length > dest.len) return error.ReadLengthInvalid;
164 self.readLastAssumeLength(dest, length);
165}
166
167/// Reads last `length` bytes written to the ring buffer into `dest`;
168/// Asserts that length not greater than ring buffer or dest length
169/// Uses memcpy and so `dest` must not overlap ring buffer data.
170/// Reduces write index by `length`.
171pub fn readLastAssumeLength(self: *RingBuffer, dest: []u8, length: usize) void {
172 assert(length <= self.len() and length <= dest.len);
173 const slice = self.sliceLast(length);
174 slice.copyTo(dest);
175 self.write_index = if (self.write_index >= self.data.len)
176 self.write_index - length
177 else
178 self.mask(self.write_index + self.data.len - length);
179}
180
181/// Returns `true` if the ring buffer is empty and `false` otherwise.
182pub fn isEmpty(self: RingBuffer) bool {
183 return self.write_index == self.read_index;
184}
185
186/// Returns `true` if the ring buffer is full and `false` otherwise.
187pub fn isFull(self: RingBuffer) bool {
188 return self.mask2(self.write_index + self.data.len) == self.read_index;
189}
190
191/// Returns the length of data available for reading
192pub fn len(self: RingBuffer) usize {
193 const wrap_offset = 2 * self.data.len * @intFromBool(self.write_index < self.read_index);
194 const adjusted_write_index = self.write_index + wrap_offset;
195 return adjusted_write_index - self.read_index;
196}
197
198/// A `Slice` represents a region of a ring buffer. The region is split into two
199/// sections as the ring buffer data will not be contiguous if the desired
200/// region wraps to the start of the backing slice.
201pub const Slice = struct {
202 first: []u8,
203 second: []u8,
204
205 /// Copy data from `self` into `dest`
206 pub fn copyTo(self: Slice, dest: []u8) void {
207 @memcpy(dest[0..self.first.len], self.first);
208 @memcpy(dest[self.first.len..][0..self.second.len], self.second);
209 }
210};
211
212/// Returns a `Slice` for the region of the ring buffer starting at
213/// `self.mask(start_unmasked)` with the specified length.
214pub fn sliceAt(self: RingBuffer, start_unmasked: usize, length: usize) Slice {
215 assert(length <= self.data.len);
216 const slice1_start = self.mask(start_unmasked);
217 const slice1_end = @min(self.data.len, slice1_start + length);
218 const slice1 = self.data[slice1_start..slice1_end];
219 const slice2 = self.data[0 .. length - slice1.len];
220 return Slice{
221 .first = slice1,
222 .second = slice2,
223 };
224}
225
226/// Returns a `Slice` for the last `length` bytes written to the ring buffer.
227/// Does not check that any bytes have been written into the region.
228pub fn sliceLast(self: RingBuffer, length: usize) Slice {
229 return self.sliceAt(self.write_index + self.data.len - length, length);
230}
lib/std/std.zig-1
......@@ -29,7 +29,6 @@ pub const PriorityQueue = @import("priority_queue.zig").PriorityQueue;
2929pub const PriorityDequeue = @import("priority_dequeue.zig").PriorityDequeue;
3030pub const Progress = @import("Progress.zig");
3131pub const Random = @import("Random.zig");
32pub const RingBuffer = @import("RingBuffer.zig");
3332pub const SegmentedList = @import("segmented_list.zig").SegmentedList;
3433pub const SemanticVersion = @import("SemanticVersion.zig");
3534pub const SinglyLinkedList = @import("SinglyLinkedList.zig");