diff --git a/src/libcore/core.rs b/src/libcore/core.rs index f97d2727194..e70a092d876 100644 --- a/src/libcore/core.rs +++ b/src/libcore/core.rs @@ -12,16 +12,16 @@ import option_iter::extensions; import ptr::extensions; import rand::extensions; import result::extensions; -import int::num; -import i8::num; -import i16::num; -import i32::num; -import i64::num; -import uint::num; -import u8::num; -import u16::num; -import u32::num; -import u64::num; +import int::{num, times}; +import i8::{num, times}; +import i16::{num, times}; +import i32::{num, times}; +import i64::{num, times}; +import uint::{num, times}; +import u8::{num, times}; +import u16::{num, times}; +import u32::{num, times}; +import u64::{num, times}; import float::num; import f32::num; import f64::num; @@ -29,7 +29,7 @@ import f64::num; export path, option, some, none, unreachable; export extensions; // The following exports are the extension impls for numeric types -export num; +export num, times; // Export the log levels as global constants. Higher levels mean // more-verbosity. Error is the bottom level, default logging level is diff --git a/src/libcore/int-template.rs b/src/libcore/int-template.rs index 407b810e95d..5c5cffb2ac1 100644 --- a/src/libcore/int-template.rs +++ b/src/libcore/int-template.rs @@ -11,7 +11,7 @@ export range; export compl; export abs; export parse_buf, from_str, to_str, to_str_bytes, str; -export num, ord, eq; +export num, ord, eq, times; const min_value: T = -1 as T << (inst::bits - 1 as T); const max_value: T = min_value - 1 as T; @@ -135,6 +135,25 @@ impl num of num::num for T { fn from_int(n: int) -> T { ret n as T; } } +impl times of iter::times for T { + #[inline(always)] + #[doc = "A convenience form for basic iteration. Given a variable `x` \ + of any numeric type, the expression `for x.times { /* anything */ }` \ + will execute the given function exactly x times. If we assume that \ + `x` is an int, this is functionally equivalent to \ + `for int::range(0, x) |_i| { /* anything */ }`."] + fn times(it: fn() -> bool) { + if self < 0 { + fail #fmt("The .times method expects a nonnegative number, \ + but found %?", self); + } + let mut i = self; + while i > 0 { + if !it() { break } + i -= 1; + } + } +} // FIXME: Has alignment issues on windows and 32-bit linux (#2609) #[test] @@ -206,8 +225,22 @@ fn test_ifaces() { assert (ten.mul(two) == ten.from_int(20)); assert (ten.div(two) == ten.from_int(5)); assert (ten.modulo(two) == ten.from_int(0)); + assert (ten.neg() == ten.from_int(-10)); } test(10 as T); } +#[test] +fn test_times() { + let ten = 10 as T; + let mut accum = 0; + for ten.times { accum += 1; } + assert (accum == 10); +} + +#[test] +#[should_fail] +fn test_times_negative() { + for (-10).times { log(error, "nope!"); } +} diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 0280221ebfc..55d47cfe75d 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -3,6 +3,10 @@ iface base_iter { fn size_hint() -> option; } +iface times { + fn times(it: fn() -> bool); +} + fn eachi>(self: IA, blk: fn(uint, A) -> bool) { let mut i = 0u; for self.each |a| { diff --git a/src/libcore/uint-template.rs b/src/libcore/uint-template.rs index 91b9eb856e4..0433cd7ce30 100644 --- a/src/libcore/uint-template.rs +++ b/src/libcore/uint-template.rs @@ -11,7 +11,7 @@ export range; export compl; export to_str, to_str_bytes; export from_str, from_str_radix, str, parse_buf; -export num, ord, eq; +export num, ord, eq, times; const min_value: T = 0 as T; const max_value: T = 0 as T - 1 as T; @@ -104,6 +104,22 @@ fn parse_buf(buf: ~[u8], radix: uint) -> option { }; } +impl times of iter::times for T { + #[inline(always)] + #[doc = "A convenience form for basic iteration. Given a variable `x` \ + of any numeric type, the expression `for x.times { /* anything */ }` \ + will execute the given function exactly x times. If we assume that \ + `x` is an int, this is functionally equivalent to \ + `for int::range(0, x) |_i| { /* anything */ }`."] + fn times(it: fn() -> bool) { + let mut i = self; + while i > 0 { + if !it() { break } + i -= 1; + } + } +} + /// Parse a string to an int fn from_str(s: str) -> option { parse_buf(str::bytes(s), 10u) } @@ -259,3 +275,11 @@ fn to_str_radix1() { fn to_str_radix17() { uint::to_str(100u, 17u); } + +#[test] +fn test_times() { + let ten = 10 as T; + let mut accum = 0; + for ten.times { accum += 1; } + assert (accum == 10); +} diff --git a/src/test/run-pass/numeric-method-autoexport.rs b/src/test/run-pass/numeric-method-autoexport.rs index 6a7bd93b929..70aafa5e8f1 100644 --- a/src/test/run-pass/numeric-method-autoexport.rs +++ b/src/test/run-pass/numeric-method-autoexport.rs @@ -1,24 +1,37 @@ - - // This file is intended to test only that methods are automatically // reachable for each numeric type, for each exported impl, with no imports // necessary. Testing the methods of the impls is done within the source // file for each numeric type. fn main() { +// ints // num assert 15.add(6) == 21; assert 15i8.add(6i8) == 21i8; assert 15i16.add(6i16) == 21i16; assert 15i32.add(6i32) == 21i32; assert 15i64.add(6i64) == 21i64; + // times + let bar = 15.times; + let bar = 15i8.times; + let bar = 15i16.times; + let bar = 15i32.times; + let bar = 15i64.times; +// uints // num assert 15u.add(6u) == 21u; assert 15u8.add(6u8) == 21u8; assert 15u16.add(6u16) == 21u16; assert 15u32.add(6u32) == 21u32; assert 15u64.add(6u64) == 21u64; + // times + let bar = 15u.times; + let bar = 15u8.times; + let bar = 15u16.times; + let bar = 15u32.times; + let bar = 15u64.times; +// floats // num assert 10f.to_int() == 10; assert 10f32.to_int() == 10; diff --git a/src/test/run-pass/static-impl.rs b/src/test/run-pass/static-impl.rs index 149efcf5da4..fe083872792 100644 --- a/src/test/run-pass/static-impl.rs +++ b/src/test/run-pass/static-impl.rs @@ -11,7 +11,7 @@ mod b { impl util for uint { fn str() -> str { uint::str(self) } - fn times(f: fn(uint)) { + fn multi(f: fn(uint)) { let mut c = 0u; while c < self { f(c); c += 1u; } } @@ -37,6 +37,6 @@ fn main() { assert (~[3, 4]).map_(|a| a + 4 )[0] == 7; assert (~[3, 4]).map_::(|a| a as uint + 4u )[0] == 7u; let mut x = 0u; - 10u.times(|_n| x += 2u ); + 10u.multi(|_n| x += 2u ); assert x == 20u; }