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 http://www.boost.org/LICENSE_1_
6 // Comparison operators for cpp_int_backend:
8 #ifndef BOOST_MP_CPP_INT_BIT_HPP
9 #define BOOST_MP_CPP_INT_BIT_HPP
13 #pragma warning(disable:4319)
16 namespace boost{ namespace multiprecision{ namespace backends{
18 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
19 void is_valid_bitwise_op(
20 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
21 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o, const mpl::int_<checked>&)
23 if(result.sign() || o.sign())
24 BOOST_THROW_EXCEPTION(std::range_error("Bitwise operations on negative values results in undefined behavior."));
27 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
28 void is_valid_bitwise_op(
29 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&,
30 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& , const mpl::int_<unchecked>&){}
32 template <unsigned MinBits1, unsigned MaxBits1, cpp_int_check_type Checked1, class Allocator1>
33 void is_valid_bitwise_op(
34 const cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>& result, const mpl::int_<checked>&)
37 BOOST_THROW_EXCEPTION(std::range_error("Bitwise operations on negative values results in undefined behavior."));
40 template <unsigned MinBits1, unsigned MaxBits1, cpp_int_check_type Checked1, class Allocator1>
41 void is_valid_bitwise_op(
42 const cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>&, const mpl::int_<checked>&){}
44 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
45 void is_valid_bitwise_op(
46 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&, const mpl::int_<unchecked>&){}
48 template <class CppInt1, class CppInt2, class Op>
52 Op op, const mpl::true_&) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<CppInt1>::value))
57 // * result negative, o positive.
58 // * o negative, result positive.
61 // When one arg is negative we convert to 2's complement form "on the fly",
62 // and then convert back to signed-magnitude form at the end.
64 // Note however, that if the type is checked, then bitwise ops on negative values
65 // are not permitted and an exception will result.
67 is_valid_bitwise_op(result, o, typename CppInt1::checked_type());
69 // First figure out how big the result needs to be and set up some data:
71 unsigned rs = result.size();
72 unsigned os = o.size();
76 typename CppInt1::limb_pointer pr = result.limbs();
77 typename CppInt2::const_limb_pointer po = o.limbs();
78 for(unsigned i = rs; i < x; ++i)
81 limb_type next_limb = 0;
87 for(unsigned i = 0; i < os; ++i)
88 pr[i] = op(pr[i], po[i]);
89 for(unsigned i = os; i < x; ++i)
90 pr[i] = op(pr[i], limb_type(0));
95 double_limb_type carry = 1;
96 for(unsigned i = 0; i < os; ++i)
98 carry += static_cast<double_limb_type>(~po[i]);
99 pr[i] = op(pr[i], static_cast<limb_type>(carry));
100 carry >>= CppInt1::limb_bits;
102 for(unsigned i = os; i < x; ++i)
104 carry += static_cast<double_limb_type>(~limb_type(0));
105 pr[i] = op(pr[i], static_cast<limb_type>(carry));
106 carry >>= CppInt1::limb_bits;
108 // Set the overflow into the "extra" limb:
109 carry += static_cast<double_limb_type>(~limb_type(0));
110 next_limb = op(limb_type(0), static_cast<limb_type>(carry));
117 // "result" is negative:
118 double_limb_type carry = 1;
119 for(unsigned i = 0; i < os; ++i)
121 carry += static_cast<double_limb_type>(~pr[i]);
122 pr[i] = op(static_cast<limb_type>(carry), po[i]);
123 carry >>= CppInt1::limb_bits;
125 for(unsigned i = os; i < x; ++i)
127 carry += static_cast<double_limb_type>(~pr[i]);
128 pr[i] = op(static_cast<limb_type>(carry), limb_type(0));
129 carry >>= CppInt1::limb_bits;
131 // Set the overflow into the "extra" limb:
132 carry += static_cast<double_limb_type>(~limb_type(0));
133 next_limb = op(static_cast<limb_type>(carry), limb_type(0));
137 // both are negative:
138 double_limb_type r_carry = 1;
139 double_limb_type o_carry = 1;
140 for(unsigned i = 0; i < os; ++i)
142 r_carry += static_cast<double_limb_type>(~pr[i]);
143 o_carry += static_cast<double_limb_type>(~po[i]);
144 pr[i] = op(static_cast<limb_type>(r_carry), static_cast<limb_type>(o_carry));
145 r_carry >>= CppInt1::limb_bits;
146 o_carry >>= CppInt1::limb_bits;
148 for(unsigned i = os; i < x; ++i)
150 r_carry += static_cast<double_limb_type>(~pr[i]);
151 o_carry += static_cast<double_limb_type>(~limb_type(0));
152 pr[i] = op(static_cast<limb_type>(r_carry), static_cast<limb_type>(o_carry));
153 r_carry >>= CppInt1::limb_bits;
154 o_carry >>= CppInt1::limb_bits;
156 // Set the overflow into the "extra" limb:
157 r_carry += static_cast<double_limb_type>(~limb_type(0));
158 o_carry += static_cast<double_limb_type>(~limb_type(0));
159 next_limb = op(static_cast<limb_type>(r_carry), static_cast<limb_type>(o_carry));
163 // See if the result is negative or not:
165 if(static_cast<signed_limb_type>(next_limb) < 0)
167 double_limb_type carry = 1;
168 for(unsigned i = 0; i < x; ++i)
170 carry += static_cast<double_limb_type>(~pr[i]);
171 pr[i] = static_cast<limb_type>(carry);
172 carry >>= CppInt1::limb_bits;
176 result.resize(x + 1, x);
177 if(result.size() > x)
178 result.limbs()[x] = static_cast<limb_type>(carry);
188 template <class CppInt1, class CppInt2, class Op>
192 Op op, const mpl::false_&) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<CppInt1>::value))
195 // Both arguments are unsigned types, very simple case handled as a special case.
197 // First figure out how big the result needs to be and set up some data:
199 unsigned rs = result.size();
200 unsigned os = o.size();
202 minmax(rs, os, m, x);
204 typename CppInt1::limb_pointer pr = result.limbs();
205 typename CppInt2::const_limb_pointer po = o.limbs();
206 for(unsigned i = rs; i < x; ++i)
209 for(unsigned i = 0; i < os; ++i)
210 pr[i] = op(pr[i], po[i]);
211 for(unsigned i = os; i < x; ++i)
212 pr[i] = op(pr[i], limb_type(0));
217 struct bit_and{ limb_type operator()(limb_type a, limb_type b)const BOOST_NOEXCEPT { return a & b; } };
218 struct bit_or { limb_type operator()(limb_type a, limb_type b)const BOOST_NOEXCEPT { return a | b; } };
219 struct bit_xor{ limb_type operator()(limb_type a, limb_type b)const BOOST_NOEXCEPT { return a ^ b; } };
221 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
222 BOOST_MP_FORCEINLINE typename enable_if_c<!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
224 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
225 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
227 bitwise_op(result, o, bit_and(),
228 mpl::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>());
231 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
232 BOOST_MP_FORCEINLINE typename enable_if_c<!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
234 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
235 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
237 bitwise_op(result, o, bit_or(),
238 mpl::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>());
241 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
242 BOOST_MP_FORCEINLINE typename enable_if_c<!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
244 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
245 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
247 bitwise_op(result, o, bit_xor(),
248 mpl::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>());
251 // Again for operands which are single limbs:
253 template <unsigned MinBits1, unsigned MaxBits1, cpp_int_check_type Checked1, class Allocator1>
254 BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1> >::value>::type
256 cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>& result,
257 limb_type l) BOOST_NOEXCEPT
259 result.limbs()[0] &= l;
263 template <unsigned MinBits1, unsigned MaxBits1, cpp_int_check_type Checked1, class Allocator1>
264 BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1> >::value>::type
266 cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>& result,
267 limb_type l) BOOST_NOEXCEPT
269 result.limbs()[0] |= l;
272 template <unsigned MinBits1, unsigned MaxBits1, cpp_int_check_type Checked1, class Allocator1>
273 BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1> >::value>::type
275 cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>& result,
276 limb_type l) BOOST_NOEXCEPT
278 result.limbs()[0] ^= l;
281 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
282 BOOST_MP_FORCEINLINE typename enable_if_c<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
284 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
285 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
287 BOOST_STATIC_ASSERT_MSG(((Checked1 != checked) || (Checked2 != checked)), "Attempt to take the complement of a signed type results in undefined behavior.");
288 // Increment and negate:
290 eval_increment(result);
294 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
295 BOOST_MP_FORCEINLINE typename enable_if_c<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
297 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
298 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
300 unsigned os = o.size();
301 result.resize(UINT_MAX, os);
302 for(unsigned i = 0; i < os; ++i)
303 result.limbs()[i] = ~o.limbs()[i];
304 for(unsigned i = os; i < result.size(); ++i)
305 result.limbs()[i] = ~static_cast<limb_type>(0);
310 inline void left_shift_byte(Int& result, double_limb_type s)
312 limb_type offset = static_cast<limb_type>(s / Int::limb_bits);
313 limb_type shift = static_cast<limb_type>(s % Int::limb_bits);
314 unsigned ors = result.size();
315 if((ors == 1) && (!*result.limbs()))
316 return; // shifting zero yields zero.
318 if(shift && (result.limbs()[ors - 1] >> (Int::limb_bits - shift)))
319 ++rs; // Most significant limb will overflow when shifted
321 result.resize(rs, rs);
324 typename Int::limb_pointer pr = result.limbs();
328 std::size_t bytes = static_cast<std::size_t>(s / CHAR_BIT);
329 std::size_t len = (std::min)(ors * sizeof(limb_type), rs * sizeof(limb_type) - bytes);
330 if(bytes >= rs * sizeof(limb_type))
331 result = static_cast<limb_type>(0u);
334 unsigned char* pc = reinterpret_cast<unsigned char*>(pr);
335 std::memmove(pc + bytes, pc, len);
336 std::memset(pc, 0, bytes);
341 inline void left_shift_limb(Int& result, double_limb_type s)
343 limb_type offset = static_cast<limb_type>(s / Int::limb_bits);
344 limb_type shift = static_cast<limb_type>(s % Int::limb_bits);
346 unsigned ors = result.size();
347 if((ors == 1) && (!*result.limbs()))
348 return; // shifting zero yields zero.
350 if(shift && (result.limbs()[ors - 1] >> (Int::limb_bits - shift)))
351 ++rs; // Most significant limb will overflow when shifted
353 result.resize(rs, rs);
355 typename Int::limb_pointer pr = result.limbs();
359 // The result is shifted past the end of the result:
360 result = static_cast<limb_type>(0);
364 unsigned i = rs - result.size();
366 pr[rs - 1 - i] = pr[ors - 1 - i];
372 inline void left_shift_generic(Int& result, double_limb_type s)
374 limb_type offset = static_cast<limb_type>(s / Int::limb_bits);
375 limb_type shift = static_cast<limb_type>(s % Int::limb_bits);
377 unsigned ors = result.size();
378 if((ors == 1) && (!*result.limbs()))
379 return; // shifting zero yields zero.
381 if(shift && (result.limbs()[ors - 1] >> (Int::limb_bits - shift)))
382 ++rs; // Most significant limb will overflow when shifted
384 result.resize(rs, rs);
385 bool truncated = result.size() != rs;
387 typename Int::limb_pointer pr = result.limbs();
391 // The result is shifted past the end of the result:
392 result = static_cast<limb_type>(0);
396 unsigned i = rs - result.size();
397 // This code only works when shift is non-zero, otherwise we invoke undefined behaviour!
401 if(rs > ors + offset)
403 pr[rs - 1 - i] = pr[ors - 1 - i] >> (Int::limb_bits - shift);
408 pr[rs - 1 - i] = pr[ors - 1 - i] << shift;
410 pr[rs - 1 - i] |= pr[ors - 2 - i] >> (Int::limb_bits - shift);
414 for(; rs - i >= 2 + offset; ++i)
416 pr[rs - 1 - i] = pr[rs - 1 - i - offset] << shift;
417 pr[rs - 1 - i] |= pr[rs - 2 - i - offset] >> (Int::limb_bits - shift);
419 if(rs - i >= 1 + offset)
421 pr[rs - 1 - i] = pr[rs - 1 - i - offset] << shift;
428 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
429 inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
431 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
432 double_limb_type s) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
434 is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
438 #if defined(BOOST_LITTLE_ENDIAN) && defined(BOOST_MP_USE_LIMB_SHIFT)
439 static const limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits - 1;
440 static const limb_type byte_shift_mask = CHAR_BIT - 1;
441 if((s & limb_shift_mask) == 0)
443 left_shift_limb(result, s);
445 else if((s & byte_shift_mask) == 0)
447 left_shift_byte(result, s);
449 #elif defined(BOOST_LITTLE_ENDIAN)
450 static const limb_type byte_shift_mask = CHAR_BIT - 1;
451 if((s & byte_shift_mask) == 0)
453 left_shift_byte(result, s);
456 static const limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits - 1;
457 if((s & limb_shift_mask) == 0)
459 left_shift_limb(result, s);
464 left_shift_generic(result, s);
467 // We may have shifted off the end and have leading zeros:
473 inline void right_shift_byte(Int& result, double_limb_type s)
475 limb_type offset = static_cast<limb_type>(s / Int::limb_bits);
477 BOOST_ASSERT((s % CHAR_BIT) == 0);
478 unsigned ors = result.size();
482 result = limb_type(0);
486 typename Int::limb_pointer pr = result.limbs();
487 unsigned char* pc = reinterpret_cast<unsigned char*>(pr);
488 shift = static_cast<limb_type>(s / CHAR_BIT);
489 std::memmove(pc, pc + shift, ors * sizeof(pr[0]) - shift);
490 shift = (sizeof(limb_type) - shift % sizeof(limb_type)) * CHAR_BIT;
491 if(shift < Int::limb_bits)
493 pr[ors - offset - 1] &= (static_cast<limb_type>(1u) << shift) - 1;
494 if(!pr[ors - offset - 1] && (rs > 1))
497 result.resize(rs, rs);
501 inline void right_shift_limb(Int& result, double_limb_type s)
503 limb_type offset = static_cast<limb_type>(s / Int::limb_bits);
504 BOOST_ASSERT((s % Int::limb_bits) == 0);
505 unsigned ors = result.size();
509 result = limb_type(0);
513 typename Int::limb_pointer pr = result.limbs();
516 pr[i] = pr[i + offset];
517 result.resize(rs, rs);
521 inline void right_shift_generic(Int& result, double_limb_type s)
523 limb_type offset = static_cast<limb_type>(s / Int::limb_bits);
524 limb_type shift = static_cast<limb_type>(s % Int::limb_bits);
525 unsigned ors = result.size();
529 result = limb_type(0);
533 typename Int::limb_pointer pr = result.limbs();
534 if((pr[ors - 1] >> shift) == 0)
538 result = limb_type(0);
544 // This code only works for non-zero shift, otherwise we invoke undefined behaviour!
546 for(; i + offset + 1 < ors; ++i)
548 pr[i] = pr[i + offset] >> shift;
549 pr[i] |= pr[i + offset + 1] << (Int::limb_bits - shift);
551 pr[i] = pr[i + offset] >> shift;
552 result.resize(rs, rs);
555 template <unsigned MinBits1, unsigned MaxBits1, cpp_int_check_type Checked1, class Allocator1>
556 inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1> >::value>::type
558 cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>& result,
559 double_limb_type s) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1> >::value))
561 is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>::checked_type());
565 #if defined(BOOST_LITTLE_ENDIAN) && defined(BOOST_MP_USE_LIMB_SHIFT)
566 static const limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::limb_bits - 1;
567 static const limb_type byte_shift_mask = CHAR_BIT - 1;
568 if((s & limb_shift_mask) == 0)
569 right_shift_limb(result, s);
570 else if((s & byte_shift_mask) == 0)
571 right_shift_byte(result, s);
572 #elif defined(BOOST_LITTLE_ENDIAN)
573 static const limb_type byte_shift_mask = CHAR_BIT - 1;
574 if((s & byte_shift_mask) == 0)
575 right_shift_byte(result, s);
577 static const limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::limb_bits - 1;
578 if((s & limb_shift_mask) == 0)
579 right_shift_limb(result, s);
582 right_shift_generic(result, s);
584 template <unsigned MinBits1, unsigned MaxBits1, cpp_int_check_type Checked1, class Allocator1>
585 inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1> >::value>::type
587 cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>& result,
588 double_limb_type s) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1> >::value))
590 is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::checked_type());
594 bool is_neg = result.sign();
596 eval_increment(result);
598 #if defined(BOOST_LITTLE_ENDIAN) && defined(BOOST_MP_USE_LIMB_SHIFT)
599 static const limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::limb_bits - 1;
600 static const limb_type byte_shift_mask = CHAR_BIT - 1;
601 if((s & limb_shift_mask) == 0)
602 right_shift_limb(result, s);
603 else if((s & byte_shift_mask) == 0)
604 right_shift_byte(result, s);
605 #elif defined(BOOST_LITTLE_ENDIAN)
606 static const limb_type byte_shift_mask = CHAR_BIT - 1;
607 if((s & byte_shift_mask) == 0)
608 right_shift_byte(result, s);
610 static const limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::limb_bits - 1;
611 if((s & limb_shift_mask) == 0)
612 right_shift_limb(result, s);
615 right_shift_generic(result, s);
617 eval_decrement(result);
621 // Over again for trivial cpp_int's:
623 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class T>
624 BOOST_MP_FORCEINLINE typename enable_if<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> > >::type
625 eval_left_shift(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, T s) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
627 is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
628 *result.limbs() = detail::checked_left_shift(*result.limbs(), s, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
632 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class T>
633 BOOST_MP_FORCEINLINE typename enable_if<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> > >::type
634 eval_right_shift(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, T s) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
636 // Nothing to check here... just make sure we don't invoke undefined behavior:
637 is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
638 *result.limbs() = (static_cast<unsigned>(s) >= sizeof(*result.limbs()) * CHAR_BIT) ? 0 : (result.sign() ? ((--*result.limbs()) >> s) + 1 : *result.limbs() >> s);
639 if(result.sign() && (*result.limbs() == 0))
640 result = static_cast<signed_limb_type>(-1);
643 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
644 inline typename enable_if_c<
645 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
646 && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
647 && (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || is_signed_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value)
650 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
651 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
653 BOOST_STATIC_ASSERT_MSG(((Checked1 != checked) || (Checked2 != checked)), "Attempt to take the complement of a signed type results in undefined behavior.");
655 // If we're not checked then emulate 2's complement behavior:
659 *result.limbs() = *o.limbs() - 1;
664 *result.limbs() = 1 + *o.limbs();
670 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
671 inline typename enable_if_c<
672 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
673 && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
674 && is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
675 && is_unsigned_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
678 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
679 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
681 *result.limbs() = ~*o.limbs();
685 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
686 inline typename enable_if_c<
687 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
688 && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
689 && is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
690 && is_unsigned_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
693 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
694 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
696 *result.limbs() &= *o.limbs();
699 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
700 inline typename enable_if_c<
701 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
702 && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
703 && (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || is_signed_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value)
706 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
707 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
709 is_valid_bitwise_op(result, o, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
711 using default_ops::eval_bit_test;
712 using default_ops::eval_increment;
714 if(result.sign() || o.sign())
716 static const unsigned m = static_unsigned_max<static_unsigned_max<MinBits1, MinBits2>::value, static_unsigned_max<MaxBits1, MaxBits2>::value>::value;
717 cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t1(result);
718 cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t2(o);
719 eval_bitwise_and(t1, t2);
720 bool s = eval_bit_test(t1, m + 1);
723 eval_complement(t1, t1);
731 *result.limbs() &= *o.limbs();
735 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
736 inline typename enable_if_c<
737 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
738 && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
739 && is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
740 && is_unsigned_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
743 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
744 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
746 *result.limbs() |= *o.limbs();
749 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
750 inline typename enable_if_c<
751 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
752 && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
753 && (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || is_signed_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value)
756 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
757 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
759 is_valid_bitwise_op(result, o, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
761 using default_ops::eval_bit_test;
762 using default_ops::eval_increment;
764 if(result.sign() || o.sign())
766 static const unsigned m = static_unsigned_max<static_unsigned_max<MinBits1, MinBits2>::value, static_unsigned_max<MaxBits1, MaxBits2>::value>::value;
767 cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t1(result);
768 cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t2(o);
769 eval_bitwise_or(t1, t2);
770 bool s = eval_bit_test(t1, m + 1);
773 eval_complement(t1, t1);
781 *result.limbs() |= *o.limbs();
786 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
787 inline typename enable_if_c<
788 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
789 && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
790 && is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
791 && is_unsigned_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
794 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
795 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
797 *result.limbs() ^= *o.limbs();
800 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
801 inline typename enable_if_c<
802 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
803 && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
804 && (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || is_signed_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value)
807 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
808 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
810 is_valid_bitwise_op(result, o, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
812 using default_ops::eval_bit_test;
813 using default_ops::eval_increment;
815 if(result.sign() || o.sign())
817 static const unsigned m = static_unsigned_max<static_unsigned_max<MinBits1, MinBits2>::value, static_unsigned_max<MaxBits1, MaxBits2>::value>::value;
818 cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t1(result);
819 cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t2(o);
820 eval_bitwise_xor(t1, t2);
821 bool s = eval_bit_test(t1, m + 1);
824 eval_complement(t1, t1);
832 *result.limbs() ^= *o.limbs();