bitwise.hpp 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889
  1. ///////////////////////////////////////////////////////////////
  2. // Copyright 2012 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_CPP_INT_BITWISE_HPP
  9. #define BOOST_MP_CPP_INT_BITWISE_HPP
  10. #include <stdexcept>
  11. #include <type_traits>
  12. #include <boost/multiprecision/detail/endian.hpp>
  13. #include <boost/multiprecision/detail/no_exceptions_support.hpp>
  14. #include <boost/multiprecision/detail/assert.hpp>
  15. #ifdef BOOST_MSVC
  16. #pragma warning(push)
  17. #pragma warning(disable : 4319)
  18. #endif
  19. namespace boost { namespace multiprecision { namespace backends {
  20. template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
  21. BOOST_MP_CXX14_CONSTEXPR void is_valid_bitwise_op(
  22. cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
  23. const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o, const std::integral_constant<int, checked>&)
  24. {
  25. if (result.sign() || o.sign())
  26. BOOST_MP_THROW_EXCEPTION(std::range_error("Bitwise operations on negative values results in undefined behavior."));
  27. }
  28. template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
  29. BOOST_MP_CXX14_CONSTEXPR void is_valid_bitwise_op(
  30. cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&,
  31. const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>&, const std::integral_constant<int, unchecked>&) {}
  32. template <std::size_t MinBits1, std::size_t MaxBits1, cpp_int_check_type Checked1, class Allocator1>
  33. BOOST_MP_CXX14_CONSTEXPR void is_valid_bitwise_op(
  34. const cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>& result, const std::integral_constant<int, checked>&)
  35. {
  36. if (result.sign())
  37. BOOST_MP_THROW_EXCEPTION(std::range_error("Bitwise operations on negative values results in undefined behavior."));
  38. }
  39. template <std::size_t MinBits1, std::size_t MaxBits1, cpp_int_check_type Checked1, class Allocator1>
  40. BOOST_MP_CXX14_CONSTEXPR void is_valid_bitwise_op(
  41. const cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>&, const std::integral_constant<int, checked>&) {}
  42. template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
  43. BOOST_MP_CXX14_CONSTEXPR void is_valid_bitwise_op(
  44. cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&, const std::integral_constant<int, unchecked>&) {}
  45. template <class CppInt1, class CppInt2, class Op>
  46. BOOST_MP_CXX14_CONSTEXPR void bitwise_op(
  47. CppInt1& result,
  48. const CppInt2& o,
  49. Op op, const std::integral_constant<bool, true>&) noexcept((is_non_throwing_cpp_int<CppInt1>::value))
  50. {
  51. //
  52. // There are 4 cases:
  53. // * Both positive.
  54. // * result negative, o positive.
  55. // * o negative, result positive.
  56. // * Both negative.
  57. //
  58. // When one arg is negative we convert to 2's complement form "on the fly",
  59. // and then convert back to signed-magnitude form at the end.
  60. //
  61. // Note however, that if the type is checked, then bitwise ops on negative values
  62. // are not permitted and an exception will result.
  63. //
  64. is_valid_bitwise_op(result, o, typename CppInt1::checked_type());
  65. //
  66. // First figure out how big the result needs to be and set up some data:
  67. //
  68. std::size_t rs = result.size();
  69. std::size_t os = o.size();
  70. std::size_t m(0), x(0);
  71. minmax(rs, os, m, x);
  72. result.resize(x, x);
  73. typename CppInt1::limb_pointer pr = result.limbs();
  74. typename CppInt2::const_limb_pointer po = o.limbs();
  75. for (std::size_t i = rs; i < x; ++i)
  76. pr[i] = 0;
  77. limb_type next_limb = 0;
  78. if (!result.sign())
  79. {
  80. if (!o.sign())
  81. {
  82. for (std::size_t i = 0; i < os; ++i)
  83. pr[i] = op(pr[i], po[i]);
  84. for (std::size_t i = os; i < x; ++i)
  85. pr[i] = op(pr[i], limb_type(0));
  86. }
  87. else
  88. {
  89. // "o" is negative:
  90. double_limb_type carry = 1;
  91. for (std::size_t i = 0; i < os; ++i)
  92. {
  93. carry += static_cast<double_limb_type>(~po[i]);
  94. pr[i] = op(pr[i], static_cast<limb_type>(carry));
  95. carry >>= CppInt1::limb_bits;
  96. }
  97. for (std::size_t i = os; i < x; ++i)
  98. {
  99. carry += static_cast<double_limb_type>(~limb_type(0));
  100. pr[i] = op(pr[i], static_cast<limb_type>(carry));
  101. carry >>= CppInt1::limb_bits;
  102. }
  103. // Set the overflow into the "extra" limb:
  104. carry += static_cast<double_limb_type>(~limb_type(0));
  105. next_limb = op(limb_type(0), static_cast<limb_type>(carry));
  106. }
  107. }
  108. else
  109. {
  110. if (!o.sign())
  111. {
  112. // "result" is negative:
  113. double_limb_type carry = 1;
  114. for (std::size_t i = 0; i < os; ++i)
  115. {
  116. carry += static_cast<double_limb_type>(~pr[i]);
  117. pr[i] = op(static_cast<limb_type>(carry), po[i]);
  118. carry >>= CppInt1::limb_bits;
  119. }
  120. for (std::size_t i = os; i < x; ++i)
  121. {
  122. carry += static_cast<double_limb_type>(~pr[i]);
  123. pr[i] = op(static_cast<limb_type>(carry), limb_type(0));
  124. carry >>= CppInt1::limb_bits;
  125. }
  126. // Set the overflow into the "extra" limb:
  127. carry += static_cast<double_limb_type>(~limb_type(0));
  128. next_limb = op(static_cast<limb_type>(carry), limb_type(0));
  129. }
  130. else
  131. {
  132. // both are negative:
  133. double_limb_type r_carry = 1;
  134. double_limb_type o_carry = 1;
  135. for (std::size_t i = 0; i < os; ++i)
  136. {
  137. r_carry += static_cast<double_limb_type>(~pr[i]);
  138. o_carry += static_cast<double_limb_type>(~po[i]);
  139. pr[i] = op(static_cast<limb_type>(r_carry), static_cast<limb_type>(o_carry));
  140. r_carry >>= CppInt1::limb_bits;
  141. o_carry >>= CppInt1::limb_bits;
  142. }
  143. for (std::size_t i = os; i < x; ++i)
  144. {
  145. r_carry += static_cast<double_limb_type>(~pr[i]);
  146. o_carry += static_cast<double_limb_type>(~limb_type(0));
  147. pr[i] = op(static_cast<limb_type>(r_carry), static_cast<limb_type>(o_carry));
  148. r_carry >>= CppInt1::limb_bits;
  149. o_carry >>= CppInt1::limb_bits;
  150. }
  151. // Set the overflow into the "extra" limb:
  152. r_carry += static_cast<double_limb_type>(~limb_type(0));
  153. o_carry += static_cast<double_limb_type>(~limb_type(0));
  154. next_limb = op(static_cast<limb_type>(r_carry), static_cast<limb_type>(o_carry));
  155. }
  156. }
  157. //
  158. // See if the result is negative or not:
  159. //
  160. if (static_cast<signed_limb_type>(next_limb) < 0)
  161. {
  162. double_limb_type carry = 1;
  163. for (std::size_t i = 0; i < x; ++i)
  164. {
  165. carry += static_cast<double_limb_type>(~pr[i]);
  166. pr[i] = static_cast<limb_type>(carry);
  167. carry >>= CppInt1::limb_bits;
  168. }
  169. if (carry)
  170. {
  171. result.resize(x + 1, x);
  172. if (result.size() > x)
  173. result.limbs()[x] = static_cast<limb_type>(carry);
  174. }
  175. result.sign(true);
  176. }
  177. else
  178. result.sign(false);
  179. result.normalize();
  180. }
  181. template <class CppInt1, class CppInt2, class Op>
  182. BOOST_MP_CXX14_CONSTEXPR void bitwise_op(
  183. CppInt1& result,
  184. const CppInt2& o,
  185. Op op, const std::integral_constant<bool, false>&) noexcept((is_non_throwing_cpp_int<CppInt1>::value))
  186. {
  187. //
  188. // Both arguments are unsigned types, very simple case handled as a special case.
  189. //
  190. // First figure out how big the result needs to be and set up some data:
  191. //
  192. std::size_t rs = result.size();
  193. std::size_t os = o.size();
  194. std::size_t m(0), x(0);
  195. minmax(rs, os, m, x);
  196. result.resize(x, x);
  197. typename CppInt1::limb_pointer pr = result.limbs();
  198. typename CppInt2::const_limb_pointer po = o.limbs();
  199. for (std::size_t i = rs; i < x; ++i)
  200. pr[i] = 0;
  201. for (std::size_t i = 0; i < os; ++i)
  202. pr[i] = op(pr[i], po[i]);
  203. for (std::size_t i = os; i < x; ++i)
  204. pr[i] = op(pr[i], limb_type(0));
  205. result.normalize();
  206. }
  207. struct bit_and
  208. {
  209. BOOST_MP_CXX14_CONSTEXPR limb_type operator()(limb_type a, limb_type b) const noexcept { return a & b; }
  210. };
  211. struct bit_or
  212. {
  213. BOOST_MP_CXX14_CONSTEXPR limb_type operator()(limb_type a, limb_type b) const noexcept { return a | b; }
  214. };
  215. struct bit_xor
  216. {
  217. BOOST_MP_CXX14_CONSTEXPR limb_type operator()(limb_type a, limb_type b) const noexcept { return a ^ b; }
  218. };
  219. template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
  220. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value>::type
  221. eval_bitwise_and(
  222. cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
  223. const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
  224. {
  225. bitwise_op(result, o, bit_and(),
  226. std::integral_constant<bool, std::numeric_limits<number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> > >::is_signed || std::numeric_limits<number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> > >::is_signed > ());
  227. }
  228. template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
  229. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value>::type
  230. eval_bitwise_or(
  231. cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
  232. const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
  233. {
  234. bitwise_op(result, o, bit_or(),
  235. std::integral_constant<bool, std::numeric_limits<number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> > >::is_signed || std::numeric_limits<number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> > >::is_signed > ());
  236. }
  237. template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
  238. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value>::type
  239. eval_bitwise_xor(
  240. cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
  241. const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
  242. {
  243. bitwise_op(result, o, bit_xor(),
  244. std::integral_constant<bool, std::numeric_limits<number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> > >::is_signed || std::numeric_limits<number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> > >::is_signed > ());
  245. }
  246. //
  247. // Again for operands which are single limbs:
  248. //
  249. template <std::size_t MinBits1, std::size_t MaxBits1, cpp_int_check_type Checked1, class Allocator1>
  250. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1> >::value>::type
  251. eval_bitwise_and(
  252. cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>& result,
  253. limb_type l) noexcept
  254. {
  255. result.limbs()[0] &= l;
  256. result.resize(1, 1);
  257. }
  258. template <std::size_t MinBits1, std::size_t MaxBits1, cpp_int_check_type Checked1, class Allocator1>
  259. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1> >::value>::type
  260. eval_bitwise_or(
  261. cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>& result,
  262. limb_type l) noexcept
  263. {
  264. result.limbs()[0] |= l;
  265. }
  266. template <std::size_t MinBits1, std::size_t MaxBits1, cpp_int_check_type Checked1, class Allocator1>
  267. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1> >::value>::type
  268. eval_bitwise_xor(
  269. cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>& result,
  270. limb_type l) noexcept
  271. {
  272. result.limbs()[0] ^= l;
  273. }
  274. template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
  275. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value>::type
  276. eval_complement(
  277. cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
  278. const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
  279. {
  280. static_assert(((Checked1 != checked) || (Checked2 != checked)), "Attempt to take the complement of a signed type results in undefined behavior.");
  281. // Increment and negate:
  282. result = o;
  283. eval_increment(result);
  284. result.negate();
  285. }
  286. template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
  287. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
  288. eval_complement(
  289. cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
  290. const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& o) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
  291. {
  292. std::size_t os = o.size();
  293. result.resize(SIZE_MAX, os);
  294. for (std::size_t i = 0; i < os; ++i)
  295. result.limbs()[i] = ~o.limbs()[i];
  296. for (std::size_t i = os; i < result.size(); ++i)
  297. result.limbs()[i] = ~static_cast<limb_type>(0);
  298. result.normalize();
  299. }
  300. template <class Int>
  301. inline void left_shift_byte(Int& result, double_limb_type s)
  302. {
  303. limb_type offset = static_cast<limb_type>(s / Int::limb_bits);
  304. limb_type shift = static_cast<limb_type>(s % Int::limb_bits);
  305. std::size_t ors = result.size();
  306. if ((ors == 1) && (!*result.limbs()))
  307. return; // shifting zero yields zero.
  308. std::size_t rs = ors;
  309. if (shift && (result.limbs()[ors - 1] >> (Int::limb_bits - shift)))
  310. ++rs; // Most significant limb will overflow when shifted
  311. rs += offset;
  312. result.resize(rs, rs);
  313. rs = result.size();
  314. typename Int::limb_pointer pr = result.limbs();
  315. if (rs != ors)
  316. pr[rs - 1] = 0u;
  317. std::size_t bytes = static_cast<std::size_t>(s / CHAR_BIT);
  318. std::size_t len = (std::min)(ors * sizeof(limb_type), rs * sizeof(limb_type) - bytes);
  319. if (bytes >= rs * sizeof(limb_type))
  320. result = static_cast<limb_type>(0u);
  321. else
  322. {
  323. unsigned char* pc = reinterpret_cast<unsigned char*>(pr);
  324. std::memmove(pc + bytes, pc, len);
  325. std::memset(pc, 0, bytes);
  326. }
  327. }
  328. template <class Int>
  329. inline BOOST_MP_CXX14_CONSTEXPR void left_shift_limb(Int& result, double_limb_type s)
  330. {
  331. limb_type offset = static_cast<limb_type>(s / Int::limb_bits);
  332. limb_type shift = static_cast<limb_type>(s % Int::limb_bits);
  333. std::size_t ors = result.size();
  334. if ((ors == 1) && (!*result.limbs()))
  335. return; // shifting zero yields zero.
  336. std::size_t rs = ors;
  337. if (shift && (result.limbs()[ors - 1] >> (Int::limb_bits - shift)))
  338. ++rs; // Most significant limb will overflow when shifted
  339. rs += offset;
  340. result.resize(rs, rs);
  341. typename Int::limb_pointer pr = result.limbs();
  342. if (offset > rs)
  343. {
  344. // The result is shifted past the end of the result:
  345. result = static_cast<limb_type>(0);
  346. return;
  347. }
  348. std::size_t i = rs - result.size();
  349. for (; i < ors; ++i)
  350. pr[rs - 1 - i] = pr[ors - 1 - i];
  351. #ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
  352. if (BOOST_MP_IS_CONST_EVALUATED(s))
  353. {
  354. for (; i < rs; ++i)
  355. pr[rs - 1 - i] = 0;
  356. }
  357. else
  358. #endif
  359. {
  360. std::memset(pr, 0, (rs - i) * sizeof(*pr));
  361. }
  362. }
  363. template <class Int>
  364. inline BOOST_MP_CXX14_CONSTEXPR void left_shift_generic(Int& result, double_limb_type s)
  365. {
  366. limb_type offset = static_cast<limb_type>(s / Int::limb_bits);
  367. limb_type shift = static_cast<limb_type>(s % Int::limb_bits);
  368. std::size_t ors = result.size();
  369. if ((ors == 1) && (!*result.limbs()))
  370. return; // shifting zero yields zero.
  371. std::size_t rs = ors;
  372. if (shift && (result.limbs()[ors - 1] >> (Int::limb_bits - shift)))
  373. ++rs; // Most significant limb will overflow when shifted
  374. rs += offset;
  375. result.resize(rs, rs);
  376. bool truncated = result.size() != rs;
  377. typename Int::limb_pointer pr = result.limbs();
  378. if (offset > rs)
  379. {
  380. // The result is shifted past the end of the result:
  381. result = static_cast<limb_type>(0);
  382. return;
  383. }
  384. std::size_t i = rs - result.size();
  385. // This code only works when shift is non-zero, otherwise we invoke undefined behaviour!
  386. BOOST_MP_ASSERT(shift);
  387. if (!truncated)
  388. {
  389. if (rs > ors + offset)
  390. {
  391. pr[rs - 1 - i] = pr[ors - 1 - i] >> (Int::limb_bits - shift);
  392. --rs;
  393. }
  394. else
  395. {
  396. pr[rs - 1 - i] = pr[ors - 1 - i] << shift;
  397. if (ors > 1)
  398. pr[rs - 1 - i] |= pr[ors - 2 - i] >> (Int::limb_bits - shift);
  399. ++i;
  400. }
  401. }
  402. for (; rs - i >= static_cast<std::size_t>(static_cast<std::size_t>(2u) + offset); ++i)
  403. {
  404. pr[rs - 1 - i] = pr[rs - 1 - i - offset] << shift;
  405. pr[rs - 1 - i] |= pr[rs - 2 - i - offset] >> (Int::limb_bits - shift);
  406. }
  407. if (rs - i >= static_cast<std::size_t>(static_cast<std::size_t>(1u) + offset))
  408. {
  409. pr[rs - 1 - i] = pr[rs - 1 - i - offset] << shift;
  410. ++i;
  411. }
  412. #ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
  413. if (BOOST_MP_IS_CONST_EVALUATED(s))
  414. {
  415. for (; i < rs; ++i)
  416. pr[rs - 1 - i] = 0;
  417. }
  418. else
  419. #endif
  420. {
  421. std::memset(pr, 0, (rs - i) * sizeof(*pr));
  422. }
  423. }
  424. template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
  425. inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
  426. eval_left_shift(
  427. cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
  428. double_limb_type s) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
  429. {
  430. is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
  431. if (!s)
  432. return;
  433. #if BOOST_MP_ENDIAN_LITTLE_BYTE && defined(BOOST_MP_USE_LIMB_SHIFT)
  434. constexpr limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits - 1;
  435. constexpr limb_type byte_shift_mask = CHAR_BIT - 1;
  436. if ((s & limb_shift_mask) == 0)
  437. {
  438. left_shift_limb(result, s);
  439. }
  440. #ifdef BOOST_MP_NO_CONSTEXPR_DETECTION
  441. else if ((s & byte_shift_mask) == 0)
  442. #else
  443. else if (((s & byte_shift_mask) == 0) && !BOOST_MP_IS_CONST_EVALUATED(s))
  444. #endif
  445. {
  446. left_shift_byte(result, s);
  447. }
  448. #elif BOOST_MP_ENDIAN_LITTLE_BYTE
  449. constexpr limb_type byte_shift_mask = CHAR_BIT - 1;
  450. #ifdef BOOST_MP_NO_CONSTEXPR_DETECTION
  451. if ((s & byte_shift_mask) == 0)
  452. #else
  453. constexpr limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits - 1;
  454. if (BOOST_MP_IS_CONST_EVALUATED(s) && ((s & limb_shift_mask) == 0))
  455. left_shift_limb(result, s);
  456. else if (((s & byte_shift_mask) == 0) && !BOOST_MP_IS_CONST_EVALUATED(s))
  457. #endif
  458. {
  459. left_shift_byte(result, s);
  460. }
  461. #else
  462. constexpr limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits - 1;
  463. if ((s & limb_shift_mask) == 0)
  464. {
  465. left_shift_limb(result, s);
  466. }
  467. #endif
  468. else
  469. {
  470. left_shift_generic(result, s);
  471. }
  472. //
  473. // We may have shifted off the end and have leading zeros:
  474. //
  475. result.normalize();
  476. }
  477. template <class Int>
  478. inline void right_shift_byte(Int& result, double_limb_type s)
  479. {
  480. limb_type offset = static_cast<limb_type>(s / Int::limb_bits);
  481. BOOST_MP_ASSERT((s % CHAR_BIT) == 0);
  482. std::size_t ors = result.size();
  483. std::size_t rs = ors;
  484. if (offset >= rs)
  485. {
  486. result = limb_type(0);
  487. return;
  488. }
  489. rs -= offset;
  490. typename Int::limb_pointer pr = result.limbs();
  491. unsigned char* pc = reinterpret_cast<unsigned char*>(pr);
  492. limb_type shift = static_cast<limb_type>(s / CHAR_BIT);
  493. std::memmove(pc, pc + shift, ors * sizeof(pr[0]) - shift);
  494. shift = (sizeof(limb_type) - shift % sizeof(limb_type)) * CHAR_BIT;
  495. if (shift < Int::limb_bits)
  496. {
  497. pr[ors - offset - 1] &= (static_cast<limb_type>(1u) << shift) - 1;
  498. if (!pr[ors - offset - 1] && (rs > 1))
  499. --rs;
  500. }
  501. result.resize(rs, rs);
  502. }
  503. template <class Int>
  504. inline BOOST_MP_CXX14_CONSTEXPR void right_shift_limb(Int& result, double_limb_type s)
  505. {
  506. limb_type offset = static_cast<limb_type>(s / Int::limb_bits);
  507. BOOST_MP_ASSERT((s % Int::limb_bits) == 0);
  508. std::size_t ors = result.size();
  509. std::size_t rs = ors;
  510. if (offset >= rs)
  511. {
  512. result = limb_type(0);
  513. return;
  514. }
  515. rs -= offset;
  516. typename Int::limb_pointer pr = result.limbs();
  517. std::size_t i = 0;
  518. for (; i < rs; ++i)
  519. pr[i] = pr[i + offset];
  520. result.resize(rs, rs);
  521. }
  522. template <class Int>
  523. inline BOOST_MP_CXX14_CONSTEXPR void right_shift_generic(Int& result, double_limb_type s)
  524. {
  525. limb_type offset = static_cast<limb_type>(s / Int::limb_bits);
  526. limb_type shift = static_cast<limb_type>(s % Int::limb_bits);
  527. std::size_t ors = result.size();
  528. std::size_t rs = ors;
  529. if (offset >= rs)
  530. {
  531. result = limb_type(0);
  532. return;
  533. }
  534. rs -= offset;
  535. typename Int::limb_pointer pr = result.limbs();
  536. if ((pr[ors - 1] >> shift) == 0)
  537. {
  538. if (--rs == 0)
  539. {
  540. result = limb_type(0);
  541. return;
  542. }
  543. }
  544. std::size_t i = 0;
  545. // This code only works for non-zero shift, otherwise we invoke undefined behaviour!
  546. BOOST_MP_ASSERT(shift);
  547. for (; i + offset + 1 < ors; ++i)
  548. {
  549. pr[i] = pr[i + offset] >> shift;
  550. pr[i] |= pr[i + offset + 1] << (Int::limb_bits - shift);
  551. }
  552. pr[i] = pr[i + offset] >> shift;
  553. result.resize(rs, rs);
  554. }
  555. template <std::size_t MinBits1, std::size_t MaxBits1, cpp_int_check_type Checked1, class Allocator1>
  556. inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1> >::value>::type
  557. eval_right_shift(
  558. cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>& result,
  559. double_limb_type s) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1> >::value))
  560. {
  561. is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>::checked_type());
  562. if (!s)
  563. return;
  564. #if BOOST_MP_ENDIAN_LITTLE_BYTE && defined(BOOST_MP_USE_LIMB_SHIFT)
  565. constexpr limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::limb_bits - 1;
  566. constexpr limb_type byte_shift_mask = CHAR_BIT - 1;
  567. if ((s & limb_shift_mask) == 0)
  568. right_shift_limb(result, s);
  569. #ifdef BOOST_MP_NO_CONSTEXPR_DETECTION
  570. else if ((s & byte_shift_mask) == 0)
  571. #else
  572. else if (((s & byte_shift_mask) == 0) && !BOOST_MP_IS_CONST_EVALUATED(s))
  573. #endif
  574. right_shift_byte(result, s);
  575. #elif BOOST_MP_ENDIAN_LITTLE_BYTE
  576. constexpr limb_type byte_shift_mask = CHAR_BIT - 1;
  577. #ifdef BOOST_MP_NO_CONSTEXPR_DETECTION
  578. if ((s & byte_shift_mask) == 0)
  579. #else
  580. constexpr limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::limb_bits - 1;
  581. if (BOOST_MP_IS_CONST_EVALUATED(s) && ((s & limb_shift_mask) == 0))
  582. right_shift_limb(result, s);
  583. else if (((s & byte_shift_mask) == 0) && !BOOST_MP_IS_CONST_EVALUATED(s))
  584. #endif
  585. right_shift_byte(result, s);
  586. #else
  587. constexpr limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::limb_bits - 1;
  588. if ((s & limb_shift_mask) == 0)
  589. right_shift_limb(result, s);
  590. #endif
  591. else
  592. right_shift_generic(result, s);
  593. }
  594. template <std::size_t MinBits1, std::size_t MaxBits1, cpp_int_check_type Checked1, class Allocator1>
  595. inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1> >::value>::type
  596. eval_right_shift(
  597. cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>& result,
  598. double_limb_type s) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1> >::value))
  599. {
  600. is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::checked_type());
  601. if (!s)
  602. return;
  603. bool is_neg = result.sign();
  604. if (is_neg)
  605. eval_increment(result);
  606. #if BOOST_MP_ENDIAN_LITTLE_BYTE && defined(BOOST_MP_USE_LIMB_SHIFT)
  607. constexpr limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::limb_bits - 1;
  608. constexpr limb_type byte_shift_mask = CHAR_BIT - 1;
  609. if ((s & limb_shift_mask) == 0)
  610. right_shift_limb(result, s);
  611. #ifdef BOOST_MP_NO_CONSTEXPR_DETECTION
  612. else if ((s & byte_shift_mask) == 0)
  613. #else
  614. else if (((s & byte_shift_mask) == 0) && !BOOST_MP_IS_CONST_EVALUATED(s))
  615. #endif
  616. right_shift_byte(result, s);
  617. #elif BOOST_MP_ENDIAN_LITTLE_BYTE
  618. constexpr limb_type byte_shift_mask = CHAR_BIT - 1;
  619. #ifdef BOOST_MP_NO_CONSTEXPR_DETECTION
  620. if ((s & byte_shift_mask) == 0)
  621. #else
  622. constexpr limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::limb_bits - 1;
  623. if (BOOST_MP_IS_CONST_EVALUATED(s) && ((s & limb_shift_mask) == 0))
  624. right_shift_limb(result, s);
  625. else if (((s & byte_shift_mask) == 0) && !BOOST_MP_IS_CONST_EVALUATED(s))
  626. #endif
  627. right_shift_byte(result, s);
  628. #else
  629. constexpr limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::limb_bits - 1;
  630. if ((s & limb_shift_mask) == 0)
  631. right_shift_limb(result, s);
  632. #endif
  633. else
  634. right_shift_generic(result, s);
  635. if (is_neg)
  636. eval_decrement(result);
  637. }
  638. //
  639. // Over again for trivial cpp_int's:
  640. //
  641. template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class T>
  642. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value >::type
  643. eval_left_shift(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, T s) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
  644. {
  645. is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
  646. *result.limbs() = detail::checked_left_shift(*result.limbs(), s, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
  647. result.normalize();
  648. }
  649. template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class T>
  650. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value >::type
  651. eval_right_shift(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, T s) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
  652. {
  653. // Nothing to check here... just make sure we don't invoke undefined behavior:
  654. is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
  655. *result.limbs() = (static_cast<unsigned>(s) >= sizeof(*result.limbs()) * CHAR_BIT) ? 0 : (result.sign() ? ((--*result.limbs()) >> s) + 1 : *result.limbs() >> s);
  656. if (result.sign() && (*result.limbs() == 0))
  657. result = static_cast<signed_limb_type>(-1);
  658. }
  659. template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
  660. inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
  661. is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value && (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || is_signed_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value)>::type
  662. eval_complement(
  663. cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
  664. const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
  665. {
  666. static_assert(((Checked1 != checked) || (Checked2 != checked)), "Attempt to take the complement of a signed type results in undefined behavior.");
  667. //
  668. // If we're not checked then emulate 2's complement behavior:
  669. //
  670. if (o.sign())
  671. {
  672. *result.limbs() = *o.limbs() - 1;
  673. result.sign(false);
  674. }
  675. else
  676. {
  677. *result.limbs() = 1 + *o.limbs();
  678. result.sign(true);
  679. }
  680. result.normalize();
  681. }
  682. template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
  683. inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
  684. is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value && is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && is_unsigned_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value>::type
  685. eval_complement(
  686. cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
  687. const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
  688. {
  689. *result.limbs() = ~*o.limbs();
  690. result.normalize();
  691. }
  692. template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
  693. inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
  694. is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value && is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && is_unsigned_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value>::type
  695. eval_bitwise_and(
  696. cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
  697. const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
  698. {
  699. *result.limbs() &= *o.limbs();
  700. }
  701. template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
  702. inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
  703. is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value && (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || is_signed_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value)>::type
  704. eval_bitwise_and(
  705. cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
  706. const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
  707. {
  708. is_valid_bitwise_op(result, o, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
  709. using default_ops::eval_bit_test;
  710. using default_ops::eval_increment;
  711. if (result.sign() || o.sign())
  712. {
  713. constexpr std::size_t m = detail::static_unsigned_max<detail::static_unsigned_max<MinBits1, MinBits2>::value, detail::static_unsigned_max<MaxBits1, MaxBits2>::value>::value;
  714. cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t1(result);
  715. cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t2(o);
  716. eval_bitwise_and(t1, t2);
  717. bool s = eval_bit_test(t1, m + 1);
  718. if (s)
  719. {
  720. eval_complement(t1, t1);
  721. eval_increment(t1);
  722. }
  723. result = t1;
  724. result.sign(s);
  725. }
  726. else
  727. {
  728. *result.limbs() &= *o.limbs();
  729. }
  730. }
  731. template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
  732. inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
  733. is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value && is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && is_unsigned_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value>::type
  734. eval_bitwise_or(
  735. cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
  736. const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
  737. {
  738. *result.limbs() |= *o.limbs();
  739. }
  740. template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
  741. inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
  742. is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value && (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || is_signed_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value)>::type
  743. eval_bitwise_or(
  744. cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
  745. const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
  746. {
  747. is_valid_bitwise_op(result, o, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
  748. using default_ops::eval_bit_test;
  749. using default_ops::eval_increment;
  750. if (result.sign() || o.sign())
  751. {
  752. constexpr std::size_t m = detail::static_unsigned_max<detail::static_unsigned_max<MinBits1, MinBits2>::value, detail::static_unsigned_max<MaxBits1, MaxBits2>::value>::value;
  753. cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t1(result);
  754. cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t2(o);
  755. eval_bitwise_or(t1, t2);
  756. bool s = eval_bit_test(t1, m + 1);
  757. if (s)
  758. {
  759. eval_complement(t1, t1);
  760. eval_increment(t1);
  761. }
  762. result = t1;
  763. result.sign(s);
  764. }
  765. else
  766. {
  767. *result.limbs() |= *o.limbs();
  768. result.normalize();
  769. }
  770. }
  771. template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
  772. inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
  773. is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value && is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && is_unsigned_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value>::type
  774. eval_bitwise_xor(
  775. cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
  776. const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
  777. {
  778. *result.limbs() ^= *o.limbs();
  779. }
  780. template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
  781. inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
  782. is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value && (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || is_signed_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value)>::type
  783. eval_bitwise_xor(
  784. cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
  785. const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
  786. {
  787. is_valid_bitwise_op(result, o, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
  788. using default_ops::eval_bit_test;
  789. using default_ops::eval_increment;
  790. if (result.sign() || o.sign())
  791. {
  792. constexpr std::size_t m = detail::static_unsigned_max<detail::static_unsigned_max<MinBits1, MinBits2>::value, detail::static_unsigned_max<MaxBits1, MaxBits2>::value>::value;
  793. cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t1(result);
  794. cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t2(o);
  795. eval_bitwise_xor(t1, t2);
  796. bool s = eval_bit_test(t1, m + 1);
  797. if (s)
  798. {
  799. eval_complement(t1, t1);
  800. eval_increment(t1);
  801. }
  802. result = t1;
  803. result.sign(s);
  804. }
  805. else
  806. {
  807. *result.limbs() ^= *o.limbs();
  808. }
  809. }
  810. }}} // namespace boost::multiprecision::backends
  811. #ifdef BOOST_MSVC
  812. #pragma warning(pop)
  813. #endif
  814. #endif