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_
5 //
6 // Comparison operators for cpp_int_backend:
7 //
8 #ifndef BOOST_MP_CPP_INT_BIT_HPP
9 #define BOOST_MP_CPP_INT_BIT_HPP
10 
11 namespace boost{ namespace multiprecision{ namespace backends{
12 
13 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>
is_valid_bitwise_op(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & result,const cpp_int_backend<MinBits2,MaxBits2,SignType2,Checked2,Allocator2> & o,const mpl::int_<checked> &)14 void is_valid_bitwise_op(
15       cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
16       const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o, const mpl::int_<checked>&)
17 {
18    if(result.sign() || o.sign())
19       BOOST_THROW_EXCEPTION(std::range_error("Bitwise operations on negative values results in undefined behavior."));
20 }
21 
22 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>
is_valid_bitwise_op(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> &,const cpp_int_backend<MinBits2,MaxBits2,SignType2,Checked2,Allocator2> &,const mpl::int_<unchecked> &)23 void is_valid_bitwise_op(
24       cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&,
25       const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& , const mpl::int_<unchecked>&){}
26 
27 template <unsigned MinBits1, unsigned MaxBits1, cpp_int_check_type Checked1, class Allocator1>
is_valid_bitwise_op(const cpp_int_backend<MinBits1,MaxBits1,signed_magnitude,Checked1,Allocator1> & result,const mpl::int_<checked> &)28 void is_valid_bitwise_op(
29       const cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>& result, const mpl::int_<checked>&)
30 {
31    if(result.sign())
32       BOOST_THROW_EXCEPTION(std::range_error("Bitwise operations on negative values results in undefined behavior."));
33 }
34 
35 template <unsigned MinBits1, unsigned MaxBits1, cpp_int_check_type Checked1, class Allocator1>
is_valid_bitwise_op(const cpp_int_backend<MinBits1,MaxBits1,unsigned_magnitude,Checked1,Allocator1> &,const mpl::int_<checked> &)36 void is_valid_bitwise_op(
37    const cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>&, const mpl::int_<checked>&){}
38 
39 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
is_valid_bitwise_op(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> &,const mpl::int_<unchecked> &)40 void is_valid_bitwise_op(
41       cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&, const mpl::int_<unchecked>&){}
42 
43 template <class CppInt1, class CppInt2, class Op>
bitwise_op(CppInt1 & result,const CppInt2 & o,Op op,const mpl::true_ &)44 void bitwise_op(
45    CppInt1& result,
46    const CppInt2& o,
47    Op op, const mpl::true_&) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<CppInt1>::value))
48 {
49    //
50    // There are 4 cases:
51    // * Both positive.
52    // * result negative, o positive.
53    // * o negative, result positive.
54    // * Both negative.
55    //
56    // When one arg is negative we convert to 2's complement form "on the fly",
57    // and then convert back to signed-magnitude form at the end.
58    //
59    // Note however, that if the type is checked, then bitwise ops on negative values
60    // are not permitted and an exception will result.
61    //
62    is_valid_bitwise_op(result, o, typename CppInt1::checked_type());
63    //
64    // First figure out how big the result needs to be and set up some data:
65    //
66    unsigned rs = result.size();
67    unsigned os = o.size();
68    unsigned m, x;
69    minmax(rs, os, m, x);
70    result.resize(x, x);
71    typename CppInt1::limb_pointer pr = result.limbs();
72    typename CppInt2::const_limb_pointer po = o.limbs();
73    for(unsigned i = rs; i < x; ++i)
74       pr[i] = 0;
75 
76    limb_type next_limb = 0;
77 
78    if(!result.sign())
79    {
80       if(!o.sign())
81       {
82          for(unsigned i = 0; i < os; ++i)
83             pr[i] = op(pr[i], po[i]);
84          for(unsigned i = os; i < x; ++i)
85             pr[i] = op(pr[i], limb_type(0));
86       }
87       else
88       {
89          // "o" is negative:
90          double_limb_type carry = 1;
91          for(unsigned i = 0; i < os; ++i)
92          {
93             carry += static_cast<double_limb_type>(~po[i]);
94             pr[i] = op(pr[i], static_cast<limb_type>(carry));
95             carry >>= CppInt1::limb_bits;
96          }
97          for(unsigned i = os; i < x; ++i)
98          {
99             carry += static_cast<double_limb_type>(~limb_type(0));
100             pr[i] = op(pr[i], static_cast<limb_type>(carry));
101             carry >>= CppInt1::limb_bits;
102          }
103          // Set the overflow into the "extra" limb:
104          carry += static_cast<double_limb_type>(~limb_type(0));
105          next_limb = op(limb_type(0), static_cast<limb_type>(carry));
106       }
107    }
108    else
109    {
110       if(!o.sign())
111       {
112          // "result" is negative:
113          double_limb_type carry = 1;
114          for(unsigned i = 0; i < os; ++i)
115          {
116             carry += static_cast<double_limb_type>(~pr[i]);
117             pr[i] = op(static_cast<limb_type>(carry), po[i]);
118             carry >>= CppInt1::limb_bits;
119          }
120          for(unsigned i = os; i < x; ++i)
121          {
122             carry += static_cast<double_limb_type>(~pr[i]);
123             pr[i] = op(static_cast<limb_type>(carry), limb_type(0));
124             carry >>= CppInt1::limb_bits;
125          }
126          // Set the overflow into the "extra" limb:
127          carry += static_cast<double_limb_type>(~limb_type(0));
128          next_limb = op(static_cast<limb_type>(carry), limb_type(0));
129       }
130       else
131       {
132          // both are negative:
133          double_limb_type r_carry = 1;
134          double_limb_type o_carry = 1;
135          for(unsigned i = 0; i < os; ++i)
136          {
137             r_carry += static_cast<double_limb_type>(~pr[i]);
138             o_carry += static_cast<double_limb_type>(~po[i]);
139             pr[i] = op(static_cast<limb_type>(r_carry), static_cast<limb_type>(o_carry));
140             r_carry >>= CppInt1::limb_bits;
141             o_carry >>= CppInt1::limb_bits;
142          }
143          for(unsigned i = os; i < x; ++i)
144          {
145             r_carry += static_cast<double_limb_type>(~pr[i]);
146             o_carry += static_cast<double_limb_type>(~limb_type(0));
147             pr[i] = op(static_cast<limb_type>(r_carry), static_cast<limb_type>(o_carry));
148             r_carry >>= CppInt1::limb_bits;
149             o_carry >>= CppInt1::limb_bits;
150          }
151          // Set the overflow into the "extra" limb:
152          r_carry += static_cast<double_limb_type>(~limb_type(0));
153          o_carry += static_cast<double_limb_type>(~limb_type(0));
154          next_limb = op(static_cast<limb_type>(r_carry), static_cast<limb_type>(o_carry));
155       }
156    }
157    //
158    // See if the result is negative or not:
159    //
160    if(static_cast<signed_limb_type>(next_limb) < 0)
161    {
162       double_limb_type carry = 1;
163       for(unsigned i = 0; i < x; ++i)
164       {
165          carry += static_cast<double_limb_type>(~pr[i]);
166          pr[i] = static_cast<limb_type>(carry);
167          carry >>= CppInt1::limb_bits;
168       }
169       if(carry)
170       {
171          result.resize(x + 1, x);
172          if(result.size() > x)
173             result.limbs()[x] = static_cast<limb_type>(carry);
174       }
175       result.sign(true);
176    }
177    else
178       result.sign(false);
179 
180    result.normalize();
181 }
182 
183 template <class CppInt1, class CppInt2, class Op>
bitwise_op(CppInt1 & result,const CppInt2 & o,Op op,const mpl::false_ &)184 void bitwise_op(
185    CppInt1& result,
186    const CppInt2& o,
187    Op op, const mpl::false_&) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<CppInt1>::value))
188 {
189    //
190    // Both arguments are unsigned types, very simple case handled as a special case.
191    //
192    // First figure out how big the result needs to be and set up some data:
193    //
194    unsigned rs = result.size();
195    unsigned os = o.size();
196    unsigned m, x;
197    minmax(rs, os, m, x);
198    result.resize(x, x);
199    typename CppInt1::limb_pointer pr = result.limbs();
200    typename CppInt2::const_limb_pointer po = o.limbs();
201    for(unsigned i = rs; i < x; ++i)
202       pr[i] = 0;
203 
204    for(unsigned i = 0; i < os; ++i)
205       pr[i] = op(pr[i], po[i]);
206    for(unsigned i = os; i < x; ++i)
207       pr[i] = op(pr[i], limb_type(0));
208 
209    result.normalize();
210 }
211 
operator ()boost::multiprecision::backends::bit_and212 struct bit_and{ limb_type operator()(limb_type a, limb_type b)const BOOST_NOEXCEPT { return a & b; } };
operator ()boost::multiprecision::backends::bit_or213 struct bit_or { limb_type operator()(limb_type a, limb_type b)const BOOST_NOEXCEPT { return a | b; } };
operator ()boost::multiprecision::backends::bit_xor214 struct bit_xor{ limb_type operator()(limb_type a, limb_type b)const BOOST_NOEXCEPT { return a ^ b; } };
215 
216 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>
217 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
eval_bitwise_and(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & result,const cpp_int_backend<MinBits2,MaxBits2,SignType2,Checked2,Allocator2> & o)218    eval_bitwise_and(
219       cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
220       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))
221 {
222    bitwise_op(result, o, bit_and(),
223       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>());
224 }
225 
226 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>
227 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
eval_bitwise_or(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & result,const cpp_int_backend<MinBits2,MaxBits2,SignType2,Checked2,Allocator2> & o)228    eval_bitwise_or(
229       cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
230       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))
231 {
232    bitwise_op(result, o, bit_or(),
233       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>());
234 }
235 
236 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>
237 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
eval_bitwise_xor(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & result,const cpp_int_backend<MinBits2,MaxBits2,SignType2,Checked2,Allocator2> & o)238    eval_bitwise_xor(
239       cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
240       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))
241 {
242    bitwise_op(result, o, bit_xor(),
243       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>());
244 }
245 //
246 // Again for operands which are single limbs:
247 //
248 template <unsigned MinBits1, unsigned MaxBits1, cpp_int_check_type Checked1, class Allocator1>
249 BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1> >::value>::type
eval_bitwise_and(cpp_int_backend<MinBits1,MaxBits1,unsigned_magnitude,Checked1,Allocator1> & result,limb_type l)250    eval_bitwise_and(
251       cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>& result,
252       limb_type l) BOOST_NOEXCEPT
253 {
254    result.limbs()[0] &= l;
255    result.resize(1, 1);
256 }
257 
258 template <unsigned MinBits1, unsigned MaxBits1, cpp_int_check_type Checked1, class Allocator1>
259 BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1> >::value>::type
eval_bitwise_or(cpp_int_backend<MinBits1,MaxBits1,unsigned_magnitude,Checked1,Allocator1> & result,limb_type l)260    eval_bitwise_or(
261       cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>& result,
262       limb_type l) BOOST_NOEXCEPT
263 {
264    result.limbs()[0] |= l;
265 }
266 
267 template <unsigned MinBits1, unsigned MaxBits1, cpp_int_check_type Checked1, class Allocator1>
268 BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1> >::value>::type
eval_bitwise_xor(cpp_int_backend<MinBits1,MaxBits1,unsigned_magnitude,Checked1,Allocator1> & result,limb_type l)269    eval_bitwise_xor(
270       cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>& result,
271       limb_type l) BOOST_NOEXCEPT
272 {
273    result.limbs()[0] ^= l;
274 }
275 
276 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>
277 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
eval_complement(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & result,const cpp_int_backend<MinBits2,MaxBits2,SignType2,Checked2,Allocator2> & o)278    eval_complement(
279       cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
280       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))
281 {
282    BOOST_STATIC_ASSERT_MSG(((Checked1 != checked) || (Checked2 != checked)), "Attempt to take the complement of a signed type results in undefined behavior.");
283    // Increment and negate:
284    result = o;
285    eval_increment(result);
286    result.negate();
287 }
288 
289 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
290 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
eval_complement(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & result,const cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & o)291    eval_complement(
292       cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
293       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))
294 {
295    unsigned os = o.size();
296    result.resize(UINT_MAX, os);
297    for(unsigned i = 0; i < os; ++i)
298       result.limbs()[i] = ~o.limbs()[i];
299    for(unsigned i = os; i < result.size(); ++i)
300       result.limbs()[i] = ~static_cast<limb_type>(0);
301    result.normalize();
302 }
303 
304 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
305 inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
eval_left_shift(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & result,double_limb_type s)306    eval_left_shift(
307       cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
308       double_limb_type s) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
309 {
310    is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
311    if(!s)
312       return;
313 
314    limb_type offset = static_cast<limb_type>(s / cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits);
315    limb_type shift  = static_cast<limb_type>(s % cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits);
316 
317    unsigned ors = result.size();
318    if((ors == 1) && (!*result.limbs()))
319       return; // shifting zero yields zero.
320    unsigned rs = ors;
321    if(shift && (result.limbs()[ors - 1] >> (cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits - shift)))
322       ++rs; // Most significant limb will overflow when shifted
323    rs += offset;
324    result.resize(rs, rs);
325    bool truncated = result.size() != rs;
326 
327    typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_pointer pr = result.limbs();
328 
329    if(offset > rs)
330    {
331       // The result is shifted past the end of the result:
332       result = static_cast<limb_type>(0);
333       return;
334    }
335 
336    unsigned i = rs - result.size();
337    if(shift)
338    {
339       // This code only works when shift is non-zero, otherwise we invoke undefined behaviour!
340       if(!truncated)
341       {
342          if(rs > ors + offset)
343          {
344             pr[rs - 1 - i] = pr[ors - 1 - i] >> (cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits - shift);
345             --rs;
346          }
347          else
348          {
349             pr[rs - 1 - i] = pr[ors - 1 - i] << shift;
350             if(ors > 1)
351                pr[rs - 1 - i] |= pr[ors - 2 - i] >> (cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits - shift);
352             ++i;
353          }
354       }
355       for(; ors > 1 + i; ++i)
356       {
357          pr[rs - 1 - i] = pr[ors - 1 - i] << shift;
358          pr[rs - 1 - i] |= pr[ors - 2 - i] >> (cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits - shift);
359       }
360       if(ors >= 1 + i)
361       {
362          pr[rs - 1 - i] = pr[ors - 1 - i] << shift;
363          ++i;
364       }
365       for(; i < rs; ++i)
366          pr[rs - 1 - i] = 0;
367    }
368    else
369    {
370       for(; i < ors; ++i)
371          pr[rs - 1 - i] = pr[ors - 1 - i];
372       for(; i < rs; ++i)
373          pr[rs - 1 - i] = 0;
374    }
375    //
376    // We may have shifted off the end and have leading zeros:
377    //
378    result.normalize();
379 }
380 
381 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
382 inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
eval_right_shift(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & result,double_limb_type s)383    eval_right_shift(
384       cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
385       double_limb_type s) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
386 {
387    is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
388    if(!s)
389       return;
390 
391    bool is_neg = result.sign();
392    if(is_neg)
393       eval_increment(result);
394 
395    limb_type offset = static_cast<limb_type>(s / cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits);
396    limb_type shift  = static_cast<limb_type>(s % cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits);
397    unsigned ors = result.size();
398    unsigned rs = ors;
399    if(offset >= rs)
400    {
401       if(is_neg)
402          result = signed_limb_type(-1);
403       else
404          result = limb_type(0);
405       return;
406    }
407    rs -= offset;
408    typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_pointer pr = result.limbs();
409    if((pr[ors - 1] >> shift) == 0)
410       --rs;
411    if(rs == 0)
412    {
413       if(is_neg)
414          result = signed_limb_type(-1);
415       else
416          result = limb_type(0);
417       return;
418    }
419    unsigned i = 0;
420    if(shift)
421    {
422       // This code only works for non-zero shift, otherwise we invoke undefined behaviour!
423       for(; i + offset + 1 < ors; ++i)
424       {
425          pr[i] = pr[i + offset] >> shift;
426          pr[i] |= pr[i + offset + 1] << (cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits - shift);
427       }
428       pr[i] = pr[i + offset] >> shift;
429    }
430    else
431    {
432       for(; i < rs; ++i)
433          pr[i] = pr[i + offset];
434    }
435    result.resize(rs, rs);
436    if(is_neg)
437       eval_decrement(result);
438 }
439 
440 //
441 // Over again for trivial cpp_int's:
442 //
443 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class T>
444 BOOST_MP_FORCEINLINE typename enable_if<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> > >::type
eval_left_shift(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & result,T s)445    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))
446 {
447    is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
448    *result.limbs() = detail::checked_left_shift(*result.limbs(), s, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
449    result.normalize();
450 }
451 
452 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class T>
453 BOOST_MP_FORCEINLINE typename enable_if<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> > >::type
eval_right_shift(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & result,T s)454    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))
455 {
456    // Nothing to check here... just make sure we don't invoke undefined behavior:
457    is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
458    *result.limbs() = (static_cast<unsigned>(s) >= sizeof(*result.limbs()) * CHAR_BIT) ? 0 : *result.limbs() >> s;
459 }
460 
461 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>
462 inline typename enable_if_c<
463          is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
464          && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
465          && (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || is_signed_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value)
466          >::type
eval_bitwise_and(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & result,const cpp_int_backend<MinBits2,MaxBits2,SignType2,Checked2,Allocator2> & o)467    eval_bitwise_and(
468       cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
469       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))
470 {
471    is_valid_bitwise_op(result, o, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
472 
473    using default_ops::eval_bit_test;
474    using default_ops::eval_increment;
475 
476    if(result.sign() || o.sign())
477    {
478       static const unsigned m = static_unsigned_max<static_unsigned_max<MinBits1, MinBits2>::value, static_unsigned_max<MaxBits1, MaxBits2>::value>::value;
479       cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t1(result);
480       cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t2(o);
481       eval_bitwise_and(t1, t2);
482       bool s = eval_bit_test(t1, m + 1);
483       if(s)
484       {
485          eval_complement(t1, t1);
486          eval_increment(t1);
487       }
488       result = t1;
489       result.sign(s);
490    }
491    else
492    {
493       *result.limbs() &= *o.limbs();
494    }
495 }
496 
497 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>
498 inline typename enable_if_c<
499          is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
500          && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
501          && is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
502          && is_unsigned_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
503          >::type
eval_bitwise_and(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & result,const cpp_int_backend<MinBits2,MaxBits2,SignType2,Checked2,Allocator2> & o)504    eval_bitwise_and(
505       cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
506       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))
507 {
508    *result.limbs() &= *o.limbs();
509 }
510 
511 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>
512 inline typename enable_if_c<
513          is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
514          && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
515          && (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || is_signed_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value)
516          >::type
eval_bitwise_or(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & result,const cpp_int_backend<MinBits2,MaxBits2,SignType2,Checked2,Allocator2> & o)517    eval_bitwise_or(
518       cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
519       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))
520 {
521    is_valid_bitwise_op(result, o, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
522 
523    using default_ops::eval_bit_test;
524    using default_ops::eval_increment;
525 
526    if(result.sign() || o.sign())
527    {
528       static const unsigned m = static_unsigned_max<static_unsigned_max<MinBits1, MinBits2>::value, static_unsigned_max<MaxBits1, MaxBits2>::value>::value;
529       cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t1(result);
530       cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t2(o);
531       eval_bitwise_or(t1, t2);
532       bool s = eval_bit_test(t1, m + 1);
533       if(s)
534       {
535          eval_complement(t1, t1);
536          eval_increment(t1);
537       }
538       result = t1;
539       result.sign(s);
540    }
541    else
542    {
543       *result.limbs() |= *o.limbs();
544       result.normalize();
545    }
546 }
547 
548 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>
549 inline typename enable_if_c<
550          is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
551          && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
552          && is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
553          && is_unsigned_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
554          >::type
eval_bitwise_or(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & result,const cpp_int_backend<MinBits2,MaxBits2,SignType2,Checked2,Allocator2> & o)555    eval_bitwise_or(
556       cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
557       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))
558 {
559    *result.limbs() |= *o.limbs();
560 }
561 
562 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>
563 inline typename enable_if_c<
564          is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
565          && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
566          && (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || is_signed_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value)
567          >::type
eval_bitwise_xor(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & result,const cpp_int_backend<MinBits2,MaxBits2,SignType2,Checked2,Allocator2> & o)568    eval_bitwise_xor(
569       cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
570       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))
571 {
572    is_valid_bitwise_op(result, o, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
573 
574    using default_ops::eval_bit_test;
575    using default_ops::eval_increment;
576 
577    if(result.sign() || o.sign())
578    {
579       static const unsigned m = static_unsigned_max<static_unsigned_max<MinBits1, MinBits2>::value, static_unsigned_max<MaxBits1, MaxBits2>::value>::value;
580       cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t1(result);
581       cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t2(o);
582       eval_bitwise_xor(t1, t2);
583       bool s = eval_bit_test(t1, m + 1);
584       if(s)
585       {
586          eval_complement(t1, t1);
587          eval_increment(t1);
588       }
589       result = t1;
590       result.sign(s);
591    }
592    else
593    {
594       *result.limbs() ^= *o.limbs();
595    }
596 }
597 
598 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>
599 inline typename enable_if_c<
600          is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
601          && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
602          && is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
603          && is_unsigned_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
604          >::type
eval_bitwise_xor(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & result,const cpp_int_backend<MinBits2,MaxBits2,SignType2,Checked2,Allocator2> & o)605    eval_bitwise_xor(
606       cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
607       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))
608 {
609    *result.limbs() ^= *o.limbs();
610 }
611 
612 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>
613 inline typename enable_if_c<
614          is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
615          && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
616          && (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || is_signed_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value)
617          >::type
eval_complement(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & result,const cpp_int_backend<MinBits2,MaxBits2,SignType2,Checked2,Allocator2> & o)618    eval_complement(
619       cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
620       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))
621 {
622    BOOST_STATIC_ASSERT_MSG(((Checked1 != checked) || (Checked2 != checked)), "Attempt to take the complement of a signed type results in undefined behavior.");
623    //
624    // If we're not checked then emulate 2's complement behavior:
625    //
626    if(o.sign())
627    {
628       *result.limbs() = *o.limbs() - 1;
629       result.sign(false);
630    }
631    else
632    {
633       *result.limbs() = 1 + *o.limbs();
634       result.sign(true);
635    }
636    result.normalize();
637 }
638 
639 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>
640 inline typename enable_if_c<
641          is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
642          && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
643          && is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
644          && is_unsigned_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value
645          >::type
eval_complement(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & result,const cpp_int_backend<MinBits2,MaxBits2,SignType2,Checked2,Allocator2> & o)646    eval_complement(
647       cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
648       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))
649 {
650    *result.limbs() = ~*o.limbs();
651    result.normalize();
652 }
653 
654 }}} // namespaces
655 
656 #endif
657