use core::cmp::Ordering;
use std::collections::BinaryHeap;
use std::sync::Arc;
type CompareRecord<Record> = Box<dyn Fn(&Record, &Record) -> Ordering + Send + Sync>;
struct NextRecord<Source, Record>
where
Source: Iterator<Item = Record>,
{
source: Source,
source_index: usize,
current_record: Option<Record>,
compare_record: Arc<CompareRecord<Record>>,
}
impl<Source: Iterator<Item = Record>, Record> Ord for NextRecord<Source, Record> {
fn cmp(&self, other: &Self) -> Ordering {
(self.compare_record)(
self.current_record.as_ref().unwrap(),
other.current_record.as_ref().unwrap(),
)
.reverse()
.then_with(|| self.source_index.cmp(&other.source_index))
}
}
impl<Source: Iterator<Item = Record>, Record> PartialOrd for NextRecord<Source, Record> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<Source: Iterator<Item = Record>, Record> PartialEq for NextRecord<Source, Record> {
fn eq(&self, other: &Self) -> bool {
(self.compare_record)(
self.current_record.as_ref().unwrap(),
other.current_record.as_ref().unwrap(),
) == Ordering::Equal
&& (other.source_index == self.source_index)
}
}
impl<Source: Iterator<Item = Record>, Record> Eq for NextRecord<Source, Record> {}
pub struct Merge<Source, Record>
where
Source: Iterator<Item = Record>,
{
sorter: BinaryHeap<NextRecord<Source, Record>>,
most_recent: Option<NextRecord<Source, Record>>,
}
impl<Source, Record> Merge<Source, Record>
where
Source: Iterator<Item = Record>,
Record: std::fmt::Debug,
{
pub fn new<CompareRecord>(
orig_sources: Vec<(usize, Source)>,
compare_record: CompareRecord,
) -> Self
where
CompareRecord: Fn(&Record, &Record) -> Ordering + 'static + Send + Sync,
{
let compare_record: self::CompareRecord<Record> = Box::new(compare_record);
let compare_record = Arc::new(compare_record);
let mut sorter = BinaryHeap::with_capacity(orig_sources.len());
for (tx_id, mut src) in orig_sources.into_iter() {
if let Some(rec) = src.next() {
sorter.push(NextRecord {
source: src,
source_index: tx_id,
current_record: Some(rec),
compare_record: compare_record.clone(),
});
}
}
Self {
sorter,
most_recent: None,
}
}
fn discard_repetitions(&mut self, current: &Record) {
loop {
{
let next = self.sorter.peek();
if next.is_none() {
break;
}
let next = next.unwrap();
match (next.compare_record)(current, next.current_record.as_ref().unwrap()) {
Ordering::Less => {
break;
} Ordering::Greater => panic!("ordering violation"),
Ordering::Equal => {} }
}
let mut best = self.sorter.pop().unwrap();
best.current_record = None;
let succ_record = best.source.next();
if let Some(succ_record) = succ_record {
best.current_record = Some(succ_record);
self.sorter.push(best);
} else {
}
}
}
}
impl<Source, Record> Iterator for Merge<Source, Record>
where
Source: Iterator<Item = Record>,
Record: std::fmt::Debug,
{
type Item = (usize, Record);
fn next(&mut self) -> Option<Self::Item> {
if let Some(mut most_recent) = self.most_recent.take() {
let source_index = most_recent.source_index;
if let Some(current) = most_recent.source.next() {
if let Some(next) = self.sorter.peek() {
match (most_recent.compare_record)(
¤t,
next.current_record.as_ref().unwrap(),
) {
Ordering::Equal
if most_recent.source_index.cmp(&next.source_index).is_lt() =>
{
}
Ordering::Less => {
self.most_recent = Some(most_recent);
return Some((source_index, current));
} Ordering::Greater => {}
Ordering::Equal => self.discard_repetitions(¤t),
}
} else {
self.most_recent = Some(most_recent);
return Some((source_index, current));
}
most_recent.current_record = Some(current);
self.sorter.push(most_recent);
}
}
let mut best = self.sorter.pop()?;
let tx_id = best.source_index;
let item = best.current_record.take().expect("current record is null");
self.discard_repetitions(&item);
self.most_recent = Some(best);
Some((tx_id, item))
}
}
#[cfg(test)]
mod tests {
use std::rc::Rc;
#[test]
fn merge1() {
let a = [1u32, 2, 3, 4, 5].iter().cloned();
let b = [1, 3, 5, 8, 10].iter().cloned();
let merged = crate::merge::Merge::new(vec![(0, a), (1, b)], |a, b| a.cmp(b));
let merged: Vec<_> = merged.map(|(_, x)| x).collect();
assert_eq!(merged, vec![1u32, 2, 3, 4, 5, 8, 10]);
}
#[test]
fn merge_with_key() {
let a = [1u32, 2, 3, 4, 5].iter().rev().cloned();
let b = [1, 3, 5, 8, 10].iter().rev().cloned();
let merged = crate::merge::Merge::new(vec![(0, a), (1, b)], |a, b| a.cmp(b).reverse());
let mut merged: Vec<_> = merged.map(|(_, x)| x).collect();
merged.reverse();
assert_eq!(merged, vec![1u32, 2, 3, 4, 5, 8, 10]);
}
#[test]
#[should_panic]
fn merge_check_sorting() {
let a = [1u32, 2, 3, 4, 5].iter().cloned();
let b = [1, 3, 5, 8, 10].iter().cloned();
let merged = crate::merge::Merge::new(vec![(0, a), (1, b)], |a, b| a.cmp(b).reverse());
let _: Vec<_> = merged.map(|(_, x)| x).collect();
}
#[test]
fn merge_str() {
let a = ["a", "b"].iter().cloned();
let b = ["a", "c"].iter().cloned();
let mut merged =
crate::merge::Merge::new(vec![(0, a), (1, b)], |a, b| a.cmp(b)).map(|(_, x)| x);
assert_eq!(merged.next().unwrap(), "a");
assert_eq!(merged.next().unwrap(), "b");
assert_eq!(merged.next().unwrap(), "c");
assert_eq!(merged.next(), None);
}
#[test]
fn merge_last_reader() {
let a = [("b", 1), ("c", 1), ("d", 1), ("e", 1)].iter().cloned();
let b = [("c", 2)].iter().cloned();
let mut merged =
crate::merge::Merge::new(vec![(0, a), (1, b)], |a, b| a.0.cmp(b.0)).map(|(_, x)| x);
assert_eq!(merged.next().unwrap(), ("b", 1));
assert_eq!(merged.next().unwrap(), ("c", 2));
assert_eq!(merged.next().unwrap(), ("d", 1));
assert_eq!(merged.next().unwrap(), ("e", 1));
assert_eq!(merged.next(), None);
}
#[test]
fn merge_count_owns() {
let first = Rc::new(0);
let a = vec![first.clone(), Rc::new(1)];
let mut merged =
crate::merge::Merge::new(vec![(0, a.into_iter())], |a, b| a.cmp(b)).map(|(_, x)| x);
assert_eq!(Rc::strong_count(&first), 2);
let m = merged.next().unwrap();
assert_eq!(Rc::strong_count(&m), 2);
eprintln!("{}", m);
assert_eq!(Rc::strong_count(&merged.next().unwrap()), 1);
assert_eq!(Rc::strong_count(&first), 2);
assert_eq!(merged.next(), None);
}
}