use std::sync::atomic::{AtomicUsize, Ordering};
pub struct IoRingBuffer {
buffer: Vec<f32>,
write_index: AtomicUsize,
read_index: AtomicUsize,
mask: usize,
}
impl IoRingBuffer {
pub fn new(capacity: usize) -> Self {
let cap = capacity.next_power_of_two();
Self {
buffer: vec![0.0f32; cap],
write_index: AtomicUsize::new(0),
read_index: AtomicUsize::new(0),
mask: cap - 1,
}
}
pub fn capacity(&self) -> usize {
self.buffer.len()
}
#[allow(dead_code)]
pub fn len(&self) -> usize {
let w = self.write_index.load(Ordering::Acquire);
let r = self.read_index.load(Ordering::Acquire);
w.wrapping_sub(r) & self.mask
}
#[allow(dead_code)]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn write(&mut self, data: &[f32]) -> usize {
let cap = self.buffer.len();
let w = self.write_index.load(Ordering::Relaxed);
let r = self.read_index.load(Ordering::Acquire);
let available = cap - (w.wrapping_sub(r) & self.mask) - 1;
let to_write = data.len().min(available);
for i in 0..to_write {
let idx = (w + i) & self.mask;
self.buffer[idx] = data[i];
}
self.write_index
.store(w.wrapping_add(to_write), Ordering::Release);
to_write
}
pub fn read(&mut self, data: &mut [f32]) -> usize {
let r = self.read_index.load(Ordering::Relaxed);
let w = self.write_index.load(Ordering::Acquire);
let available = w.wrapping_sub(r) & self.mask;
let to_read = data.len().min(available);
for i in 0..to_read {
let idx = (r + i) & self.mask;
data[i] = self.buffer[idx];
}
self.read_index
.store(r.wrapping_add(to_read), Ordering::Release);
to_read
}
#[allow(dead_code)]
pub fn clear(&mut self) {
self.read_index
.store(self.write_index.load(Ordering::Acquire), Ordering::Release);
}
#[allow(dead_code)]
pub fn clear_with_zeros(&mut self) {
self.buffer.fill(0.0);
self.write_index.store(0, Ordering::Release);
self.read_index.store(0, Ordering::Release);
}
}