]> git.lizzy.rs Git - rust.git/commitdiff
Implement DoubleEndedIterator on Range
authorKevin Ballard <kevin@sb.org>
Wed, 7 Aug 2013 05:34:22 +0000 (22:34 -0700)
committerCorey Richardson <corey@octayn.net>
Thu, 8 Aug 2013 02:41:09 +0000 (22:41 -0400)
Range is now invertable as long as its element type conforms to Integer.

Remove int::range_rev() et al in favor of range().invert().

src/libstd/iterator.rs
src/libstd/num/int_macros.rs
src/libstd/num/uint_macros.rs
src/libstd/run.rs
src/libstd/trie.rs
src/test/bench/core-map.rs
src/test/run-fail/assert-eq-macro-fail [new file with mode: 0755]
src/test/run-pass/num-range-rev.rs

index 29f54bd10fba152bffdd3805c9d5aa6936400eb0..d10a5541e41a683fef643f9c02aa2957abf2a15c 100644 (file)
@@ -18,9 +18,9 @@
 */
 
 use cmp;
-use num::{Zero, One, Saturating};
+use num::{Zero, One, Integer, Saturating};
 use option::{Option, Some, None};
-use ops::{Add, Mul};
+use ops::{Add, Mul, Sub};
 use cmp::Ord;
 use clone::Clone;
 use uint;
@@ -1531,7 +1531,7 @@ pub fn range<A: Add<A, A> + Ord + Clone + One>(start: A, stop: A) -> Range<A> {
     Range{state: start, stop: stop, one: One::one()}
 }
 
-impl<A: Add<A, A> + Ord + Clone + One> Iterator<A> for Range<A> {
+impl<A: Add<A, A> + Ord + Clone> Iterator<A> for Range<A> {
     #[inline]
     fn next(&mut self) -> Option<A> {
         if self.state < self.stop {
@@ -1544,6 +1544,22 @@ fn next(&mut self) -> Option<A> {
     }
 }
 
+impl<A: Sub<A, A> + Integer + Ord + Clone> DoubleEndedIterator<A> for Range<A> {
+    #[inline]
+    fn next_back(&mut self) -> Option<A> {
+        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 {
+            None
+        }
+    }
+}
+
 impl<A: Add<A, A> + Clone> Iterator<A> for Counter<A> {
     #[inline]
     fn next(&mut self) -> Option<A> {
@@ -2121,4 +2137,17 @@ fn test_random_access_cycle() {
         check_randacc_iter(xs.iter().cycle().take_(27), 27);
         check_randacc_iter(empty.iter().cycle(), 0);
     }
+
+    #[test]
+    fn test_double_ended_range() {
+        assert_eq!(range(11i, 14).invert().collect::<~[int]>(), ~[13i, 12, 11]);
+        for _ in range(10i, 0).invert() {
+            fail!("unreachable");
+        }
+
+        assert_eq!(range(11u, 14).invert().collect::<~[uint]>(), ~[13u, 12, 11]);
+        for _ in range(10u, 0).invert() {
+            fail!("unreachable");
+        }
+    }
 }
index 9842a570d7ea7e3c405245d5af9f9e4a17857bf7..b692bedebfd54f0ed17b39f5fcc99701abec5d32 100644 (file)
@@ -124,14 +124,6 @@ pub fn range_step_inclusive(start: $T, last: $T, step: $T, it: &fn($T) -> bool)
     range_step_core(start, last, step, Closed, it)
 }
 
-
-#[inline]
-/// Iterate over the range (`hi`..`lo`]
-pub fn range_rev(hi: $T, lo: $T, it: &fn($T) -> bool) -> bool {
-    if hi == min_value { return true; }
-    range_step_inclusive(hi-1, lo, -1 as $T, it)
-}
-
 impl Num for $T {}
 
 #[cfg(not(test))]
@@ -889,10 +881,6 @@ fn test_int_from_str_overflow() {
     fn test_ranges() {
         let mut l = ~[];
 
-        do range_rev(14,11) |i| {
-            l.push(i);
-            true
-        };
         do range_step(20,26,2) |i| {
             l.push(i);
             true
@@ -917,8 +905,7 @@ fn test_ranges() {
             l.push(i);
             true
         };
-        assert_eq!(l, ~[13,12,11,
-                        20,22,24,
+        assert_eq!(l, ~[20,22,24,
                         36,34,32,
                         max_value-2,
                         max_value-3,max_value-1,
@@ -926,9 +913,6 @@ fn test_ranges() {
                         min_value+3,min_value+1]);
 
         // None of the `fail`s should execute.
-        do range_rev(0,10) |_i| {
-            fail!(~"unreachable");
-        };
         do range_step(10,0,1) |_i| {
             fail!(~"unreachable");
         };
index a2874c9670390816c034777c231aa4d0179b048a..29b8f29d87d3f866a37bff576ea9e408be768687 100644 (file)
@@ -125,13 +125,6 @@ pub fn range_step_inclusive(start: $T, last: $T, step: $T_SIGNED, it: &fn($T) ->
     range_step_core(start, last, step, Closed, it)
 }
 
-#[inline]
-/// Iterate over the range (`hi`..`lo`]
-pub fn range_rev(hi: $T, lo: $T, it: &fn($T) -> bool) -> bool {
-    if hi == min_value { return true; }
-    range_step_inclusive(hi-1, lo, -1 as $T_SIGNED, it)
-}
-
 impl Num for $T {}
 
 #[cfg(not(test))]
@@ -654,10 +647,6 @@ pub fn to_str_radix37() {
     pub fn test_ranges() {
         let mut l = ~[];
 
-        do range_rev(14,11) |i| {
-            l.push(i);
-            true
-        };
         do range_step(20,26,2) |i| {
             l.push(i);
             true
@@ -683,8 +672,7 @@ pub fn test_ranges() {
             true
         };
 
-        assert_eq!(l, ~[13,12,11,
-                        20,22,24,
+        assert_eq!(l, ~[20,22,24,
                         36,34,32,
                         max_value-2,
                         max_value-3,max_value-1,
@@ -692,9 +680,6 @@ pub fn test_ranges() {
                         min_value+3,min_value+1]);
 
         // None of the `fail`s should execute.
-        do range_rev(0,0) |_i| {
-            fail!("unreachable");
-        };
         do range_step(10,0,1) |_i| {
             fail!("unreachable");
         };
index ef3d881c5fead58be610146747508263d37b2472..694aa672af7b3361365c6feb6818cca6229e188c 100644 (file)
@@ -632,7 +632,6 @@ fn spawn_process_os(prog: &str, args: &[~str],
 
     use libc::funcs::posix88::unistd::{fork, dup2, close, chdir, execvp};
     use libc::funcs::bsd44::getdtablesize;
-    use int;
 
     mod rustrt {
         use libc::c_void;
@@ -665,10 +664,9 @@ mod rustrt {
             fail!("failure in dup3(err_fd, 2): %s", os::last_os_error());
         }
         // close all other fds
-        do int::range_rev(getdtablesize() as int, 3) |fd| {
+        for fd in range(3, getdtablesize()).invert() {
             close(fd as c_int);
-            true
-        };
+        }
 
         do with_dirp(dir) |dirp| {
             if !dirp.is_null() && chdir(dirp) == -1 {
index a5efae542a1ff1dbaf87722707f728b5c799b7dc..5ef5526e5162d4833c3aeff09056c9d94fdc80d4 100644 (file)
@@ -282,13 +282,14 @@ fn each<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) -> bool {
     }
 
     fn each_reverse<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) -> bool {
-        do uint::range_rev(self.children.len(), 0) |idx| {
-            match self.children[idx] {
-                Internal(ref x) => x.each_reverse(|i,t| f(i,t)),
-                External(k, ref v) => f(&k, v),
-                Nothing => true
+        for elt in self.children.rev_iter() {
+            match *elt {
+                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 => ()
             }
         }
+        true
     }
 
     fn mutate_values<'a>(&'a mut self, f: &fn(&uint, &mut T) -> bool) -> bool {
@@ -539,10 +540,9 @@ fn test_each() {
     fn test_each_break() {
         let mut m = TrieMap::new();
 
-        do uint::range_rev(uint::max_value, uint::max_value - 10000) |x| {
+        for x in range(uint::max_value - 10000, uint::max_value).invert() {
             m.insert(x, x / 2);
-            true
-        };
+        }
 
         let mut n = uint::max_value - 10000;
         do m.each |k, v| {
@@ -580,10 +580,9 @@ fn test_each_reverse() {
     fn test_each_reverse_break() {
         let mut m = TrieMap::new();
 
-        do uint::range_rev(uint::max_value, uint::max_value - 10000) |x| {
+        for x in range(uint::max_value - 10000, uint::max_value).invert() {
             m.insert(x, x / 2);
-            true
-        };
+        }
 
         let mut n = uint::max_value - 1;
         do m.each_reverse |k, v| {
@@ -634,10 +633,9 @@ fn test_iteration() {
         let last = uint::max_value;
 
         let mut map = TrieMap::new();
-        do uint::range_rev(last, first) |x| {
+        for x in range(first, last).invert() {
             map.insert(x, x / 2);
-            true
-        };
+        }
 
         let mut i = 0;
         for (k, &v) in map.iter() {
index cf160ca31c6f185d3ae38b5a06ef6edda527674d..6475012e0097e9e7180f7eb55fce18ed49fe012e 100644 (file)
@@ -53,24 +53,21 @@ fn descending<M: MutableMap<uint, uint>>(map: &mut M, n_keys: uint) {
     io::println(" Descending integers:");
 
     do timed("insert") {
-        do uint::range_rev(n_keys, 0) |i| {
+        for i in range(0, n_keys).invert() {
             map.insert(i, i + 1);
-            true
-        };
+        }
     }
 
     do timed("search") {
-        do uint::range_rev(n_keys, 0) |i| {
+        for i in range(0, n_keys).invert() {
             assert_eq!(map.find(&i).unwrap(), &(i + 1));
-            true
-        };
+        }
     }
 
     do timed("remove") {
-        do uint::range_rev(n_keys, 0) |i| {
+        for i in range(0, n_keys) {
             assert!(map.remove(&i));
-            true
-        };
+        }
     }
 }
 
diff --git a/src/test/run-fail/assert-eq-macro-fail b/src/test/run-fail/assert-eq-macro-fail
new file mode 100755 (executable)
index 0000000..2841756
Binary files /dev/null and b/src/test/run-fail/assert-eq-macro-fail differ
index 5eecbe7e03afb207cec9f44a5a9a8cae76b33284..ea7d4a651f75d181b88bc80fa85fa9f771e9768d 100644 (file)
@@ -20,11 +20,11 @@ fn int_range(lo: int,  hi: int, it: &fn(int) -> bool) -> bool {
 }
 
 fn uint_range_rev(hi: uint, lo: uint, it: &fn(uint) -> bool) -> bool {
-    uint::range_rev(hi, lo, it)
+    range(lo, hi).invert().advance(it)
 }
 
 fn int_range_rev(hi: int,  lo: int, it: &fn(int) -> bool) -> bool {
-    int::range_rev(hi, lo, it)
+    range(lo, hi).invert().advance(it)
 }
 
 fn int_range_step(a: int, b: int, step: int, it: &fn(int) -> bool) -> bool {