Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file Trie.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352(* This file is free software, part of containers. See file "license" for more details. *)(** {1 Prefix Tree} *)(** {2 Signatures} *)(** {6 A Composite Word}
Words are made of characters, who belong to a total order *)moduletypeWORD=sigtypettypecharvalcompare_char:char->char->intvalappend:t->t->tvalto_iter:t->charIter.tvalof_list:charlist->tendmoduleMake(W:WORD)(* : Sigs.S with type elt = W.t *)=structtypechar=W.chartypeelt=W.tmoduleM=Map.Make(structtypet=charletcompare=W.compare_charend)type+'atrie=|Empty|Leafof'a|Nodeof'atrieM.ttypet=unittrieletempty=Emptyletrec_check_invariants=function|Empty|Leaf(_,_)->true|Nodemap->not(M.is_emptymap)&&M.for_all(fun_v->_check_invariantsv)mapletis_empty=function|Empty->true|_->falselet_idx=x(** Smart constructors *)(* sub-tree t prefixed with c *)let_consct=ifis_emptytthenEmptyelseNode(M.singletonct)let_leafx=Leafx(* build a Node value *)let_nodemap=ifM.is_emptymapthenEmptyelseifM.cardinalmap=1thenletc,sub=M.min_bindingmapin_conscsubelseNodemaplet_node2c1t1c2t2=matchis_emptyt1,is_emptyt2with|true,true->Empty|true,false->_consc2t2|false,true->_consc1t1|false,false->letmap=M.addc1t1M.emptyinletmap=M.addc2t2mapin_nodemap(** Inserting/Removing *)(* fold [f] on [iter] with accumulator [acc], and call [finish]
on the accumulator once [iter] is exhausted *)let_fold_iter_and_thenf~finishacciter=letacc=refacciniter(funx->acc:=f!accx);finish!accletupdatekeyft=(* first arg: current subtree and rebuild function; [c]: current char *)letgoto(t,rebuild)c=matchtwith|Empty|Leaf_->t,funt->rebuild(_consct)|Nodemap->trylett'=M.findcmapin(* rebuild: we modify [t], so we put the new version in [map]
if it's not empty, and make the node again *)letrebuild'new_child=rebuild(ifis_emptynew_childthen_node(M.removecmap)else_node(M.addcnew_childmap))int',rebuild'withNot_found->letrebuild'new_child=ifis_emptynew_childthenrebuildt(* ignore *)elseletmap'=M.addcnew_childmapinrebuild(_nodemap')inempty,rebuild'inletleaf_or_emptyrebuildo=matchfowith|None->rebuild(_nodeM.empty)|Somex'->rebuild(_leafx')inletfinish(t,rebuild)=matchtwith|Leafx->leaf_or_emptyrebuild@@Somex|Empty->leaf_or_emptyrebuild@@None|Nodemap->rebuild(_nodemap)inletword=W.to_iterkeyin_fold_iter_and_thengoto~finish(t,_id)wordletaddkvt=updatek(fun_->Somev)t(* let remove k t = update k (fun _ -> None) t *)letsingletonkv=addkvEmpty(** Iter/Fold *)type'adifflist='alist->'alistlet_difflist_add:'adifflist->'a->'adifflist=funfx->funl'->f(x::l')(* fold that also keeps the path from the root, so as to provide the list
of chars that lead to a value. The path is a difference list, ie
a function that prepends a list to some suffix *)letrec_foldfpathtacc=matchtwith|Empty->acc|Leafv->faccpathv(* | Cons (c, t') -> _fold f (_difflist_add path c) t' acc *)|Nodemap->M.fold(funct'acc->_foldf(_difflist_addpathc)t'acc)mapacc(* let fold f acc t =
* _fold
* (fun acc path v ->
* let key = W.of_list (path []) in
* f acc key v)
* _id t acc *)(*$T
T.fold (fun acc k v -> (k,v) :: acc) [] t1 \
|> List.sort Pervasives.compare = List.sort Pervasives.compare l1
*)letiterft=_fold(fun()pathy->f(W.of_list(path[]))y)_idt()(* let rec fold_values f acc t = match t with
* | Empty -> acc
* | Leaf v -> f acc v
* (\* | Cons (_, t') -> fold_values f acc t' *\)
* | Node map ->
* M.fold
* (fun _c t' acc -> fold_values f acc t')
* map acc
*
* let iter_values f t = fold_values (fun () x -> f x) () t *)(** Merging operations *)let_mk=functionSomex->_leafx|None->emptylet[@specialize]recmerge_with~f~left~rightt1t2=matcht1,t2with|Empty,Empty->fNoneNone|Empty,Node_->rightt2|Node_,Empty->leftt1|Leafv,Empty->f(Somev)None|Empty,Leafv->fNone(Somev)|Leafv,Leafv'->f(Somev)(Somev')|Leaf_,Node_|Node_,Leaf_->assertfalse(* | Cons (c1,t1'), Cons (c2,t2') ->
* if W.compare_char c1 c2 = 0
* then _cons c1 (merge_with ~f ~left ~right t1' t2')
* else _node2 c1 (left t1') c2 (right t2')
*
* | Cons (c1, t1'), Node (value, map) ->
* begin try
* (\* collision *\)
* let t2' = M.find c1 map in
* let new_t = merge_with ~f ~left ~right t1' t2' in
* let map' = if is_empty new_t
* then M.remove c1 map
* else M.add c1 new_t map
* in
* _node value map'
* with Not_found ->
* (\* no collision *\)
* assert (not(is_empty t1'));
* let t1' = left t1' in
* let map' = if is_empty t1' then map else M.add c1 t1' map in
* Node (value, map')
* end
* | Node (value, map), Cons (c2, t2') ->
* begin try
* (\* collision *\)
* let t1' = M.find c2 map in
* let new_t = merge_with ~f ~left ~right t1' t2' in
* let map' = if is_empty new_t
* then M.remove c2 map
* else M.add c2 new_t map
* in
* _node value map'
* with Not_found ->
* (\* no collision *\)
* assert (not(is_empty t2'));
* let t2' = left t2' in
* let map' = if is_empty t2' then map else M.add c2 t2' map in
* Node (value, map')
* end *)|Nodemap1,Nodemap2->(* let v = f v1 v2 in *)letas_optiont=ifis_emptytthenNoneelseSometinletmap'=M.merge(fun_ct1t2->matcht1,t2with|None,None->assertfalse|Somet,None->as_option@@leftt|None,Somet->as_option@@rightt|Somet1,Somet2->letnew_t=merge_with~f~left~rightt1t2inas_optionnew_t)map1map2in_nodemap'letkeepx=xletdrop_=Emptyletunionll'=letleft=keepandright=keepandfab=matcha,bwith|Some_,_->_mka|None,_->_mkbinmerge_with~f~left~rightll'letinterll'=letleft=dropandright=dropandfab=matcha,bwith|Some_,Some_->_mka|_->emptyinmerge_with~f~left~rightll'letdiffll'=letleft=keepandright=dropandfab=matcha,bwith|Some_,None->_mka|_->emptyinmerge_with~f~left~rightll'letmergel=List.fold_leftunionEmptyl(** Grafting/flatmap *)(* let map f t =
* let rec map_ = function
* | Empty -> Empty
* (\* | Cons (c, t') -> Cons (c, map_ t') *\)
* | Leaf x -> Leaf (f x)
* | Node map ->
* let map' = M.map map_ map
* in Node map'
* in map_ t *)letrecappendtt0=matchtwith|Empty->Empty|Leaf_v->t0(* | Cons (c, t') -> Cons (c, append t' t0) *)|Nodemap->letmap=M.map(funt'->appendt't0)mapinNodemap(** Misc *)(* let rec size t = match t with
* | Empty -> 0
* | Cons (_, t') -> size t'
* | Node (v, map) ->
* let s = if v=None then 0 else 1 in
* M.fold
* (fun _ t' acc -> size t' + acc)
* map s *)letof_listl=List.fold_left(funaccv->addv()acc)emptylletto_itertk=iter(funx()->kx)t(** External API *)letreturnx=singletonx()letmemoizex=xendmoduletypeORDERED=sigtypetvalcompare:t->t->intendmoduleMakeArray(X:ORDERED)=Make(structtypet=X.tarraytypechar=X.tletappend=Array.appendletcompare_char=X.compareletto_iterak=Array.iterkaletof_list=Array.of_listend)moduleMakeList(X:ORDERED)=Make(structtypet=X.tlisttypechar=X.tletappend=List.appendletcompare_char=X.compareletto_iterak=List.iterkaletof_listl=lend)moduleString=Make(structtypet=stringtypenonrecchar=charletappend=(^)letcompare_char=Char.compareletto_itersk=String.iterksletof_listl=letbuf=Buffer.create(List.lengthl)inList.iter(func->Buffer.add_charbufc)l;Buffer.contentsbufend)