Files
xen/tools/ocaml/xenstored/trie.ml
T
Edwin Török b1278939db tools/oxenstored: Use more efficient tries
No functional change, just an optimization.

Signed-off-by: Edwin Török <edvin.torok@citrix.com>
Acked-by: Christian Lindig <christian.lindig@citrix.com>
2021-01-22 18:01:35 +00:00

178 lines
4.3 KiB
OCaml

(*
* Copyright (C) 2008-2009 Citrix Ltd.
* Author Thomas Gazagnaire <thomas.gazagnaire@eu.citrix.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; version 2.1 only. with the special
* exception on linking described in file LICENSE.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*)
open Stdext
module StringMap = Map.Make(String)
module Node =
struct
type 'a t = {
key: string;
value: 'a option;
children: 'a t StringMap.t;
}
let _create key value = {
key = key;
value = Some value;
children = StringMap.empty;
}
let empty key = {
key = key;
value = None;
children = StringMap.empty;
}
let _get_key node = node.key
let get_value node =
match node.value with
| None -> raise Not_found
| Some value -> value
let _get_children node = node.children
let set_value node value =
{ node with value = Some value }
let set_children node children =
{ node with children = children }
let _add_child node child =
{ node with children = StringMap.add child.key child node.children }
end
type 'a t = 'a Node.t StringMap.t
let mem_node nodes key =
StringMap.mem key nodes
let find_node nodes key =
StringMap.find key nodes
let replace_node nodes key node =
StringMap.update key (function None -> None | Some _ -> Some node) nodes
let remove_node nodes key =
StringMap.update key (function None -> raise Not_found | Some _ -> None) nodes
let create () = StringMap.empty
let rec iter f tree =
let aux key node =
f key node.Node.value;
iter f node.Node.children
in
StringMap.iter aux tree
let rec map f tree =
let aux node =
let value =
match node.Node.value with
| None -> None
| Some value -> f value
in
{ node with Node.value = value; Node.children = map f node.Node.children }
in
tree |> StringMap.map aux
|> StringMap.filter (fun _ n -> n.Node.value <> None || not (StringMap.is_empty n.Node.children))
let rec fold f tree acc =
let aux key node accu =
fold f node.Node.children (f key node.Node.value accu)
in
StringMap.fold aux tree acc
(* return a sub-trie *)
let rec sub_node tree = function
| [] -> raise Not_found
| h::t ->
if mem_node tree h
then begin
let node = find_node tree h in
if t = []
then node
else sub_node node.Node.children t
end else
raise Not_found
let sub tree path =
try (sub_node tree path).Node.children
with Not_found -> StringMap.empty
let find tree path =
Node.get_value (sub_node tree path)
(* return false if the node doesn't exists or if it is not associated to any value *)
let rec mem tree = function
| [] -> false
| h::t ->
mem_node tree h
&& (let node = find_node tree h in
if t = []
then node.Node.value <> None
else mem node.Node.children t)
(* Iterate over the longest valid prefix *)
let rec iter_path f tree = function
| [] -> ()
| h::l ->
if mem_node tree h
then begin
let node = find_node tree h in
f node.Node.key node.Node.value;
iter_path f node.Node.children l
end
let rec set_node node path value =
if path = []
then Node.set_value node value
else begin
let children = set node.Node.children path value in
Node.set_children node children
end
and set tree path value =
match path with
| [] -> raise Not_found
| h::t ->
if mem_node tree h
then begin
let node = find_node tree h in
replace_node tree h (set_node node t value)
end else begin
let node = Node.empty h in
StringMap.add node.Node.key (set_node node t value) tree
end
let rec unset tree = function
| [] -> tree
| h::t ->
if mem_node tree h
then begin
let node = find_node tree h in
let children = unset node.Node.children t in
let new_node =
if t = []
then Node.set_children (Node.empty h) children
else Node.set_children node children
in
if StringMap.is_empty children && new_node.Node.value = None
then remove_node tree h
else replace_node tree h new_node
end else
raise Not_found