@@ -203,22 +203,55 @@ impl<V: Ord> Range<V> {
203
203
pub fn contains ( & self , v : & V ) -> bool {
204
204
for segment in self . segments . iter ( ) {
205
205
if match segment {
206
- ( Unbounded , Unbounded ) => true ,
207
- ( Unbounded , Included ( end) ) => v <= end,
208
- ( Unbounded , Excluded ( end) ) => v < end,
209
- ( Included ( start) , Unbounded ) => v >= start,
210
- ( Included ( start) , Included ( end) ) => v >= start && v <= end,
211
- ( Included ( start) , Excluded ( end) ) => v >= start && v < end,
212
- ( Excluded ( start) , Unbounded ) => v > start,
213
- ( Excluded ( start) , Included ( end) ) => v > start && v <= end,
214
- ( Excluded ( start) , Excluded ( end) ) => v > start && v < end,
206
+ ( Excluded ( start) , _) => v <= start,
207
+ ( Included ( start) , _) => v < start,
208
+ ( Unbounded , _) => false ,
209
+ } {
210
+ return false ;
211
+ }
212
+ if match segment {
213
+ ( _, Unbounded ) => true ,
214
+ ( _, Included ( end) ) => v <= end,
215
+ ( _, Excluded ( end) ) => v < end,
215
216
} {
216
217
return true ;
217
218
}
218
219
}
219
220
false
220
221
}
221
222
223
+ /// Returns true if the this Range contains the specified values.
224
+ ///
225
+ /// The `versions` iterator must be sorted.
226
+ /// Functionally equivalent to `versions.map(|v| self.contains(v))`.
227
+ /// Except it runs in `O(size_of_range + len_of_versions)` not `O(size_of_range * len_of_versions)`
228
+ pub fn contains_many < ' s , I > ( & ' s self , versions : I ) -> impl Iterator < Item = bool > + ' s
229
+ where
230
+ I : Iterator < Item = & ' s V > + ' s ,
231
+ V : ' s ,
232
+ {
233
+ versions. scan ( 0 , |i, v| {
234
+ while let Some ( segment) = self . segments . get ( * i) {
235
+ if match segment {
236
+ ( Excluded ( start) , _) => v <= start,
237
+ ( Included ( start) , _) => v < start,
238
+ ( Unbounded , _) => false ,
239
+ } {
240
+ return Some ( false ) ;
241
+ }
242
+ if match segment {
243
+ ( _, Unbounded ) => true ,
244
+ ( _, Included ( end) ) => v <= end,
245
+ ( _, Excluded ( end) ) => v < end,
246
+ } {
247
+ return Some ( true ) ;
248
+ }
249
+ * i += 1 ;
250
+ }
251
+ Some ( false )
252
+ } )
253
+ }
254
+
222
255
/// Construct a simple range from anything that impls [RangeBounds] like `v1..v2`.
223
256
pub fn from_range_bounds < R , IV > ( bounds : R ) -> Self
224
257
where
@@ -321,6 +354,71 @@ impl<V: Ord + Clone> Range<V> {
321
354
322
355
Self { segments } . check_invariants ( )
323
356
}
357
+
358
+ /// Returns a simpler Range that contains the same versions
359
+ ///
360
+ /// For every one of the Versions provided in versions the existing range and
361
+ /// the simplified range will agree on whether it is contained.
362
+ /// The simplified version may include or exclude versions that are not in versions as the implementation wishes.
363
+ /// For example:
364
+ /// - If all the versions are contained in the original than the range will be simplified to `full`.
365
+ /// - If none of the versions are contained in the original than the range will be simplified to `empty`.
366
+ ///
367
+ /// If versions are not sorted the correctness of this function is not guaranteed.
368
+ pub fn simplify < ' a , I > ( & self , versions : I ) -> Self
369
+ where
370
+ I : Iterator < Item = & ' a V > ,
371
+ V : ' a ,
372
+ {
373
+ // First we determined for each version if there is a segment that makes it match.
374
+ let mut matches = versions. scan ( 0 , |i, v| {
375
+ while let Some ( segment) = self . segments . get ( * i) {
376
+ if match segment {
377
+ ( Excluded ( start) , _) => v <= start,
378
+ ( Included ( start) , _) => v < start,
379
+ ( Unbounded , _) => false ,
380
+ } {
381
+ return Some ( None ) ;
382
+ }
383
+ if match segment {
384
+ ( _, Unbounded ) => true ,
385
+ ( _, Included ( end) ) => v <= end,
386
+ ( _, Excluded ( end) ) => v < end,
387
+ } {
388
+ return Some ( Some ( * i) ) ;
389
+ }
390
+ * i += 1 ;
391
+ }
392
+ Some ( None )
393
+ } ) ;
394
+ let mut segments = SmallVec :: Empty ;
395
+ // If the first version matched, then the lower bound of that segment is not needed
396
+ let mut seg = if let Some ( Some ( ver) ) = matches. next ( ) {
397
+ Some ( ( & Unbounded , & self . segments [ ver] . 1 ) )
398
+ } else {
399
+ None
400
+ } ;
401
+ for ver in matches {
402
+ if let Some ( ver) = ver {
403
+ // As long as were still matching versions, we keep merging into the currently matching segment
404
+ seg = Some ( (
405
+ seg. map ( |( s, _) | s) . unwrap_or ( & self . segments [ ver] . 0 ) ,
406
+ & self . segments [ ver] . 1 ,
407
+ ) ) ;
408
+ } else {
409
+ // If we have found a version that doesn't match, then right the merge segment and prepare for a new one.
410
+ if let Some ( ( s, e) ) = seg {
411
+ segments. push ( ( s. clone ( ) , e. clone ( ) ) ) ;
412
+ }
413
+ seg = None ;
414
+ }
415
+ }
416
+ // If the last version matched, then write out the merged segment but the upper bound is not needed.
417
+ if let Some ( ( s, _) ) = seg {
418
+ segments. push ( ( s. clone ( ) , Unbounded ) ) ;
419
+ }
420
+ Self { segments } . check_invariants ( )
421
+ }
324
422
}
325
423
326
424
impl < T : Debug + Display + Clone + Eq + Ord > VersionSet for Range < T > {
@@ -600,5 +698,49 @@ pub mod tests {
600
698
let rv2: Range <u32 > = rv. bounding_range( ) . map( Range :: from_range_bounds:: <_, u32 >) . unwrap_or_else( Range :: empty) ;
601
699
assert_eq!( rv, rv2) ;
602
700
}
701
+
702
+ #[ test]
703
+ fn contains( range in strategy( ) , versions in vec![ version_strat( ) ] ) {
704
+ fn direct_implementation_of_contains( s: & Range <u32 >, v: & u32 ) -> bool {
705
+ for segment in s. segments. iter( ) {
706
+ if match segment {
707
+ ( Unbounded , Unbounded ) => true ,
708
+ ( Unbounded , Included ( end) ) => v <= end,
709
+ ( Unbounded , Excluded ( end) ) => v < end,
710
+ ( Included ( start) , Unbounded ) => v >= start,
711
+ ( Included ( start) , Included ( end) ) => v >= start && v <= end,
712
+ ( Included ( start) , Excluded ( end) ) => v >= start && v < end,
713
+ ( Excluded ( start) , Unbounded ) => v > start,
714
+ ( Excluded ( start) , Included ( end) ) => v > start && v <= end,
715
+ ( Excluded ( start) , Excluded ( end) ) => v > start && v < end,
716
+ } {
717
+ return true ;
718
+ }
719
+ }
720
+ false
721
+ }
722
+
723
+ for v in versions {
724
+ assert_eq!( range. contains( & v) , direct_implementation_of_contains( & range, & v) ) ;
725
+ }
726
+ }
727
+
728
+ #[ test]
729
+ fn contains_many( range in strategy( ) , mut versions in vec![ version_strat( ) ] ) {
730
+ versions. sort( ) ;
731
+ for ( a, b) in versions. iter( ) . map( |v| range. contains( v) ) . zip( range. contains_many( versions. iter( ) ) ) {
732
+ assert_eq!( a, b) ;
733
+ }
734
+ }
735
+
736
+ #[ test]
737
+ fn simplify( range in strategy( ) , mut versions in vec![ version_strat( ) ] ) {
738
+ versions. sort( ) ;
739
+ let simp = range. simplify( versions. iter( ) ) ;
740
+ for v in versions {
741
+ assert_eq!( range. contains( & v) , simp. contains( & v) ) ;
742
+ }
743
+ assert!( simp. segments. len( ) <= range. segments. len( ) )
744
+ }
603
745
}
604
746
}
0 commit comments