1use crate::intrinsics;
2use crate::iter::{TrustedLen, TrustedRandomAccess, from_fn};
3use crate::num::NonZero;
4use crate::ops::{Range, Try};
5
6#[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 iter: I,
25 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 #[inline]
45 #[ferrocene::prevalidated]
46 fn original_step(&self) -> NonZero<usize> {
47 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 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#[stable(feature = "iterator_step_by", since = "1.28.0")]
144impl<I> ExactSizeIterator for StepBy<I> where I: ExactSizeIterator {}
145
146#[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
166unsafe 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
195unsafe 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 let mut step = self.original_step().get();
279 if n == usize::MAX {
282 self.iter.nth(step - 1);
283 } else {
284 n += 1;
285 }
286
287 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 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
424macro_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 let yield_count = inner_len.div_ceil(step);
452 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 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 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 #[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 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 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 #[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#[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);