use crate::size_hint;
use crate::Itertools;
use alloc::vec::Vec;
use std::fmt;
use std::iter::FusedIterator;
use std::mem::replace;
#[derive(Debug)]
struct HeadTail<I>
where
I: Iterator,
{
head: I::Item,
tail: I,
}
impl<I> HeadTail<I>
where
I: Iterator,
{
fn new(mut it: I) -> Option<Self> {
let head = it.next();
head.map(|h| Self { head: h, tail: it })
}
fn next(&mut self) -> Option<I::Item> {
if let Some(next) = self.tail.next() {
Some(replace(&mut self.head, next))
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
size_hint::add_scalar(self.tail.size_hint(), 1)
}
}
impl<I> Clone for HeadTail<I>
where
I: Iterator + Clone,
I::Item: Clone,
{
clone_fields!(head, tail);
}
fn heapify<T, S>(data: &mut [T], mut less_than: S)
where
S: FnMut(&T, &T) -> bool,
{
for i in (0..data.len() / 2).rev() {
sift_down(data, i, &mut less_than);
}
}
fn sift_down<T, S>(heap: &mut [T], index: usize, mut less_than: S)
where
S: FnMut(&T, &T) -> bool,
{
debug_assert!(index <= heap.len());
let mut pos = index;
let mut child = 2 * pos + 1;
while child + 1 < heap.len() {
child += less_than(&heap[child + 1], &heap[child]) as usize;
if !less_than(&heap[child], &heap[pos]) {
return;
}
heap.swap(pos, child);
pos = child;
child = 2 * pos + 1;
}
if child + 1 == heap.len() && less_than(&heap[child], &heap[pos]) {
heap.swap(pos, child);
}
}
pub type KMerge<I> = KMergeBy<I, KMergeByLt>;
pub trait KMergePredicate<T> {
fn kmerge_pred(&mut self, a: &T, b: &T) -> bool;
}
#[derive(Clone, Debug)]
pub struct KMergeByLt;
impl<T: PartialOrd> KMergePredicate<T> for KMergeByLt {
fn kmerge_pred(&mut self, a: &T, b: &T) -> bool {
a < b
}
}
impl<T, F: FnMut(&T, &T) -> bool> KMergePredicate<T> for F {
fn kmerge_pred(&mut self, a: &T, b: &T) -> bool {
self(a, b)
}
}
pub fn kmerge<I>(iterable: I) -> KMerge<<I::Item as IntoIterator>::IntoIter>
where
I: IntoIterator,
I::Item: IntoIterator,
<<I as IntoIterator>::Item as IntoIterator>::Item: PartialOrd,
{
kmerge_by(iterable, KMergeByLt)
}
#[must_use = "this iterator adaptor is not lazy but does nearly nothing unless consumed"]
pub struct KMergeBy<I, F>
where
I: Iterator,
{
heap: Vec<HeadTail<I>>,
less_than: F,
}
impl<I, F> fmt::Debug for KMergeBy<I, F>
where
I: Iterator + fmt::Debug,
I::Item: fmt::Debug,
{
debug_fmt_fields!(KMergeBy, heap);
}
pub fn kmerge_by<I, F>(
iterable: I,
mut less_than: F,
) -> KMergeBy<<I::Item as IntoIterator>::IntoIter, F>
where
I: IntoIterator,
I::Item: IntoIterator,
F: KMergePredicate<<<I as IntoIterator>::Item as IntoIterator>::Item>,
{
let iter = iterable.into_iter();
let (lower, _) = iter.size_hint();
let mut heap: Vec<_> = Vec::with_capacity(lower);
heap.extend(iter.filter_map(|it| HeadTail::new(it.into_iter())));
heapify(&mut heap, |a, b| less_than.kmerge_pred(&a.head, &b.head));
KMergeBy { heap, less_than }
}
impl<I, F> Clone for KMergeBy<I, F>
where
I: Iterator + Clone,
I::Item: Clone,
F: Clone,
{
clone_fields!(heap, less_than);
}
impl<I, F> Iterator for KMergeBy<I, F>
where
I: Iterator,
F: KMergePredicate<I::Item>,
{
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
if self.heap.is_empty() {
return None;
}
let result = if let Some(next) = self.heap[0].next() {
next
} else {
self.heap.swap_remove(0).head
};
let less_than = &mut self.less_than;
sift_down(&mut self.heap, 0, |a, b| {
less_than.kmerge_pred(&a.head, &b.head)
});
Some(result)
}
fn size_hint(&self) -> (usize, Option<usize>) {
#[allow(deprecated)] self.heap
.iter()
.map(|i| i.size_hint())
.fold1(size_hint::add)
.unwrap_or((0, Some(0)))
}
}
impl<I, F> FusedIterator for KMergeBy<I, F>
where
I: Iterator,
F: KMergePredicate<I::Item>,
{
}