use std::collections::BTreeSet; use std::str::FromStr; #[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone)] pub struct Interval { pub start: u64, pub end: u64, } impl Interval { const INTERVAL_SPLIT_CHAR: char = '-'; pub fn new(start: u64, end: u64) -> Result { if start <= end { Ok(Interval { start, end }) } else { Err(IntervalError::InvalidBoundaries) } } pub fn contains(&self, value: u64) -> bool { self.start <= value && value <= self.end } pub fn len(&self) -> u64 { self.end - self.start + 1 } } impl FromStr for Interval { type Err = IntervalError; fn from_str(s: &str) -> Result { let (x_str, y_str) = s .split_once(Self::INTERVAL_SPLIT_CHAR) .ok_or(IntervalError::ParseError)?; let x = x_str .parse::() .map_err(|_| IntervalError::ParseError)?; let y = y_str .parse::() .map_err(|_| IntervalError::ParseError)?; Interval::new(x, y) } } pub struct MultiInterval { intervals: BTreeSet, } impl MultiInterval { pub fn new() -> MultiInterval { MultiInterval { intervals: BTreeSet::new(), } } pub fn add(&mut self, mut interval: Interval) { let mut to_delete = Vec::new(); for next in self.intervals.range(&interval..) { if interval.contains(next.start) || interval.end + 1 == next.start { // New interval overlaps with the "next" interval already in the collection. if interval.end < next.end { interval.end = next.end; } to_delete.push(*next); } else { break; } } let mut do_insert = true; if let Some(prev) = self.intervals.range(..=&interval).next_back() { if interval.contains(prev.end) || prev.end + 1 == interval.start { // Enlarges new interval to replace the "previous" interval already in the collection. interval.start = prev.start; to_delete.push(*prev); } else if interval.end <= prev.end { do_insert = false; } } for del in to_delete { self.intervals.remove(&del); } if do_insert { self.intervals.insert(interval); } } pub fn contains(&self, value: u64) -> bool { let interval = Interval::new(value, value).unwrap(); if let Some(prev) = self.intervals.range(..=&interval).next_back() { prev.contains(value) } else { false } } pub fn len(&self) -> u64 { self.intervals.iter().map(|x| x.len()).sum() } } #[derive(Debug, PartialEq, Eq)] pub enum IntervalError { ParseError, InvalidBoundaries, }