diff --git a/src/point.h b/src/point.h index 3047978be41d7..fd95f65349720 100644 --- a/src/point.h +++ b/src/point.h @@ -303,11 +303,20 @@ namespace std template <> struct hash { std::size_t operator()( const point &k ) const noexcept { - constexpr uint64_t a = 2862933555777941757; - size_t result = k.y; - result *= a; - result += k.x; - return result; + // We cast k.y to uint32_t because otherwise when promoting to uint64_t for binary `or` it + // will sign extend and turn the upper 32 bits into all 1s. + uint64_t x = static_cast( k.x ) << 32 | static_cast( k.y ); + + // Found through https://nullprogram.com/blog/2018/07/31/ + // Public domain source from https://xoshiro.di.unimi.it/splitmix64.c + x ^= x >> 30; + x *= 0xbf58476d1ce4e5b9U; + x ^= x >> 27; + x *= 0x94d049bb133111ebU; + x ^= x >> 31; + return x; + + return x; } }; } // namespace std @@ -319,13 +328,21 @@ namespace std template <> struct hash { std::size_t operator()( const tripoint &k ) const noexcept { - constexpr uint64_t a = 2862933555777941757; - size_t result = k.z; - result *= a; - result += k.y; - result *= a; - result += k.x; - return result; + // We cast k.y to uint32_t because otherwise when promoting to uint64_t for binary `or` it + // will sign extend and turn the upper 32 bits into all 1s. + uint64_t x = static_cast( k.x ) << 32 | static_cast( k.y ); + + // Found through https://nullprogram.com/blog/2018/07/31/ + // Public domain source from https://xoshiro.di.unimi.it/splitmix64.c + x ^= x >> 30; + x *= 0xbf58476d1ce4e5b9U; + x ^= x >> 27; + + // Sprinkle in z now. + x ^= static_cast( k.z ); + x *= 0x94d049bb133111ebU; + x ^= x >> 31; + return x; } }; } // namespace std