mirror of
https://github.com/tlsnotary/tlsn-utils.git
synced 2026-01-09 12:48:03 -05:00
feat(rangeset): rangeset crate (#56)
This commit is contained in:
@@ -3,23 +3,5 @@ name = "tlsn-utils"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[features]
|
||||
default = ["serde"]
|
||||
serde = ["dep:serde"]
|
||||
|
||||
[lib]
|
||||
name = "utils"
|
||||
|
||||
[dependencies]
|
||||
serde = { workspace = true, optional = true, features = ["derive"] }
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = { version = "0.5" }
|
||||
rstest = "0.12"
|
||||
rand = { workspace = true }
|
||||
itertools = "0.11.0"
|
||||
|
||||
|
||||
[[bench]]
|
||||
name = "range"
|
||||
harness = false
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
|
||||
use utils::range::{RangeSet, Subset};
|
||||
|
||||
pub fn criterion_benchmark(c: &mut Criterion) {
|
||||
let mut rangeset_vec = Vec::new();
|
||||
for i in 0..10000 {
|
||||
if i % 2 == 0 {
|
||||
// [0..1, 2..3, ... , 9998..9999].
|
||||
rangeset_vec.push(i..i + 1);
|
||||
}
|
||||
}
|
||||
let rangeset = RangeSet::from(rangeset_vec);
|
||||
|
||||
c.bench_function("boundary_range_subset_of_rangeset", |b| {
|
||||
b.iter(|| boundary_range_subset_of_rangeset(black_box(&rangeset)))
|
||||
});
|
||||
|
||||
c.bench_function("rangeset_subset_of_boundary_rangeset", |b| {
|
||||
b.iter(|| rangeset_subset_of_boundary_rangeset(black_box(&rangeset)))
|
||||
});
|
||||
}
|
||||
|
||||
// To benchmark the worst case where [range.start] is close to [other.end()], i.e. N
|
||||
// iterations are needed if there is no boundary short citcuit (N == other.len_ranges()).
|
||||
fn boundary_range_subset_of_rangeset(other: &RangeSet<u32>) {
|
||||
let range = 9997..10005;
|
||||
let _ = range.is_subset(other);
|
||||
}
|
||||
|
||||
// To benchmark the worst case where [rangeset.last().start] is close to [other.end()],
|
||||
// i.e. N iterations of [is_subset()] check are needed if there is no boundary short
|
||||
// citcuit (N ~= rangeset.len_ranges()).
|
||||
#[allow(clippy::single_range_in_vec_init)]
|
||||
fn rangeset_subset_of_boundary_rangeset(rangeset: &RangeSet<u32>) {
|
||||
let other = RangeSet::from(vec![0..9998]);
|
||||
let _ = rangeset.is_subset(&other);
|
||||
}
|
||||
|
||||
criterion_group!(benches, criterion_benchmark);
|
||||
criterion_main!(benches);
|
||||
4
utils/fuzz/.gitignore
vendored
4
utils/fuzz/.gitignore
vendored
@@ -1,4 +0,0 @@
|
||||
target
|
||||
corpus
|
||||
artifacts
|
||||
coverage
|
||||
@@ -1,89 +0,0 @@
|
||||
[package]
|
||||
name = "tlsn-utils-fuzz"
|
||||
version = "0.0.0"
|
||||
publish = false
|
||||
edition = "2021"
|
||||
|
||||
[package.metadata]
|
||||
cargo-fuzz = true
|
||||
|
||||
[dependencies]
|
||||
libfuzzer-sys = { version = "0.4", features = ["arbitrary-derive"] }
|
||||
|
||||
[dependencies.tlsn-utils]
|
||||
path = ".."
|
||||
|
||||
[profile.release]
|
||||
debug = 1
|
||||
|
||||
[[bin]]
|
||||
name = "range_union_range"
|
||||
path = "fuzz_targets/range_union_range.rs"
|
||||
test = false
|
||||
doc = false
|
||||
|
||||
[[bin]]
|
||||
name = "range_union_set"
|
||||
path = "fuzz_targets/range_union_set.rs"
|
||||
test = false
|
||||
doc = false
|
||||
|
||||
[[bin]]
|
||||
name = "range_diff_range"
|
||||
path = "fuzz_targets/range_diff_range.rs"
|
||||
test = false
|
||||
doc = false
|
||||
|
||||
[[bin]]
|
||||
name = "range_diff_set"
|
||||
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"
|
||||
test = false
|
||||
doc = false
|
||||
|
||||
[[bin]]
|
||||
name = "set_union_set"
|
||||
path = "fuzz_targets/set_union_set.rs"
|
||||
test = false
|
||||
doc = false
|
||||
|
||||
[[bin]]
|
||||
name = "set_diff_set"
|
||||
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"
|
||||
test = false
|
||||
doc = false
|
||||
@@ -1,26 +0,0 @@
|
||||
#![no_main]
|
||||
|
||||
use std::ops::Range;
|
||||
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
use tlsn_utils_fuzz::assert_invariants;
|
||||
use utils::range::*;
|
||||
|
||||
fn expected_range_difference(a: Range<u8>, b: Range<u8>) -> Vec<u8> {
|
||||
a.filter(|x| !b.contains(x)).collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
fuzz_target!(|r: (Range<u8>, Range<u8>)| {
|
||||
let (r1, r2) = r;
|
||||
|
||||
let expected_values = expected_range_difference(r1.clone(), r2.clone());
|
||||
|
||||
let diff = r1.difference(&r2);
|
||||
|
||||
let actual_values = diff.iter().collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(expected_values, actual_values);
|
||||
|
||||
assert_invariants(diff);
|
||||
});
|
||||
@@ -1,28 +0,0 @@
|
||||
#![no_main]
|
||||
|
||||
use std::ops::Range;
|
||||
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
use tlsn_utils_fuzz::{assert_invariants, SmallSet};
|
||||
|
||||
use utils::range::*;
|
||||
|
||||
fn expected_difference(a: Range<u8>, b: RangeSet<u8>) -> Vec<u8> {
|
||||
a.filter(|x| !b.contains(x)).collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
fuzz_target!(|r: (Range<u8>, SmallSet)| {
|
||||
let range = r.0;
|
||||
let set: RangeSet<u8> = r.1.into();
|
||||
|
||||
let expected_values = expected_difference(range.clone(), set.clone());
|
||||
|
||||
let diff = range.difference(&set);
|
||||
|
||||
let actual_values = diff.iter().collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(expected_values, actual_values);
|
||||
|
||||
assert_invariants(diff);
|
||||
});
|
||||
@@ -1,25 +0,0 @@
|
||||
#![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);
|
||||
});
|
||||
@@ -1,20 +0,0 @@
|
||||
#![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));
|
||||
});
|
||||
@@ -1,31 +0,0 @@
|
||||
#![no_main]
|
||||
|
||||
use std::ops::Range;
|
||||
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
use tlsn_utils_fuzz::assert_invariants;
|
||||
use utils::range::*;
|
||||
|
||||
fn expected_range_union(a: Range<u8>, b: Range<u8>) -> Vec<u8> {
|
||||
let mut expected_values = a.chain(b).collect::<Vec<_>>();
|
||||
|
||||
expected_values.sort();
|
||||
expected_values.dedup();
|
||||
|
||||
expected_values
|
||||
}
|
||||
|
||||
fuzz_target!(|r: (Range<u8>, Range<u8>)| {
|
||||
let (r1, r2) = r;
|
||||
|
||||
let expected_values = expected_range_union(r1.clone(), r2.clone());
|
||||
|
||||
let union = r1.union(&r2);
|
||||
|
||||
let actual_values = union.iter().collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(expected_values, actual_values);
|
||||
|
||||
assert_invariants(union);
|
||||
});
|
||||
@@ -1,33 +0,0 @@
|
||||
#![no_main]
|
||||
|
||||
use std::ops::Range;
|
||||
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
use tlsn_utils_fuzz::{assert_invariants, SmallSet};
|
||||
|
||||
use utils::range::*;
|
||||
|
||||
fn expected_union(a: Range<u8>, b: RangeSet<u8>) -> Vec<u8> {
|
||||
let mut expected_values = a.chain(b.iter()).collect::<Vec<_>>();
|
||||
|
||||
expected_values.sort();
|
||||
expected_values.dedup();
|
||||
|
||||
expected_values
|
||||
}
|
||||
|
||||
fuzz_target!(|r: (Range<u8>, SmallSet)| {
|
||||
let r1 = r.0;
|
||||
let r2: RangeSet<u8> = r.1.into();
|
||||
|
||||
let expected_values = expected_union(r1.clone(), r2.clone());
|
||||
|
||||
let union = r1.union(&r2);
|
||||
|
||||
let actual_values = union.iter().collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(expected_values, actual_values);
|
||||
|
||||
assert_invariants(union);
|
||||
});
|
||||
@@ -1,29 +0,0 @@
|
||||
#![no_main]
|
||||
|
||||
use std::ops::Range;
|
||||
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
use tlsn_utils_fuzz::{assert_invariants, SmallSet};
|
||||
|
||||
use utils::range::*;
|
||||
|
||||
fn expected_difference(a: RangeSet<u8>, b: Range<u8>) -> Vec<u8> {
|
||||
a.iter().filter(|x| !b.contains(x)).collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
fuzz_target!(|r: (SmallSet, Range<u8>)| {
|
||||
let (set, range) = r;
|
||||
|
||||
let set = RangeSet::new(&set.ranges);
|
||||
|
||||
let expected_values = expected_difference(set.clone(), range.clone());
|
||||
|
||||
let diff = set.difference(&range);
|
||||
|
||||
let actual_values = diff.iter().collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(expected_values, actual_values);
|
||||
|
||||
assert_invariants(diff);
|
||||
});
|
||||
@@ -1,26 +0,0 @@
|
||||
#![no_main]
|
||||
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
use tlsn_utils_fuzz::{assert_invariants, SmallSet};
|
||||
|
||||
use utils::range::*;
|
||||
|
||||
fn expected_difference(a: RangeSet<u8>, b: RangeSet<u8>) -> Vec<u8> {
|
||||
a.iter().filter(|x| !b.contains(x)).collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
fuzz_target!(|r: (SmallSet, SmallSet)| {
|
||||
let s1: RangeSet<u8> = r.0.into();
|
||||
let s2: RangeSet<u8> = r.1.into();
|
||||
|
||||
let expected_values = expected_difference(s1.clone(), s2.clone());
|
||||
|
||||
let diff = s1.difference(&s2);
|
||||
|
||||
let actual_values = diff.iter().collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(expected_values, actual_values);
|
||||
|
||||
assert_invariants(diff);
|
||||
});
|
||||
@@ -1,24 +0,0 @@
|
||||
#![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);
|
||||
});
|
||||
@@ -1,19 +0,0 @@
|
||||
#![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));
|
||||
});
|
||||
@@ -1,33 +0,0 @@
|
||||
#![no_main]
|
||||
|
||||
use std::ops::Range;
|
||||
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
use tlsn_utils_fuzz::{assert_invariants, SmallSet};
|
||||
|
||||
use utils::range::*;
|
||||
|
||||
fn expected_union(a: RangeSet<u8>, b: Range<u8>) -> Vec<u8> {
|
||||
let mut expected_values = a.iter().chain(b).collect::<Vec<_>>();
|
||||
|
||||
expected_values.sort();
|
||||
expected_values.dedup();
|
||||
|
||||
expected_values
|
||||
}
|
||||
|
||||
fuzz_target!(|r: (Range<u8>, SmallSet)| {
|
||||
let r1 = r.0;
|
||||
let r2: RangeSet<u8> = r.1.into();
|
||||
|
||||
let expected_values = expected_union(r2.clone(), r1.clone());
|
||||
|
||||
let union = r2.union(&r1);
|
||||
|
||||
let actual_values = union.iter().collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(expected_values, actual_values);
|
||||
|
||||
assert_invariants(union);
|
||||
});
|
||||
@@ -1,31 +0,0 @@
|
||||
#![no_main]
|
||||
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
use tlsn_utils_fuzz::{assert_invariants, SmallSet};
|
||||
|
||||
use utils::range::*;
|
||||
|
||||
fn expected_union(a: RangeSet<u8>, b: RangeSet<u8>) -> Vec<u8> {
|
||||
let mut expected_values = a.iter().chain(b.iter()).collect::<Vec<_>>();
|
||||
|
||||
expected_values.sort();
|
||||
expected_values.dedup();
|
||||
|
||||
expected_values
|
||||
}
|
||||
|
||||
fuzz_target!(|r: (SmallSet, SmallSet)| {
|
||||
let r1: RangeSet<u8> = r.0.into();
|
||||
let r2: RangeSet<u8> = r.1.into();
|
||||
|
||||
let expected_values = expected_union(r1.clone(), r2.clone());
|
||||
|
||||
let union = r2.union(&r1);
|
||||
|
||||
let actual_values = union.iter().collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(expected_values, actual_values);
|
||||
|
||||
assert_invariants(union);
|
||||
});
|
||||
@@ -1,46 +0,0 @@
|
||||
use std::ops::Range;
|
||||
|
||||
use libfuzzer_sys::arbitrary::{Arbitrary, Result, Unstructured};
|
||||
|
||||
use utils::range::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SmallSet {
|
||||
pub ranges: Vec<Range<u8>>,
|
||||
}
|
||||
|
||||
impl From<SmallSet> for RangeSet<u8> {
|
||||
fn from(s: SmallSet) -> Self {
|
||||
RangeSet::new(&s.ranges)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Arbitrary<'a> for SmallSet {
|
||||
fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
|
||||
// Generates a set of ranges with a maximum of 8 ranges.
|
||||
let count = u8::arbitrary(u)? % 8;
|
||||
|
||||
let mut set = RangeSet::default();
|
||||
for _ in 0..count {
|
||||
let new: Range<u8> = Range::arbitrary(u)?;
|
||||
set = set.union(&new);
|
||||
}
|
||||
|
||||
Ok(SmallSet {
|
||||
ranges: set.into_inner(),
|
||||
})
|
||||
}
|
||||
|
||||
fn size_hint(_depth: usize) -> (usize, Option<usize>) {
|
||||
// Maximum of 1 byte for `count` and 8 Range<u8> which are 2 bytes each.
|
||||
(1, Some(1 + 8 * 2))
|
||||
}
|
||||
}
|
||||
|
||||
/// Asserts that the ranges of the given set are sorted, non-adjacent, non-intersecting, and non-empty.
|
||||
pub fn assert_invariants(set: RangeSet<u8>) {
|
||||
assert!(set.into_inner().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));
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
pub mod filter_drain;
|
||||
pub mod id;
|
||||
pub mod iter;
|
||||
pub mod range;
|
||||
pub mod tuple;
|
||||
|
||||
@@ -1,286 +0,0 @@
|
||||
use crate::range::{
|
||||
difference::DifferenceMut, intersection::Intersection, subset::Subset, Range, RangeSet,
|
||||
};
|
||||
|
||||
/// Set cover methods.
|
||||
pub trait Cover<Rhs> {
|
||||
/// Returns the positions of the fewest sets from `others` which exactly cover `self`.
|
||||
fn find_cover<'a>(&self, others: impl IntoIterator<Item = &'a Rhs>) -> Option<Vec<usize>>
|
||||
where
|
||||
Rhs: 'a;
|
||||
|
||||
/// Returns the fewest sets from `others` which exactly cover `self`.
|
||||
fn cover<'a>(&self, others: impl IntoIterator<Item = &'a Rhs>) -> Option<Vec<&'a Rhs>>
|
||||
where
|
||||
Rhs: 'a;
|
||||
|
||||
/// Returns the fewest sets from `others` which exactly cover `self`.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `others` - The collection of items to cover `self`.
|
||||
/// * `f` - A function that extracts a set from an item.
|
||||
fn cover_by<'a, T>(
|
||||
&self,
|
||||
others: impl IntoIterator<Item = &'a T>,
|
||||
f: impl Fn(&T) -> &Rhs,
|
||||
) -> Option<Vec<&'a T>>
|
||||
where
|
||||
T: 'a;
|
||||
}
|
||||
|
||||
impl<T> Cover<RangeSet<T>> for RangeSet<T>
|
||||
where
|
||||
T: Copy + Ord + 'static,
|
||||
Range<T>: ExactSizeIterator<Item = T>,
|
||||
{
|
||||
fn find_cover<'a>(
|
||||
&self,
|
||||
others: impl IntoIterator<Item = &'a RangeSet<T>>,
|
||||
) -> Option<Vec<usize>>
|
||||
where
|
||||
RangeSet<T>: 'a,
|
||||
{
|
||||
cover(self, |set| set, others).map(|sets| sets.into_iter().map(|(pos, _)| pos).collect())
|
||||
}
|
||||
|
||||
fn cover<'a>(
|
||||
&self,
|
||||
others: impl IntoIterator<Item = &'a RangeSet<T>>,
|
||||
) -> Option<Vec<&'a RangeSet<T>>>
|
||||
where
|
||||
RangeSet<T>: 'a,
|
||||
{
|
||||
cover(self, |set| set, others).map(|sets| sets.into_iter().map(|(_, set)| set).collect())
|
||||
}
|
||||
|
||||
fn cover_by<'a, U>(
|
||||
&self,
|
||||
others: impl IntoIterator<Item = &'a U>,
|
||||
f: impl Fn(&U) -> &RangeSet<T>,
|
||||
) -> Option<Vec<&'a U>>
|
||||
where
|
||||
T: 'a,
|
||||
{
|
||||
cover(self, f, others).map(|sets| sets.into_iter().map(|(_, item)| item).collect())
|
||||
}
|
||||
}
|
||||
|
||||
struct Candidate<'a, T> {
|
||||
/// Index in the remaining collection.
|
||||
i: usize,
|
||||
/// Position in the original collection.
|
||||
pos: usize,
|
||||
item: &'a T,
|
||||
/// The number of elements in the intersection of the set and the uncovered elements.
|
||||
cover: usize,
|
||||
}
|
||||
|
||||
/// Greedy set cover algorithm.
|
||||
///
|
||||
/// Returns the fewest sets from `others` which exactly cover `query`.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `query` - The set to cover.
|
||||
/// * `f` - A function that extracts a set from an item.
|
||||
/// * `others` - The collection of items to cover `query`.
|
||||
fn cover<'a, T: Copy + Ord + 'static, U: 'a>(
|
||||
query: &RangeSet<T>,
|
||||
f: impl Fn(&U) -> &RangeSet<T>,
|
||||
others: impl IntoIterator<Item = &'a U>,
|
||||
) -> Option<Vec<(usize, &'a U)>>
|
||||
where
|
||||
Range<T>: ExactSizeIterator<Item = T>,
|
||||
{
|
||||
if query.is_empty() {
|
||||
return Some(Default::default());
|
||||
}
|
||||
|
||||
// Filter out rangesets that are not a subset of query.
|
||||
let mut others: Vec<_> = others
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.filter_map(|(pos, other)| {
|
||||
if f(other).is_subset(query) {
|
||||
Some((pos, other))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
if others.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut uncovered = query.clone();
|
||||
let mut candidates = Vec::new();
|
||||
let mut candidate: Option<Candidate<'_, U>> = None;
|
||||
while !uncovered.is_empty() {
|
||||
// Find the set with the most coverage.
|
||||
for (i, (pos, item)) in others.iter().enumerate() {
|
||||
let cover = f(item).intersection(&uncovered).len();
|
||||
// If cover is non-empty or greater than the current candidate, update the candidate.
|
||||
if cover > candidate.as_ref().map_or(1, |c| c.cover) {
|
||||
candidate = Some(Candidate {
|
||||
i,
|
||||
pos: *pos,
|
||||
item,
|
||||
cover,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(Candidate { i, pos, item, .. }) = candidate.take() {
|
||||
// Remove the set from the uncovered elements.
|
||||
uncovered.difference_mut(f(item));
|
||||
// Remove the set from the remaining sets.
|
||||
others.swap_remove(i);
|
||||
// Add the set to the candidates.
|
||||
candidates.push((pos, item));
|
||||
} else {
|
||||
// If no set was found, we cannot cover the query.
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
Some(candidates)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_empty_rangeset_cover() {
|
||||
let query = RangeSet::<u32>::default();
|
||||
let others = [RangeSet::from(1..5), RangeSet::from(6..10)];
|
||||
|
||||
let result = query.cover(others.iter()).unwrap();
|
||||
assert!(result.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_missing_rangesets() {
|
||||
let query = RangeSet::from(1..5);
|
||||
let others: Vec<RangeSet<u32>> = vec![];
|
||||
|
||||
let result = query.cover(others.iter());
|
||||
assert!(result.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_no_subset_in_others() {
|
||||
let query = RangeSet::from(5..10);
|
||||
let others = [
|
||||
RangeSet::from(1..4), // Completely outside query
|
||||
RangeSet::from(3..7), // Partially overlaps but not a subset
|
||||
RangeSet::from(8..15), // Partially overlaps but not a subset
|
||||
RangeSet::from(11..20),
|
||||
];
|
||||
|
||||
let result = query.cover(others.iter());
|
||||
assert!(result.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_simple_cover() {
|
||||
let query = RangeSet::from(1..5);
|
||||
let others = [query.clone()];
|
||||
|
||||
let result = query.cover(others.iter()).unwrap();
|
||||
assert_eq!(result.len(), 1);
|
||||
assert_eq!(result[0], &query);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_simple_cover_with_multi_ranges() {
|
||||
let query = RangeSet::from(vec![1..5, 10..15]);
|
||||
let others = [query.clone()];
|
||||
|
||||
let result = query.cover(others.iter()).unwrap();
|
||||
assert_eq!(result.len(), 1);
|
||||
assert_eq!(result[0], &query);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_multiple_subsets_cover() {
|
||||
let query = RangeSet::from(1..10);
|
||||
let others = [RangeSet::from(1..5), RangeSet::from(5..10)];
|
||||
|
||||
let result = query.cover(others.iter()).unwrap();
|
||||
assert_eq!(result.len(), 2);
|
||||
assert!(result.contains(&&others[0]));
|
||||
assert!(result.contains(&&others[1]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_multi_range_cover_with_multi_range_sets() {
|
||||
// query with multiple disjoint ranges
|
||||
let query = RangeSet::from(vec![1..5, 10..15, 20..25]);
|
||||
|
||||
// Others with multiple ranges in each RangeSet
|
||||
let others = [
|
||||
RangeSet::from(vec![1..3, 20..23]), // Covers part of first and third ranges
|
||||
RangeSet::from(vec![3..5, 10..12]), // Covers rest of first and part of second
|
||||
RangeSet::from(vec![12..15, 23..25]),
|
||||
];
|
||||
|
||||
let result = query.cover(others.iter()).unwrap();
|
||||
|
||||
assert_eq!(result.len(), 3);
|
||||
assert!(result.contains(&&others[0]));
|
||||
assert!(result.contains(&&others[1]));
|
||||
assert!(result.contains(&&others[2]));
|
||||
}
|
||||
|
||||
#[allow(clippy::single_range_in_vec_init)]
|
||||
#[test]
|
||||
fn test_complex_nested_subsets() {
|
||||
// query with multiple ranges
|
||||
let query = RangeSet::from(vec![1..10, 15..20]);
|
||||
|
||||
// Collection with nested subsets
|
||||
let others = [
|
||||
RangeSet::from(vec![1..9, 16..20]),
|
||||
RangeSet::from(vec![1..5, 16..18]),
|
||||
RangeSet::from(2..3),
|
||||
RangeSet::from(8..20), // Not a subset
|
||||
RangeSet::from(vec![9..10, 15..17]),
|
||||
RangeSet::from(vec![21..30]),
|
||||
];
|
||||
|
||||
let result = query.cover(others.iter()).unwrap();
|
||||
|
||||
assert_eq!(result.len(), 2);
|
||||
assert!(result.contains(&&others[0]));
|
||||
assert!(result.contains(&&others[4]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_unable_to_cover_simple() {
|
||||
let query = RangeSet::from(1..10);
|
||||
let others = [RangeSet::from(1..5), RangeSet::from(6..10)];
|
||||
|
||||
let result = query.cover(others.iter());
|
||||
assert!(result.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_unable_to_cover_multiple_ranges() {
|
||||
// query with multiple ranges
|
||||
let query = RangeSet::from(vec![1..10, 15..25, 30..35]);
|
||||
|
||||
// Collection with multiple ranges in each RangeSet
|
||||
let others = [
|
||||
RangeSet::from(vec![1..5, 16..20]), // Covers part of first and second ranges
|
||||
RangeSet::from(vec![5..8, 21..25]), // Covers part of first and second ranges
|
||||
RangeSet::from(vec![15..16, 30..33]), // Covers part of second and third ranges
|
||||
RangeSet::from(vec![9..10, 34..35]),
|
||||
];
|
||||
|
||||
let result = query.cover(others.iter());
|
||||
assert!(result.is_none());
|
||||
}
|
||||
}
|
||||
@@ -1,528 +0,0 @@
|
||||
use std::ops::{Range, Sub, SubAssign};
|
||||
|
||||
use crate::range::{Disjoint, RangeSet, Subset};
|
||||
|
||||
pub trait Difference<Rhs> {
|
||||
type Output;
|
||||
|
||||
/// Returns the set difference of `self` and `other`.
|
||||
#[must_use]
|
||||
fn difference(&self, other: &Rhs) -> Self::Output;
|
||||
}
|
||||
|
||||
pub trait DifferenceMut<Rhs> {
|
||||
/// Subtracts `other` from `self`.
|
||||
fn difference_mut(&mut self, other: &Rhs);
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> DifferenceMut<Range<T>> for RangeSet<T> {
|
||||
fn difference_mut(&mut self, other: &Range<T>) {
|
||||
if other.is_empty() || self.ranges.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut i = 0;
|
||||
let ranges = &mut self.ranges;
|
||||
while i < ranges.len() {
|
||||
// If the current range is entirely before other
|
||||
if ranges[i].end <= other.start {
|
||||
// no-op
|
||||
}
|
||||
// If the current range is entirely after other
|
||||
else if ranges[i].start >= other.end {
|
||||
// we're done
|
||||
break;
|
||||
}
|
||||
// If the current range is entirely contained within other
|
||||
else if ranges[i].is_subset(other) {
|
||||
ranges.remove(i);
|
||||
continue;
|
||||
}
|
||||
// If other is a subset of the current range
|
||||
else if other.is_subset(&ranges[i]) {
|
||||
if ranges[i].start == other.start {
|
||||
ranges[i].start = other.end;
|
||||
} else if ranges[i].end == other.end {
|
||||
ranges[i].end = other.start;
|
||||
} else {
|
||||
ranges.insert(i + 1, other.end..ranges[i].end);
|
||||
ranges[i].end = other.start;
|
||||
}
|
||||
} else {
|
||||
// Trim end
|
||||
if ranges[i].start < other.start {
|
||||
ranges[i].end = other.start;
|
||||
}
|
||||
|
||||
// Trim start
|
||||
if ranges[i].end > other.end {
|
||||
ranges[i].start = other.end;
|
||||
}
|
||||
}
|
||||
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> DifferenceMut<RangeSet<T>> for RangeSet<T> {
|
||||
fn difference_mut(&mut self, other: &RangeSet<T>) {
|
||||
for range in &other.ranges {
|
||||
self.difference_mut(range);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> Difference<Range<T>> for Range<T> {
|
||||
type Output = RangeSet<T>;
|
||||
|
||||
fn difference(&self, other: &Range<T>) -> Self::Output {
|
||||
if self.is_empty() {
|
||||
return RangeSet::default();
|
||||
} else if other.is_empty() {
|
||||
return RangeSet::from(self.clone());
|
||||
}
|
||||
|
||||
// If other contains self, return an empty set.
|
||||
if self.is_subset(other) {
|
||||
return RangeSet::default();
|
||||
}
|
||||
|
||||
// If they are disjoint, return self.
|
||||
if self.is_disjoint(other) {
|
||||
return RangeSet::from(self.clone());
|
||||
}
|
||||
|
||||
let mut set = RangeSet::default();
|
||||
|
||||
if self.start < other.start {
|
||||
set.ranges.push(self.start..other.start);
|
||||
}
|
||||
|
||||
if self.end > other.end {
|
||||
set.ranges.push(other.end..self.end);
|
||||
}
|
||||
|
||||
set
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> Difference<Range<T>> for RangeSet<T> {
|
||||
type Output = RangeSet<T>;
|
||||
|
||||
fn difference(&self, other: &Range<T>) -> Self::Output {
|
||||
let mut diff = self.clone();
|
||||
diff.difference_mut(other);
|
||||
diff
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> Difference<RangeSet<T>> for Range<T> {
|
||||
type Output = RangeSet<T>;
|
||||
|
||||
fn difference(&self, other: &RangeSet<T>) -> Self::Output {
|
||||
let mut diff = RangeSet {
|
||||
ranges: vec![self.clone()],
|
||||
};
|
||||
diff.difference_mut(other);
|
||||
diff
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> Difference<RangeSet<T>> for RangeSet<T> {
|
||||
type Output = RangeSet<T>;
|
||||
|
||||
fn difference(&self, other: &RangeSet<T>) -> Self::Output {
|
||||
let mut diff = self.clone();
|
||||
diff.difference_mut(other);
|
||||
diff
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> SubAssign<Range<T>> for RangeSet<T> {
|
||||
fn sub_assign(&mut self, rhs: Range<T>) {
|
||||
self.difference_mut(&rhs);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> SubAssign<&Range<T>> for RangeSet<T> {
|
||||
fn sub_assign(&mut self, rhs: &Range<T>) {
|
||||
self.difference_mut(rhs);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> Sub<Range<T>> for RangeSet<T> {
|
||||
type Output = RangeSet<T>;
|
||||
|
||||
fn sub(mut self, rhs: Range<T>) -> Self::Output {
|
||||
self.difference_mut(&rhs);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> Sub<&Range<T>> for RangeSet<T> {
|
||||
type Output = RangeSet<T>;
|
||||
|
||||
fn sub(mut self, rhs: &Range<T>) -> Self::Output {
|
||||
self.difference_mut(rhs);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> SubAssign<RangeSet<T>> for RangeSet<T> {
|
||||
fn sub_assign(&mut self, rhs: RangeSet<T>) {
|
||||
self.difference_mut(&rhs);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> SubAssign<&RangeSet<T>> for RangeSet<T> {
|
||||
fn sub_assign(&mut self, rhs: &RangeSet<T>) {
|
||||
self.difference_mut(rhs);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> Sub<RangeSet<T>> for RangeSet<T> {
|
||||
type Output = RangeSet<T>;
|
||||
|
||||
fn sub(mut self, rhs: RangeSet<T>) -> Self::Output {
|
||||
self.difference_mut(&rhs);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> Sub<&RangeSet<T>> for RangeSet<T> {
|
||||
type Output = RangeSet<T>;
|
||||
|
||||
fn sub(mut self, rhs: &RangeSet<T>) -> Self::Output {
|
||||
self.difference_mut(rhs);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::all)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::range::Union;
|
||||
|
||||
use itertools::iproduct;
|
||||
|
||||
// Yields every possible non-empty range bounded by `max` and `offset`.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
struct EveryNonEmptyRange {
|
||||
max: usize,
|
||||
offset: usize,
|
||||
start: usize,
|
||||
end: usize,
|
||||
}
|
||||
|
||||
impl EveryNonEmptyRange {
|
||||
fn new(max: usize, offset: usize) -> Self {
|
||||
Self {
|
||||
max,
|
||||
offset,
|
||||
start: 0,
|
||||
end: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for EveryNonEmptyRange {
|
||||
type Item = Range<usize>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.start >= self.max {
|
||||
return None;
|
||||
}
|
||||
|
||||
if self.end >= self.max {
|
||||
self.start += 1;
|
||||
self.end = self.start;
|
||||
}
|
||||
|
||||
let range = self.start + self.offset..self.end + self.offset;
|
||||
self.end += 1;
|
||||
|
||||
Some(range)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_difference() {
|
||||
let a = 10..20;
|
||||
|
||||
// rightward subset
|
||||
// [-----)
|
||||
// [-----)
|
||||
assert_eq!(a.difference(&(15..25)), RangeSet::from([(10..15)]));
|
||||
|
||||
// rightward aligned
|
||||
// [-----)
|
||||
// [-----)
|
||||
assert_eq!(a.difference(&(20..25)), RangeSet::from([(10..20)]));
|
||||
|
||||
// rightward aligned inclusive
|
||||
// [-----)
|
||||
// [-----)
|
||||
assert_eq!(a.difference(&(19..25)), RangeSet::from([(10..19)]));
|
||||
|
||||
// rightward disjoint
|
||||
// [-----)
|
||||
// [-----)
|
||||
assert_eq!(a.difference(&(25..30)), RangeSet::from([(10..20)]));
|
||||
|
||||
// leftward subset
|
||||
// [-----)
|
||||
// [-----)
|
||||
assert_eq!(a.difference(&(5..15)), RangeSet::from([(15..20)]));
|
||||
|
||||
// leftward aligned
|
||||
// [-----)
|
||||
// [-----)
|
||||
assert_eq!(a.difference(&(5..10)), RangeSet::from([(10..20)]));
|
||||
|
||||
// leftward aligned inclusive
|
||||
// [-----)
|
||||
// [-----)
|
||||
assert_eq!(a.difference(&(5..11)), RangeSet::from([(11..20)]));
|
||||
|
||||
// leftward disjoint
|
||||
// [-----)
|
||||
// [-----)
|
||||
assert_eq!(a.difference(&(0..5)), RangeSet::from([(10..20)]));
|
||||
|
||||
// superset
|
||||
assert_eq!(a.difference(&(5..25)), RangeSet::default());
|
||||
|
||||
// subset
|
||||
assert_eq!(
|
||||
a.difference(&(14..16)),
|
||||
RangeSet::from([(10..14), (16..20)])
|
||||
);
|
||||
|
||||
// equal
|
||||
assert_eq!(a.difference(&(10..20)), RangeSet::default());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_diff_set() {
|
||||
let a = 10..20;
|
||||
|
||||
// rightward subset
|
||||
// [-----)
|
||||
// [-----)
|
||||
let b = RangeSet::from([(15..25)]);
|
||||
assert_eq!(a.difference(&b), RangeSet::from([(10..15)]));
|
||||
|
||||
// leftward subset
|
||||
// [-----)
|
||||
// [-----)
|
||||
let b = RangeSet::from([(5..15)]);
|
||||
assert_eq!(a.difference(&b), RangeSet::from([(15..20)]));
|
||||
|
||||
// subset
|
||||
// [-----)
|
||||
// [--)
|
||||
let b = RangeSet::from([(12..15)]);
|
||||
assert_eq!(a.difference(&b), RangeSet::from([(10..12), (15..20)]));
|
||||
|
||||
// 2 subsets
|
||||
// [-------)
|
||||
// [-)[-)
|
||||
let b = RangeSet::from([(11..13), (15..18)]);
|
||||
assert_eq!(
|
||||
a.difference(&b),
|
||||
RangeSet::from([(10..11), (13..15), (18..20)])
|
||||
);
|
||||
|
||||
// 3 subsets
|
||||
// [---------)
|
||||
// [-)[-)[-)
|
||||
let b = RangeSet::from([(11..12), (13..15), (17..19)]);
|
||||
assert_eq!(
|
||||
a.difference(&b),
|
||||
RangeSet::from([(10..11), (12..13), (15..17), (19..20)])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_set_diff_range() {
|
||||
let a = RangeSet::from([(10..20), (30..40), (50..60)]);
|
||||
|
||||
// rightward subset
|
||||
// [-----) [-----) [-----)
|
||||
// [-----)
|
||||
assert_eq!(
|
||||
a.difference(&(15..35)),
|
||||
RangeSet::from([(10..15), (35..40), (50..60)])
|
||||
);
|
||||
|
||||
// leftward subset
|
||||
// [-----) [-----) [-----)
|
||||
// [-----)
|
||||
assert_eq!(
|
||||
a.difference(&(5..15)),
|
||||
RangeSet::from([(15..20), (30..40), (50..60)])
|
||||
);
|
||||
|
||||
// subset
|
||||
// [-----) [-----) [-----)
|
||||
// [--)
|
||||
assert_eq!(
|
||||
a.difference(&(12..15)),
|
||||
RangeSet::from([(10..12), (15..20), (30..40), (50..60)])
|
||||
);
|
||||
|
||||
// subset 2
|
||||
// [-----) [-----) [-----)
|
||||
// [--)
|
||||
assert_eq!(
|
||||
a.difference(&(35..38)),
|
||||
RangeSet::from([(10..20), (30..35), (38..40), (50..60)])
|
||||
);
|
||||
|
||||
// superset of 1
|
||||
// [-----) [-----) [-----)
|
||||
// [--------)
|
||||
assert_eq!(a.difference(&(5..25)), RangeSet::from([(30..40), (50..60)]));
|
||||
|
||||
// superset of 2
|
||||
// [-----) [-----) [-----)
|
||||
// [----------------)
|
||||
assert_eq!(a.difference(&(5..45)), RangeSet::from([(50..60)]));
|
||||
|
||||
// superset
|
||||
// [-----) [-----) [-----)
|
||||
// [------------------------)
|
||||
assert_eq!(a.difference(&(5..65)), RangeSet::default());
|
||||
|
||||
// leftwards disjoint
|
||||
// [-----) [-----) [-----)
|
||||
// [-----)
|
||||
assert_eq!(a.difference(&(0..5)), a);
|
||||
|
||||
// rightwards disjoint
|
||||
// [-----) [-----) [-----)
|
||||
// [-----)
|
||||
assert_eq!(a.difference(&(65..70)), a);
|
||||
|
||||
// disjoint
|
||||
// [-----) [-----) [-----)
|
||||
// [-----)
|
||||
assert_eq!(
|
||||
a.difference(&(25..28)),
|
||||
RangeSet::from([(10..20), (30..40), (50..60)])
|
||||
);
|
||||
|
||||
// empty
|
||||
assert_eq!(a.difference(&(0..0)), a);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "expensive"]
|
||||
fn test_prove_range_diff_range_16_16() {
|
||||
fn expected(x: Range<usize>, y: Range<usize>) -> Vec<usize> {
|
||||
x.filter(|x| !y.contains(x)).collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
for (xs, xe, ys, ye) in iproduct!(0..16, 0..16, 0..16, 0..16) {
|
||||
let set = (xs..xe).difference(&(ys..ye));
|
||||
|
||||
let actual = set
|
||||
.clone()
|
||||
.into_inner()
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(
|
||||
actual,
|
||||
expected(xs..xe, ys..ye),
|
||||
"{:?} {:?} => {:?}",
|
||||
xs..xe,
|
||||
ys..ye,
|
||||
set
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "expensive"]
|
||||
fn test_prove_range_diff_set_16_16x2() {
|
||||
fn expected(x: Range<usize>, y: Range<usize>, z: Range<usize>) -> Vec<usize> {
|
||||
let set = y.union(&z);
|
||||
x.filter(|x| !set.contains(x)).collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
for (xs, xe, ys, ye, zs, ze) in iproduct!(0..16, 0..16, 0..16, 0..16, 0..16, 0..16) {
|
||||
let set = (xs..xe).difference(&RangeSet::new(&[(ys..ye), (zs..ze)]));
|
||||
|
||||
let actual = set
|
||||
.clone()
|
||||
.into_inner()
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(
|
||||
actual,
|
||||
expected(xs..xe, ys..ye, zs..ze),
|
||||
"{:?} {:?} {:?} => {:?}",
|
||||
xs..xe,
|
||||
ys..ye,
|
||||
zs..ze,
|
||||
set
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Proves every set difference operation up to size 12,
|
||||
// with up to 4 non-empty partitions.
|
||||
#[test]
|
||||
#[ignore = "expensive"]
|
||||
fn test_prove_set_diff_set_12x4_12x4() {
|
||||
#[allow(clippy::all)]
|
||||
fn expected(
|
||||
a: Range<usize>,
|
||||
b: Range<usize>,
|
||||
c: Range<usize>,
|
||||
d: Range<usize>,
|
||||
e: Range<usize>,
|
||||
f: Range<usize>,
|
||||
g: Range<usize>,
|
||||
h: Range<usize>,
|
||||
) -> Vec<usize> {
|
||||
let s2 = e.union(&f).union(&g).union(&h);
|
||||
a.union(&b)
|
||||
.union(&c)
|
||||
.union(&d)
|
||||
.iter()
|
||||
.filter(|x| !s2.contains(x))
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
for (a, b, c, d, e, f, g, h) in iproduct!(
|
||||
EveryNonEmptyRange::new(3, 0),
|
||||
EveryNonEmptyRange::new(3, 3),
|
||||
EveryNonEmptyRange::new(3, 6),
|
||||
EveryNonEmptyRange::new(3, 9),
|
||||
EveryNonEmptyRange::new(3, 0),
|
||||
EveryNonEmptyRange::new(3, 3),
|
||||
EveryNonEmptyRange::new(3, 6),
|
||||
EveryNonEmptyRange::new(3, 9)
|
||||
) {
|
||||
let set = RangeSet::new(&[a.clone(), b.clone(), c.clone(), d.clone()]).difference(
|
||||
&RangeSet::new(&[e.clone(), f.clone(), g.clone(), h.clone()]),
|
||||
);
|
||||
|
||||
let actual = set
|
||||
.clone()
|
||||
.into_inner()
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(actual, expected(a, b, c, d, e, f, g, h),);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
use super::RangeSet;
|
||||
|
||||
/// A trait implemented for collections which can be indexed by a range set.
|
||||
pub trait IndexRanges<T: Copy + Ord = usize> {
|
||||
/// The output type of the indexing operation.
|
||||
type Output;
|
||||
|
||||
/// Index the collection by the given range set.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if any of the indices in the range set are out of bounds of the collection.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use utils::range::{RangeSet, IndexRanges};
|
||||
///
|
||||
/// let data = [1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
/// let index = RangeSet::from([(0..3), (5..8)]);
|
||||
///
|
||||
/// assert_eq!(data.index_ranges(&index), vec![1, 2, 3, 6, 7, 8]);
|
||||
/// ```
|
||||
fn index_ranges(&self, ranges: &RangeSet<T>) -> Self::Output;
|
||||
}
|
||||
|
||||
impl<T: Clone> IndexRanges for [T] {
|
||||
type Output = Vec<T>;
|
||||
|
||||
#[inline]
|
||||
fn index_ranges(&self, index: &RangeSet<usize>) -> Self::Output {
|
||||
let mut out = Vec::with_capacity(index.len());
|
||||
for range in index.iter_ranges() {
|
||||
out.extend_from_slice(&self[range]);
|
||||
}
|
||||
out
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexRanges for str {
|
||||
type Output = String;
|
||||
|
||||
#[inline]
|
||||
fn index_ranges(&self, index: &RangeSet<usize>) -> Self::Output {
|
||||
let mut out = String::with_capacity(index.len());
|
||||
for range in index.iter_ranges() {
|
||||
out.push_str(&self[range]);
|
||||
}
|
||||
out
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_index_ranges_slice() {
|
||||
let data = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
let index = RangeSet::from([(0..3), (5..8)]);
|
||||
|
||||
assert_eq!(data.index_ranges(&index), vec![1, 2, 3, 6, 7, 8]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_index_empty_ranges_slice() {
|
||||
let data = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
let index = RangeSet::from([]);
|
||||
|
||||
assert_eq!(data.index_ranges(&index), vec![]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_index_ranges_out_of_bounds_slice() {
|
||||
let data = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
let index = RangeSet::from([(0..3), (5..8), (10..12)]);
|
||||
|
||||
data.index_ranges(&index);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_index_ranges_str() {
|
||||
let data = "123456789";
|
||||
let index = RangeSet::from([(0..3), (5..8)]);
|
||||
|
||||
assert_eq!(data.index_ranges(&index), "123678");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_index_empty_ranges_str() {
|
||||
let data = "123456789";
|
||||
let index = RangeSet::from([]);
|
||||
|
||||
assert_eq!(data.index_ranges(&index), "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_index_ranges_out_of_bounds_str() {
|
||||
let data = "123456789";
|
||||
let index = RangeSet::from([(0..3), (5..8), (10..12)]);
|
||||
|
||||
data.index_ranges(&index);
|
||||
}
|
||||
}
|
||||
@@ -1,280 +0,0 @@
|
||||
use std::ops::{BitAnd, BitAndAssign};
|
||||
|
||||
use crate::range::{Range, RangeSet};
|
||||
|
||||
pub trait Intersection<Rhs> {
|
||||
type Output;
|
||||
|
||||
/// Returns the set intersection of `self` and `other`.
|
||||
#[must_use]
|
||||
fn intersection(&self, other: &Rhs) -> Self::Output;
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> BitAndAssign<Range<T>> for RangeSet<T> {
|
||||
fn bitand_assign(&mut self, other: Range<T>) {
|
||||
*self = self.intersection(&other);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> BitAndAssign<&Range<T>> for RangeSet<T> {
|
||||
fn bitand_assign(&mut self, other: &Range<T>) {
|
||||
*self = self.intersection(other);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> BitAnd<RangeSet<T>> for Range<T> {
|
||||
type Output = RangeSet<T>;
|
||||
|
||||
fn bitand(self, other: RangeSet<T>) -> Self::Output {
|
||||
self.intersection(&other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> BitAnd<&RangeSet<T>> for Range<T> {
|
||||
type Output = RangeSet<T>;
|
||||
|
||||
fn bitand(self, other: &RangeSet<T>) -> Self::Output {
|
||||
self.intersection(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> BitAnd<Range<T>> for RangeSet<T> {
|
||||
type Output = RangeSet<T>;
|
||||
|
||||
fn bitand(self, other: Range<T>) -> Self::Output {
|
||||
other.intersection(&self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> BitAnd<&Range<T>> for RangeSet<T> {
|
||||
type Output = RangeSet<T>;
|
||||
|
||||
fn bitand(self, other: &Range<T>) -> Self::Output {
|
||||
other.intersection(&self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> BitAndAssign<RangeSet<T>> for RangeSet<T> {
|
||||
fn bitand_assign(&mut self, other: RangeSet<T>) {
|
||||
*self = self.intersection(&other);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> BitAndAssign<&RangeSet<T>> for RangeSet<T> {
|
||||
fn bitand_assign(&mut self, other: &RangeSet<T>) {
|
||||
*self = self.intersection(other);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> BitAnd<RangeSet<T>> for RangeSet<T> {
|
||||
type Output = RangeSet<T>;
|
||||
|
||||
fn bitand(self, other: RangeSet<T>) -> Self::Output {
|
||||
self.intersection(&other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> BitAnd<&RangeSet<T>> for RangeSet<T> {
|
||||
type Output = RangeSet<T>;
|
||||
|
||||
fn bitand(self, other: &RangeSet<T>) -> Self::Output {
|
||||
self.intersection(other)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::single_range_in_vec_init)]
|
||||
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
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,584 +0,0 @@
|
||||
mod cover;
|
||||
mod difference;
|
||||
mod index;
|
||||
mod intersection;
|
||||
mod subset;
|
||||
mod symmetric_difference;
|
||||
mod union;
|
||||
|
||||
pub use cover::Cover;
|
||||
pub use difference::{Difference, DifferenceMut};
|
||||
pub use index::IndexRanges;
|
||||
pub use intersection::Intersection;
|
||||
pub use subset::Subset;
|
||||
pub use symmetric_difference::{SymmetricDifference, SymmetricDifferenceMut};
|
||||
pub use union::{Union, UnionMut};
|
||||
|
||||
use std::ops::{Add, Range, Sub};
|
||||
|
||||
/// A set of values represented using ranges.
|
||||
///
|
||||
/// A `RangeSet` is similar to any other kind of set, such as `HashSet`, with the difference being that the
|
||||
/// values in the set are represented using ranges rather than storing each value individually.
|
||||
///
|
||||
/// # Invariants
|
||||
///
|
||||
/// `RangeSet` enforces the following invariants on the ranges it contains:
|
||||
///
|
||||
/// - The ranges are sorted.
|
||||
/// - The ranges are non-adjacent.
|
||||
/// - The ranges are non-intersecting.
|
||||
/// - The ranges are non-empty.
|
||||
///
|
||||
/// This is enforced in the constructor, and guaranteed to hold after applying any operation on a range or set.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use utils::range::*;
|
||||
///
|
||||
/// let a = 10..20;
|
||||
///
|
||||
/// // Difference
|
||||
/// assert_eq!(a.difference(&(15..25)), RangeSet::from([10..15]));
|
||||
/// assert_eq!(a.difference(&(12..15)), RangeSet::from([(10..12), (15..20)]));
|
||||
///
|
||||
/// // Union
|
||||
/// assert_eq!(a.union(&(15..25)), RangeSet::from([10..25]));
|
||||
/// assert_eq!(a.union(&(0..0)), RangeSet::from([10..20]));
|
||||
///
|
||||
/// // Comparison
|
||||
/// assert!(a.is_subset(&(0..30)));
|
||||
/// assert!(a.is_disjoint(&(0..10)));
|
||||
/// assert_eq!(a.clone(), RangeSet::from(a));
|
||||
/// ```
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[cfg_attr(
|
||||
feature = "serde",
|
||||
serde(
|
||||
bound = "for<'a> T: serde::Serialize + serde::de::Deserialize<'a> + Copy + Ord",
|
||||
from = "Vec<Range<T>>",
|
||||
into = "Vec<Range<T>>"
|
||||
)
|
||||
)]
|
||||
pub struct RangeSet<T> {
|
||||
/// The ranges of the set.
|
||||
///
|
||||
/// The ranges *MUST* be sorted, non-adjacent, non-intersecting, and non-empty.
|
||||
ranges: Vec<Range<T>>,
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> From<Vec<Range<T>>> for RangeSet<T> {
|
||||
fn from(ranges: Vec<Range<T>>) -> Self {
|
||||
Self::new(&ranges)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<RangeSet<T>> for Vec<Range<T>> {
|
||||
fn from(ranges: RangeSet<T>) -> Self {
|
||||
ranges.into_inner()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> Default for RangeSet<T> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
ranges: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> RangeSet<T> {
|
||||
/// Returns the ranges of the set.
|
||||
pub fn into_inner(self) -> Vec<Range<T>> {
|
||||
self.ranges
|
||||
}
|
||||
|
||||
/// Returns `true` if the set is empty.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.ranges.is_empty()
|
||||
}
|
||||
|
||||
/// Returns the number of ranges in the set.
|
||||
pub fn len_ranges(&self) -> usize {
|
||||
self.ranges.len()
|
||||
}
|
||||
|
||||
/// Clears the set, removing all ranges.
|
||||
pub fn clear(&mut self) {
|
||||
self.ranges.clear();
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> RangeSet<T> {
|
||||
/// Returns a new `RangeSet` from the given ranges.
|
||||
///
|
||||
/// The `RangeSet` is constructed by computing the union of the given ranges.
|
||||
pub fn new(ranges: &[Range<T>]) -> Self
|
||||
where
|
||||
Self: Union<Range<T>, Output = Self>,
|
||||
{
|
||||
let mut set = Self::default();
|
||||
|
||||
for range in ranges {
|
||||
set = set.union(range);
|
||||
}
|
||||
|
||||
set
|
||||
}
|
||||
|
||||
/// Returns an iterator over the values in the set.
|
||||
pub fn iter(&self) -> RangeSetIter<'_, T> {
|
||||
RangeSetIter {
|
||||
iter: self.ranges.iter(),
|
||||
current: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an iterator over the ranges in the set.
|
||||
pub fn iter_ranges(&self) -> RangeIter<'_, T> {
|
||||
RangeIter {
|
||||
iter: self.ranges.iter(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the set contains the given value.
|
||||
pub fn contains(&self, value: &T) -> bool {
|
||||
self.ranges.iter().any(|range| range.contains(value))
|
||||
}
|
||||
|
||||
/// Returns the minimum value in the set, or `None` if the set is empty.
|
||||
pub fn min(&self) -> Option<T> {
|
||||
self.ranges.first().map(|range| range.start)
|
||||
}
|
||||
|
||||
/// Returns the end of right-most range in the set, or `None` if the set is empty.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// This is the *non-inclusive* bound of the right-most range. See `RangeSet::max` for the
|
||||
/// maximum value in the set.
|
||||
pub fn end(&self) -> Option<T> {
|
||||
self.ranges.last().map(|range| range.end)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord + Step + Sub<Output = T>> RangeSet<T> {
|
||||
/// Returns the maximum value in the set, or `None` if the set is empty.
|
||||
pub fn max(&self) -> Option<T> {
|
||||
// This should never underflow because of the invariant that a set
|
||||
// never contains empty ranges.
|
||||
self.ranges
|
||||
.last()
|
||||
.map(|range| Step::backward(range.end, 1).expect("set is not empty"))
|
||||
}
|
||||
|
||||
/// Splits the set into two at the provided value.
|
||||
///
|
||||
/// Returns a new set containing all the existing elements `>= at`. After the call,
|
||||
/// the original set will be left containing the elements `< at`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `at` is not in the set.
|
||||
pub fn split_off(&mut self, at: &T) -> Self {
|
||||
// Find the index of the range containing `at`
|
||||
let idx = self
|
||||
.ranges
|
||||
.iter()
|
||||
.position(|range| range.contains(at))
|
||||
.expect("`at` is in the set");
|
||||
|
||||
// Split off the range containing `at` and all the ranges to the right.
|
||||
let mut split_ranges = self.ranges.split_off(idx);
|
||||
|
||||
// If the first range starts before `at` we have to push those values back
|
||||
// into the existing set and truncate.
|
||||
if *at > split_ranges[0].start {
|
||||
self.ranges.push(Range {
|
||||
start: split_ranges[0].start,
|
||||
end: *at,
|
||||
});
|
||||
split_ranges[0].start = *at;
|
||||
}
|
||||
|
||||
Self {
|
||||
ranges: split_ranges,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord + Sub<Output = T>> RangeSet<T> {
|
||||
/// Shifts every range in the set to the left by the provided offset.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the shift causes an underflow.
|
||||
pub fn shift_left(&mut self, offset: &T) {
|
||||
self.ranges.iter_mut().for_each(|range| {
|
||||
range.start = range.start - *offset;
|
||||
range.end = range.end - *offset;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord + Add<Output = T>> RangeSet<T> {
|
||||
/// Shifts every range in the set to the right by the provided offset.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the the shift causes an overflow.
|
||||
pub fn shift_right(&mut self, offset: &T) {
|
||||
self.ranges.iter_mut().for_each(|range| {
|
||||
range.start = range.start + *offset;
|
||||
range.end = range.end + *offset;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> RangeSet<T>
|
||||
where
|
||||
Range<T>: ExactSizeIterator<Item = T>,
|
||||
{
|
||||
/// Returns the number of values in the set.
|
||||
#[must_use]
|
||||
pub fn len(&self) -> usize {
|
||||
self.ranges.iter().map(|range| range.len()).sum()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> TryFrom<RangeSet<T>> for Range<T> {
|
||||
type Error = RangeSet<T>;
|
||||
|
||||
/// Attempts to convert a `RangeSet` into a single `Range`, returning the set if it
|
||||
/// does not contain exactly one range.
|
||||
fn try_from(set: RangeSet<T>) -> Result<Self, Self::Error> {
|
||||
if set.len_ranges() == 1 {
|
||||
Ok(set.ranges.into_iter().next().unwrap())
|
||||
} else {
|
||||
Err(set)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> From<Range<T>> for RangeSet<T> {
|
||||
fn from(range: Range<T>) -> Self {
|
||||
if range.is_empty() {
|
||||
return Self::default();
|
||||
}
|
||||
|
||||
Self {
|
||||
ranges: Vec::from([range]),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize, T: Copy + Ord> From<[Range<T>; N]> for RangeSet<T> {
|
||||
fn from(ranges: [Range<T>; N]) -> Self {
|
||||
Self::new(&ranges)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> From<&[Range<T>]> for RangeSet<T> {
|
||||
fn from(ranges: &[Range<T>]) -> Self {
|
||||
Self::new(ranges)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> PartialEq<Range<T>> for RangeSet<T> {
|
||||
fn eq(&self, other: &Range<T>) -> bool {
|
||||
self.ranges.len() == 1 && self.ranges[0] == *other
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> PartialEq<Range<T>> for &RangeSet<T> {
|
||||
fn eq(&self, other: &Range<T>) -> bool {
|
||||
*self == other
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> PartialEq<RangeSet<T>> for Range<T> {
|
||||
fn eq(&self, other: &RangeSet<T>) -> bool {
|
||||
other == self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> PartialEq<RangeSet<T>> for &Range<T> {
|
||||
fn eq(&self, other: &RangeSet<T>) -> bool {
|
||||
other == *self
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over the values in a `RangeSet`.
|
||||
pub struct RangeSetIter<'a, T> {
|
||||
iter: std::slice::Iter<'a, Range<T>>,
|
||||
current: Option<Range<T>>,
|
||||
}
|
||||
|
||||
impl<T> Iterator for RangeSetIter<'_, T>
|
||||
where
|
||||
T: Copy + Ord,
|
||||
Range<T>: Iterator<Item = T>,
|
||||
{
|
||||
type Item = T;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if let Some(range) = &mut self.current {
|
||||
if let Some(value) = range.next() {
|
||||
return Some(value);
|
||||
} else {
|
||||
self.current = None;
|
||||
return self.next();
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(range) = self.iter.next() {
|
||||
self.current = Some(range.clone());
|
||||
return self.next();
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over the ranges in a `RangeSet`.
|
||||
pub struct RangeIter<'a, T> {
|
||||
iter: std::slice::Iter<'a, Range<T>>,
|
||||
}
|
||||
|
||||
impl<T> Iterator for RangeIter<'_, T>
|
||||
where
|
||||
T: Copy + Ord,
|
||||
Range<T>: Iterator<Item = T>,
|
||||
{
|
||||
type Item = Range<T>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.iter.next().cloned()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ExactSizeIterator for RangeIter<'_, T>
|
||||
where
|
||||
T: Copy + Ord,
|
||||
Range<T>: Iterator<Item = T>,
|
||||
{
|
||||
fn len(&self) -> usize {
|
||||
self.iter.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DoubleEndedIterator for RangeIter<'_, T>
|
||||
where
|
||||
T: Copy + Ord,
|
||||
Range<T>: Iterator<Item = T>,
|
||||
{
|
||||
fn next_back(&mut self) -> Option<Self::Item> {
|
||||
self.iter.next_back().cloned()
|
||||
}
|
||||
}
|
||||
|
||||
/// A type which has a corresponding range set.
|
||||
pub trait ToRangeSet<T: Copy + Ord> {
|
||||
/// Returns a corresponding range set.
|
||||
fn to_range_set(&self) -> RangeSet<T>;
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> ToRangeSet<T> for RangeSet<T> {
|
||||
fn to_range_set(&self) -> RangeSet<T> {
|
||||
self.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> ToRangeSet<T> for Range<T> {
|
||||
fn to_range_set(&self) -> RangeSet<T> {
|
||||
RangeSet::from(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Disjoint<Rhs> {
|
||||
/// Returns `true` if the range is disjoint with `other`.
|
||||
#[must_use]
|
||||
fn is_disjoint(&self, other: &Rhs) -> bool;
|
||||
}
|
||||
|
||||
pub trait Contains<Rhs> {
|
||||
/// Returns `true` if `self` contains `other`.
|
||||
#[must_use]
|
||||
fn contains(&self, other: &Rhs) -> bool;
|
||||
}
|
||||
|
||||
/// A type which successor and predecessor operations can be performed on.
|
||||
///
|
||||
/// Similar to `std::iter::Step`, but not nightly-only.
|
||||
pub trait Step: Sized {
|
||||
/// Steps forwards by `count` elements.
|
||||
fn forward(start: Self, count: usize) -> Option<Self>;
|
||||
|
||||
/// Steps backwards by `count` elements.
|
||||
fn backward(start: Self, count: usize) -> Option<Self>;
|
||||
}
|
||||
|
||||
macro_rules! impl_step {
|
||||
($($ty:ty),+) => {
|
||||
$(
|
||||
impl Step for $ty {
|
||||
fn forward(start: Self, count: usize) -> Option<Self> {
|
||||
start.checked_add(count as Self)
|
||||
}
|
||||
|
||||
fn backward(start: Self, count: usize) -> Option<Self> {
|
||||
start.checked_sub(count as Self)
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
impl_step!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
|
||||
|
||||
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> 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> 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> Disjoint<Range<T>> for RangeSet<T> {
|
||||
fn is_disjoint(&self, other: &Range<T>) -> bool {
|
||||
other.is_disjoint(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// 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)]
|
||||
#[allow(clippy::all)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use rstest::*;
|
||||
|
||||
#[test]
|
||||
fn test_range_disjoint() {
|
||||
let a = 10..20;
|
||||
|
||||
// rightward
|
||||
assert!(a.is_disjoint(&(20..30)));
|
||||
// rightward aligned
|
||||
assert!(!a.is_disjoint(&(19..25)));
|
||||
// leftward
|
||||
assert!(a.is_disjoint(&(0..10)));
|
||||
// leftward aligned
|
||||
assert!(!a.is_disjoint(&(5..11)));
|
||||
// rightward subset
|
||||
assert!(!a.is_disjoint(&(15..25)));
|
||||
// leftward subset
|
||||
assert!(!a.is_disjoint(&(5..15)));
|
||||
// superset
|
||||
assert!(!a.is_disjoint(&(5..25)));
|
||||
// equal
|
||||
assert!(!a.is_disjoint(&(10..20)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_set_iter() {
|
||||
let a = RangeSet::from([(10..20), (30..40), (50..60)]);
|
||||
|
||||
let values = a.iter().collect::<Vec<_>>();
|
||||
let expected_values = (10..20).chain(30..40).chain(50..60).collect::<Vec<_>>();
|
||||
assert_eq!(values, expected_values);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_iter() {
|
||||
let a = RangeSet::from([(10..20), (30..40), (50..60)]);
|
||||
|
||||
let values = a.iter_ranges().collect::<Vec<_>>();
|
||||
let expected_values = vec![10..20, 30..40, 50..60];
|
||||
|
||||
assert_eq!(values, expected_values);
|
||||
|
||||
let reversed_values = a.iter_ranges().rev().collect::<Vec<_>>();
|
||||
let expected_reversed_values = vec![50..60, 30..40, 10..20];
|
||||
|
||||
assert_eq!(reversed_values, expected_reversed_values);
|
||||
|
||||
let mut iter = a.iter_ranges();
|
||||
assert_eq!(iter.len(), 3);
|
||||
_ = iter.next();
|
||||
assert_eq!(iter.len(), 2);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case(RangeSet::from([(0..1)]), 0)]
|
||||
#[case(RangeSet::from([(0..5)]), 1)]
|
||||
#[case(RangeSet::from([(0..5), (6..10)]), 4)]
|
||||
#[case(RangeSet::from([(0..5), (6..10)]), 6)]
|
||||
#[case(RangeSet::from([(0..5), (6..10)]), 9)]
|
||||
fn test_range_set_split_off(#[case] set: RangeSet<usize>, #[case] at: usize) {
|
||||
let mut a = set.clone();
|
||||
let b = a.split_off(&at);
|
||||
|
||||
assert!(a
|
||||
.ranges
|
||||
.last()
|
||||
.map(|range| !range.is_empty())
|
||||
.unwrap_or(true));
|
||||
assert!(b
|
||||
.ranges
|
||||
.first()
|
||||
.map(|range| !range.is_empty())
|
||||
.unwrap_or(true));
|
||||
assert_eq!(a.len() + b.len(), set.len());
|
||||
assert!(a.iter().chain(b.iter()).eq(set.iter()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic = "`at` is in the set"]
|
||||
fn test_range_set_split_off_panic_not_in_set() {
|
||||
RangeSet::from([0..1]).split_off(&1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_set_shift_left() {
|
||||
let mut a = RangeSet::from([(1..5), (6..10)]);
|
||||
a.shift_left(&1);
|
||||
|
||||
assert_eq!(a, RangeSet::from([(0..4), (5..9)]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_set_shift_right() {
|
||||
let mut a = RangeSet::from([(0..4), (5..9)]);
|
||||
a.shift_right(&1);
|
||||
|
||||
assert_eq!(a, RangeSet::from([(1..5), (6..10)]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_set_max() {
|
||||
assert!(RangeSet::<u8>::default().max().is_none());
|
||||
assert_eq!(RangeSet::from([0..1]).max(), Some(0));
|
||||
assert_eq!(RangeSet::from([0..2]).max(), Some(1));
|
||||
assert_eq!(RangeSet::from([(0..5), (6..10)]).max(), Some(9));
|
||||
}
|
||||
}
|
||||
@@ -1,186 +0,0 @@
|
||||
use crate::range::{Range, RangeSet};
|
||||
|
||||
pub trait Subset<Rhs> {
|
||||
/// Returns `true` if `self` is a subset of `other`.
|
||||
#[must_use]
|
||||
fn is_subset(&self, other: &Rhs) -> bool;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// Boundary short circuit.
|
||||
if self.start < other.min().unwrap() || self.end > other.end().unwrap() {
|
||||
// Check if self's start & end are contained within (or same as) other's.
|
||||
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;
|
||||
}
|
||||
|
||||
// Boundary short circuit.
|
||||
if self.min().unwrap() < other.min().unwrap() || self.end().unwrap() > other.end().unwrap()
|
||||
{
|
||||
// Check if self's start & end are contained within (or same as) other's.
|
||||
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)]
|
||||
#[allow(clippy::single_range_in_vec_init)]
|
||||
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])));
|
||||
}
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
use std::ops::{BitXor, BitXorAssign, Range};
|
||||
|
||||
use crate::range::{DifferenceMut, Intersection, RangeSet, UnionMut};
|
||||
|
||||
pub trait SymmetricDifferenceMut<Rhs> {
|
||||
/// Replaces `self` with the set symmetric difference of `self` and `other`.
|
||||
fn symmetric_difference_mut(&mut self, other: &Rhs);
|
||||
}
|
||||
|
||||
pub trait SymmetricDifference<Rhs> {
|
||||
type Output;
|
||||
|
||||
/// Returns the set symmetric difference of `self` and `other`.
|
||||
fn symmetric_difference(&self, other: &Rhs) -> Self::Output;
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> SymmetricDifferenceMut<Range<T>> for RangeSet<T> {
|
||||
fn symmetric_difference_mut(&mut self, other: &Range<T>) {
|
||||
let intersection = self.intersection(other);
|
||||
self.union_mut(other);
|
||||
self.difference_mut(&intersection);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> SymmetricDifferenceMut<RangeSet<T>> for RangeSet<T> {
|
||||
fn symmetric_difference_mut(&mut self, other: &RangeSet<T>) {
|
||||
let intersection = self.intersection(other);
|
||||
self.union_mut(other);
|
||||
self.difference_mut(&intersection);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> SymmetricDifference<Range<T>> for RangeSet<T> {
|
||||
type Output = RangeSet<T>;
|
||||
|
||||
fn symmetric_difference(&self, other: &Range<T>) -> Self::Output {
|
||||
let mut output = self.clone();
|
||||
output.symmetric_difference_mut(other);
|
||||
output
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> SymmetricDifference<RangeSet<T>> for RangeSet<T> {
|
||||
type Output = RangeSet<T>;
|
||||
|
||||
fn symmetric_difference(&self, other: &RangeSet<T>) -> Self::Output {
|
||||
let mut output = self.clone();
|
||||
output.symmetric_difference_mut(other);
|
||||
output
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> BitXor<Range<T>> for RangeSet<T> {
|
||||
type Output = RangeSet<T>;
|
||||
|
||||
fn bitxor(mut self, rhs: Range<T>) -> Self::Output {
|
||||
self.symmetric_difference_mut(&rhs);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> BitXor<&Range<T>> for RangeSet<T> {
|
||||
type Output = RangeSet<T>;
|
||||
|
||||
fn bitxor(mut self, rhs: &Range<T>) -> Self::Output {
|
||||
self.symmetric_difference_mut(rhs);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> BitXor<RangeSet<T>> for RangeSet<T> {
|
||||
type Output = RangeSet<T>;
|
||||
|
||||
fn bitxor(mut self, rhs: RangeSet<T>) -> Self::Output {
|
||||
self.symmetric_difference_mut(&rhs);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> BitXor<&RangeSet<T>> for RangeSet<T> {
|
||||
type Output = RangeSet<T>;
|
||||
|
||||
fn bitxor(mut self, rhs: &RangeSet<T>) -> Self::Output {
|
||||
self.symmetric_difference_mut(rhs);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> BitXor<RangeSet<T>> for &RangeSet<T> {
|
||||
type Output = RangeSet<T>;
|
||||
|
||||
fn bitxor(self, rhs: RangeSet<T>) -> Self::Output {
|
||||
self.symmetric_difference(&rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> BitXorAssign<RangeSet<T>> for RangeSet<T> {
|
||||
fn bitxor_assign(&mut self, rhs: RangeSet<T>) {
|
||||
self.symmetric_difference_mut(&rhs);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> BitXorAssign<&RangeSet<T>> for RangeSet<T> {
|
||||
fn bitxor_assign(&mut self, rhs: &RangeSet<T>) {
|
||||
self.symmetric_difference_mut(rhs);
|
||||
}
|
||||
}
|
||||
@@ -1,449 +0,0 @@
|
||||
use std::ops::{BitOr, BitOrAssign, Range};
|
||||
|
||||
use crate::range::{Disjoint, RangeSet, Subset};
|
||||
|
||||
pub trait UnionMut<Rhs> {
|
||||
/// Replaces `self` with the set union of `self` and `other`.
|
||||
fn union_mut(&mut self, other: &Rhs);
|
||||
}
|
||||
|
||||
pub trait Union<Rhs> {
|
||||
type Output;
|
||||
|
||||
/// Returns the set union of `self` and `other`.
|
||||
#[must_use]
|
||||
fn union(&self, other: &Rhs) -> Self::Output;
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> UnionMut<Range<T>> for RangeSet<T> {
|
||||
fn union_mut(&mut self, other: &Range<T>) {
|
||||
if other.is_empty() {
|
||||
return;
|
||||
} else if self.ranges.is_empty() {
|
||||
self.ranges.push(other.clone());
|
||||
return;
|
||||
}
|
||||
|
||||
let ranges = &mut self.ranges;
|
||||
|
||||
let mut i = 0;
|
||||
let mut new_range = other.clone();
|
||||
while i < ranges.len() {
|
||||
// If the new_range comes before the current range without overlapping
|
||||
if new_range.end < ranges[i].start {
|
||||
ranges.insert(i, new_range);
|
||||
|
||||
return;
|
||||
}
|
||||
// If the new_range overlaps or is adjacent with the current range
|
||||
else if new_range.start <= ranges[i].end {
|
||||
// Expand new_range to include the current range
|
||||
new_range.start = new_range.start.min(ranges[i].start);
|
||||
new_range.end = new_range.end.max(ranges[i].end);
|
||||
// Remove the current range as it is now included in new_range
|
||||
ranges.remove(i);
|
||||
}
|
||||
// If the new_range comes after the current range
|
||||
else {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// If the new_range comes after all the ranges, add it to the end
|
||||
ranges.push(new_range);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> UnionMut<RangeSet<T>> for RangeSet<T> {
|
||||
fn union_mut(&mut self, other: &RangeSet<T>) {
|
||||
for range in &other.ranges {
|
||||
self.union_mut(range);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 || other.is_subset(self) {
|
||||
return RangeSet::from(self.clone());
|
||||
}
|
||||
|
||||
// If other contains self, return other.
|
||||
if self.is_subset(other) {
|
||||
return RangeSet::from(other.clone());
|
||||
}
|
||||
|
||||
// If they are disjoint, return a set containing both, making sure
|
||||
// the ranges are in order.
|
||||
if self.is_disjoint(other) {
|
||||
if self.start < other.start {
|
||||
return RangeSet::new(&[self.clone(), other.clone()]);
|
||||
} else {
|
||||
return RangeSet::new(&[other.clone(), self.clone()]);
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, return a set containing the union of the two.
|
||||
let start = self.start.min(other.start);
|
||||
let end = self.end.max(other.end);
|
||||
|
||||
RangeSet::from(start..end)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> Union<RangeSet<T>> for Range<T> {
|
||||
type Output = RangeSet<T>;
|
||||
|
||||
fn union(&self, other: &RangeSet<T>) -> Self::Output {
|
||||
let mut other = other.clone();
|
||||
other.union_mut(self);
|
||||
other
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> Union<Range<T>> for RangeSet<T> {
|
||||
type Output = RangeSet<T>;
|
||||
|
||||
fn union(&self, other: &Range<T>) -> Self::Output {
|
||||
other.union(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> Union<RangeSet<T>> for RangeSet<T> {
|
||||
type Output = RangeSet<T>;
|
||||
|
||||
fn union(&self, other: &RangeSet<T>) -> Self::Output {
|
||||
let mut union = self.clone();
|
||||
union.union_mut(other);
|
||||
union
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> BitOrAssign<Range<T>> for RangeSet<T> {
|
||||
fn bitor_assign(&mut self, other: Range<T>) {
|
||||
self.union_mut(&other);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> BitOrAssign<&Range<T>> for RangeSet<T> {
|
||||
fn bitor_assign(&mut self, other: &Range<T>) {
|
||||
self.union_mut(other);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> BitOr<Range<T>> for RangeSet<T> {
|
||||
type Output = RangeSet<T>;
|
||||
|
||||
fn bitor(mut self, other: Range<T>) -> Self::Output {
|
||||
self.union_mut(&other);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> BitOr<&Range<T>> for RangeSet<T> {
|
||||
type Output = RangeSet<T>;
|
||||
|
||||
fn bitor(mut self, other: &Range<T>) -> Self::Output {
|
||||
self.union_mut(other);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> BitOrAssign<RangeSet<T>> for RangeSet<T> {
|
||||
fn bitor_assign(&mut self, other: RangeSet<T>) {
|
||||
self.union_mut(&other);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> BitOrAssign<&RangeSet<T>> for RangeSet<T> {
|
||||
fn bitor_assign(&mut self, other: &RangeSet<T>) {
|
||||
self.union_mut(other);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> BitOr<RangeSet<T>> for RangeSet<T> {
|
||||
type Output = RangeSet<T>;
|
||||
|
||||
fn bitor(mut self, other: RangeSet<T>) -> Self::Output {
|
||||
self.union_mut(&other);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> BitOr<&RangeSet<T>> for RangeSet<T> {
|
||||
type Output = RangeSet<T>;
|
||||
|
||||
fn bitor(mut self, other: &RangeSet<T>) -> Self::Output {
|
||||
self.union_mut(other);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::all)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use itertools::iproduct;
|
||||
|
||||
#[test]
|
||||
fn test_range_union() {
|
||||
let a = 10..20;
|
||||
|
||||
// rightward subset
|
||||
// [-----)
|
||||
// [-----)
|
||||
assert_eq!(a.union(&(15..25)), RangeSet::from([(10..25)]));
|
||||
|
||||
// leftward subset
|
||||
// [-----)
|
||||
// [-----)
|
||||
assert_eq!(a.union(&(5..15)), RangeSet::from([(5..20)]));
|
||||
|
||||
// subset
|
||||
// [-----)
|
||||
// [--)
|
||||
assert_eq!(a.union(&(12..15)), RangeSet::from([(10..20)]));
|
||||
|
||||
// superset
|
||||
// [-----)
|
||||
// [---------)
|
||||
assert_eq!(a.union(&(5..25)), RangeSet::from([(5..25)]));
|
||||
|
||||
// rightward disjoint
|
||||
// [-----)
|
||||
// [-----)
|
||||
assert_eq!(a.union(&(25..30)), RangeSet::from([(10..20), (25..30)]));
|
||||
|
||||
// leftward disjoint
|
||||
// [-----)
|
||||
// [-----)
|
||||
assert_eq!(a.union(&(0..5)), RangeSet::from([(0..5), (10..20)]));
|
||||
|
||||
// equal
|
||||
assert_eq!(a.union(&(10..20)), RangeSet::from([(10..20)]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_set_union() {
|
||||
let a = RangeSet::from([(10..20), (30..40), (50..60)]);
|
||||
|
||||
// rightward intersect
|
||||
// [-----) [-----) [-----)
|
||||
// [-----)
|
||||
assert_eq!(
|
||||
a.union(&(35..45)),
|
||||
RangeSet::from([(10..20), (30..45), (50..60)])
|
||||
);
|
||||
|
||||
// leftward intersect
|
||||
// [-----) [-----) [-----)
|
||||
// [-----)
|
||||
assert_eq!(
|
||||
a.union(&(5..15)),
|
||||
RangeSet::from([(5..20), (30..40), (50..60)])
|
||||
);
|
||||
|
||||
// subset
|
||||
// [-----) [-----) [-----)
|
||||
// [--)
|
||||
assert_eq!(
|
||||
a.union(&(12..15)),
|
||||
RangeSet::from([(10..20), (30..40), (50..60)])
|
||||
);
|
||||
|
||||
// superset of 1
|
||||
// [-----) [-----) [-----)
|
||||
// [---------)
|
||||
assert_eq!(
|
||||
a.union(&(5..25)),
|
||||
RangeSet::from([(5..25), (30..40), (50..60)])
|
||||
);
|
||||
|
||||
// superset of 2
|
||||
// [-----) [-----) [-----)
|
||||
// [----------------)
|
||||
assert_eq!(a.union(&(5..45)), RangeSet::from([(5..45), (50..60)]));
|
||||
|
||||
// superset
|
||||
// [-----) [-----) [-----)
|
||||
// [------------------------)
|
||||
assert_eq!(a.union(&(5..65)), RangeSet::from([(5..65)]));
|
||||
|
||||
// leftwards disjoint
|
||||
// [-----) [-----) [-----)
|
||||
// [-----)
|
||||
assert_eq!(
|
||||
a.union(&(0..5)),
|
||||
RangeSet::from([(0..5), (10..20), (30..40), (50..60)])
|
||||
);
|
||||
|
||||
// rightwards disjoint
|
||||
// [-----) [-----) [-----)
|
||||
// [-----)
|
||||
assert_eq!(
|
||||
a.union(&(65..70)),
|
||||
RangeSet::from([(10..20), (30..40), (50..60), (65..70)])
|
||||
);
|
||||
|
||||
// disjoint
|
||||
// [-----) [-----) [-----)
|
||||
// [-----)
|
||||
assert_eq!(
|
||||
a.union(&(25..28)),
|
||||
RangeSet::from([(10..20), (25..28), (30..40), (50..60)])
|
||||
);
|
||||
|
||||
// empty
|
||||
assert_eq!(a.union(&(0..0)), a);
|
||||
assert_eq!((0..0).union(&a), a);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_union_set() {
|
||||
let a = RangeSet::from([(10..20), (30..40), (50..60)]);
|
||||
let b = RangeSet::from([(15..25), (35..45), (55..65)]);
|
||||
|
||||
assert_eq!(a.union(&b), RangeSet::from([(10..25), (30..45), (50..65)]));
|
||||
|
||||
// disjoint
|
||||
let b = RangeSet::from([(22..23), (41..48)]);
|
||||
assert_eq!(
|
||||
a.union(&b),
|
||||
RangeSet::from([(10..20), (22..23), (30..40), (41..48), (50..60)])
|
||||
);
|
||||
|
||||
// superset
|
||||
let b = RangeSet::from([(5..65)]);
|
||||
assert_eq!(a.union(&b), b);
|
||||
|
||||
// subset
|
||||
let b = RangeSet::from([(12..18)]);
|
||||
assert_eq!(a.union(&b), a);
|
||||
}
|
||||
|
||||
// This proves the union operation for 3 sets, up to size 16.
|
||||
#[test]
|
||||
#[ignore = "expensive"]
|
||||
fn test_prove_range_union_range_16x3() {
|
||||
fn expected(x: Range<usize>, y: Range<usize>, z: Range<usize>) -> Vec<usize> {
|
||||
let mut expected_values = x.chain(y).chain(z).collect::<Vec<_>>();
|
||||
|
||||
expected_values.sort();
|
||||
expected_values.dedup();
|
||||
|
||||
expected_values
|
||||
}
|
||||
|
||||
for (xs, xe, ys, ye, zs, ze) in iproduct!(0..16, 0..16, 0..16, 0..16, 0..16, 0..16) {
|
||||
let set = (xs..xe).union(&(ys..ye)).union(&(zs..ze));
|
||||
|
||||
let actual = set
|
||||
.clone()
|
||||
.into_inner()
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(
|
||||
actual,
|
||||
expected(xs..xe, ys..ye, zs..ze),
|
||||
"{:?} {:?} {:?} => {:?}",
|
||||
xs..xe,
|
||||
ys..ye,
|
||||
zs..ze,
|
||||
set
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "expensive"]
|
||||
fn test_prove_set_union_range_8x3_8() {
|
||||
fn expected(
|
||||
x: Range<usize>,
|
||||
y: Range<usize>,
|
||||
w: Range<usize>,
|
||||
z: Range<usize>,
|
||||
) -> Vec<usize> {
|
||||
let mut expected_values = x.chain(y).chain(w).chain(z).collect::<Vec<_>>();
|
||||
|
||||
expected_values.sort();
|
||||
expected_values.dedup();
|
||||
|
||||
expected_values
|
||||
}
|
||||
|
||||
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 set = RangeSet::new(&[(xs..xe), (ys..ye), (ws..we)]).union(&(zs..ze));
|
||||
|
||||
let actual = set
|
||||
.clone()
|
||||
.into_inner()
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(
|
||||
actual,
|
||||
expected(xs..xe, ys..ye, ws..we, zs..ze),
|
||||
"{:?} {:?} {:?} {:?} => {:?}",
|
||||
xs..xe,
|
||||
ys..ye,
|
||||
ws..we,
|
||||
zs..ze,
|
||||
set
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "expensive"]
|
||||
fn test_prove_set_union_set_8x2_8x2() {
|
||||
fn expected(
|
||||
x: Range<usize>,
|
||||
y: Range<usize>,
|
||||
w: Range<usize>,
|
||||
z: Range<usize>,
|
||||
) -> Vec<usize> {
|
||||
let mut expected_values = x.chain(y).chain(w).chain(z).collect::<Vec<_>>();
|
||||
|
||||
expected_values.sort();
|
||||
expected_values.dedup();
|
||||
|
||||
expected_values
|
||||
}
|
||||
|
||||
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 set = s1.union(&s2);
|
||||
|
||||
let actual = set
|
||||
.clone()
|
||||
.into_inner()
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(
|
||||
actual,
|
||||
expected(xs..xe, ys..ye, ws..we, zs..ze),
|
||||
"{:?} {:?} {:?} {:?} => {:?}",
|
||||
xs..xe,
|
||||
ys..ye,
|
||||
ws..we,
|
||||
zs..ze,
|
||||
set
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user