pub(crate) type Bound = i64;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
struct Span {
beg: Bound,
end: Bound,
}
#[derive(Debug, Default)]
pub(crate) struct Cover {
span: Vec<Span>,
}
impl Cover {
pub(crate) fn clear(&mut self) {
self.span.clear();
}
fn find(&self, val: Bound) -> usize {
let (mut lo, mut hi) = (0usize, self.span.len());
while lo < hi {
let mid = (lo + hi) >> 1;
if val < self.span[mid].beg {
hi = mid;
} else {
lo = mid + 1;
}
}
hi
}
pub(crate) fn within(&self, val: Bound) -> bool {
let pos = self.find(val);
pos > 0 && val < self.span[pos - 1].end
}
pub(crate) fn add(&mut self, beg: Bound, end: Bound) -> i32 {
if beg >= end {
return -1;
}
let pos = self.find(beg);
let num = self.span.len();
if (pos > 0 && beg < self.span[pos - 1].end) || (pos < num && end > self.span[pos].beg) {
return 1;
}
let prec = pos > 0 && beg == self.span[pos - 1].end;
let foll = pos < num && end == self.span[pos].beg;
if prec && foll {
self.span[pos - 1].end = self.span[pos].end;
self.span.remove(pos);
} else if prec {
self.span[pos - 1].end = end;
} else if foll {
self.span[pos].beg = beg;
} else {
if self.span.len() == self.span.capacity() {
let max = if self.span.capacity() == 0 {
16
} else {
self.span.capacity() << 1
};
if self.span.try_reserve_exact(max - self.span.len()).is_err() {
return -2;
}
}
self.span.insert(pos, Span { beg, end });
}
0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn spans_merge_and_refuse_overlaps() {
let mut c = Cover::default();
assert_eq!(c.add(5, 5), -1);
assert_eq!(c.add(10, 20), 0);
assert_eq!(c.add(30, 40), 0);
assert_eq!(c.add(19, 25), 1);
assert_eq!(c.add(25, 31), 1);
assert!(c.within(10) && c.within(19) && !c.within(20) && !c.within(9));
assert_eq!(c.add(20, 30), 0); assert_eq!(c.span, vec![Span { beg: 10, end: 40 }]);
assert_eq!(c.add(0, 10), 0); assert_eq!(c.add(40, 41), 0); assert_eq!(c.span, vec![Span { beg: 0, end: 41 }]);
assert!(!c.within(41) && !c.within(-1));
c.clear();
assert!(!c.within(5));
}
#[test]
fn the_list_grows_by_doubling_from_16() {
let mut c = Cover::default();
for i in 0..17 {
assert_eq!(c.add(i * 10, i * 10 + 1), 0);
}
assert_eq!(c.span.len(), 17);
assert!(c.span.capacity() >= 32);
}
}