1 // -----------------------------------------------------------
4 // Gives the integer part of the logarithm, in base 2, of a
5 // given number. Behavior is undefined if the argument is <= 0.
7 // Copyright (c) 2003-2004, 2008 Gennaro Prota
8 // Copyright (c) 2022 Andrey Semashev
10 // Distributed under the Boost Software License, Version 1.0.
11 // (See accompanying file LICENSE_1_0.txt or copy at
12 // https://www.boost.org/LICENSE_1_0.txt)
14 // -----------------------------------------------------------
16 #ifndef BOOST_INTEGER_INTEGER_LOG2_HPP
17 #define BOOST_INTEGER_INTEGER_LOG2_HPP
21 #include <boost/config.hpp>
22 #include <boost/assert.hpp>
23 #include <boost/cstdint.hpp>
24 #include <boost/core/bit.hpp>
25 #include <boost/core/enable_if.hpp>
26 #include <boost/type_traits/is_integral.hpp>
27 #include <boost/type_traits/make_unsigned.hpp>
32 // helper to find the maximum power of two
34 template< unsigned int p, unsigned int n, bool = ((2u * n) < p) >
35 struct max_pow2_less :
36 public max_pow2_less< p, 2u * n >
40 template< unsigned int p, unsigned int n >
41 struct max_pow2_less< p, n, false >
43 BOOST_STATIC_CONSTANT(unsigned int, value = n);
46 template< typename T >
47 inline typename boost::disable_if< boost::is_integral< T >, int >::type integer_log2_impl(T x)
49 unsigned int n = detail::max_pow2_less<
50 std::numeric_limits< T >::digits,
60 result += static_cast< int >(n);
61 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
62 x = static_cast< T&& >(t);
73 template< typename T >
74 inline typename boost::enable_if< boost::is_integral< T >, int >::type integer_log2_impl(T x)
76 // We could simply rely on numeric_limits but sometimes
77 // Borland tries to use numeric_limits<const T>, because
78 // of its usual const-related problems in argument deduction
80 return static_cast< int >((sizeof(T) * CHAR_BIT - 1u) -
81 boost::core::countl_zero(static_cast< typename boost::make_unsigned< T >::type >(x)));
84 #if defined(BOOST_HAS_INT128)
85 // We need to provide explicit overloads for __int128 because (a) boost/core/bit.hpp currently does not support it and
86 // (b) std::numeric_limits are not specialized for __int128 in some standard libraries.
87 inline int integer_log2_impl(boost::uint128_type x)
89 const boost::uint64_t x_hi = static_cast< boost::uint64_t >(x >> 64u);
91 return 127 - boost::core::countl_zero(x_hi);
93 return 63 - boost::core::countl_zero(static_cast< boost::uint64_t >(x));
96 inline int integer_log2_impl(boost::int128_type x)
98 return detail::integer_log2_impl(static_cast< boost::uint128_type >(x));
100 #endif // defined(BOOST_HAS_INT128)
102 } // namespace detail
108 template< typename T >
109 inline int integer_log2(T x)
112 return detail::integer_log2_impl(x);
117 #endif // BOOST_INTEGER_INTEGER_LOG2_HPP