use std::ops::IndexMut;
pub struct CircularBuffer<T> {
data: Vec<T>,
head: usize,
}
impl<T> CircularBuffer<T> {
pub fn new(capacity: usize) -> CircularBuffer<T> {
CircularBuffer {
data: Vec::with_capacity(capacity),
head: 0,
}
}
pub fn push(&mut self, elem: T) {
if self.data.len() < self.data.capacity() {
self.data.push(elem);
self.head = self.data.len() - 1;
return;
}
self.head = (self.head + 1) % self.capacity();
*self.data.index_mut(self.head) = elem;
}
pub fn capacity(&self) -> usize {
self.data.capacity()
}
fn internal_index(&self, i: usize) -> usize {
(self.head + self.capacity() - i) % self.capacity()
}
}
impl<T> std::ops::Index<usize> for CircularBuffer<T> {
type Output = T;
fn index(&self, i: usize) -> &T {
&self.data[self.internal_index(i)]
}
}
impl<T: Clone> CircularBuffer<T> {
pub fn clone_to_front(&mut self, i: usize) -> &mut T {
let i = self.internal_index(i);
if self.data.len() < self.data.capacity() {
self.push(self.data[i].clone());
return self.data.last_mut().unwrap();
}
let tail_i = (self.head + 1) % self.capacity();
match i.cmp(&tail_i) {
std::cmp::Ordering::Equal => {
}
std::cmp::Ordering::Less => {
let (front, back) = self.data.split_at_mut(tail_i);
back[0].clone_from(&front[i]);
}
std::cmp::Ordering::Greater => {
let (front, back) = self.data.split_at_mut(i);
front[tail_i].clone_from(&back[0]);
}
}
self.head = tail_i;
self.data.index_mut(self.head)
}
}