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