/* * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #ifndef TRINITYCORE_HASH_H #define TRINITYCORE_HASH_H #include #include #include namespace Trinity { template inline void hash_combine(std::size_t& seed, T const& val) { // Taken from boost::hash_combine seed = seed + 0x9E3779B9 + std::hash()(val); if constexpr (sizeof(std::size_t) == 8) { constexpr std::size_t m = 0xE9846AF9B1A615D; seed ^= seed >> 32; seed *= m; seed ^= seed >> 32; seed *= m; seed ^= seed >> 28; } else { constexpr std::size_t m1 = 0x21F0AAAD; constexpr std::size_t m2 = 0x735A2D97; seed ^= seed >> 16; seed *= m1; seed ^= seed >> 15; seed *= m2; seed ^= seed >> 15; } } template struct HashFnv1aConstants { }; template <> struct HashFnv1aConstants<4> { static constexpr std::uint32_t Basis = 0x811C9DC5u; static constexpr std::uint32_t Prime = 0x01000193u; }; template <> struct HashFnv1aConstants<8> { static constexpr std::uint64_t Basis = 0xCBF29CE484222325ull; static constexpr std::uint64_t Prime = 0x00000100000001B3ull; }; template concept HashablePrimitive = std::is_arithmetic_v || std::is_enum_v || std::is_pointer_v; template struct HashFnv1a { using Constants = HashFnv1aConstants; T Value = Constants::Basis; template inline constexpr void UpdateData(std::span data) noexcept { T hash = Value; if (std::is_constant_evaluated()) { static_assert(std::is_integral_v || std::is_enum_v, "Only integral types can be hashed at compile time"); for (V c : data) { for (std::size_t i = 0; i < sizeof(V); ++i) { hash ^= (static_cast(c) >> (i * 8)) & 0xFF; hash *= Constants::Prime; } } } else { std::byte const* c = reinterpret_cast(data.data()); std::byte const* end = c + data.size_bytes(); while (c != end) { hash ^= static_cast(*c); hash *= Constants::Prime; ++c; } } Value = hash; } template inline constexpr void UpdateData(V data) noexcept { this->UpdateData(std::span(&data, 1)); } template inline constexpr void UpdateData(V const& data) noexcept requires requires { std::span(data); } { this->UpdateData(std::span(data)); } template inline static constexpr std::size_t GetHash(std::span data) noexcept { HashFnv1a hash; hash.UpdateData(data); return hash.Value; } template inline static constexpr std::size_t GetHash(V data) noexcept { return HashFnv1a::GetHash(std::span(&data, 1)); } template inline static constexpr std::size_t GetHash(V const& data) noexcept requires requires { std::span(data); } { return HashFnv1a::GetHash(std::span(data)); } }; template > struct TransparentHash : Hash { using is_transparent = int; }; } //! Hash implementation for std::pair to allow using pairs in unordered_set or as key for unordered_map //! Individual types used in pair must be hashable by std::hash template struct std::hash> { std::size_t operator()(std::pair const& p) const { std::size_t hashVal = std::hash()(p.first); Trinity::hash_combine(hashVal, p.second); return hashVal; } }; #endif // TRINITYCORE_HASH_H