/*
* 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