From 26728848b4c1d3a50ba8986531406e07e7d733cb Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Tue, 29 Dec 2020 00:29:44 +0200 Subject: [PATCH] Add bit_ceil --- include/boost/core/bit.hpp | 64 +++++++++++++++++++++++++++++++++++-- test/Jamfile.v2 | 1 + test/bit_ceil_test.cpp | 65 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 127 insertions(+), 3 deletions(-) create mode 100644 test/bit_ceil_test.cpp diff --git a/include/boost/core/bit.hpp b/include/boost/core/bit.hpp index efbcc50..6258591 100644 --- a/include/boost/core/bit.hpp +++ b/include/boost/core/bit.hpp @@ -197,15 +197,73 @@ BOOST_CONSTEXPR T bit_width( T x ) BOOST_NOEXCEPT return std::numeric_limits::digits - boost::core::countl_zero( x ); } -template -BOOST_CONSTEXPR T bit_ceil( T x ) BOOST_NOEXCEPT; - template BOOST_CONSTEXPR T bit_floor( T x ) BOOST_NOEXCEPT { return x == 0? 0: T(1) << ( boost::core::bit_width( x ) - 1 ); } +namespace detail +{ + +BOOST_CXX14_CONSTEXPR inline boost::uint32_t bit_ceil_impl( boost::uint32_t x ) BOOST_NOEXCEPT +{ + if( x == 0 ) + { + return 0; + } + + --x; + + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + + ++x; + + return x; +} + +BOOST_CXX14_CONSTEXPR inline boost::uint64_t bit_ceil_impl( boost::uint64_t x ) BOOST_NOEXCEPT +{ + if( x == 0 ) + { + return 0; + } + + --x; + + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + x |= x >> 32; + + ++x; + + return x; +} + +} // namespace detail + +template +BOOST_CXX14_CONSTEXPR T bit_ceil( T x ) BOOST_NOEXCEPT +{ + BOOST_STATIC_ASSERT( sizeof(T) <= sizeof(boost::uint64_t) ); + + if( sizeof(T) <= sizeof(boost::uint32_t) ) + { + return static_cast( boost::core::detail::bit_ceil_impl( static_cast( x ) ) ); + } + else + { + return static_cast( boost::core::detail::bit_ceil_impl( static_cast( x ) ) ); + } +} + // endian #if !defined(BOOST_NO_CXX11_SCOPED_ENUMS) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 76d0386..926e175 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -229,6 +229,7 @@ run bit_countl_test.cpp ; run bit_width_test.cpp ; run has_single_bit_test.cpp ; run bit_floor_test.cpp ; +run bit_ceil_test.cpp ; use-project /boost/core/swap : ./swap ; build-project ./swap ; diff --git a/test/bit_ceil_test.cpp b/test/bit_ceil_test.cpp new file mode 100644 index 0000000..1509d55 --- /dev/null +++ b/test/bit_ceil_test.cpp @@ -0,0 +1,65 @@ +// 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 + +template void test_bit_ceil( T x ) +{ + if( !boost::core::has_single_bit( x ) ) + { + x >>= 1; + } + + T y = boost::core::bit_ceil( x ); + + if( x == 0 ) + { + BOOST_TEST_EQ( y, 0 ); + } + else + { + BOOST_TEST( boost::core::has_single_bit( y ) ); + BOOST_TEST_GE( +y, +x ); + BOOST_TEST_LT( y >> 1, +x ); + } +} + +int main() +{ + { + test_bit_ceil( static_cast( 0 ) ); + test_bit_ceil( static_cast( 0 ) ); + test_bit_ceil( static_cast( 0 ) ); + test_bit_ceil( static_cast( 0 ) ); + test_bit_ceil( static_cast( 0 ) ); + } + + { + test_bit_ceil( static_cast( 0x80 ) ); + test_bit_ceil( static_cast( 0x8000 ) ); + test_bit_ceil( static_cast( 0x80000000 ) ); + test_bit_ceil( static_cast( 0x8000000000000000 ) ); + } + + boost::detail::splitmix64 rng; + + for( int i = 0; i < 1000; ++i ) + { + boost::uint64_t x = rng(); + + test_bit_ceil( static_cast( x ) ); + test_bit_ceil( static_cast( x ) ); + test_bit_ceil( static_cast( x ) ); + test_bit_ceil( static_cast( x ) ); + test_bit_ceil( static_cast( x ) ); + } + + return boost::report_errors(); +}