use num_traits::PrimInt;
pub struct RingBuffer<T: PrimInt> {
buf: Vec<T>,
pos: usize,
n: usize
}
impl <T: PrimInt> RingBuffer<T> {
pub fn create(fill: T,n: usize) -> Self {
Self {
buf: vec![fill;n],
pos: 0,
n
}
}
pub fn get_pos(&self,offset: i64) -> usize {
(self.pos as i64 + offset).rem_euclid(self.n as i64) as usize
}
pub fn set_pos(&mut self,pos: usize) {
self.pos = pos % self.n;
}
pub fn get_abs(&self,abs: usize) -> T {
self.buf[abs % self.n]
}
pub fn set_abs(&mut self,abs: usize,val: T) {
self.buf[abs % self.n] = val;
}
pub fn get(&self,offset: i64) -> T {
self.buf[(self.pos as i64 + offset).rem_euclid(self.n as i64) as usize]
}
pub fn set(&mut self,offset: i64,val: T) {
self.buf[(self.pos as i64 + offset).rem_euclid(self.n as i64) as usize] = val;
}
pub fn advance(&mut self) {
self.pos = (self.pos + 1) % self.n;
}
pub fn retreat(&mut self) {
self.pos = (self.pos - 1) % self.n;
}
pub fn distance_behind(&self,other: usize) -> usize {
(self.pos as i64 - other as i64).rem_euclid(self.n as i64) as usize
}
}
#[test]
fn offset() {
let mut ring: RingBuffer<u8> = RingBuffer::create(0,4);
ring.set_pos(5);
assert_eq!(ring.get_pos(0),1);
assert_eq!(ring.get_pos(4),1);
assert_eq!(ring.get_pos(3),0);
assert_eq!(ring.get_pos(-4),1);
}
#[test]
fn distance() {
let mut ring: RingBuffer<u8> = RingBuffer::create(0,4);
ring.set_pos(5);
assert_eq!(ring.get_pos(0),1);
assert_eq!(ring.distance_behind(0),1);
assert_eq!(ring.distance_behind(1),0);
assert_eq!(ring.distance_behind(3),2);
}