package repr

  1. Overview
  2. Docs

Source file type_random.ml

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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
open Type_core
open Staging
module R = Random.State

module Attr = Attribute.Make1 (struct
  type 'a t = R.t -> 'a

  let name = "random"
end)

type 'a random = (R.t -> 'a) staged

let ( let+ ) x f =
  let x = unstage x in
  stage (f x)

let ( and+ ) a b = stage (unstage a, unstage b)
let return x = stage (fun _ -> x)

(* Sample lengths according to a geometric distribution by inverse
   transform sampling an exponential one (characterised by [mean_length = λ⁻¹])
   and rounding to integer values. *)
let pick_len : mean:int -> len -> R.t -> int =
  let bound len x =
    match len with
    | `Int | `Int64 -> x
    | `Int8 -> min x ((1 lsl 8) - 1)
    | `Int16 -> min x ((1 lsl 16) - 1)
    | `Int32 -> min x ((0x7fff lsl 16) lor 0xffff)
  in
  fun ~mean l s ->
    match l with
    | (`Int | `Int8 | `Int16 | `Int32 | `Int64) as l ->
        bound l (Float.to_int (-.Float.log (R.float s 1.) *. Float.of_int mean))
    | `Fixed i -> i

let indexable :
    type a b.
    mean_len:int -> len -> (int -> (int -> a) -> b) -> a random -> b random =
 fun ~mean_len len init elt ->
  let+ elt = elt in
  fun s -> init (pick_len ~mean:mean_len len s) (fun _ -> elt s)

module Record_deriver = Fields_folder (struct
  type ('a, 'b) t = R.t -> 'b -> 'a
end)

let int32 =
  let open Int32 in
  let bits s = of_int (R.bits s) in
  fun s -> logxor (bits s) (shift_left (bits s) 30)

let int64 =
  let open Int64 in
  let bits s = of_int (R.bits s) in
  fun s ->
    logxor (bits s) (logxor (shift_left (bits s) 30) (shift_left (bits s) 60))

let int =
  match Sys.word_size with
  | 64 -> fun s -> Int64.to_int (int64 s)
  | 32 -> fun s -> Int32.to_int (int32 s)
  | _ -> assert false

let float s =
  R.float s (if R.bool s then Float.max_float else -.Float.max_float)

let rec t : type a. a t -> a random = function
  | Map x -> map x
  | Prim x -> prim x
  | Tuple x -> tuple x
  | List { len; v } -> indexable ~mean_len:4 len List.init (t v)
  | Array { len; v } -> indexable ~mean_len:4 len Array.init (t v)
  | Option x -> option x
  | Record x -> record x
  | Variant x -> variant x
  | Attributes { attrs; attr_type } -> (
      match Attr.find attrs with Some f -> stage f | None -> t attr_type)
  | Boxed x -> t x
  | Self x -> stage (fun s -> (* improperly staged *) unstage (t x.self_fix) s)
  | Custom _ -> failwith "Cannot generate random instance of Custom type"
  | Var v -> raise (Unbound_type_variable v)

and char : char random = stage (fun s -> Char.unsafe_chr (R.int s 256))

and prim : type a. a prim -> a random = function
  | Unit -> return ()
  | Bool -> stage R.bool
  | Char -> char
  | Int -> stage int
  | Int32 -> stage int32
  | Int64 -> stage int64
  | Float -> stage float
  | String len -> indexable ~mean_len:8 len String.init char
  | Bytes len -> indexable ~mean_len:8 len Bytes.init char

and tuple : type a. a tuple -> a random = function
  | Pair (a, b) ->
      let+ a = t a and+ b = t b in
      fun s -> (a s, b s)
  | Triple (a, b, c) ->
      let+ a = t a and+ b = t b and+ c = t c in
      fun s -> (a s, b s, c s)

and option : type a. a t -> a option random =
 fun elt ->
  let+ elt = t elt in
  fun s -> match R.bool s with true -> None | false -> Some (elt s)

and record : type a. a record -> a random =
 fun { rfields = Fields (fs, constr); _ } ->
  let nil _ v = v in
  let cons { ftype; _ } random_remaining =
    let f_random = unstage (t ftype) in
    fun s constr ->
      let f = f_random s in
      random_remaining s (constr f)
  in
  let f = Record_deriver.fold { nil; cons } fs in
  stage (fun s -> f s constr)

and variant : type a. a variant -> a random =
 fun v ->
  let random_case =
    let cases = Array.length v.vcases in
    fun s -> R.int s cases
  in
  let generators =
    ArrayLabels.map v.vcases ~f:(function
      | C0 { c0; _ } -> fun _ -> c0
      | C1 { c1; ctype1; _ } ->
          let inner = unstage (t ctype1) in
          fun s -> c1 (inner s))
  in
  stage (fun s -> generators.(random_case s) s)

and map : type a b. (a, b) map -> b random =
 fun m ->
  let+ inner = t m.x in
  fun s -> m.f (inner s)

let of_state = t

let of_global ty =
  let+ random = of_state ty in
  fun () -> random (Random.get_state ())
OCaml

Innovation. Community. Security.