Skip to content

Commit d162fa2

Browse files
bstriebrson
authored andcommitted
A new times method on numeric types
This method is intended to elegantly subsume two common iteration functions. The first is `iter::range`, which is used identically to the method introduced in this commit, but currently works only on uints. The second is a common case of `{int, i8, uint, etc.}::range`, in the case where the inductive variable is ignored. Compare the usage of the three: ``` for iter::range(100u) { // do whatever } for int::range(0, 100) |_i| { // do whatever } for 100.times { // do whatever } ``` I feel that the latter reads much more nicely than the first two approaches, and unlike the first two the new method allows the user to ignore the specific type of the number (ineed, if we're throwing away the inductive variable, who cares what type it is?). A minor benefit is that this new method will be somewhat familiar to users of Ruby, from which we borrow the name "times".
1 parent a8112f3 commit d162fa2

File tree

6 files changed

+91
-17
lines changed

6 files changed

+91
-17
lines changed

src/libcore/core.rs

+11-11
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,24 @@ import option_iter::extensions;
1212
import ptr::extensions;
1313
import rand::extensions;
1414
import result::extensions;
15-
import int::num;
16-
import i8::num;
17-
import i16::num;
18-
import i32::num;
19-
import i64::num;
20-
import uint::num;
21-
import u8::num;
22-
import u16::num;
23-
import u32::num;
24-
import u64::num;
15+
import int::{num, times};
16+
import i8::{num, times};
17+
import i16::{num, times};
18+
import i32::{num, times};
19+
import i64::{num, times};
20+
import uint::{num, times};
21+
import u8::{num, times};
22+
import u16::{num, times};
23+
import u32::{num, times};
24+
import u64::{num, times};
2525
import float::num;
2626
import f32::num;
2727
import f64::num;
2828

2929
export path, option, some, none, unreachable;
3030
export extensions;
3131
// The following exports are the extension impls for numeric types
32-
export num;
32+
export num, times;
3333

3434
// Export the log levels as global constants. Higher levels mean
3535
// more-verbosity. Error is the bottom level, default logging level is

src/libcore/int-template.rs

+34-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export range;
1111
export compl;
1212
export abs;
1313
export parse_buf, from_str, to_str, to_str_bytes, str;
14-
export num, ord, eq;
14+
export num, ord, eq, times;
1515

1616
const min_value: T = -1 as T << (inst::bits - 1 as T);
1717
const max_value: T = min_value - 1 as T;
@@ -135,6 +135,25 @@ impl num of num::num for T {
135135
fn from_int(n: int) -> T { ret n as T; }
136136
}
137137

138+
impl times of iter::times for T {
139+
#[inline(always)]
140+
#[doc = "A convenience form for basic iteration. Given a variable `x` \
141+
of any numeric type, the expression `for x.times { /* anything */ }` \
142+
will execute the given function exactly x times. If we assume that \
143+
`x` is an int, this is functionally equivalent to \
144+
`for int::range(0, x) |_i| { /* anything */ }`."]
145+
fn times(it: fn() -> bool) {
146+
if self < 0 {
147+
fail #fmt("The .times method expects a nonnegative number, \
148+
but found %?", self);
149+
}
150+
let mut i = self;
151+
while i > 0 {
152+
if !it() { break }
153+
i -= 1;
154+
}
155+
}
156+
}
138157

139158
// FIXME: Has alignment issues on windows and 32-bit linux (#2609)
140159
#[test]
@@ -206,8 +225,22 @@ fn test_ifaces() {
206225
assert (ten.mul(two) == ten.from_int(20));
207226
assert (ten.div(two) == ten.from_int(5));
208227
assert (ten.modulo(two) == ten.from_int(0));
228+
assert (ten.neg() == ten.from_int(-10));
209229
}
210230

211231
test(10 as T);
212232
}
213233

234+
#[test]
235+
fn test_times() {
236+
let ten = 10 as T;
237+
let mut accum = 0;
238+
for ten.times { accum += 1; }
239+
assert (accum == 10);
240+
}
241+
242+
#[test]
243+
#[should_fail]
244+
fn test_times_negative() {
245+
for (-10).times { log(error, "nope!"); }
246+
}

src/libcore/iter.rs

+4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ iface base_iter<A> {
33
fn size_hint() -> option<uint>;
44
}
55

6+
iface times {
7+
fn times(it: fn() -> bool);
8+
}
9+
610
fn eachi<A,IA:base_iter<A>>(self: IA, blk: fn(uint, A) -> bool) {
711
let mut i = 0u;
812
for self.each |a| {

src/libcore/uint-template.rs

+25-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export range;
1111
export compl;
1212
export to_str, to_str_bytes;
1313
export from_str, from_str_radix, str, parse_buf;
14-
export num, ord, eq;
14+
export num, ord, eq, times;
1515

1616
const min_value: T = 0 as T;
1717
const max_value: T = 0 as T - 1 as T;
@@ -104,6 +104,22 @@ fn parse_buf(buf: ~[u8], radix: uint) -> option<T> {
104104
};
105105
}
106106

107+
impl times of iter::times for T {
108+
#[inline(always)]
109+
#[doc = "A convenience form for basic iteration. Given a variable `x` \
110+
of any numeric type, the expression `for x.times { /* anything */ }` \
111+
will execute the given function exactly x times. If we assume that \
112+
`x` is an int, this is functionally equivalent to \
113+
`for int::range(0, x) |_i| { /* anything */ }`."]
114+
fn times(it: fn() -> bool) {
115+
let mut i = self;
116+
while i > 0 {
117+
if !it() { break }
118+
i -= 1;
119+
}
120+
}
121+
}
122+
107123
/// Parse a string to an int
108124
fn from_str(s: str) -> option<T> { parse_buf(str::bytes(s), 10u) }
109125

@@ -259,3 +275,11 @@ fn to_str_radix1() {
259275
fn to_str_radix17() {
260276
uint::to_str(100u, 17u);
261277
}
278+
279+
#[test]
280+
fn test_times() {
281+
let ten = 10 as T;
282+
let mut accum = 0;
283+
for ten.times { accum += 1; }
284+
assert (accum == 10);
285+
}

src/test/run-pass/numeric-method-autoexport.rs

+15-2
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,37 @@
1-
2-
31
// This file is intended to test only that methods are automatically
42
// reachable for each numeric type, for each exported impl, with no imports
53
// necessary. Testing the methods of the impls is done within the source
64
// file for each numeric type.
75
fn main() {
6+
// ints
87
// num
98
assert 15.add(6) == 21;
109
assert 15i8.add(6i8) == 21i8;
1110
assert 15i16.add(6i16) == 21i16;
1211
assert 15i32.add(6i32) == 21i32;
1312
assert 15i64.add(6i64) == 21i64;
13+
// times
14+
let bar = 15.times;
15+
let bar = 15i8.times;
16+
let bar = 15i16.times;
17+
let bar = 15i32.times;
18+
let bar = 15i64.times;
1419

20+
// uints
1521
// num
1622
assert 15u.add(6u) == 21u;
1723
assert 15u8.add(6u8) == 21u8;
1824
assert 15u16.add(6u16) == 21u16;
1925
assert 15u32.add(6u32) == 21u32;
2026
assert 15u64.add(6u64) == 21u64;
27+
// times
28+
let bar = 15u.times;
29+
let bar = 15u8.times;
30+
let bar = 15u16.times;
31+
let bar = 15u32.times;
32+
let bar = 15u64.times;
2133

34+
// floats
2235
// num
2336
assert 10f.to_int() == 10;
2437
assert 10f32.to_int() == 10;

src/test/run-pass/static-impl.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ mod b {
1111

1212
impl util for uint {
1313
fn str() -> str { uint::str(self) }
14-
fn times(f: fn(uint)) {
14+
fn multi(f: fn(uint)) {
1515
let mut c = 0u;
1616
while c < self { f(c); c += 1u; }
1717
}
@@ -37,6 +37,6 @@ fn main() {
3737
assert (~[3, 4]).map_(|a| a + 4 )[0] == 7;
3838
assert (~[3, 4]).map_::<uint>(|a| a as uint + 4u )[0] == 7u;
3939
let mut x = 0u;
40-
10u.times(|_n| x += 2u );
40+
10u.multi(|_n| x += 2u );
4141
assert x == 20u;
4242
}

0 commit comments

Comments
 (0)