/////////////////////////////////////////////////////////////// // Copyright 2012 John Maddock. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt // // Comparison operators for cpp_int_backend: // #ifndef BOOST_MP_CPP_INT_BIT_HPP #define BOOST_MP_CPP_INT_BIT_HPP #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4319) #endif namespace boost { namespace multiprecision { namespace backends { template BOOST_MP_CXX14_CONSTEXPR void is_valid_bitwise_op( cpp_int_backend& result, const cpp_int_backend& o, const std::integral_constant&) { if (result.sign() || o.sign()) BOOST_THROW_EXCEPTION(std::range_error("Bitwise operations on negative values results in undefined behavior.")); } template BOOST_MP_CXX14_CONSTEXPR void is_valid_bitwise_op( cpp_int_backend&, const cpp_int_backend&, const std::integral_constant&) {} template BOOST_MP_CXX14_CONSTEXPR void is_valid_bitwise_op( const cpp_int_backend& result, const std::integral_constant&) { if (result.sign()) BOOST_THROW_EXCEPTION(std::range_error("Bitwise operations on negative values results in undefined behavior.")); } template BOOST_MP_CXX14_CONSTEXPR void is_valid_bitwise_op( const cpp_int_backend&, const std::integral_constant&) {} template BOOST_MP_CXX14_CONSTEXPR void is_valid_bitwise_op( cpp_int_backend&, const std::integral_constant&) {} template BOOST_MP_CXX14_CONSTEXPR void bitwise_op( CppInt1& result, const CppInt2& o, Op op, const std::integral_constant&) noexcept((is_non_throwing_cpp_int::value)) { // // There are 4 cases: // * Both positive. // * result negative, o positive. // * o negative, result positive. // * Both negative. // // When one arg is negative we convert to 2's complement form "on the fly", // and then convert back to signed-magnitude form at the end. // // Note however, that if the type is checked, then bitwise ops on negative values // are not permitted and an exception will result. // is_valid_bitwise_op(result, o, typename CppInt1::checked_type()); // // First figure out how big the result needs to be and set up some data: // unsigned rs = result.size(); unsigned os = o.size(); unsigned m(0), x(0); minmax(rs, os, m, x); result.resize(x, x); typename CppInt1::limb_pointer pr = result.limbs(); typename CppInt2::const_limb_pointer po = o.limbs(); for (unsigned i = rs; i < x; ++i) pr[i] = 0; limb_type next_limb = 0; if (!result.sign()) { if (!o.sign()) { for (unsigned i = 0; i < os; ++i) pr[i] = op(pr[i], po[i]); for (unsigned i = os; i < x; ++i) pr[i] = op(pr[i], limb_type(0)); } else { // "o" is negative: double_limb_type carry = 1; for (unsigned i = 0; i < os; ++i) { carry += static_cast(~po[i]); pr[i] = op(pr[i], static_cast(carry)); carry >>= CppInt1::limb_bits; } for (unsigned i = os; i < x; ++i) { carry += static_cast(~limb_type(0)); pr[i] = op(pr[i], static_cast(carry)); carry >>= CppInt1::limb_bits; } // Set the overflow into the "extra" limb: carry += static_cast(~limb_type(0)); next_limb = op(limb_type(0), static_cast(carry)); } } else { if (!o.sign()) { // "result" is negative: double_limb_type carry = 1; for (unsigned i = 0; i < os; ++i) { carry += static_cast(~pr[i]); pr[i] = op(static_cast(carry), po[i]); carry >>= CppInt1::limb_bits; } for (unsigned i = os; i < x; ++i) { carry += static_cast(~pr[i]); pr[i] = op(static_cast(carry), limb_type(0)); carry >>= CppInt1::limb_bits; } // Set the overflow into the "extra" limb: carry += static_cast(~limb_type(0)); next_limb = op(static_cast(carry), limb_type(0)); } else { // both are negative: double_limb_type r_carry = 1; double_limb_type o_carry = 1; for (unsigned i = 0; i < os; ++i) { r_carry += static_cast(~pr[i]); o_carry += static_cast(~po[i]); pr[i] = op(static_cast(r_carry), static_cast(o_carry)); r_carry >>= CppInt1::limb_bits; o_carry >>= CppInt1::limb_bits; } for (unsigned i = os; i < x; ++i) { r_carry += static_cast(~pr[i]); o_carry += static_cast(~limb_type(0)); pr[i] = op(static_cast(r_carry), static_cast(o_carry)); r_carry >>= CppInt1::limb_bits; o_carry >>= CppInt1::limb_bits; } // Set the overflow into the "extra" limb: r_carry += static_cast(~limb_type(0)); o_carry += static_cast(~limb_type(0)); next_limb = op(static_cast(r_carry), static_cast(o_carry)); } } // // See if the result is negative or not: // if (static_cast(next_limb) < 0) { double_limb_type carry = 1; for (unsigned i = 0; i < x; ++i) { carry += static_cast(~pr[i]); pr[i] = static_cast(carry); carry >>= CppInt1::limb_bits; } if (carry) { result.resize(x + 1, x); if (result.size() > x) result.limbs()[x] = static_cast(carry); } result.sign(true); } else result.sign(false); result.normalize(); } template BOOST_MP_CXX14_CONSTEXPR void bitwise_op( CppInt1& result, const CppInt2& o, Op op, const std::integral_constant&) noexcept((is_non_throwing_cpp_int::value)) { // // Both arguments are unsigned types, very simple case handled as a special case. // // First figure out how big the result needs to be and set up some data: // unsigned rs = result.size(); unsigned os = o.size(); unsigned m(0), x(0); minmax(rs, os, m, x); result.resize(x, x); typename CppInt1::limb_pointer pr = result.limbs(); typename CppInt2::const_limb_pointer po = o.limbs(); for (unsigned i = rs; i < x; ++i) pr[i] = 0; for (unsigned i = 0; i < os; ++i) pr[i] = op(pr[i], po[i]); for (unsigned i = os; i < x; ++i) pr[i] = op(pr[i], limb_type(0)); result.normalize(); } struct bit_and { BOOST_MP_CXX14_CONSTEXPR limb_type operator()(limb_type a, limb_type b) const noexcept { return a & b; } }; struct bit_or { BOOST_MP_CXX14_CONSTEXPR limb_type operator()(limb_type a, limb_type b) const noexcept { return a | b; } }; struct bit_xor { BOOST_MP_CXX14_CONSTEXPR limb_type operator()(limb_type a, limb_type b) const noexcept { return a ^ b; } }; template BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value && !is_trivial_cpp_int >::value>::type eval_bitwise_and( cpp_int_backend& result, const cpp_int_backend& o) noexcept((is_non_throwing_cpp_int >::value)) { bitwise_op(result, o, bit_and(), std::integral_constant > >::is_signed || std::numeric_limits > >::is_signed > ()); } template BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value && !is_trivial_cpp_int >::value>::type eval_bitwise_or( cpp_int_backend& result, const cpp_int_backend& o) noexcept((is_non_throwing_cpp_int >::value)) { bitwise_op(result, o, bit_or(), std::integral_constant > >::is_signed || std::numeric_limits > >::is_signed > ()); } template BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value && !is_trivial_cpp_int >::value>::type eval_bitwise_xor( cpp_int_backend& result, const cpp_int_backend& o) noexcept((is_non_throwing_cpp_int >::value)) { bitwise_op(result, o, bit_xor(), std::integral_constant > >::is_signed || std::numeric_limits > >::is_signed > ()); } // // Again for operands which are single limbs: // template BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value>::type eval_bitwise_and( cpp_int_backend& result, limb_type l) noexcept { result.limbs()[0] &= l; result.resize(1, 1); } template BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value>::type eval_bitwise_or( cpp_int_backend& result, limb_type l) noexcept { result.limbs()[0] |= l; } template BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value>::type eval_bitwise_xor( cpp_int_backend& result, limb_type l) noexcept { result.limbs()[0] ^= l; } template BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value && !is_trivial_cpp_int >::value && !is_trivial_cpp_int >::value>::type eval_complement( cpp_int_backend& result, const cpp_int_backend& o) noexcept((is_non_throwing_cpp_int >::value)) { static_assert(((Checked1 != checked) || (Checked2 != checked)), "Attempt to take the complement of a signed type results in undefined behavior."); // Increment and negate: result = o; eval_increment(result); result.negate(); } template BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value && !is_trivial_cpp_int >::value && !is_trivial_cpp_int >::value>::type eval_complement( cpp_int_backend& result, const cpp_int_backend& o) noexcept((is_non_throwing_cpp_int >::value)) { unsigned os = o.size(); result.resize(UINT_MAX, os); for (unsigned i = 0; i < os; ++i) result.limbs()[i] = ~o.limbs()[i]; for (unsigned i = os; i < result.size(); ++i) result.limbs()[i] = ~static_cast(0); result.normalize(); } template inline void left_shift_byte(Int& result, double_limb_type s) { limb_type offset = static_cast(s / Int::limb_bits); limb_type shift = static_cast(s % Int::limb_bits); unsigned ors = result.size(); if ((ors == 1) && (!*result.limbs())) return; // shifting zero yields zero. unsigned rs = ors; if (shift && (result.limbs()[ors - 1] >> (Int::limb_bits - shift))) ++rs; // Most significant limb will overflow when shifted rs += offset; result.resize(rs, rs); rs = result.size(); typename Int::limb_pointer pr = result.limbs(); if (rs != ors) pr[rs - 1] = 0u; std::size_t bytes = static_cast(s / CHAR_BIT); std::size_t len = (std::min)(ors * sizeof(limb_type), rs * sizeof(limb_type) - bytes); if (bytes >= rs * sizeof(limb_type)) result = static_cast(0u); else { unsigned char* pc = reinterpret_cast(pr); std::memmove(pc + bytes, pc, len); std::memset(pc, 0, bytes); } } template inline BOOST_MP_CXX14_CONSTEXPR void left_shift_limb(Int& result, double_limb_type s) { limb_type offset = static_cast(s / Int::limb_bits); limb_type shift = static_cast(s % Int::limb_bits); unsigned ors = result.size(); if ((ors == 1) && (!*result.limbs())) return; // shifting zero yields zero. unsigned rs = ors; if (shift && (result.limbs()[ors - 1] >> (Int::limb_bits - shift))) ++rs; // Most significant limb will overflow when shifted rs += offset; result.resize(rs, rs); typename Int::limb_pointer pr = result.limbs(); if (offset > rs) { // The result is shifted past the end of the result: result = static_cast(0); return; } unsigned i = rs - result.size(); for (; i < ors; ++i) pr[rs - 1 - i] = pr[ors - 1 - i]; for (; i < rs; ++i) pr[rs - 1 - i] = 0; } template inline BOOST_MP_CXX14_CONSTEXPR void left_shift_generic(Int& result, double_limb_type s) { limb_type offset = static_cast(s / Int::limb_bits); limb_type shift = static_cast(s % Int::limb_bits); unsigned ors = result.size(); if ((ors == 1) && (!*result.limbs())) return; // shifting zero yields zero. unsigned rs = ors; if (shift && (result.limbs()[ors - 1] >> (Int::limb_bits - shift))) ++rs; // Most significant limb will overflow when shifted rs += offset; result.resize(rs, rs); bool truncated = result.size() != rs; typename Int::limb_pointer pr = result.limbs(); if (offset > rs) { // The result is shifted past the end of the result: result = static_cast(0); return; } unsigned i = rs - result.size(); // This code only works when shift is non-zero, otherwise we invoke undefined behaviour! BOOST_ASSERT(shift); if (!truncated) { if (rs > ors + offset) { pr[rs - 1 - i] = pr[ors - 1 - i] >> (Int::limb_bits - shift); --rs; } else { pr[rs - 1 - i] = pr[ors - 1 - i] << shift; if (ors > 1) pr[rs - 1 - i] |= pr[ors - 2 - i] >> (Int::limb_bits - shift); ++i; } } for (; rs - i >= 2 + offset; ++i) { pr[rs - 1 - i] = pr[rs - 1 - i - offset] << shift; pr[rs - 1 - i] |= pr[rs - 2 - i - offset] >> (Int::limb_bits - shift); } if (rs - i >= 1 + offset) { pr[rs - 1 - i] = pr[rs - 1 - i - offset] << shift; ++i; } for (; i < rs; ++i) pr[rs - 1 - i] = 0; } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value>::type eval_left_shift( cpp_int_backend& result, double_limb_type s) noexcept((is_non_throwing_cpp_int >::value)) { is_valid_bitwise_op(result, typename cpp_int_backend::checked_type()); if (!s) return; #if BOOST_ENDIAN_LITTLE_BYTE && defined(BOOST_MP_USE_LIMB_SHIFT) constexpr const limb_type limb_shift_mask = cpp_int_backend::limb_bits - 1; constexpr const limb_type byte_shift_mask = CHAR_BIT - 1; if ((s & limb_shift_mask) == 0) { left_shift_limb(result, s); } #ifdef BOOST_MP_NO_CONSTEXPR_DETECTION else if ((s & byte_shift_mask) == 0) #else else if (((s & byte_shift_mask) == 0) && !BOOST_MP_IS_CONST_EVALUATED(s)) #endif { left_shift_byte(result, s); } #elif BOOST_ENDIAN_LITTLE_BYTE constexpr const limb_type byte_shift_mask = CHAR_BIT - 1; #ifdef BOOST_MP_NO_CONSTEXPR_DETECTION if ((s & byte_shift_mask) == 0) #else constexpr limb_type limb_shift_mask = cpp_int_backend::limb_bits - 1; if (BOOST_MP_IS_CONST_EVALUATED(s) && ((s & limb_shift_mask) == 0)) left_shift_limb(result, s); else if (((s & byte_shift_mask) == 0) && !BOOST_MP_IS_CONST_EVALUATED(s)) #endif { left_shift_byte(result, s); } #else constexpr const limb_type limb_shift_mask = cpp_int_backend::limb_bits - 1; if ((s & limb_shift_mask) == 0) { left_shift_limb(result, s); } #endif else { left_shift_generic(result, s); } // // We may have shifted off the end and have leading zeros: // result.normalize(); } template inline void right_shift_byte(Int& result, double_limb_type s) { limb_type offset = static_cast(s / Int::limb_bits); BOOST_ASSERT((s % CHAR_BIT) == 0); unsigned ors = result.size(); unsigned rs = ors; if (offset >= rs) { result = limb_type(0); return; } rs -= offset; typename Int::limb_pointer pr = result.limbs(); unsigned char* pc = reinterpret_cast(pr); limb_type shift = static_cast(s / CHAR_BIT); std::memmove(pc, pc + shift, ors * sizeof(pr[0]) - shift); shift = (sizeof(limb_type) - shift % sizeof(limb_type)) * CHAR_BIT; if (shift < Int::limb_bits) { pr[ors - offset - 1] &= (static_cast(1u) << shift) - 1; if (!pr[ors - offset - 1] && (rs > 1)) --rs; } result.resize(rs, rs); } template inline BOOST_MP_CXX14_CONSTEXPR void right_shift_limb(Int& result, double_limb_type s) { limb_type offset = static_cast(s / Int::limb_bits); BOOST_ASSERT((s % Int::limb_bits) == 0); unsigned ors = result.size(); unsigned rs = ors; if (offset >= rs) { result = limb_type(0); return; } rs -= offset; typename Int::limb_pointer pr = result.limbs(); unsigned i = 0; for (; i < rs; ++i) pr[i] = pr[i + offset]; result.resize(rs, rs); } template inline BOOST_MP_CXX14_CONSTEXPR void right_shift_generic(Int& result, double_limb_type s) { limb_type offset = static_cast(s / Int::limb_bits); limb_type shift = static_cast(s % Int::limb_bits); unsigned ors = result.size(); unsigned rs = ors; if (offset >= rs) { result = limb_type(0); return; } rs -= offset; typename Int::limb_pointer pr = result.limbs(); if ((pr[ors - 1] >> shift) == 0) { if (--rs == 0) { result = limb_type(0); return; } } unsigned i = 0; // This code only works for non-zero shift, otherwise we invoke undefined behaviour! BOOST_ASSERT(shift); for (; i + offset + 1 < ors; ++i) { pr[i] = pr[i + offset] >> shift; pr[i] |= pr[i + offset + 1] << (Int::limb_bits - shift); } pr[i] = pr[i + offset] >> shift; result.resize(rs, rs); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value>::type eval_right_shift( cpp_int_backend& result, double_limb_type s) noexcept((is_non_throwing_cpp_int >::value)) { is_valid_bitwise_op(result, typename cpp_int_backend::checked_type()); if (!s) return; #if BOOST_ENDIAN_LITTLE_BYTE && defined(BOOST_MP_USE_LIMB_SHIFT) constexpr const limb_type limb_shift_mask = cpp_int_backend::limb_bits - 1; constexpr const limb_type byte_shift_mask = CHAR_BIT - 1; if ((s & limb_shift_mask) == 0) right_shift_limb(result, s); #ifdef BOOST_MP_NO_CONSTEXPR_DETECTION else if ((s & byte_shift_mask) == 0) #else else if (((s & byte_shift_mask) == 0) && !BOOST_MP_IS_CONST_EVALUATED(s)) #endif right_shift_byte(result, s); #elif BOOST_ENDIAN_LITTLE_BYTE constexpr const limb_type byte_shift_mask = CHAR_BIT - 1; #ifdef BOOST_MP_NO_CONSTEXPR_DETECTION if ((s & byte_shift_mask) == 0) #else constexpr limb_type limb_shift_mask = cpp_int_backend::limb_bits - 1; if (BOOST_MP_IS_CONST_EVALUATED(s) && ((s & limb_shift_mask) == 0)) right_shift_limb(result, s); else if (((s & byte_shift_mask) == 0) && !BOOST_MP_IS_CONST_EVALUATED(s)) #endif right_shift_byte(result, s); #else constexpr const limb_type limb_shift_mask = cpp_int_backend::limb_bits - 1; if ((s & limb_shift_mask) == 0) right_shift_limb(result, s); #endif else right_shift_generic(result, s); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value>::type eval_right_shift( cpp_int_backend& result, double_limb_type s) noexcept((is_non_throwing_cpp_int >::value)) { is_valid_bitwise_op(result, typename cpp_int_backend::checked_type()); if (!s) return; bool is_neg = result.sign(); if (is_neg) eval_increment(result); #if BOOST_ENDIAN_LITTLE_BYTE && defined(BOOST_MP_USE_LIMB_SHIFT) constexpr const limb_type limb_shift_mask = cpp_int_backend::limb_bits - 1; constexpr const limb_type byte_shift_mask = CHAR_BIT - 1; if ((s & limb_shift_mask) == 0) right_shift_limb(result, s); else if ((s & byte_shift_mask) == 0) right_shift_byte(result, s); #elif BOOST_ENDIAN_LITTLE_BYTE constexpr const limb_type byte_shift_mask = CHAR_BIT - 1; if ((s & byte_shift_mask) == 0) right_shift_byte(result, s); #else constexpr const limb_type limb_shift_mask = cpp_int_backend::limb_bits - 1; if ((s & limb_shift_mask) == 0) right_shift_limb(result, s); #endif else right_shift_generic(result, s); if (is_neg) eval_decrement(result); } // // Over again for trivial cpp_int's: // template BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value >::type eval_left_shift(cpp_int_backend& result, T s) noexcept((is_non_throwing_cpp_int >::value)) { is_valid_bitwise_op(result, typename cpp_int_backend::checked_type()); *result.limbs() = detail::checked_left_shift(*result.limbs(), s, typename cpp_int_backend::checked_type()); result.normalize(); } template BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if >::value >::type eval_right_shift(cpp_int_backend& result, T s) noexcept((is_non_throwing_cpp_int >::value)) { // Nothing to check here... just make sure we don't invoke undefined behavior: is_valid_bitwise_op(result, typename cpp_int_backend::checked_type()); *result.limbs() = (static_cast(s) >= sizeof(*result.limbs()) * CHAR_BIT) ? 0 : (result.sign() ? ((--*result.limbs()) >> s) + 1 : *result.limbs() >> s); if (result.sign() && (*result.limbs() == 0)) result = static_cast(-1); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< is_trivial_cpp_int >::value && is_trivial_cpp_int >::value && (is_signed_number >::value || is_signed_number >::value)>::type eval_complement( cpp_int_backend& result, const cpp_int_backend& o) noexcept((is_non_throwing_cpp_int >::value)) { static_assert(((Checked1 != checked) || (Checked2 != checked)), "Attempt to take the complement of a signed type results in undefined behavior."); // // If we're not checked then emulate 2's complement behavior: // if (o.sign()) { *result.limbs() = *o.limbs() - 1; result.sign(false); } else { *result.limbs() = 1 + *o.limbs(); result.sign(true); } result.normalize(); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< is_trivial_cpp_int >::value && is_trivial_cpp_int >::value && is_unsigned_number >::value && is_unsigned_number >::value>::type eval_complement( cpp_int_backend& result, const cpp_int_backend& o) noexcept((is_non_throwing_cpp_int >::value)) { *result.limbs() = ~*o.limbs(); result.normalize(); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< is_trivial_cpp_int >::value && is_trivial_cpp_int >::value && is_unsigned_number >::value && is_unsigned_number >::value>::type eval_bitwise_and( cpp_int_backend& result, const cpp_int_backend& o) noexcept((is_non_throwing_cpp_int >::value)) { *result.limbs() &= *o.limbs(); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< is_trivial_cpp_int >::value && is_trivial_cpp_int >::value && (is_signed_number >::value || is_signed_number >::value)>::type eval_bitwise_and( cpp_int_backend& result, const cpp_int_backend& o) noexcept((is_non_throwing_cpp_int >::value)) { is_valid_bitwise_op(result, o, typename cpp_int_backend::checked_type()); using default_ops::eval_bit_test; using default_ops::eval_increment; if (result.sign() || o.sign()) { constexpr const unsigned m = static_unsigned_max::value, static_unsigned_max::value>::value; cpp_int_backend t1(result); cpp_int_backend t2(o); eval_bitwise_and(t1, t2); bool s = eval_bit_test(t1, m + 1); if (s) { eval_complement(t1, t1); eval_increment(t1); } result = t1; result.sign(s); } else { *result.limbs() &= *o.limbs(); } } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< is_trivial_cpp_int >::value && is_trivial_cpp_int >::value && is_unsigned_number >::value && is_unsigned_number >::value>::type eval_bitwise_or( cpp_int_backend& result, const cpp_int_backend& o) noexcept((is_non_throwing_cpp_int >::value)) { *result.limbs() |= *o.limbs(); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< is_trivial_cpp_int >::value && is_trivial_cpp_int >::value && (is_signed_number >::value || is_signed_number >::value)>::type eval_bitwise_or( cpp_int_backend& result, const cpp_int_backend& o) noexcept((is_non_throwing_cpp_int >::value)) { is_valid_bitwise_op(result, o, typename cpp_int_backend::checked_type()); using default_ops::eval_bit_test; using default_ops::eval_increment; if (result.sign() || o.sign()) { constexpr const unsigned m = static_unsigned_max::value, static_unsigned_max::value>::value; cpp_int_backend t1(result); cpp_int_backend t2(o); eval_bitwise_or(t1, t2); bool s = eval_bit_test(t1, m + 1); if (s) { eval_complement(t1, t1); eval_increment(t1); } result = t1; result.sign(s); } else { *result.limbs() |= *o.limbs(); result.normalize(); } } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< is_trivial_cpp_int >::value && is_trivial_cpp_int >::value && is_unsigned_number >::value && is_unsigned_number >::value>::type eval_bitwise_xor( cpp_int_backend& result, const cpp_int_backend& o) noexcept((is_non_throwing_cpp_int >::value)) { *result.limbs() ^= *o.limbs(); } template inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if< is_trivial_cpp_int >::value && is_trivial_cpp_int >::value && (is_signed_number >::value || is_signed_number >::value)>::type eval_bitwise_xor( cpp_int_backend& result, const cpp_int_backend& o) noexcept((is_non_throwing_cpp_int >::value)) { is_valid_bitwise_op(result, o, typename cpp_int_backend::checked_type()); using default_ops::eval_bit_test; using default_ops::eval_increment; if (result.sign() || o.sign()) { constexpr const unsigned m = static_unsigned_max::value, static_unsigned_max::value>::value; cpp_int_backend t1(result); cpp_int_backend t2(o); eval_bitwise_xor(t1, t2); bool s = eval_bit_test(t1, m + 1); if (s) { eval_complement(t1, t1); eval_increment(t1); } result = t1; result.sign(s); } else { *result.limbs() ^= *o.limbs(); } } }}} // namespace boost::multiprecision::backends #ifdef _MSC_VER #pragma warning(pop) #endif #endif