blob: 19943a4d6d24d0b5afd305657e17d17ea8b98c72 [file] [log] [blame]
/**
* The default hash implementation.
*
* Copyright: Copyright Sean Kelly 2009 - 2016.
* License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
* Authors: Sean Kelly
* Source: $(DRUNTIMESRC src/rt/util/_hash.d)
*/
module rt.util.hash;
version (X86)
version = AnyX86;
version (X86_64)
version = AnyX86;
version (AnyX86)
version = HasUnalignedOps;
@trusted pure nothrow @nogc
size_t hashOf( const(void)[] buf, size_t seed )
{
/*
* This is Paul Hsieh's SuperFastHash algorithm, described here:
* http://www.azillionmonkeys.com/qed/hash.html
* It is protected by the following open source license:
* http://www.azillionmonkeys.com/qed/weblicense.html
*/
static uint get16bits( const (ubyte)* x ) pure nothrow @nogc
{
// CTFE doesn't support casting ubyte* -> ushort*, so revert to
// per-byte access when in CTFE.
version (HasUnalignedOps)
{
if (!__ctfe)
return *cast(ushort*) x;
}
return ((cast(uint) x[1]) << 8) + (cast(uint) x[0]);
}
// NOTE: SuperFastHash normally starts with a zero hash value. The seed
// value was incorporated to allow chaining.
auto data = cast(const(ubyte)*) buf.ptr;
auto len = buf.length;
auto hash = seed;
if ( len == 0 || data is null )
return 0;
int rem = len & 3;
len >>= 2;
for ( ; len > 0; len-- )
{
hash += get16bits( data );
auto tmp = (get16bits( data + 2 ) << 11) ^ hash;
hash = (hash << 16) ^ tmp;
data += 2 * ushort.sizeof;
hash += hash >> 11;
}
switch ( rem )
{
case 3: hash += get16bits( data );
hash ^= hash << 16;
hash ^= data[ushort.sizeof] << 18;
hash += hash >> 11;
break;
case 2: hash += get16bits( data );
hash ^= hash << 11;
hash += hash >> 17;
break;
case 1: hash += *data;
hash ^= hash << 10;
hash += hash >> 1;
break;
default:
break;
}
/* Force "avalanching" of final 127 bits */
hash ^= hash << 3;
hash += hash >> 5;
hash ^= hash << 4;
hash += hash >> 17;
hash ^= hash << 25;
hash += hash >> 6;
return hash;
}
unittest
{
enum test_str = "Sample string";
size_t hashval = hashOf(test_str, 5);
//import core.stdc.stdio;
//printf("hashval = %lld\n", cast(long)hashval);
if (hashval.sizeof == 4)
assert(hashval == 528740845);
else if (hashval.sizeof == 8)
assert(hashval == 8106800467257150594L);
else
assert(0);
}