ocaml/bytecomp/dectree.ml

52 lines
1.9 KiB
OCaml

open Lambda
(* Input: a list of (key, action) pairs, where keys are integers. *)
(* Output: a table of (low, high, offset) triples for Ktranslate
an array of actions for Kswitch *)
let make_decision_tree casei =
(* Sort the cases by increasing keys *)
let cases =
Sort.list (fun (key1,act1) (key2,act2) -> key1 <= key2) casei in
(* Extract the keys and the actions *)
let keyv = Array.of_list (List.map fst cases)
and actv = Array.of_list (List.map snd cases) in
let n = Array.length keyv in
(* Partition the set of keys keyv into maximal dense enough segments.
A segment is dense enough if its span (max point - min point) is
less than four times its size (number of points). *)
let rec partition start =
if start >= n then [] else
let stop = ref (n-1) in
while let span = keyv.(!stop) - keyv.(start) in
span >= 256 or span > 4 * (!stop - start) do
decr stop
done;
(* We've found a dense enough segment.
In the worst case, !stop = start and the segment is a single point *)
(* Record the segment and continue *)
(start, !stop) :: partition (!stop + 1) in
let part = partition 0 in
(* Compute the length of the switch table.
Slot 0 is reserved and always contains Lstaticfail. *)
let switchl = ref 1 in
List.iter
(fun (start, stop) -> switchl := !switchl + keyv.(stop) - keyv.(start) + 1)
part;
(* Build the two tables *)
let transl = Array.new (List.length part) (0, 0, 0)
and switch = Array.new !switchl Lstaticfail in
let tr_pos = ref 0
and sw_ind = ref 1 in
List.iter
(fun (start, stop) ->
transl.(!tr_pos) <- (keyv.(start), keyv.(stop), !sw_ind);
for i = start to stop do
switch.(!sw_ind + keyv.(i) - keyv.(start)) <- actv.(i)
done;
incr tr_pos;
sw_ind := !sw_ind + keyv.(stop) - keyv.(start) + 1)
part;
(transl, switch)