@@ -879,7 +879,7 @@ impl<V> IntoIterator for Ranges<V> {
879
879
}
880
880
}
881
881
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 > {
883
883
/// Constructor from arbitrary, unsorted and potentially overlapping ranges.
884
884
///
885
885
/// 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> {
889
889
// 1. The segments are sorted, from lowest to highest (through `Ord`): By sorting.
890
890
// 2. Each segment contains at least one version (start < end): By `union`.
891
891
// 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.
892
896
let mut segments: SmallVec < [ Interval < V > ; 1 ] > = SmallVec :: new ( ) ;
893
897
894
898
for segment in iter {
@@ -908,7 +912,8 @@ impl<V: Ord + Debug> FromIterator<(Bound<V>, Bound<V>)> for Ranges<V> {
908
912
& segment. start_bound ( ) ,
909
913
) ;
910
914
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.
912
917
let next_overlapping = insertion_point < segments. len ( )
913
918
&& !end_before_start_with_gap (
914
919
& segment. end_bound ( ) ,
@@ -920,29 +925,112 @@ impl<V: Ord + Debug> FromIterator<(Bound<V>, Bound<V>)> for Ranges<V> {
920
925
// previous: |------|
921
926
// segment: |------|
922
927
// following: |------|
928
+ // final: |---------------|
929
+ //
930
+ // OR
923
931
//
932
+ // previous: |------|
933
+ // segment: |-----------|
934
+ // following: |----|
924
935
// final: |---------------|
936
+ //
937
+ // OR
938
+ //
939
+ // previous: |------|
940
+ // segment: |----------------|
941
+ // following: |----| |------|
942
+ // final: |------------------------|
925
943
// We merge all three segments into one, which is effectively removing one of
926
944
// 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
+ }
929
966
}
930
967
( true , false ) => {
931
968
// previous: |------|
932
969
// segment: |------|
933
970
// following: |------|
934
971
//
972
+ // OR
973
+ //
974
+ // previous: |----------|
975
+ // segment: |---|
976
+ // following: |------|
977
+ //
935
978
// final: |----------| |------|
936
979
// 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
+ }
938
991
}
939
992
( false , true ) => {
940
993
// previous: |------|
941
994
// segment: |------|
942
995
// 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: |---| |------|
943
1010
//
944
- // final: |------| |---------|
1011
+ // final: |------| |----------------- |
945
1012
// 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
+ }
946
1034
segments[ insertion_point] . 0 = segment. 0 ;
947
1035
}
948
1036
( false , false ) => {
@@ -1267,8 +1355,12 @@ pub mod tests {
1267
1355
1268
1356
#[ test]
1269
1357
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:?}" ) ;
1272
1364
}
1273
1365
}
1274
1366
@@ -1306,15 +1398,6 @@ pub mod tests {
1306
1398
) ;
1307
1399
}
1308
1400
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
-
1318
1401
#[ test]
1319
1402
fn version_ord ( ) {
1320
1403
let versions: & [ Ranges < u32 > ] = & [
0 commit comments