//! 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); /// 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) } /// Subtract `x` correctly from 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) }