From cc877e6b5b12f48e9801cadd9efa5dc71884d178 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Mon, 28 Dec 2020 23:40:59 +0200 Subject: [PATCH] Add countl_zero, countl_one --- include/boost/core/bit.hpp | 58 ++++++++++++++++++++++++++++++++++---- test/Jamfile.v2 | 1 + test/bit_countl_test.cpp | 46 ++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+), 6 deletions(-) create mode 100644 test/bit_countl_test.cpp diff --git a/include/boost/core/bit.hpp b/include/boost/core/bit.hpp index 613e71b..efbcc50 100644 --- a/include/boost/core/bit.hpp +++ b/include/boost/core/bit.hpp @@ -45,20 +45,66 @@ To bit_cast( From const & from ) BOOST_NOEXCEPT namespace detail { -BOOST_CXX14_CONSTEXPR int countl_impl( boost::uint32_t x ) BOOST_NOEXCEPT +inline int countl_impl( boost::uint32_t x ) BOOST_NOEXCEPT { - return 0; + 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::uint64_t x ) BOOST_NOEXCEPT +{ + return static_cast( x >> 32 ) != 0? + boost::core::detail::countl_impl( static_cast( x >> 32 ) ): + boost::core::detail::countl_impl( static_cast( x ) ) + 32; +} + +inline int countl_impl( boost::uint8_t x ) BOOST_NOEXCEPT +{ + return boost::core::detail::countl_impl( static_cast( x ) ) - 24; +} + +inline int countl_impl( boost::uint16_t x ) BOOST_NOEXCEPT +{ + return boost::core::detail::countl_impl( static_cast( x ) ) - 16; } } // namespace detail template -BOOST_CORE_BIT_CONSTEXPR int countl_zero( T x ) BOOST_NOEXCEPT; +BOOST_CORE_BIT_CONSTEXPR int countl_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::countl_impl( static_cast( x ) ); + } + else if( sizeof(T) == sizeof(boost::uint16_t) ) + { + return boost::core::detail::countl_impl( static_cast( x ) ); + } + else if( sizeof(T) == sizeof(boost::uint32_t) ) + { + return boost::core::detail::countl_impl( static_cast( x ) ); + } + else + { + return boost::core::detail::countl_impl( static_cast( x ) ); + } +} + template BOOST_CORE_BIT_CONSTEXPR int countl_one( T x ) BOOST_NOEXCEPT { - return boost::core::countl_zero( ~x ); + return boost::core::countl_zero( static_cast( ~x ) ); } namespace detail @@ -66,7 +112,7 @@ 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 }; + 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 ]; } @@ -115,7 +161,7 @@ BOOST_CORE_BIT_CONSTEXPR int countr_zero( T x ) BOOST_NOEXCEPT template BOOST_CORE_BIT_CONSTEXPR int countr_one( T x ) BOOST_NOEXCEPT { - return boost::core::countr_zero( ~x ); + return boost::core::countr_zero( static_cast( ~x ) ); } template diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index a927a37..62942c4 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -225,6 +225,7 @@ run cmath_test.cpp ; run bit_cast_test.cpp ; run bit_rotate_test.cpp ; run bit_countr_test.cpp ; +run bit_countl_test.cpp ; use-project /boost/core/swap : ./swap ; build-project ./swap ; diff --git a/test/bit_countl_test.cpp b/test/bit_countl_test.cpp new file mode 100644 index 0000000..e9473c8 --- /dev/null +++ b/test/bit_countl_test.cpp @@ -0,0 +1,46 @@ +// Test for boost/core/bit.hpp (countl_zero, countl_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_countl( T x ) +{ + x |= static_cast( 1 ) << ( std::numeric_limits::digits - 1 ); + + for( int i = 0; i <= std::numeric_limits::digits; ++i, x >>= 1 ) + { + BOOST_TEST_EQ( boost::core::countl_zero( x ), i ); + BOOST_TEST_EQ( boost::core::countl_one( static_cast( ~x ) ), i ); + } +} + +int main() +{ + test_countl( static_cast( 0 ) ); + test_countl( static_cast( 0 ) ); + test_countl( static_cast( 0 ) ); + test_countl( static_cast( 0 ) ); + test_countl( static_cast( 0 ) ); + + boost::detail::splitmix64 rng; + + for( int i = 0; i < 1000; ++i ) + { + boost::uint64_t x = rng(); + + test_countl( static_cast( x ) ); + test_countl( static_cast( x ) ); + test_countl( static_cast( x ) ); + test_countl( static_cast( x ) ); + test_countl( static_cast( x ) ); + } + + return boost::report_errors(); +}