diff --git a/llvm/include/llvm/ADT/Hashing.h b/llvm/include/llvm/ADT/Hashing.h --- a/llvm/include/llvm/ADT/Hashing.h +++ b/llvm/include/llvm/ADT/Hashing.h @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -122,6 +123,8 @@ template hash_code hash_value(const std::basic_string &arg); +/// Compute a hash_code for a standard string. +template hash_code hash_value(const std::optional &arg); /// Override the execution seed with a fixed value. /// @@ -662,6 +665,10 @@ return hash_combine_range(arg.begin(), arg.end()); } +template hash_code hash_value(const std::optional &arg) { + return arg ? hash_combine(true, *arg) : hash_value(false); +} + template <> struct DenseMapInfo { static inline hash_code getEmptyKey() { return hash_code(-1); } static inline hash_code getTombstoneKey() { return hash_code(-2); } diff --git a/llvm/unittests/ADT/HashingTest.cpp b/llvm/unittests/ADT/HashingTest.cpp --- a/llvm/unittests/ADT/HashingTest.cpp +++ b/llvm/unittests/ADT/HashingTest.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include namespace llvm { @@ -130,6 +131,23 @@ hash_value(ws.substr(1, ws.size() - 2))); } +TEST(HashingTest, HashValueStdOptional) { + // Check that std::nullopt, false, and true all hash differently. + std::optional B, B0 = false, B1 = true; + EXPECT_NE(hash_value(B0), hash_value(B)); + EXPECT_NE(hash_value(B1), hash_value(B)); + EXPECT_NE(hash_value(B1), hash_value(B0)); + + // Check that std::nullopt, 0, and 1 all hash differently. + std::optional I, I0 = 0, I1 = 1; + EXPECT_NE(hash_value(I0), hash_value(I)); + EXPECT_NE(hash_value(I1), hash_value(I)); + EXPECT_NE(hash_value(I1), hash_value(I0)); + + // Check std::nullopt hash the same way regardless of type. + EXPECT_EQ(hash_value(B), hash_value(I)); +} + template T *begin(T (&arr)[N]) { return arr; } template T *end(T (&arr)[N]) { return arr + N; }