use crate::cache_padded::CachePadded;
use core::ops::Range;
use core::sync::atomic::{AtomicUsize, Ordering};
#[derive(Debug, Default)]
pub struct Ring {
left: CachePadded<AtomicUsize>,
right: CachePadded<AtomicUsize>,
capacity: usize,
}
impl Ring {
pub fn new(capacity: usize) -> Self {
Ring {
left: CachePadded::new(AtomicUsize::new(0)),
right: CachePadded::new(AtomicUsize::new(0)),
capacity,
}
}
#[inline]
pub fn capacity(&self) -> usize {
self.capacity
}
#[inline]
pub fn display(&self, width: usize, left_char: char, right_char: char) -> Display {
Display {
ring: self,
width,
left_char,
right_char,
}
}
pub fn left_ranges(&self) -> (Range<usize>, Range<usize>) {
let left = self.left.load(Ordering::Acquire);
let right = self.right.load(Ordering::Acquire);
let left_offset = left % self.capacity;
let right_offset = right % self.capacity;
debug_assert!(left_offset <= self.capacity);
debug_assert!(right_offset <= self.capacity);
if left == right {
return (left_offset..left_offset, left_offset..left_offset);
}
if left_offset >= right_offset {
(left_offset..self.capacity, 0..right_offset)
} else {
(left_offset..right_offset, 0..0)
}
}
pub fn left_len(&self) -> usize {
let left = self.left.load(Ordering::Acquire);
let right = self.right.load(Ordering::Acquire);
right.wrapping_sub(left) % (self.capacity * 2)
}
pub fn advance_left(&self, len: usize) {
assert!(
len <= self.left_len(),
"len was larger than left region length"
);
unsafe { self.advance_left_unchecked(len) }
}
#[inline]
pub unsafe fn advance_left_unchecked(&self, len: usize) {
self.left
.fetch_update(Ordering::AcqRel, Ordering::Acquire, |left| {
Some(left.wrapping_add(len) % (self.capacity * 2))
})
.unwrap();
}
pub fn right_ranges(&self) -> (Range<usize>, Range<usize>) {
let left = self.left.load(Ordering::Acquire);
let right = self.right.load(Ordering::Acquire);
let left_size = right.wrapping_sub(left) % (self.capacity * 2);
let left_offset = left % self.capacity;
let right_offset = right % self.capacity;
debug_assert!(left_offset <= self.capacity);
debug_assert!(right_offset <= self.capacity);
if left_size == self.capacity {
return (right_offset..right_offset, right_offset..right_offset);
}
if left_offset <= right_offset {
(right_offset..self.capacity, 0..left_offset)
} else {
(right_offset..left_offset, 0..0)
}
}
pub fn right_len(&self) -> usize {
self.capacity - self.left_len()
}
pub fn advance_right(&self, len: usize) {
assert!(
len <= self.right_len(),
"len was larger than right region length"
);
unsafe { self.advance_right_unchecked(len) }
}
#[inline]
pub unsafe fn advance_right_unchecked(&self, len: usize) {
self.right
.fetch_update(Ordering::AcqRel, Ordering::Acquire, |right| {
Some(right.wrapping_add(len) % (self.capacity * 2))
})
.unwrap();
}
}
#[derive(Debug)]
pub struct Display<'a> {
ring: &'a Ring,
width: usize,
left_char: char,
right_char: char,
}
impl core::fmt::Display for Display<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let left = self.ring.left.load(Ordering::Acquire);
let right = self.ring.right.load(Ordering::Acquire);
let left_offset = left % self.ring.capacity;
let right_offset = right % self.ring.capacity;
let cap_f32 = self.ring.capacity as f32;
let width_f32 = self.width as f32;
let left_index = ((left_offset as f32 / cap_f32) * width_f32) as usize;
let right_index = ((right_offset as f32 / cap_f32) * width_f32) as usize;
if left == right {
for _ in 0..self.width {
write!(f, "{}", self.right_char)?;
}
return Ok(());
}
let (outer_char, inner_char, inner_start, inner_end) = if left_offset >= right_offset {
(self.left_char, self.right_char, right_index, left_index)
} else {
(self.right_char, self.left_char, left_index, right_index)
};
for _ in 0..inner_start {
write!(f, "{outer_char}")?;
}
for _ in inner_start..inner_end {
write!(f, "{inner_char}")?;
}
for _ in inner_end..self.width {
write!(f, "{outer_char}")?;
}
Ok(())
}
}