Source file conex_utils.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
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
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
type 'a fmt = Format.formatter -> 'a -> unit
let pp_list pe ppf xs =
match xs with
| [] -> Format.pp_print_string ppf "empty"
| xs ->
Format.pp_print_string ppf "[" ;
let rec p1 = function
| [] -> Format.pp_print_string ppf "]" ;
| [x] -> Format.fprintf ppf "%a]" pe x
| x::xs -> Format.fprintf ppf "%a;@ " pe x ; p1 xs
in
p1 xs
module S = struct
include Set.Make(String)
let pp fmt t = pp_list Format.pp_print_string fmt (elements t)
let of_list es = List.fold_right add es empty
end
let str_pp pp e =
Format.(fprintf str_formatter "%a" pp e) ;
Format.flush_str_formatter ()
let (>>=) a f =
match a with
| Ok x -> f x
| Error e -> Error e
let guard p err = if p then Ok () else Error err
let rec foldM f n = function
| [] -> Ok n
| x::xs -> f n x >>= fun n' -> foldM f n' xs
let rec iterM f = function
| [] -> Ok ()
| x::xs -> f x >>= fun () -> iterM f xs
let foldS f a s =
S.fold (fun id r ->
r >>= fun r ->
f r id) s (Ok a)
let err_to_str pp = function
| Ok a -> Ok a
| Error e -> Error (str_pp pp e)
module String = struct
type t = string
let cut sep str =
try
let idx = String.index str sep
and l = String.length str
in
let sidx = succ idx in
Some (String.sub str 0 idx, String.sub str sidx (l - sidx))
with
Not_found -> None
let cuts sep str =
let rec doit acc s =
match cut sep s with
| None -> List.rev (s :: acc)
| Some (a, b) -> doit (a :: acc) b
in
doit [] str
let slice ?(start = 0) ?stop str =
let stop = match stop with
| None -> String.length str
| Some x -> x
in
let len = stop - start in
String.sub str start len
let is_prefix ~prefix str =
let pl = String.length prefix in
if String.length str < pl then
false
else
String.sub str 0 (String.length prefix) = prefix
let is_suffix ~suffix str =
let sl = String.length suffix in
if String.length str < sl then
false
else
String.sub str (String.length str - sl) sl = suffix
let lowercase_char = function
| 'A' .. 'Z' as c -> char_of_int (int_of_char c + 0x20)
| c -> c
let to_lower s =
let last = pred (String.length s)
and bs = Bytes.of_string s
in
for k = 0 to last do
Bytes.set bs k (lowercase_char (Bytes.get bs k))
done ;
Bytes.to_string bs
let ascii_char ?(p = fun _ -> false) = function
| '0' .. '9'
| 'A' .. 'Z'
| 'a' .. 'z' -> true
| x -> p x
let is_ascii ?p s =
let last = pred (String.length s) in
let res = ref true in
for k = 0 to last do
res := !res && ascii_char ?p (String.get s k)
done;
!res
let trim = String.trim
let get = String.get
let concat = String.concat
let compare = String.compare
let length = String.length
let compare_insensitive a b =
compare (to_lower a) (to_lower b)
let equal = String.equal
end
module Uint = struct
type t = int64
let zero = 0L
let max = -1L
let compare a b =
Int64.(compare (sub a min_int) (sub b min_int))
let succ x =
if x = max then
(true, 0L)
else
(false, Int64.succ x)
let to_string s = Printf.sprintf "%LX" s
let pp ppf i = Format.pp_print_string ppf (to_string i)
let decimal s = Printf.sprintf "%Lu" s
let of_string s =
try Some (Int64.of_string ("0x" ^ s)) with Failure _ -> None
let of_float f =
if f < 0. then
None
else
try Some (Int64.of_float f) with Failure _ -> None
let of_int_exn i =
if i < 0 then
invalid_arg "cannot convert integers smaller than 0"
else
Int64.of_int i
let of_int i = try Some (of_int_exn i) with Failure _ -> None
end
module Uint_map = struct
include Map.Make(Uint)
let find k m = try Some (find k m) with Not_found -> None
end
module M = struct
include Map.Make(String)
let find k m = try Some (find k m) with Not_found -> None
let pp pp_e ppf m =
iter (fun k v -> Format.fprintf ppf "%s -> %a@ " k pp_e v) m
end
let rec filter_map ~f = function
| [] -> []
| x::xs ->
match f x with
| None -> filter_map ~f xs
| Some x' -> x' :: filter_map ~f xs
module type LOGS = sig
module Tag : sig
type set
end
type ('a, 'b) msgf =
(?header:string -> ?tags:Tag.set ->
('a, Format.formatter, unit, 'b) format4 -> 'a) -> 'b
type 'a log = ('a, unit) msgf -> unit
type src
val warn_count : unit -> int
val debug : ?src:src -> 'a log
val info : ?src:src -> 'a log
val warn : ?src:src -> 'a log
end
type file_type = File | Directory
type path = string list
let root = []
let non_path = [ ".." ; "." ; "" ; "/" ]
let path_to_string path =
assert (not (List.exists (fun s -> List.mem s non_path) path)) ;
List.fold_left Filename.concat "" path
let string_to_path_exn str =
let segments = String.cuts '/' str in
let segs = match segments with
| ""::xs -> xs
| xs -> xs
in
if List.exists (fun s -> List.mem s non_path) segs then
invalid_arg "invalid path"
else
segs
let string_to_path str =
try Ok (string_to_path_exn str) with
| Invalid_argument m -> Error m
let path_equal a b =
let str_eq a b = String.compare a b = 0 in
try List.for_all2 str_eq a b with _ -> false
let rec subpath ~parent b =
let str_eq a b = String.compare a b = 0 in
match parent, b with
| [], [] -> false
| [], _ -> true
| _, [] -> false
| hd::tl, hd'::tl' -> if str_eq hd hd' then subpath ~parent:tl tl' else false
let pp_path fmt p = Format.pp_print_string fmt (path_to_string p)
type item = file_type * string
module Tree = struct
type 'a t = Node of 'a list * 'a t M.t
let rec equal eq (Node (del, map)) (Node (del', map')) =
(try List.for_all2 eq del del' with _ -> false) &&
M.equal (equal eq) map map'
let empty = Node ([], M.empty)
let is_empty = function
| Node ([], m) when M.is_empty m -> true
| Node (_, _) -> false
let rec sub path t = match path, t with
| [], n -> n
| hd::tl, Node (_, m) -> match M.find hd m with
| None -> empty
| Some n -> sub tl n
let fold f acc root =
let rec doit path (Node (v, map)) acc =
let acc' = f path v acc in
M.fold (fun k v acc -> doit (path @ [k]) v acc) map acc'
in
doit [] root acc
let pp pp_e ppf node =
let rec pp prefix ppf (Node (dels, map)) =
let pp_map ppf map =
List.iter (fun (key, node) ->
let prefix' = prefix ^ "/" ^ key in
Format.fprintf ppf "@[<2>%s@ ->@ %a@]@,"
prefix' (pp prefix') node)
(M.bindings map)
in
Format.fprintf ppf "@[<2>values:@ %a@.%a@,@]@,"
(pp_list pp_e) dels
pp_map map
in
(pp "") ppf node
let rec lookup path (Node (dels, map)) =
match path with
| [] -> Some dels
| hd::tl -> match M.find hd map with
| None -> None
| Some x -> lookup tl x
let lookup_prefix path node =
let rec lookup sofar path (Node (dels, map)) =
let ext = match dels with [] -> sofar | d -> d in
match path with
| [] -> ext
| hd::tl -> match M.find hd map with
| None -> ext
| Some x -> lookup ext tl x
in
lookup [] path node
let rec insert path value (Node (dels, map)) =
match path with
| [] -> Node (dels @ [ value ], map)
| hd::tl ->
let n = match M.find hd map with
| None -> empty
| Some x -> x
in
let res = insert tl value n in
Node (dels, M.add hd res map)
end