| author | |
| committer | |
| log | 1c148f161905469b0ad5cf4de801cf287c491174 |
| tree | 702966068829d7775a33e79d734f24bca5eab97d |
| parent | 26d61812a8dbad204517d00d3a1f0e52275eceeb |
7 files changed, 61 insertions(+), 48 deletions(-)
lib/std/hash/adler.zig+7-1| ... | @@ -3,7 +3,7 @@ | ... | @@ -3,7 +3,7 @@ |
| 3 | // https://tools.ietf.org/html/rfc1950#section-9 | 3 | // https://tools.ietf.org/html/rfc1950#section-9 |
| 4 | // https://github.com/madler/zlib/blob/master/adler32.c | 4 | // https://github.com/madler/zlib/blob/master/adler32.c |
| 5 | 5 | ||
| 6 | const std = @import("../std.zig"); | 6 | const std = @import("std"); |
| 7 | const testing = std.testing; | 7 | const testing = std.testing; |
| 8 | 8 | ||
| 9 | pub const Adler32 = struct { | 9 | pub const Adler32 = struct { |
| ... | @@ -126,3 +126,9 @@ test "adler32 very long with variation" { | ... | @@ -126,3 +126,9 @@ test "adler32 very long with variation" { |
| 126 | 126 | ||
| 127 | try testing.expectEqual(@as(u32, 0x5af38d6e), std.hash.Adler32.hash(long[0..])); | 127 | try testing.expectEqual(@as(u32, 0x5af38d6e), std.hash.Adler32.hash(long[0..])); |
| 128 | } | 128 | } |
| 129 | |||
| 130 | const verify = @import("verify.zig"); | ||
| 131 | |||
| 132 | test "adler32 iterative" { | ||
| 133 | try verify.iterativeApi(Adler32); | ||
| 134 | } |
lib/std/hash/crc.zig+11-1| ... | @@ -5,7 +5,7 @@ | ... | @@ -5,7 +5,7 @@ |
| 5 | // - Crc32SmallWithPoly uses only 64 bytes of memory but is slower. Be aware that this is | 5 | // - Crc32SmallWithPoly uses only 64 bytes of memory but is slower. Be aware that this is |
| 6 | // still moderately fast just slow relative to the slicing approach. | 6 | // still moderately fast just slow relative to the slicing approach. |
| 7 | 7 | ||
| 8 | const std = @import("../std.zig"); | 8 | const std = @import("std"); |
| 9 | const builtin = @import("builtin"); | 9 | const builtin = @import("builtin"); |
| 10 | const debug = std.debug; | 10 | const debug = std.debug; |
| 11 | const testing = std.testing; | 11 | const testing = std.testing; |
| ... | @@ -194,6 +194,8 @@ pub fn Crc32WithPoly(comptime poly: Polynomial) type { | ... | @@ -194,6 +194,8 @@ pub fn Crc32WithPoly(comptime poly: Polynomial) type { |
| 194 | }; | 194 | }; |
| 195 | } | 195 | } |
| 196 | 196 | ||
| 197 | const verify = @import("verify.zig"); | ||
| 198 | |||
| 197 | test "crc32 ieee" { | 199 | test "crc32 ieee" { |
| 198 | const Crc32Ieee = Crc32WithPoly(.IEEE); | 200 | const Crc32Ieee = Crc32WithPoly(.IEEE); |
| 199 | 201 | ||
| ... | @@ -210,6 +212,10 @@ test "crc32 castagnoli" { | ... | @@ -210,6 +212,10 @@ test "crc32 castagnoli" { |
| 210 | try testing.expect(Crc32Castagnoli.hash("abc") == 0x364b3fb7); | 212 | try testing.expect(Crc32Castagnoli.hash("abc") == 0x364b3fb7); |
| 211 | } | 213 | } |
| 212 | 214 | ||
| 215 | test "crc32 iterative" { | ||
| 216 | try verify.iterativeApi(Crc32WithPoly(.IEEE)); | ||
| 217 | } | ||
| 218 | |||
| 213 | // half-byte lookup table implementation. | 219 | // half-byte lookup table implementation. |
| 214 | pub fn Crc32SmallWithPoly(comptime poly: Polynomial) type { | 220 | pub fn Crc32SmallWithPoly(comptime poly: Polynomial) type { |
| 215 | return struct { | 221 | return struct { |
| ... | @@ -258,6 +264,10 @@ pub fn Crc32SmallWithPoly(comptime poly: Polynomial) type { | ... | @@ -258,6 +264,10 @@ pub fn Crc32SmallWithPoly(comptime poly: Polynomial) type { |
| 258 | }; | 264 | }; |
| 259 | } | 265 | } |
| 260 | 266 | ||
| 267 | test "small crc32 iterative" { | ||
| 268 | try verify.iterativeApi(Crc32SmallWithPoly(.IEEE)); | ||
| 269 | } | ||
| 270 | |||
| 261 | test "small crc32 ieee" { | 271 | test "small crc32 ieee" { |
| 262 | const Crc32Ieee = Crc32SmallWithPoly(.IEEE); | 272 | const Crc32Ieee = Crc32SmallWithPoly(.IEEE); |
| 263 | 273 |
lib/std/hash/crc/catalog_test.zig+1-1| ... | @@ -1,6 +1,6 @@ | ... | @@ -1,6 +1,6 @@ |
| 1 | //! This file is auto-generated by tools/update_crc_catalog.zig. | 1 | //! This file is auto-generated by tools/update_crc_catalog.zig. |
| 2 | 2 | ||
| 3 | const std = @import("../../std.zig"); | 3 | const std = @import("std"); |
| 4 | const testing = std.testing; | 4 | const testing = std.testing; |
| 5 | const catalog = @import("catalog.zig"); | 5 | const catalog = @import("catalog.zig"); |
| 6 | 6 |
lib/std/hash/fnv.zig+5| ... | @@ -40,19 +40,24 @@ fn Fnv1a(comptime T: type, comptime prime: T, comptime offset: T) type { | ... | @@ -40,19 +40,24 @@ fn Fnv1a(comptime T: type, comptime prime: T, comptime offset: T) type { |
| 40 | }; | 40 | }; |
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | const verify = @import("verify.zig"); | ||
| 44 | |||
| 43 | test "fnv1a-32" { | 45 | test "fnv1a-32" { |
| 44 | try testing.expect(Fnv1a_32.hash("") == 0x811c9dc5); | 46 | try testing.expect(Fnv1a_32.hash("") == 0x811c9dc5); |
| 45 | try testing.expect(Fnv1a_32.hash("a") == 0xe40c292c); | 47 | try testing.expect(Fnv1a_32.hash("a") == 0xe40c292c); |
| 46 | try testing.expect(Fnv1a_32.hash("foobar") == 0xbf9cf968); | 48 | try testing.expect(Fnv1a_32.hash("foobar") == 0xbf9cf968); |
| 49 | try verify.iterativeApi(Fnv1a_32); | ||
| 47 | } | 50 | } |
| 48 | 51 | ||
| 49 | test "fnv1a-64" { | 52 | test "fnv1a-64" { |
| 50 | try testing.expect(Fnv1a_64.hash("") == 0xcbf29ce484222325); | 53 | try testing.expect(Fnv1a_64.hash("") == 0xcbf29ce484222325); |
| 51 | try testing.expect(Fnv1a_64.hash("a") == 0xaf63dc4c8601ec8c); | 54 | try testing.expect(Fnv1a_64.hash("a") == 0xaf63dc4c8601ec8c); |
| 52 | try testing.expect(Fnv1a_64.hash("foobar") == 0x85944171f73967e8); | 55 | try testing.expect(Fnv1a_64.hash("foobar") == 0x85944171f73967e8); |
| 56 | try verify.iterativeApi(Fnv1a_64); | ||
| 53 | } | 57 | } |
| 54 | 58 | ||
| 55 | test "fnv1a-128" { | 59 | test "fnv1a-128" { |
| 56 | try testing.expect(Fnv1a_128.hash("") == 0x6c62272e07bb014262b821756295c58d); | 60 | try testing.expect(Fnv1a_128.hash("") == 0x6c62272e07bb014262b821756295c58d); |
| 57 | try testing.expect(Fnv1a_128.hash("a") == 0xd228cb696f1a8caf78912b704e4a8964); | 61 | try testing.expect(Fnv1a_128.hash("a") == 0xd228cb696f1a8caf78912b704e4a8964); |
| 62 | try verify.iterativeApi(Fnv1a_128); | ||
| 58 | } | 63 | } |
lib/std/hash/verify.zig+27| ... | @@ -13,6 +13,15 @@ fn hashMaybeSeed(comptime hash_fn: anytype, seed: anytype, buf: []const u8) @typ | ... | @@ -13,6 +13,15 @@ fn hashMaybeSeed(comptime hash_fn: anytype, seed: anytype, buf: []const u8) @typ |
| 13 | } | 13 | } |
| 14 | } | 14 | } |
| 15 | 15 | ||
| 16 | fn initMaybeSeed(comptime Hash: anytype, seed: anytype) Hash { | ||
| 17 | const HashFn = @typeInfo(@TypeOf(Hash.init)).Fn; | ||
| 18 | if (HashFn.params.len == 1) { | ||
| 19 | return Hash.init(@intCast(seed)); | ||
| 20 | } else { | ||
| 21 | return Hash.init(); | ||
| 22 | } | ||
| 23 | } | ||
| 24 | |||
| 16 | // Returns a verification code, the same as user by SMHasher. | 25 | // Returns a verification code, the same as user by SMHasher. |
| 17 | // | 26 | // |
| 18 | // Hash keys of the form {0}, {0,1}, {0,1,2}... up to N=255, using 256-N as seed. | 27 | // Hash keys of the form {0}, {0,1}, {0,1,2}... up to N=255, using 256-N as seed. |
| ... | @@ -33,3 +42,21 @@ pub fn smhasher(comptime hash_fn: anytype) u32 { | ... | @@ -33,3 +42,21 @@ pub fn smhasher(comptime hash_fn: anytype) u32 { |
| 33 | 42 | ||
| 34 | return @truncate(hashMaybeSeed(hash_fn, 0, buf_all[0..])); | 43 | return @truncate(hashMaybeSeed(hash_fn, 0, buf_all[0..])); |
| 35 | } | 44 | } |
| 45 | |||
| 46 | pub fn iterativeApi(comptime Hash: anytype) !void { | ||
| 47 | // Sum(1..32) = 528 | ||
| 48 | var buf: [528]u8 = [_]u8{0} ** 528; | ||
| 49 | var len: usize = 0; | ||
| 50 | const seed = 0; | ||
| 51 | |||
| 52 | var hasher = initMaybeSeed(Hash, seed); | ||
| 53 | for (1..32) |i| { | ||
| 54 | const r = hashMaybeSeed(Hash.hash, seed, buf[0 .. len + i]); | ||
| 55 | hasher.update(buf[len..][0..i]); | ||
| 56 | const f1 = hasher.final(); | ||
| 57 | const f2 = hasher.final(); | ||
| 58 | if (f1 != f2) return error.IterativeHashWasNotIdempotent; | ||
| 59 | if (f1 != r) return error.IterativeHashDidNotMatchDirect; | ||
| 60 | len += i; | ||
| 61 | } | ||
| 62 | } |
lib/std/hash/wyhash.zig+2-45| ... | @@ -234,51 +234,8 @@ test "smhasher" { | ... | @@ -234,51 +234,8 @@ test "smhasher" { |
| 234 | try expectEqual(verify.smhasher(Wyhash.hash), 0xBD5E840C); | 234 | try expectEqual(verify.smhasher(Wyhash.hash), 0xBD5E840C); |
| 235 | } | 235 | } |
| 236 | 236 | ||
| 237 | test "test vectors streaming" { | 237 | test "iterative api" { |
| 238 | const step = 5; | 238 | try verify.iterativeApi(Wyhash); |
| 239 | |||
| 240 | for (vectors) |e| { | ||
| 241 | var wh = Wyhash.init(e.seed); | ||
| 242 | var i: usize = 0; | ||
| 243 | while (i < e.input.len) : (i += step) { | ||
| 244 | const len = if (i + step > e.input.len) e.input.len - i else step; | ||
| 245 | wh.update(e.input[i..][0..len]); | ||
| 246 | } | ||
| 247 | try expectEqual(e.expected, wh.final()); | ||
| 248 | } | ||
| 249 | } | ||
| 250 | |||
| 251 | test "test ensure idempotent final call" { | ||
| 252 | const e: TestVector = .{ .seed = 6, .expected = 0xc39cab13b115aad3, .input = "12345678901234567890123456789012345678901234567890123456789012345678901234567890" }; | ||
| 253 | var wh = Wyhash.init(e.seed); | ||
| 254 | wh.update(e.input); | ||
| 255 | |||
| 256 | for (0..10) |_| { | ||
| 257 | try expectEqual(e.expected, wh.final()); | ||
| 258 | } | ||
| 259 | } | ||
| 260 | |||
| 261 | test "iterative non-divisible update" { | ||
| 262 | var buf: [8192]u8 = undefined; | ||
| 263 | for (&buf, 0..) |*e, i| { | ||
| 264 | e.* = @as(u8, @truncate(i)); | ||
| 265 | } | ||
| 266 | |||
| 267 | const seed = 0x128dad08f; | ||
| 268 | |||
| 269 | var end: usize = 32; | ||
| 270 | while (end < buf.len) : (end += 32) { | ||
| 271 | const non_iterative_hash = Wyhash.hash(seed, buf[0..end]); | ||
| 272 | |||
| 273 | var wy = Wyhash.init(seed); | ||
| 274 | var i: usize = 0; | ||
| 275 | while (i < end) : (i += 33) { | ||
| 276 | wy.update(buf[i..@min(i + 33, end)]); | ||
| 277 | } | ||
| 278 | const iterative_hash = wy.final(); | ||
| 279 | |||
| 280 | try std.testing.expectEqual(iterative_hash, non_iterative_hash); | ||
| 281 | } | ||
| 282 | } | 239 | } |
| 283 | 240 | ||
| 284 | test "iterative maintains last sixteen" { | 241 | test "iterative maintains last sixteen" { |
lib/std/hash/xxhash.zig+8| ... | @@ -461,6 +461,10 @@ test "xxhash64" { | ... | @@ -461,6 +461,10 @@ test "xxhash64" { |
| 461 | try expectEqual(verify.smhasher(H.hash), 0x024B7CF4); | 461 | try expectEqual(verify.smhasher(H.hash), 0x024B7CF4); |
| 462 | } | 462 | } |
| 463 | 463 | ||
| 464 | test "xxhash64 iterative api" { | ||
| 465 | try verify.iterativeApi(XxHash64); | ||
| 466 | } | ||
| 467 | |||
| 464 | test "xxhash32" { | 468 | test "xxhash32" { |
| 465 | const H = XxHash32; | 469 | const H = XxHash32; |
| 466 | 470 | ||
| ... | @@ -474,3 +478,7 @@ test "xxhash32" { | ... | @@ -474,3 +478,7 @@ test "xxhash32" { |
| 474 | 478 | ||
| 475 | try expectEqual(verify.smhasher(H.hash), 0xBA88B743); | 479 | try expectEqual(verify.smhasher(H.hash), 0xBA88B743); |
| 476 | } | 480 | } |
| 481 | |||
| 482 | test "xxhash32 iterative api" { | ||
| 483 | try verify.iterativeApi(XxHash32); | ||
| 484 | } |