use crate::atomic::AtomicInterval;
#[derive(Debug, Clone, PartialEq)]
pub struct IntervalSet<T> {
pub intervals: Vec<AtomicInterval<T>>,
}
impl<T: ToString> ToString for IntervalSet<T> {
fn to_string(&self) -> String {
let mut result = String::from("[");
for interval in &self.intervals {
result.push_str(&interval.to_string());
}
result.push_str("]");
result
}
}
impl<T: Clone> IntervalSet<T> {
pub fn is_empty(&self) -> bool {
self.intervals.is_empty()
}
pub fn new() -> IntervalSet<T> {
return IntervalSet { intervals: vec![] }
}
}
impl<T: Clone> From<AtomicInterval<T>> for IntervalSet<T> {
fn from(interval: AtomicInterval<T>) -> Self {
IntervalSet {
intervals: vec![interval],
}
}
}
impl<T: PartialOrd + Clone> IntervalSet<T> {
pub fn union(&self, other: &Self) -> Self {
let mut intervals = self.intervals.clone();
intervals.extend(other.intervals.iter().cloned());
intervals.sort_by(
|a, b| a.left().value().partial_cmp(b.left().value()).unwrap()
);
let mut merged: Vec<AtomicInterval<T>> = Vec::new();
for interval in intervals {
if let Some(last) = merged.last_mut() {
let union_vec = AtomicInterval::union(last, &interval);
if union_vec.len() == 1 {
*last = union_vec.into_iter().next().unwrap();
continue;
} else if union_vec.len() > 1 {
*last = union_vec[0].clone();
merged.extend(union_vec.into_iter().skip(1));
continue;
}
}
merged.push(interval);
}
IntervalSet { intervals: merged }
}
pub fn intersection(&self, other: &Self) -> Self {
let mut intervals = Vec::new();
for interval in &self.intervals {
for other_interval in &other.intervals {
interval.intersection(other_interval).iter().for_each(
|x| intervals.push(x.clone())
);
}
}
if intervals.is_empty() {
IntervalSet::new()
} else {
IntervalSet { intervals }
}
}
pub fn difference(&self, other: &Self) -> Self {
let mut result = Vec::new();
for interval in &self.intervals {
let mut remaining = vec![interval.clone()];
for other_interval in &other.intervals {
let mut new_remaining = Vec::new();
for part in remaining {
new_remaining.extend(part.difference(other_interval));
}
remaining = new_remaining;
}
result.extend(remaining);
}
IntervalSet { intervals: result }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_interval_from_atomic_interval() {
let atomic_interval = AtomicInterval::closed(1, 5);
let interval_set: IntervalSet<i32> = IntervalSet::from(atomic_interval.clone());
assert_eq!(interval_set.intervals.len(), 1);
assert_eq!(interval_set.intervals[0], atomic_interval);
}
#[test]
fn test_union_between_two_overlapping_intervals() {
let interval1 = AtomicInterval::closed(1, 3);
let interval2 = AtomicInterval::closed(4, 7);
let interval3 = AtomicInterval::closed(2, 4);
let interval4 = AtomicInterval::closed(7, 8);
let union = IntervalSet::from(interval1).union(&IntervalSet::from(interval2));
let union = union.union(&IntervalSet::from(interval3));
let union = union.union(&IntervalSet::from(interval4));
assert_eq!(union.intervals.len(), 1);
assert_eq!(union.intervals[0], AtomicInterval::closed(1, 8));
}
#[test]
fn test_union_between_two_disjoint_intervals() {
let interval1 = AtomicInterval::closed(1, 3);
let interval2 = AtomicInterval::closed(4, 7);
let interval3 = AtomicInterval::closed(5, 8);
let union = IntervalSet::from(interval1).union(&IntervalSet::from(interval2));
let union = union.union(&IntervalSet::from(interval3));
assert_eq!(union.intervals.len(), 2);
assert_eq!(union.intervals[0], AtomicInterval::closed(1, 3));
assert_eq!(union.intervals[1], AtomicInterval::closed(4, 8));
}
#[test]
fn test_intersection_between_two_overlapping_intervals() {
let interval1 = AtomicInterval::closed(1, 5);
let interval2 = AtomicInterval::closed(3, 7);
let interval1 = IntervalSet::from(interval1);
let interval2 = IntervalSet::from(interval2);
let intersection = interval1.intersection(&interval2);
assert_eq!(intersection.intervals.len(), 1);
assert_eq!(intersection.intervals[0], AtomicInterval::closed(3, 5));
}
#[test]
fn test_intersection_between_two_disjoint_intervals() {
let interval1 = AtomicInterval::closed(1, 3);
let interval2 = AtomicInterval::closed(4, 7);
let interval1 = IntervalSet::from(interval1);
let interval2 = IntervalSet::from(interval2);
let intersection = interval1.intersection(&interval2);
assert!(intersection.is_empty());
}
#[test]
fn test_difference_between_two_overlapping_intervals() {
let interval1 = AtomicInterval::closed(1, 5);
let interval2 = AtomicInterval::closed(3, 7);
let interval1 = IntervalSet::from(interval1);
let interval2 = IntervalSet::from(interval2);
let difference = interval1.difference(&interval2);
assert_eq!(difference.intervals.len(), 1);
assert_eq!(difference.intervals[0], AtomicInterval::closed_open(1, 3));
}
#[test]
fn test_difference_between_two_disjoint_intervals() {
let interval1 = AtomicInterval::closed(1, 3);
let interval2 = AtomicInterval::closed(4, 7);
let interval1 = IntervalSet::from(interval1);
let interval2 = IntervalSet::from(interval2);
let difference = interval1.difference(&interval2);
assert_eq!(difference.intervals.len(), 1);
assert_eq!(difference.intervals[0], AtomicInterval::closed(1, 3));
}
}