use std::ops::RangeInclusive; #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct ByteRange { /// inclusive from: u8, /// inclusive to: u8, } impl From> for ByteRange { fn from(value: RangeInclusive) -> Self { Self::new_range(*value.start(), *value.end()) } } impl ByteRange { pub fn new_range(from: u8, to: u8) -> Self { assert!(from <= to); Self { from, to } } #[cfg(test)] pub fn new_single(c: u8) -> Self { Self::new_range(c, c) } pub fn contains(&self, c: u8) -> bool { self.from <= c && c <= self.to } pub fn overlaps(&self, other: Self) -> bool { self.from.max(other.from) <= self.to.min(other.to) } pub fn non_overlapping(sets: Vec) -> Vec { let begins = sets.iter().map(|cs| (cs.from, 1)); let ends = sets.iter().map(|cs| (cs.to, 2)); let mut edges: Vec<_> = begins.chain(ends).collect(); edges.sort(); edges.iter_mut().for_each(|c| { if c.1 == 2 { c.1 = -1; } }); let mut last = None; let mut depth = 0; let mut out = Vec::new(); for (mut loc, delta) in edges { if let Some(last) = last && last <= loc { out.push(ByteRange::new_range(last, loc)); loc += 1; } depth += delta; if depth > 0 { last = Some(loc); } else { last = None; } } out } } impl std::fmt::Debug for ByteRange { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { if self.from == self.to { write!(f, "{}", [self.from].escape_ascii()) } else { write!( f, "{}-{}", [self.from].escape_ascii(), [self.to].escape_ascii() ) } } } #[cfg(test)] mod non_overlapping_tests { use std::ops::RangeInclusive; use super::ByteRange; fn middle(r: ByteRange) -> u8 { let a = r.from as u8; let b = r.to as u8; (a + (b - a) / 2) as u8 } fn prev(c: u8) -> u8 { c - 1 } fn next(c: u8) -> u8 { c + 1 } fn run(ranges: Vec>) { let ranges1: Vec = ranges.into_iter().map(Into::into).collect(); let ranges2 = ByteRange::non_overlapping(ranges1.clone()); let r1 = |c| ranges1.iter().any(|cr| cr.contains(c)); let r2 = |c| ranges2.iter().any(|cr| cr.contains(c)); for &range in ranges1.iter() { assert!(r1(range.from)); assert!(r1(range.to)); assert!(r1(middle(range))); assert!(r2(range.from)); assert!(r2(range.to)); assert!(r2(middle(range))); assert_eq!(r1(prev(range.from)), r2(prev(range.from))); assert_eq!(r1(next(range.from)), r2(next(range.from))); } for i in 0..ranges2.len() { for j in 0..i { assert!( !ranges2[i].overlaps(ranges2[j]), "{i} and {j} overlap: {:?}, {:?}", ranges2[i], ranges2[j] ); } } } #[test] fn overlap_correct() { assert!(ByteRange::new_range(b'a', b'g').overlaps(ByteRange::new_single(b'f'))); assert!(!ByteRange::new_range(b'a', b'g').overlaps(ByteRange::new_single(b'h'))); } #[test] fn empty() { run(vec![]); } #[test] fn singleton() { run(vec![b'0'..=b'9']); } #[test] fn contained1() { run(vec![b'0'..=b'9', b'5'..=b'6']); } #[test] fn contained2() { run(vec![b'5'..=b'6', b'0'..=b'9']); } #[test] fn overlap2() { run(vec![b'1'..=b'6', b'4'..=b'9']) } #[test] fn overlap3() { run(vec![b'a'..=b'f', b'd'..=b'j', b'g'..=b'm']) } #[test] fn overlap4() { run(vec![b'a'..=b'f', b'd'..=b'j', b'g'..=b'm', b'k'..=b'q']) } }