AuROXTL/Include/auROXTL/auHashUtils.hpp
Reece Wilson f4487c589c [+] AuToIterator (function)
[+] AuToElementType (function)
[+] AuToValueType (function)
[+] Optimized 32bit/64bit hash routines
[+] AuFnv1aRuntime (32bit/64bit auto variant)
[+] std::array reimplementation for reasons i deleted from the file bc sperging
[+] AuArrayList
2023-01-18 10:49:32 +00:00

231 lines
7.8 KiB
C++

/***
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: auHashUtils.hpp
Date: 2022-3-23
Author: Reece
***/
#pragma once
#include "auFNV1Utils.hpp"
#define _AU_HASH_UTILS_HAS_STD
template <class T>
struct AuHasHashCode
{
template <class C> static constexpr AuTrueType Test(decltype(&C::HashCode));
template <class C> static constexpr AuFalseType Test(...);
using type = decltype(Test<T>(0));
};
template <class T>
constexpr inline bool AuHasHashCode_v = AuHasHashCode<T>::type::value;
namespace AuHash
{
template <class Key>
struct hash
{
#if defined(_AU_HASH_UTILS_HAS_STD)
AuConditional_t<AuHasHashCode_v<Key>, AuUInt8, std::hash<Key>> trashHasher;
#endif
AuUInt operator()(const Key &ref) const
{
if constexpr (AuHasHashCode_v<Key>)
{
return ref.HashCode();
}
#if defined(_AU_HASH_UTILS_HAS_STD)
else
{
return trashHasher(ref);
}
#endif
}
};
// Thomas Wang, Integer Hash Functions: https://web.archive.org/web/20061201032901/http://www.concentric.net/%7ETtwang/tech/inthash.htm
// Updated version under V8: V8/v9-11/src/utils/utils.h
//
// I'm sure Google's tweaks and subsequence implementations have justification grounded in reality more so than the initial publishing of a 1999ish article by some dude at HP
// Real world experience > 1999 HP guy > whatever the fuck the stl is doing (i think ms just uses fnv1s for everything)
//
// Preserving original function names for ease of xref. unseeded vs implied seeded doesnt mean anything. see: ComputeLongHash comment.
inline constexpr AuUInt32 ComputeUnseededHash(AuUInt32 key)
{
AuUInt32 hash = key;
hash = ~hash + (hash << 15); // hash = (hash << 15) - hash - 1;
hash = hash ^ (hash >> 12);
hash = hash + (hash << 2);
hash = hash ^ (hash >> 4);
hash = hash * 2057; // hash = (hash + (hash << 3)) + (hash << 11);
hash = hash ^ (hash >> 16);
return hash;
}
// ComputeLongHash(base::double_to_uint64(AsNumber())); ( pre-maglev V8 wasn't u64 optimizated. )
// ComputeLongHash(static_cast<uint64_t>(digit(0))); ( most js wont touch >31bit ints. )
inline constexpr AuUInt64 ComputeLongHash(AuUInt64 key)// ( i'm sure this function's fine for all ranges. )
{
AuUInt64 hash = key;
hash = ~hash + (hash << 18); // hash = (hash << 18) - hash - 1;
hash = hash ^ (hash >> 31);
hash = hash * 21; // hash = (hash + (hash << 2)) + (hash << 4);
hash = hash ^ (hash >> 11); // key = key ^ (key >>> 28); ?
hash = hash + (hash << 6); // key = key + (key << 31); ?
hash = hash ^ (hash >> 22); // ???????????
return hash;
}
#define _HASH_INT(type) \
template <> \
struct hash<type> \
{ \
constexpr AuUInt operator ()(const type b) const \
{ \
return AuFnv1aType<type>(b); \
} \
};
#if defined(AURORA_IS_32BIT)
#define _HASH_INT32BIT(type) \
template <> \
struct hash<type> \
{ \
constexpr AuUInt operator ()(const type intValue) const \
{ \
return ComputeUnseededHash(AuUInt32(intValue)); \
} \
};
#else
#define _HASH_INT32BIT(type) \
template <> \
struct hash<type> \
{ \
constexpr AuUInt operator ()(const type intValue) const \
{ \
return ComputeLongHash(AuUInt64(intValue)); \
} \
};
#endif
#if defined(AURORA_IS_32BIT)
#define _HASH_INT64BIT(type) \
template <> \
struct hash<type> \
{ \
constexpr AuUInt operator ()(const type intValue) const \
{ \
return AuUInt32(ComputeLongHash(AuUInt64(intValue)) & 0xFFFFFFFF); \
} \
};
#else
#define _HASH_INT64BIT(type) \
template <> \
struct hash<type> \
{ \
constexpr AuUInt operator ()(const type intValue) const \
{ \
return ComputeLongHash(AuUInt64(intValue)); \
} \
};
#endif
_HASH_INT32BIT(bool);
_HASH_INT32BIT(char);
_HASH_INT32BIT(signed char);
_HASH_INT32BIT(unsigned char);
_HASH_INT32BIT(char8_t);
_HASH_INT32BIT(char16_t);
_HASH_INT32BIT(char32_t);
_HASH_INT32BIT(wchar_t);
_HASH_INT32BIT(short);
_HASH_INT32BIT(unsigned short);
_HASH_INT32BIT(int);
_HASH_INT32BIT(unsigned int);
_HASH_INT64BIT(long);
_HASH_INT64BIT(long long);
_HASH_INT64BIT(unsigned long);
_HASH_INT64BIT(unsigned long long);
_HASH_INT(float);
_HASH_INT(double);
_HASH_INT(long double);
_HASH_INT(std::nullptr_t);
#undef _HASH_INT
#undef _HASH_INT32BIT
#undef _HASH_INT64BIT
template <class T>
struct hash<T *>
{
AuUInt operator ()(T *ptr) const
{
#if defined(AURORA_IS_32BIT)
return ComputeUnseededHash(AuUInt(ptr));
#else
return ComputeLongHash(AuUInt(ptr));
#endif
}
};
template <class T>
struct less
{
constexpr bool operator()(const T &lhs, const T &rhs) const
{
if constexpr (AuHasHashCode_v<T>)
{
return lhs.HashCode() < rhs.HashCode();
}
else
{
return lhs < rhs;
}
}
};
template <class T>
struct equal
{
constexpr bool operator()(const T &lhs, const T &rhs) const
{
return lhs == rhs;
}
};
}
template <class T, AU_TEMPLATE_ENABLE_WHEN(AuHasHashCode_v<T>)>
inline AuUInt AuHashCode(const T &ref)
{
return ref.HashCode();
}
template <class T, AU_TEMPLATE_ENABLE_WHEN(!AuHasHashCode_v<T>)>
inline AuUInt AuHashCode(const T &ref)
{
return AuHash::hash<T>()(ref);
}
template <class T>
struct AuEnableHashCodeOnData
{
AuUInt HashCode() const
{
#if defined(AURORA_IS_32BIT)
return AuFnv1a32Runtime(AuStaticCast<AuAddConst_t<T>>(this), sizeof(T));
#else
return AuFnv1a64Runtime(AuStaticCast<AuAddConst_t<T>>(this), sizeof(T));
#endif
}
};