use std::collections::BinaryHeap;
pub struct ReverseMergeIterator<T: Ord, I: Iterator<Item = T>> {
streams: Vec<I>,
heap: BinaryHeap<(T, usize)>,
lower_bound: Option<T>,
}
impl<T: Ord, I: Iterator<Item = T>> ReverseMergeIterator<T, I> {
pub fn new<S: IntoIterator<Item = I>>(streams: S) -> Self {
let mut streams: Vec<I> = streams.into_iter().collect();
let mut heap = BinaryHeap::with_capacity(streams.len());
for (i, s) in streams.iter_mut().enumerate() {
if let Some(v) = s.next() {
heap.push((v, i));
}
}
Self {
streams,
heap,
lower_bound: None,
}
}
pub fn seek_for_prev(&mut self, target: &T) {
let mut new_heads: Vec<(T, usize)> = Vec::new();
while let Some((value, _)) = self.heap.peek() {
if value > target {
let (_value, idx) = self.heap.pop().unwrap();
let mut found: Option<T> = None;
for v in self.streams[idx].by_ref() {
if &v <= target {
found = Some(v);
break;
}
}
if let Some(v) = found {
new_heads.push((v, idx));
}
} else {
break;
}
}
for head in new_heads {
self.heap.push(head);
}
}
pub fn set_lower_bound(&mut self, bound: T) {
self.lower_bound = Some(bound);
}
pub fn clear_lower_bound(&mut self) {
self.lower_bound = None;
}
pub fn peek(&self) -> Option<&T> {
let head = self.heap.peek().map(|(value, _)| value)?;
match &self.lower_bound {
Some(lo) if head < lo => None,
_ => Some(head),
}
}
pub fn live_streams(&self) -> usize {
self.heap.len()
}
pub fn num_streams(&self) -> usize {
self.streams.len()
}
}
impl<T: Ord, I: Iterator<Item = T>> Iterator for ReverseMergeIterator<T, I> {
type Item = T;
fn next(&mut self) -> Option<T> {
self.peek()?;
let (value, idx) = self.heap.pop()?;
if let Some(next_value) = self.streams[idx].next() {
self.heap.push((next_value, idx));
}
Some(value)
}
}
#[cfg(test)]
#[path = "reverse_tests.rs"]
mod tests;