@@ -771,13 +771,11 @@ pub trait RangeBounds<T: ?Sized> {
771771 /// # Examples
772772 ///
773773 /// ```
774- /// # fn main() {
775774 /// use std::ops::Bound::*;
776775 /// use std::ops::RangeBounds;
777776 ///
778777 /// assert_eq!((..10).start_bound(), Unbounded);
779778 /// assert_eq!((3..10).start_bound(), Included(&3));
780- /// # }
781779 /// ```
782780 #[ stable( feature = "collections_range" , since = "1.28.0" ) ]
783781 fn start_bound ( & self ) -> Bound < & T > ;
@@ -789,13 +787,11 @@ pub trait RangeBounds<T: ?Sized> {
789787 /// # Examples
790788 ///
791789 /// ```
792- /// # fn main() {
793790 /// use std::ops::Bound::*;
794791 /// use std::ops::RangeBounds;
795792 ///
796793 /// assert_eq!((3..).end_bound(), Unbounded);
797794 /// assert_eq!((3..10).end_bound(), Excluded(&10));
798- /// # }
799795 /// ```
800796 #[ stable( feature = "collections_range" , since = "1.28.0" ) ]
801797 fn end_bound ( & self ) -> Bound < & T > ;
@@ -829,6 +825,71 @@ pub trait RangeBounds<T: ?Sized> {
829825 Unbounded => true ,
830826 } )
831827 }
828+
829+ /// Returns `true` if the range contains no items.
830+ /// One-sided ranges (`RangeFrom`, etc) always return `true`.
831+ ///
832+ /// # Examples
833+ ///
834+ /// ```
835+ /// #![feature(range_bounds_is_empty)]
836+ /// use std::ops::RangeBounds;
837+ ///
838+ /// assert!(!(3..).is_empty());
839+ /// assert!(!(..2).is_empty());
840+ /// assert!(!RangeBounds::is_empty(&(3..5)));
841+ /// assert!( RangeBounds::is_empty(&(3..3)));
842+ /// assert!( RangeBounds::is_empty(&(3..2)));
843+ /// ```
844+ ///
845+ /// The range is empty if either side is incomparable:
846+ ///
847+ /// ```
848+ /// #![feature(range_bounds_is_empty)]
849+ /// use std::ops::RangeBounds;
850+ ///
851+ /// assert!(!RangeBounds::is_empty(&(3.0..5.0)));
852+ /// assert!( RangeBounds::is_empty(&(3.0..f32::NAN)));
853+ /// assert!( RangeBounds::is_empty(&(f32::NAN..5.0)));
854+ /// ```
855+ ///
856+ /// But never empty is either side is unbounded:
857+ ///
858+ /// ```
859+ /// #![feature(range_bounds_is_empty)]
860+ /// use std::ops::RangeBounds;
861+ ///
862+ /// assert!(!(..0).is_empty());
863+ /// assert!(!(i32::MAX..).is_empty());
864+ /// assert!(!RangeBounds::<u8>::is_empty(&(..)));
865+ /// ```
866+ ///
867+ /// `(Excluded(a), Excluded(b))` is only empty if `a >= b`:
868+ ///
869+ /// ```
870+ /// #![feature(range_bounds_is_empty)]
871+ /// use std::ops::Bound::*;
872+ /// use std::ops::RangeBounds;
873+ ///
874+ /// assert!(!(Excluded(1), Excluded(3)).is_empty());
875+ /// assert!(!(Excluded(1), Excluded(2)).is_empty());
876+ /// assert!( (Excluded(1), Excluded(1)).is_empty());
877+ /// assert!( (Excluded(2), Excluded(1)).is_empty());
878+ /// assert!( (Excluded(3), Excluded(1)).is_empty());
879+ /// ```
880+ #[ unstable( feature = "range_bounds_is_empty" , issue = "137300" ) ]
881+ fn is_empty ( & self ) -> bool
882+ where
883+ T : PartialOrd ,
884+ {
885+ !match ( self . start_bound ( ) , self . end_bound ( ) ) {
886+ ( Unbounded , _) | ( _, Unbounded ) => true ,
887+ ( Included ( start) , Excluded ( end) )
888+ | ( Excluded ( start) , Included ( end) )
889+ | ( Excluded ( start) , Excluded ( end) ) => start < end,
890+ ( Included ( start) , Included ( end) ) => start <= end,
891+ }
892+ }
832893}
833894
834895/// Used to convert a range into start and end bounds, consuming the
@@ -845,14 +906,83 @@ pub trait IntoBounds<T>: RangeBounds<T> {
845906 ///
846907 /// ```
847908 /// #![feature(range_into_bounds)]
848- ///
849909 /// use std::ops::Bound::*;
850910 /// use std::ops::IntoBounds;
851911 ///
852912 /// assert_eq!((0..5).into_bounds(), (Included(0), Excluded(5)));
853913 /// assert_eq!((..=7).into_bounds(), (Unbounded, Included(7)));
854914 /// ```
855915 fn into_bounds ( self ) -> ( Bound < T > , Bound < T > ) ;
916+
917+ /// Compute the intersection of `self` and `other`.
918+ ///
919+ /// # Examples
920+ ///
921+ /// ```
922+ /// #![feature(range_into_bounds)]
923+ /// use std::ops::Bound::*;
924+ /// use std::ops::IntoBounds;
925+ ///
926+ /// assert_eq!((3..).intersect(..5), (Included(3), Excluded(5)));
927+ /// assert_eq!((-12..387).intersect(0..256), (Included(0), Excluded(256)));
928+ /// assert_eq!((1..5).intersect(..), (Included(1), Excluded(5)));
929+ /// assert_eq!((1..=9).intersect(0..10), (Included(1), Included(9)));
930+ /// assert_eq!((7..=13).intersect(8..13), (Included(8), Excluded(13)));
931+ /// ```
932+ ///
933+ /// Combine with `is_empty` to determine if two ranges overlap.
934+ ///
935+ /// ```
936+ /// #![feature(range_into_bounds)]
937+ /// #![feature(range_bounds_is_empty)]
938+ /// use std::ops::{RangeBounds, IntoBounds};
939+ ///
940+ /// assert!(!(3..).intersect(..5).is_empty());
941+ /// assert!(!(-12..387).intersect(0..256).is_empty());
942+ /// assert!((1..5).intersect(6..).is_empty());
943+ /// ```
944+ fn intersect < R > ( self , other : R ) -> ( Bound < T > , Bound < T > )
945+ where
946+ Self : Sized ,
947+ T : Ord ,
948+ R : Sized + IntoBounds < T > ,
949+ {
950+ let ( self_start, self_end) = IntoBounds :: into_bounds ( self ) ;
951+ let ( other_start, other_end) = IntoBounds :: into_bounds ( other) ;
952+
953+ let start = match ( self_start, other_start) {
954+ ( Included ( a) , Included ( b) ) => Included ( Ord :: max ( a, b) ) ,
955+ ( Excluded ( a) , Excluded ( b) ) => Excluded ( Ord :: max ( a, b) ) ,
956+ ( Unbounded , Unbounded ) => Unbounded ,
957+
958+ ( x, Unbounded ) | ( Unbounded , x) => x,
959+
960+ ( Included ( i) , Excluded ( e) ) | ( Excluded ( e) , Included ( i) ) => {
961+ if i > e {
962+ Included ( i)
963+ } else {
964+ Excluded ( e)
965+ }
966+ }
967+ } ;
968+ let end = match ( self_end, other_end) {
969+ ( Included ( a) , Included ( b) ) => Included ( Ord :: min ( a, b) ) ,
970+ ( Excluded ( a) , Excluded ( b) ) => Excluded ( Ord :: min ( a, b) ) ,
971+ ( Unbounded , Unbounded ) => Unbounded ,
972+
973+ ( x, Unbounded ) | ( Unbounded , x) => x,
974+
975+ ( Included ( i) , Excluded ( e) ) | ( Excluded ( e) , Included ( i) ) => {
976+ if i < e {
977+ Included ( i)
978+ } else {
979+ Excluded ( e)
980+ }
981+ }
982+ } ;
983+
984+ ( start, end)
985+ }
856986}
857987
858988use self :: Bound :: { Excluded , Included , Unbounded } ;
0 commit comments