#pragma once #include #include #include #include class IOutputStream; namespace NPrivate { void PrintFlags(IOutputStream& stream, ui64 value, size_t size); } // namespace NPrivate /** * `TFlags` wrapper provides a type-safe mechanism for storing OR combinations * of enumeration values. * * This class is intended to be used mainly via helper macros. For example: * @code * class TAligner { * public: * enum EOrientation { * Vertical = 1, * Horizontal = 2 * }; * Y_DECLARE_FLAGS(EOrientations, EOrientation); * * // ... * }; * * Y_DECLARE_OPERATORS_FOR_FLAGS(TAligner::EOrientations); * @endcode */ template class TFlags { static_assert(std::is_enum::value, "Expecting an enumeration here."); public: using TEnum = Enum; using TInt = std::underlying_type_t; constexpr TFlags(std::nullptr_t = 0) : Value_(0) { } constexpr TFlags(Enum value) : Value_(static_cast(value)) { } /* Generated copy/move ctor/assignment are OK. */ constexpr operator TInt() const { return Value_; } constexpr TInt ToBaseType() const { return Value_; } constexpr static TFlags FromBaseType(TInt value) { return TFlags(TFlag(value)); } constexpr friend TFlags operator|(TFlags l, TFlags r) { return TFlags(TFlag(l.Value_ | r.Value_)); } constexpr friend TFlags operator|(TEnum l, TFlags r) { return TFlags(TFlag(static_cast(l) | r.Value_)); } constexpr friend TFlags operator|(TFlags l, TEnum r) { return TFlags(TFlag(l.Value_ | static_cast(r))); } constexpr friend TFlags operator^(TFlags l, TFlags r) { return TFlags(TFlag(l.Value_ ^ r.Value_)); } constexpr friend TFlags operator^(TEnum l, TFlags r) { return TFlags(TFlag(static_cast(l) ^ r.Value_)); } constexpr friend TFlags operator^(TFlags l, TEnum r) { return TFlags(TFlag(l.Value_ ^ static_cast(r))); } constexpr friend TFlags operator&(TFlags l, TFlags r) { return TFlags(TFlag(l.Value_ & r.Value_)); } constexpr friend TFlags operator&(TEnum l, TFlags r) { return TFlags(TFlag(static_cast(l) & r.Value_)); } constexpr friend TFlags operator&(TFlags l, TEnum r) { return TFlags(TFlag(l.Value_ & static_cast(r))); } constexpr friend bool operator==(TFlags l, TFlags r) { return l.Value_ == r.Value_; } constexpr friend bool operator==(TEnum l, TFlags r) { return static_cast(l) == r.Value_; } constexpr friend bool operator==(TFlags l, TEnum r) { return l.Value_ == static_cast(r); } constexpr friend bool operator!=(TFlags l, TFlags r) { return l.Value_ != r.Value_; } constexpr friend bool operator!=(TEnum l, TFlags r) { return static_cast(l) != r.Value_; } constexpr friend bool operator!=(TFlags l, TEnum r) { return l.Value_ != static_cast(r); } TFlags& operator&=(TFlags flags) { *this = *this & flags; return *this; } TFlags& operator&=(Enum value) { *this = *this & value; return *this; } TFlags& operator|=(TFlags flags) { *this = *this | flags; return *this; } TFlags& operator|=(Enum value) { *this = *this | value; return *this; } TFlags& operator^=(TFlags flags) { *this = *this ^ flags; return *this; } TFlags& operator^=(Enum flags) { *this = *this ^ flags; return *this; } constexpr TFlags operator~() const { return TFlags(TFlag(~Value_)); } constexpr bool operator!() const { return !Value_; } constexpr explicit operator bool() const { return Value_; } constexpr bool HasFlag(Enum value) const { return (Value_ & static_cast(value)) == static_cast(value); } constexpr bool HasFlags(TFlags flags) const { return (Value_ & flags.Value_) == flags.Value_; } constexpr bool HasAnyOfFlags(TFlags flags) const { return (Value_ & flags.Value_) != 0; } TFlags RemoveFlag(Enum value) { Value_ &= ~static_cast(value); return *this; } TFlags RemoveFlags(TFlags flags) { Value_ &= ~flags.Value_; return *this; } friend IOutputStream& operator<<(IOutputStream& stream Y_LIFETIME_BOUND, const TFlags& flags) { ::NPrivate::PrintFlags(stream, static_cast(flags.Value_), sizeof(TInt)); return stream; } private: struct TFlag { constexpr TFlag() { } constexpr explicit TFlag(TInt value) : Value(value) { } TInt Value = 0; }; constexpr explicit TFlags(TFlag value) : Value_(value.Value) { } private: TInt Value_; }; template struct TPodTraits<::TFlags> { enum { IsPod = TTypeTraits::IsPod }; }; template struct THash<::TFlags> { size_t operator()(const TFlags& flags) const noexcept { return THash::TInt>()(flags); } }; /** * This macro defines a flags type for the provided enum. * * @param FLAGS Name of the flags type to declare. * @param ENUM Name of the base enum type to use. */ #define Y_DECLARE_FLAGS(FLAGS, ENUM) \ using FLAGS = ::TFlags /** * This macro declares global operator functions for enum base of `FLAGS` type. * This way operations on individual enum values will provide a type-safe * `TFlags` object. * * @param FLAGS Flags type to declare operator for. */ #define Y_DECLARE_OPERATORS_FOR_FLAGS(FLAGS) \ Y_DECLARE_UNUSED \ constexpr inline FLAGS operator|(FLAGS::TEnum l, FLAGS::TEnum r) { \ return FLAGS(l) | r; \ } \ Y_DECLARE_UNUSED \ constexpr inline FLAGS operator~(FLAGS::TEnum value) { \ return ~FLAGS(value); \ } \ Y_SEMICOLON_GUARD