@@ -826,6 +826,84 @@ impl<V: Ord + Clone> Ranges<V> {
826
826
}
827
827
}
828
828
829
+ impl < V : Ord > FromIterator < ( Bound < V > , Bound < V > ) > for Ranges < V > {
830
+ /// Constructor from arbitrary, unsorted and potentially overlapping ranges.
831
+ fn from_iter < T : IntoIterator < Item = ( Bound < V > , Bound < V > ) > > ( iter : T ) -> Self {
832
+ // We have three constraints we need to fulfil:
833
+ // 1. The segments are sorted, from lowest to highest (through `Ord`): By sorting.
834
+ // 2. Each segment contains at least one version (start < end): By `union`.
835
+ // 3. There is at least one version between two segments: By `union`.
836
+ let mut segments: SmallVec < [ Interval < V > ; 1 ] > = SmallVec :: new ( ) ;
837
+
838
+ for segment in iter {
839
+ if !valid_segment ( & segment. start_bound ( ) , & segment. end_bound ( ) ) {
840
+ continue ;
841
+ }
842
+ // Find where to insert the new segment
843
+ let insertion_point = segments. partition_point ( |elem : & Interval < V > | {
844
+ cmp_bounds_start ( elem. start_bound ( ) , segment. end_bound ( ) )
845
+ . unwrap ( )
846
+ . is_lt ( )
847
+ } ) ;
848
+ // Is it overlapping with the previous segment?
849
+ let previous_overlapping = insertion_point > 0
850
+ && !end_before_start_with_gap (
851
+ & segments[ insertion_point - 1 ] . end_bound ( ) ,
852
+ & segment. start_bound ( ) ,
853
+ ) ;
854
+
855
+ // Is it overlapping with the following segment?
856
+ let next_overlapping = insertion_point < segments. len ( )
857
+ && !end_before_start_with_gap (
858
+ & segment. end_bound ( ) ,
859
+ & segments[ insertion_point] . start_bound ( ) ,
860
+ ) ;
861
+
862
+ match ( previous_overlapping, next_overlapping) {
863
+ ( true , true ) => {
864
+ // previous: |-------|
865
+ // segment: |-------|
866
+ // following: |-----|
867
+ //
868
+ // final: |--------------------|
869
+ // We merge all three segments into one, which is effectively removing one of
870
+ // two previously inserted and changing the bounds on the other.
871
+ let following = segments. remove ( insertion_point) ;
872
+ segments[ insertion_point - 1 ] . 1 = following. 1 ;
873
+ }
874
+ ( true , false ) => {
875
+ // previous: |-----|
876
+ // segment: |-----|
877
+ // following: |-----|
878
+ //
879
+ // final: |---------| |-----|
880
+ // We can reuse the existing element by extending it.
881
+ segments[ insertion_point - 1 ] . 1 = segment. 1 ;
882
+ }
883
+ ( false , true ) => {
884
+ // previous: |-----|
885
+ // segment: |-----|
886
+ // following: |-----|
887
+ //
888
+ // final: |-----| |---------|
889
+ // We can reuse the existing element by extending it.
890
+ segments[ insertion_point] . 0 = segment. 0 ;
891
+ }
892
+ ( false , false ) => {
893
+ // previous: |-----|
894
+ // segment: |-----|
895
+ // following: |-----|
896
+ //
897
+ // final: |-----| |-----| |-----|
898
+ segments. insert ( insertion_point, segment) ;
899
+ }
900
+ }
901
+ }
902
+
903
+ Self { segments } . check_invariants ( )
904
+ }
905
+ }
906
+
829
907
// REPORT ######################################################################
830
908
831
909
impl < V : Display + Eq > Display for Ranges < V > {
@@ -1130,6 +1208,11 @@ pub mod tests {
1130
1208
}
1131
1209
assert!( simp. segments. len( ) <= range. segments. len( ) )
1132
1210
}
1211
+
1212
+ #[ test]
1213
+ fn from_iter_valid( segments in proptest:: collection:: vec( any:: <( Bound <u32 >, Bound <u32 >) >( ) , ..30 ) ) {
1214
+ Ranges :: from_iter( segments. clone( ) ) . check_invariants( ) ;
1215
+ }
1133
1216
}
1134
1217
1135
1218
#[ test]
0 commit comments