123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403(* This file is free software, part of containers. See file "license" for more details. *)(** {1 Functional queues (fifo)} *)type'aiter=('a->unit)->unittype'aequal='a->'a->booltype'aprinter=Format.formatter->'a->unit(** {2 Basics} *)[@@@warning"-37"]typezero=Zerotype'xsucc=Succtypeone=zerosucctypetwo=zerosuccsucctypethree=zerosuccsuccsucctype(+'a,'l)digit=|Zero:('a,zero)digit|One:'a->('a,one)digit|Two:'a*'a->('a,two)digit|Three:'a*'a*'a->('a,three)digit(* store the size in deep version *)type+'at=|Shallow:('a,_)digit->'at|Deep:int*('a,_succ)digit*('a*'a)tlazy_t*('a,_succ)digit->'atletempty:typea.at=ShallowZeroexceptionEmptylet_empty=ShallowZerolet_singlex=Shallow(Onex)let_doublexy=Shallow(Two(x,y))let_deep:typel0l1.int->('a,l0succ)digit->('a*'a)tlazy_t->('a,l1succ)digit->'at=funnhdmiddletl->Deep(n,hd,middle,tl)letis_empty=function|ShallowZero->true|_->falseletsingletonx=_singlexletdoubletonxy=_doublexyletreccons:typea.a->at->at=funxq->matchqwith|ShallowZero->_singlex|Shallow(Oney)->Shallow(Two(x,y))|Shallow(Two(y,z))->Shallow(Three(x,y,z))|Shallow(Three(y,z,z'))->_deep4(Two(x,y))(lazy_empty)(Two(z,z'))|Deep(n,Oney,middle,tl)->_deep(n+1)(Two(x,y))middletl|Deep(n,Two(y,z),middle,tl)->_deep(n+1)(Three(x,y,z))middletl|Deep(n,Three(y,z,z'),(lazyq'),tail)->_deep(n+1)(Two(x,y))(lazy(cons(z,z')q'))tailletrecsnoc:typea.at->a->at=funqx->matchqwith|ShallowZero->_singlex|Shallow(Oney)->Shallow(Two(y,x))|Shallow(Two(y,z))->Shallow(Three(y,z,x))|Shallow(Three(y,z,z'))->_deep4(Two(y,z))(lazy_empty)(Two(z',x))|Deep(n,hd,middle,Oney)->_deep(n+1)hdmiddle(Two(y,x))|Deep(n,hd,middle,Two(y,z))->_deep(n+1)hdmiddle(Three(y,z,x))|Deep(n,hd,(lazyq'),Three(y,z,z'))->_deep(n+1)hd(lazy(snocq'(y,z)))(Two(z',x))letrectake_front_exn:'a.'at->'a*'at=funq->matchqwith|ShallowZero->raiseEmpty|Shallow(Onex)->x,empty|Shallow(Two(x,y))->x,Shallow(Oney)|Shallow(Three(x,y,z))->x,Shallow(Two(y,z))|Deep(n,Onex,(lazyq'),tail)->ifis_emptyq'thenx,Shallowtailelse(let(y,z),q'=take_front_exnq'inx,_deep(n-1)(Two(y,z))(Lazy.from_valq')tail)|Deep(n,Two(x,y),middle,tail)->x,_deep(n-1)(Oney)middletail|Deep(n,Three(x,y,z),middle,tail)->x,_deep(n-1)(Two(y,z))middletaillettake_frontq=trySome(take_front_exnq)withEmpty->Nonelettake_front_lnq=ifn<0theninvalid_arg"take_back_l: cannot take negative number of arguments";letrecauxaccqn=ifn=0||is_emptyqthenList.revacc,qelse(letx,q'=take_front_exnqinaux(x::acc)q'(n-1))inaux[]qnlettake_front_whilepq=letrecauxaccq=ifis_emptyqthenList.revacc,qelse(letx,q'=take_front_exnqinifpxthenaux(x::acc)q'elseList.revacc,q)inaux[]qletrectake_back_exn:'a.'at->'at*'a=funq->matchqwith|ShallowZero->raiseEmpty|Shallow(Onex)->empty,x|Shallow(Two(x,y))->_singlex,y|Shallow(Three(x,y,z))->Shallow(Two(x,y)),z|Deep(n,hd,(lazyq'),Onex)->ifis_emptyq'thenShallowhd,xelse(letq'',(y,z)=take_back_exnq'in_deep(n-1)hd(Lazy.from_valq'')(Two(y,z)),x)|Deep(n,hd,middle,Two(x,y))->_deep(n-1)hdmiddle(Onex),y|Deep(n,hd,middle,Three(x,y,z))->_deep(n-1)hdmiddle(Two(x,y)),zlettake_backq=trySome(take_back_exnq)withEmpty->Nonelettake_back_lnq=ifn<0theninvalid_arg"take_back_l: cannot take negative number of arguments";letrecauxaccqn=ifn=0||is_emptyqthenq,accelse(letq',x=take_back_exnqinaux(x::acc)q'(n-1))inaux[]qnlettake_back_whilepq=letrecauxaccq=ifis_emptyqthenq,accelse(letq',x=take_back_exnqinifpxthenaux(x::acc)q'elseq,acc)inaux[]q(** {2 Individual extraction} *)letfirstq=trySome(fst(take_front_exnq))withEmpty->Noneletfirst_exnq=fst(take_front_exnq)letlastq=trySome(snd(take_back_exnq))withEmpty->Noneletlast_exnq=snd(take_back_exnq)let_size_digit:typel.('a,l)digit->int=function|Zero->0|One_->1|Two_->2|Three_->3letsize:'a.'at->int=function|Shallowd->_size_digitd|Deep(n,_,_,_)->nlet_nth_digit:typel.int->('a,l)digit->'a=funid->matchi,dwith|_,Zero->raiseNot_found|0,Onex->x|0,Two(x,_)->x|1,Two(_,x)->x|0,Three(x,_,_)->x|1,Three(_,x,_)->x|2,Three(_,_,x)->x|_,_->raiseNot_foundletrecnth_exn:'a.int->'at->'a=funiq->matchi,qwith|_,ShallowZero->raiseNot_found|0,Shallow(Onex)->x|0,Shallow(Two(x,_))->x|1,Shallow(Two(_,x))->x|0,Shallow(Three(x,_,_))->x|1,Shallow(Three(_,x,_))->x|2,Shallow(Three(_,_,x))->x|_,Shallow_->raiseNot_found|_,Deep(_,l,q,r)->ifi<_size_digitlthen_nth_digitilelse(leti'=i-_size_digitlinletq'=Lazy.forceqinifi'<2*sizeq'then(letx,y=nth_exn(i'/2)q'inifi'mod2=0thenxelsey)else_nth_digit(i'-(2*sizeq'))r)letnthiq=trySome(nth_exniq)withFailure_->Noneletinitq=tryfst(take_back_exnq)withEmpty->qlettailq=trysnd(take_front_exnq)withEmpty->qletadd_iter_frontseqq=letl=ref[]in(* reversed seq *)seq(funx->l:=x::!l);List.fold_left(funqx->consxq)q!lletadd_iter_backqseq=letq=refqinseq(funx->q:=snoc!qx);!qlet_digit_to_iter:typel.('a,l)digit->'aiter=fundk->matchdwith|Zero->()|Onex->kx|Two(x,y)->kx;ky|Three(x,y,z)->kx;ky;kzletrecto_iter:'a.'at->'aiter=funqk->matchqwith|Shallowd->_digit_to_iterdk|Deep(_,hd,(lazyq'),tail)->_digit_to_iterhdk;to_iterq'(fun(x,y)->kx;ky);_digit_to_itertailkletappendq1q2=matchq1,q2with|ShallowZero,_->q2|_,ShallowZero->q1|_->add_iter_backq1(to_iterq2)letadd_seq_frontseqq=(* reversed seq *)letl=Seq.fold_left(funlelt->elt::l)[]seqinList.fold_left(funqx->consxq)qlletadd_seq_backqseq=Seq.fold_left(funqx->snocqx)qseqlet_digit_to_seq:typel.('a,l)digit->'aSeq.t=fund()->matchdwith|Zero->Seq.Nil|Onex->Seq.Cons(x,Seq.empty)|Two(x,y)->Seq.Cons(x,Seq.returny)|Three(x,y,z)->Seq.Cons(x,fun()->Seq.Cons(y,Seq.returnz))letrecto_seq:'a.'at->'aSeq.t=funq->matchqwith|Shallowd->_digit_to_seqd|Deep(_,hd,(lazyq'),tail)->CCSeq.append(_digit_to_seqhd)(CCSeq.append(Seq.flat_map(fun(x,y)()->Seq.Cons(x,Seq.returny))(to_seqq'))(_digit_to_seqtail))letof_seqseq=add_seq_frontseqemptylet_map_digit:typel.('a->'b)->('a,l)digit->('b,l)digit=funfd->matchdwith|Zero->Zero|Onex->One(fx)|Two(x,y)->Two(fx,fy)|Three(x,y,z)->Three(fx,fy,fz)letrecmap:'a'b.('a->'b)->'at->'bt=funfq->matchqwith|Shallowd->Shallow(_map_digitfd)|Deep(size,hd,(lazyq'),tl)->letq''=map(fun(x,y)->fx,fy)q'in_deepsize(_map_digitfhd)(Lazy.from_valq'')(_map_digitftl)let(>|=)qf=mapfqlet_fold_digit:typel.('acc->'a->'acc)->'acc->('a,l)digit->'acc=funfaccd->matchdwith|Zero->acc|Onex->faccx|Two(x,y)->f(faccx)y|Three(x,y,z)->f(f(faccx)y)zletrecfold:'a'b.('b->'a->'b)->'b->'at->'b=funfaccq->matchqwith|Shallowd->_fold_digitfaccd|Deep(_,hd,(lazyq'),tl)->letacc=_fold_digitfacchdinletacc=fold(funacc(x,y)->f(faccx)y)accq'in_fold_digitfacctlletiterfq=to_iterqfletof_listl=List.fold_leftsnocemptylletto_listq=letl=ref[]into_iterq(funx->l:=x::!l);List.rev!lletof_iterseq=add_iter_frontseqemptyletrevq=letq'=refemptyiniter(funx->q':=consx!q')q;!q'letrec_equal_seqeql1l2=matchl1(),l2()with|Seq.Nil,Seq.Nil->true|Seq.Nil,_|_,Seq.Nil->false|Seq.Cons(x1,l1'),Seq.Cons(x2,l2')->eqx1x2&&_equal_seqeql1'l2'letequaleqq1q2=_equal_seqeq(to_seqq1)(to_seqq2)let(--)ab=letrecup_toqab=ifa=bthensnocqaelseup_to(snocqa)(a+1)banddown_toqab=ifa=bthensnocqaelsedown_to(snocqa)(a-1)binifa<=bthenup_toemptyabelsedown_toemptyablet(--^)ab=ifa=bthenemptyelseifa<bthena--(b-1)elsea--(b+1)letpppp_xoutd=letfirst=reftrueinFormat.fprintfout"@[<hov2>queue {";iter(funx->if!firstthenfirst:=falseelseFormat.fprintfout";@ ";pp_xoutx)d;Format.fprintfout"}@]"