use core::convert::Into;
use core::ops::{Sub, SubAssign};
use crate::{Arrangement, Domain, GenericRange, Ranges};
impl<T: Domain> Ranges<T> {
#[allow(clippy::too_many_lines, clippy::expect_used)]
#[must_use]
pub fn difference<R>(self, other: R) -> Self
where
R: Into<Self>,
{
if self.is_empty() {
return self;
}
let other_ranges = other.into();
if other_ranges.is_empty() {
return self;
}
let mut result = Self::new();
let mut lhs_iter = self.ranges.into_iter();
let mut rhs_iter = other_ranges.ranges.into_iter();
let mut lhs_range = lhs_iter.next();
let mut rhs_range = rhs_iter.next();
while let Some(ref inc) = lhs_range {
let arrangement = if let Some(ref exc) = rhs_range {
inc.arrangement(exc)
} else {
#[allow(clippy::integer_arithmetic)]
result.ranges.reserve(lhs_iter.len() + 1);
result
.ranges
.push(lhs_range.expect("lhs_range can't be None, as we're in a 'let Some' using it"));
for lhs_range in lhs_iter {
result.ranges.push(lhs_range);
}
return result;
};
match arrangement {
Arrangement::Disjoint { self_less: true } | Arrangement::Touching { self_less: true } => {
result.ranges.push(
lhs_range
.expect("the arrangement has been calculated and we didn't end up in Arrangement::Empty"),
);
lhs_range = lhs_iter.next();
}
Arrangement::Disjoint { self_less: false } | Arrangement::Touching { self_less: false } => {
rhs_range = rhs_iter.next();
}
Arrangement::Starting { self_shorter: true, .. }
| Arrangement::Ending { self_shorter: true, .. }
| Arrangement::Containing { self_shorter: true } => {
lhs_range = lhs_iter.next();
}
Arrangement::Equal => {
lhs_range = lhs_iter.next();
rhs_range = rhs_iter.next();
}
Arrangement::Overlapping { self_less: true, .. } => {
let lhs = lhs_range
.take()
.expect("the arrangement has been calculated and we didn't end up in Arrangement::Empty");
let rhs = rhs_range
.take()
.expect("the arrangement has been calculated and we didn't end up in Arrangement::Empty");
lhs_range = lhs_iter.next();
result.ranges.push(GenericRange {
start: lhs.start,
end: GenericRange::invert_border(rhs.start),
});
rhs_range = Some(GenericRange {
start: GenericRange::invert_border(lhs.end),
end: rhs.end,
});
}
Arrangement::Ending {
self_shorter: false, ..
} => {
let lhs = lhs_range
.take()
.expect("the arrangement has been calculated and we didn't end up in Arrangement::Empty");
let rhs = rhs_range
.take()
.expect("the arrangement has been calculated and we didn't end up in Arrangement::Empty");
lhs_range = lhs_iter.next();
rhs_range = rhs_iter.next();
result.ranges.push(GenericRange {
start: lhs.start,
end: GenericRange::invert_border(rhs.start),
});
}
Arrangement::Overlapping { self_less: false, .. }
| Arrangement::Starting {
self_shorter: false, ..
} => {
let rhs = rhs_range
.take()
.expect("the arrangement has been calculated and we didn't end up in Arrangement::Empty");
rhs_range = rhs_iter.next();
if let Some(ref mut lhs) = lhs_range {
lhs.start = GenericRange::invert_border(rhs.end);
}
}
Arrangement::Containing {
self_shorter: false, ..
} => {
let lhs = lhs_range
.take()
.expect("the arrangement has been calculated and we didn't end up in Arrangement::Empty");
let rhs = rhs_range
.take()
.expect("the arrangement has been calculated and we didn't end up in Arrangement::Empty");
rhs_range = rhs_iter.next();
result.ranges.push(GenericRange {
start: lhs.start,
end: GenericRange::invert_border(rhs.start),
});
lhs_range = Some(GenericRange {
start: GenericRange::invert_border(rhs.end),
end: lhs.end,
});
}
Arrangement::Empty { .. } => unreachable!("internal guarantee broken: empty range in set"),
}
}
result
}
}
impl<T: Domain> Sub<Ranges<T>> for Ranges<T> {
type Output = Self;
#[must_use]
fn sub(self, rhs: Self) -> Self::Output {
self.difference(rhs)
}
}
impl<T: Domain> SubAssign<Ranges<T>> for Ranges<T> {
fn sub_assign(&mut self, rhs: Self) {
let lhs = core::mem::replace(self, Self::new());
let result = lhs.difference(rhs);
*self = result;
}
}
#[cfg(test)]
mod tests {
use alloc::vec;
use core::cmp::Ordering;
use core::convert::From;
use core::ops::RangeBounds;
use proptest::prelude::*;
use crate::{GenericRange, Ranges};
#[test]
fn empty() {
let ranges1 = Ranges::from(0..10);
let ranges2 = Ranges::new();
assert_eq!(ranges1.difference(ranges2), Ranges::from(0..10));
let ranges1 = Ranges::from(0..10);
let ranges2 = Ranges::new();
assert_eq!(ranges2.difference(ranges1), Ranges::new())
}
#[test]
fn equal() {
let ranges1 = Ranges::from(0..10);
let ranges2 = Ranges::from(0..10);
assert_eq!(ranges1.difference(ranges2), Ranges::new());
}
#[test]
fn disjoint() {
let ranges1 = Ranges::from(0..3);
let ranges2 = Ranges::from(5..8);
assert_eq!(ranges1.difference(ranges2), Ranges::from(0..3));
let ranges1 = Ranges::from(0..3);
let ranges2 = Ranges::from(5..8);
assert_eq!(ranges2.difference(ranges1), Ranges::from(5..8));
}
#[test]
fn touching() {
let ranges1 = Ranges::from(0..3);
let ranges2 = Ranges::from(3..8);
assert_eq!(ranges1.difference(ranges2), Ranges::from(0..3));
let ranges1 = Ranges::from(0..3);
let ranges2 = Ranges::from(3..8);
assert_eq!(ranges2.difference(ranges1), Ranges::from(3..8));
}
#[test]
fn overlapping() {
let ranges1 = Ranges::from(0..5);
let ranges2 = Ranges::from(3..8);
assert_eq!(ranges1.difference(ranges2), Ranges::from(0..3));
let ranges1 = Ranges::from(0..5);
let ranges2 = Ranges::from(3..8);
assert_eq!(ranges2.difference(ranges1), Ranges::from(5..8));
}
#[test]
fn containing() {
let ranges1 = Ranges::from(0..10);
let ranges2 = Ranges::from(3..8);
assert_eq!(ranges1.difference(ranges2).ranges, vec![(0..3).into(), (8..10).into()]);
let ranges1 = Ranges::from(0..10);
let ranges2 = Ranges::from(3..8);
assert_eq!(ranges2.difference(ranges1), Ranges::new());
}
#[test]
fn starting() {
let ranges1 = Ranges::from(0..10);
let ranges2 = Ranges::from(0..8);
assert_eq!(ranges1.difference(ranges2), Ranges::from(8..10));
let ranges1 = Ranges::from(0..10);
let ranges2 = Ranges::from(0..8);
assert_eq!(ranges2.difference(ranges1), Ranges::new());
}
#[test]
fn ending() {
let ranges1 = Ranges::from(0..10);
let ranges2 = Ranges::from(3..10);
assert_eq!(ranges1.difference(ranges2), Ranges::from(0..3));
let ranges1 = Ranges::from(0..10);
let ranges2 = Ranges::from(3..10);
assert_eq!(ranges2.difference(ranges1), Ranges::new());
}
#[test]
fn multiple_lhs() {
let ranges1 = Ranges::from(vec![GenericRange::from(0..5), (6..9).into()]);
let ranges2 = Ranges::from(3..8);
assert_eq!(ranges1.difference(ranges2).ranges, vec![(0..3).into(), (8..9).into()]);
}
#[test]
fn multiple_rhs() {
let ranges1 = Ranges::from(vec![GenericRange::from(0..5), (6..9).into()]);
let ranges2 = Ranges::from(3..8);
assert_eq!(ranges2.difference(ranges1).ranges, vec![(5..6).into()]);
}
#[test]
fn leftover_lhs() {
let ranges1 = Ranges::from(vec![GenericRange::from(0..5), (6..9).into(), (15..20).into()]);
let ranges2 = Ranges::from(3..8);
assert_eq!(
ranges1.difference(ranges2).ranges,
vec![(0..3).into(), (8..9).into(), (15..20).into()]
);
}
#[test]
fn leftover_rhs() {
let ranges1 = Ranges::from(vec![GenericRange::from(0..5), (6..9).into(), (15..20).into()]);
let ranges2 = Ranges::from(3..8);
assert_eq!(ranges2.difference(ranges1).ranges, vec![(5..6).into()]);
}
proptest! {
#[ignore]
#[test]
fn sorted_and_disjoint(ranges1 in any::<Ranges<u8>>(), ranges2 in any::<Ranges<u8>>()) {
let result = ranges1.difference(ranges2);
let sorted_and_disjoint = result.as_slice().windows(2).all(|slice| match slice {
[left, right] => {
GenericRange::cmp_start_start(left.start_bound(), right.start_bound()) == Ordering::Less
&& GenericRange::cmp_end_start(left.end_bound(), right.start_bound()) == Ordering::Less
},
_ => false,
});
prop_assert!(sorted_and_disjoint);
}
}
}