auto merge of #7684 : pnkfelix/rust/fsk-invert-range-rev-halfclosedness-issue5270-2ndpr, r=cmr
Changes int/uint range_rev to iterate over range `(hi,lo]` instead of `[hi,lo)`. Fix #5270. Also: * Adds unit tests for int/uint range functions * Updates the uses of `range_rev` to account for the new semantics. (Note that pretty much all of the updates there were strict improvements to the code in question; yay!) * Exposes new function, `range_step_inclusive`, which does the range `[hi,lo]`, (at least when `hi-lo` is a multiple of the `step` parameter). * Special-cases when `|step| == 1` removing unnecessary bounds-check. (I did not check whether LLVM was already performing this optimization; I figure it would be a net win to not leave that analysis to the compiler. If reviewer objects, I can easily remove that from the refactored code.) (This pull request is a rebased version of PR #7524, which went stale due to recent unrelated changes to num libraries.)
This commit is contained in:
commit
53e934c2ab
|
@ -161,8 +161,8 @@ impl<V> SmallIntMap<V> {
|
||||||
/// Visit all key-value pairs in reverse order
|
/// Visit all key-value pairs in reverse order
|
||||||
pub fn each_reverse<'a>(&'a self, it: &fn(uint, &'a V) -> bool) -> bool {
|
pub fn each_reverse<'a>(&'a self, it: &fn(uint, &'a V) -> bool) -> bool {
|
||||||
for uint::range_rev(self.v.len(), 0) |i| {
|
for uint::range_rev(self.v.len(), 0) |i| {
|
||||||
match self.v[i - 1] {
|
match self.v[i] {
|
||||||
Some(ref elt) => if !it(i - 1, elt) { return false; },
|
Some(ref elt) => if !it(i, elt) { return false; },
|
||||||
None => ()
|
None => ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,28 +29,38 @@ pub static bytes : uint = ($bits / 8);
|
||||||
pub static min_value: $T = (-1 as $T) << (bits - 1);
|
pub static min_value: $T = (-1 as $T) << (bits - 1);
|
||||||
pub static max_value: $T = min_value - 1 as $T;
|
pub static max_value: $T = min_value - 1 as $T;
|
||||||
|
|
||||||
///
|
enum Range { Closed, HalfOpen }
|
||||||
/// Iterate over the range [`lo`..`hi`)
|
|
||||||
///
|
|
||||||
/// # Arguments
|
|
||||||
///
|
|
||||||
/// * `lo` - lower bound, inclusive
|
|
||||||
/// * `hi` - higher bound, exclusive
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
/// ~~~
|
|
||||||
/// let mut sum = 0;
|
|
||||||
/// for int::range(1, 5) |i| {
|
|
||||||
/// sum += i;
|
|
||||||
/// }
|
|
||||||
/// assert!(sum == 10);
|
|
||||||
/// ~~~
|
|
||||||
///
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn range_step(start: $T, stop: $T, step: $T, it: &fn($T) -> bool) -> bool {
|
///
|
||||||
|
/// Iterate through a range with a given step value.
|
||||||
|
///
|
||||||
|
/// Let `term` denote the closed interval `[stop-step,stop]` if `r` is Closed;
|
||||||
|
/// otherwise `term` denotes the half-open interval `[stop-step,stop)`.
|
||||||
|
/// Iterates through the range `[x_0, x_1, ..., x_n]` where
|
||||||
|
/// `x_j == start + step*j`, and `x_n` lies in the interval `term`.
|
||||||
|
///
|
||||||
|
/// If no such nonnegative integer `n` exists, then the iteration range
|
||||||
|
/// is empty.
|
||||||
|
///
|
||||||
|
fn range_step_core(start: $T, stop: $T, step: $T, r: Range, it: &fn($T) -> bool) -> bool {
|
||||||
let mut i = start;
|
let mut i = start;
|
||||||
if step == 0 {
|
if step == 0 {
|
||||||
fail!(~"range_step called with step == 0");
|
fail!(~"range_step called with step == 0");
|
||||||
|
} else if step == (1 as $T) { // elide bounds check to tighten loop
|
||||||
|
while i < stop {
|
||||||
|
if !it(i) { return false; }
|
||||||
|
// no need for overflow check;
|
||||||
|
// cannot have i + 1 > max_value because i < stop <= max_value
|
||||||
|
i += (1 as $T);
|
||||||
|
}
|
||||||
|
} else if step == (-1 as $T) { // elide bounds check to tighten loop
|
||||||
|
while i > stop {
|
||||||
|
if !it(i) { return false; }
|
||||||
|
// no need for underflow check;
|
||||||
|
// cannot have i - 1 < min_value because i > stop >= min_value
|
||||||
|
i -= (1 as $T);
|
||||||
|
}
|
||||||
} else if step > 0 { // ascending
|
} else if step > 0 { // ascending
|
||||||
while i < stop {
|
while i < stop {
|
||||||
if !it(i) { return false; }
|
if !it(i) { return false; }
|
||||||
|
@ -66,9 +76,55 @@ pub fn range_step(start: $T, stop: $T, step: $T, it: &fn($T) -> bool) -> bool {
|
||||||
i += step;
|
i += step;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
match r {
|
||||||
|
HalfOpen => return true,
|
||||||
|
Closed => return (i != stop || it(i))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
///
|
||||||
|
/// Iterate through the range [`start`..`stop`) with a given step value.
|
||||||
|
///
|
||||||
|
/// Iterates through the range `[x_0, x_1, ..., x_n]` where
|
||||||
|
/// * `x_i == start + step*i`, and
|
||||||
|
/// * `n` is the greatest nonnegative integer such that `x_n < stop`
|
||||||
|
///
|
||||||
|
/// (If no such `n` exists, then the iteration range is empty.)
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `start` - lower bound, inclusive
|
||||||
|
/// * `stop` - higher bound, exclusive
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// ~~~
|
||||||
|
/// let mut sum = 0;
|
||||||
|
/// for int::range(1, 5) |i| {
|
||||||
|
/// sum += i;
|
||||||
|
/// }
|
||||||
|
/// assert!(sum == 10);
|
||||||
|
/// ~~~
|
||||||
|
///
|
||||||
|
pub fn range_step(start: $T, stop: $T, step: $T, it: &fn($T) -> bool) -> bool {
|
||||||
|
range_step_core(start, stop, step, HalfOpen, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
///
|
||||||
|
/// Iterate through a range with a given step value.
|
||||||
|
///
|
||||||
|
/// Iterates through the range `[x_0, x_1, ..., x_n]` where
|
||||||
|
/// `x_i == start + step*i` and `x_n <= last < step + x_n`.
|
||||||
|
///
|
||||||
|
/// (If no such nonnegative integer `n` exists, then the iteration
|
||||||
|
/// range is empty.)
|
||||||
|
///
|
||||||
|
pub fn range_step_inclusive(start: $T, last: $T, step: $T, it: &fn($T) -> bool) -> bool {
|
||||||
|
range_step_core(start, last, step, Closed, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Iterate over the range [`lo`..`hi`)
|
/// Iterate over the range [`lo`..`hi`)
|
||||||
pub fn range(lo: $T, hi: $T, it: &fn($T) -> bool) -> bool {
|
pub fn range(lo: $T, hi: $T, it: &fn($T) -> bool) -> bool {
|
||||||
|
@ -76,9 +132,10 @@ pub fn range(lo: $T, hi: $T, it: &fn($T) -> bool) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Iterate over the range [`hi`..`lo`)
|
/// Iterate over the range (`hi`..`lo`]
|
||||||
pub fn range_rev(hi: $T, lo: $T, it: &fn($T) -> bool) -> bool {
|
pub fn range_rev(hi: $T, lo: $T, it: &fn($T) -> bool) -> bool {
|
||||||
range_step(hi, lo, -1 as $T, it)
|
if hi == min_value { return true; }
|
||||||
|
range_step_inclusive(hi-1, lo, -1 as $T, it)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Num for $T {}
|
impl Num for $T {}
|
||||||
|
@ -841,7 +898,7 @@ mod tests {
|
||||||
for range(0,3) |i| {
|
for range(0,3) |i| {
|
||||||
l.push(i);
|
l.push(i);
|
||||||
}
|
}
|
||||||
for range_rev(13,10) |i| {
|
for range_rev(14,11) |i| {
|
||||||
l.push(i);
|
l.push(i);
|
||||||
}
|
}
|
||||||
for range_step(20,26,2) |i| {
|
for range_step(20,26,2) |i| {
|
||||||
|
|
|
@ -30,32 +30,46 @@ pub static bytes : uint = ($bits / 8);
|
||||||
pub static min_value: $T = 0 as $T;
|
pub static min_value: $T = 0 as $T;
|
||||||
pub static max_value: $T = 0 as $T - 1 as $T;
|
pub static max_value: $T = 0 as $T - 1 as $T;
|
||||||
|
|
||||||
|
enum Range { Closed, HalfOpen }
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
/**
|
///
|
||||||
* Iterate through a range with a given step value.
|
/// Iterate through a range with a given step value.
|
||||||
*
|
///
|
||||||
* # Examples
|
/// Let `term` denote the closed interval `[stop-step,stop]` if `r` is Closed;
|
||||||
* ~~~ {.rust}
|
/// otherwise `term` denotes the half-open interval `[stop-step,stop)`.
|
||||||
* let nums = [1,2,3,4,5,6,7];
|
/// Iterates through the range `[x_0, x_1, ..., x_n]` where
|
||||||
*
|
/// `x_j == start + step*j`, and `x_n` lies in the interval `term`.
|
||||||
* for uint::range_step(0, nums.len() - 1, 2) |i| {
|
///
|
||||||
* println(fmt!("%d & %d", nums[i], nums[i+1]));
|
/// If no such nonnegative integer `n` exists, then the iteration range
|
||||||
* }
|
/// is empty.
|
||||||
* ~~~
|
///
|
||||||
*/
|
fn range_step_core(start: $T, stop: $T, step: $T_SIGNED, r: Range, it: &fn($T) -> bool) -> bool {
|
||||||
pub fn range_step(start: $T, stop: $T, step: $T_SIGNED, it: &fn($T) -> bool) -> bool {
|
|
||||||
let mut i = start;
|
let mut i = start;
|
||||||
if step == 0 {
|
if step == 0 {
|
||||||
fail!("range_step called with step == 0");
|
fail!("range_step called with step == 0");
|
||||||
}
|
} else if step == (1 as $T_SIGNED) { // elide bounds check to tighten loop
|
||||||
if step >= 0 {
|
while i < stop {
|
||||||
|
if !it(i) { return false; }
|
||||||
|
// no need for overflow check;
|
||||||
|
// cannot have i + 1 > max_value because i < stop <= max_value
|
||||||
|
i += (1 as $T);
|
||||||
|
}
|
||||||
|
} else if step == (-1 as $T_SIGNED) { // elide bounds check to tighten loop
|
||||||
|
while i > stop {
|
||||||
|
if !it(i) { return false; }
|
||||||
|
// no need for underflow check;
|
||||||
|
// cannot have i - 1 < min_value because i > stop >= min_value
|
||||||
|
i -= (1 as $T);
|
||||||
|
}
|
||||||
|
} else if step > 0 { // ascending
|
||||||
while i < stop {
|
while i < stop {
|
||||||
if !it(i) { return false; }
|
if !it(i) { return false; }
|
||||||
// avoiding overflow. break if i + step > max_value
|
// avoiding overflow. break if i + step > max_value
|
||||||
if i > max_value - (step as $T) { return true; }
|
if i > max_value - (step as $T) { return true; }
|
||||||
i += step as $T;
|
i += step as $T;
|
||||||
}
|
}
|
||||||
} else {
|
} else { // descending
|
||||||
while i > stop {
|
while i > stop {
|
||||||
if !it(i) { return false; }
|
if !it(i) { return false; }
|
||||||
// avoiding underflow. break if i + step < min_value
|
// avoiding underflow. break if i + step < min_value
|
||||||
|
@ -63,7 +77,52 @@ pub fn range_step(start: $T, stop: $T, step: $T_SIGNED, it: &fn($T) -> bool) ->
|
||||||
i -= -step as $T;
|
i -= -step as $T;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
match r {
|
||||||
|
HalfOpen => return true,
|
||||||
|
Closed => return (i != stop || it(i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
///
|
||||||
|
/// Iterate through the range [`start`..`stop`) with a given step value.
|
||||||
|
///
|
||||||
|
/// Iterates through the range `[x_0, x_1, ..., x_n]` where
|
||||||
|
/// - `x_i == start + step*i`, and
|
||||||
|
/// - `n` is the greatest nonnegative integer such that `x_n < stop`
|
||||||
|
///
|
||||||
|
/// (If no such `n` exists, then the iteration range is empty.)
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `start` - lower bound, inclusive
|
||||||
|
/// * `stop` - higher bound, exclusive
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// ~~~ {.rust}
|
||||||
|
/// let nums = [1,2,3,4,5,6,7];
|
||||||
|
///
|
||||||
|
/// for uint::range_step(0, nums.len() - 1, 2) |i| {
|
||||||
|
/// println(fmt!("%d & %d", nums[i], nums[i+1]));
|
||||||
|
/// }
|
||||||
|
/// ~~~
|
||||||
|
///
|
||||||
|
pub fn range_step(start: $T, stop: $T, step: $T_SIGNED, it: &fn($T) -> bool) -> bool {
|
||||||
|
range_step_core(start, stop, step, HalfOpen, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
///
|
||||||
|
/// Iterate through a range with a given step value.
|
||||||
|
///
|
||||||
|
/// Iterates through the range `[x_0, x_1, ..., x_n]` where
|
||||||
|
/// `x_i == start + step*i` and `x_n <= last < step + x_n`.
|
||||||
|
///
|
||||||
|
/// (If no such nonnegative integer `n` exists, then the iteration
|
||||||
|
/// range is empty.)
|
||||||
|
///
|
||||||
|
pub fn range_step_inclusive(start: $T, last: $T, step: $T_SIGNED, it: &fn($T) -> bool) -> bool {
|
||||||
|
range_step_core(start, last, step, Closed, it)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -73,9 +132,10 @@ pub fn range(lo: $T, hi: $T, it: &fn($T) -> bool) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Iterate over the range [`hi`..`lo`)
|
/// Iterate over the range (`hi`..`lo`]
|
||||||
pub fn range_rev(hi: $T, lo: $T, it: &fn($T) -> bool) -> bool {
|
pub fn range_rev(hi: $T, lo: $T, it: &fn($T) -> bool) -> bool {
|
||||||
range_step(hi, lo, -1 as $T_SIGNED, it)
|
if hi == min_value { return true; }
|
||||||
|
range_step_inclusive(hi-1, lo, -1 as $T_SIGNED, it)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Num for $T {}
|
impl Num for $T {}
|
||||||
|
@ -603,7 +663,7 @@ mod tests {
|
||||||
for range(0,3) |i| {
|
for range(0,3) |i| {
|
||||||
l.push(i);
|
l.push(i);
|
||||||
}
|
}
|
||||||
for range_rev(13,10) |i| {
|
for range_rev(14,11) |i| {
|
||||||
l.push(i);
|
l.push(i);
|
||||||
}
|
}
|
||||||
for range_step(20,26,2) |i| {
|
for range_step(20,26,2) |i| {
|
||||||
|
|
|
@ -669,7 +669,7 @@ fn spawn_process_os(prog: &str, args: &[~str],
|
||||||
fail!("failure in dup3(err_fd, 2): %s", os::last_os_error());
|
fail!("failure in dup3(err_fd, 2): %s", os::last_os_error());
|
||||||
}
|
}
|
||||||
// close all other fds
|
// close all other fds
|
||||||
for int::range_rev(getdtablesize() as int - 1, 2) |fd| {
|
for int::range_rev(getdtablesize() as int, 3) |fd| {
|
||||||
close(fd as c_int);
|
close(fd as c_int);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -287,7 +287,7 @@ impl<T> TrieNode<T> {
|
||||||
|
|
||||||
fn each_reverse<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) -> bool {
|
fn each_reverse<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) -> bool {
|
||||||
for uint::range_rev(self.children.len(), 0) |idx| {
|
for uint::range_rev(self.children.len(), 0) |idx| {
|
||||||
match self.children[idx - 1] {
|
match self.children[idx] {
|
||||||
Internal(ref x) => if !x.each_reverse(|i,t| f(i,t)) { return false },
|
Internal(ref x) => if !x.each_reverse(|i,t| f(i,t)) { return false },
|
||||||
External(k, ref v) => if !f(&k, v) { return false },
|
External(k, ref v) => if !f(&k, v) { return false },
|
||||||
Nothing => ()
|
Nothing => ()
|
||||||
|
@ -488,7 +488,7 @@ mod test_map {
|
||||||
m.insert(x, x / 2);
|
m.insert(x, x / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut n = uint::max_value - 9999;
|
let mut n = uint::max_value - 10000;
|
||||||
for m.each |k, v| {
|
for m.each |k, v| {
|
||||||
if n == uint::max_value - 5000 { break }
|
if n == uint::max_value - 5000 { break }
|
||||||
assert!(n < uint::max_value - 5000);
|
assert!(n < uint::max_value - 5000);
|
||||||
|
@ -525,7 +525,7 @@ mod test_map {
|
||||||
m.insert(x, x / 2);
|
m.insert(x, x / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut n = uint::max_value;
|
let mut n = uint::max_value - 1;
|
||||||
for m.each_reverse |k, v| {
|
for m.each_reverse |k, v| {
|
||||||
if n == uint::max_value - 5000 { break }
|
if n == uint::max_value - 5000 { break }
|
||||||
assert!(n > uint::max_value - 5000);
|
assert!(n > uint::max_value - 5000);
|
||||||
|
|
|
@ -0,0 +1,114 @@
|
||||||
|
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
use std::int;
|
||||||
|
use std::uint;
|
||||||
|
|
||||||
|
fn uint_range(lo: uint, hi: uint, it: &fn(uint) -> bool) -> bool {
|
||||||
|
uint::range(lo, hi, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn int_range(lo: int, hi: int, it: &fn(int) -> bool) -> bool {
|
||||||
|
int::range(lo, hi, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn uint_range_rev(hi: uint, lo: uint, it: &fn(uint) -> bool) -> bool {
|
||||||
|
uint::range_rev(hi, lo, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn int_range_rev(hi: int, lo: int, it: &fn(int) -> bool) -> bool {
|
||||||
|
int::range_rev(hi, lo, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn int_range_step(a: int, b: int, step: int, it: &fn(int) -> bool) -> bool {
|
||||||
|
int::range_step(a, b, step, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn uint_range_step(a: uint, b: uint, step: int, it: &fn(uint) -> bool) -> bool {
|
||||||
|
uint::range_step(a, b, step, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
// int and uint have same result for
|
||||||
|
// Sum{100 > i >= 2} == (Sum{1 <= i <= 99} - 1) == n*(n+1)/2 - 1 for n=99
|
||||||
|
let mut sum = 0u;
|
||||||
|
for uint_range_rev(100, 2) |i| {
|
||||||
|
sum += i;
|
||||||
|
}
|
||||||
|
assert_eq!(sum, 4949);
|
||||||
|
|
||||||
|
let mut sum = 0i;
|
||||||
|
for int_range_rev(100, 2) |i| {
|
||||||
|
sum += i;
|
||||||
|
}
|
||||||
|
assert_eq!(sum, 4949);
|
||||||
|
|
||||||
|
|
||||||
|
// elements are visited in correct order
|
||||||
|
let primes = [2,3,5,7,11];
|
||||||
|
let mut prod = 1i;
|
||||||
|
for uint_range_rev(5, 0) |i| {
|
||||||
|
println(fmt!("uint 4 downto 0: %u", i));
|
||||||
|
prod *= int::pow(primes[i], i);
|
||||||
|
}
|
||||||
|
assert_eq!(prod, 11*11*11*11*7*7*7*5*5*3*1);
|
||||||
|
let mut prod = 1i;
|
||||||
|
for int_range_rev(5, 0) |i| {
|
||||||
|
println(fmt!("int 4 downto 0: %d", i));
|
||||||
|
prod *= int::pow(primes[i], i as uint);
|
||||||
|
}
|
||||||
|
assert_eq!(prod, 11*11*11*11*7*7*7*5*5*3*1);
|
||||||
|
|
||||||
|
|
||||||
|
// range and range_rev are symmetric.
|
||||||
|
let mut sum_up = 0u;
|
||||||
|
for uint_range(10, 30) |i| {
|
||||||
|
sum_up += i;
|
||||||
|
}
|
||||||
|
let mut sum_down = 0u;
|
||||||
|
for uint_range_rev(30, 10) |i| {
|
||||||
|
sum_down += i;
|
||||||
|
}
|
||||||
|
assert_eq!(sum_up, sum_down);
|
||||||
|
|
||||||
|
let mut sum_up = 0;
|
||||||
|
for int_range(-20, 10) |i| {
|
||||||
|
sum_up += i;
|
||||||
|
}
|
||||||
|
let mut sum_down = 0;
|
||||||
|
for int_range_rev(10, -20) |i| {
|
||||||
|
sum_down += i;
|
||||||
|
}
|
||||||
|
assert_eq!(sum_up, sum_down);
|
||||||
|
|
||||||
|
|
||||||
|
// empty ranges
|
||||||
|
for int_range_rev(10, 10) |_| {
|
||||||
|
fail!("range should be empty when start == stop");
|
||||||
|
}
|
||||||
|
|
||||||
|
for uint_range_rev(0, 1) |_| {
|
||||||
|
fail!("range should be empty when start-1 underflows");
|
||||||
|
}
|
||||||
|
|
||||||
|
// range iterations do not wrap/underflow
|
||||||
|
let mut uflo_loop_visited = ~[];
|
||||||
|
for int_range_step(int::min_value+15, int::min_value, -4) |x| {
|
||||||
|
uflo_loop_visited.push(x - int::min_value);
|
||||||
|
}
|
||||||
|
assert_eq!(uflo_loop_visited, ~[15, 11, 7, 3]);
|
||||||
|
|
||||||
|
let mut uflo_loop_visited = ~[];
|
||||||
|
for uint_range_step(uint::min_value+15, uint::min_value, -4) |x| {
|
||||||
|
uflo_loop_visited.push(x - uint::min_value);
|
||||||
|
}
|
||||||
|
assert_eq!(uflo_loop_visited, ~[15, 11, 7, 3]);
|
||||||
|
}
|
|
@ -0,0 +1,119 @@
|
||||||
|
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
use std::int;
|
||||||
|
use std::uint;
|
||||||
|
|
||||||
|
fn uint_range(lo: uint, hi: uint, it: &fn(uint) -> bool) -> bool {
|
||||||
|
uint::range(lo, hi, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn int_range(lo: int, hi: int, it: &fn(int) -> bool) -> bool {
|
||||||
|
int::range(lo, hi, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn int_range_step(a: int, b: int, step: int, it: &fn(int) -> bool) -> bool {
|
||||||
|
int::range_step(a, b, step, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn uint_range_step(a: uint, b: uint, s: int, it: &fn(uint) -> bool) -> bool {
|
||||||
|
uint::range_step(a, b, s, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
println(fmt!("num-range start"));
|
||||||
|
// int and uint have same result for
|
||||||
|
// Sum{2 <= i < 100} == (Sum{1 <= i <= 99} - 1) == n*(n+1)/2 - 1 for n=99
|
||||||
|
let mut sum = 0u;
|
||||||
|
for uint_range(2, 100) |i| {
|
||||||
|
sum += i;
|
||||||
|
}
|
||||||
|
assert_eq!(sum, 4949);
|
||||||
|
|
||||||
|
let mut sum = 0i;
|
||||||
|
for int_range(2, 100) |i| {
|
||||||
|
sum += i;
|
||||||
|
}
|
||||||
|
assert_eq!(sum, 4949);
|
||||||
|
|
||||||
|
|
||||||
|
// elements are visited in correct order
|
||||||
|
let primes = [2,3,5,7];
|
||||||
|
let mut prod = 1i;
|
||||||
|
for uint_range(0, 4) |i| {
|
||||||
|
prod *= int::pow(primes[i], i);
|
||||||
|
}
|
||||||
|
assert_eq!(prod, 1*3*5*5*7*7*7);
|
||||||
|
let mut prod = 1i;
|
||||||
|
for int_range(0, 4) |i| {
|
||||||
|
prod *= int::pow(primes[i], i as uint);
|
||||||
|
}
|
||||||
|
assert_eq!(prod, 1*3*5*5*7*7*7);
|
||||||
|
|
||||||
|
|
||||||
|
// empty ranges
|
||||||
|
for int_range(10, 10) |_| {
|
||||||
|
fail!("range should be empty when start == stop");
|
||||||
|
}
|
||||||
|
|
||||||
|
for uint_range(10, 10) |_| {
|
||||||
|
fail!("range should be empty when start == stop");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// range iterations do not wrap/overflow
|
||||||
|
let mut oflo_loop_visited = ~[];
|
||||||
|
for uint_range_step(uint::max_value-15, uint::max_value, 4) |x| {
|
||||||
|
oflo_loop_visited.push(uint::max_value - x);
|
||||||
|
}
|
||||||
|
assert_eq!(oflo_loop_visited, ~[15, 11, 7, 3]);
|
||||||
|
|
||||||
|
let mut oflo_loop_visited = ~[];
|
||||||
|
for int_range_step(int::max_value-15, int::max_value, 4) |x| {
|
||||||
|
oflo_loop_visited.push(int::max_value - x);
|
||||||
|
}
|
||||||
|
assert_eq!(oflo_loop_visited, ~[15, 11, 7, 3]);
|
||||||
|
|
||||||
|
|
||||||
|
// range_step never passes nor visits the stop element
|
||||||
|
for int_range_step(0, 21, 3) |x| {
|
||||||
|
assert!(x < 21);
|
||||||
|
}
|
||||||
|
|
||||||
|
// range_step_inclusive will never pass stop element, and may skip it.
|
||||||
|
let mut saw21 = false;
|
||||||
|
for uint::range_step_inclusive(0, 21, 4) |x| {
|
||||||
|
assert!(x <= 21);
|
||||||
|
if x == 21 { saw21 = true; }
|
||||||
|
}
|
||||||
|
assert!(!saw21);
|
||||||
|
let mut saw21 = false;
|
||||||
|
for int::range_step_inclusive(0, 21, 4) |x| {
|
||||||
|
assert!(x <= 21);
|
||||||
|
if x == 21 { saw21 = true; }
|
||||||
|
}
|
||||||
|
assert!(!saw21);
|
||||||
|
|
||||||
|
// range_step_inclusive will never pass stop element, but may visit it.
|
||||||
|
let mut saw21 = false;
|
||||||
|
for uint::range_step_inclusive(0, 21, 3) |x| {
|
||||||
|
assert!(x <= 21);
|
||||||
|
println(fmt!("saw: %u", x));
|
||||||
|
if x == 21 { saw21 = true; }
|
||||||
|
}
|
||||||
|
assert!(saw21);
|
||||||
|
let mut saw21 = false;
|
||||||
|
for int::range_step_inclusive(0, 21, 3) |x| {
|
||||||
|
assert!(x <= 21);
|
||||||
|
if x == 21 { saw21 = true; }
|
||||||
|
}
|
||||||
|
assert!(saw21);
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue