From 409c809cd8d83fd7461b0b818f820539ce23bf8b Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Tue, 29 Dec 2020 01:06:22 +0200 Subject: [PATCH] Add popcount --- include/boost/core/bit.hpp | 38 +++++++++++++++++++++++++++-- test/Jamfile.v2 | 1 + test/bit_popcount_test.cpp | 46 ++++++++++++++++++++++++++++++++++++ test/has_single_bit_test.cpp | 2 +- 4 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 test/bit_popcount_test.cpp diff --git a/include/boost/core/bit.hpp b/include/boost/core/bit.hpp index 6258591..de6aada 100644 --- a/include/boost/core/bit.hpp +++ b/include/boost/core/bit.hpp @@ -100,7 +100,6 @@ BOOST_CORE_BIT_CONSTEXPR int countl_zero( T x ) BOOST_NOEXCEPT } } - template BOOST_CORE_BIT_CONSTEXPR int countl_one( T x ) BOOST_NOEXCEPT { @@ -164,8 +163,43 @@ BOOST_CORE_BIT_CONSTEXPR int countr_one( T x ) BOOST_NOEXCEPT return boost::core::countr_zero( static_cast( ~x ) ); } +namespace detail +{ + +BOOST_CXX14_CONSTEXPR inline int popcount_impl( boost::uint32_t x ) BOOST_NOEXCEPT +{ + x = x - ( ( x >> 1 ) & 0x55555555 ); + x = ( x & 0x33333333 ) + ( ( x >> 2 ) & 0x33333333 ); + x = ( x + ( x >> 4 ) ) & 0x0F0F0F0F; + + return static_cast( ( x * 0x01010101 ) >> 24 ); +} + +BOOST_CXX14_CONSTEXPR inline int popcount_impl( boost::uint64_t x ) BOOST_NOEXCEPT +{ + x = x - ( ( x >> 1 ) & 0x5555555555555555 ); + x = ( x & 0x3333333333333333 ) + ( ( x >> 2 ) & 0x3333333333333333 ); + x = ( x + ( x >> 4 ) ) & 0x0F0F0F0F0F0F0F0F; + + return static_cast( ( x * 0x0101010101010101 ) >> 56 ); +} + +} // namespace detail + template -BOOST_CORE_BIT_CONSTEXPR int popcount( T x ) BOOST_NOEXCEPT; +BOOST_CORE_BIT_CONSTEXPR int popcount( T x ) BOOST_NOEXCEPT +{ + BOOST_STATIC_ASSERT( sizeof(T) <= sizeof(boost::uint64_t) ); + + if( sizeof(T) <= sizeof(boost::uint32_t) ) + { + return boost::core::detail::popcount_impl( static_cast( x ) ); + } + else + { + return boost::core::detail::popcount_impl( static_cast( x ) ); + } +} // rotating diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 926e175..e2ec8ac 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -230,6 +230,7 @@ run bit_width_test.cpp ; run has_single_bit_test.cpp ; run bit_floor_test.cpp ; run bit_ceil_test.cpp ; +run bit_popcount_test.cpp ; use-project /boost/core/swap : ./swap ; build-project ./swap ; diff --git a/test/bit_popcount_test.cpp b/test/bit_popcount_test.cpp new file mode 100644 index 0000000..d5cc678 --- /dev/null +++ b/test/bit_popcount_test.cpp @@ -0,0 +1,46 @@ +// Test for boost/core/bit.hpp (bit_ceil) +// +// 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 +#include + +template void test_popcount( T x ) +{ + int k = 0; + for( T y = x; y; y &= y - 1, ++k ); + + BOOST_TEST_EQ( boost::core::popcount( x ), k ) || ( std::cerr << "x: " << +x << std::endl ); +} + +int main() +{ + { + test_popcount( static_cast( 0 ) ); + test_popcount( static_cast( 0 ) ); + test_popcount( static_cast( 0 ) ); + test_popcount( static_cast( 0 ) ); + test_popcount( static_cast( 0 ) ); + } + + boost::detail::splitmix64 rng; + + for( int i = 0; i < 1000; ++i ) + { + boost::uint64_t x = rng(); + + test_popcount( static_cast( x ) ); + test_popcount( static_cast( x ) ); + test_popcount( static_cast( x ) ); + test_popcount( static_cast( x ) ); + test_popcount( static_cast( x ) ); + } + + return boost::report_errors(); +} diff --git a/test/has_single_bit_test.cpp b/test/has_single_bit_test.cpp index 317d769..0be8fcd 100644 --- a/test/has_single_bit_test.cpp +++ b/test/has_single_bit_test.cpp @@ -12,7 +12,7 @@ template void test_single_bit( T x ) { - // BOOST_TEST_EQ( boost::core::has_single_bit( x ), boost::core::popcount( x ) == 1 ); + BOOST_TEST_EQ( boost::core::has_single_bit( x ), boost::core::popcount( x ) == 1 ); } int main()