1use crate::intrinsics;
2use crate::iter::{TrustedLen, TrustedRandomAccess, from_fn};
3use crate::num::NonZero;
4use crate::ops::{Range, Try};
5use crate::range::RangeIter;
6
7#[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 iter: I,
26 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 #[inline]
46 #[ferrocene::prevalidated]
47 fn original_step(&self) -> NonZero<usize> {
48 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 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#[stable(feature = "iterator_step_by", since = "1.28.0")]
145impl<I> ExactSizeIterator for StepBy<I> where I: ExactSizeIterator {}
146
147#[unstable(feature = "trusted_len", issue = "37572")]
153unsafe impl<I> TrustedLen for StepBy<I> where I: Iterator + TrustedRandomAccess {}
154
155trait SpecRangeSetup<T> {
156 fn setup(inner: T, step: usize) -> T;
157}
158
159impl<T> SpecRangeSetup<T> for T {
160 #[inline]
161 #[ferrocene::prevalidated]
162 default fn setup(inner: T, _step: usize) -> T {
163 inner
164 }
165}
166
167unsafe trait StepByImpl<I> {
178 type Item;
179
180 fn spec_next(&mut self) -> Option<Self::Item>;
181
182 fn spec_size_hint(&self) -> (usize, Option<usize>);
183
184 fn spec_nth(&mut self, n: usize) -> Option<Self::Item>;
185
186 fn spec_try_fold<Acc, F, R>(&mut self, acc: Acc, f: F) -> R
187 where
188 F: FnMut(Acc, Self::Item) -> R,
189 R: Try<Output = Acc>;
190
191 fn spec_fold<Acc, F>(self, acc: Acc, f: F) -> Acc
192 where
193 F: FnMut(Acc, Self::Item) -> Acc;
194}
195
196unsafe trait StepByBackImpl<I> {
207 type Item;
208
209 fn spec_next_back(&mut self) -> Option<Self::Item>
210 where
211 I: DoubleEndedIterator + ExactSizeIterator;
212
213 fn spec_nth_back(&mut self, n: usize) -> Option<Self::Item>
214 where
215 I: DoubleEndedIterator + ExactSizeIterator;
216
217 fn spec_try_rfold<Acc, F, R>(&mut self, init: Acc, f: F) -> R
218 where
219 I: DoubleEndedIterator + ExactSizeIterator,
220 F: FnMut(Acc, Self::Item) -> R,
221 R: Try<Output = Acc>;
222
223 fn spec_rfold<Acc, F>(self, init: Acc, f: F) -> Acc
224 where
225 I: DoubleEndedIterator + ExactSizeIterator,
226 F: FnMut(Acc, Self::Item) -> Acc;
227}
228
229unsafe impl<I: Iterator> StepByImpl<I> for StepBy<I> {
230 type Item = I::Item;
231
232 #[inline]
233 #[ferrocene::prevalidated]
234 default fn spec_next(&mut self) -> Option<I::Item> {
235 let step_size = if self.first_take { 0 } else { self.step_minus_one };
236 self.first_take = false;
237 self.iter.nth(step_size)
238 }
239
240 #[inline]
241 #[ferrocene::prevalidated]
242 default fn spec_size_hint(&self) -> (usize, Option<usize>) {
243 #[inline]
244 #[ferrocene::prevalidated]
245 fn first_size(step: NonZero<usize>) -> impl Fn(usize) -> usize {
246 move |n| if n == 0 { 0 } else { 1 + (n - 1) / step }
247 }
248
249 #[inline]
250 #[ferrocene::prevalidated]
251 fn other_size(step: NonZero<usize>) -> impl Fn(usize) -> usize {
252 move |n| n / step
253 }
254
255 let (low, high) = self.iter.size_hint();
256
257 if self.first_take {
258 let f = first_size(self.original_step());
259 (f(low), high.map(f))
260 } else {
261 let f = other_size(self.original_step());
262 (f(low), high.map(f))
263 }
264 }
265
266 #[inline]
267 #[ferrocene::prevalidated]
268 default fn spec_nth(&mut self, mut n: usize) -> Option<I::Item> {
269 if self.first_take {
270 self.first_take = false;
271 let first = self.iter.next()?;
272 if n == 0 {
273 return Some(first);
274 }
275 n -= 1;
276 }
277 let mut step = self.original_step().get();
280 if n == usize::MAX {
283 self.iter.nth(step - 1)?;
284 } else {
285 n += 1;
286 }
287
288 loop {
290 let mul = n.checked_mul(step);
291 {
292 if intrinsics::likely(mul.is_some()) {
293 return self.iter.nth(mul.unwrap() - 1);
294 }
295 }
296 let div_n = usize::MAX / n;
297 let div_step = usize::MAX / step;
298 let nth_n = div_n * n;
299 let nth_step = div_step * step;
300 let nth = if nth_n > nth_step {
301 step -= div_n;
302 nth_n
303 } else {
304 n -= div_step;
305 nth_step
306 };
307
308 self.iter.nth(nth - 1)?;
309 }
310 }
311
312 #[ferrocene::prevalidated]
313 default fn spec_try_fold<Acc, F, R>(&mut self, mut acc: Acc, mut f: F) -> R
314 where
315 F: FnMut(Acc, Self::Item) -> R,
316 R: Try<Output = Acc>,
317 {
318 #[inline]
319 #[ferrocene::prevalidated]
320 fn nth<I: Iterator>(
321 iter: &mut I,
322 step_minus_one: usize,
323 ) -> impl FnMut() -> Option<I::Item> + '_ {
324 move || iter.nth(step_minus_one)
325 }
326
327 if self.first_take {
328 self.first_take = false;
329 match self.iter.next() {
330 None => return try { acc },
331 Some(x) => acc = f(acc, x)?,
332 }
333 }
334 from_fn(nth(&mut self.iter, self.step_minus_one)).try_fold(acc, f)
335 }
336
337 #[ferrocene::prevalidated]
338 default fn spec_fold<Acc, F>(mut self, mut acc: Acc, mut f: F) -> Acc
339 where
340 F: FnMut(Acc, Self::Item) -> Acc,
341 {
342 #[inline]
343 #[ferrocene::prevalidated]
344 fn nth<I: Iterator>(
345 iter: &mut I,
346 step_minus_one: usize,
347 ) -> impl FnMut() -> Option<I::Item> + '_ {
348 move || iter.nth(step_minus_one)
349 }
350
351 if self.first_take {
352 self.first_take = false;
353 match self.iter.next() {
354 None => return acc,
355 Some(x) => acc = f(acc, x),
356 }
357 }
358 from_fn(nth(&mut self.iter, self.step_minus_one)).fold(acc, f)
359 }
360}
361
362unsafe impl<I: DoubleEndedIterator + ExactSizeIterator> StepByBackImpl<I> for StepBy<I> {
363 type Item = I::Item;
364
365 #[inline]
366 default fn spec_next_back(&mut self) -> Option<Self::Item> {
367 self.iter.nth_back(self.next_back_index())
368 }
369
370 #[inline]
371 default fn spec_nth_back(&mut self, n: usize) -> Option<I::Item> {
372 let n = n.saturating_mul(self.original_step().get()).saturating_add(self.next_back_index());
377 self.iter.nth_back(n)
378 }
379
380 default fn spec_try_rfold<Acc, F, R>(&mut self, init: Acc, mut f: F) -> R
381 where
382 F: FnMut(Acc, Self::Item) -> R,
383 R: Try<Output = Acc>,
384 {
385 #[inline]
386 fn nth_back<I: DoubleEndedIterator>(
387 iter: &mut I,
388 step_minus_one: usize,
389 ) -> impl FnMut() -> Option<I::Item> + '_ {
390 move || iter.nth_back(step_minus_one)
391 }
392
393 match self.next_back() {
394 None => try { init },
395 Some(x) => {
396 let acc = f(init, x)?;
397 from_fn(nth_back(&mut self.iter, self.step_minus_one)).try_fold(acc, f)
398 }
399 }
400 }
401
402 #[inline]
403 default fn spec_rfold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc
404 where
405 Self: Sized,
406 F: FnMut(Acc, I::Item) -> Acc,
407 {
408 #[inline]
409 fn nth_back<I: DoubleEndedIterator>(
410 iter: &mut I,
411 step_minus_one: usize,
412 ) -> impl FnMut() -> Option<I::Item> + '_ {
413 move || iter.nth_back(step_minus_one)
414 }
415
416 match self.next_back() {
417 None => init,
418 Some(x) => {
419 let acc = f(init, x);
420 from_fn(nth_back(&mut self.iter, self.step_minus_one)).fold(acc, f)
421 }
422 }
423 }
424}
425
426trait AsLegacyRange<T> {
448 fn as_legacy_range(&self) -> &Range<T>;
449 fn as_legacy_range_mut(&mut self) -> &mut Range<T>;
450}
451
452impl<T> AsLegacyRange<T> for Range<T> {
453 #[inline]
454 #[ferrocene::prevalidated]
455 fn as_legacy_range(&self) -> &Range<T> {
456 self
457 }
458 #[inline]
459 #[ferrocene::prevalidated]
460 fn as_legacy_range_mut(&mut self) -> &mut Range<T> {
461 self
462 }
463}
464
465impl<T> AsLegacyRange<T> for RangeIter<T> {
466 #[inline]
467 #[ferrocene::prevalidated]
468 fn as_legacy_range(&self) -> &Range<T> {
469 &self.0
470 }
471 #[inline]
472 #[ferrocene::prevalidated]
473 fn as_legacy_range_mut(&mut self) -> &mut Range<T> {
474 &mut self.0
475 }
476}
477
478macro_rules! spec_int_ranges {
479 ($ctor:ident; $($t:ty)*) => ($(
480
481 const _: () = assert!(usize::BITS >= <$t>::BITS);
482
483 impl SpecRangeSetup<$ctor<$t>> for $ctor<$t> {
484 #[inline]
485 #[ferrocene::prevalidated]
486 fn setup(mut r: $ctor<$t>, step: usize) -> $ctor<$t> {
487 let inner_len = r.size_hint().0;
488 let yield_count = inner_len.div_ceil(step);
491 r.as_legacy_range_mut().end = yield_count as $t;
493 r
494 }
495 }
496
497 unsafe impl StepByImpl<$ctor<$t>> for StepBy<$ctor<$t>> {
498 #[inline]
499 #[ferrocene::prevalidated]
500 fn spec_next(&mut self) -> Option<$t> {
501 let step = <$t>::try_from(self.original_step().get()).unwrap_or(<$t>::MAX);
504 let r = self.iter.as_legacy_range_mut();
505 let remaining = r.end;
506 if remaining > 0 {
507 let val = r.start;
508 r.start = val.wrapping_add(step);
511 r.end = remaining - 1;
512 Some(val)
513 } else {
514 None
515 }
516 }
517
518 #[inline]
519 #[ferrocene::prevalidated]
520 fn spec_size_hint(&self) -> (usize, Option<usize>) {
521 let remaining = self.iter.as_legacy_range().end as usize;
522 (remaining, Some(remaining))
523 }
524
525 #[inline]
529 #[ferrocene::prevalidated]
530 fn spec_nth(&mut self, n: usize) -> Option<Self::Item> {
531 self.advance_by(n).ok()?;
532 self.next()
533 }
534
535 #[inline]
536 #[ferrocene::prevalidated]
537 fn spec_try_fold<Acc, F, R>(&mut self, init: Acc, mut f: F) -> R
538 where
539 F: FnMut(Acc, Self::Item) -> R,
540 R: Try<Output = Acc>
541 {
542 let mut accum = init;
543 while let Some(x) = self.next() {
544 accum = f(accum, x)?;
545 }
546 try { accum }
547 }
548
549 #[inline]
550 #[ferrocene::prevalidated]
551 fn spec_fold<Acc, F>(self, init: Acc, mut f: F) -> Acc
552 where
553 F: FnMut(Acc, Self::Item) -> Acc
554 {
555 let step = <$t>::try_from(self.original_step().get()).unwrap_or(<$t>::MAX);
558 let r = self.iter.as_legacy_range();
559 let remaining = r.end;
560 let mut acc = init;
561 let mut val = r.start;
562 for _ in 0..remaining {
563 acc = f(acc, val);
564 val = val.wrapping_add(step);
567 }
568 acc
569 }
570 }
571 )*)
572}
573
574macro_rules! spec_int_ranges_r {
575 ($ctor:ident; $($t:ty)*) => ($(
576 const _: () = assert!(usize::BITS >= <$t>::BITS);
577
578 unsafe impl StepByBackImpl<$ctor<$t>> for StepBy<$ctor<$t>> {
579
580 #[inline]
581 fn spec_next_back(&mut self) -> Option<Self::Item> {
582 let step = self.original_step().get() as $t;
583 let r = self.iter.as_legacy_range_mut();
584 let remaining = r.end;
585 if remaining > 0 {
586 let start = r.start;
587 r.end = remaining - 1;
588 Some(start + step * (remaining - 1))
589 } else {
590 None
591 }
592 }
593
594 #[inline]
598 fn spec_nth_back(&mut self, n: usize) -> Option<Self::Item> {
599 if self.advance_back_by(n).is_err() {
600 return None;
601 }
602 self.next_back()
603 }
604
605 #[inline]
606 fn spec_try_rfold<Acc, F, R>(&mut self, init: Acc, mut f: F) -> R
607 where
608 F: FnMut(Acc, Self::Item) -> R,
609 R: Try<Output = Acc>
610 {
611 let mut accum = init;
612 while let Some(x) = self.next_back() {
613 accum = f(accum, x)?;
614 }
615 try { accum }
616 }
617
618 #[inline]
619 fn spec_rfold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc
620 where
621 F: FnMut(Acc, Self::Item) -> Acc
622 {
623 let mut accum = init;
624 while let Some(x) = self.next_back() {
625 accum = f(accum, x);
626 }
627 accum
628 }
629 }
630 )*)
631}
632
633#[cfg(target_pointer_width = "64")]
642mod step_by_spec {
643 use super::*;
644 spec_int_ranges!(Range; u8 u16 u32 u64 usize);
645 spec_int_ranges!(RangeIter; u8 u16 u32 u64 usize);
646 spec_int_ranges_r!(Range; u8 u16 u32 usize);
647 spec_int_ranges_r!(RangeIter; u8 u16 usize);
648}
649
650#[cfg(target_pointer_width = "32")]
651mod step_by_spec {
652 use super::*;
653 spec_int_ranges!(Range; u8 u16 u32 usize);
654 spec_int_ranges!(RangeIter; u8 u16 u32 usize);
655 spec_int_ranges_r!(Range; u8 u16 u32 usize);
656 spec_int_ranges_r!(RangeIter; u8 u16 usize);
657}
658
659#[cfg(target_pointer_width = "16")]
660mod step_by_spec {
661 use super::*;
662 spec_int_ranges!(Range; u8 u16 usize);
663 spec_int_ranges!(RangeIter; u8 u16 usize);
664 spec_int_ranges_r!(Range; u8 u16 usize);
665 spec_int_ranges_r!(RangeIter; u8 u16 usize);
666}