xref: /aosp_15_r20/external/cronet/third_party/libc++/src/test/support/poisoned_hash_helper.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // -*- C++ -*-
2 //===----------------------------------------------------------------------===//
3 //
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #ifndef SUPPORT_POISONED_HASH_HELPER_H
11 #define SUPPORT_POISONED_HASH_HELPER_H
12 
13 #include <cassert>
14 #include <cstddef>
15 #include <type_traits>
16 #include <utility>
17 
18 #include "test_macros.h"
19 #include "test_workarounds.h"
20 
21 #if TEST_STD_VER < 11
22 #error this header may only be used in C++11 or newer
23 #endif
24 
25 template <class ...Args> struct TypeList;
26 
27 // Test that the specified Hash meets the requirements of an enabled hash
28 template <class Hash, class Key, class InputKey = Key>
29 TEST_CONSTEXPR_CXX20 void test_hash_enabled(InputKey const& key = InputKey{});
30 
31 template <class T, class InputKey = T>
32 TEST_CONSTEXPR_CXX20 void test_hash_enabled_for_type(InputKey const& key = InputKey{}) {
33   return test_hash_enabled<std::hash<T>, T, InputKey>(key);
34 }
35 
36 // Test that the specified Hash meets the requirements of a disabled hash.
37 template <class Hash, class Key>
38 void test_hash_disabled();
39 
40 template <class T>
test_hash_disabled_for_type()41 void test_hash_disabled_for_type() {
42   return test_hash_disabled<std::hash<T>, T>();
43 }
44 
45 namespace PoisonedHashDetail {
46   enum Enum {};
47   enum EnumClass : bool {};
48   struct Class {};
49 }
50 
51 // Each header that declares the template hash provides enabled
52 // specializations of hash for nullptr t and all cv-unqualified
53 // arithmetic, enumeration, and pointer types.
54 using LibraryHashTypes = TypeList<
55 #if TEST_STD_VER > 14
56       decltype(nullptr),
57 #endif
58       bool,
59       char,
60       signed char,
61       unsigned char,
62 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
63       wchar_t,
64 #endif
65       char16_t,
66       char32_t,
67       short,
68       unsigned short,
69       int,
70       unsigned int,
71       long,
72       unsigned long,
73       long long,
74       unsigned long long,
75 #ifndef TEST_HAS_NO_INT128
76       __int128_t,
77       __uint128_t,
78 #endif
79       float,
80       double,
81       long double,
82       PoisonedHashDetail::Enum,
83       PoisonedHashDetail::EnumClass,
84       void*,
85       void const*,
86       PoisonedHashDetail::Class*
87     >;
88 
89 
90 // Test that each of the library hash specializations for  arithmetic types,
91 // enum types, and pointer types are available and enabled.
92 template <class Types = LibraryHashTypes>
93 void test_library_hash_specializations_available(Types = Types{});
94 
95 
96 namespace PoisonedHashDetail {
97 
98 template <class T, class = typename T::foo_bar_baz>
instantiate(int)99 constexpr bool instantiate(int) { return true; }
instantiate(long)100 template <class> constexpr bool instantiate(long) { return true; }
instantiate()101 template <class T> constexpr bool instantiate() { return instantiate<T>(0); }
102 
103 template <class To>
104 struct ConvertibleToSimple {
ToConvertibleToSimple105   operator To() const {
106     return To{};
107   }
108 };
109 
110 template <class To>
111 struct ConvertibleTo {
112   To to{};
113   operator To&() & { return to; }
114   operator To const&() const & { return to; }
115   operator To&&() && { return std::move(to); }
116   operator To const&&() const && { return std::move(to); }
117 };
118 
119 template <class Hasher, class Key, class Res = decltype(std::declval<Hasher&>()(std::declval<Key>()))>
can_hash(int)120 constexpr bool can_hash(int) {
121   return std::is_same<Res, std::size_t>::value;
122 }
123 template <class, class>
can_hash(long)124 constexpr bool can_hash(long) {
125   return false;
126 }
127 template <class Hasher, class Key>
can_hash()128 constexpr bool can_hash() {
129   return can_hash<Hasher, Key>(0);
130 }
131 } // namespace PoisonedHashDetail
132 
133 template <class Hash, class Key, class InputKey>
test_hash_enabled(InputKey const & key)134 TEST_CONSTEXPR_CXX20 void test_hash_enabled(InputKey const& key) {
135   using namespace PoisonedHashDetail;
136 
137   static_assert(std::is_destructible<Hash>::value, "");
138   // Enabled hash requirements
139   static_assert(std::is_default_constructible<Hash>::value, "");
140   static_assert(std::is_copy_constructible<Hash>::value, "");
141   static_assert(std::is_move_constructible<Hash>::value, "");
142   static_assert(std::is_copy_assignable<Hash>::value, "");
143   static_assert(std::is_move_assignable<Hash>::value, "");
144 
145 #if TEST_STD_VER > 14
146   static_assert(std::is_swappable<Hash>::value, "");
147 #elif defined(_LIBCPP_VERSION)
148   static_assert(std::__is_swappable<Hash>::value, "");
149 #endif
150 
151   // Hashable requirements
152   static_assert(can_hash<Hash, Key&>(), "");
153   static_assert(can_hash<Hash, Key const&>(), "");
154   static_assert(can_hash<Hash, Key&&>(), "");
155   static_assert(can_hash<Hash const, Key&>(), "");
156   static_assert(can_hash<Hash const, Key const&>(), "");
157   static_assert(can_hash<Hash const, Key&&>(), "");
158 
159   static_assert(can_hash<Hash, ConvertibleToSimple<Key>&>(), "");
160   static_assert(can_hash<Hash, ConvertibleToSimple<Key> const&>(), "");
161   static_assert(can_hash<Hash, ConvertibleToSimple<Key>&&>(), "");
162 
163   static_assert(can_hash<Hash, ConvertibleTo<Key>&>(), "");
164   static_assert(can_hash<Hash, ConvertibleTo<Key> const&>(), "");
165   static_assert(can_hash<Hash, ConvertibleTo<Key>&&>(), "");
166   static_assert(can_hash<Hash, ConvertibleTo<Key> const&&>(), "");
167 
168   const Hash h{};
169   assert(h(key) == h(key));
170 
171 }
172 
173 template <class Hash, class Key>
test_hash_disabled()174 void test_hash_disabled() {
175   using namespace PoisonedHashDetail;
176 
177   // Disabled hash requirements
178   static_assert(!std::is_default_constructible<Hash>::value, "");
179   static_assert(!std::is_copy_constructible<Hash>::value, "");
180   static_assert(!std::is_move_constructible<Hash>::value, "");
181   static_assert(!std::is_copy_assignable<Hash>::value, "");
182   static_assert(!std::is_move_assignable<Hash>::value, "");
183 
184   static_assert(!std::is_function<
185       typename std::remove_pointer<
186           typename std::remove_reference<Hash>::type
187       >::type
188     >::value, "");
189 
190   // Hashable requirements
191   static_assert(!can_hash<Hash, Key&>(), "");
192   static_assert(!can_hash<Hash, Key const&>(), "");
193   static_assert(!can_hash<Hash, Key&&>(), "");
194   static_assert(!can_hash<Hash const, Key&>(), "");
195   static_assert(!can_hash<Hash const, Key const&>(), "");
196   static_assert(!can_hash<Hash const, Key&&>(), "");
197 
198   static_assert(!can_hash<Hash, ConvertibleToSimple<Key>&>(), "");
199   static_assert(!can_hash<Hash, ConvertibleToSimple<Key> const&>(), "");
200   static_assert(!can_hash<Hash, ConvertibleToSimple<Key>&&>(), "");
201 
202   static_assert(!can_hash<Hash, ConvertibleTo<Key>&>(), "");
203   static_assert(!can_hash<Hash, ConvertibleTo<Key> const&>(), "");
204   static_assert(!can_hash<Hash, ConvertibleTo<Key>&&>(), "");
205   static_assert(!can_hash<Hash, ConvertibleTo<Key> const&&>(), "");
206 }
207 
208 
209 template <class First, class ...Rest>
210 struct TypeList<First, Rest...> {
211   template <template <class> class Trait, bool Expect = true>
212   static constexpr bool assertTrait() {
213     static_assert(Trait<First>::value == Expect, "");
214     return TypeList<Rest...>::template assertTrait<Trait, Expect>();
215   }
216 
217   template <class Trait>
218   static void applyTrait() {
219     Trait::template apply<First>();
220     TypeList<Rest...>::template applyTrait<Trait>();
221   }
222 };
223 
224 template <>
225 struct TypeList<> {
226   template <template <class> class Trait, bool Expect = true>
227   static constexpr bool assertTrait() {
228     return true;
229   }
230   template <class Trait>
231   static void applyTrait() {}
232 };
233 
234 
235 struct TestLibraryTrait {
236     template <class Type>
237     static void apply() { test_hash_enabled<std::hash<Type>, Type>(); }
238 };
239 
240 template <class Types>
241 void test_library_hash_specializations_available(Types) {
242   Types::template applyTrait<TestLibraryTrait >();
243 }
244 
245 #endif // SUPPORT_POISONED_HASH_HELPER_H
246