use crate::literal::Var;
#[allow(unused_imports)]
use crate::prelude::*;
#[derive(Debug, Clone, Default)]
pub struct VmtfBumpStats {
pub total_bumps: u64,
pub queue_size: usize,
pub max_queue_size: usize,
pub flushes: u64,
}
impl VmtfBumpStats {
pub fn display(&self) {
println!("VMTF Bump Queue Statistics:");
println!(" Total bumps: {}", self.total_bumps);
println!(" Current queue size: {}", self.queue_size);
println!(" Max queue size: {}", self.max_queue_size);
println!(" Queue flushes: {}", self.flushes);
if self.total_bumps > 0 {
let avg_queue_size = self.max_queue_size as f64 / self.flushes.max(1) as f64;
println!(" Avg queue size at flush: {:.1}", avg_queue_size);
}
}
}
#[derive(Debug)]
pub struct VmtfBumpQueue {
queue: VecDeque<Var>,
in_queue: Vec<bool>,
max_size: usize,
conflicts_before_flush: u64,
conflict_count: u64,
stats: VmtfBumpStats,
}
impl Default for VmtfBumpQueue {
fn default() -> Self {
Self::new()
}
}
impl VmtfBumpQueue {
#[must_use]
pub fn new() -> Self {
Self {
queue: VecDeque::new(),
in_queue: Vec::new(),
max_size: 100,
conflicts_before_flush: 10000,
conflict_count: 0,
stats: VmtfBumpStats::default(),
}
}
#[must_use]
pub fn with_config(max_size: usize, conflicts_before_flush: u64) -> Self {
Self {
queue: VecDeque::new(),
in_queue: Vec::new(),
max_size,
conflicts_before_flush,
conflict_count: 0,
stats: VmtfBumpStats::default(),
}
}
pub fn resize(&mut self, num_vars: usize) {
self.in_queue.resize(num_vars, false);
}
pub fn bump(&mut self, var: Var) {
let var_idx = var.index();
if var_idx >= self.in_queue.len() {
self.in_queue.resize(var_idx + 1, false);
}
if self.in_queue[var_idx] {
return;
}
self.queue.push_back(var);
self.in_queue[var_idx] = true;
self.stats.total_bumps += 1;
self.stats.queue_size = self.queue.len();
self.stats.max_queue_size = self.stats.max_queue_size.max(self.queue.len());
while self.queue.len() > self.max_size {
if let Some(old_var) = self.queue.pop_front() {
self.in_queue[old_var.index()] = false;
}
}
self.stats.queue_size = self.queue.len();
}
pub fn pop(&mut self) -> Option<Var> {
if let Some(var) = self.queue.pop_back() {
self.in_queue[var.index()] = false;
self.stats.queue_size = self.queue.len();
Some(var)
} else {
None
}
}
#[must_use]
pub fn peek(&self) -> Option<Var> {
self.queue.back().copied()
}
#[must_use]
pub fn contains(&self, var: Var) -> bool {
let idx = var.index();
idx < self.in_queue.len() && self.in_queue[idx]
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.queue.is_empty()
}
#[must_use]
pub fn len(&self) -> usize {
self.queue.len()
}
pub fn on_conflict(&mut self) {
self.conflict_count += 1;
if self.conflict_count >= self.conflicts_before_flush {
self.flush();
self.conflict_count = 0;
}
}
pub fn flush(&mut self) {
for var in &self.queue {
self.in_queue[var.index()] = false;
}
self.queue.clear();
self.stats.flushes += 1;
self.stats.queue_size = 0;
}
#[must_use]
pub fn stats(&self) -> &VmtfBumpStats {
&self.stats
}
pub fn clear(&mut self) {
self.queue.clear();
self.in_queue.clear();
self.conflict_count = 0;
self.stats = VmtfBumpStats::default();
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_vmtf_bump_queue_creation() {
let queue = VmtfBumpQueue::new();
assert!(queue.is_empty());
assert_eq!(queue.len(), 0);
}
#[test]
fn test_bump_and_pop() {
let mut queue = VmtfBumpQueue::new();
queue.resize(10);
queue.bump(Var::new(0));
queue.bump(Var::new(1));
queue.bump(Var::new(2));
assert_eq!(queue.len(), 3);
assert_eq!(queue.pop(), Some(Var::new(2))); assert_eq!(queue.pop(), Some(Var::new(1)));
assert_eq!(queue.pop(), Some(Var::new(0)));
assert!(queue.is_empty());
}
#[test]
fn test_duplicate_bump() {
let mut queue = VmtfBumpQueue::new();
queue.resize(10);
queue.bump(Var::new(0));
queue.bump(Var::new(0)); queue.bump(Var::new(0));
assert_eq!(queue.len(), 1); }
#[test]
fn test_max_size_limit() {
let mut queue = VmtfBumpQueue::with_config(3, 10000);
queue.resize(10);
for i in 0..10 {
queue.bump(Var::new(i));
}
assert_eq!(queue.len(), 3);
assert_eq!(queue.pop(), Some(Var::new(9)));
assert_eq!(queue.pop(), Some(Var::new(8)));
assert_eq!(queue.pop(), Some(Var::new(7)));
}
#[test]
fn test_contains() {
let mut queue = VmtfBumpQueue::new();
queue.resize(10);
queue.bump(Var::new(0));
queue.bump(Var::new(2));
assert!(queue.contains(Var::new(0)));
assert!(!queue.contains(Var::new(1)));
assert!(queue.contains(Var::new(2)));
}
#[test]
fn test_peek() {
let mut queue = VmtfBumpQueue::new();
queue.resize(10);
queue.bump(Var::new(0));
queue.bump(Var::new(1));
assert_eq!(queue.peek(), Some(Var::new(1)));
assert_eq!(queue.len(), 2);
queue.pop();
assert_eq!(queue.peek(), Some(Var::new(0)));
}
#[test]
fn test_auto_flush() {
let mut queue = VmtfBumpQueue::with_config(100, 5);
queue.resize(10);
queue.bump(Var::new(0));
queue.bump(Var::new(1));
for _ in 0..5 {
queue.on_conflict();
}
assert!(queue.is_empty());
assert_eq!(queue.stats().flushes, 1);
}
#[test]
fn test_manual_flush() {
let mut queue = VmtfBumpQueue::new();
queue.resize(10);
queue.bump(Var::new(0));
queue.bump(Var::new(1));
queue.bump(Var::new(2));
queue.flush();
assert!(queue.is_empty());
assert!(!queue.contains(Var::new(0)));
assert!(!queue.contains(Var::new(1)));
assert!(!queue.contains(Var::new(2)));
}
#[test]
fn test_stats_tracking() {
let mut queue = VmtfBumpQueue::new();
queue.resize(10);
queue.bump(Var::new(0));
queue.bump(Var::new(1));
queue.bump(Var::new(0));
let stats = queue.stats();
assert_eq!(stats.total_bumps, 2); assert_eq!(stats.queue_size, 2);
}
#[test]
fn test_clear() {
let mut queue = VmtfBumpQueue::new();
queue.resize(10);
queue.bump(Var::new(0));
queue.on_conflict();
queue.clear();
assert!(queue.is_empty());
assert_eq!(queue.stats().total_bumps, 0);
}
#[test]
fn test_resize() {
let mut queue = VmtfBumpQueue::new();
queue.resize(5);
queue.bump(Var::new(4));
queue.resize(10);
queue.bump(Var::new(9));
assert_eq!(queue.len(), 2);
}
}