use crate::{map::Key, set::iterators::Iter, Segment, SegmentMap, SegmentSet};
impl<T> SegmentSet<T> {
pub fn union_iter<'a>(&'a self, other: &'a Self) -> Union<'a, T> {
Union {
iter_a: self.iter(),
prev_a: None,
iter_b: other.iter(),
prev_b: None,
}
}
pub fn union<'a>(&'a self, other: &'a Self) -> SegmentSet<&'a T>
where
T: Ord,
{
SegmentSet {
map: SegmentMap {
map: self.union_iter(other).map(|r| (Key(r), ())).collect(),
store: alloc::vec::Vec::new(),
},
}
}
}
impl<T: Ord + Clone> core::ops::BitOr<&SegmentSet<T>> for &SegmentSet<T> {
type Output = SegmentSet<T>;
fn bitor(self, rhs: &SegmentSet<T>) -> SegmentSet<T> {
self.union(rhs).cloned()
}
}
impl<T: Ord + Clone> core::ops::Add<&SegmentSet<T>> for &SegmentSet<T> {
type Output = SegmentSet<T>;
fn add(self, rhs: &SegmentSet<T>) -> SegmentSet<T> {
self.union(rhs).cloned()
}
}
pub struct Union<'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 Union<'a, T> {
type Item = Segment<&'a T>;
fn next(&mut self) -> Option<Self::Item> {
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 next_a = match next_a {
Some(a) => a,
None => return next_b,
};
let next_b = match next_b {
Some(b) => b,
None => return Some(next_a),
};
if next_a.end.cmp_start(&next_b.start).is_gt() {
self.prev_b.insert(next_b);
return Some(next_a);
}
if next_a.start.cmp_end(&next_b.end).is_gt() {
self.prev_a.insert(next_a);
return Some(next_b);
}
let mut outer = Segment {
start: core::cmp::min(next_a.start, next_b.start),
end: core::cmp::max(next_a.end, next_b.end),
};
loop {
let next_a_end = if let Some(r) = self
.prev_a
.take()
.or_else(|| self.iter_a.next().map(|r| r.as_ref()))
{
if outer.touches(&r) {
Some(r.end)
} else {
self.prev_a.insert(r);
None
}
} else {
None
};
let next_b_end = if let Some(r) = self
.prev_b
.take()
.or_else(|| self.iter_b.next().map(|r| r.as_ref()))
{
if outer.touches(&r) {
Some(r.end)
} else {
self.prev_b.insert(r);
None
}
} else {
None
};
match (next_a_end, next_b_end) {
(None, None) => return Some(outer),
(Some(end), None) | (None, Some(end)) => outer.end = end,
(Some(a), Some(b)) => outer.end = core::cmp::max(a, b),
}
}
}
}