bitscan.hpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. ///////////////////////////////////////////////////////////////
  2. // Copyright 2013 John Maddock. Distributed under the Boost
  3. // Software License, Version 1.0. (See accompanying file
  4. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
  5. //
  6. // Comparison operators for cpp_int_backend:
  7. //
  8. #ifndef BOOST_MP_DETAIL_BITSCAN_HPP
  9. #define BOOST_MP_DETAIL_BITSCAN_HPP
  10. #include <boost/predef/other/endian.h>
  11. #include <boost/cstdint.hpp>
  12. #if (defined(BOOST_MSVC) || (defined(__clang__) && defined(__c2__)) || (defined(BOOST_INTEL) && defined(_MSC_VER))) && (defined(_M_IX86) || defined(_M_X64))
  13. #include <intrin.h>
  14. #endif
  15. namespace boost{ namespace multiprecision{ namespace detail{
  16. template <class Unsigned>
  17. inline unsigned find_lsb(Unsigned mask, const mpl::int_<0>&)
  18. {
  19. unsigned result = 0;
  20. while(!(mask & 1u))
  21. {
  22. mask >>= 1;
  23. ++result;
  24. }
  25. return result;
  26. }
  27. template <class Unsigned>
  28. inline unsigned find_msb(Unsigned mask, const mpl::int_<0>&)
  29. {
  30. unsigned index = 0;
  31. while(mask)
  32. {
  33. ++index;
  34. mask >>= 1;
  35. }
  36. return --index;
  37. }
  38. #if (defined(BOOST_MSVC) || (defined(__clang__) && defined(__c2__)) || (defined(BOOST_INTEL) && defined(_MSC_VER))) && (defined(_M_IX86) || defined(_M_X64))
  39. #pragma intrinsic(_BitScanForward,_BitScanReverse)
  40. BOOST_FORCEINLINE unsigned find_lsb(unsigned long mask, const mpl::int_<1>&)
  41. {
  42. unsigned long result;
  43. _BitScanForward(&result, mask);
  44. return result;
  45. }
  46. BOOST_FORCEINLINE unsigned find_msb(unsigned long mask, const mpl::int_<1>&)
  47. {
  48. unsigned long result;
  49. _BitScanReverse(&result, mask);
  50. return result;
  51. }
  52. #ifdef _M_X64
  53. #pragma intrinsic(_BitScanForward64,_BitScanReverse64)
  54. BOOST_FORCEINLINE unsigned find_lsb(unsigned __int64 mask, const mpl::int_<2>&)
  55. {
  56. unsigned long result;
  57. _BitScanForward64(&result, mask);
  58. return result;
  59. }
  60. template <class Unsigned>
  61. BOOST_FORCEINLINE unsigned find_msb(Unsigned mask, const mpl::int_<2>&)
  62. {
  63. unsigned long result;
  64. _BitScanReverse64(&result, mask);
  65. return result;
  66. }
  67. #endif
  68. template <class Unsigned>
  69. BOOST_FORCEINLINE unsigned find_lsb(Unsigned mask)
  70. {
  71. typedef typename make_unsigned<Unsigned>::type ui_type;
  72. typedef typename mpl::if_c<
  73. sizeof(Unsigned) <= sizeof(unsigned long),
  74. mpl::int_<1>,
  75. #ifdef _M_X64
  76. typename mpl::if_c<
  77. sizeof(Unsigned) <= sizeof(__int64),
  78. mpl::int_<2>,
  79. mpl::int_<0>
  80. >::type
  81. #else
  82. mpl::int_<0>
  83. #endif
  84. >::type tag_type;
  85. return find_lsb(static_cast<ui_type>(mask), tag_type());
  86. }
  87. template <class Unsigned>
  88. BOOST_FORCEINLINE unsigned find_msb(Unsigned mask)
  89. {
  90. typedef typename make_unsigned<Unsigned>::type ui_type;
  91. typedef typename mpl::if_c<
  92. sizeof(Unsigned) <= sizeof(unsigned long),
  93. mpl::int_<1>,
  94. #ifdef _M_X64
  95. typename mpl::if_c<
  96. sizeof(Unsigned) <= sizeof(__int64),
  97. mpl::int_<2>,
  98. mpl::int_<0>
  99. >::type
  100. #else
  101. mpl::int_<0>
  102. #endif
  103. >::type tag_type;
  104. return find_msb(static_cast<ui_type>(mask), tag_type());
  105. }
  106. #elif defined(BOOST_GCC) || defined(__clang__) || (defined(BOOST_INTEL) && defined(__GNUC__))
  107. BOOST_FORCEINLINE unsigned find_lsb(unsigned mask, mpl::int_<1> const&)
  108. {
  109. return __builtin_ctz(mask);
  110. }
  111. BOOST_FORCEINLINE unsigned find_lsb(unsigned long mask, mpl::int_<2> const&)
  112. {
  113. return __builtin_ctzl(mask);
  114. }
  115. BOOST_FORCEINLINE unsigned find_lsb(boost::ulong_long_type mask, mpl::int_<3> const&)
  116. {
  117. return __builtin_ctzll(mask);
  118. }
  119. BOOST_FORCEINLINE unsigned find_msb(unsigned mask, mpl::int_<1> const&)
  120. {
  121. return sizeof(unsigned) * CHAR_BIT - 1 - __builtin_clz(mask);
  122. }
  123. BOOST_FORCEINLINE unsigned find_msb(unsigned long mask, mpl::int_<2> const&)
  124. {
  125. return sizeof(unsigned long) * CHAR_BIT - 1 - __builtin_clzl(mask);
  126. }
  127. BOOST_FORCEINLINE unsigned find_msb(boost::ulong_long_type mask, mpl::int_<3> const&)
  128. {
  129. return sizeof(boost::ulong_long_type) * CHAR_BIT - 1 - __builtin_clzll(mask);
  130. }
  131. #ifdef BOOST_HAS_INT128
  132. __extension__ typedef unsigned __int128 uint128_type;
  133. BOOST_FORCEINLINE unsigned find_msb(uint128_type mask, mpl::int_<0> const&)
  134. {
  135. union { uint128_type v; boost::uint64_t sv[2]; } val;
  136. val.v = mask;
  137. #if BOOST_ENDIAN_LITTLE_BYTE
  138. if(val.sv[1])
  139. return find_msb(val.sv[1], mpl::int_<3>()) + 64;
  140. return find_msb(val.sv[0], mpl::int_<3>());
  141. #else
  142. if(val.sv[0])
  143. return find_msb(val.sv[0], mpl::int_<3>()) + 64;
  144. return find_msb(val.sv[1], mpl::int_<3>());
  145. #endif
  146. }
  147. BOOST_FORCEINLINE unsigned find_lsb(uint128_type mask, mpl::int_<0> const&)
  148. {
  149. union { uint128_type v; boost::uint64_t sv[2]; } val;
  150. val.v = mask;
  151. #if BOOST_ENDIAN_LITTLE_BYTE
  152. if(val.sv[0] == 0)
  153. return find_lsb(val.sv[1], mpl::int_<3>()) + 64;
  154. return find_lsb(val.sv[0], mpl::int_<3>());
  155. #else
  156. if(val.sv[1] == 0)
  157. return find_lsb(val.sv[0], mpl::int_<3>()) + 64;
  158. return find_lsb(val.sv[1], mpl::int_<3>());
  159. #endif
  160. }
  161. #endif
  162. template <class Unsigned>
  163. BOOST_FORCEINLINE unsigned find_lsb(Unsigned mask)
  164. {
  165. typedef typename make_unsigned<Unsigned>::type ui_type;
  166. typedef typename mpl::if_c<
  167. sizeof(Unsigned) <= sizeof(unsigned),
  168. mpl::int_<1>,
  169. typename mpl::if_c<
  170. sizeof(Unsigned) <= sizeof(unsigned long),
  171. mpl::int_<2>,
  172. typename mpl::if_c<
  173. sizeof(Unsigned) <= sizeof(boost::ulong_long_type),
  174. mpl::int_<3>,
  175. mpl::int_<0>
  176. >::type
  177. >::type
  178. >::type tag_type;
  179. return find_lsb(static_cast<ui_type>(mask), tag_type());
  180. }
  181. template <class Unsigned>
  182. BOOST_FORCEINLINE unsigned find_msb(Unsigned mask)
  183. {
  184. typedef typename make_unsigned<Unsigned>::type ui_type;
  185. typedef typename mpl::if_c<
  186. sizeof(Unsigned) <= sizeof(unsigned),
  187. mpl::int_<1>,
  188. typename mpl::if_c<
  189. sizeof(Unsigned) <= sizeof(unsigned long),
  190. mpl::int_<2>,
  191. typename mpl::if_c<
  192. sizeof(Unsigned) <= sizeof(boost::ulong_long_type),
  193. mpl::int_<3>,
  194. mpl::int_<0>
  195. >::type
  196. >::type
  197. >::type tag_type;
  198. return find_msb(static_cast<ui_type>(mask), tag_type());
  199. }
  200. #elif defined(BOOST_INTEL)
  201. BOOST_FORCEINLINE unsigned find_lsb(unsigned mask, mpl::int_<1> const&)
  202. {
  203. return _bit_scan_forward(mask);
  204. }
  205. BOOST_FORCEINLINE unsigned find_msb(unsigned mask, mpl::int_<1> const&)
  206. {
  207. return _bit_scan_reverse(mask);
  208. }
  209. template <class Unsigned>
  210. BOOST_FORCEINLINE unsigned find_lsb(Unsigned mask)
  211. {
  212. typedef typename make_unsigned<Unsigned>::type ui_type;
  213. typedef typename mpl::if_c<
  214. sizeof(Unsigned) <= sizeof(unsigned),
  215. mpl::int_<1>,
  216. mpl::int_<0>
  217. >::type tag_type;
  218. return find_lsb(static_cast<ui_type>(mask), tag_type());
  219. }
  220. template <class Unsigned>
  221. BOOST_FORCEINLINE unsigned find_msb(Unsigned mask)
  222. {
  223. typedef typename make_unsigned<Unsigned>::type ui_type;
  224. typedef typename mpl::if_c<
  225. sizeof(Unsigned) <= sizeof(unsigned),
  226. mpl::int_<1>,
  227. mpl::int_<0>
  228. >::type tag_type;
  229. return find_msb(static_cast<ui_type>(mask), tag_type());
  230. }
  231. #else
  232. template <class Unsigned>
  233. BOOST_FORCEINLINE unsigned find_lsb(Unsigned mask)
  234. {
  235. return find_lsb(mask, mpl::int_<0>());
  236. }
  237. template <class Unsigned>
  238. BOOST_FORCEINLINE unsigned find_msb(Unsigned mask)
  239. {
  240. return find_msb(mask, mpl::int_<0>());
  241. }
  242. #endif
  243. }}}
  244. #endif