summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorHuon Wilson <dbau.pp+github@gmail.com>2013-09-21 21:32:57 +1000
committerHuon Wilson <dbau.pp+github@gmail.com>2013-10-09 22:22:42 +1100
commit72bf201d61ac36f058cdea6a3487a27029fb65e6 (patch)
tree0f0c3c5fa4b827128714ee3410f7924eef85070d /src/libstd
parent3a70df1d3cf12eae47536a96e26c1e7e0030b75a (diff)
downloadrust-72bf201d61ac36f058cdea6a3487a27029fb65e6.tar.gz
rust-72bf201d61ac36f058cdea6a3487a27029fb65e6.zip
std::rand: move the Isaac implementation to its own file.
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/rand/isaac.rs198
-rw-r--r--src/libstd/rand/mod.rs193
2 files changed, 207 insertions, 184 deletions
diff --git a/src/libstd/rand/isaac.rs b/src/libstd/rand/isaac.rs
new file mode 100644
index 00000000000..d20b05db485
--- /dev/null
+++ b/src/libstd/rand/isaac.rs
@@ -0,0 +1,198 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! The ISAAC random number generator.
+
+use rand::{seed, Rng};
+use iter::{Iterator, range, range_step};
+use option::{None, Some};
+
+use cast;
+use cmp;
+use sys;
+use vec;
+
+static RAND_SIZE_LEN: u32 = 8;
+static RAND_SIZE: u32 = 1 << RAND_SIZE_LEN;
+
+/// A random number generator that uses the [ISAAC
+/// algorithm](http://en.wikipedia.org/wiki/ISAAC_%28cipher%29).
+///
+/// The ISAAC algorithm is suitable for cryptographic purposes.
+pub struct IsaacRng {
+    priv cnt: u32,
+    priv rsl: [u32, .. RAND_SIZE],
+    priv mem: [u32, .. RAND_SIZE],
+    priv a: u32,
+    priv b: u32,
+    priv c: u32
+}
+
+impl IsaacRng {
+    /// Create an ISAAC random number generator with a random seed.
+    pub fn new() -> IsaacRng {
+        IsaacRng::new_seeded(seed(RAND_SIZE as uint * 4))
+    }
+
+    /// Create an ISAAC random number generator with a seed. This can be any
+    /// length, although the maximum number of bytes used is 1024 and any more
+    /// will be silently ignored. A generator constructed with a given seed
+    /// will generate the same sequence of values as all other generators
+    /// constructed with the same seed.
+    pub fn new_seeded(seed: &[u8]) -> IsaacRng {
+        let mut rng = IsaacRng {
+            cnt: 0,
+            rsl: [0, .. RAND_SIZE],
+            mem: [0, .. RAND_SIZE],
+            a: 0, b: 0, c: 0
+        };
+
+        let array_size = sys::size_of_val(&rng.rsl);
+        let copy_length = cmp::min(array_size, seed.len());
+
+        // manually create a &mut [u8] slice of randrsl to copy into.
+        let dest = unsafe { cast::transmute((&mut rng.rsl, array_size)) };
+        vec::bytes::copy_memory(dest, seed, copy_length);
+        rng.init(true);
+        rng
+    }
+
+    /// Create an ISAAC random number generator using the default
+    /// fixed seed.
+    pub fn new_unseeded() -> IsaacRng {
+        let mut rng = IsaacRng {
+            cnt: 0,
+            rsl: [0, .. RAND_SIZE],
+            mem: [0, .. RAND_SIZE],
+            a: 0, b: 0, c: 0
+        };
+        rng.init(false);
+        rng
+    }
+
+    /// Initialises `self`. If `use_rsl` is true, then use the current value
+    /// of `rsl` as a seed, otherwise construct one algorithmically (not
+    /// randomly).
+    fn init(&mut self, use_rsl: bool) {
+        let mut a = 0x9e3779b9;
+        let mut b = a;
+        let mut c = a;
+        let mut d = a;
+        let mut e = a;
+        let mut f = a;
+        let mut g = a;
+        let mut h = a;
+
+        macro_rules! mix(
+            () => {{
+                a^=b<<11; d+=a; b+=c;
+                b^=c>>2;  e+=b; c+=d;
+                c^=d<<8;  f+=c; d+=e;
+                d^=e>>16; g+=d; e+=f;
+                e^=f<<10; h+=e; f+=g;
+                f^=g>>4;  a+=f; g+=h;
+                g^=h<<8;  b+=g; h+=a;
+                h^=a>>9;  c+=h; a+=b;
+            }}
+        );
+
+        do 4.times { mix!(); }
+
+        if use_rsl {
+            macro_rules! memloop (
+                ($arr:expr) => {{
+                    for i in range_step(0u32, RAND_SIZE, 8) {
+                        a+=$arr[i  ]; b+=$arr[i+1];
+                        c+=$arr[i+2]; d+=$arr[i+3];
+                        e+=$arr[i+4]; f+=$arr[i+5];
+                        g+=$arr[i+6]; h+=$arr[i+7];
+                        mix!();
+                        self.mem[i  ]=a; self.mem[i+1]=b;
+                        self.mem[i+2]=c; self.mem[i+3]=d;
+                        self.mem[i+4]=e; self.mem[i+5]=f;
+                        self.mem[i+6]=g; self.mem[i+7]=h;
+                    }
+                }}
+            );
+
+            memloop!(self.rsl);
+            memloop!(self.mem);
+        } else {
+            for i in range_step(0u32, RAND_SIZE, 8) {
+                mix!();
+                self.mem[i  ]=a; self.mem[i+1]=b;
+                self.mem[i+2]=c; self.mem[i+3]=d;
+                self.mem[i+4]=e; self.mem[i+5]=f;
+                self.mem[i+6]=g; self.mem[i+7]=h;
+            }
+        }
+
+        self.isaac();
+    }
+
+    /// Refills the output buffer (`self.rsl`)
+    #[inline]
+    fn isaac(&mut self) {
+        self.c += 1;
+        // abbreviations
+        let mut a = self.a;
+        let mut b = self.b + self.c;
+
+        static MIDPOINT: uint = RAND_SIZE as uint / 2;
+
+        macro_rules! ind (($x:expr) => {
+            self.mem[($x >> 2) & (RAND_SIZE - 1)]
+        });
+        macro_rules! rngstep(
+            ($j:expr, $shift:expr) => {{
+                let base = $j;
+                let mix = if $shift < 0 {
+                    a >> -$shift as uint
+                } else {
+                    a << $shift as uint
+                };
+
+                let x = self.mem[base  + mr_offset];
+                a = (a ^ mix) + self.mem[base + m2_offset];
+                let y = ind!(x) + a + b;
+                self.mem[base + mr_offset] = y;
+
+                b = ind!(y >> RAND_SIZE_LEN) + x;
+                self.rsl[base + mr_offset] = b;
+            }}
+        );
+
+        let r = [(0, MIDPOINT), (MIDPOINT, 0)];
+        for &(mr_offset, m2_offset) in r.iter() {
+            for i in range_step(0u, MIDPOINT, 4) {
+                rngstep!(i + 0, 13);
+                rngstep!(i + 1, -6);
+                rngstep!(i + 2, 2);
+                rngstep!(i + 3, -16);
+            }
+        }
+
+        self.a = a;
+        self.b = b;
+        self.cnt = RAND_SIZE;
+    }
+}
+
+impl Rng for IsaacRng {
+    #[inline]
+    fn next(&mut self) -> u32 {
+        if self.cnt == 0 {
+            // make some more numbers
+            self.isaac();
+        }
+        self.cnt -= 1;
+        self.rsl[self.cnt]
+    }
+}
diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs
index 70bcb0f7170..3348f5ee7f7 100644
--- a/src/libstd/rand/mod.rs
+++ b/src/libstd/rand/mod.rs
@@ -58,7 +58,10 @@ use uint;
 use vec;
 use libc::size_t;
 
+pub use self::isaac::IsaacRng;
+
 pub mod distributions;
+pub mod isaac;
 
 /// A type that can be randomly generated using an Rng
 pub trait Rand {
@@ -576,184 +579,6 @@ pub fn weak_rng() -> XorShiftRng {
     XorShiftRng::new()
 }
 
-static RAND_SIZE_LEN: u32 = 8;
-static RAND_SIZE: u32 = 1 << RAND_SIZE_LEN;
-
-/// A random number generator that uses the [ISAAC
-/// algorithm](http://en.wikipedia.org/wiki/ISAAC_%28cipher%29).
-///
-/// The ISAAC algorithm is suitable for cryptographic purposes.
-pub struct IsaacRng {
-    priv cnt: u32,
-    priv rsl: [u32, .. RAND_SIZE],
-    priv mem: [u32, .. RAND_SIZE],
-    priv a: u32,
-    priv b: u32,
-    priv c: u32
-}
-
-impl IsaacRng {
-    /// Create an ISAAC random number generator with a random seed.
-    pub fn new() -> IsaacRng {
-        IsaacRng::new_seeded(seed())
-    }
-
-    /// Create an ISAAC random number generator with a seed. This can be any
-    /// length, although the maximum number of bytes used is 1024 and any more
-    /// will be silently ignored. A generator constructed with a given seed
-    /// will generate the same sequence of values as all other generators
-    /// constructed with the same seed.
-    pub fn new_seeded(seed: &[u8]) -> IsaacRng {
-        let mut rng = IsaacRng {
-            cnt: 0,
-            rsl: [0, .. RAND_SIZE],
-            mem: [0, .. RAND_SIZE],
-            a: 0, b: 0, c: 0
-        };
-
-        let array_size = sys::size_of_val(&rng.rsl);
-        let copy_length = cmp::min(array_size, seed.len());
-
-        // manually create a &mut [u8] slice of randrsl to copy into.
-        let dest = unsafe { cast::transmute((&mut rng.rsl, array_size)) };
-        vec::bytes::copy_memory(dest, seed, copy_length);
-        rng.init(true);
-        rng
-    }
-
-    /// Create an ISAAC random number generator using the default
-    /// fixed seed.
-    pub fn new_unseeded() -> IsaacRng {
-        let mut rng = IsaacRng {
-            cnt: 0,
-            rsl: [0, .. RAND_SIZE],
-            mem: [0, .. RAND_SIZE],
-            a: 0, b: 0, c: 0
-        };
-        rng.init(false);
-        rng
-    }
-
-    /// Initialises `self`. If `use_rsl` is true, then use the current value
-    /// of `rsl` as a seed, otherwise construct one algorithmically (not
-    /// randomly).
-    fn init(&mut self, use_rsl: bool) {
-        let mut a = 0x9e3779b9;
-        let mut b = a;
-        let mut c = a;
-        let mut d = a;
-        let mut e = a;
-        let mut f = a;
-        let mut g = a;
-        let mut h = a;
-
-        macro_rules! mix(
-            () => {{
-                a^=b<<11; d+=a; b+=c;
-                b^=c>>2;  e+=b; c+=d;
-                c^=d<<8;  f+=c; d+=e;
-                d^=e>>16; g+=d; e+=f;
-                e^=f<<10; h+=e; f+=g;
-                f^=g>>4;  a+=f; g+=h;
-                g^=h<<8;  b+=g; h+=a;
-                h^=a>>9;  c+=h; a+=b;
-            }}
-        );
-
-        do 4.times { mix!(); }
-
-        if use_rsl {
-            macro_rules! memloop (
-                ($arr:expr) => {{
-                    for i in range_step(0u32, RAND_SIZE, 8) {
-                        a+=$arr[i  ]; b+=$arr[i+1];
-                        c+=$arr[i+2]; d+=$arr[i+3];
-                        e+=$arr[i+4]; f+=$arr[i+5];
-                        g+=$arr[i+6]; h+=$arr[i+7];
-                        mix!();
-                        self.mem[i  ]=a; self.mem[i+1]=b;
-                        self.mem[i+2]=c; self.mem[i+3]=d;
-                        self.mem[i+4]=e; self.mem[i+5]=f;
-                        self.mem[i+6]=g; self.mem[i+7]=h;
-                    }
-                }}
-            );
-
-            memloop!(self.rsl);
-            memloop!(self.mem);
-        } else {
-            for i in range_step(0u32, RAND_SIZE, 8) {
-                mix!();
-                self.mem[i  ]=a; self.mem[i+1]=b;
-                self.mem[i+2]=c; self.mem[i+3]=d;
-                self.mem[i+4]=e; self.mem[i+5]=f;
-                self.mem[i+6]=g; self.mem[i+7]=h;
-            }
-        }
-
-        self.isaac();
-    }
-
-    /// Refills the output buffer (`self.rsl`)
-    #[inline]
-    fn isaac(&mut self) {
-        self.c += 1;
-        // abbreviations
-        let mut a = self.a;
-        let mut b = self.b + self.c;
-
-        static MIDPOINT: uint = RAND_SIZE as uint / 2;
-
-        macro_rules! ind (($x:expr) => {
-            self.mem[($x >> 2) & (RAND_SIZE - 1)]
-        });
-        macro_rules! rngstep(
-            ($j:expr, $shift:expr) => {{
-                let base = $j;
-                let mix = if $shift < 0 {
-                    a >> -$shift as uint
-                } else {
-                    a << $shift as uint
-                };
-
-                let x = self.mem[base  + mr_offset];
-                a = (a ^ mix) + self.mem[base + m2_offset];
-                let y = ind!(x) + a + b;
-                self.mem[base + mr_offset] = y;
-
-                b = ind!(y >> RAND_SIZE_LEN) + x;
-                self.rsl[base + mr_offset] = b;
-            }}
-        );
-
-        let r = [(0, MIDPOINT), (MIDPOINT, 0)];
-        for &(mr_offset, m2_offset) in r.iter() {
-            for i in range_step(0u, MIDPOINT, 4) {
-                rngstep!(i + 0, 13);
-                rngstep!(i + 1, -6);
-                rngstep!(i + 2, 2);
-                rngstep!(i + 3, -16);
-            }
-        }
-
-        self.a = a;
-        self.b = b;
-        self.cnt = RAND_SIZE;
-    }
-}
-
-impl Rng for IsaacRng {
-    #[inline]
-    fn next(&mut self) -> u32 {
-        if self.cnt == 0 {
-            // make some more numbers
-            self.isaac();
-        }
-        self.cnt -= 1;
-        self.rsl[self.cnt]
-    }
-}
-
 /// An [Xorshift random number
 /// generator](http://en.wikipedia.org/wiki/Xorshift).
 ///
@@ -786,7 +611,8 @@ impl XorShiftRng {
     pub fn new() -> XorShiftRng {
         #[fixed_stack_segment]; #[inline(never)];
 
-        // generate seeds the same way as seed(), except we have a spceific size
+        // generate seeds the same way as seed(), except we have a
+        // specific size, so we can just use a fixed buffer.
         let mut s = [0u8, ..16];
         loop {
             do s.as_mut_buf |p, sz| {
@@ -817,12 +643,11 @@ impl XorShiftRng {
     }
 }
 
-/// Create a new random seed.
-pub fn seed() -> ~[u8] {
+/// Create a new random seed of length `n`.
+pub fn seed(n: uint) -> ~[u8] {
     #[fixed_stack_segment]; #[inline(never)];
 
     unsafe {
-        let n = RAND_SIZE * 4;
         let mut s = vec::from_elem(n as uint, 0_u8);
         do s.as_mut_buf |p, sz| {
             rustrt::rand_gen_seed(p, sz as size_t)
@@ -844,7 +669,7 @@ pub fn task_rng() -> @mut IsaacRng {
     let r = local_data::get(tls_rng_state, |k| k.map(|&k| *k));
     match r {
         None => {
-            let rng = @@mut IsaacRng::new_seeded(seed());
+            let rng = @@mut IsaacRng::new();
             local_data::set(tls_rng_state, rng);
             *rng
         }
@@ -877,7 +702,7 @@ mod test {
 
     #[test]
     fn test_rng_seeded() {
-        let seed = seed();
+        let seed = seed(400);
         let mut ra = IsaacRng::new_seeded(seed);
         let mut rb = IsaacRng::new_seeded(seed);
         assert_eq!(ra.gen_ascii_str(100u), rb.gen_ascii_str(100u));