123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112(**************************************************************************)(* *)(* OCamlFormat *)(* *)(* Copyright (c) Facebook, Inc. and its affiliates. *)(* *)(* This source code is licensed under the MIT license found in *)(* the LICENSE file in the root directory of this source tree. *)(* *)(**************************************************************************)moduletypeIN=sigincludeComparator.Svalcontains:t->t->boolvalcompare_width_decreasing:t->t->intendmoduletypeS=sigtypeitvtypetvalof_list:itvlist->t(** If there are duplicates in the input list, earlier elements will be
ancestors of later elements. *)valroots:t->itvlistvalchildren:t->itv->itvlistvaldump:t->Fmt.t(** Debug: dump debug representation of tree. *)endmoduleMake(Itv:IN)=struct(* simple but (asymptotically) suboptimal implementation *)typeitv=Itv.ttypet={roots:Itv.tlist;map:Itv.tlistMap.M(Itv).t}letempty={roots=[];map=Map.empty(moduleItv)}letrootst=t.rootsletmap_add_multimap~key~data=Map.updatemapkey~f:(functionNone->[data]|Somel->data::l)(** Descend tree from roots, find deepest node that contains elt. *)letrecparentsmaproots~ancestorselt=Option.value~default:ancestors(List.find_maproots~f:(funroot->ifItv.containsrooteltthenletancestors=root::ancestorsin(matchMap.findmaprootwith|Somechildren->parentsmapchildren~ancestorselt|None->ancestors)|>Option.someelseNone))letadd_roottroot={twithroots=root::t.roots}letadd_childt~parent~child={twithmap=map_add_multit.map~key:parent~data:child}letmap_lists~f{roots;map}={roots=froots;map=Map.mapmap~f}letrecfind_in_previoustelt=function|[]->parentst.mapt.rootselt~ancestors:[]|p::ancestorswhenItv.containspelt->parentst.map[p]elt~ancestors|_::px->find_in_previousteltpx(** Add elements in decreasing width order to construct tree from roots to
leaves. That is, when adding an interval to a partially constructed
tree, it will already contain all wider intervals, so the new
interval's parent will already be in the tree. *)letof_listelts=letadd(prev_ancestor,t)elt=letancestors=find_in_previousteltprev_ancestorinlett=matchancestorswith|parent::_->add_childt~parent~child:elt|[]->add_rootteltin(ancestors,t)inelts|>List.dedup_and_sort~compare:Itv.compare_width_decreasing|>List.fold~init:([],empty)~f:add|>snd|>map_lists~f:(List.sort~compare:Itv.compare_width_decreasing)letchildren{map;_}elt=Option.value~default:[](Map.findmapelt)letdumptree=letopenFmtinletrecdump_treeroots=vbox0(listrootscut_break(funroot->letchildren=childrentreerootinvbox1(str(Sexp.to_string_hum(Itv.comparator.sexp_of_troot))$wrap_if(not(List.is_emptychildren))(cut_break$str"{")(str" }")(dump_treechildren))))inset_margin100000000$dump_treetree.rootsend