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#[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#[stable(feature = "step_by_fused", since = "1.99.0")]
150impl<I> FusedIterator for StepBy<I> where I: FusedIterator {}
151
152#[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
172unsafe 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
201unsafe 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 let mut step = self.original_step().get();
285 if n == usize::MAX {
288 self.iter.nth(step - 1)?;
289 } else {
290 n += 1;
291 }
292
293 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 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
431trait 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 let yield_count = inner_len.div_ceil(step);
496 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 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 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 #[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 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 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 #[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#[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}