flags.h 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. #pragma once
  2. #include <type_traits>
  3. #include <util/system/types.h>
  4. #include <util/generic/typetraits.h>
  5. #include <util/generic/fwd.h>
  6. class IOutputStream;
  7. namespace NPrivate {
  8. void PrintFlags(IOutputStream& stream, ui64 value, size_t size);
  9. } // namespace NPrivate
  10. /**
  11. * `TFlags` wrapper provides a type-safe mechanism for storing OR combinations
  12. * of enumeration values.
  13. *
  14. * This class is intended to be used mainly via helper macros. For example:
  15. * @code
  16. * class TAligner {
  17. * public:
  18. * enum EOrientation {
  19. * Vertical = 1,
  20. * Horizontal = 2
  21. * };
  22. * Y_DECLARE_FLAGS(EOrientations, EOrientation);
  23. *
  24. * // ...
  25. * };
  26. *
  27. * Y_DECLARE_OPERATORS_FOR_FLAGS(TAligner::EOrientations);
  28. * @endcode
  29. */
  30. template <class Enum>
  31. class TFlags {
  32. static_assert(std::is_enum<Enum>::value, "Expecting an enumeration here.");
  33. public:
  34. using TEnum = Enum;
  35. using TInt = std::underlying_type_t<Enum>;
  36. constexpr TFlags(std::nullptr_t = 0)
  37. : Value_(0)
  38. {
  39. }
  40. constexpr TFlags(Enum value)
  41. : Value_(static_cast<TInt>(value))
  42. {
  43. }
  44. /* Generated copy/move ctor/assignment are OK. */
  45. constexpr operator TInt() const {
  46. return Value_;
  47. }
  48. constexpr TInt ToBaseType() const {
  49. return Value_;
  50. }
  51. constexpr static TFlags FromBaseType(TInt value) {
  52. return TFlags(TFlag(value));
  53. }
  54. constexpr friend TFlags operator|(TFlags l, TFlags r) {
  55. return TFlags(TFlag(l.Value_ | r.Value_));
  56. }
  57. constexpr friend TFlags operator|(TEnum l, TFlags r) {
  58. return TFlags(TFlag(static_cast<TInt>(l) | r.Value_));
  59. }
  60. constexpr friend TFlags operator|(TFlags l, TEnum r) {
  61. return TFlags(TFlag(l.Value_ | static_cast<TInt>(r)));
  62. }
  63. constexpr friend TFlags operator^(TFlags l, TFlags r) {
  64. return TFlags(TFlag(l.Value_ ^ r.Value_));
  65. }
  66. constexpr friend TFlags
  67. operator^(TEnum l, TFlags r) {
  68. return TFlags(TFlag(static_cast<TInt>(l) ^ r.Value_));
  69. }
  70. constexpr friend TFlags
  71. operator^(TFlags l, TEnum r) {
  72. return TFlags(TFlag(l.Value_ ^ static_cast<TInt>(r)));
  73. }
  74. constexpr friend TFlags
  75. operator&(TFlags l, TFlags r) {
  76. return TFlags(TFlag(l.Value_ & r.Value_));
  77. }
  78. constexpr friend TFlags operator&(TEnum l, TFlags r) {
  79. return TFlags(TFlag(static_cast<TInt>(l) & r.Value_));
  80. }
  81. constexpr friend TFlags operator&(TFlags l, TEnum r) {
  82. return TFlags(TFlag(l.Value_ & static_cast<TInt>(r)));
  83. }
  84. constexpr friend bool operator==(TFlags l, TFlags r) {
  85. return l.Value_ == r.Value_;
  86. }
  87. constexpr friend bool operator==(TEnum l, TFlags r) {
  88. return static_cast<TInt>(l) == r.Value_;
  89. }
  90. constexpr friend bool operator==(TFlags l, TEnum r) {
  91. return l.Value_ == static_cast<TInt>(r);
  92. }
  93. constexpr friend bool operator!=(TFlags l, TFlags r) {
  94. return l.Value_ != r.Value_;
  95. }
  96. constexpr friend bool operator!=(TEnum l, TFlags r) {
  97. return static_cast<TInt>(l) != r.Value_;
  98. }
  99. constexpr friend bool operator!=(TFlags l, TEnum r) {
  100. return l.Value_ != static_cast<TInt>(r);
  101. }
  102. TFlags& operator&=(TFlags flags) {
  103. *this = *this & flags;
  104. return *this;
  105. }
  106. TFlags& operator&=(Enum value) {
  107. *this = *this & value;
  108. return *this;
  109. }
  110. TFlags& operator|=(TFlags flags) {
  111. *this = *this | flags;
  112. return *this;
  113. }
  114. TFlags& operator|=(Enum value) {
  115. *this = *this | value;
  116. return *this;
  117. }
  118. TFlags& operator^=(TFlags flags) {
  119. *this = *this ^ flags;
  120. return *this;
  121. }
  122. TFlags& operator^=(Enum flags) {
  123. *this = *this ^ flags;
  124. return *this;
  125. }
  126. constexpr TFlags operator~() const {
  127. return TFlags(TFlag(~Value_));
  128. }
  129. constexpr bool operator!() const {
  130. return !Value_;
  131. }
  132. constexpr explicit operator bool() const {
  133. return Value_;
  134. }
  135. constexpr bool HasFlag(Enum value) const {
  136. return (Value_ & static_cast<TInt>(value)) == static_cast<TInt>(value);
  137. }
  138. constexpr bool HasFlags(TFlags flags) const {
  139. return (Value_ & flags.Value_) == flags.Value_;
  140. }
  141. constexpr bool HasAnyOfFlags(TFlags flags) const {
  142. return (Value_ & flags.Value_) != 0;
  143. }
  144. TFlags RemoveFlag(Enum value) {
  145. Value_ &= ~static_cast<TInt>(value);
  146. return *this;
  147. }
  148. TFlags RemoveFlags(TFlags flags) {
  149. Value_ &= ~flags.Value_;
  150. return *this;
  151. }
  152. friend IOutputStream& operator<<(IOutputStream& stream Y_LIFETIME_BOUND, const TFlags& flags) {
  153. ::NPrivate::PrintFlags(stream, static_cast<ui64>(flags.Value_), sizeof(TInt));
  154. return stream;
  155. }
  156. private:
  157. struct TFlag {
  158. constexpr TFlag() {
  159. }
  160. constexpr explicit TFlag(TInt value)
  161. : Value(value)
  162. {
  163. }
  164. TInt Value = 0;
  165. };
  166. constexpr explicit TFlags(TFlag value)
  167. : Value_(value.Value)
  168. {
  169. }
  170. private:
  171. TInt Value_;
  172. };
  173. template <class T>
  174. struct TPodTraits<::TFlags<T>> {
  175. enum {
  176. IsPod = TTypeTraits<T>::IsPod
  177. };
  178. };
  179. template <class Enum>
  180. struct THash<::TFlags<Enum>> {
  181. size_t operator()(const TFlags<Enum>& flags) const noexcept {
  182. return THash<typename ::TFlags<Enum>::TInt>()(flags);
  183. }
  184. };
  185. /**
  186. * This macro defines a flags type for the provided enum.
  187. *
  188. * @param FLAGS Name of the flags type to declare.
  189. * @param ENUM Name of the base enum type to use.
  190. */
  191. #define Y_DECLARE_FLAGS(FLAGS, ENUM) \
  192. using FLAGS = ::TFlags<ENUM>
  193. /**
  194. * This macro declares global operator functions for enum base of `FLAGS` type.
  195. * This way operations on individual enum values will provide a type-safe
  196. * `TFlags` object.
  197. *
  198. * @param FLAGS Flags type to declare operator for.
  199. */
  200. #define Y_DECLARE_OPERATORS_FOR_FLAGS(FLAGS) \
  201. Y_DECLARE_UNUSED \
  202. constexpr inline FLAGS operator|(FLAGS::TEnum l, FLAGS::TEnum r) { \
  203. return FLAGS(l) | r; \
  204. } \
  205. Y_DECLARE_UNUSED \
  206. constexpr inline FLAGS operator~(FLAGS::TEnum value) { \
  207. return ~FLAGS(value); \
  208. } \
  209. Y_SEMICOLON_GUARD