From ceb8e6a113809110526844d18a367d501b09ed4c Mon Sep 17 00:00:00 2001 From: Nathan Sashihara <21227491+n8sh@users.noreply.github.com> Date: Thu, 2 Aug 2018 12:08:32 -0400 Subject: [PATCH] Use identity hash for integers and pointers This is appropriate because HashArray in tanya.container.entry uses prime numbers instead of powers of 2 for its number of buckets so there is no pitfall if the hashes are all multiples of some power of 2. --- source/tanya/hash/lookup.d | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/source/tanya/hash/lookup.d b/source/tanya/hash/lookup.d index f564b53..9b0d883 100644 --- a/source/tanya/hash/lookup.d +++ b/source/tanya/hash/lookup.d @@ -89,7 +89,10 @@ private struct FNV * } * --- * - * For scalar types FNV-1a (Fowler-Noll-Vo) hash function is used internally. + * For pointers and for scalar types implicitly convertible to `size_t` this + * is an identity operation (i.e. the value is cast to `size_t` and returned + * unaltered). Integer types wider than `size_t` are XOR folded down to + * `size_t`. Other scalar types use the FNV-1a (Fowler-Noll-Vo) hash function. * If the type provides a `toHash`-function, only `toHash()` is called and its * result is returned. * @@ -110,6 +113,19 @@ size_t hash(T)(auto ref T key) { return key.toHash(); } + else static if ((isIntegral!T || isSomeChar!T || isBoolean!T) + && T.sizeof <= size_t.sizeof) + { + return cast(size_t) key; + } + else static if (isIntegral!T && T.sizeof > size_t.sizeof) + { + return cast(size_t) (key ^ (key >>> (size_t.sizeof * 8))); + } + else static if (isPointer!T || is(T : typeof(null))) + { + return (() @trusted => cast(size_t) key)(); + } else { FNV fnv; @@ -177,30 +193,29 @@ version (unittest) // Tests that work for any hash size @nogc nothrow pure @safe unittest { - assert(hash(null) == FNV.offsetBasis); + assert(hash(null) == 0); assert(hash(ToHash()) == 0U); + assert(hash('a') == 'a'); } static if (size_t.sizeof == 4) @nogc nothrow pure @safe unittest { - assert(hash('a') == 0xe40c292cU); assert(hash(HashRange()) == 0x6222e842U); assert(hash(ToHashRange()) == 1268118805U); } static if (size_t.sizeof == 8) @nogc nothrow pure @safe unittest { - assert(hash('a') == 0xaf63dc4c8601ec8cUL); assert(hash(HashRange()) == 0x08985907b541d342UL); assert(hash(ToHashRange()) == 12161962213042174405UL); } static if (size_t.sizeof == 4) @nogc nothrow pure @system unittest { - assert(hash(cast(void*) 0x6e6f6863) == 0xac297727U); + assert(hash(cast(void*) 0x6e6f6863) == 0x6e6f6863); } static if (size_t.sizeof == 8) @nogc nothrow pure @system unittest { - assert(hash(cast(void*) 0x77206f676e6f6863) == 0xd1edd10b507344d0UL); + assert(hash(cast(void*) 0x77206f676e6f6863) == 0x77206f676e6f6863); } /*