Fix std::ops::Range size_hint and ExactSizeIterator impls

When self.start > self.end, these iterators simply return None,
so we adjust the size_hint to just return zero in this case.

Certain optimizations can be implemented in and outside libstd if we
know we can trust the size_hint for all inputs to for example
Range<usize>.

This corrects the ExactSizeIterator implementations, which IMO were
unsound and incorrect previously, since they allowed a range like (2..1)
to return a size_hint of -1us in when debug assertions are turned off.
This commit is contained in:
Ulrik Sverdrup 2015-02-08 00:17:04 +01:00
parent ce5aad2f10
commit 4f61e16032
2 changed files with 8 additions and 10 deletions

View File

@ -2646,13 +2646,7 @@ impl<A: Int> Iterator for RangeStepInclusive<A> {
macro_rules! range_exact_iter_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
impl ExactSizeIterator for ::ops::Range<$t> {
#[inline]
fn len(&self) -> usize {
debug_assert!(self.end >= self.start);
(self.end - self.start) as usize
}
}
impl ExactSizeIterator for ::ops::Range<$t> { }
)*)
}
@ -2673,9 +2667,12 @@ impl<A: Int> Iterator for ::ops::Range<A> {
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
debug_assert!(self.end >= self.start);
let hint = (self.end - self.start).to_uint();
(hint.unwrap_or(0), hint)
if self.start >= self.end {
(0, Some(0))
} else {
let length = (self.end - self.start).to_uint();
(length.unwrap_or(0), length)
}
}
}

View File

@ -756,6 +756,7 @@ fn test_range() {
// this test is only meaningful when sizeof uint < sizeof u64
assert_eq!((uint::MAX - 1..uint::MAX).size_hint(), (1, Some(1)));
assert_eq!((-10..-1).size_hint(), (9, Some(9)));
assert_eq!((-1..-10).size_hint(), (0, Some(0)));
}
#[test]