/* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once #include namespace base { template class flags; template struct extended_flags; template using extended_flags_t = typename extended_flags::type; namespace details { struct flags_zero_helper_struct { }; using flags_zero_helper = void(base::details::flags_zero_helper_struct::*)(); template ::type> inline constexpr auto extended_flag_convert(ExtendedEnum value) { return static_cast(value); } template ::type> inline constexpr auto extended_flags_convert(ExtendedEnum value) { return flags(extended_flag_convert(value)); } } // namespace details template class flags { public: using Enum = EnumType; using Type = std::underlying_type_t; constexpr flags() = default; constexpr flags(details::flags_zero_helper) noexcept { } constexpr flags(Enum value) noexcept : _value(static_cast(value)) { } static constexpr flags from_raw(Type value) noexcept { return flags(static_cast(value)); } constexpr auto value() const noexcept { return _value; } constexpr operator Type() const noexcept { return value(); } constexpr auto &operator|=(flags b) noexcept { _value |= b.value(); return *this; } constexpr auto &operator&=(flags b) noexcept { _value &= b.value(); return *this; } constexpr auto &operator^=(flags b) noexcept { _value ^= b.value(); return *this; } constexpr auto operator~() const noexcept { return from_raw(~value()); } constexpr auto operator|(flags b) const noexcept { return (flags(*this) |= b); } constexpr auto operator&(flags b) const noexcept { return (flags(*this) &= b); } constexpr auto operator^(flags b) const noexcept { return (flags(*this) ^= b); } constexpr auto operator|(Enum b) const noexcept { return (flags(*this) |= b); } constexpr auto operator&(Enum b) const noexcept { return (flags(*this) &= b); } constexpr auto operator^(Enum b) const noexcept { return (flags(*this) ^= b); } constexpr auto operator==(Enum b) const noexcept { return (value() == static_cast(b)); } constexpr auto operator!=(Enum b) const noexcept { return !(*this == b); } constexpr auto operator<(Enum b) const noexcept { return value() < static_cast(b); } constexpr auto operator>(Enum b) const noexcept { return (b < *this); } constexpr auto operator<=(Enum b) const noexcept { return !(b < *this); } constexpr auto operator>=(Enum b) const noexcept { return !(*this < b); } private: Type _value = 0; }; template constexpr auto make_flags(Enum value) noexcept { return flags(value); } template ::value>, typename = std::enable_if_t> inline constexpr auto operator|(Enum a, flags b) noexcept { return b | a; } template ::value>, typename = std::enable_if_t> inline constexpr auto operator&(Enum a, flags b) noexcept { return b & a; } template ::value>, typename = std::enable_if_t> inline constexpr auto operator^(Enum a, flags b) noexcept { return b ^ a; } template ::type> inline constexpr auto operator|(flags> a, ExtendedEnum b) { return a | details::extended_flags_convert(b); } template ::type> inline constexpr auto operator|(ExtendedEnum a, flags> b) { return b | a; } template > inline constexpr auto operator&(flags> a, ExtendedEnum b) { return a & details::extended_flags_convert(b); } template ::type> inline constexpr auto operator&(ExtendedEnum a, flags> b) { return b & a; } template > inline constexpr auto operator^(flags> a, ExtendedEnum b) { return a ^ details::extended_flags_convert(b); } template ::type> inline constexpr auto operator^(ExtendedEnum a, flags> b) { return b ^ a; } template ::type> inline constexpr auto &operator&=(flags> &a, ExtendedEnum b) { return (a &= details::extended_flags_convert(b)); } template ::type> inline constexpr auto &operator|=(flags> &a, ExtendedEnum b) { return (a |= details::extended_flags_convert(b)); } template ::type> inline constexpr auto &operator^=(flags> &a, ExtendedEnum b) { return (a ^= details::extended_flags_convert(b)); } template ::type> inline constexpr auto operator==(flags> a, ExtendedEnum b) { return a == details::extended_flags_convert(b); } template ::type> inline constexpr auto operator==(ExtendedEnum a, flags> b) { return (b == a); } template ::type> inline constexpr auto operator!=(flags> a, ExtendedEnum b) { return !(a == b); } template ::type> inline constexpr auto operator!=(ExtendedEnum a, flags> b) { return !(a == b); } template ::type> inline constexpr auto operator<(flags> a, ExtendedEnum b) { return a < details::extended_flags_convert(b); } template ::type> inline constexpr auto operator<(ExtendedEnum a, flags> b) { return details::extended_flags_convert(a) < b; } template ::type> inline constexpr auto operator>(flags> a, ExtendedEnum b) { return (b < a); } template ::type> inline constexpr auto operator>(ExtendedEnum a, flags> b) { return (b < a); } template ::type> inline constexpr auto operator<=(flags> a, ExtendedEnum b) { return !(b < a); } template ::type> inline constexpr auto operator<=(ExtendedEnum a, flags> b) { return !(b < a); } template ::type> inline constexpr auto operator>=(flags> a, ExtendedEnum b) { return !(a < b); } template ::type> inline constexpr auto operator>=(ExtendedEnum a, flags> b) { return !(a < b); } } // namespace base template ::value>, typename = std::enable_if_t> inline constexpr auto operator!(Enum a) noexcept { return !base::make_flags(a); } template ::value>, typename = std::enable_if_t> inline constexpr auto operator~(Enum a) noexcept { return ~base::make_flags(a); } template ::value>, typename = std::enable_if_t> inline constexpr auto operator|(Enum a, Enum b) noexcept { return base::make_flags(a) | b; } template ::value>, typename = std::enable_if_t> inline constexpr auto operator|(Enum a, base::details::flags_zero_helper) noexcept { return base::make_flags(a); } template ::value>, typename = std::enable_if_t> inline constexpr auto operator|(base::details::flags_zero_helper, Enum b) noexcept { return base::make_flags(b); } template ::type> inline constexpr auto operator|(ExtendedEnum a, ExtendedEnum b) { return base::details::extended_flags_convert(a) | b; } template ::type> inline constexpr auto operator|(ExtendedEnum a, typename base::extended_flags::type b) { return base::details::extended_flags_convert(a) | b; } template ::type> inline constexpr auto operator|(typename base::extended_flags::type a, ExtendedEnum b) { return b | a; } template ::type> inline constexpr auto operator|(base::details::flags_zero_helper, ExtendedEnum b) { return 0 | base::details::extended_flag_convert(b); } template ::type> inline constexpr auto operator|(ExtendedEnum a, base::details::flags_zero_helper) { return base::details::extended_flag_convert(a) | 0; } template ::type> inline constexpr auto operator~(ExtendedEnum b) { return ~base::details::extended_flags_convert(b); }