From 98ae62d01613e8632a39b87e11911d182dc81e49 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Mon, 10 Dec 2012 03:57:41 +0100 Subject: [PATCH 1/2] libcore: Add range_step and range_rev functions. Closes #1817 --- src/libcore/int-template.rs | 33 +++++++++++++++++++++++++++------ src/libcore/uint-template.rs | 31 ++++++++++++++++++++++++++----- 2 files changed, 53 insertions(+), 11 deletions(-) diff --git a/src/libcore/int-template.rs b/src/libcore/int-template.rs index 4946a0997c1ed..9035abd6d1a04 100644 --- a/src/libcore/int-template.rs +++ b/src/libcore/int-template.rs @@ -54,15 +54,36 @@ pub pure fn is_nonpositive(x: T) -> bool { x <= 0 as T } pub pure fn is_nonnegative(x: T) -> bool { x >= 0 as T } #[inline(always)] -/// Iterate over the range [`lo`..`hi`) -pub fn range(lo: T, hi: T, it: fn(T) -> bool) { - let mut i = lo; - while i < hi { - if !it(i) { break } - i += 1 as T; +/// Iterate over the range [`start`,`start`+`step`..`stop`) +pub pure fn range_step(start: T, stop: T, step: T, it: fn(T) -> bool) { + let mut i = start; + if step == 0 { + fail ~"range_step called with step == 0"; + } else if step > 0 { // ascending + while i < stop { + if !it(i) { break } + i += step; + } + } else { // descending + while i > stop { + if !it(i) { break } + i += step; + } } } +#[inline(always)] +/// Iterate over the range [`lo`..`hi`) +pub pure fn range(lo: T, hi: T, it: fn(T) -> bool) { + range_step(lo, hi, 1 as T, it); +} + +#[inline(always)] +/// Iterate over the range [`hi`..`lo`) +pub pure fn range_rev(hi: T, lo: T, it: fn(T) -> bool) { + range_step(hi, lo, -1 as T, it); +} + /// Computes the bitwise complement pub pure fn compl(i: T) -> T { -1 as T ^ i diff --git a/src/libcore/uint-template.rs b/src/libcore/uint-template.rs index ad6f73e56c060..e103e6294a41a 100644 --- a/src/libcore/uint-template.rs +++ b/src/libcore/uint-template.rs @@ -51,14 +51,35 @@ pub pure fn is_negative(x: T) -> bool { x < 0 as T } pub pure fn is_nonpositive(x: T) -> bool { x <= 0 as T } pub pure fn is_nonnegative(x: T) -> bool { x >= 0 as T } +#[inline(always)] +/// Iterate over the range [`start`,`start`+`step`..`stop`) +pub pure fn range_step(start: T, stop: T, step: T, it: fn(T) -> bool) { + let mut i = start; + if step == 0 { + fail ~"range_step called with step == 0"; + } else if step > 0 { // ascending + while i < stop { + if !it(i) { break } + i += step; + } + } else { // descending + while i > stop { + if !it(i) { break } + i += step; + } + } +} + #[inline(always)] /// Iterate over the range [`lo`..`hi`) pub pure fn range(lo: T, hi: T, it: fn(T) -> bool) { - let mut i = lo; - while i < hi { - if !it(i) { break } - i += 1 as T; - } + range_step(lo, hi, 1 as T, it); +} + +#[inline(always)] +/// Iterate over the range [`hi`..`lo`) +pub pure fn range_rev(hi: T, lo: T, it: fn(T) -> bool) { + range_step(hi, lo, -1 as T, it); } /// Computes the bitwise complement From aeb3cbdff2a23155fcec8e494aa763c9100c7e29 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Thu, 10 Jan 2013 21:18:01 +0100 Subject: [PATCH 2/2] libcore: Correct behaviour of range_step for uint, tests for range* functions. Splits the range_step function into the two directions (up, low -> high, and down, high -> low) for the uint types, since there is no way to have `step < 0` for a backwards range. --- src/libcore/int-template.rs | 42 ++++++++++++++++ src/libcore/uint-template.rs | 97 ++++++++++++++++++++++++++++++------ 2 files changed, 124 insertions(+), 15 deletions(-) diff --git a/src/libcore/int-template.rs b/src/libcore/int-template.rs index 9035abd6d1a04..988ebd35cab3f 100644 --- a/src/libcore/int-template.rs +++ b/src/libcore/int-template.rs @@ -295,3 +295,45 @@ fn test_times_negative() { use iter::Times; for (-10).times { log(error, ~"nope!"); } } + +#[test] +pub fn test_ranges() { + let mut l = ~[]; + + for range(0,3) |i| { + l.push(i); + } + for range_rev(13,10) |i| { + l.push(i); + } + for range_step(20,26,2) |i| { + l.push(i); + } + for range_step(36,30,-2) |i| { + l.push(i); + } + assert l == ~[0,1,2, + 13,12,11, + 20,22,24, + 36,34,32]; + + // None of the `fail`s should execute. + for range(10,0) |_i| { + fail ~"unreachable"; + } + for range_rev(0,10) |_i| { + fail ~"unreachable"; + } + for range_step(10,0,1) |_i| { + fail ~"unreachable"; + } + for range_step(0,10,-1) |_i| { + fail ~"unreachable"; + } +} + +#[test] +#[should_fail] +fn test_range_step_zero_step() { + for range_step(0,10,0) |_i| {} +} diff --git a/src/libcore/uint-template.rs b/src/libcore/uint-template.rs index e103e6294a41a..886e6b121a058 100644 --- a/src/libcore/uint-template.rs +++ b/src/libcore/uint-template.rs @@ -52,34 +52,53 @@ pub pure fn is_nonpositive(x: T) -> bool { x <= 0 as T } pub pure fn is_nonnegative(x: T) -> bool { x >= 0 as T } #[inline(always)] -/// Iterate over the range [`start`,`start`+`step`..`stop`) -pub pure fn range_step(start: T, stop: T, step: T, it: fn(T) -> bool) { +/** + * Iterate over the range [`start`,`start`+`step`..`stop`) + * + * Note that `uint` requires separate `range_step` functions for each + * direction. + * + */ +pub pure fn range_step_up(start: T, stop: T, step: T, it: fn(T) -> bool) { let mut i = start; if step == 0 { - fail ~"range_step called with step == 0"; - } else if step > 0 { // ascending - while i < stop { - if !it(i) { break } - i += step; - } - } else { // descending - while i > stop { - if !it(i) { break } - i += step; - } + fail ~"range_step_up called with step == 0"; + } + while i < stop { + if !it(i) { break } + i += step; + } +} + +#[inline(always)] +/** + * Iterate over the range [`start`,`start`-`step`..`stop`) + * + * Note that `uint` requires separate `range_step` functions for each + * direction. + * + */ +pub pure fn range_step_down(start: T, stop: T, step: T, it: fn(T) -> bool) { + let mut i = start; + if step == 0 { + fail ~"range_step_down called with step == 0"; + } + while i > stop { + if !it(i) { break } + i -= step; } } #[inline(always)] /// Iterate over the range [`lo`..`hi`) pub pure fn range(lo: T, hi: T, it: fn(T) -> bool) { - range_step(lo, hi, 1 as T, it); + range_step_up(lo, hi, 1 as T, it); } #[inline(always)] /// Iterate over the range [`hi`..`lo`) pub pure fn range_rev(hi: T, lo: T, it: fn(T) -> bool) { - range_step(hi, lo, -1 as T, it); + range_step_down(hi, lo, 1 as T, it); } /// Computes the bitwise complement @@ -313,3 +332,51 @@ pub fn test_times() { for ten.times { accum += 1; } assert (accum == 10); } +use io; +#[test] +pub fn test_ranges() { + let mut l = ~[]; + + for range(0,3) |i| { + l.push(i); + } + for range_rev(13,10) |i| { + l.push(i); + } + for range_step_up(20,26,2) |i| { + l.push(i); + } + for range_step_down(36,30,2) |i| { + l.push(i); + } + + assert l == ~[0,1,2, + 13,12,11, + 20,22,24, + 36,34,32]; + + // None of the `fail`s should execute. + for range(0,0) |_i| { + fail ~"unreachable"; + } + for range_rev(0,0) |_i| { + fail ~"unreachable"; + } + for range_step_up(10,0,1) |_i| { + fail ~"unreachable"; + } + for range_step_down(0,10,1) |_i| { + fail ~"unreachable"; + } +} + +#[test] +#[should_fail] +fn test_range_step_up_zero_step() { + for range_step_up(0,10,0) |_i| {} +} +#[test] +#[should_fail] +fn test_range_step_down_zero_step() { + for range_step_down(0,10,0) |_i| {} +}