use std::collections::VecDeque;
use crate::constraints::props::PropId;
#[derive(Debug)]
pub struct Agenda {
q: VecDeque<PropId>,
scheduled: Vec<u64>,
}
impl Agenda {
pub fn with_props(ps: impl Iterator<Item = PropId>) -> Self {
let mut agenda = Self::default();
for p in ps {
agenda.schedule(p);
}
agenda
}
#[inline]
pub fn schedule(&mut self, p: PropId) {
if !self.is_scheduled(p) {
self.q.push_back(p);
self.set_scheduled(p, true);
}
}
#[inline]
pub fn pop(&mut self) -> Option<PropId> {
let p = self.q.pop_front()?;
self.set_scheduled(p, false);
Some(p)
}
#[inline]
fn is_scheduled(&self, p: PropId) -> bool {
let idx = p.0;
let word_idx = idx / 64;
let bit_idx = idx % 64;
if word_idx >= self.scheduled.len() {
return false;
}
(self.scheduled[word_idx] & (1u64 << bit_idx)) != 0
}
#[inline]
fn set_scheduled(&mut self, p: PropId, scheduled: bool) {
let idx = p.0;
let word_idx = idx / 64;
let bit_idx = idx % 64;
if word_idx >= self.scheduled.len() {
self.scheduled.resize(word_idx + 1, 0);
}
if scheduled {
self.scheduled[word_idx] |= 1u64 << bit_idx;
} else {
self.scheduled[word_idx] &= !(1u64 << bit_idx);
}
}
}
impl Default for Agenda {
fn default() -> Self {
Self {
q: VecDeque::new(),
scheduled: Vec::with_capacity(1),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_agenda_basic() {
let mut agenda = Agenda::default();
agenda.schedule(PropId(0));
assert!(agenda.is_scheduled(PropId(0)));
agenda.schedule(PropId(0));
assert_eq!(agenda.q.len(), 1);
let p = agenda.pop();
assert_eq!(p, Some(PropId(0)));
assert!(!agenda.is_scheduled(PropId(0)));
assert_eq!(agenda.pop(), None);
}
#[test]
fn test_agenda_multiple_propagators() {
let mut agenda = Agenda::default();
for i in 0..10 {
agenda.schedule(PropId(i));
}
for i in 0..10 {
assert!(agenda.is_scheduled(PropId(i)));
}
for i in 0..10 {
assert_eq!(agenda.pop(), Some(PropId(i)));
}
assert_eq!(agenda.pop(), None);
}
#[test]
fn test_agenda_with_props() {
let props = vec![PropId(5), PropId(10), PropId(15)];
let mut agenda = Agenda::with_props(props.into_iter());
assert_eq!(agenda.pop(), Some(PropId(5)));
assert_eq!(agenda.pop(), Some(PropId(10)));
assert_eq!(agenda.pop(), Some(PropId(15)));
assert_eq!(agenda.pop(), None);
}
#[test]
fn test_agenda_large_ids() {
let mut agenda = Agenda::default();
agenda.schedule(PropId(100));
agenda.schedule(PropId(200));
agenda.schedule(PropId(300));
assert!(agenda.is_scheduled(PropId(100)));
assert!(agenda.is_scheduled(PropId(200)));
assert!(agenda.is_scheduled(PropId(300)));
assert!(agenda.scheduled.len() >= 5);
assert_eq!(agenda.pop(), Some(PropId(100)));
assert_eq!(agenda.pop(), Some(PropId(200)));
assert_eq!(agenda.pop(), Some(PropId(300)));
}
#[test]
fn test_agenda_duplicate_scheduling() {
let mut agenda = Agenda::default();
agenda.schedule(PropId(42));
agenda.schedule(PropId(42)); agenda.schedule(PropId(42));
assert_eq!(agenda.q.len(), 1);
assert_eq!(agenda.pop(), Some(PropId(42)));
assert_eq!(agenda.pop(), None);
}
#[test]
fn test_agenda_interleaved_operations() {
let mut agenda = Agenda::default();
agenda.schedule(PropId(1));
agenda.schedule(PropId(2));
assert_eq!(agenda.pop(), Some(PropId(1)));
agenda.schedule(PropId(3));
assert_eq!(agenda.pop(), Some(PropId(2)));
assert_eq!(agenda.pop(), Some(PropId(3)));
agenda.schedule(PropId(1)); assert_eq!(agenda.pop(), Some(PropId(1)));
}
#[test]
fn test_agenda_bit_boundaries() {
let mut agenda = Agenda::default();
agenda.schedule(PropId(63)); agenda.schedule(PropId(64)); agenda.schedule(PropId(127)); agenda.schedule(PropId(128));
assert!(agenda.is_scheduled(PropId(63)));
assert!(agenda.is_scheduled(PropId(64)));
assert!(agenda.is_scheduled(PropId(127)));
assert!(agenda.is_scheduled(PropId(128)));
assert_eq!(agenda.pop(), Some(PropId(63)));
assert_eq!(agenda.pop(), Some(PropId(64)));
assert_eq!(agenda.pop(), Some(PropId(127)));
assert_eq!(agenda.pop(), Some(PropId(128)));
}
}