about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-10-22 22:51:10 -0700
committerbors <bors@rust-lang.org>2013-10-22 22:51:10 -0700
commitc1ef1ce9472cbff969cfd4051ac1379e9cbee394 (patch)
tree3c1cf56a59c190525c7dd34b1f2cc8d927662a1e /src/libstd
parent4cbc8ad3979918fafb0527cc3326dc27b21936b0 (diff)
parent6e7bbdacb9bf04c1f5bf2c3aad487122d8377b7f (diff)
downloadrust-c1ef1ce9472cbff969cfd4051ac1379e9cbee394.tar.gz
rust-c1ef1ce9472cbff969cfd4051ac1379e9cbee394.zip
auto merge of #10015 : huonw/rust/minor-fixes, r=alexcrichton
- Use ["nothing up my sleeve numbers"](http://en.wikipedia.org/wiki/Nothing_up_my_sleeve_number) for the ISAAC tests.
- Replace the default implementation of `Rng.fill_bytes` with something that doesn't try to do bad things with `transmute` and vectors just for the sake of a little speed.
- Replace the transmutes used to seed the ISAAC RNGs with calls into `vec::raw`.
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/rand/isaac.rs59
-rw-r--r--src/libstd/rand/mod.rs89
2 files changed, 78 insertions, 70 deletions
diff --git a/src/libstd/rand/isaac.rs b/src/libstd/rand/isaac.rs
index 0068b60cfa5..7dc4e5b868b 100644
--- a/src/libstd/rand/isaac.rs
+++ b/src/libstd/rand/isaac.rs
@@ -10,10 +10,11 @@
 
 //! The ISAAC random number generator.
 
-use cast;
 use rand::{Rng, SeedableRng, OSRng};
 use iter::{Iterator, range, range_step, Repeat};
 use option::{None, Some};
+use vec::raw;
+use mem;
 
 static RAND_SIZE_LEN: u32 = 8;
 static RAND_SIZE: u32 = 1 << RAND_SIZE_LEN;
@@ -42,9 +43,12 @@ impl IsaacRng {
     pub fn new() -> IsaacRng {
         let mut rng = EMPTY;
 
-        {
-            let bytes = unsafe {cast::transmute::<&mut [u32], &mut [u8]>(rng.rsl)};
-            OSRng::new().fill_bytes(bytes);
+        unsafe {
+            let ptr = raw::to_mut_ptr(rng.rsl);
+
+            do raw::mut_buf_as_slice(ptr as *mut u8, mem::size_of_val(&rng.rsl)) |slice| {
+                OSRng::new().fill_bytes(slice);
+            }
         }
 
         rng.init(true);
@@ -238,10 +242,15 @@ impl Isaac64Rng {
     /// seed.
     pub fn new() -> Isaac64Rng {
         let mut rng = EMPTY_64;
-        {
-            let bytes = unsafe {cast::transmute::<&mut [u64], &mut [u8]>(rng.rsl)};
-            OSRng::new().fill_bytes(bytes);
+
+        unsafe {
+            let ptr = raw::to_mut_ptr(rng.rsl);
+
+            do raw::mut_buf_as_slice(ptr as *mut u8, mem::size_of_val(&rng.rsl)) |slice| {
+                OSRng::new().fill_bytes(slice);
+            }
         }
+
         rng.init(true);
         rng
     }
@@ -434,14 +443,14 @@ mod test {
 
     #[test]
     fn test_rng_32_seeded() {
-        let seed = &[2, 32, 4, 32, 51];
+        let seed = &[1, 23, 456, 7890, 12345];
         let mut ra: IsaacRng = SeedableRng::from_seed(seed);
         let mut rb: IsaacRng = SeedableRng::from_seed(seed);
         assert_eq!(ra.gen_ascii_str(100u), rb.gen_ascii_str(100u));
     }
     #[test]
     fn test_rng_64_seeded() {
-        let seed = &[2, 32, 4, 32, 51];
+        let seed = &[1, 23, 456, 7890, 12345];
         let mut ra: Isaac64Rng = SeedableRng::from_seed(seed);
         let mut rb: Isaac64Rng = SeedableRng::from_seed(seed);
         assert_eq!(ra.gen_ascii_str(100u), rb.gen_ascii_str(100u));
@@ -472,46 +481,46 @@ mod test {
 
     #[test]
     fn test_rng_32_true_values() {
-        let seed = &[2, 32, 4, 32, 51];
+        let seed = &[1, 23, 456, 7890, 12345];
         let mut ra: IsaacRng = SeedableRng::from_seed(seed);
         // Regression test that isaac is actually using the above vector
         let v = vec::from_fn(10, |_| ra.next_u32());
         assert_eq!(v,
-                   ~[447462228, 2081944040, 3163797308, 2379916134, 2377489184,
-                     1132373754, 536342443, 2995223415, 1265094839, 345325140]);
+                   ~[2558573138, 873787463, 263499565, 2103644246, 3595684709,
+                     4203127393, 264982119, 2765226902, 2737944514, 3900253796]);
 
-        let seed = &[500, -4000, 123456, 9876543, 1, 1, 1, 1, 1];
+        let seed = &[12345, 67890, 54321, 9876];
         let mut rb: IsaacRng = SeedableRng::from_seed(seed);
         // skip forward to the 10000th number
         for _ in range(0, 10000) { rb.next_u32(); }
 
         let v = vec::from_fn(10, |_| rb.next_u32());
         assert_eq!(v,
-                   ~[612373032, 292987903, 1819311337, 3141271980, 422447569,
-                     310096395, 1083172510, 867909094, 2478664230, 2073577855]);
+                   ~[3676831399, 3183332890, 2834741178, 3854698763, 2717568474,
+                     1576568959, 3507990155, 179069555, 141456972, 2478885421]);
     }
     #[test]
     fn test_rng_64_true_values() {
-        let seed = &[2, 32, 4, 32, 51];
+        let seed = &[1, 23, 456, 7890, 12345];
         let mut ra: Isaac64Rng = SeedableRng::from_seed(seed);
         // Regression test that isaac is actually using the above vector
         let v = vec::from_fn(10, |_| ra.next_u64());
         assert_eq!(v,
-                   ~[15015576812873463115, 12461067598045625862, 14818626436142668771,
-                     5562406406765984441, 11813289907965514161, 13443797187798420053,
-                     6935026941854944442, 7750800609318664042, 14428747036317928637,
-                     14028894460301215947]);
+                   ~[547121783600835980, 14377643087320773276, 17351601304698403469,
+                     1238879483818134882, 11952566807690396487, 13970131091560099343,
+                     4469761996653280935, 15552757044682284409, 6860251611068737823,
+                     13722198873481261842]);
 
-        let seed = &[500, -4000, 123456, 9876543, 1, 1, 1, 1, 1];
+        let seed = &[12345, 67890, 54321, 9876];
         let mut rb: Isaac64Rng = SeedableRng::from_seed(seed);
         // skip forward to the 10000th number
         for _ in range(0, 10000) { rb.next_u64(); }
 
         let v = vec::from_fn(10, |_| rb.next_u64());
         assert_eq!(v,
-                   ~[13557216323596688637, 17060829581390442094, 4927582063811333743,
-                     2699639759356482270, 4819341314392384881, 6047100822963614452,
-                     11086255989965979163, 11901890363215659856, 5370800226050011580,
-                     16496463556025356451]);
+                   ~[18143823860592706164, 8491801882678285927, 2699425367717515619,
+                     17196852593171130876, 2606123525235546165, 15790932315217671084,
+                     596345674630742204, 9947027391921273664, 11788097613744130851,
+                     10391409374914919106]);
     }
 }
diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs
index f5c60417bac..9f611578c6a 100644
--- a/src/libstd/rand/mod.rs
+++ b/src/libstd/rand/mod.rs
@@ -52,8 +52,6 @@ fn main () {
  ```
 */
 
-use mem::size_of;
-use unstable::raw::Slice;
 use cast;
 use container::Container;
 use iter::{Iterator, range};
@@ -136,46 +134,26 @@ pub trait Rng {
     /// }
     /// ```
     fn fill_bytes(&mut self, dest: &mut [u8]) {
-        let mut slice: Slice<u64> = unsafe { cast::transmute_copy(&dest) };
-        slice.len /= size_of::<u64>();
-        let as_u64: &mut [u64] = unsafe { cast::transmute(slice) };
-        for dest in as_u64.mut_iter() {
-            *dest = self.next_u64();
-        }
-
-        // the above will have filled up the vector as much as
-        // possible in multiples of 8 bytes.
-        let mut remaining = dest.len() % 8;
-
-        // space for a u32
-        if remaining >= 4 {
-            let mut slice: Slice<u32> = unsafe { cast::transmute_copy(&dest) };
-            slice.len /= size_of::<u32>();
-            let as_u32: &mut [u32] = unsafe { cast::transmute(slice) };
-            as_u32[as_u32.len() - 1] = self.next_u32();
-            remaining -= 4;
-        }
-        // exactly filled
-        if remaining == 0 { return }
-
-        // now we know we've either got 1, 2 or 3 spots to go,
-        // i.e. exactly one u32 is enough.
-        let rand = self.next_u32();
-        let remaining_index = dest.len() - remaining;
-        match dest.mut_slice_from(remaining_index) {
-            [ref mut a] => {
-                *a = rand as u8;
+        // this could, in theory, be done by transmuting dest to a
+        // [u64], but this is (1) likely to be undefined behaviour for
+        // LLVM, (2) has to be very careful about alignment concerns,
+        // (3) adds more `unsafe` that needs to be checked, (4)
+        // probably doesn't give much performance gain if
+        // optimisations are on.
+        let mut count = 0;
+        let mut num = 0;
+        for byte in dest.mut_iter() {
+            if count == 0 {
+                // we could micro-optimise here by generating a u32 if
+                // we only need a few more bytes to fill the vector
+                // (i.e. at most 4).
+                num = self.next_u64();
+                count = 8;
             }
-            [ref mut a, ref mut b] => {
-                *a = rand as u8;
-                *b = (rand >> 8) as u8;
-            }
-            [ref mut a, ref mut b, ref mut c] => {
-                *a = rand as u8;
-                *b = (rand >> 8) as u8;
-                *c = (rand >> 16) as u8;
-            }
-            _ => fail!("Rng.fill_bytes: the impossible occurred: remaining != 1, 2 or 3")
+
+            *byte = (num & 0xff) as u8;
+            num >>= 8;
+            count -= 1;
         }
     }
 
@@ -749,14 +727,35 @@ pub fn random<T: Rand>() -> T {
 mod test {
     use iter::{Iterator, range};
     use option::{Option, Some};
+    use vec;
     use super::*;
 
+    struct ConstRng { i: u64 }
+    impl Rng for ConstRng {
+        fn next_u32(&mut self) -> u32 { self.i as u32 }
+        fn next_u64(&mut self) -> u64 { self.i }
+
+        // no fill_bytes on purpose
+    }
+
     #[test]
     fn test_fill_bytes_default() {
-        let mut r = weak_rng();
-
-        let mut v = [0u8, .. 100];
-        r.fill_bytes(v);
+        let mut r = ConstRng { i: 0x11_22_33_44_55_66_77_88 };
+
+        // check every remainder mod 8, both in small and big vectors.
+        let lengths = [0, 1, 2, 3, 4, 5, 6, 7,
+                       80, 81, 82, 83, 84, 85, 86, 87];
+        for &n in lengths.iter() {
+            let mut v = vec::from_elem(n, 0u8);
+            r.fill_bytes(v);
+
+            // use this to get nicer error messages.
+            for (i, &byte) in v.iter().enumerate() {
+                if byte == 0 {
+                    fail!("byte {} of {} is zero", i, n)
+                }
+            }
+        }
     }
 
     #[test]