1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
|
(* Copyright (C) 2009 Matthew Fluet.
* Copyright (C) 2002-2006 Henry Cejtin, Matthew Fluet, Suresh
* Jagannathan, and Stephen Weeks.
* Copyright (C) 1997-2000 NEC Research Institute.
*
* MLton is released under a HPND-style license.
* See the file MLton-LICENSE for details.
*)
structure MLtonRandom: MLTON_RANDOM =
struct
(* Uses /dev/random and /dev/urandom to get a random word.
* If they can't be read from, return NONE.
*)
local
fun make (file, name) =
let
val buf = Word8Array.array (4, 0w0)
in
fn () =>
(let
val fd =
let
open Posix.FileSys
in
openf (file, O_RDONLY, O.flags [])
end
fun loop rem =
let
val n = Posix.IO.readArr (fd,
Word8ArraySlice.slice
(buf, 4 - rem, SOME rem))
val _ = if n = 0
then (Posix.IO.close fd; raise Fail name)
else ()
val rem = rem - n
in
if rem = 0
then ()
else loop rem
end
val _ = loop 4
val _ = Posix.IO.close fd
in
SOME (Word.fromLarge (PackWord32Little.subArr (buf, 0)))
end
handle OS.SysErr _ => NONE)
end
in
val seed = make ("/dev/random", "Random.seed")
val useed = make ("/dev/urandom", "Random.useed")
end
local
open Word
val seed: word ref = ref 0w13
in
(* From page 284 of Numerical Recipes in C. *)
fun rand (): word =
let
val res = 0w1664525 * !seed + 0w1013904223
val _ = seed := res
in
res
end
fun srand (w: word): unit = seed := w
end
local
val chars =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
val numChars = String.size chars
val refresh =
let
val numChars = IntInf.fromInt numChars
fun loop (i: IntInf.int, c: int): int =
if IntInf.< (i, numChars)
then c
else loop (IntInf.div (i, numChars), c + 1)
in
loop (IntInf.pow (2, Word.wordSize), 0)
end
val r: word ref = ref 0w0
val count: int ref = ref refresh
val numChars = Word.fromInt numChars
in
fun alphaNumChar (): char =
let
val n = !count
val _ = if n = refresh
then (r := rand ()
; count := 1)
else (count := n + 1)
val w = !r
val c = String.sub (chars, Word.toInt (Word.mod (w, numChars)))
val _ = r := Word.div (w, numChars)
in
c
end
end
fun alphaNumString (length: int): string =
CharVector.tabulate (length, fn _ => alphaNumChar ())
end
|