123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155(*
* ExtHashtbl, extra functions over hashtables.
* Copyright (C) 2003 Nicolas Cannasse
*
* 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
*)moduleHashtbl=struct#ifOCAML<412externalold_hash_param:int->int->'a->int="caml_hash_univ_param""noalloc"#endiftype('a,'b)h_bucketlist =|Empty|Consof'a*'b*('a,'b)h_bucketlisttype('a,'b)h_t={mutablesize:int;mutable data:('a,'b)h_bucketlist array;mutable seed:int;initial_size:int;}includeHashtblexternalh_conv:('a,'b)t->('a,'b)h_t ="%identity"externalh_make:('a,'b)h_t->('a,'b)t="%identity"letexists=memletenumh=let recmakeiposibuckidataicount=letpos =ref ipos inletbuck=refibuckinlethdata=refidatainlethcount=reficountinletforce()=(** this is a hack inorder to keep an O(1) enum constructor **)if!hcount=-1thenbeginhcount:=(h_convh).size;hdata:=Array.copy(h_convh).data;end;inletrecnext()=force();match!buckwith|Empty->if!hcount =0thenraiseEnum.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).sizeelse!hcountinletclone()=force();make!pos!buck!hdata!hcountinEnum.make~next~count~cloneinmake (-1)Empty(Obj.magic())(-1)letkeysh=Enum.map(fun(k,_)->k)(enumh)letvaluesh=Enum.map(fun(_,v)->v)(enumh)letmapfh=letrecloop=function|Empty ->Empty|Cons(k,v,next)->Cons(k,fv,loopnext)inh_make{(h_convh)withdata=Array.maploop(h_convh).data;}(* copied from stdlib :( *)letkey_indexhkey=(* compatibility with old hash tables *)ifObj.size(Obj.reprh)>=3then(seeded_hash_param 10100(h_convh).seedkey)land(Array.length(h_convh).data-1)#ifOCAML>=412elsefailwith"Old hash function not supported anymore"#elseelse(old_hash_param10100key)mod(Array.length(h_convh).data)#endifletremove_allhkey=lethc=h_convhinletrec loop=function|Empty->Empty|Cons(k,v,next)->ifk=keythenbeginhc.size<-predhc.size;loopnextendelseCons(k,v,loopnext)inletpos=key_indexhkeyinArray.unsafe_sethc.datapos(loop(Array.unsafe_gethc.datapos))letfind_defaulthkeydefval=letrecloop=function|Empty->defval|Cons(k,v,next)->ifk=key thenvelseloopnextinletpos=key_index hkeyinloop(Array.unsafe_get(h_convh).datapos)#ifOCAML<405letfind_opthkey=letrecloop=function|Empty->None|Cons(k,v,next)->ifk=keythenSomevelseloopnextinletpos=key_indexhkeyinloop(Array.unsafe_get(h_convh).datapos)#endifletfind_option=find_optletof_enume=leth=create(ifEnum.fast_countethenEnum.counteelse0)inEnum.iter(fun(k,v)->addhkv)e;hletlengthh=(h_convh).sizeend