Skip to content

Commit b0751ae

Browse files
committed
Add Range.union
1 parent dc65edf commit b0751ae

File tree

1 file changed

+75
-0
lines changed

1 file changed

+75
-0
lines changed

src/types/range.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,14 @@ impl<T: Ord+Normalizable> Range<T> {
364364
}
365365
}
366366

367+
fn order<T:Ord>(a: T, b: T) -> (T, T) {
368+
if a < b {
369+
(a, b)
370+
} else {
371+
(b, a)
372+
}
373+
}
374+
367375
impl<T: Ord+Normalizable+Clone> Range<T> {
368376
/// Returns the intersection of this range with another
369377
pub fn intersect(&self, other: &Range<T>) -> Range<T> {
@@ -378,6 +386,37 @@ impl<T: Ord+Normalizable+Clone> Range<T> {
378386

379387
Range::new(lower.map(|v| v.clone()), upper.map(|v| v.clone()))
380388
}
389+
390+
/// Returns the union of this range with another if it is contiguous
391+
pub fn union(&self, other: &Range<T>) -> Option<Range<T>> {
392+
if self.is_empty() {
393+
return Some(other.clone());
394+
}
395+
396+
if other.is_empty() {
397+
return Some(self.clone());
398+
}
399+
400+
let (OptBound(l_lower), OptBound(u_lower)) =
401+
order(OptBound(self.lower()), OptBound(other.lower()));
402+
let (OptBound(l_upper), OptBound(u_upper)) =
403+
order(OptBound(self.upper()), OptBound(other.upper()));
404+
405+
let discontiguous = match (u_lower, l_upper) {
406+
(Some(&RangeBound { value: ref l, type_: Exclusive }),
407+
Some(&RangeBound { value: ref u, type_: Exclusive })) => l >= u,
408+
(Some(&RangeBound { value: ref l, .. }),
409+
Some(&RangeBound { value: ref u, .. })) => l > u,
410+
_ => false
411+
};
412+
413+
if discontiguous {
414+
None
415+
} else {
416+
Some(Range::new(l_lower.map(|v| v.clone()),
417+
u_upper.map(|v| v.clone())))
418+
}
419+
}
381420
}
382421

383422
#[cfg(test)]
@@ -544,6 +583,42 @@ mod test {
544583
assert_eq!(r2, r2.intersect(&r1));
545584
}
546585

586+
#[test]
587+
fn test_union() {
588+
let r1 = range!('[' 10i32, 15i32 ')');
589+
let r2 = range!('(' 20i32, 25i32 ']');
590+
assert_eq!(None, r1.union(&r2));
591+
assert_eq!(None, r2.union(&r1));
592+
593+
let r2 = range!('(', ')');
594+
assert_eq!(Some(r2), r1.union(&r2));
595+
assert_eq!(Some(r2), r2.union(&r1));
596+
597+
let r2 = range!('[' 13i32, 50i32 ')');
598+
assert_eq!(Some(range!('[' 10i32, 50i32 ')')), r1.union(&r2));
599+
assert_eq!(Some(range!('[' 10i32, 50i32 ')')), r2.union(&r1));
600+
601+
let r2 = range!('[' 3i32, 50i32 ')');
602+
assert_eq!(Some(range!('[' 3i32, 50i32 ')')), r1.union(&r2));
603+
assert_eq!(Some(range!('[' 3i32, 50i32 ')')), r2.union(&r1));
604+
605+
let r2 = range!('(', 11i32 ')');
606+
assert_eq!(Some(range!('(', 15i32 ')')), r1.union(&r2));
607+
assert_eq!(Some(range!('(', 15i32 ')')), r2.union(&r1));
608+
609+
let r2 = range!('(' 11i32, ')');
610+
assert_eq!(Some(range!('[' 10i32, ')')), r1.union(&r2));
611+
assert_eq!(Some(range!('[' 10i32, ')')), r2.union(&r1));
612+
613+
let r2 = range!('(' 15i32, 20i32 ')');
614+
assert_eq!(None, r1.union(&r2));
615+
assert_eq!(None, r2.union(&r1));
616+
617+
let r2 = range!('[' 15i32, 20i32 ']');
618+
assert_eq!(Some(range!('[' 10i32, 20i32 ']')), r1.union(&r2));
619+
assert_eq!(Some(range!('[' 10i32, 20i32 ']')), r2.union(&r1));
620+
}
621+
547622
#[test]
548623
fn test_contains_range() {
549624
assert!(Range::<i32>::empty().contains_range(&Range::empty()));

0 commit comments

Comments
 (0)