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:
parent
ce5aad2f10
commit
4f61e16032
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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]
|
||||
|
|
Loading…
Reference in New Issue