use miden_air::trace::RowIndex;
use miden_utils_indexing::IndexVec;
use super::{Felt, ZERO};
#[derive(Debug, Clone, Default)]
struct OverflowStackEntry {
pub value: Felt,
pub clk: RowIndex,
}
impl OverflowStackEntry {
pub fn new(value: Felt, clk: RowIndex) -> Self {
Self { value, clk }
}
pub fn value(&self) -> Felt {
self.value
}
}
#[derive(Debug, Default, Clone)]
struct OverflowStack {
overflow: IndexVec<RowIndex, OverflowStackEntry>,
}
impl OverflowStack {
pub fn new() -> Self {
Self { overflow: IndexVec::new() }
}
pub fn last(&self) -> Option<&OverflowStackEntry> {
self.overflow.as_slice().last()
}
pub fn num_elements(&self) -> usize {
self.overflow.len()
}
pub fn is_empty(&self) -> bool {
self.overflow.is_empty()
}
pub fn push(&mut self, entry: OverflowStackEntry) {
let _ = self.overflow.push(entry); }
pub fn pop(&mut self) -> Option<OverflowStackEntry> {
if self.overflow.is_empty() {
None
} else {
Some(self.overflow.swap_remove(self.overflow.len() - 1))
}
}
}
#[derive(Debug, Clone)]
pub struct OverflowTable {
overflow: IndexVec<RowIndex, OverflowStack>,
}
impl OverflowTable {
pub fn new() -> Self {
let mut overflow = IndexVec::new();
let _ = overflow.push(OverflowStack::new());
Self { overflow }
}
pub fn last_update_clk_in_current_ctx(&self) -> Felt {
self.get_current_overflow_stack()
.last()
.map_or(ZERO, |entry| Felt::from(entry.clk))
}
pub fn num_elements_in_current_ctx(&self) -> usize {
self.get_current_overflow_stack().num_elements()
}
pub fn push(&mut self, value: Felt, clk: RowIndex) {
self.get_current_overflow_stack_mut().push(OverflowStackEntry::new(value, clk));
}
pub fn pop(&mut self) -> Option<Felt> {
self.get_current_overflow_stack_mut()
.pop()
.as_ref()
.map(OverflowStackEntry::value)
}
pub fn start_context(&mut self) {
let _ = self.overflow.push(OverflowStack::new()); }
pub fn restore_context(&mut self) {
let overflow_stack_for_ctx = self.overflow.swap_remove(self.overflow.len() - 1);
assert!(
overflow_stack_for_ctx.is_empty(),
"the overflow stack for the current context should be empty when restoring a context"
);
}
fn get_current_overflow_stack(&self) -> &OverflowStack {
self.overflow
.as_slice()
.last()
.expect("The current context should always have an overflow stack initialized")
}
fn get_current_overflow_stack_mut(&mut self) -> &mut OverflowStack {
let len = self.overflow.len();
&mut self.overflow[RowIndex::from(len - 1)]
}
}
impl Default for OverflowTable {
fn default() -> Self {
Self::new()
}
}