File indexing completed on 2025-01-18 09:27:18
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #ifndef ABSL_HASH_HASH_TESTING_H_
0016 #define ABSL_HASH_HASH_TESTING_H_
0017
0018 #include <initializer_list>
0019 #include <tuple>
0020 #include <type_traits>
0021 #include <vector>
0022
0023 #include "gmock/gmock.h"
0024 #include "gtest/gtest.h"
0025 #include "absl/hash/internal/spy_hash_state.h"
0026 #include "absl/meta/type_traits.h"
0027 #include "absl/strings/str_cat.h"
0028 #include "absl/types/variant.h"
0029
0030 namespace absl {
0031 ABSL_NAMESPACE_BEGIN
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143 template <int&... ExplicitBarrier, typename Container>
0144 ABSL_MUST_USE_RESULT testing::AssertionResult
0145 VerifyTypeImplementsAbslHashCorrectly(const Container& values);
0146
0147 template <int&... ExplicitBarrier, typename Container, typename Eq>
0148 ABSL_MUST_USE_RESULT testing::AssertionResult
0149 VerifyTypeImplementsAbslHashCorrectly(const Container& values, Eq equals);
0150
0151 template <int&..., typename T>
0152 ABSL_MUST_USE_RESULT testing::AssertionResult
0153 VerifyTypeImplementsAbslHashCorrectly(std::initializer_list<T> values);
0154
0155 template <int&..., typename T, typename Eq>
0156 ABSL_MUST_USE_RESULT testing::AssertionResult
0157 VerifyTypeImplementsAbslHashCorrectly(std::initializer_list<T> values,
0158 Eq equals);
0159
0160 namespace hash_internal {
0161
0162 struct PrintVisitor {
0163 size_t index;
0164 template <typename T>
0165 std::string operator()(const T* value) const {
0166 return absl::StrCat("#", index, "(", testing::PrintToString(*value), ")");
0167 }
0168 };
0169
0170 template <typename Eq>
0171 struct EqVisitor {
0172 Eq eq;
0173 template <typename T, typename U>
0174 bool operator()(const T* t, const U* u) const {
0175 return eq(*t, *u);
0176 }
0177 };
0178
0179 struct ExpandVisitor {
0180 template <typename T>
0181 SpyHashState operator()(const T* value) const {
0182 return SpyHashState::combine(SpyHashState(), *value);
0183 }
0184 };
0185
0186 template <typename Container, typename Eq>
0187 ABSL_MUST_USE_RESULT testing::AssertionResult
0188 VerifyTypeImplementsAbslHashCorrectly(const Container& values, Eq equals) {
0189 using V = typename Container::value_type;
0190
0191 struct Info {
0192 const V& value;
0193 size_t index;
0194 std::string ToString() const {
0195 return absl::visit(PrintVisitor{index}, value);
0196 }
0197 SpyHashState expand() const { return absl::visit(ExpandVisitor{}, value); }
0198 };
0199
0200 using EqClass = std::vector<Info>;
0201 std::vector<EqClass> classes;
0202
0203
0204 size_t i = 0;
0205 for (const auto& value : values) {
0206 EqClass* c = nullptr;
0207 for (auto& eqclass : classes) {
0208 if (absl::visit(EqVisitor<Eq>{equals}, value, eqclass[0].value)) {
0209 c = &eqclass;
0210 break;
0211 }
0212 }
0213 if (c == nullptr) {
0214 classes.emplace_back();
0215 c = &classes.back();
0216 }
0217 c->push_back({value, i});
0218 ++i;
0219
0220
0221 if (auto error = c->back().expand().error()) {
0222 return testing::AssertionFailure() << *error;
0223 }
0224 }
0225
0226 if (classes.size() < 2) {
0227 return testing::AssertionFailure()
0228 << "At least two equivalence classes are expected.";
0229 }
0230
0231
0232
0233
0234 for (const auto& c : classes) {
0235
0236
0237 const SpyHashState expected = c[0].expand();
0238 for (const Info& v : c) {
0239 if (v.expand() != v.expand()) {
0240 return testing::AssertionFailure()
0241 << "Hash expansion for " << v.ToString()
0242 << " is non-deterministic.";
0243 }
0244 if (v.expand() != expected) {
0245 return testing::AssertionFailure()
0246 << "Values " << c[0].ToString() << " and " << v.ToString()
0247 << " evaluate as equal but have an unequal hash expansion.";
0248 }
0249 }
0250
0251
0252 for (const auto& c2 : classes) {
0253 if (&c == &c2) continue;
0254 const SpyHashState c2_hash = c2[0].expand();
0255 switch (SpyHashState::Compare(expected, c2_hash)) {
0256 case SpyHashState::CompareResult::kEqual:
0257 return testing::AssertionFailure()
0258 << "Values " << c[0].ToString() << " and " << c2[0].ToString()
0259 << " evaluate as unequal but have an equal hash expansion.";
0260 case SpyHashState::CompareResult::kBSuffixA:
0261 return testing::AssertionFailure()
0262 << "Hash expansion of " << c2[0].ToString()
0263 << " is a suffix of the hash expansion of " << c[0].ToString()
0264 << ".";
0265 case SpyHashState::CompareResult::kASuffixB:
0266 return testing::AssertionFailure()
0267 << "Hash expansion of " << c[0].ToString()
0268 << " is a suffix of the hash expansion of " << c2[0].ToString()
0269 << ".";
0270 case SpyHashState::CompareResult::kUnequal:
0271 break;
0272 }
0273 }
0274 }
0275 return testing::AssertionSuccess();
0276 }
0277
0278 template <typename... T>
0279 struct TypeSet {
0280 template <typename U, bool = disjunction<std::is_same<T, U>...>::value>
0281 struct Insert {
0282 using type = TypeSet<U, T...>;
0283 };
0284 template <typename U>
0285 struct Insert<U, true> {
0286 using type = TypeSet;
0287 };
0288
0289 template <template <typename...> class C>
0290 using apply = C<T...>;
0291 };
0292
0293 template <typename... T>
0294 struct MakeTypeSet : TypeSet<> {};
0295 template <typename T, typename... Ts>
0296 struct MakeTypeSet<T, Ts...> : MakeTypeSet<Ts...>::template Insert<T>::type {};
0297
0298 template <typename... T>
0299 using VariantForTypes = typename MakeTypeSet<
0300 const typename std::decay<T>::type*...>::template apply<absl::variant>;
0301
0302 template <typename Container>
0303 struct ContainerAsVector {
0304 using V = absl::variant<const typename Container::value_type*>;
0305 using Out = std::vector<V>;
0306
0307 static Out Do(const Container& values) {
0308 Out out;
0309 for (const auto& v : values) out.push_back(&v);
0310 return out;
0311 }
0312 };
0313
0314 template <typename... T>
0315 struct ContainerAsVector<std::tuple<T...>> {
0316 using V = VariantForTypes<T...>;
0317 using Out = std::vector<V>;
0318
0319 template <size_t... I>
0320 static Out DoImpl(const std::tuple<T...>& tuple, absl::index_sequence<I...>) {
0321 return Out{&std::get<I>(tuple)...};
0322 }
0323
0324 static Out Do(const std::tuple<T...>& values) {
0325 return DoImpl(values, absl::index_sequence_for<T...>());
0326 }
0327 };
0328
0329 template <>
0330 struct ContainerAsVector<std::tuple<>> {
0331 static std::vector<VariantForTypes<int>> Do(std::tuple<>) { return {}; }
0332 };
0333
0334 struct DefaultEquals {
0335 template <typename T, typename U>
0336 bool operator()(const T& t, const U& u) const {
0337 return t == u;
0338 }
0339 };
0340
0341 }
0342
0343 template <int&..., typename Container>
0344 ABSL_MUST_USE_RESULT testing::AssertionResult
0345 VerifyTypeImplementsAbslHashCorrectly(const Container& values) {
0346 return hash_internal::VerifyTypeImplementsAbslHashCorrectly(
0347 hash_internal::ContainerAsVector<Container>::Do(values),
0348 hash_internal::DefaultEquals{});
0349 }
0350
0351 template <int&..., typename Container, typename Eq>
0352 ABSL_MUST_USE_RESULT testing::AssertionResult
0353 VerifyTypeImplementsAbslHashCorrectly(const Container& values, Eq equals) {
0354 return hash_internal::VerifyTypeImplementsAbslHashCorrectly(
0355 hash_internal::ContainerAsVector<Container>::Do(values), equals);
0356 }
0357
0358 template <int&..., typename T>
0359 ABSL_MUST_USE_RESULT testing::AssertionResult
0360 VerifyTypeImplementsAbslHashCorrectly(std::initializer_list<T> values) {
0361 return hash_internal::VerifyTypeImplementsAbslHashCorrectly(
0362 hash_internal::ContainerAsVector<std::initializer_list<T>>::Do(values),
0363 hash_internal::DefaultEquals{});
0364 }
0365
0366 template <int&..., typename T, typename Eq>
0367 ABSL_MUST_USE_RESULT testing::AssertionResult
0368 VerifyTypeImplementsAbslHashCorrectly(std::initializer_list<T> values,
0369 Eq equals) {
0370 return hash_internal::VerifyTypeImplementsAbslHashCorrectly(
0371 hash_internal::ContainerAsVector<std::initializer_list<T>>::Do(values),
0372 equals);
0373 }
0374
0375 ABSL_NAMESPACE_END
0376 }
0377
0378 #endif