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

base / allocator / partition_allocator / src / partition_alloc / flags.h [blame]

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This header provides a type-safe way of storing OR-combinations of enum
// values.
//
// The traditional C++ approach for storing OR-combinations of enum values is to
// use an int or unsigned int variable. The inconvenience with this approach is
// that there's no type checking at all; any enum value can be OR'd with any
// other enum value and passed on to a function that takes an int or unsigned
// int.

#ifndef PARTITION_ALLOC_FLAGS_H_
#define PARTITION_ALLOC_FLAGS_H_

#include <type_traits>

namespace partition_alloc::internal {
// Returns `T` if and only if `EnumType` is a scoped enum.
template <typename EnumType, typename T = EnumType>
using IfEnum = std::enable_if_t<
    std::is_enum_v<EnumType> &&
        !std::is_convertible_v<EnumType, std::underlying_type_t<EnumType>>,
    T>;

// We assume `EnumType` defines `kMaxValue` which has the largest value and all
// powers of two are represented in `EnumType`.
template <typename EnumType>
constexpr inline EnumType kAllFlags = static_cast<IfEnum<EnumType>>(
    (static_cast<std::underlying_type_t<EnumType>>(EnumType::kMaxValue) << 1) -
    1);

template <typename EnumType>
constexpr inline IfEnum<EnumType, bool> AreValidFlags(EnumType flags) {
  const auto raw_flags = static_cast<std::underlying_type_t<EnumType>>(flags);
  const auto raw_all_flags =
      static_cast<std::underlying_type_t<EnumType>>(kAllFlags<EnumType>);
  return (raw_flags & ~raw_all_flags) == 0;
}

// Checks `subset` is a subset of `superset` or not.
template <typename EnumType>
constexpr inline IfEnum<EnumType, bool> ContainsFlags(EnumType superset,
                                                      EnumType subset) {
  return (superset & subset) == subset;
}

// A macro to define binary arithmetic over `EnumType`.
// Use inside `namespace partition_alloc::internal`.
#define PA_DEFINE_OPERATORS_FOR_FLAGS(EnumType)                              \
  [[maybe_unused]] [[nodiscard]] inline constexpr EnumType operator&(        \
      const EnumType& lhs, const EnumType& rhs) {                            \
    return static_cast<EnumType>(                                            \
        static_cast<std::underlying_type_t<EnumType>>(lhs) &                 \
        static_cast<std::underlying_type_t<EnumType>>(rhs));                 \
  }                                                                          \
  [[maybe_unused]] inline constexpr EnumType& operator&=(                    \
      EnumType& lhs, const EnumType& rhs) {                                  \
    lhs = lhs & rhs;                                                         \
    return lhs;                                                              \
  }                                                                          \
  [[maybe_unused]] [[nodiscard]] inline constexpr EnumType operator|(        \
      const EnumType& lhs, const EnumType& rhs) {                            \
    return static_cast<EnumType>(                                            \
        static_cast<std::underlying_type_t<EnumType>>(lhs) |                 \
        static_cast<std::underlying_type_t<EnumType>>(rhs));                 \
  }                                                                          \
  [[maybe_unused]] inline constexpr EnumType& operator|=(                    \
      EnumType& lhs, const EnumType& rhs) {                                  \
    lhs = lhs | rhs;                                                         \
    return lhs;                                                              \
  }                                                                          \
  [[maybe_unused]] [[nodiscard]] inline constexpr EnumType operator^(        \
      const EnumType& lhs, const EnumType& rhs) {                            \
    return static_cast<EnumType>(                                            \
        static_cast<std::underlying_type_t<EnumType>>(lhs) ^                 \
        static_cast<std::underlying_type_t<EnumType>>(rhs));                 \
  }                                                                          \
  [[maybe_unused]] inline constexpr EnumType& operator^=(                    \
      EnumType& lhs, const EnumType& rhs) {                                  \
    lhs = lhs ^ rhs;                                                         \
    return lhs;                                                              \
  }                                                                          \
  [[maybe_unused]] [[nodiscard]] inline constexpr EnumType operator~(        \
      const EnumType& val) {                                                 \
    return static_cast<EnumType>(                                            \
        static_cast<std::underlying_type_t<EnumType>>(kAllFlags<EnumType>) & \
        ~static_cast<std::underlying_type_t<EnumType>>(val));                \
  }                                                                          \
  static_assert(true) /* semicolon here */

}  // namespace partition_alloc::internal

#endif  // PARTITION_ALLOC_FLAGS_H_