flags.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. // This file is part of Desktop App Toolkit,
  2. // a set of libraries for developing nice desktop applications.
  3. //
  4. // For license and copyright information please follow this link:
  5. // https://github.com/desktop-app/legal/blob/master/LEGAL
  6. //
  7. #pragma once
  8. #include <type_traits>
  9. namespace base {
  10. template <typename EnumType>
  11. class flags;
  12. template <typename ExtendedEnum>
  13. struct extended_flags;
  14. template <typename ExtendedEnum>
  15. using extended_flags_t = typename extended_flags<ExtendedEnum>::type;
  16. namespace details {
  17. struct flags_zero_helper_struct {
  18. };
  19. using flags_zero_helper = void(base::details::flags_zero_helper_struct::*)();
  20. template <typename ExtendedEnum,
  21. typename Enum = typename base::extended_flags<ExtendedEnum>::type>
  22. inline constexpr auto extended_flag_convert(ExtendedEnum value) {
  23. return static_cast<Enum>(value);
  24. }
  25. template <typename ExtendedEnum,
  26. typename Enum = typename base::extended_flags<ExtendedEnum>::type>
  27. inline constexpr auto extended_flags_convert(ExtendedEnum value) {
  28. return flags<Enum>(extended_flag_convert(value));
  29. }
  30. } // namespace details
  31. template <typename EnumType>
  32. class flags {
  33. public:
  34. using Enum = EnumType;
  35. using Type = std::underlying_type_t<Enum>;
  36. constexpr flags() = default;
  37. constexpr flags(details::flags_zero_helper) noexcept {
  38. }
  39. constexpr flags(Enum value) noexcept
  40. : _value(static_cast<Type>(value)) {
  41. }
  42. static constexpr flags from_raw(Type value) noexcept {
  43. return flags(static_cast<Enum>(value));
  44. }
  45. constexpr auto value() const noexcept {
  46. return _value;
  47. }
  48. constexpr operator Type() const noexcept {
  49. return value();
  50. }
  51. constexpr auto &operator|=(flags b) noexcept {
  52. _value |= b.value();
  53. return *this;
  54. }
  55. constexpr auto &operator&=(flags b) noexcept {
  56. _value &= b.value();
  57. return *this;
  58. }
  59. constexpr auto &operator^=(flags b) noexcept {
  60. _value ^= b.value();
  61. return *this;
  62. }
  63. constexpr auto operator~() const noexcept {
  64. return from_raw(~value());
  65. }
  66. constexpr auto operator|(flags b) const noexcept {
  67. return (flags(*this) |= b);
  68. }
  69. constexpr auto operator&(flags b) const noexcept {
  70. return (flags(*this) &= b);
  71. }
  72. constexpr auto operator^(flags b) const noexcept {
  73. return (flags(*this) ^= b);
  74. }
  75. constexpr auto operator|(Enum b) const noexcept {
  76. return (flags(*this) |= b);
  77. }
  78. constexpr auto operator&(Enum b) const noexcept {
  79. return (flags(*this) &= b);
  80. }
  81. constexpr auto operator^(Enum b) const noexcept {
  82. return (flags(*this) ^= b);
  83. }
  84. constexpr auto operator==(Enum b) const noexcept {
  85. return (value() == static_cast<Type>(b));
  86. }
  87. constexpr auto operator!=(Enum b) const noexcept {
  88. return !(*this == b);
  89. }
  90. constexpr auto operator<(Enum b) const noexcept {
  91. return value() < static_cast<Type>(b);
  92. }
  93. constexpr auto operator>(Enum b) const noexcept {
  94. return (b < *this);
  95. }
  96. constexpr auto operator<=(Enum b) const noexcept {
  97. return !(b < *this);
  98. }
  99. constexpr auto operator>=(Enum b) const noexcept {
  100. return !(*this < b);
  101. }
  102. private:
  103. Type _value = 0;
  104. };
  105. template <typename Enum>
  106. constexpr auto make_flags(Enum value) noexcept {
  107. return flags<Enum>(value);
  108. }
  109. template <typename Enum,
  110. typename = std::enable_if_t<std::is_enum<Enum>::value>,
  111. typename = std::enable_if_t<is_flag_type(Enum{})>>
  112. inline constexpr auto operator|(Enum a, flags<Enum> b) noexcept {
  113. return b | a;
  114. }
  115. template <typename Enum,
  116. typename = std::enable_if_t<std::is_enum<Enum>::value>,
  117. typename = std::enable_if_t<is_flag_type(Enum{})>>
  118. inline constexpr auto operator&(Enum a, flags<Enum> b) noexcept {
  119. return b & a;
  120. }
  121. template <typename Enum,
  122. typename = std::enable_if_t<std::is_enum<Enum>::value>,
  123. typename = std::enable_if_t<is_flag_type(Enum{})>>
  124. inline constexpr auto operator^(Enum a, flags<Enum> b) noexcept {
  125. return b ^ a;
  126. }
  127. template <typename ExtendedEnum,
  128. typename = typename extended_flags<ExtendedEnum>::type>
  129. inline constexpr auto operator|(flags<extended_flags_t<ExtendedEnum>> a, ExtendedEnum b) {
  130. return a | details::extended_flags_convert(b);
  131. }
  132. template <typename ExtendedEnum,
  133. typename = typename extended_flags<ExtendedEnum>::type>
  134. inline constexpr auto operator|(ExtendedEnum a, flags<extended_flags_t<ExtendedEnum>> b) {
  135. return b | a;
  136. }
  137. template <typename ExtendedEnum,
  138. typename = extended_flags_t<ExtendedEnum>>
  139. inline constexpr auto operator&(flags<extended_flags_t<ExtendedEnum>> a, ExtendedEnum b) {
  140. return a & details::extended_flags_convert(b);
  141. }
  142. template <typename ExtendedEnum,
  143. typename = typename extended_flags<ExtendedEnum>::type>
  144. inline constexpr auto operator&(ExtendedEnum a, flags<extended_flags_t<ExtendedEnum>> b) {
  145. return b & a;
  146. }
  147. template <typename ExtendedEnum,
  148. typename = extended_flags_t<ExtendedEnum>>
  149. inline constexpr auto operator^(flags<extended_flags_t<ExtendedEnum>> a, ExtendedEnum b) {
  150. return a ^ details::extended_flags_convert(b);
  151. }
  152. template <typename ExtendedEnum,
  153. typename = typename extended_flags<ExtendedEnum>::type>
  154. inline constexpr auto operator^(ExtendedEnum a, flags<extended_flags_t<ExtendedEnum>> b) {
  155. return b ^ a;
  156. }
  157. template <typename ExtendedEnum,
  158. typename = typename extended_flags<ExtendedEnum>::type>
  159. inline constexpr auto &operator&=(flags<extended_flags_t<ExtendedEnum>> &a, ExtendedEnum b) {
  160. return (a &= details::extended_flags_convert(b));
  161. }
  162. template <typename ExtendedEnum,
  163. typename = typename extended_flags<ExtendedEnum>::type>
  164. inline constexpr auto &operator|=(flags<extended_flags_t<ExtendedEnum>> &a, ExtendedEnum b) {
  165. return (a |= details::extended_flags_convert(b));
  166. }
  167. template <typename ExtendedEnum,
  168. typename = typename extended_flags<ExtendedEnum>::type>
  169. inline constexpr auto &operator^=(flags<extended_flags_t<ExtendedEnum>> &a, ExtendedEnum b) {
  170. return (a ^= details::extended_flags_convert(b));
  171. }
  172. template <typename ExtendedEnum,
  173. typename = typename extended_flags<ExtendedEnum>::type>
  174. inline constexpr auto operator==(flags<extended_flags_t<ExtendedEnum>> a, ExtendedEnum b) {
  175. return a == details::extended_flags_convert(b);
  176. }
  177. template <typename ExtendedEnum,
  178. typename = typename extended_flags<ExtendedEnum>::type>
  179. inline constexpr auto operator==(ExtendedEnum a, flags<extended_flags_t<ExtendedEnum>> b) {
  180. return (b == a);
  181. }
  182. template <typename ExtendedEnum,
  183. typename = typename extended_flags<ExtendedEnum>::type>
  184. inline constexpr auto operator!=(flags<extended_flags_t<ExtendedEnum>> a, ExtendedEnum b) {
  185. return !(a == b);
  186. }
  187. template <typename ExtendedEnum,
  188. typename = typename extended_flags<ExtendedEnum>::type>
  189. inline constexpr auto operator!=(ExtendedEnum a, flags<extended_flags_t<ExtendedEnum>> b) {
  190. return !(a == b);
  191. }
  192. template <typename ExtendedEnum,
  193. typename = typename extended_flags<ExtendedEnum>::type>
  194. inline constexpr auto operator<(flags<extended_flags_t<ExtendedEnum>> a, ExtendedEnum b) {
  195. return a < details::extended_flags_convert(b);
  196. }
  197. template <typename ExtendedEnum,
  198. typename = typename extended_flags<ExtendedEnum>::type>
  199. inline constexpr auto operator<(ExtendedEnum a, flags<extended_flags_t<ExtendedEnum>> b) {
  200. return details::extended_flags_convert(a) < b;
  201. }
  202. template <typename ExtendedEnum,
  203. typename = typename extended_flags<ExtendedEnum>::type>
  204. inline constexpr auto operator>(flags<extended_flags_t<ExtendedEnum>> a, ExtendedEnum b) {
  205. return (b < a);
  206. }
  207. template <typename ExtendedEnum,
  208. typename = typename extended_flags<ExtendedEnum>::type>
  209. inline constexpr auto operator>(ExtendedEnum a, flags<extended_flags_t<ExtendedEnum>> b) {
  210. return (b < a);
  211. }
  212. template <typename ExtendedEnum,
  213. typename = typename extended_flags<ExtendedEnum>::type>
  214. inline constexpr auto operator<=(flags<extended_flags_t<ExtendedEnum>> a, ExtendedEnum b) {
  215. return !(b < a);
  216. }
  217. template <typename ExtendedEnum,
  218. typename = typename extended_flags<ExtendedEnum>::type>
  219. inline constexpr auto operator<=(ExtendedEnum a, flags<extended_flags_t<ExtendedEnum>> b) {
  220. return !(b < a);
  221. }
  222. template <typename ExtendedEnum,
  223. typename = typename extended_flags<ExtendedEnum>::type>
  224. inline constexpr auto operator>=(flags<extended_flags_t<ExtendedEnum>> a, ExtendedEnum b) {
  225. return !(a < b);
  226. }
  227. template <typename ExtendedEnum,
  228. typename = typename extended_flags<ExtendedEnum>::type>
  229. inline constexpr auto operator>=(ExtendedEnum a, flags<extended_flags_t<ExtendedEnum>> b) {
  230. return !(a < b);
  231. }
  232. // For bare-enum operators to work inside namespace base we duplicate them here.
  233. template <typename Enum,
  234. typename = std::enable_if_t<std::is_enum<Enum>::value>,
  235. typename = std::enable_if_t<is_flag_type(Enum{})>>
  236. inline constexpr auto operator!(Enum a) noexcept {
  237. return !make_flags(a);
  238. }
  239. template <typename Enum,
  240. typename = std::enable_if_t<std::is_enum<Enum>::value>,
  241. typename = std::enable_if_t<is_flag_type(Enum{})>>
  242. inline constexpr auto operator~(Enum a) noexcept {
  243. return ~make_flags(a);
  244. }
  245. template <typename Enum,
  246. typename = std::enable_if_t<std::is_enum<Enum>::value>,
  247. typename = std::enable_if_t<is_flag_type(Enum{})>>
  248. inline constexpr auto operator|(Enum a, Enum b) noexcept {
  249. return make_flags(a) | b;
  250. }
  251. template <typename Enum,
  252. typename = std::enable_if_t<std::is_enum<Enum>::value>,
  253. typename = std::enable_if_t<is_flag_type(Enum{})>>
  254. inline constexpr auto operator|(Enum a, details::flags_zero_helper) noexcept {
  255. return make_flags(a);
  256. }
  257. template <typename Enum,
  258. typename = std::enable_if_t<std::is_enum<Enum>::value>,
  259. typename = std::enable_if_t<is_flag_type(Enum{})>>
  260. inline constexpr auto operator|(details::flags_zero_helper, Enum b) noexcept {
  261. return make_flags(b);
  262. }
  263. template <typename ExtendedEnum,
  264. typename = typename extended_flags<ExtendedEnum>::type>
  265. inline constexpr auto operator|(ExtendedEnum a, ExtendedEnum b) {
  266. return details::extended_flags_convert(a) | b;
  267. }
  268. template <typename ExtendedEnum,
  269. typename = typename extended_flags<ExtendedEnum>::type>
  270. inline constexpr auto operator|(ExtendedEnum a, typename extended_flags<ExtendedEnum>::type b) {
  271. return details::extended_flags_convert(a) | b;
  272. }
  273. template <typename ExtendedEnum,
  274. typename = typename extended_flags<ExtendedEnum>::type>
  275. inline constexpr auto operator|(typename extended_flags<ExtendedEnum>::type a, ExtendedEnum b) {
  276. return b | a;
  277. }
  278. template <typename ExtendedEnum,
  279. typename = typename extended_flags<ExtendedEnum>::type>
  280. inline constexpr auto operator|(details::flags_zero_helper, ExtendedEnum b) {
  281. return 0 | details::extended_flag_convert(b);
  282. }
  283. template <typename ExtendedEnum,
  284. typename = typename extended_flags<ExtendedEnum>::type>
  285. inline constexpr auto operator|(ExtendedEnum a, details::flags_zero_helper) {
  286. return details::extended_flag_convert(a) | 0;
  287. }
  288. template <typename ExtendedEnum,
  289. typename = typename extended_flags<ExtendedEnum>::type>
  290. inline constexpr auto operator~(ExtendedEnum b) {
  291. return ~details::extended_flags_convert(b);
  292. }
  293. } // namespace base
  294. template <typename Enum,
  295. typename = std::enable_if_t<std::is_enum<Enum>::value>,
  296. typename = std::enable_if_t<is_flag_type(Enum{})>>
  297. inline constexpr auto operator!(Enum a) noexcept {
  298. return !base::make_flags(a);
  299. }
  300. template <typename Enum,
  301. typename = std::enable_if_t<std::is_enum<Enum>::value>,
  302. typename = std::enable_if_t<is_flag_type(Enum{})>>
  303. inline constexpr auto operator~(Enum a) noexcept {
  304. return ~base::make_flags(a);
  305. }
  306. template <typename Enum,
  307. typename = std::enable_if_t<std::is_enum<Enum>::value>,
  308. typename = std::enable_if_t<is_flag_type(Enum{})>>
  309. inline constexpr auto operator|(Enum a, Enum b) noexcept {
  310. return base::make_flags(a) | b;
  311. }
  312. template <typename Enum,
  313. typename = std::enable_if_t<std::is_enum<Enum>::value>,
  314. typename = std::enable_if_t<is_flag_type(Enum{})>>
  315. inline constexpr auto operator|(Enum a, base::details::flags_zero_helper) noexcept {
  316. return base::make_flags(a);
  317. }
  318. template <typename Enum,
  319. typename = std::enable_if_t<std::is_enum<Enum>::value>,
  320. typename = std::enable_if_t<is_flag_type(Enum{})>>
  321. inline constexpr auto operator|(base::details::flags_zero_helper, Enum b) noexcept {
  322. return base::make_flags(b);
  323. }
  324. template <typename ExtendedEnum,
  325. typename = typename base::extended_flags<ExtendedEnum>::type>
  326. inline constexpr auto operator|(ExtendedEnum a, ExtendedEnum b) {
  327. return base::details::extended_flags_convert(a) | b;
  328. }
  329. template <typename ExtendedEnum,
  330. typename = typename base::extended_flags<ExtendedEnum>::type>
  331. inline constexpr auto operator|(ExtendedEnum a, typename base::extended_flags<ExtendedEnum>::type b) {
  332. return base::details::extended_flags_convert(a) | b;
  333. }
  334. template <typename ExtendedEnum,
  335. typename = typename base::extended_flags<ExtendedEnum>::type>
  336. inline constexpr auto operator|(typename base::extended_flags<ExtendedEnum>::type a, ExtendedEnum b) {
  337. return b | a;
  338. }
  339. template <typename ExtendedEnum,
  340. typename = typename base::extended_flags<ExtendedEnum>::type>
  341. inline constexpr auto operator|(base::details::flags_zero_helper, ExtendedEnum b) {
  342. return 0 | base::details::extended_flag_convert(b);
  343. }
  344. template <typename ExtendedEnum,
  345. typename = typename base::extended_flags<ExtendedEnum>::type>
  346. inline constexpr auto operator|(ExtendedEnum a, base::details::flags_zero_helper) {
  347. return base::details::extended_flag_convert(a) | 0;
  348. }
  349. template <typename ExtendedEnum,
  350. typename = typename base::extended_flags<ExtendedEnum>::type>
  351. inline constexpr auto operator~(ExtendedEnum b) {
  352. return ~base::details::extended_flags_convert(b);
  353. }