TypedEnumBits.h 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. /*
  6. * MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS allows using a typed enum as bit flags.
  7. */
  8. #ifndef mozilla_TypedEnumBits_h
  9. #define mozilla_TypedEnumBits_h
  10. #include "mozilla/Attributes.h"
  11. #include "mozilla/IntegerTypeTraits.h"
  12. namespace mozilla {
  13. /*
  14. * The problem that CastableTypedEnumResult aims to solve is that
  15. * typed enums are not convertible to bool, and there is no way to make them
  16. * be, yet user code wants to be able to write
  17. *
  18. * if (myFlags & Flags::SOME_PARTICULAR_FLAG) (1)
  19. *
  20. * There are different approaches to solving this. Most of them require
  21. * adapting user code. For example, we could implement operator! and have
  22. * the user write
  23. *
  24. * if (!!(myFlags & Flags::SOME_PARTICULAR_FLAG)) (2)
  25. *
  26. * Or we could supply a IsNonZero() or Any() function returning whether
  27. * an enum value is nonzero, and have the user write
  28. *
  29. * if (Any(Flags & Flags::SOME_PARTICULAR_FLAG)) (3)
  30. *
  31. * But instead, we choose to preserve the original user syntax (1) as it
  32. * is inherently more readable, and to ease porting existing code to typed
  33. * enums. We achieve this by having operator& and other binary bitwise
  34. * operators have as return type a class, CastableTypedEnumResult,
  35. * that wraps a typed enum but adds bool convertibility.
  36. */
  37. template<typename E>
  38. class CastableTypedEnumResult
  39. {
  40. private:
  41. const E mValue;
  42. public:
  43. explicit constexpr CastableTypedEnumResult(E aValue)
  44. : mValue(aValue)
  45. {}
  46. constexpr operator E() const { return mValue; }
  47. template<typename DestinationType>
  48. explicit constexpr
  49. operator DestinationType() const { return DestinationType(mValue); }
  50. constexpr bool operator !() const { return !bool(mValue); }
  51. };
  52. #define MOZ_CASTABLETYPEDENUMRESULT_BINOP(Op, OtherType, ReturnType) \
  53. template<typename E> \
  54. constexpr ReturnType \
  55. operator Op(const OtherType& aE, const CastableTypedEnumResult<E>& aR) \
  56. { \
  57. return ReturnType(aE Op OtherType(aR)); \
  58. } \
  59. template<typename E> \
  60. constexpr ReturnType \
  61. operator Op(const CastableTypedEnumResult<E>& aR, const OtherType& aE) \
  62. { \
  63. return ReturnType(OtherType(aR) Op aE); \
  64. } \
  65. template<typename E> \
  66. constexpr ReturnType \
  67. operator Op(const CastableTypedEnumResult<E>& aR1, \
  68. const CastableTypedEnumResult<E>& aR2) \
  69. { \
  70. return ReturnType(OtherType(aR1) Op OtherType(aR2)); \
  71. }
  72. MOZ_CASTABLETYPEDENUMRESULT_BINOP(|, E, CastableTypedEnumResult<E>)
  73. MOZ_CASTABLETYPEDENUMRESULT_BINOP(&, E, CastableTypedEnumResult<E>)
  74. MOZ_CASTABLETYPEDENUMRESULT_BINOP(^, E, CastableTypedEnumResult<E>)
  75. MOZ_CASTABLETYPEDENUMRESULT_BINOP(==, E, bool)
  76. MOZ_CASTABLETYPEDENUMRESULT_BINOP(!=, E, bool)
  77. MOZ_CASTABLETYPEDENUMRESULT_BINOP(||, bool, bool)
  78. MOZ_CASTABLETYPEDENUMRESULT_BINOP(&&, bool, bool)
  79. template <typename E>
  80. constexpr CastableTypedEnumResult<E>
  81. operator ~(const CastableTypedEnumResult<E>& aR)
  82. {
  83. return CastableTypedEnumResult<E>(~(E(aR)));
  84. }
  85. #define MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(Op) \
  86. template<typename E> \
  87. E& \
  88. operator Op(E& aR1, \
  89. const CastableTypedEnumResult<E>& aR2) \
  90. { \
  91. return aR1 Op E(aR2); \
  92. }
  93. MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(&=)
  94. MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(|=)
  95. MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(^=)
  96. #undef MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP
  97. #undef MOZ_CASTABLETYPEDENUMRESULT_BINOP
  98. namespace detail {
  99. template<typename E>
  100. struct UnsignedIntegerTypeForEnum
  101. : UnsignedStdintTypeForSize<sizeof(E)>
  102. {};
  103. } // namespace detail
  104. } // namespace mozilla
  105. #define MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, Op) \
  106. inline constexpr mozilla::CastableTypedEnumResult<Name> \
  107. operator Op(Name a, Name b) \
  108. { \
  109. typedef mozilla::CastableTypedEnumResult<Name> Result; \
  110. typedef mozilla::detail::UnsignedIntegerTypeForEnum<Name>::Type U; \
  111. return Result(Name(U(a) Op U(b))); \
  112. } \
  113. \
  114. inline Name& \
  115. operator Op##=(Name& a, Name b) \
  116. { \
  117. return a = a Op b; \
  118. }
  119. /**
  120. * MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS generates standard bitwise operators
  121. * for the given enum type. Use this to enable using an enum type as bit-field.
  122. */
  123. #define MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Name) \
  124. MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, |) \
  125. MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, &) \
  126. MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, ^) \
  127. inline constexpr mozilla::CastableTypedEnumResult<Name> \
  128. operator~(Name a) \
  129. { \
  130. typedef mozilla::CastableTypedEnumResult<Name> Result; \
  131. typedef mozilla::detail::UnsignedIntegerTypeForEnum<Name>::Type U; \
  132. return Result(Name(~(U(a)))); \
  133. }
  134. #endif // mozilla_TypedEnumBits_h