use std::iter::Peekable;
use std::cmp::Ordering;
#[derive(Clone, Debug)]
pub struct Alternate<A, B> {
a: A,
b: B,
state: ChainState,
}
impl<A, B> Alternate<A, B> {
pub fn new(a: A, b: B) -> Self {
Self {
a,
b,
state: ChainState::BothA,
}
}
}
#[derive(Clone, Debug)]
enum ChainState {
BothA,
BothB,
OnlyA,
OnlyB,
}
impl<A, B> Iterator for Alternate<A, B> where
A: Iterator,
B: Iterator<Item = A::Item>
{
type Item = A::Item;
#[inline]
fn next(&mut self) -> Option<A::Item> {
match self.state {
ChainState::BothA => match self.a.next() {
elt @ Some(..) => {
self.state = ChainState::BothB;
elt
},
None => {
self.state = ChainState::OnlyB;
self.b.next()
}
},
ChainState::BothB => match self.b.next() {
elt @ Some(..) => {
self.state = ChainState::BothA;
elt
},
None => {
self.state = ChainState::OnlyA;
self.a.next()
}
},
ChainState::OnlyA => self.a.next(),
ChainState::OnlyB => self.b.next(),
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let (a_lower, a_upper) = self.a.size_hint();
let (b_lower, b_upper) = self.b.size_hint();
let lower = a_lower.saturating_add(b_lower);
let upper = match (a_upper, b_upper) {
(Some(x), Some(y)) => x.checked_add(y),
_ => None
};
(lower, upper)
}
#[inline]
fn count(self) -> usize {
match self.state {
ChainState::BothA | ChainState::BothB => self.a.count() + self.b.count(),
ChainState::OnlyA => self.a.count(),
ChainState::OnlyB => self.b.count(),
}
}
}
pub struct Merge<L, R, C> where
L: Iterator,
R: Iterator<Item = L::Item>,
C: Fn(&L::Item, &R::Item) -> Ordering,
{
left: Peekable<L>,
right: Peekable<R>,
cmp: C,
}
impl<L, R, C> Merge<L, R, C> where
L: Iterator,
R: Iterator<Item = L::Item>,
C: Fn(&L::Item, &R::Item) -> Ordering,
{
pub fn new(left: L, right: R, cmp: C) -> Self {
Merge {
left: left.peekable(),
right: right.peekable(),
cmp,
}
}
}
impl<L, R, C> Iterator for Merge<L, R, C> where
L: Iterator,
R: Iterator<Item = L::Item>,
C: Fn(&L::Item, &R::Item) -> Ordering,
{
type Item = L::Item;
fn next(&mut self) -> Option<Self::Item> {
let ordering = match (self.left.peek(), self.right.peek()) {
(Some(l), Some(r)) => Some((self.cmp)(l, r)),
(Some(_), None) => Some(Ordering::Less),
(None, Some(_)) => Some(Ordering::Greater),
(None, None) => None,
};
match ordering {
Some(Ordering::Less) => self.left.next(),
Some(Ordering::Greater) => self.right.next(),
Some(Ordering::Equal) => { self.left.next(); self.right.next() },
None => None,
}
}
}