package stog

  1. Overview
  2. Docs

Source file 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
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
(*********************************************************************************)
(*                Stog                                                           *)
(*                                                                               *)
(*    Copyright (C) 2012-2024 INRIA All rights reserved.                         *)
(*    Author: Maxence Guesdon, INRIA Saclay                                      *)
(*                                                                               *)
(*    This program is free software; you can redistribute it and/or modify       *)
(*    it under the terms of the GNU General Public License as                    *)
(*    published by the Free Software Foundation, version 3 of the 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 General Public License for more details.                               *)
(*                                                                               *)
(*    You should have received a copy of the GNU General Public                  *)
(*    License along with this program; if not, write to the Free Software        *)
(*    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA                   *)
(*    02111-1307  USA                                                            *)
(*                                                                               *)
(*    As a special exception, you have permission to link this program           *)
(*    with the OCaml compiler and distribute executables, as long as you         *)
(*    follow the requirements of the GNU GPL in regard to all of the             *)
(*    software in the executable aside from the OCaml compiler.                  *)
(*                                                                               *)
(*    Contact: Maxence.Guesdon@inria.fr                                          *)
(*                                                                               *)
(*********************************************************************************)

(** *)

module type S =
  sig
    type symbol
    type path = symbol list
    type 'a t
    exception Already_present of path
    val empty : 'a t
    val add : ?fail: bool -> path -> 'a -> 'a t -> 'a t
    val find : path -> 'a t -> 'a list
    val to_string : (symbol -> string) -> 'a t -> string
  end

module Make (P : Map.OrderedType) =
  struct
    module Map = Map.Make (P)
    type symbol = P.t
    type path = symbol list
    type 'a doc = path * 'a list
    type 'a t = Node of 'a t Map.t * 'a list | Leaf of 'a doc
    exception Already_present of path

    let empty = Node (Map.empty, [])
    let is_empty t = t = empty

    let common_prefix l1 l2 =
      let rec iter acc l1 l2 =
        match l1, l2 with
        | [], _
        | _, [] -> (List.rev acc, l1, l2)
        | h1 :: q1, h2 :: q2 ->
            match P.compare h1 h2 with
              0 -> iter (h1 :: acc) q1 q2
            | _ -> (List.rev acc, l1, l2)
      in
      iter [] l1 l2

    let rec add ?(fail=false) ?(backpath=[]) path data t =
      match path with
        [] -> t
      | sym :: q ->
          if is_empty t then
             Leaf (path, [data])
          else
            match t with
              Leaf (orig_path2, data2) ->
                let (pref, path1, path2) = common_prefix path orig_path2 in
                if path1 = [] && path2 = [] then
                  if fail then
                    raise (Already_present ((List.rev backpath) @ orig_path2))
                  else
                    (* if we are here, we just need to add the new data
                       to the existing one, and return the modified leaf *)
                     Leaf (pref, data :: data2)
                else
                  let rec iter = function
                    [] ->
                      let map, data_opt =
                        match path1 with
                          [] -> (Map.empty, [data])
                        | sym :: q -> (Map.add sym (Leaf (q, [data])) Map.empty, [])
                      in
                      let map, data_opt =
                        match path2 with
                          [] ->
                            assert (data_opt = []);
                            (map, data2)
                        | sym :: q -> (Map.add sym (Leaf (q, data2)) map, data_opt)
                      in
                      Node (map, data_opt)
                  | sym :: q ->
                      let t = iter q in
                      Node (Map.add sym t Map.empty, [])
                  in
                  iter pref

            | Node (map, data_opt) ->
                match Map.find_opt sym map with
                | None -> Node (Map.add sym (Leaf (q, [data])) map, data_opt)
                | Some t2 ->
                    match q, data_opt with
                    | [], [] ->
                        Node (map, [data])
                    | [], d ->
                        if fail then
                          raise (Already_present (List.rev (sym :: backpath)))
                        else
                          Node (map, data :: d)
                    | _, _ ->
                        let x = add ~backpath: (sym :: backpath) q data t2 in
                        Node (Map.add sym x map, data_opt)

    let add ?fail path data t = add ?fail path data t

    let rec is_path_prefix p1 p2 =
      match p1, p2 with
        [], [] -> true
      | [], _ -> true
      | _, [] -> false
      | h1 :: q1, h2 :: q2 ->
          match P.compare h1 h2 with
            0 -> is_path_prefix q1 q2
          | _ -> false

    let rec docs ?(acc=[]) path = function
      Leaf (p, data) ->
        let path =  path @ p in
        List.fold_left (fun acc d -> (path, d) :: acc) acc data
    | Node (map, data_opt) ->
        let acc =
          match data_opt with
            [] -> acc
          | data -> List.fold_left (fun acc d -> (path, d) :: acc) acc data
        in
        Map.fold (fun sym t acc -> docs ~acc (path @ [sym]) t) map acc

    let rec find ?(backpath=[]) path t =
      match path with
        [] -> List.map snd (docs (List.rev backpath) t)
      | sym :: q ->
          match t with
            Leaf (p, data) ->
              if is_path_prefix path p then
                data
              else
                []
          | Node (map, _) ->
              match Map.find_opt sym map with
              | None -> []
              | Some t -> find ~backpath: (sym :: backpath) q t

    let find path t = find path t

    let to_string f t =
      let b = Buffer.create 256 in
      let rec iter margin = function
        Leaf (p, data) ->
          Printf.bprintf b "%s[%s(leaf)]\n" margin
            (String.concat "/" (List.map f (List.rev p)))
      | Node (map, opt) ->
          begin
            match opt with
              [] -> ()
            | _ -> Printf.bprintf b "%s[data]\n" margin
          end;
          Map.iter
            (fun k v ->
               Printf.bprintf b "%s%s\n" margin (f k); iter (margin^"  ") v)
            map
      in
      iter "" t;
      Buffer.contents b


(*    let remove path t =
      let rec iter t = function
        [] -> t
      | [sym] ->
          begin
            match t with
              Leaf l when l = [sym] ->
          end
      | sym :: q ->
         *)
  end
OCaml

Innovation. Community. Security.