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 | |