diff options
| author | bors <bors@rust-lang.org> | 2013-07-16 14:37:34 -0700 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2013-07-16 14:37:34 -0700 |
| commit | 53e934c2ab773eaf61da331893d176aa3e62230b (patch) | |
| tree | e10d9c36f5f1eed33171e2a75381769076fa4857 /src/libstd | |
| parent | 9db190305f7562f15b5282fed508aef81cfc9689 (diff) | |
| parent | 3896d46c0a6b99ef166bdc29220ef6c85ad8bc8d (diff) | |
| download | rust-53e934c2ab773eaf61da331893d176aa3e62230b.tar.gz rust-53e934c2ab773eaf61da331893d176aa3e62230b.zip | |
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.)
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/num/int_macros.rs | 95 | ||||
| -rw-r--r-- | src/libstd/num/uint_macros.rs | 100 | ||||
| -rw-r--r-- | src/libstd/run.rs | 2 | ||||
| -rw-r--r-- | src/libstd/trie.rs | 6 |
4 files changed, 160 insertions, 43 deletions
diff --git a/src/libstd/num/int_macros.rs b/src/libstd/num/int_macros.rs index 75e0bbcb71b..cef32b5c7e4 100644 --- a/src/libstd/num/int_macros.rs +++ b/src/libstd/num/int_macros.rs @@ -29,28 +29,38 @@ pub static bytes : uint = ($bits / 8); pub static min_value: $T = (-1 as $T) << (bits - 1); pub static max_value: $T = min_value - 1 as $T; +enum Range { Closed, HalfOpen } + +#[inline] /// -/// Iterate over the range [`lo`..`hi`) +/// Iterate through a range with a given step value. /// -/// # Arguments +/// 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`. /// -/// * `lo` - lower bound, inclusive -/// * `hi` - higher bound, exclusive -/// -/// # Examples -/// ~~~ -/// let mut sum = 0; -/// for int::range(1, 5) |i| { -/// sum += i; -/// } -/// assert!(sum == 10); -/// ~~~ +/// If no such nonnegative integer `n` exists, then the iteration range +/// is empty. /// -#[inline] -pub fn range_step(start: $T, stop: $T, step: $T, it: &fn($T) -> bool) -> bool { +fn range_step_core(start: $T, stop: $T, step: $T, r: Range, it: &fn($T) -> bool) -> bool { let mut i = start; if 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 while i < stop { 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; } } - 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] /// Iterate over the range [`lo`..`hi`) 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] -/// 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 { - 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 {} @@ -841,7 +898,7 @@ mod tests { for range(0,3) |i| { l.push(i); } - for range_rev(13,10) |i| { + for range_rev(14,11) |i| { l.push(i); } for range_step(20,26,2) |i| { diff --git a/src/libstd/num/uint_macros.rs b/src/libstd/num/uint_macros.rs index de1b997b14b..54c1327fa93 100644 --- a/src/libstd/num/uint_macros.rs +++ b/src/libstd/num/uint_macros.rs @@ -30,32 +30,46 @@ pub static bytes : uint = ($bits / 8); pub static min_value: $T = 0 as $T; pub static max_value: $T = 0 as $T - 1 as $T; +enum Range { Closed, HalfOpen } + #[inline] -/** - * Iterate through a range with a given step value. - * - * # 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 { +/// +/// 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_SIGNED, r: Range, it: &fn($T) -> bool) -> bool { let mut i = start; if step == 0 { fail!("range_step called with step == 0"); - } - if step >= 0 { + } else if step == (1 as $T_SIGNED) { // 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_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 { if !it(i) { return false; } // avoiding overflow. break if i + step > max_value if i > max_value - (step as $T) { return true; } i += step as $T; } - } else { + } else { // descending while i > stop { if !it(i) { return false; } // 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; } } - 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] @@ -73,9 +132,10 @@ pub fn range(lo: $T, hi: $T, it: &fn($T) -> bool) -> bool { } #[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 { - 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 {} @@ -603,7 +663,7 @@ mod tests { for range(0,3) |i| { l.push(i); } - for range_rev(13,10) |i| { + for range_rev(14,11) |i| { l.push(i); } for range_step(20,26,2) |i| { diff --git a/src/libstd/run.rs b/src/libstd/run.rs index 17dc604a178..883870db1e6 100644 --- a/src/libstd/run.rs +++ b/src/libstd/run.rs @@ -669,7 +669,7 @@ fn spawn_process_os(prog: &str, args: &[~str], fail!("failure in dup3(err_fd, 2): %s", os::last_os_error()); } // 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); } diff --git a/src/libstd/trie.rs b/src/libstd/trie.rs index 3882ab0de63..396fdaf2e6a 100644 --- a/src/libstd/trie.rs +++ b/src/libstd/trie.rs @@ -287,7 +287,7 @@ impl<T> TrieNode<T> { fn each_reverse<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) -> bool { 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 }, External(k, ref v) => if !f(&k, v) { return false }, Nothing => () @@ -488,7 +488,7 @@ mod test_map { m.insert(x, x / 2); } - let mut n = uint::max_value - 9999; + let mut n = uint::max_value - 10000; for m.each |k, v| { if n == uint::max_value - 5000 { break } assert!(n < uint::max_value - 5000); @@ -525,7 +525,7 @@ mod test_map { m.insert(x, x / 2); } - let mut n = uint::max_value; + let mut n = uint::max_value - 1; for m.each_reverse |k, v| { if n == uint::max_value - 5000 { break } assert!(n > uint::max_value - 5000); |
