package albatross

  1. Overview
  2. Docs

Source file vmm_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
(* (c) 2018 Hannes Mehnert, all rights reserved *)

(* each node may have a value (of type 'a), the boolean represents whether it
   is a path or a name (i.e. foo:bar: <value> or foo:bar <value>). *)
type 'a t = N of ('a * bool) option * 'a t Vmm_core.String_map.t

let empty = N (None, Vmm_core.String_map.empty)

let insert id e t =
  let rec go e (N (es, m)) = function
    | [] ->
      begin match es with
        | None -> N (Some e, m), None
        | Some es' -> N (Some e, m), Some (fst es')
      end
    | x::xs ->
      let n = match Vmm_core.String_map.find_opt x m with
        | None -> empty
        | Some n -> n
      in
      let entry, ret = go e n xs in
      N (es, Vmm_core.String_map.add x entry m), ret
  in
  let is_path = Option.is_none (Vmm_core.Name.name id) in
  go (e, is_path) t (Vmm_core.Name.to_list id)

let remove id t =
  let rec go (N (es, m)) = function
    | [] -> if Vmm_core.String_map.is_empty m then None else Some (N (None, m))
    | x::xs ->
      let n' =
        match Vmm_core.String_map.find_opt x m with
        | None -> None
        | Some n -> go n xs
      in
      let m' =
        Option.fold
          ~none:(Vmm_core.String_map.remove x m)
          ~some:(fun entry -> Vmm_core.String_map.add x entry m)
          n'
      in
      if Vmm_core.String_map.is_empty m' && es = None then
        None
      else
        Some (N (es, m'))
  in
  match go t (Vmm_core.Name.to_list id) with
  | None -> empty
  | Some n -> n

let find id t =
  let rec go (N (es, m)) = function
    | [] -> Option.map fst es
    | x::xs ->
      match Vmm_core.String_map.find_opt x m with
      | None -> None
      | Some n -> go n xs
  in
  go t (Vmm_core.Name.to_list id)

let append_name prefix name =
  let path =
    let pre_path = Vmm_core.Name.path prefix in
    Option.fold
      ~none:pre_path
      ~some:(fun prefix_name -> Vmm_core.Name.append_path_exn pre_path prefix_name)
      (Vmm_core.Name.name prefix)
  in
  Option.fold
    ~none:(Vmm_core.Name.create_of_path path)
    ~some:(fun name -> Vmm_core.Name.create_exn path name)
    name

let collect id t =
  let rec go acc prefix (N (es, m)) =
    let acc' =
      match es with
      | None -> acc
      | Some (e, is_path) ->
        let name = if is_path then append_name prefix None else prefix in
        (name, e) :: acc
    in
    function
    | [] -> acc'
    | x::xs ->
      match Vmm_core.String_map.find_opt x m with
      | None -> acc'
      | Some n -> go acc' (append_name prefix (Some x)) n xs
  in
  go [] Vmm_core.Name.root t (Vmm_core.Name.to_list id)

let all t =
  let rec go acc prefix (N (es, m)) =
    let acc' =
      match es with
      | None -> acc
      | Some (e, is_path) ->
        let name = if is_path then append_name prefix None else prefix in
        (name, e) :: acc
    in
    List.fold_left (fun acc (name, node) ->
        go acc (append_name prefix (Some name)) node)
      acc' (Vmm_core.String_map.bindings m)
  in
  List.rev (go [] Vmm_core.Name.root t)

let fold path t f acc =
  let rec explore (N (es, m)) prefix_path name acc =
    let acc' =
      let prefix =
        if name = "" then
          prefix_path
        else
          Vmm_core.Name.append_path_exn prefix_path name
      in
      Vmm_core.String_map.fold (fun name node acc ->
          explore node prefix name acc)
        m acc
    in
    match es with
    | None -> acc'
    | Some (e, is_path) ->
      let name =
        if name = "" then
          Vmm_core.Name.create_of_path prefix_path
        else
          Vmm_core.Name.create_exn prefix_path name
      in
      let name = if is_path then append_name name None else name in
      f name e acc'
  in
  let rec down prefix (N (es, m)) =
    match prefix with
    | [] -> explore (N (es, m)) Vmm_core.Name.root_path "" acc
    | x :: xs -> match Vmm_core.String_map.find_opt x m with
      | None -> acc
      | Some n -> down xs n
  in
  down (Vmm_core.Name.path_to_list path) t
OCaml

Innovation. Community. Security.