use std::ops::Range;
use gap_buf::{GapBuffer, gap_buffer};
use crate::utils::merging_range_by_guess_and_lazy_shift;
#[derive(Clone, Default, Debug)]
pub struct Ranges {
list: GapBuffer<Range<i32>>,
from: usize,
shift: i32,
min_len: usize,
}
impl Ranges {
pub fn new(range: Range<usize>) -> Self {
Self {
list: gap_buffer![range.start as i32..range.end as i32],
..Self::empty()
}
}
pub const fn empty() -> Self {
Self {
list: GapBuffer::new(),
from: 0,
shift: 0,
min_len: 1,
}
}
pub fn set_min_len(&mut self, min: usize) {
self.min_len = min.max(1);
let mut i = 0;
self.list.retain(|range| {
i += 1;
if range.len() < self.min_len {
if i - 1 < self.from {
self.from -= 1;
}
false
} else {
true
}
});
}
#[track_caller]
pub fn add(&mut self, new: Range<usize>) -> bool {
assert_range(&new);
if new.len() < self.min_len {
return false;
}
let new = new.start as i32..new.end as i32;
let m_range = merging_range_by_guess_and_lazy_shift(
(&self.list, self.list.len()),
(self.from, [new.start, new.end]),
(self.from, self.shift, 0, std::ops::Add::add),
(|r| r.start, |r| r.end),
);
if self.from <= m_range.end {
for range in self.list.range_mut(self.from..m_range.end).iter_mut() {
range.start += self.shift;
range.end += self.shift;
}
}
let changed_ranges = if m_range.len() == 1 {
let range = self.list[m_range.start].clone();
!(range.start <= new.start && range.end >= new.end)
} else {
true
};
let added_range = {
let slice = self.list.range(m_range.clone());
let mut iter = slice.iter();
let first = iter.next().cloned().unwrap_or(new.clone());
let last = iter.next_back().cloned().unwrap_or(first.clone());
first.start.min(new.start)..last.end.max(new.end)
};
let new_from = self.from.saturating_sub(m_range.len()).max(m_range.start) + 1;
if new_from < self.list.len() + 1 - m_range.len() {
self.from = new_from;
} else {
self.from = 0;
self.shift = 0;
}
self.list.splice(m_range.clone(), [added_range]);
changed_ranges
}
pub fn extend(&mut self, ranges: impl IntoIterator<Item = Range<usize>>) -> bool {
let mut has_changed = false;
for range in ranges {
has_changed |= self.add(range);
}
has_changed
}
#[track_caller]
pub fn remove_on(&mut self, within: Range<usize>) -> impl Iterator<Item = Range<usize>> {
assert_range(&within);
let within = within.start as i32..within.end as i32;
let m_range = merging_range_by_guess_and_lazy_shift(
(&self.list, self.list.len()),
(self.from, [within.start, within.end]),
(self.from, self.shift, 0, std::ops::Add::add),
(|r| r.start, |r| r.end),
);
if self.from <= m_range.end {
for range in self.list.range_mut(self.from..m_range.end).iter_mut() {
range.start += self.shift;
range.end += self.shift;
}
}
let split_off = {
let slice = self.list.range(m_range.clone());
let first = slice.iter().next().cloned();
let last = slice.iter().next_back().cloned().or(first.clone());
let split_start = first.filter(|f| f.start < within.start).map(|first| {
self.list[m_range.start].start = within.start;
first.start..within.start
});
let split_end = last.filter(|l| l.end > within.end).map(|last| {
self.list[m_range.end - 1].end = within.end;
within.end..last.end
});
let min_len = |range: &Range<i32>| range.len() >= self.min_len;
[split_start.filter(min_len), split_end.filter(min_len)]
};
let added = split_off.iter().flatten().count();
let new_from = self.from.saturating_sub(m_range.len()).max(m_range.start) + added;
if new_from < self.list.len() + added - m_range.len() {
self.from = new_from;
} else {
self.from = 0;
self.shift = 0;
}
self.list
.splice(m_range, split_off.into_iter().flatten())
.map(|r| r.start as usize..r.end as usize)
}
#[track_caller]
pub fn remove_intersecting(
&mut self,
within: Range<usize>,
) -> impl Iterator<Item = Range<usize>> {
assert_range(&within);
let within = within.start as i32..within.end as i32;
let m_range = merging_range_by_guess_and_lazy_shift(
(&self.list, self.list.len()),
(self.from, [within.start, within.end]),
(self.from, self.shift, 0, std::ops::Add::add),
(|r| r.start, |r| r.end),
);
if self.from <= m_range.end {
for range in self.list.range_mut(self.from..m_range.end).iter_mut() {
range.start += self.shift;
range.end += self.shift;
}
}
let new_from = self.from.saturating_sub(m_range.len()).max(m_range.start);
if new_from < self.list.len() - m_range.len() {
self.from = new_from;
} else {
self.from = 0;
self.shift = 0;
}
self.list
.extract_if(m_range, move |range| {
range.start != within.end && range.end != within.start
})
.map(|range| range.start as usize..range.end as usize)
}
#[track_caller]
pub fn merge(&mut self, other: Self) -> bool {
let mut has_changed = false;
for range in other.list {
has_changed |= self.add(range.start as usize..range.end as usize);
}
has_changed
}
pub fn shift_by(&mut self, from: usize, shift: i32) {
let from = from as i32;
let m_range = merging_range_by_guess_and_lazy_shift(
(&self.list, self.list.len()),
(self.from, [from, from - shift.min(0)]),
(self.from, self.shift, 0, std::ops::Add::add),
(|r| r.start, |r| r.end),
);
if self.from < m_range.end && self.shift != 0 {
for range in self.list.range_mut(self.from..m_range.end).iter_mut() {
range.start += self.shift;
range.end += self.shift;
}
} else if self.from > m_range.end && self.shift != 0 {
for range in &mut self.list.range_mut(m_range.end..self.from) {
range.start -= self.shift;
range.end -= self.shift;
}
}
let range_left = {
let slice = self.list.range(m_range.clone());
let mut iter = slice.iter();
iter.next().and_then(|first| {
let last = iter.next_back().unwrap_or(first);
let range = first.start.min(from)..(last.end + shift).max(from);
(range.len() >= self.min_len).then_some(range)
})
};
let new_from = m_range.start + range_left.is_some() as usize;
self.list.splice(m_range.clone(), range_left);
if new_from < self.list.len() {
self.from = new_from;
self.shift += shift;
} else {
self.from = 0;
self.shift = 0;
}
}
pub fn len(&self) -> usize {
self.list.len()
}
pub fn is_empty(&self) -> bool {
self.list.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = Range<usize>> {
self.list.iter().enumerate().map(move |(i, range)| {
if i >= self.from {
(range.start + self.shift) as usize..(range.end + self.shift) as usize
} else {
range.start as usize..range.end as usize
}
})
}
#[track_caller]
pub fn iter_over(&self, within: Range<usize>) -> impl Iterator<Item = Range<usize>> {
self.iter_intersecting(within.clone())
.map(move |range| range.start.max(within.start)..range.end.min(within.end))
.filter(|range| !range.is_empty())
}
#[track_caller]
pub fn iter_intersecting(&self, within: Range<usize>) -> impl Iterator<Item = Range<usize>> {
assert_range(&within);
let m_range = merging_range_by_guess_and_lazy_shift(
(&self.list, self.list.len()),
(self.from, [within.start as i32, within.end as i32]),
(self.from, self.shift, 0, std::ops::Add::add),
(|r| r.start, |r| r.end),
);
let (s0, s1) = self.list.range(m_range.clone()).as_slices();
s0.iter().chain(s1).enumerate().filter_map(move |(i, r)| {
let range = if i + m_range.start >= self.from {
(r.start + self.shift) as usize..(r.end + self.shift) as usize
} else {
r.start as usize..r.end as usize
};
(range.start != within.end && range.end != within.start).then_some(range)
})
}
#[track_caller]
pub fn intersects_with(&self, range: Range<usize>) -> bool {
assert_range(&range);
let m_range = merging_range_by_guess_and_lazy_shift(
(&self.list, self.list.len()),
(self.from, [range.start as i32, range.end as i32]),
(self.from, self.shift, 0, std::ops::Add::add),
(|r| r.start, |r| r.end),
);
!m_range.is_empty()
}
}
impl IntoIterator for Ranges {
type IntoIter = IntoIter;
type Item = Range<usize>;
fn into_iter(self) -> Self::IntoIter {
IntoIter {
iter: self.list.into_iter().enumerate(),
from: self.from,
shift: self.shift,
}
}
}
pub struct IntoIter {
iter: std::iter::Enumerate<gap_buf::IntoIter<Range<i32>>>,
from: usize,
shift: i32,
}
impl Iterator for IntoIter {
type Item = Range<usize>;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|(i, range)| {
if i >= self.from {
(range.start + self.shift) as usize..(range.end + self.shift) as usize
} else {
range.start as usize..range.end as usize
}
})
}
}
impl ExactSizeIterator for IntoIter {}
impl PartialEq for Ranges {
fn eq(&self, other: &Self) -> bool {
self.len() == other.len() && self.iter().eq(other.iter())
}
}
impl Eq for Ranges {}
impl PartialOrd for Ranges {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Ranges {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
let cmp = |r: Range<usize>| [r.start, r.end];
self.iter().flat_map(cmp).cmp(other.iter().flat_map(cmp))
}
}
#[track_caller]
pub fn assert_range(range: &Range<usize>) {
assert!(
range.start <= range.end,
"range starts at {} but ends at {}",
range.start,
range.end
);
}