forked from vv/efemra
1
0
Fork 0
efemra/src/common/fnv1a.zig

105 lines
3.2 KiB
Zig

const testing = @import("std").testing;
pub fn toUpper(x: u8) u8 {
var c: i32 = x;
const lo: i32 = ('a' - 1) - c; // c >= 'a'
const hi: i32 = c - ('z' + 1); // c <= 'z'
const mask = (lo & hi) >> 9; // &&
c = c + (mask & ('A' - 'a'));
return @intCast(u8, c);
}
pub const Hasher32 = Hasher(u32, 16777619, 2166136261);
pub const Hasher64 = Hasher(u64, 1099511628211, 14695981039346656037);
pub const Hasher128 = Hasher(u128, 309485009821345068724781371, 144066263297769815596495629667062367629);
pub fn Hasher(comptime T: type, comptime prime: T, comptime bias: T) type {
return struct {
pub const Prime = prime;
pub const Bias = bias;
pub fn byteIgnoreCase(x: u8, hash: T) T {
return (hash ^ toUpper(x)) *% Prime;
}
pub fn byte(x: u8, hash: T) T {
return (hash ^ x) *% Prime;
}
pub fn word(x: u16, hash_in: T) T {
var hash = (hash_in ^ (0xff & (x >> 0))) *% Prime;
hash = (hash ^ (0xff & (x >> 8))) *% Prime;
return hash;
}
pub fn dword(x: u32, hash_in: T) T {
var hash = (hash_in ^ (0xff & (x >> 0))) *% Prime;
hash = (hash ^ (0xff & (x >> 8))) *% Prime;
hash = (hash ^ (0xff & (x >> 16))) *% Prime;
hash = (hash ^ (0xff & (x >> 24))) *% Prime;
return hash;
}
pub fn qword(x: u64, hash_in: T) T {
var hash = (hash_in ^ (0xff & (x >> 0))) *% Prime;
hash = (hash ^ (0xff & (x >> 8))) *% Prime;
hash = (hash ^ (0xff & (x >> 16))) *% Prime;
hash = (hash ^ (0xff & (x >> 24))) *% Prime;
hash = (hash ^ (0xff & (x >> 32))) *% Prime;
hash = (hash ^ (0xff & (x >> 40))) *% Prime;
hash = (hash ^ (0xff & (x >> 48))) *% Prime;
hash = (hash ^ (0xff & (x >> 56))) *% Prime;
return hash;
}
pub fn string(str: []const u8, hash_in: T) T {
var hash = hash_in;
for (str) |c| {
hash = byteIgnoreCase(c, hash);
}
return hash;
}
pub fn bytes(ptr: *u8, n_bytes: usize, hash: T) T {
var i = 0;
while (i < n_bytes) : (i += 1) {
hash = byte(ptr[i], hash);
}
return hash;
}
pub fn hashStr(text: []const u8) T {
var hash: T = 0;
if (text[0] != 0) {
hash = string(text, Bias);
hash = if (hash != 0) hash else 1;
}
return hash;
}
pub fn hashBytes(ptr: *u8, n_bytes: usize) T {
var hash: T = 0;
if (n_bytes > 0) {
hash = bytes(ptr, n_bytes, Bias);
hash = if (hash != 0) hash else 1;
}
return hash;
}
};
}
test "hashing 32-bit" {
try testing.expectEqual(@intCast(u32, 0x9de507a8), Hasher32.hashStr("foobar"));
try testing.expectEqual(@intCast(u32, 0x9de507a8), Hasher32.hashStr("FOObAR"));
}
test "hashing 64-bit" {
try testing.expectEqual(@intCast(u64, 0xed91fadfa4bbf528), Hasher64.hashStr("foobar"));
try testing.expectEqual(@intCast(u64, 0xed91fadfa4bbf528), Hasher64.hashStr("FOObAR"));
}