Source file option_array.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
147
148
149
150
151
152
open! Import
(** ['a Cheap_option.t] is like ['a option], but it doesn't box [some _] values.
There are several things that are unsafe about it:
- [float t array] (or any array-backed container) is not memory-safe
because float array optimization is incompatible with unboxed option
optimization. You have to use [Uniform_array.t] instead of [array].
- Nested options (['a t t]) don't work. They are believed to be
memory-safe, but not parametric.
- A record with [float t]s in it should be safe, but it's only [t] being
abstract that gives you safety. If the compiler was smart enough to peek
through the module signature then it could decide to construct a float
array instead. *)
module Cheap_option = struct
let phys_same (type a b) (a : a) (b : b) = phys_equal a (Caml.Obj.magic b : a)
module T0 : sig
type 'a t
val none : _ t
val some : 'a -> 'a t
val is_none : _ t -> bool
val is_some : _ t -> bool
val value_exn : 'a t -> 'a
val value_unsafe : 'a t -> 'a
end = struct
type +'a t
let none_substitute : _ t = Caml.Obj.obj (Caml.Obj.new_block Caml.Obj.abstract_tag 1)
let none : _ t =
Caml.Obj.magic `x6e8ee3478e1d7449
;;
let is_none x = phys_equal x none
let is_some x = not (phys_equal x none)
let some (type a) (x : a) : a t =
if phys_same x none then none_substitute else Caml.Obj.magic x
;;
let value_unsafe (type a) (x : a t) : a =
if phys_equal x none_substitute then Caml.Obj.magic none else Caml.Obj.magic x
;;
let value_exn x =
if is_some x
then value_unsafe x
else failwith "Option_array.get_some_exn: the element is [None]"
;;
end
module T1 = struct
include T0
let of_option = function
| None -> none
| Some x -> some x
;;
let to_option x = if is_some x then Some (value_unsafe x) else None
let to_sexpable = to_option
let of_sexpable = of_option
end
include T1
include Sexpable.Of_sexpable1 (Option) (T1)
end
type 'a t = 'a Cheap_option.t Uniform_array.t [@@deriving_inline sexp]
let t_of_sexp : 'a. (Ppx_sexp_conv_lib.Sexp.t -> 'a) -> Ppx_sexp_conv_lib.Sexp.t -> 'a t =
let _tp_loc = "option_array.ml.t" in
fun _of_a t -> Uniform_array.t_of_sexp (Cheap_option.t_of_sexp _of_a) t
;;
let sexp_of_t : 'a. ('a -> Ppx_sexp_conv_lib.Sexp.t) -> 'a t -> Ppx_sexp_conv_lib.Sexp.t =
fun _of_a v -> Uniform_array.sexp_of_t (Cheap_option.sexp_of_t _of_a) v
;;
[@@@end]
let empty = Uniform_array.empty
let create ~len = Uniform_array.create ~len Cheap_option.none
let init n ~f = Uniform_array.init n ~f:(fun i -> Cheap_option.of_option (f i))
let init_some n ~f = Uniform_array.init n ~f:(fun i -> Cheap_option.some (f i))
let length = Uniform_array.length
let get t i = Cheap_option.to_option (Uniform_array.get t i)
let get_some_exn t i = Cheap_option.value_exn (Uniform_array.get t i)
let is_none t i = Cheap_option.is_none (Uniform_array.get t i)
let is_some t i = Cheap_option.is_some (Uniform_array.get t i)
let set t i x = Uniform_array.set t i (Cheap_option.of_option x)
let set_some t i x = Uniform_array.set t i (Cheap_option.some x)
let set_none t i = Uniform_array.set t i Cheap_option.none
let swap t i j = Uniform_array.swap t i j
let unsafe_get t i = Cheap_option.to_option (Uniform_array.unsafe_get t i)
let unsafe_get_some_exn t i = Cheap_option.value_exn (Uniform_array.unsafe_get t i)
let unsafe_get_some_assuming_some t i =
Cheap_option.value_unsafe (Uniform_array.unsafe_get t i)
;;
let unsafe_is_some t i = Cheap_option.is_some (Uniform_array.unsafe_get t i)
let unsafe_set t i x = Uniform_array.unsafe_set t i (Cheap_option.of_option x)
let unsafe_set_some t i x = Uniform_array.unsafe_set t i (Cheap_option.some x)
let unsafe_set_none t i = Uniform_array.unsafe_set t i Cheap_option.none
let clear t =
for i = 0 to length t - 1 do
unsafe_set_none t i
done
;;
include Blit.Make1_generic (struct
type nonrec 'a t = 'a t
let length = length
let create_like ~len _ = create ~len
let unsafe_blit = Uniform_array.unsafe_blit
end)
let copy = Uniform_array.copy
module For_testing = struct
module Unsafe_cheap_option = Cheap_option
end