bitscan.hpp 10 KB

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