use core::{cmp::Ordering::*, fmt::Debug, iter::FusedIterator};
use crate::{map::Key, set::iterators::Iter, Segment, SegmentMap, SegmentSet};
impl<T> SegmentSet<T> {
pub fn symmetric_difference_iter<'a>(&'a self, other: &'a Self) -> SymmetricDifference<'a, T> {
SymmetricDifference {
iter_a: self.iter(),
prev_a: None,
iter_b: other.iter(),
prev_b: None,
}
}
pub fn symmetric_difference<'a>(&'a self, other: &'a Self) -> SegmentSet<&'a T>
where
T: Ord,
{
SegmentSet {
map: SegmentMap {
map: self
.symmetric_difference_iter(other)
.map(|r| (Key(r), ()))
.collect(),
store: alloc::vec::Vec::new(),
},
}
}
}
impl<'a, T: Ord + Clone> core::ops::BitXor<&'a SegmentSet<T>> for &'a SegmentSet<T> {
type Output = SegmentSet<&'a T>;
fn bitxor(self, rhs: &'a SegmentSet<T>) -> SegmentSet<&'a T> {
self.symmetric_difference(rhs)
}
}
#[derive(Debug, Clone)]
pub struct SymmetricDifference<'a, T> {
iter_a: Iter<'a, T>,
prev_a: Option<Segment<&'a T>>,
iter_b: Iter<'a, T>,
prev_b: Option<Segment<&'a T>>,
}
impl<'a, T: Ord> Iterator for SymmetricDifference<'a, T> {
type Item = Segment<&'a T>;
fn next(&mut self) -> Option<Segment<&'a T>> {
let next_a = self
.prev_a
.take()
.or_else(|| self.iter_a.next().map(|x| x.as_ref()));
let next_b = self
.prev_b
.take()
.or_else(|| self.iter_b.next().map(|x| x.as_ref()));
let mut next_a = match next_a {
Some(a) => a,
None => return next_b,
};
let mut next_b = match next_b {
Some(b) => b,
None => return Some(next_a),
};
loop {
if next_a.end.cmp_start(&next_b.start).is_gt() {
self.prev_b.insert(next_b);
return Some(next_b);
}
if next_a.start.cmp_end(&next_b.end).is_gt() {
self.prev_a.insert(next_a);
return Some(next_a);
}
match (next_a.start.cmp(&next_b.start), next_a.end.cmp(&next_b.end)) {
(Less, Less) => {
next_b.start =
core::mem::replace(&mut next_a.end, next_b.borrow_bound_before().unwrap())
.borrow_after()
.unwrap();
self.prev_b.insert(next_b);
return Some(next_a);
}
(Less, Equal) => {
next_a.end = next_b.borrow_bound_before().unwrap();
return Some(next_a);
}
(Less, Greater) => {
self.prev_a.insert(Segment {
start: next_b.borrow_bound_after().unwrap(),
end: next_a.end,
});
next_a.end = next_b.borrow_bound_before().unwrap();
return Some(next_a);
}
(Equal, Less) => {
next_b.start = next_a.borrow_bound_after().unwrap();
if let Some(a) = self.iter_a.next() {
next_a = a.as_ref();
continue;
} else {
return Some(next_b);
}
}
(Equal, Equal) => {
if let Some(a) = self.iter_a.next().map(|x| x.as_ref()) {
next_a = a;
} else {
return Some(next_b);
}
if let Some(b) = self.iter_b.next().map(|x| x.as_ref()) {
next_b = b;
} else {
return Some(next_a);
}
continue;
}
(Equal, Greater) => {
next_a.start = next_b.borrow_bound_after().unwrap();
if let Some(b) = self.iter_b.next().map(|x| x.as_ref()) {
next_b = b;
} else {
return Some(next_b);
}
continue;
}
(Greater, Less) => {
self.prev_b.insert(Segment {
start: next_a.borrow_bound_after().unwrap(),
end: next_b.end,
});
next_b.end = next_a.borrow_bound_before().unwrap();
return Some(next_b);
}
(Greater, Equal) => {
next_b.end = next_a.borrow_bound_before().unwrap();
return Some(next_b);
}
(Greater, Greater) => {
next_a.start =
core::mem::replace(&mut next_b.end, next_a.borrow_bound_before().unwrap())
.borrow_after()
.unwrap();
self.prev_a.insert(next_a);
return Some(next_b);
}
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(0, Some(self.iter_a.len() + self.iter_b.len()))
}
fn min(mut self) -> Option<Segment<&'a T>> {
self.next()
}
}
impl<T: Ord> FusedIterator for SymmetricDifference<'_, T> {}