feat(utils): additional set operations (#39)

* rename traits

* subset

* intersection

* prove set intersection

* assert invariants

* fix doctest
This commit is contained in:
sinu.eth
2024-09-04 19:29:29 -07:00
committed by GitHub
parent 45370ccc61
commit e7b2db6a0c
13 changed files with 524 additions and 105 deletions

View File

@@ -1,5 +1,5 @@
[workspace]
members = ["utils", "utils-aio", "spansy", "serio", "uid-mux"]
members = ["utils", "utils-aio", "spansy", "serio", "uid-mux", "utils/fuzz"]
[workspace.dependencies]
tlsn-utils = { path = "utils" }

View File

@@ -1,4 +1,4 @@
use utils::range::{RangeDifference, RangeSet, ToRangeSet};
use utils::range::{Difference, RangeSet, ToRangeSet};
use crate::{json::JsonValue, Span, Spanned};

View File

@@ -1,6 +1,6 @@
use std::ops::{Index, Range};
use utils::range::{RangeDifference, RangeSet, ToRangeSet};
use utils::range::{Difference, RangeSet, ToRangeSet};
use crate::{Span, Spanned};

View File

@@ -13,10 +13,6 @@ libfuzzer-sys = { version = "0.4", features = ["arbitrary-derive"] }
[dependencies.tlsn-utils]
path = ".."
# Prevent this from interfering with workspaces
[workspace]
members = ["."]
[profile.release]
debug = 1
@@ -44,6 +40,18 @@ path = "fuzz_targets/range_diff_set.rs"
test = false
doc = false
[[bin]]
name = "range_intersection_set"
path = "fuzz_targets/range_intersection_set.rs"
test = false
doc = false
[[bin]]
name = "range_subset_set"
path = "fuzz_targets/range_subset_set.rs"
test = false
doc = false
[[bin]]
name = "set_union_range"
path = "fuzz_targets/set_union_range.rs"
@@ -62,6 +70,18 @@ path = "fuzz_targets/set_diff_set.rs"
test = false
doc = false
[[bin]]
name = "set_intersection_set"
path = "fuzz_targets/set_intersection_set.rs"
test = false
doc = false
[[bin]]
name = "set_subset_set"
path = "fuzz_targets/set_subset_set.rs"
test = false
doc = false
[[bin]]
name = "set_diff_range"
path = "fuzz_targets/set_diff_range.rs"

View File

@@ -0,0 +1,25 @@
#![no_main]
use std::collections::HashSet;
use std::ops::Range;
use libfuzzer_sys::fuzz_target;
use tlsn_utils_fuzz::{assert_invariants, SmallSet};
use utils::range::*;
fuzz_target!(|r: (Range<u8>, SmallSet)| {
let s1 = r.0;
let s2: RangeSet<u8> = r.1.into();
let h1: HashSet<u8> = HashSet::from_iter(s1.clone());
let h2: HashSet<u8> = HashSet::from_iter(s2.iter());
let intersection = s1.intersection(&s2);
let h3: HashSet<u8> = HashSet::from_iter(intersection.iter());
assert_eq!(h3, h1.intersection(&h2).copied().collect::<HashSet<_>>());
assert_invariants(intersection);
});

View File

@@ -0,0 +1,20 @@
#![no_main]
use std::collections::HashSet;
use std::ops::Range;
use libfuzzer_sys::fuzz_target;
use tlsn_utils_fuzz::SmallSet;
use utils::range::*;
fuzz_target!(|r: (Range<u8>, SmallSet)| {
let s1 = r.0;
let s2: RangeSet<u8> = r.1.into();
let h1: HashSet<u8> = HashSet::from_iter(s1.clone());
let h2: HashSet<u8> = HashSet::from_iter(s2.iter());
assert_eq!(s1.is_subset(&s2), h1.is_subset(&h2));
});

View File

@@ -0,0 +1,24 @@
#![no_main]
use std::collections::HashSet;
use libfuzzer_sys::fuzz_target;
use tlsn_utils_fuzz::{assert_invariants, SmallSet};
use utils::range::*;
fuzz_target!(|r: (SmallSet, SmallSet)| {
let s1: RangeSet<u8> = r.0.into();
let s2: RangeSet<u8> = r.1.into();
let h1: HashSet<u8> = HashSet::from_iter(s1.iter());
let h2: HashSet<u8> = HashSet::from_iter(s2.iter());
let intersection = s1.intersection(&s2);
let h3: HashSet<u8> = HashSet::from_iter(intersection.iter());
assert_eq!(h3, h1.intersection(&h2).copied().collect::<HashSet<_>>());
assert_invariants(intersection);
});

View File

@@ -0,0 +1,19 @@
#![no_main]
use std::collections::HashSet;
use libfuzzer_sys::fuzz_target;
use tlsn_utils_fuzz::SmallSet;
use utils::range::*;
fuzz_target!(|r: (SmallSet, SmallSet)| {
let s1: RangeSet<u8> = r.0.into();
let s2: RangeSet<u8> = r.1.into();
let h1: HashSet<u8> = HashSet::from_iter(s1.iter());
let h2: HashSet<u8> = HashSet::from_iter(s2.iter());
assert_eq!(s1.is_subset(&s2), h1.is_subset(&h2));
});

View File

@@ -1,10 +1,8 @@
use std::ops::Range;
use crate::range::{
RangeDifference, RangeDisjoint, RangeSet, RangeSubset, RangeSuperset, RangeUnion,
};
use crate::range::{Difference, Disjoint, RangeSet, Subset, Union};
impl<T: Copy + Ord> RangeDifference<Range<T>> for Range<T> {
impl<T: Copy + Ord> Difference<Range<T>> for Range<T> {
type Output = RangeSet<T>;
fn difference(&self, other: &Range<T>) -> Self::Output {
@@ -14,8 +12,8 @@ impl<T: Copy + Ord> RangeDifference<Range<T>> for Range<T> {
return RangeSet::from(self.clone());
}
// If other is a superset of self, return an empty set.
if other.is_superset(self) {
// If other contains self, return an empty set.
if self.is_subset(other) {
return RangeSet::default();
}
@@ -38,9 +36,9 @@ impl<T: Copy + Ord> RangeDifference<Range<T>> for Range<T> {
}
}
impl<T: Copy + Ord> RangeDifference<RangeSet<T>> for Range<T>
impl<T: Copy + Ord> Difference<RangeSet<T>> for Range<T>
where
RangeSet<T>: RangeDifference<Range<T>, Output = RangeSet<T>>,
RangeSet<T>: Difference<Range<T>, Output = RangeSet<T>>,
{
type Output = RangeSet<T>;
@@ -59,7 +57,7 @@ where
}
}
impl<T: Copy + Ord> RangeDifference<Range<T>> for RangeSet<T> {
impl<T: Copy + Ord> Difference<Range<T>> for RangeSet<T> {
type Output = RangeSet<T>;
fn difference(&self, other: &Range<T>) -> Self::Output {
@@ -80,7 +78,7 @@ impl<T: Copy + Ord> RangeDifference<Range<T>> for RangeSet<T> {
break;
}
// If the current range is entirely contained within other
else if other.is_superset(&ranges[i]) {
else if ranges[i].is_subset(other) {
ranges.remove(i);
continue;
}
@@ -113,7 +111,7 @@ impl<T: Copy + Ord> RangeDifference<Range<T>> for RangeSet<T> {
}
}
impl<T: Copy + Ord> RangeDifference<RangeSet<T>> for RangeSet<T> {
impl<T: Copy + Ord> Difference<RangeSet<T>> for RangeSet<T> {
type Output = RangeSet<T>;
fn difference(&self, other: &RangeSet<T>) -> Self::Output {

View File

@@ -0,0 +1,197 @@
use crate::range::{Intersection, Range, RangeSet};
impl<T: Copy + Ord> Intersection<Range<T>> for Range<T> {
type Output = Option<Range<T>>;
fn intersection(&self, other: &Range<T>) -> Self::Output {
let start = self.start.max(other.start);
let end = self.end.min(other.end);
if start < end {
Some(Range { start, end })
} else {
None
}
}
}
impl<T: Copy + Ord> Intersection<RangeSet<T>> for Range<T> {
type Output = RangeSet<T>;
fn intersection(&self, other: &RangeSet<T>) -> Self::Output {
let mut set = RangeSet::default();
for other in &other.ranges {
if self.end <= other.start {
// `self` is leftward of `other`, so we can break early.
break;
} else if let Some(intersection) = self.intersection(other) {
// Given that `other` contains sorted, non-adjacent, non-intersecting, and non-empty
// ranges, the new set will also have these properties.
set.ranges.push(intersection);
}
}
set
}
}
impl<T: Copy + Ord> Intersection<Range<T>> for RangeSet<T> {
type Output = RangeSet<T>;
fn intersection(&self, other: &Range<T>) -> Self::Output {
other.intersection(self)
}
}
impl<T: Copy + Ord> Intersection<RangeSet<T>> for RangeSet<T> {
type Output = RangeSet<T>;
fn intersection(&self, other: &RangeSet<T>) -> Self::Output {
let mut set = RangeSet::default();
let mut i = 0;
let mut j = 0;
while i < self.ranges.len() && j < other.ranges.len() {
let a = &self.ranges[i];
let b = &other.ranges[j];
if a.end <= b.start {
// `a` is leftward of `b`, so we can proceed to the next range in `self`.
i += 1;
} else if b.end <= a.start {
// `b` is leftward of `a`, so we can proceed to the next range in `other`.
j += 1;
} else if let Some(intersection) = a.intersection(b) {
// Given that `self` and `other` contain sorted, non-adjacent, non-intersecting, and
// non-empty ranges, the new set will also have these properties.
set.ranges.push(intersection);
if a.end <= b.end {
i += 1;
}
if b.end <= a.end {
j += 1;
}
}
}
set
}
}
#[cfg(test)]
mod tests {
use std::collections::HashSet;
use itertools::iproduct;
use crate::range::assert_invariants;
use super::*;
#[test]
fn test_range_intersection_range() {
assert!((0..0).intersection(&(0..0)).is_none());
assert!((0..1).intersection(&(0..0)).is_none());
assert!((0..0).intersection(&(0..1)).is_none());
assert_eq!((0..1).intersection(&(0..1)), Some(0..1));
assert_eq!((0..2).intersection(&(0..1)), Some(0..1));
assert_eq!((0..1).intersection(&(0..2)), Some(0..1));
assert_eq!((0..2).intersection(&(0..2)), Some(0..2));
assert_eq!((0..2).intersection(&(1..2)), Some(1..2));
assert_eq!((1..2).intersection(&(0..2)), Some(1..2));
}
#[test]
fn test_range_intersection_set() {
let set = RangeSet::from(vec![0..1, 2..3, 4..5]);
assert_eq!(set.intersection(&(0..0)), RangeSet::default());
assert_eq!(set.intersection(&(0..1)), RangeSet::from(vec![0..1]));
assert_eq!(set.intersection(&(0..2)), RangeSet::from(vec![0..1]));
assert_eq!(set.intersection(&(0..3)), RangeSet::from(vec![0..1, 2..3]));
assert_eq!(set.intersection(&(0..4)), RangeSet::from(vec![0..1, 2..3]));
assert_eq!(set.intersection(&(1..3)), RangeSet::from(vec![2..3]));
assert_eq!(
set.intersection(&(0..6)),
RangeSet::from(vec![0..1, 2..3, 4..5])
);
assert_eq!(
set.intersection(&(0..6)),
RangeSet::from(vec![0..1, 2..3, 4..5])
);
}
#[test]
fn test_set_intersection_set() {
let set = RangeSet::from(vec![0..1, 2..3, 5..6]);
assert_eq!(set.intersection(&RangeSet::default()), RangeSet::default());
assert_eq!(
set.intersection(&RangeSet::from(vec![1..2])),
RangeSet::default()
);
assert_eq!(
set.intersection(&RangeSet::from(vec![3..5])),
RangeSet::default()
);
assert_eq!(
set.intersection(&RangeSet::from(vec![7..8])),
RangeSet::default()
);
assert_eq!(
set.intersection(&RangeSet::from(vec![0..1])),
RangeSet::from(vec![0..1])
);
assert_eq!(
set.intersection(&RangeSet::from(vec![0..2])),
RangeSet::from(vec![0..1])
);
assert_eq!(
set.intersection(&RangeSet::from(vec![0..3])),
RangeSet::from(vec![0..1, 2..3])
);
assert_eq!(set.intersection(&RangeSet::from(vec![0..6])), set);
assert_eq!(
set.intersection(&RangeSet::from(vec![1..6])),
RangeSet::from(vec![2..3, 5..6])
);
assert_eq!(
set.intersection(&RangeSet::from(vec![2..3, 5..6])),
RangeSet::from(vec![2..3, 5..6])
);
}
#[test]
#[ignore = "expensive"]
fn test_prove_set_intersection_set_8x2_8x2() {
for (xs, xe, ys, ye, ws, we, zs, ze) in
iproduct!(0..8, 0..8, 0..8, 0..8, 0..8, 0..8, 0..8, 0..8)
{
let s1 = RangeSet::new(&[(xs..xe), (ys..ye)]);
let s2 = RangeSet::new(&[(ws..we), (zs..ze)]);
let h1 = s1.iter().collect::<HashSet<_>>();
let h2 = s2.iter().collect::<HashSet<_>>();
let actual = s1.intersection(&s2);
let h3 = HashSet::<usize>::from_iter(actual.iter());
assert_invariants(&actual);
assert_eq!(
h3,
h1.intersection(&h2).copied().collect::<HashSet<_>>(),
"{:?} {:?} {:?} {:?} => {:?}",
xs..xe,
ys..ye,
ws..we,
zs..ze,
h3
);
}
}
}

View File

@@ -1,5 +1,7 @@
mod difference;
mod index;
mod intersection;
mod subset;
mod union;
pub use index::IndexRanges;
@@ -38,7 +40,6 @@ use std::ops::{Add, Range, Sub};
/// assert_eq!(a.union(&(0..0)), RangeSet::from([10..20]));
///
/// // Comparison
/// assert!(a.is_superset(&(15..18)));
/// assert!(a.is_subset(&(0..30)));
/// assert!(a.is_disjoint(&(0..10)));
/// assert_eq!(a.clone(), RangeSet::from(a));
@@ -98,7 +99,7 @@ impl<T: Copy + Ord> RangeSet<T> {
/// The `RangeSet` is constructed by computing the union of the given ranges.
pub fn new(ranges: &[Range<T>]) -> Self
where
Self: RangeUnion<Range<T>, Output = Self>,
Self: Union<Range<T>, Output = Self>,
{
let mut set = Self::default();
@@ -384,25 +385,25 @@ impl<T: Copy + Ord> ToRangeSet<T> for Range<T> {
}
}
pub trait RangeDisjoint<Rhs> {
pub trait Disjoint<Rhs> {
/// Returns `true` if the range is disjoint with `other`.
#[must_use]
fn is_disjoint(&self, other: &Rhs) -> bool;
}
pub trait RangeSuperset<Rhs> {
/// Returns `true` if `self` is a superset of `other`.
pub trait Contains<Rhs> {
/// Returns `true` if `self` contains `other`.
#[must_use]
fn is_superset(&self, other: &Rhs) -> bool;
fn contains(&self, other: &Rhs) -> bool;
}
pub trait RangeSubset<Rhs> {
pub trait Subset<Rhs> {
/// Returns `true` if `self` is a subset of `other`.
#[must_use]
fn is_subset(&self, other: &Rhs) -> bool;
}
pub trait RangeDifference<Rhs> {
pub trait Difference<Rhs> {
type Output;
/// Returns the set difference of `self` and `other`.
@@ -410,7 +411,7 @@ pub trait RangeDifference<Rhs> {
fn difference(&self, other: &Rhs) -> Self::Output;
}
pub trait RangeUnion<Rhs> {
pub trait Union<Rhs> {
type Output;
/// Returns the set union of `self` and `other`.
@@ -418,6 +419,14 @@ pub trait RangeUnion<Rhs> {
fn union(&self, other: &Rhs) -> Self::Output;
}
pub trait Intersection<Rhs> {
type Output;
/// Returns the set intersection of `self` and `other`.
#[must_use]
fn intersection(&self, other: &Rhs) -> Self::Output;
}
/// A type which successor and predecessor operations can be performed on.
///
/// Similar to `std::iter::Step`, but not nightly-only.
@@ -447,52 +456,37 @@ macro_rules! impl_step {
impl_step!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
impl<T: Copy + Ord> RangeDisjoint<Range<T>> for Range<T> {
impl<T: Copy + Ord> Disjoint<Range<T>> for Range<T> {
fn is_disjoint(&self, other: &Range<T>) -> bool {
self.start >= other.end || self.end <= other.start
}
}
impl<T: Copy + Ord> RangeDisjoint<RangeSet<T>> for Range<T> {
impl<T: Copy + Ord> Disjoint<RangeSet<T>> for Range<T> {
fn is_disjoint(&self, other: &RangeSet<T>) -> bool {
other.ranges.iter().all(|range| self.is_disjoint(range))
}
}
impl<T: Copy + Ord> RangeDisjoint<RangeSet<T>> for RangeSet<T> {
impl<T: Copy + Ord> Disjoint<RangeSet<T>> for RangeSet<T> {
fn is_disjoint(&self, other: &RangeSet<T>) -> bool {
self.ranges.iter().all(|range| range.is_disjoint(other))
}
}
impl<T: Copy + Ord> RangeDisjoint<Range<T>> for RangeSet<T> {
impl<T: Copy + Ord> Disjoint<Range<T>> for RangeSet<T> {
fn is_disjoint(&self, other: &Range<T>) -> bool {
other.is_disjoint(self)
}
}
impl<T: Copy + Ord> RangeSuperset<Range<T>> for Range<T> {
fn is_superset(&self, other: &Range<T>) -> bool {
self.start <= other.start && self.end >= other.end
}
}
impl<T: Copy + Ord> RangeSuperset<RangeSet<T>> for Range<T> {
fn is_superset(&self, other: &RangeSet<T>) -> bool {
other.ranges.iter().all(|range| self.is_superset(range))
}
}
impl<T: Copy + Ord> RangeSubset<Range<T>> for Range<T> {
fn is_subset(&self, other: &Range<T>) -> bool {
self.start >= other.start && self.end <= other.end
}
}
impl<T: Copy + Ord> RangeSubset<RangeSet<T>> for Range<T> {
fn is_subset(&self, other: &RangeSet<T>) -> bool {
other.ranges.iter().any(|range| self.is_subset(range))
}
/// Asserts that the ranges of the given set are sorted, non-adjacent, non-intersecting, and non-empty.
#[cfg(test)]
pub fn assert_invariants<T: Copy + Ord>(set: &RangeSet<T>) {
assert!(set.ranges.windows(2).all(|w| w[0].start < w[1].start
&& w[0].end < w[1].start
&& w[0].start < w[0].end
&& w[1].start < w[1].end));
}
#[cfg(test)]
@@ -523,50 +517,6 @@ mod tests {
assert!(!a.is_disjoint(&(10..20)));
}
#[test]
fn test_range_superset() {
let a = 10..20;
// rightward
assert!(!a.is_superset(&(20..30)));
// rightward aligned
assert!(!a.is_superset(&(19..25)));
// leftward
assert!(!a.is_superset(&(0..10)));
// leftward aligned
assert!(!a.is_superset(&(5..11)));
// rightward subset
assert!(a.is_superset(&(15..20)));
// leftward subset
assert!(a.is_superset(&(10..15)));
// superset
assert!(!a.is_superset(&(5..25)));
// equal
assert!(a.is_superset(&(10..20)));
}
#[test]
fn test_range_subset() {
let a = 10..20;
// rightward
assert!(!a.is_subset(&(20..30)));
// rightward aligned
assert!(!a.is_subset(&(19..25)));
// leftward
assert!(!a.is_subset(&(0..10)));
// leftward aligned
assert!(!a.is_subset(&(5..11)));
// rightward subset
assert!(!a.is_subset(&(15..20)));
// leftward subset
assert!(!a.is_subset(&(10..15)));
// superset
assert!(a.is_subset(&(5..25)));
// equal
assert!(a.is_subset(&(10..20)));
}
#[test]
fn test_range_set_iter() {
let a = RangeSet::from([(10..20), (30..40), (50..60)]);

166
utils/src/range/subset.rs Normal file
View File

@@ -0,0 +1,166 @@
use crate::range::{Range, RangeSet, Subset};
impl<T: Copy + Ord> Subset<Range<T>> for Range<T> {
fn is_subset(&self, other: &Range<T>) -> bool {
self.start >= other.start && self.end <= other.end
}
}
impl<T: Copy + Ord> Subset<RangeSet<T>> for Range<T> {
fn is_subset(&self, other: &RangeSet<T>) -> bool {
if self.is_empty() {
// empty range is subset of any set
return true;
} else if other.ranges.is_empty() {
// non-empty range is not subset of empty set
return false;
}
for other in &other.ranges {
if self.start >= other.end {
// self is rightward of other, proceed to next other
continue;
} else {
return self.is_subset(other);
}
}
false
}
}
impl<T: Copy + Ord> Subset<Range<T>> for RangeSet<T> {
fn is_subset(&self, other: &Range<T>) -> bool {
let (Some(start), Some(end)) = (self.min(), self.end()) else {
// empty set is subset of any set
return true;
};
// check if the outer bounds of this set are within the range
start >= other.start && end <= other.end
}
}
impl<T: Copy + Ord> Subset<RangeSet<T>> for RangeSet<T> {
fn is_subset(&self, other: &RangeSet<T>) -> bool {
if self.ranges.is_empty() {
// empty set is subset of any set
return true;
} else if other.ranges.is_empty() {
// non-empty set is not subset of empty set
return false;
}
let mut i = 0;
let mut j = 0;
while i < self.ranges.len() && j < other.ranges.len() {
let a = &self.ranges[i];
let b = &other.ranges[j];
if a.start >= b.end {
// a is rightward of b, proceed to next b
j += 1;
} else if a.is_subset(b) {
// a is subset of b, proceed to next a
i += 1;
} else {
// self contains values not in other
return false;
}
}
// If we've reached the end of self, then all ranges are contained in other.
i == self.ranges.len()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_range_subset_of_range() {
let a = 10..20;
// empty
assert!(!a.is_subset(&(0..0)));
// rightward
assert!(!a.is_subset(&(20..30)));
// rightward aligned
assert!(!a.is_subset(&(19..25)));
// leftward
assert!(!a.is_subset(&(0..10)));
// leftward aligned
assert!(!a.is_subset(&(5..11)));
// rightward subset
assert!(!a.is_subset(&(15..20)));
// leftward subset
assert!(!a.is_subset(&(10..15)));
// superset
assert!(a.is_subset(&(5..25)));
// equal
assert!(a.is_subset(&(10..20)));
}
#[test]
fn test_range_subset_of_rangeset() {
let a = 10..20;
let empty = RangeSet::<i32>::default();
// empty set is subset of any range
assert!(empty.is_subset(&a));
// non-empty range is not subset of empty set
assert!(!a.is_subset(&empty));
assert!(a.is_subset(&RangeSet::from(vec![0..20])));
assert!(a.is_subset(&RangeSet::from(vec![10..20])));
assert!(!a.is_subset(&RangeSet::from(vec![0..10])));
assert!(!a.is_subset(&RangeSet::from(vec![20..30])));
assert!(!a.is_subset(&RangeSet::from(vec![0..10, 20..30])));
}
#[test]
fn test_rangeset_subset_of_range() {
let a = RangeSet::from(vec![10..20, 30..40]);
assert!(!a.is_subset(&(0..0)));
assert!(!a.is_subset(&(0..10)));
assert!(!a.is_subset(&(0..15)));
assert!(!a.is_subset(&(0..20)));
assert!(!a.is_subset(&(20..30)));
assert!(!a.is_subset(&(20..40)));
assert!(!a.is_subset(&(20..50)));
assert!(!a.is_subset(&(30..40)));
assert!(!a.is_subset(&(11..40)));
assert!(!a.is_subset(&(10..39)));
assert!(a.is_subset(&(10..40)));
}
#[test]
fn test_rangeset_subset_of_rangeset() {
let empty = RangeSet::<i32>::default();
// empty set is subset of itself
assert!(empty.is_subset(&empty));
// empty set is subset of non-empty set
assert!(empty.is_subset(&RangeSet::from(vec![10..20])));
// non-empty set is not subset of empty set
assert!(!RangeSet::from(vec![10..20]).is_subset(&empty));
let a = RangeSet::from(vec![10..20, 30..40]);
// equal
assert!(a.is_subset(&a));
assert!(a.is_subset(&RangeSet::from(vec![0..20, 30..50])));
assert!(a.is_subset(&RangeSet::from(vec![10..20, 30..40, 40..50])));
assert!(!a.is_subset(&RangeSet::from(vec![10..20])));
assert!(!a.is_subset(&RangeSet::from(vec![30..40])));
assert!(!a.is_subset(&RangeSet::from(vec![0..20, 30..39])));
assert!(!a.is_subset(&RangeSet::from(vec![10..19, 30..40])));
assert!(!a.is_subset(&RangeSet::from(vec![0..10, 30..40])));
}
}

View File

@@ -1,18 +1,18 @@
use std::ops::Range;
use crate::range::{RangeDisjoint, RangeSet, RangeSuperset, RangeUnion};
use crate::range::{Disjoint, RangeSet, Subset, Union};
impl<T: Copy + Ord> RangeUnion<Range<T>> for Range<T> {
impl<T: Copy + Ord> Union<Range<T>> for Range<T> {
type Output = RangeSet<T>;
fn union(&self, other: &Range<T>) -> Self::Output {
// If the two are equal, or other is a subset, return self.
if self == other || self.is_superset(other) {
if self == other || other.is_subset(self) {
return RangeSet::from(self.clone());
}
// If other is a superset, return other.
if other.is_superset(self) {
// If other contains self, return other.
if self.is_subset(other) {
return RangeSet::from(other.clone());
}
@@ -34,7 +34,7 @@ impl<T: Copy + Ord> RangeUnion<Range<T>> for Range<T> {
}
}
impl<T: Copy + Ord> RangeUnion<RangeSet<T>> for Range<T> {
impl<T: Copy + Ord> Union<RangeSet<T>> for Range<T> {
type Output = RangeSet<T>;
fn union(&self, other: &RangeSet<T>) -> Self::Output {
@@ -74,7 +74,7 @@ impl<T: Copy + Ord> RangeUnion<RangeSet<T>> for Range<T> {
}
}
impl<T: Copy + Ord> RangeUnion<Range<T>> for RangeSet<T> {
impl<T: Copy + Ord> Union<Range<T>> for RangeSet<T> {
type Output = RangeSet<T>;
fn union(&self, other: &Range<T>) -> Self::Output {
@@ -82,7 +82,7 @@ impl<T: Copy + Ord> RangeUnion<Range<T>> for RangeSet<T> {
}
}
impl<T: Copy + Ord> RangeUnion<RangeSet<T>> for RangeSet<T> {
impl<T: Copy + Ord> Union<RangeSet<T>> for RangeSet<T> {
type Output = RangeSet<T>;
fn union(&self, other: &RangeSet<T>) -> Self::Output {