integer_log2.hpp 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. // -----------------------------------------------------------
  2. // integer_log2.hpp
  3. //
  4. // Gives the integer part of the logarithm, in base 2, of a
  5. // given number. Behavior is undefined if the argument is <= 0.
  6. //
  7. // Copyright (c) 2003-2004, 2008 Gennaro Prota
  8. // Copyright (c) 2022 Andrey Semashev
  9. //
  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)
  13. //
  14. // -----------------------------------------------------------
  15. #ifndef BOOST_INTEGER_INTEGER_LOG2_HPP
  16. #define BOOST_INTEGER_INTEGER_LOG2_HPP
  17. #include <climits>
  18. #include <limits>
  19. #include <boost/config.hpp>
  20. #include <boost/assert.hpp>
  21. #include <boost/cstdint.hpp>
  22. #include <boost/core/bit.hpp>
  23. #include <boost/core/enable_if.hpp>
  24. #include <boost/type_traits/is_integral.hpp>
  25. #include <boost/type_traits/make_unsigned.hpp>
  26. namespace boost {
  27. namespace detail {
  28. // helper to find the maximum power of two
  29. // less than p
  30. template< unsigned int p, unsigned int n, bool = ((2u * n) < p) >
  31. struct max_pow2_less :
  32. public max_pow2_less< p, 2u * n >
  33. {
  34. };
  35. template< unsigned int p, unsigned int n >
  36. struct max_pow2_less< p, n, false >
  37. {
  38. BOOST_STATIC_CONSTANT(unsigned int, value = n);
  39. };
  40. template< typename T >
  41. inline typename boost::disable_if< boost::is_integral< T >, int >::type integer_log2_impl(T x)
  42. {
  43. unsigned int n = detail::max_pow2_less<
  44. std::numeric_limits< T >::digits,
  45. CHAR_BIT / 2u
  46. >::value;
  47. int result = 0;
  48. while (x != 1)
  49. {
  50. T t(x >> n);
  51. if (t)
  52. {
  53. result += static_cast< int >(n);
  54. #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
  55. x = static_cast< T&& >(t);
  56. #else
  57. x = t;
  58. #endif
  59. }
  60. n >>= 1u;
  61. }
  62. return result;
  63. }
  64. template< typename T >
  65. inline typename boost::enable_if< boost::is_integral< T >, int >::type integer_log2_impl(T x)
  66. {
  67. // We could simply rely on numeric_limits but sometimes
  68. // Borland tries to use numeric_limits<const T>, because
  69. // of its usual const-related problems in argument deduction
  70. // - gps
  71. return static_cast< int >((sizeof(T) * CHAR_BIT - 1u) -
  72. boost::core::countl_zero(static_cast< typename boost::make_unsigned< T >::type >(x)));
  73. }
  74. #if defined(BOOST_HAS_INT128)
  75. // We need to provide explicit overloads for __int128 because (a) boost/core/bit.hpp currently does not support it and
  76. // (b) std::numeric_limits are not specialized for __int128 in some standard libraries.
  77. inline int integer_log2_impl(boost::uint128_type x)
  78. {
  79. const boost::uint64_t x_hi = static_cast< boost::uint64_t >(x >> 64u);
  80. if (x_hi != 0u)
  81. return 127 - boost::core::countl_zero(x_hi);
  82. else
  83. return 63 - boost::core::countl_zero(static_cast< boost::uint64_t >(x));
  84. }
  85. inline int integer_log2_impl(boost::int128_type x)
  86. {
  87. return detail::integer_log2_impl(static_cast< boost::uint128_type >(x));
  88. }
  89. #endif // defined(BOOST_HAS_INT128)
  90. } // namespace detail
  91. // ------------
  92. // integer_log2
  93. // ------------
  94. template< typename T >
  95. inline int integer_log2(T x)
  96. {
  97. BOOST_ASSERT(x > 0);
  98. return detail::integer_log2_impl(x);
  99. }
  100. } // namespace boost
  101. #endif // BOOST_INTEGER_INTEGER_LOG2_HPP