From 1f04a5eda0ae308157268b38248805961999e0f4 Mon Sep 17 00:00:00 2001 From: Jules Villard Date: Fri, 23 Mar 2018 05:00:40 -0700 Subject: [PATCH] [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 --- infer/src/IR/Procdesc.ml | 11 +-- infer/src/IR/Sil.ml | 11 ++- infer/src/IR/Subtype.ml | 2 +- infer/src/IR/Typ.ml | 4 +- infer/src/backend/Attribute.ml | 6 +- infer/src/backend/SymExecBlocks.ml | 23 ++--- infer/src/backend/dom.ml | 4 +- infer/src/backend/paths.ml | 8 +- infer/src/base/IList.ml | 123 ++++++++++++++++++++++++++ infer/src/base/IList.mli | 35 ++++++++ infer/src/clang/cGeneral_utils.ml | 8 +- infer/src/clang/objcInterface_decl.ml | 6 +- infer/src/eradicate/typeState.ml | 2 +- infer/src/integration/Driver.ml | 2 +- infer/src/istd/IList.ml | 100 --------------------- infer/src/istd/IList.mli | 34 ------- 16 files changed, 207 insertions(+), 172 deletions(-) create mode 100644 infer/src/base/IList.ml create mode 100644 infer/src/base/IList.mli delete mode 100644 infer/src/istd/IList.ml delete mode 100644 infer/src/istd/IList.mli diff --git a/infer/src/IR/Procdesc.ml b/infer/src/IR/Procdesc.ml index edb862819..c19e6764d 100644 --- a/infer/src/IR/Procdesc.ml +++ b/infer/src/IR/Procdesc.ml @@ -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 diff --git a/infer/src/IR/Sil.ml b/infer/src/IR/Sil.ml index 5e4ddbaa9..d2ed5b6e9 100644 --- a/infer/src/IR/Sil.ml +++ b/infer/src/IR/Sil.ml @@ -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 diff --git a/infer/src/IR/Subtype.ml b/infer/src/IR/Subtype.ml index 62047382f..601c44e94 100644 --- a/infer/src/IR/Subtype.ml +++ b/infer/src/IR/Subtype.ml @@ -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 diff --git a/infer/src/IR/Typ.ml b/infer/src/IR/Typ.ml index e71cca7a1..0b42c3fef 100644 --- a/infer/src/IR/Typ.ml +++ b/infer/src/IR/Typ.ml @@ -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 diff --git a/infer/src/backend/Attribute.ml b/infer/src/backend/Attribute.ml index 8f96dac49..23ad08f5e 100644 --- a/infer/src/backend/Attribute.ml +++ b/infer/src/backend/Attribute.ml @@ -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) diff --git a/infer/src/backend/SymExecBlocks.ml b/infer/src/backend/SymExecBlocks.ml index 916a2b428..5867bcbe0 100644 --- a/infer/src/backend/SymExecBlocks.ml +++ b/infer/src/backend/SymExecBlocks.ml @@ -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 diff --git a/infer/src/backend/dom.ml b/infer/src/backend/dom.ml index f58451d05..db3c2d53b 100644 --- a/infer/src/backend/dom.ml +++ b/infer/src/backend/dom.ml @@ -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 diff --git a/infer/src/backend/paths.ml b/infer/src/backend/paths.ml index 865fec692..e46497b75 100644 --- a/infer/src/backend/paths.ml +++ b/infer/src/backend/paths.ml @@ -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 ===============*) diff --git a/infer/src/base/IList.ml b/infer/src/base/IList.ml new file mode 100644 index 000000000..f338c54f4 --- /dev/null +++ b/infer/src/base/IList.ml @@ -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 ) diff --git a/infer/src/base/IList.mli b/infer/src/base/IList.mli new file mode 100644 index 000000000..8a3d609cb --- /dev/null +++ b/infer/src/base/IList.mli @@ -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. *) diff --git a/infer/src/clang/cGeneral_utils.ml b/infer/src/clang/cGeneral_utils.ml index c76bb3565..3e9241102 100644 --- a/infer/src/clang/cGeneral_utils.ml +++ b/infer/src/clang/cGeneral_utils.ml @@ -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 = diff --git a/infer/src/clang/objcInterface_decl.ml b/infer/src/clang/objcInterface_decl.ml index 491e9bc11..e7b35c249 100644 --- a/infer/src/clang/objcInterface_decl.ml +++ b/infer/src/clang/objcInterface_decl.ml @@ -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 diff --git a/infer/src/eradicate/typeState.ml b/infer/src/eradicate/typeState.ml index 85cf4cd04..c2a52fd71 100644 --- a/infer/src/eradicate/typeState.ml +++ b/infer/src/eradicate/typeState.ml @@ -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 = diff --git a/infer/src/integration/Driver.ml b/infer/src/integration/Driver.ml index 7be194f37..d5ffd77ed 100644 --- a/infer/src/integration/Driver.ml +++ b/infer/src/integration/Driver.ml @@ -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 diff --git a/infer/src/istd/IList.ml b/infer/src/istd/IList.ml deleted file mode 100644 index f81e6932d..000000000 --- a/infer/src/istd/IList.ml +++ /dev/null @@ -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 diff --git a/infer/src/istd/IList.mli b/infer/src/istd/IList.mli deleted file mode 100644 index 8a52bbea0..000000000 --- a/infer/src/istd/IList.mli +++ /dev/null @@ -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! *)