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