use core::ops::{Deref, DerefMut};
pub trait FastStack<T: Copy + Default> {
fn push(&mut self, v: T);
fn pop_fast(&mut self) -> T;
fn pop(&mut self) -> Option<T>;
fn len(&self) -> usize;
fn is_empty(&self) -> bool;
fn clear(&mut self);
}
#[macro_export]
macro_rules! fast_stack {
( $ty:ty,
($first:expr $(, $rest:expr)* $(,)?),
$size:expr,
$stack_ident:ident,
$body:block
) => {{
match $size {
s if s <= $first => {
let mut $stack_ident = $crate::faststack::StackStack::<$ty, $first>::default();
$body
}
$(
s if s <= $rest => {
let mut $stack_ident = $crate::faststack::StackStack::<$ty, $rest>::default();
$body
}
)*
_ => {
let mut $stack_ident = $crate::faststack::HeapStack::<$ty>::new_with_capacity($size);
$body
}
}
}};
}
#[derive(Clone)]
pub struct HeapStack<T: Copy + Default> {
data: Vec<T>,
index: usize,
}
impl<T: Copy + Default> Default for HeapStack<T> {
fn default() -> Self {
Self::new_with_capacity(1)
}
}
impl<T: Copy + Default> HeapStack<T> {
#[inline(always)]
pub fn new_with_capacity(cap: usize) -> Self {
assert!(cap > 0);
HeapStack {
data: vec![Default::default(); cap],
index: 0,
}
}
#[inline(always)]
pub fn cap(&self) -> usize {
self.data.len()
}
#[inline(always)]
pub fn reserve(&mut self, cap: usize) {
if cap < self.data.len() {
return;
}
self.data.resize(cap, Default::default());
}
}
impl<T: Copy + Default> Deref for HeapStack<T> {
type Target = [T];
fn deref(&self) -> &Self::Target {
&self.data[..self.index]
}
}
impl<T: Copy + Default> DerefMut for HeapStack<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.data[..self.index]
}
}
impl<T: Copy + Default> FastStack<T> for HeapStack<T> {
#[inline(always)]
fn push(&mut self, v: T) {
if self.index < self.data.len() {
*unsafe { self.data.get_unchecked_mut(self.index) } = v;
self.index += 1;
} else {
panic!(
"Index out of bounds: the HeapStack is full (length: {}) and cannot accommodate more elements",
self.data.len()
);
}
}
#[inline(always)]
fn pop(&mut self) -> Option<T> {
if self.index > 0 {
self.index = self.index.saturating_sub(1);
Some(self.data[self.index])
} else {
None
}
}
#[inline(always)]
fn pop_fast(&mut self) -> T {
self.index = self.index.saturating_sub(1);
let v = unsafe { self.data.get_unchecked(self.index) };
*v
}
#[inline(always)]
fn len(&self) -> usize {
self.index
}
#[inline(always)]
fn is_empty(&self) -> bool {
self.index == 0
}
#[inline(always)]
fn clear(&mut self) {
self.index = 0;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_with_capacity() {
let stack: HeapStack<i32> = HeapStack::new_with_capacity(10);
assert_eq!(stack.len(), 0);
assert_eq!(stack.data.len(), 10);
}
#[test]
fn test_push_and_pop() {
let mut stack: HeapStack<i32> = HeapStack::new_with_capacity(10);
stack.push(1);
stack.push(2);
stack.push(3);
assert_eq!(stack.len(), 3);
assert_eq!(stack.pop(), Some(3));
assert_eq!(stack.pop(), Some(2));
assert_eq!(stack.pop(), Some(1));
assert_eq!(stack.pop(), None);
}
#[test]
#[should_panic(expected = "Index out of bounds: the HeapStack is full")]
fn test_push_panic() {
let mut stack: HeapStack<i32> = HeapStack::new_with_capacity(2);
stack.push(1);
stack.push(2);
stack.push(3); }
#[test]
fn test_pop_fast() {
let mut stack: HeapStack<i32> = HeapStack::new_with_capacity(10);
stack.push(1);
stack.push(2);
stack.push(3);
assert_eq!(stack.pop_fast(), 3);
assert_eq!(stack.pop_fast(), 2);
assert_eq!(stack.pop_fast(), 1);
}
#[test]
fn test_clear() {
let mut stack: HeapStack<i32> = HeapStack::new_with_capacity(10);
stack.push(1);
stack.push(2);
stack.push(3);
stack.clear();
assert_eq!(stack.len(), 0);
assert_eq!(stack.pop(), None);
}
#[test]
fn test_reserve() {
let mut stack: HeapStack<i32> = HeapStack::new_with_capacity(5);
assert_eq!(stack.data.len(), 5);
stack.reserve(10);
assert_eq!(stack.data.len(), 10);
stack.reserve(3); assert_eq!(stack.data.len(), 10);
}
}
pub struct StackStack<T: Copy + Default, const STACK_SIZE: usize> {
data: [T; STACK_SIZE],
index: usize,
}
impl<T: Copy + Default, const STACK_SIZE: usize> Default for StackStack<T, STACK_SIZE> {
fn default() -> Self {
Self {
data: [Default::default(); STACK_SIZE],
index: Default::default(),
}
}
}
impl<T: Copy + Default, const STACK_SIZE: usize> FastStack<T> for StackStack<T, STACK_SIZE> {
#[inline(always)]
fn push(&mut self, v: T) {
*unsafe { self.data.get_unchecked_mut(self.index) } = v;
self.index = (self.index + 1).min(STACK_SIZE - 1);
}
#[inline(always)]
fn pop_fast(&mut self) -> T {
self.index = self.index.saturating_sub(1);
let v = unsafe { self.data.get_unchecked(self.index) };
*v
}
#[inline(always)]
fn pop(&mut self) -> Option<T> {
if self.index > 0 {
self.index = self.index.saturating_sub(1);
Some(self.data[self.index])
} else {
None
}
}
#[inline(always)]
fn len(&self) -> usize {
self.index
}
#[inline(always)]
fn is_empty(&self) -> bool {
self.index == 0
}
#[inline(always)]
fn clear(&mut self) {
self.index = 0;
}
}
impl<T: Copy + Default> FastStack<T> for Vec<T> {
fn push(&mut self, v: T) {
self.push(v);
}
fn pop_fast(&mut self) -> T {
self.pop().unwrap()
}
fn pop(&mut self) -> Option<T> {
self.pop()
}
fn len(&self) -> usize {
self.len()
}
fn is_empty(&self) -> bool {
self.is_empty()
}
fn clear(&mut self) {
self.clear();
}
}