-- 4eacae3ff1b14b1d309e8092185bc10e8a6203cf by Derek Mauro <dmauro@google.com>: Release SwissTable - a fast, efficient, cache-friendly hash table. https://www.youtube.com/watch?v=ncHmEUmJZf4 PiperOrigin-RevId: 214816527 -- df8c3dfab3cfb2f4365909a84d0683b193cfbb11 by Derek Mauro <dmauro@google.com>: Internal change PiperOrigin-RevId: 214785288 -- 1eabd5266bbcebc33eecc91e5309b751856a75c8 by Abseil Team <absl-team@google.com>: Internal change PiperOrigin-RevId: 214722931 -- 2ebbfac950f83146b46253038e7dd7dcde9f2951 by Derek Mauro <dmauro@google.com>: Internal change PiperOrigin-RevId: 214701684 GitOrigin-RevId: 4eacae3ff1b14b1d309e8092185bc10e8a6203cf Change-Id: I9ba64e395b22ad7863213d157b8019b082adc19d
		
			
				
	
	
		
			218 lines
		
	
	
	
		
			6.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			218 lines
		
	
	
	
		
			6.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Copyright 2018 The Abseil Authors.
 | |
| //
 | |
| // Licensed under the Apache License, Version 2.0 (the "License");
 | |
| // you may not use this file except in compliance with the License.
 | |
| // You may obtain a copy of the License at
 | |
| //
 | |
| //      http://www.apache.org/licenses/LICENSE-2.0
 | |
| //
 | |
| // Unless required by applicable law or agreed to in writing, software
 | |
| // distributed under the License is distributed on an "AS IS" BASIS,
 | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| // See the License for the specific language governing permissions and
 | |
| // limitations under the License.
 | |
| 
 | |
| #include "absl/container/node_hash_map.h"
 | |
| 
 | |
| #include "absl/container/internal/tracked.h"
 | |
| #include "absl/container/internal/unordered_map_constructor_test.h"
 | |
| #include "absl/container/internal/unordered_map_lookup_test.h"
 | |
| #include "absl/container/internal/unordered_map_modifiers_test.h"
 | |
| 
 | |
| namespace absl {
 | |
| namespace container_internal {
 | |
| namespace {
 | |
| 
 | |
| using ::testing::Field;
 | |
| using ::testing::Pair;
 | |
| using ::testing::UnorderedElementsAre;
 | |
| 
 | |
| using MapTypes = ::testing::Types<
 | |
|     absl::node_hash_map<int, int, StatefulTestingHash, StatefulTestingEqual,
 | |
|                         Alloc<std::pair<const int, int>>>,
 | |
|     absl::node_hash_map<std::string, std::string, StatefulTestingHash,
 | |
|                         StatefulTestingEqual,
 | |
|                         Alloc<std::pair<const std::string, std::string>>>>;
 | |
| 
 | |
| INSTANTIATE_TYPED_TEST_CASE_P(NodeHashMap, ConstructorTest, MapTypes);
 | |
| INSTANTIATE_TYPED_TEST_CASE_P(NodeHashMap, LookupTest, MapTypes);
 | |
| INSTANTIATE_TYPED_TEST_CASE_P(NodeHashMap, ModifiersTest, MapTypes);
 | |
| 
 | |
| using M = absl::node_hash_map<std::string, Tracked<int>>;
 | |
| 
 | |
| TEST(NodeHashMap, Emplace) {
 | |
|   M m;
 | |
|   Tracked<int> t(53);
 | |
|   m.emplace("a", t);
 | |
|   ASSERT_EQ(0, t.num_moves());
 | |
|   ASSERT_EQ(1, t.num_copies());
 | |
| 
 | |
|   m.emplace(std::string("a"), t);
 | |
|   ASSERT_EQ(0, t.num_moves());
 | |
|   ASSERT_EQ(1, t.num_copies());
 | |
| 
 | |
|   std::string a("a");
 | |
|   m.emplace(a, t);
 | |
|   ASSERT_EQ(0, t.num_moves());
 | |
|   ASSERT_EQ(1, t.num_copies());
 | |
| 
 | |
|   const std::string ca("a");
 | |
|   m.emplace(a, t);
 | |
|   ASSERT_EQ(0, t.num_moves());
 | |
|   ASSERT_EQ(1, t.num_copies());
 | |
| 
 | |
|   m.emplace(std::make_pair("a", t));
 | |
|   ASSERT_EQ(0, t.num_moves());
 | |
|   ASSERT_EQ(2, t.num_copies());
 | |
| 
 | |
|   m.emplace(std::make_pair(std::string("a"), t));
 | |
|   ASSERT_EQ(0, t.num_moves());
 | |
|   ASSERT_EQ(3, t.num_copies());
 | |
| 
 | |
|   std::pair<std::string, Tracked<int>> p("a", t);
 | |
|   ASSERT_EQ(0, t.num_moves());
 | |
|   ASSERT_EQ(4, t.num_copies());
 | |
|   m.emplace(p);
 | |
|   ASSERT_EQ(0, t.num_moves());
 | |
|   ASSERT_EQ(4, t.num_copies());
 | |
| 
 | |
|   const std::pair<std::string, Tracked<int>> cp("a", t);
 | |
|   ASSERT_EQ(0, t.num_moves());
 | |
|   ASSERT_EQ(5, t.num_copies());
 | |
|   m.emplace(cp);
 | |
|   ASSERT_EQ(0, t.num_moves());
 | |
|   ASSERT_EQ(5, t.num_copies());
 | |
| 
 | |
|   std::pair<const std::string, Tracked<int>> pc("a", t);
 | |
|   ASSERT_EQ(0, t.num_moves());
 | |
|   ASSERT_EQ(6, t.num_copies());
 | |
|   m.emplace(pc);
 | |
|   ASSERT_EQ(0, t.num_moves());
 | |
|   ASSERT_EQ(6, t.num_copies());
 | |
| 
 | |
|   const std::pair<const std::string, Tracked<int>> cpc("a", t);
 | |
|   ASSERT_EQ(0, t.num_moves());
 | |
|   ASSERT_EQ(7, t.num_copies());
 | |
|   m.emplace(cpc);
 | |
|   ASSERT_EQ(0, t.num_moves());
 | |
|   ASSERT_EQ(7, t.num_copies());
 | |
| 
 | |
|   m.emplace(std::piecewise_construct, std::forward_as_tuple("a"),
 | |
|             std::forward_as_tuple(t));
 | |
|   ASSERT_EQ(0, t.num_moves());
 | |
|   ASSERT_EQ(7, t.num_copies());
 | |
| 
 | |
|   m.emplace(std::piecewise_construct, std::forward_as_tuple(std::string("a")),
 | |
|             std::forward_as_tuple(t));
 | |
|   ASSERT_EQ(0, t.num_moves());
 | |
|   ASSERT_EQ(7, t.num_copies());
 | |
| }
 | |
| 
 | |
| TEST(NodeHashMap, AssignRecursive) {
 | |
|   struct Tree {
 | |
|     // Verify that unordered_map<K, IncompleteType> can be instantiated.
 | |
|     absl::node_hash_map<int, Tree> children;
 | |
|   };
 | |
|   Tree root;
 | |
|   const Tree& child = root.children.emplace().first->second;
 | |
|   // Verify that `lhs = rhs` doesn't read rhs after clearing lhs.
 | |
|   root = child;
 | |
| }
 | |
| 
 | |
| TEST(FlatHashMap, MoveOnlyKey) {
 | |
|   struct Key {
 | |
|     Key() = default;
 | |
|     Key(Key&&) = default;
 | |
|     Key& operator=(Key&&) = default;
 | |
|   };
 | |
|   struct Eq {
 | |
|     bool operator()(const Key&, const Key&) const { return true; }
 | |
|   };
 | |
|   struct Hash {
 | |
|     size_t operator()(const Key&) const { return 0; }
 | |
|   };
 | |
|   absl::node_hash_map<Key, int, Hash, Eq> m;
 | |
|   m[Key()];
 | |
| }
 | |
| 
 | |
| struct NonMovableKey {
 | |
|   explicit NonMovableKey(int i) : i(i) {}
 | |
|   NonMovableKey(NonMovableKey&&) = delete;
 | |
|   int i;
 | |
| };
 | |
| struct NonMovableKeyHash {
 | |
|   using is_transparent = void;
 | |
|   size_t operator()(const NonMovableKey& k) const { return k.i; }
 | |
|   size_t operator()(int k) const { return k; }
 | |
| };
 | |
| struct NonMovableKeyEq {
 | |
|   using is_transparent = void;
 | |
|   bool operator()(const NonMovableKey& a, const NonMovableKey& b) const {
 | |
|     return a.i == b.i;
 | |
|   }
 | |
|   bool operator()(const NonMovableKey& a, int b) const { return a.i == b; }
 | |
| };
 | |
| 
 | |
| TEST(NodeHashMap, MergeExtractInsert) {
 | |
|   absl::node_hash_map<NonMovableKey, int, NonMovableKeyHash, NonMovableKeyEq>
 | |
|       set1, set2;
 | |
|   set1.emplace(std::piecewise_construct, std::make_tuple(7),
 | |
|                std::make_tuple(-7));
 | |
|   set1.emplace(std::piecewise_construct, std::make_tuple(17),
 | |
|                std::make_tuple(-17));
 | |
| 
 | |
|   set2.emplace(std::piecewise_construct, std::make_tuple(7),
 | |
|                std::make_tuple(-70));
 | |
|   set2.emplace(std::piecewise_construct, std::make_tuple(19),
 | |
|                std::make_tuple(-190));
 | |
| 
 | |
|   auto Elem = [](int key, int value) {
 | |
|     return Pair(Field(&NonMovableKey::i, key), value);
 | |
|   };
 | |
| 
 | |
|   EXPECT_THAT(set1, UnorderedElementsAre(Elem(7, -7), Elem(17, -17)));
 | |
|   EXPECT_THAT(set2, UnorderedElementsAre(Elem(7, -70), Elem(19, -190)));
 | |
| 
 | |
|   // NonMovableKey is neither copyable nor movable. We should still be able to
 | |
|   // move nodes around.
 | |
|   static_assert(!std::is_move_constructible<NonMovableKey>::value, "");
 | |
|   set1.merge(set2);
 | |
| 
 | |
|   EXPECT_THAT(set1,
 | |
|               UnorderedElementsAre(Elem(7, -7), Elem(17, -17), Elem(19, -190)));
 | |
|   EXPECT_THAT(set2, UnorderedElementsAre(Elem(7, -70)));
 | |
| 
 | |
|   auto node = set1.extract(7);
 | |
|   EXPECT_TRUE(node);
 | |
|   EXPECT_EQ(node.key().i, 7);
 | |
|   EXPECT_EQ(node.mapped(), -7);
 | |
|   EXPECT_THAT(set1, UnorderedElementsAre(Elem(17, -17), Elem(19, -190)));
 | |
| 
 | |
|   auto insert_result = set2.insert(std::move(node));
 | |
|   EXPECT_FALSE(node);
 | |
|   EXPECT_FALSE(insert_result.inserted);
 | |
|   EXPECT_TRUE(insert_result.node);
 | |
|   EXPECT_EQ(insert_result.node.key().i, 7);
 | |
|   EXPECT_EQ(insert_result.node.mapped(), -7);
 | |
|   EXPECT_THAT(*insert_result.position, Elem(7, -70));
 | |
|   EXPECT_THAT(set2, UnorderedElementsAre(Elem(7, -70)));
 | |
| 
 | |
|   node = set1.extract(17);
 | |
|   EXPECT_TRUE(node);
 | |
|   EXPECT_EQ(node.key().i, 17);
 | |
|   EXPECT_EQ(node.mapped(), -17);
 | |
|   EXPECT_THAT(set1, UnorderedElementsAre(Elem(19, -190)));
 | |
| 
 | |
|   node.mapped() = 23;
 | |
| 
 | |
|   insert_result = set2.insert(std::move(node));
 | |
|   EXPECT_FALSE(node);
 | |
|   EXPECT_TRUE(insert_result.inserted);
 | |
|   EXPECT_FALSE(insert_result.node);
 | |
|   EXPECT_THAT(*insert_result.position, Elem(17, 23));
 | |
|   EXPECT_THAT(set2, UnorderedElementsAre(Elem(7, -70), Elem(17, 23)));
 | |
| }
 | |
| 
 | |
| }  // namespace
 | |
| }  // namespace container_internal
 | |
| }  // namespace absl
 |