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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
let eq_closure : type a. a -> a -> bool =
fun f g ->
let open Obj in
let adone = ref [] in
let rec fn f g =
f == g ||
match is_int f, is_int g with
| true, true -> f == g
| false, true | true, false -> false
| false, false ->
let ft = tag f and gt = tag g in
if ft = forward_tag then (
fn (field f 0) g)
else if gt = forward_tag then (
fn f (field g 0))
else if ft <> gt then false
else
if ft = string_tag || ft = double_tag || ft = double_array_tag
then f = g
else if ft = abstract_tag || ft = out_of_heap_tag
|| ft = no_scan_tag || ft = custom_tag || ft = infix_tag
then f == g
else
size f == size g &&
let rec gn i =
if i < 0 then true
else fn (field f i) (field g i) && gn (i - 1)
in
List.exists (fun (f',g') -> f == f' && g == g') !adone ||
(List.for_all (fun (f',g') -> f != f' && g != g') !adone &&
(adone := (f,g)::!adone;
gn (size f - 1)))
in fn (repr f) (repr g)
module EqHashtbl :
sig
type ('a, 'b) t
val create : int -> ('a, 'b) t
val add : ('a, 'b) t -> 'a -> 'b -> unit
val find : ('a, 'b) t -> 'a -> 'b
val iter : ('a -> 'b -> unit) -> ('a, 'b) t -> unit
end =
struct
type ('a, 'b) t =
{ mutable nb_buckets : int
; mutable buckets : ('a * 'b) list array
; mutable max_size : int
; mutable size_limit : int }
let rec log2 n = if n <= 0 then 0 else 1 + log2 (n lsr 1)
let create : int -> ('a, 'b) t =
fun nb_buckets ->
let nb_buckets = max nb_buckets 8 in
let buckets = Array.make nb_buckets [] in
let size_limit = log2 nb_buckets + 7 in
{ nb_buckets ; buckets ; max_size = 0 ; size_limit }
let iter : ('a -> 'b -> unit) -> ('a, 'b) t -> unit =
fun fn h ->
Array.iter (List.iter (fun (k,v) -> fn k v)) h.buckets
let hash = Hashtbl.hash
let find_bucket : ('a, 'b) t -> 'a -> int =
fun h k -> hash k mod h.nb_buckets
exception Size_is of int
let rec add : ('a, 'b) t -> 'a -> 'b -> unit =
fun h k v ->
let i = find_bucket h k in
let rec remove sz = function
| [] -> raise (Size_is sz)
| (kv,_) :: ls when eq_closure k kv -> ls
| e :: ls -> e :: remove (sz+1) ls
in
try h.buckets.(i) <- (k,v) :: remove 0 h.buckets.(i)
with Size_is(sz) ->
h.buckets.(i) <- (k,v) :: h.buckets.(i);
h.max_size <- max h.max_size sz;
if h.max_size > h.size_limit then grow h
and grow : ('a, 'b) t -> unit =
fun h ->
let old_tbl = h.buckets in
h.nb_buckets <- h.nb_buckets * 2;
h.buckets <- Array.make h.nb_buckets [];
h.size_limit <- h.size_limit + 1;
h.max_size <- 0;
Array.iter (List.iter (fun (k,v) -> add h k v)) old_tbl
let find : ('a, 'b) t -> 'a -> 'b =
fun h k ->
let i = find_bucket h k in
let rec find = function
| [] -> raise Not_found
| (kv,v)::xs -> if eq_closure k kv then v else find xs
in
find h.buckets.(i)
end
(** This modules implements a computation of a fixpoints for valus
that depends upon other values. Cycles are handled through update of
references. If the fixpoint is not reached, this might loop.
This modules ressemble a little the Lazy module.
*)
module Fixpoint :
sig
type 'a t
(** Standard way to construct a value of type ['a t] *)
val from_val : 'a -> 'a t
val from_fun : 'a t -> ('a -> 'b) -> 'b t
val from_fun2 : 'a t -> 'b t -> ('a -> 'b -> 'c) -> 'c t
val from_funl : 'a t list -> 'b -> ('b -> 'a -> 'b) -> 'b t
(** value obtained by reading 'b which is mutable *)
val from_ref : 'b -> ('b -> 'a t) -> 'a t
(** Must be called when updating a mutable field used in [from_ref] *)
val update : 'a t -> unit
(** Reading the value *)
val force : 'a t -> 'a
end =
struct
module rec H :
sig
type 'a fix =
{ mutable value : 'a
; compute : unit -> unit
; mutable deps : W.t option
; mutable is_ref : ('a fix * (unit -> 'a fix)) option
; ident : int }
include Hashtbl.HashedType with type t = Obj.t fix
end =
struct
type 'a fix =
{ mutable value : 'a
; compute : unit -> unit
; mutable deps : W.t option
; mutable is_ref : ('a fix * (unit -> 'a fix)) option
; ident : int }
type t = Obj.t fix
let equal a b = a.ident = b.ident
let hash a = a.ident
end
and W : Weak.S with type data = H.t = Weak.Make(H)
open H
type 'a t = 'a fix
let force : 'a t -> 'a = fun b -> b.value
let new_id =
let r = ref 0 in
(fun () -> let x = !r in r := x + 1; x)
let add_deps r {deps;_} =
match deps with
| None -> true
| Some tbl ->
let r = Obj.magic r in
if not (W.mem tbl r) then W.add tbl r;
false
let iter_deps fn {deps;_} =
match deps with
| None -> ()
| Some tbl -> W.iter (fun v -> fn (Obj.magic v)) tbl
let from_val value =
{ value
; compute = ignore
; deps = None
; is_ref = None
; ident = new_id () }
let from_fun l fn =
let rec res =
{ value = fn l.value
; compute = (fun () -> res.value <- fn l.value)
; deps = Some (W.create 7)
; is_ref = None
; ident = new_id () }
in
if add_deps res l then res.deps <- None;
res
let from_fun2 l1 l2 fn =
let rec res =
{ value = fn l1.value l2.value
; compute = (fun () -> res.value <- fn l1.value l2.value)
; deps = Some (W.create 7)
; is_ref = None
; ident = new_id () }
in
let b1 = add_deps res l1 in
let b2 = add_deps res l2 in
if b1 && b2 then res.deps <- None;
res
let rec fold l a f =
match l with
| [] -> a
| x::l -> fold l (f a x.value) f
let from_funl l a fn =
let rec res =
{ value = fold l a fn
; compute = (fun () -> res.value <- fold l a fn)
; deps = Some (W.create 7)
; is_ref = None
; ident = new_id () }
in
let fn acc x = add_deps res x && acc in
if List.fold_left fn true l then res.deps <- None;
res
let from_ref l fn =
let a = fn l in
let rec res =
{ value = a.value
; compute = (fun () -> res.value <- (fn l).value)
; deps = Some (W.create 7)
; is_ref = Some (a, fun () -> fn l)
; ident = new_id () }
in
ignore (add_deps res a);
res
let update b =
begin
match b.is_ref with
| None -> invalid_arg "Fixpoint.update";
| Some(_,f) ->
let a' = f () in
ignore (add_deps b a');
b.is_ref <- Some (a', f)
end;
let rec fn x =
let old = x.value in x.compute ();
if old <> x.value then iter_deps fn x
in fn b
end