hash_test.cc
Go to the documentation of this file.
00001 // Copyright 2018 The Abseil Authors.
00002 //
00003 // Licensed under the Apache License, Version 2.0 (the "License");
00004 // you may not use this file except in compliance with the License.
00005 // You may obtain a copy of the License at
00006 //
00007 //      https://www.apache.org/licenses/LICENSE-2.0
00008 //
00009 // Unless required by applicable law or agreed to in writing, software
00010 // distributed under the License is distributed on an "AS IS" BASIS,
00011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00012 // See the License for the specific language governing permissions and
00013 // limitations under the License.
00014 
00015 #include "absl/hash/hash.h"
00016 
00017 #include <array>
00018 #include <bitset>
00019 #include <cstring>
00020 #include <deque>
00021 #include <forward_list>
00022 #include <functional>
00023 #include <iterator>
00024 #include <limits>
00025 #include <list>
00026 #include <map>
00027 #include <memory>
00028 #include <numeric>
00029 #include <random>
00030 #include <set>
00031 #include <string>
00032 #include <tuple>
00033 #include <type_traits>
00034 #include <unordered_map>
00035 #include <utility>
00036 #include <vector>
00037 
00038 #include "gmock/gmock.h"
00039 #include "gtest/gtest.h"
00040 #include "absl/container/flat_hash_set.h"
00041 #include "absl/hash/hash_testing.h"
00042 #include "absl/hash/internal/spy_hash_state.h"
00043 #include "absl/meta/type_traits.h"
00044 #include "absl/numeric/int128.h"
00045 
00046 namespace {
00047 
00048 using absl::Hash;
00049 using absl::hash_internal::SpyHashState;
00050 
00051 template <typename T>
00052 class HashValueIntTest : public testing::Test {
00053 };
00054 TYPED_TEST_SUITE_P(HashValueIntTest);
00055 
00056 template <typename T>
00057 SpyHashState SpyHash(const T& value) {
00058   return SpyHashState::combine(SpyHashState(), value);
00059 }
00060 
00061 // Helper trait to verify if T is hashable. We use absl::Hash's poison status to
00062 // detect it.
00063 template <typename T>
00064 using is_hashable = std::is_default_constructible<absl::Hash<T>>;
00065 
00066 TYPED_TEST_P(HashValueIntTest, BasicUsage) {
00067   EXPECT_TRUE((is_hashable<TypeParam>::value));
00068 
00069   TypeParam n = 42;
00070   EXPECT_EQ(SpyHash(n), SpyHash(TypeParam{42}));
00071   EXPECT_NE(SpyHash(n), SpyHash(TypeParam{0}));
00072   EXPECT_NE(SpyHash(std::numeric_limits<TypeParam>::max()),
00073             SpyHash(std::numeric_limits<TypeParam>::min()));
00074 }
00075 
00076 TYPED_TEST_P(HashValueIntTest, FastPath) {
00077   // Test the fast-path to make sure the values are the same.
00078   TypeParam n = 42;
00079   EXPECT_EQ(absl::Hash<TypeParam>{}(n),
00080             absl::Hash<std::tuple<TypeParam>>{}(std::tuple<TypeParam>(n)));
00081 }
00082 
00083 REGISTER_TYPED_TEST_CASE_P(HashValueIntTest, BasicUsage, FastPath);
00084 using IntTypes = testing::Types<unsigned char, char, int, int32_t, int64_t, uint32_t,
00085                                 uint64_t, size_t>;
00086 INSTANTIATE_TYPED_TEST_CASE_P(My, HashValueIntTest, IntTypes);
00087 
00088 enum LegacyEnum { kValue1, kValue2, kValue3 };
00089 
00090 enum class EnumClass { kValue4, kValue5, kValue6 };
00091 
00092 TEST(HashValueTest, EnumAndBool) {
00093   EXPECT_TRUE((is_hashable<LegacyEnum>::value));
00094   EXPECT_TRUE((is_hashable<EnumClass>::value));
00095   EXPECT_TRUE((is_hashable<bool>::value));
00096 
00097   EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
00098       LegacyEnum::kValue1, LegacyEnum::kValue2, LegacyEnum::kValue3)));
00099   EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
00100       EnumClass::kValue4, EnumClass::kValue5, EnumClass::kValue6)));
00101   EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
00102       std::make_tuple(true, false)));
00103 }
00104 
00105 TEST(HashValueTest, FloatingPoint) {
00106   EXPECT_TRUE((is_hashable<float>::value));
00107   EXPECT_TRUE((is_hashable<double>::value));
00108   EXPECT_TRUE((is_hashable<long double>::value));
00109 
00110   EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
00111       std::make_tuple(42.f, 0.f, -0.f, std::numeric_limits<float>::infinity(),
00112                       -std::numeric_limits<float>::infinity())));
00113 
00114   EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
00115       std::make_tuple(42., 0., -0., std::numeric_limits<double>::infinity(),
00116                       -std::numeric_limits<double>::infinity())));
00117 
00118   EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
00119       // Add some values with small exponent to test that NORMAL values also
00120       // append their category.
00121       .5L, 1.L, 2.L, 4.L, 42.L, 0.L, -0.L,
00122       17 * static_cast<long double>(std::numeric_limits<double>::max()),
00123       std::numeric_limits<long double>::infinity(),
00124       -std::numeric_limits<long double>::infinity())));
00125 }
00126 
00127 TEST(HashValueTest, Pointer) {
00128   EXPECT_TRUE((is_hashable<int*>::value));
00129 
00130   int i;
00131   int* ptr = &i;
00132   int* n = nullptr;
00133 
00134   EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
00135       std::make_tuple(&i, ptr, nullptr, ptr + 1, n)));
00136 }
00137 
00138 TEST(HashValueTest, PointerAlignment) {
00139   // We want to make sure that pointer alignment will not cause bits to be
00140   // stuck.
00141 
00142   constexpr size_t kTotalSize = 1 << 20;
00143   std::unique_ptr<char[]> data(new char[kTotalSize]);
00144   constexpr size_t kLog2NumValues = 5;
00145   constexpr size_t kNumValues = 1 << kLog2NumValues;
00146 
00147   for (size_t align = 1; align < kTotalSize / kNumValues;
00148        align < 8 ? align += 1 : align < 1024 ? align += 8 : align += 32) {
00149     SCOPED_TRACE(align);
00150     ASSERT_LE(align * kNumValues, kTotalSize);
00151 
00152     size_t bits_or = 0;
00153     size_t bits_and = ~size_t{};
00154 
00155     for (size_t i = 0; i < kNumValues; ++i) {
00156       size_t hash = absl::Hash<void*>()(data.get() + i * align);
00157       bits_or |= hash;
00158       bits_and &= hash;
00159     }
00160 
00161     // Limit the scope to the bits we would be using for Swisstable.
00162     constexpr size_t kMask = (1 << (kLog2NumValues + 7)) - 1;
00163     size_t stuck_bits = (~bits_or | bits_and) & kMask;
00164     EXPECT_EQ(stuck_bits, 0) << "0x" << std::hex << stuck_bits;
00165   }
00166 }
00167 
00168 TEST(HashValueTest, PairAndTuple) {
00169   EXPECT_TRUE((is_hashable<std::pair<int, int>>::value));
00170   EXPECT_TRUE((is_hashable<std::pair<const int&, const int&>>::value));
00171   EXPECT_TRUE((is_hashable<std::tuple<int&, int&>>::value));
00172   EXPECT_TRUE((is_hashable<std::tuple<int&&, int&&>>::value));
00173 
00174   EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
00175       std::make_pair(0, 42), std::make_pair(0, 42), std::make_pair(42, 0),
00176       std::make_pair(0, 0), std::make_pair(42, 42), std::make_pair(1, 42))));
00177 
00178   EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
00179       std::make_tuple(std::make_tuple(0, 0, 0), std::make_tuple(0, 0, 42),
00180                       std::make_tuple(0, 23, 0), std::make_tuple(17, 0, 0),
00181                       std::make_tuple(42, 0, 0), std::make_tuple(3, 9, 9),
00182                       std::make_tuple(0, 0, -42))));
00183 
00184   // Test that tuples of lvalue references work (so we need a few lvalues):
00185   int a = 0, b = 1, c = 17, d = 23;
00186   EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
00187       std::tie(a, a), std::tie(a, b), std::tie(b, c), std::tie(c, d))));
00188 
00189   // Test that tuples of rvalue references work:
00190   EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
00191       std::forward_as_tuple(0, 0, 0), std::forward_as_tuple(0, 0, 42),
00192       std::forward_as_tuple(0, 23, 0), std::forward_as_tuple(17, 0, 0),
00193       std::forward_as_tuple(42, 0, 0), std::forward_as_tuple(3, 9, 9),
00194       std::forward_as_tuple(0, 0, -42))));
00195 }
00196 
00197 TEST(HashValueTest, CombineContiguousWorks) {
00198   std::vector<std::tuple<int>> v1 = {std::make_tuple(1), std::make_tuple(3)};
00199   std::vector<std::tuple<int>> v2 = {std::make_tuple(1), std::make_tuple(2)};
00200 
00201   auto vh1 = SpyHash(v1);
00202   auto vh2 = SpyHash(v2);
00203   EXPECT_NE(vh1, vh2);
00204 }
00205 
00206 struct DummyDeleter {
00207   template <typename T>
00208   void operator() (T* ptr) {}
00209 };
00210 
00211 struct SmartPointerEq {
00212   template <typename T, typename U>
00213   bool operator()(const T& t, const U& u) const {
00214     return GetPtr(t) == GetPtr(u);
00215   }
00216 
00217   template <typename T>
00218   static auto GetPtr(const T& t) -> decltype(&*t) {
00219     return t ? &*t : nullptr;
00220   }
00221 
00222   static std::nullptr_t GetPtr(std::nullptr_t) { return nullptr; }
00223 };
00224 
00225 TEST(HashValueTest, SmartPointers) {
00226   EXPECT_TRUE((is_hashable<std::unique_ptr<int>>::value));
00227   EXPECT_TRUE((is_hashable<std::unique_ptr<int, DummyDeleter>>::value));
00228   EXPECT_TRUE((is_hashable<std::shared_ptr<int>>::value));
00229 
00230   int i, j;
00231   std::unique_ptr<int, DummyDeleter> unique1(&i);
00232   std::unique_ptr<int, DummyDeleter> unique2(&i);
00233   std::unique_ptr<int, DummyDeleter> unique_other(&j);
00234   std::unique_ptr<int, DummyDeleter> unique_null;
00235 
00236   std::shared_ptr<int> shared1(&i, DummyDeleter());
00237   std::shared_ptr<int> shared2(&i, DummyDeleter());
00238   std::shared_ptr<int> shared_other(&j, DummyDeleter());
00239   std::shared_ptr<int> shared_null;
00240 
00241   // Sanity check of the Eq function.
00242   ASSERT_TRUE(SmartPointerEq{}(unique1, shared1));
00243   ASSERT_FALSE(SmartPointerEq{}(unique1, shared_other));
00244   ASSERT_TRUE(SmartPointerEq{}(unique_null, nullptr));
00245   ASSERT_FALSE(SmartPointerEq{}(shared2, nullptr));
00246 
00247   EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
00248       std::forward_as_tuple(&i, nullptr,                    //
00249                             unique1, unique2, unique_null,  //
00250                             absl::make_unique<int>(),       //
00251                             shared1, shared2, shared_null,  //
00252                             std::make_shared<int>()),
00253       SmartPointerEq{}));
00254 }
00255 
00256 TEST(HashValueTest, FunctionPointer) {
00257   using Func = int (*)();
00258   EXPECT_TRUE(is_hashable<Func>::value);
00259 
00260   Func p1 = [] { return 2; }, p2 = [] { return 1; };
00261   EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
00262       std::make_tuple(p1, p2, nullptr)));
00263 }
00264 
00265 struct WrapInTuple {
00266   template <typename T>
00267   std::tuple<int, T, size_t> operator()(const T& t) const {
00268     return std::make_tuple(7, t, 0xdeadbeef);
00269   }
00270 };
00271 
00272 TEST(HashValueTest, Strings) {
00273   EXPECT_TRUE((is_hashable<std::string>::value));
00274 
00275   const std::string small = "foo";
00276   const std::string dup = "foofoo";
00277   const std::string large = "large";
00278   const std::string huge = std::string(5000, 'a');
00279 
00280   EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
00281       std::string(), absl::string_view(),
00282       std::string(""), absl::string_view(""),
00283       std::string(small), absl::string_view(small),
00284       std::string(dup), absl::string_view(dup),
00285       std::string(large), absl::string_view(large),
00286       std::string(huge), absl::string_view(huge))));
00287 
00288   // Also check that nested types maintain the same hash.
00289   const WrapInTuple t{};
00290   EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
00291       //
00292       t(std::string()), t(absl::string_view()),
00293       t(std::string("")), t(absl::string_view("")),
00294       t(std::string(small)), t(absl::string_view(small)),
00295       t(std::string(dup)), t(absl::string_view(dup)),
00296       t(std::string(large)), t(absl::string_view(large)),
00297       t(std::string(huge)), t(absl::string_view(huge)))));
00298 
00299   // Make sure that hashing a `const char*` does not use its std::string-value.
00300   EXPECT_NE(SpyHash(static_cast<const char*>("ABC")),
00301             SpyHash(absl::string_view("ABC")));
00302 }
00303 
00304 TEST(HashValueTest, StdArray) {
00305   EXPECT_TRUE((is_hashable<std::array<int, 3>>::value));
00306 
00307   EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
00308       std::make_tuple(std::array<int, 3>{}, std::array<int, 3>{{0, 23, 42}})));
00309 }
00310 
00311 TEST(HashValueTest, StdBitset) {
00312   EXPECT_TRUE((is_hashable<std::bitset<257>>::value));
00313 
00314   EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
00315       {std::bitset<2>("00"), std::bitset<2>("01"), std::bitset<2>("10"),
00316        std::bitset<2>("11")}));
00317   EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
00318       {std::bitset<5>("10101"), std::bitset<5>("10001"), std::bitset<5>()}));
00319 
00320   constexpr int kNumBits = 256;
00321   std::array<std::string, 6> bit_strings;
00322   bit_strings.fill(std::string(kNumBits, '1'));
00323   bit_strings[1][0] = '0';
00324   bit_strings[2][1] = '0';
00325   bit_strings[3][kNumBits / 3] = '0';
00326   bit_strings[4][kNumBits - 2] = '0';
00327   bit_strings[5][kNumBits - 1] = '0';
00328   EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
00329       {std::bitset<kNumBits>(bit_strings[0].c_str()),
00330        std::bitset<kNumBits>(bit_strings[1].c_str()),
00331        std::bitset<kNumBits>(bit_strings[2].c_str()),
00332        std::bitset<kNumBits>(bit_strings[3].c_str()),
00333        std::bitset<kNumBits>(bit_strings[4].c_str()),
00334        std::bitset<kNumBits>(bit_strings[5].c_str())}));
00335 }  // namespace
00336 
00337 template <typename T>
00338 class HashValueSequenceTest : public testing::Test {
00339 };
00340 TYPED_TEST_SUITE_P(HashValueSequenceTest);
00341 
00342 TYPED_TEST_P(HashValueSequenceTest, BasicUsage) {
00343   EXPECT_TRUE((is_hashable<TypeParam>::value));
00344 
00345   using ValueType = typename TypeParam::value_type;
00346   auto a = static_cast<ValueType>(0);
00347   auto b = static_cast<ValueType>(23);
00348   auto c = static_cast<ValueType>(42);
00349 
00350   EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
00351       std::make_tuple(TypeParam(), TypeParam{}, TypeParam{a, b, c},
00352                       TypeParam{a, b}, TypeParam{b, c})));
00353 }
00354 
00355 REGISTER_TYPED_TEST_CASE_P(HashValueSequenceTest, BasicUsage);
00356 using IntSequenceTypes =
00357     testing::Types<std::deque<int>, std::forward_list<int>, std::list<int>,
00358                    std::vector<int>, std::vector<bool>, std::set<int>,
00359                    std::multiset<int>>;
00360 INSTANTIATE_TYPED_TEST_CASE_P(My, HashValueSequenceTest, IntSequenceTypes);
00361 
00362 // Private type that only supports AbslHashValue to make sure our chosen hash
00363 // implentation is recursive within absl::Hash.
00364 // It uses std::abs() on the value to provide different bitwise representations
00365 // of the same logical value.
00366 struct Private {
00367   int i;
00368   template <typename H>
00369   friend H AbslHashValue(H h, Private p) {
00370     return H::combine(std::move(h), std::abs(p.i));
00371   }
00372 
00373   friend bool operator==(Private a, Private b) {
00374     return std::abs(a.i) == std::abs(b.i);
00375   }
00376 
00377   friend std::ostream& operator<<(std::ostream& o, Private p) {
00378     return o << p.i;
00379   }
00380 };
00381 
00382 TEST(HashValueTest, PrivateSanity) {
00383   // Sanity check that Private is working as the tests below expect it to work.
00384   EXPECT_TRUE(is_hashable<Private>::value);
00385   EXPECT_NE(SpyHash(Private{0}), SpyHash(Private{1}));
00386   EXPECT_EQ(SpyHash(Private{1}), SpyHash(Private{1}));
00387 }
00388 
00389 TEST(HashValueTest, Optional) {
00390   EXPECT_TRUE(is_hashable<absl::optional<Private>>::value);
00391 
00392   using O = absl::optional<Private>;
00393   EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
00394       std::make_tuple(O{}, O{{1}}, O{{-1}}, O{{10}})));
00395 }
00396 
00397 TEST(HashValueTest, Variant) {
00398   using V = absl::variant<Private, std::string>;
00399   EXPECT_TRUE(is_hashable<V>::value);
00400 
00401   EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
00402       V(Private{1}), V(Private{-1}), V(Private{2}), V("ABC"), V("BCD"))));
00403 
00404 #if ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
00405   struct S {};
00406   EXPECT_FALSE(is_hashable<absl::variant<S>>::value);
00407 #endif
00408 }
00409 
00410 TEST(HashValueTest, Maps) {
00411   EXPECT_TRUE((is_hashable<std::map<int, std::string>>::value));
00412 
00413   using M = std::map<int, std::string>;
00414   EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
00415       M{}, M{{0, "foo"}}, M{{1, "foo"}}, M{{0, "bar"}}, M{{1, "bar"}},
00416       M{{0, "foo"}, {42, "bar"}}, M{{1, "foo"}, {42, "bar"}},
00417       M{{1, "foo"}, {43, "bar"}}, M{{1, "foo"}, {43, "baz"}})));
00418 
00419   using MM = std::multimap<int, std::string>;
00420   EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
00421       MM{}, MM{{0, "foo"}}, MM{{1, "foo"}}, MM{{0, "bar"}}, MM{{1, "bar"}},
00422       MM{{0, "foo"}, {0, "bar"}}, MM{{0, "bar"}, {0, "foo"}},
00423       MM{{0, "foo"}, {42, "bar"}}, MM{{1, "foo"}, {42, "bar"}},
00424       MM{{1, "foo"}, {1, "foo"}, {43, "bar"}}, MM{{1, "foo"}, {43, "baz"}})));
00425 }
00426 
00427 template <typename T, typename = void>
00428 struct IsHashCallable : std::false_type {};
00429 
00430 template <typename T>
00431 struct IsHashCallable<T, absl::void_t<decltype(std::declval<absl::Hash<T>>()(
00432                             std::declval<const T&>()))>> : std::true_type {};
00433 
00434 template <typename T, typename = void>
00435 struct IsAggregateInitializable : std::false_type {};
00436 
00437 template <typename T>
00438 struct IsAggregateInitializable<T, absl::void_t<decltype(T{})>>
00439     : std::true_type {};
00440 
00441 TEST(IsHashableTest, ValidHash) {
00442   EXPECT_TRUE((is_hashable<int>::value));
00443   EXPECT_TRUE(std::is_default_constructible<absl::Hash<int>>::value);
00444   EXPECT_TRUE(std::is_copy_constructible<absl::Hash<int>>::value);
00445   EXPECT_TRUE(std::is_move_constructible<absl::Hash<int>>::value);
00446   EXPECT_TRUE(absl::is_copy_assignable<absl::Hash<int>>::value);
00447   EXPECT_TRUE(absl::is_move_assignable<absl::Hash<int>>::value);
00448   EXPECT_TRUE(IsHashCallable<int>::value);
00449   EXPECT_TRUE(IsAggregateInitializable<absl::Hash<int>>::value);
00450 }
00451 
00452 #if ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
00453 TEST(IsHashableTest, PoisonHash) {
00454   struct X {};
00455   EXPECT_FALSE((is_hashable<X>::value));
00456   EXPECT_FALSE(std::is_default_constructible<absl::Hash<X>>::value);
00457   EXPECT_FALSE(std::is_copy_constructible<absl::Hash<X>>::value);
00458   EXPECT_FALSE(std::is_move_constructible<absl::Hash<X>>::value);
00459   EXPECT_FALSE(absl::is_copy_assignable<absl::Hash<X>>::value);
00460   EXPECT_FALSE(absl::is_move_assignable<absl::Hash<X>>::value);
00461   EXPECT_FALSE(IsHashCallable<X>::value);
00462   EXPECT_FALSE(IsAggregateInitializable<absl::Hash<X>>::value);
00463 }
00464 #endif  // ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
00465 
00466 // Hashable types
00467 //
00468 // These types exist simply to exercise various AbslHashValue behaviors, so
00469 // they are named by what their AbslHashValue overload does.
00470 struct NoOp {
00471   template <typename HashCode>
00472   friend HashCode AbslHashValue(HashCode h, NoOp n) {
00473     return h;
00474   }
00475 };
00476 
00477 struct EmptyCombine {
00478   template <typename HashCode>
00479   friend HashCode AbslHashValue(HashCode h, EmptyCombine e) {
00480     return HashCode::combine(std::move(h));
00481   }
00482 };
00483 
00484 template <typename Int>
00485 struct CombineIterative {
00486   template <typename HashCode>
00487   friend HashCode AbslHashValue(HashCode h, CombineIterative c) {
00488     for (int i = 0; i < 5; ++i) {
00489       h = HashCode::combine(std::move(h), Int(i));
00490     }
00491     return h;
00492   }
00493 };
00494 
00495 template <typename Int>
00496 struct CombineVariadic {
00497   template <typename HashCode>
00498   friend HashCode AbslHashValue(HashCode h, CombineVariadic c) {
00499     return HashCode::combine(std::move(h), Int(0), Int(1), Int(2), Int(3),
00500                              Int(4));
00501   }
00502 };
00503 enum class InvokeTag {
00504   kUniquelyRepresented,
00505   kHashValue,
00506 #if ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
00507   kLegacyHash,
00508 #endif  // ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
00509   kStdHash,
00510   kNone
00511 };
00512 
00513 template <InvokeTag T>
00514 using InvokeTagConstant = std::integral_constant<InvokeTag, T>;
00515 
00516 template <InvokeTag... Tags>
00517 struct MinTag;
00518 
00519 template <InvokeTag a, InvokeTag b, InvokeTag... Tags>
00520 struct MinTag<a, b, Tags...> : MinTag<(a < b ? a : b), Tags...> {};
00521 
00522 template <InvokeTag a>
00523 struct MinTag<a> : InvokeTagConstant<a> {};
00524 
00525 template <InvokeTag... Tags>
00526 struct CustomHashType {
00527   explicit CustomHashType(size_t val) : value(val) {}
00528   size_t value;
00529 };
00530 
00531 template <InvokeTag allowed, InvokeTag... tags>
00532 struct EnableIfContained
00533     : std::enable_if<absl::disjunction<
00534           std::integral_constant<bool, allowed == tags>...>::value> {};
00535 
00536 template <
00537     typename H, InvokeTag... Tags,
00538     typename = typename EnableIfContained<InvokeTag::kHashValue, Tags...>::type>
00539 H AbslHashValue(H state, CustomHashType<Tags...> t) {
00540   static_assert(MinTag<Tags...>::value == InvokeTag::kHashValue, "");
00541   return H::combine(std::move(state),
00542                     t.value + static_cast<int>(InvokeTag::kHashValue));
00543 }
00544 
00545 }  // namespace
00546 
00547 namespace absl {
00548 namespace hash_internal {
00549 template <InvokeTag... Tags>
00550 struct is_uniquely_represented<
00551     CustomHashType<Tags...>,
00552     typename EnableIfContained<InvokeTag::kUniquelyRepresented, Tags...>::type>
00553     : std::true_type {};
00554 }  // namespace hash_internal
00555 }  // namespace absl
00556 
00557 #if ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
00558 namespace ABSL_INTERNAL_LEGACY_HASH_NAMESPACE {
00559 template <InvokeTag... Tags>
00560 struct hash<CustomHashType<Tags...>> {
00561   template <InvokeTag... TagsIn, typename = typename EnableIfContained<
00562                                      InvokeTag::kLegacyHash, TagsIn...>::type>
00563   size_t operator()(CustomHashType<TagsIn...> t) const {
00564     static_assert(MinTag<Tags...>::value == InvokeTag::kLegacyHash, "");
00565     return t.value + static_cast<int>(InvokeTag::kLegacyHash);
00566   }
00567 };
00568 }  // namespace ABSL_INTERNAL_LEGACY_HASH_NAMESPACE
00569 #endif  // ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
00570 
00571 namespace std {
00572 template <InvokeTag... Tags>  // NOLINT
00573 struct hash<CustomHashType<Tags...>> {
00574   template <InvokeTag... TagsIn, typename = typename EnableIfContained<
00575                                      InvokeTag::kStdHash, TagsIn...>::type>
00576   size_t operator()(CustomHashType<TagsIn...> t) const {
00577     static_assert(MinTag<Tags...>::value == InvokeTag::kStdHash, "");
00578     return t.value + static_cast<int>(InvokeTag::kStdHash);
00579   }
00580 };
00581 }  // namespace std
00582 
00583 namespace {
00584 
00585 template <typename... T>
00586 void TestCustomHashType(InvokeTagConstant<InvokeTag::kNone>, T...) {
00587   using type = CustomHashType<T::value...>;
00588   SCOPED_TRACE(testing::PrintToString(std::vector<InvokeTag>{T::value...}));
00589   EXPECT_TRUE(is_hashable<type>());
00590   EXPECT_TRUE(is_hashable<const type>());
00591   EXPECT_TRUE(is_hashable<const type&>());
00592 
00593   const size_t offset = static_cast<int>(std::min({T::value...}));
00594   EXPECT_EQ(SpyHash(type(7)), SpyHash(size_t{7 + offset}));
00595 }
00596 
00597 void TestCustomHashType(InvokeTagConstant<InvokeTag::kNone>) {
00598 #if ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
00599   // is_hashable is false if we don't support any of the hooks.
00600   using type = CustomHashType<>;
00601   EXPECT_FALSE(is_hashable<type>());
00602   EXPECT_FALSE(is_hashable<const type>());
00603   EXPECT_FALSE(is_hashable<const type&>());
00604 #endif  // ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
00605 }
00606 
00607 template <InvokeTag Tag, typename... T>
00608 void TestCustomHashType(InvokeTagConstant<Tag> tag, T... t) {
00609   constexpr auto next = static_cast<InvokeTag>(static_cast<int>(Tag) + 1);
00610   TestCustomHashType(InvokeTagConstant<next>(), tag, t...);
00611   TestCustomHashType(InvokeTagConstant<next>(), t...);
00612 }
00613 
00614 TEST(HashTest, CustomHashType) {
00615   TestCustomHashType(InvokeTagConstant<InvokeTag{}>());
00616 }
00617 
00618 TEST(HashTest, NoOpsAreEquivalent) {
00619   EXPECT_EQ(Hash<NoOp>()({}), Hash<NoOp>()({}));
00620   EXPECT_EQ(Hash<NoOp>()({}), Hash<EmptyCombine>()({}));
00621 }
00622 
00623 template <typename T>
00624 class HashIntTest : public testing::Test {
00625 };
00626 TYPED_TEST_SUITE_P(HashIntTest);
00627 
00628 TYPED_TEST_P(HashIntTest, BasicUsage) {
00629   EXPECT_NE(Hash<NoOp>()({}), Hash<TypeParam>()(0));
00630   EXPECT_NE(Hash<NoOp>()({}),
00631             Hash<TypeParam>()(std::numeric_limits<TypeParam>::max()));
00632   if (std::numeric_limits<TypeParam>::min() != 0) {
00633     EXPECT_NE(Hash<NoOp>()({}),
00634               Hash<TypeParam>()(std::numeric_limits<TypeParam>::min()));
00635   }
00636 
00637   EXPECT_EQ(Hash<CombineIterative<TypeParam>>()({}),
00638             Hash<CombineVariadic<TypeParam>>()({}));
00639 }
00640 
00641 REGISTER_TYPED_TEST_CASE_P(HashIntTest, BasicUsage);
00642 using IntTypes = testing::Types<unsigned char, char, int, int32_t, int64_t, uint32_t,
00643                                 uint64_t, size_t>;
00644 INSTANTIATE_TYPED_TEST_CASE_P(My, HashIntTest, IntTypes);
00645 
00646 struct StructWithPadding {
00647   char c;
00648   int i;
00649 
00650   template <typename H>
00651   friend H AbslHashValue(H hash_state, const StructWithPadding& s) {
00652     return H::combine(std::move(hash_state), s.c, s.i);
00653   }
00654 };
00655 
00656 static_assert(sizeof(StructWithPadding) > sizeof(char) + sizeof(int),
00657               "StructWithPadding doesn't have padding");
00658 static_assert(std::is_standard_layout<StructWithPadding>::value, "");
00659 
00660 // This check has to be disabled because libstdc++ doesn't support it.
00661 // static_assert(std::is_trivially_constructible<StructWithPadding>::value, "");
00662 
00663 template <typename T>
00664 struct ArraySlice {
00665   T* begin;
00666   T* end;
00667 
00668   template <typename H>
00669   friend H AbslHashValue(H hash_state, const ArraySlice& slice) {
00670     for (auto t = slice.begin; t != slice.end; ++t) {
00671       hash_state = H::combine(std::move(hash_state), *t);
00672     }
00673     return hash_state;
00674   }
00675 };
00676 
00677 TEST(HashTest, HashNonUniquelyRepresentedType) {
00678   // Create equal StructWithPadding objects that are known to have non-equal
00679   // padding bytes.
00680   static const size_t kNumStructs = 10;
00681   unsigned char buffer1[kNumStructs * sizeof(StructWithPadding)];
00682   std::memset(buffer1, 0, sizeof(buffer1));
00683   auto* s1 = reinterpret_cast<StructWithPadding*>(buffer1);
00684 
00685   unsigned char buffer2[kNumStructs * sizeof(StructWithPadding)];
00686   std::memset(buffer2, 255, sizeof(buffer2));
00687   auto* s2 = reinterpret_cast<StructWithPadding*>(buffer2);
00688   for (int i = 0; i < kNumStructs; ++i) {
00689     SCOPED_TRACE(i);
00690     s1[i].c = s2[i].c = '0' + i;
00691     s1[i].i = s2[i].i = i;
00692     ASSERT_FALSE(memcmp(buffer1 + i * sizeof(StructWithPadding),
00693                         buffer2 + i * sizeof(StructWithPadding),
00694                         sizeof(StructWithPadding)) == 0)
00695         << "Bug in test code: objects do not have unequal"
00696         << " object representations";
00697   }
00698 
00699   EXPECT_EQ(Hash<StructWithPadding>()(s1[0]), Hash<StructWithPadding>()(s2[0]));
00700   EXPECT_EQ(Hash<ArraySlice<StructWithPadding>>()({s1, s1 + kNumStructs}),
00701             Hash<ArraySlice<StructWithPadding>>()({s2, s2 + kNumStructs}));
00702 }
00703 
00704 TEST(HashTest, StandardHashContainerUsage) {
00705   std::unordered_map<int, std::string, Hash<int>> map = {{0, "foo"},
00706                                                          {42, "bar"}};
00707 
00708   EXPECT_NE(map.find(0), map.end());
00709   EXPECT_EQ(map.find(1), map.end());
00710   EXPECT_NE(map.find(0u), map.end());
00711 }
00712 
00713 struct ConvertibleFromNoOp {
00714   ConvertibleFromNoOp(NoOp) {}  // NOLINT(runtime/explicit)
00715 
00716   template <typename H>
00717   friend H AbslHashValue(H hash_state, ConvertibleFromNoOp) {
00718     return H::combine(std::move(hash_state), 1);
00719   }
00720 };
00721 
00722 TEST(HashTest, HeterogeneousCall) {
00723   EXPECT_NE(Hash<ConvertibleFromNoOp>()(NoOp()),
00724             Hash<NoOp>()(NoOp()));
00725 }
00726 
00727 TEST(IsUniquelyRepresentedTest, SanityTest) {
00728   using absl::hash_internal::is_uniquely_represented;
00729 
00730   EXPECT_TRUE(is_uniquely_represented<unsigned char>::value);
00731   EXPECT_TRUE(is_uniquely_represented<int>::value);
00732   EXPECT_FALSE(is_uniquely_represented<bool>::value);
00733   EXPECT_FALSE(is_uniquely_represented<int*>::value);
00734 }
00735 
00736 struct IntAndString {
00737   int i;
00738   std::string s;
00739 
00740   template <typename H>
00741   friend H AbslHashValue(H hash_state, IntAndString int_and_string) {
00742     return H::combine(std::move(hash_state), int_and_string.s,
00743                       int_and_string.i);
00744   }
00745 };
00746 
00747 TEST(HashTest, SmallValueOn64ByteBoundary) {
00748   Hash<IntAndString>()(IntAndString{0, std::string(63, '0')});
00749 }
00750 
00751 struct TypeErased {
00752   size_t n;
00753 
00754   template <typename H>
00755   friend H AbslHashValue(H hash_state, const TypeErased& v) {
00756     v.HashValue(absl::HashState::Create(&hash_state));
00757     return hash_state;
00758   }
00759 
00760   void HashValue(absl::HashState state) const {
00761     absl::HashState::combine(std::move(state), n);
00762   }
00763 };
00764 
00765 TEST(HashTest, TypeErased) {
00766   EXPECT_TRUE((is_hashable<TypeErased>::value));
00767   EXPECT_TRUE((is_hashable<std::pair<TypeErased, int>>::value));
00768 
00769   EXPECT_EQ(SpyHash(TypeErased{7}), SpyHash(size_t{7}));
00770   EXPECT_NE(SpyHash(TypeErased{7}), SpyHash(size_t{13}));
00771 
00772   EXPECT_EQ(SpyHash(std::make_pair(TypeErased{7}, 17)),
00773             SpyHash(std::make_pair(size_t{7}, 17)));
00774 }
00775 
00776 struct ValueWithBoolConversion {
00777   operator bool() const { return false; }
00778   int i;
00779 };
00780 
00781 }  // namespace
00782 namespace std {
00783 template <>
00784 struct hash<ValueWithBoolConversion> {
00785   size_t operator()(ValueWithBoolConversion v) { return v.i; }
00786 };
00787 }  // namespace std
00788 
00789 namespace {
00790 
00791 TEST(HashTest, DoesNotUseImplicitConversionsToBool) {
00792   EXPECT_NE(absl::Hash<ValueWithBoolConversion>()(ValueWithBoolConversion{0}),
00793             absl::Hash<ValueWithBoolConversion>()(ValueWithBoolConversion{1}));
00794 }
00795 
00796 }  // namespace


abseil_cpp
Author(s):
autogenerated on Wed Jun 19 2019 19:42:14