@@ -879,7 +879,7 @@ impl<V> IntoIterator for Ranges<V> {
879879 }
880880}
881881
882- impl < V : Ord + Debug > FromIterator < ( Bound < V > , Bound < V > ) > for Ranges < V > {
882+ impl < V : Ord > FromIterator < ( Bound < V > , Bound < V > ) > for Ranges < V > {
883883 /// Constructor from arbitrary, unsorted and potentially overlapping ranges.
884884 ///
885885 /// This is equivalent, but faster, to computing the [`Ranges::union`] of the
@@ -889,6 +889,10 @@ impl<V: Ord + Debug> FromIterator<(Bound<V>, Bound<V>)> for Ranges<V> {
889889 // 1. The segments are sorted, from lowest to highest (through `Ord`): By sorting.
890890 // 2. Each segment contains at least one version (start < end): By `union`.
891891 // 3. There is at least one version between two segments: By `union`.
892+
893+ // For this implementation, we choose to only build a single smallvec and insert or remove
894+ // in it, instead of e.g. collecting the segments into one smallvec, sorting that and then
895+ // construction the second smallvec without shifting.
892896 let mut segments: SmallVec < [ Interval < V > ; 1 ] > = SmallVec :: new ( ) ;
893897
894898 for segment in iter {
@@ -908,7 +912,8 @@ impl<V: Ord + Debug> FromIterator<(Bound<V>, Bound<V>)> for Ranges<V> {
908912 & segment. start_bound ( ) ,
909913 ) ;
910914
911- // Is it overlapping with the following segment?
915+ // Is it overlapping with the following segment? We'll check if there's more than one
916+ // overlap later.
912917 let next_overlapping = insertion_point < segments. len ( )
913918 && !end_before_start_with_gap (
914919 & segment. end_bound ( ) ,
@@ -920,29 +925,112 @@ impl<V: Ord + Debug> FromIterator<(Bound<V>, Bound<V>)> for Ranges<V> {
920925 // previous: |------|
921926 // segment: |------|
922927 // following: |------|
928+ // final: |---------------|
929+ //
930+ // OR
923931 //
932+ // previous: |------|
933+ // segment: |-----------|
934+ // following: |----|
924935 // final: |---------------|
936+ //
937+ // OR
938+ //
939+ // previous: |------|
940+ // segment: |----------------|
941+ // following: |----| |------|
942+ // final: |------------------------|
925943 // We merge all three segments into one, which is effectively removing one of
926944 // two previously inserted and changing the bounds on the other.
927- let following = segments. remove ( insertion_point) ;
928- segments[ insertion_point - 1 ] . 1 = following. 1 ;
945+
946+ // Remove all elements covered by the final element
947+ let mut following = segments. remove ( insertion_point) ;
948+ while insertion_point < segments. len ( )
949+ && !end_before_start_with_gap (
950+ & segment. end_bound ( ) ,
951+ & segments[ insertion_point] . start_bound ( ) ,
952+ )
953+ {
954+ following = segments. remove ( insertion_point) ;
955+ }
956+
957+ // Set end to max(segment.end, <last overlapping segment>.end)
958+ if cmp_bounds_end ( segment. end_bound ( ) , following. end_bound ( ) )
959+ . unwrap ( )
960+ . is_lt ( )
961+ {
962+ segments[ insertion_point - 1 ] . 1 = following. 1 ;
963+ } else {
964+ segments[ insertion_point - 1 ] . 1 = segment. 1 ;
965+ }
929966 }
930967 ( true , false ) => {
931968 // previous: |------|
932969 // segment: |------|
933970 // following: |------|
934971 //
972+ // OR
973+ //
974+ // previous: |----------|
975+ // segment: |---|
976+ // following: |------|
977+ //
935978 // final: |----------| |------|
936979 // We can reuse the existing element by extending it.
937- segments[ insertion_point - 1 ] . 1 = segment. 1 ;
980+
981+ // Set end to max(segment.end, <previous>.end)
982+ if cmp_bounds_end (
983+ segments[ insertion_point - 1 ] . end_bound ( ) ,
984+ segment. end_bound ( ) ,
985+ )
986+ . unwrap ( )
987+ . is_lt ( )
988+ {
989+ segments[ insertion_point - 1 ] . 1 = segment. 1 ;
990+ }
938991 }
939992 ( false , true ) => {
940993 // previous: |------|
941994 // segment: |------|
942995 // following: |------|
996+ // final: |------| |----------|
997+ //
998+ // OR
999+ //
1000+ // previous: |------|
1001+ // segment: |----------|
1002+ // following: |---|
1003+ // final: |------| |----------|
1004+ //
1005+ // OR
1006+ //
1007+ // previous: |------|
1008+ // segment: |------------|
1009+ // following: |---| |------|
9431010 //
944- // final: |------| |---------|
1011+ // final: |------| |----------------- |
9451012 // We can reuse the existing element by extending it.
1013+
1014+ // Remove all fully covered segments so the next element is the last one that
1015+ // overlaps.
1016+ while insertion_point + 1 < segments. len ( )
1017+ && !end_before_start_with_gap (
1018+ & segment. end_bound ( ) ,
1019+ & segments[ insertion_point + 1 ] . start_bound ( ) ,
1020+ )
1021+ {
1022+ // We know that the one after also overlaps, so we can drop the current
1023+ // following.
1024+ segments. remove ( insertion_point) ;
1025+ }
1026+
1027+ // Set end to max(segment.end, <last overlapping segment>.end)
1028+ if cmp_bounds_end ( segments[ insertion_point] . end_bound ( ) , segment. end_bound ( ) )
1029+ . unwrap ( )
1030+ . is_lt ( )
1031+ {
1032+ segments[ insertion_point] . 1 = segment. 1 ;
1033+ }
9461034 segments[ insertion_point] . 0 = segment. 0 ;
9471035 }
9481036 ( false , false ) => {
@@ -1267,8 +1355,12 @@ pub mod tests {
12671355
12681356 #[ test]
12691357 fn from_iter_valid( segments in proptest:: collection:: vec( any:: <( Bound <u32 >, Bound <u32 >) >( ) , ..30 ) ) {
1270- // We check invariants in the method.
1271- Ranges :: from_iter( segments. clone( ) ) ;
1358+ let mut expected = Ranges :: empty( ) ;
1359+ for segment in & segments {
1360+ expected = expected. union ( & Ranges :: from_range_bounds( * segment) ) ;
1361+ }
1362+ let actual = Ranges :: from_iter( segments. clone( ) ) ;
1363+ assert_eq!( expected, actual, "{segments:?}" ) ;
12721364 }
12731365 }
12741366
@@ -1306,15 +1398,6 @@ pub mod tests {
13061398 ) ;
13071399 }
13081400
1309- #[ test]
1310- fn from_iter_regression ( ) {
1311- Ranges :: from_iter ( [
1312- ( Included ( 0 ) , Included ( 0 ) ) ,
1313- ( Excluded ( 1u32 ) , Unbounded ) ,
1314- ( Included ( 0 ) , Included ( 0 ) ) ,
1315- ] ) ;
1316- }
1317-
13181401 #[ test]
13191402 fn version_ord ( ) {
13201403 let versions: & [ Ranges < u32 > ] = & [
0 commit comments