diff options
| author | Benoît du Garreau <benoit@dugarreau.fr> | 2025-05-16 15:46:44 +0200 |
|---|---|---|
| committer | Benoît du Garreau <benoit@dugarreau.fr> | 2025-05-16 15:46:44 +0200 |
| commit | 5240cd3a8210ab56fe5710048f7ab719cbba16a2 (patch) | |
| tree | 4ec0741c36e9cc7a8e1966815d6b6e67bd2ff23a /library/core | |
| parent | 1b9efcd18f1cb95348c3ffadd4db47bfa15292e5 (diff) | |
| download | rust-5240cd3a8210ab56fe5710048f7ab719cbba16a2.tar.gz rust-5240cd3a8210ab56fe5710048f7ab719cbba16a2.zip | |
Implement `advance_by` via `try_fold` for `Sized` iterators
When `try_fold` is overriden, it is usually easier for compilers to optimize.
Diffstat (limited to 'library/core')
| -rw-r--r-- | library/core/src/iter/traits/iterator.rs | 36 |
1 files changed, 31 insertions, 5 deletions
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index d1e71f0e60f..fab403ce853 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -294,13 +294,39 @@ pub trait Iterator { #[inline] #[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")] fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> { - for i in 0..n { - if self.next().is_none() { - // SAFETY: `i` is always less than `n`. - return Err(unsafe { NonZero::new_unchecked(n - i) }); + /// Helper trait to specialize `advance_by` via `try_fold` for `Sized` iterators. + trait SpecAdvanceBy { + fn spec_advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>>; + } + + impl<I: Iterator + ?Sized> SpecAdvanceBy for I { + default fn spec_advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> { + for i in 0..n { + if self.next().is_none() { + // SAFETY: `i` is always less than `n`. + return Err(unsafe { NonZero::new_unchecked(n - i) }); + } + } + Ok(()) + } + } + + impl<I: Iterator> SpecAdvanceBy for I { + fn spec_advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> { + let Some(n) = NonZero::new(n) else { + return Ok(()); + }; + + let res = self.try_fold(n, |n, _| NonZero::new(n.get() - 1)); + + match res { + None => Ok(()), + Some(n) => Err(n), + } } } - Ok(()) + + self.spec_advance_by(n) } /// Returns the `n`th element of the iterator. |
