use num::{Integer, cast::AsPrimitive};
use std::{
clone::Clone,
ops::{Bound, Index, IndexMut, Range, RangeBounds},
};
pub struct RingBuffer<T> {
elements: Vec<T>,
current_index: isize,
}
pub struct RingBufferIter<'a, T> {
ring_buffer: &'a RingBuffer<T>,
range: Range<isize>,
}
pub struct RingBufferIterMut<'a, T> {
ring_buffer: &'a mut RingBuffer<T>,
range: Range<isize>,
}
impl<T: Clone> RingBuffer<T> {
pub fn new(size: usize, default_value: T) -> Self {
let mut elements = Vec::new();
elements.resize(size, default_value);
Self { current_index: 0, elements }
}
pub fn clone_from_iter<'a, I>(&'a mut self, iter: I)
where
I: IntoIterator<Item = &'a T>,
{
self.iter_mut().zip(iter).for_each(|(a, b)| *a = b.clone());
}
pub fn is_empty(&self) -> bool {
self.elements.is_empty()
}
pub fn iter(&self) -> RingBufferIter<'_, T> {
self.iter_range(..)
}
pub fn iter_mut(&mut self) -> RingBufferIterMut<'_, T> {
self.iter_range_mut(..)
}
pub fn iter_range<R: RangeBounds<isize>>(&self, range: R) -> RingBufferIter<'_, T> {
let range = self.get_bounds(range);
RingBufferIter { ring_buffer: self, range }
}
pub fn iter_range_mut<R: RangeBounds<isize>>(&mut self, range: R) -> RingBufferIterMut<'_, T> {
let range = self.get_bounds(range);
RingBufferIterMut { ring_buffer: self, range }
}
pub fn len(&self) -> usize {
self.elements.len()
}
pub fn resize(&mut self, new_size: usize, default_value: T) {
if new_size > 0 && !self.elements.is_empty() {
let index = self.get_array_index(0);
self.elements.rotate_left(index);
}
self.elements.resize(new_size, default_value);
self.current_index = 0;
}
pub fn rotate(&mut self, num: isize) {
self.current_index += num;
}
fn get_array_index(&self, index: isize) -> usize {
let num = self.elements.len() as isize;
(self.current_index + index).rem_euclid(num) as usize
}
fn get_bounds<R: RangeBounds<isize>>(&self, range: R) -> Range<isize> {
let start = match range.start_bound() {
Bound::Included(start) => *start,
Bound::Excluded(start) => *start + 1,
Bound::Unbounded => 0,
};
let end = match range.end_bound() {
Bound::Included(end) => *end + 1,
Bound::Excluded(end) => *end,
Bound::Unbounded => self.len() as isize,
};
start..end
}
}
impl<T: Clone, I: Integer + AsPrimitive<isize>> Index<I> for RingBuffer<T> {
type Output = T;
fn index(&self, index: I) -> &Self::Output {
let array_index = self.get_array_index(index.as_());
&self.elements[array_index]
}
}
impl<T: Clone, I: Integer + AsPrimitive<isize>> IndexMut<I> for RingBuffer<T> {
fn index_mut(&mut self, index: I) -> &mut Self::Output {
let array_index = self.get_array_index(index.as_());
&mut self.elements[array_index]
}
}
impl<'a, T: Clone> Iterator for RingBufferIter<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
if self.range.is_empty() {
return None;
}
let ret = &self.ring_buffer[self.range.start];
self.range.start += 1;
Some(ret)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.range.size_hint()
}
}
impl<'a, T: Clone> Iterator for RingBufferIterMut<'a, T> {
type Item = &'a mut T;
fn next(&mut self) -> Option<Self::Item> {
if self.range.is_empty() {
return None;
}
let elements = self.ring_buffer.elements.as_mut_ptr();
let array_index = self.ring_buffer.get_array_index(self.range.start);
let ret = unsafe { &mut *elements.add(array_index) };
self.range.start += 1;
Some(ret)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.range.size_hint()
}
}
impl<'a, T: Clone> IntoIterator for &'a RingBuffer<T> {
type Item = &'a T;
type IntoIter = RingBufferIter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, T: Clone> IntoIterator for &'a mut RingBuffer<T> {
type Item = &'a mut T;
type IntoIter = RingBufferIterMut<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty() {
let mut buffer = RingBuffer::<i32>::new(0, 5);
assert_eq!(buffer.len(), 0);
assert!(buffer.is_empty());
assert_eq!(buffer.iter().size_hint(), (0, Some(0)));
assert_eq!(buffer.iter_mut().size_hint(), (0, Some(0)));
}
#[test]
fn single_element() {
let mut buffer = RingBuffer::<i32>::new(1, 5);
assert_eq!(buffer.len(), 1);
assert!(!buffer.is_empty());
assert_eq!(buffer[0], 5);
buffer[0] = 3;
assert_eq!(buffer[0], 3);
assert!(buffer.iter().eq([3].iter()));
buffer.clone_from_iter(&[7]);
assert!(buffer.iter().eq([7].iter()));
let mut iter = buffer.iter();
assert_eq!(iter.size_hint(), (1, Some(1)));
iter.next();
assert_eq!(iter.size_hint(), (0, Some(0)));
let mut iter = buffer.iter_mut();
assert_eq!(iter.size_hint(), (1, Some(1)));
iter.next();
assert_eq!(iter.size_hint(), (0, Some(0)));
}
#[test]
fn three_elements() {
let mut buffer = RingBuffer::<i32>::new(3, 0);
assert_eq!(buffer.len(), 3);
assert_eq!(buffer[0], 0);
assert_eq!(buffer[2], 0);
buffer.clone_from_iter(&[1, 2, 3]);
assert!(buffer.iter().eq([1, 2, 3].iter()));
assert_eq!(buffer[0], 1);
assert_eq!(buffer[2], 3);
}
#[test]
fn rotate_forwards() {
let mut buffer = RingBuffer::<i32>::new(5, 0);
buffer.clone_from_iter(&[1, 2, 3, 4, 5]);
buffer.rotate(2);
assert_eq!(buffer[0], 3);
assert_eq!(buffer[4], 2);
assert!(buffer.iter().eq([3, 4, 5, 1, 2].iter()));
assert_eq!(buffer[-2], 1);
buffer.clone_from_iter(&[5, 6, 7, 8, 9]);
assert!(buffer.iter().eq([5, 6, 7, 8, 9].iter()));
}
#[test]
fn rotate_backwards() {
let mut buffer = RingBuffer::<i32>::new(3, 0);
assert!(buffer.iter().eq([0, 0, 0].iter()));
buffer[0] = 0;
buffer[1] = 2;
buffer[2] = 5;
buffer.rotate(-1);
assert!(buffer.iter().eq([5, 0, 2].iter()));
assert_eq!(buffer[-1], 2);
buffer.clone_from_iter(&[5, 6, 7]);
assert!(buffer.iter().eq([5, 6, 7].iter()));
}
#[test]
fn resize_bigger() {
let mut buffer = RingBuffer::<i32>::new(3, 0);
assert!(buffer.iter().eq([0, 0, 0].iter()));
buffer[0] = 0;
buffer[1] = 2;
buffer[2] = 5;
buffer.rotate(-1);
buffer.resize(5, 7);
assert!(buffer.iter().eq([5, 0, 2, 7, 7].iter()));
}
#[test]
fn resize_smaller() {
let mut buffer = RingBuffer::<i32>::new(3, 0);
assert!(buffer.iter().eq([0, 0, 0].iter()));
buffer[0] = 0;
buffer[1] = 2;
buffer[2] = 5;
buffer.rotate(1);
buffer.resize(2, 7);
assert!(buffer.iter().eq([2, 5].iter()));
}
#[test]
fn iter_range() {
let mut buffer = RingBuffer::<i32>::new(5, 0);
buffer.clone_from_iter(&[1, 2, 3, 4, 5]);
assert!(buffer.iter_range(1..3).eq([2, 3].iter()));
assert!(buffer.iter_range(-1..1).eq([5, 1].iter()));
}
}