flat_hash_map_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/container/flat_hash_map.h"
00016 
00017 #include "absl/container/internal/hash_generator_testing.h"
00018 #include "absl/container/internal/unordered_map_constructor_test.h"
00019 #include "absl/container/internal/unordered_map_lookup_test.h"
00020 #include "absl/container/internal/unordered_map_members_test.h"
00021 #include "absl/container/internal/unordered_map_modifiers_test.h"
00022 #include "absl/types/any.h"
00023 
00024 namespace absl {
00025 namespace container_internal {
00026 namespace {
00027 using ::absl::container_internal::hash_internal::Enum;
00028 using ::absl::container_internal::hash_internal::EnumClass;
00029 using ::testing::_;
00030 using ::testing::Pair;
00031 using ::testing::UnorderedElementsAre;
00032 
00033 template <class K, class V>
00034 using Map = flat_hash_map<K, V, StatefulTestingHash, StatefulTestingEqual,
00035                           Alloc<std::pair<const K, V>>>;
00036 
00037 static_assert(!std::is_standard_layout<NonStandardLayout>(), "");
00038 
00039 using MapTypes =
00040     ::testing::Types<Map<int, int>, Map<std::string, int>,
00041                      Map<Enum, std::string>, Map<EnumClass, int>,
00042                      Map<int, NonStandardLayout>, Map<NonStandardLayout, int>>;
00043 
00044 INSTANTIATE_TYPED_TEST_SUITE_P(FlatHashMap, ConstructorTest, MapTypes);
00045 INSTANTIATE_TYPED_TEST_SUITE_P(FlatHashMap, LookupTest, MapTypes);
00046 INSTANTIATE_TYPED_TEST_SUITE_P(FlatHashMap, MembersTest, MapTypes);
00047 INSTANTIATE_TYPED_TEST_SUITE_P(FlatHashMap, ModifiersTest, MapTypes);
00048 
00049 TEST(FlatHashMap, StandardLayout) {
00050   struct Int {
00051     explicit Int(size_t value) : value(value) {}
00052     Int() : value(0) { ADD_FAILURE(); }
00053     Int(const Int& other) : value(other.value) { ADD_FAILURE(); }
00054     Int(Int&&) = default;
00055     bool operator==(const Int& other) const { return value == other.value; }
00056     size_t value;
00057   };
00058   static_assert(std::is_standard_layout<Int>(), "");
00059 
00060   struct Hash {
00061     size_t operator()(const Int& obj) const { return obj.value; }
00062   };
00063 
00064   // Verify that neither the key nor the value get default-constructed or
00065   // copy-constructed.
00066   {
00067     flat_hash_map<Int, Int, Hash> m;
00068     m.try_emplace(Int(1), Int(2));
00069     m.try_emplace(Int(3), Int(4));
00070     m.erase(Int(1));
00071     m.rehash(2 * m.bucket_count());
00072   }
00073   {
00074     flat_hash_map<Int, Int, Hash> m;
00075     m.try_emplace(Int(1), Int(2));
00076     m.try_emplace(Int(3), Int(4));
00077     m.erase(Int(1));
00078     m.clear();
00079   }
00080 }
00081 
00082 // gcc becomes unhappy if this is inside the method, so pull it out here.
00083 struct balast {};
00084 
00085 TEST(FlatHashMap, IteratesMsan) {
00086   // Because SwissTable randomizes on pointer addresses, we keep old tables
00087   // around to ensure we don't reuse old memory.
00088   std::vector<absl::flat_hash_map<int, balast>> garbage;
00089   for (int i = 0; i < 100; ++i) {
00090     absl::flat_hash_map<int, balast> t;
00091     for (int j = 0; j < 100; ++j) {
00092       t[j];
00093       for (const auto& p : t) EXPECT_THAT(p, Pair(_, _));
00094     }
00095     garbage.push_back(std::move(t));
00096   }
00097 }
00098 
00099 // Demonstration of the "Lazy Key" pattern.  This uses heterogeneous insert to
00100 // avoid creating expensive key elements when the item is already present in the
00101 // map.
00102 struct LazyInt {
00103   explicit LazyInt(size_t value, int* tracker)
00104       : value(value), tracker(tracker) {}
00105 
00106   explicit operator size_t() const {
00107     ++*tracker;
00108     return value;
00109   }
00110 
00111   size_t value;
00112   int* tracker;
00113 };
00114 
00115 struct Hash {
00116   using is_transparent = void;
00117   int* tracker;
00118   size_t operator()(size_t obj) const {
00119     ++*tracker;
00120     return obj;
00121   }
00122   size_t operator()(const LazyInt& obj) const {
00123     ++*tracker;
00124     return obj.value;
00125   }
00126 };
00127 
00128 struct Eq {
00129   using is_transparent = void;
00130   bool operator()(size_t lhs, size_t rhs) const {
00131     return lhs == rhs;
00132   }
00133   bool operator()(size_t lhs, const LazyInt& rhs) const {
00134     return lhs == rhs.value;
00135   }
00136 };
00137 
00138 TEST(FlatHashMap, LazyKeyPattern) {
00139   // hashes are only guaranteed in opt mode, we use assertions to track internal
00140   // state that can cause extra calls to hash.
00141   int conversions = 0;
00142   int hashes = 0;
00143   flat_hash_map<size_t, size_t, Hash, Eq> m(0, Hash{&hashes});
00144   m.reserve(3);
00145 
00146   m[LazyInt(1, &conversions)] = 1;
00147   EXPECT_THAT(m, UnorderedElementsAre(Pair(1, 1)));
00148   EXPECT_EQ(conversions, 1);
00149 #ifdef NDEBUG
00150   EXPECT_EQ(hashes, 1);
00151 #endif
00152 
00153   m[LazyInt(1, &conversions)] = 2;
00154   EXPECT_THAT(m, UnorderedElementsAre(Pair(1, 2)));
00155   EXPECT_EQ(conversions, 1);
00156 #ifdef NDEBUG
00157   EXPECT_EQ(hashes, 2);
00158 #endif
00159 
00160   m.try_emplace(LazyInt(2, &conversions), 3);
00161   EXPECT_THAT(m, UnorderedElementsAre(Pair(1, 2), Pair(2, 3)));
00162   EXPECT_EQ(conversions, 2);
00163 #ifdef NDEBUG
00164   EXPECT_EQ(hashes, 3);
00165 #endif
00166 
00167   m.try_emplace(LazyInt(2, &conversions), 4);
00168   EXPECT_THAT(m, UnorderedElementsAre(Pair(1, 2), Pair(2, 3)));
00169   EXPECT_EQ(conversions, 2);
00170 #ifdef NDEBUG
00171   EXPECT_EQ(hashes, 4);
00172 #endif
00173 }
00174 
00175 TEST(FlatHashMap, BitfieldArgument) {
00176   union {
00177     int n : 1;
00178   };
00179   n = 0;
00180   flat_hash_map<int, int> m;
00181   m.erase(n);
00182   m.count(n);
00183   m.prefetch(n);
00184   m.find(n);
00185   m.contains(n);
00186   m.equal_range(n);
00187   m.insert_or_assign(n, n);
00188   m.insert_or_assign(m.end(), n, n);
00189   m.try_emplace(n);
00190   m.try_emplace(m.end(), n);
00191   m.at(n);
00192   m[n];
00193 }
00194 
00195 TEST(FlatHashMap, MergeExtractInsert) {
00196   // We can't test mutable keys, or non-copyable keys with flat_hash_map.
00197   // Test that the nodes have the proper API.
00198   absl::flat_hash_map<int, int> m = {{1, 7}, {2, 9}};
00199   auto node = m.extract(1);
00200   EXPECT_TRUE(node);
00201   EXPECT_EQ(node.key(), 1);
00202   EXPECT_EQ(node.mapped(), 7);
00203   EXPECT_THAT(m, UnorderedElementsAre(Pair(2, 9)));
00204 
00205   node.mapped() = 17;
00206   m.insert(std::move(node));
00207   EXPECT_THAT(m, UnorderedElementsAre(Pair(1, 17), Pair(2, 9)));
00208 }
00209 
00210 #if (defined(ABSL_HAVE_STD_ANY) || !defined(_LIBCPP_VERSION)) && \
00211     !defined(__EMSCRIPTEN__)
00212 TEST(FlatHashMap, Any) {
00213   absl::flat_hash_map<int, absl::any> m;
00214   m.emplace(1, 7);
00215   auto it = m.find(1);
00216   ASSERT_NE(it, m.end());
00217   EXPECT_EQ(7, absl::any_cast<int>(it->second));
00218 
00219   m.emplace(std::piecewise_construct, std::make_tuple(2), std::make_tuple(8));
00220   it = m.find(2);
00221   ASSERT_NE(it, m.end());
00222   EXPECT_EQ(8, absl::any_cast<int>(it->second));
00223 
00224   m.emplace(std::piecewise_construct, std::make_tuple(3),
00225             std::make_tuple(absl::any(9)));
00226   it = m.find(3);
00227   ASSERT_NE(it, m.end());
00228   EXPECT_EQ(9, absl::any_cast<int>(it->second));
00229 
00230   struct H {
00231     size_t operator()(const absl::any&) const { return 0; }
00232   };
00233   struct E {
00234     bool operator()(const absl::any&, const absl::any&) const { return true; }
00235   };
00236   absl::flat_hash_map<absl::any, int, H, E> m2;
00237   m2.emplace(1, 7);
00238   auto it2 = m2.find(1);
00239   ASSERT_NE(it2, m2.end());
00240   EXPECT_EQ(7, it2->second);
00241 }
00242 #endif  // (defined(ABSL_HAVE_STD_ANY) || !defined(_LIBCPP_VERSION)) &&
00243         // !defined(__EMSCRIPTEN__)
00244 
00245 }  // namespace
00246 }  // namespace container_internal
00247 }  // namespace absl


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