15 #include "absl/hash/hash.h"
22 #include <forward_list>
24 #include <initializer_list>
35 #include <type_traits>
36 #include <unordered_map>
37 #include <unordered_set>
41 #include "gmock/gmock.h"
42 #include "gtest/gtest.h"
43 #include "absl/container/btree_map.h"
44 #include "absl/container/btree_set.h"
45 #include "absl/container/flat_hash_map.h"
46 #include "absl/container/flat_hash_set.h"
47 #include "absl/container/node_hash_map.h"
48 #include "absl/container/node_hash_set.h"
49 #include "absl/hash/hash_testing.h"
50 #include "absl/hash/internal/spy_hash_state.h"
51 #include "absl/meta/type_traits.h"
52 #include "absl/numeric/int128.h"
53 #include "absl/strings/cord_test_helpers.h"
62 class TypeErasedValue {
64 TypeErasedValue() =
default;
65 TypeErasedValue(
const TypeErasedValue&) =
default;
66 TypeErasedValue(TypeErasedValue&&) =
default;
67 explicit TypeErasedValue(
const T&
n) :
n_(
n) {}
79 bool operator==(
const TypeErasedValue& rhs)
const {
return n_ == rhs.n_; }
80 bool operator!=(
const TypeErasedValue& rhs)
const {
return !(*
this == rhs); }
89 class TypeErasedContainer :
public TypeErasedValue<T> {
92 TypeErasedContainer() =
default;
93 TypeErasedContainer(
const TypeErasedContainer&) =
default;
94 TypeErasedContainer(TypeErasedContainer&&) =
default;
95 explicit TypeErasedContainer(
const T&
n) : TypeErasedValue<
T>(
n) {}
96 TypeErasedContainer(std::initializer_list<value_type> init_list)
97 : TypeErasedContainer(
T(init_list.
begin(), init_list.
end())) {}
101 : TypeErasedContainer(
T(&
v, &
v + 1)) {}
104 template <
typename T>
105 using TypeErasedVector = TypeErasedContainer<std::vector<T>>;
110 template <
typename T>
115 template <
typename T>
122 template <
typename T>
123 using is_hashable = std::is_default_constructible<absl::Hash<T>>;
129 EXPECT_EQ(SpyHash(
n), SpyHash(TypeParam{42}));
139 absl::Hash<std::tuple<TypeParam>>{}(std::tuple<TypeParam>(
n)));
147 enum LegacyEnum { kValue1, kValue2, kValue3 };
149 enum class EnumClass { kValue4, kValue5, kValue6 };
151 TEST(HashValueTest, EnumAndBool) {
157 LegacyEnum::kValue1, LegacyEnum::kValue2, LegacyEnum::kValue3)));
159 EnumClass::kValue4, EnumClass::kValue5, EnumClass::kValue6)));
164 TEST(HashValueTest, FloatingPoint) {
171 -std::numeric_limits<float>::infinity())));
175 -std::numeric_limits<double>::infinity())));
180 .5
L, 1.
L, 2.
L, 4.
L, 42.
L, 0.
L, -0.
L,
182 std::numeric_limits<long double>::infinity(),
183 -std::numeric_limits<long double>::infinity())));
199 TEST(HashValueTest, PointerAlignment) {
203 constexpr
size_t kTotalSize = 1 << 20;
204 std::unique_ptr<char[]>
data(
new char[kTotalSize]);
205 constexpr
size_t kLog2NumValues = 5;
206 constexpr
size_t kNumValues = 1 << kLog2NumValues;
208 for (
size_t align = 1;
align < kTotalSize / kNumValues;
214 size_t bits_and = ~size_t{};
216 for (
size_t i = 0;
i < kNumValues; ++
i) {
223 constexpr
size_t kMask = (1 << (kLog2NumValues + 7)) - 1;
224 size_t stuck_bits = (~bits_or | bits_and) & kMask;
225 EXPECT_EQ(stuck_bits, 0) <<
"0x" << std::hex << stuck_bits;
229 TEST(HashValueTest, PointerToMember) {
235 virtual ~A() =
default;
236 virtual void vfa() {}
238 static auto pq() -> void (
A::*)() {
return &A::q; }
242 virtual ~B() =
default;
243 virtual void vfb() {}
245 static auto pq() -> void (B::*)() {
return &B::q; }
252 int g1() & {
return 0; }
253 int g2()
const & {
return 0; }
254 int g3() && {
return 0; }
255 int g4()
const && {
return 0; }
257 int h1() & {
return 0; }
258 int h2()
const & {
return 0; }
259 int h3() && {
return 0; }
260 int h4()
const && {
return 0; }
280 &
Foo::f1,
static_cast<void (
Foo::*)()
>(
nullptr))));
286 &Foo::g1, &Foo::h1,
static_cast<int (
Foo::*)() &
>(
nullptr))));
289 &Foo::g2, &Foo::h2,
static_cast<int (
Foo::*)()
const &
>(
nullptr))));
292 &Foo::g3, &Foo::h3,
static_cast<int (
Foo::*)() &&
>(
nullptr))));
295 &Foo::g4, &Foo::h4,
static_cast<int (
Foo::*)()
const &&
>(
nullptr))));
299 static_cast<void (
Foo::*)()
>(&Foo::vfb),
300 static_cast<void (
Foo::*)()
>(
nullptr))));
304 static_cast<void (
Foo::*)()
>(Foo::B::pq()),
305 static_cast<void (
Foo::*)()
>(
nullptr))));
308 TEST(HashValueTest, PairAndTuple) {
315 std::make_pair(0, 42), std::make_pair(0, 42), std::make_pair(42, 0),
316 std::make_pair(0, 0), std::make_pair(42, 42), std::make_pair(1, 42))));
325 int a = 0,
b = 1,
c = 17,
d = 23;
327 std::tie(
a,
a), std::tie(
a,
b), std::tie(
b,
c), std::tie(
c,
d))));
331 std::forward_as_tuple(0, 0, 0), std::forward_as_tuple(0, 0, 42),
332 std::forward_as_tuple(0, 23, 0), std::forward_as_tuple(17, 0, 0),
333 std::forward_as_tuple(42, 0, 0), std::forward_as_tuple(3, 9, 9),
334 std::forward_as_tuple(0, 0, -42))));
337 TEST(HashValueTest, CombineContiguousWorks) {
341 auto vh1 = SpyHash(v1);
342 auto vh2 = SpyHash(v2);
346 struct DummyDeleter {
347 template <
typename T>
348 void operator() (
T*
ptr) {}
351 struct SmartPointerEq {
352 template <
typename T,
typename U>
353 bool operator()(
const T& t,
const U&
u)
const {
354 return GetPtr(t) == GetPtr(
u);
357 template <
typename T>
358 static auto GetPtr(
const T& t) -> decltype(&*t) {
359 return t ? &*
t :
nullptr;
362 static std::nullptr_t GetPtr(std::nullptr_t) {
return nullptr; }
365 TEST(HashValueTest, SmartPointers) {
371 std::unique_ptr<int, DummyDeleter> unique1(&
i);
372 std::unique_ptr<int, DummyDeleter> unique2(&
i);
373 std::unique_ptr<int, DummyDeleter> unique_other(&j);
374 std::unique_ptr<int, DummyDeleter> unique_null;
376 std::shared_ptr<int> shared1(&
i, DummyDeleter());
377 std::shared_ptr<int> shared2(&
i, DummyDeleter());
378 std::shared_ptr<int> shared_other(&j, DummyDeleter());
379 std::shared_ptr<int> shared_null;
384 ASSERT_TRUE(SmartPointerEq{}(unique_null,
nullptr));
388 std::forward_as_tuple(&
i,
nullptr,
389 unique1, unique2, unique_null,
390 absl::make_unique<int>(),
391 shared1, shared2, shared_null,
392 std::make_shared<int>()),
396 TEST(HashValueTest, FunctionPointer) {
400 Func p1 = [] {
return 2; }, p2 = [] {
return 1; };
406 template <
typename T>
407 std::tuple<int, T, size_t> operator()(
const T& t)
const {
422 size_t halfway = sv.
size() / 2;
423 std::vector<absl::string_view> parts = {sv.
substr(0, halfway),
446 const WrapInTuple
t{};
459 EXPECT_NE(SpyHash(
static_cast<const char*
>(
"ABC")),
463 TEST(HashValueTest, WString) {
472 TEST(HashValueTest, U16String) {
476 std::u16string(), std::u16string(
u"ABC"), std::u16string(
u"ABC"),
477 std::u16string(
u"Some other different string"),
478 std::u16string(
u"Iñtërnâtiônà lizætiøn"))));
481 TEST(HashValueTest, U32String) {
485 std::u32string(), std::u32string(U
"ABC"), std::u32string(U
"ABC"),
486 std::u32string(U
"Some other different string"),
487 std::u32string(U
"Iñtërnâtiônà lizætiøn"))));
490 TEST(HashValueTest, StdArray) {
494 std::make_tuple(std::array<int, 3>{}, std::array<int, 3>{{0, 23, 42}})));
497 TEST(HashValueTest, StdBitset) {
501 {std::bitset<2>(
"00"), std::bitset<2>(
"01"), std::bitset<2>(
"10"),
502 std::bitset<2>(
"11")}));
504 {std::bitset<5>(
"10101"), std::bitset<5>(
"10001"), std::bitset<5>()}));
506 constexpr
int kNumBits = 256;
507 std::array<std::string, 6> bit_strings;
509 bit_strings[1][0] =
'0';
510 bit_strings[2][1] =
'0';
511 bit_strings[3][kNumBits / 3] =
'0';
512 bit_strings[4][kNumBits - 2] =
'0';
513 bit_strings[5][kNumBits - 1] =
'0';
515 {std::bitset<kNumBits>(bit_strings[0].
c_str()),
516 std::bitset<kNumBits>(bit_strings[1].
c_str()),
517 std::bitset<kNumBits>(bit_strings[2].
c_str()),
518 std::bitset<kNumBits>(bit_strings[3].
c_str()),
519 std::bitset<kNumBits>(bit_strings[4].
c_str()),
520 std::bitset<kNumBits>(bit_strings[5].
c_str())}));
526 template <
typename T>
527 class UnorderedSequence {
529 UnorderedSequence() =
default;
530 template <
typename TT>
531 UnorderedSequence(std::initializer_list<TT>
l)
533 template <
typename ForwardIterator,
536 UnorderedSequence(ForwardIterator
begin, ForwardIterator
end)
540 explicit UnorderedSequence(
const T&
v) : values_(&
v, &
v + 1) {}
544 size_t size()
const {
return values_.size(); }
545 typename std::vector<T>::const_iterator
begin()
const {
546 return values_.begin();
548 typename std::vector<T>::const_iterator
end()
const {
return values_.end(); }
550 friend bool operator==(
const UnorderedSequence& lhs,
551 const UnorderedSequence& rhs) {
552 return lhs.size() == rhs.size() &&
553 std::is_permutation(lhs.begin(), lhs.end(), rhs.begin());
555 friend bool operator!=(
const UnorderedSequence& lhs,
556 const UnorderedSequence& rhs) {
557 return !(lhs == rhs);
559 template <
typename H>
561 return H::combine(H::combine_unordered(
std::move(h),
u.begin(),
u.end()),
566 std::vector<T> values_;
569 template <
typename T>
578 auto a =
static_cast<IntType
>(0);
579 auto b =
static_cast<IntType
>(23);
580 auto c =
static_cast<IntType
>(42);
582 std::vector<TypeParam> exemplars = {
583 TypeParam(), TypeParam(), TypeParam{
a,
b,
c},
584 TypeParam{
a,
c,
b}, TypeParam{
c,
a,
b}, TypeParam{
a},
585 TypeParam{
a,
a}, TypeParam{
a,
a,
a}, TypeParam{
a,
a,
b},
586 TypeParam{
a,
b,
a}, TypeParam{
b,
a,
a}, TypeParam{
a,
b},
593 std::deque<int>, std::forward_list<int>, std::list<int>, std::vector<int>,
594 std::vector<bool>, TypeErasedContainer<std::vector<int>>, std::set<int>,
595 std::multiset<int>, UnorderedSequence<int>,
596 TypeErasedContainer<UnorderedSequence<int>>, std::unordered_set<int>,
601 template <
typename T>
608 std::vector<T> exemplars = {
612 T{V{}},
T{V{}, V{}},
T{V{}, V{}, V{}},
614 T{V{1}},
T{V{1, 1}, V{1, 1}},
T{V{1, 1, 1}, V{1, 1, 1}, V{1, 1, 1}},
616 T{V{}, V{1, 2}},
T{V{}, V{2, 1}},
T{V{1, 2}, V{}},
T{V{2, 1}, V{}},
618 T{V{1, 2}, V{3, 4}},
T{V{1, 2}, V{4, 3}},
T{V{1, 3}, V{2, 4}},
619 T{V{1, 3}, V{4, 2}},
T{V{1, 4}, V{2, 3}},
T{V{1, 4}, V{3, 2}},
620 T{V{2, 3}, V{1, 4}},
T{V{2, 3}, V{4, 1}},
T{V{2, 4}, V{1, 3}},
621 T{V{2, 4}, V{3, 1}},
T{V{3, 4}, V{1, 2}},
T{V{3, 4}, V{2, 1}}};
626 template <
typename T>
627 using TypeErasedSet = TypeErasedContainer<UnorderedSequence<T>>;
630 std::vector<std::vector<int>>, std::vector<UnorderedSequence<int>>,
631 std::vector<TypeErasedSet<int>>, UnorderedSequence<std::vector<int>>,
632 UnorderedSequence<UnorderedSequence<int>>,
633 UnorderedSequence<TypeErasedSet<int>>, TypeErasedSet<std::vector<int>>,
634 TypeErasedSet<UnorderedSequence<int>>, TypeErasedSet<TypeErasedSet<int>>>;
636 NestedIntSequenceTypes);
644 template <
typename H>
646 return H::combine(
std::move(h), std::abs(
p.i));
650 return std::abs(
a.i) == std::abs(
b.i);
653 friend std::ostream&
operator<<(std::ostream&
o, Private
p) {
661 class PiecewiseHashTester {
672 split_locations_(
std::
move(split_locations)) {}
674 template <
typename H>
677 return H::combine_contiguous(
std::move(h),
p.buf_.data(),
p.buf_.size());
680 if (
p.split_locations_.empty()) {
685 for (
size_t next :
p.split_locations_) {
691 if (!last_chunk.
empty()) {
701 std::set<size_t> split_locations_;
707 template <
typename H>
709 const char*
foo =
"foo";
710 const char*
bar =
"bar";
717 TEST(HashValueTest, CombinePiecewiseBuffer) {
725 hash(PiecewiseHashTester(
"foobar", {})));
727 hash(PiecewiseHashTester(
"foobar", {3})));
740 for (
size_t big_buffer_size : {1024 * 2 + 512, 1024 * 3}) {
743 for (
int i = 0;
i < big_buffer_size; ++
i) {
745 big_buffer.push_back(32 + (
i * (
i / 3)) % 64);
747 auto big_buffer_hash =
hash(PiecewiseHashTester(big_buffer));
749 const int possible_breaks = 9;
750 size_t breaks[possible_breaks] = {1, 512, 1023, 1024, 1025,
751 1536, 2047, 2048, 2049};
752 for (
unsigned test_mask = 0; test_mask < (1
u << possible_breaks);
755 std::set<size_t> break_locations;
756 for (
int j = 0;
j < possible_breaks; ++
j) {
757 if (test_mask & (1
u << j)) {
758 break_locations.insert(breaks[j]);
762 hash(PiecewiseHashTester(big_buffer,
std::move(break_locations))),
768 TEST(HashValueTest, PrivateSanity) {
771 EXPECT_NE(SpyHash(Private{0}), SpyHash(Private{1}));
772 EXPECT_EQ(SpyHash(Private{1}), SpyHash(Private{1}));
783 TEST(HashValueTest, Variant) {
788 V(Private{1}), V(Private{-1}), V(Private{2}), V(
"ABC"), V(
"BCD"))));
790 #if ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
796 template <
typename T>
803 std::vector<M> exemplars{M{},
808 M{V{0,
"foo"}, V{42,
"bar"}},
809 M{V{42,
"bar"}, V{0,
"foo"}},
810 M{V{1,
"foo"}, V{42,
"bar"}},
811 M{V{1,
"foo"}, V{43,
"bar"}},
812 M{V{1,
"foo"}, V{43,
"baz"}}};
818 std::map<int, std::string>, std::unordered_map<int, std::string>,
821 UnorderedSequence<std::pair<const int, std::string>>>;
823 AssociativeMapTypes);
825 template <
typename T>
826 class HashValueAssociativeMultimapTest :
public testing::Test {};
829 TYPED_TEST_P(HashValueAssociativeMultimapTest, BasicUsage) {
830 using MM = TypeParam;
832 std::vector<MM> exemplars{MM{},
837 MM{V{0,
"foo"}, V{0,
"bar"}},
838 MM{V{0,
"bar"}, V{0,
"foo"}},
839 MM{V{0,
"foo"}, V{42,
"bar"}},
840 MM{V{1,
"foo"}, V{42,
"bar"}},
841 MM{V{1,
"foo"}, V{1,
"foo"}, V{43,
"bar"}},
842 MM{V{1,
"foo"}, V{43,
"bar"}, V{1,
"foo"}},
843 MM{V{1,
"foo"}, V{43,
"baz"}}};
848 using AssociativeMultimapTypes =
850 std::unordered_multimap<int, std::string>>;
852 AssociativeMultimapTypes);
854 TEST(HashValueTest, ReferenceWrapper) {
857 Private p1{1}, p10{10};
862 int one = 1, ten = 10;
868 std::tuple<std::reference_wrapper<int>>(
std::ref(ten)),
869 std::tuple<int>(one), std::tuple<int>(ten))));
872 template <
typename T,
typename =
void>
875 template <
typename T>
876 struct IsHashCallable<
T,
absl::
void_t<decltype(std::declval<absl::Hash<T>>()(
879 template <
typename T,
typename =
void>
882 template <
typename T>
883 struct IsAggregateInitializable<
T,
absl::
void_t<decltype(T{})>>
886 TEST(IsHashableTest, ValidHash) {
897 #if ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
898 TEST(IsHashableTest, PoisonHash) {
907 #if !defined(__GNUC__) || __GNUC__ < 9
912 #endif // ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
919 template <
typename HashCode>
925 struct EmptyCombine {
926 template <
typename HashCode>
932 template <
typename Int>
933 struct CombineIterative {
934 template <
typename HashCode>
936 for (
int i = 0;
i < 5; ++
i) {
943 template <
typename Int>
944 struct CombineVariadic {
945 template <
typename HashCode>
951 enum class InvokeTag {
952 kUniquelyRepresented,
954 #if ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
956 #endif // ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
961 template <InvokeTag T>
962 using InvokeTagConstant = std::integral_constant<InvokeTag, T>;
964 template <InvokeTag... Tags>
967 template <InvokeTag
a, InvokeTag
b, InvokeTag... Tags>
968 struct MinTag<
a,
b, Tags...> : MinTag<(a < b ? a : b), Tags...> {};
970 template <InvokeTag a>
971 struct MinTag<a> : InvokeTagConstant<a> {};
973 template <InvokeTag... Tags>
974 struct CustomHashType {
975 explicit CustomHashType(size_t val) : value(val) {}
979 template <InvokeTag allowed, InvokeTag... tags>
980 struct EnableIfContained
981 : std::enable_if<absl::disjunction<
982 std::integral_constant<bool, allowed == tags>...>::value> {};
985 typename H, InvokeTag... Tags,
986 typename = typename EnableIfContained<InvokeTag::kHashValue, Tags...>::type>
987 H AbslHashValue(H state, CustomHashType<Tags...> t) {
988 static_assert(MinTag<Tags...>::value == InvokeTag::kHashValue, "");
989 return H::combine(std::move(state),
990 t.value + static_cast<int>(InvokeTag::kHashValue));
997 namespace hash_internal {
998 template <InvokeTag... Tags>
999 struct is_uniquely_represented<
1000 CustomHashType<Tags...>,
1001 typename EnableIfContained<InvokeTag::kUniquelyRepresented, Tags...>::type>
1002 : std::true_type {};
1007 #if ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
1008 namespace ABSL_INTERNAL_LEGACY_HASH_NAMESPACE {
1009 template <InvokeTag... Tags>
1010 struct hash<CustomHashType<Tags...>> {
1011 template <InvokeTag... TagsIn, typename = typename EnableIfContained<
1012 InvokeTag::kLegacyHash, TagsIn...>::type>
1013 size_t operator()(CustomHashType<TagsIn...> t) const {
1014 static_assert(MinTag<Tags...>::value == InvokeTag::kLegacyHash, "");
1015 return t.value + static_cast<int>(InvokeTag::kLegacyHash);
1022 template <InvokeTag... Tags>
1023 struct hash<CustomHashType<Tags...>> {
1024 template <InvokeTag... TagsIn, typename = typename EnableIfContained<
1025 InvokeTag::kStdHash, TagsIn...>::type>
1026 size_t operator()(CustomHashType<TagsIn...> t) const {
1027 static_assert(MinTag<Tags...>::value == InvokeTag::kStdHash, "");
1028 return t.value + static_cast<int>(InvokeTag::kStdHash);
1035 template <typename... T>
1036 void TestCustomHashType(InvokeTagConstant<InvokeTag::kNone>, T...) {
1037 using type = CustomHashType<T::value...>;
1038 SCOPED_TRACE(testing::PrintToString(std::vector<InvokeTag>{T::value...}));
1039 EXPECT_TRUE(is_hashable<type>());
1040 EXPECT_TRUE(is_hashable<const type>());
1041 EXPECT_TRUE(is_hashable<const type&>());
1043 const size_t offset = static_cast<int>(std::min({T::value...}));
1044 EXPECT_EQ(SpyHash(type(7)), SpyHash(size_t{7 + offset}));
1047 void TestCustomHashType(InvokeTagConstant<InvokeTag::kNone>) {
1048 #if ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
1050 using type = CustomHashType<>;
1051 EXPECT_FALSE(is_hashable<type>());
1052 EXPECT_FALSE(is_hashable<const type>());
1053 EXPECT_FALSE(is_hashable<const type&>());
1057 template <InvokeTag Tag, typename... T>
1058 void TestCustomHashType(InvokeTagConstant<Tag> tag, T... t) {
1059 constexpr auto next = static_cast<InvokeTag>(static_cast<int>(Tag) + 1);
1060 TestCustomHashType(InvokeTagConstant<next>(), tag, t...);
1061 TestCustomHashType(InvokeTagConstant<next>(), t...);
1064 TEST(HashTest, CustomHashType) {
1065 TestCustomHashType(InvokeTagConstant<InvokeTag{}>());
1068 TEST(HashTest, NoOpsAreEquivalent) {
1069 EXPECT_EQ(Hash<NoOp>()({}), Hash<NoOp>()({}));
1070 EXPECT_EQ(Hash<NoOp>()({}), Hash<EmptyCombine>()({}));
1073 template <typename T>
1074 class HashIntTest : public testing::Test {
1076 TYPED_TEST_SUITE_P(HashIntTest);
1078 TYPED_TEST_P(HashIntTest, BasicUsage) {
1079 EXPECT_NE(Hash<NoOp>()({}), Hash<TypeParam>()(0));
1080 EXPECT_NE(Hash<NoOp>()({}),
1081 Hash<TypeParam>()(std::numeric_limits<TypeParam>::max()));
1082 if (std::numeric_limits<TypeParam>::min() != 0) {
1083 EXPECT_NE(Hash<NoOp>()({}),
1084 Hash<TypeParam>()(std::numeric_limits<TypeParam>::min()));
1087 EXPECT_EQ(Hash<CombineIterative<TypeParam>>()({}),
1088 Hash<CombineVariadic<TypeParam>>()({}));
1091 REGISTER_TYPED_TEST_SUITE_P(HashIntTest, BasicUsage);
1092 using IntTypes = testing::Types<unsigned char, char, int, int32_t, int64_t,
1093 uint32_t, uint64_t, size_t>;
1094 INSTANTIATE_TYPED_TEST_SUITE_P(My, HashIntTest, IntTypes);
1096 struct StructWithPadding {
1100 template <typename H>
1101 friend H AbslHashValue(H hash_state, const StructWithPadding& s) {
1102 return H::combine(std::move(hash_state), s.c, s.i);
1106 static_assert(sizeof(StructWithPadding) > sizeof(char) + sizeof(int),
1107 "StructWithPadding doesn't have padding");
1108 static_assert(std::is_standard_layout<StructWithPadding>::value, "");
1118 template <
typename H>
1120 for (
auto t =
slice.begin; t !=
slice.end; ++t) {
1121 hash_state = H::combine(
std::move(hash_state), *t);
1127 TEST(HashTest, HashNonUniquelyRepresentedType) {
1130 static const size_t kNumStructs = 10;
1131 unsigned char buffer1[kNumStructs *
sizeof(StructWithPadding)];
1133 auto* s1 =
reinterpret_cast<StructWithPadding*
>(buffer1);
1135 unsigned char buffer2[kNumStructs *
sizeof(StructWithPadding)];
1137 auto* s2 =
reinterpret_cast<StructWithPadding*
>(buffer2);
1138 for (
int i = 0;
i < kNumStructs; ++
i) {
1140 s1[
i].c = s2[
i].c =
'0' +
i;
1141 s1[
i].i = s2[
i].i =
i;
1142 ASSERT_FALSE(memcmp(buffer1 +
i *
sizeof(StructWithPadding),
1143 buffer2 +
i *
sizeof(StructWithPadding),
1144 sizeof(StructWithPadding)) == 0)
1145 <<
"Bug in test code: objects do not have unequal"
1146 <<
" object representations";
1150 EXPECT_EQ(
Hash<ArraySlice<StructWithPadding>>()({s1, s1 + kNumStructs}),
1151 Hash<ArraySlice<StructWithPadding>>()({s2, s2 + kNumStructs}));
1154 TEST(HashTest, StandardHashContainerUsage) {
1155 std::unordered_map<int, std::string, Hash<int>>
map = {{0,
"foo"},
1163 struct ConvertibleFromNoOp {
1164 ConvertibleFromNoOp(
NoOp) {}
1166 template <
typename H>
1168 return H::combine(
std::move(hash_state), 1);
1172 TEST(HashTest, HeterogeneousCall) {
1177 TEST(IsUniquelyRepresentedTest, SanityTest) {
1186 struct IntAndString {
1190 template <
typename H>
1192 return H::combine(
std::move(hash_state), int_and_string.s,
1197 TEST(HashTest, SmallValueOn64ByteBoundary) {
1201 TEST(HashTest, TypeErased) {
1205 EXPECT_EQ(SpyHash(TypeErasedValue<size_t>(7)), SpyHash(
size_t{7}));
1206 EXPECT_NE(SpyHash(TypeErasedValue<size_t>(7)), SpyHash(
size_t{13}));
1208 EXPECT_EQ(SpyHash(std::make_pair(TypeErasedValue<size_t>(7), 17)),
1209 SpyHash(std::make_pair(
size_t{7}, 17)));
1212 TypeErasedContainer<absl::flat_hash_set<absl::flat_hash_set<int>>> es = {
1220 struct ValueWithBoolConversion {
1221 operator bool()
const {
return false; }
1228 struct hash<ValueWithBoolConversion> {
1235 TEST(HashTest, DoesNotUseImplicitConversionsToBool) {
1244 std::tuple<int, int>
t{4, 2};
1252 TEST(
HashOf, MatchesHashOfTupleForMultipleArguments) {
1262 template <
typename T>
1263 std::true_type HashOfExplicitParameter(decltype(absl::HashOf<T>(0))) {
1266 template <
typename T>
1271 TEST(
HashOf, CantPassExplicitTemplateParameters) {