1#ifndef TEST_BITMASK_TYPE_HPP
2#define TEST_BITMASK_TYPE_HPP
3
4#include <type_traits>
5#include <cassert>
6
7#include "test_macros.h"
8
9
10template <class EnumType, EnumType Val1, EnumType Val2,
11          class UT = typename std::underlying_type<EnumType>::type,
12          UT UVal1 = static_cast<UT>(Val1),
13          UT UVal2 = static_cast<UT>(Val2),
14          UT UZero = static_cast<UT>(0),
15          EnumType Zero = static_cast<EnumType>(0)
16        >
17struct check_bitmask_type {
18
19  static constexpr UT dcast(EnumType e) { return static_cast<UT>(e); }
20  static constexpr UT unpromote(decltype((~UZero)) promoted) { return static_cast<UT>(promoted); }
21  // We need two values that are non-zero and share at least one bit.
22  static_assert(Val1 != Zero && Val2 != Zero, "");
23  static_assert(Val1 != Val2, "");
24  static_assert((UVal1 & UVal2) == 0, "");
25
26
27  static bool check()
28  {
29    {
30      EnumType ValRef = Val1;
31      ASSERT_SAME_TYPE(EnumType, decltype(Val1 & Val2));
32      ASSERT_SAME_TYPE(EnumType, decltype(Val1 | Val2));
33      ASSERT_SAME_TYPE(EnumType, decltype(Val1 ^ Val2));
34      ASSERT_SAME_TYPE(EnumType, decltype((~Val1)));
35      ASSERT_SAME_TYPE(EnumType&, decltype(ValRef &= Val2));
36      ASSERT_SAME_TYPE(EnumType&, decltype(ValRef |= Val2));
37      ASSERT_SAME_TYPE(EnumType&, decltype(ValRef ^= Val2));
38    }
39
40    static_assert((Val1 & Zero) == Zero, "");
41    static_assert((Val1 & Val1) == Val1, "");
42    static_assert(dcast(Val1 & Val2) == (UVal1 & UVal2), "");
43
44    static_assert((Val1 | Zero) == Val1, "");
45    static_assert(dcast(Val1 | Val2) == (UVal1 | UVal2), "");
46
47    static_assert((Val1 ^ Zero) == Val1, "");
48    static_assert(dcast(Val1 ^ Val2) == (UVal1 ^ UVal2), "");
49
50    static_assert(dcast(~Zero) == unpromote(~UZero), "");
51    static_assert(dcast(~Val1) == unpromote(~UVal1), "");
52
53    {
54      EnumType e = Val1;
55      EnumType& eref = (e &= Val2);
56      assert(&eref == &e);
57      assert(dcast(eref) == (UVal1 & UVal2));
58    }
59    {
60      EnumType e = Val1;
61      EnumType& eref = (e |= Val2);
62      assert(&eref == &e);
63      assert(dcast(eref) == (UVal1 | UVal2));
64    }
65    {
66      EnumType e = Val1;
67      EnumType& eref = (e ^= Val2);
68      assert(&eref == &e);
69      assert(dcast(eref) == (UVal1 ^ UVal2));
70    }
71    return true;
72  }
73};
74
75#endif // TEST_BITMASK_TYPE
76