@@ -826,7 +826,7 @@ impl<V: Ord + Clone> Ranges<V> {
826826 }
827827}
828828
829- impl < V : Ord + Debug > FromIterator < ( Bound < V > , Bound < V > ) > for Ranges < V > {
829+ impl < V : Ord > FromIterator < ( Bound < V > , Bound < V > ) > for Ranges < V > {
830830 /// Constructor from arbitrary, unsorted and potentially overlapping ranges.
831831 ///
832832 /// This is equivalent, but faster, to computing the [`Ranges::union`] of the
@@ -836,6 +836,10 @@ impl<V: Ord + Debug> FromIterator<(Bound<V>, Bound<V>)> for Ranges<V> {
836836 // 1. The segments are sorted, from lowest to highest (through `Ord`): By sorting.
837837 // 2. Each segment contains at least one version (start < end): By `union`.
838838 // 3. There is at least one version between two segments: By `union`.
839+
840+ // For this implementation, we choose to only build a single smallvec and insert or remove
841+ // in it, instead of e.g. collecting the segments into one smallvec, sorting that and then
842+ // construction the second smallvec without shifting.
839843 let mut segments: SmallVec < [ Interval < V > ; 1 ] > = SmallVec :: new ( ) ;
840844
841845 for segment in iter {
@@ -855,7 +859,8 @@ impl<V: Ord + Debug> FromIterator<(Bound<V>, Bound<V>)> for Ranges<V> {
855859 & segment. start_bound ( ) ,
856860 ) ;
857861
858- // Is it overlapping with the following segment?
862+ // Is it overlapping with the following segment? We'll check if there's more than one
863+ // overlap later.
859864 let next_overlapping = insertion_point < segments. len ( )
860865 && !end_before_start_with_gap (
861866 & segment. end_bound ( ) ,
@@ -867,29 +872,112 @@ impl<V: Ord + Debug> FromIterator<(Bound<V>, Bound<V>)> for Ranges<V> {
867872 // previous: |------|
868873 // segment: |------|
869874 // following: |------|
875+ // final: |---------------|
876+ //
877+ // OR
870878 //
879+ // previous: |------|
880+ // segment: |-----------|
881+ // following: |----|
871882 // final: |---------------|
883+ //
884+ // OR
885+ //
886+ // previous: |------|
887+ // segment: |----------------|
888+ // following: |----| |------|
889+ // final: |------------------------|
872890 // We merge all three segments into one, which is effectively removing one of
873891 // two previously inserted and changing the bounds on the other.
874- let following = segments. remove ( insertion_point) ;
875- segments[ insertion_point - 1 ] . 1 = following. 1 ;
892+
893+ // Remove all elements covered by the final element
894+ let mut following = segments. remove ( insertion_point) ;
895+ while insertion_point < segments. len ( )
896+ && !end_before_start_with_gap (
897+ & segment. end_bound ( ) ,
898+ & segments[ insertion_point] . start_bound ( ) ,
899+ )
900+ {
901+ following = segments. remove ( insertion_point) ;
902+ }
903+
904+ // Set end to max(segment.end, <last overlapping segment>.end)
905+ if cmp_bounds_end ( segment. end_bound ( ) , following. end_bound ( ) )
906+ . unwrap ( )
907+ . is_lt ( )
908+ {
909+ segments[ insertion_point - 1 ] . 1 = following. 1 ;
910+ } else {
911+ segments[ insertion_point - 1 ] . 1 = segment. 1 ;
912+ }
876913 }
877914 ( true , false ) => {
878915 // previous: |------|
879916 // segment: |------|
880917 // following: |------|
881918 //
919+ // OR
920+ //
921+ // previous: |----------|
922+ // segment: |---|
923+ // following: |------|
924+ //
882925 // final: |----------| |------|
883926 // We can reuse the existing element by extending it.
884- segments[ insertion_point - 1 ] . 1 = segment. 1 ;
927+
928+ // Set end to max(segment.end, <previous>.end)
929+ if cmp_bounds_end (
930+ segments[ insertion_point - 1 ] . end_bound ( ) ,
931+ segment. end_bound ( ) ,
932+ )
933+ . unwrap ( )
934+ . is_lt ( )
935+ {
936+ segments[ insertion_point - 1 ] . 1 = segment. 1 ;
937+ }
885938 }
886939 ( false , true ) => {
887940 // previous: |------|
888941 // segment: |------|
889942 // following: |------|
943+ // final: |------| |----------|
944+ //
945+ // OR
946+ //
947+ // previous: |------|
948+ // segment: |----------|
949+ // following: |---|
950+ // final: |------| |----------|
951+ //
952+ // OR
953+ //
954+ // previous: |------|
955+ // segment: |------------|
956+ // following: |---| |------|
890957 //
891- // final: |------| |---------|
958+ // final: |------| |----------------- |
892959 // We can reuse the existing element by extending it.
960+
961+ // Remove all fully covered segments so the next element is the last one that
962+ // overlaps.
963+ while insertion_point + 1 < segments. len ( )
964+ && !end_before_start_with_gap (
965+ & segment. end_bound ( ) ,
966+ & segments[ insertion_point + 1 ] . start_bound ( ) ,
967+ )
968+ {
969+ // We know that the one after also overlaps, so we can drop the current
970+ // following.
971+ segments. remove ( insertion_point) ;
972+ }
973+
974+ // Set end to max(segment.end, <last overlapping segment>.end)
975+ if cmp_bounds_end ( segments[ insertion_point] . end_bound ( ) , segment. end_bound ( ) )
976+ . unwrap ( )
977+ . is_lt ( )
978+ {
979+ segments[ insertion_point] . 1 = segment. 1 ;
980+ }
893981 segments[ insertion_point] . 0 = segment. 0 ;
894982 }
895983 ( false , false ) => {
@@ -1214,8 +1302,12 @@ pub mod tests {
12141302
12151303 #[ test]
12161304 fn from_iter_valid( segments in proptest:: collection:: vec( any:: <( Bound <u32 >, Bound <u32 >) >( ) , ..30 ) ) {
1217- // We check invariants in the method.
1218- Ranges :: from_iter( segments. clone( ) ) ;
1305+ let mut expected = Ranges :: empty( ) ;
1306+ for segment in & segments {
1307+ expected = expected. union ( & Ranges :: from_range_bounds( * segment) ) ;
1308+ }
1309+ let actual = Ranges :: from_iter( segments. clone( ) ) ;
1310+ assert_eq!( expected, actual, "{segments:?}" ) ;
12191311 }
12201312 }
12211313
@@ -1253,15 +1345,6 @@ pub mod tests {
12531345 ) ;
12541346 }
12551347
1256- #[ test]
1257- fn from_iter_regression ( ) {
1258- Ranges :: from_iter ( [
1259- ( Included ( 0 ) , Included ( 0 ) ) ,
1260- ( Excluded ( 1u32 ) , Unbounded ) ,
1261- ( Included ( 0 ) , Included ( 0 ) ) ,
1262- ] ) ;
1263- }
1264-
12651348 #[ test]
12661349 fn version_ord ( ) {
12671350 let versions: & [ Ranges < u32 > ] = & [
0 commit comments