@@ -826,6 +826,87 @@ 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 > {
830
+ /// Constructor from arbitrary, unsorted and potentially overlapping ranges.
831
+ ///
832
+ /// This is equivalent to computing the [`Ranges::union`] of the [`Range::from_range_bounds`] of
833
+ /// each segment.
834
+ fn from_iter < T : IntoIterator < Item = ( Bound < V > , Bound < V > ) > > ( iter : T ) -> Self {
835
+ // We have three constraints we need to fulfil:
836
+ // 1. The segments are sorted, from lowest to highest (through `Ord`): By sorting.
837
+ // 2. Each segment contains at least one version (start < end): By `union`.
838
+ // 3. There is at least one version between two segments: By `union`.
839
+ let mut segments: SmallVec < [ Interval < V > ; 1 ] > = SmallVec :: new ( ) ;
840
+
841
+ for segment in iter {
842
+ if !valid_segment ( & segment. start_bound ( ) , & segment. end_bound ( ) ) {
843
+ continue ;
844
+ }
845
+ // Find where to insert the new segment
846
+ let insertion_point = segments. partition_point ( |elem : & Interval < V > | {
847
+ cmp_bounds_start ( elem. start_bound ( ) , segment. start_bound ( ) )
848
+ . unwrap ( )
849
+ . is_lt ( )
850
+ } ) ;
851
+ // Is it overlapping with the previous segment?
852
+ let previous_overlapping = insertion_point > 0
853
+ && !end_before_start_with_gap (
854
+ & segments[ insertion_point - 1 ] . end_bound ( ) ,
855
+ & segment. start_bound ( ) ,
856
+ ) ;
857
+
858
+ // Is it overlapping with the following segment?
859
+ let next_overlapping = insertion_point < segments. len ( )
860
+ && !end_before_start_with_gap (
861
+ & segment. end_bound ( ) ,
862
+ & segments[ insertion_point] . start_bound ( ) ,
863
+ ) ;
864
+
865
+ match ( previous_overlapping, next_overlapping) {
866
+ ( true , true ) => {
867
+ // previous: |-------|
868
+ // segment: |-------|
869
+ // following: |-----|
870
+ //
871
+ // final: |--------------------|
872
+ // We merge all three segments into one, which is effectively removing one of
873
+ // 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 ;
876
+ }
877
+ ( true , false ) => {
878
+ // previous: |-----|
879
+ // segment: |-----|
880
+ // following: |-----|
881
+ //
882
+ // final: |---------| |-----|
883
+ // We can reuse the existing element by extending it.
884
+ segments[ insertion_point - 1 ] . 1 = segment. 1 ;
885
+ }
886
+ ( false , true ) => {
887
+ // previous: |-----|
888
+ // segment: |-----|
889
+ // following: |-----|
890
+ //
891
+ // final: |-----| |---------|
892
+ // We can reuse the existing element by extending it.
893
+ segments[ insertion_point] . 0 = segment. 0 ;
894
+ }
895
+ ( false , false ) => {
896
+ // previous: |-----|
897
+ // segment: |-----|
898
+ // following: |-----|
899
+ //
900
+ // final: |-----| |-----| |-----|
901
+ segments. insert ( insertion_point, segment) ;
902
+ }
903
+ }
904
+ }
905
+
906
+ Self { segments } . check_invariants ( )
907
+ }
908
+ }
909
+
829
910
// REPORT ######################################################################
830
911
831
912
impl < V : Display + Eq > Display for Ranges < V > {
@@ -1130,6 +1211,12 @@ pub mod tests {
1130
1211
}
1131
1212
assert!( simp. segments. len( ) <= range. segments. len( ) )
1132
1213
}
1214
+
1215
+ #[ test]
1216
+ 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( ) ) ;
1219
+ }
1133
1220
}
1134
1221
1135
1222
#[ test]
@@ -1166,6 +1253,15 @@ pub mod tests {
1166
1253
) ;
1167
1254
}
1168
1255
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
+
1169
1265
#[ test]
1170
1266
fn version_ord ( ) {
1171
1267
let versions: & [ Ranges < u32 > ] = & [
0 commit comments