use std::cmp::Ordering;
use std::collections::BinaryHeap;
struct EventHeapItem<G: Clone + Ord, K: Ord, V> {
group: G,
round: usize,
key: K,
value: V,
}
impl<G: Clone + Ord, K: Ord, V> PartialEq<Self> for EventHeapItem<G, K, V> {
fn eq(&self, other: &Self) -> bool {
self.key == other.key
}
}
impl<G: Clone + Ord, K: Ord, V> Eq for EventHeapItem<G, K, V> {}
impl<G: Clone + Ord, K: Ord, V> Ord for EventHeapItem<G, K, V> {
fn cmp(&self, other: &Self) -> Ordering {
self.key.cmp(&other.key).reverse()
}
}
impl<G: Clone + Ord, K: Ord, V> PartialOrd<Self> for EventHeapItem<G, K, V> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
pub struct EventSorter<G: Clone + Ord, K: Ord, V> {
heap: BinaryHeap<EventHeapItem<G, K, V>>,
round: usize,
current_group: Option<G>,
}
impl<G: Clone + Ord, K: Ord, V> EventSorter<G, K, V> {
pub fn new() -> Self {
EventSorter {
heap: BinaryHeap::new(),
round: 0,
current_group: None,
}
}
pub fn has_more(&self) -> bool {
!self.heap.is_empty()
}
pub fn advance_round(&mut self) {
self.round += 1;
self.current_group = None;
}
pub fn begin_group(&mut self, group: G) {
assert!(
Some(&group) >= self.current_group.as_ref(),
"Group keys must be monotonically increasing"
);
self.current_group = Some(group);
}
pub fn pop(&mut self) -> Option<V> {
let event = self.heap.peek()?;
if (event.round + 1, Some(&event.group)) > (self.round, self.current_group.as_ref()) {
return None;
}
self.heap.pop().map(|x| x.value)
}
}
impl<G: Clone + Ord, K: Ord, V> Extend<(K, V)> for EventSorter<G, K, V> {
fn extend<I: IntoIterator<Item = (K, V)>>(&mut self, iter: I) {
self.heap.extend(iter.into_iter().map(|(seq, value)| {
EventHeapItem {
group: self
.current_group
.clone()
.expect("begin_group must be called before insertion"),
round: self.round,
key: seq,
value,
}
}));
}
}