|
2 | 2 |
|
3 | 3 | extern mod extra; |
4 | 4 |
|
| 5 | +use std::cmp; |
5 | 6 | use extra::time::Timespec; |
6 | 7 |
|
7 | 8 | /// A trait that normalizes a range bound for a type |
@@ -145,8 +146,15 @@ impl<T: Ord+Normalizable> Range<T> { |
145 | 146 | let upper = upper.map(|bound| { Normalizable::normalize(bound) }); |
146 | 147 |
|
147 | 148 | match (&lower, &upper) { |
148 | | - (&Some(ref lower), &Some(ref upper)) => |
149 | | - assert!(lower.value <= upper.value), |
| 149 | + (&Some(ref lower), &Some(ref upper)) => { |
| 150 | + let empty = match (lower.type_, upper.type_) { |
| 151 | + (Inclusive, Inclusive) => lower.value > upper.value, |
| 152 | + _ => lower.value >= upper.value |
| 153 | + }; |
| 154 | + if empty { |
| 155 | + return Empty; |
| 156 | + } |
| 157 | + } |
150 | 158 | _ => {} |
151 | 159 | } |
152 | 160 |
|
@@ -194,6 +202,31 @@ impl<T: Ord+Normalizable> Range<T> { |
194 | 202 | } |
195 | 203 | } |
196 | 204 |
|
| 205 | +impl<T: Ord+Normalizable+Clone> Range<T> { |
| 206 | + /// Returns the intersection of this range with another |
| 207 | + pub fn intersect(&self, other: &Range<T>) -> Range<T> { |
| 208 | + if self.is_empty() || other.is_empty() { |
| 209 | + return Range::empty(); |
| 210 | + } |
| 211 | + |
| 212 | + let lower = match (self.lower(), other.lower()) { |
| 213 | + (&Some(ref a), &Some(ref b)) => Some(cmp::max(a, b).clone()), |
| 214 | + (&Some(ref a), &None) => Some(a.clone()), |
| 215 | + (&None, &Some(ref b)) => Some(b.clone()), |
| 216 | + (&None, &None) => None |
| 217 | + }; |
| 218 | + |
| 219 | + let upper = match (self.upper(), other.upper()) { |
| 220 | + (&Some(ref a), &Some(ref b)) => Some(cmp::min(a, b).clone()), |
| 221 | + (&Some(ref a), &None) => Some(a.clone()), |
| 222 | + (&None, &Some(ref b)) => Some(b.clone()), |
| 223 | + (&None, &None) => None |
| 224 | + }; |
| 225 | + |
| 226 | + Range::new(lower, upper) |
| 227 | + } |
| 228 | +} |
| 229 | + |
197 | 230 | #[cfg(test)] |
198 | 231 | mod test { |
199 | 232 | use super::*; |
@@ -320,4 +353,42 @@ mod test { |
320 | 353 | Some(RangeBound::new(16i32, Exclusive))); |
321 | 354 | assert_eq!(r1, r2); |
322 | 355 | } |
| 356 | + |
| 357 | + #[test] |
| 358 | + fn test_range_empty() { |
| 359 | + assert!(Range::new(Some(RangeBound::new(9i32, Exclusive)), |
| 360 | + Some(RangeBound::new(10i32, Exclusive))).is_empty()); |
| 361 | + assert!(Range::new(Some(RangeBound::new(10i32, Inclusive)), |
| 362 | + Some(RangeBound::new(10i32, Exclusive))).is_empty()); |
| 363 | + assert!(Range::new(Some(RangeBound::new(10i32, Exclusive)), |
| 364 | + Some(RangeBound::new(10i32, Inclusive))).is_empty()); |
| 365 | + assert!(Range::new(Some(RangeBound::new(10i32, Inclusive)), |
| 366 | + Some(RangeBound::new(9i32, Inclusive))).is_empty()); |
| 367 | + } |
| 368 | + |
| 369 | + #[test] |
| 370 | + fn test_intersection() { |
| 371 | + let r1 = Range::new(Some(RangeBound::new(10i32, Inclusive)), |
| 372 | + Some(RangeBound::new(15i32, Exclusive))); |
| 373 | + let r2 = Range::new(Some(RangeBound::new(20i32, Exclusive)), |
| 374 | + Some(RangeBound::new(25i32, Inclusive))); |
| 375 | + assert!(r1.intersect(&r2).is_empty()); |
| 376 | + assert!(r2.intersect(&r1).is_empty()); |
| 377 | + assert_eq!(r1, r1.intersect(&Range::new(None, None))); |
| 378 | + assert_eq!(r1, Range::new(None, None).intersect(&r1)); |
| 379 | + |
| 380 | + let r2 = Range::new(Some(RangeBound::new(10i32, Exclusive)), None); |
| 381 | + let exp = Range::new(r2.lower().clone(), r1.upper().clone()); |
| 382 | + assert_eq!(exp, r1.intersect(&r2)); |
| 383 | + assert_eq!(exp, r2.intersect(&r1)); |
| 384 | + |
| 385 | + let r2 = Range::new(None, Some(RangeBound::new(15i32, Inclusive))); |
| 386 | + assert_eq!(r1, r1.intersect(&r2)); |
| 387 | + assert_eq!(r1, r2.intersect(&r1)); |
| 388 | + |
| 389 | + let r2 = Range::new(Some(RangeBound::new(11i32, Inclusive)), |
| 390 | + Some(RangeBound::new(14i32, Exclusive))); |
| 391 | + assert_eq!(r2, r1.intersect(&r2)); |
| 392 | + assert_eq!(r2, r2.intersect(&r1)); |
| 393 | + } |
323 | 394 | } |
0 commit comments