]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/multiprecision/number.hpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / boost / boost / multiprecision / number.hpp
CommitLineData
7c673cae
FG
1///////////////////////////////////////////////////////////////////////////////
2// Copyright 2011 John Maddock. Distributed under the Boost
3// Software License, Version 1.0. (See accompanying file
4// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5
6#ifndef BOOST_MATH_EXTENDED_REAL_HPP
7#define BOOST_MATH_EXTENDED_REAL_HPP
8
1e59de90
TL
9#include <cstdint>
10#include <boost/multiprecision/detail/standalone_config.hpp>
92f5a8d4 11#include <boost/multiprecision/detail/precision.hpp>
7c673cae
FG
12#include <boost/multiprecision/detail/generic_interconvert.hpp>
13#include <boost/multiprecision/detail/number_compare.hpp>
14#include <boost/multiprecision/traits/is_restricted_conversion.hpp>
1e59de90
TL
15#include <boost/multiprecision/traits/is_complex.hpp>
16#include <boost/multiprecision/traits/is_convertible_arithmetic.hpp>
17#include <boost/multiprecision/detail/hash.hpp>
18#include <boost/multiprecision/detail/number_base.hpp>
92f5a8d4
TL
19#include <istream> // stream operators
20#include <cstdio> // EOF
21#include <cctype> // isspace
1e59de90
TL
22#include <functional> // std::hash
23#include <type_traits>
92f5a8d4
TL
24#ifndef BOOST_NO_CXX17_HDR_STRING_VIEW
25#include <string_view>
26#endif
7c673cae 27
1e59de90
TL
28#ifndef BOOST_MP_STANDALONE
29#include <boost/core/nvp.hpp>
30#endif
31
92f5a8d4
TL
32namespace boost {
33namespace multiprecision {
7c673cae
FG
34
35#ifdef BOOST_MSVC
36// warning C4127: conditional expression is constant
37// warning C4714: function marked as __forceinline not inlined
38#pragma warning(push)
92f5a8d4 39#pragma warning(disable : 4127 4714 6326)
7c673cae
FG
40#endif
41
42template <class Backend, expression_template_option ExpressionTemplates>
43class number
44{
1e59de90 45 using self_type = number<Backend, ExpressionTemplates>;
92f5a8d4
TL
46
47 public:
1e59de90
TL
48 using backend_type = Backend ;
49 using value_type = typename component_type<self_type>::type;
50
51 static constexpr expression_template_option et = ExpressionTemplates;
52
53 BOOST_MP_FORCEINLINE constexpr number() noexcept(noexcept(Backend())) {}
54 BOOST_MP_FORCEINLINE constexpr number(const number& e) noexcept(noexcept(Backend(std::declval<Backend const&>()))) : m_backend(e.m_backend) {}
7c673cae 55 template <class V>
1e59de90
TL
56 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const V& v,
57 typename std::enable_if<
58 (boost::multiprecision::detail::is_convertible_arithmetic<V, Backend>::value
59 || std::is_same<std::string, V>::value
60 || std::is_convertible<V, const char*>::value)
61 && !std::is_convertible<typename detail::canonical<V, Backend>::type, Backend>::value
62 && !detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value>::type* = nullptr)
7c673cae
FG
63 {
64 m_backend = canonical_value(v);
65 }
66 template <class V>
1e59de90
TL
67 BOOST_MP_FORCEINLINE constexpr number(const V& v, typename std::enable_if<
68 std::is_convertible<typename detail::canonical<V, Backend>::type, Backend>::value && !detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value>::type* = nullptr)
7c673cae 69#ifndef BOOST_INTEL
1e59de90 70 noexcept(noexcept(Backend(std::declval<typename detail::canonical<V, Backend>::type const&>())))
92f5a8d4
TL
71#endif
72 : m_backend(canonical_value(v))
73 {}
74 template <class V>
1e59de90
TL
75 BOOST_MP_FORCEINLINE constexpr number(const V& v, unsigned digits10,
76 typename std::enable_if<
77 (boost::multiprecision::detail::is_convertible_arithmetic<V, Backend>::value
78 || std::is_same<std::string, V>::value
79 || std::is_convertible<V, const char*>::value)
80 && !detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value
81 && (boost::multiprecision::number_category<Backend>::value != boost::multiprecision::number_kind_complex)
82 && (boost::multiprecision::number_category<Backend>::value != boost::multiprecision::number_kind_rational
83 && std::is_same<self_type, value_type>::value)>::type* = nullptr)
92f5a8d4
TL
84 : m_backend(canonical_value(v), digits10)
85 {}
1e59de90
TL
86 //
87 // Conversions from unscoped enum's are implicit:
88 //
89 template <class V>
90 BOOST_MP_FORCEINLINE
91#if !(defined(BOOST_MSVC) && (BOOST_MSVC <= 1900))
92 constexpr
93#endif
94 number(const V& v, typename std::enable_if<
95 std::is_enum<V>::value && std::is_convertible<V, int>::value && !std::is_convertible<typename detail::canonical<V, Backend>::type, Backend>::value && !detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value>::type* = nullptr)
96 : number(static_cast<typename std::underlying_type<V>::type>(v))
97 {}
98 //
99 // Conversions from scoped enum's are explicit:
100 //
101 template <class V>
102 BOOST_MP_FORCEINLINE explicit
103#if !(defined(BOOST_MSVC) && (BOOST_MSVC <= 1900))
104 constexpr
105#endif
106 number(const V& v, typename std::enable_if<
107 std::is_enum<V>::value && !std::is_convertible<V, int>::value && !std::is_convertible<typename detail::canonical<V, Backend>::type, Backend>::value && !detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value>::type* = nullptr)
108 : number(static_cast<typename std::underlying_type<V>::type>(v))
109 {}
110
111 BOOST_MP_FORCEINLINE constexpr number(const number& e, unsigned digits10)
112 noexcept(noexcept(Backend(std::declval<Backend const&>(), std::declval<unsigned>())))
92f5a8d4 113 : m_backend(e.m_backend, digits10) {}
7c673cae 114 template <class V>
1e59de90
TL
115 explicit BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const V& v, typename std::enable_if<
116 (boost::multiprecision::detail::is_arithmetic<V>::value || std::is_same<std::string, V>::value || std::is_convertible<V, const char*>::value) && !detail::is_explicitly_convertible<typename detail::canonical<V, Backend>::type, Backend>::value && detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value>::type* = nullptr)
117 noexcept(noexcept(std::declval<Backend&>() = std::declval<typename detail::canonical<V, Backend>::type const&>()))
7c673cae
FG
118 {
119 m_backend = canonical_value(v);
120 }
121 template <class V>
1e59de90
TL
122 explicit BOOST_MP_FORCEINLINE constexpr number(const V& v, typename std::enable_if<
123 detail::is_explicitly_convertible<typename detail::canonical<V, Backend>::type, Backend>::value && (detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value || !std::is_convertible<typename detail::canonical<V, Backend>::type, Backend>::value)>::type* = nullptr)
124 noexcept(noexcept(Backend(std::declval<typename detail::canonical<V, Backend>::type const&>())))
92f5a8d4 125 : m_backend(canonical_value(v)) {}
7c673cae 126 template <class V>
1e59de90 127 explicit BOOST_MP_FORCEINLINE constexpr number(const V& v, unsigned digits10, typename std::enable_if<(boost::multiprecision::detail::is_arithmetic<V>::value || std::is_same<std::string, V>::value || std::is_convertible<V, const char*>::value) && detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value && (boost::multiprecision::number_category<Backend>::value != boost::multiprecision::number_kind_complex) && (boost::multiprecision::number_category<Backend>::value != boost::multiprecision::number_kind_rational)>::type* = nullptr)
92f5a8d4
TL
128 : m_backend(canonical_value(v), digits10) {}
129
130 template <expression_template_option ET>
1e59de90
TL
131 BOOST_MP_FORCEINLINE constexpr number(const number<Backend, ET>& val)
132 noexcept(noexcept(Backend(std::declval<Backend const&>()))) : m_backend(val.backend()) {}
7c673cae
FG
133
134 template <class Other, expression_template_option ET>
92f5a8d4 135 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const number<Other, ET>& val,
1e59de90
TL
136 typename std::enable_if<(std::is_convertible<Other, Backend>::value && !detail::is_restricted_conversion<Other, Backend>::value)>::type* = nullptr)
137 noexcept(noexcept(Backend(std::declval<Other const&>())))
92f5a8d4 138 : m_backend(val.backend()) {}
7c673cae
FG
139
140 template <class Other, expression_template_option ET>
1e59de90
TL
141 explicit BOOST_MP_CXX14_CONSTEXPR number(const number<Other, ET>& val, typename std::enable_if<
142 (!detail::is_explicitly_convertible<Other, Backend>::value)>::type* = nullptr)
7c673cae
FG
143 {
144 //
145 // Attempt a generic interconvertion:
146 //
92f5a8d4
TL
147 detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard_1(val);
148 detail::scoped_default_precision<number<Other, ET> > precision_guard_2(val);
7c673cae 149 using detail::generic_interconvert;
1e59de90
TL
150 BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
151 {
152 if (precision_guard_1.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
153 {
154 self_type t;
155 generic_interconvert(t.backend(), val.backend(), number_category<Backend>(), number_category<Other>());
156 *this = std::move(t);
157 return;
158 }
159 }
7c673cae
FG
160 generic_interconvert(backend(), val.backend(), number_category<Backend>(), number_category<Other>());
161 }
162 template <class Other, expression_template_option ET>
1e59de90
TL
163 explicit BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const number<Other, ET>& val, typename std::enable_if<
164 (detail::is_explicitly_convertible<Other, Backend>::value && (detail::is_restricted_conversion<Other, Backend>::value || !std::is_convertible<Other, Backend>::value))>::type* = nullptr) noexcept(noexcept(Backend(std::declval<Other const&>())))
92f5a8d4 165 : m_backend(val.backend()) {}
7c673cae 166
92f5a8d4
TL
167 template <class V, class U>
168 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const V& v1, const U& v2,
1e59de90
TL
169 typename std::enable_if<
170 (std::is_convertible<V, value_type>::value
171 && std::is_convertible<U, value_type>::value
172 && !std::is_same<value_type, self_type>::value
173 && std::is_constructible<Backend, typename detail::canonical<typename std::remove_cv<typename std::remove_reference<decltype(detail::evaluate_if_expression(std::declval<const V&>()))>::type>::type, Backend>::type const&, typename detail::canonical<typename std::remove_cv<typename std::remove_reference<decltype(detail::evaluate_if_expression(std::declval<const U&>()))>::type>::type, Backend>::type const&>::value
174 && !boost::multiprecision::detail::is_variable_precision<Backend>::value)>::type* = nullptr)
175 : m_backend(canonical_value(detail::evaluate_if_expression(v1)), canonical_value(detail::evaluate_if_expression(v2)))
176 {
177 }
178 template <class V, class U>
179 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(V&& v1, const U& v2,
180 typename std::enable_if<
181 (std::is_convertible<V, value_type>::value
182 && std::is_convertible<U, value_type>::value
183 && !std::is_same<value_type, self_type>::value
184 && std::is_constructible<Backend, typename detail::canonical<typename std::remove_cv<typename std::remove_reference<decltype(detail::evaluate_if_expression(std::declval<const V&>()))>::type>::type, Backend>::type const&, typename detail::canonical<typename std::remove_cv<typename std::remove_reference<decltype(detail::evaluate_if_expression(std::declval<const U&>()))>::type>::type, Backend>::type const&>::value
185 && !boost::multiprecision::detail::is_variable_precision<Backend>::value)>::type* = nullptr)
186 : m_backend(canonical_value(detail::evaluate_if_expression(static_cast<V&&>(v1))), canonical_value(detail::evaluate_if_expression(v2)))
187 {
188 }
189 template <class V, class U>
190 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const V& v1, U&& v2,
191 typename std::enable_if<
192 (std::is_convertible<V, value_type>::value
193 && std::is_convertible<U, value_type>::value
194 && !std::is_same<value_type, self_type>::value
195 && std::is_constructible<Backend, typename detail::canonical<typename std::remove_cv<typename std::remove_reference<decltype(detail::evaluate_if_expression(std::declval<const V&>()))>::type>::type, Backend>::type const&, typename detail::canonical<typename std::remove_cv<typename std::remove_reference<decltype(detail::evaluate_if_expression(std::declval<const U&>()))>::type>::type, Backend>::type const&>::value
196 && !boost::multiprecision::detail::is_variable_precision<Backend>::value)>::type* = nullptr)
197 : m_backend(canonical_value(detail::evaluate_if_expression(v1)), canonical_value(detail::evaluate_if_expression(static_cast<U&&>(v2))))
198 {
199 }
200 template <class V, class U>
201 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(V&& v1, U&& v2,
202 typename std::enable_if<
203 (std::is_convertible<V, value_type>::value
204 && std::is_convertible<U, value_type>::value
205 && !std::is_same<value_type, self_type>::value
206 && std::is_constructible<Backend, typename detail::canonical<typename std::remove_cv<typename std::remove_reference<decltype(detail::evaluate_if_expression(std::declval<const V&>()))>::type>::type, Backend>::type const&, typename detail::canonical<typename std::remove_cv<typename std::remove_reference<decltype(detail::evaluate_if_expression(std::declval<const U&>()))>::type>::type, Backend>::type const&>::value
207 && !boost::multiprecision::detail::is_variable_precision<Backend>::value)>::type* = nullptr)
208 : m_backend(canonical_value(detail::evaluate_if_expression(static_cast<V&&>(v1))), canonical_value(detail::evaluate_if_expression(static_cast<U&&>(v2))))
209 {
210 }
211 template <class V, class U>
212 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const V& v1, const U& v2,
213 typename std::enable_if<
214 (std::is_convertible<V, value_type>::value
215 && std::is_convertible<U, value_type>::value
216 && !std::is_same<value_type, self_type>::value
217 && (!std::is_constructible<Backend, typename detail::canonical<typename std::remove_cv<typename std::remove_reference<decltype(detail::evaluate_if_expression(std::declval<const V&>()))>::type>::type, Backend>::type const&, typename detail::canonical<typename std::remove_cv<typename std::remove_reference<decltype(detail::evaluate_if_expression(std::declval<const U&>()))>::type>::type, Backend>::type const&>::value
218 || boost::multiprecision::detail::is_variable_precision<Backend>::value))>::type* = nullptr)
7c673cae
FG
219 {
220 using default_ops::assign_components;
1e59de90
TL
221 // Copy precision options from this type to component_type:
222 boost::multiprecision::detail::scoped_precision_options<value_type> scoped_opts(*this);
223 // precision guards:
224 detail::scoped_default_precision<self_type> precision_guard(v1, v2, *this);
225 detail::scoped_default_precision<value_type> component_precision_guard(v1, v2, *this);
92f5a8d4
TL
226 assign_components(m_backend, canonical_value(detail::evaluate_if_expression(v1)), canonical_value(detail::evaluate_if_expression(v2)));
227 }
228 template <class V, class U>
229 BOOST_MP_FORCEINLINE explicit BOOST_MP_CXX14_CONSTEXPR number(const V& v1, const U& v2,
1e59de90
TL
230 typename std::enable_if<
231 (std::is_constructible<value_type, V>::value || std::is_convertible<V, std::string>::value) && (std::is_constructible<value_type, U>::value || std::is_convertible<U, std::string>::value) && !std::is_same<value_type, self_type>::value && !std::is_same<V, self_type>::value && !(std::is_convertible<V, value_type>::value && std::is_convertible<U, value_type>::value)>::type* = nullptr)
92f5a8d4
TL
232 {
233 using default_ops::assign_components;
1e59de90
TL
234 // Copy precision options from this type to component_type:
235 boost::multiprecision::detail::scoped_precision_options<value_type> scoped_opts(*this);
236 // precision guards:
237 detail::scoped_default_precision<self_type> precision_guard(v1, v2, *this);
238 detail::scoped_default_precision<value_type> component_precision_guard(v1, v2, *this);
92f5a8d4
TL
239 assign_components(m_backend, canonical_value(detail::evaluate_if_expression(v1)), canonical_value(detail::evaluate_if_expression(v2)));
240 }
241#ifndef BOOST_NO_CXX17_HDR_STRING_VIEW
242 //
243 // Support for new types in C++17
244 //
245 template <class Traits>
246 explicit inline BOOST_MP_CXX14_CONSTEXPR number(const std::basic_string_view<char, Traits>& view)
247 {
248 using default_ops::assign_from_string_view;
249 assign_from_string_view(this->backend(), view);
250 }
251 template <class Traits>
252 explicit inline BOOST_MP_CXX14_CONSTEXPR number(const std::basic_string_view<char, Traits>& view_x, const std::basic_string_view<char, Traits>& view_y)
253 {
254 using default_ops::assign_from_string_view;
255 assign_from_string_view(this->backend(), view_x, view_y);
256 }
257 template <class Traits>
258 explicit BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const std::basic_string_view<char, Traits>& v, unsigned digits10)
259 : m_backend(canonical_value(v), digits10) {}
260 template <class Traits>
261 BOOST_MP_CXX14_CONSTEXPR number& assign(const std::basic_string_view<char, Traits>& view)
262 {
263 using default_ops::assign_from_string_view;
264 assign_from_string_view(this->backend(), view);
265 return *this;
7c673cae 266 }
92f5a8d4
TL
267#endif
268
269 template <class V, class U>
270 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const V& v1, const U& v2, unsigned digits10,
1e59de90 271 typename std::enable_if<(std::is_convertible<V, value_type>::value && std::is_convertible<U, value_type>::value && !std::is_same<value_type, self_type>::value)>::type* = nullptr)
92f5a8d4
TL
272 : m_backend(canonical_value(detail::evaluate_if_expression(v1)), canonical_value(detail::evaluate_if_expression(v2)), digits10)
273 {}
274 template <class V, class U>
275 BOOST_MP_FORCEINLINE explicit BOOST_MP_CXX14_CONSTEXPR number(const V& v1, const U& v2, unsigned digits10,
1e59de90
TL
276 typename std::enable_if<((std::is_constructible<value_type, V>::value || std::is_convertible<V, std::string>::value) && (std::is_constructible<value_type, U>::value || std::is_convertible<U, std::string>::value) && !std::is_same<value_type, self_type>::value) && !(std::is_convertible<V, value_type>::value && std::is_convertible<U, value_type>::value)>::type* = nullptr)
277 : m_backend(detail::evaluate_if_expression(v1), detail::evaluate_if_expression(v2), digits10) {}
92f5a8d4 278
7c673cae 279 template <class Other, expression_template_option ET>
1e59de90
TL
280 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(
281 const number<Other, ET>& v1,
282 const number<Other, ET>& v2,
283 typename std::enable_if<
284 std::is_convertible<Other, Backend>::value
285 && (!std::is_constructible<Backend, typename detail::canonical<typename std::remove_cv<typename std::remove_reference<decltype(detail::evaluate_if_expression(std::declval<const number<Other, ET>&>()))>::type>::type, Backend>::type const&, typename detail::canonical<typename std::remove_cv<typename std::remove_reference<decltype(detail::evaluate_if_expression(std::declval<const number<Other, ET>&>()))>::type>::type, Backend>::type const&>::value || boost::multiprecision::detail::is_variable_precision<Backend>::value) >::type* = nullptr)
7c673cae
FG
286 {
287 using default_ops::assign_components;
92f5a8d4 288 detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(v1, v2);
7c673cae
FG
289 assign_components(m_backend, v1.backend(), v2.backend());
290 }
291
292 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
1e59de90 293 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value, number&>::type operator=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
7c673cae 294 {
1e59de90 295 using tag_type = std::integral_constant<bool, is_equivalent_number_type<number, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value>;
92f5a8d4
TL
296 detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(e);
297 //
298 // If the current precision of *this differs from that of expression e, then we
299 // create a temporary (which will have the correct precision thanks to precision_guard)
300 // and then move the result into *this. In C++17 we add a leading "if constexpr"
301 // which causes this code to be eliminated in the common case that this type is
302 // not actually variable precision. Pre C++17 this code should still be mostly
303 // optimised away, but we can't prevent instantiation of the dead code leading
304 // to longer build and possibly link times.
305 //
1e59de90 306 BOOST_IF_CONSTEXPR (std::is_same<self_type, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value)
92f5a8d4 307 {
1e59de90
TL
308 BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
309 if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
310 {
311 number t(e);
312 return *this = std::move(t);
313 }
92f5a8d4 314 }
7c673cae
FG
315 do_assign(e, tag_type());
316 return *this;
317 }
318 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
92f5a8d4 319 BOOST_MP_CXX14_CONSTEXPR number& assign(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
7c673cae 320 {
1e59de90 321 using tag_type = std::integral_constant<bool, is_equivalent_number_type<number, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value>;
92f5a8d4
TL
322 detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(e);
323 //
324 // If the current precision of *this differs from that of expression e, then we
325 // create a temporary (which will have the correct precision thanks to precision_guard)
326 // and then move the result into *this. In C++17 we add a leading "if constexpr"
327 // which causes this code to be eliminated in the common case that this type is
328 // not actually variable precision. Pre C++17 this code should still be mostly
329 // optimised away, but we can't prevent instantiation of the dead code leading
330 // to longer build and possibly link times.
331 //
1e59de90 332 BOOST_IF_CONSTEXPR(std::is_same<self_type, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value)
92f5a8d4 333 {
1e59de90
TL
334 BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
335 if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
336 {
337 number t;
338 t.assign(e);
339 return *this = std::move(t);
340 }
92f5a8d4 341 }
7c673cae
FG
342 do_assign(e, tag_type());
343 return *this;
344 }
1e59de90
TL
345 BOOST_MP_CXX14_CONSTEXPR number& assign(const value_type& a, const value_type& b)
346 {
347 assign_components(backend(), a.backend(), b.backend());
348 return *this;
349 }
350 template <class V, class U>
351 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<(std::is_convertible<V, value_type>::value&& std::is_convertible<U, value_type>::value && !std::is_same<value_type, self_type>::value), number&>::type
352 assign(const V& v1, const U& v2, unsigned Digits)
353 {
354 self_type r(v1, v2, Digits);
355 boost::multiprecision::detail::scoped_source_precision<self_type> scope;
356 return *this = r;
357 }
358 BOOST_MP_CXX14_CONSTEXPR number& assign(const value_type & a, const value_type & b, unsigned Digits)
359 {
360 this->precision(Digits);
361 boost::multiprecision::detail::scoped_target_precision<self_type> scoped;
362 assign_components(backend(), canonical_value(detail::evaluate_if_expression(a)), canonical_value(detail::evaluate_if_expression(b)));
363 return *this;
364 }
7c673cae 365
92f5a8d4 366 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number& operator=(const number& e)
1e59de90 367 noexcept(noexcept(std::declval<Backend&>() = std::declval<Backend const&>()))
7c673cae
FG
368 {
369 m_backend = e.m_backend;
370 return *this;
371 }
372
373 template <class V>
1e59de90 374 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
92f5a8d4 375 operator=(const V& v)
1e59de90 376 noexcept(noexcept(std::declval<Backend&>() = std::declval<const typename detail::canonical<V, Backend>::type&>()))
7c673cae
FG
377 {
378 m_backend = canonical_value(v);
379 return *this;
380 }
381 template <class V>
92f5a8d4 382 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number<Backend, ExpressionTemplates>& assign(const V& v)
1e59de90 383 noexcept(noexcept(std::declval<Backend&>() = std::declval<const typename detail::canonical<V, Backend>::type&>()))
7c673cae
FG
384 {
385 m_backend = canonical_value(v);
386 return *this;
387 }
1e59de90
TL
388 template <class V, class U>
389 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number<Backend, ExpressionTemplates>& assign(const V& v, const U& digits10_or_component)
390 noexcept(noexcept(std::declval<Backend&>() = std::declval<const typename detail::canonical<V, Backend>::type&>()))
92f5a8d4 391 {
1e59de90
TL
392 number t(v, digits10_or_component);
393 boost::multiprecision::detail::scoped_source_precision<self_type> scope;
92f5a8d4
TL
394 return *this = t;
395 }
7c673cae 396 template <class Other, expression_template_option ET>
1e59de90 397 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!boost::multiprecision::detail::is_explicitly_convertible<Other, Backend>::value, number<Backend, ExpressionTemplates>&>::type
92f5a8d4 398 assign(const number<Other, ET>& v)
7c673cae
FG
399 {
400 //
401 // Attempt a generic interconvertion:
402 //
403 using detail::generic_interconvert;
1e59de90
TL
404 detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, v);
405 detail::scoped_default_precision<number<Other, ET> > precision_guard2(*this, v);
92f5a8d4
TL
406 //
407 // If the current precision of *this differs from that of value v, then we
408 // create a temporary (which will have the correct precision thanks to precision_guard)
409 // and then move the result into *this. In C++17 we add a leading "if constexpr"
410 // which causes this code to be eliminated in the common case that this type is
411 // not actually variable precision. Pre C++17 this code should still be mostly
412 // optimised away, but we can't prevent instantiation of the dead code leading
413 // to longer build and possibly link times.
414 //
415 BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
1e59de90 416 if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
92f5a8d4
TL
417 {
418 number t(v);
1e59de90 419 return *this = std::move(t);
92f5a8d4 420 }
7c673cae
FG
421 generic_interconvert(backend(), v.backend(), number_category<Backend>(), number_category<Other>());
422 return *this;
423 }
424
425 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
1e59de90 426 BOOST_MP_CXX14_CONSTEXPR number(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e, typename std::enable_if<std::is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value>::type* = nullptr)
7c673cae 427 {
92f5a8d4
TL
428 //
429 // No preicsion guard here, we already have one in operator=
430 //
7c673cae
FG
431 *this = e;
432 }
433 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
92f5a8d4 434 explicit BOOST_MP_CXX14_CONSTEXPR number(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e,
1e59de90 435 typename std::enable_if<!std::is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value && boost::multiprecision::detail::is_explicitly_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value>::type* = nullptr)
7c673cae 436 {
92f5a8d4
TL
437 //
438 // No precision guard as assign has one already:
439 //
7c673cae
FG
440 assign(e);
441 }
442
1e59de90
TL
443 // rvalues:
444 BOOST_MP_FORCEINLINE constexpr number(number&& r)
445 noexcept(noexcept(Backend(std::declval<Backend>())))
92f5a8d4
TL
446 : m_backend(static_cast<Backend&&>(r.m_backend))
447 {}
1e59de90 448 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number& operator=(number&& r) noexcept(noexcept(std::declval<Backend&>() = std::declval<Backend>()))
7c673cae
FG
449 {
450 m_backend = static_cast<Backend&&>(r.m_backend);
451 return *this;
452 }
1e59de90
TL
453 template <class Other, expression_template_option ET>
454 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(number<Other, ET>&& val,
455 typename std::enable_if<(std::is_convertible<Other, Backend>::value && !detail::is_restricted_conversion<Other, Backend>::value)>::type* = nullptr)
456 noexcept(noexcept(Backend(std::declval<Other const&>())))
457 : m_backend(static_cast<number<Other, ET>&&>(val).backend()) {}
458 template <class Other, expression_template_option ET>
459 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<(std::is_convertible<Other, Backend>::value && !detail::is_restricted_conversion<Other, Backend>::value), number&>::type
460 operator=(number<Other, ET>&& val)
461 noexcept(noexcept(Backend(std::declval<Other const&>())))
462 {
463 m_backend = std::move(val).backend();
464 return *this;
465 }
7c673cae 466
92f5a8d4 467 BOOST_MP_CXX14_CONSTEXPR number& operator+=(const self_type& val)
7c673cae 468 {
92f5a8d4
TL
469 detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, val);
470 //
471 // If the current precision of *this differs from that of expression e, then we
472 // create a temporary (which will have the correct precision thanks to precision_guard)
473 // and then move the result into *this. In C++17 we add a leading "if constexpr"
474 // which causes this code to be eliminated in the common case that this type is
475 // not actually variable precision. Pre C++17 this code should still be mostly
476 // optimised away, but we can't prevent instantiation of the dead code leading
477 // to longer build and possibly link times.
478 //
479 BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
1e59de90 480 if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
92f5a8d4
TL
481 {
482 number t(*this + val);
1e59de90 483 return *this = std::move(t);
92f5a8d4 484 }
7c673cae
FG
485 do_add(detail::expression<detail::terminal, self_type>(val), detail::terminal());
486 return *this;
487 }
488
489 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
1e59de90 490 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value, number&>::type operator+=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
7c673cae 491 {
92f5a8d4 492 detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
7c673cae
FG
493 // Create a copy if e contains this, but not if we're just doing a
494 // x += x
92f5a8d4 495 if ((contains_self(e) && !is_self(e)))
7c673cae
FG
496 {
497 self_type temp(e);
498 do_add(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
499 }
500 else
501 {
502 do_add(e, tag());
503 }
504 return *this;
505 }
506
507 template <class Arg1, class Arg2, class Arg3, class Arg4>
92f5a8d4 508 BOOST_MP_CXX14_CONSTEXPR number& operator+=(const detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>& e)
7c673cae 509 {
92f5a8d4
TL
510 detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
511 //
512 // If the current precision of *this differs from that of expression e, then we
513 // create a temporary (which will have the correct precision thanks to precision_guard)
514 // and then move the result into *this. In C++17 we add a leading "if constexpr"
515 // which causes this code to be eliminated in the common case that this type is
516 // not actually variable precision. Pre C++17 this code should still be mostly
517 // optimised away, but we can't prevent instantiation of the dead code leading
518 // to longer build and possibly link times.
519 //
1e59de90 520 BOOST_IF_CONSTEXPR(std::is_same<self_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::result_type>::value)
92f5a8d4 521 {
1e59de90
TL
522 BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
523 if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
524 {
525 number t(*this + e);
526 return *this = std::move(t);
527 }
92f5a8d4 528 }
7c673cae
FG
529 //
530 // Fused multiply-add:
531 //
532 using default_ops::eval_multiply_add;
533 eval_multiply_add(m_backend, canonical_value(e.left_ref()), canonical_value(e.right_ref()));
534 return *this;
535 }
536
537 template <class V>
1e59de90 538 typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
92f5a8d4 539 BOOST_MP_CXX14_CONSTEXPR operator+=(const V& v)
7c673cae 540 {
1e59de90
TL
541 detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, v);
542 //
543 // If the current precision of *this differs from that of value v, then we
544 // create a temporary (which will have the correct precision thanks to precision_guard)
545 // and then move the result into *this. In C++17 we add a leading "if constexpr"
546 // which causes this code to be eliminated in the common case that this type is
547 // not actually variable precision. Pre C++17 this code should still be mostly
548 // optimised away, but we can't prevent instantiation of the dead code leading
549 // to longer build and possibly link times.
550 //
551 BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
552 if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
553 {
554 number t(*this + v);
555 return *this = std::move(t);
556 }
557
7c673cae
FG
558 using default_ops::eval_add;
559 eval_add(m_backend, canonical_value(v));
560 return *this;
561 }
562
92f5a8d4 563 BOOST_MP_CXX14_CONSTEXPR number& operator-=(const self_type& val)
7c673cae 564 {
92f5a8d4
TL
565 detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, val);
566 //
567 // If the current precision of *this differs from that of expression e, then we
568 // create a temporary (which will have the correct precision thanks to precision_guard)
569 // and then move the result into *this. In C++17 we add a leading "if constexpr"
570 // which causes this code to be eliminated in the common case that this type is
571 // not actually variable precision. Pre C++17 this code should still be mostly
572 // optimised away, but we can't prevent instantiation of the dead code leading
573 // to longer build and possibly link times.
574 //
575 BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
1e59de90 576 if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
92f5a8d4
TL
577 {
578 number t(*this - val);
1e59de90 579 return *this = std::move(t);
92f5a8d4 580 }
7c673cae
FG
581 do_subtract(detail::expression<detail::terminal, self_type>(val), detail::terminal());
582 return *this;
583 }
584
585 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
1e59de90 586 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value, number&>::type operator-=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
7c673cae 587 {
92f5a8d4 588 detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
7c673cae 589 // Create a copy if e contains this:
92f5a8d4 590 if (contains_self(e))
7c673cae
FG
591 {
592 self_type temp(e);
593 do_subtract(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
594 }
595 else
596 {
597 do_subtract(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
598 }
599 return *this;
600 }
601
602 template <class V>
1e59de90 603 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
92f5a8d4 604 operator-=(const V& v)
7c673cae 605 {
1e59de90
TL
606 detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, v);
607 //
608 // If the current precision of *this differs from that of value v, then we
609 // create a temporary (which will have the correct precision thanks to precision_guard)
610 // and then move the result into *this. In C++17 we add a leading "if constexpr"
611 // which causes this code to be eliminated in the common case that this type is
612 // not actually variable precision. Pre C++17 this code should still be mostly
613 // optimised away, but we can't prevent instantiation of the dead code leading
614 // to longer build and possibly link times.
615 //
616 BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
617 if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
618 {
619 number t(*this - v);
620 return *this = std::move(t);
621 }
622
7c673cae
FG
623 using default_ops::eval_subtract;
624 eval_subtract(m_backend, canonical_value(v));
625 return *this;
626 }
627
628 template <class Arg1, class Arg2, class Arg3, class Arg4>
92f5a8d4 629 BOOST_MP_CXX14_CONSTEXPR number& operator-=(const detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>& e)
7c673cae 630 {
92f5a8d4
TL
631 detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
632 //
633 // If the current precision of *this differs from that of expression e, then we
634 // create a temporary (which will have the correct precision thanks to precision_guard)
635 // and then move the result into *this. In C++17 we add a leading "if constexpr"
636 // which causes this code to be eliminated in the common case that this type is
637 // not actually variable precision. Pre C++17 this code should still be mostly
638 // optimised away, but we can't prevent instantiation of the dead code leading
639 // to longer build and possibly link times.
640 //
1e59de90 641 BOOST_IF_CONSTEXPR(std::is_same<self_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::result_type>::value)
92f5a8d4 642 {
1e59de90
TL
643 BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
644 if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
645 {
646 number t(*this - e);
647 return *this = std::move(t);
648 }
92f5a8d4 649 }
7c673cae
FG
650 //
651 // Fused multiply-subtract:
652 //
653 using default_ops::eval_multiply_subtract;
654 eval_multiply_subtract(m_backend, canonical_value(e.left_ref()), canonical_value(e.right_ref()));
655 return *this;
656 }
657
92f5a8d4 658 BOOST_MP_CXX14_CONSTEXPR number& operator*=(const self_type& e)
7c673cae 659 {
92f5a8d4
TL
660 detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
661 //
662 // If the current precision of *this differs from that of expression e, then we
663 // create a temporary (which will have the correct precision thanks to precision_guard)
664 // and then move the result into *this. In C++17 we add a leading "if constexpr"
665 // which causes this code to be eliminated in the common case that this type is
666 // not actually variable precision. Pre C++17 this code should still be mostly
667 // optimised away, but we can't prevent instantiation of the dead code leading
668 // to longer build and possibly link times.
669 //
670 BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
1e59de90 671 if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
92f5a8d4
TL
672 {
673 number t(*this * e);
1e59de90 674 return *this = std::move(t);
92f5a8d4 675 }
7c673cae
FG
676 do_multiplies(detail::expression<detail::terminal, self_type>(e), detail::terminal());
677 return *this;
678 }
679
680 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
1e59de90 681 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value, number&>::type operator*=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
7c673cae 682 {
92f5a8d4 683 detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
7c673cae
FG
684 // Create a temporary if the RHS references *this, but not
685 // if we're just doing an x *= x;
92f5a8d4 686 if ((contains_self(e) && !is_self(e)))
7c673cae
FG
687 {
688 self_type temp(e);
689 do_multiplies(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
690 }
691 else
692 {
693 do_multiplies(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
694 }
695 return *this;
696 }
697
698 template <class V>
1e59de90 699 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
92f5a8d4 700 operator*=(const V& v)
7c673cae 701 {
1e59de90
TL
702 detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, v);
703 //
704 // If the current precision of *this differs from that of value v, then we
705 // create a temporary (which will have the correct precision thanks to precision_guard)
706 // and then move the result into *this. In C++17 we add a leading "if constexpr"
707 // which causes this code to be eliminated in the common case that this type is
708 // not actually variable precision. Pre C++17 this code should still be mostly
709 // optimised away, but we can't prevent instantiation of the dead code leading
710 // to longer build and possibly link times.
711 //
712 BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
713 if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
714 {
715 number t(*this + v);
716 return *this = std::move(t);
717 }
718
7c673cae
FG
719 using default_ops::eval_multiply;
720 eval_multiply(m_backend, canonical_value(v));
721 return *this;
722 }
723
92f5a8d4 724 BOOST_MP_CXX14_CONSTEXPR number& operator%=(const self_type& e)
7c673cae 725 {
1e59de90 726 static_assert(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
92f5a8d4
TL
727 detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
728 //
729 // If the current precision of *this differs from that of expression e, then we
730 // create a temporary (which will have the correct precision thanks to precision_guard)
731 // and then move the result into *this. In C++17 we add a leading "if constexpr"
732 // which causes this code to be eliminated in the common case that this type is
733 // not actually variable precision. Pre C++17 this code should still be mostly
734 // optimised away, but we can't prevent instantiation of the dead code leading
735 // to longer build and possibly link times.
736 //
737 BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
1e59de90 738 if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
92f5a8d4
TL
739 {
740 number t(*this % e);
1e59de90 741 return *this = std::move(t);
92f5a8d4 742 }
7c673cae
FG
743 do_modulus(detail::expression<detail::terminal, self_type>(e), detail::terminal());
744 return *this;
745 }
746 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
1e59de90 747 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value, number&>::type operator%=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
7c673cae 748 {
1e59de90 749 static_assert(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
92f5a8d4 750 detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
7c673cae 751 // Create a temporary if the RHS references *this:
92f5a8d4 752 if (contains_self(e))
7c673cae
FG
753 {
754 self_type temp(e);
755 do_modulus(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
756 }
757 else
758 {
759 do_modulus(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
760 }
761 return *this;
762 }
763 template <class V>
1e59de90 764 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
92f5a8d4 765 operator%=(const V& v)
7c673cae 766 {
1e59de90 767 static_assert(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
7c673cae
FG
768 using default_ops::eval_modulus;
769 eval_modulus(m_backend, canonical_value(v));
770 return *this;
771 }
772
773 //
774 // These operators are *not* proto-ized.
775 // The issue is that the increment/decrement must happen
776 // even if the result of the operator *is never used*.
777 // Possibly we could modify our expression wrapper to
778 // execute the increment/decrement on destruction, but
779 // correct implementation will be tricky, so defered for now...
780 //
92f5a8d4 781 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number& operator++()
7c673cae
FG
782 {
783 using default_ops::eval_increment;
784 eval_increment(m_backend);
785 return *this;
786 }
787
92f5a8d4 788 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number& operator--()
7c673cae
FG
789 {
790 using default_ops::eval_decrement;
791 eval_decrement(m_backend);
792 return *this;
793 }
794
92f5a8d4 795 inline BOOST_MP_CXX14_CONSTEXPR number operator++(int)
7c673cae
FG
796 {
797 using default_ops::eval_increment;
798 self_type temp(*this);
799 eval_increment(m_backend);
92f5a8d4 800 return temp;
7c673cae
FG
801 }
802
92f5a8d4 803 inline BOOST_MP_CXX14_CONSTEXPR number operator--(int)
7c673cae
FG
804 {
805 using default_ops::eval_decrement;
806 self_type temp(*this);
807 eval_decrement(m_backend);
92f5a8d4 808 return temp;
7c673cae
FG
809 }
810
811 template <class V>
1e59de90 812 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<V>::value, number&>::type operator<<=(V val)
7c673cae 813 {
1e59de90
TL
814 static_assert(number_category<Backend>::value == number_kind_integer, "The left-shift operation is only valid for integer types");
815 detail::check_shift_range(val, std::integral_constant<bool, (sizeof(V) > sizeof(std::size_t))>(), std::integral_constant<bool, boost::multiprecision::detail::is_signed<V>::value && boost::multiprecision::detail::is_integral<V>::value > ());
7c673cae
FG
816 eval_left_shift(m_backend, static_cast<std::size_t>(canonical_value(val)));
817 return *this;
818 }
819
820 template <class V>
1e59de90 821 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<V>::value, number&>::type operator>>=(V val)
7c673cae 822 {
1e59de90
TL
823 static_assert(number_category<Backend>::value == number_kind_integer, "The right-shift operation is only valid for integer types");
824 detail::check_shift_range(val, std::integral_constant<bool, (sizeof(V) > sizeof(std::size_t))>(), std::integral_constant<bool, boost::multiprecision::detail::is_signed<V>::value && boost::multiprecision::detail::is_integral<V>::value>());
7c673cae
FG
825 eval_right_shift(m_backend, static_cast<std::size_t>(canonical_value(val)));
826 return *this;
827 }
828
92f5a8d4 829 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number& operator/=(const self_type& e)
7c673cae 830 {
92f5a8d4
TL
831 detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
832 //
833 // If the current precision of *this differs from that of expression e, then we
834 // create a temporary (which will have the correct precision thanks to precision_guard)
835 // and then move the result into *this. In C++17 we add a leading "if constexpr"
836 // which causes this code to be eliminated in the common case that this type is
837 // not actually variable precision. Pre C++17 this code should still be mostly
838 // optimised away, but we can't prevent instantiation of the dead code leading
839 // to longer build and possibly link times.
840 //
841 BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
1e59de90 842 if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
92f5a8d4
TL
843 {
844 number t(*this / e);
1e59de90 845 return *this = std::move(t);
92f5a8d4 846 }
7c673cae
FG
847 do_divide(detail::expression<detail::terminal, self_type>(e), detail::terminal());
848 return *this;
849 }
850
851 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
1e59de90 852 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value, number&>::type operator/=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
7c673cae 853 {
92f5a8d4 854 detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
7c673cae 855 // Create a temporary if the RHS references *this:
92f5a8d4 856 if (contains_self(e))
7c673cae
FG
857 {
858 self_type temp(e);
859 do_divide(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
860 }
861 else
862 {
863 do_divide(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
864 }
865 return *this;
866 }
867
868 template <class V>
1e59de90 869 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
92f5a8d4 870 operator/=(const V& v)
7c673cae 871 {
1e59de90
TL
872 detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, v);
873 //
874 // If the current precision of *this differs from that of value v, then we
875 // create a temporary (which will have the correct precision thanks to precision_guard)
876 // and then move the result into *this. In C++17 we add a leading "if constexpr"
877 // which causes this code to be eliminated in the common case that this type is
878 // not actually variable precision. Pre C++17 this code should still be mostly
879 // optimised away, but we can't prevent instantiation of the dead code leading
880 // to longer build and possibly link times.
881 //
882 BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
883 if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
884 {
885 number t(*this + v);
886 return *this = std::move(t);
887 }
888
7c673cae
FG
889 using default_ops::eval_divide;
890 eval_divide(m_backend, canonical_value(v));
891 return *this;
892 }
893
92f5a8d4 894 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number& operator&=(const self_type& e)
7c673cae 895 {
1e59de90 896 static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types");
7c673cae
FG
897 do_bitwise_and(detail::expression<detail::terminal, self_type>(e), detail::terminal());
898 return *this;
899 }
900
901 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
1e59de90 902 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value, number&>::type operator&=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
7c673cae 903 {
1e59de90 904 static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types");
7c673cae
FG
905 // Create a temporary if the RHS references *this, but not
906 // if we're just doing an x &= x;
92f5a8d4 907 if (contains_self(e) && !is_self(e))
7c673cae
FG
908 {
909 self_type temp(e);
910 do_bitwise_and(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
911 }
912 else
913 {
914 do_bitwise_and(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
915 }
916 return *this;
917 }
918
919 template <class V>
1e59de90 920 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
92f5a8d4 921 operator&=(const V& v)
7c673cae 922 {
1e59de90 923 static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types");
7c673cae
FG
924 using default_ops::eval_bitwise_and;
925 eval_bitwise_and(m_backend, canonical_value(v));
926 return *this;
927 }
928
92f5a8d4 929 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number& operator|=(const self_type& e)
7c673cae 930 {
1e59de90 931 static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types");
7c673cae
FG
932 do_bitwise_or(detail::expression<detail::terminal, self_type>(e), detail::terminal());
933 return *this;
934 }
935
936 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
1e59de90 937 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value, number&>::type operator|=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
7c673cae 938 {
1e59de90 939 static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types");
7c673cae
FG
940 // Create a temporary if the RHS references *this, but not
941 // if we're just doing an x |= x;
92f5a8d4 942 if (contains_self(e) && !is_self(e))
7c673cae
FG
943 {
944 self_type temp(e);
945 do_bitwise_or(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
946 }
947 else
948 {
949 do_bitwise_or(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
950 }
951 return *this;
952 }
953
954 template <class V>
1e59de90 955 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
92f5a8d4 956 operator|=(const V& v)
7c673cae 957 {
1e59de90 958 static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types");
7c673cae
FG
959 using default_ops::eval_bitwise_or;
960 eval_bitwise_or(m_backend, canonical_value(v));
961 return *this;
962 }
963
92f5a8d4 964 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number& operator^=(const self_type& e)
7c673cae 965 {
1e59de90 966 static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types");
7c673cae
FG
967 do_bitwise_xor(detail::expression<detail::terminal, self_type>(e), detail::terminal());
968 return *this;
969 }
970
971 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
1e59de90 972 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value, number&>::type operator^=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
7c673cae 973 {
1e59de90 974 static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types");
92f5a8d4 975 if (contains_self(e))
7c673cae
FG
976 {
977 self_type temp(e);
978 do_bitwise_xor(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
979 }
980 else
981 {
982 do_bitwise_xor(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
983 }
984 return *this;
985 }
986
987 template <class V>
1e59de90 988 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
92f5a8d4 989 operator^=(const V& v)
7c673cae 990 {
1e59de90 991 static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types");
7c673cae
FG
992 using default_ops::eval_bitwise_xor;
993 eval_bitwise_xor(m_backend, canonical_value(v));
994 return *this;
995 }
996 //
997 // swap:
998 //
1e59de90 999 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR void swap(self_type& other) noexcept(noexcept(std::declval<Backend>().swap(std::declval<Backend&>())))
7c673cae
FG
1000 {
1001 m_backend.swap(other.backend());
1002 }
1003 //
1004 // Zero and sign:
1005 //
92f5a8d4 1006 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool is_zero() const
7c673cae
FG
1007 {
1008 using default_ops::eval_is_zero;
1009 return eval_is_zero(m_backend);
1010 }
92f5a8d4 1011 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR int sign() const
7c673cae
FG
1012 {
1013 using default_ops::eval_get_sign;
1014 return eval_get_sign(m_backend);
1015 }
1016 //
1017 // String conversion functions:
1018 //
92f5a8d4 1019 std::string str(std::streamsize digits = 0, std::ios_base::fmtflags f = std::ios_base::fmtflags(0)) const
7c673cae
FG
1020 {
1021 return m_backend.str(digits, f);
1022 }
1e59de90
TL
1023
1024 #ifndef BOOST_MP_STANDALONE
92f5a8d4
TL
1025 template <class Archive>
1026 void serialize(Archive& ar, const unsigned int /*version*/)
7c673cae 1027 {
92f5a8d4 1028 ar& boost::make_nvp("backend", m_backend);
7c673cae 1029 }
1e59de90 1030 #endif
92f5a8d4
TL
1031
1032 private:
7c673cae 1033 template <class T>
92f5a8d4 1034 BOOST_MP_CXX14_CONSTEXPR void convert_to_imp(T* result) const
7c673cae
FG
1035 {
1036 using default_ops::eval_convert_to;
1037 eval_convert_to(result, m_backend);
1038 }
1039 template <class B2, expression_template_option ET>
92f5a8d4 1040 BOOST_MP_CXX14_CONSTEXPR void convert_to_imp(number<B2, ET>* result) const
7c673cae
FG
1041 {
1042 result->assign(*this);
1043 }
92f5a8d4 1044 BOOST_MP_CXX14_CONSTEXPR void convert_to_imp(std::string* result) const
7c673cae
FG
1045 {
1046 *result = this->str();
1047 }
92f5a8d4
TL
1048
1049 public:
7c673cae 1050 template <class T>
92f5a8d4 1051 BOOST_MP_CXX14_CONSTEXPR T convert_to() const
7c673cae 1052 {
92f5a8d4 1053 T result = T();
7c673cae
FG
1054 convert_to_imp(&result);
1055 return result;
1056 }
1057 //
1058 // Use in boolean context, and explicit conversion operators:
1059 //
92f5a8d4 1060#if BOOST_WORKAROUND(BOOST_MSVC, < 1900) || (defined(__apple_build_version__) && BOOST_WORKAROUND(__clang_major__, < 9))
7c673cae 1061 template <class T>
11fdf7f2 1062#else
1e59de90 1063 template <class T, class = typename std::enable_if<std::is_enum<T>::value || !(std::is_constructible<T, detail::convertible_to<self_type const&> >::value || !std::is_default_constructible<T>::value || (!boost::multiprecision::detail::is_arithmetic<T>::value && !boost::multiprecision::detail::is_complex<T>::value)), T>::type>
11fdf7f2 1064#endif
92f5a8d4 1065 explicit BOOST_MP_CXX14_CONSTEXPR operator T() const
7c673cae
FG
1066 {
1067 return this->template convert_to<T>();
1068 }
92f5a8d4 1069 BOOST_MP_FORCEINLINE explicit BOOST_MP_CXX14_CONSTEXPR operator bool() const
7c673cae
FG
1070 {
1071 return !is_zero();
1072 }
7c673cae
FG
1073 //
1074 // Default precision:
1075 //
1e59de90 1076 static BOOST_MP_CXX14_CONSTEXPR unsigned default_precision() noexcept
7c673cae
FG
1077 {
1078 return Backend::default_precision();
1079 }
92f5a8d4 1080 static BOOST_MP_CXX14_CONSTEXPR void default_precision(unsigned digits10)
7c673cae
FG
1081 {
1082 Backend::default_precision(digits10);
1e59de90
TL
1083 Backend::thread_default_precision(digits10);
1084 }
1085 static BOOST_MP_CXX14_CONSTEXPR unsigned thread_default_precision() noexcept
1086 {
1087 return Backend::thread_default_precision();
1088 }
1089 static BOOST_MP_CXX14_CONSTEXPR void thread_default_precision(unsigned digits10)
1090 {
1091 Backend::thread_default_precision(digits10);
7c673cae 1092 }
1e59de90 1093 BOOST_MP_CXX14_CONSTEXPR unsigned precision() const noexcept
7c673cae
FG
1094 {
1095 return m_backend.precision();
1096 }
92f5a8d4 1097 BOOST_MP_CXX14_CONSTEXPR void precision(unsigned digits10)
7c673cae
FG
1098 {
1099 m_backend.precision(digits10);
1100 }
1101 //
1e59de90
TL
1102 // Variable precision options:
1103 //
1104 static constexpr variable_precision_options default_variable_precision_options()noexcept
1105 {
1106 return Backend::default_variable_precision_options();
1107 }
1108 static constexpr variable_precision_options thread_default_variable_precision_options()noexcept
1109 {
1110 return Backend::thread_default_variable_precision_options();
1111 }
1112 static BOOST_MP_CXX14_CONSTEXPR void default_variable_precision_options(variable_precision_options opts)
1113 {
1114 Backend::default_variable_precision_options(opts);
1115 }
1116 static BOOST_MP_CXX14_CONSTEXPR void thread_default_variable_precision_options(variable_precision_options opts)
1117 {
1118 Backend::thread_default_variable_precision_options(opts);
1119 }
1120 //
7c673cae
FG
1121 // Comparison:
1122 //
92f5a8d4 1123 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR int compare(const number<Backend, ExpressionTemplates>& o) const
1e59de90 1124 noexcept(noexcept(std::declval<Backend>().compare(std::declval<Backend>())))
7c673cae
FG
1125 {
1126 return m_backend.compare(o.m_backend);
1127 }
1128 template <class V>
1e59de90 1129 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_arithmetic<V>::value && (number_category<Backend>::value != number_kind_complex), int>::type compare(const V& o) const
7c673cae
FG
1130 {
1131 using default_ops::eval_get_sign;
92f5a8d4 1132 if (o == 0)
7c673cae
FG
1133 return eval_get_sign(m_backend);
1134 return m_backend.compare(canonical_value(o));
1135 }
92f5a8d4 1136 template <class V>
1e59de90 1137 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_arithmetic<V>::value && (number_category<Backend>::value == number_kind_complex), int>::type compare(const V& o) const
92f5a8d4
TL
1138 {
1139 using default_ops::eval_get_sign;
1140 return m_backend.compare(canonical_value(o));
1141 }
1142 //
1143 // Direct access to the underlying backend:
1144 //
1e59de90 1145 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR Backend& backend() & noexcept
7c673cae
FG
1146 {
1147 return m_backend;
1148 }
1e59de90
TL
1149 BOOST_MP_FORCEINLINE constexpr const Backend& backend() const& noexcept { return m_backend; }
1150 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR Backend&& backend() && noexcept { return static_cast<Backend&&>(m_backend); }
1151 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR Backend const&& backend() const&& noexcept { return static_cast<Backend const&&>(m_backend); }
92f5a8d4
TL
1152 //
1153 // Complex number real and imag:
1154 //
1155 BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex<number<Backend, ExpressionTemplates> >::type
1156 real() const
1157 {
1158 using default_ops::eval_real;
1159 detail::scoped_default_precision<typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type> precision_guard(*this);
1160 typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type result;
1161 eval_real(result.backend(), backend());
1162 return result;
1163 }
1164 BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex<number<Backend, ExpressionTemplates> >::type
1165 imag() const
1166 {
1167 using default_ops::eval_imag;
1168 detail::scoped_default_precision<typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type> precision_guard(*this);
1169 typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type result;
1170 eval_imag(result.backend(), backend());
1171 return result;
1172 }
1173 template <class T>
1e59de90 1174 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<T, self_type>::value, self_type&>::type real(const T& val)
92f5a8d4
TL
1175 {
1176 using default_ops::eval_set_real;
1177 eval_set_real(backend(), canonical_value(val));
1178 return *this;
1179 }
1180 template <class T>
1e59de90 1181 inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<T, self_type>::value && number_category<self_type>::value == number_kind_complex, self_type&>::type imag(const T& val)
92f5a8d4
TL
1182 {
1183 using default_ops::eval_set_imag;
1184 eval_set_imag(backend(), canonical_value(val));
1185 return *this;
1186 }
1187
1188 private:
7c673cae 1189 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
1e59de90
TL
1190 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_assignable<number, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value>::type
1191 do_assign(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e, const std::integral_constant<bool, false>&)
7c673cae 1192 {
1e59de90
TL
1193 // The result of the expression isn't the same type as this -
1194 // create a temporary result and assign it to *this:
1195 using temp_type = typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type;
1196 temp_type t(e);
1197 *this = std::move(t);
7c673cae
FG
1198 }
1199 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
1e59de90
TL
1200 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!std::is_assignable<number, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value>::type
1201 do_assign(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e, const std::integral_constant<bool, false>&)
7c673cae
FG
1202 {
1203 // The result of the expression isn't the same type as this -
1204 // create a temporary result and assign it to *this:
1e59de90 1205 using temp_type = typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type;
92f5a8d4 1206 temp_type t(e);
7c673cae
FG
1207 this->assign(t);
1208 }
1209
1e59de90
TL
1210 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
1211 BOOST_MP_CXX14_CONSTEXPR void do_assign(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e, const std::integral_constant<bool, true>&)
1212 {
1213 do_assign(e, tag());
1214 }
1215
7c673cae 1216 template <class Exp>
92f5a8d4 1217 BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::add_immediates&)
7c673cae
FG
1218 {
1219 using default_ops::eval_add;
92f5a8d4 1220 boost::multiprecision::detail::maybe_promote_precision(this);
7c673cae
FG
1221 eval_add(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
1222 }
1223 template <class Exp>
92f5a8d4 1224 BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::subtract_immediates&)
7c673cae
FG
1225 {
1226 using default_ops::eval_subtract;
92f5a8d4 1227 boost::multiprecision::detail::maybe_promote_precision(this);
7c673cae
FG
1228 eval_subtract(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
1229 }
1230 template <class Exp>
92f5a8d4 1231 BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::multiply_immediates&)
7c673cae
FG
1232 {
1233 using default_ops::eval_multiply;
92f5a8d4 1234 boost::multiprecision::detail::maybe_promote_precision(this);
7c673cae
FG
1235 eval_multiply(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
1236 }
1237 template <class Exp>
92f5a8d4 1238 BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::multiply_add&)
7c673cae
FG
1239 {
1240 using default_ops::eval_multiply_add;
92f5a8d4 1241 boost::multiprecision::detail::maybe_promote_precision(this);
7c673cae
FG
1242 eval_multiply_add(m_backend, canonical_value(e.left().value()), canonical_value(e.middle().value()), canonical_value(e.right().value()));
1243 }
1244 template <class Exp>
92f5a8d4 1245 BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::multiply_subtract&)
7c673cae
FG
1246 {
1247 using default_ops::eval_multiply_subtract;
92f5a8d4 1248 boost::multiprecision::detail::maybe_promote_precision(this);
7c673cae
FG
1249 eval_multiply_subtract(m_backend, canonical_value(e.left().value()), canonical_value(e.middle().value()), canonical_value(e.right().value()));
1250 }
1251
1252 template <class Exp>
92f5a8d4 1253 BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::divide_immediates&)
7c673cae
FG
1254 {
1255 using default_ops::eval_divide;
92f5a8d4 1256 boost::multiprecision::detail::maybe_promote_precision(this);
7c673cae
FG
1257 eval_divide(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
1258 }
1259
1260 template <class Exp>
92f5a8d4 1261 BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::negate&)
7c673cae 1262 {
1e59de90 1263 using left_type = typename Exp::left_type;
7c673cae
FG
1264 do_assign(e.left(), typename left_type::tag_type());
1265 m_backend.negate();
1266 }
1267 template <class Exp>
92f5a8d4 1268 BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::plus&)
7c673cae 1269 {
1e59de90
TL
1270 using left_type = typename Exp::left_type ;
1271 using right_type = typename Exp::right_type;
7c673cae 1272
1e59de90
TL
1273 constexpr int const left_depth = left_type::depth;
1274 constexpr int const right_depth = right_type::depth;
7c673cae
FG
1275
1276 bool bl = contains_self(e.left());
1277 bool br = contains_self(e.right());
1278
92f5a8d4 1279 if (bl && br)
7c673cae
FG
1280 {
1281 self_type temp(e);
1282 temp.m_backend.swap(this->m_backend);
1283 }
92f5a8d4 1284 else if (bl && is_self(e.left()))
7c673cae
FG
1285 {
1286 // Ignore the left node, it's *this, just add the right:
1287 do_add(e.right(), typename right_type::tag_type());
1288 }
92f5a8d4 1289 else if (br && is_self(e.right()))
7c673cae
FG
1290 {
1291 // Ignore the right node, it's *this, just add the left:
1292 do_add(e.left(), typename left_type::tag_type());
1293 }
92f5a8d4 1294 else if (!br && (bl || (left_depth >= right_depth)))
7c673cae
FG
1295 { // br is always false, but if bl is true we must take the this branch:
1296 do_assign(e.left(), typename left_type::tag_type());
1297 do_add(e.right(), typename right_type::tag_type());
1298 }
1299 else
1300 {
1301 do_assign(e.right(), typename right_type::tag_type());
1302 do_add(e.left(), typename left_type::tag_type());
1303 }
1304 }
1305 template <class Exp>
92f5a8d4 1306 BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::minus&)
7c673cae 1307 {
1e59de90
TL
1308 using left_type = typename Exp::left_type ;
1309 using right_type = typename Exp::right_type;
7c673cae 1310
1e59de90
TL
1311 constexpr int const left_depth = left_type::depth;
1312 constexpr int const right_depth = right_type::depth;
7c673cae
FG
1313
1314 bool bl = contains_self(e.left());
1315 bool br = contains_self(e.right());
1316
92f5a8d4 1317 if (bl && br)
7c673cae
FG
1318 {
1319 self_type temp(e);
1320 temp.m_backend.swap(this->m_backend);
1321 }
92f5a8d4 1322 else if (bl && is_self(e.left()))
7c673cae
FG
1323 {
1324 // Ignore the left node, it's *this, just subtract the right:
1325 do_subtract(e.right(), typename right_type::tag_type());
1326 }
92f5a8d4 1327 else if (br && is_self(e.right()))
7c673cae
FG
1328 {
1329 // Ignore the right node, it's *this, just subtract the left and negate the result:
1330 do_subtract(e.left(), typename left_type::tag_type());
1331 m_backend.negate();
1332 }
92f5a8d4 1333 else if (!br && (bl || (left_depth >= right_depth)))
7c673cae
FG
1334 { // br is always false, but if bl is true we must take the this branch:
1335 do_assign(e.left(), typename left_type::tag_type());
1336 do_subtract(e.right(), typename right_type::tag_type());
1337 }
1338 else
1339 {
1340 do_assign(e.right(), typename right_type::tag_type());
1341 do_subtract(e.left(), typename left_type::tag_type());
1342 m_backend.negate();
1343 }
1344 }
1345 template <class Exp>
92f5a8d4 1346 BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::multiplies&)
7c673cae 1347 {
1e59de90
TL
1348 using left_type = typename Exp::left_type ;
1349 using right_type = typename Exp::right_type;
7c673cae 1350
1e59de90
TL
1351 constexpr int const left_depth = left_type::depth;
1352 constexpr int const right_depth = right_type::depth;
7c673cae
FG
1353
1354 bool bl = contains_self(e.left());
1355 bool br = contains_self(e.right());
1356
92f5a8d4 1357 if (bl && br)
7c673cae
FG
1358 {
1359 self_type temp(e);
1360 temp.m_backend.swap(this->m_backend);
1361 }
92f5a8d4 1362 else if (bl && is_self(e.left()))
7c673cae
FG
1363 {
1364 // Ignore the left node, it's *this, just add the right:
1365 do_multiplies(e.right(), typename right_type::tag_type());
1366 }
92f5a8d4 1367 else if (br && is_self(e.right()))
7c673cae
FG
1368 {
1369 // Ignore the right node, it's *this, just add the left:
1370 do_multiplies(e.left(), typename left_type::tag_type());
1371 }
92f5a8d4 1372 else if (!br && (bl || (left_depth >= right_depth)))
7c673cae
FG
1373 { // br is always false, but if bl is true we must take the this branch:
1374 do_assign(e.left(), typename left_type::tag_type());
1375 do_multiplies(e.right(), typename right_type::tag_type());
1376 }
1377 else
1378 {
1379 do_assign(e.right(), typename right_type::tag_type());
1380 do_multiplies(e.left(), typename left_type::tag_type());
1381 }
1382 }
1383 template <class Exp>
92f5a8d4 1384 BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::divides&)
7c673cae 1385 {
1e59de90
TL
1386 using left_type = typename Exp::left_type ;
1387 using right_type = typename Exp::right_type;
7c673cae
FG
1388
1389 bool bl = contains_self(e.left());
1390 bool br = contains_self(e.right());
1391
92f5a8d4 1392 if (bl && is_self(e.left()))
7c673cae
FG
1393 {
1394 // Ignore the left node, it's *this, just add the right:
1395 do_divide(e.right(), typename right_type::tag_type());
1396 }
92f5a8d4 1397 else if (br)
7c673cae
FG
1398 {
1399 self_type temp(e);
1400 temp.m_backend.swap(this->m_backend);
1401 }
1402 else
1403 {
1404 do_assign(e.left(), typename left_type::tag_type());
1405 do_divide(e.right(), typename right_type::tag_type());
1406 }
1407 }
1408 template <class Exp>
92f5a8d4 1409 BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::modulus&)
7c673cae
FG
1410 {
1411 //
1412 // This operation is only valid for integer backends:
1413 //
1e59de90 1414 static_assert(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
7c673cae 1415
1e59de90
TL
1416 using left_type = typename Exp::left_type ;
1417 using right_type = typename Exp::right_type;
7c673cae
FG
1418
1419 bool bl = contains_self(e.left());
1420 bool br = contains_self(e.right());
1421
92f5a8d4 1422 if (bl && is_self(e.left()))
7c673cae
FG
1423 {
1424 // Ignore the left node, it's *this, just add the right:
1425 do_modulus(e.right(), typename right_type::tag_type());
1426 }
92f5a8d4 1427 else if (br)
7c673cae
FG
1428 {
1429 self_type temp(e);
1430 temp.m_backend.swap(this->m_backend);
1431 }
1432 else
1433 {
1434 do_assign(e.left(), typename left_type::tag_type());
1435 do_modulus(e.right(), typename right_type::tag_type());
1436 }
1437 }
1438 template <class Exp>
92f5a8d4 1439 BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::modulus_immediates&)
7c673cae 1440 {
1e59de90 1441 static_assert(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
7c673cae 1442 using default_ops::eval_modulus;
92f5a8d4 1443 boost::multiprecision::detail::maybe_promote_precision(this);
7c673cae
FG
1444 eval_modulus(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
1445 }
1446
1447 template <class Exp>
92f5a8d4 1448 BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_and&)
7c673cae
FG
1449 {
1450 //
1451 // This operation is only valid for integer backends:
1452 //
1e59de90 1453 static_assert(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
7c673cae 1454
1e59de90
TL
1455 using left_type = typename Exp::left_type ;
1456 using right_type = typename Exp::right_type;
7c673cae 1457
1e59de90
TL
1458 constexpr int const left_depth = left_type::depth;
1459 constexpr int const right_depth = right_type::depth;
7c673cae
FG
1460
1461 bool bl = contains_self(e.left());
1462 bool br = contains_self(e.right());
1463
92f5a8d4 1464 if (bl && is_self(e.left()))
7c673cae
FG
1465 {
1466 // Ignore the left node, it's *this, just add the right:
1467 do_bitwise_and(e.right(), typename right_type::tag_type());
1468 }
92f5a8d4 1469 else if (br && is_self(e.right()))
7c673cae
FG
1470 {
1471 do_bitwise_and(e.left(), typename left_type::tag_type());
1472 }
92f5a8d4 1473 else if (!br && (bl || (left_depth >= right_depth)))
7c673cae
FG
1474 {
1475 do_assign(e.left(), typename left_type::tag_type());
1476 do_bitwise_and(e.right(), typename right_type::tag_type());
1477 }
1478 else
1479 {
1480 do_assign(e.right(), typename right_type::tag_type());
1481 do_bitwise_and(e.left(), typename left_type::tag_type());
1482 }
1483 }
1484 template <class Exp>
92f5a8d4 1485 BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_and_immediates&)
7c673cae 1486 {
1e59de90 1487 static_assert(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
7c673cae
FG
1488 using default_ops::eval_bitwise_and;
1489 eval_bitwise_and(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
1490 }
1491
1492 template <class Exp>
92f5a8d4 1493 BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_or&)
7c673cae
FG
1494 {
1495 //
1496 // This operation is only valid for integer backends:
1497 //
1e59de90 1498 static_assert(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
7c673cae 1499
1e59de90
TL
1500 using left_type = typename Exp::left_type ;
1501 using right_type = typename Exp::right_type;
7c673cae 1502
1e59de90
TL
1503 constexpr int const left_depth = left_type::depth;
1504 constexpr int const right_depth = right_type::depth;
7c673cae
FG
1505
1506 bool bl = contains_self(e.left());
1507 bool br = contains_self(e.right());
1508
92f5a8d4 1509 if (bl && is_self(e.left()))
7c673cae
FG
1510 {
1511 // Ignore the left node, it's *this, just add the right:
1512 do_bitwise_or(e.right(), typename right_type::tag_type());
1513 }
92f5a8d4 1514 else if (br && is_self(e.right()))
7c673cae
FG
1515 {
1516 do_bitwise_or(e.left(), typename left_type::tag_type());
1517 }
92f5a8d4 1518 else if (!br && (bl || (left_depth >= right_depth)))
7c673cae
FG
1519 {
1520 do_assign(e.left(), typename left_type::tag_type());
1521 do_bitwise_or(e.right(), typename right_type::tag_type());
1522 }
1523 else
1524 {
1525 do_assign(e.right(), typename right_type::tag_type());
1526 do_bitwise_or(e.left(), typename left_type::tag_type());
1527 }
1528 }
1529 template <class Exp>
92f5a8d4 1530 BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_or_immediates&)
7c673cae 1531 {
1e59de90 1532 static_assert(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
7c673cae
FG
1533 using default_ops::eval_bitwise_or;
1534 eval_bitwise_or(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
1535 }
1536
1537 template <class Exp>
92f5a8d4 1538 BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_xor&)
7c673cae
FG
1539 {
1540 //
1541 // This operation is only valid for integer backends:
1542 //
1e59de90 1543 static_assert(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
7c673cae 1544
1e59de90
TL
1545 using left_type = typename Exp::left_type ;
1546 using right_type = typename Exp::right_type;
7c673cae 1547
1e59de90
TL
1548 constexpr int const left_depth = left_type::depth;
1549 constexpr int const right_depth = right_type::depth;
7c673cae
FG
1550
1551 bool bl = contains_self(e.left());
1552 bool br = contains_self(e.right());
1553
92f5a8d4 1554 if (bl && is_self(e.left()))
7c673cae
FG
1555 {
1556 // Ignore the left node, it's *this, just add the right:
1557 do_bitwise_xor(e.right(), typename right_type::tag_type());
1558 }
92f5a8d4 1559 else if (br && is_self(e.right()))
7c673cae
FG
1560 {
1561 do_bitwise_xor(e.left(), typename left_type::tag_type());
1562 }
92f5a8d4 1563 else if (!br && (bl || (left_depth >= right_depth)))
7c673cae
FG
1564 {
1565 do_assign(e.left(), typename left_type::tag_type());
1566 do_bitwise_xor(e.right(), typename right_type::tag_type());
1567 }
1568 else
1569 {
1570 do_assign(e.right(), typename right_type::tag_type());
1571 do_bitwise_xor(e.left(), typename left_type::tag_type());
1572 }
1573 }
1574 template <class Exp>
92f5a8d4 1575 BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_xor_immediates&)
7c673cae 1576 {
1e59de90 1577 static_assert(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
7c673cae
FG
1578 using default_ops::eval_bitwise_xor;
1579 eval_bitwise_xor(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
1580 }
1581 template <class Exp>
92f5a8d4 1582 BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::terminal&)
7c673cae 1583 {
92f5a8d4 1584 if (!is_self(e))
7c673cae
FG
1585 {
1586 m_backend = canonical_value(e.value());
1587 }
1588 }
1589 template <class Exp>
92f5a8d4 1590 BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::function&)
7c673cae 1591 {
1e59de90 1592 using tag_type = typename Exp::arity;
92f5a8d4 1593 boost::multiprecision::detail::maybe_promote_precision(this);
7c673cae
FG
1594 do_assign_function(e, tag_type());
1595 }
1596 template <class Exp>
92f5a8d4 1597 BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::shift_left&)
7c673cae
FG
1598 {
1599 // We can only shift by an integer value, not an arbitrary expression:
1e59de90
TL
1600 using left_type = typename Exp::left_type ;
1601 using right_type = typename Exp::right_type ;
1602 using right_arity = typename right_type::arity;
1603 static_assert(right_arity::value == 0, "The left shift operator requires an integer value for the shift operand.");
1604 using right_value_type = typename right_type::result_type;
1605 static_assert(boost::multiprecision::detail::is_integral<right_value_type>::value, "The left shift operator requires an integer value for the shift operand.");
1606 using tag_type = typename left_type::tag_type;
7c673cae
FG
1607 do_assign_left_shift(e.left(), canonical_value(e.right().value()), tag_type());
1608 }
1609
1610 template <class Exp>
92f5a8d4 1611 BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::shift_right&)
7c673cae
FG
1612 {
1613 // We can only shift by an integer value, not an arbitrary expression:
1e59de90
TL
1614 using left_type = typename Exp::left_type ;
1615 using right_type = typename Exp::right_type ;
1616 using right_arity = typename right_type::arity;
1617 static_assert(right_arity::value == 0, "The left shift operator requires an integer value for the shift operand.");
1618 using right_value_type = typename right_type::result_type;
1619 static_assert(boost::multiprecision::detail::is_integral<right_value_type>::value, "The left shift operator requires an integer value for the shift operand.");
1620 using tag_type = typename left_type::tag_type;
7c673cae
FG
1621 do_assign_right_shift(e.left(), canonical_value(e.right().value()), tag_type());
1622 }
1623
1624 template <class Exp>
92f5a8d4 1625 BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_complement&)
7c673cae 1626 {
1e59de90 1627 static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise ~ operation is only valid for integer types");
7c673cae
FG
1628 using default_ops::eval_complement;
1629 self_type temp(e.left());
1630 eval_complement(m_backend, temp.backend());
1631 }
1632
1633 template <class Exp>
92f5a8d4 1634 BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::complement_immediates&)
7c673cae 1635 {
1e59de90 1636 static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise ~ operation is only valid for integer types");
7c673cae
FG
1637 using default_ops::eval_complement;
1638 eval_complement(m_backend, canonical_value(e.left().value()));
1639 }
1640
1641 template <class Exp, class Val>
92f5a8d4 1642 BOOST_MP_CXX14_CONSTEXPR void do_assign_right_shift(const Exp& e, const Val& val, const detail::terminal&)
7c673cae 1643 {
1e59de90 1644 static_assert(number_category<Backend>::value == number_kind_integer, "The right shift operation is only valid for integer types");
7c673cae 1645 using default_ops::eval_right_shift;
1e59de90 1646 detail::check_shift_range(val, std::integral_constant<bool, (sizeof(Val) > sizeof(std::size_t))>(), std::integral_constant<bool, boost::multiprecision::detail::is_signed<Val>::value&& boost::multiprecision::detail::is_integral<Val>::value>());
7c673cae
FG
1647 eval_right_shift(m_backend, canonical_value(e.value()), static_cast<std::size_t>(val));
1648 }
1649
1650 template <class Exp, class Val>
92f5a8d4 1651 BOOST_MP_CXX14_CONSTEXPR void do_assign_left_shift(const Exp& e, const Val& val, const detail::terminal&)
7c673cae 1652 {
1e59de90 1653 static_assert(number_category<Backend>::value == number_kind_integer, "The left shift operation is only valid for integer types");
7c673cae 1654 using default_ops::eval_left_shift;
1e59de90 1655 detail::check_shift_range(val, std::integral_constant<bool, (sizeof(Val) > sizeof(std::size_t))>(), std::integral_constant<bool, boost::multiprecision::detail::is_signed<Val>::value&& boost::multiprecision::detail::is_integral<Val>::value>());
7c673cae
FG
1656 eval_left_shift(m_backend, canonical_value(e.value()), static_cast<std::size_t>(val));
1657 }
1658
1659 template <class Exp, class Val, class Tag>
92f5a8d4 1660 BOOST_MP_CXX14_CONSTEXPR void do_assign_right_shift(const Exp& e, const Val& val, const Tag&)
7c673cae 1661 {
1e59de90 1662 static_assert(number_category<Backend>::value == number_kind_integer, "The right shift operation is only valid for integer types");
7c673cae
FG
1663 using default_ops::eval_right_shift;
1664 self_type temp(e);
1e59de90 1665 detail::check_shift_range(val, std::integral_constant<bool, (sizeof(Val) > sizeof(std::size_t))>(), std::integral_constant<bool, boost::multiprecision::detail::is_signed<Val>::value&& boost::multiprecision::detail::is_integral<Val>::value>());
7c673cae
FG
1666 eval_right_shift(m_backend, temp.backend(), static_cast<std::size_t>(val));
1667 }
1668
1669 template <class Exp, class Val, class Tag>
92f5a8d4 1670 BOOST_MP_CXX14_CONSTEXPR void do_assign_left_shift(const Exp& e, const Val& val, const Tag&)
7c673cae 1671 {
1e59de90 1672 static_assert(number_category<Backend>::value == number_kind_integer, "The left shift operation is only valid for integer types");
7c673cae
FG
1673 using default_ops::eval_left_shift;
1674 self_type temp(e);
1e59de90 1675 detail::check_shift_range(val, std::integral_constant<bool, (sizeof(Val) > sizeof(std::size_t))>(), std::integral_constant<bool, boost::multiprecision::detail::is_signed<Val>::value&& boost::multiprecision::detail::is_integral<Val>::value>());
7c673cae
FG
1676 eval_left_shift(m_backend, temp.backend(), static_cast<std::size_t>(val));
1677 }
1678
1679 template <class Exp>
1e59de90 1680 BOOST_MP_CXX14_CONSTEXPR void do_assign_function(const Exp& e, const std::integral_constant<int, 1>&)
7c673cae
FG
1681 {
1682 e.left().value()(&m_backend);
1683 }
1684 template <class Exp>
1e59de90 1685 BOOST_MP_CXX14_CONSTEXPR void do_assign_function(const Exp& e, const std::integral_constant<int, 2>&)
7c673cae 1686 {
1e59de90
TL
1687 using right_type = typename Exp::right_type ;
1688 using tag_type = typename right_type::tag_type;
7c673cae
FG
1689 do_assign_function_1(e.left().value(), e.right_ref(), tag_type());
1690 }
1691 template <class F, class Exp>
92f5a8d4 1692 BOOST_MP_CXX14_CONSTEXPR void do_assign_function_1(const F& f, const Exp& val, const detail::terminal&)
7c673cae
FG
1693 {
1694 f(m_backend, function_arg_value(val));
1695 }
1696 template <class F, class Exp, class Tag>
92f5a8d4 1697 BOOST_MP_CXX14_CONSTEXPR void do_assign_function_1(const F& f, const Exp& val, const Tag&)
7c673cae 1698 {
92f5a8d4 1699 typename Exp::result_type t(val);
7c673cae
FG
1700 f(m_backend, t.backend());
1701 }
1702 template <class Exp>
1e59de90 1703 BOOST_MP_CXX14_CONSTEXPR void do_assign_function(const Exp& e, const std::integral_constant<int, 3>&)
7c673cae 1704 {
1e59de90
TL
1705 using middle_type = typename Exp::middle_type ;
1706 using tag_type = typename middle_type::tag_type;
1707 using end_type = typename Exp::right_type ;
1708 using end_tag = typename end_type::tag_type ;
7c673cae
FG
1709 do_assign_function_2(e.left().value(), e.middle_ref(), e.right_ref(), tag_type(), end_tag());
1710 }
1711 template <class F, class Exp1, class Exp2>
92f5a8d4 1712 BOOST_MP_CXX14_CONSTEXPR void do_assign_function_2(const F& f, const Exp1& val1, const Exp2& val2, const detail::terminal&, const detail::terminal&)
7c673cae
FG
1713 {
1714 f(m_backend, function_arg_value(val1), function_arg_value(val2));
1715 }
1716 template <class F, class Exp1, class Exp2, class Tag1>
92f5a8d4 1717 BOOST_MP_CXX14_CONSTEXPR void do_assign_function_2(const F& f, const Exp1& val1, const Exp2& val2, const Tag1&, const detail::terminal&)
7c673cae 1718 {
92f5a8d4 1719 typename Exp1::result_type temp1(val1);
1e59de90 1720 f(m_backend, std::move(temp1.backend()), function_arg_value(val2));
7c673cae
FG
1721 }
1722 template <class F, class Exp1, class Exp2, class Tag2>
92f5a8d4 1723 BOOST_MP_CXX14_CONSTEXPR void do_assign_function_2(const F& f, const Exp1& val1, const Exp2& val2, const detail::terminal&, const Tag2&)
7c673cae 1724 {
92f5a8d4 1725 typename Exp2::result_type temp2(val2);
1e59de90 1726 f(m_backend, function_arg_value(val1), std::move(temp2.backend()));
7c673cae
FG
1727 }
1728 template <class F, class Exp1, class Exp2, class Tag1, class Tag2>
92f5a8d4 1729 BOOST_MP_CXX14_CONSTEXPR void do_assign_function_2(const F& f, const Exp1& val1, const Exp2& val2, const Tag1&, const Tag2&)
7c673cae 1730 {
92f5a8d4
TL
1731 typename Exp1::result_type temp1(val1);
1732 typename Exp2::result_type temp2(val2);
1e59de90 1733 f(m_backend, std::move(temp1.backend()), std::move(temp2.backend()));
7c673cae
FG
1734 }
1735
1736 template <class Exp>
1e59de90 1737 BOOST_MP_CXX14_CONSTEXPR void do_assign_function(const Exp& e, const std::integral_constant<int, 4>&)
7c673cae 1738 {
1e59de90
TL
1739 using left_type = typename Exp::left_middle_type ;
1740 using left_tag_type = typename left_type::tag_type ;
1741 using middle_type = typename Exp::right_middle_type;
1742 using middle_tag_type = typename middle_type::tag_type ;
1743 using right_type = typename Exp::right_type ;
1744 using right_tag_type = typename right_type::tag_type ;
7c673cae
FG
1745 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());
1746 }
1e59de90 1747
7c673cae 1748 template <class F, class Exp1, class Exp2, class Exp3, class Tag2, class Tag3>
92f5a8d4 1749 BOOST_MP_CXX14_CONSTEXPR 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)
7c673cae
FG
1750 {
1751 do_assign_function_3b(f, val1, val2, val3, t2, t3);
1752 }
1753 template <class F, class Exp1, class Exp2, class Exp3, class Tag1, class Tag2, class Tag3>
92f5a8d4 1754 BOOST_MP_CXX14_CONSTEXPR 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)
7c673cae 1755 {
92f5a8d4 1756 typename Exp1::result_type t(val1);
1e59de90 1757 do_assign_function_3b(f, std::move(t), val2, val3, t2, t3);
7c673cae
FG
1758 }
1759 template <class F, class Exp1, class Exp2, class Exp3, class Tag3>
92f5a8d4 1760 BOOST_MP_CXX14_CONSTEXPR void do_assign_function_3b(const F& f, const Exp1& val1, const Exp2& val2, const Exp3& val3, const detail::terminal&, const Tag3& t3)
7c673cae
FG
1761 {
1762 do_assign_function_3c(f, val1, val2, val3, t3);
1763 }
1764 template <class F, class Exp1, class Exp2, class Exp3, class Tag2, class Tag3>
92f5a8d4 1765 BOOST_MP_CXX14_CONSTEXPR void do_assign_function_3b(const F& f, const Exp1& val1, const Exp2& val2, const Exp3& val3, const Tag2& /*t2*/, const Tag3& t3)
7c673cae 1766 {
92f5a8d4 1767 typename Exp2::result_type t(val2);
1e59de90 1768 do_assign_function_3c(f, val1, std::move(t), val3, t3);
7c673cae
FG
1769 }
1770 template <class F, class Exp1, class Exp2, class Exp3>
92f5a8d4 1771 BOOST_MP_CXX14_CONSTEXPR void do_assign_function_3c(const F& f, const Exp1& val1, const Exp2& val2, const Exp3& val3, const detail::terminal&)
7c673cae
FG
1772 {
1773 f(m_backend, function_arg_value(val1), function_arg_value(val2), function_arg_value(val3));
1774 }
1775 template <class F, class Exp1, class Exp2, class Exp3, class Tag3>
92f5a8d4 1776 BOOST_MP_CXX14_CONSTEXPR void do_assign_function_3c(const F& f, const Exp1& val1, const Exp2& val2, const Exp3& val3, const Tag3& /*t3*/)
7c673cae 1777 {
92f5a8d4 1778 typename Exp3::result_type t(val3);
1e59de90 1779 do_assign_function_3c(f, val1, val2, std::move(t), detail::terminal());
7c673cae
FG
1780 }
1781
1782 template <class Exp>
92f5a8d4 1783 BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const detail::terminal&)
7c673cae
FG
1784 {
1785 using default_ops::eval_add;
92f5a8d4 1786 boost::multiprecision::detail::maybe_promote_precision(this);
7c673cae
FG
1787 eval_add(m_backend, canonical_value(e.value()));
1788 }
1789
1790 template <class Exp>
92f5a8d4 1791 BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const detail::negate&)
7c673cae 1792 {
1e59de90 1793 using left_type = typename Exp::left_type;
92f5a8d4 1794 boost::multiprecision::detail::maybe_promote_precision(this);
7c673cae
FG
1795 do_subtract(e.left(), typename left_type::tag_type());
1796 }
1797
1798 template <class Exp>
92f5a8d4 1799 BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const detail::plus&)
7c673cae 1800 {
1e59de90
TL
1801 using left_type = typename Exp::left_type ;
1802 using right_type = typename Exp::right_type;
7c673cae
FG
1803 do_add(e.left(), typename left_type::tag_type());
1804 do_add(e.right(), typename right_type::tag_type());
1805 }
1806
1807 template <class Exp>
92f5a8d4 1808 BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const detail::minus&)
7c673cae 1809 {
1e59de90
TL
1810 using left_type = typename Exp::left_type ;
1811 using right_type = typename Exp::right_type;
7c673cae
FG
1812 do_add(e.left(), typename left_type::tag_type());
1813 do_subtract(e.right(), typename right_type::tag_type());
1814 }
1815
1816 template <class Exp, class unknown>
92f5a8d4 1817 BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const unknown&)
7c673cae
FG
1818 {
1819 self_type temp(e);
1820 do_add(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
1821 }
1822
1823 template <class Exp>
92f5a8d4 1824 BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const detail::add_immediates&)
7c673cae
FG
1825 {
1826 using default_ops::eval_add;
92f5a8d4 1827 boost::multiprecision::detail::maybe_promote_precision(this);
7c673cae
FG
1828 eval_add(m_backend, canonical_value(e.left().value()));
1829 eval_add(m_backend, canonical_value(e.right().value()));
1830 }
1831 template <class Exp>
92f5a8d4 1832 BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const detail::subtract_immediates&)
7c673cae
FG
1833 {
1834 using default_ops::eval_add;
1835 using default_ops::eval_subtract;
92f5a8d4 1836 boost::multiprecision::detail::maybe_promote_precision(this);
7c673cae
FG
1837 eval_add(m_backend, canonical_value(e.left().value()));
1838 eval_subtract(m_backend, canonical_value(e.right().value()));
1839 }
1840 template <class Exp>
92f5a8d4 1841 BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const detail::terminal&)
7c673cae
FG
1842 {
1843 using default_ops::eval_subtract;
92f5a8d4 1844 boost::multiprecision::detail::maybe_promote_precision(this);
7c673cae
FG
1845 eval_subtract(m_backend, canonical_value(e.value()));
1846 }
1847
1848 template <class Exp>
92f5a8d4 1849 BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const detail::negate&)
7c673cae 1850 {
1e59de90 1851 using left_type = typename Exp::left_type;
7c673cae
FG
1852 do_add(e.left(), typename left_type::tag_type());
1853 }
1854
1855 template <class Exp>
92f5a8d4 1856 BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const detail::plus&)
7c673cae 1857 {
1e59de90
TL
1858 using left_type = typename Exp::left_type ;
1859 using right_type = typename Exp::right_type;
7c673cae
FG
1860 do_subtract(e.left(), typename left_type::tag_type());
1861 do_subtract(e.right(), typename right_type::tag_type());
1862 }
1863
1864 template <class Exp>
92f5a8d4 1865 BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const detail::minus&)
7c673cae 1866 {
1e59de90
TL
1867 using left_type = typename Exp::left_type ;
1868 using right_type = typename Exp::right_type;
7c673cae
FG
1869 do_subtract(e.left(), typename left_type::tag_type());
1870 do_add(e.right(), typename right_type::tag_type());
1871 }
1872 template <class Exp>
92f5a8d4 1873 BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const detail::add_immediates&)
7c673cae
FG
1874 {
1875 using default_ops::eval_subtract;
92f5a8d4 1876 boost::multiprecision::detail::maybe_promote_precision(this);
7c673cae
FG
1877 eval_subtract(m_backend, canonical_value(e.left().value()));
1878 eval_subtract(m_backend, canonical_value(e.right().value()));
1879 }
1880 template <class Exp>
92f5a8d4 1881 BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const detail::subtract_immediates&)
7c673cae
FG
1882 {
1883 using default_ops::eval_add;
1884 using default_ops::eval_subtract;
1885 eval_subtract(m_backend, canonical_value(e.left().value()));
1886 eval_add(m_backend, canonical_value(e.right().value()));
1887 }
1888 template <class Exp, class unknown>
92f5a8d4 1889 BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const unknown&)
7c673cae
FG
1890 {
1891 self_type temp(e);
1892 do_subtract(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
1893 }
1894
1895 template <class Exp>
92f5a8d4 1896 BOOST_MP_CXX14_CONSTEXPR void do_multiplies(const Exp& e, const detail::terminal&)
7c673cae
FG
1897 {
1898 using default_ops::eval_multiply;
92f5a8d4 1899 boost::multiprecision::detail::maybe_promote_precision(this);
7c673cae
FG
1900 eval_multiply(m_backend, canonical_value(e.value()));
1901 }
1902
1903 template <class Exp>
92f5a8d4 1904 BOOST_MP_CXX14_CONSTEXPR void do_multiplies(const Exp& e, const detail::negate&)
7c673cae 1905 {
1e59de90 1906 using left_type = typename Exp::left_type;
7c673cae
FG
1907 do_multiplies(e.left(), typename left_type::tag_type());
1908 m_backend.negate();
1909 }
1910
1911 template <class Exp>
92f5a8d4 1912 BOOST_MP_CXX14_CONSTEXPR void do_multiplies(const Exp& e, const detail::multiplies&)
7c673cae 1913 {
1e59de90
TL
1914 using left_type = typename Exp::left_type ;
1915 using right_type = typename Exp::right_type;
7c673cae
FG
1916 do_multiplies(e.left(), typename left_type::tag_type());
1917 do_multiplies(e.right(), typename right_type::tag_type());
1918 }
1919 //
1920 // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
1921 // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
1922 //
1923 template <class Exp>
1e59de90 1924 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!(boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1)>::type
92f5a8d4 1925 do_multiplies(const Exp& e, const detail::divides&)
7c673cae 1926 {
1e59de90
TL
1927 using left_type = typename Exp::left_type ;
1928 using right_type = typename Exp::right_type;
7c673cae
FG
1929 do_multiplies(e.left(), typename left_type::tag_type());
1930 do_divide(e.right(), typename right_type::tag_type());
1931 }
1932
1933 template <class Exp>
92f5a8d4 1934 BOOST_MP_CXX14_CONSTEXPR void do_multiplies(const Exp& e, const detail::multiply_immediates&)
7c673cae
FG
1935 {
1936 using default_ops::eval_multiply;
92f5a8d4 1937 boost::multiprecision::detail::maybe_promote_precision(this);
7c673cae
FG
1938 eval_multiply(m_backend, canonical_value(e.left().value()));
1939 eval_multiply(m_backend, canonical_value(e.right().value()));
1940 }
1941 //
1942 // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
1943 // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
1944 //
1945 template <class Exp>
1e59de90 1946 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!(boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1)>::type
92f5a8d4 1947 do_multiplies(const Exp& e, const detail::divide_immediates&)
7c673cae 1948 {
7c673cae 1949 using default_ops::eval_divide;
92f5a8d4
TL
1950 using default_ops::eval_multiply;
1951 boost::multiprecision::detail::maybe_promote_precision(this);
7c673cae
FG
1952 eval_multiply(m_backend, canonical_value(e.left().value()));
1953 eval_divide(m_backend, canonical_value(e.right().value()));
1954 }
1955 template <class Exp, class unknown>
92f5a8d4 1956 BOOST_MP_CXX14_CONSTEXPR void do_multiplies(const Exp& e, const unknown&)
7c673cae
FG
1957 {
1958 using default_ops::eval_multiply;
92f5a8d4 1959 boost::multiprecision::detail::maybe_promote_precision(this);
7c673cae
FG
1960 self_type temp(e);
1961 eval_multiply(m_backend, temp.m_backend);
1962 }
1963
1964 template <class Exp>
92f5a8d4 1965 BOOST_MP_CXX14_CONSTEXPR void do_divide(const Exp& e, const detail::terminal&)
7c673cae
FG
1966 {
1967 using default_ops::eval_divide;
92f5a8d4 1968 boost::multiprecision::detail::maybe_promote_precision(this);
7c673cae
FG
1969 eval_divide(m_backend, canonical_value(e.value()));
1970 }
1971
1972 template <class Exp>
92f5a8d4 1973 BOOST_MP_CXX14_CONSTEXPR void do_divide(const Exp& e, const detail::negate&)
7c673cae 1974 {
1e59de90 1975 using left_type = typename Exp::left_type;
7c673cae
FG
1976 do_divide(e.left(), typename left_type::tag_type());
1977 m_backend.negate();
1978 }
1979 //
1980 // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
1981 // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
1982 //
1983 template <class Exp>
1e59de90 1984 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!(boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1)>::type
92f5a8d4 1985 do_divide(const Exp& e, const detail::multiplies&)
7c673cae 1986 {
1e59de90
TL
1987 using left_type = typename Exp::left_type ;
1988 using right_type = typename Exp::right_type;
7c673cae
FG
1989 do_divide(e.left(), typename left_type::tag_type());
1990 do_divide(e.right(), typename right_type::tag_type());
1991 }
1992 //
1993 // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
1994 // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
1995 //
1996 template <class Exp>
1e59de90 1997 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!(boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1)>::type
92f5a8d4 1998 do_divide(const Exp& e, const detail::divides&)
7c673cae 1999 {
1e59de90
TL
2000 using left_type = typename Exp::left_type ;
2001 using right_type = typename Exp::right_type;
7c673cae
FG
2002 do_divide(e.left(), typename left_type::tag_type());
2003 do_multiplies(e.right(), typename right_type::tag_type());
2004 }
2005 //
2006 // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
2007 // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
2008 //
2009 template <class Exp>
1e59de90 2010 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!(boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1)>::type
92f5a8d4 2011 do_divides(const Exp& e, const detail::multiply_immediates&)
7c673cae
FG
2012 {
2013 using default_ops::eval_divide;
92f5a8d4 2014 boost::multiprecision::detail::maybe_promote_precision(this);
7c673cae
FG
2015 eval_divide(m_backend, canonical_value(e.left().value()));
2016 eval_divide(m_backend, canonical_value(e.right().value()));
2017 }
2018 //
2019 // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
2020 // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
2021 //
2022 template <class Exp>
1e59de90 2023 BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!(boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1)>::type
92f5a8d4 2024 do_divides(const Exp& e, const detail::divide_immediates&)
7c673cae 2025 {
7c673cae 2026 using default_ops::eval_divide;
92f5a8d4
TL
2027 using default_ops::eval_multiply;
2028 boost::multiprecision::detail::maybe_promote_precision(this);
7c673cae
FG
2029 eval_divide(m_backend, canonical_value(e.left().value()));
2030 mutiply(m_backend, canonical_value(e.right().value()));
2031 }
2032
2033 template <class Exp, class unknown>
92f5a8d4 2034 BOOST_MP_CXX14_CONSTEXPR void do_divide(const Exp& e, const unknown&)
7c673cae
FG
2035 {
2036 using default_ops::eval_multiply;
92f5a8d4 2037 boost::multiprecision::detail::maybe_promote_precision(this);
7c673cae
FG
2038 self_type temp(e);
2039 eval_divide(m_backend, temp.m_backend);
2040 }
2041
2042 template <class Exp>
92f5a8d4 2043 BOOST_MP_CXX14_CONSTEXPR void do_modulus(const Exp& e, const detail::terminal&)
7c673cae 2044 {
1e59de90 2045 static_assert(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
7c673cae 2046 using default_ops::eval_modulus;
92f5a8d4 2047 boost::multiprecision::detail::maybe_promote_precision(this);
7c673cae
FG
2048 eval_modulus(m_backend, canonical_value(e.value()));
2049 }
2050
2051 template <class Exp, class Unknown>
92f5a8d4 2052 BOOST_MP_CXX14_CONSTEXPR void do_modulus(const Exp& e, const Unknown&)
7c673cae 2053 {
1e59de90 2054 static_assert(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
7c673cae 2055 using default_ops::eval_modulus;
92f5a8d4 2056 boost::multiprecision::detail::maybe_promote_precision(this);
7c673cae
FG
2057 self_type temp(e);
2058 eval_modulus(m_backend, canonical_value(temp));
2059 }
2060
2061 template <class Exp>
92f5a8d4 2062 BOOST_MP_CXX14_CONSTEXPR void do_bitwise_and(const Exp& e, const detail::terminal&)
7c673cae 2063 {
1e59de90 2064 static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types");
7c673cae
FG
2065 using default_ops::eval_bitwise_and;
2066 eval_bitwise_and(m_backend, canonical_value(e.value()));
2067 }
2068 template <class Exp>
92f5a8d4 2069 BOOST_MP_CXX14_CONSTEXPR void do_bitwise_and(const Exp& e, const detail::bitwise_and&)
7c673cae 2070 {
1e59de90
TL
2071 static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types");
2072 using left_type = typename Exp::left_type ;
2073 using right_type = typename Exp::right_type;
7c673cae
FG
2074 do_bitwise_and(e.left(), typename left_type::tag_type());
2075 do_bitwise_and(e.right(), typename right_type::tag_type());
2076 }
2077 template <class Exp, class unknown>
92f5a8d4 2078 BOOST_MP_CXX14_CONSTEXPR void do_bitwise_and(const Exp& e, const unknown&)
7c673cae 2079 {
1e59de90 2080 static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types");
7c673cae
FG
2081 using default_ops::eval_bitwise_and;
2082 self_type temp(e);
2083 eval_bitwise_and(m_backend, temp.m_backend);
2084 }
2085
2086 template <class Exp>
92f5a8d4 2087 BOOST_MP_CXX14_CONSTEXPR void do_bitwise_or(const Exp& e, const detail::terminal&)
7c673cae 2088 {
1e59de90 2089 static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types");
7c673cae
FG
2090 using default_ops::eval_bitwise_or;
2091 eval_bitwise_or(m_backend, canonical_value(e.value()));
2092 }
2093 template <class Exp>
92f5a8d4 2094 BOOST_MP_CXX14_CONSTEXPR void do_bitwise_or(const Exp& e, const detail::bitwise_or&)
7c673cae 2095 {
1e59de90
TL
2096 static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types");
2097 using left_type = typename Exp::left_type ;
2098 using right_type = typename Exp::right_type;
7c673cae
FG
2099 do_bitwise_or(e.left(), typename left_type::tag_type());
2100 do_bitwise_or(e.right(), typename right_type::tag_type());
2101 }
2102 template <class Exp, class unknown>
92f5a8d4 2103 BOOST_MP_CXX14_CONSTEXPR void do_bitwise_or(const Exp& e, const unknown&)
7c673cae 2104 {
1e59de90 2105 static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types");
7c673cae
FG
2106 using default_ops::eval_bitwise_or;
2107 self_type temp(e);
2108 eval_bitwise_or(m_backend, temp.m_backend);
2109 }
2110
2111 template <class Exp>
92f5a8d4 2112 BOOST_MP_CXX14_CONSTEXPR void do_bitwise_xor(const Exp& e, const detail::terminal&)
7c673cae 2113 {
1e59de90 2114 static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types");
7c673cae
FG
2115 using default_ops::eval_bitwise_xor;
2116 eval_bitwise_xor(m_backend, canonical_value(e.value()));
2117 }
2118 template <class Exp>
92f5a8d4 2119 BOOST_MP_CXX14_CONSTEXPR void do_bitwise_xor(const Exp& e, const detail::bitwise_xor&)
7c673cae 2120 {
1e59de90
TL
2121 static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types");
2122 using left_type = typename Exp::left_type ;
2123 using right_type = typename Exp::right_type;
7c673cae
FG
2124 do_bitwise_xor(e.left(), typename left_type::tag_type());
2125 do_bitwise_xor(e.right(), typename right_type::tag_type());
2126 }
2127 template <class Exp, class unknown>
92f5a8d4 2128 BOOST_MP_CXX14_CONSTEXPR void do_bitwise_xor(const Exp& e, const unknown&)
7c673cae 2129 {
1e59de90 2130 static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types");
7c673cae
FG
2131 using default_ops::eval_bitwise_xor;
2132 self_type temp(e);
2133 eval_bitwise_xor(m_backend, temp.m_backend);
2134 }
2135
2136 // Tests if the expression contains a reference to *this:
2137 template <class Exp>
1e59de90 2138 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool contains_self(const Exp& e) const noexcept
7c673cae
FG
2139 {
2140 return contains_self(e, typename Exp::arity());
2141 }
2142 template <class Exp>
1e59de90 2143 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool contains_self(const Exp& e, std::integral_constant<int, 0> const&) const noexcept
7c673cae
FG
2144 {
2145 return is_realy_self(e.value());
2146 }
2147 template <class Exp>
1e59de90 2148 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool contains_self(const Exp& e, std::integral_constant<int, 1> const&) const noexcept
7c673cae 2149 {
1e59de90 2150 using child_type = typename Exp::left_type;
7c673cae
FG
2151 return contains_self(e.left(), typename child_type::arity());
2152 }
2153 template <class Exp>
1e59de90 2154 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool contains_self(const Exp& e, std::integral_constant<int, 2> const&) const noexcept
7c673cae 2155 {
1e59de90
TL
2156 using child0_type = typename Exp::left_type ;
2157 using child1_type = typename Exp::right_type;
92f5a8d4 2158 return contains_self(e.left(), typename child0_type::arity()) || contains_self(e.right(), typename child1_type::arity());
7c673cae
FG
2159 }
2160 template <class Exp>
1e59de90 2161 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool contains_self(const Exp& e, std::integral_constant<int, 3> const&) const noexcept
7c673cae 2162 {
1e59de90
TL
2163 using child0_type = typename Exp::left_type ;
2164 using child1_type = typename Exp::middle_type;
2165 using child2_type = typename Exp::right_type ;
92f5a8d4 2166 return contains_self(e.left(), typename child0_type::arity()) || contains_self(e.middle(), typename child1_type::arity()) || contains_self(e.right(), typename child2_type::arity());
7c673cae
FG
2167 }
2168
2169 // Test if the expression is a reference to *this:
2170 template <class Exp>
1e59de90 2171 BOOST_MP_FORCEINLINE constexpr bool is_self(const Exp& e) const noexcept
7c673cae
FG
2172 {
2173 return is_self(e, typename Exp::arity());
2174 }
2175 template <class Exp>
1e59de90 2176 BOOST_MP_FORCEINLINE constexpr bool is_self(const Exp& e, std::integral_constant<int, 0> const&) const noexcept
7c673cae
FG
2177 {
2178 return is_realy_self(e.value());
2179 }
2180 template <class Exp, int v>
1e59de90 2181 BOOST_MP_FORCEINLINE constexpr bool is_self(const Exp&, std::integral_constant<int, v> const&) const noexcept
7c673cae
FG
2182 {
2183 return false;
2184 }
2185
2186 template <class Val>
1e59de90
TL
2187 BOOST_MP_FORCEINLINE constexpr bool is_realy_self(const Val&) const noexcept { return false; }
2188 BOOST_MP_FORCEINLINE constexpr bool is_realy_self(const self_type& v) const noexcept { return &v == this; }
7c673cae 2189
1e59de90 2190 static BOOST_MP_FORCEINLINE constexpr const Backend& function_arg_value(const self_type& v) noexcept { return v.backend(); }
92f5a8d4 2191 template <class Other, expression_template_option ET2>
1e59de90 2192 static BOOST_MP_FORCEINLINE constexpr const Other& function_arg_value(const number<Other, ET2>& v) noexcept { return v.backend(); }
7c673cae 2193 template <class V>
1e59de90 2194 static BOOST_MP_FORCEINLINE constexpr const V& function_arg_value(const V& v) noexcept { return v; }
7c673cae 2195 template <class A1, class A2, class A3, class A4>
1e59de90 2196 static BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR const A1& function_arg_value(const detail::expression<detail::terminal, A1, A2, A3, A4>& exp) noexcept { return exp.value(); }
7c673cae 2197 template <class A2, class A3, class A4>
1e59de90 2198 static BOOST_MP_FORCEINLINE constexpr const Backend& function_arg_value(const detail::expression<detail::terminal, number<Backend>, A2, A3, A4>& exp) noexcept { return exp.value().backend(); }
92f5a8d4 2199 Backend m_backend;
7c673cae 2200
92f5a8d4 2201 public:
7c673cae
FG
2202 //
2203 // These shouldn't really need to be public, or even member functions, but it makes implementing
2204 // the non-member operators way easier if they are:
2205 //
1e59de90
TL
2206 static BOOST_MP_FORCEINLINE constexpr const Backend& canonical_value(const self_type& v) noexcept { return v.m_backend; }
2207 template <class B2, expression_template_option ET>
2208 static BOOST_MP_FORCEINLINE constexpr const B2& canonical_value(const number<B2, ET>& v) noexcept { return v.backend(); }
7c673cae 2209 template <class B2, expression_template_option ET>
1e59de90 2210 static BOOST_MP_FORCEINLINE constexpr B2&& canonical_value(number<B2, ET>&& v) noexcept { return static_cast<number<B2, ET>&&>(v).backend(); }
7c673cae 2211 template <class V>
1e59de90
TL
2212 static BOOST_MP_FORCEINLINE constexpr typename std::enable_if<!std::is_same<typename detail::canonical<V, Backend>::type, V>::value, typename detail::canonical<V, Backend>::type>::type
2213 canonical_value(const V& v) noexcept { return static_cast<typename detail::canonical<V, Backend>::type>(v); }
7c673cae 2214 template <class V>
1e59de90
TL
2215 static BOOST_MP_FORCEINLINE constexpr typename std::enable_if<std::is_same<typename detail::canonical<V, Backend>::type, V>::value, const V&>::type
2216 canonical_value(const V& v) noexcept { return v; }
2217 static BOOST_MP_FORCEINLINE typename detail::canonical<std::string, Backend>::type canonical_value(const std::string& v) noexcept { return v.c_str(); }
7c673cae
FG
2218};
2219
2220template <class Backend, expression_template_option ExpressionTemplates>
92f5a8d4 2221inline std::ostream& operator<<(std::ostream& os, const number<Backend, ExpressionTemplates>& r)
7c673cae 2222{
92f5a8d4
TL
2223 std::streamsize d = os.precision();
2224 std::string s = r.str(d, os.flags());
7c673cae 2225 std::streamsize ss = os.width();
92f5a8d4 2226 if (ss > static_cast<std::streamsize>(s.size()))
7c673cae
FG
2227 {
2228 char fill = os.fill();
92f5a8d4 2229 if ((os.flags() & std::ios_base::left) == std::ios_base::left)
7c673cae
FG
2230 s.append(static_cast<std::string::size_type>(ss - s.size()), fill);
2231 else
2232 s.insert(static_cast<std::string::size_type>(0), static_cast<std::string::size_type>(ss - s.size()), fill);
2233 }
2234 return os << s;
2235}
2236
1e59de90
TL
2237template <class Backend, expression_template_option ExpressionTemplates>
2238std::string to_string(const number<Backend, ExpressionTemplates>& val)
2239{
2240 return val.str(6, std::ios_base::fixed|std::ios_base::showpoint);
2241}
2242
92f5a8d4 2243namespace detail {
7c673cae
FG
2244
2245template <class tag, class A1, class A2, class A3, class A4>
92f5a8d4 2246inline std::ostream& operator<<(std::ostream& os, const expression<tag, A1, A2, A3, A4>& r)
7c673cae 2247{
1e59de90 2248 using value_type = typename expression<tag, A1, A2, A3, A4>::result_type;
92f5a8d4 2249 value_type temp(r);
7c673cae
FG
2250 return os << temp;
2251}
2252//
2253// What follows is the input streaming code: this is not "proper" iostream code at all
2254// but that's fiendishly hard to write when dealing with multiple backends all
2255// with different requirements... yes we could deligate this to the backend author...
2256// but we really want backends to be EASY to write!
2257// For now just pull in all the characters that could possibly form the number
2258// and let the backend's string parser make use of it. This fixes most use cases
2259// including CSV type formats such as those used by the Random lib.
2260//
2261inline std::string read_string_while(std::istream& is, std::string const& permitted_chars)
2262{
92f5a8d4 2263 std::ios_base::iostate state = std::ios_base::goodbit;
7c673cae 2264 const std::istream::sentry sentry_check(is);
92f5a8d4 2265 std::string result;
7c673cae 2266
92f5a8d4 2267 if (sentry_check)
7c673cae
FG
2268 {
2269 int c = is.rdbuf()->sgetc();
2270
92f5a8d4
TL
2271 for (;; c = is.rdbuf()->snextc())
2272 if (std::istream::traits_type::eq_int_type(std::istream::traits_type::eof(), c))
b32b8144 2273 { // end of file:
7c673cae
FG
2274 state |= std::ios_base::eofbit;
2275 break;
2276 }
92f5a8d4 2277 else if (permitted_chars.find_first_of(std::istream::traits_type::to_char_type(c)) == std::string::npos)
7c673cae
FG
2278 {
2279 // Invalid numeric character, stop reading:
2280 //is.rdbuf()->sputbackc(static_cast<char>(c));
2281 break;
2282 }
2283 else
b32b8144 2284 {
7c673cae
FG
2285 result.append(1, std::istream::traits_type::to_char_type(c));
2286 }
2287 }
2288
92f5a8d4 2289 if (!result.size())
7c673cae
FG
2290 state |= std::ios_base::failbit;
2291 is.setstate(state);
2292 return result;
2293}
2294
2295} // namespace detail
2296
2297template <class Backend, expression_template_option ExpressionTemplates>
92f5a8d4 2298inline std::istream& operator>>(std::istream& is, number<Backend, ExpressionTemplates>& r)
7c673cae 2299{
92f5a8d4
TL
2300 bool hex_format = (is.flags() & std::ios_base::hex) == std::ios_base::hex;
2301 bool oct_format = (is.flags() & std::ios_base::oct) == std::ios_base::oct;
7c673cae 2302 std::string s;
92f5a8d4 2303 switch (boost::multiprecision::number_category<number<Backend, ExpressionTemplates> >::value)
7c673cae
FG
2304 {
2305 case boost::multiprecision::number_kind_integer:
92f5a8d4 2306 if (oct_format)
7c673cae 2307 s = detail::read_string_while(is, "+-01234567");
92f5a8d4 2308 else if (hex_format)
7c673cae
FG
2309 s = detail::read_string_while(is, "+-xXabcdefABCDEF0123456789");
2310 else
2311 s = detail::read_string_while(is, "+-0123456789");
2312 break;
2313 case boost::multiprecision::number_kind_floating_point:
2314 s = detail::read_string_while(is, "+-eE.0123456789infINFnanNANinfinityINFINITY");
2315 break;
2316 default:
2317 is >> s;
2318 }
92f5a8d4 2319 if (s.size())
7c673cae 2320 {
92f5a8d4 2321 if (hex_format && (number_category<Backend>::value == number_kind_integer) && ((s[0] != '0') || (s[1] != 'x')))
7c673cae 2322 s.insert(s.find_first_not_of("+-"), "0x");
92f5a8d4 2323 if (oct_format && (number_category<Backend>::value == number_kind_integer) && (s[0] != '0'))
7c673cae
FG
2324 s.insert(s.find_first_not_of("+-"), "0");
2325 r.assign(s);
2326 }
92f5a8d4 2327 else if (!is.fail())
7c673cae
FG
2328 is.setstate(std::istream::failbit);
2329 return is;
2330}
2331
2332template <class Backend, expression_template_option ExpressionTemplates>
92f5a8d4 2333BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR void swap(number<Backend, ExpressionTemplates>& a, number<Backend, ExpressionTemplates>& b)
1e59de90 2334 noexcept(noexcept(std::declval<number<Backend, ExpressionTemplates>&>() = std::declval<number<Backend, ExpressionTemplates>&>()))
7c673cae
FG
2335{
2336 a.swap(b);
2337}
2338//
2339// Boost.Hash support, just call hash_value for the backend, which may or may not be supported:
2340//
2341template <class Backend, expression_template_option ExpressionTemplates>
92f5a8d4 2342inline BOOST_MP_CXX14_CONSTEXPR std::size_t hash_value(const number<Backend, ExpressionTemplates>& val)
7c673cae
FG
2343{
2344 return hash_value(val.backend());
2345}
2346
1e59de90
TL
2347namespace detail {
2348
2349BOOST_MP_FORCEINLINE bool istream_peek(std::istream& is, char& c, bool have_hex)
2350{
2351 int i = is.peek();
2352 c = static_cast<char>(i);
2353 return (EOF != i) && (c == 'x' || c == 'X' || c == '-' || c == '+' || (c >= '0' && c <= '9') || (have_hex && (c >= 'a' && c <= 'f')) || (have_hex && (c >= 'A' && c <= 'F')));
2354}
2355
2356} // namespace detail
2357
92f5a8d4 2358} // namespace multiprecision
7c673cae
FG
2359
2360template <class T>
2361class rational;
2362
2363template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
92f5a8d4 2364inline std::istream& operator>>(std::istream& is, rational<multiprecision::number<Backend, ExpressionTemplates> >& r)
7c673cae 2365{
92f5a8d4 2366 std::string s1;
7c673cae 2367 multiprecision::number<Backend, ExpressionTemplates> v1, v2;
92f5a8d4
TL
2368 char c;
2369 bool have_hex = false;
2370 bool hex_format = (is.flags() & std::ios_base::hex) == std::ios_base::hex;
2371 bool oct_format = (is.flags() & std::ios_base::oct) == std::ios_base::oct;
7c673cae 2372
1e59de90 2373 while (multiprecision::detail::istream_peek(is, c, have_hex))
7c673cae 2374 {
92f5a8d4 2375 if (c == 'x' || c == 'X')
7c673cae
FG
2376 have_hex = true;
2377 s1.append(1, c);
2378 is.get();
2379 }
92f5a8d4 2380 if (hex_format && ((s1[0] != '0') || (s1[1] != 'x')))
7c673cae 2381 s1.insert(static_cast<std::string::size_type>(0), "0x");
92f5a8d4 2382 if (oct_format && (s1[0] != '0'))
7c673cae
FG
2383 s1.insert(static_cast<std::string::size_type>(0), "0");
2384 v1.assign(s1);
2385 s1.erase();
92f5a8d4 2386 if (c == '/')
7c673cae
FG
2387 {
2388 is.get();
1e59de90 2389 while (multiprecision::detail::istream_peek(is, c, have_hex))
7c673cae 2390 {
92f5a8d4 2391 if (c == 'x' || c == 'X')
7c673cae
FG
2392 have_hex = true;
2393 s1.append(1, c);
2394 is.get();
2395 }
92f5a8d4 2396 if (hex_format && ((s1[0] != '0') || (s1[1] != 'x')))
7c673cae 2397 s1.insert(static_cast<std::string::size_type>(0), "0x");
92f5a8d4 2398 if (oct_format && (s1[0] != '0'))
7c673cae
FG
2399 s1.insert(static_cast<std::string::size_type>(0), "0");
2400 v2.assign(s1);
2401 }
2402 else
2403 v2 = 1;
2404 r.assign(v1, v2);
2405 return is;
2406}
2407
7c673cae 2408template <class T, multiprecision::expression_template_option ExpressionTemplates>
92f5a8d4 2409inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<T, ExpressionTemplates> numerator(const rational<multiprecision::number<T, ExpressionTemplates> >& a)
7c673cae
FG
2410{
2411 return a.numerator();
2412}
2413
2414template <class T, multiprecision::expression_template_option ExpressionTemplates>
92f5a8d4 2415inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<T, ExpressionTemplates> denominator(const rational<multiprecision::number<T, ExpressionTemplates> >& a)
7c673cae
FG
2416{
2417 return a.denominator();
2418}
2419
92f5a8d4
TL
2420template <class T, multiprecision::expression_template_option ExpressionTemplates>
2421inline BOOST_MP_CXX14_CONSTEXPR std::size_t hash_value(const rational<multiprecision::number<T, ExpressionTemplates> >& val)
7c673cae 2422{
92f5a8d4 2423 std::size_t result = hash_value(val.numerator());
1e59de90 2424 boost::multiprecision::detail::hash_combine(result, hash_value(val.denominator()));
92f5a8d4
TL
2425 return result;
2426}
2427
2428namespace multiprecision {
7c673cae
FG
2429
2430template <class I>
2431struct component_type<boost::rational<I> >
2432{
1e59de90 2433 using type = I;
7c673cae
FG
2434};
2435
92f5a8d4 2436} // namespace multiprecision
7c673cae
FG
2437
2438#ifdef BOOST_MSVC
2439#pragma warning(pop)
2440#endif
2441
92f5a8d4 2442} // namespace boost
7c673cae 2443
7c673cae
FG
2444namespace std {
2445
92f5a8d4
TL
2446template <class Backend, boost::multiprecision::expression_template_option ExpressionTemplates>
2447struct hash<boost::multiprecision::number<Backend, ExpressionTemplates> >
2448{
2449 BOOST_MP_CXX14_CONSTEXPR std::size_t operator()(const boost::multiprecision::number<Backend, ExpressionTemplates>& val) const { return hash_value(val); }
2450};
2451template <class Backend, boost::multiprecision::expression_template_option ExpressionTemplates>
2452struct hash<boost::rational<boost::multiprecision::number<Backend, ExpressionTemplates> > >
2453{
2454 BOOST_MP_CXX14_CONSTEXPR std::size_t operator()(const boost::rational<boost::multiprecision::number<Backend, ExpressionTemplates> >& val) const
7c673cae 2455 {
92f5a8d4 2456 std::size_t result = hash_value(val.numerator());
1e59de90 2457 boost::multiprecision::detail::hash_combine(result, hash_value(val.denominator()));
92f5a8d4
TL
2458 return result;
2459 }
2460};
7c673cae 2461
92f5a8d4 2462} // namespace std
7c673cae 2463
7c673cae
FG
2464#include <boost/multiprecision/detail/ublas_interop.hpp>
2465
2466#endif