| ... | @@ -1,4 +1,5 @@ | ... | @@ -1,4 +1,5 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| | 2 | const builtin = @import("builtin"); |
| 2 | const mem = std.mem; | 3 | const mem = std.mem; |
| 3 | const expectEqual = std.testing.expectEqual; | 4 | const expectEqual = std.testing.expectEqual; |
| 4 | | 5 | |
| ... | @@ -426,6 +427,361 @@ pub const XxHash32 = struct { | ... | @@ -426,6 +427,361 @@ pub const XxHash32 = struct { |
| 426 | } | 427 | } |
| 427 | }; | 428 | }; |
| 428 | | 429 | |
| | 430 | pub const XxHash3 = struct { |
| | 431 | const Block = @Vector(8, u64); |
| | 432 | const default_secret: [192]u8 = .{ |
| | 433 | 0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c, |
| | 434 | 0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f, |
| | 435 | 0xcb, 0x79, 0xe6, 0x4e, 0xcc, 0xc0, 0xe5, 0x78, 0x82, 0x5a, 0xd0, 0x7d, 0xcc, 0xff, 0x72, 0x21, |
| | 436 | 0xb8, 0x08, 0x46, 0x74, 0xf7, 0x43, 0x24, 0x8e, 0xe0, 0x35, 0x90, 0xe6, 0x81, 0x3a, 0x26, 0x4c, |
| | 437 | 0x3c, 0x28, 0x52, 0xbb, 0x91, 0xc3, 0x00, 0xcb, 0x88, 0xd0, 0x65, 0x8b, 0x1b, 0x53, 0x2e, 0xa3, |
| | 438 | 0x71, 0x64, 0x48, 0x97, 0xa2, 0x0d, 0xf9, 0x4e, 0x38, 0x19, 0xef, 0x46, 0xa9, 0xde, 0xac, 0xd8, |
| | 439 | 0xa8, 0xfa, 0x76, 0x3f, 0xe3, 0x9c, 0x34, 0x3f, 0xf9, 0xdc, 0xbb, 0xc7, 0xc7, 0x0b, 0x4f, 0x1d, |
| | 440 | 0x8a, 0x51, 0xe0, 0x4b, 0xcd, 0xb4, 0x59, 0x31, 0xc8, 0x9f, 0x7e, 0xc9, 0xd9, 0x78, 0x73, 0x64, |
| | 441 | 0xea, 0xc5, 0xac, 0x83, 0x34, 0xd3, 0xeb, 0xc3, 0xc5, 0x81, 0xa0, 0xff, 0xfa, 0x13, 0x63, 0xeb, |
| | 442 | 0x17, 0x0d, 0xdd, 0x51, 0xb7, 0xf0, 0xda, 0x49, 0xd3, 0x16, 0x55, 0x26, 0x29, 0xd4, 0x68, 0x9e, |
| | 443 | 0x2b, 0x16, 0xbe, 0x58, 0x7d, 0x47, 0xa1, 0xfc, 0x8f, 0xf8, 0xb8, 0xd1, 0x7a, 0xd0, 0x31, 0xce, |
| | 444 | 0x45, 0xcb, 0x3a, 0x8f, 0x95, 0x16, 0x04, 0x28, 0xaf, 0xd7, 0xfb, 0xca, 0xbb, 0x4b, 0x40, 0x7e, |
| | 445 | }; |
| | 446 | |
| | 447 | const prime_mx1 = 0x165667919E3779F9; |
| | 448 | const prime_mx2 = 0x9FB21C651E98DF25; |
| | 449 | |
| | 450 | inline fn avalanche(mode: union(enum) { h3, h64, rrmxmx: u64 }, x0: u64) u64 { |
| | 451 | switch (mode) { |
| | 452 | .h3 => { |
| | 453 | const x1 = (x0 ^ (x0 >> 37)) *% prime_mx1; |
| | 454 | return x1 ^ (x1 >> 32); |
| | 455 | }, |
| | 456 | .h64 => { |
| | 457 | const x1 = (x0 ^ (x0 >> 33)) *% XxHash64.prime_2; |
| | 458 | const x2 = (x1 ^ (x1 >> 29)) *% XxHash64.prime_3; |
| | 459 | return x2 ^ (x2 >> 32); |
| | 460 | }, |
| | 461 | .rrmxmx => |len| { |
| | 462 | const x1 = (x0 ^ rotl(u64, x0, 49) ^ rotl(u64, x0, 24)) *% prime_mx2; |
| | 463 | const x2 = (x1 ^ ((x1 >> 35) +% len)) *% prime_mx2; |
| | 464 | return x2 ^ (x2 >> 28); |
| | 465 | }, |
| | 466 | } |
| | 467 | } |
| | 468 | |
| | 469 | inline fn fold(a: u64, b: u64) u64 { |
| | 470 | const wide: [2]u64 = @bitCast(@as(u128, a) *% b); |
| | 471 | return wide[0] ^ wide[1]; |
| | 472 | } |
| | 473 | |
| | 474 | inline fn swap(x: anytype) @TypeOf(x) { |
| | 475 | return if (builtin.cpu.arch.endian() == .Big) @byteSwap(x) else x; |
| | 476 | } |
| | 477 | |
| | 478 | inline fn disableAutoVectorization(x: anytype) void { |
| | 479 | if (!@inComptime()) asm volatile ("" |
| | 480 | : |
| | 481 | : [x] "r" (x), |
| | 482 | ); |
| | 483 | } |
| | 484 | |
| | 485 | inline fn mix16(seed: u64, input: []const u8, secret: []const u8) u64 { |
| | 486 | const blk: [4]u64 = @bitCast([_][16]u8{ input[0..16].*, secret[0..16].* }); |
| | 487 | disableAutoVectorization(seed); |
| | 488 | |
| | 489 | return fold( |
| | 490 | swap(blk[0]) ^ (swap(blk[2]) +% seed), |
| | 491 | swap(blk[1]) ^ (swap(blk[3]) -% seed), |
| | 492 | ); |
| | 493 | } |
| | 494 | |
| | 495 | const Accumulator = extern struct { |
| | 496 | consumed: usize = 0, |
| | 497 | seed: u64, |
| | 498 | secret: [192]u8 = undefined, |
| | 499 | state: Block = Block{ |
| | 500 | XxHash32.prime_3, |
| | 501 | XxHash64.prime_1, |
| | 502 | XxHash64.prime_2, |
| | 503 | XxHash64.prime_3, |
| | 504 | XxHash64.prime_4, |
| | 505 | XxHash32.prime_2, |
| | 506 | XxHash64.prime_5, |
| | 507 | XxHash32.prime_1, |
| | 508 | }, |
| | 509 | |
| | 510 | inline fn init(seed: u64) Accumulator { |
| | 511 | var self = Accumulator{ .seed = seed }; |
| | 512 | for ( |
| | 513 | std.mem.bytesAsSlice(Block, &self.secret), |
| | 514 | std.mem.bytesAsSlice(Block, &default_secret), |
| | 515 | ) |*dst, src| { |
| | 516 | dst.* = swap(swap(src) +% Block{ |
| | 517 | seed, @as(u64, 0) -% seed, |
| | 518 | seed, @as(u64, 0) -% seed, |
| | 519 | seed, @as(u64, 0) -% seed, |
| | 520 | seed, @as(u64, 0) -% seed, |
| | 521 | }); |
| | 522 | } |
| | 523 | return self; |
| | 524 | } |
| | 525 | |
| | 526 | inline fn round( |
| | 527 | noalias state: *Block, |
| | 528 | noalias input_block: *align(1) const Block, |
| | 529 | noalias secret_block: *align(1) const Block, |
| | 530 | ) void { |
| | 531 | const data = swap(input_block.*); |
| | 532 | const mixed = data ^ swap(secret_block.*); |
| | 533 | state.* +%= (mixed & @as(Block, @splat(0xffffffff))) *% (mixed >> @splat(32)); |
| | 534 | state.* +%= @shuffle(u64, data, undefined, [_]i32{ 1, 0, 3, 2, 5, 4, 7, 6 }); |
| | 535 | } |
| | 536 | |
| | 537 | fn accumulate(noalias self: *Accumulator, blocks: []align(1) const Block) void { |
| | 538 | const secret = std.mem.bytesAsSlice(u64, self.secret[self.consumed * 8 ..]); |
| | 539 | for (blocks, secret[0..blocks.len]) |*input_block, *secret_block| { |
| | 540 | @prefetch(@as([*]const u8, @ptrCast(input_block)) + 320, .{}); |
| | 541 | round(&self.state, input_block, @ptrCast(secret_block)); |
| | 542 | } |
| | 543 | } |
| | 544 | |
| | 545 | fn scramble(self: *Accumulator) void { |
| | 546 | const secret_block: Block = @bitCast(self.secret[192 - @sizeOf(Block) .. 192].*); |
| | 547 | self.state ^= self.state >> @splat(47); |
| | 548 | self.state ^= swap(secret_block); |
| | 549 | self.state *%= @as(Block, @splat(XxHash32.prime_1)); |
| | 550 | } |
| | 551 | |
| | 552 | fn consume(noalias self: *Accumulator, input_blocks: []align(1) const Block) void { |
| | 553 | const blocks_per_scramble = 1024 / @sizeOf(Block); |
| | 554 | std.debug.assert(self.consumed <= blocks_per_scramble); |
| | 555 | |
| | 556 | var blocks = input_blocks; |
| | 557 | var blocks_until_scramble = blocks_per_scramble - self.consumed; |
| | 558 | while (blocks.len >= blocks_until_scramble) { |
| | 559 | self.accumulate(blocks[0..blocks_until_scramble]); |
| | 560 | self.scramble(); |
| | 561 | |
| | 562 | self.consumed = 0; |
| | 563 | blocks = blocks[blocks_until_scramble..]; |
| | 564 | blocks_until_scramble = blocks_per_scramble; |
| | 565 | } |
| | 566 | |
| | 567 | self.accumulate(blocks); |
| | 568 | self.consumed += blocks.len; |
| | 569 | } |
| | 570 | |
| | 571 | fn digest(noalias self: *Accumulator, total_len: u64, noalias last_block: *align(1) const Block) u64 { |
| | 572 | const secret_block = self.secret[192 - @sizeOf(Block) - 7 ..][0..@sizeOf(Block)]; |
| | 573 | round(&self.state, last_block, @ptrCast(secret_block)); |
| | 574 | |
| | 575 | const merge_block: Block = @bitCast(self.secret[11 .. 11 + @sizeOf(Block)].*); |
| | 576 | self.state ^= swap(merge_block); |
| | 577 | |
| | 578 | var result = XxHash64.prime_1 *% total_len; |
| | 579 | inline for (0..4) |i| { |
| | 580 | result +%= fold(self.state[i * 2], self.state[i * 2 + 1]); |
| | 581 | } |
| | 582 | return avalanche(.h3, result); |
| | 583 | } |
| | 584 | }; |
| | 585 | |
| | 586 | // Public API - Oneshot |
| | 587 | |
| | 588 | pub fn hash(seed: u64, input: anytype) u64 { |
| | 589 | validateType(@TypeOf(input)); |
| | 590 | |
| | 591 | const secret = &default_secret; |
| | 592 | if (input.len > 240) return hashLong(seed, input); |
| | 593 | if (input.len > 128) return hash240(seed, input, secret); |
| | 594 | if (input.len > 16) return hash128(seed, input, secret); |
| | 595 | if (input.len > 8) return hash16(seed, input, secret); |
| | 596 | if (input.len > 3) return hash8(seed, input, secret); |
| | 597 | if (input.len > 0) return hash3(seed, input, secret); |
| | 598 | |
| | 599 | const flip: [2]u64 = @bitCast(secret[56..72].*); |
| | 600 | const key = swap(flip[0]) ^ swap(flip[1]); |
| | 601 | return avalanche(.h64, seed ^ key); |
| | 602 | } |
| | 603 | |
| | 604 | fn hash3(seed: u64, input: anytype, noalias secret: *const [192]u8) u64 { |
| | 605 | @setCold(true); |
| | 606 | std.debug.assert(input.len > 0 and input.len < 4); |
| | 607 | |
| | 608 | const flip: [2]u32 = @bitCast(secret[0..8].*); |
| | 609 | const blk: u32 = @bitCast([_]u8{ |
| | 610 | input[input.len - 1], |
| | 611 | @truncate(input.len), |
| | 612 | input[0], |
| | 613 | input[input.len / 2], |
| | 614 | }); |
| | 615 | |
| | 616 | const key = @as(u64, swap(flip[0]) ^ swap(flip[1])) +% seed; |
| | 617 | return avalanche(.h64, key ^ swap(blk)); |
| | 618 | } |
| | 619 | |
| | 620 | fn hash8(seed: u64, input: anytype, noalias secret: *const [192]u8) u64 { |
| | 621 | @setCold(true); |
| | 622 | std.debug.assert(input.len >= 4 and input.len <= 8); |
| | 623 | |
| | 624 | const flip: [2]u64 = @bitCast(secret[8..24].*); |
| | 625 | const blk: [2]u32 = @bitCast([_][4]u8{ |
| | 626 | input[0..4].*, |
| | 627 | input[input.len - 4 ..][0..4].*, |
| | 628 | }); |
| | 629 | |
| | 630 | const mixed = seed ^ (@as(u64, @byteSwap(@as(u32, @truncate(seed)))) << 32); |
| | 631 | const key = (swap(flip[0]) ^ swap(flip[1])) -% mixed; |
| | 632 | const combined = (@as(u64, swap(blk[0])) << 32) +% swap(blk[1]); |
| | 633 | return avalanche(.{ .rrmxmx = input.len }, key ^ combined); |
| | 634 | } |
| | 635 | |
| | 636 | fn hash16(seed: u64, input: anytype, noalias secret: *const [192]u8) u64 { |
| | 637 | @setCold(true); |
| | 638 | std.debug.assert(input.len > 8 and input.len <= 16); |
| | 639 | |
| | 640 | const flip: [4]u64 = @bitCast(secret[24..56].*); |
| | 641 | const blk: [2]u64 = @bitCast([_][8]u8{ |
| | 642 | input[0..8].*, |
| | 643 | input[input.len - 8 ..][0..8].*, |
| | 644 | }); |
| | 645 | |
| | 646 | const lo = swap(blk[0]) ^ ((swap(flip[0]) ^ swap(flip[1])) +% seed); |
| | 647 | const hi = swap(blk[1]) ^ ((swap(flip[2]) ^ swap(flip[3])) -% seed); |
| | 648 | const combined = @as(u64, input.len) +% @byteSwap(lo) +% hi +% fold(lo, hi); |
| | 649 | return avalanche(.h3, combined); |
| | 650 | } |
| | 651 | |
| | 652 | fn hash128(seed: u64, input: anytype, noalias secret: *const [192]u8) u64 { |
| | 653 | @setCold(true); |
| | 654 | std.debug.assert(input.len > 16 and input.len <= 128); |
| | 655 | |
| | 656 | var acc = XxHash64.prime_1 *% @as(u64, input.len); |
| | 657 | inline for (0..4) |i| { |
| | 658 | const in_offset = 48 - (i * 16); |
| | 659 | const scrt_offset = 96 - (i * 32); |
| | 660 | if (input.len > scrt_offset) { |
| | 661 | acc +%= mix16(seed, input[in_offset..], secret[scrt_offset..]); |
| | 662 | acc +%= mix16(seed, input[input.len - (in_offset + 16) ..], secret[scrt_offset + 16 ..]); |
| | 663 | } |
| | 664 | } |
| | 665 | return avalanche(.h3, acc); |
| | 666 | } |
| | 667 | |
| | 668 | fn hash240(seed: u64, input: anytype, noalias secret: *const [192]u8) u64 { |
| | 669 | @setCold(true); |
| | 670 | std.debug.assert(input.len > 128 and input.len <= 240); |
| | 671 | |
| | 672 | var acc = XxHash64.prime_1 *% @as(u64, input.len); |
| | 673 | inline for (0..8) |i| { |
| | 674 | acc +%= mix16(seed, input[i * 16 ..], secret[i * 16 ..]); |
| | 675 | } |
| | 676 | |
| | 677 | var acc_end = mix16(seed, input[input.len - 16 ..], secret[136 - 17 ..]); |
| | 678 | for (8..(input.len / 16)) |i| { |
| | 679 | acc_end +%= mix16(seed, input[i * 16 ..], secret[((i - 8) * 16) + 3 ..]); |
| | 680 | disableAutoVectorization(i); |
| | 681 | } |
| | 682 | |
| | 683 | acc = avalanche(.h3, acc) +% acc_end; |
| | 684 | return avalanche(.h3, acc); |
| | 685 | } |
| | 686 | |
| | 687 | noinline fn hashLong(seed: u64, input: []const u8) u64 { |
| | 688 | @setCold(true); |
| | 689 | std.debug.assert(input.len >= 240); |
| | 690 | |
| | 691 | const block_count = ((input.len - 1) / @sizeOf(Block)) * @sizeOf(Block); |
| | 692 | const last_block = input[input.len - @sizeOf(Block) ..][0..@sizeOf(Block)]; |
| | 693 | |
| | 694 | var acc = Accumulator.init(seed); |
| | 695 | acc.consume(std.mem.bytesAsSlice(Block, input[0..block_count])); |
| | 696 | return acc.digest(input.len, @ptrCast(last_block)); |
| | 697 | } |
| | 698 | |
| | 699 | // Public API - Streaming |
| | 700 | |
| | 701 | buffered: usize = 0, |
| | 702 | buffer: [256]u8 = undefined, |
| | 703 | total_len: usize = 0, |
| | 704 | accumulator: Accumulator, |
| | 705 | |
| | 706 | pub fn init(seed: u64) XxHash3 { |
| | 707 | return .{ .accumulator = Accumulator.init(seed) }; |
| | 708 | } |
| | 709 | |
| | 710 | pub fn update(self: *XxHash3, input: anytype) void { |
| | 711 | validateType(@TypeOf(input)); |
| | 712 | |
| | 713 | self.total_len += input.len; |
| | 714 | std.debug.assert(self.buffered <= self.buffer.len); |
| | 715 | |
| | 716 | // Copy the input into the buffer if we haven't filled it up yet. |
| | 717 | const remaining = self.buffer.len - self.buffered; |
| | 718 | if (input.len <= remaining) { |
| | 719 | @memcpy(self.buffer[self.buffered..][0..input.len], input); |
| | 720 | self.buffered += input.len; |
| | 721 | return; |
| | 722 | } |
| | 723 | |
| | 724 | // Input will overflow the buffer. Fill up the buffer with some input and consume it. |
| | 725 | var consumable: []const u8 = input; |
| | 726 | if (self.buffered > 0) { |
| | 727 | @memcpy(self.buffer[self.buffered..], consumable[0..remaining]); |
| | 728 | consumable = consumable[remaining..]; |
| | 729 | |
| | 730 | self.accumulator.consume(std.mem.bytesAsSlice(Block, &self.buffer)); |
| | 731 | self.buffered = 0; |
| | 732 | } |
| | 733 | |
| | 734 | // The input isn't small enough to fit in the buffer. Consume it directly. |
| | 735 | if (consumable.len > self.buffer.len) { |
| | 736 | const block_count = ((consumable.len - 1) / @sizeOf(Block)) * @sizeOf(Block); |
| | 737 | self.accumulator.consume(std.mem.bytesAsSlice(Block, consumable[0..block_count])); |
| | 738 | consumable = consumable[block_count..]; |
| | 739 | |
| | 740 | // In case we consume all remaining input, write the last block to end of the buffer |
| | 741 | // to populate the last_block_copy in final() similar to hashLong()'s last_block. |
| | 742 | @memcpy( |
| | 743 | self.buffer[self.buffer.len - @sizeOf(Block) .. self.buffer.len], |
| | 744 | (consumable.ptr - @sizeOf(Block))[0..@sizeOf(Block)], |
| | 745 | ); |
| | 746 | } |
| | 747 | |
| | 748 | // Copy in any remaining input into the buffer. |
| | 749 | std.debug.assert(consumable.len <= self.buffer.len); |
| | 750 | @memcpy(self.buffer[0..consumable.len], consumable); |
| | 751 | self.buffered = consumable.len; |
| | 752 | } |
| | 753 | |
| | 754 | pub fn final(self: *XxHash3) u64 { |
| | 755 | std.debug.assert(self.buffered <= self.total_len); |
| | 756 | std.debug.assert(self.buffered <= self.buffer.len); |
| | 757 | |
| | 758 | // Use Oneshot hashing for smaller sizes as it doesn't use Accumulator like hashLong. |
| | 759 | if (self.total_len <= 240) { |
| | 760 | return hash(self.accumulator.seed, self.buffer[0..self.total_len]); |
| | 761 | } |
| | 762 | |
| | 763 | // Make a copy of the Accumulator state in case `self` needs to update() / be used later. |
| | 764 | var accumulator_copy = self.accumulator; |
| | 765 | var last_block_copy: [@sizeOf(Block)]u8 = undefined; |
| | 766 | |
| | 767 | // Digest the last block onthe Accumulator copy. |
| | 768 | return accumulator_copy.digest(self.total_len, last_block: { |
| | 769 | if (self.buffered >= @sizeOf(Block)) { |
| | 770 | const block_count = ((self.buffered - 1) / @sizeOf(Block)) * @sizeOf(Block); |
| | 771 | accumulator_copy.consume(std.mem.bytesAsSlice(Block, self.buffer[0..block_count])); |
| | 772 | break :last_block @ptrCast(self.buffer[self.buffered - @sizeOf(Block) ..][0..@sizeOf(Block)]); |
| | 773 | } else { |
| | 774 | const remaining = @sizeOf(Block) - self.buffered; |
| | 775 | @memcpy(last_block_copy[0..remaining], self.buffer[self.buffer.len - remaining ..][0..remaining]); |
| | 776 | @memcpy(last_block_copy[remaining..][0..self.buffered], self.buffer[0..self.buffered]); |
| | 777 | break :last_block @ptrCast(&last_block_copy); |
| | 778 | } |
| | 779 | }); |
| | 780 | } |
| | 781 | }; |
| | 782 | |
| | 783 | const verify = @import("verify.zig"); |
| | 784 | |
| 429 | fn validateType(comptime T: type) void { | 785 | fn validateType(comptime T: type) void { |
| 430 | comptime { | 786 | comptime { |
| 431 | if (!((std.meta.trait.isSlice(T) or | 787 | if (!((std.meta.trait.isSlice(T) or |
| ... | @@ -438,16 +794,67 @@ fn validateType(comptime T: type) void { | ... | @@ -438,16 +794,67 @@ fn validateType(comptime T: type) void { |
| 438 | } | 794 | } |
| 439 | } | 795 | } |
| 440 | | 796 | |
| 441 | const verify = @import("verify.zig"); | | |
| 442 | | | |
| 443 | fn testExpect(comptime H: type, seed: anytype, input: []const u8, expected: u64) !void { | 797 | fn testExpect(comptime H: type, seed: anytype, input: []const u8, expected: u64) !void { |
| 444 | try expectEqual(expected, H.hash(0, input)); | 798 | try expectEqual(expected, H.hash(seed, input)); |
| 445 | | 799 | |
| 446 | var hasher = H.init(seed); | 800 | var hasher = H.init(seed); |
| 447 | hasher.update(input); | 801 | hasher.update(input); |
| 448 | try expectEqual(expected, hasher.final()); | 802 | try expectEqual(expected, hasher.final()); |
| 449 | } | 803 | } |
| 450 | | 804 | |
| | 805 | test "xxhash3" { |
| | 806 | const H = XxHash3; |
| | 807 | // Non-Seeded Tests |
| | 808 | try testExpect(H, 0, "", 0x2d06800538d394c2); |
| | 809 | try testExpect(H, 0, "a", 0xe6c632b61e964e1f); |
| | 810 | try testExpect(H, 0, "abc", 0x78af5f94892f3950); |
| | 811 | try testExpect(H, 0, "message", 0x0b1ca9b8977554fa); |
| | 812 | try testExpect(H, 0, "message digest", 0x160d8e9329be94f9); |
| | 813 | try testExpect(H, 0, "abcdefghijklmnopqrstuvwxyz", 0x810f9ca067fbb90c); |
| | 814 | try testExpect(H, 0, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 0x643542bb51639cb2); |
| | 815 | try testExpect(H, 0, "12345678901234567890123456789012345678901234567890123456789012345678901234567890", 0x7f58aa2520c681f9); |
| | 816 | try testExpect(H, 0, "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678", 0xb66ea795b5edc38c); |
| | 817 | try testExpect(H, 0, "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", 0x8845e0b1b57330de); |
| | 818 | try testExpect(H, 0, "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123123", 0xf031f373d63c5653); |
| | 819 | try testExpect(H, 0, "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", 0xf1bf601f9d868dce); |
| | 820 | |
| | 821 | // Seeded Tests |
| | 822 | try testExpect(H, 1, "", 0x4dc5b0cc826f6703); |
| | 823 | try testExpect(H, 1, "a", 0xd2f6d0996f37a720); |
| | 824 | try testExpect(H, 1, "abc", 0x6b4467b443c76228); |
| | 825 | try testExpect(H, 1, "message", 0x73fb1cf20d561766); |
| | 826 | try testExpect(H, 1, "message digest", 0xfe71a82a70381174); |
| | 827 | try testExpect(H, 1, "abcdefghijklmnopqrstuvwxyz", 0x902a2c2d016a37ba); |
| | 828 | try testExpect(H, 1, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 0xbf552e540c5c6882); |
| | 829 | try testExpect(H, 1, "12345678901234567890123456789012345678901234567890123456789012345678901234567890", 0xf2ca33235a6b865b); |
| | 830 | try testExpect(H, 1, "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678", 0x6ef5cf958ba52c4); |
| | 831 | try testExpect(H, 1, "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", 0xfbc5f9c53d21cb2f); |
| | 832 | try testExpect(H, 1, "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123123", 0x48682aca3b1c5c18); |
| | 833 | try testExpect(H, 1, "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", 0x3903c5437fc4e726); |
| | 834 | } |
| | 835 | |
| | 836 | test "xxhash3 smhasher" { |
| | 837 | const Test = struct { |
| | 838 | fn do() !void { |
| | 839 | try expectEqual(verify.smhasher(XxHash3.hash), 0x9a636405); |
| | 840 | } |
| | 841 | }; |
| | 842 | try Test.do(); |
| | 843 | @setEvalBranchQuota(75000); |
| | 844 | comptime try Test.do(); |
| | 845 | } |
| | 846 | |
| | 847 | test "xxhash3 iterative api" { |
| | 848 | const Test = struct { |
| | 849 | fn do() !void { |
| | 850 | try verify.iterativeApi(XxHash3); |
| | 851 | } |
| | 852 | }; |
| | 853 | try Test.do(); |
| | 854 | @setEvalBranchQuota(30000); |
| | 855 | comptime try Test.do(); |
| | 856 | } |
| | 857 | |
| 451 | test "xxhash64" { | 858 | test "xxhash64" { |
| 452 | const H = XxHash64; | 859 | const H = XxHash64; |
| 453 | try testExpect(H, 0, "", 0xef46db3751d8e999); | 860 | try testExpect(H, 0, "", 0xef46db3751d8e999); |