Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file object_graph.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253(*
* Copyright (c) 2013-2017 Thomas Gazagnaire <thomas@gazagnaire.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*)open!ImportincludeObject_graph_intfletsrc=Logs.Src.create"irmin.graph"~doc:"Irmin graph support"moduleLog=(valLogs.src_logsrc:Logs.LOG)letlist_partition_mapft=letrecauxfstsnd=function|[]->(List.revfst,List.revsnd)|h::t->(matchfhwith|`Fstx->aux(x::fst)sndt|`Sndx->auxfst(x::snd)t)inaux[][]tmoduleMake(Hash:HASH)(Branch:Type.S)=structmoduleX=structtypet=[`ContentsofHash.t|`NodeofHash.t|`CommitofHash.t|`BranchofBranch.t][@@derivingirmin]letequal=Type.(unstage(equalt))letcompare=Type.(unstage(comparet))lethash_branch=Type.(unstage(short_hashBranch.t))(* we are using cryptographic hashes here, so the first bytes
are good enough to be used as short hashes. *)lethash(t:t):int=matchtwith|`Contentsc->Hash.short_hashc|`Noden->Hash.short_hashn|`Commitc->Hash.short_hashc|`Branchb->hash_branchbendmoduleG=Graph.Imperative.Digraph.ConcreteBidirectional(X)moduleGO=Graph.Oper.I(G)moduleTopological=Graph.Topological.Make(G)moduleTable:sigtypetvalcreate:intoption->tvaladd:t->X.t->int->unitvalmem:t->X.t->boolend=structmoduleLru=Lru.Make(X)moduleTbl=Hashtbl.Make(X)typet=LofintLru.t|TofintTbl.tletcreate=function|None->T(Tbl.create1024)|Somen->L(Lru.createn)letaddtkv=matchtwithLt->Lru.addtkv|Tt->Tbl.addtkvletmemtk=matchtwithLt->Lru.memtk|Tt->Tbl.memtkendmoduleSet=Set.Make(X)includeGincludeGOtypedump=vertexlist*(vertex*vertex)list(* XXX: for the binary format, we can use offsets in the vertex list
to save space. *)moduleDump=structtypet=X.tlist*(X.t*X.t)list[@@derivingirmin]endletvertexg=G.fold_vertex(funkset->k::set)g[]letedgesg=G.fold_edges(funk1k2list->(k1,k2)::list)g[]letpp_vertices=Fmt.Dump.list(Type.ppX.t)letpp_depthppfd=ifd<>max_intthenFmt.pfppf"depth=%d,@ "dtypeaction=Visitof(X.t*int)|TreatofX.tletiter?cache_size?(depth=max_int)~pred~min~max~node?edge~skip~rev()=Log.debug(funf->f"@[<2>iter:@ %arev=%b,@ min=%a,@ max=%a@, cache=%a@]"pp_depthdepthrevpp_verticesminpp_verticesmaxFmt.(Dump.optionint)cache_size);letmarks=Table.createcache_sizeinletmarkkeylevel=Table.addmarkskeylevelinlettodo=Stack.create()in(* if a branch is in [min], add the commit it is pointing to too. *)let*min=Lwt_list.fold_left_s(funacc->function|`Branch_asx->predx>|=func->x::c@acc|x->Lwt.return(x::acc))[]mininletmin=Set.of_listmininlethas_markkey=Table.memmarkskeyinList.iter(funk->Stack.push(Visit(k,0))todo)max;lettreatkey=Log.debug(funf->f"TREAT %a"Type.(ppX.t)key);nodekey>>=fun()->ifnot(Set.memkeymin)then(* the edge function is optional to prevent an unnecessary computation
of the preds .*)matchedgewith|None->Lwt.return_unit|Someedge->let*keys=predkeyinLwt_list.iter_p(funk->edgekeyk)keyselseLwt.return_unitinletvisit_predecessors~filter_historykeylevel=let+keys=predkeyin(*if a commit is in [min] cut the history but still visit
its nodes. *)List.iter(function|`Commit_whenfilter_history->()|k->Stack.push(Visit(k,level+1))todo)keysinletvisitkeylevel=iflevel>=depththenLwt.return_unitelseifhas_markkeythenLwt.return_unitelseskipkey>>=function|true->Lwt.return_unit|false->let+()=Log.debug(funf->f"VISIT %a %d"Type.(ppX.t)keylevel);markkeylevel;ifrevthenStack.push(Treatkey)todo;matchkeywith|`Commit_->visit_predecessors~filter_history:(Set.memkeymin)keylevel|_->ifSet.memkeyminthenLwt.return_unitelsevisit_predecessors~filter_history:falsekeylevelinifnotrevthenStack.push(Treatkey)todoinletrecpop()=matchStack.poptodowith|exceptionStack.Empty->Lwt.return_unit|Treatkey->treatkey>>=pop|Visit(key,level)->visitkeylevel>>=popinpop()letclosure?(depth=max_int)~pred~min~max()=letg=G.create~size:1024()inList.iter(G.add_vertexg)max;letnodekey=ifnot(G.mem_vertexgkey)thenG.add_vertexgkeyelse();Lwt.return_unitinletedgenodepred=G.add_edgegprednode;Lwt.return_unitinletskip_=Lwt.return_falseiniter~depth~pred~min~max~node~edge~skip~rev:false()>|=fun()->gletming=G.fold_vertex(funvacc->ifG.in_degreegv=0thenv::accelseacc)g[]letmaxg=G.fold_vertex(funvacc->ifG.out_degreegv=0thenv::accelseacc)g[]letvertex_attributes=ref(fun_->[])letedge_attributes=ref(fun_->[])letgraph_name=refNonemoduleDot=Graph.Graphviz.Dot(structincludeGletedge_attributesk=!edge_attributeskletdefault_edge_attributes_=[]letvertex_namek=letstrtv="\""^Type.to_stringtv^"\""inmatchkwith|`Noden->strHash.tn|`Commitc->strHash.tc|`Contentsc->strHash.tc|`Branchb->strBranch.tbletvertex_attributesk=!vertex_attributeskletdefault_vertex_attributes_=[]letget_subgraph_=Noneletgraph_attributes_=match!graph_namewithNone->[]|Somen->[`Labeln]end)letexportt=(vertext,edgest)letimport(vs,es)=letg=G.create~size:(List.lengthvs)()inList.iter(G.add_vertexg)vs;List.iter(fun(v1,v2)->G.add_edgegv1v2)es;gletoutputppfvertexedgesname=Log.debug(funf->f"output %s"name);letg=G.create~size:(List.lengthvertex)()inList.iter(fun(v,_)->G.add_vertexgv)vertex;List.iter(fun(v1,_,v2)->G.add_edgegv1v2)edges;leteattrs(v1,v2)=tryletl=List.filter(fun(x,_,y)->x=v1&&y=v2)edgesinletl=List.fold_left(funacc(_,l,_)->l@acc)[]linletlabels,others=list_partition_map(function`Labell->`Fstl|x->`Sndx)linmatchlabelswith|[]->others|[l]->`Labell::others|_->`Label(String.concat","labels)::otherswithNot_found->[]inletvattrsv=tryList.assocvvertexwithNot_found->[]invertex_attributes:=vattrs;edge_attributes:=eattrs;graph_name:=Somename;Dot.fprint_graphppfgend