uucore/ranges: refactor and test complement

This commit is contained in:
Terts Diepraam 2022-08-18 20:02:50 +02:00
parent 7890228f82
commit 003b483705

View file

@ -81,7 +81,7 @@ impl Range {
ranges.push(range_item); ranges.push(range_item);
} }
Ok(Range::merge(ranges)) Ok(Self::merge(ranges))
} }
/// Merge any overlapping ranges /// Merge any overlapping ranges
@ -107,37 +107,25 @@ impl Range {
} }
pub fn complement(ranges: &[Range]) -> Vec<Range> { pub fn complement(ranges: &[Range]) -> Vec<Range> {
let mut prev_high = 0;
let mut complements = Vec::with_capacity(ranges.len() + 1); let mut complements = Vec::with_capacity(ranges.len() + 1);
if !ranges.is_empty() && ranges[0].low > 1 { for range in ranges {
if range.low > prev_high + 1 {
complements.push(Range { complements.push(Range {
low: 1, low: prev_high + 1,
high: ranges[0].low - 1, high: range.low - 1,
}); });
} }
prev_high = range.high;
}
let mut ranges_iter = ranges.iter().peekable(); if prev_high < usize::MAX - 1 {
loop {
match (ranges_iter.next(), ranges_iter.peek()) {
(Some(left), Some(right)) => {
if left.high + 1 != right.low {
complements.push(Range { complements.push(Range {
low: left.high + 1, low: prev_high + 1,
high: right.low - 1,
});
}
}
(Some(last), None) => {
if last.high < usize::MAX - 1 {
complements.push(Range {
low: last.high + 1,
high: usize::MAX - 1, high: usize::MAX - 1,
}); });
} }
}
_ => break,
}
}
complements complements
} }
@ -172,7 +160,7 @@ pub fn contain(ranges: &[Range], n: usize) -> bool {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::Range; use super::{complement, Range};
fn m(a: Vec<Range>, b: Vec<Range>) { fn m(a: Vec<Range>, b: Vec<Range>) {
assert_eq!(Range::merge(a), b); assert_eq!(Range::merge(a), b);
@ -212,26 +200,35 @@ mod test {
); );
// Last one joins the previous two // Last one joins the previous two
m( m(vec![r(10, 20), r(30, 40), r(20, 30)], vec![r(10, 40)]);
vec![
r(10,20),
r(30,40),
r(20,30),
],
vec![r(10,40)]
);
m( m(
vec![ vec![r(10, 20), r(30, 40), r(50, 60), r(20, 30)],
r(10,20), vec![r(10, 40), r(50, 60)],
r(30,40),
r(50,60),
r(20,30),
],
vec![r(10,40), r(50,60)]
); );
// Merge adjacent ranges // Merge adjacent ranges
m(vec![r(1, 3), r(4, 6)], vec![r(1, 6)]) m(vec![r(1, 3), r(4, 6)], vec![r(1, 6)])
} }
#[test]
fn complementing() {
// Simple
assert_eq!(complement(&[r(3, 4)]), vec![r(1, 2), r(5, usize::MAX - 1)]);
// With start
assert_eq!(
complement(&[r(1, 3), r(6, 10)]),
vec![r(4, 5), r(11, usize::MAX - 1)]
);
// With end
assert_eq!(
complement(&[r(2, 4), r(6, usize::MAX - 1)]),
vec![r(1, 1), r(5, 5)]
);
// With start and end
assert_eq!(complement(&[r(1, 4), r(6, usize::MAX - 1)]), vec![r(5, 5)]);
}
} }