From 48cd2c3f351ff188bc85684b84a91b6e6d17d896 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Thu, 27 Sep 2018 12:24:54 -0700 Subject: Export of internal Abseil changes. -- 4eacae3ff1b14b1d309e8092185bc10e8a6203cf by Derek Mauro : Release SwissTable - a fast, efficient, cache-friendly hash table. https://www.youtube.com/watch?v=ncHmEUmJZf4 PiperOrigin-RevId: 214816527 -- df8c3dfab3cfb2f4365909a84d0683b193cfbb11 by Derek Mauro : Internal change PiperOrigin-RevId: 214785288 -- 1eabd5266bbcebc33eecc91e5309b751856a75c8 by Abseil Team : Internal change PiperOrigin-RevId: 214722931 -- 2ebbfac950f83146b46253038e7dd7dcde9f2951 by Derek Mauro : Internal change PiperOrigin-RevId: 214701684 GitOrigin-RevId: 4eacae3ff1b14b1d309e8092185bc10e8a6203cf Change-Id: I9ba64e395b22ad7863213d157b8019b082adc19d --- absl/container/node_hash_map_test.cc | 218 +++++++++++++++++++++++++++++++++++ 1 file changed, 218 insertions(+) create mode 100644 absl/container/node_hash_map_test.cc (limited to 'absl/container/node_hash_map_test.cc') diff --git a/absl/container/node_hash_map_test.cc b/absl/container/node_hash_map_test.cc new file mode 100644 index 0000000..bd78964 --- /dev/null +++ b/absl/container/node_hash_map_test.cc @@ -0,0 +1,218 @@ +// 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>>, + absl::node_hash_map>>>; + +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>; + +TEST(NodeHashMap, Emplace) { + M m; + Tracked 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> 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> 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> 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> 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 can be instantiated. + absl::node_hash_map 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 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 + 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::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 -- cgit v1.2.3