use core::ops::{Sub, SubAssign};
use crate::{Domain, GenericRange, OperationResult, Ranges};
impl<T: Domain> Ranges<T> {
#[allow(clippy::expect_used)]
pub fn remove<R>(&mut self, range: R) -> bool
where
R: Into<GenericRange<T>>,
{
let new_range = range.into();
if new_range.is_empty() || self.ranges.is_empty() {
return false;
}
if new_range.is_full() {
self.ranges.clear();
return true;
}
let indices = self.find_intersecting_ranges(&new_range);
match indices {
None => {
false
}
Some((s, e)) if s == e => {
let removed = self.ranges.remove(s);
match removed.difference(new_range) {
OperationResult::Empty => (),
OperationResult::Double(r1, r2) => {
self.ranges.insert(s, r1);
#[allow(clippy::integer_arithmetic)]
self.ranges.insert(s + 1, r2);
}
OperationResult::Single(r) => self.ranges.insert(s, r),
}
true
}
Some((s, e)) => {
let mut ranges = self.ranges.drain(s..=e);
let first = ranges
.next()
.expect("find_intersecting_ranges() already tells us there has to be a first range");
let last = ranges
.last()
.expect("find_intersecting_ranges() already tells us there has to be a last range");
let existing_ranges_combined = GenericRange {
start: first.start,
end: last.end,
};
match existing_ranges_combined.difference(new_range) {
OperationResult::Empty => (),
OperationResult::Double(r1, r2) => {
self.ranges.insert(s, r1);
#[allow(clippy::integer_arithmetic)]
self.ranges.insert(s + 1, r2);
}
OperationResult::Single(r) => self.ranges.insert(s, r),
}
true
}
}
}
}
impl<T, I> Sub<I> for Ranges<T>
where
I: Into<GenericRange<T>>,
T: Domain,
{
type Output = Self;
#[must_use]
fn sub(mut self, rhs: I) -> Self::Output {
let _ = self.remove(rhs.into());
self
}
}
impl<T, I> SubAssign<I> for Ranges<T>
where
I: Into<GenericRange<T>>,
T: Domain,
{
fn sub_assign(&mut self, rhs: I) {
let _ = self.remove(rhs.into());
}
}
#[cfg(test)]
mod tests {
use alloc::vec;
use core::cmp::Ordering;
use core::ops::RangeBounds;
use proptest::prelude::*;
use crate::{GenericRange, Ranges};
#[test]
fn empty() {
let mut ranges = Ranges::new();
assert!(!ranges.remove(0..3));
assert!(ranges.is_empty());
}
#[test]
fn no_collisions() {
let mut ranges = Ranges::from(0..3);
assert!(!ranges.remove(5..10));
assert_eq!(ranges, Ranges::from(0..3))
}
#[test]
fn one_collision() {
let mut ranges = Ranges::from(0..3);
assert!(ranges.remove(2..5));
assert_eq!(ranges, Ranges::from(0..2))
}
#[test]
fn one_collision_two_results() {
let mut ranges = Ranges::from(0..10);
assert!(ranges.remove(2..5));
assert_eq!(ranges.ranges, vec![(0..2).into(), (5..10).into()])
}
#[test]
fn two_collisions() {
let mut ranges = Ranges::from(0..3);
assert!(ranges.insert(5..10));
assert!(ranges.remove(2..7));
assert_eq!(ranges.ranges, vec![(0..2).into(), (7..10).into()])
}
#[test]
fn two_collisions_single_result() {
let mut ranges = Ranges::from(0..3);
assert!(ranges.insert(5..10));
assert!(ranges.remove(2..15));
assert_eq!(ranges, Ranges::from(0..2))
}
#[test]
fn full() {
let mut ranges = Ranges::from(0..3);
assert!(ranges.remove(GenericRange::full()));
assert!(ranges.is_empty())
}
#[test]
fn muvlon() {
let mut ranges = Ranges::from(0..10);
assert!(!ranges.remove(5..5));
assert_eq!(ranges, Ranges::from(0..10));
}
#[test]
fn issue_43() {
let mut ranges = Ranges::from(23..36);
assert!(ranges.insert(10..20));
assert!(ranges.remove(10..20));
assert_eq!(ranges, Ranges::from(23..36));
}
#[test]
fn issue_43_proptest() {
let mut ranges = Ranges::from(128..128);
assert!(ranges.is_empty());
assert!(ranges.insert(0..=0));
assert_eq!(
ranges.find_intersecting_ranges(&GenericRange::from(0..=0)),
Some((0, 0))
);
assert!(ranges.remove(0..=0));
assert_eq!(ranges, Ranges::new());
}
proptest! {
#[ignore]
#[test]
fn sorted_and_disjoint(mut ranges in any::<Ranges<u8>>(), range in any::<GenericRange<u8>>()) {
let _ = ranges.remove(range);
let sorted_and_disjoint = ranges.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);
}
#[ignore]
#[test]
fn insert_remove_equality(
(range, range2) in (any::<GenericRange<u16>>(), any::<GenericRange<u16>>())
.prop_filter("Ranges need to be disjoint and first range may not be empty.",|&(ref r1, ref r2)| r1.is_disjoint(r2) && !r1.is_empty())
) {
let mut ranges = Ranges::from(range);
ranges.insert(range2);
ranges.remove(range2);
prop_assert_eq!(ranges, Ranges::from(range));
}
}
}