| //! Arithmetic on **Iterator** *.size_hint()* values. |
| //! |
| |
| use std::usize; |
| use std::cmp; |
| use std::u32; |
| |
| /// **SizeHint** is the return type of **Iterator::size_hint()**. |
| pub type SizeHint = (usize, Option<usize>); |
| |
| /// Add **SizeHint** correctly. |
| #[inline] |
| pub fn add(a: SizeHint, b: SizeHint) -> SizeHint { |
| let min = a.0.saturating_add(b.0); |
| let max = match (a.1, b.1) { |
| (Some(x), Some(y)) => x.checked_add(y), |
| _ => None, |
| }; |
| |
| (min, max) |
| } |
| |
| /// Add **x** correctly to a **SizeHint**. |
| #[inline] |
| pub fn add_scalar(sh: SizeHint, x: usize) -> SizeHint { |
| let (mut low, mut hi) = sh; |
| low = low.saturating_add(x); |
| hi = hi.and_then(|elt| elt.checked_add(x)); |
| (low, hi) |
| } |
| |
| /// Sbb **x** correctly to a **SizeHint**. |
| #[inline] |
| #[allow(dead_code)] |
| pub fn sub_scalar(sh: SizeHint, x: usize) -> SizeHint { |
| let (mut low, mut hi) = sh; |
| low = low.saturating_sub(x); |
| hi = hi.map(|elt| elt.saturating_sub(x)); |
| (low, hi) |
| } |
| |
| |
| /// Multiply **SizeHint** correctly |
| /// |
| /// ```ignore |
| /// use std::usize; |
| /// use itertools::size_hint; |
| /// |
| /// assert_eq!(size_hint::mul((3, Some(4)), (3, Some(4))), |
| /// (9, Some(16))); |
| /// |
| /// assert_eq!(size_hint::mul((3, Some(4)), (usize::MAX, None)), |
| /// (usize::MAX, None)); |
| /// |
| /// assert_eq!(size_hint::mul((3, None), (0, Some(0))), |
| /// (0, Some(0))); |
| /// ``` |
| #[inline] |
| pub fn mul(a: SizeHint, b: SizeHint) -> SizeHint { |
| let low = a.0.saturating_mul(b.0); |
| let hi = match (a.1, b.1) { |
| (Some(x), Some(y)) => x.checked_mul(y), |
| (Some(0), None) | (None, Some(0)) => Some(0), |
| _ => None, |
| }; |
| (low, hi) |
| } |
| |
| /// Multiply **x** correctly with a **SizeHint**. |
| #[inline] |
| pub fn mul_scalar(sh: SizeHint, x: usize) -> SizeHint { |
| let (mut low, mut hi) = sh; |
| low = low.saturating_mul(x); |
| hi = hi.and_then(|elt| elt.checked_mul(x)); |
| (low, hi) |
| } |
| |
| /// Raise `base` correctly by a **`SizeHint`** exponent. |
| #[inline] |
| pub fn pow_scalar_base(base: usize, exp: SizeHint) -> SizeHint { |
| let exp_low = cmp::min(exp.0, u32::MAX as usize) as u32; |
| let low = base.saturating_pow(exp_low); |
| |
| let hi = exp.1.and_then(|exp| { |
| let exp_hi = cmp::min(exp, u32::MAX as usize) as u32; |
| base.checked_pow(exp_hi) |
| }); |
| |
| (low, hi) |
| } |
| |
| /// Return the maximum |
| #[inline] |
| pub fn max(a: SizeHint, b: SizeHint) -> SizeHint { |
| let (a_lower, a_upper) = a; |
| let (b_lower, b_upper) = b; |
| |
| let lower = cmp::max(a_lower, b_lower); |
| |
| let upper = match (a_upper, b_upper) { |
| (Some(x), Some(y)) => Some(cmp::max(x, y)), |
| _ => None, |
| }; |
| |
| (lower, upper) |
| } |
| |
| /// Return the minimum |
| #[inline] |
| pub fn min(a: SizeHint, b: SizeHint) -> SizeHint { |
| let (a_lower, a_upper) = a; |
| let (b_lower, b_upper) = b; |
| let lower = cmp::min(a_lower, b_lower); |
| let upper = match (a_upper, b_upper) { |
| (Some(u1), Some(u2)) => Some(cmp::min(u1, u2)), |
| _ => a_upper.or(b_upper), |
| }; |
| (lower, upper) |
| } |