AuROXTL/Include/auROXTL/auFNV1Utils.hpp

302 lines
9.7 KiB
C++

/***
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: auFNV1Utils.hpp
Date: 2022-3-23
File: fnv1.hpp
Date: 2021-6-10
Author: Reece
***/
#pragma once
#include "auTypeUtils.hpp"
// Note: we're too early for AuroraEnv.hpp w/ AuroraEnums
#if defined(AURORA_IS_32BIT)
#define _AU_FNV1_32 1
#else
#define _AU_FNV1_32 0
#endif
#if defined(AURORA_COMPILER_CLANG) && !defined(AURORA_BUG_CLANG_SUPPORT_HASH_OVERFLOW)
#define _AU_HASH_RETARD_COMPILER
#pragma optimize("", off)
//#pragma GCC optimize ("no-fast-math")
#endif
constexpr AuUInt64 kFnv1MagicVal64 = 0xcbf29ce484222325ull;
constexpr AuUInt64 kFnv1MagicPrime64 = 0x100000001b3ull;
constexpr AuUInt32 kFnv1MagicVal32 = 0x811c9dc5;
constexpr AuUInt32 kFnv1MagicPrime32 = 0x01000193;
constexpr auto kFnv1MagicValPlatform = _AU_FNV1_32 ? kFnv1MagicVal32 : kFnv1MagicVal64;
constexpr auto kFnv1MagicPrimePlatform = _AU_FNV1_32 ? kFnv1MagicPrime32 : kFnv1MagicPrime64;
inline constexpr AuUInt64 AuFnv1a64(const char *const str, const AuUInt64 value = kFnv1MagicVal64) noexcept
{
return (str[0] == '\0') ? value : AuFnv1a64(&str[1], (value ^ AuUInt64(str[0])) * kFnv1MagicPrime64);
}
inline constexpr AuUInt32 AuFnv1aTrunc(const char *const str) noexcept
{
return static_cast<AuUInt32>(AuFnv1a64(str));
}
inline constexpr AuUInt32 AuFnv1a32(const char *const str, const AuUInt32 value = kFnv1MagicVal32) noexcept
{
return (str[0] == '\0') ? value : AuFnv1a32(&str[1], (value ^ AuUInt32(str[0])) * kFnv1MagicPrime32);
}
inline constexpr AuUInt AuFnv1aType(const char *const type, AuUInt size, AuUInt index, const AuUInt value) noexcept
{
return (index == size) ? value : AuFnv1aType(type + 1, size, index + 1, (value ^ AuUInt(*type)) * kFnv1MagicPrimePlatform);
}
inline constexpr AuUInt32 AuFnv1aType32(const char *const type, AuUInt size, AuUInt index, const AuUInt32 value) noexcept
{
return (index == size) ? value : AuFnv1aType32(type + 1, size, index + 1, (value ^ AuUInt32(*type)) * kFnv1MagicPrime32);
}
inline constexpr AuUInt64 AuFnv1aType64(const char *const type, AuUInt size, AuUInt index, const AuUInt64 value) noexcept
{
return (index == size) ? value : AuFnv1aType64(type + 1, size, index + 1, (value ^ AuUInt64(*type)) * kFnv1MagicPrime64);
}
#if !defined(_AU_HASH_RETARD_COMPILER)
template <class T>
inline constexpr AuUInt32 AuFnv1aType32(T type, const AuUInt32 value = kFnv1MagicVal32) noexcept
{
#if defined(AURORA_COMPILER_CLANG)
static_assert(false, "Unsupported constexpr hash on type");
#else
return AuFnv1aType32(((const char *)&type) + 1, sizeof(T), 1, (value ^ (AuUInt32(*(const char *)&type)) * kFnv1MagicPrime32));
#endif
}
#endif
#if !defined(_AU_HASH_RETARD_COMPILER)
template <class T>
inline constexpr AuUInt64 AuFnv1aType64(T type, const AuUInt64 value = kFnv1MagicVal64) noexcept
{
#if defined(AURORA_COMPILER_CLANG)
static_assert(false, "Unsupported constexpr hash on type");
#else
return AuFnv1aType64(((const char *)&type) + 1, sizeof(T), 1, (value ^ (AuUInt64(*(const char *)&type)) * kFnv1MagicPrime64));
#endif
}
#endif
#if !defined(_AU_HASH_RETARD_COMPILER)
template <class T>
inline constexpr AuUInt AuFnv1aType(const T &type, const AuUInt value = kFnv1MagicValPlatform) noexcept
{
#if _AU_FNV1_32
return AuFnv1aType32(type, value);
#else
return AuFnv1aType64(type, value);
#endif
}
#endif
template <class T>
inline constexpr AuUInt AuFnv1aPtr(const T *const type, AuUInt length, const AuUInt value = kFnv1MagicValPlatform) noexcept
{
return AuFnv1aType((const char *)type,
length,
0,
value);
}
template <class T>
inline constexpr AuUInt32 AuFnv1aPtr32(const T *const type, AuUInt length, const AuUInt32 value = kFnv1MagicVal32) noexcept
{
return AuFnv1aType32((const char *)type,
length,
0,
value);
}
template <class T>
inline constexpr AuUInt64 AuFnv1aPtr64(const T *const type, AuUInt length, const AuUInt64 value = kFnv1MagicVal64) noexcept
{
return AuFnv1aType64((const char *)type,
length,
0,
value);
}
inline constexpr auto AuFnv1a(const char *const str) noexcept
{
return _AU_FNV1_32 ? AuFnv1a32(str) : AuFnv1a64(str);
}
inline constexpr auto AuFnv1a(const char *const str, AuUInt length) noexcept
{
return AuFnv1aPtr(str, length);
}
inline AuUInt32 AuFnv1a32Runtime(const void *base, AuUInt length) noexcept
{
AuUInt32 result {kFnv1MagicVal32};
AuUInt i {};
for (; i < length; i++)
{
result = (result ^ AuUInt32(AuReadU8(base, i))) * AuUInt64(kFnv1MagicPrime32);
}
return result;
}
inline AuUInt64 AuFnv1a64Runtime(const void *base, AuUInt length) noexcept
{
AuUInt64 result {kFnv1MagicVal64};
AuUInt i {};
for (; i < length; i++)
{
result = (result ^ AuUInt64(AuReadU8(base, i))) * AuUInt64(kFnv1MagicPrime64);
}
return result;
}
inline auto AuFnv1aRuntime(const void *base, AuUInt length) noexcept
{
return _AU_FNV1_32 ?
AuFnv1a32Runtime(base, length) :
AuFnv1a64Runtime(base, length);
}
template <AuUInt uCount>
inline AuUInt64 AuFnv1a64Runtime(const void *base) noexcept
{
AuUInt64 result { kFnv1MagicVal64 };
AuUInt i {};
for (; i < uCount; i++)
{
result = (result ^ AuUInt64(AuReadU8(base, i))) * AuUInt64(kFnv1MagicPrime64);
}
return result;
}
template <AuUInt uCount>
inline AuUInt32 AuFnv1a32Runtime(const void *base) noexcept
{
AuUInt32 result { kFnv1MagicVal32 };
AuUInt i {};
for (; i < uCount; i++)
{
result = (result ^ AuUInt32(AuReadU8(base, i))) * AuUInt32(kFnv1MagicPrime32);
}
return result;
}
#if defined(AU_CPU_ENDIAN_LITTLE)
template <>
inline AuUInt32 AuFnv1a32Runtime<2>(const void *base) noexcept
{
AuUInt32 result { kFnv1MagicVal32 };
auto uWord16 = AuReadU16(base, 0);
result = (result ^ AuUInt32((uWord16 & 0xFF) >> 0)) * AuUInt32(kFnv1MagicPrime32);
result = (result ^ AuUInt32((uWord16 & 0xFF00) >> 8)) * AuUInt32(kFnv1MagicPrime32);
return result;
}
template <>
inline AuUInt32 AuFnv1a32Runtime<4>(const void *base) noexcept
{
AuUInt32 result { kFnv1MagicVal32 };
auto uWord32 = AuReadU32(base, 0);
result = (result ^ AuUInt32((uWord32 & 0xFF) >> 0)) * AuUInt32(kFnv1MagicPrime32);
result = (result ^ AuUInt32((uWord32 & 0xFF00) >> 8)) * AuUInt32(kFnv1MagicPrime32);
result = (result ^ AuUInt32((uWord32 & 0xFF0000) >> 16)) * AuUInt32(kFnv1MagicPrime32);
result = (result ^ AuUInt32((uWord32 & 0xFF000000) >> 24)) * AuUInt32(kFnv1MagicPrime32);
return result;
}
template <>
inline AuUInt32 AuFnv1a32Runtime<8>(const void *base) noexcept
{
AuUInt32 result { kFnv1MagicVal32 };
auto uWord32 = AuReadU32(base, 0);
auto uWord32Hi = AuReadU32(base, 4);
result = (result ^ AuUInt32((uWord32 & 0xFF) >> 0)) * AuUInt32(kFnv1MagicPrime32);
result = (result ^ AuUInt32((uWord32 & 0xFF00) >> 8)) * AuUInt32(kFnv1MagicPrime32);
result = (result ^ AuUInt32((uWord32 & 0xFF0000) >> 16)) * AuUInt32(kFnv1MagicPrime32);
result = (result ^ AuUInt32((uWord32 & 0xFF000000) >> 24)) * AuUInt32(kFnv1MagicPrime32);
result = (result ^ AuUInt32((uWord32Hi & 0xFF) >> 0)) * AuUInt32(kFnv1MagicPrime32);
result = (result ^ AuUInt32((uWord32Hi & 0xFF00) >> 8)) * AuUInt32(kFnv1MagicPrime32);
result = (result ^ AuUInt32((uWord32Hi & 0xFF0000) >> 16)) * AuUInt32(kFnv1MagicPrime32);
result = (result ^ AuUInt32((uWord32Hi & 0xFF000000) >> 24)) * AuUInt32(kFnv1MagicPrime32);
return result;
}
template <>
inline AuUInt64 AuFnv1a64Runtime<2>(const void *base) noexcept
{
AuUInt64 result { kFnv1MagicVal64 };
auto uWord16 = AuReadU16(base, 0);
result = (result ^ AuUInt64((uWord16 & 0xFF) >> 0)) * AuUInt64(kFnv1MagicPrime64);
result = (result ^ AuUInt64((uWord16 & 0xFF00) >> 8)) * AuUInt64(kFnv1MagicPrime64);
return result;
}
template <>
inline AuUInt64 AuFnv1a64Runtime<4>(const void *base) noexcept
{
AuUInt64 result { kFnv1MagicVal64 };
auto uWord64 = AuReadU32(base, 0);
result = (result ^ AuUInt64((uWord64 & 0xFF) >> 0)) * AuUInt64(kFnv1MagicPrime64);
result = (result ^ AuUInt64((uWord64 & 0xFF00) >> 8)) * AuUInt64(kFnv1MagicPrime64);
result = (result ^ AuUInt64((uWord64 & 0xFF0000) >> 16)) * AuUInt64(kFnv1MagicPrime64);
result = (result ^ AuUInt64((uWord64 & 0xFF000000) >> 24)) * AuUInt64(kFnv1MagicPrime64);
return result;
}
template <>
inline AuUInt64 AuFnv1a64Runtime<8>(const void *base) noexcept
{
AuUInt64 result { kFnv1MagicVal64 };
auto uWord32 = AuReadU32(base, 0);
auto uWord32Hi = AuReadU32(base, 4);
result = (result ^ AuUInt64((uWord32 & 0xFF) >> 0)) * AuUInt64(kFnv1MagicPrime64);
result = (result ^ AuUInt64((uWord32 & 0xFF00) >> 8)) * AuUInt64(kFnv1MagicPrime64);
result = (result ^ AuUInt64((uWord32 & 0xFF0000) >> 16)) * AuUInt64(kFnv1MagicPrime64);
result = (result ^ AuUInt64((uWord32 & 0xFF000000) >> 24)) * AuUInt64(kFnv1MagicPrime64);
result = (result ^ AuUInt64((uWord32Hi & 0xFF) >> 0)) * AuUInt64(kFnv1MagicPrime64);
result = (result ^ AuUInt64((uWord32Hi & 0xFF00) >> 8)) * AuUInt64(kFnv1MagicPrime64);
result = (result ^ AuUInt64((uWord32Hi & 0xFF0000) >> 16)) * AuUInt64(kFnv1MagicPrime64);
result = (result ^ AuUInt64((uWord32Hi & 0xFF000000) >> 24)) * AuUInt64(kFnv1MagicPrime64);
return result;
}
#endif
template <AuUInt uCount>
inline auto AuFnv1aRuntime(const void *base) noexcept
{
return _AU_FNV1_32 ?
AuFnv1a32Runtime<uCount>(base) :
AuFnv1a64Runtime<uCount>(base);
}
#undef _AU_FNV1_32
#if defined(_AU_HASH_RETARD_COMPILER)
#pragma optimize("", on)
//#pragma GCC optimize ("fast-math")
#undef _AU_HASH_RETARD_COMPILER
#endif