21 #include <forward_list> 33 #include <type_traits> 34 #include <unordered_map> 38 #include "gmock/gmock.h" 39 #include "gtest/gtest.h" 52 class HashValueIntTest :
public testing::Test {
64 using is_hashable = std::is_default_constructible<absl::Hash<T>>;
70 EXPECT_EQ(SpyHash(n), SpyHash(TypeParam{42}));
71 EXPECT_NE(SpyHash(n), SpyHash(TypeParam{0}));
72 EXPECT_NE(SpyHash(std::numeric_limits<TypeParam>::max()),
73 SpyHash(std::numeric_limits<TypeParam>::min()));
80 absl::Hash<std::tuple<TypeParam>>{}(std::tuple<TypeParam>(
n)));
84 using IntTypes = testing::Types<
unsigned char, char, int, int32_t, int64_t, uint32_t,
86 INSTANTIATE_TYPED_TEST_CASE_P(My, HashValueIntTest, IntTypes);
92 TEST(HashValueTest, EnumAndBool) {
98 LegacyEnum::kValue1, LegacyEnum::kValue2, LegacyEnum::kValue3)));
100 EnumClass::kValue4, EnumClass::kValue5, EnumClass::kValue6)));
102 std::make_tuple(
true,
false)));
105 TEST(HashValueTest, FloatingPoint) {
111 std::make_tuple(42.f, 0.f, -0.f, std::numeric_limits<float>::infinity(),
112 -std::numeric_limits<float>::infinity())));
115 std::make_tuple(42., 0., -0., std::numeric_limits<double>::infinity(),
116 -std::numeric_limits<double>::infinity())));
121 .5L, 1.L, 2.L, 4.L, 42.L, 0.L, -0.L,
122 17 * static_cast<long double>(std::numeric_limits<double>::max()),
123 std::numeric_limits<long double>::infinity(),
124 -std::numeric_limits<long double>::infinity())));
127 TEST(HashValueTest, Pointer) {
135 std::make_tuple(&i, ptr,
nullptr, ptr + 1, n)));
138 TEST(HashValueTest, PointerAlignment) {
142 constexpr
size_t kTotalSize = 1 << 20;
143 std::unique_ptr<char[]>
data(
new char[kTotalSize]);
144 constexpr
size_t kLog2NumValues = 5;
145 constexpr
size_t kNumValues = 1 << kLog2NumValues;
147 for (
size_t align = 1;
align < kTotalSize / kNumValues;
148 align < 8 ?
align += 1 : align < 1024 ? align += 8 : align += 32) {
150 ASSERT_LE(align * kNumValues, kTotalSize);
153 size_t bits_and = ~size_t{};
155 for (
size_t i = 0;
i < kNumValues; ++
i) {
162 constexpr
size_t kMask = (1 << (kLog2NumValues + 7)) - 1;
163 size_t stuck_bits = (~bits_or | bits_and) & kMask;
164 EXPECT_EQ(stuck_bits, 0) <<
"0x" << std::hex << stuck_bits;
168 TEST(HashValueTest, PairAndTuple) {
169 EXPECT_TRUE((is_hashable<std::pair<int, int>>::value));
170 EXPECT_TRUE((is_hashable<std::pair<const int&, const int&>>::value));
171 EXPECT_TRUE((is_hashable<std::tuple<int&, int&>>::value));
172 EXPECT_TRUE((is_hashable<std::tuple<int&&, int&&>>::value));
175 std::make_pair(0, 42), std::make_pair(0, 42), std::make_pair(42, 0),
176 std::make_pair(0, 0), std::make_pair(42, 42), std::make_pair(1, 42))));
179 std::make_tuple(std::make_tuple(0, 0, 0), std::make_tuple(0, 0, 42),
180 std::make_tuple(0, 23, 0), std::make_tuple(17, 0, 0),
181 std::make_tuple(42, 0, 0), std::make_tuple(3, 9, 9),
182 std::make_tuple(0, 0, -42))));
185 int a = 0,
b = 1, c = 17, d = 23;
187 std::tie(a, a), std::tie(a,
b), std::tie(
b, c), std::tie(c, d))));
191 std::forward_as_tuple(0, 0, 0), std::forward_as_tuple(0, 0, 42),
192 std::forward_as_tuple(0, 23, 0), std::forward_as_tuple(17, 0, 0),
193 std::forward_as_tuple(42, 0, 0), std::forward_as_tuple(3, 9, 9),
194 std::forward_as_tuple(0, 0, -42))));
197 TEST(HashValueTest, CombineContiguousWorks) {
198 std::vector<std::tuple<int>> v1 = {std::make_tuple(1), std::make_tuple(3)};
199 std::vector<std::tuple<int>> v2 = {std::make_tuple(1), std::make_tuple(2)};
201 auto vh1 = SpyHash(v1);
202 auto vh2 = SpyHash(v2);
206 struct DummyDeleter {
207 template <
typename T>
208 void operator() (T*
ptr) {}
211 struct SmartPointerEq {
212 template <
typename T,
typename U>
213 bool operator()(
const T& t,
const U& u)
const {
214 return GetPtr(t) == GetPtr(u);
217 template <
typename T>
218 static auto GetPtr(
const T& t) -> decltype(&*t) {
219 return t ? &*t :
nullptr;
222 static std::nullptr_t GetPtr(std::nullptr_t) {
return nullptr; }
225 TEST(HashValueTest, SmartPointers) {
226 EXPECT_TRUE((is_hashable<std::unique_ptr<int>>::value));
227 EXPECT_TRUE((is_hashable<std::unique_ptr<int, DummyDeleter>>::value));
228 EXPECT_TRUE((is_hashable<std::shared_ptr<int>>::value));
231 std::unique_ptr<int, DummyDeleter> unique1(&i);
232 std::unique_ptr<int, DummyDeleter> unique2(&i);
233 std::unique_ptr<int, DummyDeleter> unique_other(&j);
234 std::unique_ptr<int, DummyDeleter> unique_null;
236 std::shared_ptr<int> shared1(&i, DummyDeleter());
237 std::shared_ptr<int> shared2(&i, DummyDeleter());
238 std::shared_ptr<int> shared_other(&j, DummyDeleter());
239 std::shared_ptr<int> shared_null;
242 ASSERT_TRUE(SmartPointerEq{}(unique1, shared1));
243 ASSERT_FALSE(SmartPointerEq{}(unique1, shared_other));
244 ASSERT_TRUE(SmartPointerEq{}(unique_null,
nullptr));
245 ASSERT_FALSE(SmartPointerEq{}(shared2,
nullptr));
248 std::forward_as_tuple(&i,
nullptr,
249 unique1, unique2, unique_null,
250 absl::make_unique<int>(),
251 shared1, shared2, shared_null,
252 std::make_shared<int>()),
256 TEST(HashValueTest, FunctionPointer) {
257 using Func = int (*)();
260 Func p1 = [] {
return 2; }, p2 = [] {
return 1; };
262 std::make_tuple(p1, p2,
nullptr)));
266 template <
typename T>
267 std::tuple<int, T, size_t> operator()(
const T& t)
const {
268 return std::make_tuple(7, t, 0xdeadbeef);
272 TEST(HashValueTest, Strings) {
275 const std::string small =
"foo";
276 const std::string dup =
"foofoo";
277 const std::string large =
"large";
278 const std::string huge = std::string(5000,
'a');
289 const WrapInTuple t{};
300 EXPECT_NE(SpyHash(static_cast<const char*>(
"ABC")),
304 TEST(HashValueTest, StdArray) {
305 EXPECT_TRUE((is_hashable<std::array<int, 3>>::value));
308 std::make_tuple(std::array<int, 3>{}, std::array<int, 3>{{0, 23, 42}})));
311 TEST(HashValueTest, StdBitset) {
312 EXPECT_TRUE((is_hashable<std::bitset<257>>::value));
315 {std::bitset<2>(
"00"), std::bitset<2>(
"01"), std::bitset<2>(
"10"),
316 std::bitset<2>(
"11")}));
318 {std::bitset<5>(
"10101"), std::bitset<5>(
"10001"), std::bitset<5>()}));
320 constexpr
int kNumBits = 256;
321 std::array<std::string, 6> bit_strings;
322 bit_strings.fill(std::string(kNumBits,
'1'));
323 bit_strings[1][0] =
'0';
324 bit_strings[2][1] =
'0';
325 bit_strings[3][kNumBits / 3] =
'0';
326 bit_strings[4][kNumBits - 2] =
'0';
327 bit_strings[5][kNumBits - 1] =
'0';
329 {std::bitset<kNumBits>(bit_strings[0].c_str()),
330 std::bitset<kNumBits>(bit_strings[1].c_str()),
331 std::bitset<kNumBits>(bit_strings[2].c_str()),
332 std::bitset<kNumBits>(bit_strings[3].c_str()),
333 std::bitset<kNumBits>(bit_strings[4].c_str()),
334 std::bitset<kNumBits>(bit_strings[5].c_str())}));
337 template <
typename T>
338 class HashValueSequenceTest :
public testing::Test {
346 auto a =
static_cast<ValueType
>(0);
347 auto b =
static_cast<ValueType
>(23);
348 auto c =
static_cast<ValueType
>(42);
351 std::make_tuple(TypeParam(), TypeParam{}, TypeParam{
a,
b, c},
352 TypeParam{
a,
b}, TypeParam{
b, c})));
356 using IntSequenceTypes =
357 testing::Types<std::deque<int>, std::forward_list<int>, std::list<int>,
358 std::vector<int>, std::vector<bool>, std::set<int>,
360 INSTANTIATE_TYPED_TEST_CASE_P(My, HashValueSequenceTest, IntSequenceTypes);
368 template <
typename H>
370 return H::combine(
std::move(h), std::abs(p.i));
374 return std::abs(a.i) == std::abs(b.i);
377 friend std::ostream&
operator<<(std::ostream&
o, Private p) {
382 TEST(HashValueTest, PrivateSanity) {
385 EXPECT_NE(SpyHash(Private{0}), SpyHash(Private{1}));
386 EXPECT_EQ(SpyHash(Private{1}), SpyHash(Private{1}));
394 std::make_tuple(O{}, O{{1}}, O{{-1}}, O{{10}})));
397 TEST(HashValueTest, Variant) {
402 V(Private{1}), V(Private{-1}), V(Private{2}), V(
"ABC"), V(
"BCD"))));
404 #if ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ 410 TEST(HashValueTest, Maps) {
411 EXPECT_TRUE((is_hashable<std::map<int, std::string>>::value));
413 using M = std::map<int, std::string>;
415 M{}, M{{0,
"foo"}}, M{{1,
"foo"}}, M{{0,
"bar"}}, M{{1,
"bar"}},
416 M{{0,
"foo"}, {42,
"bar"}}, M{{1,
"foo"}, {42,
"bar"}},
417 M{{1,
"foo"}, {43,
"bar"}}, M{{1,
"foo"}, {43,
"baz"}})));
419 using MM = std::multimap<int, std::string>;
421 MM{}, MM{{0,
"foo"}}, MM{{1,
"foo"}}, MM{{0,
"bar"}}, MM{{1,
"bar"}},
422 MM{{0,
"foo"}, {0,
"bar"}}, MM{{0,
"bar"}, {0,
"foo"}},
423 MM{{0,
"foo"}, {42,
"bar"}}, MM{{1,
"foo"}, {42,
"bar"}},
424 MM{{1,
"foo"}, {1,
"foo"}, {43,
"bar"}}, MM{{1,
"foo"}, {43,
"baz"}})));
427 template <
typename T,
typename =
void>
428 struct IsHashCallable : std::false_type {};
430 template <
typename T>
431 struct IsHashCallable<T, absl::
void_t<decltype(std::declval<absl::Hash<T>>()(
432 std::declval<const T&>()))>> : std::true_type {};
434 template <
typename T,
typename =
void>
435 struct IsAggregateInitializable : std::false_type {};
437 template <
typename T>
438 struct IsAggregateInitializable<T, absl::
void_t<decltype(T{})>>
441 TEST(IsHashableTest, ValidHash) {
452 #if ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ 453 TEST(IsHashableTest, PoisonHash) {
456 EXPECT_FALSE(std::is_default_constructible<
absl::Hash<X>>::value);
457 EXPECT_FALSE(std::is_copy_constructible<
absl::Hash<X>>::value);
458 EXPECT_FALSE(std::is_move_constructible<
absl::Hash<X>>::value);
462 EXPECT_FALSE(IsAggregateInitializable<
absl::Hash<X>>::value);
464 #endif // ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ 471 template <
typename HashCode>
477 struct EmptyCombine {
478 template <
typename HashCode>
484 template <
typename Int>
485 struct CombineIterative {
486 template <
typename HashCode>
487 friend HashCode
AbslHashValue(HashCode h, CombineIterative c) {
488 for (
int i = 0;
i < 5; ++
i) {
495 template <
typename Int>
496 struct CombineVariadic {
497 template <
typename HashCode>
498 friend HashCode
AbslHashValue(HashCode h, CombineVariadic c) {
499 return HashCode::combine(
std::move(h), Int(0), Int(1), Int(2), Int(3),
504 kUniquelyRepresented,
506 #if ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_ 508 #endif // ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_ 513 template <InvokeTag T>
514 using InvokeTagConstant = std::integral_constant<InvokeTag, T>;
520 struct MinTag<a, b, Tags...> : MinTag<(a < b ? a : b), Tags...> {};
522 template <InvokeTag a>
523 struct MinTag<a> : InvokeTagConstant<a> {};
525 template <InvokeTag... Tags>
526 struct CustomHashType {
527 explicit CustomHashType(size_t val) : value(val) {}
531 template <InvokeTag allowed, InvokeTag... tags>
532 struct EnableIfContained
533 : std::enable_if<absl::disjunction<
534 std::integral_constant<bool, allowed == tags>...>::value> {};
537 typename H, InvokeTag... Tags,
538 typename = typename EnableIfContained<InvokeTag::kHashValue, Tags...>::type>
539 H AbslHashValue(H state, CustomHashType<Tags...> t) {
540 static_assert(MinTag<Tags...>::value == InvokeTag::kHashValue, "");
541 return H::combine(std::move(state),
542 t.value + static_cast<int>(InvokeTag::kHashValue));
548 namespace hash_internal {
549 template <InvokeTag... Tags>
550 struct is_uniquely_represented<
551 CustomHashType<Tags...>,
552 typename EnableIfContained<InvokeTag::kUniquelyRepresented, Tags...>::type>
557 #if ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
558 namespace ABSL_INTERNAL_LEGACY_HASH_NAMESPACE {
559 template <InvokeTag... Tags>
560 struct hash<CustomHashType<Tags...>> {
561 template <InvokeTag... TagsIn, typename = typename EnableIfContained<
562 InvokeTag::kLegacyHash, TagsIn...>::type>
563 size_t operator()(CustomHashType<TagsIn...> t) const {
564 static_assert(MinTag<Tags...>::value == InvokeTag::kLegacyHash, "");
565 return t.value + static_cast<int>(InvokeTag::kLegacyHash);
572 template <InvokeTag... Tags>
573 struct hash<CustomHashType<Tags...>> {
574 template <InvokeTag... TagsIn, typename = typename EnableIfContained<
575 InvokeTag::kStdHash, TagsIn...>::type>
576 size_t operator()(CustomHashType<TagsIn...> t) const {
577 static_assert(MinTag<Tags...>::value == InvokeTag::kStdHash, "");
578 return t.value + static_cast<int>(InvokeTag::kStdHash);
585 template <typename... T>
586 void TestCustomHashType(InvokeTagConstant<InvokeTag::kNone>, T...) {
587 using type = CustomHashType<T::value...>;
588 SCOPED_TRACE(testing::PrintToString(std::vector<InvokeTag>{T::value...}));
589 EXPECT_TRUE(is_hashable<type>());
590 EXPECT_TRUE(is_hashable<const type>());
591 EXPECT_TRUE(is_hashable<const type&>());
593 const size_t offset = static_cast<int>(std::min({T::value...}));
594 EXPECT_EQ(SpyHash(type(7)), SpyHash(size_t{7 + offset}));
597 void TestCustomHashType(InvokeTagConstant<InvokeTag::kNone>) {
598 #if ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
600 using type = CustomHashType<>;
601 EXPECT_FALSE(is_hashable<type>());
602 EXPECT_FALSE(is_hashable<const type>());
603 EXPECT_FALSE(is_hashable<const type&>());
607 template <InvokeTag Tag, typename... T>
608 void TestCustomHashType(InvokeTagConstant<Tag> tag, T... t) {
609 constexpr auto next = static_cast<InvokeTag>(static_cast<int>(Tag) + 1);
610 TestCustomHashType(InvokeTagConstant<next>(), tag, t...);
611 TestCustomHashType(InvokeTagConstant<next>(), t...);
614 TEST(HashTest, CustomHashType) {
615 TestCustomHashType(InvokeTagConstant<InvokeTag{}>());
618 TEST(HashTest, NoOpsAreEquivalent) {
619 EXPECT_EQ(Hash<NoOp>()({}), Hash<NoOp>()({}));
620 EXPECT_EQ(Hash<NoOp>()({}), Hash<EmptyCombine>()({}));
623 template <typename T>
624 class HashIntTest : public testing::Test {
626 TYPED_TEST_SUITE_P(HashIntTest);
628 TYPED_TEST_P(HashIntTest, BasicUsage) {
629 EXPECT_NE(Hash<NoOp>()({}), Hash<TypeParam>()(0));
630 EXPECT_NE(Hash<NoOp>()({}),
631 Hash<TypeParam>()(std::numeric_limits<TypeParam>::max()));
632 if (std::numeric_limits<TypeParam>::min() != 0) {
633 EXPECT_NE(Hash<NoOp>()({}),
634 Hash<TypeParam>()(std::numeric_limits<TypeParam>::min()));
637 EXPECT_EQ(Hash<CombineIterative<TypeParam>>()({}),
638 Hash<CombineVariadic<TypeParam>>()({}));
641 REGISTER_TYPED_TEST_CASE_P(HashIntTest, BasicUsage);
642 using IntTypes = testing::Types<unsigned char, char, int, int32_t, int64_t, uint32_t,
644 INSTANTIATE_TYPED_TEST_CASE_P(My, HashIntTest, IntTypes);
646 struct StructWithPadding {
650 template <typename H>
651 friend H AbslHashValue(H hash_state, const StructWithPadding& s) {
652 return H::combine(std::move(hash_state), s.c, s.i);
656 static_assert(sizeof(StructWithPadding) > sizeof(char) + sizeof(int),
657 "StructWithPadding doesn't have padding");
658 static_assert(std::is_standard_layout<StructWithPadding>::value, "");
663 template <typename T>
668 template <
typename H>
669 friend H
AbslHashValue(H hash_state,
const ArraySlice& slice) {
670 for (
auto t = slice.begin; t != slice.end; ++t) {
671 hash_state = H::combine(
std::move(hash_state), *t);
677 TEST(HashTest, HashNonUniquelyRepresentedType) {
680 static const size_t kNumStructs = 10;
681 unsigned char buffer1[kNumStructs *
sizeof(StructWithPadding)];
682 std::memset(buffer1, 0,
sizeof(buffer1));
683 auto* s1 =
reinterpret_cast<StructWithPadding*
>(buffer1);
685 unsigned char buffer2[kNumStructs *
sizeof(StructWithPadding)];
686 std::memset(buffer2, 255,
sizeof(buffer2));
687 auto* s2 =
reinterpret_cast<StructWithPadding*
>(buffer2);
688 for (
int i = 0;
i < kNumStructs; ++
i) {
690 s1[
i].c = s2[
i].c =
'0' +
i;
691 s1[
i].i = s2[
i].i =
i;
692 ASSERT_FALSE(memcmp(buffer1 +
i *
sizeof(StructWithPadding),
693 buffer2 +
i *
sizeof(StructWithPadding),
694 sizeof(StructWithPadding)) == 0)
695 <<
"Bug in test code: objects do not have unequal" 696 <<
" object representations";
700 EXPECT_EQ(
Hash<ArraySlice<StructWithPadding>>()({s1, s1 + kNumStructs}),
701 Hash<ArraySlice<StructWithPadding>>()({s2, s2 + kNumStructs}));
704 TEST(HashTest, StandardHashContainerUsage) {
705 std::unordered_map<int, std::string, Hash<int>> map = {{0,
"foo"},
708 EXPECT_NE(map.find(0), map.end());
709 EXPECT_EQ(map.find(1), map.end());
710 EXPECT_NE(map.find(0u), map.end());
713 struct ConvertibleFromNoOp {
714 ConvertibleFromNoOp(NoOp) {}
716 template <
typename H>
718 return H::combine(
std::move(hash_state), 1);
722 TEST(HashTest, HeterogeneousCall) {
727 TEST(IsUniquelyRepresentedTest, SanityTest) {
736 struct IntAndString {
740 template <
typename H>
741 friend H
AbslHashValue(H hash_state, IntAndString int_and_string) {
742 return H::combine(
std::move(hash_state), int_and_string.s,
747 TEST(HashTest, SmallValueOn64ByteBoundary) {
754 template <
typename H>
765 TEST(HashTest, TypeErased) {
767 EXPECT_TRUE((is_hashable<std::pair<TypeErased, int>>::value));
769 EXPECT_EQ(SpyHash(TypeErased{7}), SpyHash(
size_t{7}));
770 EXPECT_NE(SpyHash(TypeErased{7}), SpyHash(
size_t{13}));
772 EXPECT_EQ(SpyHash(std::make_pair(TypeErased{7}, 17)),
773 SpyHash(std::make_pair(
size_t{7}, 17)));
776 struct ValueWithBoolConversion {
777 operator bool()
const {
return false; }
784 struct hash<ValueWithBoolConversion> {
791 TEST(HashTest, DoesNotUseImplicitConversionsToBool) {
static HashState Create(T *state)
size_t operator()(ValueWithBoolConversion v)
static HashState combine(HashState state, const T &value, const Ts &... values)
std::ostream & operator<<(std::ostream &os, absl::LogSeverity s)
TYPED_TEST_SUITE_P(ConstructorTest)
SpyHashStateImpl< void > SpyHashState
CONSTEXPR_F fields align(second_tag, fields f) noexcept
bool operator==(const absl::InlinedVector< T, N, A > &a, const absl::InlinedVector< T, N, A > &b)
H AbslHashValue(H h, const absl::InlinedVector< TheT, TheN, TheA > &a)
static char data[kDataSize]
hash_default_hash< typename T::first_type > hash
ABSL_MUST_USE_RESULT testing::AssertionResult VerifyTypeImplementsAbslHashCorrectly(const Container &values)
typename type_traits_internal::VoidTImpl< Ts... >::type void_t
TYPED_TEST_P(ConstructorTest, NoArgs)
TEST(Symbolize, Unimplemented)
constexpr absl::remove_reference_t< T > && move(T &&t) noexcept
static bool Optional(bool)
absl::hash_internal::Hash< T > Hash
REGISTER_TYPED_TEST_CASE_P(ConstructorTest, NoArgs, BucketCount, BucketCountHash, BucketCountHashEqual, BucketCountHashEqualAlloc, BucketCountAlloc, BucketCountHashAlloc, Alloc, InputIteratorBucketHashEqualAlloc, InputIteratorBucketAlloc, InputIteratorBucketHashAlloc, CopyConstructor, CopyConstructorAlloc, MoveConstructor, MoveConstructorAlloc, InitializerListBucketHashEqualAlloc, InitializerListBucketAlloc, InitializerListBucketHashAlloc, Assignment, MoveAssignment, AssignmentFromInitializerList, AssignmentOverwritesExisting, MoveAssignmentOverwritesExisting, AssignmentFromInitializerListOverwritesExisting, AssignmentOnSelf)