Skip to content

Commit c1ef1ce

Browse files
committed
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`.
2 parents 4cbc8ad + 6e7bbda commit c1ef1ce

File tree

2 files changed

+78
-70
lines changed

2 files changed

+78
-70
lines changed

src/libstd/rand/isaac.rs

+34-25
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@
1010

1111
//! The ISAAC random number generator.
1212
13-
use cast;
1413
use rand::{Rng, SeedableRng, OSRng};
1514
use iter::{Iterator, range, range_step, Repeat};
1615
use option::{None, Some};
16+
use vec::raw;
17+
use mem;
1718

1819
static RAND_SIZE_LEN: u32 = 8;
1920
static RAND_SIZE: u32 = 1 << RAND_SIZE_LEN;
@@ -42,9 +43,12 @@ impl IsaacRng {
4243
pub fn new() -> IsaacRng {
4344
let mut rng = EMPTY;
4445

45-
{
46-
let bytes = unsafe {cast::transmute::<&mut [u32], &mut [u8]>(rng.rsl)};
47-
OSRng::new().fill_bytes(bytes);
46+
unsafe {
47+
let ptr = raw::to_mut_ptr(rng.rsl);
48+
49+
do raw::mut_buf_as_slice(ptr as *mut u8, mem::size_of_val(&rng.rsl)) |slice| {
50+
OSRng::new().fill_bytes(slice);
51+
}
4852
}
4953

5054
rng.init(true);
@@ -238,10 +242,15 @@ impl Isaac64Rng {
238242
/// seed.
239243
pub fn new() -> Isaac64Rng {
240244
let mut rng = EMPTY_64;
241-
{
242-
let bytes = unsafe {cast::transmute::<&mut [u64], &mut [u8]>(rng.rsl)};
243-
OSRng::new().fill_bytes(bytes);
245+
246+
unsafe {
247+
let ptr = raw::to_mut_ptr(rng.rsl);
248+
249+
do raw::mut_buf_as_slice(ptr as *mut u8, mem::size_of_val(&rng.rsl)) |slice| {
250+
OSRng::new().fill_bytes(slice);
251+
}
244252
}
253+
245254
rng.init(true);
246255
rng
247256
}
@@ -434,14 +443,14 @@ mod test {
434443

435444
#[test]
436445
fn test_rng_32_seeded() {
437-
let seed = &[2, 32, 4, 32, 51];
446+
let seed = &[1, 23, 456, 7890, 12345];
438447
let mut ra: IsaacRng = SeedableRng::from_seed(seed);
439448
let mut rb: IsaacRng = SeedableRng::from_seed(seed);
440449
assert_eq!(ra.gen_ascii_str(100u), rb.gen_ascii_str(100u));
441450
}
442451
#[test]
443452
fn test_rng_64_seeded() {
444-
let seed = &[2, 32, 4, 32, 51];
453+
let seed = &[1, 23, 456, 7890, 12345];
445454
let mut ra: Isaac64Rng = SeedableRng::from_seed(seed);
446455
let mut rb: Isaac64Rng = SeedableRng::from_seed(seed);
447456
assert_eq!(ra.gen_ascii_str(100u), rb.gen_ascii_str(100u));
@@ -472,46 +481,46 @@ mod test {
472481

473482
#[test]
474483
fn test_rng_32_true_values() {
475-
let seed = &[2, 32, 4, 32, 51];
484+
let seed = &[1, 23, 456, 7890, 12345];
476485
let mut ra: IsaacRng = SeedableRng::from_seed(seed);
477486
// Regression test that isaac is actually using the above vector
478487
let v = vec::from_fn(10, |_| ra.next_u32());
479488
assert_eq!(v,
480-
~[447462228, 2081944040, 3163797308, 2379916134, 2377489184,
481-
1132373754, 536342443, 2995223415, 1265094839, 345325140]);
489+
~[2558573138, 873787463, 263499565, 2103644246, 3595684709,
490+
4203127393, 264982119, 2765226902, 2737944514, 3900253796]);
482491

483-
let seed = &[500, -4000, 123456, 9876543, 1, 1, 1, 1, 1];
492+
let seed = &[12345, 67890, 54321, 9876];
484493
let mut rb: IsaacRng = SeedableRng::from_seed(seed);
485494
// skip forward to the 10000th number
486495
for _ in range(0, 10000) { rb.next_u32(); }
487496

488497
let v = vec::from_fn(10, |_| rb.next_u32());
489498
assert_eq!(v,
490-
~[612373032, 292987903, 1819311337, 3141271980, 422447569,
491-
310096395, 1083172510, 867909094, 2478664230, 2073577855]);
499+
~[3676831399, 3183332890, 2834741178, 3854698763, 2717568474,
500+
1576568959, 3507990155, 179069555, 141456972, 2478885421]);
492501
}
493502
#[test]
494503
fn test_rng_64_true_values() {
495-
let seed = &[2, 32, 4, 32, 51];
504+
let seed = &[1, 23, 456, 7890, 12345];
496505
let mut ra: Isaac64Rng = SeedableRng::from_seed(seed);
497506
// Regression test that isaac is actually using the above vector
498507
let v = vec::from_fn(10, |_| ra.next_u64());
499508
assert_eq!(v,
500-
~[15015576812873463115, 12461067598045625862, 14818626436142668771,
501-
5562406406765984441, 11813289907965514161, 13443797187798420053,
502-
6935026941854944442, 7750800609318664042, 14428747036317928637,
503-
14028894460301215947]);
509+
~[547121783600835980, 14377643087320773276, 17351601304698403469,
510+
1238879483818134882, 11952566807690396487, 13970131091560099343,
511+
4469761996653280935, 15552757044682284409, 6860251611068737823,
512+
13722198873481261842]);
504513

505-
let seed = &[500, -4000, 123456, 9876543, 1, 1, 1, 1, 1];
514+
let seed = &[12345, 67890, 54321, 9876];
506515
let mut rb: Isaac64Rng = SeedableRng::from_seed(seed);
507516
// skip forward to the 10000th number
508517
for _ in range(0, 10000) { rb.next_u64(); }
509518

510519
let v = vec::from_fn(10, |_| rb.next_u64());
511520
assert_eq!(v,
512-
~[13557216323596688637, 17060829581390442094, 4927582063811333743,
513-
2699639759356482270, 4819341314392384881, 6047100822963614452,
514-
11086255989965979163, 11901890363215659856, 5370800226050011580,
515-
16496463556025356451]);
521+
~[18143823860592706164, 8491801882678285927, 2699425367717515619,
522+
17196852593171130876, 2606123525235546165, 15790932315217671084,
523+
596345674630742204, 9947027391921273664, 11788097613744130851,
524+
10391409374914919106]);
516525
}
517526
}

src/libstd/rand/mod.rs

+44-45
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,6 @@ fn main () {
5252
```
5353
*/
5454

55-
use mem::size_of;
56-
use unstable::raw::Slice;
5755
use cast;
5856
use container::Container;
5957
use iter::{Iterator, range};
@@ -136,46 +134,26 @@ pub trait Rng {
136134
/// }
137135
/// ```
138136
fn fill_bytes(&mut self, dest: &mut [u8]) {
139-
let mut slice: Slice<u64> = unsafe { cast::transmute_copy(&dest) };
140-
slice.len /= size_of::<u64>();
141-
let as_u64: &mut [u64] = unsafe { cast::transmute(slice) };
142-
for dest in as_u64.mut_iter() {
143-
*dest = self.next_u64();
144-
}
145-
146-
// the above will have filled up the vector as much as
147-
// possible in multiples of 8 bytes.
148-
let mut remaining = dest.len() % 8;
149-
150-
// space for a u32
151-
if remaining >= 4 {
152-
let mut slice: Slice<u32> = unsafe { cast::transmute_copy(&dest) };
153-
slice.len /= size_of::<u32>();
154-
let as_u32: &mut [u32] = unsafe { cast::transmute(slice) };
155-
as_u32[as_u32.len() - 1] = self.next_u32();
156-
remaining -= 4;
157-
}
158-
// exactly filled
159-
if remaining == 0 { return }
160-
161-
// now we know we've either got 1, 2 or 3 spots to go,
162-
// i.e. exactly one u32 is enough.
163-
let rand = self.next_u32();
164-
let remaining_index = dest.len() - remaining;
165-
match dest.mut_slice_from(remaining_index) {
166-
[ref mut a] => {
167-
*a = rand as u8;
137+
// this could, in theory, be done by transmuting dest to a
138+
// [u64], but this is (1) likely to be undefined behaviour for
139+
// LLVM, (2) has to be very careful about alignment concerns,
140+
// (3) adds more `unsafe` that needs to be checked, (4)
141+
// probably doesn't give much performance gain if
142+
// optimisations are on.
143+
let mut count = 0;
144+
let mut num = 0;
145+
for byte in dest.mut_iter() {
146+
if count == 0 {
147+
// we could micro-optimise here by generating a u32 if
148+
// we only need a few more bytes to fill the vector
149+
// (i.e. at most 4).
150+
num = self.next_u64();
151+
count = 8;
168152
}
169-
[ref mut a, ref mut b] => {
170-
*a = rand as u8;
171-
*b = (rand >> 8) as u8;
172-
}
173-
[ref mut a, ref mut b, ref mut c] => {
174-
*a = rand as u8;
175-
*b = (rand >> 8) as u8;
176-
*c = (rand >> 16) as u8;
177-
}
178-
_ => fail!("Rng.fill_bytes: the impossible occurred: remaining != 1, 2 or 3")
153+
154+
*byte = (num & 0xff) as u8;
155+
num >>= 8;
156+
count -= 1;
179157
}
180158
}
181159

@@ -749,14 +727,35 @@ pub fn random<T: Rand>() -> T {
749727
mod test {
750728
use iter::{Iterator, range};
751729
use option::{Option, Some};
730+
use vec;
752731
use super::*;
753732

733+
struct ConstRng { i: u64 }
734+
impl Rng for ConstRng {
735+
fn next_u32(&mut self) -> u32 { self.i as u32 }
736+
fn next_u64(&mut self) -> u64 { self.i }
737+
738+
// no fill_bytes on purpose
739+
}
740+
754741
#[test]
755742
fn test_fill_bytes_default() {
756-
let mut r = weak_rng();
757-
758-
let mut v = [0u8, .. 100];
759-
r.fill_bytes(v);
743+
let mut r = ConstRng { i: 0x11_22_33_44_55_66_77_88 };
744+
745+
// check every remainder mod 8, both in small and big vectors.
746+
let lengths = [0, 1, 2, 3, 4, 5, 6, 7,
747+
80, 81, 82, 83, 84, 85, 86, 87];
748+
for &n in lengths.iter() {
749+
let mut v = vec::from_elem(n, 0u8);
750+
r.fill_bytes(v);
751+
752+
// use this to get nicer error messages.
753+
for (i, &byte) in v.iter().enumerate() {
754+
if byte == 0 {
755+
fail!("byte {} of {} is zero", i, n)
756+
}
757+
}
758+
}
760759
}
761760

762761
#[test]

0 commit comments

Comments
 (0)