Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/common/Time/Timezone.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
146 changes: 128 additions & 18 deletions src/common/Utilities/Hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
4 changes: 2 additions & 2 deletions src/server/database/Database/QueryResult.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
12 changes: 6 additions & 6 deletions src/server/game/AuctionHouse/AuctionHouseMgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
10 changes: 5 additions & 5 deletions src/server/game/Conditions/ConditionMgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
16 changes: 0 additions & 16 deletions src/server/game/Entities/Object/ObjectGuid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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);
Expand Down
10 changes: 5 additions & 5 deletions src/server/game/Entities/Object/ObjectGuid.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include "Define.h"
#include "EnumFlag.h"
#include "Hash.h"
#include "StringFormatFwd.h"
#include "advstd.h"
#include <array>
Expand Down Expand Up @@ -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 = { }; }
Expand Down Expand Up @@ -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); }
Expand Down Expand Up @@ -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());
}
};

Expand Down
8 changes: 4 additions & 4 deletions src/server/game/Globals/AreaTriggerDataStore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
};

Expand Down
35 changes: 18 additions & 17 deletions src/server/game/Maps/DynamicMMapTileBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -138,7 +136,7 @@ struct TileCache
MMAP::CreateVMapManager = &CreateVMapManager;

// init timer
OnCacheCleanupTimerTick({});
OnCacheCleanupTimerTick();

// start the worker
_builderThread = std::thread([this] { _taskContext.run(); });
Expand All @@ -163,15 +161,18 @@ struct TileCache
}

private:
void OnCacheCleanupTimerTick(boost::system::error_code const& error)
void OnCacheCleanupTimerTick()
{
if (error || !_builderThread.joinable() /*shutting down*/)
return;

TimePoint now = GameTime::Now();
RemoveOldCacheEntries(now - CACHE_MAX_AGE);
_cacheCleanupTimer.expires_at(now + CACHE_CLEANUP_INTERVAL);
_cacheCleanupTimer.async_wait([this](boost::system::error_code const& error) { OnCacheCleanupTimerTick(error); });
_cacheCleanupTimer.async_wait([this](boost::system::error_code const& error)
{
if (error || !_builderThread.joinable() /*shutting down*/)
return;

OnCacheCleanupTimerTick();
});
}

void RemoveOldCacheEntries(TimePoint oldestPreservedEntryTimestamp)
Expand Down
Loading