92 lines
2.8 KiB
Plaintext
92 lines
2.8 KiB
Plaintext
// Expect retcode = 0
|
||
|
||
// 哈希工具:FNV-1a 字节哈希 + 整型混合;并给出可直接交给 map 的回调
|
||
// (map 的 hash/eq 回调接收指向键字节的指针,这里按 usize / ByteView 解释)。
|
||
// 仅提供确定性哈希与等值,不承诺密码学性质。
|
||
|
||
type .{ .ByteView } = @import("byte_view.spl");
|
||
|
||
// FNV-1a 64 位,逐字节;空输入返回 offset basis。
|
||
fn hash_bytes(data: *u8, len: usize): usize {
|
||
var h: usize = 14695981039346656037; // FNV-1a 64 位 offset basis
|
||
var prime: usize = 1099511628211; // FNV 质数
|
||
var i: usize = 0;
|
||
while i < len {
|
||
h = (h ^ (data[i] as usize)) * prime;
|
||
i = i + 1;
|
||
}
|
||
ret h;
|
||
}
|
||
|
||
fn hash_byte_view(view: ByteView): usize {
|
||
ret hash_bytes(view.ptr, view.len);
|
||
}
|
||
|
||
// 整型混合(splitmix 风格的移位-乘法),保证非零与良好扩散。
|
||
fn hash_usize_value(value: usize): usize {
|
||
var prime: usize = 1099511628211; // splitmix 风格的混合乘子
|
||
var h = value;
|
||
h = (h ^ (h >> 30)) * prime;
|
||
h = h ^ (h >> 27);
|
||
h = h * prime;
|
||
h = h ^ (h >> 31);
|
||
if h == 0 { ret prime; } // 0 映射到非零
|
||
ret h;
|
||
}
|
||
|
||
// ---- map 回调 ----
|
||
|
||
// 键按 usize 解释。
|
||
fn hash_usize(key: *u8): usize {
|
||
ret hash_usize_value((key as *usize).*);
|
||
}
|
||
|
||
fn eq_usize(a: *u8, b: *u8): bool {
|
||
ret (a as *usize).* == (b as *usize).*;
|
||
}
|
||
|
||
// 键按 ByteView 解释,哈希其指向的字节。
|
||
fn hash_view(key: *u8): usize {
|
||
var view = (key as *ByteView).*;
|
||
ret hash_byte_view(view);
|
||
}
|
||
|
||
fn eq_view(a: *u8, b: *u8): bool {
|
||
ret ByteView.eq((a as *ByteView).*, (b as *ByteView).*);
|
||
}
|
||
|
||
// ---- 测试辅助 ----
|
||
|
||
fn expect_hash(view: []u8, expected: usize) {
|
||
var got = hash_bytes(view.ptr, view.len);
|
||
@assert(got == expected, "hash value");
|
||
}
|
||
|
||
fn test_fnv_vectors() {
|
||
expect_hash("", 14695981039346656037);
|
||
expect_hash("a", 12638187200555641996);
|
||
expect_hash("foobar", 9625390261332436968);
|
||
expect_hash("hello", 11831194018420276491);
|
||
|
||
// 同一输入稳定;不同输入不同。
|
||
var s1: []u8 = "abc";
|
||
var s2: []u8 = "abd";
|
||
@assert(hash_bytes(s1.ptr, 3) == hash_bytes(s1.ptr, 3), "deterministic");
|
||
@assert(hash_bytes(s1.ptr, 3) != hash_bytes(s2.ptr, 3), "distinct");
|
||
|
||
// ByteView 与 bytes 一致。
|
||
var v = ByteView.from_slice("foobar");
|
||
@assert(hash_byte_view(v) == hash_bytes(v.ptr, v.len), "view == bytes");
|
||
|
||
// 整型混合:0 不保持 0,且稳定/区分。
|
||
@assert(hash_usize_value(0) != 0, "zero mixed");
|
||
@assert(hash_usize_value(7) == hash_usize_value(7), "int stable");
|
||
@assert(hash_usize_value(7) != hash_usize_value(8), "int distinct");
|
||
}
|
||
|
||
// map 回调(hash_usize/eq_usize/hash_view/eq_view)由 map.spl 在自己的测试里验证。
|
||
|
||
fn main() {
|
||
test_fnv_vectors();
|
||
}
|