]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/multiprecision/number.hpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / boost / multiprecision / number.hpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright 2011 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_0.txt)
5
6 #ifndef BOOST_MATH_EXTENDED_REAL_HPP
7 #define BOOST_MATH_EXTENDED_REAL_HPP
8
9 #include <boost/cstdint.hpp>
10 #include <boost/mpl/max.hpp>
11 #include <boost/mpl/plus.hpp>
12 #include <boost/mpl/or.hpp>
13 #include <boost/mpl/find_if.hpp>
14 #include <boost/assert.hpp>
15 #include <boost/type_traits/remove_pointer.hpp>
16 #include <boost/type_traits/is_signed.hpp>
17 #include <boost/type_traits/is_unsigned.hpp>
18 #include <boost/type_traits/is_floating_point.hpp>
19 #include <boost/type_traits/is_integral.hpp>
20 #include <boost/type_traits/make_unsigned.hpp>
21 #include <boost/throw_exception.hpp>
22 #include <boost/multiprecision/detail/generic_interconvert.hpp>
23 #include <boost/multiprecision/detail/number_compare.hpp>
24 #include <boost/multiprecision/traits/is_restricted_conversion.hpp>
25 #include <istream> // stream operators
26 #include <cstdio> // EOF
27 #include <cctype> // isspace
28
29 namespace boost{ namespace multiprecision{
30
31 #ifdef BOOST_MSVC
32 // warning C4127: conditional expression is constant
33 // warning C4714: function marked as __forceinline not inlined
34 #pragma warning(push)
35 #pragma warning(disable:4127 4714 6326)
36 #endif
37
38 template <class Backend, expression_template_option ExpressionTemplates>
39 class number
40 {
41 typedef number<Backend, ExpressionTemplates> self_type;
42 public:
43 typedef Backend backend_type;
44 BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number() BOOST_MP_NOEXCEPT_IF(noexcept(Backend())) {}
45 BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number(const number& e) BOOST_MP_NOEXCEPT_IF(noexcept(Backend(std::declval<Backend const&>()))) : m_backend(e.m_backend){}
46 template <class V>
47 BOOST_MP_FORCEINLINE number(const V& v, typename boost::enable_if_c<
48 (boost::is_arithmetic<V>::value || is_same<std::string, V>::value || is_convertible<V, const char*>::value)
49 && !is_convertible<typename detail::canonical<V, Backend>::type, Backend>::value
50 && !detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value
51 #ifdef BOOST_HAS_FLOAT128
52 && !boost::is_same<V, __float128>::value
53 #endif
54 >::type* = 0)
55 {
56 m_backend = canonical_value(v);
57 }
58 template <class V>
59 BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number(const V& v, typename boost::enable_if_c<
60 is_convertible<typename detail::canonical<V, Backend>::type, Backend>::value
61 && !detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value
62 >::type* = 0)
63 #ifndef BOOST_INTEL
64 BOOST_MP_NOEXCEPT_IF(noexcept(Backend(std::declval<typename detail::canonical<V, Backend>::type const&>())))
65 #endif
66 : m_backend(canonical_value(v)) {}
67 BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number(const number& e, unsigned digits10)
68 BOOST_MP_NOEXCEPT_IF(noexcept(Backend(std::declval<Backend const&>(), std::declval<unsigned>())))
69 : m_backend(e.m_backend, digits10){}
70 template <class V>
71 explicit BOOST_MP_FORCEINLINE number(const V& v, typename boost::enable_if_c<
72 (boost::is_arithmetic<V>::value || is_same<std::string, V>::value || is_convertible<V, const char*>::value)
73 && !detail::is_explicitly_convertible<typename detail::canonical<V, Backend>::type, Backend>::value
74 && detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value
75 >::type* = 0)
76 BOOST_MP_NOEXCEPT_IF(noexcept(std::declval<Backend&>() = std::declval<typename detail::canonical<V, Backend>::type const&>()))
77 {
78 m_backend = canonical_value(v);
79 }
80 template <class V>
81 explicit BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number(const V& v, typename boost::enable_if_c<
82 detail::is_explicitly_convertible<typename detail::canonical<V, Backend>::type, Backend>::value
83 && (detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value
84 || !is_convertible<typename detail::canonical<V, Backend>::type, Backend>::value)
85 >::type* = 0)
86 BOOST_MP_NOEXCEPT_IF(noexcept(Backend(std::declval<typename detail::canonical<V, Backend>::type const&>())))
87 : m_backend(canonical_value(v)) {}
88 /*
89 //
90 // This conflicts with component based initialization (for rational and complex types)
91 // which is arguably more useful. Disabled for now.
92 //
93 template <class V>
94 number(V v, unsigned digits10, typename boost::enable_if<mpl::or_<boost::is_arithmetic<V>, is_same<std::string, V>, is_convertible<V, const char*> > >::type* dummy1 = 0)
95 {
96 m_backend.precision(digits10);
97 m_backend = canonical_value(v);
98 }
99 */
100 template<expression_template_option ET>
101 BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number(const number<Backend, ET>& val)
102 BOOST_MP_NOEXCEPT_IF(noexcept(Backend(std::declval<Backend const&>()))) : m_backend(val.backend()) {}
103
104 template <class Other, expression_template_option ET>
105 BOOST_MP_FORCEINLINE number(const number<Other, ET>& val,
106 typename boost::enable_if_c<(boost::is_convertible<Other, Backend>::value && !detail::is_restricted_conversion<Other, Backend>::value)>::type* = 0)
107 BOOST_MP_NOEXCEPT_IF(noexcept(Backend(std::declval<Other const&>())))
108 : m_backend(val.backend()) {}
109
110 template <class Other, expression_template_option ET>
111 explicit number(const number<Other, ET>& val, typename boost::enable_if_c<
112 (!detail::is_explicitly_convertible<Other, Backend>::value)
113 >::type* = 0)
114 {
115 //
116 // Attempt a generic interconvertion:
117 //
118 using detail::generic_interconvert;
119 generic_interconvert(backend(), val.backend(), number_category<Backend>(), number_category<Other>());
120 }
121 template <class Other, expression_template_option ET>
122 explicit BOOST_MP_FORCEINLINE number(const number<Other, ET>& val, typename boost::enable_if_c<
123 (detail::is_explicitly_convertible<Other, Backend>::value
124 && (detail::is_restricted_conversion<Other, Backend>::value || !boost::is_convertible<Other, Backend>::value))
125 >::type* = 0) BOOST_MP_NOEXCEPT_IF(noexcept(Backend(std::declval<Other const&>())))
126 : m_backend(val.backend()) {}
127
128 template <class V>
129 BOOST_MP_FORCEINLINE number(V v1, V v2, typename boost::enable_if<mpl::or_<boost::is_arithmetic<V>, is_same<std::string, V>, is_convertible<V, const char*> > >::type* = 0)
130 {
131 using default_ops::assign_components;
132 assign_components(m_backend, canonical_value(v1), canonical_value(v2));
133 }
134 template <class Other, expression_template_option ET>
135 BOOST_MP_FORCEINLINE number(const number<Other, ET>& v1, const number<Other, ET>& v2, typename boost::enable_if<boost::is_convertible<Other, Backend> >::type* = 0)
136 {
137 using default_ops::assign_components;
138 assign_components(m_backend, v1.backend(), v2.backend());
139 }
140
141 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
142 typename boost::enable_if<is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>, number&>::type operator=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
143 {
144 typedef typename is_same<number, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::type tag_type;
145 do_assign(e, tag_type());
146 return *this;
147 }
148 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
149 number& assign(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
150 {
151 typedef typename is_same<number, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::type tag_type;
152 do_assign(e, tag_type());
153 return *this;
154 }
155
156 BOOST_MP_FORCEINLINE number& operator=(const number& e)
157 BOOST_MP_NOEXCEPT_IF(noexcept(std::declval<Backend&>() = std::declval<Backend const&>()))
158 {
159 m_backend = e.m_backend;
160 return *this;
161 }
162
163 template <class V>
164 BOOST_MP_FORCEINLINE typename boost::enable_if<is_convertible<V, self_type>, number<Backend, ExpressionTemplates>& >::type
165 operator=(const V& v)
166 BOOST_MP_NOEXCEPT_IF(noexcept(std::declval<Backend&>() = std::declval<const typename detail::canonical<V, Backend>::type&>()))
167 {
168 m_backend = canonical_value(v);
169 return *this;
170 }
171 template <class V>
172 BOOST_MP_FORCEINLINE number<Backend, ExpressionTemplates>& assign(const V& v)
173 BOOST_MP_NOEXCEPT_IF(noexcept(std::declval<Backend&>() = std::declval<const typename detail::canonical<V, Backend>::type&>()))
174 {
175 m_backend = canonical_value(v);
176 return *this;
177 }
178 template <class Other, expression_template_option ET>
179 typename boost::disable_if<boost::multiprecision::detail::is_explicitly_convertible<Other, Backend>, number<Backend, ExpressionTemplates>& >::type
180 assign(const number<Other, ET>& v)
181 {
182 //
183 // Attempt a generic interconvertion:
184 //
185 using detail::generic_interconvert;
186 generic_interconvert(backend(), v.backend(), number_category<Backend>(), number_category<Other>());
187 return *this;
188 }
189
190 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
191 number(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e, typename boost::enable_if_c<is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value>::type* = 0)
192 {
193 *this = e;
194 }
195 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
196 explicit number(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e,
197 typename boost::enable_if_c<!is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value
198 && boost::multiprecision::detail::is_explicitly_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value>::type* = 0)
199 {
200 assign(e);
201 }
202
203 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
204 BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number(number&& r)
205 BOOST_MP_NOEXCEPT_IF(noexcept(Backend(std::declval<Backend>())))
206 : m_backend(static_cast<Backend&&>(r.m_backend)){}
207 BOOST_MP_FORCEINLINE number& operator=(number&& r) BOOST_MP_NOEXCEPT_IF(noexcept(std::declval<Backend&>() = std::declval<Backend>()))
208 {
209 m_backend = static_cast<Backend&&>(r.m_backend);
210 return *this;
211 }
212 #endif
213
214 number& operator+=(const self_type& val)
215 {
216 do_add(detail::expression<detail::terminal, self_type>(val), detail::terminal());
217 return *this;
218 }
219
220 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
221 typename boost::enable_if<is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>, number&>::type operator+=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
222 {
223 // Create a copy if e contains this, but not if we're just doing a
224 // x += x
225 if(contains_self(e) && !is_self(e))
226 {
227 self_type temp(e);
228 do_add(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
229 }
230 else
231 {
232 do_add(e, tag());
233 }
234 return *this;
235 }
236
237 template <class Arg1, class Arg2, class Arg3, class Arg4>
238 number& operator+=(const detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>& e)
239 {
240 //
241 // Fused multiply-add:
242 //
243 using default_ops::eval_multiply_add;
244 eval_multiply_add(m_backend, canonical_value(e.left_ref()), canonical_value(e.right_ref()));
245 return *this;
246 }
247
248 template <class V>
249 typename boost::enable_if<boost::is_convertible<V, self_type>, number<Backend, ExpressionTemplates>& >::type
250 operator+=(const V& v)
251 {
252 using default_ops::eval_add;
253 eval_add(m_backend, canonical_value(v));
254 return *this;
255 }
256
257 number& operator-=(const self_type& val)
258 {
259 do_subtract(detail::expression<detail::terminal, self_type>(val), detail::terminal());
260 return *this;
261 }
262
263 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
264 typename boost::enable_if<is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>, number&>::type operator-=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
265 {
266 // Create a copy if e contains this:
267 if(contains_self(e))
268 {
269 self_type temp(e);
270 do_subtract(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
271 }
272 else
273 {
274 do_subtract(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
275 }
276 return *this;
277 }
278
279 template <class V>
280 typename boost::enable_if<boost::is_convertible<V, self_type>, number<Backend, ExpressionTemplates>& >::type
281 operator-=(const V& v)
282 {
283 using default_ops::eval_subtract;
284 eval_subtract(m_backend, canonical_value(v));
285 return *this;
286 }
287
288 template <class Arg1, class Arg2, class Arg3, class Arg4>
289 number& operator-=(const detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>& e)
290 {
291 //
292 // Fused multiply-subtract:
293 //
294 using default_ops::eval_multiply_subtract;
295 eval_multiply_subtract(m_backend, canonical_value(e.left_ref()), canonical_value(e.right_ref()));
296 return *this;
297 }
298
299
300 number& operator *= (const self_type& e)
301 {
302 do_multiplies(detail::expression<detail::terminal, self_type>(e), detail::terminal());
303 return *this;
304 }
305
306 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
307 typename boost::enable_if<is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>, number&>::type operator*=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
308 {
309 // Create a temporary if the RHS references *this, but not
310 // if we're just doing an x *= x;
311 if(contains_self(e) && !is_self(e))
312 {
313 self_type temp(e);
314 do_multiplies(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
315 }
316 else
317 {
318 do_multiplies(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
319 }
320 return *this;
321 }
322
323 template <class V>
324 typename boost::enable_if<boost::is_convertible<V, self_type>, number<Backend, ExpressionTemplates>& >::type
325 operator*=(const V& v)
326 {
327 using default_ops::eval_multiply;
328 eval_multiply(m_backend, canonical_value(v));
329 return *this;
330 }
331
332 number& operator%=(const self_type& e)
333 {
334 BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
335 do_modulus(detail::expression<detail::terminal, self_type>(e), detail::terminal());
336 return *this;
337 }
338 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
339 typename boost::enable_if<is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>, number&>::type operator%=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
340 {
341 BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
342 // Create a temporary if the RHS references *this:
343 if(contains_self(e))
344 {
345 self_type temp(e);
346 do_modulus(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
347 }
348 else
349 {
350 do_modulus(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
351 }
352 return *this;
353 }
354 template <class V>
355 typename boost::enable_if<boost::is_convertible<V, self_type>, number<Backend, ExpressionTemplates>& >::type
356 operator%=(const V& v)
357 {
358 BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
359 using default_ops::eval_modulus;
360 eval_modulus(m_backend, canonical_value(v));
361 return *this;
362 }
363
364 //
365 // These operators are *not* proto-ized.
366 // The issue is that the increment/decrement must happen
367 // even if the result of the operator *is never used*.
368 // Possibly we could modify our expression wrapper to
369 // execute the increment/decrement on destruction, but
370 // correct implementation will be tricky, so defered for now...
371 //
372 BOOST_MP_FORCEINLINE number& operator++()
373 {
374 using default_ops::eval_increment;
375 eval_increment(m_backend);
376 return *this;
377 }
378
379 BOOST_MP_FORCEINLINE number& operator--()
380 {
381 using default_ops::eval_decrement;
382 eval_decrement(m_backend);
383 return *this;
384 }
385
386 inline number operator++(int)
387 {
388 using default_ops::eval_increment;
389 self_type temp(*this);
390 eval_increment(m_backend);
391 return BOOST_MP_MOVE(temp);
392 }
393
394 inline number operator--(int)
395 {
396 using default_ops::eval_decrement;
397 self_type temp(*this);
398 eval_decrement(m_backend);
399 return BOOST_MP_MOVE(temp);
400 }
401
402 template <class V>
403 BOOST_MP_FORCEINLINE typename boost::enable_if<is_integral<V>, number&>::type operator <<= (V val)
404 {
405 BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The left-shift operation is only valid for integer types");
406 detail::check_shift_range(val, mpl::bool_<(sizeof(V) > sizeof(std::size_t))>(), is_signed<V>());
407 eval_left_shift(m_backend, static_cast<std::size_t>(canonical_value(val)));
408 return *this;
409 }
410
411 template <class V>
412 BOOST_MP_FORCEINLINE typename boost::enable_if<is_integral<V>, number&>::type operator >>= (V val)
413 {
414 BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The right-shift operation is only valid for integer types");
415 detail::check_shift_range(val, mpl::bool_<(sizeof(V) > sizeof(std::size_t))>(), is_signed<V>());
416 eval_right_shift(m_backend, static_cast<std::size_t>(canonical_value(val)));
417 return *this;
418 }
419
420 BOOST_MP_FORCEINLINE number& operator /= (const self_type& e)
421 {
422 do_divide(detail::expression<detail::terminal, self_type>(e), detail::terminal());
423 return *this;
424 }
425
426 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
427 typename boost::enable_if<is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>, number&>::type operator/=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
428 {
429 // Create a temporary if the RHS references *this:
430 if(contains_self(e))
431 {
432 self_type temp(e);
433 do_divide(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
434 }
435 else
436 {
437 do_divide(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
438 }
439 return *this;
440 }
441
442 template <class V>
443 BOOST_MP_FORCEINLINE typename boost::enable_if<boost::is_convertible<V, self_type>, number<Backend, ExpressionTemplates>& >::type
444 operator/=(const V& v)
445 {
446 using default_ops::eval_divide;
447 eval_divide(m_backend, canonical_value(v));
448 return *this;
449 }
450
451 BOOST_MP_FORCEINLINE number& operator&=(const self_type& e)
452 {
453 BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types");
454 do_bitwise_and(detail::expression<detail::terminal, self_type>(e), detail::terminal());
455 return *this;
456 }
457
458 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
459 typename boost::enable_if<is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>, number&>::type operator&=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
460 {
461 BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types");
462 // Create a temporary if the RHS references *this, but not
463 // if we're just doing an x &= x;
464 if(contains_self(e) && !is_self(e))
465 {
466 self_type temp(e);
467 do_bitwise_and(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
468 }
469 else
470 {
471 do_bitwise_and(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
472 }
473 return *this;
474 }
475
476 template <class V>
477 BOOST_MP_FORCEINLINE typename boost::enable_if<boost::is_convertible<V, self_type>, number<Backend, ExpressionTemplates>& >::type
478 operator&=(const V& v)
479 {
480 BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types");
481 using default_ops::eval_bitwise_and;
482 eval_bitwise_and(m_backend, canonical_value(v));
483 return *this;
484 }
485
486 BOOST_MP_FORCEINLINE number& operator|=(const self_type& e)
487 {
488 BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types");
489 do_bitwise_or(detail::expression<detail::terminal, self_type>(e), detail::terminal());
490 return *this;
491 }
492
493 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
494 typename boost::enable_if<is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>, number&>::type operator|=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
495 {
496 BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types");
497 // Create a temporary if the RHS references *this, but not
498 // if we're just doing an x |= x;
499 if(contains_self(e) && !is_self(e))
500 {
501 self_type temp(e);
502 do_bitwise_or(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
503 }
504 else
505 {
506 do_bitwise_or(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
507 }
508 return *this;
509 }
510
511 template <class V>
512 BOOST_MP_FORCEINLINE typename boost::enable_if<boost::is_convertible<V, self_type>, number<Backend, ExpressionTemplates>& >::type
513 operator|=(const V& v)
514 {
515 BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types");
516 using default_ops::eval_bitwise_or;
517 eval_bitwise_or(m_backend, canonical_value(v));
518 return *this;
519 }
520
521 BOOST_MP_FORCEINLINE number& operator^=(const self_type& e)
522 {
523 BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types");
524 do_bitwise_xor(detail::expression<detail::terminal, self_type>(e), detail::terminal());
525 return *this;
526 }
527
528 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
529 typename boost::enable_if<is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>, number&>::type operator^=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
530 {
531 BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types");
532 if(contains_self(e))
533 {
534 self_type temp(e);
535 do_bitwise_xor(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
536 }
537 else
538 {
539 do_bitwise_xor(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
540 }
541 return *this;
542 }
543
544 template <class V>
545 BOOST_MP_FORCEINLINE typename boost::enable_if<boost::is_convertible<V, self_type>, number<Backend, ExpressionTemplates>& >::type
546 operator^=(const V& v)
547 {
548 BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types");
549 using default_ops::eval_bitwise_xor;
550 eval_bitwise_xor(m_backend, canonical_value(v));
551 return *this;
552 }
553 //
554 // swap:
555 //
556 BOOST_MP_FORCEINLINE void swap(self_type& other) BOOST_MP_NOEXCEPT_IF(noexcept(std::declval<Backend>().swap(std::declval<Backend&>())))
557 {
558 m_backend.swap(other.backend());
559 }
560 //
561 // Zero and sign:
562 //
563 BOOST_MP_FORCEINLINE bool is_zero()const
564 {
565 using default_ops::eval_is_zero;
566 return eval_is_zero(m_backend);
567 }
568 BOOST_MP_FORCEINLINE int sign()const
569 {
570 using default_ops::eval_get_sign;
571 return eval_get_sign(m_backend);
572 }
573 //
574 // String conversion functions:
575 //
576 std::string str(std::streamsize digits = 0, std::ios_base::fmtflags f = std::ios_base::fmtflags(0))const
577 {
578 return m_backend.str(digits, f);
579 }
580 template<class Archive>
581 void serialize(Archive & ar, const unsigned int /*version*/)
582 {
583 ar & m_backend;
584 }
585 private:
586 template <class T>
587 void convert_to_imp(T* result)const
588 {
589 using default_ops::eval_convert_to;
590 eval_convert_to(result, m_backend);
591 }
592 template <class B2, expression_template_option ET>
593 void convert_to_imp(number<B2, ET>* result)const
594 {
595 result->assign(*this);
596 }
597 void convert_to_imp(std::string* result)const
598 {
599 *result = this->str();
600 }
601 public:
602 template <class T>
603 T convert_to()const
604 {
605 T result;
606 convert_to_imp(&result);
607 return result;
608 }
609 //
610 // Use in boolean context, and explicit conversion operators:
611 //
612 #ifndef BOOST_MP_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS
613 # if (defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 7)) || (defined(BOOST_INTEL) && (BOOST_INTEL <= 1500))
614 //
615 // Horrible workaround for gcc-4.6.x which always prefers the template
616 // operator bool() rather than the non-template operator when converting to
617 // an arithmetic type:
618 //
619 template <class T, typename boost::enable_if<is_same<T, bool>, int>::type = 0>
620 explicit operator T ()const
621 {
622 using default_ops::eval_is_zero;
623 return !eval_is_zero(backend());
624 }
625 template <class T, typename boost::disable_if_c<is_same<T, bool>::value || is_void<T>::value, int>::type = 0>
626 explicit operator T ()const
627 {
628 return this->template convert_to<T>();
629 }
630 # else
631 template <class T>
632 explicit operator T()const
633 {
634 return this->template convert_to<T>();
635 }
636 BOOST_MP_FORCEINLINE explicit operator bool()const
637 {
638 return !is_zero();
639 }
640 #if BOOST_WORKAROUND(BOOST_GCC_VERSION, < 40800)
641 BOOST_MP_FORCEINLINE explicit operator void()const {}
642 #endif
643 # endif
644 #else
645 typedef bool (self_type::*unmentionable_type)()const;
646
647 BOOST_MP_FORCEINLINE operator unmentionable_type()const
648 {
649 return is_zero() ? 0 : &self_type::is_zero;
650 }
651 #endif
652 //
653 // Default precision:
654 //
655 static unsigned default_precision() BOOST_NOEXCEPT
656 {
657 return Backend::default_precision();
658 }
659 static void default_precision(unsigned digits10)
660 {
661 Backend::default_precision(digits10);
662 }
663 unsigned precision()const BOOST_NOEXCEPT
664 {
665 return m_backend.precision();
666 }
667 void precision(unsigned digits10)
668 {
669 m_backend.precision(digits10);
670 }
671 //
672 // Comparison:
673 //
674 BOOST_MP_FORCEINLINE int compare(const number<Backend, ExpressionTemplates>& o)const
675 BOOST_MP_NOEXCEPT_IF(noexcept(std::declval<Backend>().compare(std::declval<Backend>())))
676 {
677 return m_backend.compare(o.m_backend);
678 }
679 template <class V>
680 BOOST_MP_FORCEINLINE typename boost::enable_if<is_arithmetic<V>, int>::type compare(const V& o)const
681 {
682 using default_ops::eval_get_sign;
683 if(o == 0)
684 return eval_get_sign(m_backend);
685 return m_backend.compare(canonical_value(o));
686 }
687 BOOST_MP_FORCEINLINE Backend& backend() BOOST_NOEXCEPT
688 {
689 return m_backend;
690 }
691 BOOST_MP_FORCEINLINE BOOST_CONSTEXPR const Backend& backend()const BOOST_NOEXCEPT
692 {
693 return m_backend;
694 }
695 private:
696 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
697 void do_assign(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e, const mpl::true_&)
698 {
699 do_assign(e, tag());
700 }
701 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
702 void do_assign(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e, const mpl::false_&)
703 {
704 // The result of the expression isn't the same type as this -
705 // create a temporary result and assign it to *this:
706 typedef typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type temp_type;
707 temp_type t(e);
708 this->assign(t);
709 }
710
711
712 template <class Exp>
713 void do_assign(const Exp& e, const detail::add_immediates&)
714 {
715 using default_ops::eval_add;
716 eval_add(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
717 }
718 template <class Exp>
719 void do_assign(const Exp& e, const detail::subtract_immediates&)
720 {
721 using default_ops::eval_subtract;
722 eval_subtract(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
723 }
724 template <class Exp>
725 void do_assign(const Exp& e, const detail::multiply_immediates&)
726 {
727 using default_ops::eval_multiply;
728 eval_multiply(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
729 }
730 template <class Exp>
731 void do_assign(const Exp& e, const detail::multiply_add&)
732 {
733 using default_ops::eval_multiply_add;
734 eval_multiply_add(m_backend, canonical_value(e.left().value()), canonical_value(e.middle().value()), canonical_value(e.right().value()));
735 }
736 template <class Exp>
737 void do_assign(const Exp& e, const detail::multiply_subtract&)
738 {
739 using default_ops::eval_multiply_subtract;
740 eval_multiply_subtract(m_backend, canonical_value(e.left().value()), canonical_value(e.middle().value()), canonical_value(e.right().value()));
741 }
742
743 template <class Exp>
744 void do_assign(const Exp& e, const detail::divide_immediates&)
745 {
746 using default_ops::eval_divide;
747 eval_divide(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
748 }
749
750 template <class Exp>
751 void do_assign(const Exp& e, const detail::negate&)
752 {
753 typedef typename Exp::left_type left_type;
754 do_assign(e.left(), typename left_type::tag_type());
755 m_backend.negate();
756 }
757 template <class Exp>
758 void do_assign(const Exp& e, const detail::plus&)
759 {
760 typedef typename Exp::left_type left_type;
761 typedef typename Exp::right_type right_type;
762
763 static int const left_depth = left_type::depth;
764 static int const right_depth = right_type::depth;
765
766 bool bl = contains_self(e.left());
767 bool br = contains_self(e.right());
768
769 if(bl && br)
770 {
771 self_type temp(e);
772 temp.m_backend.swap(this->m_backend);
773 }
774 else if(bl && is_self(e.left()))
775 {
776 // Ignore the left node, it's *this, just add the right:
777 do_add(e.right(), typename right_type::tag_type());
778 }
779 else if(br && is_self(e.right()))
780 {
781 // Ignore the right node, it's *this, just add the left:
782 do_add(e.left(), typename left_type::tag_type());
783 }
784 else if(!br && (bl || (left_depth >= right_depth)))
785 { // br is always false, but if bl is true we must take the this branch:
786 do_assign(e.left(), typename left_type::tag_type());
787 do_add(e.right(), typename right_type::tag_type());
788 }
789 else
790 {
791 do_assign(e.right(), typename right_type::tag_type());
792 do_add(e.left(), typename left_type::tag_type());
793 }
794 }
795 template <class Exp>
796 void do_assign(const Exp& e, const detail::minus&)
797 {
798 typedef typename Exp::left_type left_type;
799 typedef typename Exp::right_type right_type;
800
801 static int const left_depth = left_type::depth;
802 static int const right_depth = right_type::depth;
803
804 bool bl = contains_self(e.left());
805 bool br = contains_self(e.right());
806
807 if(bl && br)
808 {
809 self_type temp(e);
810 temp.m_backend.swap(this->m_backend);
811 }
812 else if(bl && is_self(e.left()))
813 {
814 // Ignore the left node, it's *this, just subtract the right:
815 do_subtract(e.right(), typename right_type::tag_type());
816 }
817 else if(br && is_self(e.right()))
818 {
819 // Ignore the right node, it's *this, just subtract the left and negate the result:
820 do_subtract(e.left(), typename left_type::tag_type());
821 m_backend.negate();
822 }
823 else if(!br && (bl || (left_depth >= right_depth)))
824 { // br is always false, but if bl is true we must take the this branch:
825 do_assign(e.left(), typename left_type::tag_type());
826 do_subtract(e.right(), typename right_type::tag_type());
827 }
828 else
829 {
830 do_assign(e.right(), typename right_type::tag_type());
831 do_subtract(e.left(), typename left_type::tag_type());
832 m_backend.negate();
833 }
834 }
835 template <class Exp>
836 void do_assign(const Exp& e, const detail::multiplies&)
837 {
838 typedef typename Exp::left_type left_type;
839 typedef typename Exp::right_type right_type;
840
841 static int const left_depth = left_type::depth;
842 static int const right_depth = right_type::depth;
843
844 bool bl = contains_self(e.left());
845 bool br = contains_self(e.right());
846
847 if(bl && br)
848 {
849 self_type temp(e);
850 temp.m_backend.swap(this->m_backend);
851 }
852 else if(bl && is_self(e.left()))
853 {
854 // Ignore the left node, it's *this, just add the right:
855 do_multiplies(e.right(), typename right_type::tag_type());
856 }
857 else if(br && is_self(e.right()))
858 {
859 // Ignore the right node, it's *this, just add the left:
860 do_multiplies(e.left(), typename left_type::tag_type());
861 }
862 else if(!br && (bl || (left_depth >= right_depth)))
863 { // br is always false, but if bl is true we must take the this branch:
864 do_assign(e.left(), typename left_type::tag_type());
865 do_multiplies(e.right(), typename right_type::tag_type());
866 }
867 else
868 {
869 do_assign(e.right(), typename right_type::tag_type());
870 do_multiplies(e.left(), typename left_type::tag_type());
871 }
872 }
873 template <class Exp>
874 void do_assign(const Exp& e, const detail::divides&)
875 {
876 typedef typename Exp::left_type left_type;
877 typedef typename Exp::right_type right_type;
878
879 bool bl = contains_self(e.left());
880 bool br = contains_self(e.right());
881
882 if(bl && is_self(e.left()))
883 {
884 // Ignore the left node, it's *this, just add the right:
885 do_divide(e.right(), typename right_type::tag_type());
886 }
887 else if(br)
888 {
889 self_type temp(e);
890 temp.m_backend.swap(this->m_backend);
891 }
892 else
893 {
894 do_assign(e.left(), typename left_type::tag_type());
895 do_divide(e.right(), typename right_type::tag_type());
896 }
897 }
898 template <class Exp>
899 void do_assign(const Exp& e, const detail::modulus&)
900 {
901 //
902 // This operation is only valid for integer backends:
903 //
904 BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
905
906 typedef typename Exp::left_type left_type;
907 typedef typename Exp::right_type right_type;
908
909 bool bl = contains_self(e.left());
910 bool br = contains_self(e.right());
911
912 if(bl && is_self(e.left()))
913 {
914 // Ignore the left node, it's *this, just add the right:
915 do_modulus(e.right(), typename right_type::tag_type());
916 }
917 else if(br)
918 {
919 self_type temp(e);
920 temp.m_backend.swap(this->m_backend);
921 }
922 else
923 {
924 do_assign(e.left(), typename left_type::tag_type());
925 do_modulus(e.right(), typename right_type::tag_type());
926 }
927 }
928 template <class Exp>
929 void do_assign(const Exp& e, const detail::modulus_immediates&)
930 {
931 BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
932 using default_ops::eval_modulus;
933 eval_modulus(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
934 }
935
936 template <class Exp>
937 void do_assign(const Exp& e, const detail::bitwise_and&)
938 {
939 //
940 // This operation is only valid for integer backends:
941 //
942 BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
943
944 typedef typename Exp::left_type left_type;
945 typedef typename Exp::right_type right_type;
946
947 static int const left_depth = left_type::depth;
948 static int const right_depth = right_type::depth;
949
950 bool bl = contains_self(e.left());
951 bool br = contains_self(e.right());
952
953 if(bl && is_self(e.left()))
954 {
955 // Ignore the left node, it's *this, just add the right:
956 do_bitwise_and(e.right(), typename right_type::tag_type());
957 }
958 else if(br && is_self(e.right()))
959 {
960 do_bitwise_and(e.left(), typename left_type::tag_type());
961 }
962 else if(!br && (bl || (left_depth >= right_depth)))
963 {
964 do_assign(e.left(), typename left_type::tag_type());
965 do_bitwise_and(e.right(), typename right_type::tag_type());
966 }
967 else
968 {
969 do_assign(e.right(), typename right_type::tag_type());
970 do_bitwise_and(e.left(), typename left_type::tag_type());
971 }
972 }
973 template <class Exp>
974 void do_assign(const Exp& e, const detail::bitwise_and_immediates&)
975 {
976 BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
977 using default_ops::eval_bitwise_and;
978 eval_bitwise_and(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
979 }
980
981 template <class Exp>
982 void do_assign(const Exp& e, const detail::bitwise_or&)
983 {
984 //
985 // This operation is only valid for integer backends:
986 //
987 BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
988
989 typedef typename Exp::left_type left_type;
990 typedef typename Exp::right_type right_type;
991
992 static int const left_depth = left_type::depth;
993 static int const right_depth = right_type::depth;
994
995 bool bl = contains_self(e.left());
996 bool br = contains_self(e.right());
997
998 if(bl && is_self(e.left()))
999 {
1000 // Ignore the left node, it's *this, just add the right:
1001 do_bitwise_or(e.right(), typename right_type::tag_type());
1002 }
1003 else if(br && is_self(e.right()))
1004 {
1005 do_bitwise_or(e.left(), typename left_type::tag_type());
1006 }
1007 else if(!br && (bl || (left_depth >= right_depth)))
1008 {
1009 do_assign(e.left(), typename left_type::tag_type());
1010 do_bitwise_or(e.right(), typename right_type::tag_type());
1011 }
1012 else
1013 {
1014 do_assign(e.right(), typename right_type::tag_type());
1015 do_bitwise_or(e.left(), typename left_type::tag_type());
1016 }
1017 }
1018 template <class Exp>
1019 void do_assign(const Exp& e, const detail::bitwise_or_immediates&)
1020 {
1021 BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
1022 using default_ops::eval_bitwise_or;
1023 eval_bitwise_or(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
1024 }
1025
1026 template <class Exp>
1027 void do_assign(const Exp& e, const detail::bitwise_xor&)
1028 {
1029 //
1030 // This operation is only valid for integer backends:
1031 //
1032 BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
1033
1034 typedef typename Exp::left_type left_type;
1035 typedef typename Exp::right_type right_type;
1036
1037 static int const left_depth = left_type::depth;
1038 static int const right_depth = right_type::depth;
1039
1040 bool bl = contains_self(e.left());
1041 bool br = contains_self(e.right());
1042
1043 if(bl && is_self(e.left()))
1044 {
1045 // Ignore the left node, it's *this, just add the right:
1046 do_bitwise_xor(e.right(), typename right_type::tag_type());
1047 }
1048 else if(br && is_self(e.right()))
1049 {
1050 do_bitwise_xor(e.left(), typename left_type::tag_type());
1051 }
1052 else if(!br && (bl || (left_depth >= right_depth)))
1053 {
1054 do_assign(e.left(), typename left_type::tag_type());
1055 do_bitwise_xor(e.right(), typename right_type::tag_type());
1056 }
1057 else
1058 {
1059 do_assign(e.right(), typename right_type::tag_type());
1060 do_bitwise_xor(e.left(), typename left_type::tag_type());
1061 }
1062 }
1063 template <class Exp>
1064 void do_assign(const Exp& e, const detail::bitwise_xor_immediates&)
1065 {
1066 BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
1067 using default_ops::eval_bitwise_xor;
1068 eval_bitwise_xor(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
1069 }
1070 template <class Exp>
1071 void do_assign(const Exp& e, const detail::terminal&)
1072 {
1073 if(!is_self(e))
1074 {
1075 m_backend = canonical_value(e.value());
1076 }
1077 }
1078 template <class Exp>
1079 void do_assign(const Exp& e, const detail::function&)
1080 {
1081 typedef typename Exp::arity tag_type;
1082 do_assign_function(e, tag_type());
1083 }
1084 template <class Exp>
1085 void do_assign(const Exp& e, const detail::shift_left&)
1086 {
1087 // We can only shift by an integer value, not an arbitrary expression:
1088 typedef typename Exp::left_type left_type;
1089 typedef typename Exp::right_type right_type;
1090 typedef typename right_type::arity right_arity;
1091 BOOST_STATIC_ASSERT_MSG(right_arity::value == 0, "The left shift operator requires an integer value for the shift operand.");
1092 typedef typename right_type::result_type right_value_type;
1093 BOOST_STATIC_ASSERT_MSG(is_integral<right_value_type>::value, "The left shift operator requires an integer value for the shift operand.");
1094 typedef typename left_type::tag_type tag_type;
1095 do_assign_left_shift(e.left(), canonical_value(e.right().value()), tag_type());
1096 }
1097
1098 template <class Exp>
1099 void do_assign(const Exp& e, const detail::shift_right&)
1100 {
1101 // We can only shift by an integer value, not an arbitrary expression:
1102 typedef typename Exp::left_type left_type;
1103 typedef typename Exp::right_type right_type;
1104 typedef typename right_type::arity right_arity;
1105 BOOST_STATIC_ASSERT_MSG(right_arity::value == 0, "The left shift operator requires an integer value for the shift operand.");
1106 typedef typename right_type::result_type right_value_type;
1107 BOOST_STATIC_ASSERT_MSG(is_integral<right_value_type>::value, "The left shift operator requires an integer value for the shift operand.");
1108 typedef typename left_type::tag_type tag_type;
1109 do_assign_right_shift(e.left(), canonical_value(e.right().value()), tag_type());
1110 }
1111
1112 template <class Exp>
1113 void do_assign(const Exp& e, const detail::bitwise_complement&)
1114 {
1115 BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise ~ operation is only valid for integer types");
1116 using default_ops::eval_complement;
1117 self_type temp(e.left());
1118 eval_complement(m_backend, temp.backend());
1119 }
1120
1121 template <class Exp>
1122 void do_assign(const Exp& e, const detail::complement_immediates&)
1123 {
1124 BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise ~ operation is only valid for integer types");
1125 using default_ops::eval_complement;
1126 eval_complement(m_backend, canonical_value(e.left().value()));
1127 }
1128
1129 template <class Exp, class Val>
1130 void do_assign_right_shift(const Exp& e, const Val& val, const detail::terminal&)
1131 {
1132 BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The right shift operation is only valid for integer types");
1133 using default_ops::eval_right_shift;
1134 detail::check_shift_range(val, mpl::bool_<(sizeof(Val) > sizeof(std::size_t))>(), is_signed<Val>());
1135 eval_right_shift(m_backend, canonical_value(e.value()), static_cast<std::size_t>(val));
1136 }
1137
1138 template <class Exp, class Val>
1139 void do_assign_left_shift(const Exp& e, const Val& val, const detail::terminal&)
1140 {
1141 BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The left shift operation is only valid for integer types");
1142 using default_ops::eval_left_shift;
1143 detail::check_shift_range(val, mpl::bool_<(sizeof(Val) > sizeof(std::size_t))>(), is_signed<Val>());
1144 eval_left_shift(m_backend, canonical_value(e.value()), static_cast<std::size_t>(val));
1145 }
1146
1147 template <class Exp, class Val, class Tag>
1148 void do_assign_right_shift(const Exp& e, const Val& val, const Tag&)
1149 {
1150 BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The right shift operation is only valid for integer types");
1151 using default_ops::eval_right_shift;
1152 self_type temp(e);
1153 detail::check_shift_range(val, mpl::bool_<(sizeof(Val) > sizeof(std::size_t))>(), is_signed<Val>());
1154 eval_right_shift(m_backend, temp.backend(), static_cast<std::size_t>(val));
1155 }
1156
1157 template <class Exp, class Val, class Tag>
1158 void do_assign_left_shift(const Exp& e, const Val& val, const Tag&)
1159 {
1160 BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The left shift operation is only valid for integer types");
1161 using default_ops::eval_left_shift;
1162 self_type temp(e);
1163 detail::check_shift_range(val, mpl::bool_<(sizeof(Val) > sizeof(std::size_t))>(), is_signed<Val>());
1164 eval_left_shift(m_backend, temp.backend(), static_cast<std::size_t>(val));
1165 }
1166
1167 template <class Exp>
1168 void do_assign_function(const Exp& e, const mpl::int_<1>&)
1169 {
1170 e.left().value()(&m_backend);
1171 }
1172 template <class Exp>
1173 void do_assign_function(const Exp& e, const mpl::int_<2>&)
1174 {
1175 typedef typename Exp::right_type right_type;
1176 typedef typename right_type::tag_type tag_type;
1177 do_assign_function_1(e.left().value(), e.right_ref(), tag_type());
1178 }
1179 template <class F, class Exp>
1180 void do_assign_function_1(const F& f, const Exp& val, const detail::terminal&)
1181 {
1182 f(m_backend, function_arg_value(val));
1183 }
1184 template <class F, class Exp, class Tag>
1185 void do_assign_function_1(const F& f, const Exp& val, const Tag&)
1186 {
1187 number t(val);
1188 f(m_backend, t.backend());
1189 }
1190 template <class Exp>
1191 void do_assign_function(const Exp& e, const mpl::int_<3>&)
1192 {
1193 typedef typename Exp::middle_type middle_type;
1194 typedef typename middle_type::tag_type tag_type;
1195 typedef typename Exp::right_type end_type;
1196 typedef typename end_type::tag_type end_tag;
1197 do_assign_function_2(e.left().value(), e.middle_ref(), e.right_ref(), tag_type(), end_tag());
1198 }
1199 template <class F, class Exp1, class Exp2>
1200 void do_assign_function_2(const F& f, const Exp1& val1, const Exp2& val2, const detail::terminal&, const detail::terminal&)
1201 {
1202 f(m_backend, function_arg_value(val1), function_arg_value(val2));
1203 }
1204 template <class F, class Exp1, class Exp2, class Tag1>
1205 void do_assign_function_2(const F& f, const Exp1& val1, const Exp2& val2, const Tag1&, const detail::terminal&)
1206 {
1207 self_type temp1(val1);
1208 f(m_backend, BOOST_MP_MOVE(temp1.backend()), function_arg_value(val2));
1209 }
1210 template <class F, class Exp1, class Exp2, class Tag2>
1211 void do_assign_function_2(const F& f, const Exp1& val1, const Exp2& val2, const detail::terminal&, const Tag2&)
1212 {
1213 self_type temp2(val2);
1214 f(m_backend, function_arg_value(val1), BOOST_MP_MOVE(temp2.backend()));
1215 }
1216 template <class F, class Exp1, class Exp2, class Tag1, class Tag2>
1217 void do_assign_function_2(const F& f, const Exp1& val1, const Exp2& val2, const Tag1&, const Tag2&)
1218 {
1219 self_type temp1(val1);
1220 self_type temp2(val2);
1221 f(m_backend, BOOST_MP_MOVE(temp1.backend()), BOOST_MP_MOVE(temp2.backend()));
1222 }
1223
1224 template <class Exp>
1225 void do_assign_function(const Exp& e, const mpl::int_<4>&)
1226 {
1227 typedef typename Exp::left_middle_type left_type;
1228 typedef typename left_type::tag_type left_tag_type;
1229 typedef typename Exp::right_middle_type middle_type;
1230 typedef typename middle_type::tag_type middle_tag_type;
1231 typedef typename Exp::right_type right_type;
1232 typedef typename right_type::tag_type right_tag_type;
1233 do_assign_function_3a(e.left().value(), e.left_middle_ref(), e.right_middle_ref(), e.right_ref(), left_tag_type(), middle_tag_type(), right_tag_type());
1234 }
1235 template <class F, class Exp1, class Exp2, class Exp3, class Tag2, class Tag3>
1236 void do_assign_function_3a(const F& f, const Exp1& val1, const Exp2& val2, const Exp3& val3, const detail::terminal&, const Tag2& t2, const Tag3& t3)
1237 {
1238 do_assign_function_3b(f, val1, val2, val3, t2, t3);
1239 }
1240 template <class F, class Exp1, class Exp2, class Exp3, class Tag1, class Tag2, class Tag3>
1241 void do_assign_function_3a(const F& f, const Exp1& val1, const Exp2& val2, const Exp3& val3, const Tag1&, const Tag2& t2, const Tag3& t3)
1242 {
1243 number t(val1);
1244 do_assign_function_3b(f, BOOST_MP_MOVE(t), val2, val3, t2, t3);
1245 }
1246 template <class F, class Exp1, class Exp2, class Exp3, class Tag3>
1247 void do_assign_function_3b(const F& f, const Exp1& val1, const Exp2& val2, const Exp3& val3, const detail::terminal&, const Tag3& t3)
1248 {
1249 do_assign_function_3c(f, val1, val2, val3, t3);
1250 }
1251 template <class F, class Exp1, class Exp2, class Exp3, class Tag2, class Tag3>
1252 void do_assign_function_3b(const F& f, const Exp1& val1, const Exp2& val2, const Exp3& val3, const Tag2& /*t2*/, const Tag3& t3)
1253 {
1254 number t(val2);
1255 do_assign_function_3c(f, val1, BOOST_MP_MOVE(t), val3, t3);
1256 }
1257 template <class F, class Exp1, class Exp2, class Exp3>
1258 void do_assign_function_3c(const F& f, const Exp1& val1, const Exp2& val2, const Exp3& val3, const detail::terminal&)
1259 {
1260 f(m_backend, function_arg_value(val1), function_arg_value(val2), function_arg_value(val3));
1261 }
1262 template <class F, class Exp1, class Exp2, class Exp3, class Tag3>
1263 void do_assign_function_3c(const F& f, const Exp1& val1, const Exp2& val2, const Exp3& val3, const Tag3& /*t3*/)
1264 {
1265 number t(val3);
1266 do_assign_function_3c(f, val1, val2, BOOST_MP_MOVE(t), detail::terminal());
1267 }
1268
1269 template <class Exp>
1270 void do_add(const Exp& e, const detail::terminal&)
1271 {
1272 using default_ops::eval_add;
1273 eval_add(m_backend, canonical_value(e.value()));
1274 }
1275
1276 template <class Exp>
1277 void do_add(const Exp& e, const detail::negate&)
1278 {
1279 typedef typename Exp::left_type left_type;
1280 do_subtract(e.left(), typename left_type::tag_type());
1281 }
1282
1283 template <class Exp>
1284 void do_add(const Exp& e, const detail::plus&)
1285 {
1286 typedef typename Exp::left_type left_type;
1287 typedef typename Exp::right_type right_type;
1288 do_add(e.left(), typename left_type::tag_type());
1289 do_add(e.right(), typename right_type::tag_type());
1290 }
1291
1292 template <class Exp>
1293 void do_add(const Exp& e, const detail::minus&)
1294 {
1295 typedef typename Exp::left_type left_type;
1296 typedef typename Exp::right_type right_type;
1297 do_add(e.left(), typename left_type::tag_type());
1298 do_subtract(e.right(), typename right_type::tag_type());
1299 }
1300
1301 template <class Exp, class unknown>
1302 void do_add(const Exp& e, const unknown&)
1303 {
1304 self_type temp(e);
1305 do_add(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
1306 }
1307
1308 template <class Exp>
1309 void do_add(const Exp& e, const detail::add_immediates&)
1310 {
1311 using default_ops::eval_add;
1312 eval_add(m_backend, canonical_value(e.left().value()));
1313 eval_add(m_backend, canonical_value(e.right().value()));
1314 }
1315 template <class Exp>
1316 void do_add(const Exp& e, const detail::subtract_immediates&)
1317 {
1318 using default_ops::eval_add;
1319 using default_ops::eval_subtract;
1320 eval_add(m_backend, canonical_value(e.left().value()));
1321 eval_subtract(m_backend, canonical_value(e.right().value()));
1322 }
1323 template <class Exp>
1324 void do_subtract(const Exp& e, const detail::terminal&)
1325 {
1326 using default_ops::eval_subtract;
1327 eval_subtract(m_backend, canonical_value(e.value()));
1328 }
1329
1330 template <class Exp>
1331 void do_subtract(const Exp& e, const detail::negate&)
1332 {
1333 typedef typename Exp::left_type left_type;
1334 do_add(e.left(), typename left_type::tag_type());
1335 }
1336
1337 template <class Exp>
1338 void do_subtract(const Exp& e, const detail::plus&)
1339 {
1340 typedef typename Exp::left_type left_type;
1341 typedef typename Exp::right_type right_type;
1342 do_subtract(e.left(), typename left_type::tag_type());
1343 do_subtract(e.right(), typename right_type::tag_type());
1344 }
1345
1346 template <class Exp>
1347 void do_subtract(const Exp& e, const detail::minus&)
1348 {
1349 typedef typename Exp::left_type left_type;
1350 typedef typename Exp::right_type right_type;
1351 do_subtract(e.left(), typename left_type::tag_type());
1352 do_add(e.right(), typename right_type::tag_type());
1353 }
1354 template <class Exp>
1355 void do_subtract(const Exp& e, const detail::add_immediates&)
1356 {
1357 using default_ops::eval_subtract;
1358 eval_subtract(m_backend, canonical_value(e.left().value()));
1359 eval_subtract(m_backend, canonical_value(e.right().value()));
1360 }
1361 template <class Exp>
1362 void do_subtract(const Exp& e, const detail::subtract_immediates&)
1363 {
1364 using default_ops::eval_add;
1365 using default_ops::eval_subtract;
1366 eval_subtract(m_backend, canonical_value(e.left().value()));
1367 eval_add(m_backend, canonical_value(e.right().value()));
1368 }
1369 template <class Exp, class unknown>
1370 void do_subtract(const Exp& e, const unknown&)
1371 {
1372 self_type temp(e);
1373 do_subtract(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
1374 }
1375
1376 template <class Exp>
1377 void do_multiplies(const Exp& e, const detail::terminal&)
1378 {
1379 using default_ops::eval_multiply;
1380 eval_multiply(m_backend, canonical_value(e.value()));
1381 }
1382
1383 template <class Exp>
1384 void do_multiplies(const Exp& e, const detail::negate&)
1385 {
1386 typedef typename Exp::left_type left_type;
1387 do_multiplies(e.left(), typename left_type::tag_type());
1388 m_backend.negate();
1389 }
1390
1391 template <class Exp>
1392 void do_multiplies(const Exp& e, const detail::multiplies&)
1393 {
1394 typedef typename Exp::left_type left_type;
1395 typedef typename Exp::right_type right_type;
1396 do_multiplies(e.left(), typename left_type::tag_type());
1397 do_multiplies(e.right(), typename right_type::tag_type());
1398 }
1399 //
1400 // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
1401 // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
1402 //
1403 template <class Exp>
1404 typename boost::disable_if_c<boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1>::type
1405 do_multiplies(const Exp& e, const detail::divides&)
1406 {
1407 typedef typename Exp::left_type left_type;
1408 typedef typename Exp::right_type right_type;
1409 do_multiplies(e.left(), typename left_type::tag_type());
1410 do_divide(e.right(), typename right_type::tag_type());
1411 }
1412
1413 template <class Exp>
1414 void do_multiplies(const Exp& e, const detail::multiply_immediates&)
1415 {
1416 using default_ops::eval_multiply;
1417 eval_multiply(m_backend, canonical_value(e.left().value()));
1418 eval_multiply(m_backend, canonical_value(e.right().value()));
1419 }
1420 //
1421 // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
1422 // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
1423 //
1424 template <class Exp>
1425 typename boost::disable_if_c<boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1>::type
1426 do_multiplies(const Exp& e, const detail::divide_immediates&)
1427 {
1428 using default_ops::eval_multiply;
1429 using default_ops::eval_divide;
1430 eval_multiply(m_backend, canonical_value(e.left().value()));
1431 eval_divide(m_backend, canonical_value(e.right().value()));
1432 }
1433 template <class Exp, class unknown>
1434 void do_multiplies(const Exp& e, const unknown&)
1435 {
1436 using default_ops::eval_multiply;
1437 self_type temp(e);
1438 eval_multiply(m_backend, temp.m_backend);
1439 }
1440
1441 template <class Exp>
1442 void do_divide(const Exp& e, const detail::terminal&)
1443 {
1444 using default_ops::eval_divide;
1445 eval_divide(m_backend, canonical_value(e.value()));
1446 }
1447
1448 template <class Exp>
1449 void do_divide(const Exp& e, const detail::negate&)
1450 {
1451 typedef typename Exp::left_type left_type;
1452 do_divide(e.left(), typename left_type::tag_type());
1453 m_backend.negate();
1454 }
1455 //
1456 // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
1457 // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
1458 //
1459 template <class Exp>
1460 typename boost::disable_if_c<boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1>::type
1461 do_divide(const Exp& e, const detail::multiplies&)
1462 {
1463 typedef typename Exp::left_type left_type;
1464 typedef typename Exp::right_type right_type;
1465 do_divide(e.left(), typename left_type::tag_type());
1466 do_divide(e.right(), typename right_type::tag_type());
1467 }
1468 //
1469 // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
1470 // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
1471 //
1472 template <class Exp>
1473 typename boost::disable_if_c<boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1>::type
1474 do_divide(const Exp& e, const detail::divides&)
1475 {
1476 typedef typename Exp::left_type left_type;
1477 typedef typename Exp::right_type right_type;
1478 do_divide(e.left(), typename left_type::tag_type());
1479 do_multiplies(e.right(), typename right_type::tag_type());
1480 }
1481 //
1482 // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
1483 // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
1484 //
1485 template <class Exp>
1486 typename boost::disable_if_c<boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1>::type
1487 do_divides(const Exp& e, const detail::multiply_immediates&)
1488 {
1489 using default_ops::eval_divide;
1490 eval_divide(m_backend, canonical_value(e.left().value()));
1491 eval_divide(m_backend, canonical_value(e.right().value()));
1492 }
1493 //
1494 // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
1495 // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
1496 //
1497 template <class Exp>
1498 typename boost::disable_if_c<boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1>::type
1499 do_divides(const Exp& e, const detail::divide_immediates&)
1500 {
1501 using default_ops::eval_multiply;
1502 using default_ops::eval_divide;
1503 eval_divide(m_backend, canonical_value(e.left().value()));
1504 mutiply(m_backend, canonical_value(e.right().value()));
1505 }
1506
1507 template <class Exp, class unknown>
1508 void do_divide(const Exp& e, const unknown&)
1509 {
1510 using default_ops::eval_multiply;
1511 self_type temp(e);
1512 eval_divide(m_backend, temp.m_backend);
1513 }
1514
1515 template <class Exp>
1516 void do_modulus(const Exp& e, const detail::terminal&)
1517 {
1518 BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
1519 using default_ops::eval_modulus;
1520 eval_modulus(m_backend, canonical_value(e.value()));
1521 }
1522
1523 template <class Exp, class Unknown>
1524 void do_modulus(const Exp& e, const Unknown&)
1525 {
1526 BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
1527 using default_ops::eval_modulus;
1528 self_type temp(e);
1529 eval_modulus(m_backend, canonical_value(temp));
1530 }
1531
1532 template <class Exp>
1533 void do_bitwise_and(const Exp& e, const detail::terminal&)
1534 {
1535 BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types");
1536 using default_ops::eval_bitwise_and;
1537 eval_bitwise_and(m_backend, canonical_value(e.value()));
1538 }
1539 template <class Exp>
1540 void do_bitwise_and(const Exp& e, const detail::bitwise_and&)
1541 {
1542 BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types");
1543 typedef typename Exp::left_type left_type;
1544 typedef typename Exp::right_type right_type;
1545 do_bitwise_and(e.left(), typename left_type::tag_type());
1546 do_bitwise_and(e.right(), typename right_type::tag_type());
1547 }
1548 template <class Exp, class unknown>
1549 void do_bitwise_and(const Exp& e, const unknown&)
1550 {
1551 BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types");
1552 using default_ops::eval_bitwise_and;
1553 self_type temp(e);
1554 eval_bitwise_and(m_backend, temp.m_backend);
1555 }
1556
1557 template <class Exp>
1558 void do_bitwise_or(const Exp& e, const detail::terminal&)
1559 {
1560 BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types");
1561 using default_ops::eval_bitwise_or;
1562 eval_bitwise_or(m_backend, canonical_value(e.value()));
1563 }
1564 template <class Exp>
1565 void do_bitwise_or(const Exp& e, const detail::bitwise_or&)
1566 {
1567 BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types");
1568 typedef typename Exp::left_type left_type;
1569 typedef typename Exp::right_type right_type;
1570 do_bitwise_or(e.left(), typename left_type::tag_type());
1571 do_bitwise_or(e.right(), typename right_type::tag_type());
1572 }
1573 template <class Exp, class unknown>
1574 void do_bitwise_or(const Exp& e, const unknown&)
1575 {
1576 BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types");
1577 using default_ops::eval_bitwise_or;
1578 self_type temp(e);
1579 eval_bitwise_or(m_backend, temp.m_backend);
1580 }
1581
1582 template <class Exp>
1583 void do_bitwise_xor(const Exp& e, const detail::terminal&)
1584 {
1585 BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types");
1586 using default_ops::eval_bitwise_xor;
1587 eval_bitwise_xor(m_backend, canonical_value(e.value()));
1588 }
1589 template <class Exp>
1590 void do_bitwise_xor(const Exp& e, const detail::bitwise_xor&)
1591 {
1592 BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types");
1593 typedef typename Exp::left_type left_type;
1594 typedef typename Exp::right_type right_type;
1595 do_bitwise_xor(e.left(), typename left_type::tag_type());
1596 do_bitwise_xor(e.right(), typename right_type::tag_type());
1597 }
1598 template <class Exp, class unknown>
1599 void do_bitwise_xor(const Exp& e, const unknown&)
1600 {
1601 BOOST_STATIC_ASSERT_MSG(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types");
1602 using default_ops::eval_bitwise_xor;
1603 self_type temp(e);
1604 eval_bitwise_xor(m_backend, temp.m_backend);
1605 }
1606
1607 // Tests if the expression contains a reference to *this:
1608 template <class Exp>
1609 BOOST_MP_FORCEINLINE bool contains_self(const Exp& e)const BOOST_NOEXCEPT
1610 {
1611 return contains_self(e, typename Exp::arity());
1612 }
1613 template <class Exp>
1614 BOOST_MP_FORCEINLINE bool contains_self(const Exp& e, mpl::int_<0> const&)const BOOST_NOEXCEPT
1615 {
1616 return is_realy_self(e.value());
1617 }
1618 template <class Exp>
1619 BOOST_MP_FORCEINLINE bool contains_self(const Exp& e, mpl::int_<1> const&)const BOOST_NOEXCEPT
1620 {
1621 typedef typename Exp::left_type child_type;
1622 return contains_self(e.left(), typename child_type::arity());
1623 }
1624 template <class Exp>
1625 BOOST_MP_FORCEINLINE bool contains_self(const Exp& e, mpl::int_<2> const&)const BOOST_NOEXCEPT
1626 {
1627 typedef typename Exp::left_type child0_type;
1628 typedef typename Exp::right_type child1_type;
1629 return contains_self(e.left(), typename child0_type::arity())
1630 || contains_self(e.right(), typename child1_type::arity());
1631 }
1632 template <class Exp>
1633 BOOST_MP_FORCEINLINE bool contains_self(const Exp& e, mpl::int_<3> const&)const BOOST_NOEXCEPT
1634 {
1635 typedef typename Exp::left_type child0_type;
1636 typedef typename Exp::middle_type child1_type;
1637 typedef typename Exp::right_type child2_type;
1638 return contains_self(e.left(), typename child0_type::arity())
1639 || contains_self(e.middle(), typename child1_type::arity())
1640 || contains_self(e.right(), typename child2_type::arity());
1641 }
1642
1643 // Test if the expression is a reference to *this:
1644 template <class Exp>
1645 BOOST_MP_FORCEINLINE BOOST_CONSTEXPR bool is_self(const Exp& e)const BOOST_NOEXCEPT
1646 {
1647 return is_self(e, typename Exp::arity());
1648 }
1649 template <class Exp>
1650 BOOST_MP_FORCEINLINE BOOST_CONSTEXPR bool is_self(const Exp& e, mpl::int_<0> const&)const BOOST_NOEXCEPT
1651 {
1652 return is_realy_self(e.value());
1653 }
1654 template <class Exp, int v>
1655 BOOST_MP_FORCEINLINE BOOST_CONSTEXPR bool is_self(const Exp&, mpl::int_<v> const&)const BOOST_NOEXCEPT
1656 {
1657 return false;
1658 }
1659
1660 template <class Val>
1661 BOOST_MP_FORCEINLINE BOOST_CONSTEXPR bool is_realy_self(const Val&)const BOOST_NOEXCEPT{ return false; }
1662 BOOST_MP_FORCEINLINE BOOST_CONSTEXPR bool is_realy_self(const self_type& v)const BOOST_NOEXCEPT{ return &v == this; }
1663
1664 static BOOST_MP_FORCEINLINE BOOST_CONSTEXPR const Backend& function_arg_value(const self_type& v) BOOST_NOEXCEPT { return v.backend(); }
1665 template <class V>
1666 static BOOST_MP_FORCEINLINE BOOST_CONSTEXPR const V& function_arg_value(const V& v) BOOST_NOEXCEPT { return v; }
1667 template <class A1, class A2, class A3, class A4>
1668 static BOOST_MP_FORCEINLINE const A1& function_arg_value(const detail::expression<detail::terminal, A1, A2, A3, A4>& exp) BOOST_NOEXCEPT { return exp.value(); }
1669 template <class A2, class A3, class A4>
1670 static BOOST_MP_FORCEINLINE BOOST_CONSTEXPR const Backend& function_arg_value(const detail::expression<detail::terminal, number<Backend>, A2, A3, A4>& exp) BOOST_NOEXCEPT { return exp.value().backend(); }
1671 Backend m_backend;
1672
1673 public:
1674 //
1675 // These shouldn't really need to be public, or even member functions, but it makes implementing
1676 // the non-member operators way easier if they are:
1677 //
1678 static BOOST_MP_FORCEINLINE BOOST_CONSTEXPR const Backend& canonical_value(const self_type& v) BOOST_NOEXCEPT { return v.m_backend; }
1679 template <class B2, expression_template_option ET>
1680 static BOOST_MP_FORCEINLINE BOOST_CONSTEXPR const B2& canonical_value(const number<B2, ET>& v) BOOST_NOEXCEPT { return v.backend(); }
1681 template <class V>
1682 static BOOST_MP_FORCEINLINE BOOST_CONSTEXPR typename boost::disable_if<is_same<typename detail::canonical<V, Backend>::type, V>, typename detail::canonical<V, Backend>::type>::type
1683 canonical_value(const V& v) BOOST_NOEXCEPT { return static_cast<typename detail::canonical<V, Backend>::type>(v); }
1684 template <class V>
1685 static BOOST_MP_FORCEINLINE BOOST_CONSTEXPR typename boost::enable_if<is_same<typename detail::canonical<V, Backend>::type, V>, const V&>::type
1686 canonical_value(const V& v) BOOST_NOEXCEPT { return v; }
1687 static BOOST_MP_FORCEINLINE typename detail::canonical<std::string, Backend>::type canonical_value(const std::string& v) BOOST_NOEXCEPT { return v.c_str(); }
1688
1689 };
1690
1691 template <class Backend, expression_template_option ExpressionTemplates>
1692 inline std::ostream& operator << (std::ostream& os, const number<Backend, ExpressionTemplates>& r)
1693 {
1694 std::streamsize d = os.precision();
1695 std::string s = r.str(d, os.flags());
1696 std::streamsize ss = os.width();
1697 if(ss > static_cast<std::streamsize>(s.size()))
1698 {
1699 char fill = os.fill();
1700 if((os.flags() & std::ios_base::left) == std::ios_base::left)
1701 s.append(static_cast<std::string::size_type>(ss - s.size()), fill);
1702 else
1703 s.insert(static_cast<std::string::size_type>(0), static_cast<std::string::size_type>(ss - s.size()), fill);
1704 }
1705 return os << s;
1706 }
1707
1708 namespace detail{
1709
1710 template <class tag, class A1, class A2, class A3, class A4>
1711 inline std::ostream& operator << (std::ostream& os, const expression<tag, A1, A2, A3, A4>& r)
1712 {
1713 typedef typename expression<tag, A1, A2, A3, A4>::result_type value_type;
1714 value_type temp(r);
1715 return os << temp;
1716 }
1717 //
1718 // What follows is the input streaming code: this is not "proper" iostream code at all
1719 // but that's fiendishly hard to write when dealing with multiple backends all
1720 // with different requirements... yes we could deligate this to the backend author...
1721 // but we really want backends to be EASY to write!
1722 // For now just pull in all the characters that could possibly form the number
1723 // and let the backend's string parser make use of it. This fixes most use cases
1724 // including CSV type formats such as those used by the Random lib.
1725 //
1726 inline std::string read_string_while(std::istream& is, std::string const& permitted_chars)
1727 {
1728 std::ios_base::iostate state = std::ios_base::goodbit;
1729 const std::istream::sentry sentry_check(is);
1730 std::string result;
1731
1732 if(sentry_check)
1733 {
1734 int c = is.rdbuf()->sgetc();
1735
1736 for(;; c = is.rdbuf()->snextc())
1737 if(std::istream::traits_type::eq_int_type(std::istream::traits_type::eof(), c))
1738 { // end of file:
1739 state |= std::ios_base::eofbit;
1740 break;
1741 }
1742 else if(permitted_chars.find_first_of(std::istream::traits_type::to_char_type(c)) == std::string::npos)
1743 {
1744 // Invalid numeric character, stop reading:
1745 //is.rdbuf()->sputbackc(static_cast<char>(c));
1746 break;
1747 }
1748 else
1749 {
1750 result.append(1, std::istream::traits_type::to_char_type(c));
1751 }
1752 }
1753
1754 if(!result.size())
1755 state |= std::ios_base::failbit;
1756 is.setstate(state);
1757 return result;
1758 }
1759
1760 } // namespace detail
1761
1762 template <class Backend, expression_template_option ExpressionTemplates>
1763 inline std::istream& operator >> (std::istream& is, number<Backend, ExpressionTemplates>& r)
1764 {
1765 bool hex_format = (is.flags() & std::ios_base::hex) == std::ios_base::hex;
1766 bool oct_format = (is.flags() & std::ios_base::oct) == std::ios_base::oct;
1767 std::string s;
1768 switch(boost::multiprecision::number_category<number<Backend, ExpressionTemplates> >::value)
1769 {
1770 case boost::multiprecision::number_kind_integer:
1771 if(oct_format)
1772 s = detail::read_string_while(is, "+-01234567");
1773 else if(hex_format)
1774 s = detail::read_string_while(is, "+-xXabcdefABCDEF0123456789");
1775 else
1776 s = detail::read_string_while(is, "+-0123456789");
1777 break;
1778 case boost::multiprecision::number_kind_floating_point:
1779 s = detail::read_string_while(is, "+-eE.0123456789infINFnanNANinfinityINFINITY");
1780 break;
1781 default:
1782 is >> s;
1783 }
1784 if(s.size())
1785 {
1786 if(hex_format && (number_category<Backend>::value == number_kind_integer) && ((s[0] != '0') || (s[1] != 'x')))
1787 s.insert(s.find_first_not_of("+-"), "0x");
1788 if(oct_format && (number_category<Backend>::value == number_kind_integer) && (s[0] != '0'))
1789 s.insert(s.find_first_not_of("+-"), "0");
1790 r.assign(s);
1791 }
1792 else if(!is.fail())
1793 is.setstate(std::istream::failbit);
1794 return is;
1795 }
1796
1797 template <class Backend, expression_template_option ExpressionTemplates>
1798 BOOST_MP_FORCEINLINE void swap(number<Backend, ExpressionTemplates>& a, number<Backend, ExpressionTemplates>& b)
1799 BOOST_MP_NOEXCEPT_IF(noexcept(std::declval<number<Backend, ExpressionTemplates>&>() = std::declval<number<Backend, ExpressionTemplates>&>()))
1800 {
1801 a.swap(b);
1802 }
1803 //
1804 // Boost.Hash support, just call hash_value for the backend, which may or may not be supported:
1805 //
1806 template <class Backend, expression_template_option ExpressionTemplates>
1807 inline std::size_t hash_value(const number<Backend, ExpressionTemplates>& val)
1808 {
1809 return hash_value(val.backend());
1810 }
1811
1812 } // namespace multiprecision
1813
1814 template <class T>
1815 class rational;
1816
1817 template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
1818 inline std::istream& operator >> (std::istream& is, rational<multiprecision::number<Backend, ExpressionTemplates> >& r)
1819 {
1820 std::string s1;
1821 multiprecision::number<Backend, ExpressionTemplates> v1, v2;
1822 char c;
1823 bool have_hex = false;
1824 bool hex_format = (is.flags() & std::ios_base::hex) == std::ios_base::hex;
1825 bool oct_format = (is.flags() & std::ios_base::oct) == std::ios_base::oct;
1826
1827 while((EOF != (c = static_cast<char>(is.peek()))) && (c == 'x' || c == 'X' || c == '-' || c == '+' || (c >= '0' && c <= '9') || (have_hex && (c >= 'a' && c <= 'f')) || (have_hex && (c >= 'A' && c <= 'F'))))
1828 {
1829 if(c == 'x' || c == 'X')
1830 have_hex = true;
1831 s1.append(1, c);
1832 is.get();
1833 }
1834 if(hex_format && ((s1[0] != '0') || (s1[1] != 'x')))
1835 s1.insert(static_cast<std::string::size_type>(0), "0x");
1836 if(oct_format && (s1[0] != '0'))
1837 s1.insert(static_cast<std::string::size_type>(0), "0");
1838 v1.assign(s1);
1839 s1.erase();
1840 if(c == '/')
1841 {
1842 is.get();
1843 while((EOF != (c = static_cast<char>(is.peek()))) && (c == 'x' || c == 'X' || c == '-' || c == '+' || (c >= '0' && c <= '9') || (have_hex && (c >= 'a' && c <= 'f')) || (have_hex && (c >= 'A' && c <= 'F'))))
1844 {
1845 if(c == 'x' || c == 'X')
1846 have_hex = true;
1847 s1.append(1, c);
1848 is.get();
1849 }
1850 if(hex_format && ((s1[0] != '0') || (s1[1] != 'x')))
1851 s1.insert(static_cast<std::string::size_type>(0), "0x");
1852 if(oct_format && (s1[0] != '0'))
1853 s1.insert(static_cast<std::string::size_type>(0), "0");
1854 v2.assign(s1);
1855 }
1856 else
1857 v2 = 1;
1858 r.assign(v1, v2);
1859 return is;
1860 }
1861
1862 template <class T, multiprecision::expression_template_option ExpressionTemplates>
1863 inline multiprecision::number<T, ExpressionTemplates> numerator(const rational<multiprecision::number<T, ExpressionTemplates> >& a)
1864 {
1865 return a.numerator();
1866 }
1867
1868 template <class T, multiprecision::expression_template_option ExpressionTemplates>
1869 inline multiprecision::number<T, ExpressionTemplates> denominator(const rational<multiprecision::number<T, ExpressionTemplates> >& a)
1870 {
1871 return a.denominator();
1872 }
1873
1874 namespace multiprecision
1875 {
1876
1877 template <class I>
1878 struct component_type<boost::rational<I> >
1879 {
1880 typedef I type;
1881 };
1882
1883 }
1884
1885 #ifdef BOOST_MSVC
1886 #pragma warning(pop)
1887 #endif
1888
1889 } // namespaces
1890
1891 #ifndef BOOST_NO_CXX11_HDR_FUNCTIONAL
1892
1893 #include <functional>
1894
1895 namespace std {
1896
1897 template <class Backend, boost::multiprecision::expression_template_option ExpressionTemplates>
1898 struct hash<boost::multiprecision::number<Backend, ExpressionTemplates> >
1899 {
1900 std::size_t operator()(const boost::multiprecision::number<Backend, ExpressionTemplates>& val)const { return hash_value(val); }
1901 };
1902
1903 }
1904
1905 #endif
1906
1907 #include <boost/multiprecision/detail/ublas_interop.hpp>
1908
1909 #endif