about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2012-01-31 18:52:20 -0800
committerNiko Matsakis <niko@alum.mit.edu>2012-01-31 19:21:26 -0800
commit56db37d4c7fea8085f80783d1f3dc3204fcfc0b6 (patch)
tree4d891ff22d4d1d15bccd0893fdf4c289af9af5a5
parente5d095d67e3926fa104ac495076fe9d4cd4f5562 (diff)
downloadrust-56db37d4c7fea8085f80783d1f3dc3204fcfc0b6.tar.gz
rust-56db37d4c7fea8085f80783d1f3dc3204fcfc0b6.zip
add iter library in preliminary form (limited syntactic support)
-rw-r--r--src/libcore/core.rc4
-rw-r--r--src/libcore/iter.rs171
2 files changed, 173 insertions, 2 deletions
diff --git a/src/libcore/core.rc b/src/libcore/core.rc
index b90c1c16d1a..3bc5a031949 100644
--- a/src/libcore/core.rc
+++ b/src/libcore/core.rc
@@ -30,7 +30,7 @@ This behavior can be disabled with the `no_core` crate attribute."
 
 export box, char, float, bessel, f32, f64, int, str, ptr;
 export uint, u8, u32, u64, vec, bool;
-export either, option, result;
+export either, option, result, iter;
 export ctypes, sys, unsafe, comm, task, logging;
 export extfmt;
 export math;
@@ -64,7 +64,7 @@ mod either;
 mod option;
 mod result;
 mod tuple;
-
+mod iter;
 
 // Runtime and language-primitive support
 
diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs
new file mode 100644
index 00000000000..7aa08a6980c
--- /dev/null
+++ b/src/libcore/iter.rs
@@ -0,0 +1,171 @@
+iface iterable<A> {
+    fn iter(blk: fn(A));
+}
+
+impl<A> of iterable<A> for fn@(fn(A)) {
+    fn iter(blk: fn(A)) {
+        self(blk);
+    }
+}
+
+// accomodate the fact that int/uint are passed by value by default:
+impl of iterable<int> for fn@(fn(int)) {
+    fn iter(blk: fn(&&int)) {
+        self {|i| blk(i)}
+    }
+}
+
+impl of iterable<uint> for fn@(fn(uint)) {
+    fn iter(blk: fn(&&uint)) {
+        self {|i| blk(i)}
+    }
+}
+
+impl<A> of iterable<A> for [A] {
+    fn iter(blk: fn(A)) {
+        vec::iter(self, blk)
+    }
+}
+
+impl<A> of iterable<A> for option<A> {
+    fn iter(blk: fn(A)) {
+        option::may(self, blk)
+    }
+}
+
+fn enumerate<A,IA:iterable<A>>(self: IA, blk: fn(uint, A)) {
+    let i = 0u;
+    self.iter {|a|
+        blk(i, a);
+        i += 1u;
+    }
+}
+
+// Here: we have to use fn@ for predicates and map functions, because
+// we will be binding them up into a closure.  Disappointing.  A true
+// region type system might be able to do better than this.
+
+fn filter<A,IA:iterable<A>>(self: IA, prd: fn@(A) -> bool, blk: fn(A)) {
+    self.iter {|a|
+        if prd(a) { blk(a) }
+    }
+}
+
+fn map<A,B,IA:iterable<A>>(self: IA, cnv: fn@(A) -> B, blk: fn(B)) {
+    self.iter {|a|
+        let b = cnv(a);
+        blk(b);
+    }
+}
+
+fn flat_map<A,B,IA:iterable<A>,IB:iterable<B>>(
+    self: IA, cnv: fn@(A) -> IB, blk: fn(B)) {
+    self.iter {|a|
+        cnv(a).iter(blk)
+    }
+}
+
+fn foldl<A,B:copy,IA:iterable<A>>(self: IA, b0: B, blk: fn(B, A) -> B) -> B {
+    let b = b0;
+    self.iter {|a|
+        b = blk(b, a);
+    }
+    ret b;
+}
+
+fn to_list<A:copy,IA:iterable<A>>(self: IA) -> [A] {
+    foldl::<A,[A],IA>(self, [], {|r, a| r + [a]})
+}
+
+fn repeat(times: uint, blk: fn()) {
+    let i = 0u;
+    while i < times {
+        blk();
+        i += 1u;
+    }
+}
+
+
+#[test]
+fn test_enumerate() {
+    enumerate(["0", "1", "2"]) {|i,j|
+        assert #fmt["%u",i] == j;
+    }
+}
+
+#[test]
+fn test_map_and_to_list() {
+    let a = bind vec::iter([0, 1, 2], _);
+    let b = bind map(a, {|i| i*2}, _);
+    let c = to_list(b);
+    assert c == [0, 2, 4];
+}
+
+#[test]
+fn test_map_directly_on_vec() {
+    let b = bind map([0, 1, 2], {|i| i*2}, _);
+    let c = to_list(b);
+    assert c == [0, 2, 4];
+}
+
+#[test]
+fn test_filter_on_int_range() {
+    fn is_even(&&i: int) -> bool {
+        ret (i % 2) == 0;
+    }
+
+    let l = to_list(bind filter(bind int::range(0, 10, _), is_even, _));
+    assert l == [0, 2, 4, 6, 8];
+}
+
+#[test]
+fn test_filter_on_uint_range() {
+    fn is_even(&&i: uint) -> bool {
+        ret (i % 2u) == 0u;
+    }
+
+    let l = to_list(bind filter(bind uint::range(0u, 10u, _), is_even, _));
+    assert l == [0u, 2u, 4u, 6u, 8u];
+}
+
+#[test]
+fn test_flat_map_with_option() {
+    fn if_even(&&i: int) -> option<int> {
+        if (i % 2) == 0 { some(i) }
+        else { none }
+    }
+
+    let a = bind vec::iter([0, 1, 2], _);
+    let b = bind flat_map(a, if_even, _);
+    let c = to_list(b);
+    assert c == [0, 2];
+}
+
+#[test]
+fn test_flat_map_with_list() {
+    fn repeat(&&i: int) -> [int] {
+        let r = [];
+        int::range(0, i) {|_j| r += [i]; }
+        r
+    }
+
+    let a = bind vec::iter([0, 1, 2, 3], _);
+    let b = bind flat_map(a, repeat, _);
+    let c = to_list(b);
+    #debug["c = %?", c];
+    assert c == [1, 2, 2, 3, 3, 3];
+}
+
+#[test]
+fn test_repeat() {
+    let c = [],
+        i = 0u;
+    repeat(5u) {||
+        c += [(i * i)];
+        i += 1u;
+    };
+    #debug["c = %?", c];
+    assert c == [0u, 1u, 4u, 9u, 16u];
+}
+
+