Skip to content

Commit 40133fe

Browse files
author
Felix Stegmaier
committed
Merge remote-tracking branch 'origin/master' into const-fn-feature
2 parents c7bac27 + f51e625 commit 40133fe

File tree

4 files changed

+88
-3
lines changed

4 files changed

+88
-3
lines changed

src/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@
8484
#![deny(warnings)]
8585
#![cfg_attr(feature = "const-fn", feature(const_fn))]
8686
#![feature(core_intrinsics)]
87-
#![feature(nonzero)]
8887
#![feature(untagged_unions)]
8988
#![no_std]
9089

src/ring_buffer/mod.rs

+30-2
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ where
212212
let tail = self.tail.load_relaxed().into();
213213

214214
if head > tail {
215-
head - tail
215+
self.capacity().into() + 1 - head + tail
216216
} else {
217217
tail - head
218218
}
@@ -343,7 +343,7 @@ macro_rules! impl_ {
343343
let tail = self.tail.load_relaxed();
344344

345345
if head > tail {
346-
head - tail
346+
self.capacity() + 1 - head + tail
347347
} else {
348348
tail - head
349349
}
@@ -573,4 +573,32 @@ mod tests {
573573

574574
assert_eq!(rb.len(), 2);
575575
}
576+
577+
#[test]
578+
fn ready_flag() {
579+
let mut rb: RingBuffer<i32, U2> = RingBuffer::new();
580+
let (mut p, mut c) = rb.split();
581+
assert_eq!(c.ready(), false);
582+
assert_eq!(p.ready(), true);
583+
584+
p.enqueue(0).unwrap();
585+
586+
assert_eq!(c.ready(), true);
587+
assert_eq!(p.ready(), true);
588+
589+
p.enqueue(1).unwrap();
590+
591+
assert_eq!(c.ready(), true);
592+
assert_eq!(p.ready(), false);
593+
594+
c.dequeue().unwrap();
595+
596+
assert_eq!(c.ready(), true);
597+
assert_eq!(p.ready(), true);
598+
599+
c.dequeue().unwrap();
600+
601+
assert_eq!(c.ready(), false);
602+
assert_eq!(p.ready(), true);
603+
}
576604
}

src/ring_buffer/spsc.rs

+23
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,14 @@ macro_rules! impl_ {
7979
N: Add<U1> + Unsigned,
8080
Sum<N, U1>: ArrayLength<T>,
8181
{
82+
/// Returns if there are any items to dequeue. When this returns true, at least the
83+
/// first subsequent dequeue will succeed.
84+
pub fn ready(&self) -> bool {
85+
let tail = unsafe { self.rb.as_ref().tail.load_acquire() };
86+
let head = unsafe { self.rb.as_ref().head.load_relaxed() };
87+
return head != tail;
88+
}
89+
8290
/// Returns the item in the front of the queue, or `None` if the queue is empty
8391
pub fn dequeue(&mut self) -> Option<T> {
8492
let tail = unsafe { self.rb.as_ref().tail.load_acquire() };
@@ -119,6 +127,21 @@ macro_rules! impl_ {
119127
N: Add<U1> + Unsigned,
120128
Sum<N, U1>: ArrayLength<T>,
121129
{
130+
/// Returns if there is any space to enqueue a new item. When this returns true, at
131+
/// least the first subsequent enqueue will succeed.
132+
pub fn ready(&self) -> bool {
133+
let n = unsafe { self.rb.as_ref().capacity() + 1 };
134+
let tail = unsafe { self.rb.as_ref().tail.load_relaxed() };
135+
// NOTE we could replace this `load_acquire` with a `load_relaxed` and this method
136+
// would be sound on most architectures but that change would result in UB according
137+
// to the C++ memory model, which is what Rust currently uses, so we err on the side
138+
// of caution and stick to `load_acquire`. Check issue google#sanitizers#882 for
139+
// more details.
140+
let head = unsafe { self.rb.as_ref().head.load_acquire() };
141+
let next_tail = (tail + 1) % n;
142+
return next_tail != head;
143+
}
144+
122145
/// Adds an `item` to the end of the queue
123146
///
124147
/// Returns back the `item` if the queue is full

tests/tsan.rs

+35
Original file line numberDiff line numberDiff line change
@@ -157,3 +157,38 @@ fn unchecked() {
157157

158158
assert_eq!(rb.len(), N::to_usize() / 2);
159159
}
160+
161+
#[test]
162+
fn len_properly_wraps() {
163+
type N = U3;
164+
let mut rb: RingBuffer<u8, N> = RingBuffer::new();
165+
166+
rb.enqueue(1).unwrap();
167+
assert_eq!(rb.len(), 1);
168+
rb.dequeue();
169+
assert_eq!(rb.len(), 0);
170+
rb.enqueue(2).unwrap();
171+
assert_eq!(rb.len(), 1);
172+
rb.enqueue(3).unwrap();
173+
assert_eq!(rb.len(), 2);
174+
rb.enqueue(4).unwrap();
175+
assert_eq!(rb.len(), 3);
176+
}
177+
178+
#[test]
179+
fn iterator_properly_wraps() {
180+
type N = U3;
181+
let mut rb: RingBuffer<u8, N> = RingBuffer::new();
182+
183+
rb.enqueue(1).unwrap();
184+
rb.dequeue();
185+
rb.enqueue(2).unwrap();
186+
rb.enqueue(3).unwrap();
187+
rb.enqueue(4).unwrap();
188+
let expected = [2, 3, 4];
189+
let mut actual = [0, 0, 0];
190+
for (idx, el) in rb.iter().enumerate() {
191+
actual[idx] = *el;
192+
}
193+
assert_eq!(expected, actual)
194+
}

0 commit comments

Comments
 (0)