Skip to content

Commit 1b548ae

Browse files
Add ExactSizeIterator impl for iter::Chain
1 parent a0d40f8 commit 1b548ae

File tree

3 files changed

+98
-0
lines changed

3 files changed

+98
-0
lines changed

src/libcore/iter/adapters/chain.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,36 @@ impl<A, B> FusedIterator for Chain<A, B>
283283
B: FusedIterator<Item=A::Item>,
284284
{}
285285

286+
#[stable(feature = "chain_exact_size", since = "1.41.0")]
287+
impl<A, B> ExactSizeIterator for Chain<A, B>
288+
where
289+
A: ExactSizeIterator,
290+
B: ExactSizeIterator<Item = A::Item>,
291+
{
292+
/// Returns the exact number of times the iterator will iterate.
293+
///
294+
/// # Overflow Behavior
295+
///
296+
/// The method does no guarding against overflows, so calling `len` on an
297+
/// iterator with more than [`usize::MAX`] elements either produces the
298+
/// wrong result or panics. If debug assertions are enabled, a panic is
299+
/// guaranteed.
300+
///
301+
/// # Panics
302+
///
303+
/// This function might panic if the iterator has more than [`usize::MAX`]
304+
/// elements.
305+
///
306+
/// [`usize::MAX`]: ../../std/usize/constant.MAX.html
307+
fn len(&self) -> usize {
308+
match self.state {
309+
ChainState::Both => self.a.len() + self.b.len(),
310+
ChainState::Front => self.a.len(),
311+
ChainState::Back => self.b.len(),
312+
}
313+
}
314+
}
315+
286316
#[unstable(feature = "trusted_len", issue = "37572")]
287317
unsafe impl<A, B> TrustedLen for Chain<A, B>
288318
where A: TrustedLen, B: TrustedLen<Item=A::Item>,

src/libcore/iter/traits/iterator.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
// ignore-tidy-filelength
2+
// This file almost exclusively consists of the definition of `Iterator`. We
3+
// can't split that into multiple files.
4+
15
use crate::cmp::{self, Ordering};
26
use crate::ops::{Add, Try};
37

@@ -388,6 +392,26 @@ pub trait Iterator {
388392
/// [`once`] is commonly used to adapt a single value into a chain of
389393
/// other kinds of iteration.
390394
///
395+
///
396+
/// # Overflowing behavior for long iterators
397+
///
398+
/// This method allows to easily build an iterator that yields more than
399+
/// [`usize::MAX`] items. In that case, some methods that return `usize`
400+
/// are not guarded against overflow. For example, this includes the
401+
/// following methods:
402+
///
403+
/// - [`Iterator::count`]
404+
/// - [`Iterator::enumerate`]
405+
/// - [`Iterator::position`] and [`Iterator::rposition`]
406+
/// - [`ExactSizeIterator::len`]
407+
///
408+
/// An overflow in those methods leads to a wrong result or a panic. If
409+
/// debug assertions are enabled, a panic is guaranteed.
410+
///
411+
///
412+
/// [`usize::MAX`]: ../../std/usize/constant.MAX.html
413+
///
414+
///
391415
/// # Examples
392416
///
393417
/// Basic usage:

src/libcore/tests/iter.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,50 @@ fn test_iterator_chain_size_hint() {
256256
assert_eq!(iter.size_hint(), (0, Some(0)));
257257
}
258258

259+
#[test]
260+
fn test_iterator_chain_len() {
261+
let xs = [0, 1, 2];
262+
let ys = [30, 40, 50, 60];
263+
264+
// First iterator is exhausted first
265+
let mut iter = xs.iter().chain(&ys);
266+
assert_eq!(iter.len(), 7);
267+
assert_eq!(iter.next(), Some(&0));
268+
assert_eq!(iter.len(), 6);
269+
assert_eq!(iter.next(), Some(&1));
270+
assert_eq!(iter.len(), 5);
271+
assert_eq!(iter.next_back(), Some(&60));
272+
assert_eq!(iter.len(), 4);
273+
assert_eq!(iter.next(), Some(&2));
274+
assert_eq!(iter.len(), 3);
275+
assert_eq!(iter.next(), Some(&30));
276+
assert_eq!(iter.len(), 2);
277+
assert_eq!(iter.next(), Some(&40));
278+
assert_eq!(iter.len(), 1);
279+
assert_eq!(iter.next(), Some(&50));
280+
assert_eq!(iter.len(), 0);
281+
assert_eq!(iter.next(), None);
282+
283+
// Second iterator is exhausted first
284+
let mut iter = xs.iter().chain(&ys);
285+
assert_eq!(iter.len(), 7);
286+
assert_eq!(iter.next_back(), Some(&60));
287+
assert_eq!(iter.len(), 6);
288+
assert_eq!(iter.next(), Some(&0));
289+
assert_eq!(iter.len(), 5);
290+
assert_eq!(iter.next_back(), Some(&50));
291+
assert_eq!(iter.len(), 4);
292+
assert_eq!(iter.next_back(), Some(&40));
293+
assert_eq!(iter.len(), 3);
294+
assert_eq!(iter.next_back(), Some(&30));
295+
assert_eq!(iter.len(), 2);
296+
assert_eq!(iter.next(), Some(&1));
297+
assert_eq!(iter.len(), 1);
298+
assert_eq!(iter.next(), Some(&2));
299+
assert_eq!(iter.len(), 0);
300+
assert_eq!(iter.next(), None);
301+
}
302+
259303
#[test]
260304
fn test_zip_nth() {
261305
let xs = [0, 1, 2, 4, 5];

0 commit comments

Comments
 (0)