Bug 1433142 - Add support for hashing enum values. r=jwalden

Differential Revision: https://phabricator.services.mozilla.com/D70647
This commit is contained in:
Chris Fronk 2020-05-27 23:44:51 +00:00
parent c2dda9f2ae
commit dfcd4afc6e
3 changed files with 55 additions and 4 deletions

View File

@ -179,7 +179,8 @@ inline HashNumber AddUintptrToHash<8>(HashNumber aHash, uintptr_t aValue) {
* convert to uint32_t, data pointers, and function pointers.
*/
template <typename T, bool TypeIsNotIntegral = !std::is_integral_v<T>,
typename U = std::enable_if_t<TypeIsNotIntegral>>
bool TypeIsNotEnum = !std::is_enum_v<T>,
std::enable_if_t<TypeIsNotIntegral && TypeIsNotEnum, int> = 0>
MOZ_MUST_USE inline HashNumber AddToHash(HashNumber aHash, T aA) {
/*
* Try to convert |A| to uint32_t implicitly. If this works, great. If not,
@ -204,11 +205,19 @@ MOZ_MUST_USE inline HashNumber AddToHash(HashNumber aHash, A* aA) {
// types are treated the same as 64-bit pointers, and smaller integral types are
// first implicitly converted to 32 bits and then passed to AddUintptrToHash()
// to be hashed.
template <typename T, typename U = std::enable_if_t<std::is_integral_v<T>>>
template <typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
MOZ_MUST_USE constexpr HashNumber AddToHash(HashNumber aHash, T aA) {
return detail::AddUintptrToHash<sizeof(T)>(aHash, aA);
}
template <typename T, std::enable_if_t<std::is_enum_v<T>, int> = 0>
MOZ_MUST_USE constexpr HashNumber AddToHash(HashNumber aHash, T aA) {
// Hash using AddUintptrToHash with the underlying type of the enum type
using UnderlyingType = typename std::underlying_type<T>::type;
return detail::AddUintptrToHash<sizeof(UnderlyingType)>(
aHash, static_cast<UnderlyingType>(aA));
}
template <typename A, typename... Args>
MOZ_MUST_USE HashNumber AddToHash(HashNumber aHash, A aArg, Args... aArgs) {
return AddToHash(AddToHash(aHash, aArg), aArgs...);

View File

@ -94,7 +94,7 @@
namespace mozilla {
template <class>
template <class, class = void>
struct DefaultHasher;
template <class, class>
@ -744,7 +744,7 @@ struct PointerHasher {
};
// The default hash policy, which only works with integers.
template <class Key>
template <class Key, typename>
struct DefaultHasher {
using Lookup = Key;
@ -763,6 +763,22 @@ struct DefaultHasher {
static void rekey(Key& aKey, const Key& aNewKey) { aKey = aNewKey; }
};
// A DefaultHasher specialization for enums.
template <class T>
struct DefaultHasher<T, std::enable_if_t<std::is_enum_v<T>>> {
using Key = T;
using Lookup = Key;
static HashNumber hash(const Lookup& aLookup) { return HashGeneric(aLookup); }
static bool match(const Key& aKey, const Lookup& aLookup) {
// Use builtin or overloaded operator==.
return aKey == static_cast<Key>(aLookup);
}
static void rekey(Key& aKey, const Key& aNewKey) { aKey = aNewKey; }
};
// A DefaultHasher specialization for pointers.
template <class T>
struct DefaultHasher<T*> : PointerHasher<T*> {};

View File

@ -29,7 +29,33 @@ void TestMoveConstructor() {
MOZ_RELEASE_ASSERT(!map.count());
}
enum SimpleEnum { SIMPLE_1, SIMPLE_2 };
enum class ClassEnum : int {
CLASS_ENUM_1,
CLASS_ENUM_2,
};
void TestEnumHash() {
using namespace mozilla;
HashMap<SimpleEnum, int> map;
MOZ_RELEASE_ASSERT(map.put(SIMPLE_1, 1));
MOZ_RELEASE_ASSERT(map.put(SIMPLE_2, 2));
MOZ_RELEASE_ASSERT(map.lookup(SIMPLE_1)->value() == 1);
MOZ_RELEASE_ASSERT(map.lookup(SIMPLE_1)->value() == 2);
HashMap<ClassEnum, int> map2;
MOZ_RELEASE_ASSERT(map2.put(ClassEnum::CLASS_ENUM_1, 1));
MOZ_RELEASE_ASSERT(map2.put(ClassEnum::CLASS_ENUM_2, 2));
MOZ_RELEASE_ASSERT(map2.lookup(ClassEnum::CLASS_ENUM_1)->value() == 1);
MOZ_RELEASE_ASSERT(map2.lookup(ClassEnum::CLASS_ENUM_2)->value() == 2);
}
int main() {
TestMoveConstructor();
TestEnumHash();
return 0;
}