1111
1212const Allocator = @import ("std" ).mem .Allocator ;
1313const assert = @import ("std" ).debug .assert ;
14+ const copyForwards = @import ("std" ).mem .copyForwards ;
1415
1516const RingBuffer = @This ();
1617
1718data : []u8 ,
1819read_index : usize ,
1920write_index : usize ,
2021
21- pub const Error = error {Full };
22+ pub const Error = error { Full , ReadLengthInvalid };
2223
2324/// Allocate a new `RingBuffer`; `deinit()` should be called to free the buffer.
2425pub fn init (allocator : Allocator , capacity : usize ) Allocator.Error ! RingBuffer {
@@ -63,15 +64,59 @@ pub fn writeAssumeCapacity(self: *RingBuffer, byte: u8) void {
6364
6465/// Write `bytes` into the ring buffer. Returns `error.Full` if the ring
6566/// buffer does not have enough space, without writing any data.
67+ /// Uses memcpy and so `bytes` must not overlap ring buffer data.
6668pub fn writeSlice (self : * RingBuffer , bytes : []const u8 ) Error ! void {
6769 if (self .len () + bytes .len > self .data .len ) return error .Full ;
6870 self .writeSliceAssumeCapacity (bytes );
6971}
7072
7173/// Write `bytes` into the ring buffer. If there is not enough space, older
7274/// bytes will be overwritten.
75+ /// Uses memcpy and so `bytes` must not overlap ring buffer data.
7376pub fn writeSliceAssumeCapacity (self : * RingBuffer , bytes : []const u8 ) void {
74- for (bytes ) | b | self .writeAssumeCapacity (b );
77+ const data_start = self .mask (self .write_index );
78+ const part1_data_end = @min (data_start + bytes .len , self .data .len );
79+ const part1_len = part1_data_end - data_start ;
80+ @memcpy (self .data [data_start .. part1_data_end ], bytes [0.. part1_len ]);
81+
82+ const remaining = bytes .len - part1_len ;
83+ const to_write = @min (remaining , remaining % self .data .len + self .data .len );
84+ const part2_bytes_start = bytes .len - to_write ;
85+ const part2_bytes_end = @min (part2_bytes_start + self .data .len , bytes .len );
86+ const part2_len = part2_bytes_end - part2_bytes_start ;
87+ @memcpy (self .data [0.. part2_len ], bytes [part2_bytes_start .. part2_bytes_end ]);
88+ if (part2_bytes_end != bytes .len ) {
89+ const part3_len = bytes .len - part2_bytes_end ;
90+ @memcpy (self .data [0.. part3_len ], bytes [part2_bytes_end .. bytes .len ]);
91+ }
92+ self .write_index = self .mask2 (self .write_index + bytes .len );
93+ }
94+
95+ /// Write `bytes` into the ring buffer. Returns `error.Full` if the ring
96+ /// buffer does not have enough space, without writing any data.
97+ /// Uses copyForwards and can write slices from this RingBuffer into itself.
98+ pub fn writeSliceForwards (self : * RingBuffer , bytes : []const u8 ) Error ! void {
99+ if (self .len () + bytes .len > self .data .len ) return error .Full ;
100+ self .writeSliceForwardsAssumeCapacity (bytes );
101+ }
102+
103+ /// Write `bytes` into the ring buffer. If there is not enough space, older
104+ /// bytes will be overwritten.
105+ /// Uses copyForwards and can write slices from this RingBuffer into itself.
106+ pub fn writeSliceForwardsAssumeCapacity (self : * RingBuffer , bytes : []const u8 ) void {
107+ const data_start = self .mask (self .write_index );
108+ const part1_data_end = @min (data_start + bytes .len , self .data .len );
109+ const part1_len = part1_data_end - data_start ;
110+ copyForwards (u8 , self .data [data_start .. ], bytes [0.. part1_len ]);
111+
112+ const remaining = bytes .len - part1_len ;
113+ const to_write = @min (remaining , remaining % self .data .len + self .data .len );
114+ const part2_bytes_start = bytes .len - to_write ;
115+ const part2_bytes_end = @min (part2_bytes_start + self .data .len , bytes .len );
116+ copyForwards (u8 , self .data [0.. ], bytes [part2_bytes_start .. part2_bytes_end ]);
117+ if (part2_bytes_end != bytes .len )
118+ copyForwards (u8 , self .data [0.. ], bytes [part2_bytes_end .. bytes .len ]);
119+ self .write_index = self .mask2 (self .write_index + bytes .len );
75120}
76121
77122/// Consume a byte from the ring buffer and return it. Returns `null` if the
@@ -90,6 +135,50 @@ pub fn readAssumeLength(self: *RingBuffer) u8 {
90135 return byte ;
91136}
92137
138+ /// Reads first `length` bytes written to the ring buffer into `dest`; Returns
139+ /// Error.ReadLengthInvalid if length greater than ring or dest length
140+ /// Uses memcpy and so `dest` must not overlap ring buffer data.
141+ pub fn readFirst (self : * RingBuffer , dest : []u8 , length : usize ) Error ! void {
142+ if (length > self .len () or length > dest .len ) return error .ReadLengthInvalid ;
143+ self .readFirstAssumeLength (dest , length );
144+ }
145+
146+ /// Reads first `length` bytes written to the ring buffer into `dest`;
147+ /// Asserts that length not greater than ring buffer or dest length
148+ /// Uses memcpy and so `dest` must not overlap ring buffer data.
149+ pub fn readFirstAssumeLength (self : * RingBuffer , dest : []u8 , length : usize ) void {
150+ assert (length <= self .len () and length <= dest .len );
151+ const data_start = self .mask (self .read_index );
152+ const part1_data_end = @min (self .data .len , data_start + length );
153+ const part1_len = part1_data_end - data_start ;
154+ const part2_len = length - part1_len ;
155+ @memcpy (dest [0.. part1_len ], self .data [data_start .. part1_data_end ]);
156+ @memcpy (dest [part1_len .. length ], self .data [0.. part2_len ]);
157+ self .read_index = self .mask2 (self .read_index + length );
158+ }
159+
160+ /// Reads last `length` bytes written to the ring buffer into `dest`; Returns
161+ /// Error.ReadLengthInvalid if length greater than ring or dest length
162+ /// Uses memcpy and so `dest` must not overlap ring buffer data.
163+ pub fn readLast (self : * RingBuffer , dest : []u8 , length : usize ) Error ! void {
164+ if (length > self .len () or length > dest .len ) return error .ReadLengthInvalid ;
165+ self .readLastAssumeLength (dest , length );
166+ }
167+
168+ /// Reads last `length` bytes written to the ring buffer into `dest`;
169+ /// Asserts that length not greater than ring buffer or dest length
170+ /// Uses memcpy and so `dest` must not overlap ring buffer data.
171+ pub fn readLastAssumeLength (self : * RingBuffer , dest : []u8 , length : usize ) void {
172+ assert (length <= self .len () and length <= dest .len );
173+ const data_start = self .mask (self .write_index + self .data .len - length );
174+ const part1_data_end = @min (self .data .len , data_start + length );
175+ const part1_len = part1_data_end - data_start ;
176+ const part2_len = length - part1_len ;
177+ @memcpy (dest [0.. part1_len ], self .data [data_start .. part1_data_end ]);
178+ @memcpy (dest [part1_len .. length ], self .data [0.. part2_len ]);
179+ self .write_index = if (self .write_index >= self .data_len ) self .write_index - length else data_start ;
180+ }
181+
93182/// Returns `true` if the ring buffer is empty and `false` otherwise.
94183pub fn isEmpty (self : RingBuffer ) bool {
95184 return self .write_index == self .read_index ;
0 commit comments