use core::{cmp::Ordering::*, fmt::Debug};
use crate::{map::Key, set::iterators::Iter, Segment, SegmentMap, SegmentSet};
impl<T> SegmentSet<T> {
pub fn iter_difference<'a>(&'a self, other: &'a Self) -> Difference<'a, T>
where
T: Ord,
{
if let Some((self_range, other_range)) = self
.map
.bounds()
.map(|s| other.map.bounds().map(|o| (s, o)))
.flatten()
{
if self_range.overlaps(&other_range) {
return Difference(DifferenceInner::Stitch {
self_iter: self.iter(),
prev_self: None,
other_iter: other.iter(),
prev_other: None,
});
}
}
Difference(DifferenceInner::Iterate(self.iter()))
}
pub fn difference<'a>(&'a self, other: &'a Self) -> SegmentSet<&'a T>
where
T: Ord,
{
SegmentSet {
map: SegmentMap {
map: self.iter_difference(other).map(|r| (Key(r), ())).collect(),
store: alloc::vec::Vec::new(),
},
}
}
}
impl<'a, T: Ord + Clone> core::ops::Sub<&'a SegmentSet<T>> for &'a SegmentSet<T> {
type Output = SegmentSet<&'a T>;
fn sub(self, rhs: &'a SegmentSet<T>) -> SegmentSet<&'a T> {
self.difference(rhs)
}
}
impl<T: Ord + Clone> core::ops::SubAssign<&SegmentSet<T>> for SegmentSet<T> {
fn sub_assign(&mut self, rhs: &SegmentSet<T>) {
for range in rhs.iter() {
self.remove(range);
}
}
}
impl<T: Ord + Clone> core::ops::SubAssign<SegmentSet<T>> for SegmentSet<T> {
fn sub_assign(&mut self, rhs: SegmentSet<T>) {
for range in rhs.iter() {
self.remove(range);
}
}
}
pub struct Difference<'a, T: Ord>(DifferenceInner<'a, T>);
#[derive(Debug)]
enum DifferenceInner<'a, T: 'a + Ord> {
Stitch {
self_iter: Iter<'a, T>,
prev_self: Option<Segment<&'a T>>,
other_iter: Iter<'a, T>,
prev_other: Option<Segment<&'a T>>,
},
Iterate(Iter<'a, T>),
}
impl<'a, T: Ord> Iterator for Difference<'a, T> {
type Item = Segment<&'a T>;
fn next(&mut self) -> Option<Segment<&'a T>> {
match &mut self.0 {
DifferenceInner::Iterate(iter) => iter.next().map(|x| x.as_ref()),
DifferenceInner::Stitch {
self_iter,
prev_self,
other_iter,
prev_other,
} => {
let mut range = prev_self
.take()
.or_else(|| self_iter.next().map(|x| x.as_ref()))?;
loop {
if let Some(other) = prev_other
.take()
.or_else(|| other_iter.next().map(|x| x.as_ref()))
{
if range.end.cmp_start(&other.start).is_gt() {
prev_other.insert(other);
return Some(range);
}
if range.start.cmp_end(&other.end).is_gt() {
continue;
}
match (range.start.cmp(&other.start), range.end.cmp(&other.end)) {
(Less, Less) => {
range.end = other.borrow_bound_before().unwrap();
prev_other.insert(other);
return Some(range);
}
(Less, Equal) => {
range.end = other.borrow_bound_before().unwrap();
return Some(range);
}
(Greater | Equal, Less) => {
range = self_iter.next()?.as_ref();
prev_other.insert(other);
continue;
}
(Greater | Equal, Equal) => {
range = self_iter.next()?.as_ref();
continue;
}
(Greater | Equal, Greater) => {
range.start = other.borrow_bound_after().unwrap();
continue;
}
(Less, Greater) => {
prev_self.insert(Segment {
start: other.borrow_bound_after().unwrap(),
end: core::mem::replace(
&mut range.end,
other.borrow_bound_before().unwrap(),
),
});
return Some(range);
}
}
} else {
return Some(range);
}
}
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let (self_len, other_len) = match &self.0 {
DifferenceInner::Stitch {
self_iter,
other_iter,
..
} => (self_iter.len(), other_iter.len()),
DifferenceInner::Iterate(iter) => (iter.len(), 0),
};
(self_len.saturating_sub(other_len), Some(self_len))
}
fn min(mut self) -> Option<Segment<&'a T>> {
self.next()
}
}