You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
193 lines
5.4 KiB
193 lines
5.4 KiB
(*
|
|
* 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.
|
|
*)
|
|
|
|
let exists = List.exists
|
|
let filter = List.filter
|
|
let find = List.find
|
|
let fold_left = List.fold_left
|
|
let fold_left2 = List.fold_left2
|
|
let for_all = List.for_all
|
|
let for_all2 = List.for_all2
|
|
let hd = List.hd
|
|
let iter = List.iter
|
|
let iter2 = List.iter2
|
|
let iteri = List.iteri
|
|
let length = List.length
|
|
let nth = List.nth
|
|
let partition = List.partition
|
|
let rev = List.rev
|
|
let rev_append = List.rev_append
|
|
let rev_map = List.rev_map
|
|
let sort = List.sort
|
|
let stable_sort = List.stable_sort
|
|
let tl = List.tl
|
|
|
|
(** tail-recursive variant of List.fold_right *)
|
|
let fold_right f l a =
|
|
let g x y = f y x in
|
|
fold_left g a (rev l)
|
|
|
|
(** tail-recursive variant of List.combine *)
|
|
let combine =
|
|
let rec combine acc l1 l2 = match l1, l2 with
|
|
| [], [] -> acc
|
|
| x1:: l1, x2:: l2 -> combine ((x1, x2):: acc) l1 l2
|
|
| [], _:: _
|
|
| _:: _, [] -> raise (Invalid_argument "IList.combine") in
|
|
fun l1 l2 -> rev (combine [] l1 l2)
|
|
|
|
(** tail-recursive variant of List.split *)
|
|
let split =
|
|
let rec split acc1 acc2 = function
|
|
| [] -> (acc1, acc2)
|
|
| (x, y):: l -> split (x:: acc1) (y:: acc2) l in
|
|
fun l ->
|
|
let acc1, acc2 = split [] [] l in
|
|
rev acc1, rev acc2
|
|
|
|
(** Like List.mem but without builtin equality *)
|
|
let mem equal x l = exists (equal x) l
|
|
|
|
(** tail-recursive variant of List.flatten *)
|
|
let flatten =
|
|
let rec flatten acc l = match l with
|
|
| [] -> acc
|
|
| x:: l' -> flatten (rev_append x acc) l' in
|
|
fun l -> rev (flatten [] l)
|
|
|
|
let flatten_options list =
|
|
fold_left (fun list -> function | Some x -> x:: list | None -> list) [] list
|
|
|> rev
|
|
|
|
let rec drop_first n = function
|
|
| xs when n == 0 -> xs
|
|
| _ :: xs -> drop_first (n - 1) xs
|
|
| [] -> []
|
|
|
|
let drop_last n list =
|
|
rev (drop_first n (rev list))
|
|
|
|
(** Generic comparison of lists given a compare function for the elements of the list *)
|
|
let rec compare cmp l1 l2 =
|
|
match l1, l2 with
|
|
| [],[] -> 0
|
|
| [], _ -> - 1
|
|
| _, [] -> 1
|
|
| x1:: l1', x2:: l2' ->
|
|
let n = cmp x1 x2 in
|
|
if n <> 0 then n else compare cmp l1' l2'
|
|
|
|
(** Generic equality of lists given a compare function for the elements of the list *)
|
|
let equal cmp l1 l2 =
|
|
compare cmp l1 l2 = 0
|
|
|
|
(** Returns (reverse input_list) *)
|
|
let rec rev_with_acc acc = function
|
|
| [] -> acc
|
|
| x :: xs -> rev_with_acc (x:: acc) xs
|
|
|
|
(** tail-recursive variant of List.append *)
|
|
let append l1 l2 =
|
|
rev_append (rev l1) l2
|
|
|
|
(** tail-recursive variant of List.map *)
|
|
let map f l =
|
|
rev (rev_map f l)
|
|
|
|
(** tail-recursive variant of List.mapi *)
|
|
let mapi f l =
|
|
let i = ref 0 in
|
|
rev (rev_map
|
|
(fun x ->
|
|
incr i;
|
|
f (!i - 1) x)
|
|
l)
|
|
|
|
(** Remove consecutive equal elements from a list (according to the given comparison functions) *)
|
|
let remove_duplicates compare l =
|
|
let rec remove compare acc = function
|
|
| [] -> rev acc
|
|
| [x] -> rev (x:: acc)
|
|
| x:: ((y:: l'') as l') ->
|
|
if compare x y = 0 then remove compare acc (x:: l'')
|
|
else remove compare (x:: acc) l' in
|
|
remove compare [] 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
|
|
| [] -> rev acc
|
|
| [x] -> rev (x:: acc)
|
|
| x:: ((y:: l'') as l') ->
|
|
if compare x y = 0 then begin
|
|
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'
|
|
end
|
|
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
|
|
| [], _ ->
|
|
rev_with_acc xs2 res
|
|
| _, [] ->
|
|
rev_with_acc xs1 res
|
|
| 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 intersect compare l1 l2 =
|
|
let l1_sorted = sort compare l1 in
|
|
let l2_sorted = sort compare l2 in
|
|
let rec f l1 l2 = match l1, l2 with
|
|
| ([], _) | (_,[]) -> false
|
|
| (x1:: l1', x2:: l2') ->
|
|
let x_comparison = compare x1 x2 in
|
|
if x_comparison = 0 then true
|
|
else if x_comparison < 0 then f l1' l2
|
|
else f l1 l2' in
|
|
f l1_sorted l2_sorted
|
|
|
|
exception Fail
|
|
|
|
(** Apply [f] to pairs of elements; raise [Fail] if the two lists have different lenghts. *)
|
|
let map2 f l1 l2 =
|
|
let rec go l1 l2 acc =
|
|
match l1, l2 with
|
|
| [],[] -> rev acc
|
|
| x1 :: l1', x2 :: l2' ->
|
|
let x' = f x1 x2 in
|
|
go l1' l2' (x':: acc)
|
|
| _ -> raise Fail in
|
|
go l1 l2 []
|
|
|
|
let to_string f l =
|
|
let rec aux l =
|
|
match l with
|
|
| [] -> ""
|
|
| s:: [] -> (f s)
|
|
| s:: rest -> (f s)^", "^(aux rest) in
|
|
"["^(aux l)^"]"
|
|
|
|
(** Like List.mem_assoc but without builtin equality *)
|
|
let mem_assoc equal a l =
|
|
exists (fun x -> equal a (fst x)) l
|
|
|
|
(** Like List.assoc but without builtin equality *)
|
|
let assoc equal a l =
|
|
snd (find (fun x -> equal a (fst x)) l)
|