diff options
| author | bors <bors@rust-lang.org> | 2013-04-24 06:48:50 -0700 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2013-04-24 06:48:50 -0700 |
| commit | e26f992d5e199a1ff8c26733650d254d63be066a (patch) | |
| tree | c1aa3ef0f5e49f777912683ae95144541dd07cd1 /src/libcore | |
| parent | c8ac057545f7b2edf1e488aa4562138a6ed7a096 (diff) | |
| parent | 9860fe10a19cc4997e58861df905f8dbe4de3c5b (diff) | |
| download | rust-e26f992d5e199a1ff8c26733650d254d63be066a.tar.gz rust-e26f992d5e199a1ff8c26733650d254d63be066a.zip | |
auto merge of #6036 : huonw/rust/core-less-at, r=nikomatsakis
From a cursory `git grep` this removes the last part of `core` that requires on `@` (other than `io` and the task local data section). It renames `RandRes` to ~~StdRng~~ `IsaacRng` and `XorShiftState` to `XorShiftRng` as well as moving their constructors to static methods. To go with this, it adds `rng()` which is designed to be used when the programmer just wants a random number generator, without caring about which exact algorithm is being used. It also removes all the `gen_int`, `gen_uint`, `gen_char` (etc) methods on `RngUtil` (by moving the defintions to the actual `Rand` instances). The replacement is using `RngUtil::gen`, either type-inferred or with an annotation (`rng.gen::<uint>()`). I tried to have the `Rng` and `RngUtil` traits exported by `core::prelude` (since `core::rand` (except for `random()`) is useless without them), but this caused [an explosion of (seemingly unrelated) `error: unresolved import`'s](https://gist.github.com/5451839).
Diffstat (limited to 'src/libcore')
| -rw-r--r-- | src/libcore/flate.rs | 2 | ||||
| -rw-r--r-- | src/libcore/hashmap.rs | 2 | ||||
| -rw-r--r-- | src/libcore/os.rs | 2 | ||||
| -rw-r--r-- | src/libcore/rand.rs | 551 | ||||
| -rw-r--r-- | src/libcore/run.rs | 218 | ||||
| -rw-r--r-- | src/libcore/unstable/at_exit.rs | 2 |
6 files changed, 336 insertions, 441 deletions
diff --git a/src/libcore/flate.rs b/src/libcore/flate.rs index 70c96c9c806..5c4181c10cf 100644 --- a/src/libcore/flate.rs +++ b/src/libcore/flate.rs @@ -85,7 +85,7 @@ pub fn inflate_bytes(bytes: &const [u8]) -> ~[u8] { #[test] #[allow(non_implicitly_copyable_typarams)] fn test_flate_round_trip() { - let r = rand::Rng(); + let r = rand::rng(); let mut words = ~[]; for 20.times { words.push(r.gen_bytes(r.gen_uint_range(1, 10))); diff --git a/src/libcore/hashmap.rs b/src/libcore/hashmap.rs index 1d7cc8515a6..d2be0416371 100644 --- a/src/libcore/hashmap.rs +++ b/src/libcore/hashmap.rs @@ -56,7 +56,7 @@ fn resize_at(capacity: uint) -> uint { pub fn linear_map_with_capacity<K:Eq + Hash,V>( initial_capacity: uint) -> HashMap<K, V> { let r = rand::task_rng(); - linear_map_with_capacity_and_keys(r.gen_u64(), r.gen_u64(), + linear_map_with_capacity_and_keys(r.gen(), r.gen(), initial_capacity) } diff --git a/src/libcore/os.rs b/src/libcore/os.rs index fa3ca4577c6..1000fd88b52 100644 --- a/src/libcore/os.rs +++ b/src/libcore/os.rs @@ -1259,7 +1259,7 @@ mod tests { } fn make_rand_name() -> ~str { - let rng: @rand::Rng = rand::Rng(); + let rng = rand::rng(); let n = ~"TEST" + rng.gen_str(10u); assert!(getenv(n).is_none()); n diff --git a/src/libcore/rand.rs b/src/libcore/rand.rs index 919c7bbb036..cdf6a5bb63d 100644 --- a/src/libcore/rand.rs +++ b/src/libcore/rand.rs @@ -8,7 +8,34 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Random number generation +/*! +Random number generation. + +The key functions are `random()` and `RngUtil::gen()`. These are polymorphic +and so can be used to generate any type that implements `Rand`. Type inference +means that often a simple call to `rand::random()` or `rng.gen()` will +suffice, but sometimes an annotation is required, e.g. `rand::random::<float>()`. + +# Examples +~~~ +use core::rand::RngUtil; + +fn main() { + let rng = rand::rng(); + if rng.gen() { // bool + println(fmt!("int: %d, uint: %u", rng.gen(), rng.gen())) + } +} +~~~ + +~~~ +fn main () { + let tuple_ptr = rand::random::<~(f64, char)>(); + println(fmt!("%?", tuple_ptr)) +} +~~~ +*/ + use int; use prelude::*; @@ -20,98 +47,111 @@ use util; use vec; use libc::size_t; -/// A type that can be randomly generated using an RNG +/// A type that can be randomly generated using an Rng pub trait Rand { - fn rand(rng: @rand::Rng) -> Self; + fn rand<R: Rng>(rng: &R) -> Self; } impl Rand for int { - fn rand(rng: @rand::Rng) -> int { - rng.gen_int() + fn rand<R: Rng>(rng: &R) -> int { + if int::bits == 32 { + rng.next() as int + } else { + rng.gen::<i64>() as int + } } } impl Rand for i8 { - fn rand(rng: @rand::Rng) -> i8 { - rng.gen_i8() + fn rand<R: Rng>(rng: &R) -> i8 { + rng.next() as i8 } } impl Rand for i16 { - fn rand(rng: @rand::Rng) -> i16 { - rng.gen_i16() + fn rand<R: Rng>(rng: &R) -> i16 { + rng.next() as i16 } } impl Rand for i32 { - fn rand(rng: @rand::Rng) -> i32 { - rng.gen_i32() + fn rand<R: Rng>(rng: &R) -> i32 { + rng.next() as i32 } } impl Rand for i64 { - fn rand(rng: @rand::Rng) -> i64 { - rng.gen_i64() + fn rand<R: Rng>(rng: &R) -> i64 { + (rng.next() as i64 << 32) | rng.next() as i64 } } impl Rand for uint { - fn rand(rng: @rand::Rng) -> uint { - rng.gen_uint() + fn rand<R: Rng>(rng: &R) -> uint { + if uint::bits == 32 { + rng.next() as uint + } else { + rng.gen::<u64>() as uint + } } } impl Rand for u8 { - fn rand(rng: @rand::Rng) -> u8 { - rng.gen_u8() + fn rand<R: Rng>(rng: &R) -> u8 { + rng.next() as u8 } } impl Rand for u16 { - fn rand(rng: @rand::Rng) -> u16 { - rng.gen_u16() + fn rand<R: Rng>(rng: &R) -> u16 { + rng.next() as u16 } } impl Rand for u32 { - fn rand(rng: @rand::Rng) -> u32 { - rng.gen_u32() + fn rand<R: Rng>(rng: &R) -> u32 { + rng.next() } } impl Rand for u64 { - fn rand(rng: @rand::Rng) -> u64 { - rng.gen_u64() + fn rand<R: Rng>(rng: &R) -> u64 { + (rng.next() as u64 << 32) | rng.next() as u64 } } impl Rand for float { - fn rand(rng: @rand::Rng) -> float { - rng.gen_float() + fn rand<R: Rng>(rng: &R) -> float { + rng.gen::<f64>() as float } } impl Rand for f32 { - fn rand(rng: @rand::Rng) -> f32 { - rng.gen_f32() + fn rand<R: Rng>(rng: &R) -> f32 { + rng.gen::<f64>() as f32 } } +static scale : f64 = (u32::max_value as f64) + 1.0f64; impl Rand for f64 { - fn rand(rng: @rand::Rng) -> f64 { - rng.gen_f64() + fn rand<R: Rng>(rng: &R) -> f64 { + let u1 = rng.next() as f64; + let u2 = rng.next() as f64; + let u3 = rng.next() as f64; + + ((u1 / scale + u2) / scale + u3) / scale } } impl Rand for char { - fn rand(rng: @rand::Rng) -> char { - rng.gen_char() + fn rand<R: Rng>(rng: &R) -> char { + rng.next() as char } } impl Rand for bool { - fn rand(rng: @rand::Rng) -> bool { - rng.gen_bool() + fn rand<R: Rng>(rng: &R) -> bool { + rng.next() & 1u32 == 1u32 } } @@ -123,10 +163,10 @@ macro_rules! tuple_impl { $( $tyvar : Rand ),* > Rand for ( $( $tyvar ),* , ) { - fn rand (_rng: @Rng) -> ( $( $tyvar ),* , ) { + fn rand<R: Rng>(_rng: &R) -> ( $( $tyvar ),* , ) { ( - // use the $var's to get the appropriate number of repeats - // (they're not actually needed) + // use the $tyvar's to get the appropriate number of + // repeats (they're not actually needed) $( _rng.gen::<$tyvar>() ),* @@ -137,7 +177,7 @@ macro_rules! tuple_impl { } } -impl Rand for () { fn rand(_: @Rng) -> () { () } } +impl Rand for () { fn rand<R: Rng>(_: &R) -> () { () } } tuple_impl!{A} tuple_impl!{A, B} tuple_impl!{A, B, C} @@ -150,9 +190,9 @@ tuple_impl!{A, B, C, D, E, F, G, H, I} tuple_impl!{A, B, C, D, E, F, G, H, I, J} impl<T:Rand> Rand for Option<T> { - fn rand(rng: @rand::Rng) -> Option<T> { - if rng.gen_bool() { - Some(Rand::rand(rng)) + fn rand<R: Rng>(rng: &R) -> Option<T> { + if rng.gen() { + Some(rng.gen()) } else { None } @@ -160,11 +200,11 @@ impl<T:Rand> Rand for Option<T> { } impl<T: Rand> Rand for ~T { - fn rand(rng: @Rng) -> ~T { ~rng.gen() } + fn rand<R: Rng>(rng: &R) -> ~T { ~rng.gen() } } impl<T: Rand> Rand for @T { - fn rand(rng: @Rng) -> @T { @rng.gen() } + fn rand<R: Rng>(rng: &R) -> @T { @rng.gen() } } #[allow(non_camel_case_types)] // runtime type @@ -173,7 +213,7 @@ pub enum rust_rng {} #[abi = "cdecl"] pub mod rustrt { use libc::size_t; - use rand::rust_rng; + use super::rust_rng; pub extern { unsafe fn rand_seed_size() -> size_t; @@ -187,7 +227,7 @@ pub mod rustrt { /// A random number generator pub trait Rng { /// Return the next random integer - fn next(&self) -> u32; + pub fn next(&self) -> u32; } /// A value with a particular weight compared to other values @@ -197,91 +237,23 @@ pub struct Weighted<T> { } pub trait RngUtil { - /// Return a random value for a Rand type + /// Return a random value of a Rand type fn gen<T:Rand>(&self) -> T; /** - * Return a random int - * - * *Example* - * - * ~~~ - * - * use core::rand::RngUtil; - * - * fn main() { - * rng = rand::Rng(); - * println(fmt!("%d",rng.gen_int())); - * } - * ~~~ + * Return a int randomly chosen from the range [start, end), + * failing if start >= end */ - fn gen_int(&self) -> int; fn gen_int_range(&self, start: int, end: int) -> int; - /// Return a random i8 - fn gen_i8(&self) -> i8; - /// Return a random i16 - fn gen_i16(&self) -> i16; - /// Return a random i32 - fn gen_i32(&self) -> i32; - /// Return a random i64 - fn gen_i64(&self) -> i64; - /// Return a random uint - fn gen_uint(&self) -> uint; /** * Return a uint randomly chosen from the range [start, end), * failing if start >= end */ fn gen_uint_range(&self, start: uint, end: uint) -> uint; - /// Return a random u8 - fn gen_u8(&self) -> u8; - /// Return a random u16 - fn gen_u16(&self) -> u16; - /// Return a random u32 - fn gen_u32(&self) -> u32; - /// Return a random u64 - fn gen_u64(&self) -> u64; - /** - * Return random float in the interval [0,1] - * - * *Example* - * - * ~~~ - * - * use core::rand::RngUtil; - * - * fn main() { - * rng = rand::Rng(); - * println(fmt!("%f",rng.gen_float())); - * } - * ~~~ - */ - fn gen_float(&self) -> float; - /// Return a random f32 in the interval [0,1] - fn gen_f32(&self) -> f32; - /// Return a random f64 in the interval [0,1] - fn gen_f64(&self) -> f64; - /// Return a random char - fn gen_char(&self) -> char; /** * Return a char randomly chosen from chars, failing if chars is empty */ fn gen_char_from(&self, chars: &str) -> char; /** - * Return a random bool - * - * *Example* - * - * ~~~ - * - * use core::rand::RngUtil; - * - * fn main() { - * rng = rand::Rng(); - * println(fmt!("%b",rng.gen_bool())); - * } - * ~~~ - */ - fn gen_bool(&self) -> bool; - /** * Return a bool with a 1 in n chance of true * * *Example* @@ -291,7 +263,7 @@ pub trait RngUtil { * use core::rand::RngUtil; * * fn main() { - * rng = rand::Rng(); + * rng = rand::rng(); * println(fmt!("%b",rng.gen_weighted_bool(3))); * } * ~~~ @@ -307,7 +279,7 @@ pub trait RngUtil { * use core::rand::RngUtil; * * fn main() { - * rng = rand::Rng(); + * rng = rand::rng(); * println(rng.gen_str(8)); * } * ~~~ @@ -323,13 +295,12 @@ pub trait RngUtil { * use core::rand::RngUtil; * * fn main() { - * rng = rand::Rng(); + * rng = rand::rng(); * println(fmt!("%?",rng.gen_bytes(8))); * } * ~~~ */ fn gen_bytes(&self, len: uint) -> ~[u8]; - /// /** * Choose an item randomly, failing if values is empty * @@ -340,7 +311,7 @@ pub trait RngUtil { * use core::rand::RngUtil; * * fn main() { - * rng = rand::Rng(); + * rng = rand::rng(); * println(fmt!("%d",rng.choose([1,2,4,8,16,32]))); * } * ~~~ @@ -359,7 +330,7 @@ pub trait RngUtil { * use core::rand::RngUtil; * * fn main() { - * rng = rand::Rng(); + * rng = rand::rng(); * let x = [rand::Weighted {weight: 4, item: 'a'}, * rand::Weighted {weight: 2, item: 'b'}, * rand::Weighted {weight: 2, item: 'c'}]; @@ -379,7 +350,7 @@ pub trait RngUtil { * use core::rand::RngUtil; * * fn main() { - * rng = rand::Rng(); + * rng = rand::rng(); * let x = [rand::Weighted {weight: 4, item: 'a'}, * rand::Weighted {weight: 2, item: 'b'}, * rand::Weighted {weight: 2, item: 'c'}]; @@ -399,7 +370,7 @@ pub trait RngUtil { * use core::rand::RngUtil; * * fn main() { - * rng = rand::Rng(); + * rng = rand::rng(); * let x = [rand::Weighted {weight: 4, item: 'a'}, * rand::Weighted {weight: 2, item: 'b'}, * rand::Weighted {weight: 2, item: 'c'}]; @@ -418,7 +389,7 @@ pub trait RngUtil { * use core::rand::RngUtil; * * fn main() { - * rng = rand::Rng(); + * rng = rand::rng(); * println(fmt!("%?",rng.shuffle([1,2,3]))); * } * ~~~ @@ -434,7 +405,7 @@ pub trait RngUtil { * use core::rand::RngUtil; * * fn main() { - * rng = rand::Rng(); + * rng = rand::rng(); * let mut y = [1,2,3]; * rng.shuffle_mut(y); * println(fmt!("%?",y)); @@ -447,15 +418,10 @@ pub trait RngUtil { } /// Extension methods for random number generators -impl RngUtil for @Rng { +impl<R: Rng> RngUtil for R { /// Return a random value for a Rand type - fn gen<T:Rand>(&self) -> T { - Rand::rand(*self) - } - - /// Return a random int - fn gen_int(&self) -> int { - self.gen_i64() as int + fn gen<T: Rand>(&self) -> T { + Rand::rand(self) } /** @@ -464,32 +430,7 @@ impl RngUtil for @Rng { */ fn gen_int_range(&self, start: int, end: int) -> int { assert!(start < end); - start + int::abs(self.gen_int() % (end - start)) - } - - /// Return a random i8 - fn gen_i8(&self) -> i8 { - self.next() as i8 - } - - /// Return a random i16 - fn gen_i16(&self) -> i16 { - self.next() as i16 - } - - /// Return a random i32 - fn gen_i32(&self) -> i32 { - self.next() as i32 - } - - /// Return a random i64 - fn gen_i64(&self) -> i64 { - (self.next() as i64 << 32) | self.next() as i64 - } - - /// Return a random uint - fn gen_uint(&self) -> uint { - self.gen_u64() as uint + start + int::abs(self.gen::<int>() % (end - start)) } /** @@ -498,51 +439,7 @@ impl RngUtil for @Rng { */ fn gen_uint_range(&self, start: uint, end: uint) -> uint { assert!(start < end); - start + (self.gen_uint() % (end - start)) - } - - /// Return a random u8 - fn gen_u8(&self) -> u8 { - self.next() as u8 - } - - /// Return a random u16 - fn gen_u16(&self) -> u16 { - self.next() as u16 - } - - /// Return a random u32 - fn gen_u32(&self) -> u32 { - self.next() - } - - /// Return a random u64 - fn gen_u64(&self) -> u64 { - (self.next() as u64 << 32) | self.next() as u64 - } - - /// Return a random float in the interval [0,1] - fn gen_float(&self) -> float { - self.gen_f64() as float - } - - /// Return a random f32 in the interval [0,1] - fn gen_f32(&self) -> f32 { - self.gen_f64() as f32 - } - - /// Return a random f64 in the interval [0,1] - fn gen_f64(&self) -> f64 { - let u1 = self.next() as f64; - let u2 = self.next() as f64; - let u3 = self.next() as f64; - static scale : f64 = (u32::max_value as f64) + 1.0f64; - return ((u1 / scale + u2) / scale + u3) / scale; - } - - /// Return a random char - fn gen_char(&self) -> char { - self.next() as char + start + (self.gen::<uint>() % (end - start)) } /** @@ -555,11 +452,6 @@ impl RngUtil for @Rng { self.choose(cs) } - /// Return a random bool - fn gen_bool(&self) -> bool { - self.next() & 1u32 == 1u32 - } - /// Return a bool with a 1-in-n chance of true fn gen_weighted_bool(&self, n: uint) -> bool { if n == 0u { @@ -588,7 +480,7 @@ impl RngUtil for @Rng { /// Return a random byte string of the specified length fn gen_bytes(&self, len: uint) -> ~[u8] { do vec::from_fn(len) |_i| { - self.gen_u8() + self.gen() } } @@ -605,7 +497,6 @@ impl RngUtil for @Rng { Some(values[self.gen_uint_range(0u, values.len())]) } } - /** * Choose an item respecting the relative weights, failing if the sum of * the weights is 0 @@ -668,14 +559,18 @@ impl RngUtil for @Rng { vec::swap(values, i, self.gen_uint_range(0u, i + 1u)); } } +} +/// Create a random number generator with a default algorithm and seed. +pub fn rng() -> IsaacRng { + IsaacRng::new() } -struct RandRes { - rng: *rust_rng, +pub struct IsaacRng { + priv rng: *rust_rng, } -impl Drop for RandRes { +impl Drop for IsaacRng { fn finalize(&self) { unsafe { rustrt::rand_free(self.rng); @@ -683,21 +578,42 @@ impl Drop for RandRes { } } -fn RandRes(rng: *rust_rng) -> RandRes { - RandRes { - rng: rng +pub impl IsaacRng { + priv fn from_rust_rng(rng: *rust_rng) -> IsaacRng { + IsaacRng { + rng: rng + } + } + + /// Create an ISAAC random number generator with a system specified seed + fn new() -> IsaacRng { + IsaacRng::new_seeded(seed()) + } + + /** + * Create a random number generator using the specified seed. A generator + * constructed with a given seed will generate the same sequence of values as + * all other generators constructed with the same seed. The seed may be any + * length. + */ + fn new_seeded(seed: &[u8]) -> IsaacRng { + unsafe { + do vec::as_imm_buf(seed) |p, sz| { + IsaacRng::from_rust_rng(rustrt::rand_new_seeded(p, sz as size_t)) + } + } } } -impl Rng for @RandRes { - fn next(&self) -> u32 { +impl Rng for IsaacRng { + pub fn next(&self) -> u32 { unsafe { - return rustrt::rand_next((*self).rng); + return rustrt::rand_next(self.rng); } } } -/// Create a new random seed for seeded_rng +/// Create a new random seed for IsaacRng::new_seeded pub fn seed() -> ~[u8] { unsafe { let n = rustrt::rand_seed_size() as uint; @@ -709,38 +625,15 @@ pub fn seed() -> ~[u8] { } } -/// Create a random number generator with a system specified seed -pub fn Rng() -> @Rng { - seeded_rng(seed()) -} - -/** - * Create a random number generator using the specified seed. A generator - * constructed with a given seed will generate the same sequence of values as - * all other generators constructed with the same seed. The seed may be any - * length. - */ -pub fn seeded_rng(seed: &[u8]) -> @Rng { - @seeded_randres(seed) as @Rng -} - -fn seeded_randres(seed: &[u8]) -> @RandRes { - unsafe { - do vec::as_imm_buf(seed) |p, sz| { - @RandRes(rustrt::rand_new_seeded(p, sz as size_t)) - } - } -} - -struct XorShiftState { - mut x: u32, - mut y: u32, - mut z: u32, - mut w: u32, +struct XorShiftRng { + priv mut x: u32, + priv mut y: u32, + priv mut z: u32, + priv mut w: u32, } -impl Rng for XorShiftState { - fn next(&self) -> u32 { +impl Rng for XorShiftRng { + pub fn next(&self) -> u32 { let x = self.x; let t = x ^ (x << 11); self.x = self.y; @@ -752,41 +645,54 @@ impl Rng for XorShiftState { } } -pub fn xorshift() -> @Rng { - // constants taken from http://en.wikipedia.org/wiki/Xorshift - seeded_xorshift(123456789u32, 362436069u32, 521288629u32, 88675123u32) -} +pub impl XorShiftRng { + /// Create an xor shift random number generator with a default seed. + fn new() -> XorShiftRng { + // constants taken from http://en.wikipedia.org/wiki/Xorshift + XorShiftRng::new_seeded(123456789u32, 362436069u32, 521288629u32, 88675123u32) + } -pub fn seeded_xorshift(x: u32, y: u32, z: u32, w: u32) -> @Rng { - @XorShiftState { x: x, y: y, z: z, w: w } as @Rng -} + /** + * Create a random number generator using the specified seed. A generator + * constructed with a given seed will generate the same sequence of values as + * all other generators constructed with the same seed. + */ + fn new_seeded(x: u32, y: u32, z: u32, w: u32) -> XorShiftRng { + XorShiftRng { x: x, y: y, z: z, w: w } + } +} // used to make space in TLS for a random number generator -fn tls_rng_state(_v: @RandRes) {} +fn tls_rng_state(_v: @IsaacRng) {} /** * Gives back a lazily initialized task-local random number generator, * seeded by the system. Intended to be used in method chaining style, ie - * task_rng().gen_int(). + * `task_rng().gen::<int>()`. */ -pub fn task_rng() -> @Rng { - let r : Option<@RandRes>; +pub fn task_rng() -> @IsaacRng { + let r : Option<@IsaacRng>; unsafe { r = task::local_data::local_data_get(tls_rng_state); } match r { None => { unsafe { - let rng = seeded_randres(seed()); + let rng = @IsaacRng::new_seeded(seed()); task::local_data::local_data_set(tls_rng_state, rng); - @rng as @Rng + rng } } - Some(rng) => @rng as @Rng + Some(rng) => rng } } +// Allow direct chaining with `task_rng` +impl<R: Rng> Rng for @R { + fn next(&self) -> u32 { (*self).next() } +} + /** * Returns a random value of a Rand type, using the task's random number * generator. @@ -795,33 +701,32 @@ pub fn random<T: Rand>() -> T { task_rng().gen() } - #[cfg(test)] mod tests { use option::{Option, Some}; - use rand; + use super::*; #[test] - fn rng_seeded() { - let seed = rand::seed(); - let ra = rand::seeded_rng(seed); - let rb = rand::seeded_rng(seed); + fn test_rng_seeded() { + let seed = seed(); + let ra = IsaacRng::new_seeded(seed); + let rb = IsaacRng::new_seeded(seed); assert!(ra.gen_str(100u) == rb.gen_str(100u)); } #[test] - fn rng_seeded_custom_seed() { + fn test_rng_seeded_custom_seed() { // much shorter than generated seeds which are 1024 bytes let seed = [2u8, 32u8, 4u8, 32u8, 51u8]; - let ra = rand::seeded_rng(seed); - let rb = rand::seeded_rng(seed); + let ra = IsaacRng::new_seeded(seed); + let rb = IsaacRng::new_seeded(seed); assert!(ra.gen_str(100u) == rb.gen_str(100u)); } #[test] - fn rng_seeded_custom_seed2() { + fn test_rng_seeded_custom_seed2() { let seed = [2u8, 32u8, 4u8, 32u8, 51u8]; - let ra = rand::seeded_rng(seed); + let ra = IsaacRng::new_seeded(seed); // Regression test that isaac is actually using the above vector let r = ra.next(); error!("%?", r); @@ -830,8 +735,8 @@ mod tests { } #[test] - fn gen_int_range() { - let r = rand::Rng(); + fn test_gen_int_range() { + let r = rng(); let a = r.gen_int_range(-3, 42); assert!(a >= -3 && a < 42); assert!(r.gen_int_range(0, 1) == 0); @@ -841,13 +746,13 @@ mod tests { #[test] #[should_fail] #[ignore(cfg(windows))] - fn gen_int_from_fail() { - rand::Rng().gen_int_range(5, -2); + fn test_gen_int_from_fail() { + rng().gen_int_range(5, -2); } #[test] - fn gen_uint_range() { - let r = rand::Rng(); + fn test_gen_uint_range() { + let r = rng(); let a = r.gen_uint_range(3u, 42u); assert!(a >= 3u && a < 42u); assert!(r.gen_uint_range(0u, 1u) == 0u); @@ -857,28 +762,28 @@ mod tests { #[test] #[should_fail] #[ignore(cfg(windows))] - fn gen_uint_range_fail() { - rand::Rng().gen_uint_range(5u, 2u); + fn test_gen_uint_range_fail() { + rng().gen_uint_range(5u, 2u); } #[test] - fn gen_float() { - let r = rand::Rng(); - let a = r.gen_float(); - let b = r.gen_float(); + fn test_gen_float() { + let r = rng(); + let a = r.gen::<float>(); + let b = r.gen::<float>(); debug!((a, b)); } #[test] - fn gen_weighted_bool() { - let r = rand::Rng(); + fn test_gen_weighted_bool() { + let r = rng(); assert!(r.gen_weighted_bool(0u) == true); assert!(r.gen_weighted_bool(1u) == true); } #[test] - fn gen_str() { - let r = rand::Rng(); + fn test_gen_str() { + let r = rng(); debug!(r.gen_str(10u)); debug!(r.gen_str(10u)); debug!(r.gen_str(10u)); @@ -888,91 +793,91 @@ mod tests { } #[test] - fn gen_bytes() { - let r = rand::Rng(); + fn test_gen_bytes() { + let r = rng(); assert!(r.gen_bytes(0u).len() == 0u); assert!(r.gen_bytes(10u).len() == 10u); assert!(r.gen_bytes(16u).len() == 16u); } #[test] - fn choose() { - let r = rand::Rng(); + fn test_choose() { + let r = rng(); assert!(r.choose([1, 1, 1]) == 1); } #[test] - fn choose_option() { - let r = rand::Rng(); + fn test_choose_option() { + let r = rng(); let x: Option<int> = r.choose_option([]); assert!(x.is_none()); assert!(r.choose_option([1, 1, 1]) == Some(1)); } #[test] - fn choose_weighted() { - let r = rand::Rng(); + fn test_choose_weighted() { + let r = rng(); assert!(r.choose_weighted(~[ - rand::Weighted { weight: 1u, item: 42 }, + Weighted { weight: 1u, item: 42 }, ]) == 42); assert!(r.choose_weighted(~[ - rand::Weighted { weight: 0u, item: 42 }, - rand::Weighted { weight: 1u, item: 43 }, + Weighted { weight: 0u, item: 42 }, + Weighted { weight: 1u, item: 43 }, ]) == 43); } #[test] - fn choose_weighted_option() { - let r = rand::Rng(); + fn test_choose_weighted_option() { + let r = rng(); assert!(r.choose_weighted_option(~[ - rand::Weighted { weight: 1u, item: 42 }, + Weighted { weight: 1u, item: 42 }, ]) == Some(42)); assert!(r.choose_weighted_option(~[ - rand::Weighted { weight: 0u, item: 42 }, - rand::Weighted { weight: 1u, item: 43 }, + Weighted { weight: 0u, item: 42 }, + Weighted { weight: 1u, item: 43 }, ]) == Some(43)); let v: Option<int> = r.choose_weighted_option([]); assert!(v.is_none()); } #[test] - fn weighted_vec() { - let r = rand::Rng(); + fn test_weighted_vec() { + let r = rng(); let empty: ~[int] = ~[]; assert!(r.weighted_vec(~[]) == empty); assert!(r.weighted_vec(~[ - rand::Weighted { weight: 0u, item: 3u }, - rand::Weighted { weight: 1u, item: 2u }, - rand::Weighted { weight: 2u, item: 1u }, + Weighted { weight: 0u, item: 3u }, + Weighted { weight: 1u, item: 2u }, + Weighted { weight: 2u, item: 1u }, ]) == ~[2u, 1u, 1u]); } #[test] - fn shuffle() { - let r = rand::Rng(); + fn test_shuffle() { + let r = rng(); let empty: ~[int] = ~[]; assert!(r.shuffle(~[]) == empty); assert!(r.shuffle(~[1, 1, 1]) == ~[1, 1, 1]); } #[test] - fn task_rng() { - let r = rand::task_rng(); - r.gen_int(); + fn test_task_rng() { + let r = task_rng(); + r.gen::<int>(); assert!(r.shuffle(~[1, 1, 1]) == ~[1, 1, 1]); assert!(r.gen_uint_range(0u, 1u) == 0u); } #[test] - fn random() { + fn test_random() { // not sure how to test this aside from just getting some values - let _n : uint = rand::random(); - let _f : f32 = rand::random(); - let _o : Option<Option<i8>> = rand::random(); + let _n : uint = random(); + let _f : f32 = random(); + let _o : Option<Option<i8>> = random(); let _many : ((), (~uint, @int, ~Option<~(@char, ~(@bool,))>), (u8, i8, u16, i16, u32, i32, u64, i64), - (f32, (f64, (float,)))) = rand::random(); + (f32, (f64, (float,)))) = random(); } } diff --git a/src/libcore/run.rs b/src/libcore/run.rs index 2455954ebe1..e7df95e20c8 100644 --- a/src/libcore/run.rs +++ b/src/libcore/run.rs @@ -47,28 +47,117 @@ pub struct RunProgramResult { handle: *(), } +struct ProgRepr { + pid: pid_t, + handle: *(), + in_fd: c_int, + out_file: *libc::FILE, + err_file: *libc::FILE, + finished: bool, +} + +impl ProgRepr { + fn close_input(&mut self) { + let invalid_fd = -1i32; + if self.in_fd != invalid_fd { + unsafe { + libc::close(self.in_fd); + } + self.in_fd = invalid_fd; + } + } + + fn close_outputs(&mut self) { + unsafe { + fclose_and_null(&mut self.out_file); + fclose_and_null(&mut self.err_file); + } + } + + fn finish(&mut self) -> int { + if self.finished { return 0; } + self.finished = true; + self.close_input(); + return waitpid(self.pid); + } + + fn destroy(&mut self, force: bool) { + killpid(self.pid, force); + self.finish(); + self.close_outputs(); + + #[cfg(windows)] + fn killpid(pid: pid_t, _force: bool) { + unsafe { + libc::funcs::extra::kernel32::TerminateProcess( + cast::transmute(pid), 1); + } + } + + #[cfg(unix)] + fn killpid(pid: pid_t, force: bool) { + let signal = if force { + libc::consts::os::posix88::SIGKILL + } else { + libc::consts::os::posix88::SIGTERM + }; + + unsafe { + libc::funcs::posix88::signal::kill(pid, signal as c_int); + } + } + } +} + /// A value representing a child process -pub trait Program { +pub struct Program { + priv r: ProgRepr, +} + +impl Drop for Program { + fn finalize(&self) { + // FIXME #4943: transmute is bad. + let selfr: &mut ProgRepr = unsafe { cast::transmute(&self.r) }; + + selfr.finish(); + selfr.close_outputs(); + free_handle(self.r.handle); + } +} + +pub impl Program { + priv fn new(r: ProgRepr) -> Program { + Program { + r: r + } + } + /// Returns the process id of the program - fn get_id(&mut self) -> pid_t; + fn get_id(&mut self) -> pid_t { self.r.pid } /// Returns an io::Writer that can be used to write to stdin - fn input(&mut self) -> @io::Writer; + fn input(&mut self) -> @io::Writer { + io::fd_writer(self.r.in_fd, false) + } /// Returns an io::Reader that can be used to read from stdout - fn output(&mut self) -> @io::Reader; + fn output(&mut self) -> @io::Reader { + io::FILE_reader(self.r.out_file, false) + } /// Returns an io::Reader that can be used to read from stderr - fn err(&mut self) -> @io::Reader; + fn err(&mut self) -> @io::Reader { + io::FILE_reader(self.r.err_file, false) + } /// Closes the handle to the child processes standard input - fn close_input(&mut self); + fn close_input(&mut self) { self.r.close_input(); } /** * Waits for the child process to terminate. Closes the handle * to stdin if necessary. */ - fn finish(&mut self) -> int; + fn finish(&mut self) -> int { self.r.finish() } /** * Terminate the program, giving it a chance to clean itself up if @@ -77,7 +166,7 @@ pub trait Program { * On Posix OSs SIGTERM will be sent to the process. On Win32 * TerminateProcess(..) will be called. */ - fn destroy(&mut self); + fn destroy(&mut self) { self.r.destroy(false); } /** * Terminate the program as soon as possible without giving it a @@ -86,7 +175,7 @@ pub trait Program { * On Posix OSs SIGKILL will be sent to the process. On Win32 * TerminateProcess(..) will be called. */ - fn force_destroy(&mut self); + fn force_destroy(&mut self) { self.r.destroy(true); } } @@ -248,9 +337,9 @@ pub fn run_program(prog: &str, args: &[~str]) -> int { /** * Spawns a process and returns a Program * - * The returned value is a boxed class containing a <Program> object that can - * be used for sending and receiving data over the standard file descriptors. - * The class will ensure that file descriptors are closed properly. + * The returned value is a <Program> object that can be used for sending and + * receiving data over the standard file descriptors. The class will ensure + * that file descriptors are closed properly. * * # Arguments * @@ -259,9 +348,9 @@ pub fn run_program(prog: &str, args: &[~str]) -> int { * * # Return value * - * A class with a <program> field + * A <Program> object */ -pub fn start_program(prog: &str, args: &[~str]) -> @Program { +pub fn start_program(prog: &str, args: &[~str]) -> Program { let pipe_input = os::pipe(); let pipe_output = os::pipe(); let pipe_err = os::pipe(); @@ -277,105 +366,6 @@ pub fn start_program(prog: &str, args: &[~str]) -> @Program { libc::close(pipe_err.out); } - struct ProgRepr { - pid: pid_t, - handle: *(), - in_fd: c_int, - out_file: *libc::FILE, - err_file: *libc::FILE, - finished: bool, - } - - fn close_repr_input(r: &mut ProgRepr) { - let invalid_fd = -1i32; - if r.in_fd != invalid_fd { - unsafe { - libc::close(r.in_fd); - } - r.in_fd = invalid_fd; - } - } - - fn close_repr_outputs(r: &mut ProgRepr) { - unsafe { - fclose_and_null(&mut r.out_file); - fclose_and_null(&mut r.err_file); - } - } - - fn finish_repr(r: &mut ProgRepr) -> int { - if r.finished { return 0; } - r.finished = true; - close_repr_input(&mut *r); - return waitpid(r.pid); - } - - fn destroy_repr(r: &mut ProgRepr, force: bool) { - killpid(r.pid, force); - finish_repr(&mut *r); - close_repr_outputs(&mut *r); - - #[cfg(windows)] - fn killpid(pid: pid_t, _force: bool) { - unsafe { - libc::funcs::extra::kernel32::TerminateProcess( - cast::transmute(pid), 1); - } - } - - #[cfg(unix)] - fn killpid(pid: pid_t, force: bool) { - - let signal = if force { - libc::consts::os::posix88::SIGKILL - } else { - libc::consts::os::posix88::SIGTERM - }; - - unsafe { - libc::funcs::posix88::signal::kill(pid, signal as c_int); - } - } - } - - struct ProgRes { - r: ProgRepr, - } - - impl Drop for ProgRes { - fn finalize(&self) { - unsafe { - // FIXME #4943: transmute is bad. - finish_repr(cast::transmute(&self.r)); - close_repr_outputs(cast::transmute(&self.r)); - } - free_handle(self.r.handle); - } - } - - fn ProgRes(r: ProgRepr) -> ProgRes { - ProgRes { - r: r - } - } - - impl Program for ProgRes { - fn get_id(&mut self) -> pid_t { return self.r.pid; } - fn input(&mut self) -> @io::Writer { - io::fd_writer(self.r.in_fd, false) - } - fn output(&mut self) -> @io::Reader { - io::FILE_reader(self.r.out_file, false) - } - fn err(&mut self) -> @io::Reader { - io::FILE_reader(self.r.err_file, false) - } - fn close_input(&mut self) { close_repr_input(&mut self.r); } - fn finish(&mut self) -> int { finish_repr(&mut self.r) } - fn destroy(&mut self) { destroy_repr(&mut self.r, false); } - fn force_destroy(&mut self) { destroy_repr(&mut self.r, true); } - } - let repr = ProgRepr { pid: res.pid, handle: res.handle, @@ -385,7 +375,7 @@ pub fn start_program(prog: &str, args: &[~str]) -> @Program { finished: false, }; - @ProgRes(repr) as @Program + Program::new(repr) } fn read_all(rd: @io::Reader) -> ~str { diff --git a/src/libcore/unstable/at_exit.rs b/src/libcore/unstable/at_exit.rs index 83f0c3695e8..bc4ec620aa8 100644 --- a/src/libcore/unstable/at_exit.rs +++ b/src/libcore/unstable/at_exit.rs @@ -62,7 +62,7 @@ fn exit_runner(exit_fns: *ExitFunctions) { // give us ownership of the array of functions let mut exit_fns_vec = unsafe { vec::from_buf(start, count as uint) }; // Let's not make any promises about execution order - rand::Rng().shuffle_mut(exit_fns_vec); + rand::rng().shuffle_mut(exit_fns_vec); debug!("running %u exit functions", exit_fns_vec.len()); |
