authorgravatar for sahnvour@pm.meSahnvour <sahnvour@pm.me> 2019-07-16 20:31:02+02:00
committergravatar for sahnvour@pm.meSahnvour <sahnvour@pm.me> 2019-08-04 12:34:37+02:00
log3faf5d38576616d033c343130607189eb9fe613c
tree84be60a7cd7107cdb4617f20e9b37e00cea2be25
parent4b5172d2879742b98e3e34b90b05ac28da9f39fe

wyhash: stateless is faster for both iterative hashing and small keys.


1 files changed, 20 insertions(+), 32 deletions(-)

std/hash/wyhash.zig+20-32
...@@ -33,16 +33,11 @@ fn mix1(a: u64, b: u64, seed: u64) u64 {...@@ -33,16 +33,11 @@ fn mix1(a: u64, b: u64, seed: u64) u64 {
3333
34pub const Wyhash = struct {34pub const Wyhash = struct {
35 seed: u64,35 seed: u64,
36
37 buf: [32]u8,
38 buf_len: usize,
39 msg_len: usize,36 msg_len: usize,
4037
41 pub fn init(seed: u64) Wyhash {38 pub fn init(seed: u64) Wyhash {
42 return Wyhash{39 return Wyhash{
43 .seed = seed,40 .seed = seed,
44 .buf = undefined,
45 .buf_len = 0,
46 .msg_len = 0,41 .msg_len = 0,
47 };42 };
48 }43 }
...@@ -61,34 +56,12 @@ pub const Wyhash = struct {...@@ -61,34 +56,12 @@ pub const Wyhash = struct {
61 );56 );
62 }57 }
6358
64 pub fn update(self: *Wyhash, b: []const u8) void {59 fn partial(self: *Wyhash, b: []const u8) void {
65 var off: usize = 0;60 const rem_key = b;
6661 const rem_len = b.len;
67 // Partial from previous.
68 if (self.buf_len != 0 and self.buf_len + b.len > 32) {
69 off += 32 - self.buf_len;
70 mem.copy(u8, self.buf[self.buf_len..], b[0..off]);
71 self.round(self.buf[0..]);
72 self.buf_len = 0;
73 }
74
75 // Full middle blocks.
76 while (off + 32 <= b.len) : (off += 32) {
77 @inlineCall(self.round, b[off .. off + 32]);
78 }
79
80 // Remainder for next pass.
81 mem.copy(u8, self.buf[self.buf_len..], b[off..]);
82 self.buf_len += @intCast(u8, b[off..].len);
83 self.msg_len += b.len;
84 }
85
86 pub fn final(self: *Wyhash) u64 {
87 const seed = self.seed;
88 const rem_len = @intCast(u5, self.buf_len);
89 const rem_key = self.buf[0..self.buf_len];
9062
91 self.seed = switch (rem_len) {63 var seed = self.seed;
64 seed = switch (@intCast(u5, rem_len)) {
92 0 => seed,65 0 => seed,
93 1 => mix0(read_bytes(1, rem_key), primes[4], seed),66 1 => mix0(read_bytes(1, rem_key), primes[4], seed),
94 2 => mix0(read_bytes(2, rem_key), primes[4], seed),67 2 => mix0(read_bytes(2, rem_key), primes[4], seed),
...@@ -122,7 +95,22 @@ pub const Wyhash = struct {...@@ -122,7 +95,22 @@ pub const Wyhash = struct {
122 30 => mix0(read_8bytes_swapped(rem_key), read_8bytes_swapped(rem_key[8..]), seed) ^ mix1(read_8bytes_swapped(rem_key[16..]), (read_bytes(4, rem_key[24..]) << 16) | read_bytes(2, rem_key[28..]), seed),95 30 => mix0(read_8bytes_swapped(rem_key), read_8bytes_swapped(rem_key[8..]), seed) ^ mix1(read_8bytes_swapped(rem_key[16..]), (read_bytes(4, rem_key[24..]) << 16) | read_bytes(2, rem_key[28..]), seed),
123 31 => mix0(read_8bytes_swapped(rem_key), read_8bytes_swapped(rem_key[8..]), seed) ^ mix1(read_8bytes_swapped(rem_key[16..]), (read_bytes(4, rem_key[24..]) << 24) | (read_bytes(2, rem_key[28..]) << 8) | read_bytes(1, rem_key[30..]), seed),96 31 => mix0(read_8bytes_swapped(rem_key), read_8bytes_swapped(rem_key[8..]), seed) ^ mix1(read_8bytes_swapped(rem_key[16..]), (read_bytes(4, rem_key[24..]) << 24) | (read_bytes(2, rem_key[28..]) << 8) | read_bytes(1, rem_key[30..]), seed),
124 };97 };
98 self.seed = seed;
99 }
100
101 pub fn update(self: *Wyhash, b: []const u8) void {
102 var off: usize = 0;
103
104 // Full middle blocks.
105 while (off + 32 <= b.len) : (off += 32) {
106 @inlineCall(self.round, b[off .. off + 32]);
107 }
125108
109 self.partial(b[off..]);
110 self.msg_len += b.len;
111 }
112
113 pub fn final(self: *Wyhash) u64 {
126 return mum(self.seed ^ self.msg_len, primes[4]);114 return mum(self.seed ^ self.msg_len, primes[4]);
127 }115 }
128116