use std::{cmp, fmt, ops::Range};
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct Interval {
start: u64,
length: u64,
}
impl Interval {
pub fn new(start: u64, length: u64) -> Self {
Self { start, length }
}
pub fn len(&self) -> u64 {
self.length
}
pub fn is_empty(&self) -> bool {
self.length == 0
}
pub fn start(&self) -> u64 {
self.start
}
pub fn end(&self) -> u64 {
self.start + self.length
}
pub fn contains(&self, p: u64) -> bool {
p >= self.start && p < self.end()
}
pub fn intersect(&self, other: &Self) -> bool {
let connected = self.connect(other);
connected.length < (self.length + other.length)
}
pub fn near(&self, other: &Self) -> bool {
let connected = self.connect(other);
connected.length <= (self.length + other.length)
}
pub fn connect(&self, other: &Self) -> Self {
let min_start = cmp::min(self.start, other.start);
let max_end = cmp::max(self.end(), other.end());
Interval::new(min_start, max_end - min_start)
}
pub fn split(&self, length: u64) -> (Self, Self) {
let left = Self::new(self.start, length);
let right = Self::new(self.start + length, self.length - length);
(left, right)
}
pub fn try_join(&self, other: &Self) -> Option<Self> {
match self.near(other) {
true => Some(self.connect(other)),
false => None,
}
}
pub fn iter(&self) -> impl Iterator<Item = u64> {
self.start()..self.end()
}
}
impl From<Range<u64>> for Interval {
fn from(r: Range<u64>) -> Self {
Interval::new(r.start, r.end - r.start)
}
}
impl fmt::Display for Interval {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "[{}, {})", self.start(), self.end())
}
}
#[cfg(test)]
mod tests {
use crate::interval::Interval;
#[test]
fn connect() {
let i1 = Interval::new(0, 10);
let i2 = Interval::new(15, 10);
let conn = i1.connect(&i2);
assert_eq!(conn.start(), i1.start());
assert_eq!(conn.end(), i2.end());
let conn_refl = i2.connect(&i1);
assert_eq!(conn, conn_refl);
}
#[test]
fn split() {
let i = Interval::new(0, 10);
let sp = 3;
let (s1, s2) = i.split(sp);
assert_eq!(s1.start(), i.start());
assert_eq!(s1.len(), sp);
assert_eq!(s2.len(), i.len() - s1.len());
assert_eq!(s2.start(), s1.end())
}
#[test]
fn join() {
let i1 = Interval::new(0, 10);
let i2 = Interval::new(5, 10);
let i3 = Interval::new(20, 10);
let join = i1.try_join(&i2).unwrap();
assert_eq!(join.start(), i1.start());
assert_eq!(join.end(), i2.end());
let join_refl = i2.try_join(&i1).unwrap();
assert_eq!(join, join_refl);
assert!(i1.try_join(&i3).is_none());
assert!(i3.try_join(&i1).is_none());
}
#[test]
fn test_iter() {
let i = Interval::new(0, 3);
let mut iter = i.iter();
assert_eq!(iter.next(), Some(0));
assert_eq!(iter.next(), Some(1));
assert_eq!(iter.next(), Some(2));
assert_eq!(iter.next(), None);
}
}