use std::default::Default;
use std::slice;
#[derive(Debug, Clone)]
pub struct DStack<I> {
stacks: Vec<I>,
left_head: Option<usize>,
right_head: usize,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum StackVal<I> {
Enter(I),
Exit(I),
}
impl<I: Default> Default for StackVal<I> {
fn default() -> Self {
Self::Enter(I::default())
}
}
impl<I> DStack<I>
where
I: Clone,
{
pub fn with_capacity(n: usize) -> Self
where
I: Default,
{
assert!(n > 1);
Self {
stacks: vec![I::default(); n],
left_head: None,
right_head: n,
}
}
pub fn capacity(&self) -> usize {
self.stacks.len()
}
pub fn is_left_empty(&self) -> bool {
self.left_head.is_none()
}
pub fn is_right_empty(&self) -> bool {
self.right_head == self.capacity()
}
pub fn push_left(&mut self, value: I) {
let head = self.left_head.map_or(0, |x| x + 1);
assert!(head < self.right_head);
self.stacks[head] = value;
self.left_head = Some(head);
}
pub fn push_right(&mut self, value: I) {
self.right_head -= 1;
if let Some(left_head) = self.left_head {
assert!(self.right_head > left_head);
}
self.stacks[self.right_head] = value;
}
pub fn pop_left(&mut self) -> Option<I> {
match self.left_head {
Some(left_head) => {
let res = self.stacks[left_head].clone();
self.left_head = if left_head > 0 {
Some(left_head - 1)
} else {
None
};
Some(res)
}
None => None,
}
}
pub fn pop_right(&mut self) -> Option<I> {
if self.right_head >= self.stacks.len() {
None
} else {
let res = self.stacks[self.right_head].clone();
self.right_head += 1;
Some(res)
}
}
pub fn len_right(&self) -> usize {
let n = self.stacks.len();
n - self.right_head
}
pub fn clear_right(&mut self) {
self.right_head = self.stacks.len();
}
pub fn clear_left(&mut self) {
self.left_head = None;
}
pub fn iter_right(&self) -> slice::Iter<I> {
self.stacks[self.right_head..].iter()
}
pub fn push_left_on_right(&mut self) {
while let Some(val) = self.pop_left() {
self.push_right(val);
}
}
pub fn push_right_on_left(&mut self) {
while let Some(val) = self.pop_right() {
self.push_left(val);
}
}
}
pub fn extract_stack_val<I>(stack_val: &StackVal<I>) -> &I {
match stack_val {
StackVal::Enter(i) | StackVal::Exit(i) => i,
}
}