use smallvec::SmallVec;
use std::{cmp::Ordering, fmt::Debug, iter, ops::Range, slice::Iter};
#[derive(Clone, Debug, PartialEq)]
pub struct RangedStates<I, T> {
ranges: SmallVec<[(Range<I>, T); 1]>,
}
impl<I: Copy + PartialOrd, T: Copy + PartialEq> RangedStates<I, T> {
pub fn empty() -> Self {
RangedStates {
ranges: SmallVec::new(),
}
}
pub fn from_range(range: Range<I>, value: T) -> Self {
RangedStates {
ranges: iter::once((range, value)).collect(),
}
}
#[cfg(test)]
pub fn from_slice(values: &[(Range<I>, T)]) -> Self {
RangedStates {
ranges: values.iter().cloned().collect(),
}
}
pub fn clear(&mut self) {
self.ranges.clear();
}
pub fn append(&mut self, index: Range<I>, value: T) {
if let Some(last) = self.ranges.last() {
debug_assert!(last.0.end <= index.start);
}
self.ranges.push((index, value));
}
#[cfg(test)]
fn check_sanity(&self) {
for a in self.ranges.iter() {
assert!(a.0.start < a.0.end);
}
for (a, b) in self.ranges.iter().zip(self.ranges[1..].iter()) {
assert!(a.0.end <= b.0.start);
}
}
pub fn coalesce(&mut self) {
let mut num_removed = 0;
let mut iter = self.ranges.iter_mut();
let mut cur = match iter.next() {
Some(elem) => elem,
None => return,
};
for next in iter {
if cur.0.end == next.0.start && cur.1 == next.1 {
num_removed += 1;
cur.0.end = next.0.end;
next.0.end = next.0.start;
} else {
cur = next;
}
}
if num_removed != 0 {
self.ranges.retain(|pair| pair.0.start != pair.0.end);
}
}
pub fn query<U: PartialEq>(
&self,
index: &Range<I>,
fun: impl Fn(&T) -> U,
) -> Option<Result<U, ()>> {
let mut result = None;
for &(ref range, ref value) in self.ranges.iter() {
if range.end > index.start && range.start < index.end {
let old = result.replace(fun(value));
if old.is_some() && old != result {
return Some(Err(()));
}
}
}
result.map(Ok)
}
pub fn isolate(&mut self, index: &Range<I>, default: T) -> &mut [(Range<I>, T)] {
let mut start_pos = match self.ranges.iter().position(|pair| pair.0.end > index.start) {
Some(pos) => pos,
None => {
let pos = self.ranges.len();
self.ranges.push((index.clone(), default));
return &mut self.ranges[pos..];
}
};
{
let (range, value) = self.ranges[start_pos].clone();
if range.start < index.start {
self.ranges[start_pos].0.start = index.start;
self.ranges
.insert(start_pos, (range.start..index.start, value));
start_pos += 1;
}
}
let mut pos = start_pos;
let mut range_pos = index.start;
loop {
let (range, value) = self.ranges[pos].clone();
if range.start >= index.end {
self.ranges.insert(pos, (range_pos..index.end, default));
pos += 1;
break;
}
if range.start > range_pos {
self.ranges.insert(pos, (range_pos..range.start, default));
pos += 1;
range_pos = range.start;
}
if range.end >= index.end {
if range.end != index.end {
self.ranges[pos].0.start = index.end;
self.ranges.insert(pos, (range_pos..index.end, value));
}
pos += 1;
break;
}
pos += 1;
range_pos = range.end;
if pos == self.ranges.len() {
self.ranges.push((range_pos..index.end, default));
pos += 1;
break;
}
}
&mut self.ranges[start_pos..pos]
}
#[cfg(test)]
pub fn sanely_isolated(&self, index: Range<I>, default: T) -> Vec<(Range<I>, T)> {
let mut clone = self.clone();
let result = clone.isolate(&index, default).to_vec();
clone.check_sanity();
result
}
pub fn merge<'a>(&'a self, other: &'a Self, base: I) -> Merge<'a, I, T> {
Merge {
base,
sa: self.ranges.iter().peekable(),
sb: other.ranges.iter().peekable(),
}
}
}
#[derive(Debug)]
pub struct Merge<'a, I, T> {
base: I,
sa: iter::Peekable<Iter<'a, (Range<I>, T)>>,
sb: iter::Peekable<Iter<'a, (Range<I>, T)>>,
}
impl<'a, I: Copy + Debug + Ord, T: Copy + Debug> Iterator for Merge<'a, I, T> {
type Item = (Range<I>, Range<Option<T>>);
fn next(&mut self) -> Option<Self::Item> {
match (self.sa.peek(), self.sb.peek()) {
(Some(&(ref ra, va)), Some(&(ref rb, vb))) => {
let (range, usage) = if ra.start < self.base {
if self.base == rb.start {
debug_assert!(self.base < ra.end);
(self.base..ra.end.min(rb.end), Some(*va)..Some(*vb))
} else {
debug_assert!(self.base < rb.start);
(self.base..rb.start, Some(*va)..None)
}
} else if rb.start < self.base {
if self.base == ra.start {
debug_assert!(self.base < rb.end);
(self.base..ra.end.min(rb.end), Some(*va)..Some(*vb))
} else {
debug_assert!(self.base < ra.start);
(self.base..ra.start, None..Some(*vb))
}
} else {
match ra.start.cmp(&rb.start) {
Ordering::Equal => (ra.start..ra.end.min(rb.end), Some(*va)..Some(*vb)),
Ordering::Less => (ra.start..rb.start.min(ra.end), Some(*va)..None),
Ordering::Greater => (rb.start..ra.start.min(rb.end), None..Some(*vb)),
}
};
self.base = range.end;
if ra.end == range.end {
let _ = self.sa.next();
}
if rb.end == range.end {
let _ = self.sb.next();
}
Some((range, usage))
}
(None, Some(&(ref rb, vb))) => {
let range = self.base.max(rb.start)..rb.end;
self.base = rb.end;
let _ = self.sb.next();
Some((range, None..Some(*vb)))
}
(Some(&(ref ra, va)), None) => {
let range = self.base.max(ra.start)..ra.end;
self.base = ra.end;
let _ = self.sa.next();
Some((range, Some(*va)..None))
}
(None, None) => None,
}
}
}
#[cfg(test)]
mod test {
use super::RangedStates;
use std::{fmt::Debug, ops::Range};
fn easy_merge<T: PartialEq + Copy + Debug>(
ra: &[(Range<usize>, T)],
rb: &[(Range<usize>, T)],
) -> Vec<(Range<usize>, Range<Option<T>>)> {
RangedStates::from_slice(ra)
.merge(&RangedStates::from_slice(rb), 0)
.collect()
}
#[test]
fn sane_good() {
let rs = RangedStates::from_slice(&[(1..4, 9u8), (4..5, 9)]);
rs.check_sanity();
}
#[test]
#[should_panic]
fn sane_empty() {
let rs = RangedStates::from_slice(&[(1..4, 9u8), (5..5, 9)]);
rs.check_sanity();
}
#[test]
#[should_panic]
fn sane_intersect() {
let rs = RangedStates::from_slice(&[(1..4, 9u8), (3..5, 9)]);
rs.check_sanity();
}
#[test]
fn coalesce() {
let mut rs = RangedStates::from_slice(&[(1..4, 9u8), (4..5, 9), (5..7, 1), (8..9, 1)]);
rs.coalesce();
rs.check_sanity();
assert_eq!(rs.ranges.as_slice(), &[(1..5, 9), (5..7, 1), (8..9, 1),]);
}
#[test]
fn query() {
let rs = RangedStates::from_slice(&[(1..4, 1u8), (5..7, 2)]);
assert_eq!(rs.query(&(0..1), |v| *v), None);
assert_eq!(rs.query(&(1..3), |v| *v), Some(Ok(1)));
assert_eq!(rs.query(&(1..6), |v| *v), Some(Err(())));
}
#[test]
fn isolate() {
let rs = RangedStates::from_slice(&[(1..4, 9u8), (4..5, 9), (5..7, 1), (8..9, 1)]);
assert_eq!(&rs.sanely_isolated(4..5, 0), &[(4..5, 9u8),]);
assert_eq!(
&rs.sanely_isolated(0..6, 0),
&[(0..1, 0), (1..4, 9u8), (4..5, 9), (5..6, 1),]
);
assert_eq!(&rs.sanely_isolated(8..10, 1), &[(8..9, 1), (9..10, 1),]);
assert_eq!(
&rs.sanely_isolated(6..9, 0),
&[(6..7, 1), (7..8, 0), (8..9, 1),]
);
}
#[test]
fn merge_same() {
assert_eq!(
&easy_merge(&[(1..4, 0u8),], &[(1..4, 2u8),],),
&[(1..4, Some(0)..Some(2)),]
);
}
#[test]
fn merge_empty() {
assert_eq!(
&easy_merge(&[(1..2, 0u8),], &[],),
&[(1..2, Some(0)..None),]
);
assert_eq!(
&easy_merge(&[], &[(3..4, 1u8),],),
&[(3..4, None..Some(1)),]
);
}
#[test]
fn merge_separate() {
assert_eq!(
&easy_merge(&[(1..2, 0u8), (5..6, 1u8),], &[(2..4, 2u8),],),
&[
(1..2, Some(0)..None),
(2..4, None..Some(2)),
(5..6, Some(1)..None),
]
);
}
#[test]
fn merge_subset() {
assert_eq!(
&easy_merge(&[(1..6, 0u8),], &[(2..4, 2u8),],),
&[
(1..2, Some(0)..None),
(2..4, Some(0)..Some(2)),
(4..6, Some(0)..None),
]
);
assert_eq!(
&easy_merge(&[(2..4, 0u8),], &[(1..4, 2u8),],),
&[(1..2, None..Some(2)), (2..4, Some(0)..Some(2)),]
);
}
#[test]
fn merge_all() {
assert_eq!(
&easy_merge(&[(1..4, 0u8), (5..8, 1u8),], &[(2..6, 2u8), (7..9, 3u8),],),
&[
(1..2, Some(0)..None),
(2..4, Some(0)..Some(2)),
(4..5, None..Some(2)),
(5..6, Some(1)..Some(2)),
(6..7, Some(1)..None),
(7..8, Some(1)..Some(3)),
(8..9, None..Some(3)),
]
);
}
}