diff --git a/src/libcore/iter/adapters/flatten.rs b/src/libcore/iter/adapters/flatten.rs index 40f6865d38bcf..565546da6a80a 100644 --- a/src/libcore/iter/adapters/flatten.rs +++ b/src/libcore/iter/adapters/flatten.rs @@ -226,11 +226,19 @@ impl Iterator for FlattenCompat fn size_hint(&self) -> (usize, Option) { let (flo, fhi) = self.frontiter.as_ref().map_or((0, Some(0)), |it| it.size_hint()); let (blo, bhi) = self.backiter.as_ref().map_or((0, Some(0)), |it| it.size_hint()); - let lo = flo.saturating_add(blo); - match (self.iter.size_hint(), fhi, bhi) { - ((0, Some(0)), Some(a), Some(b)) => (lo, a.checked_add(b)), - _ => (lo, None) - } + let (mlo, mhi) = self.iter.size_hint(); + let max = U::max_size_hint(); + + let lo = flo.saturating_add(blo).saturating_add(mlo.saturating_mul(max.unwrap_or(0))); + let hi = match (fhi, bhi, mhi, max) { + (Some(f), Some(b), Some(0), None) => f.checked_add(b), + (Some(f), Some(b), Some(m), Some(max)) => try { + f.checked_add(b)?.checked_add(m.checked_mul(max)?)? + }, + _ => None, + }; + + (lo, hi) } #[inline] diff --git a/src/libcore/iter/traits/iterator.rs b/src/libcore/iter/traits/iterator.rs index 9dfa83f473baf..12b14ffb28ec0 100644 --- a/src/libcore/iter/traits/iterator.rs +++ b/src/libcore/iter/traits/iterator.rs @@ -199,6 +199,15 @@ pub trait Iterator { #[stable(feature = "rust1", since = "1.0.0")] fn size_hint(&self) -> (usize, Option) { (0, None) } + /// An estimate of the maximum size of iterators of this type. + /// + /// This is similar to [`size_hint`], with the exception that it applies to all + /// iterators of this type. It can be used to optimize adapters like [`flatten`] + /// and provide better size hints. + #[inline] + #[unstable(feature = "max_size_hint", issue = "0")] + fn max_size_hint() -> Option where Self: Sized { None } + /// Consumes the iterator, counting the number of iterations and returning it. /// /// This method will evaluate the iterator until its [`next`] returns diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 0e54397db0247..ff65a8c0aaade 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -1172,6 +1172,8 @@ impl<'a, A> Iterator for Iter<'a, A> { fn next(&mut self) -> Option<&'a A> { self.inner.next() } #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + #[inline] + fn max_size_hint() -> Option { Some(1) } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1218,6 +1220,8 @@ impl<'a, A> Iterator for IterMut<'a, A> { fn next(&mut self) -> Option<&'a mut A> { self.inner.next() } #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + #[inline] + fn max_size_hint() -> Option { Some(1) } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1255,6 +1259,8 @@ impl Iterator for IntoIter { fn next(&mut self) -> Option { self.inner.next() } #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + #[inline] + fn max_size_hint() -> Option { Some(1) } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 1ebf0714e23e4..545dc16fe9edc 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -1077,6 +1077,8 @@ impl<'a, T> Iterator for Iter<'a, T> { let n = if self.inner.is_some() {1} else {0}; (n, Some(n)) } + #[inline] + fn max_size_hint() -> Option { Some(1) } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1122,6 +1124,8 @@ impl<'a, T> Iterator for IterMut<'a, T> { let n = if self.inner.is_some() {1} else {0}; (n, Some(n)) } + #[inline] + fn max_size_hint() -> Option { Some(1) } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1165,6 +1169,8 @@ impl Iterator for IntoIter { let n = if self.inner.is_some() {1} else {0}; (n, Some(n)) } + #[inline] + fn max_size_hint() -> Option { Some(1) } } #[stable(feature = "rust1", since = "1.0.0")]