141 lines
3.6 KiB
C++
141 lines
3.6 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
|
||
|
|
||
|
// 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
|
||
|
{
|
||
|
return AuUInt(ptr);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
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
|
||
|
{
|
||
|
return AuFnv1aType(*AuStaticCast<T>(this));
|
||
|
}
|
||
|
};
|