rpcsx/rpcs3/util/fnv_hash.hpp
2025-02-26 11:04:02 +02:00

91 lines
1.8 KiB
C++

#pragma once
#include "util/types.hpp"
#include <cstring>
namespace rpcs3
{
constexpr usz fnv_seed = 14695981039346656037ull;
constexpr usz fnv_prime = 1099511628211ull;
template <typename T>
static usz hash_base(T value)
{
return static_cast<usz>(value);
}
template <typename T>
requires std::is_integral_v<T>
static inline usz hash64(usz hash_value, T data)
{
hash_value ^= data;
hash_value *= fnv_prime;
return hash_value;
}
template <typename T, typename U>
static usz hash_struct_base(const T& value)
{
// FNV 64-bit
usz result = fnv_seed;
const uchar* bits = reinterpret_cast<const uchar*>(&value);
for (usz n = 0; n < (sizeof(T) / sizeof(U)); ++n)
{
U val{};
std::memcpy(&val, bits + (n * sizeof(U)), sizeof(U));
result = hash64(result, val);
}
return result;
}
template <typename T>
static usz hash_struct(const T& value)
{
static constexpr auto block_sz = sizeof(T);
if constexpr ((block_sz & 0x7) == 0)
{
return hash_struct_base<T, u64>(value);
}
if constexpr ((block_sz & 0x3) == 0)
{
return hash_struct_base<T, u32>(value);
}
if constexpr ((block_sz & 0x1) == 0)
{
return hash_struct_base<T, u16>(value);
}
return hash_struct_base<T, u8>(value);
}
template <typename T, size_t N>
requires std::is_integral_v<T>
static inline usz hash_array(const T(&arr)[N])
{
usz hash = fnv_seed;
for (size_t i = 0; i < N; ++i)
{
hash = hash64(hash, arr[i]);
}
return hash;
}
template <typename T, size_t N>
requires std::is_class_v<T>
static inline usz hash_array(const T(&arr)[N])
{
usz hash = fnv_seed;
for (size_t i = 0; i < N; ++i)
{
const u64 item_hash = hash_struct(arr[i]);
hash = hash64(hash, item_hash);
}
return hash;
}
}