feat(rangeset): rangeset crate (#56)

This commit is contained in:
sinu.eth
2025-03-19 16:59:28 -07:00
committed by GitHub
parent 76d9424238
commit e6e64ee9a5
35 changed files with 324 additions and 77 deletions

View File

@@ -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

View File

@@ -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);

View File

@@ -1,4 +0,0 @@
target
corpus
artifacts
coverage

View File

@@ -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

View File

@@ -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);
});

View File

@@ -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);
});

View File

@@ -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);
});

View File

@@ -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));
});

View File

@@ -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);
});

View File

@@ -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);
});

View File

@@ -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);
});

View File

@@ -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);
});

View File

@@ -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);
});

View File

@@ -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));
});

View File

@@ -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);
});

View File

@@ -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);
});

View File

@@ -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));
}

View File

@@ -1,5 +1,4 @@
pub mod filter_drain;
pub mod id;
pub mod iter;
pub mod range;
pub mod tuple;

View File

@@ -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());
}
}

View File

@@ -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),);
}
}
}

View File

@@ -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);
}
}

View File

@@ -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
);
}
}
}

View File

@@ -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));
}
}

View File

@@ -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])));
}
}

View File

@@ -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);
}
}

View File

@@ -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
);
}
}
}