Skip to content

Commit bc27e1e

Browse files
authored
Fix merge functions in patricia trees (#339)
1 parent c922a18 commit bc27e1e

File tree

1 file changed

+43
-51
lines changed

1 file changed

+43
-51
lines changed

middle_end/flambda/compilenv_deps/patricia_tree.ml

Lines changed: 43 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ open! Int_replace_polymorphic_compare
2121

2222
(* The following is a "little endian" implementation. *)
2323

24+
(* CR mshinwell: Can we fix the traversal order by swapping endianness?
25+
What other (dis)advantages might that have? *)
26+
2427
let zero_bit i bit =
2528
i land bit = 0
2629

@@ -924,12 +927,31 @@ struct
924927
let bindings s =
925928
List.sort (fun (id1, _) (id2, _) -> Int.compare id1 id2)
926929
(bindings_aux [] s)
927-
(*
928-
(* XXX still wrong *)
929-
let rec merge' f t0 t1 =
930+
931+
let rec merge' : type a b c.
932+
(key -> a option -> b option -> c option)
933+
-> a t -> b t -> c t
934+
= fun f t0 t1 ->
930935
match t0, t1 with
931-
| Empty, _ -> t1
932-
| _, Empty -> t0
936+
(* Empty cases, just recurse and be sure to call f on all
937+
leaf cases recursively *)
938+
| Empty, Empty -> Empty
939+
| Empty, Leaf (i, d) ->
940+
begin match f i None (Some d) with
941+
| None -> Empty
942+
| Some d' -> Leaf (i, d')
943+
end
944+
| Leaf (i, d), Empty ->
945+
begin match f i (Some d) None with
946+
| None -> Empty
947+
| Some d' -> Leaf (i, d')
948+
end
949+
| Empty, Branch (prefix, bit, t10, t11) ->
950+
Branch (prefix, bit, merge' f t0 t10, merge' f t0 t11)
951+
| Branch (prefix, bit, t00, t01), Empty ->
952+
Branch (prefix, bit, merge' f t00 t1, merge' f t01 t1)
953+
954+
(* Leaf cases *)
933955
| Leaf (i, d0), Leaf (j, d1) when i = j ->
934956
begin match f i (Some d0) (Some d1) with
935957
| None -> Empty
@@ -942,45 +964,46 @@ struct
942964
| None, Some d1 -> Leaf (j, d1)
943965
| Some d0, Some d1 -> join i (Leaf (i, d0)) j (Leaf (j, d1))
944966
end
967+
968+
(* leaf <-> Branch cases *)
945969
| Leaf (i, d), Branch (prefix, bit, t10, t11) ->
946970
if match_prefix i prefix bit then
947971
if zero_bit i bit then
948-
branch prefix bit (merge' f t0 t10) t11
972+
branch prefix bit (merge' f t0 t10) (merge' f Empty t11)
949973
else
950-
branch prefix bit t10 (merge' f t0 t11)
974+
branch prefix bit (merge' f Empty t10) (merge' f t0 t11)
951975
else
952976
begin match f i (Some d) None with
953-
| None -> t1
954-
| Some d -> join i (Leaf(i, d)) prefix t1
977+
| None -> merge' f Empty t1
978+
| Some d -> join i (Leaf(i, d)) prefix (merge' f Empty t1)
955979
end
956980
| Branch (prefix, bit, t00, t01), Leaf (i, d) ->
957981
if match_prefix i prefix bit then
958982
let f i d0 d1 = f i d1 d0 in (* CR mshinwell: add flag to disable? *)
959983
if zero_bit i bit then
960-
branch prefix bit (merge' f t1 t00) t01
984+
branch prefix bit (merge' f t1 t00) (merge' f Empty t01)
961985
else
962-
branch prefix bit t00 (merge' f t1 t01)
986+
branch prefix bit (merge' f Empty t00) (merge' f t1 t01)
963987
else
964988
begin match f i None (Some d) with
965-
| None -> t0
966-
| Some d -> join i (Leaf(i, d)) prefix t0
989+
| None -> merge' f t0 Empty
990+
| Some d -> join i (Leaf(i, d)) prefix (merge' f t0 Empty)
967991
end
968992
| Branch(prefix0, bit0, t00, t01), Branch(prefix1, bit1, t10, t11) ->
969993
if equal_prefix prefix0 bit0 prefix1 bit1 then
970994
branch prefix0 bit0 (merge' f t00 t10) (merge' f t01 t11)
971995
else if includes_prefix prefix0 bit0 prefix1 bit1 then
972996
if zero_bit prefix1 bit0 then
973-
branch prefix0 bit0 (merge' f t00 t1) t01
997+
branch prefix0 bit0 (merge' f t00 t1) (merge' f t01 Empty)
974998
else
975-
branch prefix0 bit0 t00 (merge' f t01 t1)
999+
branch prefix0 bit0 (merge' f t00 Empty) (merge' f t01 t1)
9761000
else if includes_prefix prefix1 bit1 prefix0 bit0 then
9771001
if zero_bit prefix0 bit1 then
978-
branch prefix1 bit1 (merge' f t0 t10) t11
1002+
branch prefix1 bit1 (merge' f t0 t10) (merge' f Empty t11)
9791003
else
980-
branch prefix1 bit1 t10 (merge' f t0 t11)
1004+
branch prefix1 bit1 (merge' f Empty t10) (merge' f t0 t11)
9811005
else
982-
join prefix0 t0 prefix1 t1
983-
*)
1006+
join prefix0 (merge' f t0 Empty) prefix1 (merge' f Empty t1)
9841007

9851008
let find_opt t key =
9861009
match find t key with
@@ -1036,41 +1059,10 @@ struct
10361059
| Some r -> add id r map)
10371060
t empty
10381061

1039-
let to_list t =
1040-
let rec to_list' t acc =
1041-
match t with
1042-
| Empty -> acc
1043-
| Leaf (id, v) -> (id, v) :: acc
1044-
| Branch(_, _, t0, t1) -> to_list' t0 (to_list' t1 acc)
1045-
in
1046-
List.sort (fun (id1, _) (id2, _) -> Int.compare id1 id2)
1047-
(to_list' t [])
1048-
10491062
let of_list l =
10501063
List.fold_left (fun map (id, v) -> add id v map) empty l
10511064

1052-
let merge f t0 t1 =
1053-
let l1 = to_list t0 in
1054-
let l2 = to_list t1 in
1055-
let rec loop l1 l2 acc =
1056-
let accum id a b =
1057-
match f id a b with
1058-
| None -> acc
1059-
| Some v -> add id v acc
1060-
in
1061-
match l1, l2 with
1062-
| [], [] -> acc
1063-
| (id, h1) :: t1, [] -> loop t1 [] (accum id (Some h1) None)
1064-
| [], (id, h2) :: t2 -> loop [] t2 (accum id None (Some h2))
1065-
| (id1, h1) :: t1, (id2, h2) :: t2 ->
1066-
if id1 = id2 then
1067-
loop t1 t2 (accum id1 (Some h1) (Some h2))
1068-
else if id1 < id2 then
1069-
loop t1 l2 (accum id1 (Some h1) None)
1070-
else
1071-
loop l1 t2 (accum id2 None (Some h2))
1072-
in
1073-
loop l1 l2 Empty
1065+
let merge f t0 t1 = merge' f t0 t1
10741066

10751067
(* CR mshinwell: fix this *)
10761068
let disjoint_union ?eq ?print t1 t2 =

0 commit comments

Comments
 (0)