| 1 | //! Arithmetic on `Iterator.size_hint()` values. |
| 2 | //! |
| 3 | |
| 4 | use std::cmp; |
| 5 | use std::usize; |
| 6 | |
| 7 | /// `SizeHint` is the return type of `Iterator::size_hint()`. |
| 8 | pub type SizeHint = (usize, Option<usize>); |
| 9 | |
| 10 | /// Add `SizeHint` correctly. |
| 11 | #[inline ] |
| 12 | pub fn add(a: SizeHint, b: SizeHint) -> SizeHint { |
| 13 | let min: usize = a.0.saturating_add(b.0); |
| 14 | let max: Option = match (a.1, b.1) { |
| 15 | (Some(x: usize), Some(y: usize)) => x.checked_add(y), |
| 16 | _ => None, |
| 17 | }; |
| 18 | |
| 19 | (min, max) |
| 20 | } |
| 21 | |
| 22 | /// Add `x` correctly to a `SizeHint`. |
| 23 | #[inline ] |
| 24 | pub fn add_scalar(sh: SizeHint, x: usize) -> SizeHint { |
| 25 | let (mut low: usize, mut hi: Option) = sh; |
| 26 | low = low.saturating_add(x); |
| 27 | hi = hi.and_then(|elt: usize| elt.checked_add(x)); |
| 28 | (low, hi) |
| 29 | } |
| 30 | |
| 31 | /// Subtract `x` correctly from a `SizeHint`. |
| 32 | #[inline ] |
| 33 | pub fn sub_scalar(sh: SizeHint, x: usize) -> SizeHint { |
| 34 | let (mut low: usize, mut hi: Option) = sh; |
| 35 | low = low.saturating_sub(x); |
| 36 | hi = hi.map(|elt: usize| elt.saturating_sub(x)); |
| 37 | (low, hi) |
| 38 | } |
| 39 | |
| 40 | /// Multiply `SizeHint` correctly |
| 41 | #[inline ] |
| 42 | pub fn mul(a: SizeHint, b: SizeHint) -> SizeHint { |
| 43 | let low: usize = a.0.saturating_mul(b.0); |
| 44 | let hi: Option = match (a.1, b.1) { |
| 45 | (Some(x: usize), Some(y: usize)) => x.checked_mul(y), |
| 46 | (Some(0), None) | (None, Some(0)) => Some(0), |
| 47 | _ => None, |
| 48 | }; |
| 49 | (low, hi) |
| 50 | } |
| 51 | |
| 52 | /// Multiply `x` correctly with a `SizeHint`. |
| 53 | #[inline ] |
| 54 | pub fn mul_scalar(sh: SizeHint, x: usize) -> SizeHint { |
| 55 | let (mut low: usize, mut hi: Option) = sh; |
| 56 | low = low.saturating_mul(x); |
| 57 | hi = hi.and_then(|elt: usize| elt.checked_mul(x)); |
| 58 | (low, hi) |
| 59 | } |
| 60 | |
| 61 | /// Return the maximum |
| 62 | #[inline ] |
| 63 | pub fn max(a: SizeHint, b: SizeHint) -> SizeHint { |
| 64 | let (a_lower: usize, a_upper: Option) = a; |
| 65 | let (b_lower: usize, b_upper: Option) = b; |
| 66 | |
| 67 | let lower: usize = cmp::max(v1:a_lower, v2:b_lower); |
| 68 | |
| 69 | let upper: Option = match (a_upper, b_upper) { |
| 70 | (Some(x: usize), Some(y: usize)) => Some(cmp::max(v1:x, v2:y)), |
| 71 | _ => None, |
| 72 | }; |
| 73 | |
| 74 | (lower, upper) |
| 75 | } |
| 76 | |
| 77 | /// Return the minimum |
| 78 | #[inline ] |
| 79 | pub fn min(a: SizeHint, b: SizeHint) -> SizeHint { |
| 80 | let (a_lower: usize, a_upper: Option) = a; |
| 81 | let (b_lower: usize, b_upper: Option) = b; |
| 82 | let lower: usize = cmp::min(v1:a_lower, v2:b_lower); |
| 83 | let upper: Option = match (a_upper, b_upper) { |
| 84 | (Some(u1: usize), Some(u2: usize)) => Some(cmp::min(v1:u1, v2:u2)), |
| 85 | _ => a_upper.or(optb:b_upper), |
| 86 | }; |
| 87 | (lower, upper) |
| 88 | } |
| 89 | |
| 90 | #[test ] |
| 91 | fn mul_size_hints() { |
| 92 | assert_eq!(mul((3, Some(4)), (3, Some(4))), (9, Some(16))); |
| 93 | assert_eq!(mul((3, Some(4)), (usize::MAX, None)), (usize::MAX, None)); |
| 94 | assert_eq!(mul((3, None), (0, Some(0))), (0, Some(0))); |
| 95 | } |
| 96 | |