aboutsummaryrefslogtreecommitdiffhomepage
path: root/clib/trie.ml
blob: ea43e9e0bd389b4bfb4a0bc847e737cbc1a9bfd0 (plain)
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
(************************************************************************)
(*         *   The Coq Proof Assistant / The Coq Development Team       *)
(*  v      *   INRIA, CNRS and contributors - Copyright 1999-2018       *)
(* <O___,, *       (see CREDITS file for the list of authors)           *)
(*   \VV/  **************************************************************)
(*    //   *    This file is distributed under the terms of the         *)
(*         *     GNU Lesser General Public License Version 2.1          *)
(*         *     (see LICENSE file for the text of the license)         *)
(************************************************************************)

module type S =
sig
  type label
  type data
  type t
  val empty : t
  val get : t -> data
  val next : t -> label -> t
  val labels : t -> label list
  val add : label list -> data -> t -> t
  val remove : label list -> data -> t -> t
  val iter : (label list -> data -> unit) -> t -> unit
end

module type Grp =
sig
  type t
  val nil : t
  val is_nil : t -> bool
  val add : t -> t -> t
  val sub : t -> t -> t
end

module Make (Y : Map.OrderedType) (X : Grp) =
struct

module T_codom = Map.Make(Y)

type data = X.t
type label = Y.t
type t = Node of X.t * t T_codom.t

let codom_for_all f m =
  let fold key v accu = f v && accu in
  T_codom.fold fold m true

let empty = Node (X.nil, T_codom.empty)

let next (Node (_,m)) lbl = T_codom.find lbl m

let get (Node (hereset,_)) = hereset

let labels (Node (_,m)) =
  (** FIXME: this is order-dependent. Try to find a more robust presentation? *)
  List.rev (T_codom.fold (fun x _ acc -> x::acc) m [])

let is_empty_node (Node(a,b)) = (X.is_nil a) && (T_codom.is_empty b)

let assure_arc m lbl =
  if T_codom.mem lbl m then
    m
  else
    T_codom.add lbl (Node (X.nil,T_codom.empty)) m

let cleanse_arcs (Node (hereset,m)) =
  let m = if codom_for_all is_empty_node m then T_codom.empty else m in
  Node(hereset, m)

let rec at_path f (Node (hereset,m)) = function
  | [] ->
      cleanse_arcs (Node(f hereset,m))
  | h::t ->
      let m = assure_arc m h in
      cleanse_arcs (Node(hereset,
                         T_codom.add h (at_path f (T_codom.find h m) t) m))

let add path v tm =
  at_path (fun hereset -> X.add v hereset) tm path

let remove path v tm =
  at_path (fun hereset -> X.sub hereset v) tm path

let iter f tlm =
  let rec apprec pfx (Node(hereset,m)) =
    let path = List.rev pfx in
    f path hereset;
    T_codom.iter (fun l tm -> apprec (l::pfx) tm) m
  in
  apprec [] tlm

end