diff --git a/include/boost/core/bit.hpp b/include/boost/core/bit.hpp index 22f098d..613e71b 100644 --- a/include/boost/core/bit.hpp +++ b/include/boost/core/bit.hpp @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -28,8 +29,9 @@ namespace core { // bit_cast + template -To bit_cast( From const & from) BOOST_NOEXCEPT +To bit_cast( From const & from ) BOOST_NOEXCEPT { BOOST_STATIC_ASSERT( sizeof(To) == sizeof(From) ); @@ -39,6 +41,17 @@ To bit_cast( From const & from) BOOST_NOEXCEPT } // counting + +namespace detail +{ + +BOOST_CXX14_CONSTEXPR int countl_impl( boost::uint32_t x ) BOOST_NOEXCEPT +{ + return 0; +} + +} // namespace detail + template BOOST_CORE_BIT_CONSTEXPR int countl_zero( T x ) BOOST_NOEXCEPT; @@ -48,8 +61,56 @@ BOOST_CORE_BIT_CONSTEXPR int countl_one( T x ) BOOST_NOEXCEPT return boost::core::countl_zero( ~x ); } +namespace detail +{ + +inline int countr_impl( boost::uint32_t x ) BOOST_NOEXCEPT +{ + static unsigned char const mod37[] = { 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::uint64_t x ) BOOST_NOEXCEPT +{ + return static_cast( x ) != 0? + boost::core::detail::countr_impl( static_cast( x ) ): + boost::core::detail::countr_impl( static_cast( x >> 32 ) ) + 32; +} + +inline int countr_impl( boost::uint8_t x ) BOOST_NOEXCEPT +{ + return boost::core::detail::countr_impl( static_cast( x ) | 0x100 ); +} + +inline int countr_impl( boost::uint16_t x ) BOOST_NOEXCEPT +{ + return boost::core::detail::countr_impl( static_cast( x ) | 0x10000 ); +} + +} // namespace detail + template -BOOST_CORE_BIT_CONSTEXPR int countr_zero( T x ) BOOST_NOEXCEPT; +BOOST_CORE_BIT_CONSTEXPR int countr_zero( T x ) BOOST_NOEXCEPT +{ + BOOST_STATIC_ASSERT( sizeof(T) == sizeof(boost::uint8_t) || sizeof(T) == sizeof(boost::uint16_t) || sizeof(T) == sizeof(boost::uint32_t) || sizeof(T) == sizeof(boost::uint64_t) ); + + if( sizeof(T) == sizeof(boost::uint8_t) ) + { + return boost::core::detail::countr_impl( static_cast( x ) ); + } + else if( sizeof(T) == sizeof(boost::uint16_t) ) + { + return boost::core::detail::countr_impl( static_cast( x ) ); + } + else if( sizeof(T) == sizeof(boost::uint32_t) ) + { + return boost::core::detail::countr_impl( static_cast( x ) ); + } + else + { + return boost::core::detail::countr_impl( static_cast( x ) ); + } +} template BOOST_CORE_BIT_CONSTEXPR int countr_one( T x ) BOOST_NOEXCEPT @@ -61,6 +122,7 @@ template BOOST_CORE_BIT_CONSTEXPR int popcount( T x ) BOOST_NOEXCEPT; // rotating + template BOOST_CXX14_CONSTEXPR T rotl( T x, int s ) BOOST_NOEXCEPT { @@ -76,6 +138,7 @@ BOOST_CXX14_CONSTEXPR T rotr( T x, int s ) BOOST_NOEXCEPT } // integral powers of 2 + template BOOST_CONSTEXPR bool has_single_bit( T x ) BOOST_NOEXCEPT { diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 18856f7..a927a37 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -224,6 +224,7 @@ run cmath_test.cpp ; run bit_cast_test.cpp ; run bit_rotate_test.cpp ; +run bit_countr_test.cpp ; use-project /boost/core/swap : ./swap ; build-project ./swap ; diff --git a/test/bit_cast_test.cpp b/test/bit_cast_test.cpp index c9fba44..3d3408f 100644 --- a/test/bit_cast_test.cpp +++ b/test/bit_cast_test.cpp @@ -1,4 +1,4 @@ -// Test for boost/core/bit.hpp +// Test for boost/core/bit.hpp (bit_cast) // // Copyright 2020 Peter Dimov // Distributed under the Boost Software License, Version 1.0. diff --git a/test/bit_countr_test.cpp b/test/bit_countr_test.cpp new file mode 100644 index 0000000..dedcf9e --- /dev/null +++ b/test/bit_countr_test.cpp @@ -0,0 +1,46 @@ +// Test for boost/core/bit.hpp (countr_zero, countr_one) +// +// Copyright 2020 Peter Dimov +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include +#include + +template void test_countr( T x ) +{ + x |= 1; + + for( int i = 0; i <= std::numeric_limits::digits; ++i, x <<= 1 ) + { + BOOST_TEST_EQ( boost::core::countr_zero( x ), i ); + BOOST_TEST_EQ( boost::core::countr_one( static_cast( ~x ) ), i ); + } +} + +int main() +{ + test_countr( static_cast( 0 ) ); + test_countr( static_cast( 0 ) ); + test_countr( static_cast( 0 ) ); + test_countr( static_cast( 0 ) ); + test_countr( static_cast( 0 ) ); + + boost::detail::splitmix64 rng; + + for( int i = 0; i < 1000; ++i ) + { + boost::uint64_t x = rng(); + + test_countr( static_cast( x ) ); + test_countr( static_cast( x ) ); + test_countr( static_cast( x ) ); + test_countr( static_cast( x ) ); + test_countr( static_cast( x ) ); + } + + return boost::report_errors(); +} diff --git a/test/bit_rotate_test.cpp b/test/bit_rotate_test.cpp index a81ea04..2fbc226 100644 --- a/test/bit_rotate_test.cpp +++ b/test/bit_rotate_test.cpp @@ -1,4 +1,4 @@ -// Test for boost/core/bit.hpp +// Test for boost/core/bit.hpp (rotl, rotr) // // Copyright 2020 Peter Dimov // Distributed under the Boost Software License, Version 1.0.