@@ -879,6 +879,87 @@ impl<V> IntoIterator for Ranges<V> {
879879 }
880880}
881881
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+
882963// REPORT ######################################################################
883964
884965impl < V : Display + Eq > Display for Ranges < V > {
@@ -1183,6 +1264,12 @@ pub mod tests {
11831264 }
11841265 assert!( simp. segments. len( ) <= range. segments. len( ) )
11851266 }
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+ }
11861273 }
11871274
11881275 #[ test]
@@ -1219,6 +1306,15 @@ pub mod tests {
12191306 ) ;
12201307 }
12211308
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+
12221318 #[ test]
12231319 fn version_ord ( ) {
12241320 let versions: & [ Ranges < u32 > ] = & [
0 commit comments