Core/Misc: Hashing update
* Update hash_combine with latest version from boost * Change most std::hash specializations to simply hash all of the input bytes instead of combining their hashes
This commit is contained in:
@@ -46,7 +46,7 @@ std::unordered_map<uint32, Minutes, std::identity> InitTimezoneHashDb()
|
||||
std::chrono::sys_info sysInfo = zone.get_info(dummmy);
|
||||
Minutes offsetMinutes = std::chrono::duration_cast<Minutes>(sysInfo.offset);
|
||||
std::string offsetStr = Trinity::ToString(offsetMinutes.count());
|
||||
hashToOffset.emplace(Trinity::HashFnv1a(offsetStr), offsetMinutes);
|
||||
hashToOffset.emplace(Trinity::HashFnv1a<uint32>::GetHash(offsetStr), offsetMinutes);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
+128
-18
@@ -15,46 +15,156 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TrinityCore_Hash_h__
|
||||
#define TrinityCore_Hash_h__
|
||||
#ifndef TRINITYCORE_HASH_H
|
||||
#define TRINITYCORE_HASH_H
|
||||
|
||||
#include <functional>
|
||||
#include <string_view>
|
||||
#include <span>
|
||||
#include <utility>
|
||||
|
||||
namespace Trinity
|
||||
{
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
inline void hash_combine(std::size_t& seed, T const& val)
|
||||
{
|
||||
seed ^= std::hash<T>()(val) + 0x9E3779B9 + (seed << 6) + (seed >> 2);
|
||||
// Taken from boost::hash_combine
|
||||
|
||||
seed = seed + 0x9E3779B9 + std::hash<T>()(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;
|
||||
}
|
||||
}
|
||||
|
||||
inline constexpr std::uint32_t HashFnv1a(std::string_view data)
|
||||
template <std::size_t>
|
||||
struct HashFnv1aConstants { };
|
||||
|
||||
template <>
|
||||
struct HashFnv1aConstants<4>
|
||||
{
|
||||
std::uint32_t hash = 0x811C9DC5u;
|
||||
for (char c : data)
|
||||
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 <typename T>
|
||||
concept HashablePrimitive = std::is_arithmetic_v<T> || std::is_enum_v<T> || std::is_pointer_v<T>;
|
||||
|
||||
template <typename T = std::size_t>
|
||||
struct HashFnv1a
|
||||
{
|
||||
using Constants = HashFnv1aConstants<sizeof(T)>;
|
||||
|
||||
T Value = Constants::Basis;
|
||||
|
||||
template <HashablePrimitive V, std::size_t Extent>
|
||||
inline constexpr void UpdateData(std::span<V, Extent> data) noexcept
|
||||
{
|
||||
hash ^= c;
|
||||
hash *= 0x1000193u;
|
||||
T hash = Value;
|
||||
|
||||
if (std::is_constant_evaluated())
|
||||
{
|
||||
static_assert(std::is_integral_v<V> || std::is_enum_v<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<T>(c) >> (i * 8)) & 0xFF;
|
||||
hash *= Constants::Prime;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::byte const* c = reinterpret_cast<std::byte const*>(data.data());
|
||||
std::byte const* end = c + data.size_bytes();
|
||||
while (c != end)
|
||||
{
|
||||
hash ^= static_cast<T>(*c);
|
||||
hash *= Constants::Prime;
|
||||
++c;
|
||||
}
|
||||
}
|
||||
|
||||
Value = hash;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
template <HashablePrimitive V>
|
||||
inline constexpr void UpdateData(V data) noexcept
|
||||
{
|
||||
this->UpdateData(std::span<V, 1>(&data, 1));
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
inline constexpr void UpdateData(V const& data) noexcept requires requires { std::span(data); }
|
||||
{
|
||||
this->UpdateData(std::span(data));
|
||||
}
|
||||
|
||||
template <HashablePrimitive V, std::size_t Extent>
|
||||
inline static constexpr std::size_t GetHash(std::span<V, Extent> data) noexcept
|
||||
{
|
||||
HashFnv1a hash;
|
||||
hash.UpdateData(data);
|
||||
return hash.Value;
|
||||
}
|
||||
|
||||
template <HashablePrimitive V>
|
||||
inline static constexpr std::size_t GetHash(V data) noexcept
|
||||
{
|
||||
return HashFnv1a::GetHash(std::span<V, 1>(&data, 1));
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
inline static constexpr std::size_t GetHash(V const& data) noexcept requires requires { std::span(data); }
|
||||
{
|
||||
return HashFnv1a::GetHash(std::span(data));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename Hash = std::hash<T>>
|
||||
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<class K, class V>
|
||||
template <typename K, typename V>
|
||||
struct std::hash<std::pair<K, V>>
|
||||
{
|
||||
public:
|
||||
size_t operator()(std::pair<K, V> const& p) const
|
||||
std::size_t operator()(std::pair<K, V> const& p) const
|
||||
{
|
||||
size_t hashVal = 0;
|
||||
Trinity::hash_combine(hashVal, p.first);
|
||||
std::size_t hashVal = std::hash<K>()(p.first);
|
||||
Trinity::hash_combine(hashVal, p.second);
|
||||
return hashVal;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // TrinityCore_Hash_h__
|
||||
#endif // TRINITYCORE_HASH_H
|
||||
|
||||
@@ -32,11 +32,11 @@ struct FieldLookupByAliasKey
|
||||
std::string_view Alias;
|
||||
|
||||
// implicit constructor from string literal for users of the query result
|
||||
consteval FieldLookupByAliasKey(char const* alias) : HashValue(HashFnv1a(alias)), Alias(alias) { }
|
||||
consteval FieldLookupByAliasKey(char const* alias) : HashValue(HashFnv1a<>::GetHash(std::span(alias, std::char_traits<char>::length(alias)))), Alias(alias) { }
|
||||
|
||||
// runtime only constructor used internally to fill alias to index mapping
|
||||
struct RuntimeInitTag { } static inline constexpr RuntimeInit = { };
|
||||
FieldLookupByAliasKey(RuntimeInitTag, std::string_view alias) : HashValue(HashFnv1a(alias)), Alias(std::move(alias)) { }
|
||||
FieldLookupByAliasKey(RuntimeInitTag, std::string_view alias) : HashValue(HashFnv1a<>::GetHash(alias)), Alias(std::move(alias)) { }
|
||||
|
||||
friend bool operator==(FieldLookupByAliasKey const& left, FieldLookupByAliasKey const& right) = default;
|
||||
|
||||
|
||||
@@ -56,12 +56,12 @@ AuctionsBucketKey::AuctionsBucketKey(WorldPackets::AuctionHouse::AuctionBucketKe
|
||||
|
||||
std::size_t AuctionsBucketKey::Hash(AuctionsBucketKey const& key)
|
||||
{
|
||||
std::size_t hashVal = 0;
|
||||
Trinity::hash_combine(hashVal, std::hash<uint32>()(key.ItemId));
|
||||
Trinity::hash_combine(hashVal, std::hash<uint16>()(key.ItemLevel));
|
||||
Trinity::hash_combine(hashVal, std::hash<uint16>()(key.BattlePetSpeciesId));
|
||||
Trinity::hash_combine(hashVal, std::hash<uint16>()(key.SuffixItemNameDescriptionId));
|
||||
return hashVal;
|
||||
Trinity::HashFnv1a<> hash;
|
||||
hash.UpdateData(key.ItemId);
|
||||
hash.UpdateData(key.ItemLevel);
|
||||
hash.UpdateData(key.BattlePetSpeciesId);
|
||||
hash.UpdateData(key.SuffixItemNameDescriptionId);
|
||||
return hash.Value;
|
||||
}
|
||||
|
||||
AuctionsBucketKey AuctionsBucketKey::ForItem(Item const* item)
|
||||
|
||||
@@ -182,11 +182,11 @@ ConditionSourceInfo::ConditionSourceInfo(Map const* map) :
|
||||
|
||||
std::size_t ConditionId::GetHash() const
|
||||
{
|
||||
std::size_t hashVal = 0;
|
||||
Trinity::hash_combine(hashVal, SourceGroup);
|
||||
Trinity::hash_combine(hashVal, SourceEntry);
|
||||
Trinity::hash_combine(hashVal, SourceId);
|
||||
return hashVal;
|
||||
Trinity::HashFnv1a<> hash;
|
||||
hash.UpdateData(SourceGroup);
|
||||
hash.UpdateData(SourceEntry);
|
||||
hash.UpdateData(SourceId);
|
||||
return hash.Value;
|
||||
}
|
||||
|
||||
// Checks if object meets the condition
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#include "ObjectGuid.h"
|
||||
#include "ByteBuffer.h"
|
||||
#include "Errors.h"
|
||||
#include "Hash.h"
|
||||
#include "RealmList.h"
|
||||
#include "StringFormat.h"
|
||||
#include "Util.h"
|
||||
@@ -838,21 +837,6 @@ ObjectGuid ObjectGuid::FromString(std::string_view guidString)
|
||||
return Info.Parse(guidString);
|
||||
}
|
||||
|
||||
std::size_t ObjectGuid::GetHash() const
|
||||
{
|
||||
std::size_t hashVal = 0;
|
||||
Trinity::hash_combine(hashVal, _data[0]);
|
||||
Trinity::hash_combine(hashVal, _data[1]);
|
||||
return hashVal;
|
||||
}
|
||||
|
||||
std::array<uint8, 16> ObjectGuid::GetRawValue() const
|
||||
{
|
||||
std::array<uint8, 16> raw;
|
||||
memcpy(raw.data(), _data.data(), BytesSize);
|
||||
return raw;
|
||||
}
|
||||
|
||||
void ObjectGuid::SetRawValue(std::span<uint8 const> rawBytes)
|
||||
{
|
||||
ASSERT(rawBytes.size() == BytesSize, SZFMTD " == " SZFMTD, rawBytes.size(), BytesSize);
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "Define.h"
|
||||
#include "EnumFlag.h"
|
||||
#include "Hash.h"
|
||||
#include "StringFormatFwd.h"
|
||||
#include "advstd.h"
|
||||
#include <array>
|
||||
@@ -322,7 +323,7 @@ class TC_GAME_API ObjectGuid
|
||||
constexpr ObjectGuid() = default;
|
||||
|
||||
uint64 GetRawValue(std::size_t i) const { return _data[i]; }
|
||||
std::array<uint8, 16> GetRawValue() const;
|
||||
std::span<uint8 const, 16> GetRawValue() const { return std::span<uint8 const, 16>(reinterpret_cast<uint8 const*>(_data.data()), BytesSize); }
|
||||
void SetRawValue(std::span<uint8 const> rawBytes);
|
||||
void SetRawValue(uint64 high, uint64 low) { _data[0] = low; _data[1] = high; }
|
||||
void Clear() { _data = { }; }
|
||||
@@ -396,7 +397,6 @@ class TC_GAME_API ObjectGuid
|
||||
std::string ToString() const;
|
||||
std::string ToHexString() const;
|
||||
static ObjectGuid FromString(std::string_view guidString);
|
||||
std::size_t GetHash() const;
|
||||
|
||||
template <HighGuid type, std::enable_if_t<ObjectGuidTraits<type>::Format::value == ObjectGuidFormatType::Null, int32> = 0> static constexpr ObjectGuid Create() { return ObjectGuidFactory::CreateNull(); }
|
||||
template <HighGuid type, std::enable_if_t<ObjectGuidTraits<type>::Format::value == ObjectGuidFormatType::Uniq, int32> = 0> static constexpr ObjectGuid Create(LowType id) { return ObjectGuidFactory::CreateUniq(id); }
|
||||
@@ -437,12 +437,12 @@ using GuidUnorderedSet = std::unordered_set<ObjectGuid>;
|
||||
TC_GAME_API ByteBuffer& operator<<(ByteBuffer& buf, ObjectGuid const& guid);
|
||||
TC_GAME_API ByteBuffer& operator>>(ByteBuffer& buf, ObjectGuid& guid);
|
||||
|
||||
template<>
|
||||
template <>
|
||||
struct std::hash<ObjectGuid>
|
||||
{
|
||||
size_t operator()(ObjectGuid const& key) const noexcept
|
||||
std::size_t operator()(ObjectGuid const& key) const noexcept
|
||||
{
|
||||
return key.GetHash();
|
||||
return Trinity::HashFnv1a<>::GetHash(key.GetRawValue());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -34,10 +34,10 @@ struct std::hash<AreaTriggerId>
|
||||
{
|
||||
std::size_t operator()(AreaTriggerId const& value) const noexcept
|
||||
{
|
||||
size_t hashVal = 0;
|
||||
Trinity::hash_combine(hashVal, value.Id);
|
||||
Trinity::hash_combine(hashVal, value.IsCustom);
|
||||
return hashVal;
|
||||
Trinity::HashFnv1a<> hash;
|
||||
hash.UpdateData(value.Id);
|
||||
hash.UpdateData(value.IsCustom);
|
||||
return hash.Value;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -63,20 +63,18 @@ struct std::hash<TileCacheKey>
|
||||
{
|
||||
static std::size_t Compute(TileCacheKey const& key) noexcept
|
||||
{
|
||||
size_t hashVal = 0;
|
||||
Trinity::hash_combine(hashVal, key.TerrainMapId);
|
||||
Trinity::hash_combine(hashVal, key.X);
|
||||
Trinity::hash_combine(hashVal, key.Y);
|
||||
Trinity::HashFnv1a<> hash;
|
||||
hash.UpdateData(key.TerrainMapId);
|
||||
hash.UpdateData(key.X);
|
||||
hash.UpdateData(key.Y);
|
||||
for (TileCacheKeyObject const& object : key.Objects)
|
||||
{
|
||||
Trinity::hash_combine(hashVal, object.DisplayId);
|
||||
Trinity::hash_combine(hashVal, object.Scale);
|
||||
Trinity::hash_combine(hashVal, object.Position[0]);
|
||||
Trinity::hash_combine(hashVal, object.Position[1]);
|
||||
Trinity::hash_combine(hashVal, object.Position[2]);
|
||||
Trinity::hash_combine(hashVal, object.Rotation);
|
||||
hash.UpdateData(object.DisplayId);
|
||||
hash.UpdateData(object.Scale);
|
||||
hash.UpdateData(object.Position);
|
||||
hash.UpdateData(object.Rotation);
|
||||
}
|
||||
return hashVal;
|
||||
return hash.Value;
|
||||
}
|
||||
|
||||
std::size_t operator()(TileCacheKey const& key) const noexcept
|
||||
|
||||
Reference in New Issue
Block a user