[@@@warning "-37"] module Peano = struct type zero = Zero type 'a succ = Succ type one = zero succ type two = zero succ succ type three = zero succ succ end type ('a, 'l) digit = | Zero : ('a, Peano.zero) digit | One : 'a -> ('a, Peano.one) digit | Two : 'a * 'a -> ('a, Peano.two) digit | Three : 'a * 'a * 'a -> ('a, Peano.three) digit type 'a t = | Shallow : ('a, 'l) digit -> 'a t | Deep : { s : int; f : ('a, 'f Peano.succ) digit; m : ('a * 'a) t Lazy.t; r : ('a, 'r Peano.succ) digit; } -> 'a t let empty = Shallow Zero exception Empty let _one x = Shallow (One x) let _two x y = Shallow (Two (x, y)) let _three x y z = Shallow (Three (x, y, z)) let _deep s f m r = Deep { s; f; m; r } let is_empty : type a. a t -> bool = function | Shallow Zero -> true | Shallow _ | Deep _ -> false let rec push : type a. a t -> a -> a t = fun q x -> match q with | Shallow Zero -> _one x | Shallow (One y) -> _two y x | Shallow (Two (y, z)) -> _three y z x | Shallow (Three (a, b, c)) -> _deep 4 (Two (a, b)) (Lazy.from_val empty) (Two (c, x)) | Deep { s; f; m; r = One y } -> _deep (s + 1) f m (Two (y, x)) | Deep { s; f; m; r = Two (y, z) } -> _deep (s + 1) f m (Three (y, z, x)) | Deep { s; f; m = (lazy q'); r = Three (y, z, z') } -> _deep (s + 1) f (lazy (push q' (y, z))) (Two (z', x)) let rec pop_exn : type a. a t -> a * a t = fun q -> match q with | Shallow Zero -> raise Empty | Shallow (One x) -> (x, empty) | Shallow (Two (x, y)) -> (x, _one y) | Shallow (Three (x, y, z)) -> (x, _two y z) | Deep { s; f = One x; m = (lazy q'); r } -> if is_empty q' then (x, Shallow r) else let (y, z), q' = pop_exn q' in (x, _deep (s - 1) (Two (y, z)) (Lazy.from_val q') r) | Deep { s; f = Two (x, y); m; r } -> (x, _deep (s - 1) (One y) m r) | Deep { s; f = Three (x, y, z); m; r } -> (x, _deep (s - 1) (Two (y, z)) m r) let rec tail_exn : type a. a t -> a t * a = fun q -> match q with | Shallow Zero -> raise Empty | Shallow (One x) -> (empty, x) | Shallow (Two (x, y)) -> (_one x, y) | Shallow (Three (x, y, z)) -> (_two x y, z) | Deep { s; f; m = (lazy q'); r = One x } -> if is_empty q' then (Shallow f, x) else let q'', (y, z) = tail_exn q' in (_deep (s - 1) f (Lazy.from_val q'') (Two (y, z)), x) | Deep { s; f; m; r = Two (x, y) } -> (_deep (s - 1) f m (One x), y) | Deep { s; f; m; r = Three (x, y, z) } -> (_deep (s - 1) f m (Two (x, y)), z) let peek_exn : type a. a t -> a = fun q -> match q with | Shallow Zero -> raise Empty | Shallow (One x) -> x | Shallow (Two (x, _)) -> x | Shallow (Three (x, _, _)) -> x | Deep { f = One x; _ } -> x | Deep { f = Two (x, _); _ } -> x | Deep { f = Three (x, _, _); _ } -> x let pop q = try Some (pop_exn q) with Empty -> None let tail q = try Some (tail_exn q) with Empty -> None let peek q = try Some (peek_exn q) with Empty -> None let rec cons : type a. a t -> a -> a t = fun q x -> match q with | Shallow Zero -> _one x | Shallow (One y) -> _two x y | Shallow (Two (y, z)) -> _three x y z | Shallow (Three (y, z, z')) -> _deep 4 (Two (x, y)) (Lazy.from_val empty) (Two (z, z')) | Deep { s; f = One y; m; r } -> _deep (s + 1) (Two (x, y)) m r | Deep { s; f = Two (y, z); m; r } -> _deep (s + 1) (Three (x, y, z)) m r | Deep { s; f = Three (y, z, z'); m = (lazy q'); r } -> _deep (s + 1) (Three (x, y, z)) (lazy (cons q' (z, z'))) r let iter : type a. (a -> unit) -> a t -> unit = fun f q -> let rec go : type a. (a -> unit) -> a t -> unit = fun f -> function | Shallow Zero -> () | Shallow (One x) -> f x | Shallow (Two (x, y)) -> f x; f y | Shallow (Three (x, y, z)) -> f x; f y; f z | Deep { f = hd; m = (lazy q); r = tl; _ } -> go f (Shallow hd); go (fun (x, y) -> f x; f y) q; go f (Shallow tl) in go f q let rev_iter : type a. (a -> unit) -> a t -> unit = fun f q -> let rec go : type a. (a -> unit) -> a t -> unit = fun f -> function | Shallow Zero -> () | Shallow (One x) -> f x | Shallow (Two (y, x)) -> f x; f y | Shallow (Three (z, y, x)) -> f x; f y; f z | Deep { f = hd; m = (lazy q); r = tl; _ } -> go f (Shallow tl); go (fun (y, x) -> f x; f y) q; go f (Shallow hd) in go f q let fold : type acc x. (acc -> x -> acc) -> acc -> x t -> acc = fun f a q -> let rec go : type acc x. (acc -> x -> acc) -> acc -> x t -> acc = fun f a -> function | Shallow Zero -> a | Shallow (One x) -> f a x | Shallow (Two (x, y)) -> f (f a x) y | Shallow (Three (x, y, z)) -> f (f (f a x) y) z | Deep { f = hd; m = (lazy q); r = tl; _ } -> let a = go f a (Shallow hd) in let a = go (fun a (x, y) -> f (f a x) y) a q in go f a (Shallow tl) in go f a q let length = function | Deep { s; _ } -> s | Shallow Zero -> 0 | Shallow (One _) -> 1 | Shallow (Two _) -> 2 | Shallow (Three _) -> 3 let pp ?sep pp_elt = Fmt.iter ?sep iter pp_elt let dump pp_elt = Fmt.Dump.iter iter (Fmt.any "fke") pp_elt module Weighted = struct type ('a, 'b) t = { r : int; w : int; c : int; k : ('a, 'b) Bigarray.kind; v : ('a, 'b, Bigarray.c_layout) Bigarray.Array1.t; } exception Empty exception Full let[@inline always] mask t v = v land (t.c - 1) let[@inline always] empty t = t.r = t.w let[@inline always] size t = t.w - t.r let[@inline always] full t = size t = t.c let[@inline always] available t = t.c - (t.w - t.r) let is_empty t = (empty [@inlined]) t let length q = size q let[@inline always] to_power_of_two v = let res = ref (pred v) in res := !res lor (!res lsr 1); res := !res lor (!res lsr 2); res := !res lor (!res lsr 4); res := !res lor (!res lsr 8); res := !res lor (!res lsr 16); succ !res let[@inline always] is_power_of_two v = v <> 0 && v land (lnot v + 1) = v let create ?capacity kind = let capacity = match capacity with | None | Some 0 -> 1 | Some n -> if n < 0 then Fmt.invalid_arg "Rke.Weighted.create" else to_power_of_two n in ( { r = 0; w = 0; c = capacity; k = kind; v = Bigarray.Array1.create kind Bigarray.c_layout capacity; }, capacity ) let copy t = let v = Bigarray.Array1.create t.k Bigarray.c_layout t.c in Bigarray.Array1.blit t.v v; { r = t.r; w = t.w; c = t.c; v; k = t.k } let from v = if not (is_power_of_two (Bigarray.Array1.dim v)) then Fmt.invalid_arg "RBA.from"; let c = Bigarray.Array1.dim v in let k = Bigarray.Array1.kind v in { r = 0; w = 0; c; k; v } let push_exn t v = if (full [@inlined]) t then raise Full; Bigarray.Array1.unsafe_set t.v ((mask [@inlined]) t t.w) v; { t with w = t.w + 1 } let push t v = try Some (push_exn t v) with Full -> None let cons_exn t v = if (full [@inlined]) t then raise Full; let i = t.r - 1 in Bigarray.Array1.unsafe_set t.v ((mask [@inlined]) t i) v; { t with r = i } let cons t v = try Some (cons_exn t v) with Full -> None let pop_exn t = if (empty [@inlined]) t then raise Empty; let r = Bigarray.Array1.unsafe_get t.v ((mask [@inlined]) t t.r) in (r, { t with r = t.r + 1 }) let pop t = try Some (pop_exn t) with Empty -> None let peek_exn t = if (empty [@inlined]) t then raise Empty; Bigarray.Array1.unsafe_get t.v ((mask [@inlined]) t t.r) let peek t = try Some (peek_exn t) with Empty -> None module N = struct type ('a, 'b) bigarray = ('a, 'b, Bigarray.c_layout) Bigarray.Array1.t type ('a, 'b) blit = 'a -> int -> 'b -> int -> int -> unit type 'a length = 'a -> int let push_exn t ~blit ~length ?(off = 0) ?len v = let len = match len with None -> length v - off | Some len -> len in if (available [@inlined]) t < len then raise Full; let msk = (mask [@inlined]) t t.w in let pre = t.c - msk in let rst = len - pre in let ret = if rst > 0 then ( blit v off t.v msk pre; blit v (off + pre) t.v 0 rst; [ Bigarray.Array1.sub t.v ((mask [@inlined]) t t.w) pre; Bigarray.Array1.sub t.v 0 rst; ]) else ( blit v off t.v msk len; [ Bigarray.Array1.sub t.v ((mask [@inlined]) t t.w) len ]) in (ret, { t with w = t.w + len }) let push t ~blit ~length ?off ?len v = try Some (push_exn t ~blit ~length ?off ?len v) with Full -> None let keep_exn t ~blit ~length ?(off = 0) ?len v = let len = match len with None -> length v | Some len -> len in if (size [@inlined]) t < len then raise Empty; let msk = (mask [@inlined]) t t.r in let pre = t.c - msk in let rst = len - pre in if rst > 0 then ( blit t.v msk v off pre; blit t.v 0 v (off + pre) rst) else blit t.v msk v off len let keep t ~blit ~length ?off ?len v = try Some (keep_exn t ~blit ~length ?off ?len v) with Empty -> None let unsafe_shift t len = { t with r = t.r + len } let shift_exn t len = if (size [@inlined]) t < len then raise Empty; unsafe_shift t len let shift t len = try Some (shift_exn t len) with Empty -> None end let iter f t = let idx = ref t.r in let max = t.w in while !idx <> max do f (Bigarray.Array1.unsafe_get t.v ((mask [@inlined]) t !idx)); incr idx done let rev_iter f t = if t.r == t.w then () else let idx = ref (pred t.w) in let min = t.r in while f (Bigarray.Array1.unsafe_get t.v ((mask [@inlined]) t !idx)); !idx <> min do decr idx done let fold f a t = let a = ref a in iter (fun x -> a := f !a x) t; !a let clear t = { t with r = 0; w = 0 } let unsafe_bigarray { v; _ } = v let pp ?sep pp_elt = Fmt.iter ?sep iter pp_elt let dump pp_elt = Fmt.Dump.iter iter (Fmt.any "fke:weighted") pp_elt end