112 lines
2.9 KiB
Rust
112 lines
2.9 KiB
Rust
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<Interval, IntervalError> {
|
|
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<Self, Self::Err> {
|
|
let (x_str, y_str) = s
|
|
.split_once(Self::INTERVAL_SPLIT_CHAR)
|
|
.ok_or(IntervalError::ParseError)?;
|
|
let x = x_str
|
|
.parse::<u64>()
|
|
.map_err(|_| IntervalError::ParseError)?;
|
|
let y = y_str
|
|
.parse::<u64>()
|
|
.map_err(|_| IntervalError::ParseError)?;
|
|
Interval::new(x, y)
|
|
}
|
|
}
|
|
|
|
pub struct MultiInterval {
|
|
intervals: BTreeSet<Interval>,
|
|
}
|
|
|
|
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,
|
|
}
|