Use C++11 underlying_type trait in BOOST_BITMASK.

This bumps the language requirement to C++11, although for compilers
that support the __underlying_type intrinsic this may work even in C++03
mode.

The operators generated by BOOST_BITMASK now use proper underlying types
for casts, which means the operators will no longer truncate bits from
large enums.

Also mark the operators as noexcept and constexpr (since C++14).
This commit is contained in:
Andrey Semashev
2025-06-12 18:19:34 +03:00
parent 5b10a0b9b5
commit f7fdaf08a3

View File

@@ -1,6 +1,7 @@
// boost/detail/bitmask.hpp ------------------------------------------------// // boost/detail/bitmask.hpp ------------------------------------------------//
// Copyright Beman Dawes 2006 // Copyright Beman Dawes 2006
// Copyright Andrey Semashev 2025
// Distributed under the Boost Software License, Version 1.0 // Distributed under the Boost Software License, Version 1.0
// http://www.boost.org/LICENSE_1_0.txt // http://www.boost.org/LICENSE_1_0.txt
@@ -18,41 +19,71 @@
#define BOOST_BITMASK_HPP #define BOOST_BITMASK_HPP
#include <boost/config.hpp> #include <boost/config.hpp>
#include <boost/cstdint.hpp>
#define BOOST_BITMASK(Bitmask) \ #if defined(__has_builtin)
\ #if __has_builtin(__underlying_type)
inline BOOST_CONSTEXPR Bitmask operator| (Bitmask x , Bitmask y ) \ #define BOOST_BITMASK_DETAIL_UNDERLYING_TYPE(enum_type) __underlying_type(enum_type)
{ return static_cast<Bitmask>( static_cast<boost::int_least32_t>(x) \ #endif
| static_cast<boost::int_least32_t>(y)); } \ #endif
\
inline BOOST_CONSTEXPR Bitmask operator& (Bitmask x , Bitmask y ) \ #if !defined(BOOST_BITMASK_DETAIL_UNDERLYING_TYPE) && defined(BOOST_GCC_VERSION) && (BOOST_GCC_VERSION >= 40700)
{ return static_cast<Bitmask>( static_cast<boost::int_least32_t>(x) \ #define BOOST_BITMASK_DETAIL_UNDERLYING_TYPE(enum_type) __underlying_type(enum_type)
& static_cast<boost::int_least32_t>(y)); } \ #endif
\
inline BOOST_CONSTEXPR Bitmask operator^ (Bitmask x , Bitmask y ) \ #if !defined(BOOST_BITMASK_DETAIL_UNDERLYING_TYPE)
{ return static_cast<Bitmask>( static_cast<boost::int_least32_t>(x) \ #include <type_traits>
^ static_cast<boost::int_least32_t>(y)); } \ #endif
\
inline BOOST_CONSTEXPR Bitmask operator~ (Bitmask x ) \ namespace boost {
{ return static_cast<Bitmask>(~static_cast<boost::int_least32_t>(x)); } \ namespace detail {
\ namespace bitmask {
inline Bitmask & operator&=(Bitmask& x , Bitmask y) \
{ x = x & y ; return x ; } \ #if defined(BOOST_BITMASK_DETAIL_UNDERLYING_TYPE)
\ template< typename Enum >
inline Bitmask & operator|=(Bitmask& x , Bitmask y) \ using underlying_type_t = BOOST_BITMASK_DETAIL_UNDERLYING_TYPE(Enum);
{ x = x | y ; return x ; } \ #elif (BOOST_CXX_VERSION >= 201402)
\ using std::underlying_type_t;
inline Bitmask & operator^=(Bitmask& x , Bitmask y) \ #else
{ x = x ^ y ; return x ; } \ template< typename Enum >
\ using underlying_type_t = typename std::underlying_type< Enum >::type;
/* Boost extensions to [bitmask.types] */ \ #endif
\
inline BOOST_CONSTEXPR bool operator!(Bitmask x) \ }}}
{ return !static_cast<int>(x); } \
\ #undef BOOST_BITMASK_DETAIL_UNDERLYING_TYPE
inline BOOST_CONSTEXPR bool bitmask_set(Bitmask x) \
#define BOOST_BITMASK(Bitmask) \
\
inline BOOST_CONSTEXPR Bitmask operator| (Bitmask x, Bitmask y) BOOST_NOEXCEPT \
{ return static_cast< Bitmask >(static_cast< ::boost::detail::bitmask::underlying_type_t< Bitmask > >(x) \
| static_cast< ::boost::detail::bitmask::underlying_type_t< Bitmask > >(y)); } \
\
inline BOOST_CONSTEXPR Bitmask operator& (Bitmask x, Bitmask y) BOOST_NOEXCEPT \
{ return static_cast< Bitmask >(static_cast< ::boost::detail::bitmask::underlying_type_t< Bitmask > >(x) \
& static_cast< ::boost::detail::bitmask::underlying_type_t< Bitmask > >(y)); } \
\
inline BOOST_CONSTEXPR Bitmask operator^ (Bitmask x, Bitmask y) BOOST_NOEXCEPT \
{ return static_cast< Bitmask >(static_cast< ::boost::detail::bitmask::underlying_type_t< Bitmask > >(x) \
^ static_cast< ::boost::detail::bitmask::underlying_type_t< Bitmask > >(y)); } \
\
inline BOOST_CONSTEXPR Bitmask operator~ (Bitmask x) BOOST_NOEXCEPT \
{ return static_cast< Bitmask >(~static_cast< ::boost::detail::bitmask::underlying_type_t< Bitmask > >(x)); } \
\
inline BOOST_CXX14_CONSTEXPR Bitmask& operator&=(Bitmask& x, Bitmask y) BOOST_NOEXCEPT \
{ x = x & y; return x; } \
\
inline BOOST_CXX14_CONSTEXPR Bitmask& operator|=(Bitmask& x, Bitmask y) BOOST_NOEXCEPT \
{ x = x | y; return x; } \
\
inline BOOST_CXX14_CONSTEXPR Bitmask& operator^=(Bitmask& x, Bitmask y) BOOST_NOEXCEPT \
{ x = x ^ y; return x; } \
\
/* Boost extensions to [bitmask.types] */ \
\
inline BOOST_CONSTEXPR bool operator!(Bitmask x) BOOST_NOEXCEPT \
{ return !static_cast< ::boost::detail::bitmask::underlying_type_t< Bitmask > >(x); } \
\
inline BOOST_CONSTEXPR bool bitmask_set(Bitmask x) BOOST_NOEXCEPT \
{ return !!x; } { return !!x; }
#endif // BOOST_BITMASK_HPP #endif // BOOST_BITMASK_HPP