diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 305f32e2637..8cea98d2a21 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -306,7 +306,7 @@ use default::Default; use marker; use mem; use num::{Zero, One}; -use ops::{self, Add, Sub, FnMut, Mul, RangeFrom}; +use ops::{self, Add, Sub, FnMut, Mul}; use option::Option::{self, Some, None}; use marker::Sized; use usize; @@ -4286,7 +4286,7 @@ step_impl_no_between!(u64 i64); /// /// The resulting iterator handles overflow by stopping. The `A` /// parameter is the type being iterated over, while `R` is the range -/// type (usually one of `std::ops::{Range, RangeFrom}`. +/// type (usually one of `std::ops::{Range, RangeFrom, RangeInclusive}`. #[derive(Clone)] #[unstable(feature = "step_by", reason = "recent addition", issue = "27741")] @@ -4295,7 +4295,7 @@ pub struct StepBy { range: R, } -impl RangeFrom { +impl ops::RangeFrom { /// Creates an iterator starting at the same point, but stepping by /// the given amount at each iteration. /// @@ -4355,8 +4355,44 @@ impl ops::Range { } } +impl ops::RangeInclusive { + /// Creates an iterator with the same range, but stepping by the + /// given amount at each iteration. + /// + /// The resulting iterator handles overflow by stopping. + /// + /// # Examples + /// + /// ``` + /// #![feature(step_by, inclusive_range_syntax)] + /// + /// for i in (0...10).step_by(2) { + /// println!("{}", i); + /// } + /// ``` + /// + /// This prints: + /// + /// ```text + /// 0 + /// 2 + /// 4 + /// 6 + /// 8 + /// 10 + /// ``` + #[unstable(feature = "step_by", reason = "recent addition", + issue = "27741")] + pub fn step_by(self, by: A) -> StepBy { + StepBy { + step_by: by, + range: self + } + } +} + #[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for StepBy> where +impl Iterator for StepBy> where A: Clone, for<'a> &'a A: Add<&'a A, Output = A> { @@ -4412,6 +4448,74 @@ impl Iterator for StepBy> { } } +#[unstable(feature = "inclusive_range", + reason = "recently added, follows RFC", + issue = "28237")] +impl Iterator for StepBy> { + type Item = A; + + #[inline] + fn next(&mut self) -> Option { + use ops::RangeInclusive::*; + + // this function has a sort of odd structure due to borrowck issues + // we may need to replace self.range, so borrows of start and end need to end early + + let (finishing, n) = match self.range { + Empty { .. } => return None, // empty iterators yield no values + + NonEmpty { ref mut start, ref mut end } => { + let zero = A::zero(); + let rev = self.step_by < zero; + + // march start towards (maybe past!) end and yield the old value + if (rev && start >= end) || + (!rev && start <= end) + { + match start.step(&self.step_by) { + Some(mut n) => { + mem::swap(start, &mut n); + (None, Some(n)) // yield old value, remain non-empty + }, + None => { + let mut n = end.clone(); + mem::swap(start, &mut n); + (None, Some(n)) // yield old value, remain non-empty + } + } + } else { + // found range in inconsistent state (start at or past end), so become empty + (Some(mem::replace(end, zero)), None) + } + } + }; + + // turn into an empty iterator if we've reached the end + if let Some(end) = finishing { + self.range = Empty { at: end }; + } + + n + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + use ops::RangeInclusive::*; + + match self.range { + Empty { .. } => (0, Some(0)), + + NonEmpty { ref start, ref end } => + match Step::steps_between(start, + end, + &self.step_by) { + Some(hint) => (hint.saturating_add(1), hint.checked_add(1)), + None => (0, None) + } + } + } +} + macro_rules! range_exact_iter_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/test/run-pass/range_inclusive.rs b/src/test/run-pass/range_inclusive.rs index e64c453a3c4..c1bc6adf7b8 100644 --- a/src/test/run-pass/range_inclusive.rs +++ b/src/test/run-pass/range_inclusive.rs @@ -10,7 +10,7 @@ // Test inclusive range syntax. -#![feature(inclusive_range_syntax, inclusive_range)] +#![feature(inclusive_range_syntax, inclusive_range, step_by)] use std::ops::{RangeInclusive, RangeToInclusive}; @@ -35,14 +35,12 @@ pub fn main() { } assert_eq!(count, 55); - /* FIXME let mut count = 0; for i in (0_usize...10).step_by(2) { assert!(i >= 0 && i <= 10 && i % 2 == 0); count += i; } assert_eq!(count, 30); - */ let _ = 0_usize...4+4-3; let _ = 0...foo();