mod num_traits;
use std::{
collections::{BTreeSet, HashSet},
fmt::{Debug, Display},
iter::{Map, Peekable},
ops::{Bound, RangeInclusive},
};
pub use num_traits::{Adjacent, Step};
#[derive(Debug)]
pub struct DiffIter<
E: Clone + Adjacent + PartialOrd,
I: Iterator<Item = RangeInclusive<E>>,
J: Iterator<Item = RangeInclusive<E>>,
> {
lhs: Peekable<I>,
rhs: Peekable<J>,
next_min: Option<E>,
}
#[derive(Debug)]
pub struct IntersectIter<
E: PartialOrd,
I: Iterator<Item = RangeInclusive<E>>,
J: Iterator<Item = RangeInclusive<E>>,
> {
lhs: Peekable<I>,
rhs: Peekable<J>,
}
pub trait IntervalIterator<E: PartialOrd> {
type IntervalIter: Iterator<Item = RangeInclusive<E>>;
fn card(&self) -> Option<usize>
where
E: Step,
{
let mut card: usize = 0;
for r in self.intervals() {
let c = Step::steps_between(r.start(), r.end())?;
card = card.checked_add(c)?.checked_add(1)?
}
Some(card)
}
fn contains(&self, elem: &E) -> bool {
self.intervals().any(|r| r.contains(elem))
}
fn diff<O, R>(&self, other: &O) -> R
where
E: Clone + Adjacent,
O: IntervalIterator<E>,
R: FromIterator<RangeInclusive<E>>,
{
DiffIter::from_iters(self.intervals(), other.intervals()).collect()
}
fn disjoint<O: IntervalIterator<E> + ?Sized>(&self, other: &O) -> bool {
let mut lhs = self.intervals().peekable();
let mut rhs = other.intervals().peekable();
while let (Some(l), Some(r)) = (lhs.peek(), rhs.peek()) {
match overlap(l, r) {
RangeOrdering::Less => {
let _ = lhs.next();
}
RangeOrdering::Overlap => return false,
RangeOrdering::Greater => {
let _ = rhs.next();
}
}
}
true
}
fn intersect<O, R>(&self, other: &O) -> R
where
E: Clone,
O: IntervalIterator<E>,
R: FromIterator<RangeInclusive<E>>,
{
IntersectIter::from_iters(self.intervals(), other.intervals()).collect()
}
fn intervals(&self) -> Self::IntervalIter;
fn subset<O: IntervalIterator<E> + ?Sized>(&self, other: &O) -> bool {
let mut lhs = self.intervals().peekable();
let mut rhs = other.intervals().peekable();
while let (Some(l), Some(r)) = (lhs.peek(), rhs.peek()) {
match overlap(l, r) {
RangeOrdering::Overlap if r.start() <= l.start() && l.end() <= r.end() => {
let _ = lhs.next();
}
RangeOrdering::Greater => {
let _ = rhs.next();
}
_ => {
return false;
}
}
}
lhs.peek().is_none()
}
fn superset<O: IntervalIterator<E> + ?Sized>(&self, other: &O) -> bool {
other.subset(self)
}
fn union<O, R>(&self, other: &O) -> R
where
E: Clone,
O: IntervalIterator<E>,
R: FromIterator<RangeInclusive<E>>,
{
UnionIter::from_iters(self.intervals(), other.intervals()).collect()
}
}
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd)]
pub struct RangeList<E: PartialOrd> {
ranges: Vec<(E, E)>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
enum RangeOrdering {
Less,
Overlap,
Greater,
}
#[derive(Debug)]
pub struct UnionIter<
E: PartialOrd,
I: Iterator<Item = RangeInclusive<E>>,
J: Iterator<Item = RangeInclusive<E>>,
> {
lhs: Peekable<I>,
rhs: Peekable<J>,
}
fn max<E: PartialOrd>(a: E, b: E) -> E {
if a > b { a } else { b }
}
fn min<E: PartialOrd>(a: E, b: E) -> E {
if a < b { a } else { b }
}
fn overlap<E: PartialOrd>(r1: &RangeInclusive<E>, r2: &RangeInclusive<E>) -> RangeOrdering {
if r1.end() < r2.start() {
RangeOrdering::Less
} else if r2.end() < r1.start() {
RangeOrdering::Greater
} else {
RangeOrdering::Overlap
}
}
impl<E: Clone + Ord> IntervalIterator<E> for BTreeSet<E> {
type IntervalIter = Map<<BTreeSet<E> as IntoIterator>::IntoIter, fn(E) -> RangeInclusive<E>>;
fn intervals(&self) -> Self::IntervalIter {
self.clone().into_iter().map(|e| e.clone()..=e)
}
}
impl<E: Clone + Adjacent + PartialOrd, I, J> DiffIter<E, I, J>
where
I: Iterator<Item = RangeInclusive<E>>,
J: Iterator<Item = RangeInclusive<E>>,
{
pub fn from_iters(lhs: I, rhs: J) -> Self {
Self {
next_min: None,
lhs: lhs.peekable(),
rhs: rhs.peekable(),
}
}
pub fn new<A, B>(lhs: &A, rhs: &B) -> Self
where
A: IntervalIterator<E, IntervalIter = I>,
B: IntervalIterator<E, IntervalIter = J>,
{
Self::from_iters(lhs.intervals(), rhs.intervals())
}
}
impl<E: Clone + Adjacent + PartialOrd, I, J> Iterator for DiffIter<E, I, J>
where
I: Iterator<Item = RangeInclusive<E>>,
J: Iterator<Item = RangeInclusive<E>>,
{
type Item = RangeInclusive<E>;
fn next(&mut self) -> Option<Self::Item> {
let mut lhs = self.lhs.peek()?.clone();
if let Some(min) = self.next_min.take() {
lhs = min..=lhs.end().clone();
}
loop {
let Some(rhs) = self.rhs.peek() else {
let _ = self.lhs.next().unwrap();
return Some(lhs);
};
match overlap(&lhs, rhs) {
RangeOrdering::Less => {
let _ = self.lhs.next().unwrap();
return Some(lhs);
}
RangeOrdering::Overlap => {
match (rhs.start() <= lhs.start(), rhs.end() >= lhs.end()) {
(true, true) => {
let _ = self.lhs.next().unwrap();
lhs = self.lhs.peek()?.clone();
}
(true, false) => {
lhs = rhs.end().successor().unwrap()..=lhs.end().clone();
let _ = self.rhs.next();
}
(false, true) => {
let _ = self.lhs.next().unwrap();
return Some(lhs.start().clone()..=rhs.start().predecessor().unwrap());
}
(false, false) => {
let lhs_cut = lhs.start().clone()..=rhs.start().predecessor().unwrap();
self.next_min = Some(rhs.end().successor().unwrap());
let _ = self.rhs.next();
return Some(lhs_cut);
}
}
}
RangeOrdering::Greater => {
let _ = self.rhs.next();
}
}
}
}
}
impl<E: Clone + Ord> IntervalIterator<E> for HashSet<E> {
type IntervalIter = Map<<Vec<E> as IntoIterator>::IntoIter, fn(E) -> RangeInclusive<E>>;
fn intervals(&self) -> Self::IntervalIter {
let mut v: Vec<_> = self.iter().cloned().collect();
v.sort_unstable();
v.into_iter().map(|e| e.clone()..=e)
}
}
impl<E: Clone + PartialOrd, I, J> IntersectIter<E, I, J>
where
I: Iterator<Item = RangeInclusive<E>>,
J: Iterator<Item = RangeInclusive<E>>,
{
pub fn from_iters(lhs: I, rhs: J) -> Self {
Self {
lhs: lhs.peekable(),
rhs: rhs.peekable(),
}
}
pub fn new<A, B>(lhs: &A, rhs: &B) -> Self
where
A: IntervalIterator<E, IntervalIter = I>,
B: IntervalIterator<E, IntervalIter = J>,
{
Self::from_iters(lhs.intervals(), rhs.intervals())
}
}
impl<E: PartialOrd + Clone, I, J> Iterator for IntersectIter<E, I, J>
where
I: Iterator<Item = RangeInclusive<E>>,
J: Iterator<Item = RangeInclusive<E>>,
{
type Item = RangeInclusive<E>;
fn next(&mut self) -> Option<Self::Item> {
while let (Some(l), Some(r)) = (self.lhs.peek(), self.rhs.peek()) {
match overlap(l, r) {
RangeOrdering::Less => {
let _ = self.lhs.next();
}
RangeOrdering::Greater => {
let _ = self.rhs.next();
}
RangeOrdering::Overlap => {
let v = max(l.start(), r.start()).clone()..=min(l.end(), r.end()).clone();
if l.end() <= r.end() {
let _ = self.lhs.next();
} else {
let _ = self.rhs.next();
}
return Some(v);
}
}
}
None
}
}
impl<E: PartialOrd> RangeList<E> {
pub fn first_position_bound(&self, bound: &Bound<E>) -> Option<usize>
where
E: Clone + Step,
{
let elem = match bound {
Bound::Included(x) => x,
Bound::Excluded(x) => x,
Bound::Unbounded => {
return None;
}
};
let mut pos = 0;
let card = self.card()?;
for (start, end) in &self.ranges {
if elem < start {
return Some(pos);
}
if elem <= end {
pos += Step::steps_between(start, elem)?;
match bound {
Bound::Excluded(_) if pos > card => return None,
Bound::Excluded(_) => pos += 1,
_ => {}
}
debug_assert!(pos <= card);
return Some(pos);
}
pos += Step::steps_between(start, end)? + 1;
}
debug_assert_eq!(pos, self.card().unwrap());
None
}
pub fn from_elements<T: IntoIterator<Item = E>>(iter: T) -> Self
where
E: Adjacent + Clone,
{
let mut elems: Vec<E> = iter.into_iter().collect();
elems.sort_by(|a, b| {
a.partial_cmp(b)
.expect("the order of the elements in the RangeList cannot be partial")
});
Self::from_sorted_elements(elems)
}
pub fn from_sorted_elements<T: IntoIterator<Item = E>>(iter: T) -> Self
where
E: Adjacent + Clone,
{
let mut it = iter.into_iter();
let mut ranges = Vec::new();
let Some(mut start) = it.next() else {
return Self::default();
};
let mut end = start.clone();
for next in it {
if next < end {
panic!("elements must be yielded in sorted order");
}
if next == end {
continue;
}
if end.successor().unwrap() == next {
end = next;
} else {
ranges.push((start, end));
start = next.clone();
end = next;
}
}
ranges.push((start, end));
Self { ranges }
}
pub fn from_sorted_ranges<T: IntoIterator<Item = RangeInclusive<E>>>(iter: T) -> Self
where
E: Adjacent + Clone,
{
let mut it = iter.into_iter();
let mut ranges = Vec::new();
let Some(mut cur) = it.next().map(|r| (r.start().clone(), r.end().clone())) else {
return Self::default();
};
for next in it {
if next.start() < &cur.0 {
panic!("ranges must be yielded in sorted order");
}
let next = (next.start().clone(), next.end().clone());
let adjacent = cur.1.successor().is_some_and(|succ| next.0 <= succ);
if cur.1 >= next.0 || adjacent {
cur.1 = max(cur.1, next.1)
} else {
ranges.push(cur);
cur = next;
}
}
ranges.push(cur);
Self { ranges }
}
pub fn is_empty(&self) -> bool {
self.ranges.is_empty()
}
#[allow(
clippy::type_complexity,
reason = "type is less understandable if split up"
)]
pub fn iter<'a>(
&'a self,
) -> Map<
<&'a RangeList<E> as IntoIterator>::IntoIter,
fn(RangeInclusive<&'a E>) -> RangeInclusive<E>,
>
where
E: Copy,
{
self.into_iter().map(|r| **r.start()..=**r.end())
}
pub fn last_position_bound(&self, bound: &Bound<E>) -> Option<usize>
where
E: Clone + Step,
{
let mut pos = self.card()?;
let lb = self.min()?;
let elem = match bound {
Bound::Included(x) => {
if x < lb {
return None;
}
x
}
Bound::Excluded(x) => {
if x <= lb {
return None;
}
x
}
Bound::Unbounded => {
return None;
}
};
for (start, end) in self.ranges.iter().rev() {
if elem > end {
return Some(pos);
}
if elem >= start {
pos -= Step::steps_between(elem, end)? + 1;
if matches!(bound, Bound::Excluded(_)) {
pos -= 1;
}
return Some(pos);
}
pos -= Step::steps_between(start, end)? + 1;
}
unreachable!()
}
#[deprecated(since = "0.5.0", note = "use `min` instead")]
pub fn lower_bound(&self) -> Option<&E> {
self.min()
}
pub fn max(&self) -> Option<&E> {
self.ranges.last().map(|(_, end)| end)
}
pub fn min(&self) -> Option<&E> {
self.ranges.first().map(|(start, _)| start)
}
pub fn position(&self, elem: &E) -> Option<usize>
where
E: Step,
{
let mut pos = 0;
for (start, end) in &self.ranges {
if elem < start {
return None;
}
if elem <= end {
let elems = Step::steps_between(start, elem)?;
return Some(pos + elems);
}
pos += Step::steps_between(start, end)? + 1;
}
None
}
#[deprecated(since = "0.5.0", note = "use `tighten_min` instead")]
pub fn set_lower_bound(&mut self, lower_bound: E)
where
E: Debug,
{
self.tighten_min(lower_bound)
}
#[deprecated(since = "0.5.0", note = "use `tighten_max` instead")]
pub fn set_upper_bound(&mut self, upper_bound: E) {
self.tighten_max(upper_bound)
}
pub fn tighten_max(&mut self, max: E) {
let last_kept = self
.ranges
.iter()
.enumerate()
.rfind(|(_, (start, _))| *start <= max)
.map(|(i, _)| i);
if let Some(end) = last_kept {
self.ranges.truncate(end + 1);
let last = self.ranges.last_mut().unwrap();
if last.1 > max {
last.1 = max;
}
} else {
self.ranges = Vec::new();
}
}
pub fn tighten_min(&mut self, min: E)
where
E: Debug,
{
let first_kept = self
.ranges
.iter()
.enumerate()
.find_map(|(i, (_, end))| (*end >= min).then_some(i));
if let Some(start) = first_kept {
if self.ranges[start].0 < min {
self.ranges[start].0 = min;
}
if start > 0 {
for i in start..self.ranges.len() {
self.ranges.swap(i, i - start);
}
self.ranges.truncate(self.ranges.len() - start);
}
} else {
self.ranges = Vec::new();
}
}
#[deprecated(since = "0.5.0", note = "use `max` instead")]
pub fn upper_bound(&self) -> Option<&E> {
self.max()
}
}
impl<E: Debug + PartialOrd> Debug for RangeList<E> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.ranges.is_empty() {
return write!(f, "RangeList::default()");
}
if self.ranges.len() == 1 {
return write!(
f,
"RangeList::from({:?}..={:?})",
self.ranges[0].0, self.ranges[0].1
);
}
write!(f, "RangeList::from_iter([")?;
let mut first = true;
for r in self {
if !first {
write!(f, ", ")?
}
write!(f, "{:?}", r)?;
first = false;
}
write!(f, "])")
}
}
impl<E: PartialOrd> Default for RangeList<E> {
fn default() -> Self {
Self {
ranges: Default::default(),
}
}
}
impl<E: Debug + PartialOrd> Display for RangeList<E> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut first = true;
for r in &self.ranges {
if !first {
write!(f, " union ")?;
}
write!(f, "{:?}..{:?}", r.0, r.1)?;
first = false;
}
if first {
write!(f, "1..0")?;
}
Ok(())
}
}
impl<E: Clone + PartialOrd> From<&RangeInclusive<E>> for RangeList<E> {
fn from(value: &RangeInclusive<E>) -> Self {
if value.is_empty() {
RangeList { ranges: Vec::new() }
} else {
Self {
ranges: vec![(value.start().clone(), value.end().clone())],
}
}
}
}
impl<E: Clone + PartialOrd> From<RangeInclusive<E>> for RangeList<E> {
fn from(value: RangeInclusive<E>) -> Self {
(&value).into()
}
}
impl<E, R> FromIterator<R> for RangeList<E>
where
E: Adjacent + Clone + PartialOrd,
R: Into<RangeInclusive<E>>,
{
fn from_iter<T: IntoIterator<Item = R>>(iter: T) -> Self {
let mut non_empty: Vec<RangeInclusive<E>> = iter
.into_iter()
.map(|r| r.into())
.filter(|r| !r.is_empty())
.collect();
non_empty.sort_by(|a, b| {
a.start()
.partial_cmp(b.start())
.expect("the order of the bounds in the RangeList cannot be partial")
});
Self::from_sorted_ranges(non_empty)
}
}
impl<E: PartialOrd + Clone> IntervalIterator<E> for RangeList<E> {
type IntervalIter = <RangeList<E> as IntoIterator>::IntoIter;
fn intervals(&self) -> Self::IntervalIter {
self.clone().into_iter()
}
}
impl<E: PartialOrd + Clone> IntoIterator for RangeList<E> {
type IntoIter = Map<std::vec::IntoIter<(E, E)>, fn((E, E)) -> RangeInclusive<E>>;
type Item = RangeInclusive<E>;
fn into_iter(self) -> Self::IntoIter {
self.ranges
.into_iter()
.map(|(start, end)| RangeInclusive::new(start, end))
}
}
impl<'a, E: PartialOrd> IntoIterator for &'a RangeList<E> {
type IntoIter = Map<std::slice::Iter<'a, (E, E)>, fn(&'a (E, E)) -> RangeInclusive<&'a E>>;
type Item = RangeInclusive<&'a E>;
fn into_iter(self) -> Self::IntoIter {
self.ranges
.iter()
.map(|(start, end)| RangeInclusive::new(start, end))
}
}
impl<E: Clone + PartialOrd, I, J> UnionIter<E, I, J>
where
I: Iterator<Item = RangeInclusive<E>>,
J: Iterator<Item = RangeInclusive<E>>,
{
pub fn from_iters(lhs: I, rhs: J) -> Self {
Self {
lhs: lhs.peekable(),
rhs: rhs.peekable(),
}
}
pub fn new<A, B>(lhs: &A, rhs: &B) -> Self
where
A: IntervalIterator<E, IntervalIter = I>,
B: IntervalIterator<E, IntervalIter = J>,
{
Self::from_iters(lhs.intervals(), rhs.intervals())
}
}
impl<E: PartialOrd + Clone, I, J> Iterator for UnionIter<E, I, J>
where
I: Iterator<Item = RangeInclusive<E>>,
J: Iterator<Item = RangeInclusive<E>>,
{
type Item = RangeInclusive<E>;
fn next(&mut self) -> Option<Self::Item> {
match (self.lhs.peek(), self.rhs.peek()) {
(Some(l), None) => {
let v = l.clone();
let _ = self.lhs.next();
Some(v)
}
(None, Some(r)) => {
let v = r.clone();
let _ = self.rhs.next();
Some(v)
}
(Some(l), Some(r)) => match overlap(l, r) {
RangeOrdering::Less => {
let v = l.clone();
let _ = self.lhs.next();
Some(v)
}
RangeOrdering::Greater => {
let v = r.clone();
let _ = self.rhs.next();
Some(v)
}
RangeOrdering::Overlap => {
let mut ext = min(l.start(), r.start()).clone()..=max(l.end(), r.end()).clone();
let _ = self.lhs.next();
let _ = self.rhs.next();
loop {
if let Some(l) = self.lhs.peek()
&& overlap(&ext, l) == RangeOrdering::Overlap
{
ext = ext.start().clone()..=max(ext.end(), l.end()).clone();
let _ = self.lhs.next();
continue;
}
if let Some(r) = self.rhs.peek()
&& overlap(&ext, r) == RangeOrdering::Overlap
{
ext = ext.start().clone()..=max(ext.end(), r.end()).clone();
let _ = self.rhs.next();
continue;
}
break;
}
Some(ext)
}
},
(None, None) => None,
}
}
}
#[cfg(test)]
mod tests {
use expect_test::expect;
use super::*;
#[test]
fn test_display_rangelist() {
let empty: RangeList<i64> = RangeList::default();
assert_eq!(empty.to_string(), "1..0");
let single_range = RangeList::from_iter([1..=4]);
assert_eq!(single_range.to_string(), "1..4");
let multi_range = RangeList::from_iter([1..=4, 6..=7, -5..=-3]);
assert_eq!(multi_range.to_string(), "-5..-3 union 1..4 union 6..7");
let float_range = RangeList::from_iter([0.1..=3.2, 8.1..=50.0]);
assert_eq!(float_range.to_string(), "0.1..3.2 union 8.1..50.0");
}
#[test]
fn test_from_elements() {
let elems = [5_u32, 1, 4, 2, 1, 6];
let rl = RangeList::from_elements(elems);
let expected = RangeList::from_iter([1_u32..=2, 4..=6]);
assert_eq!(rl, expected);
let rl2 = RangeList::from_elements([3_i64, -2, -1, 3, 0]);
let expected2 = RangeList::from_iter([-2_i64..=0, 3..=3]);
assert_eq!(rl2, expected2);
let rl_empty: RangeList<u32> = RangeList::from_elements([]);
assert!(rl_empty.is_empty());
}
#[test]
fn test_from_sorted_elements() {
let elems = [1_u32, 1, 2, 4, 5, 6];
let rl = RangeList::from_sorted_elements(elems);
let expected = RangeList::from_iter([1_u32..=2, 4..=6]);
assert_eq!(rl, expected);
let rl2 = RangeList::from_sorted_elements([10_u8]);
let expected2 = RangeList::from_iter([10_u8..=10]);
assert_eq!(rl2, expected2);
let rl_empty: RangeList<u32> = RangeList::from_sorted_elements([]);
assert!(rl_empty.is_empty());
}
#[test]
fn test_from_sorted_ranges() {
let rl = RangeList::from_sorted_ranges([1..=2, 2..=4, 6..=7]);
let expected = RangeList::from_iter([1..=4, 6..=7]);
assert_eq!(rl, expected);
let rl2 = RangeList::from_sorted_ranges([-5..=-3, -3..=-1, 0..=0]);
let expected2 = RangeList::from_iter([-5..=-1, 0..=0]);
assert_eq!(rl2, expected2);
let rl3 = RangeList::from_sorted_ranges([0.1..=3.2, 3.2..=4.0]);
let expected3 = RangeList::from_iter([0.1..=4.0]);
assert_eq!(rl3, expected3);
let rl4 = RangeList::from_sorted_ranges([1..=10, 2..=3]);
let expected4 = RangeList::from_iter([1..=10]);
assert_eq!(rl4, expected4);
let rl5 = RangeList::from_sorted_ranges([0.0..=10.0, 2.0..=3.0]);
let expected5 = RangeList::from_iter([0.0..=10.0]);
assert_eq!(rl5, expected5);
let rl_empty: RangeList<f64> = RangeList::from_sorted_ranges([]);
assert!(rl_empty.is_empty());
}
#[test]
fn test_position_overflow() {
let full = RangeList::from(0_u64..=u64::MAX);
assert_eq!(full.card(), None);
assert_eq!(full.position(&0), Some(0));
assert_eq!(full.position(&u64::MAX), Some(usize::MAX));
let signed = RangeList::from(i64::MIN..=i64::MAX);
assert_eq!(signed.card(), None);
assert_eq!(signed.position(&i64::MIN), Some(0));
assert_eq!(signed.position(&i64::MAX), Some(usize::MAX));
}
#[test]
fn test_rangelist() {
let empty: RangeList<i64> = RangeList::default();
expect![[r#"
RangeList::default()
"#]]
.assert_debug_eq(&empty);
assert!(empty.is_empty());
let single_range = RangeList::from_iter([1..=4]);
expect![[r#"
RangeList::from(1..=4)
"#]]
.assert_debug_eq(&single_range);
assert!(!single_range.is_empty());
assert!(single_range.contains(&1));
assert!(single_range.contains(&2));
assert!(single_range.contains(&4));
assert!(!single_range.contains(&0));
assert!(!single_range.contains(&5));
let multi_range = RangeList::from_iter([1..=4, 6..=7, -5..=-3]);
expect![[r#"
RangeList::from_iter([-5..=-3, 1..=4, 6..=7])
"#]]
.assert_debug_eq(&multi_range);
assert!(multi_range.contains(&-5));
assert!(multi_range.contains(&-3));
assert!(multi_range.contains(&1));
assert!(multi_range.contains(&4));
assert!(multi_range.contains(&6));
assert!(multi_range.contains(&7));
assert!(!multi_range.contains(&0));
assert!(!multi_range.contains(&5));
assert!(!multi_range.contains(&-6));
assert!(!multi_range.contains(&8));
let collapse_range = RangeList::from_iter([1..=2, 2..=3, 10..=12, 11..=15]);
expect![[r#"
RangeList::from_iter([1..=3, 10..=15])
"#]]
.assert_debug_eq(&collapse_range);
let float_range = RangeList::from_iter([0.1..=3.2, 8.1..=11.2, 10.0..=50.0]);
expect![[r#"
RangeList::from_iter([0.1..=3.2, 8.1..=50.0])
"#]]
.assert_debug_eq(&float_range);
}
#[test]
fn test_set_bounds() {
let mut empty = RangeList::<i64>::default();
empty.tighten_min(10);
empty.tighten_max(20);
assert_eq!(empty.min(), None);
assert_eq!(empty.max(), None);
let mut r = RangeList::<i64>::from_iter([1..=2, 4..=6, 8..=9]);
r.tighten_min(0);
assert_eq!(r.min(), Some(&1));
r.tighten_min(1);
assert_eq!(r.min(), Some(&1));
r.tighten_min(2);
assert_eq!(r.min(), Some(&2));
r.tighten_min(4);
assert_eq!(r.min(), Some(&4));
assert_eq!(r.iter().collect::<Vec<_>>(), vec![4..=6, 8..=9]);
r.tighten_min(9);
assert_eq!(r.min(), Some(&9));
assert_eq!(r.iter().collect::<Vec<_>>(), vec![9..=9]);
r.tighten_min(10);
assert_eq!(r.min(), None);
assert!(r.is_empty());
let mut r = RangeList::<i64>::from_iter([1..=2, 4..=6, 8..=9]);
r.tighten_max(10);
assert_eq!(r.max(), Some(&9));
r.tighten_max(9);
assert_eq!(r.max(), Some(&9));
r.tighten_max(8);
assert_eq!(r.max(), Some(&8));
r.tighten_max(6);
assert_eq!(r.max(), Some(&6));
assert_eq!(r.iter().collect::<Vec<_>>(), vec![1..=2, 4..=6]);
r.tighten_max(1);
assert_eq!(r.max(), Some(&1));
assert_eq!(r.iter().collect::<Vec<_>>(), vec![1..=1]);
r.tighten_max(0);
assert_eq!(r.max(), None);
assert!(r.is_empty());
}
#[test]
fn test_set_card() {
let empty = RangeList::<i64>::default();
assert_eq!(empty.card(), Some(0));
let full: RangeList<i64> = (i64::MIN..=i64::MAX).into();
assert_eq!(full.card(), None);
let x = RangeList::<i8>::from(1..=5);
assert_eq!(x.card(), Some(5));
let y = RangeList::<u32>::from_iter([1..=2, 4..=6, 8..=9]);
assert_eq!(y.card(), Some(7));
}
#[test]
fn test_set_diff() {
let empty: RangeList<i64> = RangeList::default();
let inf: RangeList<i64> = RangeList::from_iter([i64::MIN..=i64::MAX]);
let res: RangeList<_> = empty.diff(&empty);
assert_eq!(res, empty);
let res: RangeList<_> = inf.diff(&inf);
assert_eq!(res, empty);
let res: RangeList<_> = empty.diff(&inf);
assert_eq!(res, empty);
let res: RangeList<_> = inf.diff(&empty);
assert_eq!(res, inf);
let x = RangeList::from(1..=5);
let y = RangeList::from(4..=9);
let z: RangeList<_> = x.diff(&y);
expect!["1..3"].assert_eq(&z.to_string());
let z: RangeList<_> = y.diff(&x);
expect!["6..9"].assert_eq(&z.to_string());
let z: RangeList<_> = x.diff(&x);
expect!["1..0"].assert_eq(&z.to_string());
let z: RangeList<_> = y.diff(&y);
expect!["1..0"].assert_eq(&z.to_string());
let z: RangeList<_> = x.diff(&RangeList::from_iter([1..=2, 5..=5]));
expect!["3..4"].assert_eq(&z.to_string());
let z: RangeList<_> = x.diff(&RangeList::from(2..=4));
expect!["1..1 union 5..5"].assert_eq(&z.to_string());
let z: RangeList<_> = y.diff(&RangeList::from_iter([5..=5, 7..=7, 9..=9]));
expect!["4..4 union 6..6 union 8..8"].assert_eq(&z.to_string());
let x = RangeList::from_iter([1..=3, 5..=7, 9..=11]);
let z: RangeList<_> = x.diff(&y);
expect!["1..3 union 10..11"].assert_eq(&z.to_string());
let z: RangeList<_> = x.diff(&RangeList::from(-1..=8));
expect!["9..11"].assert_eq(&z.to_string());
let z: RangeList<_> = x.diff(&RangeList::from_iter([4..=4, 8..=8]));
assert_eq!(x, z);
let x = RangeList::from_iter([3..=4, 6..=9, 11..=12, 14..=14, 16..=16]);
let z: RangeList<_> = x.diff(&RangeList::from_iter([1..=1, 3..=3, 12..=14]));
expect!["4..4 union 6..9 union 11..11 union 16..16"].assert_eq(&z.to_string());
let x = RangeList::from(1.0..=5.0);
let z: RangeList<f64> = x.diff(&RangeList::from(2.0..=4.0));
assert_eq!(
z.iter().collect::<Vec<_>>(),
vec![1.0..=2.0_f64.next_down(), 4.0_f64.next_up()..=5.0]
);
}
#[test]
fn test_set_disjoint() {
let empty = RangeList::default();
let inf = RangeList::from(i64::MIN..=i64::MAX);
assert!(empty.disjoint(&empty));
assert!(empty.disjoint(&inf));
assert!(inf.disjoint(&empty));
assert!(!inf.disjoint(&inf));
let x = RangeList::from_iter([1..=2, 4..=6, 8..=9]);
assert!(empty.disjoint(&x));
assert!(x.disjoint(&empty));
assert!(!x.disjoint(&x));
assert!(!inf.disjoint(&x));
assert!(!x.disjoint(&inf));
let x = RangeList::from_iter([1.0..=2.0, 5.0..=6.0]);
let y = RangeList::from_iter([3.0..=4.0, 7.0..=8.0]);
assert!(x.disjoint(&y));
assert!(y.disjoint(&x));
}
#[test]
fn test_set_intersect() {
let empty = RangeList::default();
let inf = RangeList::from_iter([i64::MIN..=i64::MAX]);
let res: RangeList<_> = empty.intersect(&empty);
assert_eq!(res, empty);
let res: RangeList<_> = inf.intersect(&inf);
assert_eq!(res, inf);
let res: RangeList<_> = empty.intersect(&inf);
assert_eq!(res, empty);
let res: RangeList<_> = inf.intersect(&empty);
assert_eq!(res, empty);
let x = RangeList::from(1..=5);
let y = RangeList::from(4..=9);
let z: RangeList<_> = x.intersect(&y);
expect!["4..5"].assert_eq(&z.to_string());
let y = RangeList::from_iter([1..=2, 4..=9]);
let z: RangeList<_> = x.intersect(&y);
expect!["1..2 union 4..5"].assert_eq(&z.to_string());
let z: RangeList<_> = y.intersect(&x);
expect!["1..2 union 4..5"].assert_eq(&z.to_string());
let y = RangeList::from_iter([-5..=-1, 1..=3]);
let z: RangeList<_> = x.intersect(&y);
expect!["1..3"].assert_eq(&z.to_string());
let z: RangeList<_> = y.intersect(&x);
expect!["1..3"].assert_eq(&z.to_string());
let x = RangeList::from(1.0..=5.0);
let y = RangeList::from(4.0..=9.0);
let z: RangeList<_> = x.intersect(&y);
expect!["4.0..5.0"].assert_eq(&z.to_string());
}
#[test]
fn test_set_subset() {
let empty = RangeList::default();
let inf = RangeList::from(i64::MIN..=i64::MAX);
assert!(empty.subset(&inf));
assert!(!inf.subset(&empty));
let x = RangeList::from(1..=5);
let y = RangeList::from(1..=9);
assert!(x.subset(&x));
assert!(x.subset(&y));
assert!(!y.subset(&x));
assert!(y.subset(&y));
let x = RangeList::from_iter([1..=2, 4..=9]);
assert!(x.subset(&x));
assert!(x.subset(&y));
let x = RangeList::from(1.0..=5.0);
let y = RangeList::from(1.0..=9.0);
assert!(x.subset(&x));
assert!(x.subset(&y));
assert!(!y.subset(&x));
assert!(y.subset(&y));
}
#[test]
fn test_set_union() {
let empty: RangeList<i64> = RangeList::default();
let inf: RangeList<i64> = RangeList::from_iter([i64::MIN..=i64::MAX]);
let res: RangeList<_> = empty.union(&empty);
assert_eq!(res, empty);
let res: RangeList<_> = inf.union(&inf);
assert_eq!(res, inf);
let res: RangeList<_> = empty.union(&inf);
assert_eq!(res, inf);
let res: RangeList<_> = inf.union(&empty);
assert_eq!(res, inf);
let x = RangeList::from(1..=5);
let y = RangeList::from(4..=9);
let z: RangeList<_> = x.union(&y);
expect!["1..9"].assert_eq(&z.to_string());
let y = RangeList::from_iter([1..=2, 4..=4]);
let z: RangeList<_> = x.union(&y);
expect!["1..5"].assert_eq(&z.to_string());
let y = RangeList::from_iter([-5..=-1, 6..=9]);
let z: RangeList<_> = x.union(&y);
expect!["-5..-1 union 1..9"].assert_eq(&z.to_string());
let z: RangeList<_> = y.union(&x);
expect!["-5..-1 union 1..9"].assert_eq(&z.to_string());
let x = RangeList::from(1..=9);
let y = RangeList::from_iter([1..=2, 4..=5, 7..=8]);
let z: RangeList<_> = x.union(&y);
expect!["1..9"].assert_eq(&z.to_string());
let z: RangeList<_> = y.union(&x);
expect!["1..9"].assert_eq(&z.to_string());
let x = RangeList::from(1.0..=5.0);
let y = RangeList::from(4.0..=9.0);
let z: RangeList<_> = x.union(&y);
expect!["1.0..9.0"].assert_eq(&z.to_string());
}
}