conformance_profile.h 15.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376
// Copyright 2019 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.
//
// -----------------------------------------------------------------------------
// conformance_profiles.h
// -----------------------------------------------------------------------------
//
// This file contains templates for representing "Regularity Profiles" and
// concisely-named versions of commonly used Regularity Profiles.
//
// A Regularity Profile is a compile-time description of the types of operations
// that a given type supports, along with properties of those operations when
// they do exist. For instance, a Regularity Profile may describe a type that
// has a move-constructor that is noexcept and a copy constructor that is not
// noexcept. This description can then be examined and passed around to other
// templates for the purposes of asserting expectations on user-defined types
// via a series trait checks, or for determining what kinds of run-time tests
// are able to be performed.
//
// Regularity Profiles are also used when creating "archetypes," which are
// minimum-conforming types that meet all of the requirements of a given
// Regularity Profile. For more information regarding archetypes, see
// "conformance_archetypes.h".

#ifndef ABSL_TYPES_INTERNAL_CONFORMANCE_PROFILE_H_
#define ABSL_TYPES_INTERNAL_CONFORMANCE_PROFILE_H_

#include <type_traits>
#include <utility>

#include "absl/meta/type_traits.h"

// TODO(calabrese) Add support for extending profiles.

namespace absl {
ABSL_NAMESPACE_BEGIN
namespace types_internal {

template <class T, class /*Enabler*/ = void>
struct PropertiesOfImpl {};

template <class T>
struct PropertiesOfImpl<T, absl::void_t<typename T::properties>> {
  using type = typename T::properties;
};

template <class T>
struct PropertiesOfImpl<T, absl::void_t<typename T::profile_alias_of>> {
  using type = typename PropertiesOfImpl<typename T::profile_alias_of>::type;
};

template <class T>
struct PropertiesOf : PropertiesOfImpl<T> {};

template <class T>
using PropertiesOfT = typename PropertiesOf<T>::type;

// NOTE: These enums use this naming convention to be consistent with the
// standard trait names, which is useful since it allows us to match up each
// enum name with a corresponding trait name in macro definitions.

enum class function_kind { maybe, yes, nothrow, trivial };

#define ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM(name) \
  enum class name { maybe, yes, nothrow, trivial }

ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM(default_constructible);
ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM(move_constructible);
ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM(copy_constructible);
ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM(move_assignable);
ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM(copy_assignable);
ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM(destructible);

#undef ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM

#define ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM(name) \
  enum class name { maybe, yes, nothrow }

ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM(equality_comparable);
ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM(inequality_comparable);
ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM(less_than_comparable);
ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM(less_equal_comparable);
ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM(greater_equal_comparable);
ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM(greater_than_comparable);

ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM(swappable);

#undef ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM

enum class hashable { maybe, yes };

constexpr const char* PropertyName(hashable v) {
  return "support for std::hash";
}

template <
    default_constructible DefaultConstructibleValue =
        default_constructible::maybe,
    move_constructible MoveConstructibleValue = move_constructible::maybe,
    copy_constructible CopyConstructibleValue = copy_constructible::maybe,
    move_assignable MoveAssignableValue = move_assignable::maybe,
    copy_assignable CopyAssignableValue = copy_assignable::maybe,
    destructible DestructibleValue = destructible::maybe,
    equality_comparable EqualityComparableValue = equality_comparable::maybe,
    inequality_comparable InequalityComparableValue =
        inequality_comparable::maybe,
    less_than_comparable LessThanComparableValue = less_than_comparable::maybe,
    less_equal_comparable LessEqualComparableValue =
        less_equal_comparable::maybe,
    greater_equal_comparable GreaterEqualComparableValue =
        greater_equal_comparable::maybe,
    greater_than_comparable GreaterThanComparableValue =
        greater_than_comparable::maybe,
    swappable SwappableValue = swappable::maybe,
    hashable HashableValue = hashable::maybe>
struct ConformanceProfile {
  using properties = ConformanceProfile;

  static constexpr default_constructible
      default_constructible_support =  // NOLINT
      DefaultConstructibleValue;

  static constexpr move_constructible move_constructible_support =  // NOLINT
      MoveConstructibleValue;

  static constexpr copy_constructible copy_constructible_support =  // NOLINT
      CopyConstructibleValue;

  static constexpr move_assignable move_assignable_support =  // NOLINT
      MoveAssignableValue;

  static constexpr copy_assignable copy_assignable_support =  // NOLINT
      CopyAssignableValue;

  static constexpr destructible destructible_support =  // NOLINT
      DestructibleValue;

  static constexpr equality_comparable equality_comparable_support =  // NOLINT
      EqualityComparableValue;

  static constexpr inequality_comparable
      inequality_comparable_support =  // NOLINT
      InequalityComparableValue;

  static constexpr less_than_comparable
      less_than_comparable_support =  // NOLINT
      LessThanComparableValue;

  static constexpr less_equal_comparable
      less_equal_comparable_support =  // NOLINT
      LessEqualComparableValue;

  static constexpr greater_equal_comparable
      greater_equal_comparable_support =  // NOLINT
      GreaterEqualComparableValue;

  static constexpr greater_than_comparable
      greater_than_comparable_support =  // NOLINT
      GreaterThanComparableValue;

  static constexpr swappable swappable_support = SwappableValue;  // NOLINT

  static constexpr hashable hashable_support = HashableValue;  // NOLINT

  static constexpr bool is_default_constructible =  // NOLINT
      DefaultConstructibleValue != default_constructible::maybe;

  static constexpr bool is_move_constructible =  // NOLINT
      MoveConstructibleValue != move_constructible::maybe;

  static constexpr bool is_copy_constructible =  // NOLINT
      CopyConstructibleValue != copy_constructible::maybe;

  static constexpr bool is_move_assignable =  // NOLINT
      MoveAssignableValue != move_assignable::maybe;

  static constexpr bool is_copy_assignable =  // NOLINT
      CopyAssignableValue != copy_assignable::maybe;

  static constexpr bool is_destructible =  // NOLINT
      DestructibleValue != destructible::maybe;

  static constexpr bool is_equality_comparable =  // NOLINT
      EqualityComparableValue != equality_comparable::maybe;

  static constexpr bool is_inequality_comparable =  // NOLINT
      InequalityComparableValue != inequality_comparable::maybe;

  static constexpr bool is_less_than_comparable =  // NOLINT
      LessThanComparableValue != less_than_comparable::maybe;

  static constexpr bool is_less_equal_comparable =  // NOLINT
      LessEqualComparableValue != less_equal_comparable::maybe;

  static constexpr bool is_greater_equal_comparable =  // NOLINT
      GreaterEqualComparableValue != greater_equal_comparable::maybe;

  static constexpr bool is_greater_than_comparable =  // NOLINT
      GreaterThanComparableValue != greater_than_comparable::maybe;

  static constexpr bool is_swappable =  // NOLINT
      SwappableValue != swappable::maybe;

  static constexpr bool is_hashable =  // NOLINT
      HashableValue != hashable::maybe;
};

#define ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF_IMPL(type, name)     \
  template <default_constructible DefaultConstructibleValue,                   \
            move_constructible MoveConstructibleValue,                         \
            copy_constructible CopyConstructibleValue,                         \
            move_assignable MoveAssignableValue,                               \
            copy_assignable CopyAssignableValue,                               \
            destructible DestructibleValue,                                    \
            equality_comparable EqualityComparableValue,                       \
            inequality_comparable InequalityComparableValue,                   \
            less_than_comparable LessThanComparableValue,                      \
            less_equal_comparable LessEqualComparableValue,                    \
            greater_equal_comparable GreaterEqualComparableValue,              \
            greater_than_comparable GreaterThanComparableValue,                \
            swappable SwappableValue, hashable HashableValue>                  \
  constexpr type ConformanceProfile<                                           \
      DefaultConstructibleValue, MoveConstructibleValue,                       \
      CopyConstructibleValue, MoveAssignableValue, CopyAssignableValue,        \
      DestructibleValue, EqualityComparableValue, InequalityComparableValue,   \
      LessThanComparableValue, LessEqualComparableValue,                       \
      GreaterEqualComparableValue, GreaterThanComparableValue, SwappableValue, \
      HashableValue>::name

#define ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(type)           \
  ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF_IMPL(type,            \
                                                         type##_support); \
  ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF_IMPL(bool, is_##type)

ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(default_constructible);
ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(move_constructible);
ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(copy_constructible);
ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(move_assignable);
ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(copy_assignable);
ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(destructible);
ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(equality_comparable);
ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(inequality_comparable);
ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(less_than_comparable);
ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(less_equal_comparable);
ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(greater_equal_comparable);
ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(greater_than_comparable);
ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(swappable);
ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(hashable);

#undef ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF
#undef ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF_IMPL

// Converts an enum to its underlying integral value.
template <class Enum>
constexpr absl::underlying_type_t<Enum> UnderlyingValue(Enum value) {
  return static_cast<absl::underlying_type_t<Enum>>(value);
}

// Retrieve the enum with the greatest underlying value.
// Note: std::max is not constexpr in C++11, which is why this is necessary.
template <class H>
constexpr H MaxEnum(H head) {
  return head;
}

template <class H, class N, class... T>
constexpr H MaxEnum(H head, N next, T... tail) {
  return (UnderlyingValue)(next) < (UnderlyingValue)(head)
             ? (MaxEnum)(head, tail...)
             : (MaxEnum)(next, tail...);
}

template <class... Profs>
struct CombineProfilesImpl {
  static constexpr default_constructible
      default_constructible_support =  // NOLINT
      (MaxEnum)(PropertiesOfT<Profs>::default_constructible_support...);

  static constexpr move_constructible move_constructible_support =  // NOLINT
      (MaxEnum)(PropertiesOfT<Profs>::move_constructible_support...);

  static constexpr copy_constructible copy_constructible_support =  // NOLINT
      (MaxEnum)(PropertiesOfT<Profs>::copy_constructible_support...);

  static constexpr move_assignable move_assignable_support =  // NOLINT
      (MaxEnum)(PropertiesOfT<Profs>::move_assignable_support...);

  static constexpr copy_assignable copy_assignable_support =  // NOLINT
      (MaxEnum)(PropertiesOfT<Profs>::copy_assignable_support...);

  static constexpr destructible destructible_support =  // NOLINT
      (MaxEnum)(PropertiesOfT<Profs>::destructible_support...);

  static constexpr equality_comparable equality_comparable_support =  // NOLINT
      (MaxEnum)(PropertiesOfT<Profs>::equality_comparable_support...);

  static constexpr inequality_comparable
      inequality_comparable_support =  // NOLINT
      (MaxEnum)(PropertiesOfT<Profs>::inequality_comparable_support...);

  static constexpr less_than_comparable
      less_than_comparable_support =  // NOLINT
      (MaxEnum)(PropertiesOfT<Profs>::less_than_comparable_support...);

  static constexpr less_equal_comparable
      less_equal_comparable_support =  // NOLINT
      (MaxEnum)(PropertiesOfT<Profs>::less_equal_comparable_support...);

  static constexpr greater_equal_comparable
      greater_equal_comparable_support =  // NOLINT
      (MaxEnum)(PropertiesOfT<Profs>::greater_equal_comparable_support...);

  static constexpr greater_than_comparable
      greater_than_comparable_support =  // NOLINT
      (MaxEnum)(PropertiesOfT<Profs>::greater_than_comparable_support...);

  static constexpr swappable swappable_support =  // NOLINT
      (MaxEnum)(PropertiesOfT<Profs>::swappable_support...);

  static constexpr hashable hashable_support =  // NOLINT
      (MaxEnum)(PropertiesOfT<Profs>::hashable_support...);

  using properties = ConformanceProfile<
      default_constructible_support, move_constructible_support,
      copy_constructible_support, move_assignable_support,
      copy_assignable_support, destructible_support,
      equality_comparable_support, inequality_comparable_support,
      less_than_comparable_support, less_equal_comparable_support,
      greater_equal_comparable_support, greater_than_comparable_support,
      swappable_support, hashable_support>;
};

// NOTE: We use this as opposed to a direct alias of CombineProfilesImpl so that
// when named aliases of CombineProfiles are created (such as in
// conformance_aliases.h), we only pay for the combination algorithm on the
// profiles that are actually used.
template <class... Profs>
struct CombineProfiles {
  using profile_alias_of = CombineProfilesImpl<Profs...>;
};

template <>
struct CombineProfiles<> {
  using properties = ConformanceProfile<>;
};

template <class Profile, class Tag>
struct StrongProfileTypedef {
  using properties = PropertiesOfT<Profile>;
};

template <class T, class /*Enabler*/ = void>
struct IsProfileImpl : std::false_type {};

template <class T>
struct IsProfileImpl<T, absl::void_t<PropertiesOfT<T>>> : std::true_type {};

template <class T>
struct IsProfile : IsProfileImpl<T>::type {};

}  // namespace types_internal
ABSL_NAMESPACE_END
}  // namespace absl

#endif  // ABSL_TYPES_INTERNAL_CONFORMANCE_PROFILE_H_