bitscan.hpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  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 https://www.boost.org/LICENSE_1_0.txt
  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 <cstdint>
  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 BOOST_MP_CXX14_CONSTEXPR unsigned find_lsb_default(Unsigned mask)
  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 BOOST_MP_CXX14_CONSTEXPR unsigned find_msb_default(Unsigned mask)
  29. {
  30. unsigned index = 0;
  31. while (mask)
  32. {
  33. ++index;
  34. mask >>= 1;
  35. }
  36. return --index;
  37. }
  38. template <class Unsigned>
  39. inline BOOST_MP_CXX14_CONSTEXPR unsigned find_lsb(Unsigned mask, const std::integral_constant<int, 0>&)
  40. {
  41. return find_lsb_default(mask);
  42. }
  43. template <class Unsigned>
  44. inline BOOST_MP_CXX14_CONSTEXPR unsigned find_msb(Unsigned mask, const std::integral_constant<int, 0>&)
  45. {
  46. return find_msb_default(mask);
  47. }
  48. #if (defined(BOOST_MSVC) || (defined(__clang__) && defined(__c2__)) || (defined(BOOST_INTEL) && defined(_MSC_VER))) && (defined(_M_IX86) || defined(_M_X64))
  49. #pragma intrinsic(_BitScanForward, _BitScanReverse)
  50. BOOST_FORCEINLINE unsigned find_lsb(unsigned long mask, const std::integral_constant<int, 1>&)
  51. {
  52. unsigned long result;
  53. _BitScanForward(&result, mask);
  54. return result;
  55. }
  56. BOOST_FORCEINLINE unsigned find_msb(unsigned long mask, const std::integral_constant<int, 1>&)
  57. {
  58. unsigned long result;
  59. _BitScanReverse(&result, mask);
  60. return result;
  61. }
  62. #ifdef _M_X64
  63. #pragma intrinsic(_BitScanForward64, _BitScanReverse64)
  64. BOOST_FORCEINLINE unsigned find_lsb(unsigned __int64 mask, const std::integral_constant<int, 2>&)
  65. {
  66. unsigned long result;
  67. _BitScanForward64(&result, mask);
  68. return result;
  69. }
  70. template <class Unsigned>
  71. BOOST_FORCEINLINE unsigned find_msb(Unsigned mask, const std::integral_constant<int, 2>&)
  72. {
  73. unsigned long result;
  74. _BitScanReverse64(&result, mask);
  75. return result;
  76. }
  77. #endif
  78. template <class Unsigned>
  79. BOOST_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR unsigned find_lsb(Unsigned mask)
  80. {
  81. using ui_type = typename boost::multiprecision::detail::make_unsigned<Unsigned>::type;
  82. using tag_type = typename std::conditional<
  83. sizeof(Unsigned) <= sizeof(unsigned long),
  84. std::integral_constant<int, 1>,
  85. #ifdef _M_X64
  86. typename std::conditional<
  87. sizeof(Unsigned) <= sizeof(__int64),
  88. std::integral_constant<int, 2>,
  89. std::integral_constant<int, 0> >::type
  90. #else
  91. std::integral_constant<int, 0>
  92. #endif
  93. >::type;
  94. #ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
  95. if (BOOST_MP_IS_CONST_EVALUATED(mask))
  96. {
  97. return find_lsb_default(mask);
  98. }
  99. else
  100. #endif
  101. return find_lsb(static_cast<ui_type>(mask), tag_type());
  102. }
  103. template <class Unsigned>
  104. BOOST_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR unsigned find_msb(Unsigned mask)
  105. {
  106. using ui_type = typename boost::multiprecision::detail::make_unsigned<Unsigned>::type;
  107. using tag_type = typename std::conditional<
  108. sizeof(Unsigned) <= sizeof(unsigned long),
  109. std::integral_constant<int, 1>,
  110. #ifdef _M_X64
  111. typename std::conditional<
  112. sizeof(Unsigned) <= sizeof(__int64),
  113. std::integral_constant<int, 2>,
  114. std::integral_constant<int, 0> >::type
  115. #else
  116. std::integral_constant<int, 0>
  117. #endif
  118. >::type;
  119. #ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
  120. if (BOOST_MP_IS_CONST_EVALUATED(mask))
  121. {
  122. return find_msb_default(mask);
  123. }
  124. else
  125. #endif
  126. return find_msb(static_cast<ui_type>(mask), tag_type());
  127. }
  128. #elif defined(BOOST_GCC) || defined(__clang__) || (defined(BOOST_INTEL) && defined(__GNUC__))
  129. BOOST_FORCEINLINE unsigned find_lsb(unsigned mask, std::integral_constant<int, 1> const&)
  130. {
  131. return __builtin_ctz(mask);
  132. }
  133. BOOST_FORCEINLINE unsigned find_lsb(unsigned long mask, std::integral_constant<int, 2> const&)
  134. {
  135. return __builtin_ctzl(mask);
  136. }
  137. BOOST_FORCEINLINE unsigned find_lsb(boost::ulong_long_type mask, std::integral_constant<int, 3> const&)
  138. {
  139. return __builtin_ctzll(mask);
  140. }
  141. BOOST_FORCEINLINE unsigned find_msb(unsigned mask, std::integral_constant<int, 1> const&)
  142. {
  143. return sizeof(unsigned) * CHAR_BIT - 1 - __builtin_clz(mask);
  144. }
  145. BOOST_FORCEINLINE unsigned find_msb(unsigned long mask, std::integral_constant<int, 2> const&)
  146. {
  147. return sizeof(unsigned long) * CHAR_BIT - 1 - __builtin_clzl(mask);
  148. }
  149. BOOST_FORCEINLINE unsigned find_msb(boost::ulong_long_type mask, std::integral_constant<int, 3> const&)
  150. {
  151. return sizeof(boost::ulong_long_type) * CHAR_BIT - 1 - __builtin_clzll(mask);
  152. }
  153. #ifdef BOOST_HAS_INT128
  154. __extension__ using uint128_type = unsigned __int128;
  155. BOOST_FORCEINLINE unsigned find_msb(uint128_type mask, std::integral_constant<int, 0> const&)
  156. {
  157. union
  158. {
  159. uint128_type v;
  160. std::uint64_t sv[2];
  161. } val;
  162. val.v = mask;
  163. #if BOOST_ENDIAN_LITTLE_BYTE
  164. if (val.sv[1])
  165. return find_msb(val.sv[1], std::integral_constant<int, 3>()) + 64;
  166. return find_msb(val.sv[0], std::integral_constant<int, 3>());
  167. #else
  168. if (val.sv[0])
  169. return find_msb(val.sv[0], std::integral_constant<int, 3>()) + 64;
  170. return find_msb(val.sv[1], std::integral_constant<int, 3>());
  171. #endif
  172. }
  173. BOOST_FORCEINLINE unsigned find_lsb(uint128_type mask, std::integral_constant<int, 0> const&)
  174. {
  175. union
  176. {
  177. uint128_type v;
  178. std::uint64_t sv[2];
  179. } val;
  180. val.v = mask;
  181. #if BOOST_ENDIAN_LITTLE_BYTE
  182. if (val.sv[0] == 0)
  183. return find_lsb(val.sv[1], std::integral_constant<int, 3>()) + 64;
  184. return find_lsb(val.sv[0], std::integral_constant<int, 3>());
  185. #else
  186. if (val.sv[1] == 0)
  187. return find_lsb(val.sv[0], std::integral_constant<int, 3>()) + 64;
  188. return find_lsb(val.sv[1], std::integral_constant<int, 3>());
  189. #endif
  190. }
  191. #endif
  192. template <class Unsigned>
  193. BOOST_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR unsigned find_lsb(Unsigned mask)
  194. {
  195. using ui_type = typename boost::multiprecision::detail::make_unsigned<Unsigned>::type;
  196. using tag_type = typename std::conditional<
  197. sizeof(Unsigned) <= sizeof(unsigned),
  198. std::integral_constant<int, 1>,
  199. typename std::conditional<
  200. sizeof(Unsigned) <= sizeof(unsigned long),
  201. std::integral_constant<int, 2>,
  202. typename std::conditional<
  203. sizeof(Unsigned) <= sizeof(boost::ulong_long_type),
  204. std::integral_constant<int, 3>,
  205. std::integral_constant<int, 0> >::type>::type>::type;
  206. #ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
  207. if (BOOST_MP_IS_CONST_EVALUATED(mask))
  208. {
  209. return find_lsb_default(mask);
  210. }
  211. else
  212. #endif
  213. return find_lsb(static_cast<ui_type>(mask), tag_type());
  214. }
  215. template <class Unsigned>
  216. BOOST_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR unsigned find_msb(Unsigned mask)
  217. {
  218. using ui_type = typename boost::multiprecision::detail::make_unsigned<Unsigned>::type;
  219. using tag_type = typename std::conditional<
  220. sizeof(Unsigned) <= sizeof(unsigned),
  221. std::integral_constant<int, 1>,
  222. typename std::conditional<
  223. sizeof(Unsigned) <= sizeof(unsigned long),
  224. std::integral_constant<int, 2>,
  225. typename std::conditional<
  226. sizeof(Unsigned) <= sizeof(boost::ulong_long_type),
  227. std::integral_constant<int, 3>,
  228. std::integral_constant<int, 0> >::type>::type>::type;
  229. #ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
  230. if (BOOST_MP_IS_CONST_EVALUATED(mask))
  231. {
  232. return find_msb_default(mask);
  233. }
  234. else
  235. #endif
  236. return find_msb(static_cast<ui_type>(mask), tag_type());
  237. }
  238. #elif defined(BOOST_INTEL)
  239. BOOST_FORCEINLINE unsigned find_lsb(unsigned mask, std::integral_constant<int, 1> const&)
  240. {
  241. return _bit_scan_forward(mask);
  242. }
  243. BOOST_FORCEINLINE unsigned find_msb(unsigned mask, std::integral_constant<int, 1> const&)
  244. {
  245. return _bit_scan_reverse(mask);
  246. }
  247. template <class Unsigned>
  248. BOOST_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR unsigned find_lsb(Unsigned mask)
  249. {
  250. using ui_type = typename boost::multiprecision::detail::make_unsigned<Unsigned>::type;
  251. using tag_type = typename std::conditional<
  252. sizeof(Unsigned) <= sizeof(unsigned),
  253. std::integral_constant<int, 1>,
  254. std::integral_constant<int, 0> >::type;
  255. #ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
  256. if (BOOST_MP_IS_CONST_EVALUATED(mask))
  257. {
  258. return find_lsb_default(mask);
  259. }
  260. else
  261. #endif
  262. return find_lsb(static_cast<ui_type>(mask), tag_type());
  263. }
  264. template <class Unsigned>
  265. BOOST_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR unsigned find_msb(Unsigned mask)
  266. {
  267. using ui_type = typename boost::multiprecision::detail::make_unsigned<Unsigned>::type;
  268. using tag_type = typename std::conditional<
  269. sizeof(Unsigned) <= sizeof(unsigned),
  270. std::integral_constant<int, 1>,
  271. std::integral_constant<int, 0> >::type;
  272. #ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
  273. if (BOOST_MP_IS_CONST_EVALUATED(mask))
  274. {
  275. return find_msb_default(mask);
  276. }
  277. else
  278. #endif
  279. return find_msb(static_cast<ui_type>(mask), tag_type());
  280. }
  281. #else
  282. template <class Unsigned>
  283. BOOST_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR unsigned find_lsb(Unsigned mask)
  284. {
  285. return find_lsb(mask, std::integral_constant<int, 0>());
  286. }
  287. template <class Unsigned>
  288. BOOST_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR unsigned find_msb(Unsigned mask)
  289. {
  290. return find_msb(mask, std::integral_constant<int, 0>());
  291. }
  292. #endif
  293. }}} // namespace boost::multiprecision::detail
  294. #endif