12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088(*
* BatHashtbl, extra functions over hashtables.
* Copyright (C) 1996 Xavier Leroy
* 2003 Nicolas Cannasse
* 2005 Damien Doligez
* 2009 David Rajchenbach-Teller, LIFO, Universite d'Orleans
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version,
* with the special exception on linking described in file LICENSE.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*)(** {6 Import the contents of {!Hashtbl}}
Note: We can't directly [include Hashtbl] as this would cause a
collision on [Make]*)type('a,'b)t=('a,'b)Hashtbl.tletcreates=Hashtbl.createsletclear=Hashtbl.clearletreset=Hashtbl.resetletadd=Hashtbl.addletcopy=Hashtbl.copyletfind=Hashtbl.findletfind_all=Hashtbl.find_allletmem=Hashtbl.memletremove=Hashtbl.removeletreplace=Hashtbl.replaceletiter=Hashtbl.iterletfold=Hashtbl.foldlethash=Hashtbl.hashtype statistics=Hashtbl.statisticsletstats=Hashtbl.stats##V>=4.07##letto_seq=Hashtbl.to_seq##V>=4.07##letto_seq_keys=Hashtbl.to_seq_keys##V>=4.07##letto_seq_values=Hashtbl.to_seq_values##V>=4.07##letadd_seq =Hashtbl.add_seq##V>=4.07##letreplace_seq =Hashtbl.replace_seq##V>=4.07##letof_seq=Hashtbl.of_seq##V>=5.5##letfind_and_remove =Hashtbl.find_and_remove##V>=5.5##letfind_and_replace=Hashtbl.find_and_replacetype('a,'b)h_bucketlist =|Empty|Consof'a*'b*('a,'b)h_bucketlisttype('a,'b)h_t={mutable size:int;mutable data:('a,'b)h_bucketlist array;##V>=4##mutableseed:int;##V>=4##initial_size:int;}externalh_conv :('a,'b)t->('a,'b)h_t="%identity"external h_make:('a,'b)h_t->('a,'b)t="%identity"##V>=4##letkey_indexhkey=##V>=4## ifObj.size (Obj.reprh)>=3##V>=4##thenHashtbl.seeded_hash(h_convh).seedkey##V>=4##land(Array.length(h_convh).data-1)##V>=4##else(Hashtbl.hashkeylandmax_int)mod(Array.length(h_convh).data)##V<4##letkey_indexhkey=(Hashtbl.hashkeylandmax_int)##V<4##mod(Array.length(h_convh).data)(* NOT EXPOSED
let resize hashfun tbl =
let odata = tbl.data in
let osize = Array.length odata in
let nsize = min (2 * osize + 1) Sys.max_array_length in
if nsize <> osize then (
let ndata = Array.create nsize Empty in
let rec insert_bucket = function
Empty -> ()
| Cons(key, data, rest) ->
insert_bucket rest; (* preserve original order of elements *)
let nidx = (hashfun key) mod nsize in
ndata.(nidx) <- Cons(key, data, ndata.(nidx)) in for i = 0 to osize - 1 do
insert_bucket odata.(i)
done;
tbl.data <- ndata;
)
*)letenumh=letrecmakeiposibuckidataicount=letpos=refiposinletbuck=refibuckinlethdata=refidatainlethcount=reficountinletforce()=(* this is a hack in order to keep an O(1)enum constructor **)if!hcount=-1then(hcount :=(h_convh).size;hdata:=Array.copy(h_convh).data;);inletrecnext()=force();match!buckwith|Empty->if!hcount =0thenraiseBatEnum.No_more_elements;incrpos;buck:=Array.unsafe_get!hdata!pos;next()|Cons(k,i,next_buck)->buck :=next_buck;decrhcount;(k,i)inletcount()=if!hcount =-1then(h_convh).size else!hcountinletclone()=force();make!pos!buck!hdata!hcountinBatEnum.make~next~count~cloneinmake(-1)Empty(Obj.magic())(-1)letto_listht=fold(funkvacc->(k,v)::acc)ht[](*$T to_list
let ht = create 1 in \
add ht 1 '2'; \
to_list ht = [(1, '2')]
*)letof_listl=let res=create11inList.iter(fun(k,v)->addreskv)l;res(*$T of_list
let l = [(1,2);(2,3);(3,4)] in \
List.sort compare (to_list (of_list l)) = l
*)letbindingsht=to_listht(*$T bindings
let ht = create 1 in \
add ht 1 '2'; \
bindings ht =[(1, '2')]
*)letkeysh=BatEnum.map(fun(k,_)->k)(enumh)letvaluesh=BatEnum.map(fun(_,v)->v)(enumh)letmapfh=letrecloop=function|Empty->Empty|Cons(k,v,next)->Cons(k,fkv,loopnext)inlethc=h_convhinh_make{hcwithdata=Array.maploophc.data;}(*$T map
(* non regression test forbug #354 *) \
let h =create 20 and k = (0,5) in add h k 3 ; \
let h2 = map (fun _ v -> v) h in mem h2 k
*)letmap_inplacefh=letrecloop=function|Empty->Empty|Cons(k,v,next)->Cons(k,fkv,loopnext)inBatArray.modifyloop(h_convh).data(* Helper functions to test hashtables which values are integers: *)(*$inject
let (|>) x f = f x
let printer = IO.to_string (List.print Int.print)
let to_sorted_list h = values h |> List.of_enum |> List.sort Int.compare
*)(*$= map_inplace & ~printer
(let h = Enum.combine (1 -- 5) (1 -- 5) |>of_enum in \
map_inplace (fun _ x -> x+1) h ; \
to_sorted_list h) [2;3;4;5;6]
*)letremove_allhkey=lethc=h_conv hinletrecloop=function|Empty->Empty|Cons(k,v,next)->ifk=key then(hc.size<-predhc.size;loopnext)elseCons(k,v,loop next)inletpos=key_indexhkeyinArray.unsafe_sethc.datapos(loop (Array.unsafe_gethc.data pos))letfind_default hkeydefval=letrecloop=function|Empty->defval|Cons(k,v,next)->ifk=keythenvelseloopnextinletpos=key_indexhkeyinloop(Array.unsafe_get(h_convh).datapos)letfind_optionhkey=letrecloop=function|Empty->None|Cons(k,v,next)->ifk=keythenSomevelseloopnextinletpos=key_indexhkeyinloop(Array.unsafe_get(h_convh).datapos)letfind_opt=find_optionexceptionVerifiedletexistspht=tryiter(funkv->ifpkvthenraiseVerified)ht;falsewithVerified ->true(*$T exists
exists (fun k v -> k = v)(of_list [(1,2);(2,3);(3,3)])
not(exists (fun k v -> k = v) (of_list []))
*)letof_enume=leth=create(ifBatEnum.fast_countethenBatEnum.counteelse0)inBatEnum.iter(fun(k,v)->addhkv)e;hletlengthh=(h_convh).sizeletis_emptyh=lengthh=0exceptionHashtbl_key_not_foundletmodify_optkeyfh=lethc=h_convhinletrecloop=function(* Inserting an element might require a resize of the hash table.
Werely on Hashtbl.addfunction to grow the hashtbl if needed
instead of duplicating logic from the OCaml standard library. *)|Empty->raiseHashtbl_key_not_found|Cons(k,v,next)->if k=keythenmatch f(Somev)with|Somev->Cons(key,v,next)|None->hc.size<-predhc.size;nextelseCons(k,v,loopnext)intryletpos=key_indexhkeyinArray.unsafe_sethc.datapos(loop(Array.unsafe_gethc.datapos))with|Hashtbl_key_not_found->beginmatchfNonewith|None->()|Somev->(* Add the element to make sure the hashtbl is grown correctly if
needed. *)addhkeyvend(*$T modify_opt
let h = create 3 in \
modify_opt "foo" (function None -> Some 0 | _ -> assert false) h; \
length h = 1 && find_optionh"foo" = Some 0
let h = create 3 in \
add h "foo" 1; \
modify_opt "foo" (function Some 1 ->None | _ -> assert false) h; \
length h = 0 && find_option h "foo" = None
*)letmodifykeyfh=lethc=h_convhinletrecloop=function|Empty->raiseNot_found|Cons(k,v,next)->ifk=keythen(Cons(key,fv,next))elseCons(k,v,loopnext)inletpos=key_indexhkeyinArray.unsafe_sethc.datapos(loop(Array.unsafe_gethc.datapos))(*$T modify
let h = create 3 in \
add h"foo"1; add h "bar" 2; \
modify "foo" succ h; \ values h |> List.of_enum =[ 2; 2 ]
let h = create 3in \
try modify "baz" succ h; false \
with Not_found -> true
*)letmodify_defv0keyfh=letf'=function|None->Some(fv0)|Somev->Some(fv)inmodify_optkeyf'h(*$T modify_def
let h = create 3 in \ modify_def 0 "foo" succ h; \
length h = 1 && find_option h "foo"= Some1
*)letprint?(first="{\n")?(last="\n}")?(sep=",\n")?(kvsep=": ")print_kprint_voutt=BatEnum.print~first~last~sep(funout(k,v)->BatPrintf.fprintfout"%a%s%a"print_kkkvsepprint_vv)out(enumt)letfilteri(f:'key->'a->bool)(t:('key,'a)t)=letresult=create16initer(funka->iffkathen addresultka)t;resultletfilteri_inplace fh=lethc=h_convhinletrecloop=function|Empty->Empty|Cons(k,v,next)->iffkvthenCons(k,v,loopnext)else(hc.size<-predhc.size;loopnext)inBatArray.modifyloophc.data(*$= filteri_inplace & ~printer
(let h = Enum.combine (1 -- 5)(1 --5) |> of_enum in \
filteri_inplace (fun _ x -> x>3) h ; \
to_sorted_list h) [4; 5]
*)letfilterft=filteri(fun_ka->fa)tletfilter_inplacefh=filteri_inplace(fun_ka->fa)h(*$= filter_inplace&~printer:(IO.to_string (List.print Int.print))
(let h =Enum.combine (1 -- 5) (1 -- 5) |> of_enum in \
filter_inplace (fun x -> x>3) h ; \
to_sorted_list h) [4; 5]
*)letfilter_mapft=letresult=create16initer(funka->matchfkawith|None->()|Somev->addresultkv)t;resultletfilter_map_inplacefh=lethc=h_convhinletrecloop=function|Empty->Empty|Cons(k,v,next)->(matchfkvwith|None->hc.size<-predhc.size;loopnext|Somev'->Cons(k,v',loopnext))inBatArray.modifyloophc.data(*$= filter_map_inplace & ~printer
(let h = Enum.combine (1 -- 5) (1 -- 5) |> of_enum in \
filter_map_inplace (fun _ x -> if x>3 thenSome (x+1) else None) h; \
to_sorted_list h) [5; 6]
*)letmergefh1h2=let res=create(max(lengthh1)(length h2))inletmay_add_reskv1v2=BatOption.may(addresk)(fkv1v2)initer(funkv1->may_add_resk(Somev1)(find_optionh2k))h1;iter(funkv2->ifnot(memh1k)thenmay_add_reskNone(Somev2))h2;res(*$inject
let union = merge (fun _ l r -> if l = None then r else l)
let inter = merge (fun _ l r -> if l = None then l else r)
let equal h1 h2 = to_sorted_list h1 = to_sorted_list h2
let empty = create 0
let h_1_5 = Enum.combine (1 -- 5) (1 -- 5) |> of_enum
let h_1_3 = Enum.combine (1 -- 3) (1 -- 3) |> of_enum
let h_3_5 = Enum.combine (3 -- 5) (3 -- 5) |> of_enum
let of_uniq_list l = List.unique l |> List.map (fun i -> i, i) |> of_list
*)(*$= merge & ~printer
[] \
(merge (fun k _ _ -> Some k) empty empty |> to_sorted_list)
[1; 2; 3; 4; 5] \
(merge (fun _ l _ -> l) h_1_5 empty |> to_sorted_list)
[] \
(merge (fun _ _ r -> r) h_1_5 empty |> to_sorted_list)
[] \
(merge (fun _ l _ -> l) empty h_1_5 |> to_sorted_list)
[1; 2; 3; 4; 5] \
(merge (fun _ _ r -> r) empty h_1_5 |> to_sorted_list)
[1; 2; 3] \
(let h = Enum.combine (3 -- 6) (13 -- 15) |> of_enum in \
merge (fun _ l _ -> l) h_1_3 h |> to_sorted_list)
[13; 14; 15] \
(let h = Enum.combine (3 -- 5) (13 -- 15) |> of_enum in \
merge (fun _ _ r -> r) h_1_3 h |> to_sorted_list)
[] \
(merge (fun _ _ _ -> None) h_1_3 h_3_5 |> to_sorted_list)
*)(*$= union & ~printer
[1; 2; 3; 4; 5] \
(union h_1_3 h_3_5 |> to_sorted_list)
*)(*$= inter & ~printer
[3] \
(inter h_1_3 h_3_5 |> to_sorted_list)
*)(*$Q equal
(Q.list Q.small_int) (fun l -> \
let h = of_uniq_list l in \
equal (inter h h) h)
(Q.list Q.small_int) (fun l -> \
let h = of_uniq_list l in \
equal (union h h) h)
(Q.list Q.small_int) (fun l -> \
let h = of_uniq_list l in \
equal (union h empty) h)
(Q.list Q.small_int) (fun l -> \
let h = of_uniq_list l in \
equal (inter h empty) empty)
(Q.pair (Q.list Q.small_int) (Q.list Q.small_int)) (fun (l1, l2) -> \
let h1 = of_uniq_list l1 and h2 = of_uniq_list l2 in \
equal (inter h1 h2) (inter h2h1))
(Q.pair (Q.list Q.small_int) (Q.list Q.small_int)) (fun (l1, l2) -> \
let h1 = of_uniq_list l1 and h2 = of_uniq_listl2 in \
equal (unionh1 h2) (union h2 h1))
*)letmerge_allfh1 h2=letres=create(max(lengthh1)(lengthh2))inletmay_add_reskv1v2=List.iter(addresk)(List.rev(fkv1v2))initer(funk_->letl1=find_allh1kandl2=find_allh2kinmay_add_res kl1l2)h1;iter(funk_->matchfind_allh1kwith|[]->letl2=find_allh2kinmay_add_resk[]l2|_->()(* done above *))h2;res(*$= merge_all & ~printer
[] \
(let h1 = create 0 and h2 = create 0 in \
merge_all (fun k _ _ -> [k]) h1 h2 |> to_sorted_list)
[1; 2; 3; 4; 5] \
(let h = create 0 in \
merge_all (fun _ l _ -> l) h_1_5 h |> to_sorted_list)
[] \
(let h = create 0 in \
merge_all (fun _ _ r -> r) h_1_5 h |> to_sorted_list)
[] \
(let h = create 0 in \
merge_all (fun _ l _ -> l) h h_1_5 |> to_sorted_list)
[1; 2; 3; 4; 5] \
(let h = create 0 in \
merge_all (fun _ _ r -> r) h h_1_5 |> to_sorted_list)
[1; 2; 3] \
(let h = Enum.combine (3 -- 6) (13 -- 15) |> of_enum in \
merge_all (fun _ l _ -> l) h_1_3 h |> to_sorted_list)
[13; 14; 15] \
(let h = Enum.combine (3 -- 5) (13 -- 15) |> of_enum in \
merge_all (fun _ _ r -> r) h_1_3 h |> to_sorted_list)
[] \
(merge_all (fun _ _ _ -> []) h_1_3 h_3_5 |> to_sorted_list)
[2; 1] \
(let h1 = of_list [1, 1] in \
let h2 = copyh1 in \
Hashtbl.add h212 ;\
let h = merge_all (fun _ _ r -> r) h1 h2 in \
find_all h 1)
*)exceptionFalsified(* test if predicate holds for all key-value pairs *)letfor_allpht=tryiter(funkv->ifnot(pkv)thenraiseFalsified)ht;truewithFalsified->false(*$T for_all
for_all (fun k v -> k = v) (of_list [(1,1);(2,2);(3,3)])
not (for_all(fun k v -> k = v) (of_list [(1,1);(2,2);(3,4)]))
for_all (fun kv ->k = v) empty*)moduleExceptionless=structletfind=find_optionletmodify kf=BatPervasives.wrap(modifykf)endmoduleInfix=structlet (-->)hk=find hklet(<--)h(k,v)=addhkvendmoduleLabels=structletlabelf=funkeydata->f~key~dataletadde~key~data=addekeydataletreplacee~key~data=replaceekeydataletiter~fe=iter(labelf)eletfor_all~fe=for_all(labelf)eletmap~fe=map(labelf)eletmap_inplace~fe=map_inplace(labelf)eletfilter~fe=filterfeletfilter_inplace~fe=filter_inplacefeletfilteri~fe=filteri(labelf)eletfilteri_inplace~fe=filteri_inplace (labelf)eletfilter_map~fe=filter_map(labelf)eletfilter_map_inplace~fe=filter_map_inplace(labelf)eletfold~fe~init=fold(labelf)einitletexists~fe=exists(labelf)eletmodify~key~f=modify keyfletmodify_def ~default~key~f=modify_defdefaultkeyfletmodify_opt~key~f=modify_optkeyflet merge~f~left~right=mergefleftrightletmerge_all ~f~left~right=merge_all fleftrightendmoduletypeHashedType=Hashtbl.HashedTypemodule typeS=sigtypekeytype 'atvalcreate:int->'atvallength:'at->intvalis_empty:'at->boolvalclear:'at->unitvalreset:'at->unitvalcopy:'at->'atvaladd:'at->key->'a->unitvalremove:'at->key->unitvalremove_all:'at->key->unitvalfind :'at->key->'avalfind_all:'at->key ->'alistvalfind_default:'at->key->'a->'avalfind_option:'at-> key->'aoptionvalfind_opt:'at->key ->'aoption##V>=5.5##valfind_and_remove:'at->key->'aoption##V>=5.5## valfind_and_replace :'at->key->'a->'aoptionval replace:'at->key->'a->unitvalmem:'at->key-> boolvaliter:(key->'a->unit)->'at->unitvalfor_all:(key->'a->bool)->'at->boolvalfold:(key->'a->'b->'b)->'at->'b->'bvalexists:(key->'a->bool)->'at->boolvalmap:(key ->'b-> 'c)->'bt->'ctvalmap_inplace:(key->'a->'a)->'at->unitvalfilter:('a->bool)->'at->'atvalfilter_inplace :('a->bool)->'at->unitvalfilteri:(key->'a->bool)->'at->'atvalfilteri_inplace:(key->'a->bool)->'at->unitvalfilter_map:(key->'a->'boption)->'at->'btvalfilter_map_inplace :(key->'a->'aoption)->'at->unitval modify:key->('a->'a)->'at->unitvalmodify_def:'a->key->('a->'a)->'at->unitvalmodify_opt:key->('aoption ->'aoption)->'at->unitvalmerge:(key->'aoption ->'boption ->'coption)->'at->'bt->'ctvalmerge_all:(key->'alist->'blist->'clist)->'at->'bt->'ctvalstats:'at->statistics##V>=4.07##valto_seq:'at->(key*'a)Seq.t##V>=4.07##valto_seq_keys:_t->keySeq.t##V>=4.07##val to_seq_values:'at->'aSeq.t##V>=4.07##valadd_seq:'at->(key*'a)Seq.t->unit##V>=4.07##valreplace_seq :'at->(key*'a)Seq.t->unit##V>=4.07##valof_seq:(key*'a)Seq.t->'atvalkeys:'at->keyBatEnum.tvalvalues :'at->'aBatEnum.tvalenum:'at->(key*'a)BatEnum.tvalto_list:'at->(key*'a)listvalof_enum:(key*'a)BatEnum.t->'atvalof_list:(key*'a)list->'atvalprint:?first:string ->?last:string->?sep:string->('aBatInnerIO.output->key->unit)->('aBatInnerIO.output->'b->unit)->'aBatInnerIO.output->'bt->unit(** Operations on {!Hashtbl} without exceptions.*)moduleExceptionless:sigvalfind:'at->key->'aoptionvalmodify:key->('a->'a)->'at->(unit,exn)BatPervasives.resultend(** Infix operators over a {!BatHashtbl} *)moduleInfix:sigval(-->):'at->key->'a(** [tbl-->x] returns the current binding of [x] in [tbl],
or raises [Not_found] if no such binding exists.
Equivalent to [Hashtbl.find tbl x]*)val(<--):'at->key*'a->unit(** [tbl<--(x, y)] adds a binding of [x] to [y] in table [tbl].
Previous bindings for [x] are not removed, but simply
hidden. That is, after performing {!Hashtbl.remove}[ tbl x],
the previous binding for [x], if any, is restored.
(Same behavior as with association lists.)
Equivalent to [Hashtbl.add tbl x y]*)end(** Operations on {!Hashtbl} with labels.
This module overrides a number of functions of {!Hashtbl} by
functions in which some arguments require labels. These labels are
there to improve readability and safety and to let you change the
order of arguments to functions. In every case, the behavior of the
function is identical to that of the corresponding function of {!Hashtbl}.
*)moduleLabels:sigval add:'at->key:key->data:'a->unitvalreplace:'at-> key:key->data:'a->unitvaliter :f:(key:key->data:'a->unit)->'at->unitval for_all:f:(key:key->data:'a->bool)->'at->boolval map:f:(key:key->data:'a->'b)->'at->'btvalmap_inplace:f:(key:key->data:'a->'a)->'at->unitvalfilter:f:('a->bool)-> 'at->'atvalfilter_inplace:f:('a->bool)->'at-> unitvalfilteri:f:(key:key->data:'a->bool)->'at->'atvalfilteri_inplace :f:(key:key->data:'a->bool)->'at->unitvalfilter_map :f:(key:key->data:'a->'boption)->'at->'btvalfilter_map_inplace:f:(key:key ->data:'a->'aoption)->'at->unitvalfold:f:(key:key->data:'a->'b->'b)->'at->init:'b->'bvalexists:f:(key:key ->data:'a->bool)->'at->boolvalmodify:key:key->f:('a->'a)->'at->unitvalmodify_def:default:'a->key:key ->f:('a->'a)->'at->unitvalmodify_opt:key:key->f:('aoption->'aoption)->'at->unitvalmerge:f:(key->'aoption->'boption->'coption)->left:'at->right:'bt->'ctval merge_all:f:(key->'alist ->'blist->'clist)->left:'at->right:'bt->'ctendendmoduleMake(H:HashedType):(Swithtypekey=H.tandtype'at='aHashtbl.Make(H).t)=structincludeHashtbl.Make(H)externalto_hash:'at->(key,'a)Hashtbl.t="%identity"externalof_hash:(key,'a)Hashtbl.t->'at="%identity"(* Warning: these two externals are unsafe, as they forget about the user-provided
HashtedType implementation. They are used to avoid code duplication for functions
that do *not* use the hashing function, but only traverse the bucket structure. *)(* type key = H.t
type 'a hashtbl = (key, 'a) t
type 'a t = 'a hashtbl
let create = create
let clear = clear
let copy = copy
let safehash key = (H.hash key) land max_int
let add h key info =
let h = h_conv h in
let i = (safehash key) mod (Array.length h.data) in
let bucket = Cons(key, info, h.data.(i)) in
h.data.(i) <- bucket;
h.size <- succ h.size;
if h.size > Array.length h.data lsl 1 then resize safehash h
let remove h key =
let h = h_conv h in
let rec remove_bucket = function
Empty ->
Empty
| Cons(k, i, next) ->
if H.equal k key
then begin h.size <- pred h.size; next end
else Cons(k, i, remove_bucket next) in
let i = (safehash key) mod (Array.length h.data) in
h.data.(i) <- remove_bucket h.data.(i)
let rec find_rec key = function
Empty ->
raise Not_found
| Cons(k, d, rest) ->
if H.equal key k then d else find_rec key rest
let find h key =
let h = h_conv h in
match h.data.((safehash key) mod (Array.length h.data)) with
Empty -> raise Not_found
| Cons(k1, d1, rest1) ->
if H.equal key k1 then d1 else
match rest1 with
Empty -> raise Not_found
| Cons(k2, d2, rest2) ->
if H.equal key k2 then d2 else
match rest2 with
Empty -> raise Not_found
| Cons(k3, d3, rest3) ->
if H.equal key k3 then d3 else find_rec key rest3
let find_all h key =
let rec find_in_bucket = function
Empty ->
[]
| Cons(k, d, rest) ->
if H.equal k key
then d :: find_in_bucket rest
else find_in_bucket rest in
find_in_bucket h.data.((safehash key) mod (Array.length h.data))
let replace h key info =
let rec replace_bucket = function
Empty ->
raise Not_found
| Cons(k, i, next) ->
if H.equal k key
then Cons(k, info, next)
else Cons(k, i, replace_bucket next) in
let i = (safehash key) mod (Array.length h.data) in
let l = h.data.(i) in
try
h.data.(i) <- replace_bucket l
with Not_found ->
h.data.(i) <- Cons(key, info, l);
h.size <- succ h.size;
if h.size > Array.length h.data lsl 1 then resize safehash h
let mem h key =
let rec mem_in_bucket = function
| Empty ->
false
| Cons(k, d, rest) -> H.equal k key || mem_in_bucket rest in
mem_in_bucket h.data.((safehash key) mod (Array.length h.data))*)letkey_indexhkey=(H.hashkey)land(Array.length(h_conv(to_hashh)).data-1)letiter=iterletfor_allpht=for_allp(to_hashht)letfold=foldletlength=lengthletstats=stats(* the functions here do not hash values, theyonly traverse the buckets *)letenumh=enum(to_hashh)letto_listh=to_list(to_hashh)letvaluesh=values(to_hash h)letkeysh=keys(to_hashh)letmap(f:key->'a->'b)h=of_hash(mapf(to_hashh))letexists(f:key->'a->bool)h=existsf(to_hashh)(* We can use polymorphic filteri since we do not use the key at all for inline ops *)letmap_inplace(f:key->'a->'b)h=map_inplacef(to_hashh)letfilteri_inplacefh=filteri_inplacef(to_hashh)letfilter_inplacefh=filter_inplacef(to_hashh)##V<4.3##letfilter_map_inplace fh=filter_map_inplace f(to_hashh)(* these functions do need to hash values, so we cannot use {to,of}_hash *)letof_enum e=lettbl=create11inBatEnum.iter(fun (k,v)->addtblkv)e;tblletof_listli=lettbl=create11inList.iter(fun(k,v)->addtblkv)li;tblletfind_optionhkey=lethc=h_conv(to_hashh)inletrecloop=function|Empty->None|Cons(k,v,next)->ifH.equalkkeythenSomevelseloopnextinletpos=key_index hkeyinloop(Array.unsafe_gethc.datapos)##V<4.05##letfind_opt=find_optionletfind_defaulthkeydefval=lethc=h_conv(to_hashh)inletrecloop=function|Empty->defval|Cons(k,v,next)->ifH.equal kkeythenvelseloopnextinlet pos=key_indexhkeyinloop(Array.unsafe_gethc.datapos)letremove_allhkey=lethc=h_conv(to_hashh)inletrecloop=function|Empty -> Empty|Cons(k,v,next)->ifH.equalkkeythenbeginhc.size<-predhc.size;loopnextendelseCons(k,v,loopnext)inletpos=key_indexhkeyinArray.unsafe_sethc.datapos(loop(Array.unsafe_gethc.datapos))letis_empty h=lengthh=0letprint?first?last?sepprint_kprint_voutt=print?first?last?sepprint_kprint_vout(to_hasht)letfilterift=letresult=create16initer(funka->iffkathenaddresultka)t;resultletfilterft=filteri(fun_ka->fa)tletfilter_mapft=letresult=create16initer(funka->matchfkawith|None->()|Somev->addresultkv)t;resultletmodify_optkeyfh=lethc=h_conv (to_hashh)inletrecloop=function(* Inserting an element might require a resize of the hash table.
We rely on Hashtbl.add function to grow the hashtbl if needed
instead of duplicatinglogic from the OCaml standard library. *)|Empty ->raiseHashtbl_key_not_found|Cons(k,v,next)->ifH.equalkkeythenmatchf(Somev)with|Somev->Cons(key,v,next)|None->hc.size<-predhc.size;nextelseCons(k,v,loopnext)intryletpos=key_indexhkeyinArray.unsafe_sethc.datapos(loop(Array.unsafe_gethc.datapos))with|Hashtbl_key_not_found->beginmatchfNonewith|None->()|Somev->(* Add the elementtomakesure the hashtbl is grown correctly if needed. *)addhkeyvendletmodifykeyfh=lethc=h_conv(to_hash h)inletrecloop=function|Empty->raiseNot_found|Cons(k,v,next)->ifH.equal kkeythen(Cons(key,fv,next))elseCons(k,v,loopnext)inletpos=key_indexhkeyinArray.unsafe_sethc.datapos(loop(Array.unsafe_gethc.datapos))letmodify_defv0keyfh=letf'=function|None->Some(fv0)|Somev->Some(fv)inmodify_optkeyf'hletmergefab=letres=create(max(lengtha)(lengthb))inletmay_add_reskv1v2=BatOption.may(addresk)(fkv1v2)initer(funkv1->may_add_resk(Some v1)(find_optionbk))a;iter(funkv2->ifnot (memak)thenmay_add_reskNone(Somev2))b;resletmerge_allfab=letres=create(max(lengtha)(lengthb))inletmay_add_reskv1v2=List.iter(addresk)(List.rev(fkv1v2))initer(funk_->letl1=find_allakand l2=find_allbkinmay_add_res kl1l2)a;iter (funk_->matchfind_allakwith|[]->letl2=find_allbkinmay_add_resk[]l2|_->()(* done above *))b;resmoduleLabels=structletlabelf=funkeydata->f~key~dataletadde~key~data=addekeydataletreplacee~key~data=replaceekeydataletiter~fe=iter(labelf)eletfor_all~fe=for_all(labelf)eletmap~fe=map(labelf)eletmap_inplace~fe=map_inplace(labelf)eletfilter~fe=filterfeletfilter_inplace~fe=filter_inplace feletfilteri~fe=filteri (labelf)eletfilteri_inplace~fe=filteri_inplace (labelf)eletfilter_map~fe=filter_map(labelf)eletfilter_map_inplace~fe=filter_map_inplace (labelf)eletfold~fe~init=fold(labelf)einitletexists~fe=exists(labelf)eletmodify~key~f=modifykeyfletmodify_def~default~key~f=modify_defdefaultkeyfletmodify_opt~key~f=modify_opt keyfletmerge~f~left~right=mergefleftrightletmerge_all~f~left~right=merge_allfleftrightendmoduleExceptionless=structletfind =find_optionletmodifykf=BatPervasives.wrap(modifykf)endmoduleInfix=structlet(-->)hk=findhklet(<--)h(k,v)=addhkvendendmoduleCap=structtype('a,'b,'c)t=('a,'b)Hashtbl.tconstraint 'c=[<`Read|`Write]letcreate =createexternalof_table:('a,'b)Hashtbl.t->('a,'b,_)t="%identity"externalto_table:('a,'b,[`Read|`Write])t->('a,'b)Hashtbl.t="%identity"external read_only:('a,'b,[>`Read])t->('a,'b,[`Read])t="%identity"externalwrite_only:('a,'b,[>`Write])t->('a,'b,[`Write])t="%identity"letlength =lengthlet is_empty=is_emptyletadd=addletremove=removeletremove_all=remove_allletreplace=replaceletcopy=copyletclear=clearletfind=findletfind_all=find_allletfind_default=find_defaultletfind_option=find_optionletexists=existsletmem=memletiter=iterletfor_all=for_allletfold=foldletmap=mapletmap_inplace=map_inplaceletfilter=filterletfilter_inplace=filter_inplaceletfilteri =filteriletfilteri_inplace =filteri_inplaceletfilter_map=filter_mapletfilter_map_inplace=filter_map_inplaceletmodify=modifyletmodify_def=modify_defletmodify_opt=modify_optletstats=statsletkeys=keysletvalues=valuesletenum =enumletto_list =to_listletof_enum=of_enumletof_list=of_listletprint=printletfilter=filterletfilteri=filteriletfilter_map=filter_mapletmerge=mergeletmerge_all=merge_allmoduleLabels=structletlabelf=funkeydata->f~key~dataletadde~key~data=addekeydataletreplacee~key~data=replaceekeydataletiter~fe=iter(labelf)eletfor_all~fe=for_all(labelf)eletmap~fe=map(labelf)eletmap_inplace~fe=map_inplace(labelf)eletfilter~fe=filterfeletfilter_inplace~fe=filter_inplace feletfilteri~fe=filteri (labelf)eletfilteri_inplace~fe=filteri_inplace (labelf)eletfilter_map~fe=filter_map(labelf)eletfilter_map_inplace~fe=filter_map_inplace (labelf)eletfold ~fe~init=fold(labelf)einitletexists~fe=exists(labelf)eletmodify~key~f=modifykeyfletmodify_def~default~key~f=modify_defdefaultkeyfletmodify_opt~key~f=modify_optkeyfletmerge~f~left~right=mergefleftrightletmerge_all~f~left~right=merge_allfleftrightendmoduleExceptionless=structletfind=find_optionletmodifykf=BatPervasives.wrap(modifykf)endend