Source file ordered_trie.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
open! Core
(** This is a trie that remembers the insertion order of its values, but only within a
single prefix. Unlike the version in [Expectable], this one stores associated data
with each leaf. *)
type 'a t =
{ children : 'a t String.Table.t
; mutable insertion_order : string list
; mutable leaf_data : 'a option
}
[@@deriving sexp_of]
let create () =
{ children = String.Table.create (); insertion_order = []; leaf_data = None }
;;
let get_or_add_one t =
Hashtbl.find_and_call t.children ~if_found:Fn.id ~if_not_found:(fun key ->
let data = create () in
Hashtbl.set t.children ~key ~data;
t.insertion_order <- key :: t.insertion_order;
data)
;;
let rec add t ~data path =
match path with
| [] -> t.leaf_data <- Some data
| key :: rest -> add (get_or_add_one t key) ~data rest
;;
(** Convert the trie to a list of tree nodes at the top level, preserving insertion order.
This is the main function for building navigable trees. *)
let to_tree_nodes t ~branch ~leaf =
let rec build_node key subtrie =
let children =
List.map (List.rev subtrie.insertion_order) ~f:(fun child_key ->
let child = Hashtbl.find_exn subtrie.children child_key in
build_node child_key child)
in
match subtrie.leaf_data, children with
| Some data, [] -> leaf data
| None, children -> branch key children
| Some data, children ->
branch key (leaf data :: children)
in
List.map (List.rev t.insertion_order) ~f:(fun key ->
let child = Hashtbl.find_exn t.children key in
build_node key child)
;;