105 lines
3.2 KiB
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"));
|
|
}
|