/*** 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(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 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 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 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 inline constexpr AuUInt AuFnv1aPtr(const T *const type, AuUInt length, const AuUInt value = kFnv1MagicValPlatform) noexcept { return AuFnv1aType((const char *)type, length, 0, value); } template inline constexpr AuUInt32 AuFnv1aPtr32(const T *const type, AuUInt length, const AuUInt32 value = kFnv1MagicVal32) noexcept { return AuFnv1aType32((const char *)type, length, 0, value); } template 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 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 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 inline auto AuFnv1aRuntime(const void *base) noexcept { return _AU_FNV1_32 ? AuFnv1a32Runtime(base) : AuFnv1a64Runtime(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