123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175(* This file is free software, part of containers. See file "license" for more details. *)(** {1 Hash combinators} *)typehash=inttype'at='a->hashtype'aiter=('a->unit)->unittype'agen=unit->'aoption(* FNV hashing
https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
*)letfnv_offset_basis=0xcbf29ce484222325Lletfnv_prime=0x100000001b3L(* hash an integer *)lethash_int_n=leth=reffnv_offset_basisinfork=0to7do(h:=Int64.(mul!hfnv_prime));h:=Int64.(logxor!h(of_int((nlsr(k*8))land0xff)))done;(* truncate back to int and remove sign *)Int64.to_int!hlandmax_intletcombine2ab=leth=reffnv_offset_basisin(* we only do one loop, where we mix bytes of [a] and [b], so as
to simplify control flow *)fork=0to7do(h:=Int64.(mul!hfnv_prime));(h:=Int64.(logxor!h(of_int((alsr(k*8))land0xff))));(h:=Int64.(mul!hfnv_prime));h:=Int64.(logxor!h(of_int((blsr(k*8))land0xff)))done;Int64.to_int!hlandmax_intlet[@inline]combinefsx=combine2s(fx)letcombine3abc=leth=reffnv_offset_basisin(* we only do one loop, where we mix bytes of [a] [b] and [c], so as
to simplify control flow *)fork=0to7do(h:=Int64.(mul!hfnv_prime));(h:=Int64.(logxor!h(of_int((alsr(k*8))land0xff))));(h:=Int64.(mul!hfnv_prime));(h:=Int64.(logxor!h(of_int((blsr(k*8))land0xff))));(h:=Int64.(mul!hfnv_prime));h:=Int64.(logxor!h(of_int((clsr(k*8))land0xff)))done;Int64.to_int!hlandmax_intletcombine4abcd=leth=reffnv_offset_basisinfork=0to7do(h:=Int64.(mul!hfnv_prime));(h:=Int64.(logxor!h(of_int((alsr(k*8))land0xff))));(h:=Int64.(mul!hfnv_prime));(h:=Int64.(logxor!h(of_int((blsr(k*8))land0xff))));(h:=Int64.(mul!hfnv_prime));(h:=Int64.(logxor!h(of_int((clsr(k*8))land0xff))));(h:=Int64.(mul!hfnv_prime));h:=Int64.(logxor!h(of_int((dlsr(k*8))land0xff)))done;Int64.to_int!hlandmax_intletcombine5abcde=combine3ab(combine3cde)letcombine6abcdef=combine4abc(combine3def)(** {2 Combinators} *)letconsth_=hletconst0_=0letint=hash_int_letboolb=hash_int_(ifbthen1else2)letcharx=hash_int_(Char.codex)(* hash an integer *)letint64n:int=leth=reffnv_offset_basisinfork=0to7do(h:=Int64.(mul!hfnv_prime));h:=Int64.(logxor!h(logand(shift_right_logicaln(k*8))0xffL))done;(* truncate back to int and remove sign *)Int64.to_int!hlandmax_intletint32(x:int32)=int64(Int64.of_int32x)letnativeint(x:nativeint)=int64(Int64.of_nativeintx)(* do not hash more than 128 bytes in strings/bytes *)letmax_len_b_=128letbytes(x:bytes)=leth=reffnv_offset_basisinfori=0tominmax_len_b_(Bytes.lengthx-1)do(h:=Int64.(mul!hfnv_prime));letbyte=Char.code(Bytes.unsafe_getxi)inh:=Int64.(logxor!h(of_intbyte))done;Int64.to_int!hlandmax_intletstring(x:string)=bytes(Bytes.unsafe_of_stringx)letslicexilen=letj=i+leninletrecauxis=ifi=jthenselseaux(i+1)(combine2(Char.codex.[i])s)inauxi0letoptf=function|None->42|Somex->combine243(fx)letlistfl=List.fold_left(combinef)0x42lletarrayfl=Array.fold_left(combinef)0x42lletpairfg(x,y)=combine2(fx)(gy)lettriplefgh(x,y,z)=combine2(combine2(fx)(gy))(hz)letquadfghi(x,y,z,w)=combine2(combine2(fx)(gy))(combine2(hz)(iw))letmapfhx=h(fx)letif_bthen_else_h=ifbthenthen_helseelse_hletpolyx=Hashtbl.hashxletarray_of_hashes_arr=Array.sortCCInt.comparearr;(* sort the hashes, so their order does not matter *)Array.fold_leftcombine20x42arrletarray_commfa=letarr=Array.init(Array.lengtha)(funi->fa.(i))inarray_of_hashes_arrletlist_commfl=letarr=Array.make(List.lengthl)0inList.iteri(funix->arr.(i)<-fx)l;array_of_hashes_arrletiterfseq=leth=ref0x43inseq(funx->h:=combinef!hx);!hletseqfseq=leth=ref0x43inSeq.iter(funx->h:=combinef!hx)seq;!hletgenfg=letrecauxs=matchg()with|None->s|Somex->aux(combine2s(fx))inaux0x42