utility.hpp 8.0 KB

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