From 8377563a0d0d20f1e7f67b7cfcec4c27a02b7a3f Mon Sep 17 00:00:00 2001 From: Daniil Baturin Date: Mon, 9 Jan 2017 11:52:13 +0700 Subject: T245: add Vytree.merge_children function for de-duplicating children that share the same name by merging subsequent nodes into the first one. Bad thing: the comments of the outer nodes will be lost, but then again one should attach them to the inner node anyway, in non-pathological cases. --- src/vytree.ml | 36 ++++++++++++++++++++++++++++++++++++ src/vytree.mli | 2 ++ 2 files changed, 38 insertions(+) (limited to 'src') diff --git a/src/vytree.ml b/src/vytree.ml index 0e379ee..b27aea6 100644 --- a/src/vytree.ml +++ b/src/vytree.ml @@ -81,6 +81,42 @@ let rec insert ?(position=Default) node path data = | None -> raise (Insert_error "Path does not exist") +(** Given a node N check if it has children with duplicate names, + and merge subsequent children's children into the first child by + that name. + + While all insert functions maintain the "every child has unique name" + invariant, for nodes constructed manually with make/make_full and adopt + it may not hold, and constructing nodes this way is a sensible approach + for config parsing. Depending on the config format, duplicate node names + may be normal and even expected, such as "ethernet eth0" and "ethernet eth1" + in the "curly" format. + *) +let merge_children node = + (* Given a node N and a list of nodes NS, find all nodes in NS that + have the same name as N and merge their children into N *) + let rec merge_into n ns = + match ns with + | [] -> n + | n' :: ns' -> + if n.name = n'.name then + let children = List.append n.children n'.children in + let n = {n with children=children} in + merge_into n ns' + else merge_into n ns' + in + (* Given a list of nodes, for every node, find subsequent children with + the same name and merge them into the first node, then delete remaining + nodes from the list *) + let rec aux ns = + match ns with + | [] -> [] + | n :: ns -> + let n = merge_into n ns in + let ns = List.filter (fun x -> x.name <> n.name) ns in + n :: (aux ns) + in {node with children=(aux node.children)} + (* When inserting at a path that, entirely or partially, does not exist yet, create missing nodes on the way with default data *) let rec insert_multi_level default_data node path_done path_remaining data = diff --git a/src/vytree.mli b/src/vytree.mli index 6de65c5..d00d3ff 100644 --- a/src/vytree.mli +++ b/src/vytree.mli @@ -23,6 +23,8 @@ val insert : ?position:position -> 'a t -> string list -> 'a -> 'a t val insert_multi_level : 'a -> 'a t -> string list -> string list -> 'a -> 'a t +val merge_children : 'a t -> 'a t + val delete : 'a t -> string list -> 'a t val update : 'a t -> string list -> 'a -> 'a t -- cgit v1.2.3