@@ -623,14 +623,21 @@ size_t bytesHash()(scope const(void)* buf, size_t len, size_t seed)
623623
624624private template bytesHashAlignedBy (AlignType)
625625{
626- alias bytesHashAlignedBy = bytesHash! (AlignType.alignof >= uint .alignof);
626+ static if (size_t .sizeof == 4 )
627+ alias bytesHashAlignedBy = bytesHash32! (
628+ AlignType.alignof >= uint .alignof ? uint .alignof :
629+ ubyte .alignof);
630+ else
631+ alias bytesHashAlignedBy = bytesHash64! (
632+ AlignType.alignof >= ulong .alignof ? ulong .alignof :
633+ AlignType.alignof >= uint .alignof ? uint .alignof :
634+ ubyte .alignof);
627635}
628636
629637private template bytesHashWithExactSizeAndAlignment (SizeAndAlignType)
630638{
631- static if (SizeAndAlignType.alignof < uint .alignof
632- ? SizeAndAlignType.sizeof <= 12
633- : SizeAndAlignType.sizeof <= 10 )
639+ static if (SizeAndAlignType.sizeof <= 3 || size_t .sizeof <= 4 &&
640+ SizeAndAlignType.sizeof <= (SizeAndAlignType.alignof < uint .alignof ? 12 : 10 ))
634641 alias bytesHashWithExactSizeAndAlignment = smallBytesHash;
635642 else
636643 alias bytesHashWithExactSizeAndAlignment = bytesHashAlignedBy! SizeAndAlignType;
@@ -666,13 +673,36 @@ private uint get32bits()(scope const(ubyte)* x) @nogc nothrow pure @system
666673 }
667674}
668675
669- /+
670- Params:
671- dataKnownToBeAligned = whether the data is known at compile time to be uint-aligned.
672- +/
676+ private ulong get64bits ()(scope const (ubyte )* x) @nogc nothrow pure @system
677+ {
678+ version (BigEndian )
679+ {
680+ return ((cast (ulong ) x[0 ]) << 56 ) |
681+ ((cast (ulong ) x[1 ]) << 48 ) |
682+ ((cast (ulong ) x[2 ]) << 40 ) |
683+ ((cast (ulong ) x[3 ]) << 32 ) |
684+ ((cast (ulong ) x[4 ]) << 24 ) |
685+ ((cast (ulong ) x[5 ]) << 16 ) |
686+ ((cast (ulong ) x[6 ]) << 8 ) |
687+ (cast (ulong ) x[7 ]); }
688+ else
689+ {
690+ return ((cast (ulong ) x[7 ]) << 56 ) |
691+ ((cast (ulong ) x[6 ]) << 48 ) |
692+ ((cast (ulong ) x[5 ]) << 40 ) |
693+ ((cast (ulong ) x[4 ]) << 32 ) |
694+ ((cast (ulong ) x[3 ]) << 24 ) |
695+ ((cast (ulong ) x[2 ]) << 16 ) |
696+ ((cast (ulong ) x[1 ]) << 8 ) |
697+ (cast (ulong ) x[0 ]);
698+ }
699+ }
700+
701+ static if (size_t .sizeof == 4 )
673702@nogc nothrow pure @trusted
674- private size_t bytesHash ( bool dataKnownToBeAligned )(scope const (ubyte )[] bytes, size_t seed)
703+ private uint bytesHash32 ( uint alignment )(scope const (ubyte )[] bytes, size_t seed)
675704{
705+ // MurmurHash3_x86_32.
676706 auto len = bytes.length;
677707 auto data = bytes.ptr;
678708 auto nblocks = len / 4 ;
@@ -688,10 +718,12 @@ private size_t bytesHash(bool dataKnownToBeAligned)(scope const(ubyte)[] bytes,
688718 auto end_data = data+ nblocks* uint .sizeof;
689719 for (; data!= end_data; data += uint .sizeof)
690720 {
691- static if (dataKnownToBeAligned )
721+ static if (alignment == uint .alignof )
692722 uint k1 = __ctfe ? get32bits(data) : * (cast (const uint * ) data);
693- else
723+ else static if (alignment == ubyte .alignof)
694724 uint k1 = get32bits(data);
725+ else
726+ static assert (0 , " Do not create unnecessary template instantiations." );
695727 k1 *= c1;
696728 k1 = (k1 << 15 ) | (k1 >> (32 - 15 ));
697729 k1 *= c2;
@@ -725,6 +757,74 @@ private size_t bytesHash(bool dataKnownToBeAligned)(scope const(ubyte)[] bytes,
725757 return h1;
726758}
727759
760+ static if (size_t .sizeof == 8 )
761+ @nogc nothrow pure @trusted
762+ private ulong bytesHash64 (uint alignment)(scope const ubyte [] bytes, ulong seed)
763+ {
764+ // MurmurHash3_x86_32 modified to be 64-bit using constants from MurmurHash3_x64_128.
765+ alias h1 = seed;
766+
767+ enum ulong c1 = 0x87c37b91114253d5 ;
768+ enum ulong c2 = 0x4cf5ad432745937f ;
769+ enum uint c3 = 0x52dce729 ;
770+
771+ const (ubyte )* data = bytes.ptr;
772+ // ----------
773+ // body
774+ for (const end_data = bytes.ptr + (bytes.length & ~ 7 );
775+ data ! is end_data;
776+ data += 8 )
777+ {
778+ static if (alignment == ulong .alignof)
779+ auto k1 = __ctfe ? get64bits(data) : * cast (ulong * ) data;
780+ else static if (alignment == uint .alignof)
781+ {
782+ version (BigEndian )
783+ auto k1 = __ctfe ? get64bits(data) : (((cast (ulong ) * cast (uint * ) data) << 32 ) | * cast (uint * ) (data + 4 ));
784+ else
785+ auto k1 = __ctfe ? get64bits(data) : (((cast (ulong ) * cast (uint * ) (data + 4 )) << 32 ) | * cast (uint * ) data);
786+ }
787+ else static if (alignment == ubyte .alignof)
788+ auto k1 = get64bits(data);
789+ else
790+ static assert (0 , " Do not create unnecessary template instantiations." );
791+
792+ k1 *= c1;
793+ k1 = (k1 << 31 ) | (k1 >> (64 - 31 ));
794+ k1 *= c2;
795+
796+ h1 ^= k1;
797+ h1 = (h1 << 27 ) | (h1 >> (64 - 27 ));
798+ h1 = h1* 5 + c3;
799+ }
800+
801+ // ----------
802+ // tail
803+ ulong k1 = 0 ;
804+
805+ switch (bytes.length & 7 )
806+ {
807+ case 7 : k1 ^= (cast (ulong ) data[6 ]) << 48 ; goto case ;
808+ case 6 : k1 ^= (cast (ulong ) data[5 ]) << 40 ; goto case ;
809+ case 5 : k1 ^= (cast (ulong ) data[4 ]) << 32 ; goto case ;
810+ case 4 : k1 ^= (cast (ulong ) data[3 ]) << 24 ; goto case ;
811+ case 3 : k1 ^= (cast (ulong ) data[2 ]) << 16 ; goto case ;
812+ case 2 : k1 ^= (cast (ulong ) data[1 ]) << 8 ; goto case ;
813+ case 1 : k1 ^= (cast (ulong ) data[0 ]);
814+ k1 *= c1; k1 = (k1 << 31 ) | (k1 >> (64 - 31 )); k1 *= c2; h1 ^= k1;
815+ goto default ;
816+ default :
817+ }
818+
819+ // ----------
820+ // finalization
821+ h1 ^= bytes.length;
822+ // Force all bits of the hash block to avalanche.
823+ h1 = (h1 ^ (h1 >> 33 )) * 0xff51afd7ed558ccd ;
824+ h1 = (h1 ^ (h1 >> 33 )) * 0xc4ceb9fe1a85ec53 ;
825+ return h1 ^= h1 >> 33 ;
826+ }
827+
728828// Check that bytesHash works with CTFE
729829pure nothrow @system @nogc unittest
730830{
@@ -742,15 +842,21 @@ pure nothrow @system @nogc unittest
742842 {
743843 const ubyte [7 ] a = [99 , 4 , 3 , 2 , 1 , 5 , 88 ];
744844 const uint [2 ] b = [0x04_03_02_01, 0x05_ff_ff_ff];
845+ const ulong [1 ] c = [0x04_03_02_01_05_ff_ff_ff];
745846 }
746847 else
747848 {
748849 const ubyte [7 ] a = [99 , 1 , 2 , 3 , 4 , 5 , 88 ];
749850 const uint [2 ] b = [0x04_03_02_01, 0xff_ff_ff_05];
851+ const ulong [1 ] c = [0xff_ff_ff_05_04_03_02_01];
750852 }
751853 // It is okay to change the below values if you make a change
752854 // 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 );
855+ enum expectedResult = size_t .sizeof == 4 ? 2727459272U : 10677742034643552556UL ;
856+ assert (bytesHash(&a[1 ], a.length - 2 , 0 ) == expectedResult);
857+ assert (bytesHash(&b, 5 , 0 ) == expectedResult);
858+ assert (bytesHashAlignedBy! uint ((cast (const ubyte * ) &b)[0 .. 5 ], 0 ) == expectedResult);
859+ assert (bytesHashAlignedBy! ulong ((cast (const ubyte * ) &c)[0 .. 5 ], 0 ) == expectedResult);
860+ assert (bytesHashAlignedBy! ulong ((cast (const ubyte * ) &c)[0 .. c.sizeof], 0 ) ==
861+ (size_t .sizeof == 4 ? 2948526704 : 7625915911016357963 ));
756862}
0 commit comments