summaryrefslogtreecommitdiff
path: root/absl/container/node_hash_map_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'absl/container/node_hash_map_test.cc')
-rw-r--r--absl/container/node_hash_map_test.cc220
1 files changed, 220 insertions, 0 deletions
diff --git a/absl/container/node_hash_map_test.cc b/absl/container/node_hash_map_test.cc
new file mode 100644
index 00000000..76a387b8
--- /dev/null
+++ b/absl/container/node_hash_map_test.cc
@@ -0,0 +1,220 @@
+// 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 {
+inline namespace lts_2018_12_18 {
+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
+} // inline namespace lts_2018_12_18
+} // namespace absl