diff --git a/src/libstd/iter.rs b/src/libstd/iter.rs
index ec3c02a31f2f5..22e8a1defbda9 100644
--- a/src/libstd/iter.rs
+++ b/src/libstd/iter.rs
@@ -21,7 +21,7 @@ use cmp;
use num::{Zero, One, Integer, CheckedAdd, CheckedSub, Saturating};
use option::{Option, Some, None};
use ops::{Add, Mul, Sub};
-use cmp::Ord;
+use cmp::{Eq, Ord};
use clone::Clone;
use uint;
use util;
@@ -1719,7 +1719,21 @@ pub fn count(start: A, step: A) -> Counter {
Counter{state: start, step: step}
}
-/// A range of numbers from [0, N)
+impl + Clone> Iterator for Counter {
+ #[inline]
+ fn next(&mut self) -> Option {
+ let result = self.state.clone();
+ self.state = self.state + self.step;
+ Some(result)
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (uint, Option) {
+ (uint::max_value, None) // Too bad we can't specify an infinite lower bound
+ }
+}
+
+/// An iterator over the range [start, stop)
#[deriving(Clone, DeepClone)]
pub struct Range {
priv state: A,
@@ -1749,14 +1763,12 @@ impl + Ord + Clone> Iterator for Range {
// Blocked on #8605 Need numeric trait for converting to `Option`
}
-impl + Integer + Ord + Clone> DoubleEndedIterator for Range {
+/// `Integer` is required to ensure the range will be the same regardless of
+/// the direction it is consumed.
+impl DoubleEndedIterator for Range {
#[inline]
fn next_back(&mut self) -> Option {
if self.stop > self.state {
- // Integer doesn't technically define this rule, but we're going to assume that every
- // Integer is reachable from every other one by adding or subtracting enough Ones. This
- // seems like a reasonable-enough rule that every Integer should conform to, even if it
- // can't be statically checked.
self.stop = self.stop - self.one;
Some(self.stop.clone())
} else {
@@ -1765,7 +1777,7 @@ impl + Integer + Ord + Clone> DoubleEndedIterator for Range {
}
}
-/// A range of numbers from [0, N]
+/// An iterator over the range [start, stop]
#[deriving(Clone, DeepClone)]
pub struct RangeInclusive {
priv range: Range,
@@ -1826,17 +1838,78 @@ impl + Integer + Ord + Clone> DoubleEndedIterator for RangeInclu
}
}
-impl + Clone> Iterator for Counter {
+/// An iterator over the range [start, stop) by `step`. It handles overflow by stopping.
+#[deriving(Clone, DeepClone)]
+pub struct RangeStep {
+ priv state: A,
+ priv stop: A,
+ priv step: A,
+ priv rev: bool
+}
+
+/// Return an iterator over the range [start, stop) by `step`. It handles overflow by stopping.
+#[inline]
+pub fn range_step(start: A, stop: A, step: A) -> RangeStep {
+ let rev = step < Zero::zero();
+ RangeStep{state: start, stop: stop, step: step, rev: rev}
+}
+
+impl Iterator for RangeStep {
#[inline]
fn next(&mut self) -> Option {
- let result = self.state.clone();
- self.state = self.state + self.step;
- Some(result)
+ if (self.rev && self.state > self.stop) || self.state < self.stop {
+ let result = self.state.clone();
+ match self.state.checked_add(&self.step) {
+ Some(x) => self.state = x,
+ None => self.state = self.stop.clone()
+ }
+ Some(result)
+ } else {
+ None
+ }
}
+}
+
+/// An iterator over the range [start, stop] by `step`. It handles overflow by stopping.
+#[deriving(Clone, DeepClone)]
+pub struct RangeStepInclusive {
+ priv state: A,
+ priv stop: A,
+ priv step: A,
+ priv rev: bool,
+ priv done: bool
+}
+/// Return an iterator over the range [start, stop] by `step`. It handles overflow by stopping.
+#[inline]
+pub fn range_step_inclusive(start: A, stop: A,
+ step: A) -> RangeStepInclusive {
+ let rev = step < Zero::zero();
+ RangeStepInclusive{state: start, stop: stop, step: step, rev: rev, done: false}
+}
+
+impl Iterator for RangeStepInclusive {
#[inline]
- fn size_hint(&self) -> (uint, Option) {
- (uint::max_value, None) // Too bad we can't specify an infinite lower bound
+ fn next(&mut self) -> Option {
+ if !self.done {
+ if (self.rev && self.state > self.stop) || self.state < self.stop {
+ let result = self.state.clone();
+ match self.state.checked_add(&self.step) {
+ Some(x) => self.state = x,
+ None => self.done = true
+ }
+ Some(result)
+ } else {
+ if self.state == self.stop {
+ self.done = true;
+ Some(self.state.clone())
+ } else {
+ None
+ }
+ }
+ } else {
+ None
+ }
}
}
@@ -2649,6 +2722,20 @@ mod tests {
assert_eq!(range_inclusive(0i, 5).invert().collect::<~[int]>(), ~[5i, 4, 3, 2, 1, 0]);
}
+ #[test]
+ fn test_range_step() {
+ assert_eq!(range_step(0i, 20, 5).collect::<~[int]>(), ~[0, 5, 10, 15]);
+ assert_eq!(range_step(20i, 0, -5).collect::<~[int]>(), ~[20, 15, 10, 5]);
+ assert_eq!(range_step(200u8, 255, 50).collect::<~[u8]>(), ~[200u8, 250]);
+ }
+
+ #[test]
+ fn test_range_step_inclusive() {
+ assert_eq!(range_step_inclusive(0i, 20, 5).collect::<~[int]>(), ~[0, 5, 10, 15, 20]);
+ assert_eq!(range_step_inclusive(20i, 0, -5).collect::<~[int]>(), ~[20, 15, 10, 5, 0]);
+ assert_eq!(range_step_inclusive(200u8, 255, 50).collect::<~[u8]>(), ~[200u8, 250]);
+ }
+
#[test]
fn test_reverse() {
let mut ys = [1, 2, 3, 4, 5];