static_log2.hpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. // -------------- Boost static_log2.hpp header file ----------------------- //
  2. //
  3. // Copyright (C) 2001 Daryle Walker.
  4. // Copyright (C) 2003 Vesa Karvonen.
  5. // Copyright (C) 2003 Gennaro Prota.
  6. //
  7. // Distributed under the Boost Software License, Version 1.0.
  8. // (See accompanying file LICENSE_1_0.txt or copy at
  9. // https://www.boost.org/LICENSE_1_0.txt)
  10. //
  11. // ---------------------------------------------------
  12. // See https://www.boost.org/libs/integer for documentation.
  13. // ------------------------------------------------------------------------- //
  14. #ifndef BOOST_INTEGER_STATIC_LOG2_HPP
  15. #define BOOST_INTEGER_STATIC_LOG2_HPP
  16. #include <boost/config.hpp>
  17. #include <boost/integer_fwd.hpp>
  18. namespace boost {
  19. namespace detail {
  20. namespace static_log2_impl {
  21. // choose_initial_n<>
  22. //
  23. // Recursively doubles its integer argument, until it
  24. // becomes >= of the "width" (C99, 6.2.6.2p4) of
  25. // static_log2_argument_type.
  26. //
  27. // Used to get the maximum power of two less then the width.
  28. //
  29. // Example: if on your platform argument_type has 48 value
  30. // bits it yields n=32.
  31. //
  32. // It's easy to prove that, starting from such a value
  33. // of n, the core algorithm works correctly for any width
  34. // of static_log2_argument_type and that recursion always
  35. // terminates with x = 1 and n = 0 (see the algorithm's
  36. // invariant).
  37. typedef boost::static_log2_argument_type argument_type;
  38. typedef boost::static_log2_result_type result_type;
  39. template <result_type n>
  40. struct choose_initial_n {
  41. BOOST_STATIC_CONSTANT(bool, c = (argument_type(1) << n << n) != 0);
  42. BOOST_STATIC_CONSTANT(
  43. result_type,
  44. value = !c*n + choose_initial_n<2*c*n>::value
  45. );
  46. };
  47. template <>
  48. struct choose_initial_n<0> {
  49. BOOST_STATIC_CONSTANT(result_type, value = 0);
  50. };
  51. // start computing from n_zero - must be a power of two
  52. const result_type n_zero = 16;
  53. const result_type initial_n = choose_initial_n<n_zero>::value;
  54. // static_log2_impl<>
  55. //
  56. // * Invariant:
  57. // 2n
  58. // 1 <= x && x < 2 at the start of each recursion
  59. // (see also choose_initial_n<>)
  60. //
  61. // * Type requirements:
  62. //
  63. // argument_type maybe any unsigned type with at least n_zero + 1
  64. // value bits. (Note: If larger types will be standardized -e.g.
  65. // unsigned long long- then the argument_type typedef can be
  66. // changed without affecting the rest of the code.)
  67. //
  68. template <argument_type x, result_type n = initial_n>
  69. struct static_log2_impl {
  70. BOOST_STATIC_CONSTANT(bool, c = (x >> n) > 0); // x >= 2**n ?
  71. BOOST_STATIC_CONSTANT(
  72. result_type,
  73. value = c*n + (static_log2_impl< (x>>c*n), n/2 >::value)
  74. );
  75. };
  76. template <>
  77. struct static_log2_impl<1, 0> {
  78. BOOST_STATIC_CONSTANT(result_type, value = 0);
  79. };
  80. }
  81. } // detail
  82. // --------------------------------------
  83. // static_log2<x>
  84. // ----------------------------------------
  85. template <static_log2_argument_type x>
  86. struct static_log2 {
  87. BOOST_STATIC_CONSTANT(
  88. static_log2_result_type,
  89. value = detail::static_log2_impl::static_log2_impl<x>::value
  90. );
  91. };
  92. template <>
  93. struct static_log2<0> { };
  94. }
  95. #endif // include guard