use std::marker::PhantomData;
use std::iter::Peekable;
pub trait SetOperation {
fn eval(is_in_a: bool, is_in_b: bool) -> bool;
}
pub struct Union;
impl SetOperation for Union {
fn eval(is_in_a: bool, is_in_b: bool) -> bool {
is_in_a || is_in_b
}
}
pub struct Difference;
impl SetOperation for Difference {
fn eval(is_in_a: bool, is_in_b: bool) -> bool {
is_in_a && !is_in_b
}
}
pub struct SymmetricDifference;
impl SetOperation for SymmetricDifference {
fn eval(is_in_a: bool, is_in_b: bool) -> bool {
is_in_a ^ is_in_b
}
}
pub struct Intersection;
impl SetOperation for Intersection {
fn eval(is_in_a: bool, is_in_b: bool) -> bool {
is_in_a && is_in_b
}
}
pub struct SetOpIter<A, B, Op>
where A: Iterator,
B: Iterator {
a: Peekable<A>,
b: Peekable<B>,
_op: PhantomData<Op>,
}
fn net_set_op<A, B, E, Op>(a: A, b: B) -> SetOpIter<A::IntoIter, B::IntoIter, Op>
where A: IntoIterator<Item=E>,
B: IntoIterator<Item=E>,
E: Eq + Ord,
Op: SetOperation {
SetOpIter {
a: a.into_iter().peekable(),
b: b.into_iter().peekable(),
_op: Default::default(),
}
}
pub fn intersection<A, B, E>(a: A, b: B) -> SetOpIter<A::IntoIter, B::IntoIter, Intersection>
where A: IntoIterator<Item=E>,
B: IntoIterator<Item=E>,
E: Eq + Ord {
net_set_op(a, b)
}
pub fn union<A, B, E>(a: A, b: B) -> SetOpIter<A::IntoIter, B::IntoIter, Union>
where A: IntoIterator<Item=E>,
B: IntoIterator<Item=E>,
E: Eq + Ord {
net_set_op(a, b)
}
pub fn difference<A, B, E>(a: A, b: B) -> SetOpIter<A::IntoIter, B::IntoIter, Difference>
where A: IntoIterator<Item=E>,
B: IntoIterator<Item=E>,
E: Eq + Ord {
net_set_op(a, b)
}
pub fn symmetric_difference<A, B, E>(a: A, b: B) -> SetOpIter<A::IntoIter, B::IntoIter, SymmetricDifference>
where A: IntoIterator<Item=E>,
B: IntoIterator<Item=E>,
E: Eq + Ord {
net_set_op(a, b)
}
impl<A, B, E, Op> Iterator for SetOpIter<A, B, Op>
where A: Iterator<Item=E>,
B: Iterator<Item=E>,
E: Eq + Ord,
Op: SetOperation {
type Item = E;
fn next(&mut self) -> Option<Self::Item> {
loop {
let (a, b) = match (self.a.peek(), self.b.peek()) {
(Some(_), None) => (self.a.next(), None),
(None, Some(_)) => (None, self.b.next()),
(Some(a), Some(b)) => {
if a < b {
(self.a.next(), None)
} else if b < a {
(None, self.b.next())
} else {
debug_assert!(a == b);
(self.a.next(), self.b.next())
}
}
(None, None) => break None,
};
debug_assert!(
if let (Some(a), Some(a_next)) = (&a, self.a.peek()) {
a <= a_next
} else {
true
},
"iterator A is not sorted"
);
debug_assert!(
if let (Some(b), Some(b_next)) = (&b, self.b.peek()) {
b <= b_next
} else {
true
},
"iterator B is not sorted"
);
let output_element = match (a, b) {
(Some(a), None) if Op::eval(true, false) => Some(a),
(None, Some(b)) if Op::eval(false, true) => Some(b),
(Some(a), Some(b)) if Op::eval(true, true) => {
debug_assert!(a == b);
Some(a)
}
(None, None) => unreachable!(),
_ => None
};
if output_element.is_some() {
break output_element;
}
}
}
}
#[test]
fn test_union() {
let a = vec![1, 2, 3];
let b = vec![2, 4];
let union: Vec<_> = union(a, b).collect();
assert_eq!(union, vec![1, 2, 3, 4])
}
#[test]
fn test_difference() {
let a = vec![1, 2, 3];
let b = vec![2, 4];
let diff: Vec<_> = difference(a, b).collect();
assert_eq!(diff, vec![1, 3])
}
#[test]
fn test_symmetric_difference() {
let a = vec![1, 2, 3];
let b = vec![2, 4];
let xor: Vec<_> = symmetric_difference(a, b).collect();
assert_eq!(xor, vec![1, 3, 4])
}
#[test]
fn test_intersection() {
let a = vec![1, 2, 3];
let b = vec![2, 4];
let intersection: Vec<_> = intersection(a, b).collect();
assert_eq!(intersection, vec![2])
}