use collections::Set;
use lexer::nfa::Test;
use std::cmp;
pub fn remove_overlap(ranges: &Set<Test>) -> Vec<Test> {
let mut disjoint_ranges = vec![];
for &range in ranges {
add_range(range, 0, &mut disjoint_ranges);
}
disjoint_ranges.retain(|r| !r.is_empty());
disjoint_ranges
}
fn add_range(range: Test,
start_index: usize,
disjoint_ranges: &mut Vec<Test>)
{
if range.is_empty() {
return;
}
match disjoint_ranges[start_index..].iter().position(|r| r.intersects(range)) {
Some(index) => {
let index = index + start_index;
let overlapping_range = disjoint_ranges[index];
if overlapping_range == range {
return;
}
let min_min = cmp::min(range.start, overlapping_range.start);
let mid_min = cmp::max(range.start, overlapping_range.start);
let mid_max = cmp::min(range.end, overlapping_range.end);
let max_max = cmp::max(range.end, overlapping_range.end);
let low_range = Test { start: min_min, end: mid_min };
let mid_range = Test { start: mid_min, end: mid_max };
let max_range = Test { start: mid_max, end: max_max };
assert!(low_range.is_disjoint(mid_range));
assert!(low_range.is_disjoint(max_range));
assert!(mid_range.is_disjoint(max_range));
disjoint_ranges[index] = low_range;
add_range(mid_range, index + 1, disjoint_ranges);
add_range(max_range, index + 1, disjoint_ranges);
}
None => {
disjoint_ranges.push(range);
}
}
}
macro_rules! test {
($($range:expr,)*) => {
{
use collections::set;
use lexer::nfa::Test;
use std::char;
let mut s = set();
$({ let r = $range; s.insert(Test::exclusive_range(r.start, r.end)); })*
remove_overlap(&s).into_iter()
.map(|r|
char::from_u32(r.start).unwrap() ..
char::from_u32(r.end).unwrap())
.collect::<Vec<_>>()
}
}
}
#[test]
fn alphabet() {
let result = test! {
'a' .. 'z',
'c' .. 'l',
'0' .. '9',
};
assert_eq!(result, vec!['0'..'9', 'a'..'c', 'c'..'l', 'l'..'z']);
}
#[test]
fn repeat() {
let result = test! {
'a' .. 'z',
'c' .. 'l',
'l' .. 'z',
'0' .. '9',
};
assert_eq!(result, vec!['0'..'9', 'a'..'c', 'c'..'l', 'l'..'z']);
}
#[test]
fn stagger() {
let result = test! {
'0' .. '3',
'2' .. '4',
'3' .. '5',
};
assert_eq!(result, vec!['0'..'2', '2'..'3', '3'..'4', '4'..'5']);
}