Imported Upstream version 1.64.0
[platform/upstream/boost.git] / boost / multiprecision / cpp_int / bitwise.hpp
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 #ifdef _MSC_VER
12 #pragma warning(push)
13 #pragma warning(disable:4319)
14 #endif
15
16 namespace boost{ namespace multiprecision{ namespace backends{
17
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>&)
22 {
23    if(result.sign() || o.sign())
24       BOOST_THROW_EXCEPTION(std::range_error("Bitwise operations on negative values results in undefined behavior."));
25 }
26
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>&){}
31
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>&)
35 {
36    if(result.sign())
37       BOOST_THROW_EXCEPTION(std::range_error("Bitwise operations on negative values results in undefined behavior."));
38 }
39
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>&){}
43
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>&){}
47
48 template <class CppInt1, class CppInt2, class Op>
49 void bitwise_op(
50    CppInt1& result,
51    const CppInt2& o,
52    Op op, const mpl::true_&) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<CppInt1>::value))
53 {
54    //
55    // There are 4 cases:
56    // * Both positive.
57    // * result negative, o positive.
58    // * o negative, result positive.
59    // * Both negative.
60    //
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.
63    //
64    // Note however, that if the type is checked, then bitwise ops on negative values
65    // are not permitted and an exception will result.
66    //
67    is_valid_bitwise_op(result, o, typename CppInt1::checked_type());
68    //
69    // First figure out how big the result needs to be and set up some data:
70    //
71    unsigned rs = result.size();
72    unsigned os = o.size();
73    unsigned m, x;
74    minmax(rs, os, m, x);
75    result.resize(x, x);
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)
79       pr[i] = 0;
80
81    limb_type next_limb = 0;
82
83    if(!result.sign())
84    {
85       if(!o.sign())
86       {
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));
91       }
92       else
93       {
94          // "o" is negative:
95          double_limb_type carry = 1;
96          for(unsigned i = 0; i < os; ++i)
97          {
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;
101          }
102          for(unsigned i = os; i < x; ++i)
103          {
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;
107          }
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));
111       }
112    }
113    else
114    {
115       if(!o.sign())
116       {
117          // "result" is negative:
118          double_limb_type carry = 1;
119          for(unsigned i = 0; i < os; ++i)
120          {
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;
124          }
125          for(unsigned i = os; i < x; ++i)
126          {
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;
130          }
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));
134       }
135       else
136       {
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)
141          {
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;
147          }
148          for(unsigned i = os; i < x; ++i)
149          {
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;
155          }
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));
160       }
161    }
162    //
163    // See if the result is negative or not:
164    //
165    if(static_cast<signed_limb_type>(next_limb) < 0)
166    {
167       double_limb_type carry = 1;
168       for(unsigned i = 0; i < x; ++i)
169       {
170          carry += static_cast<double_limb_type>(~pr[i]);
171          pr[i] = static_cast<limb_type>(carry);
172          carry >>= CppInt1::limb_bits;
173       }
174       if(carry)
175       {
176          result.resize(x + 1, x);
177          if(result.size() > x)
178             result.limbs()[x] = static_cast<limb_type>(carry);
179       }
180       result.sign(true);
181    }
182    else
183       result.sign(false);
184
185    result.normalize();
186 }
187
188 template <class CppInt1, class CppInt2, class Op>
189 void bitwise_op(
190    CppInt1& result,
191    const CppInt2& o,
192    Op op, const mpl::false_&) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<CppInt1>::value))
193 {
194    //
195    // Both arguments are unsigned types, very simple case handled as a special case.
196    //
197    // First figure out how big the result needs to be and set up some data:
198    //
199    unsigned rs = result.size();
200    unsigned os = o.size();
201    unsigned m, x;
202    minmax(rs, os, m, x);
203    result.resize(x, 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)
207       pr[i] = 0;
208
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));
213
214    result.normalize();
215 }
216
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; } };
220
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
223    eval_bitwise_and(
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))
226 {
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>());
229 }
230
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
233    eval_bitwise_or(
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))
236 {
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>());
239 }
240
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
243    eval_bitwise_xor(
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))
246 {
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>());
249 }
250 //
251 // Again for operands which are single limbs:
252 //
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
255    eval_bitwise_and(
256       cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>& result,
257       limb_type l) BOOST_NOEXCEPT
258 {
259    result.limbs()[0] &= l;
260    result.resize(1, 1);
261 }
262
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
265    eval_bitwise_or(
266       cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>& result,
267       limb_type l) BOOST_NOEXCEPT
268 {
269    result.limbs()[0] |= l;
270 }
271
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
274    eval_bitwise_xor(
275       cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>& result,
276       limb_type l) BOOST_NOEXCEPT
277 {
278    result.limbs()[0] ^= l;
279 }
280
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
283    eval_complement(
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))
286 {
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:
289    result = o;
290    eval_increment(result);
291    result.negate();
292 }
293
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
296    eval_complement(
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))
299 {
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);
306    result.normalize();
307 }
308
309 template <class Int>
310 inline void left_shift_byte(Int& result, double_limb_type s)
311 {
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.
317    unsigned rs = ors;
318    if(shift && (result.limbs()[ors - 1] >> (Int::limb_bits - shift)))
319       ++rs; // Most significant limb will overflow when shifted
320    rs += offset;
321    result.resize(rs, rs);
322    rs = result.size();
323
324    typename Int::limb_pointer pr = result.limbs();
325
326    if(rs != ors)
327       pr[rs - 1] = 0u;
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);
332    else
333    {
334       unsigned char* pc = reinterpret_cast<unsigned char*>(pr);
335       std::memmove(pc + bytes, pc, len);
336       std::memset(pc, 0, bytes);
337    }
338 }
339
340 template <class Int>
341 inline void left_shift_limb(Int& result, double_limb_type s)
342 {
343    limb_type offset = static_cast<limb_type>(s / Int::limb_bits);
344    limb_type shift = static_cast<limb_type>(s % Int::limb_bits);
345
346    unsigned ors = result.size();
347    if((ors == 1) && (!*result.limbs()))
348       return; // shifting zero yields zero.
349    unsigned rs = ors;
350    if(shift && (result.limbs()[ors - 1] >> (Int::limb_bits - shift)))
351       ++rs; // Most significant limb will overflow when shifted
352    rs += offset;
353    result.resize(rs, rs);
354
355    typename Int::limb_pointer pr = result.limbs();
356
357    if(offset > rs)
358    {
359       // The result is shifted past the end of the result:
360       result = static_cast<limb_type>(0);
361       return;
362    }
363
364    unsigned i = rs - result.size();
365    for(; i < ors; ++i)
366       pr[rs - 1 - i] = pr[ors - 1 - i];
367    for(; i < rs; ++i)
368       pr[rs - 1 - i] = 0;
369 }
370
371 template <class Int>
372 inline void left_shift_generic(Int& result, double_limb_type s)
373 {
374    limb_type offset = static_cast<limb_type>(s / Int::limb_bits);
375    limb_type shift = static_cast<limb_type>(s % Int::limb_bits);
376
377    unsigned ors = result.size();
378    if((ors == 1) && (!*result.limbs()))
379       return; // shifting zero yields zero.
380    unsigned rs = ors;
381    if(shift && (result.limbs()[ors - 1] >> (Int::limb_bits - shift)))
382       ++rs; // Most significant limb will overflow when shifted
383    rs += offset;
384    result.resize(rs, rs);
385    bool truncated = result.size() != rs;
386
387    typename Int::limb_pointer pr = result.limbs();
388
389    if(offset > rs)
390    {
391       // The result is shifted past the end of the result:
392       result = static_cast<limb_type>(0);
393       return;
394    }
395
396    unsigned i = rs - result.size();
397    // This code only works when shift is non-zero, otherwise we invoke undefined behaviour!
398    BOOST_ASSERT(shift);
399    if(!truncated)
400    {
401       if(rs > ors + offset)
402       {
403          pr[rs - 1 - i] = pr[ors - 1 - i] >> (Int::limb_bits - shift);
404          --rs;
405       }
406       else
407       {
408          pr[rs - 1 - i] = pr[ors - 1 - i] << shift;
409          if(ors > 1)
410             pr[rs - 1 - i] |= pr[ors - 2 - i] >> (Int::limb_bits - shift);
411          ++i;
412       }
413    }
414    for(; rs - i >= 2 + offset; ++i)
415    {
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);
418    }
419    if(rs - i >= 1 + offset)
420    {
421       pr[rs - 1 - i] = pr[rs - 1 - i - offset] << shift;
422       ++i;
423    }
424    for(; i < rs; ++i)
425       pr[rs - 1 - i] = 0;
426 }
427
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
430    eval_left_shift(
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))
433 {
434    is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
435    if(!s)
436       return;
437
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)
442    {
443       left_shift_limb(result, s);
444    }
445    else if((s & byte_shift_mask) == 0)
446    {
447       left_shift_byte(result, s);
448    }
449 #elif defined(BOOST_LITTLE_ENDIAN)
450    static const limb_type byte_shift_mask = CHAR_BIT - 1;
451    if((s & byte_shift_mask) == 0)
452    {
453       left_shift_byte(result, s);
454    }
455 #else
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)
458    {
459       left_shift_limb(result, s);
460    }
461 #endif
462    else
463    {
464       left_shift_generic(result, s);
465    }
466    //
467    // We may have shifted off the end and have leading zeros:
468    //
469    result.normalize();
470 }
471
472 template <class Int>
473 inline void right_shift_byte(Int& result, double_limb_type s)
474 {
475    limb_type offset = static_cast<limb_type>(s / Int::limb_bits);
476    limb_type shift;
477    BOOST_ASSERT((s % CHAR_BIT) == 0);
478    unsigned ors = result.size();
479    unsigned rs = ors;
480    if(offset >= rs)
481    {
482       result = limb_type(0);
483       return;
484    }
485    rs -= offset;
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)
492    {
493       pr[ors - offset - 1] &= (static_cast<limb_type>(1u) << shift) - 1;
494       if(!pr[ors - offset - 1] && (rs > 1))
495          --rs;
496    }
497    result.resize(rs, rs);
498 }
499
500 template <class Int>
501 inline void right_shift_limb(Int& result, double_limb_type s)
502 {
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();
506    unsigned rs = ors;
507    if(offset >= rs)
508    {
509       result = limb_type(0);
510       return;
511    }
512    rs -= offset;
513    typename Int::limb_pointer pr = result.limbs();
514    unsigned i = 0;
515    for(; i < rs; ++i)
516       pr[i] = pr[i + offset];
517    result.resize(rs, rs);
518 }
519
520 template <class Int>
521 inline void right_shift_generic(Int& result, double_limb_type s)
522 {
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();
526    unsigned rs = ors;
527    if(offset >= rs)
528    {
529       result = limb_type(0);
530       return;
531    }
532    rs -= offset;
533    typename Int::limb_pointer pr = result.limbs();
534    if((pr[ors - 1] >> shift) == 0)
535    {
536       if(--rs == 0)
537       {
538          result = limb_type(0);
539          return;
540       }
541    }
542    unsigned i = 0;
543
544    // This code only works for non-zero shift, otherwise we invoke undefined behaviour!
545    BOOST_ASSERT(shift);
546    for(; i + offset + 1 < ors; ++i)
547    {
548       pr[i] = pr[i + offset] >> shift;
549       pr[i] |= pr[i + offset + 1] << (Int::limb_bits - shift);
550    }
551    pr[i] = pr[i + offset] >> shift;
552    result.resize(rs, rs);
553 }
554
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
557    eval_right_shift(
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))
560 {
561    is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>::checked_type());
562    if(!s)
563       return;
564
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);
576 #else
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);
580 #endif
581    else
582       right_shift_generic(result, s);
583 }
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
586    eval_right_shift(
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))
589 {
590    is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::checked_type());
591    if(!s)
592       return;
593
594    bool is_neg = result.sign();
595    if(is_neg)
596       eval_increment(result);
597
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);
609 #else
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);
613 #endif
614    else
615       right_shift_generic(result, s);
616    if(is_neg)
617       eval_decrement(result);
618 }
619
620 //
621 // Over again for trivial cpp_int's:
622 //
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))
626 {
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());
629    result.normalize();
630 }
631
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))
635 {
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);
641 }
642
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)
648          >::type
649    eval_complement(
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))
652 {
653    BOOST_STATIC_ASSERT_MSG(((Checked1 != checked) || (Checked2 != checked)), "Attempt to take the complement of a signed type results in undefined behavior.");
654    //
655    // If we're not checked then emulate 2's complement behavior:
656    //
657    if(o.sign())
658    {
659       *result.limbs() = *o.limbs() - 1;
660       result.sign(false);
661    }
662    else
663    {
664       *result.limbs() = 1 + *o.limbs();
665       result.sign(true);
666    }
667    result.normalize();
668 }
669
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
676          >::type
677    eval_complement(
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))
680 {
681    *result.limbs() = ~*o.limbs();
682    result.normalize();
683 }
684
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
691          >::type
692    eval_bitwise_and(
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))
695 {
696    *result.limbs() &= *o.limbs();
697 }
698
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)
704          >::type
705    eval_bitwise_and(
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))
708 {
709    is_valid_bitwise_op(result, o, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
710
711    using default_ops::eval_bit_test;
712    using default_ops::eval_increment;
713
714    if(result.sign() || o.sign())
715    {
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);
721       if(s)
722       {
723          eval_complement(t1, t1);
724          eval_increment(t1);
725       }
726       result = t1;
727       result.sign(s);
728    }
729    else
730    {
731       *result.limbs() &= *o.limbs();
732    }
733 }
734
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
741          >::type
742    eval_bitwise_or(
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))
745 {
746    *result.limbs() |= *o.limbs();
747 }
748
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)
754          >::type
755    eval_bitwise_or(
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))
758 {
759    is_valid_bitwise_op(result, o, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
760
761    using default_ops::eval_bit_test;
762    using default_ops::eval_increment;
763
764    if(result.sign() || o.sign())
765    {
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);
771       if(s)
772       {
773          eval_complement(t1, t1);
774          eval_increment(t1);
775       }
776       result = t1;
777       result.sign(s);
778    }
779    else
780    {
781       *result.limbs() |= *o.limbs();
782       result.normalize();
783    }
784 }
785
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
792          >::type
793    eval_bitwise_xor(
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))
796 {
797    *result.limbs() ^= *o.limbs();
798 }
799
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)
805          >::type
806    eval_bitwise_xor(
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))
809 {
810    is_valid_bitwise_op(result, o, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
811
812    using default_ops::eval_bit_test;
813    using default_ops::eval_increment;
814
815    if(result.sign() || o.sign())
816    {
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);
822       if(s)
823       {
824          eval_complement(t1, t1);
825          eval_increment(t1);
826       }
827       result = t1;
828       result.sign(s);
829    }
830    else
831    {
832       *result.limbs() ^= *o.limbs();
833    }
834 }
835
836 }}} // namespaces
837
838 #ifdef _MSC_VER
839 #pragma warning(pop)
840 #endif
841
842 #endif