static_log2.hpp 3.5 KB

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