[llvm] Add support for hashing std::optional

The credit for the hashing code, taken from D138934, goes to Ramkumar
Ramachandra.  The test comes from OptionalTest.cpp and updated for
std::optional.

This is part of an effort to migrate from llvm::Optional to
std::optional:

https://discourse.llvm.org/t/deprecating-llvm-optional-x-hasvalue-getvalue-getvalueor/63716

Differential Revision: https://reviews.llvm.org/D139240
This commit is contained in:
Kazu Hirata 2022-12-02 18:53:00 -08:00
parent 8a1f12c6fb
commit f64d4a26ce
2 changed files with 25 additions and 0 deletions

View File

@ -51,6 +51,7 @@
#include <algorithm>
#include <cassert>
#include <cstring>
#include <optional>
#include <string>
#include <tuple>
#include <utility>
@ -122,6 +123,8 @@ hash_code hash_value(const std::tuple<Ts...> &arg);
template <typename T>
hash_code hash_value(const std::basic_string<T> &arg);
/// Compute a hash_code for a standard string.
template <typename T> hash_code hash_value(const std::optional<T> &arg);
/// Override the execution seed with a fixed value.
///
@ -662,6 +665,10 @@ hash_code hash_value(const std::basic_string<T> &arg) {
return hash_combine_range(arg.begin(), arg.end());
}
template <typename T> hash_code hash_value(const std::optional<T> &arg) {
return arg ? hash_combine(true, *arg) : hash_value(false);
}
template <> struct DenseMapInfo<hash_code, void> {
static inline hash_code getEmptyKey() { return hash_code(-1); }
static inline hash_code getTombstoneKey() { return hash_code(-2); }

View File

@ -17,6 +17,7 @@
#include <deque>
#include <list>
#include <map>
#include <optional>
#include <vector>
namespace llvm {
@ -130,6 +131,23 @@ TEST(HashingTest, HashValueStdString) {
hash_value(ws.substr(1, ws.size() - 2)));
}
TEST(HashingTest, HashValueStdOptional) {
// Check that std::nullopt, false, and true all hash differently.
std::optional<bool> 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<int> 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 <typename T, size_t N> T *begin(T (&arr)[N]) { return arr; }
template <typename T, size_t N> T *end(T (&arr)[N]) { return arr + N; }