use std::cmp::Ordering;
use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Interval {
pub start: u32,
pub end: u32,
}
impl Interval {
pub fn new(start: u32, end: u32) -> Self {
assert!(start <= end, "invalid interval [{}, {})", start, end);
Self { start, end }
}
pub fn len(&self) -> u32 {
self.end - self.start
}
pub fn is_empty(&self) -> bool {
self.start == self.end
}
pub fn contains(&self, point: u32) -> bool {
point >= self.start && point < self.end
}
pub fn overlaps(&self, other: &Interval) -> bool {
self.start < other.end && other.start < self.end
}
pub fn intersect(&self, other: &Interval) -> Option<Interval> {
let start = self.start.max(other.start);
let end = self.end.min(other.end);
if start < end {
Some(Interval::new(start, end))
} else {
None
}
}
pub fn union(&self, other: &Interval) -> Option<Interval> {
if self.overlaps(other) || self.end == other.start || other.end == self.start {
Some(Interval::new(
self.start.min(other.start),
self.end.max(other.end),
))
} else {
None
}
}
}
impl PartialOrd for Interval {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Interval {
fn cmp(&self, other: &Self) -> Ordering {
self.start
.cmp(&other.start)
.then_with(|| self.end.cmp(&other.end))
}
}
impl fmt::Display for Interval {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "[{}, {})", self.start, self.end)
}
}
#[derive(Debug, Clone)]
pub struct IntervalMap<V: Clone> {
entries: Vec<(Interval, V)>,
}
impl<V: Clone> IntervalMap<V> {
pub fn new() -> Self {
Self {
entries: Vec::new(),
}
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub fn insert(&mut self, interval: Interval, value: V) {
if interval.is_empty() {
return;
}
let pos = self
.entries
.binary_search_by(|(iv, _)| iv.start.cmp(&interval.start))
.unwrap_or_else(|e| e);
if pos > 0 {
let (prev_iv, _) = &self.entries[pos - 1];
if prev_iv.overlaps(&interval) || prev_iv.end == interval.start {
self.entries[pos - 1].0.end = self.entries[pos - 1].0.end.max(interval.end);
return;
}
}
if pos < self.entries.len() {
let (next_iv, _) = &self.entries[pos];
if next_iv.overlaps(&interval) || interval.end == next_iv.start {
let new_start = interval.start.min(next_iv.start);
let new_end = interval.end.max(next_iv.end);
self.entries[pos] = (Interval::new(new_start, new_end), value);
return;
}
}
self.entries.insert(pos, (interval, value));
}
pub fn get(&self, point: u32) -> Option<&V> {
let pos = self
.entries
.binary_search_by(|(iv, _)| {
if point < iv.start {
Ordering::Greater } else if point >= iv.end {
Ordering::Less } else {
Ordering::Equal
}
})
.ok()?;
Some(&self.entries[pos].1)
}
pub fn get_interval(&self, point: u32) -> Option<(&Interval, &V)> {
let pos = self
.entries
.binary_search_by(|(iv, _)| {
if point < iv.start {
Ordering::Greater
} else if point >= iv.end {
Ordering::Less
} else {
Ordering::Equal
}
})
.ok()?;
Some((&self.entries[pos].0, &self.entries[pos].1))
}
pub fn clear(&mut self) {
self.entries.clear();
}
pub fn iter(&self) -> impl Iterator<Item = &(Interval, V)> {
self.entries.iter()
}
pub fn intervals(&self) -> &[(Interval, V)] {
&self.entries
}
pub fn find_overlapping(&self, query: &Interval) -> Vec<&(Interval, V)> {
self.entries
.iter()
.filter(|(iv, _)| iv.overlaps(query))
.collect()
}
pub fn begin_index(&self) -> Option<u32> {
self.entries.first().map(|(iv, _)| iv.start)
}
pub fn end_index(&self) -> Option<u32> {
self.entries.last().map(|(iv, _)| iv.end)
}
}
impl<V: Clone> Default for IntervalMap<V> {
fn default() -> Self {
Self::new()
}
}
impl<V: Clone + fmt::Display> fmt::Display for IntervalMap<V> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{{")?;
for (i, (iv, val)) in self.entries.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}:{}", iv, val)?;
}
write!(f, "}}")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_interval_basic() {
let iv = Interval::new(10, 20);
assert_eq!(iv.len(), 10);
assert!(iv.contains(15));
assert!(!iv.contains(20));
assert!(!iv.contains(9));
}
#[test]
fn test_interval_overlaps() {
let a = Interval::new(0, 10);
let b = Interval::new(5, 15);
let c = Interval::new(10, 20);
assert!(a.overlaps(&b));
assert!(!a.overlaps(&c));
}
#[test]
fn test_interval_intersect() {
let a = Interval::new(0, 10);
let b = Interval::new(5, 15);
let isect = a.intersect(&b).unwrap();
assert_eq!(isect, Interval::new(5, 10));
}
#[test]
fn test_interval_union() {
let a = Interval::new(0, 10);
let c = Interval::new(10, 20);
let u = a.union(&c).unwrap();
assert_eq!(u, Interval::new(0, 20));
}
#[test]
fn test_interval_map_insert() {
let mut map = IntervalMap::new();
map.insert(Interval::new(0, 10), "A");
map.insert(Interval::new(20, 30), "B");
assert_eq!(map.len(), 2);
}
#[test]
fn test_interval_map_coalesce() {
let mut map = IntervalMap::new();
map.insert(Interval::new(0, 10), "A");
map.insert(Interval::new(5, 20), "A"); assert_eq!(map.len(), 1);
let (iv, _) = &map.intervals()[0];
assert_eq!(iv.start, 0);
assert_eq!(iv.end, 20);
}
#[test]
fn test_interval_map_get() {
let mut map = IntervalMap::new();
map.insert(Interval::new(10, 20), "hello");
assert_eq!(map.get(15), Some(&"hello"));
assert_eq!(map.get(5), None);
assert_eq!(map.get(20), None);
}
#[test]
fn test_interval_map_find_overlapping() {
let mut map = IntervalMap::new();
map.insert(Interval::new(0, 10), "A");
map.insert(Interval::new(15, 25), "B");
map.insert(Interval::new(30, 40), "C");
let overlaps = map.find_overlapping(&Interval::new(5, 20));
assert_eq!(overlaps.len(), 2); }
#[test]
fn test_interval_map_clear() {
let mut map = IntervalMap::new();
map.insert(Interval::new(0, 10), "X");
map.clear();
assert!(map.is_empty());
}
#[test]
fn test_interval_map_begin_end() {
let mut map = IntervalMap::new();
map.insert(Interval::new(10, 20), "A");
map.insert(Interval::new(30, 50), "B");
assert_eq!(map.begin_index(), Some(10));
assert_eq!(map.end_index(), Some(50));
}
}