123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150(* (c) Frédéric Bour
* (c) Romain Calascibetta
*)moduleTbl=struct(* XXX(dinosaure): [Tbl] is a small re-implementation
* of [Hashtbl] where [find_all] is needed by [prj]. To
* avoid an allocation of an intermediate list, we directly
* use the underlying linked-list to do the projection.
*
* This implementation wants to be:
* - deterministic (seed = 0)
* - fast
*
* Memoization is done by [last_k]/[last_v] where the common use
* of [Conduit] is a loop with multiple calls of [send]/[recv]
* with the same [flow] value.
*)type'vt={mutablesize:int;mutabledata:'vlstarray;mutablelast_k:int;mutablelast_v:'v;}and'vlst=Empty|Consof{key:int;data:'v;mutablenext:'vlst}letrecpower_2_abovexn=ifx>=nthenxelseifx*2>Sys.max_array_lengththenxelsepower_2_above(x*2)nletcreate~epsilonsize=letsize=power_2_above16sizein{size=0;data=Array.makesizeEmpty;last_k=0;last_v=epsilon}externalcaml_hash:int->int->int->'a->int="caml_hash"[@@noalloc]lethashv=caml_hash101000vletresizet=letold_data=t.datainletold_size=Array.lengthold_datainletnew_size=old_size*2inifnew_size<Sys.max_array_lengththen(letnew_data=Array.makenew_sizeEmptyinletnew_data_tail=Array.makenew_sizeEmptyint.data<-new_data;letrecinsert=function|Empty->()|Cons{key;next;_}ascell->letnew_idx=hashkeyland(new_size-1)in(matchnew_data_tail.(new_idx)with|Empty->new_data.(new_idx)<-cell|Constail->tail.next<-cell);new_data_tail.(new_idx)<-cell;insertnextinfori=0toold_size-1doinsertold_data.(i)done;fori=0tonew_size-1domatchnew_data_tail.(i)with|Empty->()|Constail->tail.next<-Emptydone)letaddtkeydata=leti=hashkeyland(Array.lengtht.data-1)inletv=Cons{key;data;next=t.data.(i)}int.data.(i)<-v;t.size<-t.size+1;ift.size>Array.lengtht.datalsl1thenresizetendmoduletypeKEY_INFO=sigtype'atendmoduleMake(Key_info:KEY_INFO)=structtypet=..type'akey='aKey_info.tmoduletypeWITNESS=sigtypeatypet+=Tofavalkey:akeyendtype'awitness=(moduleWITNESSwithtypea='a)typepack=Key:'akey->packtypevalue=Value:'a*'akey->valueletepsilon_=raise_notraceNot_foundlethandlers=Tbl.create~epsilon0x10letkeys=Hashtbl.create0x10moduleInjection(M:sigtypetvalkey:tkeyend):WITNESSwithtypea=M.t=structtypea=M.ttypet+=Tofaletkey=M.keylethandler=functionTa->Value(a,key)|_->raiseNot_foundlet()=let[@warning"-3"]uid=Stdlib.Obj.Extension_constructor.id[%extension_constructorT]inTbl.addhandlersuidhandler;Hashtbl.addkeysuid(Keykey)endletinj(typea)(key:akey):awitness=(moduleInjection(structtypet=aletkey=keyend))(* XXX(dinosaure): we ensure that a value [t : t] must have an implementation
* availble into [handlers]. By this way,
* [let[@warning "-8"] Tbl.Cons _ = lst in] is safe where we must find an
* implementation.
*)letrecitertuidlst=let[@warning"-8"](Tbl.Cons{key=k;data=f;next=r;_})=lstintryifuid<>kthenraise_notraceNot_found;handlers.Tbl.last_v<-f;ftwith_->(iter[@tailcall])tuidrletprjt=letarr=handlers.Tbl.datainletuid=Stdlib.Obj.Extension_constructor.(id(of_valt))inifhandlers.Tbl.last_k==uidthenhandlers.Tbl.last_vtelseletres=itertuidarr.(Tbl.hashuidland(Array.lengtharr-1))inhandlers.Tbl.last_k<-uid;resletbindings()=Hashtbl.fold(fun_va->v::a)keys[]end