@@ -623,14 +623,16 @@ size_t bytesHash()(scope const(void)* buf, size_t len, size_t seed)
623
623
624
624
private template bytesHashAlignedBy (AlignType)
625
625
{
626
- alias bytesHashAlignedBy = bytesHash! (AlignType.alignof >= uint .alignof);
626
+ static if (size_t .sizeof == 4 )
627
+ alias bytesHashAlignedBy = bytesHash32! (AlignType.alignof >= uint .alignof);
628
+ else
629
+ alias bytesHashAlignedBy = bytesHash64! ();
627
630
}
628
631
629
632
private template bytesHashWithExactSizeAndAlignment (SizeAndAlignType)
630
633
{
631
- static if (SizeAndAlignType.alignof < uint .alignof
632
- ? SizeAndAlignType.sizeof <= 12
633
- : SizeAndAlignType.sizeof <= 10 )
634
+ static if (SizeAndAlignType.sizeof <= 3 || size_t .sizeof <= 4 &&
635
+ SizeAndAlignType.sizeof <= (SizeAndAlignType.alignof < uint .alignof ? 12 : 10 ))
634
636
alias bytesHashWithExactSizeAndAlignment = smallBytesHash;
635
637
else
636
638
alias bytesHashWithExactSizeAndAlignment = bytesHashAlignedBy! SizeAndAlignType;
@@ -670,9 +672,11 @@ private uint get32bits()(scope const(ubyte)* x) @nogc nothrow pure @system
670
672
Params:
671
673
dataKnownToBeAligned = whether the data is known at compile time to be uint-aligned.
672
674
+/
675
+ static if (size_t .sizeof == 4 )
673
676
@nogc nothrow pure @trusted
674
- private size_t bytesHash (bool dataKnownToBeAligned)(scope const (ubyte )[] bytes, size_t seed)
677
+ private uint bytesHash32 (bool dataKnownToBeAligned)(scope const (ubyte )[] bytes, size_t seed)
675
678
{
679
+ // MurmurHash3_x86_32.
676
680
auto len = bytes.length;
677
681
auto data = bytes.ptr;
678
682
auto nblocks = len / 4 ;
@@ -725,6 +729,85 @@ private size_t bytesHash(bool dataKnownToBeAligned)(scope const(ubyte)[] bytes,
725
729
return h1;
726
730
}
727
731
732
+ static if (size_t .sizeof == 8 )
733
+ @nogc nothrow pure @trusted
734
+ private ulong bytesHash64 ()(scope const ubyte [] bytes, ulong seed)
735
+ {
736
+ // MurmurHash3_x86_32 modified to be 64-bit using constants from MurmurHash3_x64_128.
737
+ alias h1 = seed;
738
+
739
+ enum ulong c1 = 0x87c37b91114253d5 ;
740
+ enum ulong c2 = 0x4cf5ad432745937f ;
741
+ enum uint c3 = 0x52dce729 ;
742
+
743
+ const (ubyte )* data = bytes.ptr;
744
+ // ----------
745
+ // body
746
+ for (const end_data = bytes.ptr + (bytes.length & ~ 7 );
747
+ data ! is end_data;
748
+ data += 8 )
749
+ {
750
+ version (BigEndian )
751
+ {
752
+ auto k1 =
753
+ ((cast (ulong ) data[0 ]) << 56 ) |
754
+ ((cast (ulong ) data[1 ]) << 48 ) |
755
+ ((cast (ulong ) data[2 ]) << 40 ) |
756
+ ((cast (ulong ) data[3 ]) << 32 ) |
757
+ ((cast (ulong ) data[4 ]) << 24 ) |
758
+ ((cast (ulong ) data[5 ]) << 16 ) |
759
+ ((cast (ulong ) data[6 ]) << 8 ) |
760
+ (cast (ulong ) data[7 ]);
761
+ }
762
+ else
763
+ {
764
+ auto k1 =
765
+ ((cast (ulong ) data[7 ]) << 56 ) |
766
+ ((cast (ulong ) data[6 ]) << 48 ) |
767
+ ((cast (ulong ) data[5 ]) << 40 ) |
768
+ ((cast (ulong ) data[4 ]) << 32 ) |
769
+ ((cast (ulong ) data[3 ]) << 24 ) |
770
+ ((cast (ulong ) data[2 ]) << 16 ) |
771
+ ((cast (ulong ) data[1 ]) << 8 ) |
772
+ (cast (ulong ) data[0 ]);
773
+ }
774
+
775
+ k1 *= c1;
776
+ k1 = (k1 << 31 ) | (k1 >> (64 - 31 ));
777
+ k1 *= c2;
778
+
779
+ h1 ^= k1;
780
+ h1 = (h1 << 27 ) | (h1 >> (64 - 27 ));
781
+ h1 = h1* 5 + c3;
782
+ }
783
+
784
+ // ----------
785
+ // tail
786
+ ulong k1 = 0 ;
787
+
788
+ switch (bytes.length & 7 )
789
+ {
790
+ case 7 : k1 ^= (cast (ulong ) data[6 ]) << 48 ; goto case ;
791
+ case 6 : k1 ^= (cast (ulong ) data[5 ]) << 40 ; goto case ;
792
+ case 5 : k1 ^= (cast (ulong ) data[4 ]) << 32 ; goto case ;
793
+ case 4 : k1 ^= (cast (ulong ) data[3 ]) << 24 ; goto case ;
794
+ case 3 : k1 ^= (cast (ulong ) data[2 ]) << 16 ; goto case ;
795
+ case 2 : k1 ^= (cast (ulong ) data[1 ]) << 8 ; goto case ;
796
+ case 1 : k1 ^= (cast (ulong ) data[0 ]);
797
+ k1 *= c1; k1 = (k1 << 31 ) | (k1 >> (64 - 31 )); k1 *= c2; h1 ^= k1;
798
+ goto default ;
799
+ default :
800
+ }
801
+
802
+ // ----------
803
+ // finalization
804
+ h1 ^= bytes.length;
805
+ // Force all bits of the hash block to avalanche.
806
+ h1 = (h1 ^ (h1 >> 33 )) * 0xff51afd7ed558ccd ;
807
+ h1 = (h1 ^ (h1 >> 33 )) * 0xc4ceb9fe1a85ec53 ;
808
+ return h1 ^= h1 >> 33 ;
809
+ }
810
+
728
811
// Check that bytesHash works with CTFE
729
812
pure nothrow @system @nogc unittest
730
813
{
@@ -750,7 +833,8 @@ pure nothrow @system @nogc unittest
750
833
}
751
834
// It is okay to change the below values if you make a change
752
835
// that you expect to change the result of bytesHash.
753
- assert (bytesHash(&a[1 ], a.length - 2 , 0 ) == 2727459272 );
754
- assert (bytesHash(&b, 5 , 0 ) == 2727459272 );
755
- assert (bytesHashAlignedBy! uint ((cast (const ubyte * ) &b)[0 .. 5 ], 0 ) == 2727459272 );
836
+ enum expectedResult = size_t .sizeof == 4 ? 2727459272U : 10677742034643552556UL ;
837
+ assert (bytesHash(&a[1 ], a.length - 2 , 0 ) == expectedResult);
838
+ assert (bytesHash(&b, 5 , 0 ) == expectedResult);
839
+ assert (bytesHashAlignedBy! uint ((cast (const ubyte * ) &b)[0 .. 5 ], 0 ) == expectedResult);
756
840
}
0 commit comments