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 { + fn iter(blk: fn(A)); +} + +impl of iterable 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 for fn@(fn(int)) { + fn iter(blk: fn(&&int)) { + self {|i| blk(i)} + } +} + +impl of iterable for fn@(fn(uint)) { + fn iter(blk: fn(&&uint)) { + self {|i| blk(i)} + } +} + +impl of iterable for [A] { + fn iter(blk: fn(A)) { + vec::iter(self, blk) + } +} + +impl of iterable for option { + fn iter(blk: fn(A)) { + option::may(self, blk) + } +} + +fn enumerate>(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>(self: IA, prd: fn@(A) -> bool, blk: fn(A)) { + self.iter {|a| + if prd(a) { blk(a) } + } +} + +fn map>(self: IA, cnv: fn@(A) -> B, blk: fn(B)) { + self.iter {|a| + let b = cnv(a); + blk(b); + } +} + +fn flat_map,IB:iterable>( + self: IA, cnv: fn@(A) -> IB, blk: fn(B)) { + self.iter {|a| + cnv(a).iter(blk) + } +} + +fn foldl>(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>(self: IA) -> [A] { + foldl::(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 { + 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]; +} + +