use std::clone::Clone;
use std::cmp::Ordering;
use std::collections::BinaryHeap;
use std::collections::HashSet;
use std::fmt::Debug;
use std::hash::Hash;
use std::iter::FromIterator;
const TRACE: bool = false;
#[derive(Debug)]
struct Element<K, V>
where K: Ord + Hash + Clone + Debug,
V: Ord + Debug,
{
key: K,
value: V,
}
impl<K, V> Ord for Element<K, V>
where K: Ord + Hash + Clone + Debug,
V: Ord + Debug,
{
fn cmp(&self, other: &Self) -> Ordering {
self.value.cmp(&other.value)
.then(self.key.cmp(&other.key).reverse())
}
}
impl<K, V> PartialOrd for Element<K, V>
where K: Ord + Hash + Clone + Debug,
V: Ord + Debug,
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<K, V> PartialEq for Element<K, V>
where K: Ord + Hash + Clone + Debug,
V: Ord + Debug,
{
fn eq(&self, other: &Self) -> bool {
self.cmp(&other) == Ordering::Equal
}
}
impl<K, V> Eq for Element<K, V>
where K: Ord + Hash + Clone + Debug,
V: Ord + Debug,
{
}
pub(super) struct PriorityQueue<K, V>
where K: Ord + Hash + Clone + Debug,
V: Ord + Debug,
{
threshold: usize,
bh: BinaryHeap<Element<K, V>>,
pending: Vec<Element<K, V>>,
have_keys: Option<HashSet<K>>,
is_tidy: bool,
}
const THRESHOLD: usize = 16;
impl<K, V> PriorityQueue<K, V>
where K: Ord + Hash + Clone + Debug,
V: Ord + Debug,
{
pub fn new() -> Self {
Self::with_threshold(THRESHOLD)
}
pub fn with_threshold(threshold: usize) -> Self {
Self {
threshold,
bh: BinaryHeap::new(),
pending: Vec::with_capacity(threshold),
have_keys: Some(HashSet::new()),
is_tidy: true,
}
}
fn tidy(&mut self) {
tracer!(TRACE, "PriorityQueue::tidy");
if self.is_tidy {
assert!(self.bh.is_empty()
|| self.pending.len() == 0);
assert!(self.have_keys.is_some());
self.pending[..].windows(2).for_each(|v| {
assert!(v[0] <= v[1]);
});
return;
}
t!("pre: bh: {} elements; pending:\n{}",
self.bh.iter().count(),
self.pending.iter().enumerate().map(|(i, e)| {
format!(" {}. {:?}: {:?}", i, e.key, e.value)
})
.collect::<Vec<_>>()
.join("\n"));
if self.have_keys.is_some()
&& (! self.bh.is_empty()
|| self.pending.len() > self.threshold)
{
t!(" No duplicates, merging pending into bh");
self.bh.extend(self.pending.drain(..));
self.is_tidy = true;
return;
}
if self.have_keys.is_none() {
t!(" Have duplicates (moving bh to pending).");
if ! self.bh.is_empty() {
let bh = std::mem::replace(&mut self.bh, BinaryHeap::new());
self.pending.append(&mut bh.into_sorted_vec());
}
}
let mut keys: Vec<(&K, usize)>
= self.pending.iter().enumerate().map(|(i, e)| {
(&e.key, i)
})
.collect();
keys.sort_by_key(|a| a.0);
keys.dedup_by(|a, b| {
if a.0 == b.0 {
if self.pending[a.1].value > self.pending[b.1].value {
b.1 = a.1
}
true
} else {
false
}
});
if keys.len() != self.pending.len() {
let mut retain = vec![ false; self.pending.len() ];
for (_, i) in keys.into_iter() {
retain[i] = true;
}
let mut i = 0;
self.pending.retain(|_| (retain[i], i += 1).0);
}
self.pending.sort_by(|a, b| {
a.value.cmp(&b.value)
.then(a.key.cmp(&b.key).reverse())
});
self.have_keys
= Some(HashSet::from_iter(
self.pending.iter().map(|e| e.key.clone())));
self.is_tidy = true;
t!("pending (post):\n{}",
self.pending.iter().enumerate().map(|(i, e)| {
format!(" {}. {:?}: {:?}", i, e.key, e.value)
})
.collect::<Vec<_>>()
.join("\n"));
}
pub fn push(&mut self, key: K, value: V) {
tracer!(TRACE, "PriorityQueue::push");
t!("<{:?}, {:?}>", key, value);
if ! self.bh.is_empty() || self.pending.len() > 0 {
self.is_tidy = false;
if let Some(ref mut have_keys) = self.have_keys {
if have_keys.replace(key.clone()).is_some() {
t!("DUP!");
self.have_keys = None;
}
}
} else {
assert!(self.have_keys.as_ref().expect("some").is_empty());
self.is_tidy = true;
self.have_keys
= Some(HashSet::from_iter(std::iter::once(key.clone())));
}
self.pending.push(Element { key, value });
}
pub fn pop(&mut self) -> Option<(K, V)> {
tracer!(TRACE, "PriorityQueue::pop");
self.tidy();
if let Some((key, value)) = self.pending.pop()
.or_else(|| self.bh.pop())
.map(|e| (e.key, e.value))
{
t!(" => <{:?}, {:?}>", key, value);
if let Some(ref mut have_keys) = self.have_keys {
let was_present = have_keys.remove(&key);
assert!(was_present);
} else if self.bh.is_empty()
&& self.pending.len() == 1
{
self.have_keys = Some(HashSet::new());
}
Some((key, value))
} else {
t!(" => None");
None
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use quickcheck::quickcheck;
const THRESHOLDS: &[usize] = &[ 1, 4, 16, 32 ];
#[test]
fn simple() {
for &t in THRESHOLDS.iter() {
let mut pq: PriorityQueue<isize, isize>
= PriorityQueue::with_threshold(t);
pq.push(0, 0);
pq.push(1, 1);
pq.push(2, 2);
pq.push(3, 3);
pq.push(4, 4);
pq.push(5, 5);
assert_eq!(pq.pop(), Some((5, 5)));
assert_eq!(pq.pop(), Some((4, 4)));
assert_eq!(pq.pop(), Some((3, 3)));
assert_eq!(pq.pop(), Some((2, 2)));
assert_eq!(pq.pop(), Some((1, 1)));
assert_eq!(pq.pop(), Some((0, 0)));
assert_eq!(pq.pop(), None);
assert_eq!(pq.pop(), None);
let mut pq: PriorityQueue<isize, isize>
= PriorityQueue::with_threshold(t);
pq.push(0, 0);
pq.push(1, -1);
pq.push(2, -2);
pq.push(3, -3);
pq.push(4, -4);
pq.push(5, -5);
assert_eq!(pq.pop(), Some((0, 0)));
assert_eq!(pq.pop(), Some((1, -1)));
assert_eq!(pq.pop(), Some((2, -2)));
assert_eq!(pq.pop(), Some((3, -3)));
assert_eq!(pq.pop(), Some((4, -4)));
assert_eq!(pq.pop(), Some((5, -5)));
assert_eq!(pq.pop(), None);
assert_eq!(pq.pop(), None);
let mut pq: PriorityQueue<isize, isize>
= PriorityQueue::with_threshold(t);
pq.push(0, 0);
pq.push(1, 1);
pq.push(5, 5);
pq.push(2, 2);
pq.push(4, 4);
pq.push(3, 3);
assert_eq!(pq.pop(), Some((5, 5)));
assert_eq!(pq.pop(), Some((4, 4)));
assert_eq!(pq.pop(), Some((3, 3)));
assert_eq!(pq.pop(), Some((2, 2)));
assert_eq!(pq.pop(), Some((1, 1)));
assert_eq!(pq.pop(), Some((0, 0)));
assert_eq!(pq.pop(), None);
assert_eq!(pq.pop(), None);
let mut pq: PriorityQueue<isize, isize>
= PriorityQueue::with_threshold(t);
assert_eq!(pq.pop(), None);
pq.push(0, 0);
pq.push(0, 0);
assert_eq!(pq.pop(), Some((0, 0)));
assert_eq!(pq.pop(), None);
let mut pq: PriorityQueue<isize, isize>
= PriorityQueue::with_threshold(t);
assert_eq!(pq.pop(), None);
pq.push(0, 0);
pq.push(0, 0);
assert_eq!(pq.pop(), Some((0, 0)));
pq.push(0, 0);
assert_eq!(pq.pop(), Some((0, 0)));
assert_eq!(pq.pop(), None);
}
}
#[test]
fn duplicates() {
let mut pq: PriorityQueue<isize, isize> = PriorityQueue::new();
for i in 0..20 {
pq.push(i, 0);
}
for i in 0..20 {
pq.push(i, i);
}
for i in 0..20 {
pq.push(i, 0);
}
for i in (0..20).rev() {
assert_eq!(pq.pop(), Some((i, i)));
}
assert_eq!(pq.pop(), None);
assert_eq!(pq.pop(), None);
}
#[test]
fn push_pop() {
let mut pq: PriorityQueue<isize, isize> = PriorityQueue::new();
for i in 0..10 {
pq.push(i, 0);
}
for i in (0..10).rev() {
pq.push(i, i);
assert_eq!(pq.pop(), Some((i, i)));
}
assert_eq!(pq.pop(), None);
assert_eq!(pq.pop(), None);
}
fn pq(e: Vec<(u8, u8)>, threshold: usize) -> bool {
tracer!(TRACE, "pq");
t!("\n\nGot {} elements; threshold: {}", e.len(), threshold);
t!("elements: {:?}", e);
let mut expected = e.clone();
expected.sort_by(|a, b| {
a.0.cmp(&b.0)
});
expected.dedup_by(|a, b| {
if a.0 == b.0 {
if a.1 > b.1 {
b.1 = a.1;
}
true
} else {
false
}
});
expected.sort_by(|a, b| {
a.1.cmp(&b.1).reverse()
.then(a.0.cmp(&b.0))
});
let mut pq: PriorityQueue<u8, u8>
= PriorityQueue::with_threshold(threshold);
let mut popped = e.clone();
for _i in 0..5 {
let topush = popped;
popped = Vec::new();
for (j, (k, v)) in topush.iter().enumerate() {
pq.push(*k, *v);
if j % 3 == 1 || j % 7 == 1 {
let (k, v) = pq.pop().unwrap();
assert!(e.contains(&(k, v)));
popped.push((k, v));
}
}
}
for (k, v) in popped.into_iter() {
pq.push(k, v);
}
let mut got = Vec::new();
while let Some((k, v)) = pq.pop() {
got.push((k, v));
}
t!(" e: {:?}", e);
t!("expected: {:?}", expected);
t!(" got: {:?}", got);
if got == expected {
true
} else {
t!("BAD");
false
}
}
quickcheck! {
fn pq1(e: Vec<(u8, u8)>) -> bool {
pq(e, 1)
}
}
quickcheck! {
fn pq4(e: Vec<(u8, u8)>) -> bool {
pq(e, 4)
}
}
quickcheck! {
fn pq16(e: Vec<(u8, u8)>) -> bool {
pq(e, 16)
}
}
quickcheck! {
fn pq64(e: Vec<(u8, u8)>) -> bool {
pq(e, 64)
}
}
#[test]
fn extra() {
pq([(75, 0), (75, 0)].to_vec(), 1);
}
}