use crate::{StateId, SymbolId};
use std::rc::Rc;
#[derive(Debug, Clone)]
pub struct StackNode {
pub state: StateId,
pub symbol: Option<SymbolId>,
pub parent: Option<Rc<StackNode>>,
pub depth: usize,
}
impl StackNode {
pub fn new(state: StateId, symbol: Option<SymbolId>, parent: Option<Rc<StackNode>>) -> Self {
let depth = parent.as_ref().map_or(0, |p| p.depth + 1);
Self {
state,
symbol,
parent,
depth,
}
}
pub fn get_states(&self) -> Vec<StateId> {
let mut states = Vec::with_capacity(self.depth + 1);
let mut current = Some(self);
while let Some(node) = current {
states.push(node.state);
current = node.parent.as_deref();
}
states.reverse();
states
}
pub fn shares_prefix_with(&self, other: &StackNode) -> bool {
if let (Some(p1), Some(p2)) = (&self.parent, &other.parent) {
Rc::ptr_eq(p1, p2)
} else {
self.parent.is_none() && other.parent.is_none()
}
}
}
pub struct GraphStructuredStack {
pub active_heads: Vec<Rc<StackNode>>,
pub completed_heads: Vec<Rc<StackNode>>,
pub stats: GSSStats,
}
#[derive(Debug, Default)]
pub struct GSSStats {
pub total_nodes_created: usize,
pub max_active_heads: usize,
pub total_forks: usize,
pub total_merges: usize,
pub shared_segments: usize,
}
impl GraphStructuredStack {
pub fn new(initial_state: StateId) -> Self {
let initial_node = Rc::new(StackNode::new(initial_state, None, None));
Self {
active_heads: vec![initial_node],
completed_heads: Vec::new(),
stats: GSSStats {
total_nodes_created: 1,
max_active_heads: 1,
..Default::default()
},
}
}
pub fn fork_head(&mut self, head_idx: usize) -> usize {
let head = self.active_heads[head_idx].clone();
self.active_heads.push(head);
self.stats.total_forks += 1;
self.stats.max_active_heads = self.stats.max_active_heads.max(self.active_heads.len());
self.active_heads.len() - 1
}
pub fn push(&mut self, head_idx: usize, state: StateId, symbol: Option<SymbolId>) {
let parent = Some(self.active_heads[head_idx].clone());
let new_node = Rc::new(StackNode::new(state, symbol, parent));
self.active_heads[head_idx] = new_node;
self.stats.total_nodes_created += 1;
}
pub fn pop(&mut self, head_idx: usize, count: usize) -> Option<Vec<StateId>> {
let mut current = Some(self.active_heads[head_idx].as_ref());
let mut popped_states = Vec::with_capacity(count);
for _ in 0..count {
match current {
Some(node) => {
popped_states.push(node.state);
current = node.parent.as_deref();
}
None => return None, }
}
if let Some(node) = current {
self.active_heads[head_idx] =
Rc::new(StackNode::new(node.state, node.symbol, node.parent.clone()));
}
popped_states.reverse();
Some(popped_states)
}
pub fn top_state(&self, head_idx: usize) -> StateId {
self.active_heads[head_idx].state
}
pub fn can_merge(&self, idx1: usize, idx2: usize) -> bool {
if idx1 == idx2 {
return false;
}
let head1 = &self.active_heads[idx1];
let head2 = &self.active_heads[idx2];
head1.state == head2.state && head1.shares_prefix_with(head2)
}
pub fn merge_heads(&mut self, keep_idx: usize, remove_idx: usize) {
if keep_idx != remove_idx && self.can_merge(keep_idx, remove_idx) {
self.active_heads.remove(remove_idx);
self.stats.total_merges += 1;
let head = &self.active_heads[keep_idx.min(self.active_heads.len() - 1)];
if head.parent.is_some() {
self.stats.shared_segments += 1;
}
}
}
pub fn mark_completed(&mut self, head_idx: usize) {
let head = self.active_heads.remove(head_idx);
self.completed_heads.push(head);
}
pub fn get_stats(&self) -> &GSSStats {
&self.stats
}
pub fn deduplicate(&mut self) {
let mut i = 0;
while i < self.active_heads.len() {
let mut j = i + 1;
while j < self.active_heads.len() {
if self.can_merge(i, j) {
self.merge_heads(i, j);
} else {
j += 1;
}
}
i += 1;
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_gss_basic_operations() {
let mut gss = GraphStructuredStack::new(StateId(0));
gss.push(0, StateId(1), Some(SymbolId(10)));
gss.push(0, StateId(2), Some(SymbolId(20)));
assert_eq!(gss.top_state(0), StateId(2));
let fork_idx = gss.fork_head(0);
assert_eq!(gss.active_heads.len(), 2);
assert_eq!(gss.top_state(0), gss.top_state(fork_idx));
gss.push(0, StateId(3), Some(SymbolId(30)));
gss.push(fork_idx, StateId(4), Some(SymbolId(40)));
assert_ne!(gss.top_state(0), gss.top_state(fork_idx));
}
#[test]
fn test_gss_shared_segments() {
let mut gss = GraphStructuredStack::new(StateId(0));
gss.push(0, StateId(1), None);
gss.push(0, StateId(2), None);
let fork1 = gss.fork_head(0);
let fork2 = gss.fork_head(0);
assert!(gss.active_heads[0].shares_prefix_with(&gss.active_heads[fork1]));
assert!(gss.active_heads[0].shares_prefix_with(&gss.active_heads[fork2]));
assert!(Rc::ptr_eq(
gss.active_heads[0].parent.as_ref().unwrap(),
gss.active_heads[fork1].parent.as_ref().unwrap()
));
}
#[test]
fn test_gss_merge() {
let mut gss = GraphStructuredStack::new(StateId(0));
gss.push(0, StateId(1), None);
let fork = gss.fork_head(0);
gss.push(0, StateId(2), None);
gss.push(fork, StateId(2), None);
assert!(gss.can_merge(0, fork));
gss.deduplicate();
assert_eq!(gss.active_heads.len(), 1);
assert_eq!(gss.stats.total_merges, 1);
}
#[test]
fn test_gss_pop() {
let mut gss = GraphStructuredStack::new(StateId(0));
gss.push(0, StateId(1), None);
gss.push(0, StateId(2), None);
gss.push(0, StateId(3), None);
let mut popped = gss.pop(0, 2).unwrap();
popped.sort_by_key(|s| s.0);
assert_eq!(popped, vec![StateId(2), StateId(3)]);
assert_eq!(gss.top_state(0), StateId(1));
}
}