123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242(* This file is free software, part of iter. See file "license" for more details. *)type'at=('a->unit)->unit(** Iter abstract iterator type *)type'aiter='attype'aequal='a->'a->booltype'ahash='a->int(** Build an iterator from a iter function *)letfrom_iterf=fletfrom_labelled_iteriterf=iter~fletrecfrom_funfk=matchf()with|None->()|Somex->kx;from_funfklet[@inline]empty_=()let[@inline]returnxk=kxletsingleton=returnletpure=returnlet[@inline]doubletonxyk=kx;kylet[@inline]consxlk=kx;lklet[@inline]snoclxk=lk;kxlet[@inline]repeatxk=whiletruedokxdoneletinitfyield=letrecauxi=yield(fi);aux(i+1)inaux0letreciteratefxk=kx;iteratef(fx)kletrecforeverfk=k(f());foreverfkletcyclesk=whiletruedoskdonelet[@inline]iterfseq=seqfletiterifseq=letr=ref0inseq(funx->f!rx;incrr)letfor_eachseqf=iterfseqletfor_eachiseqf=iterifseqletfoldfinitseq=letr=refinitinseq(funelt->r:=f!relt);!rletfoldifinitseq=leti=ref0inletr=refinitinseq(funelt->r:=f!r!ielt;incri);!rletfold_mapfinitseqyield=letr=refinitinseq(funx->letacc',y=f!rxinr:=acc';yieldy)letfold_filter_mapfinitseqyield=letr=refinitinseq(funx->letacc',y=f!rxinr:=acc';matchywith|None->()|Somey'->yieldy')let[@inline]mapfseqk=seq(funx->k(fx))let[@inline]mapifseqk=leti=ref0inseq(funx->k(f!ix);incri)letmap_by_2fseqk=letr=refNoneinletfy=match!rwith|None->r:=Somey|Somex->r:=None;k(fxy)inseqf;match!rwith|None->()|Somex->kxlet[@inline]filterpseqk=seq(funx->ifpxthenkx)let[@inline]appends1s2k=s1k;s2klet[@inline]append_llk=List.iter(funsub->subk)llet[@inline]concatsk=s(funs'->s'k)letflatten=concatlet[@inline]flat_mapfseqk=seq(funx->fxk)let[@inline]flat_map_lfseqk=seq(funx->List.iterk(fx))let[@unroll2]recseq_list_mapflk=matchlwith|[]->k[]|x::tail->fx(funx'->seq_list_mapftail(funtail'->k(x'::tail')))let[@inline]seq_listl=seq_list_map(funx->x)llet[@inline]filter_mapfseqk=seq(funx->matchfxwith|None->()|Somey->ky)letfilter_mapifseqk=leti=ref0inseq(funx->letj=!iinincri;matchfjxwith|None->()|Somey->ky)letfilter_countfseq=leti=ref0inseq(funx->iffxthenincri);!iletintersperseelemseqk=letfirst=reftrueinseq(funx->if!firstthenfirst:=falseelsekelem;kx)letkeep_someseqk=seq(function|Somex->kx|None->())letkeep_okseqk=seq(function|Result.Okx->kx|Result.Error_->())letkeep_errorseqk=seq(function|Result.Errorx->kx|Result.Ok_->())(** Mutable unrolled list to serve as intermediate storage *)moduleMList=structtype'anode=|Nil|Consof{a:'aarray;mutablen:int;mutabletl:'anode}(* build and call callback on every element *)letof_iter_withseqk=letchunk_size=ref8inletacc=refNilinletcur=refNilinlettail=refNilinlet[@inline]replace_tail()=match!accwith|Nil->acc:=!cur|_->(match!tailwith|Nil->()|Consr->r.tl<-!cur)inseq(funx->kx;(* callback *)match!curwith|Nil->letn=!chunk_sizeinifn<4096thenchunk_size:=2*n;cur:=Cons{a=Array.makenx;n=1;tl=Nil}|Consr->assert(r.n<Array.lengthr.a);r.a.(r.n)<-x;r.n<-succr.n;ifr.n=Array.lengthr.athen(replace_tail();tail:=!cur;cur:=Nil));replace_tail();!accletof_iterseq=of_iter_withseq(fun_->())letreciterfl=matchlwith|Nil->()|Cons{a;n;tl}->fori=0ton-1dofa.(i)done;iterftlletiterifl=letreciteriifl=matchlwith|Nil->()|Cons{a;n;tl}->forj=0ton-1dof(i+j)a.(j)done;iteri(i+n)ftliniteri0flletreciter_revfl=matchlwith|Nil->()|Cons{a;n;tl}->iter_revftl;fori=n-1downto0dofa.(i)doneletlengthl=letreclenaccl=matchlwith|Nil->acc|Cons{n;tl;_}->len(acc+n)tlinlen0l(** Get element by index *)letrecgetli=matchlwith|Nil->raise(Invalid_argument"MList.get")|Cons{a;n;_}wheni<n->a.(i)|Cons{n;tl;_}->gettl(i-n)letto_iterlk=iterkllet_to_nextargl=letcur=reflinleti=ref0in(* offset in cons *)letrecget_next_=match!curwith|Nil->None|Cons{n;tl;_}when!i=n->cur:=tl;i:=0;get_nextarg|Cons{a;_}->letx=a.(!i)inincri;Somexinget_nextletto_genl=_to_next()lletto_seql=letrecmake(l,i)()=matchlwith|Nil->Seq.Nil|Cons{n;tl;_}wheni=n->make(tl,0)()|Cons{a;_}->Seq.Cons(a.(i),make(l,i+1))inmake(l,0)endletpersistentseq=letl=MList.of_iterseqinMList.to_iterltype'alazy_state=LazySuspend|LazyCachedof'atletpersistent_lazy(seq:'at)=letr=refLazySuspendinfunk->match!rwith|LazyCachedseq'->seq'k|LazySuspend->(* here if this traversal is interruted, no caching occurs *)letseq'=MList.of_iter_withseqkinr:=LazyCached(MList.to_iterseq')letsort?(cmp=Stdlib.compare)seq=(* use an intermediate list, then sort the list *)letl=fold(funlx->x::l)[]seqinletl=List.fast_sortcmplinfunk->List.iterklletsorted?(cmp=Stdlib.compare)seq=letexceptionExit_sortedinletprev=refNoneintryseq(funx->match!prevwith|Someywhencmpyx>0->raise_notraceExit_sorted|_->prev:=Somex);truewithExit_sorted->falseletgroup_succ_by?(eq=funxy->x=y)seqk=letcur=ref[]inseq(funx->match!curwith|[]->cur:=[x]|y::_aslwheneqxy->cur:=x::l(* [x] belongs to the group *)|_::_asl->kl;(* yield group, and start another one *)cur:=[x]);(* last list *)match!curwith|[]->()|_::_asl->klletgroup_by(typek)?(hash=Hashtbl.hash)?(eq=(=))seq=letmoduleTbl=Hashtbl.Make(structtypet=kletequal=eqlethash=hashend)in(* compute group table *)lettbl=lazy(lettbl=Tbl.create32inseq(funx->letl=tryTbl.findtblxwithNot_found->[]inTbl.replacetblx(x::l));tbl)infunyield->Tbl.iter(fun_l->yieldl)(Lazy.forcetbl)letcount(typek)?(hash=Hashtbl.hash)?(eq=(=))seq=letmoduleTbl=Hashtbl.Make(structtypet=kletequal=eqlethash=hashend)in(* compute group table *)lettbl=lazy(lettbl=Tbl.create32inseq(funx->letn=tryTbl.findtblxwithNot_found->0inTbl.replacetblx(n+1));tbl)infunyield->Tbl.iter(funxn->yield(x,n))(Lazy.forcetbl)letuniq?(eq=funxy->x=y)seqk=lethas_prev=reffalseandprev=ref(Obj.magic0)in(* avoid option type, costly *)seq(funx->if!has_prev&&eq!prevxthen()(* duplicate *)else(has_prev:=true;prev:=x;kx))letsort_uniq(typeelt)?(cmp=Stdlib.compare)seq=letmoduleS=Set.Make(structtypet=eltletcompare=cmpend)inletset=fold(funaccx->S.addxacc)S.emptyseqinfunk->S.iterksetlet[@inline]productouterinnerk=outer(funx->inner(funy->k(x,y)))letrecdiagonal_llyield=matchlwith|[]->()|x::tail->List.iter(funy->yield(x,y))tail;diagonal_ltailyieldletdiagonalseq=letl=ref[]inseq(funx->l:=x::!l);diagonal_l(List.rev!l)letjoin~join_rows1s2k=s1(funa->s2(funb->matchjoin_rowabwith|None->()|Somec->kc))letjoin_by(typea)?(eq=(=))?(hash=Hashtbl.hash)f1f2~mergec1c2=letmoduleTbl=Hashtbl.Make(structtypet=aletequal=eqlethash=hashend)inlettbl=Tbl.create32inc1(funx->letkey=f1xinTbl.addtblkeyx);letres=ref[]inc2(funy->letkey=f2yinletxs=Tbl.find_alltblkeyinList.iter(funx->matchmergekeyxywith|None->()|Somez->res:=z::!res)xs);funyield->List.iteryield!restype('a,'b)join_all_cell={mutableja_left:'alist;mutableja_right:'blist;}letjoin_all_by(typea)?(eq=(=))?(hash=Hashtbl.hash)f1f2~mergec1c2=letmoduleTbl=Hashtbl.Make(structtypet=aletequal=eqlethash=hashend)inlettbl=Tbl.create32in(* build the map [key -> cell] *)c1(funx->letkey=f1xintryletc=Tbl.findtblkeyinc.ja_left<-x::c.ja_leftwithNot_found->Tbl.addtblkey{ja_left=[x];ja_right=[]});c2(funy->letkey=f2yintryletc=Tbl.findtblkeyinc.ja_right<-y::c.ja_rightwithNot_found->Tbl.addtblkey{ja_left=[];ja_right=[y]});letres=ref[]inTbl.iter(funkeycell->matchmergekeycell.ja_leftcell.ja_rightwith|None->()|Somez->res:=z::!res)tbl;funyield->List.iteryield!resletgroup_join_by(typea)?(eq=(=))?(hash=Hashtbl.hash)fc1c2=letmoduleTbl=Hashtbl.Make(structtypet=aletequal=eqlethash=hashend)inlettbl=Tbl.create32inc1(funx->Tbl.replacetblx[]);c2(funy->(* project [y] into some element of [c1] *)letkey=fyintryletl=Tbl.findtblkeyinTbl.replacetblkey(y::l)withNot_found->());funyield->Tbl.iter(funkl->yield(k,l))tblletunion(typea)?(eq=(=))?(hash=Hashtbl.hash)c1c2=letmoduleTbl=Hashtbl.Make(structtypet=aletequal=eqlethash=hashend)inlettbl=Tbl.create32inc1(funx->Tbl.replacetblx());c2(funx->Tbl.replacetblx());funyield->Tbl.iter(funx_->yieldx)tbltypeinter_status=Inter_left|Inter_bothletinter(typea)?(eq=(=))?(hash=Hashtbl.hash)c1c2=letmoduleTbl=Hashtbl.Make(structtypet=aletequal=eqlethash=hashend)inlettbl=Tbl.create32inc1(funx->Tbl.replacetblxInter_left);c2(funx->trymatchTbl.findtblxwith|Inter_left->Tbl.replacetblxInter_both(* save *)|Inter_both->()withNot_found->());funyield->Tbl.iter(funxres->ifres=Inter_boththenyieldx)tblletdiff(typea)?(eq=(=))?(hash=Hashtbl.hash)c1c2=letmoduleTbl=Hashtbl.Make(structtypet=aletequal=eqlethash=hashend)inlettbl=Tbl.create32inc2(funx->Tbl.replacetblx());funyield->c1(funx->ifnot(Tbl.memtblx)thenyieldx)letsubset(typea)?(eq=(=))?(hash=Hashtbl.hash)c1c2=letexceptionSubset_exitinletmoduleTbl=Hashtbl.Make(structtypet=aletequal=eqlethash=hashend)inlettbl=Tbl.create32inc2(funx->Tbl.replacetblx());tryc1(funx->ifnot(Tbl.memtblx)thenraise_notraceSubset_exit);truewithSubset_exit->falseletrecunfoldrfbk=matchfbwith|None->()|Some(x,b')->kx;unfoldrfb'kletscanfaccseqk=kacc;letacc=refaccinseq(funelt->letacc'=f!acceltinkacc';acc:=acc')letmax?(lt=funxy->x<y)seq=letret=refNoneinseq(funx->match!retwith|None->ret:=Somex|Somey->ifltyxthenret:=Somex);!retletmax_exn?ltseq=matchmax?ltseqwith|Somex->x|None->raise_notraceNot_foundletmin?(lt=funxy->x<y)seq=letret=refNoneinseq(funx->match!retwith|None->ret:=Somex|Somey->ifltxythenret:=Somex);!retletmin_exn?ltseq=matchmin?ltseqwith|Somex->x|None->raiseNot_foundlet[@inline]sumseq=letn=ref0inseq(funx->n:=!n+x);!n(* https://en.wikipedia.org/wiki/Kahan_summation_algorithm *)letsumfseq:float=letsum=ref0.inletc=ref0.in(* error compensation *)seq(funx->lety=x-.!cinlett=!sum+.yinc:=t-.!sum-.y;sum:=t);!sumletheadseq=letexceptionExitHeadinletr=refNoneintryseq(funx->r:=Somex;raise_notraceExitHead);NonewithExitHead->!rlethead_exnseq=matchheadseqwith|None->invalid_arg"Iter.head_exn"|Somex->xlettakenseqk=letexceptionExitTakeinletcount=ref0intryseq(funx->if!count=nthenraise_notraceExitTake;incrcount;kx)withExitTake->()lettake_whilepseqk=letexceptionExitTakeWhileintryseq(funx->ifpxthenkxelseraise_notraceExitTakeWhile)withExitTakeWhile->()letmap_whilefseqk=letexceptionExitMapWhileinletconsumex=matchfxwith|`Yieldy->ky|`Returny->ky;raise_notraceExitMapWhile|`Stop->raise_notraceExitMapWhileintryseqconsumewithExitMapWhile->()letfold_whilefsseq=letexceptionExitFoldWhileinletstate=refsinletconsumex=letacc,cont=f!statexinstate:=acc;matchcontwith|`Stop->raise_notraceExitFoldWhile|`Continue->()intryseqconsume;!statewithExitFoldWhile->!stateletdropnseqk=letcount=ref0inseq(funx->if!count>=nthenkxelseincrcount)letdrop_whilepseqk=letdrop=reftrueinseq(funx->if!dropthenifpxthen()else(drop:=false;kx)elsekx)letrevseq=letl=MList.of_iterseqinfunk->MList.iter_revklletfor_allpseq=letexceptionExitForallintryseq(funx->ifnot(px)thenraise_notraceExitForall);truewithExitForall->false(** Exists there some element satisfying the predicate? *)letexistspseq=letexceptionExitExistsintryseq(funx->ifpxthenraise_notraceExitExists);falsewithExitExists->trueletmem?(eq=(=))xseq=exists(eqx)seqletfind_mapfseq=letexceptionExitFindinletr=refNonein(tryseq(funx->matchfxwith|None->()|Some_asres->r:=res;raise_notraceExitFind)withExitFind->());!rletfind=find_mapletfind_mapifseq=letexceptionExitFindinleti=ref0inletr=refNonein(tryseq(funx->matchf!ixwith|None->incri|Some_asres->r:=res;raise_notraceExitFind)withExitFind->());!rletfindi=find_mapiletfind_predfseq=find_map(funx->iffxthenSomexelseNone)seqletfind_pred_exnfseq=matchfind_predfseqwith|Somex->x|None->raiseNot_foundlet[@inline]lengthseq=letr=ref0inseq(fun_->incrr);!rletis_emptyseq=letexceptionExitIsEmptyintryseq(fun_->raise_notraceExitIsEmpty);truewithExitIsEmpty->false(** {2 Transform an iterator} *)let[@inline]zip_iseqk=letr=ref0inseq(funx->letn=!rinincrr;k(n,x))letfold2faccseq2=letacc=refaccinseq2(fun(x,y)->acc:=f!accxy);!acclet[@inline]iter2fseq2=seq2(fun(x,y)->fxy)let[@inline]map2fseq2k=seq2(fun(x,y)->k(fxy))let[@inline]map2_2fgseq2k=seq2(fun(x,y)->k(fxy,gxy))(** {2 Basic data structures converters} *)letto_listseq=List.rev(fold(funyx->x::y)[]seq)let[@inline]to_rev_listseq=fold(funyx->x::y)[]seqlet[@inline]of_listlk=List.iterklleton_listfl=to_list(f(of_listl))letpair_with_idxseqk=letr=ref0inseq(funx->letn=!rinincrr;k(n,x))letto_opt=headlet[@inline]of_optok=matchowith|None->()|Somex->kxletto_arrayseq=letl=MList.of_iterseqinletn=MList.lengthlinifn=0then[||]else(leta=Array.maken(MList.getl0)inMList.iteri(funix->a.(i)<-x)l;a)let[@inline]of_arrayak=Array.iterkalet[@inline]of_array_iak=fori=0toArray.lengtha-1dok(i,Array.unsafe_getai)doneletarray_sliceaijk=assert(i>=0&&j<Array.lengtha);foridx=itojdoka.(idx)(* iterate on sub-array *)doneletrecof_seqlk=matchl()with|Seq.Nil->()|Seq.Cons(x,tl)->kx;of_seqtlkletto_seq_persistentseq=letl=MList.of_iterseqinMList.to_seqllet[@inline]to_stacksseq=iter(funx->Stack.pushxs)seqlet[@inline]of_stacksk=Stack.iterkslet[@inline]to_queueqseq=seq(funx->Queue.pushxq)let[@inline]of_queueqk=Queue.iterkqlet[@inline]hashtbl_addhseq=seq(fun(k,v)->Hashtbl.addhkv)lethashtbl_replacehseq=seq(fun(k,v)->Hashtbl.replacehkv)letto_hashtblseq=leth=Hashtbl.create3inhashtbl_replacehseq;hlet[@inline]of_hashtblhk=Hashtbl.iter(funab->k(a,b))hlethashtbl_keyshk=Hashtbl.iter(funa_->ka)hlethashtbl_valueshk=Hashtbl.iter(fun_b->kb)hlet[@inline]of_strsk=String.iterksletto_strseq=letb=Buffer.create64initer(func->Buffer.add_charbc)seq;Buffer.contentsbletconcat_strseq=letb=Buffer.create64initer(Buffer.add_stringb)seq;Buffer.contentsbexceptionOneShotSequenceletof_in_channelic=letfirst=reftrueinfunk->ifnot!firstthenraiseOneShotSequenceelse(first:=false;trywhiletruedoletc=input_charicinkcdonewithEnd_of_file->())letto_bufferseqbuf=seq(func->Buffer.add_charbufc)(** Iterator on integers in [start...stop] by steps 1 *)letint_range~start~stopk=fori=starttostopdokidoneletint_range_dec~start~stopk=fori=startdowntostopdokidoneletint_range_by~stepijyield=ifstep=0theninvalid_arg"int_range_by";fork=0to(j-i)/stepdoyield((k*step)+i)doneletboolsk=kfalse;ktrueletof_set(typesv)mset=letmoduleS=(valm:Set.Swithtypet=sandtypeelt=v)infunk->S.iterksetletto_set(typesv)mseq=letmoduleS=(valm:Set.Swithtypet=sandtypeelt=v)infold(funsetx->S.addxset)S.emptyseqtype'agen=unit->'aoption(* consume the generator to build a MList *)letrecof_gen1_gk=matchg()with|None->()|Somex->kx;of_gen1_gkletof_gen_onceg=letfirst=reftrueinfunk->if!firstthenfirst:=falseelseraiseOneShotSequence;of_gen1_gkletof_geng=letl=MList.of_iter(of_gen1_g)inMList.to_iterlletto_genseq=letl=MList.of_iterseqinMList.to_genl(** {2 Functorial conversions between sets and iterators} *)moduleSet=structmoduletypeS=sigincludeSet.Svalof_iter:eltiter->tvalto_iter:t->eltitervalto_list:t->eltlistvalof_list:eltlist->tvalof_seq:eltiter->t(** @deprecated use {!of_iter} instead *)valto_seq:t->eltiter(** @deprecated use {!to_iter} instead *)end(** Create an enriched Set module from the given one *)moduleAdapt(X:Set.S):Swithtypeelt=X.eltandtypet=X.t=structletto_iter_setk=X.iterksetletof_iter_seq=fold(funsetx->X.addxset)X.emptyseqincludeXletto_iter=to_iter_letof_iter=of_iter_letto_seq=to_iter_letof_seq=of_iter_letof_listl=List.fold_left(funsetx->addxset)emptylletto_list=elementsend(** Functor to build an extended Set module from an ordered type *)moduleMake(X:Set.OrderedType)=structmoduleMySet=Set.Make(X)includeAdapt(MySet)endend(** {2 Conversion between maps and iterators.} *)moduleMap=structmoduletypeS=sigincludeMap.Svalto_iter:'at->(key*'a)itervalof_iter:(key*'a)iter->'atvalkeys:'at->keyitervalvalues:'at->'aitervalto_list:'at->(key*'a)listvalof_list:(key*'a)list->'atvalto_seq:'at->(key*'a)iter(** @deprecated use {!to_iter} instead *)valof_seq:(key*'a)iter->'at(** @deprecated use {!of_iter} instead *)end(** Adapt a pre-existing Map module to make it iterator-aware *)moduleAdapt(M:Map.S)=structletto_iter_m=from_iter(funk->M.iter(funxy->k(x,y))m)letof_iter_seq=fold(funm(k,v)->M.addkvm)M.emptyseqletkeysm=from_iter(funk->M.iter(funx_->kx)m)letvaluesm=from_iter(funk->M.iter(fun_y->ky)m)[@@@ocaml.warning"-32"]letof_listl=of_iter_(of_listl)letto_listx=to_list(to_iter_x)[@@@ocaml.warning"+32"]includeMletto_iter=to_iter_letof_iter=of_iter_letto_seq=to_iter_letof_seq=of_iter_end(** Create an enriched Map module, with iterator-aware functions *)moduleMake(V:Map.OrderedType):Swithtypekey=V.t=structmoduleM=Map.Make(V)includeAdapt(M)endend(** {2 Infinite iterators of random values} *)letrandom_intbound=forever(fun()->Random.intbound)letrandom_bool=foreverRandom.boolletrandom_floatbound=forever(fun()->Random.floatbound)letrandom_arrayak=assert(Array.lengtha>0);whiletruedoleti=Random.int(Array.lengtha)inka.(i)doneletrandom_listl=random_array(Array.of_listl)(* See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle *)letshuffle_arraya=fork=Array.lengtha-1downto0+1doletl=Random.int(k+1)inlettmp=a.(l)ina.(l)<-a.(k);a.(k)<-tmpdoneletshuffleseq=leta=to_arrayseqinshuffle_arraya;of_arrayaletshuffle_buffernseqk=letseq_front=takenseqinleta=to_arrayseq_frontinletl=Array.lengthainifl<nthen(shuffle_arraya;of_arrayak)else(letseq=dropnseqinletfx=leti=Random.intninlety=a.(i)ina.(i)<-x;kyinseqf)(** {2 Sampling} *)(** See https://en.wikipedia.org/wiki/Reservoir_sampling#Algorithm_R *)letsamplekseq=matchheadseqwith|None->[||]|Somex->leta=Array.makekxinleti=ref(-1)inletfx=incri;if!i<kthena.(!i)<-xelse(letj=Random.int!iinifj<kthena.(j)<-xelse())inseqf;if!i<kthenArray.suba0(!i+1)elsea(** {2 Infix functions} *)moduleInfix=structlet[@inline](--)ij=int_range~start:i~stop:jlet[@inline](--^)ij=int_range_dec~start:i~stop:jlet[@inline](>>=)xf=flat_mapfxlet[@inline](>|=)xf=mapfxlet[@inline](<*>)funsargsk=funs(funf->args(funx->k(fx)))let(<+>)=appendlet[@inline](let+)xf=mapfxlet[@inline](let*)xf=flat_mapfxlet(and+)=productlet(and*)=productendincludeInfix(** {2 Pretty printing of iterators} *)(** Pretty print an ['a iter], using the given pretty printer
to print each elements. An optional separator string can be provided. *)letpp_seq?(sep=", ")pp_eltformatterseq=letfirst=reftrueinseq(funx->if!firstthenfirst:=falseelse(Format.pp_print_stringformattersep;Format.pp_print_cutformatter());pp_eltformatterx)letpp_buf?(sep=", ")pp_eltbufseq=letfirst=reftrueinseq(funx->if!firstthenfirst:=falseelseBuffer.add_stringbufsep;pp_eltbufx)letto_string?seppp_eltseq=letbuf=Buffer.create25inpp_buf?sep(funbufx->Buffer.add_stringbuf(pp_eltx))bufseq;Buffer.contentsbuf(** {2 Basic IO} *)moduleIO=structletlines_of?(mode=0o644)?(flags=[Open_rdonly])filenamek=letic=open_in_genflagsmodefilenameintrywhiletruedoletline=input_lineicinklinedonewith|End_of_file->close_inic|e->close_in_noerric;raiseeletchunks_of?(mode=0o644)?(flags=[])?(size=1024)filenamek=letic=open_in_genflagsmodefilenameintryletbuf=Bytes.createsizeinletn=ref0inletstop=reffalseinwhilenot!stopdon:=0;(* try to read [size] chars. If [input] returns [0] it means
the end of file, so we stop, but first we yield the current chunk *)while!n<size&¬!stopdoletn'=inputicbuf!n(size-!n)inifn'=0thenstop:=trueelsen:=!n+n'done;if!n>0thenk(Bytes.sub_stringbuf0!n)done;close_inicwithe->close_in_noerric;raiseeletwith_out_?(mode=0o644)?(flags=[Open_creat;Open_wronly])filenamef=letoc=open_out_genflagsmodefilenameintryfoc;close_outocwithe->close_outoc;raiseeletwrite_bytes_to?mode?flagsfilenameit=with_out_?mode?flagsfilename(funoc->it(funs->outputocs0(Bytes.lengths)))letwrite_to?mode?flagsfilenameseq=write_bytes_to?mode?flagsfilename(mapBytes.unsafe_of_stringseq)letwrite_bytes_lines?mode?flagsfilenameit=with_out_?mode?flagsfilename(funoc->it(funs->outputocs0(Bytes.lengths);output_charoc'\n'))letwrite_lines?mode?flagsfilenameseq=write_bytes_lines?mode?flagsfilename(mapBytes.unsafe_of_stringseq)end