use std::cmp::Reverse;
use std::collections::BinaryHeap;
use std::collections::VecDeque;
use crate::containers::KeyedVec;
use crate::propagation::Priority;
use crate::propagation::PropagatorId;
use crate::pumpkin_assert_moderate;
#[derive(Debug, Clone)]
pub(crate) struct PropagatorQueue {
queues: Vec<VecDeque<PropagatorId>>,
is_enqueued: KeyedVec<PropagatorId, bool>,
num_enqueued: usize,
present_priorities: BinaryHeap<Reverse<u32>>,
}
impl Default for PropagatorQueue {
fn default() -> Self {
Self::new(5)
}
}
impl PropagatorQueue {
pub(crate) fn new(num_priority_levels: u32) -> PropagatorQueue {
PropagatorQueue {
queues: vec![VecDeque::new(); num_priority_levels as usize],
is_enqueued: KeyedVec::default(),
num_enqueued: 0,
present_priorities: BinaryHeap::new(),
}
}
pub(crate) fn is_empty(&self) -> bool {
self.num_enqueued == 0
}
pub(crate) fn enqueue_propagator(&mut self, propagator_id: PropagatorId, priority: Priority) {
pumpkin_assert_moderate!((priority as usize) < self.queues.len());
if !self.is_propagator_enqueued(propagator_id) {
self.is_enqueued.accomodate(propagator_id, false);
self.is_enqueued[propagator_id] = true;
self.num_enqueued += 1;
if self.queues[priority as usize].is_empty() {
self.present_priorities.push(Reverse(priority as u32));
}
self.queues[priority as usize].push_back(propagator_id);
}
}
pub(crate) fn pop(&mut self) -> Option<PropagatorId> {
if self.present_priorities.is_empty() {
return None;
}
let top_priority = self.present_priorities.peek().unwrap().0 as usize;
pumpkin_assert_moderate!(!self.queues[top_priority].is_empty());
let next_propagator_id = self.queues[top_priority].pop_front();
if let Some(propagator_id) = next_propagator_id {
self.is_enqueued[propagator_id] = false;
if self.queues[top_priority].is_empty() {
let _ = self.present_priorities.pop();
}
}
self.num_enqueued -= 1;
next_propagator_id
}
pub(crate) fn clear(&mut self) {
while !self.present_priorities.is_empty() {
let priority = self.present_priorities.pop().unwrap().0 as usize;
pumpkin_assert_moderate!(!self.queues[priority].is_empty());
self.queues[priority].clear();
}
for is_propagator_enqueued in self.is_enqueued.iter_mut() {
*is_propagator_enqueued = false;
}
self.present_priorities.clear();
self.num_enqueued = 0;
}
pub(crate) fn is_propagator_enqueued(&self, propagator_id: PropagatorId) -> bool {
self.is_enqueued
.get(propagator_id)
.copied()
.unwrap_or_default()
}
}
#[cfg(test)]
mod tests {
use crate::engine::PropagatorQueue;
use crate::propagation::Priority;
use crate::state::PropagatorId;
#[test]
fn test_ordering() {
let mut queue = PropagatorQueue::default();
queue.enqueue_propagator(PropagatorId(1), Priority::High);
queue.enqueue_propagator(PropagatorId(0), Priority::Medium);
queue.enqueue_propagator(PropagatorId(3), Priority::VeryLow);
queue.enqueue_propagator(PropagatorId(4), Priority::Low);
assert_eq!(PropagatorId(1), queue.pop().unwrap());
assert_eq!(PropagatorId(0), queue.pop().unwrap());
assert_eq!(PropagatorId(4), queue.pop().unwrap());
assert_eq!(PropagatorId(3), queue.pop().unwrap());
assert_eq!(None, queue.pop());
}
}