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 https://www.boost.org/LICENSE_1_0.txt
5//
6// Comparison operators for cpp_int_backend:
7//
8#ifndef BOOST_MP_CPP_INT_BITWISE_HPP
9#define BOOST_MP_CPP_INT_BITWISE_HPP
10
11#include <stdexcept>
12#include <type_traits>
13#include <boost/multiprecision/detail/endian.hpp>
14#include <boost/multiprecision/detail/no_exceptions_support.hpp>
15#include <boost/multiprecision/detail/assert.hpp>
16
17#ifdef BOOST_MSVC
18#pragma warning(push)
19#pragma warning(disable : 4319)
20#endif
21
22
23namespace boost { namespace multiprecision { namespace backends {
24
25template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
26BOOST_MP_CXX14_CONSTEXPR void is_valid_bitwise_op(
27 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
28 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o, const std::integral_constant<int, checked>&)
29{
30 if (result.sign() || o.sign())
31 BOOST_MP_THROW_EXCEPTION(std::range_error("Bitwise operations on negative values results in undefined behavior."));
32}
33
34template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
35BOOST_MP_CXX14_CONSTEXPR void is_valid_bitwise_op(
36 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&,
37 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>&, const std::integral_constant<int, unchecked>&) {}
38
39template <std::size_t MinBits1, std::size_t MaxBits1, cpp_int_check_type Checked1, class Allocator1>
40BOOST_MP_CXX14_CONSTEXPR void is_valid_bitwise_op(
41 const cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>& result, const std::integral_constant<int, checked>&)
42{
43 if (result.sign())
44 BOOST_MP_THROW_EXCEPTION(std::range_error("Bitwise operations on negative values results in undefined behavior."));
45}
46
47template <std::size_t MinBits1, std::size_t MaxBits1, cpp_int_check_type Checked1, class Allocator1>
48BOOST_MP_CXX14_CONSTEXPR void is_valid_bitwise_op(
49 const cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>&, const std::integral_constant<int, checked>&) {}
50
51template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
52BOOST_MP_CXX14_CONSTEXPR void is_valid_bitwise_op(
53 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&, const std::integral_constant<int, unchecked>&) {}
54
55template <class CppInt1, class CppInt2, class Op>
56BOOST_MP_CXX14_CONSTEXPR void bitwise_op(
57 CppInt1& result,
58 const CppInt2& o,
59 Op op, const std::integral_constant<bool, true>&) noexcept((is_non_throwing_cpp_int<CppInt1>::value))
60{
61 //
62 // There are 4 cases:
63 // * Both positive.
64 // * result negative, o positive.
65 // * o negative, result positive.
66 // * Both negative.
67 //
68 // When one arg is negative we convert to 2's complement form "on the fly",
69 // and then convert back to signed-magnitude form at the end.
70 //
71 // Note however, that if the type is checked, then bitwise ops on negative values
72 // are not permitted and an exception will result.
73 //
74 is_valid_bitwise_op(result, o, typename CppInt1::checked_type());
75 //
76 // First figure out how big the result needs to be and set up some data:
77 //
78 std::size_t rs = result.size();
79 std::size_t os = o.size();
80 std::size_t m(0), x(0);
81 minmax(a: rs, b: os, aa&: m, bb&: x);
82 result.resize(x, x);
83 typename CppInt1::limb_pointer pr = result.limbs();
84 typename CppInt2::const_limb_pointer po = o.limbs();
85 for (std::size_t i = rs; i < x; ++i)
86 pr[i] = 0;
87
88 limb_type next_limb = 0;
89
90 if (!result.sign())
91 {
92 if (!o.sign())
93 {
94 for (std::size_t i = 0; i < os; ++i)
95 pr[i] = op(pr[i], po[i]);
96 for (std::size_t i = os; i < x; ++i)
97 pr[i] = op(pr[i], limb_type(0));
98 }
99 else
100 {
101 // "o" is negative:
102 double_limb_type carry = 1;
103 for (std::size_t i = 0; i < os; ++i)
104 {
105 carry += static_cast<double_limb_type>(~po[i]);
106 pr[i] = op(pr[i], static_cast<limb_type>(carry));
107 carry >>= CppInt1::limb_bits;
108 }
109 for (std::size_t i = os; i < x; ++i)
110 {
111 carry += static_cast<double_limb_type>(~limb_type(0));
112 pr[i] = op(pr[i], static_cast<limb_type>(carry));
113 carry >>= CppInt1::limb_bits;
114 }
115 // Set the overflow into the "extra" limb:
116 carry += static_cast<double_limb_type>(~limb_type(0));
117 next_limb = op(limb_type(0), static_cast<limb_type>(carry));
118 }
119 }
120 else
121 {
122 if (!o.sign())
123 {
124 // "result" is negative:
125 double_limb_type carry = 1;
126 for (std::size_t i = 0; i < os; ++i)
127 {
128 carry += static_cast<double_limb_type>(~pr[i]);
129 pr[i] = op(static_cast<limb_type>(carry), po[i]);
130 carry >>= CppInt1::limb_bits;
131 }
132 for (std::size_t i = os; i < x; ++i)
133 {
134 carry += static_cast<double_limb_type>(~pr[i]);
135 pr[i] = op(static_cast<limb_type>(carry), limb_type(0));
136 carry >>= CppInt1::limb_bits;
137 }
138 // Set the overflow into the "extra" limb:
139 carry += static_cast<double_limb_type>(~limb_type(0));
140 next_limb = op(static_cast<limb_type>(carry), limb_type(0));
141 }
142 else
143 {
144 // both are negative:
145 double_limb_type r_carry = 1;
146 double_limb_type o_carry = 1;
147 for (std::size_t i = 0; i < os; ++i)
148 {
149 r_carry += static_cast<double_limb_type>(~pr[i]);
150 o_carry += static_cast<double_limb_type>(~po[i]);
151 pr[i] = op(static_cast<limb_type>(r_carry), static_cast<limb_type>(o_carry));
152 r_carry >>= CppInt1::limb_bits;
153 o_carry >>= CppInt1::limb_bits;
154 }
155 for (std::size_t i = os; i < x; ++i)
156 {
157 r_carry += static_cast<double_limb_type>(~pr[i]);
158 o_carry += static_cast<double_limb_type>(~limb_type(0));
159 pr[i] = op(static_cast<limb_type>(r_carry), static_cast<limb_type>(o_carry));
160 r_carry >>= CppInt1::limb_bits;
161 o_carry >>= CppInt1::limb_bits;
162 }
163 // Set the overflow into the "extra" limb:
164 r_carry += static_cast<double_limb_type>(~limb_type(0));
165 o_carry += static_cast<double_limb_type>(~limb_type(0));
166 next_limb = op(static_cast<limb_type>(r_carry), static_cast<limb_type>(o_carry));
167 }
168 }
169 //
170 // See if the result is negative or not:
171 //
172 if (static_cast<signed_limb_type>(next_limb) < 0)
173 {
174 double_limb_type carry = 1;
175 for (std::size_t i = 0; i < x; ++i)
176 {
177 carry += static_cast<double_limb_type>(~pr[i]);
178 pr[i] = static_cast<limb_type>(carry);
179 carry >>= CppInt1::limb_bits;
180 }
181 if (carry)
182 {
183 result.resize(x + 1, x);
184 if (result.size() > x)
185 result.limbs()[x] = static_cast<limb_type>(carry);
186 }
187 result.sign(true);
188 }
189 else
190 result.sign(false);
191
192 result.normalize();
193}
194
195template <class CppInt1, class CppInt2, class Op>
196BOOST_MP_CXX14_CONSTEXPR void bitwise_op(
197 CppInt1& result,
198 const CppInt2& o,
199 Op op, const std::integral_constant<bool, false>&) noexcept((is_non_throwing_cpp_int<CppInt1>::value))
200{
201 //
202 // Both arguments are unsigned types, very simple case handled as a special case.
203 //
204 // First figure out how big the result needs to be and set up some data:
205 //
206 std::size_t rs = result.size();
207 std::size_t os = o.size();
208 std::size_t m(0), x(0);
209 minmax(a: rs, b: os, aa&: m, bb&: x);
210 result.resize(x, x);
211 typename CppInt1::limb_pointer pr = result.limbs();
212 typename CppInt2::const_limb_pointer po = o.limbs();
213 for (std::size_t i = rs; i < x; ++i)
214 pr[i] = 0;
215
216 for (std::size_t i = 0; i < os; ++i)
217 pr[i] = op(pr[i], po[i]);
218 for (std::size_t i = os; i < x; ++i)
219 pr[i] = op(pr[i], limb_type(0));
220
221 result.normalize();
222}
223
224struct bit_and
225{
226 BOOST_MP_CXX14_CONSTEXPR limb_type operator()(limb_type a, limb_type b) const noexcept { return a & b; }
227};
228struct bit_or
229{
230 BOOST_MP_CXX14_CONSTEXPR limb_type operator()(limb_type a, limb_type b) const noexcept { return a | b; }
231};
232struct bit_xor
233{
234 BOOST_MP_CXX14_CONSTEXPR limb_type operator()(limb_type a, limb_type b) const noexcept { return a ^ b; }
235};
236
237template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
238BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value>::type
239eval_bitwise_and(
240 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
241 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
242{
243 bitwise_op(result, o, bit_and(),
244 std::integral_constant<bool, std::numeric_limits<number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> > >::is_signed || std::numeric_limits<number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> > >::is_signed > ());
245}
246
247template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
248BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value>::type
249eval_bitwise_or(
250 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
251 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
252{
253 bitwise_op(result, o, bit_or(),
254 std::integral_constant<bool, std::numeric_limits<number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> > >::is_signed || std::numeric_limits<number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> > >::is_signed > ());
255}
256
257template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
258BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value>::type
259eval_bitwise_xor(
260 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
261 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
262{
263 bitwise_op(result, o, bit_xor(),
264 std::integral_constant<bool, std::numeric_limits<number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> > >::is_signed || std::numeric_limits<number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> > >::is_signed > ());
265}
266//
267// Again for operands which are single limbs:
268//
269template <std::size_t MinBits1, std::size_t MaxBits1, cpp_int_check_type Checked1, class Allocator1>
270BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1> >::value>::type
271eval_bitwise_and(
272 cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>& result,
273 limb_type l) noexcept
274{
275 result.limbs()[0] &= l;
276 result.resize(1, 1);
277}
278
279template <std::size_t MinBits1, std::size_t MaxBits1, cpp_int_check_type Checked1, class Allocator1>
280BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1> >::value>::type
281eval_bitwise_or(
282 cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>& result,
283 limb_type l) noexcept
284{
285 result.limbs()[0] |= l;
286}
287
288template <std::size_t MinBits1, std::size_t MaxBits1, cpp_int_check_type Checked1, class Allocator1>
289BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1> >::value>::type
290eval_bitwise_xor(
291 cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>& result,
292 limb_type l) noexcept
293{
294 result.limbs()[0] ^= l;
295}
296
297template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
298BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value>::type
299eval_complement(
300 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
301 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
302{
303 static_assert(((Checked1 != checked) || (Checked2 != checked)), "Attempt to take the complement of a signed type results in undefined behavior.");
304 // Increment and negate:
305 result = o;
306 eval_increment(result);
307 result.negate();
308}
309
310template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
311BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
312eval_complement(
313 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
314 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& o) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
315{
316 std::size_t os = o.size();
317 result.resize(SIZE_MAX, os);
318 for (std::size_t i = 0; i < os; ++i)
319 result.limbs()[i] = ~o.limbs()[i];
320 for (std::size_t i = os; i < result.size(); ++i)
321 result.limbs()[i] = ~static_cast<limb_type>(0);
322 result.normalize();
323}
324
325template <class Int>
326inline void left_shift_byte(Int& result, double_limb_type s)
327{
328 limb_type offset = static_cast<limb_type>(s / Int::limb_bits);
329 limb_type shift = static_cast<limb_type>(s % Int::limb_bits);
330 std::size_t ors = result.size();
331 if ((ors == 1) && (!*result.limbs()))
332 return; // shifting zero yields zero.
333 std::size_t rs = ors;
334 if (shift && (result.limbs()[ors - 1] >> (Int::limb_bits - shift)))
335 ++rs; // Most significant limb will overflow when shifted
336 rs += offset;
337 result.resize(rs, rs);
338 rs = result.size();
339
340 typename Int::limb_pointer pr = result.limbs();
341
342 if (rs != ors)
343 pr[rs - 1] = 0u;
344 std::size_t bytes = static_cast<std::size_t>(s / CHAR_BIT);
345 std::size_t len = (std::min)(a: ors * sizeof(limb_type), b: rs * sizeof(limb_type) - bytes);
346 if (bytes >= rs * sizeof(limb_type))
347 result = static_cast<limb_type>(0u);
348 else
349 {
350 unsigned char* pc = reinterpret_cast<unsigned char*>(pr);
351 std::memmove(dest: pc + bytes, src: pc, n: len);
352 std::memset(s: pc, c: 0, n: bytes);
353 }
354}
355
356template <class Int>
357inline BOOST_MP_CXX14_CONSTEXPR void left_shift_limb(Int& result, double_limb_type s)
358{
359 limb_type offset = static_cast<limb_type>(s / Int::limb_bits);
360 limb_type shift = static_cast<limb_type>(s % Int::limb_bits);
361
362 std::size_t ors = result.size();
363 if ((ors == 1) && (!*result.limbs()))
364 return; // shifting zero yields zero.
365 std::size_t rs = ors;
366 if (shift && (result.limbs()[ors - 1] >> (Int::limb_bits - shift)))
367 ++rs; // Most significant limb will overflow when shifted
368 rs += offset;
369 result.resize(rs, rs);
370
371 typename Int::limb_pointer pr = result.limbs();
372
373 if (offset > rs)
374 {
375 // The result is shifted past the end of the result:
376 result = static_cast<limb_type>(0);
377 return;
378 }
379
380 std::size_t i = rs - result.size();
381 for (; i < ors; ++i)
382 pr[rs - 1 - i] = pr[ors - 1 - i];
383#ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
384 if (BOOST_MP_IS_CONST_EVALUATED(s))
385 {
386 for (; i < rs; ++i)
387 pr[rs - 1 - i] = 0;
388 }
389 else
390#endif
391 {
392 std::memset(s: pr, c: 0, n: (rs - i) * sizeof(*pr));
393 }
394}
395
396template <class Int>
397inline BOOST_MP_CXX14_CONSTEXPR void left_shift_generic(Int& result, double_limb_type s)
398{
399 limb_type offset = static_cast<limb_type>(s / Int::limb_bits);
400 limb_type shift = static_cast<limb_type>(s % Int::limb_bits);
401
402 std::size_t ors = result.size();
403 if ((ors == 1) && (!*result.limbs()))
404 return; // shifting zero yields zero.
405 std::size_t rs = ors;
406 if (shift && (result.limbs()[ors - 1] >> (Int::limb_bits - shift)))
407 ++rs; // Most significant limb will overflow when shifted
408 rs += offset;
409 result.resize(rs, rs);
410 bool truncated = result.size() != rs;
411
412 typename Int::limb_pointer pr = result.limbs();
413
414 if (offset > rs)
415 {
416 // The result is shifted past the end of the result:
417 result = static_cast<limb_type>(0);
418 return;
419 }
420
421 std::size_t i = rs - result.size();
422 // This code only works when shift is non-zero, otherwise we invoke undefined behaviour!
423 BOOST_MP_ASSERT(shift);
424 if (!truncated)
425 {
426 if (rs > ors + offset)
427 {
428 pr[rs - 1 - i] = pr[ors - 1 - i] >> (Int::limb_bits - shift);
429 --rs;
430 }
431 else
432 {
433 pr[rs - 1 - i] = pr[ors - 1 - i] << shift;
434 if (ors > 1)
435 pr[rs - 1 - i] |= pr[ors - 2 - i] >> (Int::limb_bits - shift);
436 ++i;
437 }
438 }
439 for (; rs - i >= static_cast<std::size_t>(static_cast<std::size_t>(2u) + offset); ++i)
440 {
441 pr[rs - 1 - i] = pr[rs - 1 - i - offset] << shift;
442 pr[rs - 1 - i] |= pr[rs - 2 - i - offset] >> (Int::limb_bits - shift);
443 }
444 if (rs - i >= static_cast<std::size_t>(static_cast<std::size_t>(1u) + offset))
445 {
446 pr[rs - 1 - i] = pr[rs - 1 - i - offset] << shift;
447 ++i;
448 }
449#ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
450 if (BOOST_MP_IS_CONST_EVALUATED(s))
451 {
452 for (; i < rs; ++i)
453 pr[rs - 1 - i] = 0;
454 }
455 else
456#endif
457 {
458 std::memset(s: pr, c: 0, n: (rs - i) * sizeof(*pr));
459 }
460}
461
462template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
463inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
464eval_left_shift(
465 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
466 double_limb_type s) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
467{
468 is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
469 if (!s)
470 return;
471
472#if BOOST_MP_ENDIAN_LITTLE_BYTE && defined(BOOST_MP_USE_LIMB_SHIFT)
473 constexpr limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits - 1;
474 constexpr limb_type byte_shift_mask = CHAR_BIT - 1;
475
476 if ((s & limb_shift_mask) == 0)
477 {
478 left_shift_limb(result, s);
479 }
480#ifdef BOOST_MP_NO_CONSTEXPR_DETECTION
481 else if ((s & byte_shift_mask) == 0)
482#else
483 else if (((s & byte_shift_mask) == 0) && !BOOST_MP_IS_CONST_EVALUATED(s))
484#endif
485 {
486 left_shift_byte(result, s);
487 }
488#elif BOOST_MP_ENDIAN_LITTLE_BYTE
489 constexpr limb_type byte_shift_mask = CHAR_BIT - 1;
490
491#ifdef BOOST_MP_NO_CONSTEXPR_DETECTION
492 if ((s & byte_shift_mask) == 0)
493#else
494 constexpr limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits - 1;
495 if (BOOST_MP_IS_CONST_EVALUATED(s) && ((s & limb_shift_mask) == 0))
496 left_shift_limb(result, s);
497 else if (((s & byte_shift_mask) == 0) && !BOOST_MP_IS_CONST_EVALUATED(s))
498#endif
499 {
500 left_shift_byte(result, s);
501 }
502#else
503 constexpr limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits - 1;
504
505 if ((s & limb_shift_mask) == 0)
506 {
507 left_shift_limb(result, s);
508 }
509#endif
510 else
511 {
512 left_shift_generic(result, s);
513 }
514 //
515 // We may have shifted off the end and have leading zeros:
516 //
517 result.normalize();
518}
519
520template <class Int>
521inline void right_shift_byte(Int& result, double_limb_type s)
522{
523 limb_type offset = static_cast<limb_type>(s / Int::limb_bits);
524 BOOST_MP_ASSERT((s % CHAR_BIT) == 0);
525 std::size_t ors = result.size();
526 std::size_t 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 unsigned char* pc = reinterpret_cast<unsigned char*>(pr);
535 limb_type shift = static_cast<limb_type>(s / CHAR_BIT);
536 std::memmove(dest: pc, src: pc + shift, n: ors * sizeof(pr[0]) - shift);
537 shift = (sizeof(limb_type) - shift % sizeof(limb_type)) * CHAR_BIT;
538 if (shift < Int::limb_bits)
539 {
540 pr[ors - offset - 1] &= (static_cast<limb_type>(1u) << shift) - 1;
541 if (!pr[ors - offset - 1] && (rs > 1))
542 --rs;
543 }
544 result.resize(rs, rs);
545}
546
547template <class Int>
548inline BOOST_MP_CXX14_CONSTEXPR void right_shift_limb(Int& result, double_limb_type s)
549{
550 limb_type offset = static_cast<limb_type>(s / Int::limb_bits);
551 BOOST_MP_ASSERT((s % Int::limb_bits) == 0);
552 std::size_t ors = result.size();
553 std::size_t rs = ors;
554 if (offset >= rs)
555 {
556 result = limb_type(0);
557 return;
558 }
559 rs -= offset;
560 typename Int::limb_pointer pr = result.limbs();
561 std::size_t i = 0;
562 for (; i < rs; ++i)
563 pr[i] = pr[i + offset];
564 result.resize(rs, rs);
565}
566
567template <class Int>
568inline BOOST_MP_CXX14_CONSTEXPR void right_shift_generic(Int& result, double_limb_type s)
569{
570 limb_type offset = static_cast<limb_type>(s / Int::limb_bits);
571 limb_type shift = static_cast<limb_type>(s % Int::limb_bits);
572 std::size_t ors = result.size();
573 std::size_t rs = ors;
574 if (offset >= rs)
575 {
576 result = limb_type(0);
577 return;
578 }
579 rs -= offset;
580 typename Int::limb_pointer pr = result.limbs();
581 if ((pr[ors - 1] >> shift) == 0)
582 {
583 if (--rs == 0)
584 {
585 result = limb_type(0);
586 return;
587 }
588 }
589 std::size_t i = 0;
590
591 // This code only works for non-zero shift, otherwise we invoke undefined behaviour!
592 BOOST_MP_ASSERT(shift);
593 for (; i + offset + 1 < ors; ++i)
594 {
595 pr[i] = pr[i + offset] >> shift;
596 pr[i] |= pr[i + offset + 1] << (Int::limb_bits - shift);
597 }
598 pr[i] = pr[i + offset] >> shift;
599 result.resize(rs, rs);
600}
601
602template <std::size_t MinBits1, std::size_t MaxBits1, cpp_int_check_type Checked1, class Allocator1>
603inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1> >::value>::type
604eval_right_shift(
605 cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>& result,
606 double_limb_type s) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1> >::value))
607{
608 is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, unsigned_magnitude, Checked1, Allocator1>::checked_type());
609 if (!s)
610 return;
611
612#if BOOST_MP_ENDIAN_LITTLE_BYTE && defined(BOOST_MP_USE_LIMB_SHIFT)
613 constexpr limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::limb_bits - 1;
614 constexpr limb_type byte_shift_mask = CHAR_BIT - 1;
615
616 if ((s & limb_shift_mask) == 0)
617 right_shift_limb(result, s);
618#ifdef BOOST_MP_NO_CONSTEXPR_DETECTION
619 else if ((s & byte_shift_mask) == 0)
620#else
621 else if (((s & byte_shift_mask) == 0) && !BOOST_MP_IS_CONST_EVALUATED(s))
622#endif
623 right_shift_byte(result, s);
624#elif BOOST_MP_ENDIAN_LITTLE_BYTE
625 constexpr limb_type byte_shift_mask = CHAR_BIT - 1;
626
627#ifdef BOOST_MP_NO_CONSTEXPR_DETECTION
628 if ((s & byte_shift_mask) == 0)
629#else
630 constexpr limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::limb_bits - 1;
631 if (BOOST_MP_IS_CONST_EVALUATED(s) && ((s & limb_shift_mask) == 0))
632 right_shift_limb(result, s);
633 else if (((s & byte_shift_mask) == 0) && !BOOST_MP_IS_CONST_EVALUATED(s))
634#endif
635 right_shift_byte(result, s);
636#else
637 constexpr limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::limb_bits - 1;
638
639 if ((s & limb_shift_mask) == 0)
640 right_shift_limb(result, s);
641#endif
642 else
643 right_shift_generic(result, s);
644}
645template <std::size_t MinBits1, std::size_t MaxBits1, cpp_int_check_type Checked1, class Allocator1>
646inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1> >::value>::type
647eval_right_shift(
648 cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>& result,
649 double_limb_type s) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1> >::value))
650{
651 is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::checked_type());
652 if (!s)
653 return;
654
655 bool is_neg = result.sign();
656 if (is_neg)
657 eval_increment(result);
658
659#if BOOST_MP_ENDIAN_LITTLE_BYTE && defined(BOOST_MP_USE_LIMB_SHIFT)
660 constexpr limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::limb_bits - 1;
661 constexpr limb_type byte_shift_mask = CHAR_BIT - 1;
662
663 if ((s & limb_shift_mask) == 0)
664 right_shift_limb(result, s);
665#ifdef BOOST_MP_NO_CONSTEXPR_DETECTION
666 else if ((s & byte_shift_mask) == 0)
667#else
668 else if (((s & byte_shift_mask) == 0) && !BOOST_MP_IS_CONST_EVALUATED(s))
669#endif
670 right_shift_byte(result, s);
671#elif BOOST_MP_ENDIAN_LITTLE_BYTE
672 constexpr limb_type byte_shift_mask = CHAR_BIT - 1;
673
674#ifdef BOOST_MP_NO_CONSTEXPR_DETECTION
675 if ((s & byte_shift_mask) == 0)
676#else
677 constexpr limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::limb_bits - 1;
678 if (BOOST_MP_IS_CONST_EVALUATED(s) && ((s & limb_shift_mask) == 0))
679 right_shift_limb(result, s);
680 else if (((s & byte_shift_mask) == 0) && !BOOST_MP_IS_CONST_EVALUATED(s))
681#endif
682 right_shift_byte(result, s);
683#else
684 constexpr limb_type limb_shift_mask = cpp_int_backend<MinBits1, MaxBits1, signed_magnitude, Checked1, Allocator1>::limb_bits - 1;
685
686 if ((s & limb_shift_mask) == 0)
687 right_shift_limb(result, s);
688#endif
689 else
690 right_shift_generic(result, s);
691 if (is_neg)
692 eval_decrement(result);
693}
694
695//
696// Over again for trivial cpp_int's:
697//
698template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class T>
699BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value >::type
700eval_left_shift(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, T s) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
701{
702 is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
703 *result.limbs() = detail::checked_left_shift(*result.limbs(), s, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
704 result.normalize();
705}
706
707template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class T>
708BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value >::type
709eval_right_shift(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, T s) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
710{
711 // Nothing to check here... just make sure we don't invoke undefined behavior:
712 is_valid_bitwise_op(result, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
713 *result.limbs() = (static_cast<unsigned>(s) >= sizeof(*result.limbs()) * CHAR_BIT) ? 0 : (result.sign() ? ((--*result.limbs()) >> s) + 1 : *result.limbs() >> s);
714 if (result.sign() && (*result.limbs() == 0))
715 result = static_cast<signed_limb_type>(-1);
716}
717
718template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
719inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
720 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value && (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || is_signed_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value)>::type
721eval_complement(
722 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
723 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
724{
725 static_assert(((Checked1 != checked) || (Checked2 != checked)), "Attempt to take the complement of a signed type results in undefined behavior.");
726 //
727 // If we're not checked then emulate 2's complement behavior:
728 //
729 if (o.sign())
730 {
731 *result.limbs() = *o.limbs() - 1;
732 result.sign(false);
733 }
734 else
735 {
736 *result.limbs() = 1 + *o.limbs();
737 result.sign(true);
738 }
739 result.normalize();
740}
741
742template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
743inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
744 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value && is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && is_unsigned_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value>::type
745eval_complement(
746 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
747 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
748{
749 *result.limbs() = ~*o.limbs();
750 result.normalize();
751}
752
753template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
754inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
755 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value && is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && is_unsigned_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value>::type
756eval_bitwise_and(
757 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
758 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
759{
760 *result.limbs() &= *o.limbs();
761}
762
763template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
764inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
765 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value && (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || is_signed_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value)>::type
766eval_bitwise_and(
767 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
768 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
769{
770 is_valid_bitwise_op(result, o, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
771
772 using default_ops::eval_bit_test;
773 using default_ops::eval_increment;
774
775 if (result.sign() || o.sign())
776 {
777 constexpr std::size_t m = detail::static_unsigned_max<detail::static_unsigned_max<MinBits1, MinBits2>::value, detail::static_unsigned_max<MaxBits1, MaxBits2>::value>::value;
778 cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t1(result);
779 cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t2(o);
780 eval_bitwise_and(t1, t2);
781 bool s = eval_bit_test(t1, m + 1);
782 if (s)
783 {
784 eval_complement(t1, t1);
785 eval_increment(t1);
786 }
787 result = t1;
788 result.sign(s);
789 }
790 else
791 {
792 *result.limbs() &= *o.limbs();
793 }
794}
795
796template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
797inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
798 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value && is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && is_unsigned_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value>::type
799eval_bitwise_or(
800 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
801 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
802{
803 *result.limbs() |= *o.limbs();
804}
805
806template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
807inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
808 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value && (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || is_signed_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value)>::type
809eval_bitwise_or(
810 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
811 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
812{
813 is_valid_bitwise_op(result, o, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
814
815 using default_ops::eval_bit_test;
816 using default_ops::eval_increment;
817
818 if (result.sign() || o.sign())
819 {
820 constexpr std::size_t m = detail::static_unsigned_max<detail::static_unsigned_max<MinBits1, MinBits2>::value, detail::static_unsigned_max<MaxBits1, MaxBits2>::value>::value;
821 cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t1(result);
822 cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t2(o);
823 eval_bitwise_or(t1, t2);
824 bool s = eval_bit_test(t1, m + 1);
825 if (s)
826 {
827 eval_complement(t1, t1);
828 eval_increment(t1);
829 }
830 result = t1;
831 result.sign(s);
832 }
833 else
834 {
835 *result.limbs() |= *o.limbs();
836 result.normalize();
837 }
838}
839
840template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
841inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
842 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value && is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && is_unsigned_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value>::type
843eval_bitwise_xor(
844 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
845 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
846{
847 *result.limbs() ^= *o.limbs();
848}
849
850template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
851inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
852 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value && (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || is_signed_number<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value)>::type
853eval_bitwise_xor(
854 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
855 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) noexcept((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
856{
857 is_valid_bitwise_op(result, o, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
858
859 using default_ops::eval_bit_test;
860 using default_ops::eval_increment;
861
862 if (result.sign() || o.sign())
863 {
864 constexpr std::size_t m = detail::static_unsigned_max<detail::static_unsigned_max<MinBits1, MinBits2>::value, detail::static_unsigned_max<MaxBits1, MaxBits2>::value>::value;
865 cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t1(result);
866 cpp_int_backend<m + 1, m + 1, unsigned_magnitude, unchecked, void> t2(o);
867 eval_bitwise_xor(t1, t2);
868 bool s = eval_bit_test(t1, m + 1);
869 if (s)
870 {
871 eval_complement(t1, t1);
872 eval_increment(t1);
873 }
874 result = t1;
875 result.sign(s);
876 }
877 else
878 {
879 *result.limbs() ^= *o.limbs();
880 }
881}
882
883}}} // namespace boost::multiprecision::backends
884
885#ifdef BOOST_MSVC
886#pragma warning(pop)
887#endif
888
889#endif
890

source code of boost/libs/multiprecision/include/boost/multiprecision/cpp_int/bitwise.hpp