1
0
forked from boostorg/core

Make bit manipulation functions constexpr on MSVC 19.25+. Closes #109.

This commit is contained in:
Peter Dimov
2023-05-30 02:56:37 +03:00
parent 42c8898d24
commit b2fe98edf8
6 changed files with 264 additions and 75 deletions

View File

@@ -38,6 +38,10 @@
#endif // defined(_MSC_VER)
#if defined(BOOST_MSVC) && BOOST_MSVC >= 1925
# define BOOST_CORE_HAS_BUILTIN_ISCONSTEVAL
#endif
namespace boost
{
namespace core
@@ -102,10 +106,51 @@ BOOST_CONSTEXPR int countl_zero( T x ) BOOST_NOEXCEPT
namespace detail
{
#if defined(_MSC_VER) && defined(BOOST_CORE_HAS_BUILTIN_ISCONSTEVAL)
BOOST_CXX14_CONSTEXPR inline int countl_impl( boost::uint32_t x ) BOOST_NOEXCEPT
{
if( __builtin_is_constant_evaluated() )
{
constexpr unsigned char mod37[ 37 ] = { 32, 31, 6, 30, 9, 5, 0, 29, 16, 8, 2, 4, 21, 0, 19, 28, 25, 15, 0, 7, 10, 1, 17, 3, 22, 20, 26, 0, 11, 18, 23, 27, 12, 24, 13, 14, 0 };
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return mod37[ x % 37 ];
}
else
{
unsigned long r;
if( _BitScanReverse( &r, x ) )
{
return 31 - static_cast<int>( r );
}
else
{
return 32;
}
}
}
BOOST_CXX14_CONSTEXPR inline int countl_impl( boost::uint8_t x ) BOOST_NOEXCEPT
{
return boost::core::detail::countl_impl( static_cast<boost::uint32_t>( x ) ) - 24;
}
BOOST_CXX14_CONSTEXPR inline int countl_impl( boost::uint16_t x ) BOOST_NOEXCEPT
{
return boost::core::detail::countl_impl( static_cast<boost::uint32_t>( x ) ) - 16;
}
#elif defined(_MSC_VER)
inline int countl_impl( boost::uint32_t x ) BOOST_NOEXCEPT
{
#if defined(_MSC_VER)
unsigned long r;
if( _BitScanReverse( &r, x ) )
@@ -116,44 +161,6 @@ inline int countl_impl( boost::uint32_t x ) BOOST_NOEXCEPT
{
return 32;
}
#else
static unsigned char const mod37[ 37 ] = { 32, 31, 6, 30, 9, 5, 0, 29, 16, 8, 2, 4, 21, 0, 19, 28, 25, 15, 0, 7, 10, 1, 17, 3, 22, 20, 26, 0, 11, 18, 23, 27, 12, 24, 13, 14, 0 };
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return mod37[ x % 37 ];
#endif
}
inline int countl_impl( boost::uint64_t x ) BOOST_NOEXCEPT
{
#if defined(_MSC_VER) && defined(_M_X64)
unsigned long r;
if( _BitScanReverse64( &r, x ) )
{
return 63 - static_cast<int>( r );
}
else
{
return 64;
}
#else
return static_cast<boost::uint32_t>( x >> 32 ) != 0?
boost::core::detail::countl_impl( static_cast<boost::uint32_t>( x >> 32 ) ):
boost::core::detail::countl_impl( static_cast<boost::uint32_t>( x ) ) + 32;
#endif
}
inline int countl_impl( boost::uint8_t x ) BOOST_NOEXCEPT
@@ -166,10 +173,89 @@ inline int countl_impl( boost::uint16_t x ) BOOST_NOEXCEPT
return boost::core::detail::countl_impl( static_cast<boost::uint32_t>( x ) ) - 16;
}
#else
inline int countl_impl( boost::uint32_t x ) BOOST_NOEXCEPT
{
static unsigned char const mod37[ 37 ] = { 32, 31, 6, 30, 9, 5, 0, 29, 16, 8, 2, 4, 21, 0, 19, 28, 25, 15, 0, 7, 10, 1, 17, 3, 22, 20, 26, 0, 11, 18, 23, 27, 12, 24, 13, 14, 0 };
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return mod37[ x % 37 ];
}
inline int countl_impl( boost::uint8_t x ) BOOST_NOEXCEPT
{
return boost::core::detail::countl_impl( static_cast<boost::uint32_t>( x ) ) - 24;
}
inline int countl_impl( boost::uint16_t x ) BOOST_NOEXCEPT
{
return boost::core::detail::countl_impl( static_cast<boost::uint32_t>( x ) ) - 16;
}
#endif
#if defined(_MSC_VER) && defined(_M_X64) && defined(BOOST_CORE_HAS_BUILTIN_ISCONSTEVAL)
BOOST_CXX14_CONSTEXPR inline int countl_impl( boost::uint64_t x ) BOOST_NOEXCEPT
{
if( __builtin_is_constant_evaluated() )
{
return static_cast<boost::uint32_t>( x >> 32 ) != 0?
boost::core::detail::countl_impl( static_cast<boost::uint32_t>( x >> 32 ) ):
boost::core::detail::countl_impl( static_cast<boost::uint32_t>( x ) ) + 32;
}
else
{
unsigned long r;
if( _BitScanReverse64( &r, x ) )
{
return 63 - static_cast<int>( r );
}
else
{
return 64;
}
}
}
#elif defined(_MSC_VER) && defined(_M_X64)
inline int countl_impl( boost::uint64_t x ) BOOST_NOEXCEPT
{
unsigned long r;
if( _BitScanReverse64( &r, x ) )
{
return 63 - static_cast<int>( r );
}
else
{
return 64;
}
}
#else
inline int countl_impl( boost::uint64_t x ) BOOST_NOEXCEPT
{
return static_cast<boost::uint32_t>( x >> 32 ) != 0?
boost::core::detail::countl_impl( static_cast<boost::uint32_t>( x >> 32 ) ):
boost::core::detail::countl_impl( static_cast<boost::uint32_t>( x ) ) + 32;
}
#endif
} // namespace detail
template<class T>
int countl_zero( T x ) BOOST_NOEXCEPT
BOOST_CXX14_CONSTEXPR int countl_zero( T x ) BOOST_NOEXCEPT
{
BOOST_STATIC_ASSERT( std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed );
@@ -250,10 +336,44 @@ BOOST_CONSTEXPR int countr_zero( T x ) BOOST_NOEXCEPT
namespace detail
{
#if defined(_MSC_VER) && defined(BOOST_CORE_HAS_BUILTIN_ISCONSTEVAL)
BOOST_CXX14_CONSTEXPR inline int countr_impl( boost::uint32_t x ) BOOST_NOEXCEPT
{
if( __builtin_is_constant_evaluated() )
{
constexpr unsigned char mod37[ 37 ] = { 32, 0, 1, 26, 2, 23, 27, 0, 3, 16, 24, 30, 28, 11, 0, 13, 4, 7, 17, 0, 25, 22, 31, 15, 29, 10, 12, 6, 0, 21, 14, 9, 5, 20, 8, 19, 18 };
return mod37[ ( -(boost::int32_t)x & x ) % 37 ];
}
else
{
unsigned long r;
if( _BitScanForward( &r, x ) )
{
return static_cast<int>( r );
}
else
{
return 32;
}
}
}
BOOST_CXX14_CONSTEXPR inline int countr_impl( boost::uint8_t x ) BOOST_NOEXCEPT
{
return boost::core::detail::countr_impl( static_cast<boost::uint32_t>( x ) | 0x100 );
}
BOOST_CXX14_CONSTEXPR inline int countr_impl( boost::uint16_t x ) BOOST_NOEXCEPT
{
return boost::core::detail::countr_impl( static_cast<boost::uint32_t>( x ) | 0x10000 );
}
#elif defined(_MSC_VER)
inline int countr_impl( boost::uint32_t x ) BOOST_NOEXCEPT
{
#if defined(_MSC_VER)
unsigned long r;
if( _BitScanForward( &r, x ) )
@@ -264,37 +384,6 @@ inline int countr_impl( boost::uint32_t x ) BOOST_NOEXCEPT
{
return 32;
}
#else
static unsigned char const mod37[ 37 ] = { 32, 0, 1, 26, 2, 23, 27, 0, 3, 16, 24, 30, 28, 11, 0, 13, 4, 7, 17, 0, 25, 22, 31, 15, 29, 10, 12, 6, 0, 21, 14, 9, 5, 20, 8, 19, 18 };
return mod37[ ( -(boost::int32_t)x & x ) % 37 ];
#endif
}
inline int countr_impl( boost::uint64_t x ) BOOST_NOEXCEPT
{
#if defined(_MSC_VER) && defined(_M_X64)
unsigned long r;
if( _BitScanForward64( &r, x ) )
{
return static_cast<int>( r );
}
else
{
return 64;
}
#else
return static_cast<boost::uint32_t>( x ) != 0?
boost::core::detail::countr_impl( static_cast<boost::uint32_t>( x ) ):
boost::core::detail::countr_impl( static_cast<boost::uint32_t>( x >> 32 ) ) + 32;
#endif
}
inline int countr_impl( boost::uint8_t x ) BOOST_NOEXCEPT
@@ -307,10 +396,82 @@ inline int countr_impl( boost::uint16_t x ) BOOST_NOEXCEPT
return boost::core::detail::countr_impl( static_cast<boost::uint32_t>( x ) | 0x10000 );
}
#else
inline int countr_impl( boost::uint32_t x ) BOOST_NOEXCEPT
{
static unsigned char const mod37[ 37 ] = { 32, 0, 1, 26, 2, 23, 27, 0, 3, 16, 24, 30, 28, 11, 0, 13, 4, 7, 17, 0, 25, 22, 31, 15, 29, 10, 12, 6, 0, 21, 14, 9, 5, 20, 8, 19, 18 };
return mod37[ ( -(boost::int32_t)x & x ) % 37 ];
}
inline int countr_impl( boost::uint8_t x ) BOOST_NOEXCEPT
{
return boost::core::detail::countr_impl( static_cast<boost::uint32_t>( x ) | 0x100 );
}
inline int countr_impl( boost::uint16_t x ) BOOST_NOEXCEPT
{
return boost::core::detail::countr_impl( static_cast<boost::uint32_t>( x ) | 0x10000 );
}
#endif
#if defined(_MSC_VER) && defined(_M_X64) && defined(BOOST_CORE_HAS_BUILTIN_ISCONSTEVAL)
BOOST_CXX14_CONSTEXPR inline int countr_impl( boost::uint64_t x ) BOOST_NOEXCEPT
{
if( __builtin_is_constant_evaluated() )
{
return static_cast<boost::uint32_t>( x ) != 0?
boost::core::detail::countr_impl( static_cast<boost::uint32_t>( x ) ):
boost::core::detail::countr_impl( static_cast<boost::uint32_t>( x >> 32 ) ) + 32;
}
else
{
unsigned long r;
if( _BitScanForward64( &r, x ) )
{
return static_cast<int>( r );
}
else
{
return 64;
}
}
}
#elif defined(_MSC_VER) && defined(_M_X64)
inline int countr_impl( boost::uint64_t x ) BOOST_NOEXCEPT
{
unsigned long r;
if( _BitScanForward64( &r, x ) )
{
return static_cast<int>( r );
}
else
{
return 64;
}
}
#else
inline int countr_impl( boost::uint64_t x ) BOOST_NOEXCEPT
{
return static_cast<boost::uint32_t>( x ) != 0?
boost::core::detail::countr_impl( static_cast<boost::uint32_t>( x ) ):
boost::core::detail::countr_impl( static_cast<boost::uint32_t>( x >> 32 ) ) + 32;
}
#endif
} // namespace detail
template<class T>
int countr_zero( T x ) BOOST_NOEXCEPT
BOOST_CXX14_CONSTEXPR int countr_zero( T x ) BOOST_NOEXCEPT
{
BOOST_STATIC_ASSERT( std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed );

View File

@@ -4,6 +4,10 @@
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#if defined(_MSC_VER)
# pragma warning(disable: 4310) // cast truncates constant value
#endif
#include <boost/config.hpp>
#include <boost/config/pragma_message.hpp>
@@ -11,6 +15,10 @@
BOOST_PRAGMA_MESSAGE( "Test skipped because BOOST_NO_CXX14_CONSTEXPR is defined" )
#elif defined(BOOST_MSVC) && BOOST_MSVC / 10 == 191
BOOST_PRAGMA_MESSAGE( "Test skipped because BOOST_MSVC is " BOOST_STRINGIZE(BOOST_MSVC) )
#else
#include <boost/core/bit.hpp>

View File

@@ -4,6 +4,10 @@
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#if defined(_MSC_VER)
# pragma warning(disable: 4310) // cast truncates constant value
#endif
#include <boost/config.hpp>
#include <boost/config/pragma_message.hpp>
@@ -11,6 +15,10 @@
BOOST_PRAGMA_MESSAGE( "Test skipped because BOOST_NO_CXX14_CONSTEXPR is defined" )
#elif defined(BOOST_MSVC) && BOOST_MSVC / 10 == 191
BOOST_PRAGMA_MESSAGE( "Test skipped because BOOST_MSVC is " BOOST_STRINGIZE(BOOST_MSVC) )
#else
#include <boost/core/bit.hpp>

View File

@@ -11,6 +11,10 @@
BOOST_PRAGMA_MESSAGE( "Test skipped because BOOST_NO_CXX14_CONSTEXPR is defined" )
#elif defined(BOOST_MSVC) && BOOST_MSVC / 10 == 191
BOOST_PRAGMA_MESSAGE( "Test skipped because BOOST_MSVC is " BOOST_STRINGIZE(BOOST_MSVC) )
#else
#include <boost/core/bit.hpp>

View File

@@ -4,6 +4,10 @@
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#if defined(_MSC_VER) && _MSC_VER / 10 == 191
# pragma warning(disable: 4307) // '*': integral constant overflow
#endif
#include <boost/config.hpp>
#include <boost/config/pragma_message.hpp>

View File

@@ -11,6 +11,10 @@
BOOST_PRAGMA_MESSAGE( "Test skipped because BOOST_NO_CXX14_CONSTEXPR is defined" )
#elif defined(BOOST_MSVC) && BOOST_MSVC / 10 == 191
BOOST_PRAGMA_MESSAGE( "Test skipped because BOOST_MSVC is " BOOST_STRINGIZE(BOOST_MSVC) )
#else
#include <boost/core/bit.hpp>