2
0

hashing.zig 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. const std = @import("std");
  2. pub fn hashKey(k: []const u8) u32 {
  3. return fnv1a(k);
  4. }
  5. pub fn fnv1a(key: []const u8) u32 {
  6. var hash: u32 = 2166136261;
  7. for (key) |c| {
  8. hash ^= c;
  9. hash *%= 16777619;
  10. }
  11. return hash;
  12. }
  13. pub fn xoramasrosas(k: []const u8) u32 {
  14. var hash: u32 = 17 * 22;
  15. const x = "xoramasrosas";
  16. for (k, 0..) |char, i| {
  17. hash = hash +% (char ^ x[i % 12]) << 12;
  18. }
  19. return hash;
  20. }
  21. pub fn djb2(key: []const u8) u32 {
  22. var hash: u32 = 5381;
  23. for (key) |c| {
  24. hash = ((hash << 5) +% hash) +% c;
  25. }
  26. return hash;
  27. }
  28. test "fnv1a known values" {
  29. // FNV-1a 32-bit test vectors
  30. try std.testing.expectEqual(@as(u32, 2166136261), fnv1a(""));
  31. try std.testing.expect(fnv1a("hello") != fnv1a("world"));
  32. try std.testing.expect(fnv1a("hello") != fnv1a("Hello"));
  33. }
  34. test "fnv1a deterministic" {
  35. const h1 = fnv1a("test_key");
  36. const h2 = fnv1a("test_key");
  37. try std.testing.expectEqual(h1, h2);
  38. }
  39. test "hashKey delegates to fnv1a" {
  40. try std.testing.expectEqual(fnv1a("mykey"), hashKey("mykey"));
  41. }
  42. test "djb2 known values" {
  43. try std.testing.expectEqual(@as(u32, 5381), djb2(""));
  44. try std.testing.expect(djb2("hello") != djb2("world"));
  45. }
  46. test "djb2 deterministic" {
  47. try std.testing.expectEqual(djb2("abc"), djb2("abc"));
  48. }
  49. test "xoramasrosas deterministic" {
  50. try std.testing.expectEqual(xoramasrosas("key"), xoramasrosas("key"));
  51. try std.testing.expect(xoramasrosas("a") != xoramasrosas("b"));
  52. }
  53. test "different hash functions produce different results" {
  54. const key = "pizzakv";
  55. const f = fnv1a(key);
  56. const d = djb2(key);
  57. const x = xoramasrosas(key);
  58. // They should generally differ (not a guarantee but practically true)
  59. try std.testing.expect(f != d or f != x or d != x);
  60. }
  61. test "hash distribution - no trivial collisions for short keys" {
  62. const keys = [_][]const u8{ "a", "b", "c", "d", "e", "f", "g", "h" };
  63. var hashes: [8]u32 = undefined;
  64. for (keys, 0..) |k, i| {
  65. hashes[i] = fnv1a(k);
  66. }
  67. // All hashes should be unique for single-char keys
  68. for (0..8) |i| {
  69. for (i + 1..8) |j| {
  70. try std.testing.expect(hashes[i] != hashes[j]);
  71. }
  72. }
  73. }