mirror of
https://github.com/c-cube/ocaml-containers.git
synced 2026-01-23 09:36:41 -05:00
214 lines
7 KiB
OCaml
214 lines
7 KiB
OCaml
|
|
(*
|
|
copyright (c) 2013-2014, Simon Cruanes, Emmanuel Surleau
|
|
all rights reserved.
|
|
|
|
redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
redistributions of source code must retain the above copyright notice, this
|
|
list of conditions and the following disclaimer. redistributions in binary
|
|
form must reproduce the above copyright notice, this list of conditions and the
|
|
following disclaimer in the documentation and/or other materials provided with
|
|
the distribution.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*)
|
|
|
|
|
|
type +'a t = [`Node of 'a * 'a t list]
|
|
|
|
type 'a tree = 'a t
|
|
|
|
type 'a sequence = ('a -> unit) -> unit
|
|
type 'a printer = Format.formatter -> 'a -> unit
|
|
|
|
let rec fold ~f init_acc (`Node (value, children)) =
|
|
let acc = f value init_acc in
|
|
List.fold_left (fun acc' child_node -> fold ~f acc' child_node) acc children
|
|
|
|
let to_seq t yield =
|
|
let rec iter (`Node (value, children)) =
|
|
yield value;
|
|
List.iter iter children
|
|
in
|
|
iter t
|
|
|
|
let split_at_length_minus_1 l =
|
|
let rev_list = List.rev l in
|
|
match rev_list with
|
|
| [] -> (l, None)
|
|
| [item] -> ([], Some item)
|
|
| item::items -> (List.rev items, Some item)
|
|
|
|
let print pp_val formatter tree =
|
|
let rec print_children children indent_string =
|
|
let non_last_children, maybe_last_child =
|
|
split_at_length_minus_1 children
|
|
in
|
|
print_non_last_children non_last_children indent_string;
|
|
match maybe_last_child with
|
|
| Some last_child -> print_last_child last_child indent_string;
|
|
| None -> ();
|
|
and print_non_last_children non_last_children indent_string =
|
|
List.iter (fun (`Node (child_value, grandchildren)) ->
|
|
Format.pp_print_string formatter indent_string;
|
|
Format.pp_print_string formatter "|- ";
|
|
pp_val formatter child_value;
|
|
Format.pp_force_newline formatter ();
|
|
let indent_string' = indent_string ^ "| " in
|
|
print_children grandchildren indent_string'
|
|
) non_last_children;
|
|
and print_last_child (`Node (last_child_value, last_grandchildren)) indent_string =
|
|
Format.pp_print_string formatter indent_string;
|
|
Format.pp_print_string formatter "'- ";
|
|
pp_val formatter last_child_value;
|
|
Format.pp_force_newline formatter ();
|
|
let indent_string' = indent_string ^ " " in
|
|
print_children last_grandchildren indent_string'
|
|
in
|
|
let print_root (`Node (root_value, root_children)) =
|
|
pp_val formatter root_value;
|
|
Format.pp_force_newline formatter ();
|
|
print_children root_children ""
|
|
in
|
|
print_root tree;
|
|
Format.pp_print_flush formatter ()
|
|
|
|
module Zipper = struct
|
|
|
|
type 'a parent = {
|
|
left_siblings: ('a tree) list ;
|
|
value: 'a ;
|
|
right_siblings: ('a tree) list ;
|
|
}
|
|
|
|
type 'a t = {
|
|
tree: 'a tree ;
|
|
lefts: ('a tree) list ;
|
|
rights: ('a tree) list ;
|
|
parents: ('a parent) list ;
|
|
}
|
|
|
|
let zipper tree = { tree = tree ; lefts = []; rights = []; parents = [] }
|
|
|
|
let tree zipper = zipper.tree
|
|
|
|
let left_sibling zipper =
|
|
let rev_lefts = List.rev zipper.lefts in
|
|
match rev_lefts with
|
|
| [] -> None
|
|
| last_left::tail_rev_lefts ->
|
|
Some {
|
|
tree = last_left ;
|
|
lefts = List.rev tail_rev_lefts;
|
|
rights = zipper.tree::zipper.rights ;
|
|
parents = zipper.parents
|
|
}
|
|
|
|
let right_sibling zipper =
|
|
match zipper.rights with
|
|
| [] -> None
|
|
| right::other_rights ->
|
|
Some {
|
|
tree = right ;
|
|
lefts = zipper.tree::zipper.lefts ;
|
|
rights = other_rights ;
|
|
parents = zipper.parents ;
|
|
}
|
|
|
|
let parent zipper =
|
|
match zipper.parents with
|
|
| [] -> None
|
|
| { left_siblings ; value ; right_siblings }::other_parents ->
|
|
Some {
|
|
tree = `Node (value, zipper.lefts @ [zipper.tree] @ zipper.rights) ;
|
|
lefts = left_siblings ;
|
|
rights = right_siblings ;
|
|
parents = other_parents ;
|
|
}
|
|
|
|
let rec root zipper =
|
|
let maybe_parent_zipper = parent zipper in
|
|
match maybe_parent_zipper with
|
|
| None -> zipper
|
|
| Some parent_zipper -> root parent_zipper
|
|
|
|
let nth_child n ({ tree = `Node (value, children) ; _ } as zipper ) =
|
|
let lefts, maybe_child, rev_rights, counter = List.fold_left (
|
|
fun (lefts, maybe_child, rev_rights, counter) tree ->
|
|
let lefts', maybe_child', rev_rights' =
|
|
match counter with
|
|
| _ when counter == n -> (lefts, Some tree, [])
|
|
| _ when counter < n ->
|
|
(tree::lefts, None, [])
|
|
| _ ->
|
|
(lefts, maybe_child, tree::rev_rights)
|
|
in
|
|
(lefts', maybe_child', rev_rights', counter+1)
|
|
) ([], None, [], 0) children
|
|
in
|
|
begin match maybe_child with
|
|
| Some child ->
|
|
Some {
|
|
tree = child ;
|
|
lefts = List.rev lefts;
|
|
rights = List.rev rev_rights ;
|
|
parents = {
|
|
left_siblings = zipper.lefts ;
|
|
value = value ;
|
|
right_siblings = zipper.rights ;
|
|
}::zipper.parents ;
|
|
}
|
|
| None -> None
|
|
end
|
|
|
|
let append_child tree ({ tree = `Node (value, children) ; _ } as zipper ) =
|
|
{
|
|
tree ;
|
|
lefts = children ;
|
|
rights = [] ;
|
|
parents = {
|
|
left_siblings = zipper.lefts ;
|
|
value = value ;
|
|
right_siblings = zipper.rights ;
|
|
}::zipper.parents ;
|
|
}
|
|
|
|
let insert_left_sibling tree zipper =
|
|
match zipper.parents with
|
|
| [] -> None
|
|
| _ -> Some { zipper with tree ; rights = zipper.tree::zipper.rights }
|
|
|
|
let insert_right_sibling tree zipper =
|
|
match zipper.parents with
|
|
| [] -> None
|
|
| _ -> Some { zipper with tree ; lefts = zipper.tree::zipper.lefts }
|
|
|
|
let replace tree zipper =
|
|
{ zipper with tree }
|
|
|
|
let delete ({ tree = `Node (value, children) ; _ } as zipper ) =
|
|
match zipper with
|
|
| { lefts = first_left::other_lefts ; _ } ->
|
|
Some { zipper with tree = first_left ; lefts = other_lefts }
|
|
| { rights = first_right::other_rights ; _ } ->
|
|
Some { zipper with tree = first_right ; rights = other_rights }
|
|
| { parents = { left_siblings ; value ; right_siblings }::other_parents ; _ } ->
|
|
Some {
|
|
tree = `Node (value, zipper.lefts @ zipper.rights) ;
|
|
lefts = left_siblings ;
|
|
rights = right_siblings ;
|
|
parents = other_parents ;
|
|
}
|
|
| _ -> None
|
|
end
|