use std::{
marker::PhantomData,
mem::{replace, take},
};
#[derive(Debug)]
pub struct LimitedQueue<T> {
q: Vec<Option<T>>,
front: usize,
rear: usize,
sz: usize,
}
impl<T> LimitedQueue<T> {
#[inline]
pub fn with_capacity(cap: usize) -> LimitedQueue<T> {
if cap == 0 {
panic!("Cannot create a LimitedQueue with zero capacity");
}
let mut q = Vec::with_capacity(cap);
q.resize_with(cap, Option::default);
LimitedQueue {
q,
front: 0usize,
rear: 0usize,
sz: 0usize,
}
}
#[inline]
pub fn get(&self, idx: usize) -> Option<&T> {
if idx >= self.sz {
None
} else {
Some(&self[idx])
}
}
#[inline]
pub fn peek(&self) -> Option<&T> {
if self.is_empty() {
None
} else {
self.q[self.front].as_ref()
}
}
#[inline]
pub fn push(&mut self, ele: T) -> Option<T> {
let mut popped = None;
if self.is_full() {
popped = replace(&mut self.q[self.rear], Some(ele));
self.front = self.next_idx(self.front);
} else {
let _ = std::mem::replace(&mut self.q[self.rear], Some(ele));
self.sz += 1;
}
self.rear = self.next_idx(self.rear);
popped
}
#[inline]
fn next_idx(&self, idx: usize) -> usize {
(idx + 1) % self.q.capacity()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.sz == 0
}
#[inline]
pub fn is_full(&self) -> bool {
self.sz == self.q.capacity()
}
#[inline]
pub fn len(&self) -> usize {
self.sz
}
#[inline]
pub fn iter(&self) -> LimitedQueueIterator<T> {
LimitedQueueIterator {
lq: self,
front_idx: 0,
back_idx: self.sz,
}
}
#[inline]
pub fn iter_mut(&mut self) -> LimitedQueueIteratorMut<T> {
let len = self.sz;
let cap = self.q.capacity();
let front = self.front;
let q_ptr = self.q.as_mut_ptr(); LimitedQueueIteratorMut {
q_ptr,
front,
capacity: cap,
front_idx: 0,
back_idx: len,
_marker: PhantomData, }
}
#[inline]
pub fn clear(&mut self) {
self.front = 0;
self.rear = 0;
self.sz = 0;
}
#[inline]
fn indexing(&self, idx: usize) -> usize {
if idx >= self.sz {
panic!("Invalid subscription index: {}", idx)
}
(idx + self.front) % self.q.capacity()
}
#[inline]
pub fn pop(&mut self) -> Option<T> {
if self.is_empty() {
None
} else {
let ret = take(&mut self.q[self.front]);
self.front = self.next_idx(self.front);
self.sz -= 1;
ret
}
}
}
impl<T> std::ops::Index<usize> for LimitedQueue<T> {
type Output = T;
#[inline]
fn index(&self, idx: usize) -> &Self::Output {
let real_idx = self.indexing(idx);
self.q[real_idx].as_ref().unwrap()
}
}
impl<T> std::ops::IndexMut<usize> for LimitedQueue<T> {
#[inline]
fn index_mut(&mut self, idx: usize) -> &mut Self::Output {
let real_idx = self.indexing(idx);
self.q[real_idx].as_mut().unwrap()
}
}
pub struct LimitedQueueIterator<'a, T> {
lq: &'a LimitedQueue<T>,
front_idx: usize,
back_idx: usize,
}
#[cfg(not(tarpaulin_include))]
impl<'a, T> Iterator for LimitedQueueIterator<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
if self.front_idx == self.back_idx {
None } else {
let cur_idx = self.front_idx;
self.front_idx += 1;
Some(&self.lq[cur_idx])
}
}
}
impl<'a, T> DoubleEndedIterator for LimitedQueueIterator<'a, T> {
fn next_back(&mut self) -> Option<Self::Item> {
if self.front_idx == self.back_idx {
None } else {
self.back_idx -= 1;
let cur_idx = self.back_idx;
Some(&self.lq[cur_idx])
}
}
}
pub struct LimitedQueueIteratorMut<'a, T> {
q_ptr: *mut Option<T>, front: usize, capacity: usize,
front_idx: usize, back_idx: usize, _marker: PhantomData<&'a mut T>, }
impl<'a, T> Iterator for LimitedQueueIteratorMut<'a, T> {
type Item = &'a mut T;
fn next(&mut self) -> Option<Self::Item> {
if self.front_idx == self.back_idx {
None
} else {
let cur_idx = self.front_idx;
self.front_idx += 1;
let real_idx = (cur_idx + self.front) % self.capacity;
unsafe {
let elem_ptr = self.q_ptr.add(real_idx);
let opt_ref = &mut *elem_ptr;
Some(opt_ref.as_mut().unwrap())
}
}
}
}
impl<'a, T> DoubleEndedIterator for LimitedQueueIteratorMut<'a, T> {
fn next_back(&mut self) -> Option<Self::Item> {
if self.front_idx == self.back_idx {
None
} else {
self.back_idx -= 1;
let cur_idx = self.back_idx;
let real_idx = (cur_idx + self.front) % self.capacity;
unsafe {
let elem_ptr = self.q_ptr.add(real_idx);
let opt_ref = &mut *elem_ptr;
Some(opt_ref.as_mut().unwrap())
}
}
}
}
#[cfg(test)]
mod tests {
use std::panic;
use rand::Rng;
use crate::LimitedQueue;
#[derive(Debug, PartialEq, Eq, Clone)]
struct NoDefault(i32);
#[test]
fn test_pop_no_default() {
let mut q = LimitedQueue::with_capacity(2);
q.push(NoDefault(1));
q.push(NoDefault(2));
assert_eq!(q.push(NoDefault(3)), Some(NoDefault(1)));
assert_eq!(q.peek(), Some(&NoDefault(2)));
assert_eq!(q.pop(), Some(NoDefault(2)));
assert_eq!(q.pop(), Some(NoDefault(3)));
assert_eq!(q.pop(), None);
}
#[test]
fn test_iter() {
let mut q = crate::LimitedQueue::with_capacity(5);
let push_ret = [[None; 5], core::array::from_fn(|i| Some(i))].concat();
for (i, pr) in (0..10).zip(push_ret) {
assert_eq!(q.push(i), pr);
}
assert_eq!(q.len(), 5);
for (n, element) in q.iter().enumerate() {
assert_eq!(element.clone(), q[n]); assert_eq!(element.clone(), n + 5); }
for (n, element) in q.iter().rev().enumerate() {
assert_eq!(element.clone(), q[4 - n]); assert_eq!(element.clone(), 9 - n); }
}
#[test]
fn test_iter_mut() {
let mut q = LimitedQueue::with_capacity(5);
for i in 0..5 {
q.push(i); }
for element in q.iter_mut() {
*element += 10;
}
for (n, element) in q.iter().enumerate() {
assert_eq!(*element, n + 10);
}
assert_eq!(q.push(99), Some(10)); assert_eq!(q.peek(), Some(&11));
}
#[test]
fn test_double_ended_iter_mut() {
let mut q = LimitedQueue::with_capacity(5);
for i in 0..5 {
q.push(i); }
let mut iter_mut = q.iter_mut();
*iter_mut.next().unwrap() = 100; *iter_mut.next_back().unwrap() = 400; *iter_mut.next().unwrap() = 200; *iter_mut.next_back().unwrap() = 300;
let mut iter = q.iter();
assert_eq!(iter.next(), Some(&100));
assert_eq!(iter.next(), Some(&200));
assert_eq!(iter.next(), Some(&2));
assert_eq!(iter.next(), Some(&300));
assert_eq!(iter.next(), Some(&400));
assert_eq!(iter.next(), None);
}
#[test]
fn test_change_size() {
const MAX_SZ: usize = 25;
let mut q: LimitedQueue<i32> = crate::LimitedQueue::with_capacity(MAX_SZ);
let mut sz = 0;
let mut rng = rand::thread_rng();
for _ in 0..1000 {
let op = rng.gen_range(0..=2);
match op {
0 => {
if q.push(rng.gen()).is_none() {
sz += 1
};
}
1 => {
if q.pop().is_some() {
sz -= 1
};
}
_ => {
assert!(match sz {
0 => q.is_empty() && q.pop().is_none() && q.peek().is_none(),
MAX_SZ => q.is_full(),
_ => sz == q.len() && sz < MAX_SZ,
});
}
};
}
}
#[test]
#[should_panic]
fn test_zero_len_invalid_indexing() {
LimitedQueue::<i32>::with_capacity(0)[0];
}
#[test]
fn test_invalid_indexing() {
let old_hook = panic::take_hook();
panic::set_hook(Box::new(|_info| {}));
let mut q = LimitedQueue::with_capacity(5);
q.push(1);
for i in 5..100 {
let invalid_access = || q[i];
let should_be_false = panic::catch_unwind(invalid_access).is_err();
if !should_be_false {
panic::set_hook(old_hook);
panic!("Indexing with idx: {} cannot trigger panic.", i);
}
}
panic::set_hook(old_hook);
}
#[test]
fn test_clear() {
let mut q = LimitedQueue::with_capacity(10);
q.clear();
assert_eq!(q.len(), 0);
assert!(q.is_empty());
for _ in 0..3 {
q.push(1);
}
assert_eq!(q.len(), 3);
q.clear();
assert_eq!(q.len(), 0);
assert_eq!(q.peek(), None);
assert!(q.is_empty());
for i in 0..10 {
q.push(i);
}
assert!(q.is_full());
q.clear();
assert!(q.is_empty());
assert_eq!(q.len(), 0);
assert_eq!(q.peek(), None);
assert_eq!(q.push(100), None);
assert_eq!(q.len(), 1);
assert_eq!(q.peek(), Some(&100));
assert_eq!(q.pop(), Some(100));
assert_eq!(q.len(), 0);
assert!(q.is_empty());
}
#[test]
fn test_capacity_one() {
let mut q = LimitedQueue::with_capacity(1);
assert!(q.is_empty());
assert_eq!(q.push(1), None);
assert!(q.is_full());
assert_eq!(q.peek(), Some(&1));
assert_eq!(q.push(2), Some(1)); assert!(q.is_full());
assert_eq!(q.peek(), Some(&2));
assert_eq!(q.pop(), Some(2));
assert!(q.is_empty());
assert_eq!(q.peek(), None);
assert_eq!(q.pop(), None);
assert_eq!(q.push(3), None);
assert_eq!(q.len(), 1);
assert_eq!(q.peek(), Some(&3));
}
#[test]
#[should_panic]
fn test_capacity_zero_push_panic() {
let mut q = LimitedQueue::<i32>::with_capacity(0);
q.push(1); }
#[test]
fn test_get_method() {
let mut q = LimitedQueue::with_capacity(3);
assert_eq!(q.get(0), None); assert_eq!(q.get(1), None);
q.push(10); q.push(20); assert_eq!(q.get(0), Some(&10));
assert_eq!(q.get(1), Some(&20));
assert_eq!(q.get(2), None);
q.push(30); assert_eq!(q.get(2), Some(&30));
assert_eq!(q.get(3), None);
q.push(40); assert_eq!(q.get(0), Some(&20));
assert_eq!(q.get(1), Some(&30));
assert_eq!(q.get(2), Some(&40));
assert_eq!(q.get(3), None); }
#[test]
fn test_iter_empty() {
let mut q = LimitedQueue::<i32>::with_capacity(5);
assert_eq!(q.iter().next(), None);
assert_eq!(q.iter().next_back(), None);
assert_eq!(q.iter_mut().next(), None);
assert_eq!(q.iter_mut().next_back(), None);
}
#[test]
fn test_iter_mixed() {
let mut q = LimitedQueue::with_capacity(5);
for i in 0..5 {
q.push(i); }
let mut iter = q.iter();
assert_eq!(iter.next(), Some(&0));
assert_eq!(iter.next_back(), Some(&4));
assert_eq!(iter.next(), Some(&1));
assert_eq!(iter.next_back(), Some(&3));
assert_eq!(iter.next(), Some(&2));
assert_eq!(iter.next(), None);
assert_eq!(iter.next_back(), None);
}
#[test]
fn test_index_mut() {
let mut q = LimitedQueue::with_capacity(3);
q.push(1);
q.push(2);
q[0] = 100; q[1] = 200;
assert_eq!(q.get(0), Some(&100));
assert_eq!(q.get(1), Some(&200));
}
#[test]
fn test_debug_format() {
let mut q = LimitedQueue::with_capacity(3);
q.push(1);
q.push(2);
let formatted = format!("{:?}", q);
assert!(formatted.contains("LimitedQueue"));
assert!(formatted.contains("Some(1)"));
assert!(formatted.contains("Some(2)"));
}
#[test]
#[should_panic(expected = "Invalid subscription index: 1")]
fn test_indexing_panic_simple() {
let mut q = LimitedQueue::with_capacity(3);
q.push(1); let _ = q[1]; }
}