#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct RasHistory {
pushed: bool,
popped: Option<PoppedEntry>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
struct PoppedEntry {
tos: usize,
entry: Option<u64>,
}
#[derive(Debug)]
pub struct Ras {
stack: Vec<Option<u64>>,
tos: usize,
}
impl Ras {
pub fn new(capacity: usize) -> Self {
Self { stack: vec![None; capacity], tos: 0 }
}
pub fn push(&mut self, addr: u64, history: &mut RasHistory) {
if self.stack.is_empty() {
return;
}
self.tos = self.above(self.tos);
self.stack[self.tos] = Some(addr);
history.pushed = true;
}
pub fn pop(&mut self, history: &mut RasHistory) -> Option<u64> {
let entry = self.top();
if self.stack.is_empty() {
return entry;
}
history.popped = Some(PoppedEntry { tos: self.tos, entry });
self.tos = self.below(self.tos);
entry
}
pub fn top(&self) -> Option<u64> {
self.stack.get(self.tos).copied().flatten()
}
pub fn squash(&mut self, history: RasHistory) {
if history.pushed {
self.tos = self.below(self.tos);
}
if let Some(popped) = history.popped {
self.tos = popped.tos;
self.stack[self.tos] = popped.entry;
}
}
const fn above(&self, index: usize) -> usize {
if index + 1 == self.stack.len() { 0 } else { index + 1 }
}
const fn below(&self, index: usize) -> usize {
if index == 0 { self.stack.len() - 1 } else { index - 1 }
}
}