@@ -669,14 +669,21 @@ size_t bytesHash()(scope const(void)* buf, size_t len, size_t seed)
669
669
670
670
private template bytesHashAlignedBy (AlignType)
671
671
{
672
- alias bytesHashAlignedBy = bytesHash! (AlignType.alignof >= uint .alignof);
672
+ static if (size_t .sizeof == 4 )
673
+ alias bytesHashAlignedBy = bytesHash32! (
674
+ AlignType.alignof >= uint .alignof ? uint .alignof :
675
+ ubyte .alignof);
676
+ else
677
+ alias bytesHashAlignedBy = bytesHash64! (
678
+ AlignType.alignof >= ulong .alignof ? ulong .alignof :
679
+ AlignType.alignof >= uint .alignof ? uint .alignof :
680
+ ubyte .alignof);
673
681
}
674
682
675
683
private template bytesHashWithExactSizeAndAlignment (SizeAndAlignType)
676
684
{
677
- static if (SizeAndAlignType.alignof < uint .alignof
678
- ? SizeAndAlignType.sizeof <= 12
679
- : SizeAndAlignType.sizeof <= 10 )
685
+ static if (SizeAndAlignType.sizeof <= 3 || size_t .sizeof <= 4 &&
686
+ SizeAndAlignType.sizeof <= (SizeAndAlignType.alignof < uint .alignof ? 12 : 10 ))
680
687
alias bytesHashWithExactSizeAndAlignment = smallBytesHash;
681
688
else
682
689
alias bytesHashWithExactSizeAndAlignment = bytesHashAlignedBy! SizeAndAlignType;
@@ -712,13 +719,36 @@ private uint get32bits()(scope const(ubyte)* x) @nogc nothrow pure @system
712
719
}
713
720
}
714
721
715
- /+
716
- Params:
717
- dataKnownToBeAligned = whether the data is known at compile time to be uint-aligned.
718
- +/
722
+ private ulong get64bits ()(scope const (ubyte )* x) @nogc nothrow pure @system
723
+ {
724
+ version (BigEndian )
725
+ {
726
+ return ((cast (ulong ) x[0 ]) << 56 ) |
727
+ ((cast (ulong ) x[1 ]) << 48 ) |
728
+ ((cast (ulong ) x[2 ]) << 40 ) |
729
+ ((cast (ulong ) x[3 ]) << 32 ) |
730
+ ((cast (ulong ) x[4 ]) << 24 ) |
731
+ ((cast (ulong ) x[5 ]) << 16 ) |
732
+ ((cast (ulong ) x[6 ]) << 8 ) |
733
+ (cast (ulong ) x[7 ]); }
734
+ else
735
+ {
736
+ return ((cast (ulong ) x[7 ]) << 56 ) |
737
+ ((cast (ulong ) x[6 ]) << 48 ) |
738
+ ((cast (ulong ) x[5 ]) << 40 ) |
739
+ ((cast (ulong ) x[4 ]) << 32 ) |
740
+ ((cast (ulong ) x[3 ]) << 24 ) |
741
+ ((cast (ulong ) x[2 ]) << 16 ) |
742
+ ((cast (ulong ) x[1 ]) << 8 ) |
743
+ (cast (ulong ) x[0 ]);
744
+ }
745
+ }
746
+
747
+ static if (size_t .sizeof == 4 )
719
748
@nogc nothrow pure @trusted
720
- private size_t bytesHash ( bool dataKnownToBeAligned )(scope const (ubyte )[] bytes, size_t seed)
749
+ private uint bytesHash32 ( uint alignment )(scope const (ubyte )[] bytes, size_t seed)
721
750
{
751
+ // MurmurHash3_x86_32.
722
752
auto len = bytes.length;
723
753
auto data = bytes.ptr;
724
754
auto nblocks = len / 4 ;
@@ -734,10 +764,12 @@ private size_t bytesHash(bool dataKnownToBeAligned)(scope const(ubyte)[] bytes,
734
764
auto end_data = data+ nblocks* uint .sizeof;
735
765
for (; data!= end_data; data += uint .sizeof)
736
766
{
737
- static if (dataKnownToBeAligned )
767
+ static if (alignment == uint .alignof )
738
768
uint k1 = __ctfe ? get32bits(data) : * (cast (const uint * ) data);
739
- else
769
+ else static if (alignment == ubyte .alignof)
740
770
uint k1 = get32bits(data);
771
+ else
772
+ static assert (0 , " Do not create unnecessary template instantiations." );
741
773
k1 *= c1;
742
774
k1 = (k1 << 15 ) | (k1 >> (32 - 15 ));
743
775
k1 *= c2;
@@ -771,6 +803,74 @@ private size_t bytesHash(bool dataKnownToBeAligned)(scope const(ubyte)[] bytes,
771
803
return h1;
772
804
}
773
805
806
+ static if (size_t .sizeof == 8 )
807
+ @nogc nothrow pure @trusted
808
+ private ulong bytesHash64 (uint alignment)(scope const ubyte [] bytes, ulong seed)
809
+ {
810
+ // MurmurHash3_x86_32 modified to be 64-bit using constants from MurmurHash3_x64_128.
811
+ alias h1 = seed;
812
+
813
+ enum ulong c1 = 0x87c37b91114253d5 ;
814
+ enum ulong c2 = 0x4cf5ad432745937f ;
815
+ enum uint c3 = 0x52dce729 ;
816
+
817
+ const (ubyte )* data = bytes.ptr;
818
+ // ----------
819
+ // body
820
+ for (const end_data = bytes.ptr + (bytes.length & ~ 7 );
821
+ data ! is end_data;
822
+ data += 8 )
823
+ {
824
+ static if (alignment == ulong .alignof)
825
+ auto k1 = __ctfe ? get64bits(data) : * cast (ulong * ) data;
826
+ else static if (alignment == uint .alignof)
827
+ {
828
+ version (BigEndian )
829
+ auto k1 = __ctfe ? get64bits(data) : (((cast (ulong ) * cast (uint * ) data) << 32 ) | * cast (uint * ) (data + 4 ));
830
+ else
831
+ auto k1 = __ctfe ? get64bits(data) : (((cast (ulong ) * cast (uint * ) (data + 4 )) << 32 ) | * cast (uint * ) data);
832
+ }
833
+ else static if (alignment == ubyte .alignof)
834
+ auto k1 = get64bits(data);
835
+ else
836
+ static assert (0 , " Do not create unnecessary template instantiations." );
837
+
838
+ k1 *= c1;
839
+ k1 = (k1 << 31 ) | (k1 >> (64 - 31 ));
840
+ k1 *= c2;
841
+
842
+ h1 ^= k1;
843
+ h1 = (h1 << 27 ) | (h1 >> (64 - 27 ));
844
+ h1 = h1* 5 + c3;
845
+ }
846
+
847
+ // ----------
848
+ // tail
849
+ ulong k1 = 0 ;
850
+
851
+ switch (bytes.length & 7 )
852
+ {
853
+ case 7 : k1 ^= (cast (ulong ) data[6 ]) << 48 ; goto case ;
854
+ case 6 : k1 ^= (cast (ulong ) data[5 ]) << 40 ; goto case ;
855
+ case 5 : k1 ^= (cast (ulong ) data[4 ]) << 32 ; goto case ;
856
+ case 4 : k1 ^= (cast (ulong ) data[3 ]) << 24 ; goto case ;
857
+ case 3 : k1 ^= (cast (ulong ) data[2 ]) << 16 ; goto case ;
858
+ case 2 : k1 ^= (cast (ulong ) data[1 ]) << 8 ; goto case ;
859
+ case 1 : k1 ^= (cast (ulong ) data[0 ]);
860
+ k1 *= c1; k1 = (k1 << 31 ) | (k1 >> (64 - 31 )); k1 *= c2; h1 ^= k1;
861
+ goto default ;
862
+ default :
863
+ }
864
+
865
+ // ----------
866
+ // finalization
867
+ h1 ^= bytes.length;
868
+ // Force all bits of the hash block to avalanche.
869
+ h1 = (h1 ^ (h1 >> 33 )) * 0xff51afd7ed558ccd ;
870
+ h1 = (h1 ^ (h1 >> 33 )) * 0xc4ceb9fe1a85ec53 ;
871
+ return h1 ^= h1 >> 33 ;
872
+ }
873
+
774
874
// Check that bytesHash works with CTFE
775
875
pure nothrow @system @nogc unittest
776
876
{
@@ -788,15 +888,21 @@ pure nothrow @system @nogc unittest
788
888
{
789
889
const ubyte [7 ] a = [99 , 4 , 3 , 2 , 1 , 5 , 88 ];
790
890
const uint [2 ] b = [0x04_03_02_01, 0x05_ff_ff_ff];
891
+ const ulong [1 ] c = [0x04_03_02_01_05_ff_ff_ff];
791
892
}
792
893
else
793
894
{
794
895
const ubyte [7 ] a = [99 , 1 , 2 , 3 , 4 , 5 , 88 ];
795
896
const uint [2 ] b = [0x04_03_02_01, 0xff_ff_ff_05];
897
+ const ulong [1 ] c = [0xff_ff_ff_05_04_03_02_01];
796
898
}
797
899
// It is okay to change the below values if you make a change
798
900
// that you expect to change the result of bytesHash.
799
- assert (bytesHash(&a[1 ], a.length - 2 , 0 ) == 2727459272 );
800
- assert (bytesHash(&b, 5 , 0 ) == 2727459272 );
801
- assert (bytesHashAlignedBy! uint ((cast (const ubyte * ) &b)[0 .. 5 ], 0 ) == 2727459272 );
901
+ enum expectedResult = size_t .sizeof == 4 ? 2727459272U : 10677742034643552556UL ;
902
+ assert (bytesHash(&a[1 ], a.length - 2 , 0 ) == expectedResult);
903
+ assert (bytesHash(&b, 5 , 0 ) == expectedResult);
904
+ assert (bytesHashAlignedBy! uint ((cast (const ubyte * ) &b)[0 .. 5 ], 0 ) == expectedResult);
905
+ assert (bytesHashAlignedBy! ulong ((cast (const ubyte * ) &c)[0 .. 5 ], 0 ) == expectedResult);
906
+ assert (bytesHashAlignedBy! ulong ((cast (const ubyte * ) &c)[0 .. c.sizeof], 0 ) ==
907
+ (size_t .sizeof == 4 ? 2948526704 : 7625915911016357963 ));
802
908
}
0 commit comments