Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:42:13

0001 ///////////////////////////////////////////////////////////////
0002 //  Copyright 2012 John Maddock. Distributed under the Boost
0003 //  Software License, Version 1.0. (See accompanying file
0004 //  LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt
0005 //
0006 // Comparison operators for cpp_int_backend:
0007 //
0008 #ifndef BOOST_MP_CPP_INT_BITWISE_HPP
0009 #define BOOST_MP_CPP_INT_BITWISE_HPP
0010 
0011 #include <stdexcept>
0012 #include <type_traits>
0013 #include <boost/multiprecision/detail/endian.hpp>
0014 #include <boost/multiprecision/detail/no_exceptions_support.hpp>
0015 #include <boost/multiprecision/detail/assert.hpp>
0016 
0017 #ifdef BOOST_MSVC
0018 #pragma warning(push)
0019 #pragma warning(disable : 4319)
0020 #endif
0021 
0022 
0023 namespace boost { namespace multiprecision { namespace backends {
0024 
0025 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>
0026 BOOST_MP_CXX14_CONSTEXPR void is_valid_bitwise_op(
0027     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
0028     const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o, const std::integral_constant<int, checked>&)
0029 {
0030    if (result.sign() || o.sign())
0031       BOOST_MP_THROW_EXCEPTION(std::range_error("Bitwise operations on negative values results in undefined behavior."));
0032 }
0033 
0034 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>
0035 BOOST_MP_CXX14_CONSTEXPR void is_valid_bitwise_op(
0036     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&,
0037     const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>&, const std::integral_constant<int, unchecked>&) {}
0038 
0039 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_int_check_type Checked1, class Allocator1>
0040 BOOST_MP_CXX14_CONSTEXPR void is_valid_bitwise_op(
0041     const cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>& result, const std::integral_constant<int, checked>&)
0042 {
0043    if (result.sign())
0044       BOOST_MP_THROW_EXCEPTION(std::range_error("Bitwise operations on negative values results in undefined behavior."));
0045 }
0046 
0047 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_int_check_type Checked1, class Allocator1>
0048 BOOST_MP_CXX14_CONSTEXPR void is_valid_bitwise_op(
0049     const cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>&, const std::integral_constant<int, checked>&) {}
0050 
0051 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
0052 BOOST_MP_CXX14_CONSTEXPR void is_valid_bitwise_op(
0053     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&, const std::integral_constant<int, unchecked>&) {}
0054 
0055 template <class CppInt1, class CppInt2, class Op>
0056 BOOST_MP_CXX14_CONSTEXPR void bitwise_op(
0057     CppInt1&       result,
0058     const CppInt2& o,
0059     Op             op, const std::integral_constant<bool, true>&) noexcept((is_non_throwing_cpp_int<CppInt1>::value))
0060 {
0061    //
0062    // There are 4 cases:
0063    // * Both positive.
0064    // * result negative, o positive.
0065    // * o negative, result positive.
0066    // * Both negative.
0067    //
0068    // When one arg is negative we convert to 2's complement form "on the fly",
0069    // and then convert back to signed-magnitude form at the end.
0070    //
0071    // Note however, that if the type is checked, then bitwise ops on negative values
0072    // are not permitted and an exception will result.
0073    //
0074    is_valid_bitwise_op(result, o, typename CppInt1::checked_type());
0075    //
0076    // First figure out how big the result needs to be and set up some data:
0077    //
0078    std::size_t rs = result.size();
0079    std::size_t os = o.size();
0080    std::size_t m(0), x(0);
0081    minmax(rs, os, m, x);
0082    result.resize(x, x);
0083    typename CppInt1::limb_pointer       pr = result.limbs();
0084    typename CppInt2::const_limb_pointer po = o.limbs();
0085    for (std::size_t i = rs; i < x; ++i)
0086       pr[i] = 0;
0087 
0088    limb_type next_limb = 0;
0089 
0090    if (!result.sign())
0091    {
0092       if (!o.sign())
0093       {
0094          for (std::size_t i = 0; i < os; ++i)
0095             pr[i] = op(pr[i], po[i]);
0096          for (std::size_t i = os; i < x; ++i)
0097             pr[i] = op(pr[i], limb_type(0));
0098       }
0099       else
0100       {
0101          // "o" is negative:
0102          double_limb_type carry = 1;
0103          for (std::size_t i = 0; i < os; ++i)
0104          {
0105             carry += static_cast<double_limb_type>(~po[i]);
0106             pr[i] = op(pr[i], static_cast<limb_type>(carry));
0107             carry >>= CppInt1::limb_bits;
0108          }
0109          for (std::size_t i = os; i < x; ++i)
0110          {
0111             carry += static_cast<double_limb_type>(~limb_type(0));
0112             pr[i] = op(pr[i], static_cast<limb_type>(carry));
0113             carry >>= CppInt1::limb_bits;
0114          }
0115          // Set the overflow into the "extra" limb:
0116          carry += static_cast<double_limb_type>(~limb_type(0));
0117          next_limb = op(limb_type(0), static_cast<limb_type>(carry));
0118       }
0119    }
0120    else
0121    {
0122       if (!o.sign())
0123       {
0124          // "result" is negative:
0125          double_limb_type carry = 1;
0126          for (std::size_t i = 0; i < os; ++i)
0127          {
0128             carry += static_cast<double_limb_type>(~pr[i]);
0129             pr[i] = op(static_cast<limb_type>(carry), po[i]);
0130             carry >>= CppInt1::limb_bits;
0131          }
0132          for (std::size_t i = os; i < x; ++i)
0133          {
0134             carry += static_cast<double_limb_type>(~pr[i]);
0135             pr[i] = op(static_cast<limb_type>(carry), limb_type(0));
0136             carry >>= CppInt1::limb_bits;
0137          }
0138          // Set the overflow into the "extra" limb:
0139          carry += static_cast<double_limb_type>(~limb_type(0));
0140          next_limb = op(static_cast<limb_type>(carry), limb_type(0));
0141       }
0142       else
0143       {
0144          // both are negative:
0145          double_limb_type r_carry = 1;
0146          double_limb_type o_carry = 1;
0147          for (std::size_t i = 0; i < os; ++i)
0148          {
0149             r_carry += static_cast<double_limb_type>(~pr[i]);
0150             o_carry += static_cast<double_limb_type>(~po[i]);
0151             pr[i] = op(static_cast<limb_type>(r_carry), static_cast<limb_type>(o_carry));
0152             r_carry >>= CppInt1::limb_bits;
0153             o_carry >>= CppInt1::limb_bits;
0154          }
0155          for (std::size_t i = os; i < x; ++i)
0156          {
0157             r_carry += static_cast<double_limb_type>(~pr[i]);
0158             o_carry += static_cast<double_limb_type>(~limb_type(0));
0159             pr[i] = op(static_cast<limb_type>(r_carry), static_cast<limb_type>(o_carry));
0160             r_carry >>= CppInt1::limb_bits;
0161             o_carry >>= CppInt1::limb_bits;
0162          }
0163          // Set the overflow into the "extra" limb:
0164          r_carry += static_cast<double_limb_type>(~limb_type(0));
0165          o_carry += static_cast<double_limb_type>(~limb_type(0));
0166          next_limb = op(static_cast<limb_type>(r_carry), static_cast<limb_type>(o_carry));
0167       }
0168    }
0169    //
0170    // See if the result is negative or not:
0171    //
0172    if (static_cast<signed_limb_type>(next_limb) < 0)
0173    {
0174       double_limb_type carry = 1;
0175       for (std::size_t i = 0; i < x; ++i)
0176       {
0177          carry += static_cast<double_limb_type>(~pr[i]);
0178          pr[i] = static_cast<limb_type>(carry);
0179          carry >>= CppInt1::limb_bits;
0180       }
0181       if (carry)
0182       {
0183          result.resize(x + 1, x);
0184          if (result.size() > x)
0185             result.limbs()[x] = static_cast<limb_type>(carry);
0186       }
0187       result.sign(true);
0188    }
0189    else
0190       result.sign(false);
0191 
0192    result.normalize();
0193 }
0194 
0195 template <class CppInt1, class CppInt2, class Op>
0196 BOOST_MP_CXX14_CONSTEXPR void bitwise_op(
0197     CppInt1&       result,
0198     const CppInt2& o,
0199     Op             op, const std::integral_constant<bool, false>&) noexcept((is_non_throwing_cpp_int<CppInt1>::value))
0200 {
0201    //
0202    // Both arguments are unsigned types, very simple case handled as a special case.
0203    //
0204    // First figure out how big the result needs to be and set up some data:
0205    //
0206    std::size_t rs = result.size();
0207    std::size_t os = o.size();
0208    std::size_t m(0), x(0);
0209    minmax(rs, os, m, x);
0210    result.resize(x, x);
0211    typename CppInt1::limb_pointer       pr = result.limbs();
0212    typename CppInt2::const_limb_pointer po = o.limbs();
0213    for (std::size_t i = rs; i < x; ++i)
0214       pr[i] = 0;
0215 
0216    for (std::size_t i = 0; i < os; ++i)
0217       pr[i] = op(pr[i], po[i]);
0218    for (std::size_t i = os; i < x; ++i)
0219       pr[i] = op(pr[i], limb_type(0));
0220 
0221    result.normalize();
0222 }
0223 
0224 struct bit_and
0225 {
0226    BOOST_MP_CXX14_CONSTEXPR limb_type operator()(limb_type a, limb_type b) const noexcept { return a & b; }
0227 };
0228 struct bit_or
0229 {
0230    BOOST_MP_CXX14_CONSTEXPR limb_type operator()(limb_type a, limb_type b) const noexcept { return a | b; }
0231 };
0232 struct bit_xor
0233 {
0234    BOOST_MP_CXX14_CONSTEXPR limb_type operator()(limb_type a, limb_type b) const noexcept { return a ^ b; }
0235 };
0236 
0237 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>
0238 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
0239 eval_bitwise_and(
0240     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
0241     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))
0242 {
0243    bitwise_op(result, o, bit_and(),
0244               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 > ());
0245 }
0246 
0247 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>
0248 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
0249 eval_bitwise_or(
0250     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
0251     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))
0252 {
0253    bitwise_op(result, o, bit_or(),
0254               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 > ());
0255 }
0256 
0257 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>
0258 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
0259 eval_bitwise_xor(
0260     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
0261     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))
0262 {
0263    bitwise_op(result, o, bit_xor(),
0264               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 > ());
0265 }
0266 //
0267 // Again for operands which are single limbs:
0268 //
0269 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_int_check_type Checked1, class Allocator1>
0270 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
0271 eval_bitwise_and(
0272     cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>& result,
0273     limb_type                                                                      l) noexcept
0274 {
0275    result.limbs()[0] &= l;
0276    result.resize(1, 1);
0277 }
0278 
0279 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_int_check_type Checked1, class Allocator1>
0280 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
0281 eval_bitwise_or(
0282     cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>& result,
0283     limb_type                                                                      l) noexcept
0284 {
0285    result.limbs()[0] |= l;
0286 }
0287 
0288 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_int_check_type Checked1, class Allocator1>
0289 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
0290 eval_bitwise_xor(
0291     cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>& result,
0292     limb_type                                                                      l) noexcept
0293 {
0294    result.limbs()[0] ^= l;
0295 }
0296 
0297 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>
0298 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
0299 eval_complement(
0300     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
0301     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))
0302 {
0303    static_assert(((Checked1 != checked) || (Checked2 != checked)), "Attempt to take the complement of a signed type results in undefined behavior.");
0304    // Increment and negate:
0305    result = o;
0306    eval_increment(result);
0307    result.negate();
0308 }
0309 
0310 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
0311 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
0312 eval_complement(
0313     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
0314     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))
0315 {
0316    std::size_t os = o.size();
0317    result.resize(SIZE_MAX, os);
0318    for (std::size_t i = 0; i < os; ++i)
0319       result.limbs()[i] = ~o.limbs()[i];
0320    for (std::size_t i = os; i < result.size(); ++i)
0321       result.limbs()[i] = ~static_cast<limb_type>(0);
0322    result.normalize();
0323 }
0324 
0325 template <class Int>
0326 inline void left_shift_byte(Int& result, double_limb_type s)
0327 {
0328    limb_type offset = static_cast<limb_type>(s / Int::limb_bits);
0329    limb_type shift  = static_cast<limb_type>(s % Int::limb_bits);
0330    std::size_t  ors    = result.size();
0331    if ((ors == 1) && (!*result.limbs()))
0332       return; // shifting zero yields zero.
0333    std::size_t rs = ors;
0334    if (shift && (result.limbs()[ors - 1] >> (Int::limb_bits - shift)))
0335       ++rs; // Most significant limb will overflow when shifted
0336    rs += offset;
0337    result.resize(rs, rs);
0338    rs = result.size();
0339 
0340    typename Int::limb_pointer pr = result.limbs();
0341 
0342    if (rs != ors)
0343       pr[rs - 1] = 0u;
0344    std::size_t bytes = static_cast<std::size_t>(s / CHAR_BIT);
0345    std::size_t len   = (std::min)(ors * sizeof(limb_type), rs * sizeof(limb_type) - bytes);
0346    if (bytes >= rs * sizeof(limb_type))
0347       result = static_cast<limb_type>(0u);
0348    else
0349    {
0350       unsigned char* pc = reinterpret_cast<unsigned char*>(pr);
0351       std::memmove(pc + bytes, pc, len);
0352       std::memset(pc, 0, bytes);
0353    }
0354 }
0355 
0356 template <class Int>
0357 inline BOOST_MP_CXX14_CONSTEXPR void left_shift_limb(Int& result, double_limb_type s)
0358 {
0359    limb_type offset = static_cast<limb_type>(s / Int::limb_bits);
0360    limb_type shift  = static_cast<limb_type>(s % Int::limb_bits);
0361 
0362    std::size_t ors = result.size();
0363    if ((ors == 1) && (!*result.limbs()))
0364       return; // shifting zero yields zero.
0365    std::size_t rs = ors;
0366    if (shift && (result.limbs()[ors - 1] >> (Int::limb_bits - shift)))
0367       ++rs; // Most significant limb will overflow when shifted
0368    rs += offset;
0369    result.resize(rs, rs);
0370 
0371    typename Int::limb_pointer pr = result.limbs();
0372 
0373    if (offset > rs)
0374    {
0375       // The result is shifted past the end of the result:
0376       result = static_cast<limb_type>(0);
0377       return;
0378    }
0379 
0380    std::size_t i = rs - result.size();
0381    for (; i < ors; ++i)
0382       pr[rs - 1 - i] = pr[ors - 1 - i];
0383 #ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
0384    if (BOOST_MP_IS_CONST_EVALUATED(s))
0385    {
0386       for (; i < rs; ++i)
0387          pr[rs - 1 - i] = 0;
0388    }
0389    else
0390 #endif
0391    {
0392       std::memset(pr, 0, (rs - i) * sizeof(*pr));
0393    }
0394 }
0395 
0396 template <class Int>
0397 inline BOOST_MP_CXX14_CONSTEXPR void left_shift_generic(Int& result, double_limb_type s)
0398 {
0399    limb_type offset = static_cast<limb_type>(s / Int::limb_bits);
0400    limb_type shift  = static_cast<limb_type>(s % Int::limb_bits);
0401 
0402    std::size_t ors = result.size();
0403    if ((ors == 1) && (!*result.limbs()))
0404       return; // shifting zero yields zero.
0405    std::size_t rs = ors;
0406    if (shift && (result.limbs()[ors - 1] >> (Int::limb_bits - shift)))
0407       ++rs; // Most significant limb will overflow when shifted
0408    rs += offset;
0409    result.resize(rs, rs);
0410    bool truncated = result.size() != rs;
0411 
0412    typename Int::limb_pointer pr = result.limbs();
0413 
0414    if (offset > rs)
0415    {
0416       // The result is shifted past the end of the result:
0417       result = static_cast<limb_type>(0);
0418       return;
0419    }
0420 
0421    std::size_t i = rs - result.size();
0422    // This code only works when shift is non-zero, otherwise we invoke undefined behaviour!
0423    BOOST_MP_ASSERT(shift);
0424    if (!truncated)
0425    {
0426       if (rs > ors + offset)
0427       {
0428          pr[rs - 1 - i] = pr[ors - 1 - i] >> (Int::limb_bits - shift);
0429          --rs;
0430       }
0431       else
0432       {
0433          pr[rs - 1 - i] = pr[ors - 1 - i] << shift;
0434          if (ors > 1)
0435             pr[rs - 1 - i] |= pr[ors - 2 - i] >> (Int::limb_bits - shift);
0436          ++i;
0437       }
0438    }
0439    for (; rs - i >= static_cast<std::size_t>(static_cast<std::size_t>(2u) + offset); ++i)
0440    {
0441       pr[rs - 1 - i] = pr[rs - 1 - i - offset] << shift;
0442       pr[rs - 1 - i] |= pr[rs - 2 - i - offset] >> (Int::limb_bits - shift);
0443    }
0444    if (rs - i >= static_cast<std::size_t>(static_cast<std::size_t>(1u) + offset))
0445    {
0446       pr[rs - 1 - i] = pr[rs - 1 - i - offset] << shift;
0447       ++i;
0448    }
0449 #ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
0450    if (BOOST_MP_IS_CONST_EVALUATED(s))
0451    {
0452       for (; i < rs; ++i)
0453          pr[rs - 1 - i] = 0;
0454    }
0455    else
0456 #endif
0457    {
0458       std::memset(pr, 0, (rs - i) * sizeof(*pr));
0459    }
0460 }
0461 
0462 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
0463 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
0464 eval_left_shift(
0465     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
0466     double_limb_type                                                      s) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
0467 {
0468    is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
0469    if (!s)
0470       return;
0471 
0472 #if BOOST_MP_ENDIAN_LITTLE_BYTE && defined(BOOST_MP_USE_LIMB_SHIFT)
0473    constexpr limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits - 1;
0474    constexpr limb_type byte_shift_mask = CHAR_BIT - 1;
0475 
0476    if ((s & limb_shift_mask) == 0)
0477    {
0478       left_shift_limb(result, s);
0479    }
0480 #ifdef BOOST_MP_NO_CONSTEXPR_DETECTION
0481    else if ((s & byte_shift_mask) == 0)
0482 #else
0483    else if (((s & byte_shift_mask) == 0) && !BOOST_MP_IS_CONST_EVALUATED(s))
0484 #endif
0485    {
0486       left_shift_byte(result, s);
0487    }
0488 #elif BOOST_MP_ENDIAN_LITTLE_BYTE
0489    constexpr limb_type byte_shift_mask = CHAR_BIT - 1;
0490 
0491 #ifdef BOOST_MP_NO_CONSTEXPR_DETECTION
0492    if ((s & byte_shift_mask) == 0)
0493 #else
0494    constexpr limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits - 1;
0495    if (BOOST_MP_IS_CONST_EVALUATED(s) && ((s & limb_shift_mask) == 0))
0496       left_shift_limb(result, s);
0497    else if (((s & byte_shift_mask) == 0) && !BOOST_MP_IS_CONST_EVALUATED(s))
0498 #endif
0499    {
0500       left_shift_byte(result, s);
0501    }
0502 #else
0503    constexpr limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits - 1;
0504 
0505    if ((s & limb_shift_mask) == 0)
0506    {
0507       left_shift_limb(result, s);
0508    }
0509 #endif
0510    else
0511    {
0512       left_shift_generic(result, s);
0513    }
0514    //
0515    // We may have shifted off the end and have leading zeros:
0516    //
0517    result.normalize();
0518 }
0519 
0520 template <class Int>
0521 inline void right_shift_byte(Int& result, double_limb_type s)
0522 {
0523    limb_type offset = static_cast<limb_type>(s / Int::limb_bits);
0524    BOOST_MP_ASSERT((s % CHAR_BIT) == 0);
0525    std::size_t ors = result.size();
0526    std::size_t rs  = ors;
0527    if (offset >= rs)
0528    {
0529       result = limb_type(0);
0530       return;
0531    }
0532    rs -= offset;
0533    typename Int::limb_pointer pr = result.limbs();
0534    unsigned char*             pc = reinterpret_cast<unsigned char*>(pr);
0535    limb_type                  shift = static_cast<limb_type>(s / CHAR_BIT);
0536    std::memmove(pc, pc + shift, ors * sizeof(pr[0]) - shift);
0537    shift = (sizeof(limb_type) - shift % sizeof(limb_type)) * CHAR_BIT;
0538    if (shift < Int::limb_bits)
0539    {
0540       pr[ors - offset - 1] &= (static_cast<limb_type>(1u) << shift) - 1;
0541       if (!pr[ors - offset - 1] && (rs > 1))
0542          --rs;
0543    }
0544    result.resize(rs, rs);
0545 }
0546 
0547 template <class Int>
0548 inline BOOST_MP_CXX14_CONSTEXPR void right_shift_limb(Int& result, double_limb_type s)
0549 {
0550    limb_type offset = static_cast<limb_type>(s / Int::limb_bits);
0551    BOOST_MP_ASSERT((s % Int::limb_bits) == 0);
0552    std::size_t ors = result.size();
0553    std::size_t rs  = ors;
0554    if (offset >= rs)
0555    {
0556       result = limb_type(0);
0557       return;
0558    }
0559    rs -= offset;
0560    typename Int::limb_pointer pr = result.limbs();
0561    std::size_t                   i  = 0;
0562    for (; i < rs; ++i)
0563       pr[i] = pr[i + offset];
0564    result.resize(rs, rs);
0565 }
0566 
0567 template <class Int>
0568 inline BOOST_MP_CXX14_CONSTEXPR void right_shift_generic(Int& result, double_limb_type s)
0569 {
0570    limb_type offset = static_cast<limb_type>(s / Int::limb_bits);
0571    limb_type shift  = static_cast<limb_type>(s % Int::limb_bits);
0572    std::size_t  ors    = result.size();
0573    std::size_t  rs     = ors;
0574    if (offset >= rs)
0575    {
0576       result = limb_type(0);
0577       return;
0578    }
0579    rs -= offset;
0580    typename Int::limb_pointer pr = result.limbs();
0581    if ((pr[ors - 1] >> shift) == 0)
0582    {
0583       if (--rs == 0)
0584       {
0585          result = limb_type(0);
0586          return;
0587       }
0588    }
0589    std::size_t i = 0;
0590 
0591    // This code only works for non-zero shift, otherwise we invoke undefined behaviour!
0592    BOOST_MP_ASSERT(shift);
0593    for (; i + offset + 1 < ors; ++i)
0594    {
0595       pr[i] = pr[i + offset] >> shift;
0596       pr[i] |= pr[i + offset + 1] << (Int::limb_bits - shift);
0597    }
0598    pr[i] = pr[i + offset] >> shift;
0599    result.resize(rs, rs);
0600 }
0601 
0602 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_int_check_type Checked1, class Allocator1>
0603 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1> >::value>::type
0604 eval_right_shift(
0605     cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>& result,
0606     double_limb_type                                                               s) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1> >::value))
0607 {
0608    is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>::checked_type());
0609    if (!s)
0610       return;
0611 
0612 #if BOOST_MP_ENDIAN_LITTLE_BYTE && defined(BOOST_MP_USE_LIMB_SHIFT)
0613    constexpr limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::limb_bits - 1;
0614    constexpr limb_type byte_shift_mask = CHAR_BIT - 1;
0615 
0616    if ((s & limb_shift_mask) == 0)
0617       right_shift_limb(result, s);
0618 #ifdef BOOST_MP_NO_CONSTEXPR_DETECTION
0619    else if ((s & byte_shift_mask) == 0)
0620 #else
0621    else if (((s & byte_shift_mask) == 0) && !BOOST_MP_IS_CONST_EVALUATED(s))
0622 #endif
0623       right_shift_byte(result, s);
0624 #elif BOOST_MP_ENDIAN_LITTLE_BYTE
0625    constexpr limb_type byte_shift_mask = CHAR_BIT - 1;
0626 
0627 #ifdef BOOST_MP_NO_CONSTEXPR_DETECTION
0628    if ((s & byte_shift_mask) == 0)
0629 #else
0630    constexpr limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::limb_bits - 1;
0631    if (BOOST_MP_IS_CONST_EVALUATED(s) && ((s & limb_shift_mask) == 0))
0632       right_shift_limb(result, s);
0633    else if (((s & byte_shift_mask) == 0) && !BOOST_MP_IS_CONST_EVALUATED(s))
0634 #endif
0635       right_shift_byte(result, s);
0636 #else
0637    constexpr limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::limb_bits - 1;
0638 
0639    if ((s & limb_shift_mask) == 0)
0640       right_shift_limb(result, s);
0641 #endif
0642    else
0643       right_shift_generic(result, s);
0644 }
0645 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_int_check_type Checked1, class Allocator1>
0646 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1> >::value>::type
0647 eval_right_shift(
0648     cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>& result,
0649     double_limb_type                                                             s) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1> >::value))
0650 {
0651    is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::checked_type());
0652    if (!s)
0653       return;
0654 
0655    bool is_neg = result.sign();
0656    if (is_neg)
0657       eval_increment(result);
0658 
0659 #if BOOST_MP_ENDIAN_LITTLE_BYTE && defined(BOOST_MP_USE_LIMB_SHIFT)
0660    constexpr limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::limb_bits - 1;
0661    constexpr limb_type byte_shift_mask = CHAR_BIT - 1;
0662 
0663    if ((s & limb_shift_mask) == 0)
0664       right_shift_limb(result, s);
0665 #ifdef BOOST_MP_NO_CONSTEXPR_DETECTION
0666    else if ((s & byte_shift_mask) == 0)
0667 #else
0668    else if (((s & byte_shift_mask) == 0) && !BOOST_MP_IS_CONST_EVALUATED(s))
0669 #endif
0670       right_shift_byte(result, s);
0671 #elif BOOST_MP_ENDIAN_LITTLE_BYTE
0672    constexpr limb_type byte_shift_mask = CHAR_BIT - 1;
0673 
0674 #ifdef BOOST_MP_NO_CONSTEXPR_DETECTION
0675    if ((s & byte_shift_mask) == 0)
0676 #else
0677    constexpr limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::limb_bits - 1;
0678    if (BOOST_MP_IS_CONST_EVALUATED(s) && ((s & limb_shift_mask) == 0))
0679       right_shift_limb(result, s);
0680    else if (((s & byte_shift_mask) == 0) && !BOOST_MP_IS_CONST_EVALUATED(s))
0681 #endif
0682       right_shift_byte(result, s);
0683 #else
0684    constexpr limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::limb_bits - 1;
0685 
0686    if ((s & limb_shift_mask) == 0)
0687       right_shift_limb(result, s);
0688 #endif
0689    else
0690       right_shift_generic(result, s);
0691    if (is_neg)
0692       eval_decrement(result);
0693 }
0694 
0695 //
0696 // Over again for trivial cpp_int's:
0697 //
0698 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class T>
0699 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
0700 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))
0701 {
0702    is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
0703    *result.limbs() = detail::checked_left_shift(*result.limbs(), s, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
0704    result.normalize();
0705 }
0706 
0707 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class T>
0708 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
0709 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))
0710 {
0711    // Nothing to check here... just make sure we don't invoke undefined behavior:
0712    is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
0713    *result.limbs() = (static_cast<unsigned>(s) >= sizeof(*result.limbs()) * CHAR_BIT) ? 0 : (result.sign() ? ((--*result.limbs()) >> s) + 1 : *result.limbs() >> s);
0714    if (result.sign() && (*result.limbs() == 0))
0715       result = static_cast<signed_limb_type>(-1);
0716 }
0717 
0718 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>
0719 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
0720     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
0721 eval_complement(
0722     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
0723     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))
0724 {
0725    static_assert(((Checked1 != checked) || (Checked2 != checked)), "Attempt to take the complement of a signed type results in undefined behavior.");
0726    //
0727    // If we're not checked then emulate 2's complement behavior:
0728    //
0729    if (o.sign())
0730    {
0731       *result.limbs() = *o.limbs() - 1;
0732       result.sign(false);
0733    }
0734    else
0735    {
0736       *result.limbs() = 1 + *o.limbs();
0737       result.sign(true);
0738    }
0739    result.normalize();
0740 }
0741 
0742 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>
0743 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
0744     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
0745 eval_complement(
0746     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
0747     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))
0748 {
0749    *result.limbs() = ~*o.limbs();
0750    result.normalize();
0751 }
0752 
0753 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>
0754 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
0755     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
0756 eval_bitwise_and(
0757     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
0758     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))
0759 {
0760    *result.limbs() &= *o.limbs();
0761 }
0762 
0763 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>
0764 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
0765     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
0766 eval_bitwise_and(
0767     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
0768     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))
0769 {
0770    is_valid_bitwise_op(result, o, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
0771 
0772    using default_ops::eval_bit_test;
0773    using default_ops::eval_increment;
0774 
0775    if (result.sign() || o.sign())
0776    {
0777       constexpr std::size_t m = detail::static_unsigned_max<detail::static_unsigned_max<MinBits1, MinBits2>::value, detail::static_unsigned_max<MaxBits1, MaxBits2>::value>::value;
0778       cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t1(result);
0779       cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t2(o);
0780       eval_bitwise_and(t1, t2);
0781       bool s = eval_bit_test(t1, m + 1);
0782       if (s)
0783       {
0784          eval_complement(t1, t1);
0785          eval_increment(t1);
0786       }
0787       result = t1;
0788       result.sign(s);
0789    }
0790    else
0791    {
0792       *result.limbs() &= *o.limbs();
0793    }
0794 }
0795 
0796 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>
0797 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
0798     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
0799 eval_bitwise_or(
0800     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
0801     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))
0802 {
0803    *result.limbs() |= *o.limbs();
0804 }
0805 
0806 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>
0807 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
0808     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
0809 eval_bitwise_or(
0810     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
0811     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))
0812 {
0813    is_valid_bitwise_op(result, o, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
0814 
0815    using default_ops::eval_bit_test;
0816    using default_ops::eval_increment;
0817 
0818    if (result.sign() || o.sign())
0819    {
0820       constexpr std::size_t m = detail::static_unsigned_max<detail::static_unsigned_max<MinBits1, MinBits2>::value, detail::static_unsigned_max<MaxBits1, MaxBits2>::value>::value;
0821       cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t1(result);
0822       cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t2(o);
0823       eval_bitwise_or(t1, t2);
0824       bool s = eval_bit_test(t1, m + 1);
0825       if (s)
0826       {
0827          eval_complement(t1, t1);
0828          eval_increment(t1);
0829       }
0830       result = t1;
0831       result.sign(s);
0832    }
0833    else
0834    {
0835       *result.limbs() |= *o.limbs();
0836       result.normalize();
0837    }
0838 }
0839 
0840 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>
0841 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
0842     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
0843 eval_bitwise_xor(
0844     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
0845     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))
0846 {
0847    *result.limbs() ^= *o.limbs();
0848 }
0849 
0850 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>
0851 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
0852     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
0853 eval_bitwise_xor(
0854     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
0855     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))
0856 {
0857    is_valid_bitwise_op(result, o, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
0858 
0859    using default_ops::eval_bit_test;
0860    using default_ops::eval_increment;
0861 
0862    if (result.sign() || o.sign())
0863    {
0864       constexpr std::size_t m = detail::static_unsigned_max<detail::static_unsigned_max<MinBits1, MinBits2>::value, detail::static_unsigned_max<MaxBits1, MaxBits2>::value>::value;
0865       cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t1(result);
0866       cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t2(o);
0867       eval_bitwise_xor(t1, t2);
0868       bool s = eval_bit_test(t1, m + 1);
0869       if (s)
0870       {
0871          eval_complement(t1, t1);
0872          eval_increment(t1);
0873       }
0874       result = t1;
0875       result.sign(s);
0876    }
0877    else
0878    {
0879       *result.limbs() ^= *o.limbs();
0880    }
0881 }
0882 
0883 }}} // namespace boost::multiprecision::backends
0884 
0885 #ifdef BOOST_MSVC
0886 #pragma warning(pop)
0887 #endif
0888 
0889 #endif