From fbc13cf952a47b40faf1cb1df4a4927c49d85510 Mon Sep 17 00:00:00 2001 From: Mehdi Bouaziz Date: Wed, 30 May 2018 16:24:58 -0700 Subject: [PATCH] Fix IList.map_changed Summary: `IList.map_changed` relies on `take_append`. The existing code was a `take_rev_append` instead. Fixed it. Tests are still passing, we might want to look at callsites and consider a `map_changed_unordered`. Reviewed By: jvillard Differential Revision: D8201187 fbshipit-source-id: 151b95c --- infer/src/istd/IList.ml | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/infer/src/istd/IList.ml b/infer/src/istd/IList.ml index a68023e4c..4d0705bff 100644 --- a/infer/src/istd/IList.ml +++ b/infer/src/istd/IList.ml @@ -9,9 +9,26 @@ 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 +(* [take_append ~max list ~tail] takes the first max elements of [list] and appends [tail] to the result. + Does not create garbage for [max] <= 1000. *) +let take_append = + let rec take_append_non_tailrec ~max list ~tail = + match list with + | hd :: tl when max > 0 -> + hd :: take_append_non_tailrec ~max:(max - 1) tl ~tail + | _ -> + tail + in + let rec take_append_tailrec ~max list acc ~tail = + match list with + | hd :: tl when max > 0 -> + (take_append_tailrec [@tailcall]) ~max:(max - 1) tl (hd :: acc) ~tail + | _ -> + List.rev_append acc tail + in + fun list ~max ~tail -> + if max <= 1000 then take_append_non_tailrec ~max list ~tail + else take_append_tailrec ~max list [] ~tail (** like map, but returns the original list if unchanged *) @@ -21,7 +38,8 @@ let map_changed ~equal ~f l = 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 + if not (equal x x') then + take_append ~max:unchanged_prefix_length ~tail:(x' :: List.map ~f tl) l else aux (unchanged_prefix_length + 1) tl in aux 0 l