123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372(**************************************************************************)(* *)(* OCaml *)(* *)(* Damien Doligez, projet Para, INRIA Rocquencourt *)(* *)(* Copyright 1997 Institut National de Recherche en Informatique et *)(* en Automatique. *)(* *)(* All rights reserved. This file is distributed under the terms of *)(* the GNU Lesser General Public License version 2.1, with the *)(* special exception on linking described in the file LICENSE. *)(* *)(**************************************************************************)(** Weak array operations *)type'atexternalcreate:int->'at="caml_weak_create"letcreatel=ifnot(0<=l&&l<=Obj.Ephemeron.max_ephe_length)theninvalid_arg("Weak.create");createl(** number of additional values in a weak pointer *)letadditional_values=2letlengthx=Obj.size(Obj.reprx)-additional_valuesletraise_if_invalid_offseteomsg=ifnot(0<=o&&o<lengthe)theninvalid_arg(msg)externalset':'at->int->'a->unit="caml_ephe_set_key"externalunset:'at->int->unit="caml_ephe_unset_key"letseteox=raise_if_invalid_offseteo"Weak.set";matchxwith|None->unseteo|Somex->set'eoxexternalget:'at->int->'aoption="caml_weak_get"letgeteo=raise_if_invalid_offseteo"Weak.get";geteoexternalget_copy:'at->int->'aoption="caml_weak_get_copy"letget_copyeo=raise_if_invalid_offseteo"Weak.get_copy";get_copyeoexternalcheck:'at->int->bool="caml_weak_check"letcheckeo=raise_if_invalid_offseteo"Weak.check";checkeoexternalblit:'at->int->'at->int->int->unit="caml_weak_blit"(* blit: src srcoff dst dstoff len *)letblite1o1e2o2l=ifl<0||o1<0||o1>lengthe1-l||o2<0||o2>lengthe2-ltheninvalid_arg"Weak.blit"elseifl<>0thenblite1o1e2o2lletfillarofslenx=ifofs<0||len<0||ofs>lengthar-lenthenraise(Invalid_argument"Weak.fill")elsebeginfori=ofsto(ofs+len-1)dosetarixdoneend(** Weak hash tables *)moduletypeS=sigtypedatatypetvalcreate:int->tvalclear:t->unitvalmerge:t->data->datavaladd:t->data->unitvalremove:t->data->unitvalfind:t->data->datavalfind_opt:t->data->dataoptionvalfind_all:t->data->datalistvalmem:t->data->boolvaliter:(data->unit)->t->unitvalfold:(data->'a->'a)->t->'a->'avalcount:t->intvalstats:t->int*int*int*int*int*intendmoduleMake(H:Hashtbl.HashedType):(Swithtypedata=H.t)=structtype'aweak_t='atletweak_create=createletemptybucket=weak_create0typedata=H.ttypet={mutabletable:dataweak_tarray;mutablehashes:intarrayarray;mutablelimit:int;(* bucket size limit *)mutableoversize:int;(* number of oversize buckets *)mutablerover:int;(* for internal bookkeeping *)}letget_indexth=(hlandmax_int)mod(Array.lengtht.table)letlimit=7letover_limit=2letcreatesz=letsz=ifsz<7then7elseszinletsz=ifsz>Sys.max_array_lengththenSys.max_array_lengthelseszin{table=Array.makeszemptybucket;hashes=Array.makesz[||];limit=limit;oversize=0;rover=0;}letcleart=fori=0toArray.lengtht.table-1dot.table.(i)<-emptybucket;t.hashes.(i)<-[||];done;t.limit<-limit;t.oversize<-0letfoldftinit=letrecfold_bucketibaccu=ifi>=lengthbthenaccuelsematchgetbiwith|Somev->fold_bucket(i+1)b(fvaccu)|None->fold_bucket(i+1)baccuinArray.fold_right(fold_bucket0)t.tableinitletiterft=letreciter_bucketib=ifi>=lengthbthen()elsematchgetbiwith|Somev->fv;iter_bucket(i+1)b|None->iter_bucket(i+1)binArray.iter(iter_bucket0)t.tableletiter_weakft=letreciter_bucketijb=ifi>=lengthbthen()elsematchcheckbiwith|true->fbt.hashes.(j)i;iter_bucket(i+1)jb|false->iter_bucket(i+1)jbinArray.iteri(iter_bucket0)t.tableletreccount_bucketibaccu=ifi>=lengthbthenaccuelsecount_bucket(i+1)b(accu+(ifcheckbithen1else0))letcountt=Array.fold_right(count_bucket0)t.table0letnext_szn=min(3*n/2+3)Sys.max_array_lengthletprev_szn=((n-3)*2+2)/3lettest_shrink_buckett=letbucket=t.table.(t.rover)inlethbucket=t.hashes.(t.rover)inletlen=lengthbucketinletprev_len=prev_szleninletlive=count_bucket0bucket0iniflive<=prev_lenthenbeginletrecloopij=ifj>=prev_lenthenbeginifcheckbucketithenloop(i+1)jelseifcheckbucketjthenbeginblitbucketjbucketi1;hbucket.(i)<-hbucket.(j);loop(i+1)(j-1);endelseloopi(j-1);end;inloop0(lengthbucket-1);ifprev_len=0thenbegint.table.(t.rover)<-emptybucket;t.hashes.(t.rover)<-[||];endelsebeginletnewbucket=weak_createprev_leninblitbucket0newbucket0prev_len;t.table.(t.rover)<-newbucket;t.hashes.(t.rover)<-Array.subhbucket0prev_lenend;iflen>t.limit&&prev_len<=t.limitthent.oversize<-t.oversize-1;end;t.rover<-(t.rover+1)mod(Array.lengtht.table)letrecresizet=letoldlen=Array.lengtht.tableinletnewlen=next_szoldleninifnewlen>oldlenthenbeginletnewt=createnewleninletadd_weakobohoi=letsetternbni_=blitoboinbni1inleth=oh.(oi)inadd_auxnewtsetterNoneh(get_indexnewth);initer_weakadd_weakt;t.table<-newt.table;t.hashes<-newt.hashes;t.limit<-newt.limit;t.oversize<-newt.oversize;t.rover<-t.rovermodArray.lengthnewt.table;endelsebegint.limit<-max_int;(* maximum size already reached *)t.oversize<-0;endandadd_auxtsetterdhindex=letbucket=t.table.(index)inlethashes=t.hashes.(index)inletsz=lengthbucketinletrecloopi=ifi>=szthenbeginletnewsz=min(3*sz/2+3)(Sys.max_array_length-additional_values)inifnewsz<=szthenfailwith"Weak.Make: hash bucket cannot grow more";letnewbucket=weak_createnewszinletnewhashes=Array.makenewsz0inblitbucket0newbucket0sz;Array.blithashes0newhashes0sz;setternewbucketszd;newhashes.(sz)<-h;t.table.(index)<-newbucket;t.hashes.(index)<-newhashes;ifsz<=t.limit&&newsz>t.limitthenbegint.oversize<-t.oversize+1;for_i=0toover_limitdotest_shrink_buckettdone;end;ift.oversize>Array.lengtht.table/over_limitthenresizet;endelseifcheckbucketithenbeginloop(i+1)endelsebeginsetterbucketid;hashes.(i)<-h;end;inloop0letaddtd=leth=H.hashdinadd_auxtset(Somed)h(get_indexth)letfind_ortdifnotfound=leth=H.hashdinletindex=get_indexthinletbucket=t.table.(index)inlethashes=t.hashes.(index)inletsz=lengthbucketinletrecloopi=ifi>=szthenifnotfoundhindexelseifh=hashes.(i)thenbeginmatchget_copybucketiwith|SomevwhenH.equalvd->beginmatchgetbucketiwith|Somev->v|None->loop(i+1)end|_->loop(i+1)endelseloop(i+1)inloop0letmergetd=find_ortd(funhindex->add_auxtset(Somed)hindex;d)letfindtd=find_ortd(fun_h_index->raiseNot_found)letfind_opttd=leth=H.hashdinletindex=get_indexthinletbucket=t.table.(index)inlethashes=t.hashes.(index)inletsz=lengthbucketinletrecloopi=ifi>=szthenNoneelseifh=hashes.(i)thenbeginmatchget_copybucketiwith|SomevwhenH.equalvd->beginmatchgetbucketiwith|Some_asv->v|None->loop(i+1)end|_->loop(i+1)endelseloop(i+1)inloop0letfind_shadowtdiffoundifnotfound=leth=H.hashdinletindex=get_indexthinletbucket=t.table.(index)inlethashes=t.hashes.(index)inletsz=lengthbucketinletrecloopi=ifi>=szthenifnotfoundelseifh=hashes.(i)thenbeginmatchget_copybucketiwith|SomevwhenH.equalvd->iffoundbucketi|_->loop(i+1)endelseloop(i+1)inloop0letremovetd=find_shadowtd(funwi->setwiNone)()letmemtd=find_shadowtd(fun_w_i->true)falseletfind_alltd=leth=H.hashdinletindex=get_indexthinletbucket=t.table.(index)inlethashes=t.hashes.(index)inletsz=lengthbucketinletrecloopiaccu=ifi>=szthenaccuelseifh=hashes.(i)thenbeginmatchget_copybucketiwith|SomevwhenH.equalvd->beginmatchgetbucketiwith|Somev->loop(i+1)(v::accu)|None->loop(i+1)accuend|_->loop(i+1)accuendelseloop(i+1)accuinloop0[]letstatst=letlen=Array.lengtht.tableinletlens=Array.maplengtht.tableinArray.sortcomparelens;lettotlen=Array.fold_left(+)0lensin(len,countt,totlen,lens.(0),lens.(len/2),lens.(len-1))end