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