use std::ops::Range;
#[derive(Debug, Clone, Default)]
pub struct DirtyRanges {
ranges: Vec<Range<usize>>,
}
impl DirtyRanges {
pub fn new() -> Self {
Self { ranges: Vec::new() }
}
pub fn mark_dirty(&mut self, start: usize, end: usize) {
if start >= end {
return;
}
let new_range = start..end;
let mut insert_idx = self.ranges.len();
let mut merge_start_idx = None;
let mut merge_end_idx = None;
for (i, range) in self.ranges.iter().enumerate() {
if ranges_overlap_or_adjacent(&new_range, range) {
if merge_start_idx.is_none() {
merge_start_idx = Some(i);
}
merge_end_idx = Some(i);
} else if range.start > end {
if merge_start_idx.is_none() {
insert_idx = i;
}
break;
}
}
match (merge_start_idx, merge_end_idx) {
(Some(start_idx), Some(end_idx)) => {
let merged_start = self.ranges[start_idx].start.min(start);
let merged_end = self.ranges[end_idx].end.max(end);
self.ranges.drain(start_idx..=end_idx);
self.ranges.insert(start_idx, merged_start..merged_end);
}
(None, None) => {
self.ranges.insert(insert_idx, new_range);
}
_ => unreachable!(),
}
}
pub fn clear(&mut self) {
self.ranges.clear();
}
pub fn is_empty(&self) -> bool {
self.ranges.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = &Range<usize>> {
self.ranges.iter()
}
}
fn ranges_overlap_or_adjacent(a: &Range<usize>, b: &Range<usize>) -> bool {
(a.start < b.end && b.start < a.end) || a.end == b.start || b.end == a.start
}