/*************************************************************************** * Copyright (c) 2022 Werner Mayer * * * * This file is part of the FreeCAD CAx development system. * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Library General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Library General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this library; see the file COPYING.LIB. If not, * * write to the Free Software Foundation, Inc., 51 Franklin Street, * * Fifth Floor, Boston, MA 02110-1301, USA * * * ***************************************************************************/ #ifndef BASE_BITMASK_H #define BASE_BITMASK_H #include /*! Using enum classes as type-safe bitmasks. @code enum class Color { Red = 1 << 0, Green = 1 << 1, Blue = 1 << 2 }; ENABLE_BITMASK_OPERATORS(Color) Color yellow = Color::Red | Color::Green; Flags flags(yellow); flags.testFlag(Color::Red); flags.testFlag(Color::Green); @endcode */ // NOLINTBEGIN // clang-format off // Based on https://stackoverflow.com/questions/1448396/how-to-use-enums-as-flags-in-c template struct enum_traits {}; template<> struct enum_traits { struct _allow_bitops { static constexpr bool allow_bitops = true; }; using allow_bitops = _allow_bitops; template using t = typename std::enable_if::value && enum_traits::allow_bitops, R>::type; template using u = typename std::underlying_type::type; }; template constexpr enum_traits<>::t operator~(T a) { return static_cast(~static_cast::u>(a)); } template constexpr enum_traits<>::t operator|(T a, T b) { return static_cast( static_cast::u>(a) | static_cast::u>(b)); } template constexpr enum_traits<>::t operator&(T a, T b) { return static_cast( static_cast::u>(a) & static_cast::u>(b)); } template constexpr enum_traits<>::t operator^(T a, T b) { return static_cast( static_cast::u>(a) ^ static_cast::u>(b)); } template constexpr enum_traits<>::t operator|=(T& a, T b) { a = a | b; return a; } template constexpr enum_traits<>::t operator&=(T& a, T b) { a = a & b; return a; } template constexpr enum_traits<>::t operator^=(T& a, T b) { a = a ^ b; return a; } #define ENABLE_BITMASK_OPERATORS(x) \ template<> \ struct enum_traits : \ enum_traits<>::allow_bitops {}; namespace Base { template class Flags { static_assert(std::is_enum::value, "Flags is only usable on enumeration types."); Enum i; public: constexpr inline Flags(Enum f) : i(f) {} constexpr bool testFlag(Enum f) const { using u = typename std::underlying_type::type; return (i & f) == f && (static_cast(f) != 0 || i == f); } constexpr inline void setFlag(Enum f, bool on = true) { on ? (i |= f) : (i &= ~f); } constexpr bool isEqual(Flags f) const { using u = typename std::underlying_type::type; return static_cast(i) == static_cast(f.i); } typename std::underlying_type::type toUnderlyingType() const { return static_cast::type>(i); } }; } // clang-format on // NOLINTEND #endif