@@ -202,23 +202,40 @@ impl<V: Ord> Range<V> {
202
202
/// Returns true if the this Range contains the specified value.
203
203
pub fn contains ( & self , v : & V ) -> bool {
204
204
for segment in self . segments . iter ( ) {
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,
215
- } {
205
+ if !within_lower_bound ( segment, v) {
206
+ return false ;
207
+ }
208
+ if within_uppern_bound ( segment, v) {
216
209
return true ;
217
210
}
218
211
}
219
212
false
220
213
}
221
214
215
+ /// Returns true if the this Range contains the specified values.
216
+ ///
217
+ /// The `versions` iterator must be sorted.
218
+ /// Functionally equivalent to `versions.map(|v| self.contains(v))`.
219
+ /// Except it runs in `O(size_of_range + len_of_versions)` not `O(size_of_range * len_of_versions)`
220
+ pub fn contains_many < ' s , I > ( & ' s self , versions : I ) -> impl Iterator < Item = bool > + ' s
221
+ where
222
+ I : Iterator < Item = & ' s V > + ' s ,
223
+ V : ' s ,
224
+ {
225
+ versions. scan ( 0 , |i, v| {
226
+ while let Some ( segment) = self . segments . get ( * i) {
227
+ if !within_lower_bound ( segment, v) {
228
+ return Some ( false ) ;
229
+ }
230
+ if within_uppern_bound ( segment, v) {
231
+ return Some ( true ) ;
232
+ }
233
+ * i += 1 ;
234
+ }
235
+ Some ( false )
236
+ } )
237
+ }
238
+
222
239
/// Construct a simple range from anything that impls [RangeBounds] like `v1..v2`.
223
240
pub fn from_range_bounds < R , IV > ( bounds : R ) -> Self
224
241
where
@@ -264,6 +281,22 @@ impl<V: Ord> Range<V> {
264
281
}
265
282
}
266
283
284
+ fn within_lower_bound < V : PartialOrd > ( segment : & Interval < V > , v : & V ) -> bool {
285
+ match segment {
286
+ ( Excluded ( start) , _) => start < v,
287
+ ( Included ( start) , _) => start <= v,
288
+ ( Unbounded , _) => true ,
289
+ }
290
+ }
291
+
292
+ fn within_uppern_bound < V : PartialOrd > ( segment : & Interval < V > , v : & V ) -> bool {
293
+ match segment {
294
+ ( _, Unbounded ) => true ,
295
+ ( _, Included ( end) ) => v <= end,
296
+ ( _, Excluded ( end) ) => v < end,
297
+ }
298
+ }
299
+
267
300
fn valid_segment < T : PartialOrd > ( start : & Bound < T > , end : & Bound < T > ) -> bool {
268
301
match ( start, end) {
269
302
( Included ( s) , Included ( e) ) => s <= e,
@@ -321,6 +354,63 @@ 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 !within_lower_bound ( segment, v) {
377
+ return Some ( None ) ;
378
+ }
379
+ if within_uppern_bound ( segment, v) {
380
+ return Some ( Some ( * i) ) ;
381
+ }
382
+ * i += 1 ;
383
+ }
384
+ Some ( None )
385
+ } ) ;
386
+ let mut segments = SmallVec :: Empty ;
387
+ // If the first version matched, then the lower bound of that segment is not needed
388
+ let mut seg = if let Some ( Some ( ver) ) = matches. next ( ) {
389
+ Some ( ( & Unbounded , & self . segments [ ver] . 1 ) )
390
+ } else {
391
+ None
392
+ } ;
393
+ for ver in matches {
394
+ if let Some ( ver) = ver {
395
+ // As long as were still matching versions, we keep merging into the currently matching segment
396
+ seg = Some ( (
397
+ seg. map ( |( s, _) | s) . unwrap_or ( & self . segments [ ver] . 0 ) ,
398
+ & self . segments [ ver] . 1 ,
399
+ ) ) ;
400
+ } else {
401
+ // If we have found a version that doesn't match, then right the merge segment and prepare for a new one.
402
+ if let Some ( ( s, e) ) = seg {
403
+ segments. push ( ( s. clone ( ) , e. clone ( ) ) ) ;
404
+ }
405
+ seg = None ;
406
+ }
407
+ }
408
+ // If the last version matched, then write out the merged segment but the upper bound is not needed.
409
+ if let Some ( ( s, _) ) = seg {
410
+ segments. push ( ( s. clone ( ) , Unbounded ) ) ;
411
+ }
412
+ Self { segments } . check_invariants ( )
413
+ }
324
414
}
325
415
326
416
impl < T : Debug + Display + Clone + Eq + Ord > VersionSet for Range < T > {
@@ -600,5 +690,30 @@ pub mod tests {
600
690
let rv2: Range <u32 > = rv. bounding_range( ) . map( Range :: from_range_bounds:: <_, u32 >) . unwrap_or_else( Range :: empty) ;
601
691
assert_eq!( rv, rv2) ;
602
692
}
693
+
694
+ #[ test]
695
+ fn contains( range in strategy( ) , versions in vec![ version_strat( ) ] ) {
696
+ for v in versions {
697
+ assert_eq!( range. contains( & v) , range. segments. iter( ) . any( |s| RangeBounds :: contains( s, & v) ) ) ;
698
+ }
699
+ }
700
+
701
+ #[ test]
702
+ fn contains_many( range in strategy( ) , mut versions in vec![ version_strat( ) ] ) {
703
+ versions. sort( ) ;
704
+ for ( a, b) in versions. iter( ) . zip( range. contains_many( versions. iter( ) ) ) {
705
+ assert_eq!( range. contains( a) , b) ;
706
+ }
707
+ }
708
+
709
+ #[ test]
710
+ fn simplify( range in strategy( ) , mut versions in vec![ version_strat( ) ] ) {
711
+ versions. sort( ) ;
712
+ let simp = range. simplify( versions. iter( ) ) ;
713
+ for v in versions {
714
+ assert_eq!( range. contains( & v) , simp. contains( & v) ) ;
715
+ }
716
+ assert!( simp. segments. len( ) <= range. segments. len( ) )
717
+ }
603
718
}
604
719
}
0 commit comments