about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorFelix S. Klock II <pnkfelix@pnkfx.org>2013-06-27 14:20:42 +0200
committerFelix S. Klock II <pnkfelix@pnkfx.org>2013-07-10 09:35:35 +0200
commit3c19f1bca83be3f4abef378d0a4cd852c8615164 (patch)
tree02e3a0567d5295474bb41f278ddb7509138d91f9 /src/libstd
parent41dcec2fe16e272016ae77d10a6a5ff3a737f192 (diff)
downloadrust-3c19f1bca83be3f4abef378d0a4cd852c8615164.tar.gz
rust-3c19f1bca83be3f4abef378d0a4cd852c8615164.zip
Refactored int/uint range code in preparation for change to range_rev semantics.
Also added unit tests of range code to test refactoring.  The
num-range-rev.rs test will need to be updated when the range_rev
semantics change.
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/num/int_macros.rs88
-rw-r--r--src/libstd/num/uint_macros.rs93
2 files changed, 148 insertions, 33 deletions
diff --git a/src/libstd/num/int_macros.rs b/src/libstd/num/int_macros.rs
index 75e0bbcb71b..4fd30be80e6 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 {
diff --git a/src/libstd/num/uint_macros.rs b/src/libstd/num/uint_macros.rs
index de1b997b14b..09397ecfd77 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]