use size_hint;
use Itertools;
use std::cmp::Ordering;
use std::mem::replace;
macro_rules! clone_fields {
($name:ident, $base:expr, $($field:ident),+) => (
$name {
$(
$field : $base . $field .clone()
),*
}
);
}
struct HeadTail<I>
where I: Iterator
{
head: I::Item,
tail: I,
}
impl<I> HeadTail<I>
where I: Iterator
{
fn new(mut it: I) -> Option<HeadTail<I>> {
let head = it.next();
head.map(|h| {
HeadTail {
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
{
fn clone(&self) -> Self {
clone_fields!(HeadTail, self, head, tail)
}
}
impl<I> PartialEq for HeadTail<I>
where I: Iterator,
I::Item: PartialEq
{
fn eq(&self, other: &HeadTail<I>) -> bool {
self.head.eq(&other.head)
}
}
impl<I> Eq for HeadTail<I>
where I: Iterator,
I::Item: Eq
{}
impl<I> PartialOrd for HeadTail<I>
where I: Iterator,
I::Item: PartialOrd
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
other.head.partial_cmp(&self.head)
}
fn lt(&self, other: &Self) -> bool {
other.head.lt(&self.head)
}
fn le(&self, other: &Self) -> bool {
other.head.le(&self.head)
}
fn gt(&self, other: &Self) -> bool {
other.head.gt(&self.head)
}
fn ge(&self, other: &Self) -> bool {
other.head.ge(&self.head)
}
}
impl<I> Ord for HeadTail<I>
where I: Iterator,
I::Item: Ord
{
fn cmp(&self, other: &Self) -> Ordering {
other.head.cmp(&self.head)
}
}
fn heapify<T: Ord>(data: &mut [T]) {
for i in (0..data.len() / 2).rev() {
sift_down(data, i);
}
}
fn sift_down<T: Ord>(heap: &mut [T], index: usize) {
debug_assert!(index <= heap.len());
let mut pos = index;
let mut child = 2 * pos + 1;
while pos < heap.len() && child < heap.len() {
let right = child + 1;
if right < heap.len() && heap[child] < heap[right] {
child = right;
}
if heap[pos] >= heap[child] {
return;
}
heap.swap(pos, child);
pos = child;
child = 2 * pos + 1;
}
}
pub struct KMerge<I>
where I: Iterator
{
heap: Vec<HeadTail<I>>,
}
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: Ord
{
let iter = iterable.into_iter();
let (lower, _) = iter.size_hint();
let mut heap = Vec::with_capacity(lower);
heap.extend(iter.filter_map(|it| HeadTail::new(it.into_iter())));
heapify(&mut heap);
KMerge { heap: heap }
}
impl<I> Clone for KMerge<I>
where I: Iterator + Clone,
I::Item: Clone
{
fn clone(&self) -> KMerge<I> {
clone_fields!(KMerge, self, heap)
}
}
impl<I> Iterator for KMerge<I>
where I: Iterator,
I::Item: Ord
{
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
};
sift_down(&mut self.heap, 0);
Some(result)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.heap.iter()
.map(|i| i.size_hint())
.fold1(size_hint::add)
.unwrap_or((0, Some(0)))
}
}