Skip to main content

core/iter/adapters/
step_by.rs

1use crate::intrinsics;
2use crate::iter::{FusedIterator, TrustedLen, TrustedRandomAccess, from_fn};
3use crate::num::NonZero;
4use crate::ops::{Range, Try};
5use crate::range::RangeIter;
6
7/// An iterator for stepping iterators by a custom amount.
8///
9/// This `struct` is created by the [`step_by`] method on [`Iterator`]. See
10/// its documentation for more.
11///
12/// [`step_by`]: Iterator::step_by
13/// [`Iterator`]: trait.Iterator.html
14#[must_use = "iterators are lazy and do nothing unless consumed"]
15#[stable(feature = "iterator_step_by", since = "1.28.0")]
16#[derive(Clone, Debug)]
17#[ferrocene::prevalidated]
18pub struct StepBy<I> {
19    /// This field is guaranteed to be preprocessed by the specialized `SpecRangeSetup::setup`
20    /// in the constructor.
21    /// For most iterators that processing is a no-op, but for Range<{integer}> types it is lossy
22    /// which means the inner iterator cannot be returned to user code.
23    /// Additionally this type-dependent preprocessing means specialized implementations
24    /// cannot be used interchangeably.
25    iter: I,
26    /// This field is `step - 1`, aka the correct amount to pass to `nth` when iterating.
27    /// It MUST NOT be `usize::MAX`, as `unsafe` code depends on being able to add one
28    /// without the risk of overflow.  (This is important so that length calculations
29    /// don't need to check for division-by-zero, for example.)
30    step_minus_one: usize,
31    first_take: bool,
32}
33
34impl<I> StepBy<I> {
35    #[inline]
36    #[ferrocene::prevalidated]
37    pub(in crate::iter) fn new(iter: I, step: usize) -> StepBy<I> {
38        assert!(step != 0);
39        let iter = <I as SpecRangeSetup<I>>::setup(iter, step);
40        StepBy { iter, step_minus_one: step - 1, first_take: true }
41    }
42
43    /// The `step` that was originally passed to `Iterator::step_by(step)`,
44    /// aka `self.step_minus_one + 1`.
45    #[inline]
46    #[ferrocene::prevalidated]
47    fn original_step(&self) -> NonZero<usize> {
48        // SAFETY: By type invariant, `step_minus_one` cannot be `MAX`, which
49        // means the addition cannot overflow and the result cannot be zero.
50        unsafe { NonZero::new_unchecked(intrinsics::unchecked_add(self.step_minus_one, 1)) }
51    }
52}
53
54#[stable(feature = "iterator_step_by", since = "1.28.0")]
55impl<I> Iterator for StepBy<I>
56where
57    I: Iterator,
58{
59    type Item = I::Item;
60
61    #[inline]
62    #[ferrocene::prevalidated]
63    fn next(&mut self) -> Option<Self::Item> {
64        self.spec_next()
65    }
66
67    #[inline]
68    #[ferrocene::prevalidated]
69    fn size_hint(&self) -> (usize, Option<usize>) {
70        self.spec_size_hint()
71    }
72
73    #[inline]
74    #[ferrocene::prevalidated]
75    fn nth(&mut self, n: usize) -> Option<Self::Item> {
76        self.spec_nth(n)
77    }
78
79    #[ferrocene::prevalidated]
80    fn try_fold<Acc, F, R>(&mut self, acc: Acc, f: F) -> R
81    where
82        F: FnMut(Acc, Self::Item) -> R,
83        R: Try<Output = Acc>,
84    {
85        self.spec_try_fold(acc, f)
86    }
87
88    #[inline]
89    #[ferrocene::prevalidated]
90    fn fold<Acc, F>(self, acc: Acc, f: F) -> Acc
91    where
92        F: FnMut(Acc, Self::Item) -> Acc,
93    {
94        self.spec_fold(acc, f)
95    }
96}
97
98impl<I> StepBy<I>
99where
100    I: ExactSizeIterator,
101{
102    // The zero-based index starting from the end of the iterator of the
103    // last element. Used in the `DoubleEndedIterator` implementation.
104    fn next_back_index(&self) -> usize {
105        let rem = self.iter.len() % self.original_step();
106        if self.first_take { if rem == 0 { self.step_minus_one } else { rem - 1 } } else { rem }
107    }
108}
109
110#[stable(feature = "double_ended_step_by_iterator", since = "1.38.0")]
111impl<I> DoubleEndedIterator for StepBy<I>
112where
113    I: DoubleEndedIterator + ExactSizeIterator,
114{
115    #[inline]
116    fn next_back(&mut self) -> Option<Self::Item> {
117        self.spec_next_back()
118    }
119
120    #[inline]
121    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
122        self.spec_nth_back(n)
123    }
124
125    fn try_rfold<Acc, F, R>(&mut self, init: Acc, f: F) -> R
126    where
127        F: FnMut(Acc, Self::Item) -> R,
128        R: Try<Output = Acc>,
129    {
130        self.spec_try_rfold(init, f)
131    }
132
133    #[inline]
134    fn rfold<Acc, F>(self, init: Acc, f: F) -> Acc
135    where
136        Self: Sized,
137        F: FnMut(Acc, Self::Item) -> Acc,
138    {
139        self.spec_rfold(init, f)
140    }
141}
142
143// StepBy can only make the iterator shorter, so the len will still fit.
144#[stable(feature = "iterator_step_by", since = "1.28.0")]
145impl<I> ExactSizeIterator for StepBy<I> where I: ExactSizeIterator {}
146
147// StepBy stops yielding items once the underlying iterator does, so it is fused
148// whenever the underlying iterator is fused.
149#[stable(feature = "step_by_fused", since = "1.99.0")]
150impl<I> FusedIterator for StepBy<I> where I: FusedIterator {}
151
152// SAFETY: This adapter is shortening. TrustedLen requires the upper bound to be calculated correctly.
153// These requirements can only be satisfied when the upper bound of the inner iterator's upper
154// bound is never `None`. I: TrustedRandomAccess happens to provide this guarantee while
155// I: TrustedLen would not.
156// This also covers the Range specializations since the ranges also implement TRA
157#[unstable(feature = "trusted_len", issue = "37572")]
158unsafe impl<I> TrustedLen for StepBy<I> where I: Iterator + TrustedRandomAccess {}
159
160trait SpecRangeSetup<T> {
161    fn setup(inner: T, step: usize) -> T;
162}
163
164impl<T> SpecRangeSetup<T> for T {
165    #[inline]
166    #[ferrocene::prevalidated]
167    default fn setup(inner: T, _step: usize) -> T {
168        inner
169    }
170}
171
172/// Specialization trait to optimize `StepBy<Range<{integer}>>` iteration.
173///
174/// # Safety
175///
176/// Technically this is safe to implement (look ma, no unsafe!), but in reality
177/// a lot of unsafe code relies on ranges over integers being correct.
178///
179/// For correctness *all* public StepBy methods must be specialized
180/// because `setup` drastically alters the meaning of the struct fields so that mixing
181/// different implementations would lead to incorrect results.
182unsafe trait StepByImpl<I> {
183    type Item;
184
185    fn spec_next(&mut self) -> Option<Self::Item>;
186
187    fn spec_size_hint(&self) -> (usize, Option<usize>);
188
189    fn spec_nth(&mut self, n: usize) -> Option<Self::Item>;
190
191    fn spec_try_fold<Acc, F, R>(&mut self, acc: Acc, f: F) -> R
192    where
193        F: FnMut(Acc, Self::Item) -> R,
194        R: Try<Output = Acc>;
195
196    fn spec_fold<Acc, F>(self, acc: Acc, f: F) -> Acc
197    where
198        F: FnMut(Acc, Self::Item) -> Acc;
199}
200
201/// Specialization trait for double-ended iteration.
202///
203/// See also: `StepByImpl`
204///
205/// # Safety
206///
207/// The specializations must be implemented together with `StepByImpl`
208/// where applicable. I.e. if `StepBy` does support backwards iteration
209/// for a given iterator and that is specialized for forward iteration then
210/// it must also be specialized for backwards iteration.
211unsafe trait StepByBackImpl<I> {
212    type Item;
213
214    fn spec_next_back(&mut self) -> Option<Self::Item>
215    where
216        I: DoubleEndedIterator + ExactSizeIterator;
217
218    fn spec_nth_back(&mut self, n: usize) -> Option<Self::Item>
219    where
220        I: DoubleEndedIterator + ExactSizeIterator;
221
222    fn spec_try_rfold<Acc, F, R>(&mut self, init: Acc, f: F) -> R
223    where
224        I: DoubleEndedIterator + ExactSizeIterator,
225        F: FnMut(Acc, Self::Item) -> R,
226        R: Try<Output = Acc>;
227
228    fn spec_rfold<Acc, F>(self, init: Acc, f: F) -> Acc
229    where
230        I: DoubleEndedIterator + ExactSizeIterator,
231        F: FnMut(Acc, Self::Item) -> Acc;
232}
233
234unsafe impl<I: Iterator> StepByImpl<I> for StepBy<I> {
235    type Item = I::Item;
236
237    #[inline]
238    #[ferrocene::prevalidated]
239    default fn spec_next(&mut self) -> Option<I::Item> {
240        let step_size = if self.first_take { 0 } else { self.step_minus_one };
241        self.first_take = false;
242        self.iter.nth(step_size)
243    }
244
245    #[inline]
246    #[ferrocene::prevalidated]
247    default fn spec_size_hint(&self) -> (usize, Option<usize>) {
248        #[inline]
249        #[ferrocene::prevalidated]
250        fn first_size(step: NonZero<usize>) -> impl Fn(usize) -> usize {
251            move |n| if n == 0 { 0 } else { 1 + (n - 1) / step }
252        }
253
254        #[inline]
255        #[ferrocene::prevalidated]
256        fn other_size(step: NonZero<usize>) -> impl Fn(usize) -> usize {
257            move |n| n / step
258        }
259
260        let (low, high) = self.iter.size_hint();
261
262        if self.first_take {
263            let f = first_size(self.original_step());
264            (f(low), high.map(f))
265        } else {
266            let f = other_size(self.original_step());
267            (f(low), high.map(f))
268        }
269    }
270
271    #[inline]
272    #[ferrocene::prevalidated]
273    default fn spec_nth(&mut self, mut n: usize) -> Option<I::Item> {
274        if self.first_take {
275            self.first_take = false;
276            let first = self.iter.next()?;
277            if n == 0 {
278                return Some(first);
279            }
280            n -= 1;
281        }
282        // n and self.step_minus_one are indices, we need to add 1 to get the amount of elements
283        // When calling `.nth`, we need to subtract 1 again to convert back to an index
284        let mut step = self.original_step().get();
285        // n + 1 could overflow
286        // thus, if n is usize::MAX, instead of adding one, we call .nth(step)
287        if n == usize::MAX {
288            self.iter.nth(step - 1)?;
289        } else {
290            n += 1;
291        }
292
293        // overflow handling
294        loop {
295            let mul = n.checked_mul(step);
296            {
297                if intrinsics::likely(mul.is_some()) {
298                    return self.iter.nth(mul.unwrap() - 1);
299                }
300            }
301            let div_n = usize::MAX / n;
302            let div_step = usize::MAX / step;
303            let nth_n = div_n * n;
304            let nth_step = div_step * step;
305            let nth = if nth_n > nth_step {
306                step -= div_n;
307                nth_n
308            } else {
309                n -= div_step;
310                nth_step
311            };
312
313            self.iter.nth(nth - 1)?;
314        }
315    }
316
317    #[ferrocene::prevalidated]
318    default fn spec_try_fold<Acc, F, R>(&mut self, mut acc: Acc, mut f: F) -> R
319    where
320        F: FnMut(Acc, Self::Item) -> R,
321        R: Try<Output = Acc>,
322    {
323        #[inline]
324        #[ferrocene::prevalidated]
325        fn nth<I: Iterator>(
326            iter: &mut I,
327            step_minus_one: usize,
328        ) -> impl FnMut() -> Option<I::Item> + '_ {
329            move || iter.nth(step_minus_one)
330        }
331
332        if self.first_take {
333            self.first_take = false;
334            match self.iter.next() {
335                None => return try { acc },
336                Some(x) => acc = f(acc, x)?,
337            }
338        }
339        from_fn(nth(&mut self.iter, self.step_minus_one)).try_fold(acc, f)
340    }
341
342    #[ferrocene::prevalidated]
343    default fn spec_fold<Acc, F>(mut self, mut acc: Acc, mut f: F) -> Acc
344    where
345        F: FnMut(Acc, Self::Item) -> Acc,
346    {
347        #[inline]
348        #[ferrocene::prevalidated]
349        fn nth<I: Iterator>(
350            iter: &mut I,
351            step_minus_one: usize,
352        ) -> impl FnMut() -> Option<I::Item> + '_ {
353            move || iter.nth(step_minus_one)
354        }
355
356        if self.first_take {
357            self.first_take = false;
358            match self.iter.next() {
359                None => return acc,
360                Some(x) => acc = f(acc, x),
361            }
362        }
363        from_fn(nth(&mut self.iter, self.step_minus_one)).fold(acc, f)
364    }
365}
366
367unsafe impl<I: DoubleEndedIterator + ExactSizeIterator> StepByBackImpl<I> for StepBy<I> {
368    type Item = I::Item;
369
370    #[inline]
371    default fn spec_next_back(&mut self) -> Option<Self::Item> {
372        self.iter.nth_back(self.next_back_index())
373    }
374
375    #[inline]
376    default fn spec_nth_back(&mut self, n: usize) -> Option<I::Item> {
377        // `self.iter.nth_back(usize::MAX)` does the right thing here when `n`
378        // is out of bounds because the length of `self.iter` does not exceed
379        // `usize::MAX` (because `I: ExactSizeIterator`) and `nth_back` is
380        // zero-indexed
381        let n = n.saturating_mul(self.original_step().get()).saturating_add(self.next_back_index());
382        self.iter.nth_back(n)
383    }
384
385    default fn spec_try_rfold<Acc, F, R>(&mut self, init: Acc, mut f: F) -> R
386    where
387        F: FnMut(Acc, Self::Item) -> R,
388        R: Try<Output = Acc>,
389    {
390        #[inline]
391        fn nth_back<I: DoubleEndedIterator>(
392            iter: &mut I,
393            step_minus_one: usize,
394        ) -> impl FnMut() -> Option<I::Item> + '_ {
395            move || iter.nth_back(step_minus_one)
396        }
397
398        match self.next_back() {
399            None => try { init },
400            Some(x) => {
401                let acc = f(init, x)?;
402                from_fn(nth_back(&mut self.iter, self.step_minus_one)).try_fold(acc, f)
403            }
404        }
405    }
406
407    #[inline]
408    default fn spec_rfold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc
409    where
410        Self: Sized,
411        F: FnMut(Acc, I::Item) -> Acc,
412    {
413        #[inline]
414        fn nth_back<I: DoubleEndedIterator>(
415            iter: &mut I,
416            step_minus_one: usize,
417        ) -> impl FnMut() -> Option<I::Item> + '_ {
418            move || iter.nth_back(step_minus_one)
419        }
420
421        match self.next_back() {
422            None => init,
423            Some(x) => {
424                let acc = f(init, x);
425                from_fn(nth_back(&mut self.iter, self.step_minus_one)).fold(acc, f)
426            }
427        }
428    }
429}
430
431/// For these implementations, `SpecRangeSetup` calculates the number
432/// of iterations that will be needed and stores that in `iter.end`.
433///
434/// The various iterator implementations then rely on that to not need
435/// overflow checking, letting loops just be counted instead.
436///
437/// These only work for unsigned types, and will need to be reworked
438/// if you want to use it to specialize on signed types.
439///
440/// Currently these are only implemented for integers up to `usize` due to
441/// correctness issues around `ExactSizeIterator` impls on 16bit platforms.
442/// And since `ExactSizeIterator` is a prerequisite for backwards iteration
443/// and we must consistently specialize backwards and forwards iteration
444/// that makes the situation complicated enough that it's not covered
445/// for now.
446///
447/// After `SpecRangeSetup::setup`, both `Range<T>` and its new-range wrapper
448/// `RangeIter<T>` carry the cursor and countdown in the same underlying legacy
449/// `Range`. This accessor exposes that shared range so one specialization can
450/// serve both: it is an identity for `Range<T>` and unwraps the newtype for
451/// `RangeIter<T>`, so it compiles away.
452trait AsLegacyRange<T> {
453    fn as_legacy_range(&self) -> &Range<T>;
454    fn as_legacy_range_mut(&mut self) -> &mut Range<T>;
455}
456
457impl<T> AsLegacyRange<T> for Range<T> {
458    #[inline]
459    #[ferrocene::prevalidated]
460    fn as_legacy_range(&self) -> &Range<T> {
461        self
462    }
463    #[inline]
464    #[ferrocene::prevalidated]
465    fn as_legacy_range_mut(&mut self) -> &mut Range<T> {
466        self
467    }
468}
469
470impl<T> AsLegacyRange<T> for RangeIter<T> {
471    #[inline]
472    #[ferrocene::prevalidated]
473    fn as_legacy_range(&self) -> &Range<T> {
474        &self.0
475    }
476    #[inline]
477    #[ferrocene::prevalidated]
478    fn as_legacy_range_mut(&mut self) -> &mut Range<T> {
479        &mut self.0
480    }
481}
482
483macro_rules! spec_int_ranges {
484    ($ctor:ident; $($t:ty)*) => ($(
485
486        const _: () = assert!(usize::BITS >= <$t>::BITS);
487
488        impl SpecRangeSetup<$ctor<$t>> for $ctor<$t> {
489            #[inline]
490            #[ferrocene::prevalidated]
491            fn setup(mut r: $ctor<$t>, step: usize) -> $ctor<$t> {
492                let inner_len = r.size_hint().0;
493                // If step exceeds $t::MAX, then the count will be at most 1 and
494                // thus always fit into $t.
495                let yield_count = inner_len.div_ceil(step);
496                // Turn the range end into an iteration counter
497                r.as_legacy_range_mut().end = yield_count as $t;
498                r
499            }
500        }
501
502        unsafe impl StepByImpl<$ctor<$t>> for StepBy<$ctor<$t>> {
503            #[inline]
504            #[ferrocene::prevalidated]
505            fn spec_next(&mut self) -> Option<$t> {
506                // if a step size larger than the type has been specified fall back to
507                // t::MAX, in which case remaining will be at most 1.
508                let step = <$t>::try_from(self.original_step().get()).unwrap_or(<$t>::MAX);
509                let r = self.iter.as_legacy_range_mut();
510                let remaining = r.end;
511                if remaining > 0 {
512                    let val = r.start;
513                    // this can only overflow during the last step, after which the value
514                    // will not be used
515                    r.start = val.wrapping_add(step);
516                    r.end = remaining - 1;
517                    Some(val)
518                } else {
519                    None
520                }
521            }
522
523            #[inline]
524            #[ferrocene::prevalidated]
525            fn spec_size_hint(&self) -> (usize, Option<usize>) {
526                let remaining = self.iter.as_legacy_range().end as usize;
527                (remaining, Some(remaining))
528            }
529
530            // The methods below are all copied from the Iterator trait default impls.
531            // We have to repeat them here so that the specialization overrides the StepByImpl defaults
532
533            #[inline]
534            #[ferrocene::prevalidated]
535            fn spec_nth(&mut self, n: usize) -> Option<Self::Item> {
536                self.advance_by(n).ok()?;
537                self.next()
538            }
539
540            #[inline]
541            #[ferrocene::prevalidated]
542            fn spec_try_fold<Acc, F, R>(&mut self, init: Acc, mut f: F) -> R
543                where
544                    F: FnMut(Acc, Self::Item) -> R,
545                    R: Try<Output = Acc>
546            {
547                let mut accum = init;
548                while let Some(x) = self.next() {
549                    accum = f(accum, x)?;
550                }
551                try { accum }
552            }
553
554            #[inline]
555            #[ferrocene::prevalidated]
556            fn spec_fold<Acc, F>(self, init: Acc, mut f: F) -> Acc
557                where
558                    F: FnMut(Acc, Self::Item) -> Acc
559            {
560                // if a step size larger than the type has been specified fall back to
561                // t::MAX, in which case remaining will be at most 1.
562                let step = <$t>::try_from(self.original_step().get()).unwrap_or(<$t>::MAX);
563                let r = self.iter.as_legacy_range();
564                let remaining = r.end;
565                let mut acc = init;
566                let mut val = r.start;
567                for _ in 0..remaining {
568                    acc = f(acc, val);
569                    // this can only overflow during the last step, after which the value
570                    // will no longer be used
571                    val = val.wrapping_add(step);
572                }
573                acc
574            }
575        }
576    )*)
577}
578
579macro_rules! spec_int_ranges_r {
580    ($ctor:ident; $($t:ty)*) => ($(
581        const _: () = assert!(usize::BITS >= <$t>::BITS);
582
583        unsafe impl StepByBackImpl<$ctor<$t>> for StepBy<$ctor<$t>> {
584
585            #[inline]
586            fn spec_next_back(&mut self) -> Option<Self::Item> {
587                let step = self.original_step().get() as $t;
588                let r = self.iter.as_legacy_range_mut();
589                let remaining = r.end;
590                if remaining > 0 {
591                    let start = r.start;
592                    r.end = remaining - 1;
593                    Some(start + step * (remaining - 1))
594                } else {
595                    None
596                }
597            }
598
599            // The methods below are all copied from the Iterator trait default impls.
600            // We have to repeat them here so that the specialization overrides the StepByImplBack defaults
601
602            #[inline]
603            fn spec_nth_back(&mut self, n: usize) -> Option<Self::Item> {
604                if self.advance_back_by(n).is_err() {
605                    return None;
606                }
607                self.next_back()
608            }
609
610            #[inline]
611            fn spec_try_rfold<Acc, F, R>(&mut self, init: Acc, mut f: F) -> R
612            where
613                F: FnMut(Acc, Self::Item) -> R,
614                R: Try<Output = Acc>
615            {
616                let mut accum = init;
617                while let Some(x) = self.next_back() {
618                    accum = f(accum, x)?;
619                }
620                try { accum }
621            }
622
623            #[inline]
624            fn spec_rfold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc
625            where
626                F: FnMut(Acc, Self::Item) -> Acc
627            {
628                let mut accum = init;
629                while let Some(x) = self.next_back() {
630                    accum = f(accum, x);
631                }
632                accum
633            }
634        }
635    )*)
636}
637
638// The same specialization covers `Range<{integer}>` and the new-range iterator
639// `RangeIter<{integer}>`, which wraps a `Range` (see `AsLegacyRange`).
640//
641// The backward (`_r`) specialization requires `ExactSizeIterator`. `RangeIter`
642// implements it only for `usize`/`u8`/`u16` (see `range_exact_iter_impl!` in
643// `range::iter`), narrower than `Range`, so `RangeIter`'s backward set omits
644// `u32` even where `Range` includes it; `Range<u64>` is likewise omitted on
645// 64-bit since its length can exceed `usize`.
646#[cfg(target_pointer_width = "64")]
647mod step_by_spec {
648    use super::*;
649    spec_int_ranges!(Range; u8 u16 u32 u64 usize);
650    spec_int_ranges!(RangeIter; u8 u16 u32 u64 usize);
651    spec_int_ranges_r!(Range; u8 u16 u32 usize);
652    spec_int_ranges_r!(RangeIter; u8 u16 usize);
653}
654
655#[cfg(target_pointer_width = "32")]
656mod step_by_spec {
657    use super::*;
658    spec_int_ranges!(Range; u8 u16 u32 usize);
659    spec_int_ranges!(RangeIter; u8 u16 u32 usize);
660    spec_int_ranges_r!(Range; u8 u16 u32 usize);
661    spec_int_ranges_r!(RangeIter; u8 u16 usize);
662}
663
664#[cfg(target_pointer_width = "16")]
665mod step_by_spec {
666    use super::*;
667    spec_int_ranges!(Range; u8 u16 usize);
668    spec_int_ranges!(RangeIter; u8 u16 usize);
669    spec_int_ranges_r!(Range; u8 u16 usize);
670    spec_int_ranges_r!(RangeIter; u8 u16 usize);
671}