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
(** Uniform Arrays: non-flat arrays (even floats are boxed, i.e., doesn't use
{!Obj.double_array_tag}) *)
module UArray :
sig
type 'a t
val empty : 'a t
val unsafe_get : 'a t -> int -> 'a
val unsafe_set : 'a t -> int -> 'a -> unit
val length : 'a t -> int
val make : int -> 'a -> 'a t
val copy : 'a t -> 'a t
val of_array : 'a array -> 'a t
val to_array : 'a t -> 'a array
val unsafe_of_obj : Obj.t -> 'a t
end =
struct
type 'a t = Obj.t array
(** Guaranteed to be a non-flat array and no funny business with write
barriers because of the opacity of Obj.t. *)
let empty = [||]
let length (v : 'a t) = Array.length v
let of_array v =
if (Obj.tag (Obj.repr v) == Obj.double_array_tag) then begin
let n = Array.length v in
let ans = Array.make n (Obj.repr ()) in
for i = 0 to n - 1 do
Array.unsafe_set ans i (Obj.repr (Array.unsafe_get v i))
done;
ans
end else
(Obj.magic (Array.copy v))
let obj_is_float x = Obj.tag x == Obj.double_tag
let to_array (type a) (v : a t) : a array =
let () = assert (not (Array.exists obj_is_float v)) in
Obj.magic (Array.copy v)
let unsafe_of_obj (type a) (v : Obj.t) =
let () = assert (Obj.tag v == 0) in
(Obj.obj v : a t)
let unsafe_get = Obj.magic Array.unsafe_get
let unsafe_set = Obj.magic Array.unsafe_set
let make (type a) n (x : a) : a t =
let ans = Array.make n (Obj.repr ()) in
let () = Array.fill ans 0 n (Obj.repr x) in
ans
let copy = Array.copy
end
let max_array_length32 = 4194303
let max_length = Uint63.of_int max_array_length32
let length_to_int i = snd (Uint63.to_int2 i)
let trunc_size n =
if Uint63.le Uint63.zero n && Uint63.lt n (Uint63.of_int max_array_length32) then
length_to_int n
else max_array_length32
type 'a t = ('a kind) ref
and 'a kind =
| Array of 'a UArray.t * 'a
| Updated of int * 'a * 'a t
let unsafe_of_obj t def = ref (Array (UArray.unsafe_of_obj t, def))
let of_array t def = ref (Array (UArray.of_array t, def))
let rec rerootk t k =
match !t with
| Array (a, _) -> k a
| Updated (i, v, p) ->
let k' a =
let v' = UArray.unsafe_get a i in
UArray.unsafe_set a i v;
t := !p;
p := Updated (i, v', t);
k a in
rerootk p k'
let reroot t = rerootk t (fun a -> a)
let length_int p =
UArray.length (reroot p)
let length p = Uint63.of_int @@ length_int p
let get p n =
let t = reroot p in
let l = UArray.length t in
if Uint63.le Uint63.zero n && Uint63.lt n (Uint63.of_int l) then
UArray.unsafe_get t (length_to_int n)
else
match !p with
| Array (_, def) -> def
| Updated _ -> assert false
let set p n e =
let a = reroot p in
let l = Uint63.of_int (UArray.length a) in
if Uint63.le Uint63.zero n && Uint63.lt n l then
let i = length_to_int n in
let v' = UArray.unsafe_get a i in
UArray.unsafe_set a i e;
let t = ref !p in
p := Updated (i, v', t);
t
else p
let default p =
let _ = reroot p in
match !p with
| Array (_,def) -> def
| Updated _ -> assert false
let make_int n def =
ref (Array (UArray.make n def, def))
let make n def = make_int (trunc_size n) def
let uinit n f =
if Int.equal n 0 then UArray.empty
else begin
let t = UArray.make n (f 0) in
for i = 1 to n - 1 do
UArray.unsafe_set t i (f i)
done;
t
end
let init n f def =
let n = trunc_size n in
let t = uinit n f in
ref (Array (t, def))
let to_array p =
let _ = reroot p in
match !p with
| Array (t,def) -> UArray.to_array t, def
| Updated _ -> assert false
let copy p =
let _ = reroot p in
match !p with
| Array (t, def) -> ref (Array (UArray.copy t, def))
| Updated _ -> assert false
let is_rooted p = match !p with
| Array _ -> true
| Updated _ -> false
type 'a cache = {
orig : 'a t;
mutable self : 'a UArray.t;
mutable rerooted_again : bool;
}
let make_cache p = {
orig = p;
self = reroot p;
rerooted_again = false;
}
let uget_cache cache i =
let () = if not cache.rerooted_again && not (is_rooted cache.orig)
then begin
cache.self <- UArray.copy (reroot cache.orig);
cache.rerooted_again <- true
end
in
UArray.unsafe_get cache.self i
let map f p =
let t = make_cache p in
let len = UArray.length t.self in
let res = uinit len (fun i -> f (uget_cache t i)) in
let def = f (default p) in
ref (Array (res, def))
let fold_left f x p =
let r = ref x in
let t = make_cache p in
let len = UArray.length t.self in
for i = 0 to len - 1 do
r := f !r (uget_cache t i)
done;
f !r (default p)
let fold_left2 f a p1 p2 =
let r = ref a in
let t1 = make_cache p1 in
let len = UArray.length t1.self in
let t2 = make_cache p2 in
if UArray.length t2.self <> len then invalid_arg "Parray.fold_left2";
for i = 0 to len - 1 do
let v1 = uget_cache t1 i in
let v2 = uget_cache t2 i in
r := f !r v1 v2
done;
f !r (default p1) (default p2)