|
|
|
@ -8,46 +8,141 @@
|
|
|
|
|
open! IStd
|
|
|
|
|
module F = Format
|
|
|
|
|
|
|
|
|
|
type t = Sil.instr list
|
|
|
|
|
module RevArray : sig
|
|
|
|
|
type 'a t
|
|
|
|
|
|
|
|
|
|
let empty = []
|
|
|
|
|
val is_empty : 'a t -> bool
|
|
|
|
|
|
|
|
|
|
let singleton instr = [instr]
|
|
|
|
|
val length : 'a t -> int
|
|
|
|
|
|
|
|
|
|
let append_list = List.append
|
|
|
|
|
val of_rev_array : 'a Array.t -> 'a t
|
|
|
|
|
|
|
|
|
|
let prepend_one instr instrs = instr :: instrs
|
|
|
|
|
val get : 'a t -> int -> 'a
|
|
|
|
|
|
|
|
|
|
let reverse_order = List.rev
|
|
|
|
|
val last_opt : 'a t -> 'a option
|
|
|
|
|
|
|
|
|
|
let is_empty = List.is_empty
|
|
|
|
|
val fold : ('a t, 'a, 'accum) Container.fold
|
|
|
|
|
end = struct
|
|
|
|
|
type 'a t = 'a Array.t
|
|
|
|
|
|
|
|
|
|
let exists = List.exists
|
|
|
|
|
let is_empty = Array.is_empty
|
|
|
|
|
|
|
|
|
|
let for_all = List.for_all
|
|
|
|
|
let length = Array.length
|
|
|
|
|
|
|
|
|
|
let count = List.length
|
|
|
|
|
let of_rev_array a = a
|
|
|
|
|
|
|
|
|
|
let nth_exists instrs index = IList.drop instrs index |> List.is_empty |> not
|
|
|
|
|
let get a index = a.(Array.length a - 1 - index)
|
|
|
|
|
|
|
|
|
|
let nth_exn = List.nth_exn
|
|
|
|
|
let last_opt a = if is_empty a then None else Some (Array.unsafe_get a 0)
|
|
|
|
|
|
|
|
|
|
let last = List.last
|
|
|
|
|
let fold a ~init ~f =
|
|
|
|
|
let f = Fn.flip f in
|
|
|
|
|
Array.fold_right a ~init ~f
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
let find_map = List.find_map
|
|
|
|
|
type reversed
|
|
|
|
|
|
|
|
|
|
let pp pe fmt instrs =
|
|
|
|
|
List.iter instrs ~f:(fun instr -> F.fprintf fmt "%a;@\n" (Sil.pp_instr pe) instr)
|
|
|
|
|
type not_reversed
|
|
|
|
|
|
|
|
|
|
type 'rev t =
|
|
|
|
|
| NotReversed: Sil.instr Array.t -> not_reversed t
|
|
|
|
|
| Reversed: Sil.instr RevArray.t -> reversed t
|
|
|
|
|
|
|
|
|
|
let filter_map = List.filter_map
|
|
|
|
|
type not_reversed_t = not_reversed t
|
|
|
|
|
|
|
|
|
|
let fold = List.fold
|
|
|
|
|
(* Some functions are only used on non-reversed arrays, let's specialize them.
|
|
|
|
|
The argument of the type helps us make sure they can't be used otherwise. *)
|
|
|
|
|
(* Functions on non-reversed arrays *)
|
|
|
|
|
|
|
|
|
|
let iter = List.iter
|
|
|
|
|
let of_array instrs = NotReversed instrs
|
|
|
|
|
|
|
|
|
|
let map_changed ~equal instrs ~f = IList.map_changed ~equal instrs ~f
|
|
|
|
|
let empty = of_array [||]
|
|
|
|
|
|
|
|
|
|
let of_list instrs = instrs
|
|
|
|
|
let singleton instr = of_array [|instr|]
|
|
|
|
|
|
|
|
|
|
let of_rev_list instrs = List.rev instrs
|
|
|
|
|
let append_list (NotReversed instrs) list = NotReversed (Array.append instrs (Array.of_list list))
|
|
|
|
|
|
|
|
|
|
let prepend_one instr (NotReversed instrs) = NotReversed (Array.append [|instr|] instrs)
|
|
|
|
|
|
|
|
|
|
let of_list l = NotReversed (Array.of_list l)
|
|
|
|
|
|
|
|
|
|
let of_rev_list l = NotReversed (Array.of_list_rev l)
|
|
|
|
|
|
|
|
|
|
let filter_map (NotReversed instrs) ~f = NotReversed (Array.filter_map instrs ~f)
|
|
|
|
|
|
|
|
|
|
let map_changed =
|
|
|
|
|
let aux_changed arr ~f i =
|
|
|
|
|
for i = i to Array.length arr - 1 do Array.unsafe_get arr i |> f |> Array.unsafe_set arr i done ;
|
|
|
|
|
arr
|
|
|
|
|
in
|
|
|
|
|
let rec aux_unchanged ~equal arr ~f i =
|
|
|
|
|
if i >= Array.length arr then arr
|
|
|
|
|
else
|
|
|
|
|
let e = Array.unsafe_get arr i in
|
|
|
|
|
let e' = f e in
|
|
|
|
|
if equal e e' then aux_unchanged ~equal arr ~f (i + 1)
|
|
|
|
|
else
|
|
|
|
|
let arr = Array.copy arr in
|
|
|
|
|
Array.unsafe_set arr i e' ;
|
|
|
|
|
aux_changed arr ~f (i + 1)
|
|
|
|
|
in
|
|
|
|
|
fun ~equal (NotReversed instrs as t) ~f ->
|
|
|
|
|
let instrs' = aux_unchanged ~equal instrs ~f 0 in
|
|
|
|
|
if phys_equal instrs instrs' then t else NotReversed instrs'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let reverse_order (NotReversed instrs) = Reversed (RevArray.of_rev_array instrs)
|
|
|
|
|
|
|
|
|
|
(* Functions on both reversed and non-reversed arrays *)
|
|
|
|
|
|
|
|
|
|
let is_empty (type r) (t: r t) =
|
|
|
|
|
match t with
|
|
|
|
|
| NotReversed instrs ->
|
|
|
|
|
Array.is_empty instrs
|
|
|
|
|
| Reversed rev_instrs ->
|
|
|
|
|
RevArray.is_empty rev_instrs
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let fold (type r) (t: r t) ~init ~f =
|
|
|
|
|
match t with
|
|
|
|
|
| NotReversed instrs ->
|
|
|
|
|
Array.fold instrs ~init ~f
|
|
|
|
|
| Reversed rev_instrs ->
|
|
|
|
|
RevArray.fold rev_instrs ~init ~f
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let iter t ~f = Container.iter ~fold t ~f
|
|
|
|
|
|
|
|
|
|
let exists t ~f = Container.exists ~iter t ~f
|
|
|
|
|
|
|
|
|
|
let for_all t ~f = Container.for_all ~iter t ~f
|
|
|
|
|
|
|
|
|
|
let count (type r) (t: r t) =
|
|
|
|
|
match t with
|
|
|
|
|
| NotReversed instrs ->
|
|
|
|
|
Array.length instrs
|
|
|
|
|
| Reversed rev_instrs ->
|
|
|
|
|
RevArray.length rev_instrs
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let nth_exists t index = index < count t
|
|
|
|
|
|
|
|
|
|
let nth_exn (type r) (t: r t) index =
|
|
|
|
|
match t with
|
|
|
|
|
| NotReversed instrs ->
|
|
|
|
|
instrs.(index)
|
|
|
|
|
| Reversed rev_instrs ->
|
|
|
|
|
RevArray.get rev_instrs index
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let last (type r) (t: r t) =
|
|
|
|
|
match t with
|
|
|
|
|
| NotReversed instrs ->
|
|
|
|
|
if is_empty t then None else Some (Array.last instrs)
|
|
|
|
|
| Reversed rev_instrs ->
|
|
|
|
|
RevArray.last_opt rev_instrs
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let find_map t ~f = Container.find_map ~iter t ~f
|
|
|
|
|
|
|
|
|
|
let pp pe fmt t = iter t ~f:(fun instr -> F.fprintf fmt "%a;@\n" (Sil.pp_instr pe) instr)
|
|
|
|
|