]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/multiprecision/include/boost/multiprecision/cpp_int/bitwise.hpp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / libs / multiprecision / include / 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(; ors > 1 + i; ++i)
415 {
416 pr[rs - 1 - i] = pr[ors - 1 - i] << shift;
417 pr[rs - 1 - i] |= pr[ors - 2 - i] >> (Int::limb_bits - shift);
418 }
419 if(ors >= 1 + i)
420 {
421 pr[rs - 1 - i] = pr[ors - 1 - i] << 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