Skip to main content

core/iter/adapters/
step_by.rs

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