Skip to content

Commit c3c9312

Browse files
author
Alexandre Rames
committed
[Support] Automatically support hash_value when HashBuilder support is available.
Use the `HBuilder` interface to provide default implementations of `llvm::hash_value`. Reviewed By: dexonsmith Differential Revision: https://reviews.llvm.org/D109024
1 parent e6597db commit c3c9312

File tree

2 files changed

+61
-0
lines changed

2 files changed

+61
-0
lines changed

llvm/include/llvm/Support/HashBuilder.h

+28
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#define LLVM_SUPPORT_HASHBUILDER_H
1717

1818
#include "llvm/ADT/ArrayRef.h"
19+
#include "llvm/ADT/Hashing.h"
1920
#include "llvm/ADT/STLExtras.h"
2021
#include "llvm/ADT/StringRef.h"
2122
#include "llvm/Support/Endian.h"
@@ -405,6 +406,33 @@ using HashBuilder =
405406
HashBuilderImpl<HasherT, (Endianness == support::endianness::native
406407
? support::endian::system_endianness()
407408
: Endianness)>;
409+
410+
namespace hashbuilder_detail {
411+
class HashCodeHasher {
412+
public:
413+
HashCodeHasher() : Code(0) {}
414+
void update(ArrayRef<uint8_t> Data) {
415+
hash_code DataCode = hash_value(Data);
416+
Code = hash_combine(Code, DataCode);
417+
}
418+
hash_code Code;
419+
};
420+
421+
using HashCodeHashBuilder = HashBuilder<hashbuilder_detail::HashCodeHasher,
422+
support::endianness::native>;
423+
} // namespace hashbuilder_detail
424+
425+
/// Provide a default implementation of `hash_value` when `addHash(const T &)`
426+
/// is supported.
427+
template <typename T>
428+
std::enable_if_t<
429+
is_detected<hashbuilder_detail::HashCodeHashBuilder::HasAddHashT, T>::value,
430+
hash_code>
431+
hash_value(const T &Value) {
432+
hashbuilder_detail::HashCodeHashBuilder HBuilder;
433+
HBuilder.add(Value);
434+
return HBuilder.getHasher().Code;
435+
}
408436
} // end namespace llvm
409437

410438
#endif // LLVM_SUPPORT_HASHBUILDER_H

llvm/unittests/ADT/HashingTest.cpp

+33
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include "llvm/ADT/Hashing.h"
1414
#include "llvm/Support/DataTypes.h"
15+
#include "llvm/Support/HashBuilder.h"
1516
#include "gtest/gtest.h"
1617
#include <deque>
1718
#include <list>
@@ -402,4 +403,36 @@ TEST(HashingTest, HashCombineArgs18) {
402403
#undef CHECK_SAME
403404
}
404405

406+
struct StructWithHashBuilderSupport {
407+
char C;
408+
int I;
409+
template <typename HasherT, llvm::support::endianness Endianness>
410+
friend void addHash(llvm::HashBuilderImpl<HasherT, Endianness> &HBuilder,
411+
const StructWithHashBuilderSupport &Value) {
412+
HBuilder.add(Value.C, Value.I);
413+
}
414+
};
415+
416+
TEST(HashingTest, HashWithHashBuilder) {
417+
StructWithHashBuilderSupport S{'c', 1};
418+
EXPECT_NE(static_cast<size_t>(llvm::hash_value(S)), static_cast<size_t>(0));
405419
}
420+
421+
struct StructWithHashBuilderAndHashValueSupport {
422+
char C;
423+
int I;
424+
template <typename HasherT, llvm::support::endianness Endianness>
425+
friend void addHash(llvm::HashBuilderImpl<HasherT, Endianness> &HBuilder,
426+
const StructWithHashBuilderAndHashValueSupport &Value) {}
427+
friend hash_code
428+
hash_value(const StructWithHashBuilderAndHashValueSupport &Value) {
429+
return 0xbeef;
430+
}
431+
};
432+
433+
TEST(HashingTest, HashBuilderAndHashValue) {
434+
StructWithHashBuilderAndHashValueSupport S{'c', 1};
435+
EXPECT_EQ(static_cast<size_t>(hash_value(S)), static_cast<size_t>(0xbeef));
436+
}
437+
438+
} // namespace

0 commit comments

Comments
 (0)