#[derive(Debug)]
pub(crate) struct RingBuffer<T> {
head: usize,
len: usize,
buffer: Vec<Option<T>>,
}
impl<T> RingBuffer<T> {
pub(crate) fn with_capacity(capacity: usize) -> RingBuffer<T> {
let mut buffer = Vec::with_capacity(capacity);
buffer.resize_with(capacity, || None);
RingBuffer {
head: 0,
len: 0,
buffer,
}
}
pub(crate) fn is_empty(&self) -> bool {
self.len == 0
}
pub(crate) fn is_full(&self) -> bool {
self.len == self.buffer.capacity()
}
pub(crate) fn get(&self, index: usize) -> Option<&T> {
self.buffer.get(index).and_then(Option::as_ref)
}
pub(crate) fn push_back(&mut self, value: T) -> Option<usize> {
if self.is_full() {
return None;
}
let physical_idx = self.wrap_add(self.head, self.len);
self.buffer[physical_idx] = Some(value);
self.len += 1;
Some(physical_idx)
}
pub(crate) fn pop_front(&mut self) -> Option<T> {
if self.is_empty() {
None
} else {
while self.len >= 1 {
let t = self.buffer[self.head].take();
self.head = self.wrap_add(self.head, 1);
self.len -= 1;
match t {
None => continue,
item @ Some(_) => {
return item;
}
}
}
None
}
}
pub(crate) fn remove(&mut self, index: usize) -> Option<T> {
self.buffer[index].take()
}
fn wrap_add(&self, idx: usize, addend: usize) -> usize {
let capacity = self.buffer.capacity();
let idx = idx.wrapping_add(addend);
if idx >= capacity { idx - capacity } else { idx }
}
}
#[cfg(test)]
mod tests {
use crate::cache::ring_buffer::RingBuffer;
#[test]
fn it_is_empty() {
let mut ring_buffer = RingBuffer::with_capacity(1);
ring_buffer.push_back(String::from("hello world")).unwrap();
ring_buffer.pop_front();
let is_empty = ring_buffer.is_empty();
assert!(is_empty)
}
#[test]
fn it_is_not_empty() {
let mut ring_buffer = RingBuffer::with_capacity(1);
ring_buffer.push_back(String::from("hello world")).unwrap();
let is_empty = ring_buffer.is_empty();
assert!(!is_empty)
}
#[test]
fn it_is_full() {
let mut ring_buffer = RingBuffer::with_capacity(1);
ring_buffer.push_back(String::from("hello world")).unwrap();
let is_full = ring_buffer.is_full();
assert!(is_full)
}
#[test]
fn it_is_not_full() {
let mut ring_buffer = RingBuffer::with_capacity(1);
ring_buffer.push_back(String::from("hello world")).unwrap();
ring_buffer.pop_front();
let is_full = ring_buffer.is_full();
assert!(!is_full)
}
#[test]
fn it_pushes_back_by_wrapping_around() {
let mut ring_buffer = RingBuffer::with_capacity(5);
ring_buffer.push_back(String::from("first")).unwrap();
ring_buffer.push_back(String::from("second")).unwrap();
ring_buffer.push_back(String::from("third")).unwrap();
ring_buffer.push_back(String::from("fourth")).unwrap();
ring_buffer.push_back(String::from("fifth")).unwrap();
ring_buffer.pop_front();
ring_buffer.pop_front();
ring_buffer.pop_front();
assert_eq!(ring_buffer.head, 3);
assert_eq!(ring_buffer.buffer.len(), 5);
assert_eq!(ring_buffer.len, 2);
let idx = ring_buffer.push_back(String::from("sixth")).unwrap();
assert_eq!(idx, 0);
assert_eq!(ring_buffer.head, 3);
assert_eq!(ring_buffer.buffer.len(), 5);
assert_eq!(ring_buffer.len, 3);
}
#[test]
fn it_pushes_back_when_fully_wrapped() {
let mut ring_buffer = RingBuffer::with_capacity(5);
ring_buffer.push_back(String::from("first")).unwrap();
ring_buffer.push_back(String::from("second")).unwrap();
ring_buffer.push_back(String::from("third")).unwrap();
ring_buffer.push_back(String::from("fourth")).unwrap();
ring_buffer.push_back(String::from("fifth")).unwrap();
ring_buffer.pop_front();
ring_buffer.pop_front();
ring_buffer.pop_front();
ring_buffer.pop_front();
ring_buffer.pop_front();
assert_eq!(ring_buffer.head, 0);
assert_eq!(ring_buffer.buffer.len(), 5);
assert_eq!(ring_buffer.len, 0);
let idx = ring_buffer.push_back(String::from("sixth")).unwrap();
assert_eq!(idx, 0);
assert_eq!(ring_buffer.head, 0);
assert_eq!(ring_buffer.buffer.len(), 5);
assert_eq!(ring_buffer.len, 1);
}
#[test]
fn it_does_not_push_back_when_full() {
let mut ring_buffer = RingBuffer::with_capacity(5);
ring_buffer.push_back(String::from("first")).unwrap();
ring_buffer.push_back(String::from("second")).unwrap();
ring_buffer.push_back(String::from("third")).unwrap();
ring_buffer.push_back(String::from("fourth")).unwrap();
ring_buffer.push_back(String::from("fifth")).unwrap();
let option = ring_buffer.push_back(String::from("sixth"));
assert!(option.is_none());
}
#[test]
fn it_handles_deletions() {
let mut ring_buffer = RingBuffer::with_capacity(5);
ring_buffer.push_back(String::from("first")).unwrap();
ring_buffer.push_back(String::from("second")).unwrap();
ring_buffer.push_back(String::from("third")).unwrap();
ring_buffer.push_back(String::from("fourth")).unwrap();
ring_buffer.push_back(String::from("fifth")).unwrap();
ring_buffer.pop_front();
ring_buffer.pop_front();
ring_buffer.pop_front();
ring_buffer.remove(3);
assert_eq!(ring_buffer.head, 3);
assert_eq!(ring_buffer.buffer.len(), 5);
assert_eq!(ring_buffer.len, 2);
let item = ring_buffer.pop_front().unwrap();
assert!(ring_buffer.is_empty());
assert_eq!(ring_buffer.head, 0);
assert_eq!(ring_buffer.buffer.len(), 5);
assert_eq!(ring_buffer.len, 0);
assert_eq!(item, "fifth")
}
}