#ifndef TEST_BITMASK_TYPE_H
#define TEST_BITMASK_TYPE_H
#include <type_traits>
#include <cassert>
#include "test_macros.h"
template <class EnumType, EnumType Val1, EnumType Val2,
class UT = typename std::underlying_type<EnumType>::type,
UT UVal1 = static_cast<UT>(Val1),
UT UVal2 = static_cast<UT>(Val2),
UT UZero = static_cast<UT>(0),
EnumType Zero = static_cast<EnumType>(0)
>
struct check_bitmask_type {
static constexpr UT dcast(EnumType e) { return static_cast<UT>(e); }
static constexpr UT unpromote(decltype((~UZero)) promoted) { return static_cast<UT>(promoted); }
// We need two values that are non-zero and share at least one bit.
static_assert(Val1 != Zero && Val2 != Zero, "");
static_assert(Val1 != Val2, "");
static_assert((UVal1 & UVal2) == 0, "");
static bool check()
{
{
EnumType ValRef = Val1;
ASSERT_SAME_TYPE(EnumType, decltype(Val1 & Val2));
ASSERT_SAME_TYPE(EnumType, decltype(Val1 | Val2));
ASSERT_SAME_TYPE(EnumType, decltype(Val1 ^ Val2));
ASSERT_SAME_TYPE(EnumType, decltype((~Val1)));
ASSERT_SAME_TYPE(EnumType&, decltype(ValRef &= Val2));
ASSERT_SAME_TYPE(EnumType&, decltype(ValRef |= Val2));
ASSERT_SAME_TYPE(EnumType&, decltype(ValRef ^= Val2));
}
static_assert((Val1 & Zero) == Zero, "");
static_assert((Val1 & Val1) == Val1, "");
static_assert(dcast(Val1 & Val2) == (UVal1 & UVal2), "");
static_assert((Val1 | Zero) == Val1, "");
static_assert(dcast(Val1 | Val2) == (UVal1 | UVal2), "");
static_assert((Val1 ^ Zero) == Val1, "");
static_assert(dcast(Val1 ^ Val2) == (UVal1 ^ UVal2), "");
static_assert(dcast(~Zero) == unpromote(~UZero), "");
static_assert(dcast(~Val1) == unpromote(~UVal1), "");
{
EnumType e = Val1;
EnumType& eref = (e &= Val2);
assert(&eref == &e);
assert(dcast(eref) == (UVal1 & UVal2));
}
{
EnumType e = Val1;
EnumType& eref = (e |= Val2);
assert(&eref == &e);
assert(dcast(eref) == (UVal1 | UVal2));
}
{
EnumType e = Val1;
EnumType& eref = (e ^= Val2);
assert(&eref == &e);
assert(dcast(eref) == (UVal1 ^ UVal2));
}
return true;
}
};
#endif // TEST_BITMASK_TYPE