]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 |