120 lines
2.9 KiB
Rust
120 lines
2.9 KiB
Rust
//! 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)
|
|
}
|