Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file containers_pvec.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434(* Persistent vector structure with fast get/push/pop.
We follow https://hypirion.com/musings/understanding-persistent-vector-pt-1
and following posts. *)type'aiter=('a->unit)->unitletnum_bits=4letbranching_factor=1lslnum_bitsletbitmask=branching_factor-1(** Short array with functional semantics *)moduleA=structopenArraytype'at='aarrayletlength=lengthletget=getlet[@inline]is_emptyself=self=[||]let[@inline]returnself=[|self|]let[@inline]is_fullself=lengthself=branching_factorletequaleqab=lengtha=lengthb&&tryfori=0tolengtha-1doifnot(eq(unsafe_getai)(unsafe_getbi))thenraise_notraceExitdone;truewithExit->falselet[@inline]push(self:_t)x=letn=lengthselfinifn=branching_factortheninvalid_arg"Pvec.push";letarr=Array.make(n+1)xinArray.blitself0arr0n;arrlet[@inline]popself:_t=letn=lengthselfinifn=0theninvalid_arg"Pvec.pop";Array.subself0(n-1)letset(self:_t)ix:_t=ifi<0||i>lengthself||i>=branching_factortheninvalid_arg"Pvec.set";ifi=lengthselfthen((* insert in a longer copy *)letarr=Array.make(i+1)xinArray.blitself0arr0i;arr)else((* replace element at [i] in copy *)letarr=Array.copyselfinarr.(i)<-x;arr)endtype'atree=|Empty|Nodeof'atreeA.t|Leafof'aA.ttype'at={t:'atree;(** The 32-way tree *)size:int;(** Exact number of elements *)shift:int;(** num_bits*(depth of tree) *)tail:'aA.t;(** Tail array, for fast push/pop *)}(* invariants:
- if size>0 then [not (is_empty tail)]
- all leaves in [t] are at depth shift/5
*)letempty_tree=Emptyletempty={t=empty_tree;size=0;shift=0;tail=[||]}let[@inline]is_empty_tree=function|Empty->true|_->falselet[@inline]is_empty(self:_t)=self.size=0let[@inline]length(self:_t)=self.sizelet[@inline]returnx={emptywithsize=1;tail=A.returnx}let[@inline]tail_off(self:_t):int=self.size-A.lengthself.taillet[@unroll2]recget_tree_(self:'atree)(shift:int)i:'a=matchselfwith|Empty->invalid_arg"pvec.get"|Leafa->A.geta(ilandbitmask)|Nodea->letidx=(ilsrshift)landbitmaskinget_tree_(A.getaidx)(shift-num_bits)iletget(self:'at)(i:int):'a=ifi<0theninvalid_arg"pvec.get"else(lettail_off=self.size-A.lengthself.tailinifi>=tail_offthenA.getself.tail(i-tail_off)elseget_tree_self.tself.shifti)let[@inline]get_optselfi=trySome(getselfi)withInvalid_argument_->None(** Build a tree leading to [tail] with indices 0 at each node *)letrecbuild_new_tail_spine_shifttail:_tree=ifshift=0thenLeaftailelseNode[|build_new_tail_spine_(shift-num_bits)tail|]letrecinsert_tail_(self:_tree)shifti(tail:_A.t):_tree=matchselfwith|Empty->ifshift=0thenLeaftailelse(assert((ilslshift)landbitmask=0);Node[|insert_tail_Empty(shift-num_bits)itail|])|Leaf_->assertfalse|Nodea->(* would be in the {!build_new_tail_spine_} case *)assert(i<>0);letidx=(ilsrshift)landbitmaskinletsub,must_push=ifidx<A.lengthathenA.getaidx,falseelseEmpty,trueinletnew_sub=insert_tail_sub(shift-num_bits)itailinleta=ifmust_pushthenA.pushanew_subelseA.setaidxnew_subinNodealet[@inlinenever]push_full_selfx:_t=if1lsl(self.shift+num_bits)=self.size-A.lengthself.tailthen((* tree is full, add a level *)lett=Node[|self.t;build_new_tail_spine_self.shiftself.tail|]in{t;size=self.size+1;shift=self.shift+num_bits;tail=[|x|]})else((* insert at the end of the current tree *)letidx=self.size-A.lengthself.tailinlett=insert_tail_self.tself.shiftidxself.tailin{t;size=self.size+1;shift=self.shift;tail=[|x|]})let[@inline]push(self:_t)x:_t=ifA.is_fullself.tailthenpush_full_selfxelse{selfwithtail=A.pushself.tailx;size=self.size+1}letrecpop_tail_from_tree_(self:_tree)shifti:'aA.t*'atree=matchselfwith|Empty->assertfalse|Leaftail->assert(shift=0);tail,Empty|Nodea->letidx=(ilsrshift)landbitmaskinletsub=A.getaidxinlettail,new_sub=pop_tail_from_tree_sub(shift-num_bits)iinletnew_tree=ifis_empty_treenew_subthen(leta=A.popainifA.is_emptyathenEmptyelseNodea)elseNode(A.setaidxnew_sub)intail,new_treelet[@inlinenever]move_last_leaf_to_tail(self:_t):_t=assert(A.lengthself.tail=1);ifself.size=1then(* back to empty *)emptyelse((* idx of the beginning of the tail *)letidx=self.size-1-branching_factorinlettail,t=pop_tail_from_tree_self.tself.shiftidxinlett,shift=matchtwith|Node[|t'|]->(* all indices have 00000 as MSB, remove one level *)t',self.shift-num_bits|_->t,self.shiftin{tail;size=self.size-1;shift;t})letpop(self:'at):'a*'at=ifself.size=0theninvalid_arg"pvec.pop";letx=A.getself.tail(A.lengthself.tail-1)inletnew_tail=A.popself.tailinifA.is_emptynew_tailthen(letnew_self=move_last_leaf_to_tailselfinx,new_self)else(letnew_self={selfwithsize=self.size-1;tail=new_tail}inx,new_self)letpop_opt(self:'at):('a*'at)option=ifself.size=0thenNoneelseSome(popself)let[@inline]lastself=ifself.size=0theninvalid_arg"pvec.last";A.getself.tail(A.lengthself.tail-1)letlast_optself=ifself.size=0thenNoneelseSome(A.getself.tail(A.lengthself.tail-1))letdrop_lastself=ifself.size=0thenselfelsesnd(popself)letreciter_rec_f(self:_tree)=matchselfwith|Empty->()|Leafa->fori=0toA.lengtha-1dof(Array.unsafe_getai)done|Nodea->fori=0toA.lengtha-1doiter_rec_f(Array.unsafe_getai)doneletiterfself=iter_rec_fself.t;fori=0toA.lengthself.tail-1dof(Array.unsafe_getself.taili)doneletfold_leftfxm=letacc=refxiniter(funx->acc:=f!accx)m;!accletreciteri_rec_fidx(self:_tree)=matchselfwith|Empty->()|Leafa->fori=0toA.lengtha-1doletj=idxloriinfj(Array.unsafe_getai)done|Nodea->fori=0toA.lengtha-1doletidx=(idxlslnum_bits)loriiniteri_rec_fidx(Array.unsafe_getai)doneletiterif(self:'at):unit=iteri_rec_f0self.t;lettail_off=tail_offselfinfori=0toA.lengthself.tail-1dof(i+tail_off)(Array.unsafe_getself.taili)doneletreciter_rev_rec_f(self:_tree)=matchselfwith|Empty->()|Leafa->fori=A.lengtha-1downto0dof(Array.unsafe_getai)done|Nodea->fori=A.lengtha-1downto0doiter_rev_rec_f(Array.unsafe_getai)doneletiter_revf(self:'at):unit=fori=A.lengthself.tail-1downto0dof(Array.unsafe_getself.taili)done;iter_rev_rec_fself.tletreciteri_rev_rec_fidx(self:_tree)=matchselfwith|Empty->()|Leafa->fori=A.lengtha-1downto0doletj=idxloriinfj(Array.unsafe_getai)done|Nodea->fori=A.lengtha-1downto0doletidx=(idxlslnum_bits)loriiniteri_rev_rec_fidx(Array.unsafe_getai)doneletiteri_revf(self:'at):unit=lettail_off=tail_offselfinfori=A.lengthself.tail-1downto0dof(i+tail_off)(Array.unsafe_getself.taili)done;iteri_rev_rec_f(tail_off-1)self.tletfold_leftifxm=letacc=refxiniteri(funix->acc:=f!accix)m;!accletfold_revifxm=letacc=refxiniteri_rev(funix->acc:=f!accix)m;!accletfold_revfxm=letacc=refxiniter_rev(funx->acc:=f!accx)m;!accletrecmap_tf(self:_tree):_tree=matchselfwith|Empty->Empty|Nodea->leta=Array.map(map_tf)ainNodea|Leafa->Leaf(Array.mapfa)letmapf(self:_t):_t={selfwitht=map_tfself.t;tail=Array.mapfself.tail}letappendab=ifis_emptybthenaelsefold_leftpushabletrecequal_treeeqt1t2=matcht1,t2with|Empty,Empty->true|Nodea,Nodeb->A.equal(equal_treeeq)ab|Leafa,Leafb->A.equaleqab|(Empty|Leaf_|Node_),_->falseletequaleq(a:_t)(b:_t):bool=a.size=b.size&&A.equaleqa.tailb.tail&&equal_treeeqa.tb.tletadd_listvl=List.fold_leftpushvlletof_listl=add_listemptylletto_listm=fold_rev(funaccx->x::acc)[]mletadd_itervseq=letv=refvinseq(funx->v:=push!vx);!vletof_iters=add_iteremptysletto_itermyield=iteri(fun_v->yieldv)mletmakenx:_t=(* TODO: probably we can optimize that? *)of_iter(funk->for_i=1tondokxdone)letrecadd_seqselfseq=matchseq()with|Seq.Nil->self|Seq.Cons(x,tl)->add_seq(pushselfx)tlletof_seqseq=add_seqemptyseqletto_seqself:_Seq.t=letrecto_seq(stack:('atree*int)list)()=matchstackwith|[]->Seq.Nil|(Empty,_)::tl->to_seqtl()|(Leafa,i)::tlwheni<Array.lengtha->Seq.Cons(A.getai,to_seq((Leafa,i+1)::tl))|(Leaf_,_)::tl->to_seqtl()|(Nodea,i)::tlwheni<A.lengtha->to_seq((A.getai,0)::(Nodea,i+1)::tl)()|(Node_,_)::tl->to_seqtl()into_seq[self.t,0;Leafself.tail,0]letchooseself=ifself.size=0thenNoneelseSome(A.getself.tail0)modulePrivate_=structtype'aprinter=Format.formatter->'a->unitletfpf=Format.fprintfletpp_arrayppxouta=fpfout"[@[%a@]]"(Format.pp_print_list~pp_sep:(funout()->Format.fprintfout";@ ")ppx)(Array.to_lista)letrecdebugtreeppxout(self:_tree):unit=matchselfwith|Empty->fpfout"()"|Leafa->fpfout"leaf(%a)"(pp_arrayppx)a|Nodea->fpfout"node(%a)"(pp_array@@debugtreeppx)aletdebugppxoutself=fpfout"@[<v>pvec {@ size: %d; shift: %d;@ @[<2>tree:@ %a@];@ @[<2>tail:@ \
%a@]@]}"self.sizeself.shift(debugtreeppx)self.t(pp_arrayppx)self.tailend