Skip to content

Commit b1b4f50

Browse files
committed
add StepBy for RangeInclusive
1 parent 24cc902 commit b1b4f50

File tree

2 files changed

+109
-7
lines changed

2 files changed

+109
-7
lines changed

src/libcore/iter.rs

Lines changed: 108 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ use default::Default;
306306
use marker;
307307
use mem;
308308
use num::{Zero, One};
309-
use ops::{self, Add, Sub, FnMut, Mul, RangeFrom};
309+
use ops::{self, Add, Sub, FnMut, Mul};
310310
use option::Option::{self, Some, None};
311311
use marker::Sized;
312312
use usize;
@@ -4286,7 +4286,7 @@ step_impl_no_between!(u64 i64);
42864286
///
42874287
/// The resulting iterator handles overflow by stopping. The `A`
42884288
/// parameter is the type being iterated over, while `R` is the range
4289-
/// type (usually one of `std::ops::{Range, RangeFrom}`.
4289+
/// type (usually one of `std::ops::{Range, RangeFrom, RangeInclusive}`.
42904290
#[derive(Clone)]
42914291
#[unstable(feature = "step_by", reason = "recent addition",
42924292
issue = "27741")]
@@ -4295,7 +4295,7 @@ pub struct StepBy<A, R> {
42954295
range: R,
42964296
}
42974297

4298-
impl<A: Step> RangeFrom<A> {
4298+
impl<A: Step> ops::RangeFrom<A> {
42994299
/// Creates an iterator starting at the same point, but stepping by
43004300
/// the given amount at each iteration.
43014301
///
@@ -4355,8 +4355,44 @@ impl<A: Step> ops::Range<A> {
43554355
}
43564356
}
43574357

4358+
impl<A: Step> ops::RangeInclusive<A> {
4359+
/// Creates an iterator with the same range, but stepping by the
4360+
/// given amount at each iteration.
4361+
///
4362+
/// The resulting iterator handles overflow by stopping.
4363+
///
4364+
/// # Examples
4365+
///
4366+
/// ```
4367+
/// #![feature(step_by, inclusive_range_syntax)]
4368+
///
4369+
/// for i in (0...10).step_by(2) {
4370+
/// println!("{}", i);
4371+
/// }
4372+
/// ```
4373+
///
4374+
/// This prints:
4375+
///
4376+
/// ```text
4377+
/// 0
4378+
/// 2
4379+
/// 4
4380+
/// 6
4381+
/// 8
4382+
/// 10
4383+
/// ```
4384+
#[unstable(feature = "step_by", reason = "recent addition",
4385+
issue = "27741")]
4386+
pub fn step_by(self, by: A) -> StepBy<A, Self> {
4387+
StepBy {
4388+
step_by: by,
4389+
range: self
4390+
}
4391+
}
4392+
}
4393+
43584394
#[stable(feature = "rust1", since = "1.0.0")]
4359-
impl<A> Iterator for StepBy<A, RangeFrom<A>> where
4395+
impl<A> Iterator for StepBy<A, ops::RangeFrom<A>> where
43604396
A: Clone,
43614397
for<'a> &'a A: Add<&'a A, Output = A>
43624398
{
@@ -4412,6 +4448,74 @@ impl<A: Step + Zero + Clone> Iterator for StepBy<A, ops::Range<A>> {
44124448
}
44134449
}
44144450

4451+
#[unstable(feature = "inclusive_range",
4452+
reason = "recently added, follows RFC",
4453+
issue = "28237")]
4454+
impl<A: Step + Zero + Clone> Iterator for StepBy<A, ops::RangeInclusive<A>> {
4455+
type Item = A;
4456+
4457+
#[inline]
4458+
fn next(&mut self) -> Option<A> {
4459+
use ops::RangeInclusive::*;
4460+
4461+
// this function has a sort of odd structure due to borrowck issues
4462+
// we may need to replace self.range, so borrows of start and end need to end early
4463+
4464+
let (finishing, n) = match self.range {
4465+
Empty { .. } => return None, // empty iterators yield no values
4466+
4467+
NonEmpty { ref mut start, ref mut end } => {
4468+
let zero = A::zero();
4469+
let rev = self.step_by < zero;
4470+
4471+
// march start towards (maybe past!) end and yield the old value
4472+
if (rev && start >= end) ||
4473+
(!rev && start <= end)
4474+
{
4475+
match start.step(&self.step_by) {
4476+
Some(mut n) => {
4477+
mem::swap(start, &mut n);
4478+
(None, Some(n)) // yield old value, remain non-empty
4479+
},
4480+
None => {
4481+
let mut n = end.clone();
4482+
mem::swap(start, &mut n);
4483+
(None, Some(n)) // yield old value, remain non-empty
4484+
}
4485+
}
4486+
} else {
4487+
// found range in inconsistent state (start at or past end), so become empty
4488+
(Some(mem::replace(end, zero)), None)
4489+
}
4490+
}
4491+
};
4492+
4493+
// turn into an empty iterator if we've reached the end
4494+
if let Some(end) = finishing {
4495+
self.range = Empty { at: end };
4496+
}
4497+
4498+
n
4499+
}
4500+
4501+
#[inline]
4502+
fn size_hint(&self) -> (usize, Option<usize>) {
4503+
use ops::RangeInclusive::*;
4504+
4505+
match self.range {
4506+
Empty { .. } => (0, Some(0)),
4507+
4508+
NonEmpty { ref start, ref end } =>
4509+
match Step::steps_between(start,
4510+
end,
4511+
&self.step_by) {
4512+
Some(hint) => (hint.saturating_add(1), hint.checked_add(1)),
4513+
None => (0, None)
4514+
}
4515+
}
4516+
}
4517+
}
4518+
44154519
macro_rules! range_exact_iter_impl {
44164520
($($t:ty)*) => ($(
44174521
#[stable(feature = "rust1", since = "1.0.0")]

src/test/run-pass/range_inclusive.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
// Test inclusive range syntax.
1212

13-
#![feature(inclusive_range_syntax, inclusive_range)]
13+
#![feature(inclusive_range_syntax, inclusive_range, step_by)]
1414

1515
use std::ops::{RangeInclusive, RangeToInclusive};
1616

@@ -35,14 +35,12 @@ pub fn main() {
3535
}
3636
assert_eq!(count, 55);
3737

38-
/* FIXME
3938
let mut count = 0;
4039
for i in (0_usize...10).step_by(2) {
4140
assert!(i >= 0 && i <= 10 && i % 2 == 0);
4241
count += i;
4342
}
4443
assert_eq!(count, 30);
45-
*/
4644

4745
let _ = 0_usize...4+4-3;
4846
let _ = 0...foo();

0 commit comments

Comments
 (0)