#[macro_export]
macro_rules! ring {
($(#[$attr:meta])* $visibility : vis $name : ident[$type : ty; $size : expr]) => {
$(
#[$attr]
)*
#[allow(dead_code)]
$visibility struct $name { tail : usize, head : usize, buffer : [$type; $size], }
#[allow(dead_code)]
impl $name {
pub fn new() -> $name {
#[cfg(not(feature = "no_limit"))]
assert!($size as usize >= $crate::NSRB_LOWER_LIMIT);
#[cfg(not(feature = "no_limit"))]
assert!($size as usize <= $crate::NSRB_UPPER_LIMIT);
$name {
tail: 0,
head: 0,
buffer: [<$type>::default(); $size],
}
}
#[inline(always)]
pub fn push(&mut self, item : $type) {
self.buffer[self.head] = item;
self.push_head();
}
#[inline(always)]
pub fn pop(&mut self) -> Option<&$type> {
if self.tail != self.head {
let tail = self.tail;
self.push_tail();
Some(&self.buffer[tail])
} else {
None
}
}
#[inline(always)]
fn push_head(&mut self) {
if self.head >= $size - 1 {
self.head = 0;
} else {
self.head += 1;
}
if self.head == self.tail {
self.push_tail();
}
}
#[inline(always)]
fn push_tail(&mut self) {
if self.tail >= $size - 1 {
self.tail = 0;
} else {
self.tail += 1;
}
}
}
};
(@unchecked($int:ty) $(#[$attr:meta])* $visibility : vis $name : ident[$type : ty]) => {
$(
#[$attr]
)*
#[allow(dead_code)]
$visibility struct $name {
tail : $int,
head : $int,
buffer : [$type; <$int>::MAX as usize + 1],
}
#[allow(dead_code)]
impl $name {
pub fn new() -> $name {
#[cfg(not(feature = "no_limit"))]
assert!(<$int>::MAX as usize <= $crate::NSRB_UPPER_LIMIT);
$name {
tail: 0,
head: 0,
buffer: [<$type>::default(); <$int>::MAX as usize + 1],
}
}
#[inline(always)]
pub fn push(&mut self, item : $type) {
self.buffer[self.head as usize] = item;
self.head += 1;
if self.head == self.tail {
self.tail += 1;
}
}
#[inline(always)]
pub fn pop(&mut self) -> Option<&$type> {
if self.tail != self.head {
let tail = self.tail;
self.tail += 1;
Some(&self.buffer[tail as usize])
} else {
None
}
}
}
};
}
#[cfg(test)]
#[cfg(not(feature = "no_limit"))] pub(crate) mod tests_checked {
ring!(TooSmall[usize;super::super::NSRB_LOWER_LIMIT - 1]);
#[test]
#[should_panic]
fn ring_lower_limit() {
let _ = TooSmall::new();
}
ring!(TooBig[usize;super::super::NSRB_UPPER_LIMIT + 1]);
#[test]
#[should_panic]
fn ring_upper_limit() {
let _ = TooBig::new();
}
ring!(RbPP[usize;10]);
#[test]
fn ring_push_pop() {
let mut rb = RbPP::new();
for i in 0..15 {
rb.push(i);
}
for i in 6..15 {
assert_eq!(*rb.pop().unwrap(), i);
}
assert!(rb.pop().is_none());
}
ring!(RbExtra[usize;50]);
impl RbExtra {
pub fn clear(&mut self) {
self.tail = self.head;
}
pub fn len(&self) -> usize {
if self.tail > self.head {
self.buffer.len() + self.head - self.tail
} else {
self.head - self.tail
}
}
}
#[test]
fn ring_extra_impl() {
let mut rb = RbExtra::new();
assert!(rb.len() == 0);
for i in 0..15 {
rb.push(i);
}
assert_eq!(rb.len(), 15);
rb.clear();
assert!(rb.len() == 0);
while rb.tail <= rb.head {
rb.push(0);
}
assert_eq!(rb.len(), 35);
rb.clear();
assert!(rb.len() == 0);
let mut rb = RbExtra::new();
for i in 0..255 {
if i < rb.buffer.len() {
assert_eq!(rb.len(), i);
} else {
assert_eq!(rb.len(), 49);
}
rb.push(i);
}
rb.pop();
assert_eq!(rb.len(), 48);
}
}
#[cfg(test)]
#[cfg(not(feature = "no_limit"))] pub(crate) mod tests_unchecked {
ring!(@unchecked(u32) TooBig[usize]);
#[test]
#[should_panic]
fn ring_upper_limit() {
let _ = TooBig::new();
}
ring!(@unchecked(u8) RbPP[usize]);
#[test]
fn ring_push_pop() {
let mut rb = RbPP::new();
for i in 0..u8::MAX as usize {
rb.push(i);
}
for i in 0..u8::MAX as usize {
assert_eq!(*rb.pop().unwrap(), i);
}
assert!(rb.pop().is_none());
}
ring!(@unchecked(u8) RbExtra[usize]);
impl RbExtra {
pub fn clear(&mut self) {
self.tail = self.head;
}
pub fn len(&self) -> usize {
if self.tail > self.head {
self.buffer.len() as usize + self.head as usize - self.tail as usize
} else {
self.head as usize - self.tail as usize
}
}
}
#[test]
fn ring_extra_impl() {
let mut rb = RbExtra::new();
assert!(rb.len() == 0);
for i in 0..15 {
rb.push(i);
}
assert_eq!(rb.len(), 15);
rb.clear();
assert!(rb.len() == 0);
while rb.tail <= rb.head {
rb.push(0);
}
assert_eq!(rb.len(), 241);
rb.clear();
assert!(rb.len() == 0);
let mut rb = RbExtra::new();
for i in 0..255 {
if i < rb.buffer.len() {
assert_eq!(rb.len(), i);
} else {
assert_eq!(rb.len(), 49);
}
rb.push(i);
}
rb.pop();
assert_eq!(rb.len(), 254);
}
}