// // EnumClass.h // ArticleEnumClass // // Created by Gabriel Aubut-Lussier on 17-08-07. // Copyright © 2017 Gabriel Aubut-Lussier. All rights reserved. // #ifndef EnumClass_h #define EnumClass_h #include #include template struct enable_enum_class_bitmask { static constexpr bool value = false; }; #define enableEnumClassBitmask(T) template<> \ struct enable_enum_class_bitmask \ { \ static constexpr bool value = true; \ } /** * Wrapper for an enumerator that provides implicit bool conversion */ template struct enumerator { constexpr enumerator(const T& value) : value(value) {} constexpr explicit operator bool() const { using underlying_type = typename std::underlying_type::type; return static_cast(value) != 0; } constexpr operator T() const { return value; } T value; }; /** * Wrapper that differentiates combined enumerators from a single enumerator * to provent accidental comparisons between a bitmask and a single enumerator * using operator== or operator!= */ template struct bitmask { using underlying_type = typename std::underlying_type::type; constexpr bitmask(const T& value) : value(static_cast(value)) {} constexpr bitmask(const enumerator& enumerator) : value(static_cast(enumerator.value)) {} constexpr explicit operator bool() const { return value != 0; } underlying_type value; }; template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bitmask>::type make_bitmask(const T& t) { return bitmask{t}; } /** * operator&(T, T) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, enumerator>::type operator&(const T& lhs, const T& rhs) { using underlying_type = typename std::underlying_type::type; assert((static_cast(lhs) & (static_cast(lhs) - 1)) == 0); return enumerator{static_cast(static_cast(lhs) & static_cast(rhs))}; } /** * operator&(enumerator, enumerator) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, enumerator>::type operator&(const enumerator& lhs, const enumerator& rhs) { using underlying_type = typename std::underlying_type::type; return enumerator{static_cast(static_cast(lhs.value) & static_cast(rhs.value))}; } /** * operator&(bitmask, bitmask) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bitmask>::type operator&(const bitmask& lhs, const bitmask& rhs) { return bitmask{static_cast(lhs.value & rhs.value)}; } /** * operator&(bitmask, T) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, enumerator>::type operator&(const bitmask& lhs, const T& rhs) { using underlying_type = typename std::underlying_type::type; return enumerator{static_cast(lhs.value & static_cast(rhs))}; } /** * operator&(T, bitmask) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, enumerator>::type operator&(const T& lhs, const bitmask& rhs) { using underlying_type = typename std::underlying_type::type; return enumerator{static_cast(static_cast(lhs) & rhs.value)}; } /** * operator&(bitmask, enumerator) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, enumerator>::type operator&(const bitmask& lhs, const enumerator& rhs) { using underlying_type = typename std::underlying_type::type; return enumerator{static_cast(lhs.value & static_cast(rhs.value))}; } /** * operator&(enumerator, bitmask) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, enumerator>::type operator&(const enumerator& lhs, const bitmask& rhs) { using underlying_type = typename std::underlying_type::type; return enumerator{static_cast(static_cast(lhs.value) & rhs.value)}; } /** * operator&(T, enumerator) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, enumerator>::type operator&(const T& lhs, const enumerator& rhs) { using underlying_type = typename std::underlying_type::type; return enumerator{static_cast(static_cast(lhs) & static_cast(rhs.value))}; } /** * operator&(enumerator, T) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, enumerator>::type operator&(const enumerator& lhs, const T& rhs) { using underlying_type = typename std::underlying_type::type; return enumerator{static_cast(static_cast(lhs.value) & static_cast(rhs))}; } /** * operator|(T, T) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bitmask>::type operator|(const T& lhs, const T& rhs) { using underlying_type = typename std::underlying_type::type; return bitmask{static_cast(static_cast(lhs) | static_cast(rhs))}; } /** * operator|(enumerator, enumerator) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bitmask>::type operator|(const enumerator& lhs, const enumerator& rhs) { using underlying_type = typename std::underlying_type::type; return bitmask{static_cast(static_cast(lhs.value) | static_cast(rhs.value))}; } /** * operator|(bitmask, bitmask) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bitmask>::type operator|(const bitmask& lhs, const bitmask& rhs) { return bitmask{static_cast(lhs.value | rhs.value)}; } /** * operator|(bitmask, T) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bitmask>::type operator|(const bitmask& lhs, const T& rhs) { using underlying_type = typename std::underlying_type::type; return bitmask{static_cast(lhs.value | static_cast(rhs))}; } /** * operator|(T, bitmask) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bitmask>::type operator|(const T& lhs, const bitmask& rhs) { using underlying_type = typename std::underlying_type::type; return bitmask{static_cast(static_cast(lhs) | rhs.value)}; } /** * operator|(bitmask, enumerator) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bitmask>::type operator|(const bitmask& lhs, const enumerator& rhs) { using underlying_type = typename std::underlying_type::type; return bitmask{static_cast(lhs.value | static_cast(rhs.value))}; } /** * operator|(enumerator, bitmask) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bitmask>::type operator|(const enumerator& lhs, const bitmask& rhs) { using underlying_type = typename std::underlying_type::type; return bitmask{static_cast(static_cast(lhs.value) | rhs.value)}; } /** * operator|(enumerator, T) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bitmask>::type operator|(const enumerator& lhs, const T& rhs) { using underlying_type = typename std::underlying_type::type; return bitmask{static_cast(static_cast(lhs.value) | static_cast(rhs))}; } /** * operator|(T, enumerator) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bitmask>::type operator|(const T& lhs, const enumerator& rhs) { using underlying_type = typename std::underlying_type::type; return bitmask{static_cast(static_cast(lhs) | static_cast(rhs.value))}; } /** * operator^(T, T) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bitmask>::type operator^(const T& lhs, const T& rhs) { using underlying_type = typename std::underlying_type::type; return bitmask{static_cast(static_cast(lhs) ^ static_cast(rhs))}; } /** * operator^(enumerator, enumerator) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bitmask>::type operator^(const enumerator& lhs, const enumerator& rhs) { using underlying_type = typename std::underlying_type::type; return bitmask{static_cast(static_cast(lhs.value) ^ static_cast(rhs.value))}; } /** * operator^(bitmask, bitmask) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bitmask>::type operator^(const bitmask& lhs, const bitmask& rhs) { return bitmask{static_cast(lhs.value ^ rhs.value)}; } /** * operator^(bitmask, T) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bitmask>::type operator^(const bitmask& lhs, const T& rhs) { using underlying_type = typename std::underlying_type::type; return bitmask{static_cast(lhs.value ^ static_cast(rhs))}; } /** * operator^(T, bitmask) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bitmask>::type operator^(const T& lhs, const bitmask& rhs) { using underlying_type = typename std::underlying_type::type; return bitmask{static_cast(static_cast(lhs) ^ rhs.value)}; } /** * operator^(bitmask, enumerator) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bitmask>::type operator^(const bitmask& lhs, const enumerator& rhs) { using underlying_type = typename std::underlying_type::type; return bitmask{static_cast(lhs.value ^ static_cast(rhs.value))}; } /** * operator^(enumerator, bitmask) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bitmask>::type operator^(const enumerator& lhs, const bitmask& rhs) { using underlying_type = typename std::underlying_type::type; return bitmask{static_cast(static_cast(lhs.value) ^ rhs.value)}; } /** * operator^(enumerator, T) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bitmask>::type operator^(const enumerator& lhs, const T& rhs) { using underlying_type = typename std::underlying_type::type; return bitmask{static_cast(static_cast(lhs.value) ^ static_cast(rhs))}; } /** * operator^(T, enumerator) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bitmask>::type operator^(const T& lhs, const enumerator& rhs) { using underlying_type = typename std::underlying_type::type; return bitmask{static_cast(static_cast(lhs) ^ static_cast(rhs.value))}; } /** * operator~(T) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bitmask>::type operator~(const T& value) { using underlying_type = typename std::underlying_type::type; return bitmask{static_cast(~ static_cast(value))}; } /** * operator~(enumerator) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bitmask>::type operator~(const enumerator& lhs) { using underlying_type = typename std::underlying_type::type; return bitmask{static_cast(~ static_cast(lhs.value))}; } /** * operator~(bitmask) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bitmask>::type operator~(const bitmask& lhs) { return bitmask{static_cast(~ lhs.value)}; } /** * operator&=(bitmask, T) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bitmask&>::type operator&=(bitmask& lhs, const T& rhs) { using underlying_type = typename std::underlying_type::type; lhs.value &= static_cast(rhs); return lhs; } /** * operator&=(bitmask, enumerator) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bitmask&>::type operator&=(bitmask& lhs, const enumerator& rhs) { using underlying_type = typename std::underlying_type::type; lhs.value &= static_cast(rhs.value); return lhs; } /** * operator&=(bitmask, bitmask) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bitmask&>::type operator&=(bitmask& lhs, const bitmask& rhs) { lhs.value &= rhs.value; return lhs; } /** * operator|=(bitmask, T) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bitmask&>::type operator|=(bitmask& lhs, const T& rhs) { using underlying_type = typename std::underlying_type::type; lhs.value |= static_cast(rhs); return lhs; } /** * operator|=(bitmask, enumerator) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bitmask&>::type operator|=(bitmask& lhs, const enumerator& rhs) { using underlying_type = typename std::underlying_type::type; lhs.value |= static_cast(rhs.value); return lhs; } /** * operator|=(bitmask, bitmask) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bitmask&>::type operator|=(bitmask& lhs, const bitmask& rhs) { lhs.value |= rhs.value; return lhs; } /** * operator^=(bitmask, T) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bitmask&>::type operator^=(bitmask& lhs, const T& rhs) { using underlying_type = typename std::underlying_type::type; lhs.value ^= static_cast(rhs); return lhs; } /** * operator^=(bitmask, enumerator) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bitmask&>::type operator^=(bitmask& lhs, const enumerator& rhs) { using underlying_type = typename std::underlying_type::type; lhs.value ^= static_cast(rhs.value); return lhs; } /** * operator^=(bitmask, bitmask) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bitmask&>::type operator^=(bitmask& lhs, const bitmask& rhs) { lhs.value ^= rhs.value; return lhs; } /** * operator==(T, T) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bool>::type operator==(const T& lhs, const T& rhs) { return lhs == rhs; } /** * operator==(enumerator, enumerator) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bool>::type operator==(const enumerator& lhs, const enumerator& rhs) { return lhs.value == rhs.value; } /** * operator==(bitmask, bitmask) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bool>::type operator==(const bitmask& lhs, const bitmask& rhs) { return lhs.value == rhs.value; } /** * operator==(enumerator, T) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bool>::type operator==(const enumerator& lhs, const T& rhs) { return lhs.value == rhs; } /** * operator==(T, enumerator) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bool>::type operator==(const T& lhs, const enumerator& rhs) { return lhs == rhs.value; } /** * operator==(bitmask, T) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bool>::type operator==(const bitmask& lhs, const T& rhs) { static_assert(!std::is_same::underlying_type, typename std::underlying_type::type>::value, "A bitmask can't be compared to an enumerator. Use & first."); return false; } /** * operator==(T, bitmask) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bool>::type operator==(const T& lhs, const bitmask& rhs) { static_assert(!std::is_same::underlying_type, typename std::underlying_type::type>::value, "A bitmask can't be compared to an enumerator. Use & first."); return false; } /** * operator==(bitmask, enumerator) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bool>::type operator==(const bitmask& lhs, const enumerator& rhs) { static_assert(!std::is_same::underlying_type, typename std::underlying_type::type>::value, "A bitmask can't be compared to an enumerator. Use & first."); return false; } /** * operator==(enumerator, bitmask) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bool>::type operator==(const enumerator& lhs, const bitmask& rhs) { static_assert(!std::is_same::underlying_type, typename std::underlying_type::type>::value, "A bitmask can't be compared to an enumerator. Use & first."); return false; } /** * operator!=(T, T) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bool>::type operator!=(const T& lhs, const T& rhs) { return lhs != rhs; } /** * operator!=(enumerator, enumerator) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bool>::type operator!=(const enumerator& lhs, const enumerator& rhs) { return lhs.value != rhs.value; } /** * operator!=(bitmask, bitmask) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bool>::type operator!=(const bitmask& lhs, const bitmask& rhs) { return lhs.value != rhs.value; } /** * operator!=(enumerator, T) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bool>::type operator!=(const enumerator& lhs, const T& rhs) { return lhs.value != rhs; } /** * operator!=(T, enumerator) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bool>::type operator!=(const T& lhs, const enumerator& rhs) { return lhs != rhs.value; } /** * operator!=(bitmask, T) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bool>::type operator!=(const bitmask& lhs, const T& rhs) { static_assert(!std::is_same::underlying_type, typename std::underlying_type::type>::value, "A bitmask can't be compared to an enumerator. Use & first."); return false; } /** * operator!=(T, bitmask) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bool>::type operator!=(const T& lhs, const bitmask& rhs) { static_assert(!std::is_same::underlying_type, typename std::underlying_type::type>::value, "A bitmask can't be compared to an enumerator. Use & first."); return false; } /** * operator!=(bitmask, enumerator) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bool>::type operator!=(const bitmask& lhs, const enumerator& rhs) { static_assert(!std::is_same::underlying_type, typename std::underlying_type::type>::value, "A bitmask can't be compared to an enumerator. Use & first."); return false; } /** * operator!=(enumerator, bitmask) */ template constexpr typename std::enable_if::value && enable_enum_class_bitmask::value, bool>::type operator!=(const enumerator& lhs, const bitmask& rhs) { static_assert(!std::is_same::underlying_type, typename std::underlying_type::type>::value, "A bitmask can't be compared to an enumerator. Use & first."); return false; } #endif /* EnumClass_h */