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