use crate::{
BOUNDED_RING_BUFFER_DEFAULT_SIZE,
ring_iter::{IntoIter, Iter, IterMut},
};
#[derive(Debug, Clone)]
pub struct BoundedRingBuffer<T> {
pub(crate) data: Vec<T>,
pub(crate) get_idx: usize,
pub(crate) put_idx: usize,
pub(crate) capacity: usize,
pub(crate) len: usize,
}
impl<T> BoundedRingBuffer<T>
where
T: Copy + Default,
{
#[must_use]
pub fn new() -> Self {
Self::with_capacity(BOUNDED_RING_BUFFER_DEFAULT_SIZE)
}
#[must_use]
pub fn with_capacity(cap: usize) -> Self {
assert_ne!(cap, 0, "Capacity cannot be zero!");
Self {
data: vec![T::default(); cap],
put_idx: 0,
get_idx: 0,
capacity: cap,
len: 0,
}
}
#[must_use]
pub fn len(&self) -> usize {
self.len
}
#[must_use]
pub fn capacity(&self) -> usize {
self.capacity
}
#[must_use]
pub fn get_idx(&self) -> usize {
self.get_idx
}
#[must_use]
pub fn put_idx(&self) -> usize {
self.put_idx
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.get_idx == self.put_idx && self.len == 0
}
#[must_use]
pub fn iter(&self) -> Iter<'_, T> {
if self.is_empty() {
return Iter([].iter().chain([].iter()));
}
let (first, second) = self.as_slice();
let second_iter = match second {
Some(slice) => slice.iter(),
None => [].iter(),
};
Iter(first.iter().chain(second_iter))
}
#[must_use]
pub fn iter_mut(&mut self) -> IterMut<'_, T> {
if self.is_empty() {
return IterMut([].iter_mut().chain([].iter_mut()));
}
let (first, second) = self.as_mut_slice();
let second_iter = match second {
Some(slice) => slice.iter_mut(),
None => [].iter_mut(),
};
IterMut(first.iter_mut().chain(second_iter))
}
#[must_use]
pub fn full(&self) -> bool {
self.get_idx == self.put_idx && self.len == self.capacity
}
#[must_use]
pub fn back(&self) -> Option<&T> {
if self.is_empty() {
None
} else {
Some(&self.data[(self.put_idx + self.capacity - 1) % self.capacity])
}
}
#[must_use]
pub fn back_mut(&mut self) -> Option<&mut T> {
if self.is_empty() {
None
} else {
Some(&mut self.data[(self.put_idx + self.capacity - 1) % self.capacity])
}
}
#[must_use]
pub fn front(&self) -> Option<&T> {
if self.is_empty() {
None
} else {
Some(&self.data[self.get_idx])
}
}
#[must_use]
pub fn front_mut(&mut self) -> Option<&mut T> {
if self.is_empty() {
None
} else {
let idx = self.get_idx;
Some(&mut self.data[idx])
}
}
pub fn enqueue(&mut self, data: T) {
if self.full() {
self.get_idx = (self.get_idx + 1) % self.capacity;
} else {
self.len += 1;
}
self.data[self.put_idx] = data;
self.put_idx = (self.put_idx + 1) % self.capacity;
}
#[must_use]
pub fn dequeue(&mut self) -> Option<T> {
if self.is_empty() {
return None;
}
let item = self.data[self.get_idx];
self.get_idx = (self.get_idx + 1) % self.capacity;
self.len -= 1;
Some(item)
}
pub fn advance(&mut self, size: usize) {
let size = size.min(self.capacity);
let new_put_idx = (self.put_idx + size) % self.capacity;
let remaining_space = self.capacity - self.len;
let offset = size.saturating_sub(remaining_space);
let new_get_idx = (self.get_idx + offset) % self.capacity;
self.get_idx = new_get_idx;
self.put_idx = new_put_idx;
self.len = (self.len + size).min(self.capacity);
}
pub fn enqueue_slice(&mut self, data: &[T]) {
match data.len().cmp(&self.capacity) {
std::cmp::Ordering::Less => {
let new_put_idx = (self.put_idx + data.len()) % self.capacity;
let remaining_space = self.capacity - self.len;
let offset = data.len().saturating_sub(remaining_space);
let new_get_idx = (self.get_idx + offset) % self.capacity;
if new_put_idx < self.put_idx {
let middle = self.capacity - self.put_idx;
self.data[self.put_idx..].copy_from_slice(&data[0..middle]);
self.data[..new_put_idx].copy_from_slice(&data[middle..]);
} else {
self.data[self.put_idx..self.put_idx + data.len()].copy_from_slice(data);
}
self.get_idx = new_get_idx;
self.put_idx = new_put_idx;
self.len = (self.len + data.len()).min(self.capacity);
}
std::cmp::Ordering::Equal => {
self.data.copy_from_slice(data);
self.put_idx = 0;
self.get_idx = 0;
self.len = data.len();
}
std::cmp::Ordering::Greater => {
let new_data_len = data.len();
let start = new_data_len - self.capacity;
let new_data = &data[start..new_data_len];
self.enqueue_slice(new_data);
}
}
}
#[must_use]
pub fn dequeue_slice(&mut self, out_buffer: &mut [T], dequeue_size: usize) -> usize {
if self.is_empty() {
return 0;
}
assert!(
out_buffer.len() >= dequeue_size,
"Dequeue size cannot be greater than out buffer"
);
match dequeue_size.cmp(&self.len) {
std::cmp::Ordering::Less => {
let new_get_idx = (self.get_idx + dequeue_size) % self.capacity;
if new_get_idx < self.get_idx {
let middle = self.capacity - self.get_idx;
out_buffer[0..middle].copy_from_slice(&self.data[self.get_idx..]);
out_buffer[middle..dequeue_size].copy_from_slice(&self.data[..new_get_idx]);
} else {
out_buffer[0..dequeue_size]
.copy_from_slice(&self.data[self.get_idx..new_get_idx]);
}
self.get_idx = new_get_idx;
self.len -= dequeue_size;
dequeue_size
}
std::cmp::Ordering::Equal => {
if self.get_idx >= self.put_idx {
let middle = self.capacity - self.get_idx;
out_buffer[0..middle].copy_from_slice(&self.data[self.get_idx..]);
out_buffer[middle..dequeue_size].copy_from_slice(&self.data[..self.put_idx]);
} else {
out_buffer[0..dequeue_size]
.copy_from_slice(&self.data[self.get_idx..self.put_idx]);
}
self.get_idx = self.put_idx;
self.len = 0;
dequeue_size
}
std::cmp::Ordering::Greater => {
self.dequeue_slice(&mut out_buffer[0..self.len], self.len)
}
}
}
#[must_use]
pub fn as_slice(&self) -> (&[T], Option<&[T]>) {
if self.get_idx < self.put_idx {
(&self.data[self.get_idx..self.put_idx], None)
} else {
(&self.data[self.get_idx..], Some(&self.data[..self.put_idx]))
}
}
#[must_use]
pub fn as_mut_slice(&mut self) -> (&mut [T], Option<&mut [T]>) {
if self.get_idx < self.put_idx {
(&mut self.data[self.get_idx..self.put_idx], None)
} else {
let (left, right) = self.data.split_at_mut(self.get_idx);
(right, Some(&mut left[..self.put_idx]))
}
}
}
impl<T> IntoIterator for BoundedRingBuffer<T>
where
T: Copy + Default,
{
type Item = T;
type IntoIter = IntoIter<T>;
fn into_iter(self) -> Self::IntoIter {
IntoIter(self)
}
}
impl<'a, T> IntoIterator for &'a BoundedRingBuffer<T>
where
T: Copy + Default,
{
type Item = &'a T;
type IntoIter = Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, T> IntoIterator for &'a mut BoundedRingBuffer<T>
where
T: Copy + Default,
{
type Item = &'a mut T;
type IntoIter = IterMut<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}