use std::ops::Range;
pub type Interval = Range<usize>;
#[derive(PartialEq, Eq, Debug)]
pub enum Mutation<V> {
ModifiedBegin(Interval, usize),
ModifiedEnd(Interval, usize),
Split(Interval, Interval, Interval),
Removed(Interval, V),
}
pub struct ItemIter<'a, V> {
map: &'a IntervalMap<V>,
i: usize,
}
impl<'a, V> Iterator for ItemIter<'a, V> {
type Item = (Interval, &'a V);
fn next(&mut self) -> Option<Self::Item> {
let i = self.i;
let m = self.map;
if i >= m.starts.len() {
return None;
}
let rv = Some(((m.starts[i]..m.ends[i]), &m.vals[i]));
self.i += 1;
rv
}
}
pub struct KeyIter<'a, V> {
map: &'a IntervalMap<V>,
i: usize,
}
impl<'a, V> Iterator for KeyIter<'a, V> {
type Item = Interval;
fn next(&mut self) -> Option<Self::Item> {
let i = self.i;
let m = self.map;
if i >= m.starts.len() {
return None;
}
let rv = Some(m.starts[i]..m.ends[i]);
self.i += 1;
rv
}
}
#[derive(Clone, Debug)]
pub struct IntervalMap<V> {
starts: Vec<usize>,
ends: Vec<usize>,
vals: Vec<V>,
}
impl<V: Clone> IntervalMap<V> {
pub fn new() -> IntervalMap<V> {
IntervalMap {
starts: Vec::new(),
ends: Vec::new(),
vals: Vec::new(),
}
}
pub fn keys(&self) -> KeyIter<V> {
KeyIter { map: self, i: 0 }
}
pub fn iter(&self) -> ItemIter<V> {
ItemIter { map: self, i: 0 }
}
pub fn iter_from(&self, begin: usize) -> ItemIter<V> {
let idx = match self.starts.binary_search(&begin) {
Ok(i) => i,
Err(i) if (i > 0 && begin < self.ends[i - 1]) => i - 1,
Err(i) => i,
};
ItemIter { map: self, i: idx }
}
pub fn clear(&mut self, interval: Interval) -> Vec<Mutation<V>> {
self.splice(interval, None)
}
pub fn insert(&mut self, interval: Interval, val: V) -> Vec<Mutation<V>> {
self.splice(interval, Some(val))
}
fn splice(&mut self, interval: Interval, val: Option<V>) -> Vec<Mutation<V>> {
let start = interval.start;
let end = interval.end;
assert!(start < end);
let mut mutations = Vec::new();
let mut starts_insertions = Vec::new();
let mut ends_insertions = Vec::new();
let mut vals_insertions = Vec::new();
if let Some(v) = val {
starts_insertions.push(start);
ends_insertions.push(end);
vals_insertions.push(v);
};
let splice_start = match self.starts.binary_search(&start) {
Ok(i) | Err(i) => i,
};
if splice_start > 0 && self.ends[splice_start - 1] > start {
let overlapping_idx = splice_start - 1;
let overlapping_int = self.starts[overlapping_idx]..self.ends[overlapping_idx];
if overlapping_int.end <= end {
self.ends[overlapping_idx] = start;
mutations.push(Mutation::ModifiedEnd(
overlapping_int,
self.ends[overlapping_idx],
));
} else {
let new1 = overlapping_int.start..start;
let new2 = end..overlapping_int.end;
self.ends[overlapping_idx] = new1.end;
starts_insertions.push(new2.start);
ends_insertions.push(new2.end);
vals_insertions.push(self.vals[overlapping_idx].clone());
mutations.push(Mutation::Split(overlapping_int, new1, new2));
}
}
let splice_end = match self.ends.binary_search(&end) {
Ok(i) => i + 1,
Err(i) => i,
};
let mut modified_start: Option<Mutation<V>> = None;
if splice_end < self.starts.len()
&& self.starts[splice_end] < end
&& self.ends[splice_end] > end
{
let overlapping_idx = splice_end;
let overlapping_int = self.starts[overlapping_idx]..self.ends[overlapping_idx];
self.starts[overlapping_idx] = end;
modified_start = Some(Mutation::ModifiedBegin(
overlapping_int,
self.starts[overlapping_idx],
));
}
let dropped_starts = self
.starts
.splice(splice_start..splice_end, starts_insertions);
let dropped_ends = self.ends.splice(splice_start..splice_end, ends_insertions);
let mut dropped_vals = self.vals.splice(splice_start..splice_end, vals_insertions);
for (dropped_start, dropped_end) in dropped_starts.zip(dropped_ends) {
mutations.push(Mutation::Removed(
dropped_start..dropped_end,
dropped_vals.next().unwrap(),
));
}
if let Some(m) = modified_start {
mutations.push(m)
}
mutations
}
fn get_index(&self, x: usize) -> Option<usize> {
match self.starts.binary_search(&x) {
Ok(i) => Some(i),
Err(i) => {
if i == 0 {
None
} else if x < self.ends[i - 1] {
Some(i - 1)
} else {
None
}
}
}
}
pub fn get(&self, x: usize) -> Option<(Interval, &V)> {
self.get_index(x)
.map(|i| (self.starts[i]..self.ends[i], &self.vals[i]))
}
pub fn get_mut(&mut self, x: usize) -> Option<(Interval, &mut V)> {
match self.get_index(x) {
None => None,
Some(i) => Some((self.starts[i]..self.ends[i], &mut self.vals[i])),
}
}
}
impl<V: Clone> Default for IntervalMap<V> {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
fn interval_sum<I>(i: I) -> usize
where
I: Iterator<Item = Interval>,
{
i.map(|x| x.end - x.start).sum()
}
fn validate_map<V: Clone>(m: &IntervalMap<V>) -> Result<(), String> {
for i in m.keys() {
if i.start >= i.end {
return Err(format!("Invalid interval {:?}", i));
}
}
for (i1, i2) in m.keys().zip(m.keys().skip(1)) {
if i1.end > i2.start {
return Err(format!("Overlapping intervals {:?} and {:?}", i1, i2));
}
}
Ok(())
}
fn insert_and_sanity_check(
m: &mut IntervalMap<String>,
interval: Interval,
val: &str,
) -> Result<Vec<Mutation<String>>, String> {
let old_len_sum = interval_sum(m.keys());
let mutations = m.insert(interval.clone(), val.to_string());
validate_map(m)?;
let new_len_sum = interval_sum(m.keys());
let new_len = m.keys().count();
if new_len_sum < old_len_sum {
return Err(format!(
"length-sum shrunk from {} to {}",
old_len_sum, new_len_sum
));
}
if new_len_sum < (interval.end - interval.start) {
return Err(format!(
"length-sum {} is smaller than inserted interval length {}",
new_len_sum,
interval.end - interval.start
));
}
if new_len == 0 {
return Err("new length is zero".to_string());
}
Ok(mutations)
}
#[test]
#[cfg_attr(miri, ignore)]
fn test_insert_random() {
use rand::Rng;
use rand_core::SeedableRng;
let dist = rand::distributions::Uniform::new_inclusive(0, 10);
let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(10);
for i in 0..1000 {
let mut m = IntervalMap::new();
for j in 0..10 {
let start: usize = rng.sample(dist);
let end: usize = start + rng.sample(dist) + 1;
let mut m_clone = m.clone();
let res = std::panic::catch_unwind(move || {
insert_and_sanity_check(&mut m_clone, start..end, &format!("{}.{}", i, j))
.unwrap();
m_clone
});
if res.is_err() {
println!(
"Failed inserting {} -> {} into {:?}",
start,
end,
m.iter().map(|(i, s)| (i, s.clone())).collect::<Vec<_>>()
);
}
m = res.unwrap();
}
}
}
fn insert_and_validate(
m: &mut IntervalMap<String>,
interval: Interval,
val: &str,
expected_mutations: &[Mutation<String>],
expected_val: &[(Interval, &str)],
) {
let mutations = insert_and_sanity_check(m, interval, val).unwrap();
assert_eq!(mutations, expected_mutations);
assert_eq!(
m.iter().map(|(i, s)| (i, s.clone())).collect::<Vec<_>>(),
expected_val
.iter()
.map(|(i, s)| (i.clone(), s.to_string()))
.collect::<Vec<_>>()
);
}
#[test]
fn test_insert_into_empty() {
let mut m = IntervalMap::new();
insert_and_validate(&mut m, 10..20, "x", &[], &[(10..20, "x")]);
}
#[test]
fn test_insert_after() {
let mut m = IntervalMap::new();
m.insert(1..3, "i1".to_string());
insert_and_validate(&mut m, 4..6, "i2", &[], &[(1..3, "i1"), (4..6, "i2")]);
}
#[test]
fn test_insert_before() {
let mut m = IntervalMap::new();
m.insert(4..6, "i1".to_string());
insert_and_validate(&mut m, 1..3, "i2", &[], &[(1..3, "i2"), (4..6, "i1")]);
}
#[test]
fn test_insert_just_before() {
let mut m = IntervalMap::new();
m.insert(20..30, "first".to_string());
insert_and_validate(
&mut m,
10..20,
"second",
&[],
&[(10..20, "second"), (20..30, "first")],
);
}
#[test]
fn test_insert_over_start() {
let mut m = IntervalMap::new();
m.insert(20..30, "first".to_string());
insert_and_validate(
&mut m,
10..21,
"second",
&[Mutation::ModifiedBegin(20..30, 21)],
&[(10..21, "second"), (21..30, "first")],
);
}
#[test]
fn test_insert_on_start() {
let mut m = IntervalMap::new();
m.insert(20..30, "first".to_string());
insert_and_validate(
&mut m,
20..21,
"second",
&[Mutation::ModifiedBegin(20..30, 21)],
&[(20..21, "second"), (21..30, "first")],
);
}
#[test]
fn test_insert_just_after() {
let mut m = IntervalMap::new();
m.insert(20..30, "first".to_string());
insert_and_validate(
&mut m,
30..40,
"second",
&[],
&[(20..30, "first"), (30..40, "second")],
);
}
#[test]
fn test_insert_over_end() {
let mut m = IntervalMap::new();
m.insert(20..30, "first".to_string());
insert_and_validate(
&mut m,
29..31,
"second",
&[Mutation::ModifiedEnd(20..30, 29)],
&[(20..29, "first"), (29..31, "second")],
);
}
#[test]
fn test_insert_on_end() {
let mut m = IntervalMap::new();
m.insert(20..30, "first".to_string());
insert_and_validate(
&mut m,
29..30,
"second",
&[Mutation::ModifiedEnd(20..30, 29)],
&[(20..29, "first"), (29..30, "second")],
);
}
#[test]
fn test_insert_removing() {
let mut m = IntervalMap::new();
m.insert(20..30, "first".to_string());
insert_and_validate(
&mut m,
10..40,
"second",
&[Mutation::Removed(20..30, "first".to_string())],
&[(10..40, "second")],
);
}
#[test]
fn test_insert_forcing_split() {
let mut m = IntervalMap::new();
m.insert(20..30, "first".to_string());
insert_and_validate(
&mut m,
24..25,
"second",
&[Mutation::Split(20..30, 20..24, 25..30)],
&[(20..24, "first"), (24..25, "second"), (25..30, "first")],
);
}
#[test]
fn test_insert_over_exact() {
let mut m = IntervalMap::new();
m.insert(1..2, "old".to_string());
insert_and_validate(
&mut m,
1..2,
"new",
&[Mutation::Removed(1..2, "old".to_string())],
&[(1..2, "new")],
);
}
#[test]
fn test_insert_all_mutations() {
let mut m = IntervalMap::new();
m.insert(0..10, "first".to_string());
m.insert(20..30, "second".to_string());
m.insert(40..50, "third".to_string());
insert_and_validate(
&mut m,
5..45,
"clobbering",
&[
Mutation::ModifiedEnd(0..10, 5),
Mutation::Removed(20..30, "second".to_string()),
Mutation::ModifiedBegin(40..50, 45),
],
&[(0..5, "first"), (5..45, "clobbering"), (45..50, "third")],
);
}
fn clear_and_sanity_check(
m: &mut IntervalMap<String>,
start: usize,
end: usize,
) -> Result<Vec<Mutation<String>>, String> {
let old_len = interval_sum(m.keys());
let mutations = m.clear(start..end);
validate_map(m)?;
let new_len = interval_sum(m.keys());
if new_len > old_len {
return Err(format!("new_len {} > old_len {}", new_len, old_len));
}
Ok(mutations)
}
#[test]
#[cfg_attr(miri, ignore)]
fn test_clear_random() {
use rand::Rng;
use rand_core::SeedableRng;
let dist = rand::distributions::Uniform::new_inclusive(0, 10);
let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(10);
for i in 0..1000 {
let mut m = IntervalMap::new();
for j in 0..10 {
let insert_start = rng.sample(dist);
let insert_end = insert_start + 1 + rng.sample(dist);
let clear_start = rng.sample(dist);
let clear_end = clear_start + 1 + rng.sample(dist);
let mut m_clone = m.clone();
let res = std::panic::catch_unwind(move || {
clear_and_sanity_check(&mut m_clone, clear_start, clear_end).unwrap();
insert_and_sanity_check(
&mut m_clone,
insert_start..insert_end,
&format!("{}.{}", i, j),
)
.unwrap();
m_clone
});
if res.is_err() {
println!(
"Failed after inserting {} -> {} and clearing {} -> {} in {:?}",
insert_start,
insert_end,
clear_start,
clear_end,
m.iter().map(|(i, s)| (i, s.clone())).collect::<Vec<_>>()
);
}
m = res.unwrap();
}
}
}
fn clear_and_validate(
m: &mut IntervalMap<String>,
interval: Interval,
expected_mutations: &[Mutation<String>],
expected_val: &[(Interval, &str)],
) {
let start = interval.start;
let end = interval.end;
let mutations = clear_and_sanity_check(m, start, end).unwrap();
assert_eq!(mutations, expected_mutations);
assert_eq!(
m.iter().map(|(i, s)| (i, s.clone())).collect::<Vec<_>>(),
expected_val
.iter()
.map(|(i, s)| (i.clone(), s.to_string()))
.collect::<Vec<_>>()
);
}
#[test]
fn test_clear_over_start() {
let mut m = IntervalMap::new();
m.insert(20..30, "first".to_string());
clear_and_validate(
&mut m,
10..21,
&[Mutation::ModifiedBegin(20..30, 21)],
&[(21..30, "first")],
);
}
#[test]
fn test_clear_over_end() {
let mut m = IntervalMap::new();
m.insert(20..30, "first".to_string());
clear_and_validate(
&mut m,
29..31,
&[Mutation::ModifiedEnd(20..30, 29)],
&[(20..29, "first")],
);
}
#[test]
fn test_clear_forcing_split() {
let mut m = IntervalMap::new();
m.insert(20..30, "first".to_string());
clear_and_validate(
&mut m,
24..25,
&[Mutation::Split(20..30, 20..24, 25..30)],
&[(20..24, "first"), (25..30, "first")],
);
}
#[test]
fn test_clear_removing() {
let mut m = IntervalMap::new();
m.insert(20..30, "first".to_string());
clear_and_validate(
&mut m,
10..40,
&[Mutation::Removed(20..30, "first".to_string())],
&[],
);
}
#[test]
fn test_get_empty() {
let m = IntervalMap::<String>::new();
assert_eq!(m.get(10), None);
}
#[test]
fn test_get_single_interval() {
let mut m = IntervalMap::<String>::new();
m.insert(1..4, "interval".to_string());
assert_eq!(m.get(0), None);
assert_eq!(m.get(1), Some((1..4, &"interval".to_string())));
assert_eq!(m.get(2), Some((1..4, &"interval".to_string())));
assert_eq!(m.get(3), Some((1..4, &"interval".to_string())));
assert_eq!(m.get(4), None);
assert_eq!(m.get(5), None);
}
#[test]
fn test_get_two_intervals_with_gap() {
let mut m = IntervalMap::<String>::new();
m.insert(1..4, "i1".to_string());
m.insert(5..9, "i2".to_string());
assert_eq!(m.get(0), None);
assert_eq!(m.get(1), Some((1..4, &"i1".to_string())));
assert_eq!(m.get(2), Some((1..4, &"i1".to_string())));
assert_eq!(m.get(3), Some((1..4, &"i1".to_string())));
assert_eq!(m.get(4), None);
assert_eq!(m.get(5), Some((5..9, &"i2".to_string())));
assert_eq!(m.get(6), Some((5..9, &"i2".to_string())));
assert_eq!(m.get(7), Some((5..9, &"i2".to_string())));
assert_eq!(m.get(8), Some((5..9, &"i2".to_string())));
assert_eq!(m.get(9), None);
}
#[test]
fn test_get_two_intervals_without_gap() {
let mut m = IntervalMap::<String>::new();
m.insert(1..3, "i1".to_string());
m.insert(3..6, "i2".to_string());
assert_eq!(m.get(0), None);
assert_eq!(m.get(1), Some((1..3, &"i1".to_string())));
assert_eq!(m.get(2), Some((1..3, &"i1".to_string())));
assert_eq!(m.get(3), Some((3..6, &"i2".to_string())));
assert_eq!(m.get(4), Some((3..6, &"i2".to_string())));
assert_eq!(m.get(5), Some((3..6, &"i2".to_string())));
assert_eq!(m.get(6), None);
}
#[test]
fn test_iter_from() {
let mut m = IntervalMap::<&str>::new();
m.insert(1..3, "i1");
m.insert(4..6, "i2");
assert_eq!(
m.iter_from(0).collect::<Vec<_>>(),
vec![(1..3, &"i1"), (4..6, &"i2")]
);
assert_eq!(
m.iter_from(1).collect::<Vec<_>>(),
vec![(1..3, &"i1"), (4..6, &"i2")]
);
assert_eq!(
m.iter_from(2).collect::<Vec<_>>(),
vec![(1..3, &"i1"), (4..6, &"i2")]
);
assert_eq!(m.iter_from(3).collect::<Vec<_>>(), vec![(4..6, &"i2")]);
assert_eq!(m.iter_from(4).collect::<Vec<_>>(), vec![(4..6, &"i2")]);
assert_eq!(m.iter_from(5).collect::<Vec<_>>(), vec![(4..6, &"i2")]);
assert_eq!(m.iter_from(6).collect::<Vec<_>>(), vec![]);
assert_eq!(m.iter_from(7).collect::<Vec<_>>(), vec![]);
}
}