[IList] move to base/ and use Core

Summary:
There's no real reason not to use `Core` lists in this module. Changed the
interface to be more `Core`-like. Changed the `*_changed` functions to use a
ref to track changes instead of passing the changed state around.

Reviewed By: mbouaziz

Differential Revision: D7123211

fbshipit-source-id: b27791a
master
Jules Villard 7 years ago committed by Facebook Github Bot
parent 7efb5cb549
commit 1f04a5eda0

@ -736,6 +736,12 @@ let specialize_with_block_args_instrs resolved_pdesc substitutions =
f_instr_list
let append_no_duplicates_formals_and_annot =
Staged.unstage
(IList.append_no_duplicates ~cmp:(fun ((name1, _), _) ((name2, _), _) ->
Mangled.compare name1 name2 ))
let specialize_with_block_args callee_pdesc pname_with_block_args block_args =
let callee_attributes = get_attributes callee_pdesc in
(* Substitution from a block parameter to the block name and the new formals
@ -764,11 +770,6 @@ let specialize_with_block_args callee_pdesc pname_with_block_args block_args =
let formals_annots =
List.zip_exn callee_attributes.formals (snd callee_attributes.method_annotation)
in
let append_no_duplicates_formals_and_annot list1 list2 =
IList.append_no_duplicates
(fun ((name1, _), _) ((name2, _), _) -> Mangled.equal name1 name2)
list1 list2
in
List.fold formals_annots ~init:[] ~f:(fun acc ((param_name, typ), annot) ->
try
let _, captured = Mangled.Map.find param_name substitutions in

@ -1263,7 +1263,8 @@ let rec exp_sub_ids (f: subst_fun) exp =
| Closure c ->
let captured_vars =
IList.map_changed
(fun ((e, pvar, typ) as captured) ->
~equal:[%compare.equal : Exp.t * Pvar.t * Typ.t]
~f:(fun ((e, pvar, typ) as captured) ->
let e' = exp_sub_ids f e in
let typ' = f_typ typ in
if phys_equal e' e && phys_equal typ typ' then captured else (e', pvar, typ') )
@ -1361,7 +1362,8 @@ let instr_sub_ids ~sub_id_binders f instr =
let fun_exp' = exp_sub_ids f fun_exp in
let actuals' =
IList.map_changed
(fun ((actual, typ) as actual_pair) ->
~equal:[%compare.equal : Exp.t * Typ.t]
~f:(fun ((actual, typ) as actual_pair) ->
let actual' = exp_sub_ids f actual in
let typ' = sub_typ typ in
if phys_equal actual' actual && phys_equal typ typ' then actual_pair
@ -1375,12 +1377,13 @@ let instr_sub_ids ~sub_id_binders f instr =
let exp' = exp_sub_ids f exp in
if phys_equal exp' exp then instr else Prune (exp', loc, true_branch, if_kind)
| Remove_temps (ids, loc) ->
let ids' = IList.map_changed sub_id ids in
let ids' = IList.map_changed ~equal:Ident.equal ~f:sub_id ids in
if phys_equal ids' ids then instr else Remove_temps (ids', loc)
| Declare_locals (locals, loc) ->
let locals' =
IList.map_changed
(fun ((name, typ) as local_var) ->
~equal:[%compare.equal : Pvar.t * Typ.t]
~f:(fun ((name, typ) as local_var) ->
let typ' = sub_typ typ in
if phys_equal typ typ' then local_var else (name, typ') )
locals

@ -41,7 +41,7 @@ let sub_type tname_subst st_pair =
let st, kind = st_pair in
match st with
| Subtypes tnames ->
let tnames' = IList.map_changed tname_subst tnames in
let tnames' = IList.map_changed ~equal:Typ.Name.equal ~f:tname_subst tnames in
if phys_equal tnames tnames' then st_pair else (Subtypes tnames', kind)
| Exact ->
st_pair

@ -157,6 +157,8 @@ module T = struct
let equal_quals = [%compare.equal : type_quals]
let equal_template_arg = [%compare.equal : template_arg]
let equal = [%compare.equal : t]
let hash = Hashtbl.hash
@ -308,7 +310,7 @@ and sub_tname subst tname =
| TInt _ | TNull | TNullPtr | TOpaque ->
typ_opt
in
let args' = IList.map_changed sub_typ_opt args in
let args' = IList.map_changed ~equal:equal_template_arg ~f:sub_typ_opt args in
if phys_equal args args' then tname else CppClass (name, Template {mangled; args= args'})
| _ ->
tname

@ -45,7 +45,7 @@ let add_or_replace_check_changed tenv check_attribute_change prop atom =
atom'
in
let pi = prop.Prop.pi in
let pi' = IList.map_changed atom_map pi in
let pi' = IList.map_changed ~equal:Sil.equal_atom ~f:atom_map pi in
if phys_equal pi pi' then Prop.prop_atom_and tenv prop atom
else Prop.normalize tenv (Prop.set prop ~pi:pi')
| _ ->
@ -109,7 +109,7 @@ let has_dangling_uninit tenv prop exp =
let filter_atoms tenv ~f prop =
let pi0 = prop.Prop.pi in
let pi1 = IList.filter_changed f pi0 in
let pi1 = IList.filter_changed ~f pi0 in
if phys_equal pi1 pi0 then prop else Prop.normalize tenv (Prop.set prop ~pi:pi1)
@ -160,7 +160,7 @@ let map_resource tenv prop f =
atom
in
let pi0 = prop.Prop.pi in
let pi1 = IList.map_changed atom_map pi0 in
let pi1 = IList.map_changed ~equal:Sil.equal_atom ~f:atom_map pi0 in
if phys_equal pi1 pi0 then prop else Prop.normalize tenv (Prop.set prop ~pi:pi1)

@ -9,21 +9,22 @@
open! IStd
(* Given two lists of tuples (exp1, var1, typ1) and (exp2, var2, typ2)
append the lists avoiding duplicates, where if the variables exist we check their
equality, otherwise we check the equality of the expressions. This is to avoid
adding the same captured variable twice. *)
let append_no_duplicates_vars list1 list2 =
let eq (exp1, var1_opt, _) (exp2, var2_opt, _) =
(* Given two lists of tuples (exp1, var1, typ1) and (exp2, var2, typ2) append the lists avoiding
duplicates, where if the variables exist we check their equality, otherwise we check the equality
of the expressions. This is to avoid adding the same captured variable twice. *)
let append_no_duplicates_vars =
let cmp (exp1, var1_opt, _) (exp2, var2_opt, _) =
match (var1_opt, var2_opt) with
| Some var1, Some var2 ->
Pvar.equal var1 var2
Pvar.compare var1 var2
| None, None ->
Exp.equal exp1 exp2
| _ ->
false
Exp.compare exp1 exp2
| Some _, None ->
1
| None, Some _ ->
-1
in
IList.append_no_duplicates eq list1 list2
Staged.unstage (IList.append_no_duplicates ~cmp)
(* Given a list of actual parameters for a function, replaces the closures with the

@ -1824,7 +1824,7 @@ let pi_partial_join tenv mode (ep1: Prop.exposed Prop.t) (ep2: Prop.exposed Prop
List.fold ~f:(handle_atom_with_widening Rhs p1 pi1) ~init:[] pi2
in
if Config.trace_join then ( L.d_str "atom_list2: " ; Prop.d_pi atom_list2 ; L.d_ln () ) ;
let atom_list_combined = IList.inter Sil.compare_atom atom_list1 atom_list2 in
let atom_list_combined = IList.inter ~cmp:Sil.compare_atom atom_list1 atom_list2 in
if Config.trace_join then (
L.d_str "atom_list_combined: " ; Prop.d_pi atom_list_combined ; L.d_ln () ) ;
atom_list_combined
@ -1862,7 +1862,7 @@ let eprop_partial_meet tenv (ep1: 'a Prop.t) (ep2: 'b Prop.t) : 'c Prop.t =
let sigma2 = ep2.Prop.sigma in
let es1 = sigma_get_start_lexps_sort sigma1 in
let es2 = sigma_get_start_lexps_sort sigma2 in
let es = IList.merge_sorted_nodup Exp.compare [] es1 es2 in
let es = IList.merge_sorted_nodup ~cmp:Exp.compare ~res:[] es1 es2 in
let sub_check _ =
let sub1 = ep1.Prop.sub in
let sub2 = ep2.Prop.sub in

@ -530,12 +530,12 @@ end = struct
()
in
iter_shortest_sequence g pos_opt path ;
let compare lt1 lt2 =
let n = Int.compare lt1.Errlog.lt_level lt2.Errlog.lt_level in
if n <> 0 then n else Location.compare lt1.Errlog.lt_loc lt2.Errlog.lt_loc
let equal lt1 lt2 =
[%compare.equal : int * Location.t]
(lt1.Errlog.lt_level, lt1.Errlog.lt_loc) (lt2.Errlog.lt_level, lt2.Errlog.lt_loc)
in
let relevant lt = lt.Errlog.lt_node_tags <> [] in
IList.remove_irrelevant_duplicates compare relevant (List.rev !trace)
IList.remove_irrelevant_duplicates ~equal ~f:relevant (List.rev !trace)
end
(* =============== END of the Path module ===============*)

@ -0,0 +1,123 @@
(*
* Copyright (c) 2015 - present Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*)
open! IStd
let rec take_append n ~tail l =
if n <= 0 then tail
else match l with [] -> tail | x :: tl -> take_append (n - 1) ~tail:(x :: tail) tl
(** like map, but returns the original list if unchanged *)
let map_changed ~equal ~f l =
let rec aux unchanged_prefix_length = function
| [] ->
l
| x :: tl ->
let x' = f x in
if not (equal x x') then take_append unchanged_prefix_length ~tail:(x' :: List.map ~f tl) l
else aux (unchanged_prefix_length + 1) tl
in
aux 0 l
(** like filter, but returns the original list if unchanged *)
let filter_changed ~f l =
let res_rev, changed =
List.fold_left l ~init:([], false) ~f:(fun (l, changed) x ->
if f x then (x :: l, changed) else (l, true) )
in
if changed then List.rev res_rev else l
(** Remove consecutive equal irrelevant elements from a list (according to the given comparison and
relevance functions) *)
let remove_irrelevant_duplicates ~equal ~f l =
let rec remove acc = function
| [] ->
List.rev acc
| [x] ->
List.rev (x :: acc)
| x :: (y :: l'' as l') ->
if equal x y then
match (f x, f y) with
| false, _ ->
remove acc l'
| true, false ->
remove acc (x :: l'')
| true, true ->
remove (x :: acc) l'
else remove (x :: acc) l'
in
remove [] l
(** The function works on sorted lists without duplicates, and keeps only one copy of elements that
appear in both lists. *)
let rec merge_sorted_nodup ~cmp ~res xs1 xs2 =
match (xs1, xs2) with
| [], _ ->
List.rev_append res xs2
| _, [] ->
List.rev_append res xs1
| x1 :: xs1', x2 :: xs2' ->
let n = cmp x1 x2 in
if Int.equal n 0 then merge_sorted_nodup ~cmp ~res:(x1 :: res) xs1' xs2'
else if n < 0 then merge_sorted_nodup ~cmp ~res:(x1 :: res) xs1' xs2
else merge_sorted_nodup ~cmp ~res:(x2 :: res) xs1 xs2'
let inter ~cmp xs ys =
let rev_sort xs = List.sort ~cmp:(fun x y -> cmp y x) xs in
let rev_xs = rev_sort xs in
let rev_ys = rev_sort ys in
let rec inter_ is rev_xxs rev_yys =
match (rev_xxs, rev_yys) with
| [], _ | _, [] ->
is
| x :: rev_xs, y :: rev_ys ->
let c = cmp x y in
if Int.equal c 0 then inter_ (x :: is) rev_xs rev_ys
else if c < 0 then inter_ is rev_xs rev_yys
else inter_ is rev_xxs rev_ys
in
inter_ [] rev_xs rev_ys
(** like fold, but apply [f_last] to the last element *)
let rec fold_last l ~init ~f ~f_last =
match l with
| [] ->
init
| [last] ->
f_last init last
| hd :: tl ->
fold_last tl ~init:(f init hd) ~f ~f_last
let append_no_duplicates (type a) ~(cmp: a -> a -> int) =
(* roughly based on [Core.List.stable_dedup_staged] but also takes care of the append and takes
into account the invariant that [list1] and [list2] do not contain duplicates individually *)
let module Set = Set.Make (struct
type t = a
let compare = cmp
(* we never calls these *)
let t_of_sexp _ = assert false
let sexp_of_t _ = assert false
end) in
Staged.stage (fun (list1: a list) (list2: a list) ->
let set1 = Set.of_list list1 in
let res_rev =
List.fold_left list2 ~init:(List.rev list1) ~f:(fun res_rev x ->
if Set.mem set1 x then res_rev else x :: res_rev )
in
List.rev res_rev )

@ -0,0 +1,35 @@
(*
* Copyright (c) 2015 - present Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*)
open! IStd
val map_changed : equal:('a -> 'a -> bool) -> f:('a -> 'a) -> 'a list -> 'a list
(** like map, but returns the original list if unchanged *)
val filter_changed : f:('a -> bool) -> 'a list -> 'a list
(** like filter, but returns the original list if unchanged *)
val remove_irrelevant_duplicates : equal:('a -> 'a -> bool) -> f:('a -> bool) -> 'a list -> 'a list
(** Remove consecutive equal irrelevant elements from a list (according to the given comparison and
relevance functions) *)
val merge_sorted_nodup : cmp:('a -> 'a -> int) -> res:'a list -> 'a list -> 'a list -> 'a list
(** The function works on sorted lists without duplicates, and keeps only one copy of elements that
appear in both lists. *)
val inter : cmp:('a -> 'a -> int) -> 'a list -> 'a list -> 'a list
(** [inter cmp xs ys] are the elements in both [xs] and [ys], sorted according to [cmp]. *)
val fold_last : 'a list -> init:'b -> f:('b -> 'a -> 'b) -> f_last:('b -> 'a -> 'b) -> 'b
(** like fold, but apply f_last to the last element *)
val append_no_duplicates : cmp:('a -> 'a -> int) -> ('a list -> 'a list -> 'a list) Staged.t
(** [append_no_duplicates list1 list2], assuming that list1 and list2 have no duplicates on their
own, it computes list1 @ (filtered list2), so it keeps the order of both lists and has no
duplicates. *)

@ -26,11 +26,11 @@ let rec swap_elements_list l =
assert false
let append_no_duplicates_annotations list1 list2 =
let equal (annot1, _) (annot2, _) =
String.equal annot1.Annot.class_name annot2.Annot.class_name
let append_no_duplicates_annotations =
let cmp (annot1, _) (annot2, _) =
String.compare annot1.Annot.class_name annot2.Annot.class_name
in
IList.append_no_duplicates equal list1 list2
Staged.unstage (IList.append_no_duplicates ~cmp)
let add_no_duplicates_fields field_tuple l =

@ -84,6 +84,10 @@ let create_supers_fields qual_type_to_sil_type tenv class_tname decl_list otdi_s
(supers, fields)
let append_no_duplicates_typ_name =
Staged.unstage (IList.append_no_duplicates ~cmp:Typ.Name.compare)
(* Adds pairs (interface name, interface_type_info) to the global environment. *)
let add_class_to_tenv qual_type_to_sil_type tenv decl_info name_info decl_list ocidi =
let class_name = CAst_utils.get_qualified_name name_info in
@ -107,7 +111,7 @@ let add_class_to_tenv qual_type_to_sil_type tenv decl_info name_info decl_list o
match Tenv.lookup tenv interface_name with
| Some {fields; supers} ->
( CGeneral_utils.append_no_duplicates_fields decl_fields fields
, IList.append_no_duplicates Typ.Name.equal decl_supers supers )
, append_no_duplicates_typ_name decl_supers supers )
| _ ->
(decl_fields, decl_supers)
in

@ -67,7 +67,7 @@ let pp ext fmt typestate =
let type_join typ1 typ2 = if PatternMatch.type_is_object typ1 then typ2 else typ1
let locs_join locs1 locs2 = IList.merge_sorted_nodup Location.compare [] locs1 locs2
let locs_join locs1 locs2 = IList.merge_sorted_nodup ~cmp:Location.compare ~res:[] locs1 locs2
(** Add a list of locations to a range. *)
let range_add_locs (typ, ta, locs1) locs2 =

@ -267,7 +267,7 @@ let capture ~changed_files mode =
(Option.to_list (Sys.getenv CLOpt.args_env_var) @ ["--buck"])
in
Unix.putenv ~key:CLOpt.args_env_var ~data:infer_args_with_buck ;
let prog, buck_args = IList.uncons_exn build_cmd in
let prog, buck_args = (List.hd_exn build_cmd, List.tl_exn build_cmd) in
let {Buck.command; rev_not_targets; targets} =
Buck.add_flavors_to_buck_arguments ~filter_kind:`Auto ~dep_depth:None
~extra_flavors:[] buck_args

@ -1,100 +0,0 @@
(*
* Copyright (c) 2015 - present Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*)
(** like map, but returns the original list if unchanged *)
let map_changed (f: 'a -> 'a) l =
let l', changed =
List.fold_left
(fun (l_acc, changed) e ->
let e' = f e in
(e' :: l_acc, changed || e' != e) )
([], false) l
in
if changed then List.rev l' else l
(** like filter, but returns the original list if unchanged *)
let filter_changed (f: 'a -> bool) l =
let l', changed =
List.fold_left
(fun (l_acc, changed) e -> if f e then (e :: l_acc, changed) else (l_acc, true))
([], false) l
in
if changed then List.rev l' else l
(** Remove consecutive equal irrelevant elements from a list
(according to the given comparison and relevance functions) *)
let remove_irrelevant_duplicates compare relevant l =
let rec remove compare acc = function
| [] ->
List.rev acc
| [x] ->
List.rev (x :: acc)
| x :: (y :: l'' as l') ->
if compare x y = 0 then
match (relevant x, relevant y) with
| false, _ ->
remove compare acc l'
| true, false ->
remove compare acc (x :: l'')
| true, true ->
remove compare (x :: acc) l'
else remove compare (x :: acc) l'
in
remove compare [] l
(** The function works on sorted lists without duplicates *)
let rec merge_sorted_nodup compare res xs1 xs2 =
match (xs1, xs2) with
| [], _ ->
List.rev_append res xs2
| _, [] ->
List.rev_append res xs1
| x1 :: xs1', x2 :: xs2' ->
let n = compare x1 x2 in
if n = 0 then merge_sorted_nodup compare (x1 :: res) xs1' xs2'
else if n < 0 then merge_sorted_nodup compare (x1 :: res) xs1' xs2
else merge_sorted_nodup compare (x2 :: res) xs1 xs2'
let inter compare xs ys =
let rev_sort xs = List.sort (fun x y -> compare y x) xs in
let rev_xs = rev_sort xs in
let rev_ys = rev_sort ys in
let rec inter_ is rev_xxs rev_yys =
match (rev_xxs, rev_yys) with
| [], _ | _, [] ->
is
| x :: rev_xs, y :: rev_ys ->
let c = compare x y in
if c = 0 then inter_ (x :: is) rev_xs rev_ys
else if c < 0 then inter_ is rev_xs rev_yys
else inter_ is rev_xxs rev_ys
in
inter_ [] rev_xs rev_ys
(** like fold, but apply f_last to the last element *)
let rec fold_last l ~init ~f ~f_last =
match l with
| [] ->
init
| [last] ->
f_last init last
| hd :: tl ->
fold_last tl ~init:(f init hd) ~f ~f_last
let uncons_exn = function [] -> failwith "uncons_exn" | hd :: tl -> (hd, tl)
let append_no_duplicates eq list1 list2 =
let list2_no_dup = List.filter (fun x2 -> List.for_all (fun x1 -> not (eq x2 x1)) list1) list2 in
list1 @ list2_no_dup

@ -1,34 +0,0 @@
(*
* Copyright (c) 2015 - present Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*)
val map_changed : ('a -> 'a) -> 'a list -> 'a list
(** like map, but returns the original list if unchanged *)
val filter_changed : ('a -> bool) -> 'a list -> 'a list
(** like filter, but returns the original list if unchanged *)
val remove_irrelevant_duplicates : ('a -> 'a -> int) -> ('a -> bool) -> 'a list -> 'a list
(** Remove consecutive equal irrelevant elements from a list (according to the given comparison and relevance functions) *)
val merge_sorted_nodup : ('a -> 'a -> int) -> 'a list -> 'a list -> 'a list -> 'a list
(** The function works on sorted lists without duplicates *)
val inter : ('a -> 'a -> int) -> 'a list -> 'a list -> 'a list
(** [inter cmp xs ys] are the elements in both [xs] and [ys], sorted according to [cmp]. *)
val fold_last : 'a list -> init:'b -> f:('b -> 'a -> 'b) -> f_last:('b -> 'a -> 'b) -> 'b
(** like fold, but apply f_last to the last element *)
val uncons_exn : 'a list -> 'a * 'a list
(** deconstruct a list, like hd_exn and tl_exn *)
val append_no_duplicates : ('a -> 'a -> bool) -> 'a list -> 'a list -> 'a list
(** [append_no_duplicates list1 list2], assuming that list1 and list2 have no duplicates on their own,
it computes list1 @ (filtered list2), so it keeps the order of both lists and has no duplicates.
However, the complexity is O(n^2), don't use for big lists! *)
Loading…
Cancel
Save