struct XxHash32 [src]

Alias for std.hash.xxhash.XxHash32

Fields

accumulator: Accumulator
seed: u32
buf: [16]u8
buf_len: usize
byte_count: usize

Members

Source

pub const XxHash32 = struct { accumulator: Accumulator, seed: u32, buf: [16]u8, buf_len: usize, byte_count: usize, const prime_1 = 0x9E3779B1; // 0b10011110001101110111100110110001 const prime_2 = 0x85EBCA77; // 0b10000101111010111100101001110111 const prime_3 = 0xC2B2AE3D; // 0b11000010101100101010111000111101 const prime_4 = 0x27D4EB2F; // 0b00100111110101001110101100101111 const prime_5 = 0x165667B1; // 0b00010110010101100110011110110001 const Accumulator = struct { acc1: u32, acc2: u32, acc3: u32, acc4: u32, fn init(seed: u32) Accumulator { return .{ .acc1 = seed +% prime_1 +% prime_2, .acc2 = seed +% prime_2, .acc3 = seed, .acc4 = seed -% prime_1, }; } fn updateEmpty(self: *Accumulator, input: anytype, comptime unroll_count: usize) usize { var i: usize = 0; if (unroll_count > 0) { const unrolled_bytes = unroll_count * 16; while (i + unrolled_bytes <= input.len) : (i += unrolled_bytes) { inline for (0..unroll_count) |j| { self.processStripe(input[i + j * 16 ..][0..16]); } } } while (i + 16 <= input.len) : (i += 16) { self.processStripe(input[i..][0..16]); } return i; } fn processStripe(self: *Accumulator, buf: *const [16]u8) void { self.acc1 = round(self.acc1, mem.readInt(u32, buf[0..4], .little)); self.acc2 = round(self.acc2, mem.readInt(u32, buf[4..8], .little)); self.acc3 = round(self.acc3, mem.readInt(u32, buf[8..12], .little)); self.acc4 = round(self.acc4, mem.readInt(u32, buf[12..16], .little)); } fn merge(self: Accumulator) u32 { return rotl(u32, self.acc1, 1) +% rotl(u32, self.acc2, 7) +% rotl(u32, self.acc3, 12) +% rotl(u32, self.acc4, 18); } }; pub fn init(seed: u32) XxHash32 { return XxHash32{ .accumulator = Accumulator.init(seed), .seed = seed, .buf = undefined, .buf_len = 0, .byte_count = 0, }; } pub fn update(self: *XxHash32, input: []const u8) void { if (input.len < 16 - self.buf_len) { @memcpy(self.buf[self.buf_len..][0..input.len], input); self.buf_len += input.len; return; } var i: usize = 0; if (self.buf_len > 0) { i = 16 - self.buf_len; @memcpy(self.buf[self.buf_len..][0..i], input[0..i]); self.accumulator.processStripe(&self.buf); self.byte_count += self.buf_len; self.buf_len = 0; } i += self.accumulator.updateEmpty(input[i..], 16); self.byte_count += i; const remaining_bytes = input[i..]; @memcpy(self.buf[0..remaining_bytes.len], remaining_bytes); self.buf_len = remaining_bytes.len; } fn round(acc: u32, lane: u32) u32 { const a = acc +% (lane *% prime_2); const b = rotl(u32, a, 13); return b *% prime_1; } pub fn final(self: *XxHash32) u32 { const unfinished = if (self.byte_count < 16) self.seed +% prime_5 else self.accumulator.merge(); return finalize(unfinished, self.byte_count, self.buf[0..self.buf_len]); } fn finalize(unfinished: u32, byte_count: usize, partial: anytype) u32 { std.debug.assert(partial.len < 16); var acc = unfinished +% @as(u32, @intCast(byte_count)) +% @as(u32, @intCast(partial.len)); switch (partial.len) { inline 0, 1, 2, 3 => |count| { inline for (0..count) |i| acc = finalize1(acc, partial[i]); return avalanche(acc); }, inline 4, 5, 6, 7 => |count| { acc = finalize4(acc, partial[0..4]); inline for (4..count) |i| acc = finalize1(acc, partial[i]); return avalanche(acc); }, inline 8, 9, 10, 11 => |count| { acc = finalize4(acc, partial[0..4]); acc = finalize4(acc, partial[4..8]); inline for (8..count) |i| acc = finalize1(acc, partial[i]); return avalanche(acc); }, inline 12, 13, 14, 15 => |count| { acc = finalize4(acc, partial[0..4]); acc = finalize4(acc, partial[4..8]); acc = finalize4(acc, partial[8..12]); inline for (12..count) |i| acc = finalize1(acc, partial[i]); return avalanche(acc); }, else => unreachable, } return avalanche(acc); } fn finalize4(v: u32, bytes: *const [4]u8) u32 { var acc = v; const lane = mem.readInt(u32, bytes, .little); acc +%= lane *% prime_3; acc = rotl(u32, acc, 17) *% prime_4; return acc; } fn finalize1(v: u32, byte: u8) u32 { var acc = v; const lane = @as(u32, byte); acc +%= lane *% prime_5; acc = rotl(u32, acc, 11) *% prime_1; return acc; } fn avalanche(value: u32) u32 { var acc = value ^ value >> 15; acc *%= prime_2; acc ^= acc >> 13; acc *%= prime_3; acc ^= acc >> 16; return acc; } pub fn hash(seed: u32, input: anytype) u32 { if (input.len < 16) { return finalize(seed +% prime_5, 0, input); } else { var hasher = Accumulator.init(seed); const i = hasher.updateEmpty(input, 0); return finalize(hasher.merge(), i, input[i..]); } } }