use std::iter::Peekable;
pub struct BinaryAijOperator<Item1, Item2, Iter1, Iter2, Out, F>
where
Item1: Copy,
Item2: Copy,
Out: Copy,
F: Fn(Item1, Item2) -> Out,
Iter1: Iterator<Item = ([usize; 2], Item1)>,
Iter2: Iterator<Item = ([usize; 2], Item2)>,
{
iter1: Peekable<Iter1>,
iter2: Peekable<Iter2>,
func: F,
finished: bool,
}
impl<Item1, Item2, Iter1, Iter2, Out, F> BinaryAijOperator<Item1, Item2, Iter1, Iter2, Out, F>
where
Item1: Copy,
Item2: Copy,
Out: Copy,
F: Fn(Item1, Item2) -> Out,
Iter1: Iterator<Item = ([usize; 2], Item1)>,
Iter2: Iterator<Item = ([usize; 2], Item2)>,
{
pub fn new(iter1: Iter1, iter2: Iter2, func: F) -> Self {
Self {
iter1: iter1.peekable(),
iter2: iter2.peekable(),
func,
finished: false,
}
}
}
impl<Item1, Item2, Iter1, Iter2, Out, F> Iterator
for BinaryAijOperator<Item1, Item2, Iter1, Iter2, Out, F>
where
Item1: Copy + Default,
Item2: Copy + Default,
Out: Copy + Default + PartialEq,
F: Fn(Item1, Item2) -> Out,
Iter1: Iterator<Item = ([usize; 2], Item1)>,
Iter2: Iterator<Item = ([usize; 2], Item2)>,
{
type Item = ([usize; 2], Out);
fn next(&mut self) -> Option<Self::Item> {
fn compare(a1: [usize; 2], a2: [usize; 2]) -> std::cmp::Ordering {
if a1[0] < a2[0] {
std::cmp::Ordering::Less
} else if a1[0] > a2[0] {
std::cmp::Ordering::Greater
} else if a1[1] < a2[1] {
std::cmp::Ordering::Less
} else if a1[1] > a2[1] {
std::cmp::Ordering::Greater
} else {
std::cmp::Ordering::Equal
}
}
if self.finished {
return None;
}
let next1 = self.iter1.peek();
let next2 = self.iter2.peek();
let out_candidate = if next1.is_none() && next2.is_none() {
self.iter1.next();
self.iter2.next();
self.finished = true;
None
} else if next1.is_some() && next2.is_none() {
self.iter2.next();
let (index, value) = self.iter1.next().unwrap();
Some((index, (self.func)(value, Item2::default())))
} else if next1.is_none() && next2.is_some() {
self.iter1.next(); let (index, value) = self.iter2.next().unwrap();
Some((index, (self.func)(Item1::default(), value)))
} else {
let (index1, value1) = *next1.unwrap();
let (index2, value2) = *next2.unwrap();
match compare(index1, index2) {
std::cmp::Ordering::Less => {
self.iter1.next(); Some((index1, (self.func)(value1, Item2::default())))
}
std::cmp::Ordering::Greater => {
self.iter2.next(); Some((index2, (self.func)(Item1::default(), value2)))
}
std::cmp::Ordering::Equal => {
self.iter1.next(); self.iter2.next();
Some((index1, (self.func)(value1, value2)))
}
}
};
if let Some((index, out_value)) = out_candidate {
if out_value != Out::default() {
Some((index, out_value))
} else {
self.next()
}
} else {
None
}
}
}