utility.hpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. #ifndef BOOST_NUMERIC_UTILITY_HPP
  2. #define BOOST_NUMERIC_UTILITY_HPP
  3. // Copyright (c) 2015 Robert Ramey
  4. //
  5. // Distributed under the Boost Software License, Version 1.0. (See
  6. // accompanying file LICENSE_1_0.txt or copy at
  7. // http://www.boost.org/LICENSE_1_0.txt)
  8. #include <cstdint> // intmax_t, uintmax_t, uint8_t, ...
  9. #include <algorithm>
  10. #include <type_traits> // conditional
  11. #include <limits>
  12. #include <cassert>
  13. #include <utility> // pair
  14. #include <boost/integer.hpp> // (u)int_t<>::least, exact
  15. namespace boost {
  16. namespace safe_numerics {
  17. namespace utility {
  18. ///////////////////////////////////////////////////////////////////////////////
  19. // used for debugging
  20. // usage - print_type<T>;
  21. // provokes error message with name of type T
  22. template<typename Tx>
  23. using print_type = typename Tx::error_message;
  24. template<int N>
  25. struct print_value
  26. {
  27. enum test : char {
  28. value = N < 0 ? N - 256 : N + 256
  29. };
  30. };
  31. /*
  32. // can be called by constexpr to produce a compile time
  33. // trap of parameter passed is false.
  34. // usage constexpr_assert(bool)
  35. constexpr int constexpr_assert(const bool tf){
  36. return 1 / tf;
  37. }
  38. */
  39. ///////////////////////////////////////////////////////////////////////////////
  40. // return an integral constant equal to the the number of bits
  41. // held by some integer type (including the sign bit)
  42. template<typename T>
  43. using bits_type = std::integral_constant<
  44. int,
  45. std::numeric_limits<T>::digits
  46. + (std::numeric_limits<T>::is_signed ? 1 : 0)
  47. >;
  48. /*
  49. From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogObvious
  50. Find the log base 2 of an integer with a lookup table
  51. static const char LogTable256[256] =
  52. {
  53. #define LT(n) n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n
  54. -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
  55. LT(4), LT(5), LT(5), LT(6), LT(6), LT(6), LT(6),
  56. LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7)
  57. };
  58. unsigned int v; // 32-bit word to find the log of
  59. unsigned r; // r will be lg(v)
  60. register unsigned int t, tt; // temporaries
  61. if (tt = v >> 16)
  62. {
  63. r = (t = tt >> 8) ? 24 + LogTable256[t] : 16 + LogTable256[tt];
  64. }
  65. else
  66. {
  67. r = (t = v >> 8) ? 8 + LogTable256[t] : LogTable256[v];
  68. }
  69. The lookup table method takes only about 7 operations to find the log of a 32-bit value.
  70. If extended for 64-bit quantities, it would take roughly 9 operations. Another operation
  71. can be trimmed off by using four tables, with the possible additions incorporated into each.
  72. Using int table elements may be faster, depending on your architecture.
  73. */
  74. namespace ilog2_detail {
  75. // I've "improved" the above and recast as C++ code which depends upon
  76. // the optimizer to minimize the operations. This should result in
  77. // nine operations to calculate the position of the highest order
  78. // bit in a 64 bit number. RR
  79. constexpr static unsigned int ilog2(const boost::uint_t<8>::exact & t){
  80. #define LT(n) n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n
  81. const char LogTable256[256] = {
  82. static_cast<const char>(-1), 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
  83. LT(4), LT(5), LT(5), LT(6), LT(6), LT(6), LT(6),
  84. LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7)
  85. };
  86. return LogTable256[t];
  87. }
  88. constexpr static unsigned int ilog2(const boost::uint_t<16>::exact & t){
  89. const boost::uint_t<8>::exact upper_half = (t >> 8);
  90. return upper_half == 0
  91. ? ilog2(static_cast<boost::uint_t<8>::exact>(t))
  92. : 8 + ilog2(upper_half);
  93. }
  94. constexpr static unsigned int ilog2(const boost::uint_t<32>::exact & t){
  95. const boost::uint_t<16>::exact upper_half = (t >> 16);
  96. return upper_half == 0
  97. ? ilog2(static_cast<boost::uint_t<16>::exact>(t))
  98. : 16 + ilog2(upper_half);
  99. }
  100. constexpr static unsigned int ilog2(const boost::uint_t<64>::exact & t){
  101. const boost::uint_t<32>::exact upper_half = (t >> 32);
  102. return upper_half == 0
  103. ? ilog2(static_cast<boost::uint_t<32>::exact>(t))
  104. : 32 + ilog2(upper_half);
  105. }
  106. } // ilog2_detail
  107. template<typename T>
  108. constexpr unsigned int ilog2(const T & t){
  109. // log not defined for negative numbers
  110. // assert(t > 0);
  111. if(t == 0)
  112. return 0;
  113. return ilog2_detail::ilog2(
  114. static_cast<
  115. typename boost::uint_t<
  116. bits_type<T>::value
  117. >::least
  118. >(t)
  119. );
  120. }
  121. // the number of bits required to render the value in x
  122. // including sign bit
  123. template<typename T>
  124. constexpr unsigned int significant_bits(const T & t){
  125. return 1 + ((t < 0) ? ilog2(~t) : ilog2(t));
  126. }
  127. /*
  128. // give the value t, return the number which corresponds
  129. // to all 1's which is higher than that number
  130. template<typename T>
  131. constexpr unsigned int bits_value(const T & t){
  132. const unsigned int sb = significant_bits(t);
  133. const unsigned int sb_max = significant_bits(std::numeric_limits<T>::max());
  134. return sb < sb_max ? ((sb << 1) - 1) : std::numeric_limits<T>::max();
  135. }
  136. */
  137. ///////////////////////////////////////////////////////////////////////////////
  138. // meta functions returning types
  139. // If we use std::max in here we get internal compiler errors
  140. // with MSVC (tested VC2017) ...
  141. // Notes from https://en.cppreference.com/w/cpp/algorithm/max
  142. // Capturing the result of std::max by reference if one of the parameters
  143. // is rvalue produces a dangling reference if that parameter is returned.
  144. template <class T>
  145. // turns out this problem crashes all versions of gcc compilers. So
  146. // make sure we return by value
  147. //constexpr const T & max(
  148. constexpr T max(
  149. const T & lhs,
  150. const T & rhs
  151. ){
  152. return lhs > rhs ? lhs : rhs;
  153. }
  154. // given a signed range, return type required to hold all the values
  155. // in the range
  156. template<
  157. std::intmax_t Min,
  158. std::intmax_t Max
  159. >
  160. using signed_stored_type = typename boost::int_t<
  161. max(
  162. significant_bits(Min),
  163. significant_bits(Max)
  164. ) + 1
  165. >::least ;
  166. // given an unsigned range, return type required to hold all the values
  167. // in the range
  168. template<
  169. std::uintmax_t Min,
  170. std::uintmax_t Max
  171. >
  172. // unsigned range
  173. using unsigned_stored_type = typename boost::uint_t<
  174. significant_bits(Max)
  175. >::least;
  176. ///////////////////////////////////////////////////////////////////////////////
  177. // constexpr functions
  178. // need our own version because official version
  179. // a) is not constexpr
  180. // b) is not guarenteed to handle non-assignable types
  181. template<typename T>
  182. constexpr std::pair<T, T>
  183. minmax(const std::initializer_list<T> l){
  184. assert(l.size() > 0);
  185. const T * minimum = l.begin();
  186. const T * maximum = l.begin();
  187. for(const T * i = l.begin(); i != l.end(); ++i){
  188. if(*i < * minimum)
  189. minimum = i;
  190. else
  191. if(* maximum < *i)
  192. maximum = i;
  193. }
  194. return std::pair<T, T>{* minimum, * maximum};
  195. }
  196. // for any given t
  197. // a) figure number of significant bits
  198. // b) return a value with all significant bits set
  199. // so for example:
  200. // 3 == round_out(2) because
  201. // 2 == 10 and 3 == 11
  202. template<typename T>
  203. constexpr T round_out(const T & t){
  204. if(t >= 0){
  205. const std::uint8_t sb = utility::significant_bits(t);
  206. return (sb < sizeof(T) * 8)
  207. ? ((T)1 << sb) - 1
  208. : std::numeric_limits<T>::max();
  209. }
  210. else{
  211. const std::uint8_t sb = utility::significant_bits(~t);
  212. return (sb < sizeof(T) * 8)
  213. ? ~(((T)1 << sb) - 1)
  214. : std::numeric_limits<T>::min();
  215. }
  216. }
  217. } // utility
  218. } // safe_numerics
  219. } // boost
  220. #endif // BOOST_NUMERIC_UTILITY_HPP