enum_mask_base.h 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #ifndef CARBON_COMMON_ENUM_MASK_BASE_H_
  5. #define CARBON_COMMON_ENUM_MASK_BASE_H_
  6. #include <bit>
  7. #include "common/enum_base.h"
  8. #include "llvm/ADT/StringExtras.h"
  9. namespace Carbon::Internal {
  10. // CRTP-style base class similar to `EnumBase`, but supporting mask enums.
  11. // Enumerator values are consecutive bit shifts (1 << 0, 1 << 1, 1 << 2, 1 << 3,
  12. // ...).
  13. //
  14. // Users must be in the `Carbon` namespace and should look like the following.
  15. //
  16. // In `my_kind.h`:
  17. // ```
  18. // #define CARBON_MY_KIND(X) \
  19. // X(Enumerator1) \
  20. // X(Enumerator2) \
  21. // X(Enumerator3) \
  22. // ...
  23. //
  24. // CARBON_DEFINE_RAW_ENUM_MASK(MyKind, uint32_t) {
  25. // CARBON_MY_KIND(CARBON_RAW_ENUM_MASK_ENUMERATOR)
  26. // };
  27. //
  28. // class MyKind : public CARBON_ENUM_MASK_BASE(MyKind) {
  29. // public:
  30. // CARBON_MY_KIND(CARBON_ENUM_MASK_CONSTANT_DECL)
  31. //
  32. // // Plus, anything else you wish to include.
  33. // };
  34. //
  35. // #define CARBON_MY_KIND_WITH_TYPE(X) \
  36. // CARBON_ENUM_MASK_CONSTANT_DEFINITION(MyKind, X)
  37. // CARBON_MY_KIND(CARBON_MY_KIND_WITH_TYPE)
  38. // #undef CARBON_MY_KIND_WITH_TYPE
  39. // ```
  40. //
  41. // In `my_kind.cpp`:
  42. // ```
  43. // CARBON_DEFINE_ENUM_MASK_NAMES(MyKind) {
  44. // CARBON_MY_KIND(CARBON_ENUM_MASK_NAME_STRING)
  45. // };
  46. // ```
  47. template <typename DerivedT, typename EnumT, const llvm::StringLiteral Names[]>
  48. class EnumMaskBase : public EnumBase<DerivedT, EnumT, Names> {
  49. public:
  50. // Provide a standard `None`.
  51. //
  52. // This uses a `&` to trigger slightly different instantiation behaviors in
  53. // Clang. For context on why this is needed, see http://wg21.link/CWG2800.
  54. // NOLINTNEXTLINE(readability-identifier-naming)
  55. static const DerivedT& None;
  56. // Returns true if there's a non-empty set intersection.
  57. constexpr auto HasAnyOf(DerivedT other) const -> bool {
  58. return !(*this & other).empty();
  59. }
  60. // Adds entries to the mask.
  61. auto Add(DerivedT other) -> void { *this = *this | other; }
  62. // Removes entries from the mask.
  63. auto Remove(DerivedT other) -> void { *this = *this & ~other; }
  64. constexpr auto empty() const -> bool { return this->AsInt() == 0; }
  65. constexpr auto operator|(DerivedT other) const -> DerivedT {
  66. return DerivedT::FromInt(this->AsInt() | other.AsInt());
  67. }
  68. constexpr auto operator&(DerivedT other) const -> DerivedT {
  69. return DerivedT::FromInt(this->AsInt() & other.AsInt());
  70. }
  71. constexpr auto operator~() const -> DerivedT {
  72. return DerivedT::FromInt(~this->AsInt());
  73. }
  74. // Use `Print` for mask entries. This hides `EnumBase::name`; it's not
  75. // compatible with `EnumMaskBase`.
  76. auto name() const -> llvm::StringRef = delete;
  77. // Prints this value as a `|`-separated list of mask entries, or `None`.
  78. //
  79. // This shadows EnumBase::Print.
  80. auto Print(llvm::raw_ostream& out) const -> void {
  81. int value = this->AsInt();
  82. if (value == 0) {
  83. out << "None";
  84. return;
  85. }
  86. llvm::ListSeparator sep("|");
  87. for (int bit = 0; value != 0; value >>= 1, ++bit) {
  88. if (value & 1) {
  89. out << sep << Names[bit];
  90. }
  91. }
  92. }
  93. };
  94. template <typename DerivedT, typename EnumT, const llvm::StringLiteral Names[]>
  95. constexpr const DerivedT& EnumMaskBase<DerivedT, EnumT, Names>::None =
  96. DerivedT::FromInt(0);
  97. } // namespace Carbon::Internal
  98. // Use this before defining a class that derives from `EnumMaskBase` to begin
  99. // the definition of the raw `enum class`. It should be followed by the body of
  100. // that raw enum class.
  101. #define CARBON_DEFINE_RAW_ENUM_MASK(EnumMaskName, UnderlyingType) \
  102. namespace Internal { \
  103. struct EnumMaskName##Data { \
  104. static const llvm::StringLiteral Names[]; \
  105. /* For bit shifts, track the initial counter value. This will increment on \
  106. * each enum entry. */ \
  107. static constexpr uint64_t BitShiftCounter = __COUNTER__ + 1; \
  108. enum class RawEnum : UnderlyingType; \
  109. }; \
  110. } \
  111. enum class Internal::EnumMaskName##Data::RawEnum : UnderlyingType
  112. // In the `CARBON_DEFINE_RAW_ENUM_MASK` block, use this to generate each
  113. // enumerator.
  114. #define CARBON_RAW_ENUM_MASK_ENUMERATOR(Name) \
  115. Name = 1 << (__COUNTER__ - BitShiftCounter),
  116. // Use this to compute the `Internal::EnumMaskBase` specialization for a Carbon
  117. // enum mask. It both computes the name of the raw enum and ensures all the
  118. // namespaces are correct.
  119. #define CARBON_ENUM_MASK_BASE(EnumMaskName) \
  120. ::Carbon::Internal::EnumMaskBase<EnumMaskName, \
  121. Internal::EnumMaskName##Data::RawEnum, \
  122. Internal::EnumMaskName##Data::Names>
  123. // Constants and names are declared equivalently as to `EnumBase`.
  124. #define CARBON_ENUM_MASK_CONSTANT_DECL(Name) CARBON_ENUM_CONSTANT_DECL(Name)
  125. #define CARBON_ENUM_MASK_CONSTANT_DEFINITION(EnumMaskName, Name) \
  126. CARBON_ENUM_CONSTANT_DEFINITION(EnumMaskName, Name)
  127. #define CARBON_DEFINE_ENUM_MASK_NAMES(EnumMaskName) \
  128. CARBON_DEFINE_ENUM_CLASS_NAMES(EnumMaskName)
  129. #define CARBON_ENUM_MASK_NAME_STRING(Name) CARBON_ENUM_CLASS_NAME_STRING(Name)
  130. #endif // CARBON_COMMON_ENUM_MASK_BASE_H_