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