@@ -771,13 +771,11 @@ pub trait RangeBounds<T: ?Sized> {
771
771
/// # Examples
772
772
///
773
773
/// ```
774
- /// # fn main() {
775
774
/// use std::ops::Bound::*;
776
775
/// use std::ops::RangeBounds;
777
776
///
778
777
/// assert_eq!((..10).start_bound(), Unbounded);
779
778
/// assert_eq!((3..10).start_bound(), Included(&3));
780
- /// # }
781
779
/// ```
782
780
#[ stable( feature = "collections_range" , since = "1.28.0" ) ]
783
781
fn start_bound ( & self ) -> Bound < & T > ;
@@ -789,13 +787,11 @@ pub trait RangeBounds<T: ?Sized> {
789
787
/// # Examples
790
788
///
791
789
/// ```
792
- /// # fn main() {
793
790
/// use std::ops::Bound::*;
794
791
/// use std::ops::RangeBounds;
795
792
///
796
793
/// assert_eq!((3..).end_bound(), Unbounded);
797
794
/// assert_eq!((3..10).end_bound(), Excluded(&10));
798
- /// # }
799
795
/// ```
800
796
#[ stable( feature = "collections_range" , since = "1.28.0" ) ]
801
797
fn end_bound ( & self ) -> Bound < & T > ;
@@ -829,6 +825,71 @@ pub trait RangeBounds<T: ?Sized> {
829
825
Unbounded => true ,
830
826
} )
831
827
}
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
+ }
832
893
}
833
894
834
895
/// Used to convert a range into start and end bounds, consuming the
@@ -845,14 +906,83 @@ pub trait IntoBounds<T>: RangeBounds<T> {
845
906
///
846
907
/// ```
847
908
/// #![feature(range_into_bounds)]
848
- ///
849
909
/// use std::ops::Bound::*;
850
910
/// use std::ops::IntoBounds;
851
911
///
852
912
/// assert_eq!((0..5).into_bounds(), (Included(0), Excluded(5)));
853
913
/// assert_eq!((..=7).into_bounds(), (Unbounded, Included(7)));
854
914
/// ```
855
915
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
+ }
856
986
}
857
987
858
988
use self :: Bound :: { Excluded , Included , Unbounded } ;
0 commit comments