123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334(* Copyright (c) 2015-2016 David Kaloper Meršinjak. All rights reserved.
See LICENSE.md *)moduletypeWeighted=sigtypetvalweight:t->intendletinvalid_argfmt=Format.ksprintfinvalid_argfmttype'afmt=Format.formatter->'a->unitletpf=Format.fprintfletpp_iter?(sep=Format.pp_print_space)ppppfi=letfirst=reftrueini@@funx->(match!firstwithtrue->first:=false|_->sepppf());ppppfxletcap_makes_sense~m~fcap=ifcap<0theninvalid_arg"Lru.%s.%s: ~cap:%d"mfcapmoduleF=structmoduletypeS=sigtypettypektypevvalempty:int->tvalis_empty:t->boolvalsize:t->intvalweight:t->intvalcapacity:t->intvalresize:int->t->tvaltrim:t->tvalmem:k->t->boolvalfind:k->t->voptionvalpromote:k->t->tvaladd:k->v->t->tvalremove:k->t->tvalpop:k->t->(v*t)optionvallru:t->(k*v)optionvaldrop_lru:t->tvalpop_lru:t->((k*v)*t)optionvalfold:(k->v->'a->'a)->'a->t->'avalfold_k:(k->v->'a->'a)->'a->t->'avaliter:(k->v->unit)->t->unitvaliter_k:(k->v->unit)->t->unitvalof_list:(k*v)list->tvalto_list:t->(k*v)listvalpp:?pp_size:(int*int)fmt->?sep:unitfmt->(k*v)fmt->tfmtvalpp_dump:kfmt->vfmt->tfmtendmoduleMake(K:Map.OrderedType)(V:Weighted)=structmoduleQ=Psq.Make(K)(structtypet=int*V.tletcompare(g1,_)(g2,_)=compare(g1:int)g2end)typek=K.ttypev=V.ttypet={cap:int;w:int;gen:int;q:Q.t}letg0=min_intletis_emptyt=Q.is_emptyt.qletsizet=Q.sizet.qletweightt=t.wletcapacityt=t.capletcap_makes_sense=cap_makes_sense~m:"F"letemptycap=cap_makes_sense~f:"empty"cap;{cap;w=0;gen=g0;q=Q.empty}letresizecapt=cap_makes_sense~f:"resize"cap;{twithcap}letmemkt=Q.memkt.qletfindkt=matchQ.findkt.qwithSome(_,v)->Somev|_->Nonelettrimt=letrecgotwq=ifw>t.capthenmatchQ.popqwithSome((_,(_,v)),q)->got(w-V.weightv)q|None->assertfalseelse{twithw;q}inift.w>t.capthengott.wt.qelsetletpromotek({gen;_}ast)=ifgen=max_intthenemptyt.capelse{twithgen=gen+1;q=Q.adjustk(fun(_,v)->gen,v)t.q}letrecaddkv({gen;_}ast)=ifgen=max_intthenaddkv(emptyt.cap)elseletp=Some(gen,v)andp0=refNoneinletq=Q.updatek(funx->p0:=x;p)t.qinletw=t.w+V.weightv-(match!p0withSome(_,v0)->V.weightv0|_->0)in{twithgen=gen+1;w;q}letremovekt=matchQ.findkt.qwithNone->t|Some(_,v)->{twithw=t.w-V.weightv;q=Q.removekt.q}letpopkt=matchQ.findkt.qwithNone->None|Some(_,v)->Some(v,{twithw=t.w-V.weightv;q=Q.removekt.q})letlrut=matchQ.mint.qwithSome(k,(_,v))->Some(k,v)|_->Noneletpop_lrut=matchQ.popt.qwithNone->None|Some((k,(_,v)),q)->Some((k,v),{twithw=t.w-V.weightv;q})letdrop_lrut=matchQ.popt.qwithNone->t|Some((_,(_,v)),q)->{twithw=t.w-V.weightv;q}letsort_uniq_rxs=letrecsievek0kv0=function|[]->[kv0]|(k,_askv)::kvswhenK.comparek0k=0->sievekkvkvs|(k,_askv)::kvs->kv0::sievekkvkvsinletcmp(k1,(g1,_))(k2,(g2,_))=matchK.comparek1k2with0->compare(g1:int)g2|r->rinmatchList.sortcmpxswith[]->[]|(k,_askv)::kvs->sievekkvkvsletof_listxs=letrecannotategacc=function|(k,v)::kvs->annotate(succg)((k,(g,v))::acc)kvs|[]->g,sort_uniq_raccinletgen,kgvs=annotateg0[]xsinletq=Q.of_sorted_listkgvsinletw=Q.fold(fun_(_,v)w->w+V.weightv)0qin{cap=w;w;gen;q}letfoldfzt=List.fold_right(fun(k,(_,v))acc->fkvacc)(Q.to_priority_listt.q)zletiterft=Q.to_priority_listt.q|>List.iter(fun(k,(_,v))->fkv)letto_listt=fold(funkvkvs->(k,v)::kvs)[]tletfold_kfzt=Q.fold(funk(_,v)->fkv)zt.qletiter_kft=Q.iter(funk(_,v)->fkv)t.qletpp?(pp_size=fun_->ignore)?sepppppft=letppxppf(k,(_,v))=ppppf(k,v)inpfppf"@[%a@[%a@]@]"pp_size(t.w,t.cap)(pp_iter?sepppx)(funf->List.iterf(Q.to_priority_listt.q))letpp_dumpppkppvppf=letsepppf()=pfppf";@ "andppkvppf(k,v)=pfppf"(@[%a,@ %a@])"ppkkppvvinpfppf"of_list [%a]"(pp~sepppkv)endendmoduleM=structmoduleQ=structtype'anode={value:'a;mutablenext:'anodeoption;mutableprev:'anodeoption}type'at={mutablefirst:'anodeoption;mutablelast:'anodeoption}letdetachtn=letnp=n.prevandnn=n.nextin(matchnpwith|None->t.first<-nn|Somex->x.next<-nn;n.prev<-None);(matchnnwith|None->t.last<-np|Somex->x.prev<-np;n.next<-None)letappendtn=leton=Someninmatcht.lastwith|Somexasl->x.next<-on;t.last<-on;n.prev<-l|None->t.first<-on;t.last<-onletnodex={value=x;prev=None;next=None}letcreate()={first=None;last=None}letiterft=letrecgof=functionSomen->fn.value;gofn.next|_->()ingoft.firstletfoldftz=letrecgofz=functionSomen->gof(fn.valuez)n.prev|_->zingofzt.lastendmoduletypeS=sigtypettypektypevvalcreate:?random:bool->int->tvalis_empty:t->boolvalsize:t->intvalweight:t->intvalcapacity:t->intvalresize:int->t->unitvaltrim:t->unitvalmem:k->t->boolvalfind:k->t->voptionvalpromote:k->t->unitvaladd:k->v->t->unitvalremove:k->t->unitvallru:t->(k*v)optionvaldrop_lru:t->unitvalfold:(k->v->'a->'a)->'a->t->'avaliter:(k->v->unit)->t->unitvalof_list:(k*v)list->tvalto_list:t->(k*v)listvalpp:?pp_size:(int*int)fmt->?sep:unitfmt->(k*v)fmt->tfmtvalpp_dump:kfmt->vfmt->tfmtendmoduleBake(HT:Hashtbl.SeededS)(V:Weighted)=structtypek=HT.keytypev=V.ttypet={ht:(k*v)Q.nodeHT.t;q:(k*v)Q.t;mutablecap:int;mutablew:int;}letsizet=HT.lengtht.htletweightt=t.wletcapacityt=t.capletis_emptyt=HT.lengtht.ht=0letcap_makes_sense=cap_makes_sense~m:"M"letcreate?randomcap=cap_makes_sense~f:"create"cap;{cap;w=0;ht=HT.create?randomcap;q=Q.create()}letlrut=matcht.q.Q.firstwithSomen->Somen.Q.value|_->Noneletdrop_lrut=matcht.q.Q.firstwithNone->()|Some({Q.value=(k,v);_}asn)->t.w<-t.w-V.weightv;HT.removet.htk;Q.detacht.qnletrectrimt=ifweightt>t.capthen(drop_lrut;trimt)letresizecapt=cap_makes_sense~f:"resize"cap;t.cap<-capletremovekt=tryletn=HT.findt.htkint.w<-t.w-(sndn.Q.value|>V.weight);HT.removet.htk;Q.detacht.qnwithNot_found->()letaddkvt=removekt;letn=Q.node(k,v)int.w<-t.w+V.weightv;HT.addt.htkn;Q.appendt.qnletpromotekt=tryletn=HT.findt.htkinQ.(detacht.qn;appendt.qn)withNot_found->()letfindkt=trySome(snd(HT.findt.htk).Q.value)withNot_found->Noneletmemkt=HT.memt.htkletiterft=Q.iter(fun(k,v)->fkv)t.qletfoldfzt=Q.fold(fun(k,v)a->fkva)t.qzletto_listt=Q.fold(funxxs->x::xs)t.q[]letof_listxs=lett=create0inList.iter(fun(k,v)->addkvt)xs;resize(Q.fold(fun(_,v)w->w+V.weightv)t.q0)t;tletpp?(pp_size=fun_->ignore)?sepppppft=pfppf"@[%a@[%a@]@]"pp_size(t.w,t.cap)(pp_iter?seppp)(funf->Q.iterft.q)letpp_dumpppkppvppf=letsepppf()=pfppf";@ "andppkvppf(k,v)=pfppf"(@[%a,@ %a@])"ppkkppvvinpfppf"of_list [%a]"(pp~sepppkv)endmoduleMake(K:Hashtbl.HashedType)(V:Weighted)=Bake(Hashtbl.MakeSeeded(structincludeKlethash_=hashletseeded_hash=hash[@@ocaml.warning"-32"]end))(V)moduleMakeSeeded(K:Hashtbl.SeededHashedType)(V:Weighted)=Bake(Hashtbl.MakeSeeded(K))(V)endletmemo(typek)(typev)?(hashed=(Hashtbl.hash,(=)))?(weight=fun_->1)~capf=letmoduleC=M.Make(structtypet=klethash=fsthashedletequal=sndhashedend)(structtypet=vletweight=weightend)inletc=C.createcapinletrecgk=matchC.findkcwithNone->letv=fgkinC.addkvc;v|Somev->C.promotekc;ving