1
0

Move Cafeteria code into new MultiInterval struct, add FromStr implementation for Interval

This commit is contained in:
Stefan Müller
2026-02-06 00:14:14 +01:00
parent e223c50a0d
commit 5c95df93b7
2 changed files with 104 additions and 55 deletions
+95 -3
View File
@@ -1,12 +1,21 @@
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone)]
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 {
pub fn new(start: u64, end: u64) -> Interval {
Interval { start, end }
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 {
@@ -17,3 +26,86 @@ impl Interval {
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,
}