use std::fmt::Display;
#[derive(Debug, Clone)]
pub struct RangeMap<K, V> {
mapping: Vec<(K, K, V)>,
}
impl<K: Clone + Copy + Display + PartialOrd + Ord, V> RangeMap<K, V> {
pub fn empty() -> Self {
RangeMap {
mapping: Vec::new(),
}
}
pub fn builder() -> RangeMapBuilder<K, V> {
RangeMapBuilder {
mapping: Vec::new(),
}
}
pub fn get(&self, key: K) -> Option<&V> {
let idx = self
.mapping
.binary_search_by_key(&key, |&(start, end, _)| {
if key >= start && key < end {
key
} else {
start
}
})
.ok()?;
self.mapping.get(idx).map(|(_, _, val)| val)
}
}
#[derive(Debug, Clone)]
pub struct RangeMapBuilder<K, V> {
mapping: Vec<(K, K, V)>,
}
impl<K: Clone + Copy + Display + PartialOrd + Ord, V> RangeMapBuilder<K, V> {
pub fn try_add_range(
&mut self,
start: K,
end: K,
val: V,
) -> Result<&mut Self, RangeMapError<K>> {
let (start, end) = if start < end {
(start, end)
} else {
(end, start)
};
if start == end {
return Err(RangeMapError::EmptyRange(start));
}
if let Some(&(s, e, _)) = self.mapping.iter().find(|&&(s, e, _)| start < e && end > s) {
return Err(RangeMapError::OverlappingRanges {
proposed: (start, end),
existing: (s, e),
});
}
self.mapping.push((start, end, val));
Ok(self)
}
pub fn add_range(mut self, start: K, end: K, val: V) -> Self {
if let Err(e) = self.try_add_range(start, end, val) {
panic!("{e}")
}
self
}
pub fn build(mut self) -> RangeMap<K, V> {
self.mapping.sort_by_key(|&(start, _, _)| start);
RangeMap {
mapping: self.mapping,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
pub enum RangeMapError<K: Display> {
#[error("Block range cannot be empty: start and end values must be different, but got {} for both", .0)]
EmptyRange(K),
#[error("Overlapping block ranges are not allowed: proposed range is {}..{}, but we already have {}..{}", proposed.0, proposed.1, existing.0, existing.1)]
OverlappingRanges {
proposed: (K, K),
existing: (K, K),
},
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_rangemap_get() {
let spec_version = RangeMap::builder()
.add_range(0, 100, 1)
.add_range(100, 200, 2)
.add_range(200, 300, 3)
.build();
assert_eq!(spec_version.get(0), Some(&1));
assert_eq!(spec_version.get(50), Some(&1));
assert_eq!(spec_version.get(100), Some(&2));
assert_eq!(spec_version.get(150), Some(&2));
assert_eq!(spec_version.get(200), Some(&3));
assert_eq!(spec_version.get(250), Some(&3));
assert_eq!(spec_version.get(300), None);
}
#[test]
fn test_rangemap_set() {
let mut spec_version = RangeMap::builder()
.add_range(0, 100, 1)
.add_range(200, 300, 3);
assert_eq!(
spec_version.try_add_range(99, 130, 2).unwrap_err(),
RangeMapError::OverlappingRanges {
proposed: (99, 130),
existing: (0, 100),
}
);
assert_eq!(
spec_version.try_add_range(170, 201, 2).unwrap_err(),
RangeMapError::OverlappingRanges {
proposed: (170, 201),
existing: (200, 300),
}
);
}
}