
#ifndef SCOPEDENUMBITWISEOPERATORS_H
#define SCOPEDENUMBITWISEOPERATORS_H
#include <type_traits>


template<typename Enum>
std::enable_if_t<std::is_enum_v<Enum>, Enum>
operator^(Enum lhs, Enum rhs) {
    using underlying = std::underlying_type_t<Enum>;
    return static_cast<Enum>(static_cast<underlying>(lhs) ^ static_cast<underlying>(rhs));
}

template<typename Enum>
std::enable_if_t<std::is_enum_v<Enum>, Enum>
operator|(Enum lhs, Enum rhs) {
    using underlying = std::underlying_type_t<Enum>;
    return static_cast<Enum>(static_cast<underlying>(lhs) | static_cast<underlying>(rhs));
}

template<typename Enum>
std::enable_if_t<std::is_enum_v<Enum>, Enum>
operator&(Enum lhs, Enum rhs) {
    using underlying = std::underlying_type_t<Enum>;
    return static_cast<Enum>(static_cast<underlying>(lhs) & static_cast<underlying>(rhs));
}

template<typename Enum>
std::enable_if_t<std::is_enum_v<Enum>, Enum>
operator~(Enum rhs) {
    using underlying = std::underlying_type_t<Enum>;
    return static_cast<Enum>(~static_cast<underlying>(rhs));
}

template<typename Enum>
std::enable_if_t<std::is_enum_v<Enum>, Enum>
operator|=(Enum &lhs, Enum rhs) {
    using underlying = std::underlying_type_t<Enum>;
    lhs = static_cast<Enum>(static_cast<underlying>(lhs) | static_cast<underlying>(rhs));
    return lhs;
}

template<typename Enum>
std::enable_if_t<std::is_enum_v<Enum>, Enum>
operator&=(Enum &lhs, Enum rhs) {
    using underlying = std::underlying_type_t<Enum>;
    lhs = static_cast<Enum>(static_cast<underlying>(lhs) & static_cast<underlying>(rhs));
    return lhs;
}

template<typename Enum>
std::enable_if_t<std::is_enum_v<Enum>, Enum>
operator^=(Enum &lhs, Enum rhs) {
    using underlying = std::underlying_type_t<Enum>;
    lhs = static_cast<Enum>(static_cast<underlying>(lhs) ^ static_cast<underlying>(rhs));
    return lhs;
}

#endif //SCOPEDENUMBITWISEOPERATORS_H
