Skip to content

Commit dcc9c46

Browse files
committed
iter: extend step_by specialization to cover StepBy<RangeIter<{integer}>>
Signed-off-by: 林晨 (Leo Cheng) <leo-cheng@vip.qq.com>
1 parent b960fcf commit dcc9c46

3 files changed

Lines changed: 122 additions & 28 deletions

File tree

library/core/src/iter/adapters/step_by.rs

Lines changed: 83 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use crate::intrinsics;
22
use crate::iter::{TrustedLen, TrustedRandomAccess, from_fn};
33
use crate::num::NonZero;
44
use crate::ops::{Range, Try};
5+
use crate::range::RangeIter;
56

67
/// An iterator for stepping iterators by a custom amount.
78
///
@@ -418,37 +419,71 @@ unsafe impl<I: DoubleEndedIterator + ExactSizeIterator> StepByBackImpl<I> for St
418419
/// and we must consistently specialize backwards and forwards iteration
419420
/// that makes the situation complicated enough that it's not covered
420421
/// for now.
422+
///
423+
/// After `SpecRangeSetup::setup`, both `Range<T>` and its new-range wrapper
424+
/// `RangeIter<T>` carry the cursor and countdown in the same underlying legacy
425+
/// `Range`. This accessor exposes that shared range so one specialization can
426+
/// serve both: it is an identity for `Range<T>` and unwraps the newtype for
427+
/// `RangeIter<T>`, so it compiles away.
428+
trait AsLegacyRange<T> {
429+
fn as_legacy_range(&self) -> &Range<T>;
430+
fn as_legacy_range_mut(&mut self) -> &mut Range<T>;
431+
}
432+
433+
impl<T> AsLegacyRange<T> for Range<T> {
434+
#[inline]
435+
fn as_legacy_range(&self) -> &Range<T> {
436+
self
437+
}
438+
#[inline]
439+
fn as_legacy_range_mut(&mut self) -> &mut Range<T> {
440+
self
441+
}
442+
}
443+
444+
impl<T> AsLegacyRange<T> for RangeIter<T> {
445+
#[inline]
446+
fn as_legacy_range(&self) -> &Range<T> {
447+
&self.0
448+
}
449+
#[inline]
450+
fn as_legacy_range_mut(&mut self) -> &mut Range<T> {
451+
&mut self.0
452+
}
453+
}
454+
421455
macro_rules! spec_int_ranges {
422-
($($t:ty)*) => ($(
456+
($ctor:ident; $($t:ty)*) => ($(
423457

424458
const _: () = assert!(usize::BITS >= <$t>::BITS);
425459

426-
impl SpecRangeSetup<Range<$t>> for Range<$t> {
460+
impl SpecRangeSetup<$ctor<$t>> for $ctor<$t> {
427461
#[inline]
428-
fn setup(mut r: Range<$t>, step: usize) -> Range<$t> {
462+
fn setup(mut r: $ctor<$t>, step: usize) -> $ctor<$t> {
429463
let inner_len = r.size_hint().0;
430464
// If step exceeds $t::MAX, then the count will be at most 1 and
431465
// thus always fit into $t.
432466
let yield_count = inner_len.div_ceil(step);
433467
// Turn the range end into an iteration counter
434-
r.end = yield_count as $t;
468+
r.as_legacy_range_mut().end = yield_count as $t;
435469
r
436470
}
437471
}
438472

439-
unsafe impl StepByImpl<Range<$t>> for StepBy<Range<$t>> {
473+
unsafe impl StepByImpl<$ctor<$t>> for StepBy<$ctor<$t>> {
440474
#[inline]
441475
fn spec_next(&mut self) -> Option<$t> {
442476
// if a step size larger than the type has been specified fall back to
443477
// t::MAX, in which case remaining will be at most 1.
444478
let step = <$t>::try_from(self.original_step().get()).unwrap_or(<$t>::MAX);
445-
let remaining = self.iter.end;
479+
let r = self.iter.as_legacy_range_mut();
480+
let remaining = r.end;
446481
if remaining > 0 {
447-
let val = self.iter.start;
482+
let val = r.start;
448483
// this can only overflow during the last step, after which the value
449484
// will not be used
450-
self.iter.start = val.wrapping_add(step);
451-
self.iter.end = remaining - 1;
485+
r.start = val.wrapping_add(step);
486+
r.end = remaining - 1;
452487
Some(val)
453488
} else {
454489
None
@@ -457,7 +492,7 @@ macro_rules! spec_int_ranges {
457492

458493
#[inline]
459494
fn spec_size_hint(&self) -> (usize, Option<usize>) {
460-
let remaining = self.iter.end as usize;
495+
let remaining = self.iter.as_legacy_range().end as usize;
461496
(remaining, Some(remaining))
462497
}
463498

@@ -491,9 +526,10 @@ macro_rules! spec_int_ranges {
491526
// if a step size larger than the type has been specified fall back to
492527
// t::MAX, in which case remaining will be at most 1.
493528
let step = <$t>::try_from(self.original_step().get()).unwrap_or(<$t>::MAX);
494-
let remaining = self.iter.end;
529+
let r = self.iter.as_legacy_range();
530+
let remaining = r.end;
495531
let mut acc = init;
496-
let mut val = self.iter.start;
532+
let mut val = r.start;
497533
for _ in 0..remaining {
498534
acc = f(acc, val);
499535
// this can only overflow during the last step, after which the value
@@ -507,18 +543,19 @@ macro_rules! spec_int_ranges {
507543
}
508544

509545
macro_rules! spec_int_ranges_r {
510-
($($t:ty)*) => ($(
546+
($ctor:ident; $($t:ty)*) => ($(
511547
const _: () = assert!(usize::BITS >= <$t>::BITS);
512548

513-
unsafe impl StepByBackImpl<Range<$t>> for StepBy<Range<$t>> {
549+
unsafe impl StepByBackImpl<$ctor<$t>> for StepBy<$ctor<$t>> {
514550

515551
#[inline]
516552
fn spec_next_back(&mut self) -> Option<Self::Item> {
517553
let step = self.original_step().get() as $t;
518-
let remaining = self.iter.end;
554+
let r = self.iter.as_legacy_range_mut();
555+
let remaining = r.end;
519556
if remaining > 0 {
520-
let start = self.iter.start;
521-
self.iter.end = remaining - 1;
557+
let start = r.start;
558+
r.end = remaining - 1;
522559
Some(start + step * (remaining - 1))
523560
} else {
524561
None
@@ -564,18 +601,37 @@ macro_rules! spec_int_ranges_r {
564601
)*)
565602
}
566603

604+
// The same specialization covers `Range<{integer}>` and the new-range iterator
605+
// `RangeIter<{integer}>`, which wraps a `Range` (see `AsLegacyRange`).
606+
//
607+
// The backward (`_r`) specialization requires `ExactSizeIterator`. `RangeIter`
608+
// implements it only for `usize`/`u8`/`u16` (see `range_exact_iter_impl!` in
609+
// `range::iter`), narrower than `Range`, so `RangeIter`'s backward set omits
610+
// `u32` even where `Range` includes it; `Range<u64>` is likewise omitted on
611+
// 64-bit since its length can exceed `usize`.
567612
#[cfg(target_pointer_width = "64")]
568-
spec_int_ranges!(u8 u16 u32 u64 usize);
569-
// DoubleEndedIterator requires ExactSizeIterator, which isn't implemented for Range<u64>
570-
#[cfg(target_pointer_width = "64")]
571-
spec_int_ranges_r!(u8 u16 u32 usize);
613+
mod step_by_spec {
614+
use super::*;
615+
spec_int_ranges!(Range; u8 u16 u32 u64 usize);
616+
spec_int_ranges!(RangeIter; u8 u16 u32 u64 usize);
617+
spec_int_ranges_r!(Range; u8 u16 u32 usize);
618+
spec_int_ranges_r!(RangeIter; u8 u16 usize);
619+
}
572620

573621
#[cfg(target_pointer_width = "32")]
574-
spec_int_ranges!(u8 u16 u32 usize);
575-
#[cfg(target_pointer_width = "32")]
576-
spec_int_ranges_r!(u8 u16 u32 usize);
622+
mod step_by_spec {
623+
use super::*;
624+
spec_int_ranges!(Range; u8 u16 u32 usize);
625+
spec_int_ranges!(RangeIter; u8 u16 u32 usize);
626+
spec_int_ranges_r!(Range; u8 u16 u32 usize);
627+
spec_int_ranges_r!(RangeIter; u8 u16 usize);
628+
}
577629

578630
#[cfg(target_pointer_width = "16")]
579-
spec_int_ranges!(u8 u16 usize);
580-
#[cfg(target_pointer_width = "16")]
581-
spec_int_ranges_r!(u8 u16 usize);
631+
mod step_by_spec {
632+
use super::*;
633+
spec_int_ranges!(Range; u8 u16 usize);
634+
spec_int_ranges!(RangeIter; u8 u16 usize);
635+
spec_int_ranges_r!(Range; u8 u16 usize);
636+
spec_int_ranges_r!(RangeIter; u8 u16 usize);
637+
}

library/core/src/range/iter.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use crate::{intrinsics, mem};
88
/// By-value [`Range`] iterator.
99
#[stable(feature = "new_range_api", since = "1.96.0")]
1010
#[derive(Debug, Clone)]
11-
pub struct RangeIter<A>(legacy::Range<A>);
11+
pub struct RangeIter<A>(pub(crate) legacy::Range<A>);
1212

1313
impl<A> RangeIter<A> {
1414
#[unstable(feature = "new_range_remainder", issue = "154458")]

library/coretests/tests/iter/adapters/step_by.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,3 +299,41 @@ fn test_step_by_fold_range_specialization() {
299299
assert_eq!(r.sum::<usize>(), usize::MAX - 1);
300300
});
301301
}
302+
303+
#[test]
304+
fn test_step_by_new_range_iter() {
305+
use core::range::Range as NewRange;
306+
307+
// forward iteration
308+
let v: Vec<u32> = NewRange::from(0_u32..10).into_iter().step_by(3).collect();
309+
assert_eq!(v, [0, 3, 6, 9]);
310+
311+
// size_hint
312+
assert_eq!(NewRange::from(0_u32..10).into_iter().step_by(3).size_hint(), (4, Some(4)));
313+
assert_eq!(NewRange::from(0_u32..9).into_iter().step_by(3).size_hint(), (3, Some(3)));
314+
315+
// nth
316+
assert_eq!(NewRange::from(0_u32..20).into_iter().step_by(5).nth(2), Some(10));
317+
318+
// empty range
319+
assert_eq!(NewRange::from(5_u32..5).into_iter().step_by(1).next(), None);
320+
321+
// step larger than range
322+
assert_eq!(NewRange::from(0_u32..3).into_iter().step_by(10).collect::<Vec<_>>(), [0]);
323+
324+
// backward iteration (usize has ExactSizeIterator)
325+
let mut it = NewRange::from(0_usize..11).into_iter().step_by(3);
326+
assert_eq!(it.next_back(), Some(9));
327+
assert_eq!(it.next_back(), Some(6));
328+
assert_eq!(it.next_back(), Some(3));
329+
assert_eq!(it.next_back(), Some(0));
330+
assert_eq!(it.next_back(), None);
331+
332+
// interleaved forward and backward
333+
let mut it = NewRange::from(0_usize..16).into_iter().step_by(5);
334+
assert_eq!(it.next(), Some(0));
335+
assert_eq!(it.next_back(), Some(15));
336+
assert_eq!(it.next(), Some(5));
337+
assert_eq!(it.next_back(), Some(10));
338+
assert_eq!(it.next(), None);
339+
}

0 commit comments

Comments
 (0)