diff options
author | Benjamin Barenblat <bbaren@google.com> | 2023-06-26 13:09:57 -0400 |
---|---|---|
committer | Benjamin Barenblat <bbaren@google.com> | 2023-08-02 12:52:59 -0400 |
commit | 17046ae7503e82dd8484584619413eab688fa717 (patch) | |
tree | 3baf6b63a80153e58d9c0645df640f66ce8f0157 /debian | |
parent | eb6db73f663df4eef48517a4dae62240c90783ff (diff) |
Split hash tests to make life easier for mipsel
Some of the Abseil tests use so much RAM in template expansion that they
exhaust memory on the mipsel buildds. Backport a patch from upstream to
split the problematic tests into smaller files.
Diffstat (limited to 'debian')
-rw-r--r-- | debian/changelog | 1 | ||||
-rw-r--r-- | debian/patches/series | 1 | ||||
-rw-r--r-- | debian/patches/split-hash-tests.diff | 677 |
3 files changed, 679 insertions, 0 deletions
diff --git a/debian/changelog b/debian/changelog index 70a57c02..6abc1938 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,6 +2,7 @@ abseil (20230125.3-2) UNRELEASED; urgency=medium * Reenable unit tests, which were accidentally disabled in the previous version. + * Backport an upstream patch to allow building tests on mipsel. -- Benjamin Barenblat <bbaren@debian.org> Tue, 27 Jun 2023 17:00:12 -0400 diff --git a/debian/patches/series b/debian/patches/series index 29630f3c..66bf33ce 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -4,3 +4,4 @@ latomic.diff empty-flags-library.diff cordz-info-statistics-test.diff pkg-config-directives.diff +split-hash-tests.diff diff --git a/debian/patches/split-hash-tests.diff b/debian/patches/split-hash-tests.diff new file mode 100644 index 00000000..ae0d066f --- /dev/null +++ b/debian/patches/split-hash-tests.diff @@ -0,0 +1,677 @@ +From: Benjamin Barenblat <bbaren@google.com> +Subject: Split absl/hash/hash_test.cc into two files +Origin: backport, https://github.com/abseil/abseil-cpp/commit/c154d20abce2f1ae6bd35bd774313e351493219b + +hash_test.cc leans heavily on INSTANTIATE_TYPED_TEST_SUITE_P, which is quite +memory- and CPU-hungry. Split a few heavyweight tests into a new +hash_instantiated_test.cc, reducing peak RAM consumption (or, on multicore +systems, compilation time). + +--- a/absl/hash/BUILD.bazel ++++ b/absl/hash/BUILD.bazel +@@ -68,13 +68,17 @@ + + cc_test( + name = "hash_test", +- srcs = ["hash_test.cc"], ++ srcs = [ ++ "hash_test.cc", ++ "internal/hash_test.h", ++ ], + copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, + deps = [ + ":hash", + ":hash_testing", + ":spy_hash_state", ++ "//absl/base:config", + "//absl/base:core_headers", + "//absl/container:btree", + "//absl/container:flat_hash_map", +@@ -87,6 +91,27 @@ + "@com_google_googletest//:gtest_main", + ], + ) ++ ++cc_test( ++ name = "hash_instantiated_test", ++ srcs = [ ++ "hash_instantiated_test.cc", ++ "internal/hash_test.h", ++ ], ++ copts = ABSL_TEST_COPTS, ++ linkopts = ABSL_DEFAULT_LINKOPTS, ++ deps = [ ++ ":hash", ++ ":hash_testing", ++ "//absl/base:config", ++ "//absl/container:btree", ++ "//absl/container:flat_hash_map", ++ "//absl/container:flat_hash_set", ++ "//absl/container:node_hash_map", ++ "//absl/container:node_hash_set", ++ "@com_google_googletest//:gtest_main", ++ ], ++) + + cc_binary( + name = "hash_benchmark", +--- a/absl/hash/CMakeLists.txt ++++ b/absl/hash/CMakeLists.txt +@@ -64,6 +64,7 @@ + hash_test + SRCS + "hash_test.cc" ++ "internal/hash_test.h" + COPTS + ${ABSL_TEST_COPTS} + DEPS +@@ -82,6 +83,26 @@ + GTest::gmock_main + ) + ++absl_cc_test( ++ NAME ++ hash_instantiated_test ++ SRCS ++ "hash_test.cc" ++ "internal/hash_test.h" ++ COPTS ++ ${ABSL_TEST_COPTS} ++ DEPS ++ absl::hash ++ absl::hash_testing ++ absl::config ++ absl::btree ++ absl::flat_hash_map ++ absl::flat_hash_set ++ absl::node_hash_map ++ absl::node_hash_set ++ GTest::gtest_main ++) ++ + # Internal-only target, do not depend on directly. + # + # Note: Even though external code should not depend on this target +--- /dev/null ++++ b/absl/hash/hash_instantiated_test.cc +@@ -0,0 +1,224 @@ ++// 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 ++// ++// https://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. ++ ++// This file contains a few select absl::Hash tests that, due to their reliance ++// on INSTANTIATE_TYPED_TEST_SUITE_P, require a large amount of memory to ++// compile. Put new tests in hash_test.cc, not this file. ++ ++#include "absl/hash/hash.h" ++ ++#include <stddef.h> ++ ++#include <algorithm> ++#include <deque> ++#include <forward_list> ++#include <initializer_list> ++#include <list> ++#include <map> ++#include <set> ++#include <string> ++#include <type_traits> ++#include <unordered_map> ++#include <unordered_set> ++#include <utility> ++#include <vector> ++ ++#include "gtest/gtest.h" ++#include "absl/container/btree_map.h" ++#include "absl/container/btree_set.h" ++#include "absl/container/flat_hash_map.h" ++#include "absl/container/flat_hash_set.h" ++#include "absl/container/node_hash_map.h" ++#include "absl/container/node_hash_set.h" ++#include "absl/hash/hash_testing.h" ++#include "absl/hash/internal/hash_test.h" ++ ++namespace { ++ ++using ::absl::hash_test_internal::is_hashable; ++using ::absl::hash_test_internal::TypeErasedContainer; ++ ++// Dummy type with unordered equality and hashing semantics. This preserves ++// input order internally, and is used below to ensure we get test coverage ++// for equal sequences with different iteraton orders. ++template <typename T> ++class UnorderedSequence { ++ public: ++ UnorderedSequence() = default; ++ template <typename TT> ++ UnorderedSequence(std::initializer_list<TT> l) ++ : values_(l.begin(), l.end()) {} ++ template <typename ForwardIterator, ++ typename std::enable_if<!std::is_integral<ForwardIterator>::value, ++ bool>::type = true> ++ UnorderedSequence(ForwardIterator begin, ForwardIterator end) ++ : values_(begin, end) {} ++ // one-argument constructor of value type T, to appease older toolchains that ++ // get confused by one-element initializer lists in some contexts ++ explicit UnorderedSequence(const T& v) : values_(&v, &v + 1) {} ++ ++ using value_type = T; ++ ++ size_t size() const { return values_.size(); } ++ typename std::vector<T>::const_iterator begin() const { ++ return values_.begin(); ++ } ++ typename std::vector<T>::const_iterator end() const { return values_.end(); } ++ ++ friend bool operator==(const UnorderedSequence& lhs, ++ const UnorderedSequence& rhs) { ++ return lhs.size() == rhs.size() && ++ std::is_permutation(lhs.begin(), lhs.end(), rhs.begin()); ++ } ++ friend bool operator!=(const UnorderedSequence& lhs, ++ const UnorderedSequence& rhs) { ++ return !(lhs == rhs); ++ } ++ template <typename H> ++ friend H AbslHashValue(H h, const UnorderedSequence& u) { ++ return H::combine(H::combine_unordered(std::move(h), u.begin(), u.end()), ++ u.size()); ++ } ++ ++ private: ++ std::vector<T> values_; ++}; ++ ++template <typename T> ++class HashValueSequenceTest : public testing::Test {}; ++TYPED_TEST_SUITE_P(HashValueSequenceTest); ++ ++TYPED_TEST_P(HashValueSequenceTest, BasicUsage) { ++ EXPECT_TRUE((is_hashable<TypeParam>::value)); ++ ++ using IntType = typename TypeParam::value_type; ++ auto a = static_cast<IntType>(0); ++ auto b = static_cast<IntType>(23); ++ auto c = static_cast<IntType>(42); ++ ++ std::vector<TypeParam> exemplars = { ++ TypeParam(), TypeParam(), TypeParam{a, b, c}, ++ TypeParam{a, c, b}, TypeParam{c, a, b}, TypeParam{a}, ++ TypeParam{a, a}, TypeParam{a, a, a}, TypeParam{a, a, b}, ++ TypeParam{a, b, a}, TypeParam{b, a, a}, TypeParam{a, b}, ++ TypeParam{b, c}}; ++ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(exemplars)); ++} ++ ++REGISTER_TYPED_TEST_SUITE_P(HashValueSequenceTest, BasicUsage); ++using IntSequenceTypes = testing::Types< ++ std::deque<int>, std::forward_list<int>, std::list<int>, std::vector<int>, ++ std::vector<bool>, TypeErasedContainer<std::vector<int>>, std::set<int>, ++ std::multiset<int>, UnorderedSequence<int>, ++ TypeErasedContainer<UnorderedSequence<int>>, std::unordered_set<int>, ++ std::unordered_multiset<int>, absl::flat_hash_set<int>, ++ absl::node_hash_set<int>, absl::btree_set<int>>; ++INSTANTIATE_TYPED_TEST_SUITE_P(My, HashValueSequenceTest, IntSequenceTypes); ++ ++template <typename T> ++class HashValueNestedSequenceTest : public testing::Test {}; ++TYPED_TEST_SUITE_P(HashValueNestedSequenceTest); ++ ++TYPED_TEST_P(HashValueNestedSequenceTest, BasicUsage) { ++ using T = TypeParam; ++ using V = typename T::value_type; ++ std::vector<T> exemplars = { ++ // empty case ++ T{}, ++ // sets of empty sets ++ T{V{}}, T{V{}, V{}}, T{V{}, V{}, V{}}, ++ // multisets of different values ++ T{V{1}}, T{V{1, 1}, V{1, 1}}, T{V{1, 1, 1}, V{1, 1, 1}, V{1, 1, 1}}, ++ // various orderings of same nested sets ++ T{V{}, V{1, 2}}, T{V{}, V{2, 1}}, T{V{1, 2}, V{}}, T{V{2, 1}, V{}}, ++ // various orderings of various nested sets, case 2 ++ T{V{1, 2}, V{3, 4}}, T{V{1, 2}, V{4, 3}}, T{V{1, 3}, V{2, 4}}, ++ T{V{1, 3}, V{4, 2}}, T{V{1, 4}, V{2, 3}}, T{V{1, 4}, V{3, 2}}, ++ T{V{2, 3}, V{1, 4}}, T{V{2, 3}, V{4, 1}}, T{V{2, 4}, V{1, 3}}, ++ T{V{2, 4}, V{3, 1}}, T{V{3, 4}, V{1, 2}}, T{V{3, 4}, V{2, 1}}}; ++ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(exemplars)); ++} ++ ++REGISTER_TYPED_TEST_SUITE_P(HashValueNestedSequenceTest, BasicUsage); ++template <typename T> ++using TypeErasedSet = TypeErasedContainer<UnorderedSequence<T>>; ++ ++using NestedIntSequenceTypes = testing::Types< ++ std::vector<std::vector<int>>, std::vector<UnorderedSequence<int>>, ++ std::vector<TypeErasedSet<int>>, UnorderedSequence<std::vector<int>>, ++ UnorderedSequence<UnorderedSequence<int>>, ++ UnorderedSequence<TypeErasedSet<int>>, TypeErasedSet<std::vector<int>>, ++ TypeErasedSet<UnorderedSequence<int>>, TypeErasedSet<TypeErasedSet<int>>>; ++INSTANTIATE_TYPED_TEST_SUITE_P(My, HashValueNestedSequenceTest, ++ NestedIntSequenceTypes); ++ ++template <typename T> ++class HashValueAssociativeMapTest : public testing::Test {}; ++TYPED_TEST_SUITE_P(HashValueAssociativeMapTest); ++ ++TYPED_TEST_P(HashValueAssociativeMapTest, BasicUsage) { ++ using M = TypeParam; ++ using V = typename M::value_type; ++ std::vector<M> exemplars{M{}, ++ M{V{0, "foo"}}, ++ M{V{1, "foo"}}, ++ M{V{0, "bar"}}, ++ M{V{1, "bar"}}, ++ M{V{0, "foo"}, V{42, "bar"}}, ++ M{V{42, "bar"}, V{0, "foo"}}, ++ M{V{1, "foo"}, V{42, "bar"}}, ++ M{V{1, "foo"}, V{43, "bar"}}, ++ M{V{1, "foo"}, V{43, "baz"}}}; ++ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(exemplars)); ++} ++ ++REGISTER_TYPED_TEST_SUITE_P(HashValueAssociativeMapTest, BasicUsage); ++using AssociativeMapTypes = testing::Types< ++ std::map<int, std::string>, std::unordered_map<int, std::string>, ++ absl::flat_hash_map<int, std::string>, ++ absl::node_hash_map<int, std::string>, absl::btree_map<int, std::string>, ++ UnorderedSequence<std::pair<const int, std::string>>>; ++INSTANTIATE_TYPED_TEST_SUITE_P(My, HashValueAssociativeMapTest, ++ AssociativeMapTypes); ++ ++template <typename T> ++class HashValueAssociativeMultimapTest : public testing::Test {}; ++TYPED_TEST_SUITE_P(HashValueAssociativeMultimapTest); ++ ++TYPED_TEST_P(HashValueAssociativeMultimapTest, BasicUsage) { ++ using MM = TypeParam; ++ using V = typename MM::value_type; ++ std::vector<MM> exemplars{MM{}, ++ MM{V{0, "foo"}}, ++ MM{V{1, "foo"}}, ++ MM{V{0, "bar"}}, ++ MM{V{1, "bar"}}, ++ MM{V{0, "foo"}, V{0, "bar"}}, ++ MM{V{0, "bar"}, V{0, "foo"}}, ++ MM{V{0, "foo"}, V{42, "bar"}}, ++ MM{V{1, "foo"}, V{42, "bar"}}, ++ MM{V{1, "foo"}, V{1, "foo"}, V{43, "bar"}}, ++ MM{V{1, "foo"}, V{43, "bar"}, V{1, "foo"}}, ++ MM{V{1, "foo"}, V{43, "baz"}}}; ++ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(exemplars)); ++} ++ ++REGISTER_TYPED_TEST_SUITE_P(HashValueAssociativeMultimapTest, BasicUsage); ++using AssociativeMultimapTypes = ++ testing::Types<std::multimap<int, std::string>, ++ std::unordered_multimap<int, std::string>>; ++INSTANTIATE_TYPED_TEST_SUITE_P(My, HashValueAssociativeMultimapTest, ++ AssociativeMultimapTypes); ++ ++} // namespace +--- a/absl/hash/hash_test.cc ++++ b/absl/hash/hash_test.cc +@@ -47,6 +47,7 @@ + #include "absl/container/node_hash_map.h" + #include "absl/container/node_hash_set.h" + #include "absl/hash/hash_testing.h" ++#include "absl/hash/internal/hash_test.h" + #include "absl/hash/internal/spy_hash_state.h" + #include "absl/meta/type_traits.h" + #include "absl/numeric/int128.h" +@@ -54,52 +55,9 @@ + + namespace { + +-// Utility wrapper of T for the purposes of testing the `AbslHash` type erasure +-// mechanism. `TypeErasedValue<T>` can be constructed with a `T`, and can +-// be compared and hashed. However, all hashing goes through the hashing +-// type-erasure framework. +-template <typename T> +-class TypeErasedValue { +- public: +- TypeErasedValue() = default; +- TypeErasedValue(const TypeErasedValue&) = default; +- TypeErasedValue(TypeErasedValue&&) = default; +- explicit TypeErasedValue(const T& n) : n_(n) {} +- +- template <typename H> +- friend H AbslHashValue(H hash_state, const TypeErasedValue& v) { +- v.HashValue(absl::HashState::Create(&hash_state)); +- return hash_state; +- } +- +- void HashValue(absl::HashState state) const { +- absl::HashState::combine(std::move(state), n_); +- } +- +- bool operator==(const TypeErasedValue& rhs) const { return n_ == rhs.n_; } +- bool operator!=(const TypeErasedValue& rhs) const { return !(*this == rhs); } +- +- private: +- T n_; +-}; +- +-// A TypeErasedValue refinement, for containers. It exposes the wrapped +-// `value_type` and is constructible from an initializer list. +-template <typename T> +-class TypeErasedContainer : public TypeErasedValue<T> { +- public: +- using value_type = typename T::value_type; +- TypeErasedContainer() = default; +- TypeErasedContainer(const TypeErasedContainer&) = default; +- TypeErasedContainer(TypeErasedContainer&&) = default; +- explicit TypeErasedContainer(const T& n) : TypeErasedValue<T>(n) {} +- TypeErasedContainer(std::initializer_list<value_type> init_list) +- : TypeErasedContainer(T(init_list.begin(), init_list.end())) {} +- // one-argument constructor of value type T, to appease older toolchains that +- // get confused by one-element initializer lists in some contexts +- explicit TypeErasedContainer(const value_type& v) +- : TypeErasedContainer(T(&v, &v + 1)) {} +-}; ++using ::absl::hash_test_internal::is_hashable; ++using ::absl::hash_test_internal::TypeErasedContainer; ++using ::absl::hash_test_internal::TypeErasedValue; + + template <typename T> + using TypeErasedVector = TypeErasedContainer<std::vector<T>>; +@@ -117,11 +75,6 @@ + return SpyHashState::combine(SpyHashState(), value); + } + +-// Helper trait to verify if T is hashable. We use absl::Hash's poison status to +-// detect it. +-template <typename T> +-using is_hashable = std::is_default_constructible<absl::Hash<T>>; +- + TYPED_TEST_P(HashValueIntTest, BasicUsage) { + EXPECT_TRUE((is_hashable<TypeParam>::value)); + +@@ -520,121 +473,6 @@ + std::bitset<kNumBits>(bit_strings[5].c_str())})); + } // namespace + +-// Dummy type with unordered equality and hashing semantics. This preserves +-// input order internally, and is used below to ensure we get test coverage +-// for equal sequences with different iteraton orders. +-template <typename T> +-class UnorderedSequence { +- public: +- UnorderedSequence() = default; +- template <typename TT> +- UnorderedSequence(std::initializer_list<TT> l) +- : values_(l.begin(), l.end()) {} +- template <typename ForwardIterator, +- typename std::enable_if<!std::is_integral<ForwardIterator>::value, +- bool>::type = true> +- UnorderedSequence(ForwardIterator begin, ForwardIterator end) +- : values_(begin, end) {} +- // one-argument constructor of value type T, to appease older toolchains that +- // get confused by one-element initializer lists in some contexts +- explicit UnorderedSequence(const T& v) : values_(&v, &v + 1) {} +- +- using value_type = T; +- +- size_t size() const { return values_.size(); } +- typename std::vector<T>::const_iterator begin() const { +- return values_.begin(); +- } +- typename std::vector<T>::const_iterator end() const { return values_.end(); } +- +- friend bool operator==(const UnorderedSequence& lhs, +- const UnorderedSequence& rhs) { +- return lhs.size() == rhs.size() && +- std::is_permutation(lhs.begin(), lhs.end(), rhs.begin()); +- } +- friend bool operator!=(const UnorderedSequence& lhs, +- const UnorderedSequence& rhs) { +- return !(lhs == rhs); +- } +- template <typename H> +- friend H AbslHashValue(H h, const UnorderedSequence& u) { +- return H::combine(H::combine_unordered(std::move(h), u.begin(), u.end()), +- u.size()); +- } +- +- private: +- std::vector<T> values_; +-}; +- +-template <typename T> +-class HashValueSequenceTest : public testing::Test { +-}; +-TYPED_TEST_SUITE_P(HashValueSequenceTest); +- +-TYPED_TEST_P(HashValueSequenceTest, BasicUsage) { +- EXPECT_TRUE((is_hashable<TypeParam>::value)); +- +- using IntType = typename TypeParam::value_type; +- auto a = static_cast<IntType>(0); +- auto b = static_cast<IntType>(23); +- auto c = static_cast<IntType>(42); +- +- std::vector<TypeParam> exemplars = { +- TypeParam(), TypeParam(), TypeParam{a, b, c}, +- TypeParam{a, c, b}, TypeParam{c, a, b}, TypeParam{a}, +- TypeParam{a, a}, TypeParam{a, a, a}, TypeParam{a, a, b}, +- TypeParam{a, b, a}, TypeParam{b, a, a}, TypeParam{a, b}, +- TypeParam{b, c}}; +- EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(exemplars)); +-} +- +-REGISTER_TYPED_TEST_SUITE_P(HashValueSequenceTest, BasicUsage); +-using IntSequenceTypes = testing::Types< +- std::deque<int>, std::forward_list<int>, std::list<int>, std::vector<int>, +- std::vector<bool>, TypeErasedContainer<std::vector<int>>, std::set<int>, +- std::multiset<int>, UnorderedSequence<int>, +- TypeErasedContainer<UnorderedSequence<int>>, std::unordered_set<int>, +- std::unordered_multiset<int>, absl::flat_hash_set<int>, +- absl::node_hash_set<int>, absl::btree_set<int>>; +-INSTANTIATE_TYPED_TEST_SUITE_P(My, HashValueSequenceTest, IntSequenceTypes); +- +-template <typename T> +-class HashValueNestedSequenceTest : public testing::Test {}; +-TYPED_TEST_SUITE_P(HashValueNestedSequenceTest); +- +-TYPED_TEST_P(HashValueNestedSequenceTest, BasicUsage) { +- using T = TypeParam; +- using V = typename T::value_type; +- std::vector<T> exemplars = { +- // empty case +- T{}, +- // sets of empty sets +- T{V{}}, T{V{}, V{}}, T{V{}, V{}, V{}}, +- // multisets of different values +- T{V{1}}, T{V{1, 1}, V{1, 1}}, T{V{1, 1, 1}, V{1, 1, 1}, V{1, 1, 1}}, +- // various orderings of same nested sets +- T{V{}, V{1, 2}}, T{V{}, V{2, 1}}, T{V{1, 2}, V{}}, T{V{2, 1}, V{}}, +- // various orderings of various nested sets, case 2 +- T{V{1, 2}, V{3, 4}}, T{V{1, 2}, V{4, 3}}, T{V{1, 3}, V{2, 4}}, +- T{V{1, 3}, V{4, 2}}, T{V{1, 4}, V{2, 3}}, T{V{1, 4}, V{3, 2}}, +- T{V{2, 3}, V{1, 4}}, T{V{2, 3}, V{4, 1}}, T{V{2, 4}, V{1, 3}}, +- T{V{2, 4}, V{3, 1}}, T{V{3, 4}, V{1, 2}}, T{V{3, 4}, V{2, 1}}}; +- EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(exemplars)); +-} +- +-REGISTER_TYPED_TEST_SUITE_P(HashValueNestedSequenceTest, BasicUsage); +-template <typename T> +-using TypeErasedSet = TypeErasedContainer<UnorderedSequence<T>>; +- +-using NestedIntSequenceTypes = testing::Types< +- std::vector<std::vector<int>>, std::vector<UnorderedSequence<int>>, +- std::vector<TypeErasedSet<int>>, UnorderedSequence<std::vector<int>>, +- UnorderedSequence<UnorderedSequence<int>>, +- UnorderedSequence<TypeErasedSet<int>>, TypeErasedSet<std::vector<int>>, +- TypeErasedSet<UnorderedSequence<int>>, TypeErasedSet<TypeErasedSet<int>>>; +-INSTANTIATE_TYPED_TEST_SUITE_P(My, HashValueNestedSequenceTest, +- NestedIntSequenceTypes); +- + // Private type that only supports AbslHashValue to make sure our chosen hash + // implementation is recursive within absl::Hash. + // It uses std::abs() on the value to provide different bitwise representations +@@ -793,64 +631,6 @@ + #endif + } + +-template <typename T> +-class HashValueAssociativeMapTest : public testing::Test {}; +-TYPED_TEST_SUITE_P(HashValueAssociativeMapTest); +- +-TYPED_TEST_P(HashValueAssociativeMapTest, BasicUsage) { +- using M = TypeParam; +- using V = typename M::value_type; +- std::vector<M> exemplars{M{}, +- M{V{0, "foo"}}, +- M{V{1, "foo"}}, +- M{V{0, "bar"}}, +- M{V{1, "bar"}}, +- M{V{0, "foo"}, V{42, "bar"}}, +- M{V{42, "bar"}, V{0, "foo"}}, +- M{V{1, "foo"}, V{42, "bar"}}, +- M{V{1, "foo"}, V{43, "bar"}}, +- M{V{1, "foo"}, V{43, "baz"}}}; +- EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(exemplars)); +-} +- +-REGISTER_TYPED_TEST_SUITE_P(HashValueAssociativeMapTest, BasicUsage); +-using AssociativeMapTypes = testing::Types< +- std::map<int, std::string>, std::unordered_map<int, std::string>, +- absl::flat_hash_map<int, std::string>, +- absl::node_hash_map<int, std::string>, absl::btree_map<int, std::string>, +- UnorderedSequence<std::pair<const int, std::string>>>; +-INSTANTIATE_TYPED_TEST_SUITE_P(My, HashValueAssociativeMapTest, +- AssociativeMapTypes); +- +-template <typename T> +-class HashValueAssociativeMultimapTest : public testing::Test {}; +-TYPED_TEST_SUITE_P(HashValueAssociativeMultimapTest); +- +-TYPED_TEST_P(HashValueAssociativeMultimapTest, BasicUsage) { +- using MM = TypeParam; +- using V = typename MM::value_type; +- std::vector<MM> exemplars{MM{}, +- MM{V{0, "foo"}}, +- MM{V{1, "foo"}}, +- MM{V{0, "bar"}}, +- MM{V{1, "bar"}}, +- MM{V{0, "foo"}, V{0, "bar"}}, +- MM{V{0, "bar"}, V{0, "foo"}}, +- MM{V{0, "foo"}, V{42, "bar"}}, +- MM{V{1, "foo"}, V{42, "bar"}}, +- MM{V{1, "foo"}, V{1, "foo"}, V{43, "bar"}}, +- MM{V{1, "foo"}, V{43, "bar"}, V{1, "foo"}}, +- MM{V{1, "foo"}, V{43, "baz"}}}; +- EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(exemplars)); +-} +- +-REGISTER_TYPED_TEST_SUITE_P(HashValueAssociativeMultimapTest, BasicUsage); +-using AssociativeMultimapTypes = +- testing::Types<std::multimap<int, std::string>, +- std::unordered_multimap<int, std::string>>; +-INSTANTIATE_TYPED_TEST_SUITE_P(My, HashValueAssociativeMultimapTest, +- AssociativeMultimapTypes); +- + TEST(HashValueTest, ReferenceWrapper) { + EXPECT_TRUE(is_hashable<std::reference_wrapper<Private>>::value); + +--- /dev/null ++++ b/absl/hash/internal/hash_test.h +@@ -0,0 +1,87 @@ ++// Copyright 2023 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 ++// ++// https://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. ++ ++// Common code shared between absl/hash/hash_test.cc and ++// absl/hash/hash_instantiated_test.cc. ++ ++#ifndef ABSL_HASH_INTERNAL_HASH_TEST_H_ ++#define ABSL_HASH_INTERNAL_HASH_TEST_H_ ++ ++#include <type_traits> ++#include <utility> ++ ++#include "absl/base/config.h" ++#include "absl/hash/hash.h" ++ ++namespace absl { ++ABSL_NAMESPACE_BEGIN ++namespace hash_test_internal { ++ ++// Utility wrapper of T for the purposes of testing the `AbslHash` type erasure ++// mechanism. `TypeErasedValue<T>` can be constructed with a `T`, and can ++// be compared and hashed. However, all hashing goes through the hashing ++// type-erasure framework. ++template <typename T> ++class TypeErasedValue { ++ public: ++ TypeErasedValue() = default; ++ TypeErasedValue(const TypeErasedValue&) = default; ++ TypeErasedValue(TypeErasedValue&&) = default; ++ explicit TypeErasedValue(const T& n) : n_(n) {} ++ ++ template <typename H> ++ friend H AbslHashValue(H hash_state, const TypeErasedValue& v) { ++ v.HashValue(absl::HashState::Create(&hash_state)); ++ return hash_state; ++ } ++ ++ void HashValue(absl::HashState state) const { ++ absl::HashState::combine(std::move(state), n_); ++ } ++ ++ bool operator==(const TypeErasedValue& rhs) const { return n_ == rhs.n_; } ++ bool operator!=(const TypeErasedValue& rhs) const { return !(*this == rhs); } ++ ++ private: ++ T n_; ++}; ++ ++// A TypeErasedValue refinement, for containers. It exposes the wrapped ++// `value_type` and is constructible from an initializer list. ++template <typename T> ++class TypeErasedContainer : public TypeErasedValue<T> { ++ public: ++ using value_type = typename T::value_type; ++ TypeErasedContainer() = default; ++ TypeErasedContainer(const TypeErasedContainer&) = default; ++ TypeErasedContainer(TypeErasedContainer&&) = default; ++ explicit TypeErasedContainer(const T& n) : TypeErasedValue<T>(n) {} ++ TypeErasedContainer(std::initializer_list<value_type> init_list) ++ : TypeErasedContainer(T(init_list.begin(), init_list.end())) {} ++ // one-argument constructor of value type T, to appease older toolchains that ++ // get confused by one-element initializer lists in some contexts ++ explicit TypeErasedContainer(const value_type& v) ++ : TypeErasedContainer(T(&v, &v + 1)) {} ++}; ++ ++// Helper trait to verify if T is hashable. We use absl::Hash's poison status to ++// detect it. ++template <typename T> ++using is_hashable = std::is_default_constructible<absl::Hash<T>>; ++ ++} // namespace hash_test_internal ++ABSL_NAMESPACE_END ++} // namespace absl ++ ++#endif // ABSL_HASH_INTERNAL_HASH_TEST_H_ |