hash_test.cc (42450B)
1 // Copyright 2018 The Abseil Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "absl/hash/hash.h" 16 17 #include <algorithm> 18 #include <array> 19 #include <bitset> 20 #include <cstddef> 21 #include <cstdint> 22 #include <cstdlib> 23 #include <cstring> 24 #include <functional> 25 #include <initializer_list> 26 #include <ios> 27 #include <limits> 28 #include <memory> 29 #include <ostream> 30 #include <set> 31 #include <string> 32 #include <tuple> 33 #include <type_traits> 34 #include <unordered_map> 35 #include <utility> 36 #include <vector> 37 38 #include "gmock/gmock.h" 39 #include "gtest/gtest.h" 40 #include "absl/base/config.h" 41 #include "absl/container/flat_hash_set.h" 42 #include "absl/hash/hash_testing.h" 43 #include "absl/hash/internal/hash_test.h" 44 #include "absl/hash/internal/spy_hash_state.h" 45 #include "absl/memory/memory.h" 46 #include "absl/meta/type_traits.h" 47 #include "absl/numeric/bits.h" 48 #include "absl/strings/cord_test_helpers.h" 49 #include "absl/strings/string_view.h" 50 #include "absl/types/optional.h" 51 #include "absl/types/variant.h" 52 53 #ifdef ABSL_INTERNAL_STD_FILESYSTEM_PATH_HASH_AVAILABLE 54 #include <filesystem> // NOLINT 55 #endif 56 57 #ifdef ABSL_HAVE_STD_STRING_VIEW 58 #include <string_view> 59 #endif 60 61 namespace { 62 63 using ::absl::hash_test_internal::is_hashable; 64 using ::absl::hash_test_internal::TypeErasedContainer; 65 using ::absl::hash_test_internal::TypeErasedValue; 66 using ::testing::SizeIs; 67 68 template <typename T> 69 using TypeErasedVector = TypeErasedContainer<std::vector<T>>; 70 71 using absl::Hash; 72 using absl::hash_internal::SpyHashState; 73 74 template <typename T> 75 class HashValueIntTest : public testing::Test { 76 }; 77 TYPED_TEST_SUITE_P(HashValueIntTest); 78 79 template <typename T> 80 SpyHashState SpyHash(const T& value) { 81 return SpyHashState::combine(SpyHashState(), value); 82 } 83 84 TYPED_TEST_P(HashValueIntTest, BasicUsage) { 85 EXPECT_TRUE((is_hashable<TypeParam>::value)); 86 87 TypeParam n = 42; 88 EXPECT_EQ(SpyHash(n), SpyHash(TypeParam{42})); 89 EXPECT_NE(SpyHash(n), SpyHash(TypeParam{0})); 90 EXPECT_NE(SpyHash(std::numeric_limits<TypeParam>::max()), 91 SpyHash(std::numeric_limits<TypeParam>::min())); 92 } 93 94 TYPED_TEST_P(HashValueIntTest, FastPath) { 95 // Test the fast-path to make sure the values are the same. 96 TypeParam n = 42; 97 EXPECT_EQ(absl::Hash<TypeParam>{}(n), 98 absl::Hash<std::tuple<TypeParam>>{}(std::tuple<TypeParam>(n))); 99 } 100 101 REGISTER_TYPED_TEST_SUITE_P(HashValueIntTest, BasicUsage, FastPath); 102 using IntTypes = testing::Types<unsigned char, char, int, int32_t, int64_t, 103 uint32_t, uint64_t, size_t>; 104 INSTANTIATE_TYPED_TEST_SUITE_P(My, HashValueIntTest, IntTypes); 105 106 enum LegacyEnum { kValue1, kValue2, kValue3 }; 107 108 enum class EnumClass { kValue4, kValue5, kValue6 }; 109 110 TEST(HashValueTest, EnumAndBool) { 111 EXPECT_TRUE((is_hashable<LegacyEnum>::value)); 112 EXPECT_TRUE((is_hashable<EnumClass>::value)); 113 EXPECT_TRUE((is_hashable<bool>::value)); 114 115 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple( 116 LegacyEnum::kValue1, LegacyEnum::kValue2, LegacyEnum::kValue3))); 117 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple( 118 EnumClass::kValue4, EnumClass::kValue5, EnumClass::kValue6))); 119 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly( 120 std::make_tuple(true, false))); 121 } 122 123 TEST(HashValueTest, HashConsistentAcrossIntTypes){ 124 std::vector<size_t> hashes = { 125 absl::Hash<int8_t>{}(1), absl::Hash<uint8_t>{}(1), 126 absl::Hash<int16_t>{}(1), absl::Hash<uint16_t>{}(1), 127 absl::Hash<int32_t>{}(1), absl::Hash<uint32_t>{}(1), 128 absl::Hash<int64_t>{}(1), absl::Hash<uint64_t>{}(1)}; 129 EXPECT_THAT(hashes, testing::Each(absl::Hash<int>{}(1))); 130 } 131 132 TEST(HashValueTest, FloatingPoint) { 133 EXPECT_TRUE((is_hashable<float>::value)); 134 EXPECT_TRUE((is_hashable<double>::value)); 135 EXPECT_TRUE((is_hashable<long double>::value)); 136 137 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly( 138 std::make_tuple(42.f, 0.f, -0.f, std::numeric_limits<float>::infinity(), 139 -std::numeric_limits<float>::infinity()))); 140 141 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly( 142 std::make_tuple(42., 0., -0., std::numeric_limits<double>::infinity(), 143 -std::numeric_limits<double>::infinity()))); 144 145 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple( 146 // Add some values with small exponent to test that NORMAL values also 147 // append their category. 148 .5L, 1.L, 2.L, 4.L, 42.L, 0.L, -0.L, 149 17 * static_cast<long double>(std::numeric_limits<double>::max()), 150 std::numeric_limits<long double>::infinity(), 151 -std::numeric_limits<long double>::infinity()))); 152 } 153 154 TEST(HashValueTest, Pointer) { 155 EXPECT_TRUE((is_hashable<int*>::value)); 156 EXPECT_TRUE((is_hashable<int(*)(char, float)>::value)); 157 EXPECT_TRUE((is_hashable<void(*)(int, int, ...)>::value)); 158 159 int i; 160 int* ptr = &i; 161 int* n = nullptr; 162 163 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly( 164 std::make_tuple(&i, ptr, nullptr, ptr + 1, n))); 165 } 166 167 TEST(HashValueTest, PointerAlignment) { 168 // We want to make sure that pointer alignment will not cause too many bits to 169 // be stuck. 170 171 constexpr size_t kTotalSize = 1 << 20; 172 std::unique_ptr<char[]> data(new char[kTotalSize]); 173 constexpr size_t kLog2NumValues = 5; 174 constexpr size_t kNumValues = 1 << kLog2NumValues; 175 176 for (size_t align = 1; align < kTotalSize / kNumValues; 177 align < 8 ? align += 1 : align < 1024 ? align += 8 : align += 32) { 178 SCOPED_TRACE(align); 179 ASSERT_LE(align * kNumValues, kTotalSize); 180 181 size_t bits_or = 0; 182 size_t bits_and = ~size_t{}; 183 184 for (size_t i = 0; i < kNumValues; ++i) { 185 size_t hash = absl::Hash<void*>()(data.get() + i * align); 186 bits_or |= hash; 187 bits_and &= hash; 188 } 189 190 // Limit the scope to the bits we would be using for Swisstable. 191 constexpr size_t kMask = (1 << (kLog2NumValues + 7)) - 1; 192 size_t stuck_bits = (~bits_or | bits_and) & kMask; 193 // Test that there are at most 2 stuck bits. Sometimes we see stuck_bits 194 // of 0x3. 195 EXPECT_LE(absl::popcount(stuck_bits), 2) << "0x" << std::hex << stuck_bits; 196 } 197 } 198 199 TEST(HashValueTest, PointerToMember) { 200 struct Bass { 201 void q() {} 202 }; 203 204 struct A : Bass { 205 virtual ~A() = default; 206 virtual void vfa() {} 207 208 static auto pq() -> void (A::*)() { return &A::q; } 209 }; 210 211 struct B : Bass { 212 virtual ~B() = default; 213 virtual void vfb() {} 214 215 static auto pq() -> void (B::*)() { return &B::q; } 216 }; 217 218 struct Foo : A, B { 219 void f1() {} 220 void f2() const {} 221 222 int g1() & { return 0; } 223 int g2() const & { return 0; } 224 int g3() && { return 0; } 225 int g4() const && { return 0; } 226 227 int h1() & { return 0; } 228 int h2() const & { return 0; } 229 int h3() && { return 0; } 230 int h4() const && { return 0; } 231 232 int a; 233 int b; 234 235 const int c = 11; 236 const int d = 22; 237 }; 238 239 EXPECT_TRUE((is_hashable<float Foo::*>::value)); 240 EXPECT_TRUE((is_hashable<double (Foo::*)(int, int)&&>::value)); 241 242 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly( 243 std::make_tuple(&Foo::a, &Foo::b, static_cast<int Foo::*>(nullptr)))); 244 245 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly( 246 std::make_tuple(&Foo::c, &Foo::d, static_cast<const int Foo::*>(nullptr), 247 &Foo::a, &Foo::b))); 248 249 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple( 250 &Foo::f1, static_cast<void (Foo::*)()>(nullptr)))); 251 252 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple( 253 &Foo::f2, static_cast<void (Foo::*)() const>(nullptr)))); 254 255 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple( 256 &Foo::g1, &Foo::h1, static_cast<int (Foo::*)() &>(nullptr)))); 257 258 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple( 259 &Foo::g2, &Foo::h2, static_cast<int (Foo::*)() const &>(nullptr)))); 260 261 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple( 262 &Foo::g3, &Foo::h3, static_cast<int (Foo::*)() &&>(nullptr)))); 263 264 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple( 265 &Foo::g4, &Foo::h4, static_cast<int (Foo::*)() const &&>(nullptr)))); 266 267 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly( 268 std::make_tuple(static_cast<void (Foo::*)()>(&Foo::vfa), 269 static_cast<void (Foo::*)()>(&Foo::vfb), 270 static_cast<void (Foo::*)()>(nullptr)))); 271 272 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly( 273 std::make_tuple(static_cast<void (Foo::*)()>(Foo::A::pq()), 274 static_cast<void (Foo::*)()>(Foo::B::pq()), 275 static_cast<void (Foo::*)()>(nullptr)))); 276 } 277 278 TEST(HashValueTest, PairAndTuple) { 279 EXPECT_TRUE((is_hashable<std::pair<int, int>>::value)); 280 EXPECT_TRUE((is_hashable<std::pair<const int&, const int&>>::value)); 281 EXPECT_TRUE((is_hashable<std::tuple<int&, int&>>::value)); 282 EXPECT_TRUE((is_hashable<std::tuple<int&&, int&&>>::value)); 283 284 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple( 285 std::make_pair(0, 42), std::make_pair(0, 42), std::make_pair(42, 0), 286 std::make_pair(0, 0), std::make_pair(42, 42), std::make_pair(1, 42)))); 287 288 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly( 289 std::make_tuple(std::make_tuple(0, 0, 0), std::make_tuple(0, 0, 42), 290 std::make_tuple(0, 23, 0), std::make_tuple(17, 0, 0), 291 std::make_tuple(42, 0, 0), std::make_tuple(3, 9, 9), 292 std::make_tuple(0, 0, -42)))); 293 294 // Test that tuples of lvalue references work (so we need a few lvalues): 295 int a = 0, b = 1, c = 17, d = 23; 296 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple( 297 std::tie(a, a), std::tie(a, b), std::tie(b, c), std::tie(c, d)))); 298 299 // Test that tuples of rvalue references work: 300 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple( 301 std::forward_as_tuple(0, 0, 0), std::forward_as_tuple(0, 0, 42), 302 std::forward_as_tuple(0, 23, 0), std::forward_as_tuple(17, 0, 0), 303 std::forward_as_tuple(42, 0, 0), std::forward_as_tuple(3, 9, 9), 304 std::forward_as_tuple(0, 0, -42)))); 305 } 306 307 TEST(HashValueTest, CombineContiguousWorks) { 308 std::vector<std::tuple<int>> v1 = {std::make_tuple(1), std::make_tuple(3)}; 309 std::vector<std::tuple<int>> v2 = {std::make_tuple(1), std::make_tuple(2)}; 310 311 auto vh1 = SpyHash(v1); 312 auto vh2 = SpyHash(v2); 313 EXPECT_NE(vh1, vh2); 314 } 315 316 struct DummyDeleter { 317 template <typename T> 318 void operator() (T*) {} 319 }; 320 321 struct SmartPointerEq { 322 template <typename T, typename U> 323 bool operator()(const T& t, const U& u) const { 324 return GetPtr(t) == GetPtr(u); 325 } 326 327 template <typename T> 328 static auto GetPtr(const T& t) -> decltype(&*t) { 329 return t ? &*t : nullptr; 330 } 331 332 static std::nullptr_t GetPtr(std::nullptr_t) { return nullptr; } 333 }; 334 335 TEST(HashValueTest, SmartPointers) { 336 EXPECT_TRUE((is_hashable<std::unique_ptr<int>>::value)); 337 EXPECT_TRUE((is_hashable<std::unique_ptr<int, DummyDeleter>>::value)); 338 EXPECT_TRUE((is_hashable<std::shared_ptr<int>>::value)); 339 340 int i, j; 341 std::unique_ptr<int, DummyDeleter> unique1(&i); 342 std::unique_ptr<int, DummyDeleter> unique2(&i); 343 std::unique_ptr<int, DummyDeleter> unique_other(&j); 344 std::unique_ptr<int, DummyDeleter> unique_null; 345 346 std::shared_ptr<int> shared1(&i, DummyDeleter()); 347 std::shared_ptr<int> shared2(&i, DummyDeleter()); 348 std::shared_ptr<int> shared_other(&j, DummyDeleter()); 349 std::shared_ptr<int> shared_null; 350 351 // Sanity check of the Eq function. 352 ASSERT_TRUE(SmartPointerEq{}(unique1, shared1)); 353 ASSERT_FALSE(SmartPointerEq{}(unique1, shared_other)); 354 ASSERT_TRUE(SmartPointerEq{}(unique_null, nullptr)); 355 ASSERT_FALSE(SmartPointerEq{}(shared2, nullptr)); 356 357 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly( 358 std::forward_as_tuple(&i, nullptr, // 359 unique1, unique2, unique_null, // 360 absl::make_unique<int>(), // 361 shared1, shared2, shared_null, // 362 std::make_shared<int>()), 363 SmartPointerEq{})); 364 } 365 366 TEST(HashValueTest, FunctionPointer) { 367 using Func = int (*)(); 368 EXPECT_TRUE(is_hashable<Func>::value); 369 370 Func p1 = [] { return 2; }, p2 = [] { return 1; }; 371 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly( 372 std::make_tuple(p1, p2, nullptr))); 373 } 374 375 struct WrapInTuple { 376 template <typename T> 377 std::tuple<int, T, size_t> operator()(const T& t) const { 378 return std::make_tuple(7, t, 0xdeadbeef); 379 } 380 }; 381 382 absl::Cord FlatCord(absl::string_view sv) { 383 absl::Cord c(sv); 384 c.Flatten(); 385 return c; 386 } 387 388 absl::Cord FragmentedCord(absl::string_view sv) { 389 if (sv.size() < 2) { 390 return absl::Cord(sv); 391 } 392 size_t halfway = sv.size() / 2; 393 std::vector<absl::string_view> parts = {sv.substr(0, halfway), 394 sv.substr(halfway)}; 395 return absl::MakeFragmentedCord(parts); 396 } 397 398 #ifdef ABSL_HAVE_INTRINSIC_INT128 399 TEST(HashValueTest, TestIntrinsicInt128) { 400 EXPECT_TRUE((is_hashable<__int128_t>::value)); 401 EXPECT_TRUE((is_hashable<__uint128_t>::value)); 402 403 absl::flat_hash_set<size_t> hashes; 404 std::vector<__uint128_t> values; 405 for (int i = 0; i < 128; ++i) { 406 // Some arbitrary pattern to check if changing each bit changes the hash. 407 static constexpr __uint128_t kPattern = 408 __uint128_t{0x0123456789abcdef} | 409 (__uint128_t{0x0123456789abcdef} << 64); 410 const __uint128_t value = kPattern ^ (__uint128_t{1} << i); 411 const __int128_t as_signed = static_cast<__int128_t>(value); 412 413 values.push_back(value); 414 hashes.insert(absl::Hash<__uint128_t>{}(value)); 415 416 // Verify that the fast-path for MixingHashState does not break the hash. 417 EXPECT_EQ(absl::HashOf(value), absl::Hash<__uint128_t>{}(value)); 418 EXPECT_EQ(absl::HashOf(as_signed), absl::Hash<__int128_t>{}(as_signed)); 419 } 420 EXPECT_THAT(hashes, SizeIs(128)); 421 422 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(values)); 423 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly( 424 std::vector<__int128_t>(values.begin(), values.end()))); 425 } 426 #endif // ABSL_HAVE_INTRINSIC_INT128 427 428 TEST(HashValueTest, Strings) { 429 EXPECT_TRUE((is_hashable<std::string>::value)); 430 431 const std::string small = "foo"; 432 const std::string dup = "foofoo"; 433 const std::string large = std::string(2048, 'x'); // multiple of chunk size 434 const std::string huge = std::string(5000, 'a'); // not a multiple 435 436 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple( 437 std::string(), absl::string_view(), absl::Cord(), std::string(""), 438 absl::string_view(""), absl::Cord(""), std::string(small), 439 absl::string_view(small), absl::Cord(small), FragmentedCord(small), 440 std::string(dup), absl::string_view(dup), absl::Cord(dup), 441 std::string(large), absl::string_view(large), absl::Cord(large), 442 std::string(huge), absl::string_view(huge), FlatCord(huge), 443 FragmentedCord(huge)))); 444 445 // Also check that nested types maintain the same hash. 446 const WrapInTuple t{}; 447 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple( 448 t(std::string()), t(absl::string_view()), t(absl::Cord()), 449 t(std::string("")), t(absl::string_view("")), t(absl::Cord("")), 450 t(std::string(small)), t(absl::string_view(small)), t(absl::Cord(small)), 451 t(FragmentedCord(small)), t(std::string(dup)), t(absl::string_view(dup)), 452 t(absl::Cord(dup)), t(std::string(large)), t(absl::string_view(large)), 453 t(absl::Cord(large)), t(std::string(huge)), t(absl::string_view(huge)), 454 t(FlatCord(huge)), t(FragmentedCord(huge))))); 455 456 // Make sure that hashing a `const char*` does not use its string-value. 457 EXPECT_NE(SpyHash(static_cast<const char*>("ABC")), 458 SpyHash(absl::string_view("ABC"))); 459 } 460 461 TEST(HashValueTest, StringsVector) { 462 using Vec = std::vector<std::string>; 463 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple( 464 Vec{"abc", "def"}, Vec{"abcde", "f"}, 465 Vec{"abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"}, 466 Vec{"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXY", "Z"}))); 467 } 468 469 TEST(HashValueTest, WString) { 470 EXPECT_TRUE((is_hashable<std::wstring>::value)); 471 472 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple( 473 std::wstring(), std::wstring(L"ABC"), std::wstring(L"ABC"), 474 std::wstring(L"Some other different string"), 475 std::wstring(L"Iñtërnâtiônà lizætiøn")))); 476 } 477 478 TEST(HashValueTest, U16String) { 479 EXPECT_TRUE((is_hashable<std::u16string>::value)); 480 481 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple( 482 std::u16string(), std::u16string(u"ABC"), std::u16string(u"ABC"), 483 std::u16string(u"Some other different string"), 484 std::u16string(u"Iñtërnâtiônà lizætiøn")))); 485 } 486 487 TEST(HashValueTest, U32String) { 488 EXPECT_TRUE((is_hashable<std::u32string>::value)); 489 490 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple( 491 std::u32string(), std::u32string(U"ABC"), std::u32string(U"ABC"), 492 std::u32string(U"Some other different string"), 493 std::u32string(U"Iñtërnâtiônà lizætiøn")))); 494 } 495 496 TEST(HashValueTest, WStringView) { 497 #ifndef ABSL_HAVE_STD_STRING_VIEW 498 GTEST_SKIP(); 499 #else 500 EXPECT_TRUE((is_hashable<std::wstring_view>::value)); 501 502 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple( 503 std::wstring_view(), std::wstring_view(L"ABC"), std::wstring_view(L"ABC"), 504 std::wstring_view(L"Some other different string_view"), 505 std::wstring_view(L"Iñtërnâtiônà lizætiøn")))); 506 #endif 507 } 508 509 TEST(HashValueTest, U16StringView) { 510 #ifndef ABSL_HAVE_STD_STRING_VIEW 511 GTEST_SKIP(); 512 #else 513 EXPECT_TRUE((is_hashable<std::u16string_view>::value)); 514 515 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly( 516 std::make_tuple(std::u16string_view(), std::u16string_view(u"ABC"), 517 std::u16string_view(u"ABC"), 518 std::u16string_view(u"Some other different string_view"), 519 std::u16string_view(u"Iñtërnâtiônà lizætiøn")))); 520 #endif 521 } 522 523 TEST(HashValueTest, U32StringView) { 524 #ifndef ABSL_HAVE_STD_STRING_VIEW 525 GTEST_SKIP(); 526 #else 527 EXPECT_TRUE((is_hashable<std::u32string_view>::value)); 528 529 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly( 530 std::make_tuple(std::u32string_view(), std::u32string_view(U"ABC"), 531 std::u32string_view(U"ABC"), 532 std::u32string_view(U"Some other different string_view"), 533 std::u32string_view(U"Iñtërnâtiônà lizætiøn")))); 534 #endif 535 } 536 537 TEST(HashValueTest, StdFilesystemPath) { 538 #ifndef ABSL_INTERNAL_STD_FILESYSTEM_PATH_HASH_AVAILABLE 539 GTEST_SKIP() << "std::filesystem::path is unavailable on this platform"; 540 #else 541 EXPECT_TRUE((is_hashable<std::filesystem::path>::value)); 542 543 // clang-format off 544 const auto kTestCases = std::make_tuple( 545 std::filesystem::path(), 546 std::filesystem::path("/"), 547 #ifndef __GLIBCXX__ 548 // libstdc++ has a known issue normalizing "//". 549 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106452 550 std::filesystem::path("//"), 551 #endif 552 std::filesystem::path("/a/b"), 553 std::filesystem::path("/a//b"), 554 std::filesystem::path("a/b"), 555 std::filesystem::path("a/b/"), 556 std::filesystem::path("a//b"), 557 std::filesystem::path("a//b/"), 558 std::filesystem::path("c:/"), 559 std::filesystem::path("c:\\"), 560 std::filesystem::path("c:\\/"), 561 std::filesystem::path("c:\\//"), 562 std::filesystem::path("c://"), 563 std::filesystem::path("c://\\"), 564 std::filesystem::path("/e/p"), 565 std::filesystem::path("/s/../e/p"), 566 std::filesystem::path("e/p"), 567 std::filesystem::path("s/../e/p")); 568 // clang-format on 569 570 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(kTestCases)); 571 #endif 572 } 573 574 TEST(HashValueTest, StdArray) { 575 EXPECT_TRUE((is_hashable<std::array<int, 3>>::value)); 576 577 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly( 578 std::make_tuple(std::array<int, 3>{}, std::array<int, 3>{{0, 23, 42}}))); 579 } 580 581 TEST(HashValueTest, StdBitset) { 582 EXPECT_TRUE((is_hashable<std::bitset<257>>::value)); 583 584 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly( 585 {std::bitset<2>("00"), std::bitset<2>("01"), std::bitset<2>("10"), 586 std::bitset<2>("11")})); 587 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly( 588 {std::bitset<5>("10101"), std::bitset<5>("10001"), std::bitset<5>()})); 589 590 constexpr int kNumBits = 256; 591 std::array<std::string, 6> bit_strings; 592 bit_strings.fill(std::string(kNumBits, '1')); 593 bit_strings[1][0] = '0'; 594 bit_strings[2][1] = '0'; 595 bit_strings[3][kNumBits / 3] = '0'; 596 bit_strings[4][kNumBits - 2] = '0'; 597 bit_strings[5][kNumBits - 1] = '0'; 598 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly( 599 {std::bitset<kNumBits>(bit_strings[0].c_str()), 600 std::bitset<kNumBits>(bit_strings[1].c_str()), 601 std::bitset<kNumBits>(bit_strings[2].c_str()), 602 std::bitset<kNumBits>(bit_strings[3].c_str()), 603 std::bitset<kNumBits>(bit_strings[4].c_str()), 604 std::bitset<kNumBits>(bit_strings[5].c_str())})); 605 } // namespace 606 607 // Private type that only supports AbslHashValue to make sure our chosen hash 608 // implementation is recursive within absl::Hash. 609 // It uses std::abs() on the value to provide different bitwise representations 610 // of the same logical value. 611 struct Private { 612 int i; 613 template <typename H> 614 friend H AbslHashValue(H h, Private p) { 615 return H::combine(std::move(h), std::abs(p.i)); 616 } 617 618 friend bool operator==(Private a, Private b) { 619 return std::abs(a.i) == std::abs(b.i); 620 } 621 622 friend std::ostream& operator<<(std::ostream& o, Private p) { 623 return o << p.i; 624 } 625 }; 626 627 // Test helper for combine_piecewise_buffer. It holds a string_view to the 628 // buffer-to-be-hashed. Its AbslHashValue specialization will split up its 629 // contents at the character offsets requested. 630 class PiecewiseHashTester { 631 public: 632 // Create a hash view of a buffer to be hashed contiguously. 633 explicit PiecewiseHashTester(absl::string_view buf) 634 : buf_(buf), piecewise_(false), split_locations_() {} 635 636 // Create a hash view of a buffer to be hashed piecewise, with breaks at the 637 // given locations. 638 PiecewiseHashTester(absl::string_view buf, std::set<size_t> split_locations) 639 : buf_(buf), 640 piecewise_(true), 641 split_locations_(std::move(split_locations)) {} 642 643 template <typename H> 644 friend H AbslHashValue(H h, const PiecewiseHashTester& p) { 645 if (!p.piecewise_) { 646 return H::combine_contiguous(std::move(h), p.buf_.data(), p.buf_.size()); 647 } 648 absl::hash_internal::PiecewiseCombiner combiner; 649 if (p.split_locations_.empty()) { 650 h = combiner.add_buffer(std::move(h), p.buf_.data(), p.buf_.size()); 651 return combiner.finalize(std::move(h)); 652 } 653 size_t begin = 0; 654 for (size_t next : p.split_locations_) { 655 absl::string_view chunk = p.buf_.substr(begin, next - begin); 656 h = combiner.add_buffer(std::move(h), chunk.data(), chunk.size()); 657 begin = next; 658 } 659 absl::string_view last_chunk = p.buf_.substr(begin); 660 if (!last_chunk.empty()) { 661 h = combiner.add_buffer(std::move(h), last_chunk.data(), 662 last_chunk.size()); 663 } 664 return combiner.finalize(std::move(h)); 665 } 666 667 private: 668 absl::string_view buf_; 669 bool piecewise_; 670 std::set<size_t> split_locations_; 671 }; 672 673 // Dummy object that hashes as two distinct contiguous buffers, "foo" followed 674 // by "bar" 675 struct DummyFooBar { 676 template <typename H> 677 friend H AbslHashValue(H h, const DummyFooBar&) { 678 const char* foo = "foo"; 679 const char* bar = "bar"; 680 h = H::combine_contiguous(std::move(h), foo, 3); 681 h = H::combine_contiguous(std::move(h), bar, 3); 682 return h; 683 } 684 }; 685 686 TEST(HashValueTest, CombinePiecewiseBuffer) { 687 absl::Hash<PiecewiseHashTester> hash; 688 689 // Check that hashing an empty buffer through the piecewise API works. 690 EXPECT_EQ(hash(PiecewiseHashTester("")), hash(PiecewiseHashTester("", {}))); 691 692 // Similarly, small buffers should give consistent results 693 EXPECT_EQ(hash(PiecewiseHashTester("foobar")), 694 hash(PiecewiseHashTester("foobar", {}))); 695 EXPECT_EQ(hash(PiecewiseHashTester("foobar")), 696 hash(PiecewiseHashTester("foobar", {3}))); 697 698 // But hashing "foobar" in pieces gives a different answer than hashing "foo" 699 // contiguously, then "bar" contiguously. 700 EXPECT_NE(hash(PiecewiseHashTester("foobar", {3})), 701 absl::Hash<DummyFooBar>()(DummyFooBar{})); 702 703 // Test hashing a large buffer incrementally, broken up in several different 704 // ways. Arrange for breaks on and near the stride boundaries to look for 705 // off-by-one errors in the implementation. 706 // 707 // This test is run on a buffer that is a multiple of the stride size, and one 708 // that isn't. 709 for (size_t big_buffer_size : {1024u * 2 + 512u, 1024u * 3}) { 710 SCOPED_TRACE(big_buffer_size); 711 std::string big_buffer; 712 for (size_t i = 0; i < big_buffer_size; ++i) { 713 // Arbitrary string 714 big_buffer.push_back(32 + (i * (i / 3)) % 64); 715 } 716 auto big_buffer_hash = hash(PiecewiseHashTester(big_buffer)); 717 718 const int possible_breaks = 9; 719 size_t breaks[possible_breaks] = {1, 512, 1023, 1024, 1025, 720 1536, 2047, 2048, 2049}; 721 for (unsigned test_mask = 0; test_mask < (1u << possible_breaks); 722 ++test_mask) { 723 SCOPED_TRACE(test_mask); 724 std::set<size_t> break_locations; 725 for (int j = 0; j < possible_breaks; ++j) { 726 if (test_mask & (1u << j)) { 727 break_locations.insert(breaks[j]); 728 } 729 } 730 EXPECT_EQ( 731 hash(PiecewiseHashTester(big_buffer, std::move(break_locations))), 732 big_buffer_hash); 733 } 734 } 735 } 736 737 TEST(HashValueTest, PrivateSanity) { 738 // Sanity check that Private is working as the tests below expect it to work. 739 EXPECT_TRUE(is_hashable<Private>::value); 740 EXPECT_NE(SpyHash(Private{0}), SpyHash(Private{1})); 741 EXPECT_EQ(SpyHash(Private{1}), SpyHash(Private{1})); 742 } 743 744 TEST(HashValueTest, Optional) { 745 EXPECT_TRUE(is_hashable<absl::optional<Private>>::value); 746 747 using O = absl::optional<Private>; 748 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly( 749 std::make_tuple(O{}, O{{1}}, O{{-1}}, O{{10}}))); 750 } 751 752 TEST(HashValueTest, Variant) { 753 using V = absl::variant<Private, std::string>; 754 EXPECT_TRUE(is_hashable<V>::value); 755 756 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple( 757 V(Private{1}), V(Private{-1}), V(Private{2}), V("ABC"), V("BCD")))); 758 759 #if ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ 760 struct S {}; 761 EXPECT_FALSE(is_hashable<absl::variant<S>>::value); 762 #endif 763 } 764 765 TEST(HashValueTest, ReferenceWrapper) { 766 EXPECT_TRUE(is_hashable<std::reference_wrapper<Private>>::value); 767 768 Private p1{1}, p10{10}; 769 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple( 770 p1, p10, std::ref(p1), std::ref(p10), std::cref(p1), std::cref(p10)))); 771 772 EXPECT_TRUE(is_hashable<std::reference_wrapper<int>>::value); 773 int one = 1, ten = 10; 774 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple( 775 one, ten, std::ref(one), std::ref(ten), std::cref(one), std::cref(ten)))); 776 777 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly( 778 std::make_tuple(std::tuple<std::reference_wrapper<int>>(std::ref(one)), 779 std::tuple<std::reference_wrapper<int>>(std::ref(ten)), 780 std::tuple<int>(one), std::tuple<int>(ten)))); 781 } 782 783 template <typename T, typename = void> 784 struct IsHashCallable : std::false_type {}; 785 786 template <typename T> 787 struct IsHashCallable<T, absl::void_t<decltype(std::declval<absl::Hash<T>>()( 788 std::declval<const T&>()))>> : std::true_type {}; 789 790 template <typename T, typename = void> 791 struct IsAggregateInitializable : std::false_type {}; 792 793 template <typename T> 794 struct IsAggregateInitializable<T, absl::void_t<decltype(T{})>> 795 : std::true_type {}; 796 797 TEST(IsHashableTest, ValidHash) { 798 EXPECT_TRUE((is_hashable<int>::value)); 799 EXPECT_TRUE(std::is_default_constructible<absl::Hash<int>>::value); 800 EXPECT_TRUE(std::is_copy_constructible<absl::Hash<int>>::value); 801 EXPECT_TRUE(std::is_move_constructible<absl::Hash<int>>::value); 802 EXPECT_TRUE(absl::is_copy_assignable<absl::Hash<int>>::value); 803 EXPECT_TRUE(absl::is_move_assignable<absl::Hash<int>>::value); 804 EXPECT_TRUE(IsHashCallable<int>::value); 805 EXPECT_TRUE(IsAggregateInitializable<absl::Hash<int>>::value); 806 } 807 808 #if ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ 809 TEST(IsHashableTest, PoisonHash) { 810 struct X {}; 811 EXPECT_FALSE((is_hashable<X>::value)); 812 EXPECT_FALSE(std::is_default_constructible<absl::Hash<X>>::value); 813 EXPECT_FALSE(std::is_copy_constructible<absl::Hash<X>>::value); 814 EXPECT_FALSE(std::is_move_constructible<absl::Hash<X>>::value); 815 EXPECT_FALSE(absl::is_copy_assignable<absl::Hash<X>>::value); 816 EXPECT_FALSE(absl::is_move_assignable<absl::Hash<X>>::value); 817 EXPECT_FALSE(IsHashCallable<X>::value); 818 #if !defined(__GNUC__) || defined(__clang__) 819 // TODO(b/144368551): As of GCC 8.4 this does not compile. 820 EXPECT_FALSE(IsAggregateInitializable<absl::Hash<X>>::value); 821 #endif 822 } 823 #endif // ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ 824 825 // Hashable types 826 // 827 // These types exist simply to exercise various AbslHashValue behaviors, so 828 // they are named by what their AbslHashValue overload does. 829 struct NoOp { 830 template <typename HashCode> 831 friend HashCode AbslHashValue(HashCode h, NoOp n) { 832 return h; 833 } 834 }; 835 836 struct EmptyCombine { 837 template <typename HashCode> 838 friend HashCode AbslHashValue(HashCode h, EmptyCombine e) { 839 return HashCode::combine(std::move(h)); 840 } 841 }; 842 843 template <typename Int> 844 struct CombineIterative { 845 template <typename HashCode> 846 friend HashCode AbslHashValue(HashCode h, CombineIterative c) { 847 for (int i = 0; i < 5; ++i) { 848 h = HashCode::combine(std::move(h), Int(i)); 849 } 850 return h; 851 } 852 }; 853 854 template <typename Int> 855 struct CombineVariadic { 856 template <typename HashCode> 857 friend HashCode AbslHashValue(HashCode h, CombineVariadic c) { 858 return HashCode::combine(std::move(h), Int(0), Int(1), Int(2), Int(3), 859 Int(4)); 860 } 861 }; 862 enum class InvokeTag { 863 kUniquelyRepresented, 864 kHashValue, 865 #if ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_ 866 kLegacyHash, 867 #endif // ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_ 868 kStdHash, 869 kNone 870 }; 871 872 template <InvokeTag T> 873 using InvokeTagConstant = std::integral_constant<InvokeTag, T>; 874 875 template <InvokeTag... Tags> 876 struct MinTag; 877 878 template <InvokeTag a, InvokeTag b, InvokeTag... Tags> 879 struct MinTag<a, b, Tags...> : MinTag<(a < b ? a : b), Tags...> {}; 880 881 template <InvokeTag a> 882 struct MinTag<a> : InvokeTagConstant<a> {}; 883 884 template <InvokeTag... Tags> 885 struct CustomHashType { 886 explicit CustomHashType(size_t val) : value(val) {} 887 size_t value; 888 }; 889 890 template <InvokeTag allowed, InvokeTag... tags> 891 struct EnableIfContained 892 : std::enable_if<absl::disjunction< 893 std::integral_constant<bool, allowed == tags>...>::value> {}; 894 895 template < 896 typename H, InvokeTag... Tags, 897 typename = typename EnableIfContained<InvokeTag::kHashValue, Tags...>::type> 898 H AbslHashValue(H state, CustomHashType<Tags...> t) { 899 static_assert(MinTag<Tags...>::value == InvokeTag::kHashValue, ""); 900 return H::combine(std::move(state), 901 t.value + static_cast<int>(InvokeTag::kHashValue)); 902 } 903 904 } // namespace 905 906 namespace absl { 907 ABSL_NAMESPACE_BEGIN 908 namespace hash_internal { 909 template <InvokeTag... Tags> 910 struct is_uniquely_represented< 911 CustomHashType<Tags...>, 912 typename EnableIfContained<InvokeTag::kUniquelyRepresented, Tags...>::type> 913 : std::true_type {}; 914 } // namespace hash_internal 915 ABSL_NAMESPACE_END 916 } // namespace absl 917 918 #if ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_ 919 namespace ABSL_INTERNAL_LEGACY_HASH_NAMESPACE { 920 template <InvokeTag... Tags> 921 struct hash<CustomHashType<Tags...>> { 922 template <InvokeTag... TagsIn, typename = typename EnableIfContained< 923 InvokeTag::kLegacyHash, TagsIn...>::type> 924 size_t operator()(CustomHashType<TagsIn...> t) const { 925 static_assert(MinTag<Tags...>::value == InvokeTag::kLegacyHash, ""); 926 return t.value + static_cast<int>(InvokeTag::kLegacyHash); 927 } 928 }; 929 } // namespace ABSL_INTERNAL_LEGACY_HASH_NAMESPACE 930 #endif // ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_ 931 932 namespace std { 933 template <InvokeTag... Tags> // NOLINT 934 struct hash<CustomHashType<Tags...>> { 935 template <InvokeTag... TagsIn, typename = typename EnableIfContained< 936 InvokeTag::kStdHash, TagsIn...>::type> 937 size_t operator()(CustomHashType<TagsIn...> t) const { 938 static_assert(MinTag<Tags...>::value == InvokeTag::kStdHash, ""); 939 return t.value + static_cast<int>(InvokeTag::kStdHash); 940 } 941 }; 942 } // namespace std 943 944 namespace { 945 946 template <typename... T> 947 void TestCustomHashType(InvokeTagConstant<InvokeTag::kNone>, T...) { 948 using type = CustomHashType<T::value...>; 949 SCOPED_TRACE(testing::PrintToString(std::vector<InvokeTag>{T::value...})); 950 EXPECT_TRUE(is_hashable<type>()); 951 EXPECT_TRUE(is_hashable<const type>()); 952 EXPECT_TRUE(is_hashable<const type&>()); 953 954 const size_t offset = static_cast<int>(std::min({T::value...})); 955 EXPECT_EQ(SpyHash(type(7)), SpyHash(size_t{7 + offset})); 956 } 957 958 void TestCustomHashType(InvokeTagConstant<InvokeTag::kNone>) { 959 #if ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ 960 // is_hashable is false if we don't support any of the hooks. 961 using type = CustomHashType<>; 962 EXPECT_FALSE(is_hashable<type>()); 963 EXPECT_FALSE(is_hashable<const type>()); 964 EXPECT_FALSE(is_hashable<const type&>()); 965 #endif // ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ 966 } 967 968 template <InvokeTag Tag, typename... T> 969 void TestCustomHashType(InvokeTagConstant<Tag> tag, T... t) { 970 constexpr auto next = static_cast<InvokeTag>(static_cast<int>(Tag) + 1); 971 TestCustomHashType(InvokeTagConstant<next>(), tag, t...); 972 TestCustomHashType(InvokeTagConstant<next>(), t...); 973 } 974 975 TEST(HashTest, CustomHashType) { 976 TestCustomHashType(InvokeTagConstant<InvokeTag{}>()); 977 } 978 979 TEST(HashTest, NoOpsAreEquivalent) { 980 EXPECT_EQ(Hash<NoOp>()({}), Hash<NoOp>()({})); 981 EXPECT_EQ(Hash<NoOp>()({}), Hash<EmptyCombine>()({})); 982 } 983 984 template <typename T> 985 class HashIntTest : public testing::Test { 986 }; 987 TYPED_TEST_SUITE_P(HashIntTest); 988 989 TYPED_TEST_P(HashIntTest, BasicUsage) { 990 EXPECT_NE(Hash<NoOp>()({}), Hash<TypeParam>()(0)); 991 EXPECT_NE(Hash<NoOp>()({}), 992 Hash<TypeParam>()(std::numeric_limits<TypeParam>::max())); 993 if (std::numeric_limits<TypeParam>::min() != 0) { 994 EXPECT_NE(Hash<NoOp>()({}), 995 Hash<TypeParam>()(std::numeric_limits<TypeParam>::min())); 996 } 997 998 EXPECT_EQ(Hash<CombineIterative<TypeParam>>()({}), 999 Hash<CombineVariadic<TypeParam>>()({})); 1000 } 1001 1002 REGISTER_TYPED_TEST_SUITE_P(HashIntTest, BasicUsage); 1003 using IntTypes = testing::Types<unsigned char, char, int, int32_t, int64_t, 1004 uint32_t, uint64_t, size_t>; 1005 INSTANTIATE_TYPED_TEST_SUITE_P(My, HashIntTest, IntTypes); 1006 1007 struct StructWithPadding { 1008 char c; 1009 int i; 1010 1011 template <typename H> 1012 friend H AbslHashValue(H hash_state, const StructWithPadding& s) { 1013 return H::combine(std::move(hash_state), s.c, s.i); 1014 } 1015 }; 1016 1017 static_assert(sizeof(StructWithPadding) > sizeof(char) + sizeof(int), 1018 "StructWithPadding doesn't have padding"); 1019 static_assert(std::is_standard_layout<StructWithPadding>::value, ""); 1020 1021 // This check has to be disabled because libstdc++ doesn't support it. 1022 // static_assert(std::is_trivially_constructible<StructWithPadding>::value, ""); 1023 1024 template <typename T> 1025 struct ArraySlice { 1026 T* begin; 1027 T* end; 1028 1029 template <typename H> 1030 friend H AbslHashValue(H hash_state, const ArraySlice& slice) { 1031 for (auto t = slice.begin; t != slice.end; ++t) { 1032 hash_state = H::combine(std::move(hash_state), *t); 1033 } 1034 return hash_state; 1035 } 1036 }; 1037 1038 TEST(HashTest, HashNonUniquelyRepresentedType) { 1039 // Create equal StructWithPadding objects that are known to have non-equal 1040 // padding bytes. 1041 static const size_t kNumStructs = 10; 1042 unsigned char buffer1[kNumStructs * sizeof(StructWithPadding)]; 1043 std::memset(buffer1, 0, sizeof(buffer1)); 1044 auto* s1 = reinterpret_cast<StructWithPadding*>(buffer1); 1045 1046 unsigned char buffer2[kNumStructs * sizeof(StructWithPadding)]; 1047 std::memset(buffer2, 255, sizeof(buffer2)); 1048 auto* s2 = reinterpret_cast<StructWithPadding*>(buffer2); 1049 for (size_t i = 0; i < kNumStructs; ++i) { 1050 SCOPED_TRACE(i); 1051 s1[i].c = s2[i].c = static_cast<char>('0' + i); 1052 s1[i].i = s2[i].i = static_cast<int>(i); 1053 ASSERT_FALSE(memcmp(buffer1 + i * sizeof(StructWithPadding), 1054 buffer2 + i * sizeof(StructWithPadding), 1055 sizeof(StructWithPadding)) == 0) 1056 << "Bug in test code: objects do not have unequal" 1057 << " object representations"; 1058 } 1059 1060 EXPECT_EQ(Hash<StructWithPadding>()(s1[0]), Hash<StructWithPadding>()(s2[0])); 1061 EXPECT_EQ(Hash<ArraySlice<StructWithPadding>>()({s1, s1 + kNumStructs}), 1062 Hash<ArraySlice<StructWithPadding>>()({s2, s2 + kNumStructs})); 1063 } 1064 1065 TEST(HashTest, StandardHashContainerUsage) { 1066 std::unordered_map<int, std::string, Hash<int>> map = {{0, "foo"}, 1067 {42, "bar"}}; 1068 1069 EXPECT_NE(map.find(0), map.end()); 1070 EXPECT_EQ(map.find(1), map.end()); 1071 EXPECT_NE(map.find(0u), map.end()); 1072 } 1073 1074 struct ConvertibleFromNoOp { 1075 ConvertibleFromNoOp(NoOp) {} // NOLINT(runtime/explicit) 1076 1077 template <typename H> 1078 friend H AbslHashValue(H hash_state, ConvertibleFromNoOp) { 1079 return H::combine(std::move(hash_state), 1); 1080 } 1081 }; 1082 1083 TEST(HashTest, HeterogeneousCall) { 1084 EXPECT_NE(Hash<ConvertibleFromNoOp>()(NoOp()), 1085 Hash<NoOp>()(NoOp())); 1086 } 1087 1088 TEST(IsUniquelyRepresentedTest, SanityTest) { 1089 using absl::hash_internal::is_uniquely_represented; 1090 1091 EXPECT_TRUE(is_uniquely_represented<unsigned char>::value); 1092 EXPECT_TRUE(is_uniquely_represented<int>::value); 1093 EXPECT_FALSE(is_uniquely_represented<bool>::value); 1094 EXPECT_FALSE(is_uniquely_represented<int*>::value); 1095 } 1096 1097 struct IntAndString { 1098 int i; 1099 std::string s; 1100 1101 template <typename H> 1102 friend H AbslHashValue(H hash_state, IntAndString int_and_string) { 1103 return H::combine(std::move(hash_state), int_and_string.s, 1104 int_and_string.i); 1105 } 1106 }; 1107 1108 TEST(HashTest, SmallValueOn64ByteBoundary) { 1109 Hash<IntAndString>()(IntAndString{0, std::string(63, '0')}); 1110 } 1111 1112 TEST(HashTest, TypeErased) { 1113 EXPECT_TRUE((is_hashable<TypeErasedValue<size_t>>::value)); 1114 EXPECT_TRUE((is_hashable<std::pair<TypeErasedValue<size_t>, int>>::value)); 1115 1116 EXPECT_EQ(SpyHash(TypeErasedValue<size_t>(7)), SpyHash(size_t{7})); 1117 EXPECT_NE(SpyHash(TypeErasedValue<size_t>(7)), SpyHash(size_t{13})); 1118 1119 EXPECT_EQ(SpyHash(std::make_pair(TypeErasedValue<size_t>(7), 17)), 1120 SpyHash(std::make_pair(size_t{7}, 17))); 1121 1122 absl::flat_hash_set<absl::flat_hash_set<int>> ss = {{1, 2}, {3, 4}}; 1123 TypeErasedContainer<absl::flat_hash_set<absl::flat_hash_set<int>>> es = { 1124 absl::flat_hash_set<int>{1, 2}, {3, 4}}; 1125 absl::flat_hash_set<TypeErasedContainer<absl::flat_hash_set<int>>> se = { 1126 {1, 2}, {3, 4}}; 1127 EXPECT_EQ(SpyHash(ss), SpyHash(es)); 1128 EXPECT_EQ(SpyHash(ss), SpyHash(se)); 1129 } 1130 1131 struct ValueWithBoolConversion { 1132 operator bool() const { return false; } 1133 int i; 1134 }; 1135 1136 } // namespace 1137 namespace std { 1138 template <> 1139 struct hash<ValueWithBoolConversion> { 1140 size_t operator()(ValueWithBoolConversion v) { 1141 return static_cast<size_t>(v.i); 1142 } 1143 }; 1144 } // namespace std 1145 1146 namespace { 1147 1148 TEST(HashTest, DoesNotUseImplicitConversionsToBool) { 1149 EXPECT_NE(absl::Hash<ValueWithBoolConversion>()(ValueWithBoolConversion{0}), 1150 absl::Hash<ValueWithBoolConversion>()(ValueWithBoolConversion{1})); 1151 } 1152 1153 TEST(HashOf, MatchesHashForSingleArgument) { 1154 std::string s = "forty two"; 1155 double d = 42.0; 1156 std::tuple<int, int> t{4, 2}; 1157 int i = 42; 1158 int neg_i = -42; 1159 int16_t i16 = 42; 1160 int16_t neg_i16 = -42; 1161 int8_t i8 = 42; 1162 int8_t neg_i8 = -42; 1163 1164 EXPECT_EQ(absl::HashOf(s), absl::Hash<std::string>{}(s)); 1165 EXPECT_EQ(absl::HashOf(d), absl::Hash<double>{}(d)); 1166 EXPECT_EQ(absl::HashOf(t), (absl::Hash<std::tuple<int, int>>{}(t))); 1167 EXPECT_EQ(absl::HashOf(i), absl::Hash<int>{}(i)); 1168 EXPECT_EQ(absl::HashOf(neg_i), absl::Hash<int>{}(neg_i)); 1169 EXPECT_EQ(absl::HashOf(i16), absl::Hash<int16_t>{}(i16)); 1170 EXPECT_EQ(absl::HashOf(neg_i16), absl::Hash<int16_t>{}(neg_i16)); 1171 EXPECT_EQ(absl::HashOf(i8), absl::Hash<int8_t>{}(i8)); 1172 EXPECT_EQ(absl::HashOf(neg_i8), absl::Hash<int8_t>{}(neg_i8)); 1173 } 1174 1175 TEST(HashOf, MatchesHashOfTupleForMultipleArguments) { 1176 std::string hello = "hello"; 1177 std::string world = "world"; 1178 1179 EXPECT_EQ(absl::HashOf(), absl::HashOf(std::make_tuple())); 1180 EXPECT_EQ(absl::HashOf(hello), absl::HashOf(std::make_tuple(hello))); 1181 EXPECT_EQ(absl::HashOf(hello, world), 1182 absl::HashOf(std::make_tuple(hello, world))); 1183 } 1184 1185 template <typename T> 1186 std::true_type HashOfExplicitParameter(decltype(absl::HashOf<T>(0))) { 1187 return {}; 1188 } 1189 template <typename T> 1190 std::false_type HashOfExplicitParameter(size_t) { 1191 return {}; 1192 } 1193 1194 TEST(HashOf, CantPassExplicitTemplateParameters) { 1195 EXPECT_FALSE(HashOfExplicitParameter<int>(0)); 1196 } 1197 1198 struct TypeErasedHashStateUser { 1199 int a; 1200 std::string b; 1201 1202 template <typename H> 1203 friend H AbslHashValue(H state, const TypeErasedHashStateUser& value) { 1204 absl::HashState type_erased_state = absl::HashState::Create(&state); 1205 absl::HashState::combine(std::move(type_erased_state), value.a, value.b); 1206 return state; 1207 } 1208 }; 1209 1210 TEST(HashOf, MatchesTypeErasedHashState) { 1211 std::string s = "s"; 1212 EXPECT_EQ(absl::HashOf(1, s), absl::Hash<TypeErasedHashStateUser>{}( 1213 TypeErasedHashStateUser{1, s})); 1214 } 1215 1216 } // namespace