Make overflow behaviour more obvious in the iterator module of libcore

Explicitely spell out behaviour on overflow for `usize`-returning iterator
functions.

Mention that panics are guaranteed if debug assertions are active, otherwise a
wrong result might be returned.
This commit is contained in:
Tobias Bucher
2015-03-31 12:21:12 +02:00
parent 6afa669524
commit 29d7fed994

View File

@@ -106,6 +106,18 @@ pub trait Iterator {
/// Counts the number of elements in this iterator. /// Counts the number of elements in this iterator.
/// ///
/// # Overflow Behavior
///
/// The method does no guarding against overflows, so counting elements of
/// an iterator with more than `usize::MAX` elements either produces the
/// wrong result or panics. If debug assertions are enabled, a panic is
/// guaranteed.
///
/// # Panics
///
/// This functions might panic if the iterator has more than `usize::MAX`
/// elements.
///
/// # Examples /// # Examples
/// ///
/// ``` /// ```
@@ -115,7 +127,8 @@ pub trait Iterator {
#[inline] #[inline]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
fn count(self) -> usize where Self: Sized { fn count(self) -> usize where Self: Sized {
self.fold(0, |cnt, _x| cnt + 1) // Might overflow.
self.fold(0, |cnt, _| cnt + 1)
} }
/// Loops through the entire iterator, returning the last element. /// Loops through the entire iterator, returning the last element.
@@ -281,6 +294,17 @@ pub trait Iterator {
/// different sized integer, the `zip` function provides similar /// different sized integer, the `zip` function provides similar
/// functionality. /// functionality.
/// ///
/// # Overflow Behavior
///
/// The method does no guarding against overflows, so enumerating more than
/// `usize::MAX` elements either produces the wrong result or panics. If
/// debug assertions are enabled, a panic is guaranteed.
///
/// # Panics
///
/// The returned iterator might panic if the to-be-returned index would
/// overflow a `usize`.
///
/// # Examples /// # Examples
/// ///
/// ``` /// ```
@@ -672,6 +696,18 @@ pub trait Iterator {
/// ///
/// Does not consume the iterator past the first found element. /// Does not consume the iterator past the first found element.
/// ///
/// # Overflow Behavior
///
/// The method does no guarding against overflows, so if there are more
/// than `usize::MAX` non-matching elements, it either produces the wrong
/// result or panics. If debug assertions are enabled, a panic is
/// guaranteed.
///
/// # Panics
///
/// This functions might panic if the iterator has more than `usize::MAX`
/// non-matching elements.
///
/// # Examples /// # Examples
/// ///
/// ``` /// ```
@@ -685,12 +721,11 @@ pub trait Iterator {
Self: Sized, Self: Sized,
P: FnMut(Self::Item) -> bool, P: FnMut(Self::Item) -> bool,
{ {
let mut i = 0; // `enumerate` might overflow.
for x in self.by_ref() { for (i, x) in self.by_ref().enumerate() {
if predicate(x) { if predicate(x) {
return Some(i); return Some(i);
} }
i += 1;
} }
None None
} }
@@ -720,6 +755,8 @@ pub trait Iterator {
if predicate(v) { if predicate(v) {
return Some(i - 1); return Some(i - 1);
} }
// No need for an overflow check here, because `ExactSizeIterator`
// implies that the number of elements fits into a `usize`.
i -= 1; i -= 1;
} }
None None
@@ -1783,17 +1820,27 @@ impl<B, I: DoubleEndedIterator, F> DoubleEndedIterator for FilterMap<I, F>
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub struct Enumerate<I> { pub struct Enumerate<I> {
iter: I, iter: I,
count: usize count: usize,
} }
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<I> Iterator for Enumerate<I> where I: Iterator { impl<I> Iterator for Enumerate<I> where I: Iterator {
type Item = (usize, <I as Iterator>::Item); type Item = (usize, <I as Iterator>::Item);
/// # Overflow Behavior
///
/// The method does no guarding against overflows, so enumerating more than
/// `usize::MAX` elements either produces the wrong result or panics. If
/// debug assertions are enabled, a panic is guaranteed.
///
/// # Panics
///
/// Might panic if the index of the element overflows a `usize`.
#[inline] #[inline]
fn next(&mut self) -> Option<(usize, <I as Iterator>::Item)> { fn next(&mut self) -> Option<(usize, <I as Iterator>::Item)> {
self.iter.next().map(|a| { self.iter.next().map(|a| {
let ret = (self.count, a); let ret = (self.count, a);
// Possible undefined overflow.
self.count += 1; self.count += 1;
ret ret
}) })
@@ -1827,6 +1874,8 @@ impl<I> DoubleEndedIterator for Enumerate<I> where
fn next_back(&mut self) -> Option<(usize, <I as Iterator>::Item)> { fn next_back(&mut self) -> Option<(usize, <I as Iterator>::Item)> {
self.iter.next_back().map(|a| { self.iter.next_back().map(|a| {
let len = self.iter.len(); let len = self.iter.len();
// Can safely add, `ExactSizeIterator` promises that the number of
// elements fits into a `usize`.
(self.count + len, a) (self.count + len, a)
}) })
} }
@@ -1841,6 +1890,9 @@ impl<I> RandomAccessIterator for Enumerate<I> where I: RandomAccessIterator {
#[inline] #[inline]
fn idx(&mut self, index: usize) -> Option<(usize, <I as Iterator>::Item)> { fn idx(&mut self, index: usize) -> Option<(usize, <I as Iterator>::Item)> {
// Can safely add, `ExactSizeIterator` (ancestor of
// `RandomAccessIterator`) promises that the number of elements fits
// into a `usize`.
self.iter.idx(index).map(|a| (self.count + index, a)) self.iter.idx(index).map(|a| (self.count + index, a))
} }
} }