Index: include/llvm/ADT/DenseMapInfo.h =================================================================== --- include/llvm/ADT/DenseMapInfo.h +++ include/llvm/ADT/DenseMapInfo.h @@ -30,6 +30,34 @@ //static bool isEqual(const T &LHS, const T &RHS); }; +template struct CachedHash { + CachedHash(T Val) : Val(Val) { Hash = DenseMapInfo::getHashValue(Val); } + CachedHash(T Val, unsigned Hash) : Val(Val), Hash(Hash) {} + T Val; + unsigned Hash; +}; + +// Provide DenseMapInfo for all CachedHash. +template struct DenseMapInfo> { + static CachedHash getEmptyKey() { + T N = DenseMapInfo::getEmptyKey(); + return {N, 0}; + } + static CachedHash getTombstoneKey() { + T N = DenseMapInfo::getTombstoneKey(); + return {N, 0}; + } + static unsigned getHashValue(CachedHash Val) { + assert(!isEqual(Val, getEmptyKey()) && "Cannot hash the empty key!"); + assert(!isEqual(Val, getTombstoneKey()) && + "Cannot hash the tombstone key!"); + return Val.Hash; + } + static bool isEqual(CachedHash A, CachedHash B) { + return DenseMapInfo::isEqual(A.Val, B.Val); + } +}; + // Provide DenseMapInfo for all pointers. template struct DenseMapInfo { Index: unittests/ADT/DenseMapTest.cpp =================================================================== --- unittests/ADT/DenseMapTest.cpp +++ unittests/ADT/DenseMapTest.cpp @@ -496,6 +496,55 @@ EXPECT_EQ(42, M.lookup(StringRef("a", 0))); } +struct CachedHashTest { + unsigned Val; + unsigned *Counter = nullptr; + CachedHashTest(unsigned Val) : Val(Val) {} + CachedHashTest(unsigned Val, unsigned *Counter) + : Val(Val), Counter(Counter) {} +}; +} +namespace llvm { +template <> struct DenseMapInfo { + static CachedHashTest getEmptyKey() { return ~0; } + static CachedHashTest getTombstoneKey() { return ~0U - 1; } + static unsigned getHashValue(const CachedHashTest &X) { + (*X.Counter)++; + return X.Val; + } + static bool isEqual(const CachedHashTest &LHS, const CachedHashTest &RHS) { + return LHS.Val == RHS.Val; + } +}; +} +namespace { + +TEST(DenseMapCustomTest, CachedHashTest) { + unsigned Counter = 0; + CachedHashTest Val(0, &Counter); + DenseMap Map; + + Map[Val] = 0; + ASSERT_EQ(1u, Counter); + + Map.reserve(64); + ASSERT_EQ(2u, Counter); +} + +// Like above, but now cache the hash. +TEST(DenseMapCustomTest, CachedHashTest2) { + unsigned Counter = 0; + CachedHashTest Val(0, &Counter); + typedef CachedHash Cached; + DenseMap Map; + + Map[Val] = 0; + ASSERT_EQ(1u, Counter); + + Map.reserve(64); + ASSERT_EQ(1u, Counter); +} + // Key traits that allows lookup with either an unsigned or char* key; // In the latter case, "a" == 0, "b" == 1 and so on. struct TestDenseMapInfo {