File: random.sml

package info (click to toggle)
mlton 20210117%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 58,464 kB
  • sloc: ansic: 27,682; sh: 4,455; asm: 3,569; lisp: 2,879; makefile: 2,347; perl: 1,169; python: 191; pascal: 68; javascript: 7
file content (105 lines) | stat: -rw-r--r-- 3,490 bytes parent folder | download
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