{
Author: Wang Yi <godspeed_china@yeah.net>
https://github.com/wangyi-fudan/wyhash
ref
https://github.com/rurban/smhasher
https://docs.rs/wyhash/0.3.0/wyhash/
https://www.partow.net/programming/hashfunctions/
}
{ version 2 64 bit only }
{$mode delphi}
unit wyhash_v2;
interface
function wyhash64(AString :String) :UInt64; inline;
implementation
const
_wyp0 = UInt64($a0761d6478bd642f);
_wyp1 = UInt64($e7037ed1a0b428db);
_wyp2 = UInt64($8ebc6af09c88c6e3);
_wyp3 = UInt64($589965cc75374cc3);
_wyp4 = UInt64($1d8e4e27c47d124f);
var
wyseed :UInt64;
(*
// dangling c boolean true = 1 or not zero
#include <stdint.h>
#include <stdio.h>
int main()
{
uint64_t rl = 10, t = 0, c = t < rl;
printf("%lu", c); // result 1 using gcc
return 0;
}
*)
function _wymum(A, B :UInt64) :UInt64; inline;
var ha, hb, la, lb, hi, lo :UInt64;
rh, rm0, rm1, rl, t, c :UInt64;
begin
ha := A shr 32;
hb := B shr 32;
la := UInt32(A); // A and $FFFFFFFF;
lb := UInt32(B); // B and $FFFFFFFF;
rh := ha * hb;
rm0 := ha * lb;
rm1 := hb * la;
rl := la * lb;
t := rl + (rm0 shl 32);
c := UInt64(t < rl); // c ? true = 1
lo := t + (rm1 shl 32);
c := c + UInt64(lo < t); // c ? true = 1
hi := rh + (rm0 shr 32) + (rm1 shr 32) + c;
result := hi xor lo;
end;
function _wymix0(A, B, seed :UInt64) :UInt64; inline;
begin
result := _wymum(A xor seed xor _wyp0, B xor seed xor _wyp1);
end;
function _wymix1(A, B, seed :UInt64) :UInt64; inline;
begin
result := _wymum(A xor seed xor _wyp2, B xor seed xor _wyp3);
end;
// macro ?? or better endian
function _wyr08(const p :PUInt8) :UInt64; inline;
begin
Move(p, result, 1);
end;
function _wyr16(const p :PUInt8) :UInt64; inline;
begin
Move(p, result, 2);
end;
function _wyr32(const p :PUInt8) :UInt64; inline;
begin
Move(p, result, 4);
end;
function _wyr64(const p :PUInt8) :UInt64; inline;
begin
Move(p, result, 8);
end;
function __wyr64(const p :PUInt8) :UInt64; inline;
begin
result := (_wyr32(p) shl 32) or _wyr32(p + 4);
end;
// to avoid attacks, seed should be initialized as a secret
function wyhash(const key :Pointer; len, seed :UInt64) :UInt64; inline;
var i, len1 :UInt64; p :PUInt8;
begin
p := key;
i := 0;
len1 := len;
while (i + 32 <= len) do
begin
seed := _wymix0(_wyr64(p ), _wyr64(p + 8), seed)
xor _wymix1(_wyr64(p + 16), _wyr64(p + 24), seed);
i := i + 32;
p := p + 32;
end;
case (len and 31) of
0: len1 := _wymix0( len1, 0, seed);
1: seed := _wymix0( _wyr08(p), 0, seed);
2: seed := _wymix0( _wyr16(p), 0, seed);
3: seed := _wymix0((_wyr16(p) shl 8) or _wyr08(p + 2), 0, seed);
4: seed := _wymix0( _wyr32(p), 0, seed);
5: seed := _wymix0((_wyr32(p) shl 8) or _wyr08(p + 4), 0, seed);
6: seed := _wymix0((_wyr32(p) shl 16) or _wyr16(p + 4), 0, seed);
7: seed := _wymix0((_wyr32(p) shl 24) or (_wyr16(p + 4) shl 8) or _wyr08(p + 6), 0, seed);
8: seed := _wymix0(__wyr64(p), 0, seed);
9: seed := _wymix0(__wyr64(p), _wyr08(p + 8), seed);
10: seed := _wymix0(__wyr64(p), _wyr16(p + 8), seed);
11: seed := _wymix0(__wyr64(p), (_wyr16(p + 8) shl 8) or _wyr08(p + 8 + 2), seed);
12: seed := _wymix0(__wyr64(p), _wyr32(p + 8), seed);
13: seed := _wymix0(__wyr64(p), (_wyr32(p + 8) shl 8) or _wyr08(p + 8 + 4), seed);
14: seed := _wymix0(__wyr64(p), (_wyr32(p + 8) shl 16) or _wyr16(p + 8 + 4), seed);
15: seed := _wymix0(__wyr64(p), (_wyr32(p + 8) shl 24) or (_wyr16(p + 8 + 4) shl 8) or _wyr08(p + 8 + 6), seed);
16: seed := _wymix0(__wyr64(p), __wyr64(p + 8), seed);
17: seed := _wymix0(__wyr64(p), __wyr64(p + 8), seed) xor _wymix1( _wyr08(p + 16), 0, seed);
18: seed := _wymix0(__wyr64(p), __wyr64(p + 8), seed) xor _wymix1( _wyr16(p + 16), 0, seed);
19: seed := _wymix0(__wyr64(p), __wyr64(p + 8), seed) xor _wymix1((_wyr16(p + 16) shl 8) or _wyr08(p + 16 + 2), 0, seed);
20: seed := _wymix0(__wyr64(p), __wyr64(p + 8), seed) xor _wymix1( _wyr32(p + 16), 0, seed);
21: seed := _wymix0(__wyr64(p), __wyr64(p + 8), seed) xor _wymix1((_wyr32(p + 16) shl 8) or _wyr08(p + 16 + 4), 0, seed);
22: seed := _wymix0(__wyr64(p), __wyr64(p + 8), seed) xor _wymix1((_wyr32(p + 16) shl 16) or _wyr16(p + 16 + 4), 0, seed);
23: seed := _wymix0(__wyr64(p), __wyr64(p + 8), seed) xor _wymix1((_wyr32(p + 16) shl 24) or (_wyr16(p + 16 + 4) shl 8) or _wyr08(p + 16 + 6), 0, seed);
24: seed := _wymix0(__wyr64(p), __wyr64(p + 8), seed) xor _wymix1(__wyr64(p + 16), 0, seed);
25: seed := _wymix0(__wyr64(p), __wyr64(p + 8), seed) xor _wymix1(__wyr64(p + 16), _wyr08(p + 24), seed);
26: seed := _wymix0(__wyr64(p), __wyr64(p + 8), seed) xor _wymix1(__wyr64(p + 16), _wyr16(p + 24), seed);
27: seed := _wymix0(__wyr64(p), __wyr64(p + 8), seed) xor _wymix1(__wyr64(p + 16), (_wyr16(p + 24) shl 8) or _wyr08(p + 24 + 2), seed);
28: seed := _wymix0(__wyr64(p), __wyr64(p + 8), seed) xor _wymix1(__wyr64(p + 16), _wyr32(p + 24), seed);
29: seed := _wymix0(__wyr64(p), __wyr64(p + 8), seed) xor _wymix1(__wyr64(p + 16), (_wyr32(p + 24) shl 8) or _wyr08(p + 24 + 4), seed);
30: seed := _wymix0(__wyr64(p), __wyr64(p + 8), seed) xor _wymix1(__wyr64(p + 16), (_wyr32(p + 24) shl 16) or _wyr16(p + 24 + 4), seed);
31: seed := _wymix0(__wyr64(p), __wyr64(p + 8), seed) xor _wymix1(__wyr64(p + 16), (_wyr32(p + 24) shl 24) or (_wyr16(p + 24 + 4) shl 8) or _wyr08(p + 24 + 6), seed);
end;
result := _wymum(seed xor len1, _wyp4);
end;
function wyrand(seed :UInt64) :UInt64; inline;
begin
seed := seed + _wyp0;
result := _wymum(seed xor _wyp1, seed);
end;
function wyhash64(AString :String) :UInt64; inline;
begin
result := wyhash(@AString[1], Length(AString), wyseed);
end;
initialization
wyseed := wyrand(33);
end.