@@ -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+
367375impl < 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