AuroraRuntime/Include/auROXTL/auHashUtils.hpp

149 lines
3.9 KiB
C++
Raw Normal View History

/***
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
// Thy shall pollute me, not std:: or any other namespace
// ...namespace
// ...namespace
// Has the penny dropped yet?
// It's amazing how every other language with a similar concept has conventions or other limitations on overloading packages/namespaces/modules, but C++ morons took the stance of the FSB on Chechnya, Crimea and Ukraine.
// We could potentially be even nicer with a dedicated namespace (`AuUserHashes`?) for user-defined overloads and substitution-is-often-compiler-crash behavior on a nicer template (Static? ::Hashcode() instead of operator?), so that AuHash doesn't get invaded.
template<typename T>
struct AuHasHashCode
{
template<typename C> static constexpr AuTrueType Test(decltype(&C::HashCode));
template<typename C> static constexpr AuFalseType Test(...);
using type = decltype(Test<T>(0));
};
template<typename 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
}
};
#define _HASH_F_CPP(type) \
template<> struct hash<type> \
{ \
AuUInt operator ()(type b) const \
{ \
return AuFnv1aType<type>(b); \
} \
};
_HASH_F_CPP(bool);
_HASH_F_CPP(char);
_HASH_F_CPP(signed char);
_HASH_F_CPP(unsigned char);
_HASH_F_CPP(char8_t);
_HASH_F_CPP(char16_t);
_HASH_F_CPP(char32_t);
_HASH_F_CPP(wchar_t);
_HASH_F_CPP(short);
_HASH_F_CPP(unsigned short);
_HASH_F_CPP(int);
_HASH_F_CPP(unsigned int);
_HASH_F_CPP(long);
_HASH_F_CPP(long long);
_HASH_F_CPP(unsigned long);
_HASH_F_CPP(unsigned long long);
_HASH_F_CPP(float);
_HASH_F_CPP(double);
_HASH_F_CPP(long double);
_HASH_F_CPP(std::nullptr_t);
#undef _HASH_F_CPP
template<class T> struct hash<T *>
{
AuUInt operator ()(T *ptr) const
{
#if defined(AURORA_IS_32BIT)
return AuFnv1a32Runtime(&ptr, sizeof(T *));
#else
return AuFnv1a64Runtime(&ptr, sizeof(T *));
#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<typename T, AU_TEMPLATE_ENABLE_WHEN(AuHasHashCode_v<T>)>
inline AuUInt AuHashCode(const T &ref)
{
return ref.HashCode();
}
template<typename T, AU_TEMPLATE_ENABLE_WHEN(!AuHasHashCode_v<T>)>
inline AuUInt AuHashCode(const T &ref)
{
return AuHash::hash<T>()(ref);
}
template<typename T>
struct AuEnableHashCodeOnData
{
AuUInt HashCode() const
{
2022-03-23 19:32:33 +00:00
#if defined(AURORA_IS_32BIT)
return AuFnv1a32Runtime(AuStaticCast<T>(this), sizeof(T));
#else
return AuFnv1a64Runtime(AuStaticCast<T>(this), sizeof(T));
#endif
}
};