From 6c0a7c7b7d304157f31189bf34f50ef4027e1d66 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Wed, 24 Apr 2013 00:00:43 +1000 Subject: [PATCH 1/4] libcore: remove @Rng from rand, and use traits instead. Also, rename RandRes -> IsaacRng, and make the constructors static methods. --- src/libcore/flate.rs | 2 +- src/libcore/hashmap.rs | 2 +- src/libcore/os.rs | 2 +- src/libcore/rand.rs | 324 ++++++++++++++++--------------- src/libcore/unstable/at_exit.rs | 2 +- src/librustpkg/path_util.rs | 2 +- src/libstd/bitv.rs | 5 +- src/libstd/sort.rs | 10 +- src/libstd/tempfile.rs | 2 +- src/libstd/test.rs | 2 +- src/libstd/timer.rs | 4 +- src/libstd/treemap.rs | 2 +- src/test/bench/core-map.rs | 2 +- src/test/bench/core-set.rs | 14 +- src/test/bench/core-std.rs | 6 +- src/test/bench/graph500-bfs.rs | 8 +- src/test/bench/noise.rs | 6 +- src/test/bench/shootout-fasta.rs | 2 +- src/test/run-pass/morestack6.rs | 3 +- 19 files changed, 205 insertions(+), 195 deletions(-) diff --git a/src/libcore/flate.rs b/src/libcore/flate.rs index 70c96c9c806e4..5c4181c10cf3b 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 1d7cc8515a656..3233207b8bd6a 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( initial_capacity: uint) -> HashMap { 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_u64(), (*r).gen_u64(), initial_capacity) } diff --git a/src/libcore/os.rs b/src/libcore/os.rs index fa3ca4577c6d1..1000fd88b5246 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 919c7bbb036d6..86509c81eb34d 100644 --- a/src/libcore/rand.rs +++ b/src/libcore/rand.rs @@ -22,95 +22,95 @@ use libc::size_t; /// A type that can be randomly generated using an RNG pub trait Rand { - fn rand(rng: @rand::Rng) -> Self; + fn rand(rng: &R) -> Self; } impl Rand for int { - fn rand(rng: @rand::Rng) -> int { + fn rand(rng: &R) -> int { rng.gen_int() } } impl Rand for i8 { - fn rand(rng: @rand::Rng) -> i8 { + fn rand(rng: &R) -> i8 { rng.gen_i8() } } impl Rand for i16 { - fn rand(rng: @rand::Rng) -> i16 { + fn rand(rng: &R) -> i16 { rng.gen_i16() } } impl Rand for i32 { - fn rand(rng: @rand::Rng) -> i32 { + fn rand(rng: &R) -> i32 { rng.gen_i32() } } impl Rand for i64 { - fn rand(rng: @rand::Rng) -> i64 { + fn rand(rng: &R) -> i64 { rng.gen_i64() } } impl Rand for uint { - fn rand(rng: @rand::Rng) -> uint { + fn rand(rng: &R) -> uint { rng.gen_uint() } } impl Rand for u8 { - fn rand(rng: @rand::Rng) -> u8 { + fn rand(rng: &R) -> u8 { rng.gen_u8() } } impl Rand for u16 { - fn rand(rng: @rand::Rng) -> u16 { + fn rand(rng: &R) -> u16 { rng.gen_u16() } } impl Rand for u32 { - fn rand(rng: @rand::Rng) -> u32 { + fn rand(rng: &R) -> u32 { rng.gen_u32() } } impl Rand for u64 { - fn rand(rng: @rand::Rng) -> u64 { + fn rand(rng: &R) -> u64 { rng.gen_u64() } } impl Rand for float { - fn rand(rng: @rand::Rng) -> float { + fn rand(rng: &R) -> float { rng.gen_float() } } impl Rand for f32 { - fn rand(rng: @rand::Rng) -> f32 { + fn rand(rng: &R) -> f32 { rng.gen_f32() } } impl Rand for f64 { - fn rand(rng: @rand::Rng) -> f64 { + fn rand(rng: &R) -> f64 { rng.gen_f64() } } impl Rand for char { - fn rand(rng: @rand::Rng) -> char { + fn rand(rng: &R) -> char { rng.gen_char() } } impl Rand for bool { - fn rand(rng: @rand::Rng) -> bool { + fn rand(rng: &R) -> bool { rng.gen_bool() } } @@ -123,10 +123,10 @@ macro_rules! tuple_impl { $( $tyvar : Rand ),* > Rand for ( $( $tyvar ),* , ) { - fn rand (_rng: @Rng) -> ( $( $tyvar ),* , ) { + fn rand(_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 +137,7 @@ macro_rules! tuple_impl { } } -impl Rand for () { fn rand(_: @Rng) -> () { () } } +impl Rand for () { fn rand(_: &R) -> () { () } } tuple_impl!{A} tuple_impl!{A, B} tuple_impl!{A, B, C} @@ -150,9 +150,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 Rand for Option { - fn rand(rng: @rand::Rng) -> Option { + fn rand(rng: &R) -> Option { if rng.gen_bool() { - Some(Rand::rand(rng)) + Some(rng.gen()) } else { None } @@ -160,11 +160,11 @@ impl Rand for Option { } impl Rand for ~T { - fn rand(rng: @Rng) -> ~T { ~rng.gen() } + fn rand(rng: &R) -> ~T { ~rng.gen() } } impl Rand for @T { - fn rand(rng: @Rng) -> @T { @rng.gen() } + fn rand(rng: &R) -> @T { @rng.gen() } } #[allow(non_camel_case_types)] // runtime type @@ -173,7 +173,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 +187,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 @@ -195,9 +195,10 @@ pub struct Weighted { weight: uint, item: T, } - +// this should be in gen_f64, but it causes an ICE there. +static scale : f64 = (u32::max_value as f64) + 1.0f64; pub trait RngUtil { - /// Return a random value for a Rand type + /// Return a random value of a Rand type fn gen(&self) -> T; /** * Return a random int @@ -209,7 +210,7 @@ pub trait RngUtil { * use core::rand::RngUtil; * * fn main() { - * rng = rand::Rng(); + * rng = rand::rng(); * println(fmt!("%d",rng.gen_int())); * } * ~~~ @@ -249,7 +250,7 @@ pub trait RngUtil { * use core::rand::RngUtil; * * fn main() { - * rng = rand::Rng(); + * rng = rand::rng(); * println(fmt!("%f",rng.gen_float())); * } * ~~~ @@ -275,7 +276,7 @@ pub trait RngUtil { * use core::rand::RngUtil; * * fn main() { - * rng = rand::Rng(); + * rng = rand::rng(); * println(fmt!("%b",rng.gen_bool())); * } * ~~~ @@ -291,7 +292,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 +308,7 @@ pub trait RngUtil { * use core::rand::RngUtil; * * fn main() { - * rng = rand::Rng(); + * rng = rand::rng(); * println(rng.gen_str(8)); * } * ~~~ @@ -323,13 +324,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 +340,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 +359,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 +379,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 +399,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 +418,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 +434,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,10 +447,10 @@ pub trait RngUtil { } /// Extension methods for random number generators -impl RngUtil for @Rng { +impl RngUtil for R { /// Return a random value for a Rand type - fn gen(&self) -> T { - Rand::rand(*self) + fn gen(&self) -> T { + Rand::rand(self) } /// Return a random int @@ -536,7 +536,7 @@ impl RngUtil for @Rng { 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; } @@ -605,7 +605,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 +667,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 +686,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 +733,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,38 +753,46 @@ 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(). */ -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 } } @@ -792,36 +801,35 @@ pub fn task_rng() -> @Rng { * generator. */ pub fn random() -> T { - task_rng().gen() + (*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 +838,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 +849,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 +865,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(); + 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 +896,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 = 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 = 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(); - assert!(r.shuffle(~[1, 1, 1]) == ~[1, 1, 1]); - assert!(r.gen_uint_range(0u, 1u) == 0u); + 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> = rand::random(); + let _n : uint = random(); + let _f : f32 = random(); + let _o : Option> = 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/unstable/at_exit.rs b/src/libcore/unstable/at_exit.rs index 83f0c3695e82f..bc4ec620aa86a 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()); diff --git a/src/librustpkg/path_util.rs b/src/librustpkg/path_util.rs index 140d9ced5808d..b35b9face2a8f 100644 --- a/src/librustpkg/path_util.rs +++ b/src/librustpkg/path_util.rs @@ -78,7 +78,7 @@ mod test { // Helper function to create a directory name that doesn't exist pub fn mk_nonexistent(tmpdir: &Path, suffix: &str) -> Path { - let r = rand::Rng(); + let r = rand::rng(); for 1000.times { let p = tmpdir.push(r.gen_str(16) + suffix); if !os::path_exists(&p) { diff --git a/src/libstd/bitv.rs b/src/libstd/bitv.rs index d1f6bf982a7ff..5f4d507568a10 100644 --- a/src/libstd/bitv.rs +++ b/src/libstd/bitv.rs @@ -876,6 +876,7 @@ mod tests { use core::uint; use core::vec; use core::rand; + use core::rand::Rng; static bench_bits : uint = 1 << 14; @@ -1424,9 +1425,9 @@ mod tests { assert!(a.capacity() == uint::bits); } - fn rng() -> @rand::Rng { + fn rng() -> rand::RandRes { let seed = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; - rand::seeded_rng(seed) + rand::IsaacRng::new_seeded(seed) } #[bench] diff --git a/src/libstd/sort.rs b/src/libstd/sort.rs index febaea637efe1..be32fb2565755 100644 --- a/src/libstd/sort.rs +++ b/src/libstd/sort.rs @@ -915,7 +915,7 @@ mod test_tim_sort { impl Ord for CVal { fn lt(&self, other: &CVal) -> bool { - let rng = rand::Rng(); + let rng = rand::rng(); if rng.gen_float() > 0.995 { fail!(~"It's happening!!!"); } (*self).val < other.val } @@ -964,7 +964,7 @@ mod test_tim_sort { #[should_fail] #[cfg(unix)] fn crash_test() { - let rng = rand::Rng(); + let rng = rand::rng(); let mut arr = do vec::from_fn(1000) |_i| { let randVal = rng.gen_float(); CVal { val: randVal } @@ -985,7 +985,7 @@ mod test_tim_sort { #[test] fn test_bad_Ord_impl() { - let rng = rand::Rng(); + let rng = rand::rng(); let mut arr = do vec::from_fn(500) |_i| { let randVal = rng.gen_uint(); DVal { val: randVal } @@ -1045,7 +1045,7 @@ mod big_tests { } } - let rng = rand::Rng(); + let rng = rand::rng(); for uint::range(lo, hi) |i| { let n = 1 << i; @@ -1117,7 +1117,7 @@ mod big_tests { } } - let rng = rand::Rng(); + let rng = rand::rng(); for uint::range(lo, hi) |i| { let n = 1 << i; diff --git a/src/libstd/tempfile.rs b/src/libstd/tempfile.rs index 895ccbc820b16..b92e652b7af9b 100644 --- a/src/libstd/tempfile.rs +++ b/src/libstd/tempfile.rs @@ -16,7 +16,7 @@ use core::rand::RngUtil; use core::rand; pub fn mkdtemp(tmpdir: &Path, suffix: &str) -> Option { - let r = rand::Rng(); + let r = rand::rng(); for 1000.times { let p = tmpdir.push(r.gen_str(16) + suffix); if os::make_dir(&p, 0x1c0) { // 700 diff --git a/src/libstd/test.rs b/src/libstd/test.rs index addc1da6394ee..113d66b30204d 100644 --- a/src/libstd/test.rs +++ b/src/libstd/test.rs @@ -705,7 +705,7 @@ pub mod bench { // not met, it may run as long as the Go algorithm. pub fn auto_bench(&mut self, f: &fn(&mut BenchHarness)) -> ~[f64] { - let rng = rand::Rng(); + let rng = rand::rng(); let mut magnitude = 10; let mut prev_madp = 0.0; diff --git a/src/libstd/timer.rs b/src/libstd/timer.rs index e862fe6077cb6..f0daf407073af 100644 --- a/src/libstd/timer.rs +++ b/src/libstd/timer.rs @@ -220,7 +220,7 @@ mod test { let hl_loop_clone = hl_loop.clone(); do task::spawn { use core::rand::*; - let rng = Rng(); + let rng = rng(); for iter::repeat(times) { sleep(&hl_loop_clone, rng.next() as uint % maxms); } @@ -277,7 +277,7 @@ mod test { let hl_loop = uv::global_loop::get(); for iter::repeat(times as uint) { - let expected = rand::Rng().gen_str(16u); + let expected = rand::rng().gen_str(16u); let (test_po, test_ch) = stream::<~str>(); let hl_loop_clone = hl_loop.clone(); do task::spawn() { diff --git a/src/libstd/treemap.rs b/src/libstd/treemap.rs index ac887c7fdc41d..dbb01b6ce397b 100644 --- a/src/libstd/treemap.rs +++ b/src/libstd/treemap.rs @@ -835,7 +835,7 @@ mod test_treemap { check_equal(ctrl, &map); assert!(map.find(&5).is_none()); - let rng = rand::seeded_rng(&[42]); + let rng = rand::IsaacRng::new_seeded(&[42]); for 3.times { for 90.times { diff --git a/src/test/bench/core-map.rs b/src/test/bench/core-map.rs index b75aa3c909b96..0c53ccd46e8b7 100644 --- a/src/test/bench/core-map.rs +++ b/src/test/bench/core-map.rs @@ -102,7 +102,7 @@ fn main() { let mut rand = vec::with_capacity(n_keys); { - let rng = core::rand::seeded_rng([1, 1, 1, 1, 1, 1, 1]); + let rng = core::rand::IsaacRng::new_seeded([1, 1, 1, 1, 1, 1, 1]); let mut set = HashSet::new(); while set.len() != n_keys { let next = rng.next() as uint; diff --git a/src/test/bench/core-set.rs b/src/test/bench/core-set.rs index 5f8f13896fb95..2ed3f668684d8 100644 --- a/src/test/bench/core-set.rs +++ b/src/test/bench/core-set.rs @@ -32,7 +32,7 @@ fn timed(result: &mut float, op: &fn()) { } pub impl Results { - fn bench_int>(&mut self, rng: @rand::Rng, num_keys: uint, + fn bench_int>(&mut self, rng: &rand::Rng, num_keys: uint, rand_cap: uint, f: &fn() -> T) { { let mut set = f(); @@ -70,7 +70,7 @@ pub impl Results { } } - fn bench_str>(&mut self, rng: @rand::Rng, num_keys: uint, + fn bench_str>(&mut self, rng: &rand::Rng, num_keys: uint, f: &fn() -> T) { { let mut set = f(); @@ -156,15 +156,15 @@ fn main() { let max = 200000; { - let rng = rand::seeded_rng(seed); + let rng = rand::IsaacRng::new_seeded(seed); let mut results = empty_results(); - results.bench_int(rng, num_keys, max, || HashSet::new::()); - results.bench_str(rng, num_keys, || HashSet::new::<~str>()); + results.bench_int(&rng, num_keys, max, || HashSet::new::()); + results.bench_str(&rng, num_keys, || HashSet::new::<~str>()); write_results("core::hashmap::HashSet", &results); } { - let rng = rand::seeded_rng(seed); + let rng = rand::IsaacRng::new_seeded(seed); let mut results = empty_results(); results.bench_int(rng, num_keys, max, || TreeSet::new::()); results.bench_str(rng, num_keys, || TreeSet::new::<~str>()); @@ -172,7 +172,7 @@ fn main() { } { - let rng = rand::seeded_rng(seed); + let rng = rand::IsaacRng::new_seeded(seed); let mut results = empty_results(); results.bench_int(rng, num_keys, max, || BitvSet::new()); write_results("std::bitv::BitvSet", &results); diff --git a/src/test/bench/core-std.rs b/src/test/bench/core-std.rs index 0a68d29ac560e..8438759b5c8d3 100644 --- a/src/test/bench/core-std.rs +++ b/src/test/bench/core-std.rs @@ -71,7 +71,7 @@ fn read_line() { } fn vec_plus() { - let r = rand::Rng(); + let r = rand::rng(); let mut v = ~[]; let mut i = 0; @@ -88,7 +88,7 @@ fn vec_plus() { } fn vec_append() { - let r = rand::Rng(); + let r = rand::rng(); let mut v = ~[]; let mut i = 0; @@ -105,7 +105,7 @@ fn vec_append() { } fn vec_push_all() { - let r = rand::Rng(); + let r = rand::rng(); let mut v = ~[]; for uint::range(0, 1500) |i| { diff --git a/src/test/bench/graph500-bfs.rs b/src/test/bench/graph500-bfs.rs index 396ea08136281..e84d8abf9790c 100644 --- a/src/test/bench/graph500-bfs.rs +++ b/src/test/bench/graph500-bfs.rs @@ -34,9 +34,9 @@ type graph = ~[~[node_id]]; type bfs_result = ~[node_id]; fn make_edges(scale: uint, edgefactor: uint) -> ~[(node_id, node_id)] { - let r = rand::xorshift(); + let r = rand::XorShiftRng::new(); - fn choose_edge(i: node_id, j: node_id, scale: uint, r: @rand::Rng) + fn choose_edge(i: node_id, j: node_id, scale: uint, r: &R) -> (node_id, node_id) { let A = 0.57; @@ -75,7 +75,7 @@ fn make_edges(scale: uint, edgefactor: uint) -> ~[(node_id, node_id)] { } do vec::from_fn((1u << scale) * edgefactor) |_i| { - choose_edge(0i64, 0i64, scale, r) + choose_edge(0i64, 0i64, scale, &r) } } @@ -105,7 +105,7 @@ fn make_graph(N: uint, edges: ~[(node_id, node_id)]) -> graph { fn gen_search_keys(graph: &[~[node_id]], n: uint) -> ~[node_id] { let mut keys = HashSet::new(); - let r = rand::Rng(); + let r = rand::rng(); while keys.len() < n { let k = r.gen_uint_range(0u, graph.len()); diff --git a/src/test/bench/noise.rs b/src/test/bench/noise.rs index 4397dcd5247f5..e032274482a02 100644 --- a/src/test/bench/noise.rs +++ b/src/test/bench/noise.rs @@ -13,7 +13,7 @@ fn lerp(a: f32, b: f32, v: f32) -> f32 { a * (1.0 - v) + b * v } #[inline(always)] fn smooth(v: f32) -> f32 { v * v * (3.0 - 2.0 * v) } -fn random_gradient(r: @Rng) -> Vec2 { +fn random_gradient(r: &Rng) -> Vec2 { let v = r.gen_float() * float::consts::pi * 2.0; Vec2 { x: float::cos(v) as f32, @@ -33,9 +33,9 @@ struct Noise2DContext { pub impl Noise2DContext { fn new() -> Noise2DContext { - let r = rand::Rng(); + let r = rand::rng(); let mut rgradients = [ Vec2 { x: 0.0, y: 0.0 }, ..256 ]; - for int::range(0, 256) |i| { rgradients[i] = random_gradient(r); } + for int::range(0, 256) |i| { rgradients[i] = random_gradient(&r); } let mut permutations = [ 0, ..256 ]; for int::range(0, 256) |i| { permutations[i] = i; } r.shuffle_mut(permutations); diff --git a/src/test/bench/shootout-fasta.rs b/src/test/bench/shootout-fasta.rs index 8c371150e1ea2..83e1a958d3ca8 100644 --- a/src/test/bench/shootout-fasta.rs +++ b/src/test/bench/shootout-fasta.rs @@ -63,7 +63,7 @@ fn make_random_fasta(wr: @io::Writer, genelist: ~[AminoAcids], n: int) { wr.write_line(~">" + id + ~" " + desc); - let rng = @mut MyRandom {last: rand::Rng().next()}; + let rng = @mut MyRandom {last: rand::rng().next()}; let mut op: ~str = ~""; for uint::range(0u, n as uint) |_i| { str::push_char(&mut op, select_random(myrandom_next(rng, 100u32), diff --git a/src/test/run-pass/morestack6.rs b/src/test/run-pass/morestack6.rs index 7e0b4b47846e0..1f908936aef47 100644 --- a/src/test/run-pass/morestack6.rs +++ b/src/test/run-pass/morestack6.rs @@ -54,6 +54,7 @@ fn runtest2(f: extern fn(), frame_backoff: u32, last_stk: *u8) -> u32 { } pub fn main() { + use core::rand::Rng; let fns = ~[ calllink01, calllink02, @@ -61,7 +62,7 @@ pub fn main() { calllink09, calllink10 ]; - let rng = rand::Rng(); + let rng = rand::rng(); for fns.each |f| { let f = *f; let sz = rng.next() % 256u32 + 256u32; From 7b009210c66d6b62ca6be123b752b464f8f178e5 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Wed, 24 Apr 2013 00:16:48 +1000 Subject: [PATCH 2/4] libcore: convert the Program @-object to be a plain struct + impl. Removes the dynamic @ indirection, and also converts the functions acting on `ProgRepr`s to methods. --- src/libcore/run.rs | 218 +++++++++++++++++++++------------------------ 1 file changed, 104 insertions(+), 114 deletions(-) diff --git a/src/libcore/run.rs b/src/libcore/run.rs index 2455954ebe128..e7df95e20c80b 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 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 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 field + * A 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 { From 4a24f10ac6f155699f086051ba6a728d9afb5ca6 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Wed, 24 Apr 2013 22:29:19 +1000 Subject: [PATCH 3/4] libcore: unify `gen_` methods on `rand::RngUtil` into the generic `gen`. This moves all the basic random value generation into the Rand instances for each type and then removes the `gen_int`, `gen_char` (etc) methods on RngUtil, leaving only the generic `gen` and the more specialised methods. Also, removes some imports that are redundant due to a `use core::prelude::*` statement. --- src/libcore/hashmap.rs | 2 +- src/libcore/rand.rs | 253 +++++++++---------------------- src/librustpkg/path_util.rs | 2 +- src/libstd/bitv.rs | 2 +- src/libstd/sort.rs | 35 ++--- src/libstd/tempfile.rs | 2 - src/libstd/test.rs | 17 +-- src/libstd/timer.rs | 4 - src/libstd/treemap.rs | 5 +- src/test/bench/core-map.rs | 1 + src/test/bench/core-set.rs | 13 +- src/test/bench/core-std.rs | 8 +- src/test/bench/graph500-bfs.rs | 3 +- src/test/bench/noise.rs | 4 +- src/test/bench/shootout-fasta.rs | 2 +- 15 files changed, 106 insertions(+), 247 deletions(-) diff --git a/src/libcore/hashmap.rs b/src/libcore/hashmap.rs index 3233207b8bd6a..d2be0416371be 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( initial_capacity: uint) -> HashMap { 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/rand.rs b/src/libcore/rand.rs index 86509c81eb34d..367278f66f321 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::()`. + +# 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: &R) -> Self; } impl Rand for int { fn rand(rng: &R) -> int { - rng.gen_int() + if int::bits == 32 { + rng.next() as int + } else { + rng.gen::() as int + } } } impl Rand for i8 { fn rand(rng: &R) -> i8 { - rng.gen_i8() + rng.next() as i8 } } impl Rand for i16 { fn rand(rng: &R) -> i16 { - rng.gen_i16() + rng.next() as i16 } } impl Rand for i32 { fn rand(rng: &R) -> i32 { - rng.gen_i32() + rng.next() as i32 } } impl Rand for i64 { fn rand(rng: &R) -> i64 { - rng.gen_i64() + (rng.next() as i64 << 32) | rng.next() as i64 } } impl Rand for uint { fn rand(rng: &R) -> uint { - rng.gen_uint() + if uint::bits == 32 { + rng.next() as uint + } else { + rng.gen::() as uint + } } } impl Rand for u8 { fn rand(rng: &R) -> u8 { - rng.gen_u8() + rng.next() as u8 } } impl Rand for u16 { fn rand(rng: &R) -> u16 { - rng.gen_u16() + rng.next() as u16 } } impl Rand for u32 { fn rand(rng: &R) -> u32 { - rng.gen_u32() + rng.next() } } impl Rand for u64 { fn rand(rng: &R) -> u64 { - rng.gen_u64() + (rng.next() as u64 << 32) | rng.next() as u64 } } impl Rand for float { fn rand(rng: &R) -> float { - rng.gen_float() + rng.gen::() as float } } impl Rand for f32 { fn rand(rng: &R) -> f32 { - rng.gen_f32() + rng.gen::() as f32 } } +static scale : f64 = (u32::max_value as f64) + 1.0f64; impl Rand for f64 { fn rand(rng: &R) -> f64 { - rng.gen_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: &R) -> char { - rng.gen_char() + rng.next() as char } } impl Rand for bool { fn rand(rng: &R) -> bool { - rng.gen_bool() + rng.next() & 1u32 == 1u32 } } @@ -151,7 +191,7 @@ tuple_impl!{A, B, C, D, E, F, G, H, I, J} impl Rand for Option { fn rand(rng: &R) -> Option { - if rng.gen_bool() { + if rng.gen() { Some(rng.gen()) } else { None @@ -195,93 +235,24 @@ pub struct Weighted { weight: uint, item: T, } -// this should be in gen_f64, but it causes an ICE there. -static scale : f64 = (u32::max_value as f64) + 1.0f64; + pub trait RngUtil { /// Return a random value of a Rand type fn gen(&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 * @@ -453,43 +424,13 @@ impl RngUtil for R { Rand::rand(self) } - /// Return a random int - fn gen_int(&self) -> int { - self.gen_i64() as int - } - /** * Return an int randomly chosen from the range [start, end), * failing if start >= end */ 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::() % (end - start)) } /** @@ -498,51 +439,7 @@ impl RngUtil for R { */ 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; - - return ((u1 / scale + u2) / scale + u3) / scale; - } - - /// Return a random char - fn gen_char(&self) -> char { - self.next() as char + start + (self.gen::() % (end - start)) } /** @@ -555,11 +452,6 @@ impl RngUtil for R { 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 R { /// 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() } } @@ -777,7 +669,7 @@ 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::()`. */ pub fn task_rng() -> @IsaacRng { let r : Option<@IsaacRng>; @@ -796,6 +688,11 @@ pub fn task_rng() -> @IsaacRng { } } +// Allow direct chaining with `task_rng` +impl Rng for @R { + fn next(&self) -> u32 { (*self).next() } +} + /** * Returns a random value of a Rand type, using the task's random number * generator. @@ -872,8 +769,8 @@ mod tests { #[test] fn test_gen_float() { let r = rng(); - let a = r.gen_float(); - let b = r.gen_float(); + let a = r.gen::(); + let b = r.gen::(); debug!((a, b)); } @@ -966,9 +863,9 @@ mod tests { #[test] 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); + r.gen::(); + assert!(r.shuffle(~[1, 1, 1]) == ~[1, 1, 1]); + assert!(r.gen_uint_range(0u, 1u) == 0u); } #[test] diff --git a/src/librustpkg/path_util.rs b/src/librustpkg/path_util.rs index b35b9face2a8f..cd9b44c278e46 100644 --- a/src/librustpkg/path_util.rs +++ b/src/librustpkg/path_util.rs @@ -73,8 +73,8 @@ pub fn normalize(p: ~Path) -> ~Path { mod test { use core::{os, rand}; use core::path::Path; - use core::rand::RngUtil; use path_util::*; + use core::rand::RngUtil; // Helper function to create a directory name that doesn't exist pub fn mk_nonexistent(tmpdir: &Path, suffix: &str) -> Path { diff --git a/src/libstd/bitv.rs b/src/libstd/bitv.rs index 5f4d507568a10..8bfa201395069 100644 --- a/src/libstd/bitv.rs +++ b/src/libstd/bitv.rs @@ -1425,7 +1425,7 @@ mod tests { assert!(a.capacity() == uint::bits); } - fn rng() -> rand::RandRes { + fn rng() -> rand::IsaacRng { let seed = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; rand::IsaacRng::new_seeded(seed) } diff --git a/src/libstd/sort.rs b/src/libstd/sort.rs index be32fb2565755..db6efdf3f52aa 100644 --- a/src/libstd/sort.rs +++ b/src/libstd/sort.rs @@ -902,12 +902,8 @@ mod tests { #[cfg(test)] mod test_tim_sort { use core::prelude::*; - use sort::tim_sort; - use core::rand::RngUtil; - use core::rand; - use core::vec; struct CVal { val: float, @@ -916,7 +912,7 @@ mod test_tim_sort { impl Ord for CVal { fn lt(&self, other: &CVal) -> bool { let rng = rand::rng(); - if rng.gen_float() > 0.995 { fail!(~"It's happening!!!"); } + if rng.gen::() > 0.995 { fail!(~"It's happening!!!"); } (*self).val < other.val } fn le(&self, other: &CVal) -> bool { (*self).val <= other.val } @@ -966,8 +962,7 @@ mod test_tim_sort { fn crash_test() { let rng = rand::rng(); let mut arr = do vec::from_fn(1000) |_i| { - let randVal = rng.gen_float(); - CVal { val: randVal } + CVal { val: rng.gen() } }; tim_sort(arr); @@ -987,8 +982,7 @@ mod test_tim_sort { fn test_bad_Ord_impl() { let rng = rand::rng(); let mut arr = do vec::from_fn(500) |_i| { - let randVal = rng.gen_uint(); - DVal { val: randVal } + DVal { val: rng.gen() } }; tim_sort(arr); @@ -998,14 +992,8 @@ mod test_tim_sort { #[cfg(test)] mod big_tests { use core::prelude::*; - use sort::*; - use core::rand::RngUtil; - use core::rand; - use core::task; - use core::uint; - use core::vec; #[test] fn test_unique() { @@ -1049,10 +1037,9 @@ mod big_tests { for uint::range(lo, hi) |i| { let n = 1 << i; - let arr = do vec::from_fn(n) |_i| { - rng.gen_float() + let mut arr: ~[float] = do vec::from_fn(n) |_i| { + rng.gen() }; - let mut arr = arr; tim_sort(arr); // *sort isSorted(arr); @@ -1076,7 +1063,7 @@ mod big_tests { let size = arr.len(); let mut idx = 1; while idx <= 10 { - arr[size-idx] = rng.gen_float(); + arr[size-idx] = rng.gen(); idx += 1; } } @@ -1085,7 +1072,7 @@ mod big_tests { for (n/100).times { let idx = rng.gen_uint_range(0, n); - arr[idx] = rng.gen_float(); + arr[idx] = rng.gen(); } tim_sort(arr); isSorted(arr); @@ -1121,8 +1108,8 @@ mod big_tests { for uint::range(lo, hi) |i| { let n = 1 << i; - let arr = do vec::from_fn(n) |_i| { - @rng.gen_float() + let arr: ~[@float] = do vec::from_fn(n) |_i| { + @rng.gen() }; let mut arr = arr; @@ -1148,7 +1135,7 @@ mod big_tests { let size = arr.len(); let mut idx = 1; while idx <= 10 { - arr[size-idx] = @rng.gen_float(); + arr[size-idx] = @rng.gen(); idx += 1; } } @@ -1157,7 +1144,7 @@ mod big_tests { for (n/100).times { let idx = rng.gen_uint_range(0, n); - arr[idx] = @rng.gen_float(); + arr[idx] = @rng.gen(); } tim_sort(arr); isSorted(arr); diff --git a/src/libstd/tempfile.rs b/src/libstd/tempfile.rs index b92e652b7af9b..c9bcb3b8952be 100644 --- a/src/libstd/tempfile.rs +++ b/src/libstd/tempfile.rs @@ -10,10 +10,8 @@ //! Temporary files and directories -use core::os; use core::prelude::*; use core::rand::RngUtil; -use core::rand; pub fn mkdtemp(tmpdir: &Path, suffix: &str) -> Option { let r = rand::rng(); diff --git a/src/libstd/test.rs b/src/libstd/test.rs index 113d66b30204d..f82cc25e0f618 100644 --- a/src/libstd/test.rs +++ b/src/libstd/test.rs @@ -19,20 +19,9 @@ use getopts; use sort; use term; -use core::cmp::Eq; - use core::to_str::ToStr; -use core::either::Either; -use core::either; -use core::io::WriterUtil; -use core::io; use core::comm::{stream, SharedChan}; -use core::option; use core::prelude::*; -use core::result; -use core::str; -use core::task; -use core::vec; pub mod rustrt { use core::libc::size_t; @@ -608,12 +597,8 @@ pub mod bench { use time::precise_time_ns; use test::{BenchHarness, BenchSamples}; use stats::Stats; - - use core::num; + use core::prelude::*; use core::rand::RngUtil; - use core::rand; - use core::u64; - use core::vec; pub impl BenchHarness { diff --git a/src/libstd/timer.rs b/src/libstd/timer.rs index f0daf407073af..1e48ce5aa6f2e 100644 --- a/src/libstd/timer.rs +++ b/src/libstd/timer.rs @@ -175,11 +175,7 @@ mod test { use timer::*; use uv; - - use core::iter; use core::rand::RngUtil; - use core::rand; - use core::task; use core::pipes::{stream, SharedChan}; #[test] diff --git a/src/libstd/treemap.rs b/src/libstd/treemap.rs index dbb01b6ce397b..020f4daefd9d6 100644 --- a/src/libstd/treemap.rs +++ b/src/libstd/treemap.rs @@ -698,7 +698,6 @@ mod test_treemap { use core::iterator::*; use super::*; use core::rand::RngUtil; - use core::rand; #[test] fn find_empty() { @@ -839,8 +838,8 @@ mod test_treemap { for 3.times { for 90.times { - let k = rng.gen_int(); - let v = rng.gen_int(); + let k = rng.gen(); + let v = rng.gen(); if !ctrl.contains(&(k, v)) { assert!(map.insert(k, v)); ctrl.push((k, v)); diff --git a/src/test/bench/core-map.rs b/src/test/bench/core-map.rs index 0c53ccd46e8b7..e216215ace7f9 100644 --- a/src/test/bench/core-map.rs +++ b/src/test/bench/core-map.rs @@ -15,6 +15,7 @@ use std::time; use std::treemap::TreeMap; use core::hashmap::{HashMap, HashSet}; use core::trie::TrieMap; +use core::rand::Rng; fn timed(label: &str, f: &fn()) { let start = time::precise_time_s(); diff --git a/src/test/bench/core-set.rs b/src/test/bench/core-set.rs index 2ed3f668684d8..b3e3d295c0fad 100644 --- a/src/test/bench/core-set.rs +++ b/src/test/bench/core-set.rs @@ -12,7 +12,6 @@ extern mod std; use core::hashmap::HashSet; use std::bitv::BitvSet; use std::treemap::TreeSet; -use core::io::WriterUtil; struct Results { sequential_ints: float, @@ -32,7 +31,7 @@ fn timed(result: &mut float, op: &fn()) { } pub impl Results { - fn bench_int>(&mut self, rng: &rand::Rng, num_keys: uint, + fn bench_int, R: rand::Rng>(&mut self, rng: &R, num_keys: uint, rand_cap: uint, f: &fn() -> T) { { let mut set = f(); @@ -70,8 +69,8 @@ pub impl Results { } } - fn bench_str>(&mut self, rng: &rand::Rng, num_keys: uint, - f: &fn() -> T) { + fn bench_str, R: rand::Rng>(&mut self, rng: &R, num_keys: uint, + f: &fn() -> T) { { let mut set = f(); do timed(&mut self.sequential_strings) { @@ -166,15 +165,15 @@ fn main() { { let rng = rand::IsaacRng::new_seeded(seed); let mut results = empty_results(); - results.bench_int(rng, num_keys, max, || TreeSet::new::()); - results.bench_str(rng, num_keys, || TreeSet::new::<~str>()); + results.bench_int(&rng, num_keys, max, || TreeSet::new::()); + results.bench_str(&rng, num_keys, || TreeSet::new::<~str>()); write_results("std::treemap::TreeSet", &results); } { let rng = rand::IsaacRng::new_seeded(seed); let mut results = empty_results(); - results.bench_int(rng, num_keys, max, || BitvSet::new()); + results.bench_int(&rng, num_keys, max, || BitvSet::new()); write_results("std::bitv::BitvSet", &results); } } diff --git a/src/test/bench/core-std.rs b/src/test/bench/core-std.rs index 8438759b5c8d3..1af3538a0219d 100644 --- a/src/test/bench/core-std.rs +++ b/src/test/bench/core-std.rs @@ -13,8 +13,6 @@ extern mod std; use std::time::precise_time_s; - -use core::io::{Reader, ReaderUtil}; use core::rand::RngUtil; macro_rules! bench ( @@ -77,7 +75,7 @@ fn vec_plus() { let mut i = 0; while i < 1500 { let rv = vec::from_elem(r.gen_uint_range(0, i + 1), i); - if r.gen_bool() { + if r.gen() { v += rv; } else { @@ -94,7 +92,7 @@ fn vec_append() { let mut i = 0; while i < 1500 { let rv = vec::from_elem(r.gen_uint_range(0, i + 1), i); - if r.gen_bool() { + if r.gen() { v = vec::append(v, rv); } else { @@ -110,7 +108,7 @@ fn vec_push_all() { let mut v = ~[]; for uint::range(0, 1500) |i| { let mut rv = vec::from_elem(r.gen_uint_range(0, i + 1), i); - if r.gen_bool() { + if r.gen() { v.push_all(rv); } else { diff --git a/src/test/bench/graph500-bfs.rs b/src/test/bench/graph500-bfs.rs index e84d8abf9790c..bd3de4a1b8aba 100644 --- a/src/test/bench/graph500-bfs.rs +++ b/src/test/bench/graph500-bfs.rs @@ -25,7 +25,6 @@ use std::time; use std::deque::Deque; use std::par; use core::hashmap::{HashMap, HashSet}; -use core::io::WriterUtil; use core::int::abs; use core::rand::RngUtil; @@ -51,7 +50,7 @@ fn make_edges(scale: uint, edgefactor: uint) -> ~[(node_id, node_id)] { let j = j * 2i64; let scale = scale - 1u; - let x = r.gen_float(); + let x = r.gen::(); if x < A { choose_edge(i, j, scale, r) diff --git a/src/test/bench/noise.rs b/src/test/bench/noise.rs index e032274482a02..0da3a2e5d68d0 100644 --- a/src/test/bench/noise.rs +++ b/src/test/bench/noise.rs @@ -13,8 +13,8 @@ fn lerp(a: f32, b: f32, v: f32) -> f32 { a * (1.0 - v) + b * v } #[inline(always)] fn smooth(v: f32) -> f32 { v * v * (3.0 - 2.0 * v) } -fn random_gradient(r: &Rng) -> Vec2 { - let v = r.gen_float() * float::consts::pi * 2.0; +fn random_gradient(r: &R) -> Vec2 { + let v = 2.0 * float::consts::pi * r.gen(); Vec2 { x: float::cos(v) as f32, y: float::sin(v) as f32, diff --git a/src/test/bench/shootout-fasta.rs b/src/test/bench/shootout-fasta.rs index 83e1a958d3ca8..0fcf8341ac852 100644 --- a/src/test/bench/shootout-fasta.rs +++ b/src/test/bench/shootout-fasta.rs @@ -16,7 +16,7 @@ * http://shootout.alioth.debian.org/ */ extern mod std; -use core::io::WriterUtil; +use core::rand::Rng; fn LINE_LENGTH() -> uint { return 60u; } From 9860fe10a19cc4997e58861df905f8dbe4de3c5b Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Wed, 24 Apr 2013 23:03:04 +1000 Subject: [PATCH 4/4] libcore: remove unnecessary deref --- src/libcore/rand.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/rand.rs b/src/libcore/rand.rs index 367278f66f321..cdf6a5bb63ded 100644 --- a/src/libcore/rand.rs +++ b/src/libcore/rand.rs @@ -698,7 +698,7 @@ impl Rng for @R { * generator. */ pub fn random() -> T { - (*task_rng()).gen() + task_rng().gen() } #[cfg(test)]