@@ -879,6 +879,87 @@ 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 > {
883
+ /// Constructor from arbitrary, unsorted and potentially overlapping ranges.
884
+ ///
885
+ /// This is equivalent, but faster, to computing the [`Ranges::union`] of the
886
+ /// [`Ranges::from_range_bounds`] of each segment.
887
+ fn from_iter < T : IntoIterator < Item = ( Bound < V > , Bound < V > ) > > ( iter : T ) -> Self {
888
+ // We have three constraints we need to fulfil:
889
+ // 1. The segments are sorted, from lowest to highest (through `Ord`): By sorting.
890
+ // 2. Each segment contains at least one version (start < end): By `union`.
891
+ // 3. There is at least one version between two segments: By `union`.
892
+ let mut segments: SmallVec < [ Interval < V > ; 1 ] > = SmallVec :: new ( ) ;
893
+
894
+ for segment in iter {
895
+ if !valid_segment ( & segment. start_bound ( ) , & segment. end_bound ( ) ) {
896
+ continue ;
897
+ }
898
+ // Find where to insert the new segment
899
+ let insertion_point = segments. partition_point ( |elem : & Interval < V > | {
900
+ cmp_bounds_start ( elem. start_bound ( ) , segment. start_bound ( ) )
901
+ . unwrap ( )
902
+ . is_lt ( )
903
+ } ) ;
904
+ // Is it overlapping with the previous segment?
905
+ let previous_overlapping = insertion_point > 0
906
+ && !end_before_start_with_gap (
907
+ & segments[ insertion_point - 1 ] . end_bound ( ) ,
908
+ & segment. start_bound ( ) ,
909
+ ) ;
910
+
911
+ // Is it overlapping with the following segment?
912
+ let next_overlapping = insertion_point < segments. len ( )
913
+ && !end_before_start_with_gap (
914
+ & segment. end_bound ( ) ,
915
+ & segments[ insertion_point] . start_bound ( ) ,
916
+ ) ;
917
+
918
+ match ( previous_overlapping, next_overlapping) {
919
+ ( true , true ) => {
920
+ // previous: |-------|
921
+ // segment: |-------|
922
+ // following: |-----|
923
+ //
924
+ // final: |--------------------|
925
+ // We merge all three segments into one, which is effectively removing one of
926
+ // 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 ;
929
+ }
930
+ ( true , false ) => {
931
+ // previous: |-----|
932
+ // segment: |-----|
933
+ // following: |-----|
934
+ //
935
+ // final: |---------| |-----|
936
+ // We can reuse the existing element by extending it.
937
+ segments[ insertion_point - 1 ] . 1 = segment. 1 ;
938
+ }
939
+ ( false , true ) => {
940
+ // previous: |-----|
941
+ // segment: |-----|
942
+ // following: |-----|
943
+ //
944
+ // final: |-----| |---------|
945
+ // We can reuse the existing element by extending it.
946
+ segments[ insertion_point] . 0 = segment. 0 ;
947
+ }
948
+ ( false , false ) => {
949
+ // previous: |-----|
950
+ // segment: |-----|
951
+ // following: |-----|
952
+ //
953
+ // final: |-----| |-----| |-----|
954
+ segments. insert ( insertion_point, segment) ;
955
+ }
956
+ }
957
+ }
958
+
959
+ Self { segments } . check_invariants ( )
960
+ }
961
+ }
962
+
882
963
// REPORT ######################################################################
883
964
884
965
impl < V : Display + Eq > Display for Ranges < V > {
@@ -1183,6 +1264,12 @@ pub mod tests {
1183
1264
}
1184
1265
assert!( simp. segments. len( ) <= range. segments. len( ) )
1185
1266
}
1267
+
1268
+ #[ test]
1269
+ 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( ) ) ;
1272
+ }
1186
1273
}
1187
1274
1188
1275
#[ test]
@@ -1219,6 +1306,15 @@ pub mod tests {
1219
1306
) ;
1220
1307
}
1221
1308
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
+
1222
1318
#[ test]
1223
1319
fn version_ord ( ) {
1224
1320
let versions: & [ Ranges < u32 > ] = & [
0 commit comments