use std::sync::Arc;
const SMALL_VEC_PAIR_CAP: usize = 4;
const ENTRY_CAP: usize = SMALL_VEC_PAIR_CAP * 2;
const NO_SYM: u16 = u16::MAX;
const BASE_EMPTY_STATE: u16 = 0;
#[derive(Clone, Debug)]
pub struct StackNode {
pub state: u16,
pub symbol: Option<u16>,
pub head: Vec<u16>,
pub tail: Option<Arc<StackNode>>,
}
impl StackNode {
#[inline]
fn push_pair(head: &mut Vec<u16>, state: u16, sym: Option<u16>) {
debug_assert!(
head.len().is_multiple_of(2),
"head must contain pairs before push"
);
debug_assert!(sym != Some(NO_SYM), "symbol id must be < u16::MAX");
head.push(state);
head.push(sym.unwrap_or(NO_SYM));
debug_assert!(
head.len().is_multiple_of(2),
"head must contain pairs after push"
);
}
#[inline]
fn pop_pair(head: &mut Vec<u16>) -> Option<(u16, Option<u16>)> {
debug_assert!(head.len().is_multiple_of(2), "head must contain pairs");
if head.len() < 2 {
return None;
}
let sym = head.pop().expect("length checked >= 2");
let state = head.pop().expect("length checked >= 2");
Some((state, (sym != NO_SYM).then_some(sym)))
}
pub fn new() -> Self {
Self {
state: BASE_EMPTY_STATE,
symbol: None,
head: Vec::with_capacity(ENTRY_CAP),
tail: None,
}
}
pub fn with_state(state: u16) -> Self {
Self {
state,
symbol: None,
head: Vec::with_capacity(ENTRY_CAP),
tail: None,
}
}
pub fn push(&mut self, state: u16, symbol: Option<u16>) {
if self.head.len() + 2 > ENTRY_CAP {
let old_node = Self {
state: self.state,
symbol: self.symbol,
head: std::mem::replace(&mut self.head, Vec::with_capacity(ENTRY_CAP)),
tail: self.tail.take(),
};
self.tail = Some(Arc::new(old_node));
}
Self::push_pair(&mut self.head, state, symbol);
#[cfg(debug_assertions)]
self.assert_well_formed();
}
pub fn pop(&mut self) -> Option<(u16, Option<u16>)> {
if let Some(pair) = Self::pop_pair(&mut self.head) {
#[cfg(debug_assertions)]
self.assert_well_formed();
return Some(pair);
}
if let Some(tail) = self.tail.take() {
match Arc::try_unwrap(tail) {
Ok(node) => {
self.state = node.state;
self.symbol = node.symbol;
self.head = node.head;
self.tail = node.tail;
self.pop()
}
Err(arc) => {
let node = (*arc).clone();
self.state = node.state;
self.symbol = node.symbol;
self.head = node.head;
self.tail = node.tail;
self.pop()
}
}
} else if self.state != 0 {
let state = self.state;
let symbol = self.symbol;
self.state = 0;
self.symbol = None;
#[cfg(debug_assertions)]
self.assert_well_formed();
Some((state, symbol))
} else {
None
}
}
#[inline]
pub fn top(&self) -> Option<u16> {
let mut node: Option<&StackNode> = Some(self);
while let Some(n) = node {
debug_assert!(n.head.len() % 2 == 0, "head must contain pairs");
if n.head.len() >= 2 {
return Some(n.head[n.head.len() - 2]);
}
if n.state != 0 {
return Some(n.state);
}
node = n.tail.as_deref();
}
None
}
#[inline]
pub fn last(&self) -> Option<u16> {
self.top()
}
pub fn depth(&self) -> usize {
let mut count = 0;
let mut cur: Option<&StackNode> = Some(self);
while let Some(n) = cur {
if n.state != 0 {
count += 1;
}
debug_assert!(n.head.len() % 2 == 0, "head must contain pairs");
count += n.head.len() / 2;
cur = n.tail.as_deref();
}
count
}
#[inline]
pub fn is_empty(&self) -> bool {
self.head.is_empty() && self.tail.is_none() && self.state == 0
}
pub fn to_vec(&self) -> Vec<u16> {
let mut out = Vec::with_capacity(self.depth());
let mut chain: Vec<&StackNode> = Vec::new();
let mut cur: Option<&StackNode> = Some(self);
while let Some(n) = cur {
chain.push(n);
cur = n.tail.as_deref();
}
for n in chain.iter().rev() {
if n.state != 0 {
out.push(n.state);
}
debug_assert!(n.head.len() % 2 == 0, "head must contain pairs");
for i in (0..n.head.len()).step_by(2) {
out.push(n.head[i]);
}
}
out
}
pub fn fork(&self) -> Self {
self.clone()
}
pub fn can_merge_with(&self, other: &Self) -> bool {
self.depth() == other.depth() && self.top() == other.top()
}
#[inline]
#[cfg_attr(not(any(test, debug_assertions)), doc(hidden))]
pub fn assert_well_formed(&self) {
let mut cur: Option<&StackNode> = Some(self);
while let Some(n) = cur {
debug_assert!(n.head.len() % 2 == 0, "head must contain pairs");
cur = n.tail.as_deref();
}
}
#[cfg(any(test, feature = "test-api"))]
pub fn from_raw(state: u16, head: Vec<u16>, tail: Option<Arc<StackNode>>) -> Self {
let s = Self {
state,
symbol: None,
head,
tail,
};
s.assert_well_formed();
s
}
}
impl Default for StackNode {
fn default() -> Self {
Self::new()
}
}
#[cfg(any(test, feature = "test-api"))]
pub mod test_helpers {
use super::*;
pub trait GlrStack: Clone {
fn push(&mut self, state: u16);
fn pop(&mut self) -> Option<u16>;
fn peek(&self) -> Option<u16>;
fn len(&self) -> usize;
fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl GlrStack for Vec<u16> {
fn push(&mut self, state: u16) {
Vec::push(self, state)
}
fn pop(&mut self) -> Option<u16> {
Vec::pop(self)
}
fn peek(&self) -> Option<u16> {
self.last().copied()
}
fn len(&self) -> usize {
Vec::len(self)
}
}
impl GlrStack for StackNode {
fn push(&mut self, state: u16) {
StackNode::push(self, state, None)
}
fn pop(&mut self) -> Option<u16> {
StackNode::pop(self).map(|(state, _)| state)
}
fn peek(&self) -> Option<u16> {
self.top()
}
fn len(&self) -> usize {
self.depth()
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_push_pop() {
let mut stack = StackNode::new();
stack.push(1, None);
stack.push(2, Some(100));
stack.push(3, None);
assert_eq!(stack.pop(), Some((3, None)));
assert_eq!(stack.pop(), Some((2, Some(100))));
assert_eq!(stack.pop(), Some((1, None)));
assert_eq!(stack.pop(), None);
}
#[test]
fn test_fork_sharing() {
let mut stack1 = StackNode::with_state(1);
stack1.push(2, None);
stack1.push(3, None);
let stack2 = stack1.fork();
assert_eq!(stack1.to_vec(), vec![1, 2, 3]);
assert_eq!(stack2.to_vec(), vec![1, 2, 3]);
stack1.push(4, None);
assert_eq!(stack1.to_vec(), vec![1, 2, 3, 4]);
assert_eq!(stack2.to_vec(), vec![1, 2, 3]);
}
#[test]
fn test_spill_to_tail() {
let mut stack = StackNode::new();
for i in 0..20 {
stack.push(i, None);
}
assert_eq!(stack.depth(), 20);
for i in (0..20).rev() {
assert_eq!(stack.pop(), Some((i, None)));
}
assert!(stack.is_empty());
}
#[test]
fn top_ignores_symbol_and_reads_state() {
let mut s = StackNode::new();
s.push(7, Some(11));
assert_eq!(s.top(), Some(7));
s.assert_well_formed();
s.push(9, None);
assert_eq!(s.top(), Some(9));
s.assert_well_formed();
}
}