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.
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.
6
11
7
12
const Allocator = @import ("std" ).mem .Allocator ;
8
13
const assert = @import ("std" ).debug .assert ;
@@ -15,7 +20,7 @@ write_index: usize,
15
20
16
21
pub const Error = error {Full };
17
22
18
- /// Allocate a new `RingBuffer`
23
+ /// Allocate a new `RingBuffer`; `deinit()` should be called to free the buffer.
19
24
pub fn init (allocator : Allocator , capacity : usize ) Allocator.Error ! RingBuffer {
20
25
const bytes = try allocator .alloc (u8 , capacity );
21
26
return RingBuffer {
@@ -25,7 +30,8 @@ pub fn init(allocator: Allocator, capacity: usize) Allocator.Error!RingBuffer {
25
30
};
26
31
}
27
32
28
- /// Free a `RingBuffer`
33
+ /// Free the data backing a `RingBuffer`; must be passed the same `Allocator` as
34
+ /// `init()`.
29
35
pub fn deinit (self : * RingBuffer , allocator : Allocator ) void {
30
36
allocator .free (self .data );
31
37
self .* = undefined ;
@@ -36,7 +42,7 @@ pub fn mask(self: RingBuffer, index: usize) usize {
36
42
return index % self .data .len ;
37
43
}
38
44
39
- /// Returns `index` module twice the length of the backing slice.
45
+ /// Returns `index` modulo twice the length of the backing slice.
40
46
pub fn mask2 (self : RingBuffer , index : usize ) usize {
41
47
return index % (2 * self .data .len );
42
48
}
@@ -55,7 +61,7 @@ pub fn writeAssumeCapacity(self: *RingBuffer, byte: u8) void {
55
61
self .write_index = self .mask2 (self .write_index + 1 );
56
62
}
57
63
58
- /// Write `bytes` into the ring bufffer . Returns `error.Full` if the ring
64
+ /// Write `bytes` into the ring buffer . Returns `error.Full` if the ring
59
65
/// buffer does not have enough space, without writing any data.
60
66
pub fn writeSlice (self : * RingBuffer , bytes : []const u8 ) Error ! void {
61
67
if (self .len () + bytes .len > self .data .len ) return error .Full ;
@@ -72,6 +78,13 @@ pub fn writeSliceAssumeCapacity(self: *RingBuffer, bytes: []const u8) void {
72
78
/// ring buffer is empty.
73
79
pub fn read (self : * RingBuffer ) ? u8 {
74
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 ());
75
88
const byte = self .data [self .mask (self .read_index )];
76
89
self .read_index = self .mask2 (self .read_index + 1 );
77
90
return byte ;
@@ -95,15 +108,15 @@ pub fn len(self: RingBuffer) usize {
95
108
}
96
109
97
110
/// 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.
111
+ /// sections as the ring buffer data will not be contiguous if the desired
112
+ /// region wraps to the start of the backing slice.
100
113
pub const Slice = struct {
101
114
first : []u8 ,
102
115
second : []u8 ,
103
116
};
104
117
105
- /// Returns a `Slice` for the region of the ring buffer staring at `self.mask(start_unmasked)`
106
- /// with the specified length.
118
+ /// Returns a `Slice` for the region of the ring buffer starting at
119
+ /// `self.mask(start_unmasked)` with the specified length.
107
120
pub fn sliceAt (self : RingBuffer , start_unmasked : usize , length : usize ) Slice {
108
121
assert (length <= self .data .len );
109
122
const slice1_start = self .mask (start_unmasked );
@@ -117,6 +130,7 @@ pub fn sliceAt(self: RingBuffer, start_unmasked: usize, length: usize) Slice {
117
130
}
118
131
119
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.
120
134
pub fn sliceLast (self : RingBuffer , length : usize ) Slice {
121
135
return self .sliceAt (self .write_index + self .data .len - length , length );
122
136
}
0 commit comments