• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 // -----------------------------------------------------------------------------
16 // conformance_profiles.h
17 // -----------------------------------------------------------------------------
18 //
19 // This file contains templates for representing "Regularity Profiles" and
20 // concisely-named versions of commonly used Regularity Profiles.
21 //
22 // A Regularity Profile is a compile-time description of the types of operations
23 // that a given type supports, along with properties of those operations when
24 // they do exist. For instance, a Regularity Profile may describe a type that
25 // has a move-constructor that is noexcept and a copy constructor that is not
26 // noexcept. This description can then be examined and passed around to other
27 // templates for the purposes of asserting expectations on user-defined types
28 // via a series trait checks, or for determining what kinds of run-time tests
29 // are able to be performed.
30 //
31 // Regularity Profiles are also used when creating "archetypes," which are
32 // minimum-conforming types that meet all of the requirements of a given
33 // Regularity Profile. For more information regarding archetypes, see
34 // "conformance_archetypes.h".
35 
36 #ifndef ABSL_TYPES_INTERNAL_CONFORMANCE_PROFILE_H_
37 #define ABSL_TYPES_INTERNAL_CONFORMANCE_PROFILE_H_
38 
39 #include <type_traits>
40 #include <utility>
41 
42 #include "absl/meta/type_traits.h"
43 
44 // TODO(calabrese) Add support for extending profiles.
45 
46 namespace absl {
47 ABSL_NAMESPACE_BEGIN
48 namespace types_internal {
49 
50 template <class T, class /*Enabler*/ = void>
51 struct PropertiesOfImpl {};
52 
53 template <class T>
54 struct PropertiesOfImpl<T, absl::void_t<typename T::properties>> {
55   using type = typename T::properties;
56 };
57 
58 template <class T>
59 struct PropertiesOfImpl<T, absl::void_t<typename T::profile_alias_of>> {
60   using type = typename PropertiesOfImpl<typename T::profile_alias_of>::type;
61 };
62 
63 template <class T>
64 struct PropertiesOf : PropertiesOfImpl<T> {};
65 
66 template <class T>
67 using PropertiesOfT = typename PropertiesOf<T>::type;
68 
69 // NOTE: These enums use this naming convention to be consistent with the
70 // standard trait names, which is useful since it allows us to match up each
71 // enum name with a corresponding trait name in macro definitions.
72 
73 enum class function_kind { maybe, yes, nothrow, trivial };
74 
75 #define ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM(name) \
76   enum class name { maybe, yes, nothrow, trivial }
77 
78 ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM(default_constructible);
79 ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM(move_constructible);
80 ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM(copy_constructible);
81 ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM(move_assignable);
82 ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM(copy_assignable);
83 ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM(destructible);
84 
85 #undef ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM
86 
87 #define ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM(name) \
88   enum class name { maybe, yes, nothrow }
89 
90 ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM(equality_comparable);
91 ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM(inequality_comparable);
92 ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM(less_than_comparable);
93 ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM(less_equal_comparable);
94 ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM(greater_equal_comparable);
95 ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM(greater_than_comparable);
96 
97 ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM(swappable);
98 
99 #undef ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM
100 
101 enum class hashable { maybe, yes };
102 
103 constexpr const char* PropertyName(hashable v) {
104   return "support for std::hash";
105 }
106 
107 template <
108     default_constructible DefaultConstructibleValue =
109         default_constructible::maybe,
110     move_constructible MoveConstructibleValue = move_constructible::maybe,
111     copy_constructible CopyConstructibleValue = copy_constructible::maybe,
112     move_assignable MoveAssignableValue = move_assignable::maybe,
113     copy_assignable CopyAssignableValue = copy_assignable::maybe,
114     destructible DestructibleValue = destructible::maybe,
115     equality_comparable EqualityComparableValue = equality_comparable::maybe,
116     inequality_comparable InequalityComparableValue =
117         inequality_comparable::maybe,
118     less_than_comparable LessThanComparableValue = less_than_comparable::maybe,
119     less_equal_comparable LessEqualComparableValue =
120         less_equal_comparable::maybe,
121     greater_equal_comparable GreaterEqualComparableValue =
122         greater_equal_comparable::maybe,
123     greater_than_comparable GreaterThanComparableValue =
124         greater_than_comparable::maybe,
125     swappable SwappableValue = swappable::maybe,
126     hashable HashableValue = hashable::maybe>
127 struct ConformanceProfile {
128   using properties = ConformanceProfile;
129 
130   static constexpr default_constructible
131       default_constructible_support =  // NOLINT
132       DefaultConstructibleValue;
133 
134   static constexpr move_constructible move_constructible_support =  // NOLINT
135       MoveConstructibleValue;
136 
137   static constexpr copy_constructible copy_constructible_support =  // NOLINT
138       CopyConstructibleValue;
139 
140   static constexpr move_assignable move_assignable_support =  // NOLINT
141       MoveAssignableValue;
142 
143   static constexpr copy_assignable copy_assignable_support =  // NOLINT
144       CopyAssignableValue;
145 
146   static constexpr destructible destructible_support =  // NOLINT
147       DestructibleValue;
148 
149   static constexpr equality_comparable equality_comparable_support =  // NOLINT
150       EqualityComparableValue;
151 
152   static constexpr inequality_comparable
153       inequality_comparable_support =  // NOLINT
154       InequalityComparableValue;
155 
156   static constexpr less_than_comparable
157       less_than_comparable_support =  // NOLINT
158       LessThanComparableValue;
159 
160   static constexpr less_equal_comparable
161       less_equal_comparable_support =  // NOLINT
162       LessEqualComparableValue;
163 
164   static constexpr greater_equal_comparable
165       greater_equal_comparable_support =  // NOLINT
166       GreaterEqualComparableValue;
167 
168   static constexpr greater_than_comparable
169       greater_than_comparable_support =  // NOLINT
170       GreaterThanComparableValue;
171 
172   static constexpr swappable swappable_support = SwappableValue;  // NOLINT
173 
174   static constexpr hashable hashable_support = HashableValue;  // NOLINT
175 
176   static constexpr bool is_default_constructible =  // NOLINT
177       DefaultConstructibleValue != default_constructible::maybe;
178 
179   static constexpr bool is_move_constructible =  // NOLINT
180       MoveConstructibleValue != move_constructible::maybe;
181 
182   static constexpr bool is_copy_constructible =  // NOLINT
183       CopyConstructibleValue != copy_constructible::maybe;
184 
185   static constexpr bool is_move_assignable =  // NOLINT
186       MoveAssignableValue != move_assignable::maybe;
187 
188   static constexpr bool is_copy_assignable =  // NOLINT
189       CopyAssignableValue != copy_assignable::maybe;
190 
191   static constexpr bool is_destructible =  // NOLINT
192       DestructibleValue != destructible::maybe;
193 
194   static constexpr bool is_equality_comparable =  // NOLINT
195       EqualityComparableValue != equality_comparable::maybe;
196 
197   static constexpr bool is_inequality_comparable =  // NOLINT
198       InequalityComparableValue != inequality_comparable::maybe;
199 
200   static constexpr bool is_less_than_comparable =  // NOLINT
201       LessThanComparableValue != less_than_comparable::maybe;
202 
203   static constexpr bool is_less_equal_comparable =  // NOLINT
204       LessEqualComparableValue != less_equal_comparable::maybe;
205 
206   static constexpr bool is_greater_equal_comparable =  // NOLINT
207       GreaterEqualComparableValue != greater_equal_comparable::maybe;
208 
209   static constexpr bool is_greater_than_comparable =  // NOLINT
210       GreaterThanComparableValue != greater_than_comparable::maybe;
211 
212   static constexpr bool is_swappable =  // NOLINT
213       SwappableValue != swappable::maybe;
214 
215   static constexpr bool is_hashable =  // NOLINT
216       HashableValue != hashable::maybe;
217 };
218 
219 #define ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF_IMPL(type, name)     \
220   template <default_constructible DefaultConstructibleValue,                   \
221             move_constructible MoveConstructibleValue,                         \
222             copy_constructible CopyConstructibleValue,                         \
223             move_assignable MoveAssignableValue,                               \
224             copy_assignable CopyAssignableValue,                               \
225             destructible DestructibleValue,                                    \
226             equality_comparable EqualityComparableValue,                       \
227             inequality_comparable InequalityComparableValue,                   \
228             less_than_comparable LessThanComparableValue,                      \
229             less_equal_comparable LessEqualComparableValue,                    \
230             greater_equal_comparable GreaterEqualComparableValue,              \
231             greater_than_comparable GreaterThanComparableValue,                \
232             swappable SwappableValue, hashable HashableValue>                  \
233   constexpr type ConformanceProfile<                                           \
234       DefaultConstructibleValue, MoveConstructibleValue,                       \
235       CopyConstructibleValue, MoveAssignableValue, CopyAssignableValue,        \
236       DestructibleValue, EqualityComparableValue, InequalityComparableValue,   \
237       LessThanComparableValue, LessEqualComparableValue,                       \
238       GreaterEqualComparableValue, GreaterThanComparableValue, SwappableValue, \
239       HashableValue>::name
240 
241 #define ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(type)           \
242   ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF_IMPL(type,            \
243                                                          type##_support); \
244   ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF_IMPL(bool, is_##type)
245 
246 ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(default_constructible);
247 ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(move_constructible);
248 ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(copy_constructible);
249 ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(move_assignable);
250 ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(copy_assignable);
251 ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(destructible);
252 ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(equality_comparable);
253 ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(inequality_comparable);
254 ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(less_than_comparable);
255 ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(less_equal_comparable);
256 ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(greater_equal_comparable);
257 ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(greater_than_comparable);
258 ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(swappable);
259 ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(hashable);
260 
261 #undef ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF
262 #undef ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF_IMPL
263 
264 // Converts an enum to its underlying integral value.
265 template <class Enum>
266 constexpr absl::underlying_type_t<Enum> UnderlyingValue(Enum value) {
267   return static_cast<absl::underlying_type_t<Enum>>(value);
268 }
269 
270 // Retrieve the enum with the greatest underlying value.
271 // Note: std::max is not constexpr in C++11, which is why this is necessary.
272 template <class H>
273 constexpr H MaxEnum(H head) {
274   return head;
275 }
276 
277 template <class H, class N, class... T>
278 constexpr H MaxEnum(H head, N next, T... tail) {
279   return (UnderlyingValue)(next) < (UnderlyingValue)(head)
280              ? (MaxEnum)(head, tail...)
281              : (MaxEnum)(next, tail...);
282 }
283 
284 template <class... Profs>
285 struct CombineProfilesImpl {
286   static constexpr default_constructible
287       default_constructible_support =  // NOLINT
288       (MaxEnum)(PropertiesOfT<Profs>::default_constructible_support...);
289 
290   static constexpr move_constructible move_constructible_support =  // NOLINT
291       (MaxEnum)(PropertiesOfT<Profs>::move_constructible_support...);
292 
293   static constexpr copy_constructible copy_constructible_support =  // NOLINT
294       (MaxEnum)(PropertiesOfT<Profs>::copy_constructible_support...);
295 
296   static constexpr move_assignable move_assignable_support =  // NOLINT
297       (MaxEnum)(PropertiesOfT<Profs>::move_assignable_support...);
298 
299   static constexpr copy_assignable copy_assignable_support =  // NOLINT
300       (MaxEnum)(PropertiesOfT<Profs>::copy_assignable_support...);
301 
302   static constexpr destructible destructible_support =  // NOLINT
303       (MaxEnum)(PropertiesOfT<Profs>::destructible_support...);
304 
305   static constexpr equality_comparable equality_comparable_support =  // NOLINT
306       (MaxEnum)(PropertiesOfT<Profs>::equality_comparable_support...);
307 
308   static constexpr inequality_comparable
309       inequality_comparable_support =  // NOLINT
310       (MaxEnum)(PropertiesOfT<Profs>::inequality_comparable_support...);
311 
312   static constexpr less_than_comparable
313       less_than_comparable_support =  // NOLINT
314       (MaxEnum)(PropertiesOfT<Profs>::less_than_comparable_support...);
315 
316   static constexpr less_equal_comparable
317       less_equal_comparable_support =  // NOLINT
318       (MaxEnum)(PropertiesOfT<Profs>::less_equal_comparable_support...);
319 
320   static constexpr greater_equal_comparable
321       greater_equal_comparable_support =  // NOLINT
322       (MaxEnum)(PropertiesOfT<Profs>::greater_equal_comparable_support...);
323 
324   static constexpr greater_than_comparable
325       greater_than_comparable_support =  // NOLINT
326       (MaxEnum)(PropertiesOfT<Profs>::greater_than_comparable_support...);
327 
328   static constexpr swappable swappable_support =  // NOLINT
329       (MaxEnum)(PropertiesOfT<Profs>::swappable_support...);
330 
331   static constexpr hashable hashable_support =  // NOLINT
332       (MaxEnum)(PropertiesOfT<Profs>::hashable_support...);
333 
334   using properties = ConformanceProfile<
335       default_constructible_support, move_constructible_support,
336       copy_constructible_support, move_assignable_support,
337       copy_assignable_support, destructible_support,
338       equality_comparable_support, inequality_comparable_support,
339       less_than_comparable_support, less_equal_comparable_support,
340       greater_equal_comparable_support, greater_than_comparable_support,
341       swappable_support, hashable_support>;
342 };
343 
344 // NOTE: We use this as opposed to a direct alias of CombineProfilesImpl so that
345 // when named aliases of CombineProfiles are created (such as in
346 // conformance_aliases.h), we only pay for the combination algorithm on the
347 // profiles that are actually used.
348 template <class... Profs>
349 struct CombineProfiles {
350   using profile_alias_of = CombineProfilesImpl<Profs...>;
351 };
352 
353 template <>
354 struct CombineProfiles<> {
355   using properties = ConformanceProfile<>;
356 };
357 
358 template <class Profile, class Tag>
359 struct StrongProfileTypedef {
360   using properties = PropertiesOfT<Profile>;
361 };
362 
363 template <class T, class /*Enabler*/ = void>
364 struct IsProfileImpl : std::false_type {};
365 
366 template <class T>
367 struct IsProfileImpl<T, absl::void_t<PropertiesOfT<T>>> : std::true_type {};
368 
369 template <class T>
370 struct IsProfile : IsProfileImpl<T>::type {};
371 
372 }  // namespace types_internal
373 ABSL_NAMESPACE_END
374 }  // namespace absl
375 
376 #endif  // ABSL_TYPES_INTERNAL_CONFORMANCE_PROFILE_H_
377