123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305(* This file is free software, part of containers. See file "license" for more details. *)(** {1 Hash Tries} *)type'aiter=('a->unit)->unittype'agen=unit->'aoptiontype'aprinter=Format.formatter->'a->unittype'aktree=unit->[`Nil|`Nodeof'a*'aktreelist](* TODO
(** {2 Transient IDs} *)
module Transient = struct
type state = { mutable frozen: bool }
type t = Nil | St of state
let empty = Nil
let equal a b = Stdlib.(==) a b
let create () = St {frozen=false}
let active = function Nil -> false | St st -> not st.frozen
let frozen = function Nil -> true | St st -> st.frozen
let freeze = function Nil -> () | St st -> st.frozen <- true
let with_ f =
let r = create() in
try
let x = f r in
freeze r;
x
with e ->
freeze r;
raise e
exception Frozen
end
*)(* function array *)moduleA=structtype'at='aarrayletlength_log=5letmax_length=32letmask=max_length-1let()=assert(max_length=1lsllength_log)letlength=Array.lengthletiteri=Array.iteriletiter=Array.iterletmap=Array.mapletiteri_revfa=fori=lengtha-1downto0dofia.(i)doneletempty=[||]letis_emptya=lengtha=0letreturnx=[|x|]letgetai=ifi<0||i>=lengthatheninvalid_arg"A.get";Array.unsafe_getai(* push at the back *)letpushxa=letn=lengthainifn=max_lengththeninvalid_arg"A.push";letarr=Array.make(n+1)xinArray.blita0arr0n;arrletpopa=letn=lengthainifn=0theninvalid_arg"A.pop";Array.suba0(n-1)letset~mutaix=ifi<0||i>lengtha||i>=max_lengththeninvalid_arg"A.set";ifi=lengthathen((* insert in a longer copy *)letarr=Array.make(i+1)xinArray.blita0arr0i;arr)elseifmutthen((* replace element at [i] in place *)a.(i)<-x;a)else((* replace element at [i] in copy *)letarr=Array.copyainarr.(i)<-x;arr)end(** {2 Functors} *)type'at={size:int;leaves:'aA.t;subs:'atA.t;}(* invariant:
- [A.length leaves < A.max_length ==> A.is_empty subs]
- either:
* [exists n. forall i. subs[i].size = n] (all subtrees of same size)
* [exists n i.
(forall j<i. sub[j].size=32^{n+1}-1) &
(forall j>=i, sub[j].size<32^{n+1}-1)]
(prefix of subs has size of complete binary tree; suffix has
smaller size (actually decreasing))
*)letempty={size=0;leaves=A.empty;subs=A.empty}letis_empty{size;_}=size=0letlength{size;_}=sizeletreturnx={leaves=A.returnx;subs=A.empty;size=1}typeidx_l=|I_oneofint|I_consofint*idx_l(* split an index into a low and high parts *)letlow_idx_i=ilandA.masklethigh_idx_i=ilsrA.length_logletcombine_idxij=(ilslA.length_log)lorj(* split an index into a high part, < 32, and a low part *)letsplit_idxi:idx_l=letrecauxhighlow=ifhigh=0thenlowelseifhigh<A.max_lengththenI_cons(high-1,low)elseaux(high_idx_high)(I_cons(low_idx_high,low))inaux(high_idx_i)(I_one(low_idx_i))letget_(i:int)(m:'at):'a=letrecauxlm=matchlwith|I_onex->assert(x<A.lengthm.leaves);A.getm.leavesx|I_cons(x,tl)->auxtl(A.getm.subsx)inaux(split_idxi)mletget_exniv=ifi>=0&&i<lengthvthenget_ivelseraiseNot_foundletgetiv=ifi>=0&&i<lengthvthenSome(get_iv)elseNoneletpush_(i:int)(x:'a)(m:'at):'at=letrecauxlm=matchlwith|I_onei->assert(i=A.lengthm.leaves);assert(A.lengthm.leaves<A.max_length);assert(A.is_emptym.subs);{mwithsize=m.size+1;leaves=A.pushxm.leaves}|I_cons(i,tl)->aux_replace_subtlmiandaux_replace_sublmx=assert(x<=A.lengthm.subs);(* insert in subtree, possibly a new one *)letsub_m=ifx<A.lengthm.substhenA.getm.subsxelseemptyinletsub_m=auxlsub_min{mwithsize=m.size+1;subs=A.set~mut:falsem.subsxsub_m}inaux(split_idxi)mletpushx(v:_t):_t=push_v.sizexvletpop_i(m:'at):'a*'at=letrecauxlm=matchlwith|I_onex->assert(x+1=A.lengthm.leaves);(* last one *)letx=A.getm.leavesxinx,{mwithsize=m.size-1;leaves=A.popm.leaves}|I_cons(x,tl)->aux_remove_subtlmxandaux_remove_sublmx=letsub=A.getm.subsxinlety,sub'=auxlsubinifis_emptysub'then(assert(x+1=A.lengthm.subs);(* last one *)y,{mwithsize=m.size-1;subs=A.popm.subs})elsey,{mwithsize=m.size-1;subs=A.set~mut:falsem.subsxsub'}inaux(split_idxi)mletpop_exn(v:'at):'a*'at=ifv.size=0theninvalid_arg"Fun_vec.pop_exn";pop_(v.size-1)vletpop(v:'at):('a*'at)option=ifv.size=0thenNoneelseSome(pop_(v.size-1)v)letiteri~f(m:'at):unit=(* basically, a 32-way BFS traversal.
The queue contains subtrees to explore, along with their high_idx_ offsets *)letq:(int*'at)Queue.t=Queue.create()inQueue.push(0,m)q;whilenot(Queue.is_emptyq)dolethigh,m=Queue.popqinA.iteri(funix->f(combine_idxhighi)x)m.leaves;A.iteri(funisub->Queue.push(combine_idxihigh,sub)q)m.subsdoneletiteri_rev~f(m:'at):unit=(* like {!iteri} but last element comes first *)letrecauxhighm=A.iteri_rev(funisub->aux(combine_idxihigh)sub)m.subs;(* only now, explore current leaves *)A.iteri_rev(funix->f(combine_idxhighi)x)m.leavesinaux0mletfoldi~f~xm=letacc=refxiniterim~f:(funix->acc:=f!accix);!accletfoldi_rev~f~xm=letacc=refxiniteri_revm~f:(funix->acc:=f!accix);!accletiter~fm=iteri~f:(fun_x->fx)mletfold~f~xm=foldi~f:(funacc_x->faccx)~xmletfold_rev~f~xm=foldi_rev~f:(funacc_x->faccx)~xmletrecmapfm:_t={subs=A.map(mapf)m.subs;leaves=A.mapfm.leaves;size=m.size}letappendab=ifis_emptybthenaelsefold~f:(funvx->pushxv)~x:abletadd_listvl=List.fold_left(funvx->pushxv)vlletof_listl=add_listemptylletto_listm=fold_revm~f:(funaccx->x::acc)~x:[]letadd_itervseq=letv=refvinseq(funx->v:=pushx!v);!vletof_iters=add_iteremptysletto_itermyield=iteri~f:(fun_v->yieldv)mletrecadd_genmg=matchg()with|None->m|Somex->add_gen(pushxm)gletof_geng=add_genemptyg(* traverse the tree by increasing hash order, where the order compares
hashes lexicographically by A.length_log-wide chunks of bits,
least-significant chunks first *)letto_genm=letq_cur:'aQueue.t=Queue.create()inletq_sub:'atQueue.t=Queue.create()inQueue.pushmq_sub;letrecnext()=ifnot(Queue.is_emptyq_cur)thenSome(Queue.popq_cur)elseifnot(Queue.is_emptyq_sub)then(letm=Queue.popq_subinA.iter(funx->Queue.pushxq_cur)m.leaves;A.iter(funsub->Queue.pushsubq_sub)m.subs;next())elseNoneinnextletchoosem=to_genm()letppppvoutm=letfirst=reftrueiniterm~f:(funv->if!firstthenfirst:=falseelseFormat.fprintfout";@ ";ppvoutv)