@@ -826,7 +826,7 @@ impl<V: Ord + Clone> Ranges<V> {
826
826
}
827
827
}
828
828
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 > {
830
830
/// Constructor from arbitrary, unsorted and potentially overlapping ranges.
831
831
///
832
832
/// 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> {
836
836
// 1. The segments are sorted, from lowest to highest (through `Ord`): By sorting.
837
837
// 2. Each segment contains at least one version (start < end): By `union`.
838
838
// 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.
839
843
let mut segments: SmallVec < [ Interval < V > ; 1 ] > = SmallVec :: new ( ) ;
840
844
841
845
for segment in iter {
@@ -855,7 +859,8 @@ impl<V: Ord + Debug> FromIterator<(Bound<V>, Bound<V>)> for Ranges<V> {
855
859
& segment. start_bound ( ) ,
856
860
) ;
857
861
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.
859
864
let next_overlapping = insertion_point < segments. len ( )
860
865
&& !end_before_start_with_gap (
861
866
& segment. end_bound ( ) ,
@@ -867,29 +872,112 @@ impl<V: Ord + Debug> FromIterator<(Bound<V>, Bound<V>)> for Ranges<V> {
867
872
// previous: |------|
868
873
// segment: |------|
869
874
// following: |------|
875
+ // final: |---------------|
876
+ //
877
+ // OR
870
878
//
879
+ // previous: |------|
880
+ // segment: |-----------|
881
+ // following: |----|
871
882
// final: |---------------|
883
+ //
884
+ // OR
885
+ //
886
+ // previous: |------|
887
+ // segment: |----------------|
888
+ // following: |----| |------|
889
+ // final: |------------------------|
872
890
// We merge all three segments into one, which is effectively removing one of
873
891
// 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
+ }
876
913
}
877
914
( true , false ) => {
878
915
// previous: |------|
879
916
// segment: |------|
880
917
// following: |------|
881
918
//
919
+ // OR
920
+ //
921
+ // previous: |----------|
922
+ // segment: |---|
923
+ // following: |------|
924
+ //
882
925
// final: |----------| |------|
883
926
// 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
+ }
885
938
}
886
939
( false , true ) => {
887
940
// previous: |------|
888
941
// segment: |------|
889
942
// 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: |---| |------|
890
957
//
891
- // final: |------| |---------|
958
+ // final: |------| |----------------- |
892
959
// 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
+ }
893
981
segments[ insertion_point] . 0 = segment. 0 ;
894
982
}
895
983
( false , false ) => {
@@ -1214,8 +1302,12 @@ pub mod tests {
1214
1302
1215
1303
#[ test]
1216
1304
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:?}" ) ;
1219
1311
}
1220
1312
}
1221
1313
@@ -1253,15 +1345,6 @@ pub mod tests {
1253
1345
) ;
1254
1346
}
1255
1347
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
-
1265
1348
#[ test]
1266
1349
fn version_ord ( ) {
1267
1350
let versions: & [ Ranges < u32 > ] = & [
0 commit comments