1 // Copyright (C) 2016-2020 Jonathan Müller <jonathanmueller.dev@gmail.com>
2 // This file is subject to the license terms in the LICENSE file
3 // found in the top-level directory of this distribution.
4
5 #ifndef TYPE_SAFE_FLAG_SET_HPP_INCLUDED
6 #define TYPE_SAFE_FLAG_SET_HPP_INCLUDED
7
8 #include <climits>
9 #include <cstdint>
10 #include <type_traits>
11
12 #include <type_safe/flag.hpp>
13 #include <type_safe/types.hpp>
14
15 namespace type_safe
16 {
17 /// \exclude
18 namespace detail
19 {
20 template <typename Enum, typename = void>
21 struct is_flag_set : std::false_type
22 {};
23
24 template <typename Enum>
25 struct is_flag_set<Enum, decltype(static_cast<void>(Enum::_flag_set_size))> : std::is_enum<Enum>
26 {};
27
28 template <typename Enum>
29 constexpr typename std::enable_if<is_flag_set<Enum>::value, std::size_t>::type
flag_set_size()30 flag_set_size() noexcept
31 {
32 return static_cast<std::size_t>(Enum::_flag_set_size);
33 }
34
35 template <typename Enum>
36 constexpr typename std::enable_if<!is_flag_set<Enum>::value, std::size_t>::type
flag_set_size()37 flag_set_size() noexcept
38 {
39 return 0u;
40 }
41 } // namespace detail
42
43 /// Traits for the enum used in a [ts::flag_set]().
44 ///
45 /// For each enum that should be used with [ts::flag_set]() it must provide the following interface:
46 /// * Inherit from [std::true_type]().
47 /// * `static constexpr std::size_t size()` that returns the number of enumerators.
48 ///
49 /// The default specialization automatically works for enums that have an enumerator
50 /// `_flag_set_size`, whose value is the number of enumerators. But you can also specialize the
51 /// traits for your own enums. Enums which work with [ts::flag_set]() are called flags.
52 ///
53 /// \requires For all specializations the enum must be contiguous starting at `0`,
54 /// simply don't set an explicit value to the enumerators.
55 template <typename Enum>
56 struct flag_set_traits : detail::is_flag_set<Enum>
57 {
sizetype_safe::flag_set_traits58 static constexpr std::size_t size() noexcept
59 {
60 return detail::flag_set_size<Enum>();
61 }
62 };
63
64 /// Tag type to mark a [ts::flag_set]() without any flags set.
65 struct noflag_t
66 {
noflag_ttype_safe::noflag_t67 constexpr noflag_t() {}
68 };
69
70 /// Tag object of type [ts::noflag_t]().
71 constexpr noflag_t noflag;
72
73 /// \exclude
74 namespace detail
75 {
76 template <std::size_t Size, typename = void>
77 struct select_flag_set_int
78 {
79 static_assert(Size != 0u,
80 "number of bits not supported, complain loud enough so I'll do it");
81 };
82
83 /// \exclude
84 #define TYPE_SAFE_DETAIL_SELECT(Min, Max, Type) \
85 template <std::size_t Size> \
86 struct select_flag_set_int<Size, typename std::enable_if<(Size > Min && Size <= Max)>::type> \
87 { \
88 using type = Type; \
89 };
90
91 TYPE_SAFE_DETAIL_SELECT(0u, 8u, std::uint_least8_t)
92 TYPE_SAFE_DETAIL_SELECT(8u, 16u, std::uint_least16_t)
93 TYPE_SAFE_DETAIL_SELECT(16u, 32u, std::uint_least32_t)
94 TYPE_SAFE_DETAIL_SELECT(32u, sizeof(std::uint_least64_t) * CHAR_BIT, std::uint_least64_t)
95
96 #undef TYPE_SAFE_DETAIL_SELECT
97
98 template <typename Enum, typename Tag = void>
99 class flag_set_impl
100 {
101 public:
102 using traits = flag_set_traits<Enum>;
103 using int_type = typename select_flag_set_int<traits::size()>::type;
104
all_set()105 static constexpr flag_set_impl all_set()
106 {
107 return flag_set_impl(int_type((int_type(1) << traits::size()) - int_type(1)));
108 }
none_set()109 static constexpr flag_set_impl none_set()
110 {
111 return flag_set_impl(int_type(0));
112 }
113
flag_set_impl(const Enum & e)114 explicit constexpr flag_set_impl(const Enum& e) : bits_(mask(e)) {}
115 template <typename Tag2>
flag_set_impl(const flag_set_impl<Enum,Tag2> & other)116 explicit constexpr flag_set_impl(const flag_set_impl<Enum, Tag2>& other)
117 : bits_(other.bits_)
118 {}
119
set(const Enum & e) const120 constexpr flag_set_impl set(const Enum& e) const
121 {
122 return flag_set_impl(bits_ | mask(e));
123 }
reset(const Enum & e) const124 constexpr flag_set_impl reset(const Enum& e) const
125 {
126 return flag_set_impl(bits_ & ~mask(e));
127 }
toggle(const Enum & e) const128 constexpr flag_set_impl toggle(const Enum& e) const
129 {
130 return flag_set_impl(bits_ ^ mask(e));
131 }
132
toggle_all() const133 constexpr flag_set_impl toggle_all() const
134 {
135 return flag_set_impl(bits_ ^ all_set().to_int());
136 }
137
to_int() const138 constexpr int_type to_int() const
139 {
140 return bits_;
141 }
142
is_set(const Enum & e) const143 constexpr bool is_set(const Enum& e) const
144 {
145 return (bits_ & mask(e)) != int_type(0u);
146 }
147
bitwise_or(const flag_set_impl & other) const148 constexpr flag_set_impl bitwise_or(const flag_set_impl& other) const
149 {
150 return flag_set_impl(bits_ | other.bits_);
151 }
152
bitwise_xor(const flag_set_impl & other) const153 constexpr flag_set_impl bitwise_xor(const flag_set_impl& other) const
154 {
155 return flag_set_impl(bits_ ^ other.bits_);
156 }
157
bitwise_and(const flag_set_impl & other) const158 constexpr flag_set_impl bitwise_and(const flag_set_impl& other) const
159 {
160 return flag_set_impl(bits_ & other.bits_);
161 }
162
163 private:
mask(const Enum & e)164 static constexpr int_type mask(const Enum& e)
165 {
166 return int_type(int_type(1u) << static_cast<std::size_t>(e));
167 }
168
169 template <typename T, typename = typename std::enable_if<std::is_integral<T>::value
170 && std::is_unsigned<T>::value>>
flag_set_impl(T bits)171 explicit constexpr flag_set_impl(T bits) : bits_(int_type(bits))
172 {}
173
174 int_type bits_;
175
176 template <typename Enum2, typename Tag2>
177 friend class flag_set_impl;
178 };
179
180 template <typename Enum>
181 using flag_combo = flag_set_impl<Enum, struct combo_tag>;
182
183 template <typename Enum>
184 using flag_mask = flag_set_impl<Enum, struct mask_tag>;
185
186 template <typename Enum>
operator ==(const flag_combo<Enum> & a,noflag_t)187 constexpr bool operator==(const flag_combo<Enum>& a, noflag_t)
188 {
189 return a == a.none_set();
190 }
191 template <typename Enum>
operator ==(noflag_t,const flag_combo<Enum> & a)192 constexpr bool operator==(noflag_t, const flag_combo<Enum>& a)
193 {
194 return a == a.none_set();
195 }
196 template <typename Enum>
operator ==(const flag_combo<Enum> & a,const flag_combo<Enum> & b)197 constexpr bool operator==(const flag_combo<Enum>& a, const flag_combo<Enum>& b)
198 {
199 return a.to_int() == b.to_int();
200 }
201 template <typename Enum>
operator ==(const flag_combo<Enum> & a,const Enum & b)202 constexpr bool operator==(const flag_combo<Enum>& a, const Enum& b)
203 {
204 return a == flag_combo<Enum>(b);
205 }
206 template <typename Enum>
operator ==(const Enum & a,const flag_combo<Enum> & b)207 constexpr bool operator==(const Enum& a, const flag_combo<Enum>& b)
208 {
209 return flag_combo<Enum>(a) == b;
210 }
211
212 template <typename Enum>
operator !=(const flag_combo<Enum> & a,noflag_t b)213 constexpr bool operator!=(const flag_combo<Enum>& a, noflag_t b)
214 {
215 return !(a == b);
216 }
217 template <typename Enum>
operator !=(noflag_t a,const flag_combo<Enum> & b)218 constexpr bool operator!=(noflag_t a, const flag_combo<Enum>& b)
219 {
220 return !(a == b);
221 }
222 template <typename Enum>
operator !=(const flag_combo<Enum> & a,const flag_combo<Enum> & b)223 constexpr bool operator!=(const flag_combo<Enum>& a, const flag_combo<Enum>& b)
224 {
225 return !(a == b);
226 }
227 template <typename Enum>
operator !=(const flag_combo<Enum> & a,const Enum & b)228 constexpr bool operator!=(const flag_combo<Enum>& a, const Enum& b)
229 {
230 return !(a == b);
231 }
232 template <typename Enum>
operator !=(const Enum & a,const flag_combo<Enum> & b)233 constexpr bool operator!=(const Enum& a, const flag_combo<Enum>& b)
234 {
235 return !(a == b);
236 }
237
238 template <typename Enum>
operator |(const flag_combo<Enum> & a,const flag_combo<Enum> & b)239 constexpr flag_combo<Enum> operator|(const flag_combo<Enum>& a, const flag_combo<Enum>& b)
240 {
241 return a.bitwise_or(b);
242 }
243 template <typename Enum>
operator |(const flag_combo<Enum> & a,const Enum & b)244 constexpr flag_combo<Enum> operator|(const flag_combo<Enum>& a, const Enum& b)
245 {
246 return a | flag_combo<Enum>(b);
247 }
248 template <typename Enum>
operator |(const Enum & a,const flag_combo<Enum> & b)249 constexpr flag_combo<Enum> operator|(const Enum& a, const flag_combo<Enum>& b)
250 {
251 return flag_combo<Enum>(a) | b;
252 }
253
254 template <typename Enum>
operator ==(const flag_mask<Enum> & a,const flag_mask<Enum> & b)255 constexpr bool operator==(const flag_mask<Enum>& a, const flag_mask<Enum>& b)
256 {
257 return a.to_int() == b.to_int();
258 }
259 template <typename Enum>
operator ==(const flag_mask<Enum> & a,noflag_t)260 constexpr bool operator==(const flag_mask<Enum>& a, noflag_t)
261 {
262 return a == a.none_set();
263 }
264 template <typename Enum>
operator ==(noflag_t,const flag_mask<Enum> & a)265 constexpr bool operator==(noflag_t, const flag_mask<Enum>& a)
266 {
267 return a == a.none_set();
268 }
269 template <typename Enum>
operator !=(const flag_mask<Enum> & a,const flag_mask<Enum> & b)270 constexpr bool operator!=(const flag_mask<Enum>& a, const flag_mask<Enum>& b)
271 {
272 return !(a == b);
273 }
274 template <typename Enum>
operator !=(const flag_mask<Enum> & a,noflag_t b)275 constexpr bool operator!=(const flag_mask<Enum>& a, noflag_t b)
276 {
277 return !(a == b);
278 }
279 template <typename Enum>
operator !=(noflag_t a,const flag_mask<Enum> & b)280 constexpr bool operator!=(noflag_t a, const flag_mask<Enum>& b)
281 {
282 return !(a == b);
283 }
284
285 template <typename Enum>
operator &(const flag_mask<Enum> & a,const flag_mask<Enum> & b)286 constexpr flag_mask<Enum> operator&(const flag_mask<Enum>& a, const flag_mask<Enum>& b)
287 {
288 return a.bitwise_and(b);
289 }
290
291 template <typename Enum>
operator ~(const flag_combo<Enum> & a)292 constexpr flag_mask<Enum> operator~(const flag_combo<Enum>& a)
293 {
294 return flag_mask<Enum>(a.toggle_all());
295 }
296 template <typename Enum>
operator ~(const flag_mask<Enum> & a)297 constexpr flag_combo<Enum> operator~(const flag_mask<Enum>& a)
298 {
299 return flag_combo<Enum>(a.toggle_all());
300 }
301
302 template <typename T, typename Enum>
303 struct is_flag_combo : std::false_type
304 {};
305
306 template <typename Enum>
307 struct is_flag_combo<Enum, Enum> : flag_set_traits<Enum>
308 {};
309
310 template <typename Enum>
311 struct is_flag_combo<flag_combo<Enum>, Enum> : flag_set_traits<Enum>
312 {};
313
314 template <typename T>
315 using enable_flag = typename std::enable_if<flag_set_traits<T>::value>::type;
316
317 template <typename T, typename Enum>
318 using enable_flag_combo = typename std::enable_if<is_flag_combo<T, Enum>::value>::type;
319
320 struct get_flag_set_impl
321 {
322 template <class Set>
gettype_safe::detail::get_flag_set_impl323 static constexpr auto get(const Set& set) -> decltype(set.flags_)
324 {
325 return set.flags_;
326 }
327 };
328 } // namespace detail
329
330 /// Represents a combination of multiple flags.
331 ///
332 /// This type is created when you write `a | b`,
333 /// where `a` and `b` are enumerators of a flag.
334 ///
335 /// Objects of this type and the flags themselves
336 /// are flag combinations.
337 /// You can compare two flag combinations,
338 /// combine two with `|`
339 /// and use them in [ts::flag_set]() to set or toggle a combination of flags.
340 /// Creating the complement with `~` will create a [ts::flag_mask]().
341 ///
342 /// \requires `Enum` must be a flag,
343 /// i.e. valid with the [ts::flag_set_traits]().
344 template <typename Enum>
345 using flag_combo = detail::flag_combo<Enum>;
346
347 /// Represents a mask of flags.
348 ///
349 /// This type is created when you write `~a`,
350 /// where `a` is the enumerator of a flag.
351 ///
352 /// Objects of this type are flag masks.
353 /// You can compare two flag masks,
354 /// combine them with `&`
355 /// and use them in [ts::flag_set]() to clear a combination of flags.
356 /// Creating the complement with `~` will create a [ts::flag_combo]().
357 ///
358 /// \requires `Enum` must be a flag,
359 /// i.e. valid with the [ts::flag_set_traits]().
360 template <typename Enum>
361 using flag_mask = detail::flag_mask<Enum>;
362
363 /// Converts a flag mask to a flag combination.
364 /// \returns The flag combination with the same value as the mask.
365 /// \notes As you cannot use a mask to set flags in a [ts::flag_set](),
366 /// you cannot write `~a` to set all flags except `a` directly,
367 /// you have to be explicit.
368 template <typename Enum>
combo(const flag_mask<Enum> & mask)369 constexpr flag_combo<Enum> combo(const flag_mask<Enum>& mask) noexcept
370 {
371 return flag_combo<Enum>(mask);
372 }
373
374 /// Converts a flag combination to a flag mask.
375 /// \returns The flag mask with the same value as the flag combination.
376 /// \notes (1) does not participate in overload resolution,
377 /// unless the argument is a flagg.
378 /// \notes As you cannot use a combination to clear flags in a [ts::flag_set](),
379 /// you cannot write `a` to clear all flags except `a` directly,
380 /// you have to be explicit.
381 /// \group mask_combo
382 /// \param 1
383 /// \exclude
384 template <typename Enum, typename = detail::enable_flag<Enum>>
mask(const Enum & flag)385 constexpr flag_mask<Enum> mask(const Enum& flag) noexcept
386 {
387 return flag_mask<Enum>(flag);
388 }
389
390 /// \group mask_combo
391 template <typename Enum>
mask(const flag_combo<Enum> & combo)392 constexpr flag_mask<Enum> mask(const flag_combo<Enum>& combo) noexcept
393 {
394 return flag_mask<Enum>(combo);
395 }
396
397 /// A set of flags where each one can either be `0` or `1`.
398 ///
399 /// Each enumeration member represents the index of one bit.
400 ///
401 /// Unlike [ts::flag_combo]() or [ts::flag_mask]() this does not have this semantic distinction.
402 /// It is just a generic container of flags,
403 /// which can be set, cleared or toggled.
404 /// It can be interpreted as either a flag combination or flag mask, however.
405 ///
406 /// \requires `Enum` must be a flag,
407 /// i.e. valid with the [ts::flag_set_traits]().
408 template <typename Enum>
409 class flag_set
410 {
411 static_assert(std::is_enum<Enum>::value, "not an enum");
412 static_assert(flag_set_traits<Enum>::value, "invalid enum for flag_set");
413
414 public:
415 //=== constructors/assignment ===//
416 /// \effects Creates a set where all flags are set to `0`.
417 /// \group ctor_null
flag_set()418 constexpr flag_set() noexcept : flags_(detail::flag_set_impl<Enum>::none_set()) {}
419
420 /// \group ctor_null
flag_set(noflag_t)421 constexpr flag_set(noflag_t) noexcept : flag_set() {}
422
423 /// \effects Creates a set where all bits are set to `0` except the given ones.
424 /// \notes This constructor only participates in overload resolution
425 /// if the argument is a flag combination.
426 template <typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
flag_set(const FlagCombo & combo)427 constexpr flag_set(const FlagCombo& combo) noexcept : flags_(combo)
428 {}
429
430 /// \effects Same as `*this = flag_set(combo)`.
431 template <typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
operator =(const FlagCombo & combo)432 flag_set& operator=(const FlagCombo& combo) noexcept
433 {
434 return *this = flag_set(combo);
435 }
436
437 /// \effects Same as [*reset_all]().
operator =(noflag_t)438 flag_set& operator=(noflag_t) noexcept
439 {
440 reset_all();
441 return *this;
442 }
443
444 //=== flag operation ===//
445 /// \effects Sets the specified flag to `1` (1)/`value` (2/3).
446 /// \notes (2) does not participate in overload resolution unless `T` is a boolean-like type.
447 /// \group set
set(const Enum & flag)448 void set(const Enum& flag) noexcept
449 {
450 flags_ = flags_.set(flag);
451 }
452
453 /// \group set
454 /// \param 1
455 /// \exclude
456 template <typename T, typename = detail::enable_boolean<T>>
set(const Enum & flag,T value)457 void set(const Enum& flag, T value) noexcept
458 {
459 if (value)
460 set(flag);
461 else
462 reset(flag);
463 }
464
465 /// \group set
set(const Enum & f,flag value)466 void set(const Enum& f, flag value) noexcept
467 {
468 set(f, value == true);
469 }
470
471 /// \effects Sets the specified flag to `0`.
reset(const Enum & flag)472 void reset(const Enum& flag) noexcept
473 {
474 flags_ = flags_.reset(flag);
475 }
476
477 /// \effects Toggles the specified flag.
toggle(const Enum & flag)478 void toggle(const Enum& flag) noexcept
479 {
480 flags_ = flags_.toggle(flag);
481 }
482
483 /// \effects Sets/resets/toggles all flags.
484 /// \group all
set_all()485 void set_all() noexcept
486 {
487 flags_ = flags_.all_set();
488 }
489
490 /// \group all
491 /// \param 1
492 /// \exclude
493 template <typename T, typename = detail::enable_boolean<T>>
set_all(T value)494 void set_all(T value) noexcept
495 {
496 if (value)
497 set_all();
498 else
499 reset_all();
500 }
501
502 /// \group all
set_all(flag value)503 void set_all(flag value) noexcept
504 {
505 set_all(value == true);
506 }
507
508 /// \group all
reset_all()509 void reset_all() noexcept
510 {
511 flags_ = flags_.none_set();
512 }
513
514 /// \group all
toggle_all()515 void toggle_all() noexcept
516 {
517 flags_ = flags_.toggle_all();
518 }
519
520 /// \returns Whether or not the specified flag is set.
is_set(const Enum & flag) const521 constexpr bool is_set(const Enum& flag) const noexcept
522 {
523 return flags_.is_set(flag);
524 }
525
526 /// \returns Same as `flag(is_set(flag))`.
as_flag(const Enum & flag) const527 constexpr flag as_flag(const Enum& flag) const noexcept
528 {
529 return is_set(flag);
530 }
531
532 //=== accessors ===//
533 /// \returns Whether any flag is set.
any() const534 constexpr bool any() const noexcept
535 {
536 return flags_.to_int() != flags_.none_set().to_int();
537 }
538
539 /// \returns Whether all flags are set.
all() const540 constexpr bool all() const noexcept
541 {
542 return flags_.to_int() == flags_.all_set().to_int();
543 }
544
545 /// \returns Whether no flag is set.
none() const546 constexpr bool none() const noexcept
547 {
548 return !any();
549 }
550
551 /// \returns An integer where each bit has the value of the corresponding flag.
552 /// \requires `T` must be an unsigned integer type with enough bits.
553 template <typename T>
to_int() const554 constexpr T to_int() const noexcept
555 {
556 static_assert(std::is_unsigned<T>::value
557 && sizeof(T) * CHAR_BIT >= flag_set_traits<Enum>::size(),
558 "invalid integer type, lossy conversion");
559 return flags_.to_int();
560 }
561
562 //=== bitwise operations ===//
563 /// \returns A set with all the flags flipped.
operator ~() const564 constexpr flag_set operator~() const noexcept
565 {
566 return flag_set(flag_combo<Enum>(flags_.toggle_all()));
567 }
568
569 /// \effects Sets all flags that are set in the given flag combination.
570 /// \returns `*this`
571 /// \notes This operator does not participate in overload resolution,
572 /// unless the argument is a flag combination.
573 /// If you truly want to write `set |= ~a`,
574 /// i.e. set all flags except `a`, use `set |= combo(~a)`.
575 template <typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
operator |=(const FlagCombo & other)576 flag_set& operator|=(const FlagCombo& other) noexcept
577 {
578 flags_ = flags_.bitwise_or(detail::flag_set_impl<Enum>(other));
579 return *this;
580 }
581
582 /// \effects Toggles all flags that are set in the given flag combination.
583 /// \returns `*this`
584 /// \notes This operator does not participate in overload resolution,
585 /// unless the argument is a flag combination.
586 /// If you truly want to write `set ^= ~a`,
587 /// i.e. toggle all flags except `a`, use `set ^= combo(~a)`.
588 template <typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
operator ^=(const FlagCombo & other)589 flag_set& operator^=(const FlagCombo& other) noexcept
590 {
591 flags_ = flags_.bitwise_xor(detail::flag_set_impl<Enum>(other));
592 return *this;
593 }
594
595 /// \effects Clears all flags that aren't set in the given flag mask.
596 /// \returns `*this`
597 /// \notes This operator does not participate in overload resolution,
598 /// unless the argument is a flag mask.
599 /// If you truly want to write `set &= a`,
600 /// i.e. clear all flags except `a`, use `set &= mask(a)`.
operator &=(const flag_mask<Enum> & other)601 flag_set& operator&=(const flag_mask<Enum>& other) noexcept
602 {
603 flags_ = flags_.bitwise_and(detail::flag_set_impl<Enum>(other));
604 return *this;
605 }
606
607 private:
608 detail::flag_set_impl<Enum> flags_;
609
610 friend detail::get_flag_set_impl;
611 };
612
613 /// Converts a [ts::flag_set]() to a flag combination.
614 /// \returns The flag combination with the same value as the set.
615 template <typename Enum>
combo(const flag_set<Enum> & set)616 constexpr flag_combo<Enum> combo(const flag_set<Enum>& set) noexcept
617 {
618 return flag_combo<Enum>(detail::get_flag_set_impl::get(set));
619 }
620
621 /// Converts a [ts::flag_set]() to a flag mask.
622 /// \returns The flag mask with the same value as the set.
623 template <typename Enum>
mask(const flag_set<Enum> & set)624 constexpr flag_mask<Enum> mask(const flag_set<Enum>& set) noexcept
625 {
626 return flag_mask<Enum>(detail::get_flag_set_impl::get(set));
627 }
628
629 /// `flag_set` equality comparison.
630 /// \returns Whether both flag sets have the same combination of flags set/not set.
631 /// \group flag_set_equal flag_set equality comparison
632 template <typename Enum>
operator ==(const flag_set<Enum> & a,const flag_set<Enum> & b)633 constexpr bool operator==(const flag_set<Enum>& a, const flag_set<Enum>& b) noexcept
634 {
635 return combo(a) == combo(b);
636 }
637
638 /// \group flag_set_equal
639 template <typename Enum>
operator ==(const flag_set<Enum> & a,noflag_t b)640 constexpr bool operator==(const flag_set<Enum>& a, noflag_t b) noexcept
641 {
642 return combo(a) == b;
643 }
644
645 /// \group flag_set_equal
646 template <typename Enum>
operator ==(noflag_t a,const flag_set<Enum> & b)647 constexpr bool operator==(noflag_t a, const flag_set<Enum>& b) noexcept
648 {
649 return a == combo(b);
650 }
651
652 /// \group flag_set_equal
653 template <typename Enum, typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
operator ==(const flag_set<Enum> & a,const FlagCombo & b)654 constexpr bool operator==(const flag_set<Enum>& a, const FlagCombo& b) noexcept
655 {
656 return combo(a) == b;
657 }
658
659 /// \group flag_set_equal
660 template <typename Enum, typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
operator ==(const FlagCombo & a,const flag_set<Enum> & b)661 constexpr bool operator==(const FlagCombo& a, const flag_set<Enum>& b) noexcept
662 {
663 return a == combo(b);
664 }
665
666 /// \group flag_set_equal
667 template <typename Enum>
operator !=(const flag_set<Enum> & a,const flag_set<Enum> & b)668 constexpr bool operator!=(const flag_set<Enum>& a, const flag_set<Enum>& b) noexcept
669 {
670 return !(a == b);
671 }
672
673 /// \group flag_set_equal
674 template <typename Enum>
operator !=(const flag_set<Enum> & a,noflag_t b)675 constexpr bool operator!=(const flag_set<Enum>& a, noflag_t b) noexcept
676 {
677 return !(a == b);
678 }
679
680 /// \group flag_set_equal
681 template <typename Enum>
operator !=(noflag_t a,const flag_set<Enum> & b)682 constexpr bool operator!=(noflag_t a, const flag_set<Enum>& b) noexcept
683 {
684 return !(a == b);
685 }
686
687 /// \group flag_set_equal
688 template <typename Enum, typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
operator !=(const flag_set<Enum> & a,const FlagCombo & b)689 constexpr bool operator!=(const flag_set<Enum>& a, const FlagCombo& b) noexcept
690 {
691 return !(a == b);
692 }
693
694 /// \group flag_set_equal
695 template <typename Enum, typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
operator !=(const FlagCombo & a,const flag_set<Enum> & b)696 constexpr bool operator!=(const FlagCombo& a, const flag_set<Enum>& b) noexcept
697 {
698 return !(a == b);
699 }
700
701 /// \returns The same as `a Op= b`.
702 /// \group bitwise_op Bitwise operations for flag_set
703 /// \param 2
704 /// \exclude
705 template <typename Enum, typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
operator |(const flag_set<Enum> & a,const FlagCombo & b)706 constexpr flag_set<Enum> operator|(const flag_set<Enum>& a, const FlagCombo& b)
707 {
708 return combo(a).bitwise_or(flag_combo<Enum>(b));
709 }
710 /// \group bitwise_op
711 /// \param 2
712 /// \exclude
713 template <typename Enum, typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
operator |(const FlagCombo & a,const flag_set<Enum> & b)714 constexpr flag_set<Enum> operator|(const FlagCombo& a, const flag_set<Enum>& b)
715 {
716 return b | a;
717 }
718 /// \group bitwise_op
719 /// \param 2
720 /// \exclude
721 template <typename Enum, typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
operator ^(const flag_set<Enum> & a,const FlagCombo & b)722 constexpr flag_set<Enum> operator^(const flag_set<Enum>& a, const FlagCombo& b)
723 {
724 return combo(a).bitwise_xor(flag_combo<Enum>(b));
725 }
726 /// \group bitwise_op
727 /// \param 2
728 /// \exclude
729 template <typename Enum, typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
operator ^(const FlagCombo & a,const flag_set<Enum> & b)730 constexpr flag_set<Enum> operator^(const FlagCombo& a, const flag_set<Enum>& b)
731 {
732 return b ^ a;
733 }
734 /// \group bitwise_op
735 template <typename Enum>
operator &(const flag_set<Enum> & a,const flag_mask<Enum> & b)736 constexpr flag_set<Enum> operator&(const flag_set<Enum>& a, const flag_mask<Enum>& b)
737 {
738 return combo(mask(a).bitwise_and(b));
739 }
740 /// \group bitwise_op
741 template <typename Enum>
operator &(const flag_mask<Enum> & a,const flag_set<Enum> & b)742 constexpr flag_set<Enum> operator&(const flag_mask<Enum>& a, const flag_set<Enum>& b)
743 {
744 return b & a;
745 }
746
747 /// Checks whether a combination of flags is set in `a`.
748 /// \returns `true` if all the flags set in `b` are also set in `a`,
749 /// `false` otherwise.
750 /// \notes These functions do not participate in overload resolution,
751 /// unless `FlagCombo` is a flag operation.
752 /// \group bitwise_and_check Bitwise and for flag_set
753 /// \param 2
754 /// \exclude
755 template <typename Enum, typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
operator &(const flag_set<Enum> & a,const FlagCombo & b)756 constexpr bool operator&(const flag_set<Enum>& a, const FlagCombo& b)
757 {
758 return static_cast<bool>(combo(a).bitwise_and(flag_combo<Enum>(b)).to_int());
759 }
760 /// \group bitwise_and_check
761 /// \param 2
762 /// \exclude
763 template <typename Enum, typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
operator &(const FlagCombo & a,const flag_set<Enum> & b)764 constexpr bool operator&(const FlagCombo& a, const flag_set<Enum>& b)
765 {
766 return b & a;
767 }
768 } // namespace type_safe
769
770 /// Creates a [ts::flag_mask]() for the single enum value.
771 /// \returns A [ts::flag_mask]() where all bits are set,
772 /// unless the given one.
773 /// \notes This function does not participate in overload resolution,
774 /// unless `Enum` is an `enum` where the [ts::flag_set_traits]() are specialized.
775 /// \param 1
776 /// \exclude
777 template <typename Enum, typename = type_safe::detail::enable_flag<Enum>>
operator ~(const Enum & e)778 constexpr type_safe::flag_mask<Enum> operator~(const Enum& e) noexcept
779 {
780 return type_safe::flag_mask<Enum>::all_set().reset(e);
781 }
782
783 /// Creates a [ts::flag_combo]() from two enums.
784 /// \returns A [ts::flag_combo]() where the two given bits are set.
785 /// \notes These functions do not participate in overload resolution,
786 /// unless `Enum` is an `enum` where the [ts::flag_set_traits]() are specialized.
787 /// \param 1
788 /// \exclude
789 template <typename Enum, typename = type_safe::detail::enable_flag<Enum>>
operator |(const Enum & a,const Enum & b)790 constexpr type_safe::flag_combo<Enum> operator|(const Enum& a, const Enum& b) noexcept
791 {
792 return type_safe::flag_combo<Enum>(a) | b;
793 }
794
795 #endif // TYPE_SAFE_FLAG_SET_HPP_INCLUDED
796