Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Copyright 2011 John Maddock. Distributed under the Boost Chris@16: // Software License, Version 1.0. (See accompanying file Chris@16: // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: #ifndef BOOST_MATH_EXTENDED_REAL_HPP Chris@16: #define BOOST_MATH_EXTENDED_REAL_HPP Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include // stream operators Chris@16: #include // EOF Chris@16: Chris@16: namespace boost{ namespace multiprecision{ Chris@16: Chris@16: #ifdef BOOST_MSVC Chris@16: // warning C4127: conditional expression is constant Chris@16: // warning C4714: function marked as __forceinline not inlined Chris@16: #pragma warning(push) Chris@16: #pragma warning(disable:4127 4714) Chris@16: #endif Chris@16: Chris@16: template Chris@16: class number Chris@16: { Chris@16: typedef number self_type; Chris@16: public: Chris@16: typedef Backend backend_type; Chris@16: BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number() BOOST_NOEXCEPT_IF(noexcept(Backend())) {} Chris@101: BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number(const number& e) BOOST_NOEXCEPT_IF(noexcept(Backend(std::declval()))) : m_backend(e.m_backend){} Chris@16: template Chris@16: BOOST_MP_FORCEINLINE number(const V& v, typename boost::enable_if_c< Chris@16: (boost::is_arithmetic::value || is_same::value || is_convertible::value) Chris@16: && !is_convertible::type, Backend>::value Chris@16: && !detail::is_restricted_conversion::type, Backend>::value Chris@16: >::type* = 0) Chris@16: { Chris@16: m_backend = canonical_value(v); Chris@16: } Chris@16: template Chris@16: BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number(const V& v, typename boost::enable_if_c< Chris@16: is_convertible::type, Backend>::value Chris@16: && !detail::is_restricted_conversion::type, Backend>::value Chris@101: >::type* = 0) Chris@101: #ifndef BOOST_INTEL Chris@101: BOOST_NOEXCEPT_IF(noexcept(Backend(std::declval::type const&>()))) Chris@101: #endif Chris@16: : m_backend(canonical_value(v)) {} Chris@101: BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number(const number& e, unsigned digits10) Chris@101: BOOST_NOEXCEPT_IF(noexcept(Backend(std::declval(), std::declval()))) Chris@16: : m_backend(e.m_backend, digits10){} Chris@16: template Chris@16: explicit BOOST_MP_FORCEINLINE number(const V& v, typename boost::enable_if_c< Chris@16: (boost::is_arithmetic::value || is_same::value || is_convertible::value) Chris@16: && !detail::is_explicitly_convertible::type, Backend>::value Chris@16: && detail::is_restricted_conversion::type, Backend>::value Chris@101: >::type* = 0) Chris@101: BOOST_NOEXCEPT_IF(noexcept(std::declval() = std::declval::type const&>())) Chris@16: { Chris@16: m_backend = canonical_value(v); Chris@16: } Chris@16: template Chris@16: explicit BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number(const V& v, typename boost::enable_if_c< Chris@16: detail::is_explicitly_convertible::type, Backend>::value Chris@16: && (detail::is_restricted_conversion::type, Backend>::value Chris@16: || !is_convertible::type, Backend>::value) Chris@16: >::type* = 0) Chris@101: BOOST_NOEXCEPT_IF(noexcept(Backend(std::declval::type const&>()))) Chris@16: : m_backend(canonical_value(v)) {} Chris@16: /* Chris@16: // Chris@16: // This conflicts with component based initialization (for rational and complex types) Chris@16: // which is arguably more useful. Disabled for now. Chris@16: // Chris@16: template Chris@16: number(V v, unsigned digits10, typename boost::enable_if, is_same, is_convertible > >::type* dummy1 = 0) Chris@16: { Chris@16: m_backend.precision(digits10); Chris@16: m_backend = canonical_value(v); Chris@16: } Chris@16: */ Chris@16: template Chris@16: BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number(const number& val) Chris@101: BOOST_NOEXCEPT_IF(noexcept(Backend(std::declval()))) : m_backend(val.backend()) {} Chris@16: Chris@16: template Chris@16: BOOST_MP_FORCEINLINE number(const number& val, Chris@16: typename boost::enable_if_c<(boost::is_convertible::value && !detail::is_restricted_conversion::value)>::type* = 0) Chris@101: BOOST_NOEXCEPT_IF(noexcept(Backend(std::declval()))) Chris@16: : m_backend(val.backend()) {} Chris@16: Chris@16: template Chris@16: explicit number(const number& val, typename boost::enable_if_c< Chris@16: (!detail::is_explicitly_convertible::value) Chris@16: >::type* = 0) Chris@16: { Chris@16: // Chris@16: // Attempt a generic interconvertion: Chris@16: // Chris@16: detail::generic_interconvert(backend(), val.backend(), number_category(), number_category()); Chris@16: } Chris@16: template Chris@16: explicit BOOST_MP_FORCEINLINE number(const number& val, typename boost::enable_if_c< Chris@16: (detail::is_explicitly_convertible::value Chris@16: && (detail::is_restricted_conversion::value || !boost::is_convertible::value)) Chris@101: >::type* = 0) BOOST_NOEXCEPT_IF(noexcept(Backend(std::declval()))) Chris@16: : m_backend(val.backend()) {} Chris@16: Chris@16: template Chris@16: BOOST_MP_FORCEINLINE number(V v1, V v2, typename boost::enable_if, is_same, is_convertible > >::type* = 0) Chris@16: { Chris@16: using default_ops::assign_components; Chris@16: assign_components(m_backend, canonical_value(v1), canonical_value(v2)); Chris@16: } Chris@16: template Chris@16: BOOST_MP_FORCEINLINE number(const number& v1, const number& v2, typename boost::enable_if >::type* = 0) Chris@16: { Chris@16: using default_ops::assign_components; Chris@16: assign_components(m_backend, v1.backend(), v2.backend()); Chris@16: } Chris@16: Chris@16: template Chris@16: typename boost::enable_if::result_type, self_type>, number&>::type operator=(const detail::expression& e) Chris@16: { Chris@16: typedef typename is_same::result_type>::type tag_type; Chris@16: do_assign(e, tag_type()); Chris@16: return *this; Chris@16: } Chris@16: template Chris@16: number& assign(const detail::expression& e) Chris@16: { Chris@16: typedef typename is_same::result_type>::type tag_type; Chris@16: do_assign(e, tag_type()); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: BOOST_MP_FORCEINLINE number& operator=(const number& e) Chris@101: BOOST_NOEXCEPT_IF(noexcept(std::declval() = std::declval())) Chris@16: { Chris@16: m_backend = e.m_backend; Chris@16: return *this; Chris@16: } Chris@16: Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename boost::enable_if, number& >::type Chris@16: operator=(const V& v) Chris@101: BOOST_NOEXCEPT_IF(noexcept(std::declval() = std::declval::type&>())) Chris@16: { Chris@16: m_backend = canonical_value(v); Chris@16: return *this; Chris@16: } Chris@16: template Chris@16: BOOST_MP_FORCEINLINE number& assign(const V& v) Chris@101: BOOST_NOEXCEPT_IF(noexcept(std::declval() = std::declval::type&>())) Chris@16: { Chris@16: m_backend = canonical_value(v); Chris@16: return *this; Chris@16: } Chris@16: template Chris@16: typename boost::disable_if, number& >::type Chris@16: assign(const number& v) Chris@16: { Chris@16: // Chris@16: // Attempt a generic interconvertion: Chris@16: // Chris@16: detail::generic_interconvert(backend(), v.backend(), number_category(), number_category()); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: template Chris@16: number(const detail::expression& e, typename boost::enable_if_c::result_type, self_type>::value>::type* = 0) Chris@16: { Chris@16: *this = e; Chris@16: } Chris@16: template Chris@16: explicit number(const detail::expression& e, Chris@16: typename boost::enable_if_c::result_type, self_type>::value Chris@16: && boost::multiprecision::detail::is_explicitly_convertible::result_type, self_type>::value>::type* = 0) Chris@16: { Chris@16: assign(e); Chris@16: } Chris@16: Chris@16: #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES Chris@16: BOOST_MP_FORCEINLINE BOOST_CONSTEXPR number(number&& r) Chris@16: BOOST_NOEXCEPT_IF(noexcept(Backend(std::declval()))) Chris@16: : m_backend(static_cast(r.m_backend)){} Chris@101: BOOST_MP_FORCEINLINE number& operator=(number&& r) BOOST_NOEXCEPT_IF(noexcept(std::declval() = std::declval())) Chris@16: { Chris@16: m_backend = static_cast(r.m_backend); Chris@16: return *this; Chris@16: } Chris@16: #endif Chris@16: Chris@16: number& operator+=(const self_type& val) Chris@16: { Chris@16: do_add(detail::expression(val), detail::terminal()); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: template Chris@16: number& operator+=(const detail::expression& e) Chris@16: { Chris@16: // Create a copy if e contains this, but not if we're just doing a Chris@16: // x += x Chris@16: if(contains_self(e) && !is_self(e)) Chris@16: { Chris@16: self_type temp(e); Chris@16: do_add(detail::expression(temp), detail::terminal()); Chris@16: } Chris@16: else Chris@16: { Chris@16: do_add(e, tag()); Chris@16: } Chris@16: return *this; Chris@16: } Chris@16: Chris@16: template Chris@16: number& operator+=(const detail::expression& e) Chris@16: { Chris@16: // Chris@16: // Fused multiply-add: Chris@16: // Chris@16: using default_ops::eval_multiply_add; Chris@16: eval_multiply_add(m_backend, canonical_value(e.left_ref()), canonical_value(e.right_ref())); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: template Chris@16: typename boost::enable_if, number& >::type Chris@16: operator+=(const V& v) Chris@16: { Chris@16: using default_ops::eval_add; Chris@16: eval_add(m_backend, canonical_value(v)); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: number& operator-=(const self_type& val) Chris@16: { Chris@16: do_subtract(detail::expression(val), detail::terminal()); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: template Chris@16: number& operator-=(const detail::expression& e) Chris@16: { Chris@16: // Create a copy if e contains this: Chris@16: if(contains_self(e)) Chris@16: { Chris@16: self_type temp(e); Chris@16: do_subtract(detail::expression(temp), detail::terminal()); Chris@16: } Chris@16: else Chris@16: { Chris@16: do_subtract(e, typename detail::expression::tag_type()); Chris@16: } Chris@16: return *this; Chris@16: } Chris@16: Chris@16: template Chris@16: typename boost::enable_if, number& >::type Chris@16: operator-=(const V& v) Chris@16: { Chris@16: using default_ops::eval_subtract; Chris@16: eval_subtract(m_backend, canonical_value(v)); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: template Chris@16: number& operator-=(const detail::expression& e) Chris@16: { Chris@16: // Chris@16: // Fused multiply-subtract: Chris@16: // Chris@16: using default_ops::eval_multiply_subtract; Chris@16: eval_multiply_subtract(m_backend, canonical_value(e.left_ref()), canonical_value(e.right_ref())); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: Chris@16: number& operator *= (const self_type& e) Chris@16: { Chris@16: do_multiplies(detail::expression(e), detail::terminal()); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: template Chris@16: number& operator*=(const detail::expression& e) Chris@16: { Chris@16: // Create a temporary if the RHS references *this, but not Chris@16: // if we're just doing an x *= x; Chris@16: if(contains_self(e) && !is_self(e)) Chris@16: { Chris@16: self_type temp(e); Chris@16: do_multiplies(detail::expression(temp), detail::terminal()); Chris@16: } Chris@16: else Chris@16: { Chris@16: do_multiplies(e, typename detail::expression::tag_type()); Chris@16: } Chris@16: return *this; Chris@16: } Chris@16: Chris@16: template Chris@16: typename boost::enable_if, number& >::type Chris@16: operator*=(const V& v) Chris@16: { Chris@16: using default_ops::eval_multiply; Chris@16: eval_multiply(m_backend, canonical_value(v)); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: number& operator%=(const self_type& e) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_integer, "The modulus operation is only valid for integer types"); Chris@16: do_modulus(detail::expression(e), detail::terminal()); Chris@16: return *this; Chris@16: } Chris@16: template Chris@16: number& operator%=(const detail::expression& e) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_integer, "The modulus operation is only valid for integer types"); Chris@16: // Create a temporary if the RHS references *this: Chris@16: if(contains_self(e)) Chris@16: { Chris@16: self_type temp(e); Chris@16: do_modulus(detail::expression(temp), detail::terminal()); Chris@16: } Chris@16: else Chris@16: { Chris@16: do_modulus(e, typename detail::expression::tag_type()); Chris@16: } Chris@16: return *this; Chris@16: } Chris@16: template Chris@16: typename boost::enable_if, number& >::type Chris@16: operator%=(const V& v) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_integer, "The modulus operation is only valid for integer types"); Chris@16: using default_ops::eval_modulus; Chris@16: eval_modulus(m_backend, canonical_value(v)); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: // Chris@16: // These operators are *not* proto-ized. Chris@16: // The issue is that the increment/decrement must happen Chris@16: // even if the result of the operator *is never used*. Chris@16: // Possibly we could modify our expression wrapper to Chris@16: // execute the increment/decrement on destruction, but Chris@16: // correct implementation will be tricky, so defered for now... Chris@16: // Chris@16: BOOST_MP_FORCEINLINE number& operator++() Chris@16: { Chris@16: using default_ops::eval_increment; Chris@16: eval_increment(m_backend); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: BOOST_MP_FORCEINLINE number& operator--() Chris@16: { Chris@16: using default_ops::eval_decrement; Chris@16: eval_decrement(m_backend); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: inline number operator++(int) Chris@16: { Chris@16: using default_ops::eval_increment; Chris@16: self_type temp(*this); Chris@16: eval_increment(m_backend); Chris@16: return BOOST_MP_MOVE(temp); Chris@16: } Chris@16: Chris@16: inline number operator--(int) Chris@16: { Chris@16: using default_ops::eval_decrement; Chris@16: self_type temp(*this); Chris@16: eval_decrement(m_backend); Chris@16: return BOOST_MP_MOVE(temp); Chris@16: } Chris@16: Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename boost::enable_if, number&>::type operator <<= (V val) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_integer, "The left-shift operation is only valid for integer types"); Chris@16: detail::check_shift_range(val, mpl::bool_<(sizeof(V) > sizeof(std::size_t))>(), is_signed()); Chris@16: eval_left_shift(m_backend, static_cast(canonical_value(val))); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename boost::enable_if, number&>::type operator >>= (V val) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_integer, "The right-shift operation is only valid for integer types"); Chris@16: detail::check_shift_range(val, mpl::bool_<(sizeof(V) > sizeof(std::size_t))>(), is_signed()); Chris@16: eval_right_shift(m_backend, static_cast(canonical_value(val))); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: BOOST_MP_FORCEINLINE number& operator /= (const self_type& e) Chris@16: { Chris@16: do_divide(detail::expression(e), detail::terminal()); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: template Chris@16: number& operator/=(const detail::expression& e) Chris@16: { Chris@16: // Create a temporary if the RHS references *this: Chris@16: if(contains_self(e)) Chris@16: { Chris@16: self_type temp(e); Chris@16: do_divide(detail::expression(temp), detail::terminal()); Chris@16: } Chris@16: else Chris@16: { Chris@16: do_divide(e, typename detail::expression::tag_type()); Chris@16: } Chris@16: return *this; Chris@16: } Chris@16: Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename boost::enable_if, number& >::type Chris@16: operator/=(const V& v) Chris@16: { Chris@16: using default_ops::eval_divide; Chris@16: eval_divide(m_backend, canonical_value(v)); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: BOOST_MP_FORCEINLINE number& operator&=(const self_type& e) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_integer, "The bitwise & operation is only valid for integer types"); Chris@16: do_bitwise_and(detail::expression(e), detail::terminal()); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: template Chris@16: number& operator&=(const detail::expression& e) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_integer, "The bitwise & operation is only valid for integer types"); Chris@16: // Create a temporary if the RHS references *this, but not Chris@16: // if we're just doing an x &= x; Chris@16: if(contains_self(e) && !is_self(e)) Chris@16: { Chris@16: self_type temp(e); Chris@16: do_bitwise_and(detail::expression(temp), detail::terminal()); Chris@16: } Chris@16: else Chris@16: { Chris@16: do_bitwise_and(e, typename detail::expression::tag_type()); Chris@16: } Chris@16: return *this; Chris@16: } Chris@16: Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename boost::enable_if, number& >::type Chris@16: operator&=(const V& v) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_integer, "The bitwise & operation is only valid for integer types"); Chris@16: using default_ops::eval_bitwise_and; Chris@16: eval_bitwise_and(m_backend, canonical_value(v)); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: BOOST_MP_FORCEINLINE number& operator|=(const self_type& e) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_integer, "The bitwise | operation is only valid for integer types"); Chris@16: do_bitwise_or(detail::expression(e), detail::terminal()); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: template Chris@16: number& operator|=(const detail::expression& e) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_integer, "The bitwise | operation is only valid for integer types"); Chris@16: // Create a temporary if the RHS references *this, but not Chris@16: // if we're just doing an x |= x; Chris@16: if(contains_self(e) && !is_self(e)) Chris@16: { Chris@16: self_type temp(e); Chris@16: do_bitwise_or(detail::expression(temp), detail::terminal()); Chris@16: } Chris@16: else Chris@16: { Chris@16: do_bitwise_or(e, typename detail::expression::tag_type()); Chris@16: } Chris@16: return *this; Chris@16: } Chris@16: Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename boost::enable_if, number& >::type Chris@16: operator|=(const V& v) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_integer, "The bitwise | operation is only valid for integer types"); Chris@16: using default_ops::eval_bitwise_or; Chris@16: eval_bitwise_or(m_backend, canonical_value(v)); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: BOOST_MP_FORCEINLINE number& operator^=(const self_type& e) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types"); Chris@16: do_bitwise_xor(detail::expression(e), detail::terminal()); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: template Chris@16: number& operator^=(const detail::expression& e) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types"); Chris@16: if(contains_self(e)) Chris@16: { Chris@16: self_type temp(e); Chris@16: do_bitwise_xor(detail::expression(temp), detail::terminal()); Chris@16: } Chris@16: else Chris@16: { Chris@16: do_bitwise_xor(e, typename detail::expression::tag_type()); Chris@16: } Chris@16: return *this; Chris@16: } Chris@16: Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename boost::enable_if, number& >::type Chris@16: operator^=(const V& v) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types"); Chris@16: using default_ops::eval_bitwise_xor; Chris@16: eval_bitwise_xor(m_backend, canonical_value(v)); Chris@16: return *this; Chris@16: } Chris@16: // Chris@16: // swap: Chris@16: // Chris@101: BOOST_MP_FORCEINLINE void swap(self_type& other) BOOST_NOEXCEPT_IF(noexcept(std::declval().swap(std::declval()))) Chris@16: { Chris@16: m_backend.swap(other.backend()); Chris@16: } Chris@16: // Chris@16: // Zero and sign: Chris@16: // Chris@16: BOOST_MP_FORCEINLINE bool is_zero()const Chris@16: { Chris@16: using default_ops::eval_is_zero; Chris@16: return eval_is_zero(m_backend); Chris@16: } Chris@16: BOOST_MP_FORCEINLINE int sign()const Chris@16: { Chris@16: using default_ops::eval_get_sign; Chris@16: return eval_get_sign(m_backend); Chris@16: } Chris@16: // Chris@16: // String conversion functions: Chris@16: // Chris@16: std::string str(std::streamsize digits = 0, std::ios_base::fmtflags f = std::ios_base::fmtflags(0))const Chris@16: { Chris@16: return m_backend.str(digits, f); Chris@16: } Chris@16: template Chris@16: void serialize(Archive & ar, const unsigned int /*version*/) Chris@16: { Chris@16: ar & m_backend; Chris@16: } Chris@16: private: Chris@16: template Chris@16: void convert_to_imp(T* result)const Chris@16: { Chris@16: using default_ops::eval_convert_to; Chris@16: eval_convert_to(result, m_backend); Chris@16: } Chris@16: template Chris@101: typename enable_if_c::value>::type convert_to_imp(number* result)const Chris@16: { Chris@16: result->assign(*this); Chris@16: } Chris@16: void convert_to_imp(std::string* result)const Chris@16: { Chris@16: *result = this->str(); Chris@16: } Chris@16: public: Chris@16: template Chris@16: T convert_to()const Chris@16: { Chris@16: T result; Chris@16: convert_to_imp(&result); Chris@16: return result; Chris@16: } Chris@16: // Chris@16: // Use in boolean context, and explicit conversion operators: Chris@16: // Chris@16: #ifndef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS Chris@101: # if (defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 7)) || (defined(BOOST_INTEL) && (BOOST_INTEL <= 1500)) Chris@16: // Chris@16: // Horrible workaround for gcc-4.6.x which always prefers the template Chris@16: // operator bool() rather than the non-template operator when converting to Chris@16: // an arithmetic type: Chris@16: // Chris@16: template , int>::type = 0> Chris@16: explicit operator T ()const Chris@16: { Chris@16: using default_ops::eval_is_zero; Chris@16: return !eval_is_zero(backend()); Chris@16: } Chris@16: template ::value || is_void::value, int>::type = 0> Chris@16: explicit operator T ()const Chris@16: { Chris@16: return this->template convert_to(); Chris@16: } Chris@16: # else Chris@16: template Chris@16: explicit operator T()const Chris@16: { Chris@16: return this->template convert_to(); Chris@16: } Chris@16: BOOST_MP_FORCEINLINE explicit operator bool()const Chris@16: { Chris@16: return !is_zero(); Chris@16: } Chris@16: explicit operator void()const {} Chris@16: # endif Chris@16: #else Chris@16: typedef bool (self_type::*unmentionable_type)()const; Chris@16: Chris@16: BOOST_MP_FORCEINLINE operator unmentionable_type()const Chris@16: { Chris@16: return is_zero() ? 0 : &self_type::is_zero; Chris@16: } Chris@16: #endif Chris@16: // Chris@16: // Default precision: Chris@16: // Chris@16: static unsigned default_precision() BOOST_NOEXCEPT Chris@16: { Chris@16: return Backend::default_precision(); Chris@16: } Chris@16: static void default_precision(unsigned digits10) Chris@16: { Chris@16: Backend::default_precision(digits10); Chris@16: } Chris@16: unsigned precision()const BOOST_NOEXCEPT Chris@16: { Chris@16: return m_backend.precision(); Chris@16: } Chris@16: void precision(unsigned digits10) Chris@16: { Chris@16: m_backend.precision(digits10); Chris@16: } Chris@16: // Chris@16: // Comparison: Chris@16: // Chris@16: BOOST_MP_FORCEINLINE int compare(const number& o)const Chris@16: BOOST_NOEXCEPT_IF(noexcept(std::declval().compare(std::declval()))) Chris@16: { Chris@16: return m_backend.compare(o.m_backend); Chris@16: } Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename boost::enable_if, int>::type compare(const V& o)const Chris@16: { Chris@16: using default_ops::eval_get_sign; Chris@16: if(o == 0) Chris@16: return eval_get_sign(m_backend); Chris@16: return m_backend.compare(canonical_value(o)); Chris@16: } Chris@16: BOOST_MP_FORCEINLINE Backend& backend() BOOST_NOEXCEPT Chris@16: { Chris@16: return m_backend; Chris@16: } Chris@16: BOOST_MP_FORCEINLINE BOOST_CONSTEXPR const Backend& backend()const BOOST_NOEXCEPT Chris@16: { Chris@16: return m_backend; Chris@16: } Chris@16: private: Chris@16: template Chris@16: void do_assign(const detail::expression& e, const mpl::true_&) Chris@16: { Chris@16: do_assign(e, tag()); Chris@16: } Chris@16: template Chris@16: void do_assign(const detail::expression& e, const mpl::false_&) Chris@16: { Chris@16: // The result of the expression isn't the same type as this - Chris@16: // create a temporary result and assign it to *this: Chris@16: typedef typename detail::expression::result_type temp_type; Chris@16: temp_type t(e); Chris@16: this->assign(t); Chris@16: } Chris@16: Chris@16: Chris@16: template Chris@16: void do_assign(const Exp& e, const detail::add_immediates&) Chris@16: { Chris@16: using default_ops::eval_add; Chris@16: eval_add(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value())); Chris@16: } Chris@16: template Chris@16: void do_assign(const Exp& e, const detail::subtract_immediates&) Chris@16: { Chris@16: using default_ops::eval_subtract; Chris@16: eval_subtract(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value())); Chris@16: } Chris@16: template Chris@16: void do_assign(const Exp& e, const detail::multiply_immediates&) Chris@16: { Chris@16: using default_ops::eval_multiply; Chris@16: eval_multiply(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value())); Chris@16: } Chris@16: template Chris@16: void do_assign(const Exp& e, const detail::multiply_add&) Chris@16: { Chris@16: using default_ops::eval_multiply_add; Chris@16: eval_multiply_add(m_backend, canonical_value(e.left().value()), canonical_value(e.middle().value()), canonical_value(e.right().value())); Chris@16: } Chris@16: template Chris@16: void do_assign(const Exp& e, const detail::multiply_subtract&) Chris@16: { Chris@16: using default_ops::eval_multiply_subtract; Chris@16: eval_multiply_subtract(m_backend, canonical_value(e.left().value()), canonical_value(e.middle().value()), canonical_value(e.right().value())); Chris@16: } Chris@16: Chris@16: template Chris@16: void do_assign(const Exp& e, const detail::divide_immediates&) Chris@16: { Chris@16: using default_ops::eval_divide; Chris@16: eval_divide(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value())); Chris@16: } Chris@16: Chris@16: template Chris@16: void do_assign(const Exp& e, const detail::negate&) Chris@16: { Chris@16: typedef typename Exp::left_type left_type; Chris@16: do_assign(e.left(), typename left_type::tag_type()); Chris@16: m_backend.negate(); Chris@16: } Chris@16: template Chris@16: void do_assign(const Exp& e, const detail::plus&) Chris@16: { Chris@16: typedef typename Exp::left_type left_type; Chris@16: typedef typename Exp::right_type right_type; Chris@16: Chris@16: static int const left_depth = left_type::depth; Chris@16: static int const right_depth = right_type::depth; Chris@16: Chris@16: bool bl = contains_self(e.left()); Chris@16: bool br = contains_self(e.right()); Chris@16: Chris@16: if(bl && is_self(e.left())) Chris@16: { Chris@16: // Ignore the left node, it's *this, just add the right: Chris@16: do_add(e.right(), typename right_type::tag_type()); Chris@16: } Chris@16: else if(br && is_self(e.right())) Chris@16: { Chris@16: // Ignore the right node, it's *this, just add the left: Chris@16: do_add(e.left(), typename left_type::tag_type()); Chris@16: } Chris@16: else if(bl && br) Chris@16: { Chris@16: self_type temp(e); Chris@16: temp.m_backend.swap(this->m_backend); Chris@16: } Chris@16: else if(!br && (bl || (left_depth >= right_depth))) Chris@16: { // br is always false, but if bl is true we must take the this branch: Chris@16: do_assign(e.left(), typename left_type::tag_type()); Chris@16: do_add(e.right(), typename right_type::tag_type()); Chris@16: } Chris@16: else Chris@16: { Chris@16: do_assign(e.right(), typename right_type::tag_type()); Chris@16: do_add(e.left(), typename left_type::tag_type()); Chris@16: } Chris@16: } Chris@16: template Chris@16: void do_assign(const Exp& e, const detail::minus&) Chris@16: { Chris@16: typedef typename Exp::left_type left_type; Chris@16: typedef typename Exp::right_type right_type; Chris@16: Chris@16: static int const left_depth = left_type::depth; Chris@16: static int const right_depth = right_type::depth; Chris@16: Chris@16: bool bl = contains_self(e.left()); Chris@16: bool br = contains_self(e.right()); Chris@16: Chris@16: if(bl && is_self(e.left())) Chris@16: { Chris@16: // Ignore the left node, it's *this, just subtract the right: Chris@16: do_subtract(e.right(), typename right_type::tag_type()); Chris@16: } Chris@16: else if(br && is_self(e.right())) Chris@16: { Chris@16: // Ignore the right node, it's *this, just subtract the left and negate the result: Chris@16: do_subtract(e.left(), typename left_type::tag_type()); Chris@16: m_backend.negate(); Chris@16: } Chris@16: else if(bl && br) Chris@16: { Chris@16: self_type temp(e); Chris@16: temp.m_backend.swap(this->m_backend); Chris@16: } Chris@16: else if(!br && (bl || (left_depth >= right_depth))) Chris@16: { // br is always false, but if bl is true we must take the this branch: Chris@16: do_assign(e.left(), typename left_type::tag_type()); Chris@16: do_subtract(e.right(), typename right_type::tag_type()); Chris@16: } Chris@16: else Chris@16: { Chris@16: do_assign(e.right(), typename right_type::tag_type()); Chris@16: do_subtract(e.left(), typename left_type::tag_type()); Chris@16: m_backend.negate(); Chris@16: } Chris@16: } Chris@16: template Chris@16: void do_assign(const Exp& e, const detail::multiplies&) Chris@16: { Chris@16: typedef typename Exp::left_type left_type; Chris@16: typedef typename Exp::right_type right_type; Chris@16: Chris@16: static int const left_depth = left_type::depth; Chris@16: static int const right_depth = right_type::depth; Chris@16: Chris@16: bool bl = contains_self(e.left()); Chris@16: bool br = contains_self(e.right()); Chris@16: Chris@16: if(bl && is_self(e.left())) Chris@16: { Chris@16: // Ignore the left node, it's *this, just add the right: Chris@16: do_multiplies(e.right(), typename right_type::tag_type()); Chris@16: } Chris@16: else if(br && is_self(e.right())) Chris@16: { Chris@16: // Ignore the right node, it's *this, just add the left: Chris@16: do_multiplies(e.left(), typename left_type::tag_type()); Chris@16: } Chris@16: else if(bl && br) Chris@16: { Chris@16: self_type temp(e); Chris@16: temp.m_backend.swap(this->m_backend); Chris@16: } Chris@16: else if(!br && (bl || (left_depth >= right_depth))) Chris@16: { // br is always false, but if bl is true we must take the this branch: Chris@16: do_assign(e.left(), typename left_type::tag_type()); Chris@16: do_multiplies(e.right(), typename right_type::tag_type()); Chris@16: } Chris@16: else Chris@16: { Chris@16: do_assign(e.right(), typename right_type::tag_type()); Chris@16: do_multiplies(e.left(), typename left_type::tag_type()); Chris@16: } Chris@16: } Chris@16: template Chris@16: void do_assign(const Exp& e, const detail::divides&) Chris@16: { Chris@16: typedef typename Exp::left_type left_type; Chris@16: typedef typename Exp::right_type right_type; Chris@16: Chris@16: bool bl = contains_self(e.left()); Chris@16: bool br = contains_self(e.right()); Chris@16: Chris@16: if(bl && is_self(e.left())) Chris@16: { Chris@16: // Ignore the left node, it's *this, just add the right: Chris@16: do_divide(e.right(), typename right_type::tag_type()); Chris@16: } Chris@16: else if(br) Chris@16: { Chris@16: self_type temp(e); Chris@16: temp.m_backend.swap(this->m_backend); Chris@16: } Chris@16: else Chris@16: { Chris@16: do_assign(e.left(), typename left_type::tag_type()); Chris@16: do_divide(e.right(), typename right_type::tag_type()); Chris@16: } Chris@16: } Chris@16: template Chris@16: void do_assign(const Exp& e, const detail::modulus&) Chris@16: { Chris@16: // Chris@16: // This operation is only valid for integer backends: Chris@16: // Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_integer, "The modulus operation is only valid for integer types"); Chris@16: Chris@16: typedef typename Exp::left_type left_type; Chris@16: typedef typename Exp::right_type right_type; Chris@16: Chris@16: bool bl = contains_self(e.left()); Chris@16: bool br = contains_self(e.right()); Chris@16: Chris@16: if(bl && is_self(e.left())) Chris@16: { Chris@16: // Ignore the left node, it's *this, just add the right: Chris@16: do_modulus(e.right(), typename right_type::tag_type()); Chris@16: } Chris@16: else if(br) Chris@16: { Chris@16: self_type temp(e); Chris@16: temp.m_backend.swap(this->m_backend); Chris@16: } Chris@16: else Chris@16: { Chris@16: do_assign(e.left(), typename left_type::tag_type()); Chris@16: do_modulus(e.right(), typename right_type::tag_type()); Chris@16: } Chris@16: } Chris@16: template Chris@16: void do_assign(const Exp& e, const detail::modulus_immediates&) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_integer, "The modulus operation is only valid for integer types"); Chris@16: using default_ops::eval_modulus; Chris@16: eval_modulus(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value())); Chris@16: } Chris@16: Chris@16: template Chris@16: void do_assign(const Exp& e, const detail::bitwise_and&) Chris@16: { Chris@16: // Chris@16: // This operation is only valid for integer backends: Chris@16: // Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_integer, "Bitwise operations are only valid for integer types"); Chris@16: Chris@16: typedef typename Exp::left_type left_type; Chris@16: typedef typename Exp::right_type right_type; Chris@16: Chris@16: static int const left_depth = left_type::depth; Chris@16: static int const right_depth = right_type::depth; Chris@16: Chris@16: bool bl = contains_self(e.left()); Chris@16: bool br = contains_self(e.right()); Chris@16: Chris@16: if(bl && is_self(e.left())) Chris@16: { Chris@16: // Ignore the left node, it's *this, just add the right: Chris@16: do_bitwise_and(e.right(), typename right_type::tag_type()); Chris@16: } Chris@16: else if(br && is_self(e.right())) Chris@16: { Chris@16: do_bitwise_and(e.left(), typename left_type::tag_type()); Chris@16: } Chris@16: else if(!br && (bl || (left_depth >= right_depth))) Chris@16: { Chris@16: do_assign(e.left(), typename left_type::tag_type()); Chris@16: do_bitwise_and(e.right(), typename right_type::tag_type()); Chris@16: } Chris@16: else Chris@16: { Chris@16: do_assign(e.right(), typename right_type::tag_type()); Chris@16: do_bitwise_and(e.left(), typename left_type::tag_type()); Chris@16: } Chris@16: } Chris@16: template Chris@16: void do_assign(const Exp& e, const detail::bitwise_and_immediates&) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_integer, "Bitwise operations are only valid for integer types"); Chris@16: using default_ops::eval_bitwise_and; Chris@16: eval_bitwise_and(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value())); Chris@16: } Chris@16: Chris@16: template Chris@16: void do_assign(const Exp& e, const detail::bitwise_or&) Chris@16: { Chris@16: // Chris@16: // This operation is only valid for integer backends: Chris@16: // Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_integer, "Bitwise operations are only valid for integer types"); Chris@16: Chris@16: typedef typename Exp::left_type left_type; Chris@16: typedef typename Exp::right_type right_type; Chris@16: Chris@16: static int const left_depth = left_type::depth; Chris@16: static int const right_depth = right_type::depth; Chris@16: Chris@16: bool bl = contains_self(e.left()); Chris@16: bool br = contains_self(e.right()); Chris@16: Chris@16: if(bl && is_self(e.left())) Chris@16: { Chris@16: // Ignore the left node, it's *this, just add the right: Chris@16: do_bitwise_or(e.right(), typename right_type::tag_type()); Chris@16: } Chris@16: else if(br && is_self(e.right())) Chris@16: { Chris@16: do_bitwise_or(e.left(), typename left_type::tag_type()); Chris@16: } Chris@16: else if(!br && (bl || (left_depth >= right_depth))) Chris@16: { Chris@16: do_assign(e.left(), typename left_type::tag_type()); Chris@16: do_bitwise_or(e.right(), typename right_type::tag_type()); Chris@16: } Chris@16: else Chris@16: { Chris@16: do_assign(e.right(), typename right_type::tag_type()); Chris@16: do_bitwise_or(e.left(), typename left_type::tag_type()); Chris@16: } Chris@16: } Chris@16: template Chris@16: void do_assign(const Exp& e, const detail::bitwise_or_immediates&) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_integer, "Bitwise operations are only valid for integer types"); Chris@16: using default_ops::eval_bitwise_or; Chris@16: eval_bitwise_or(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value())); Chris@16: } Chris@16: Chris@16: template Chris@16: void do_assign(const Exp& e, const detail::bitwise_xor&) Chris@16: { Chris@16: // Chris@16: // This operation is only valid for integer backends: Chris@16: // Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_integer, "Bitwise operations are only valid for integer types"); Chris@16: Chris@16: typedef typename Exp::left_type left_type; Chris@16: typedef typename Exp::right_type right_type; Chris@16: Chris@16: static int const left_depth = left_type::depth; Chris@16: static int const right_depth = right_type::depth; Chris@16: Chris@16: bool bl = contains_self(e.left()); Chris@16: bool br = contains_self(e.right()); Chris@16: Chris@16: if(bl && is_self(e.left())) Chris@16: { Chris@16: // Ignore the left node, it's *this, just add the right: Chris@16: do_bitwise_xor(e.right(), typename right_type::tag_type()); Chris@16: } Chris@16: else if(br && is_self(e.right())) Chris@16: { Chris@16: do_bitwise_xor(e.left(), typename left_type::tag_type()); Chris@16: } Chris@16: else if(!br && (bl || (left_depth >= right_depth))) Chris@16: { Chris@16: do_assign(e.left(), typename left_type::tag_type()); Chris@16: do_bitwise_xor(e.right(), typename right_type::tag_type()); Chris@16: } Chris@16: else Chris@16: { Chris@16: do_assign(e.right(), typename right_type::tag_type()); Chris@16: do_bitwise_xor(e.left(), typename left_type::tag_type()); Chris@16: } Chris@16: } Chris@16: template Chris@16: void do_assign(const Exp& e, const detail::bitwise_xor_immediates&) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_integer, "Bitwise operations are only valid for integer types"); Chris@16: using default_ops::eval_bitwise_xor; Chris@16: eval_bitwise_xor(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value())); Chris@16: } Chris@16: template Chris@16: void do_assign(const Exp& e, const detail::terminal&) Chris@16: { Chris@16: if(!is_self(e)) Chris@16: { Chris@16: m_backend = canonical_value(e.value()); Chris@16: } Chris@16: } Chris@16: template Chris@16: void do_assign(const Exp& e, const detail::function&) Chris@16: { Chris@16: typedef typename Exp::arity tag_type; Chris@16: do_assign_function(e, tag_type()); Chris@16: } Chris@16: template Chris@16: void do_assign(const Exp& e, const detail::shift_left&) Chris@16: { Chris@16: // We can only shift by an integer value, not an arbitrary expression: Chris@16: typedef typename Exp::left_type left_type; Chris@16: typedef typename Exp::right_type right_type; Chris@16: typedef typename right_type::arity right_arity; Chris@16: BOOST_STATIC_ASSERT_MSG(right_arity::value == 0, "The left shift operator requires an integer value for the shift operand."); Chris@16: typedef typename right_type::result_type right_value_type; Chris@16: BOOST_STATIC_ASSERT_MSG(is_integral::value, "The left shift operator requires an integer value for the shift operand."); Chris@16: typedef typename left_type::tag_type tag_type; Chris@16: do_assign_left_shift(e.left(), canonical_value(e.right().value()), tag_type()); Chris@16: } Chris@16: Chris@16: template Chris@16: void do_assign(const Exp& e, const detail::shift_right&) Chris@16: { Chris@16: // We can only shift by an integer value, not an arbitrary expression: Chris@16: typedef typename Exp::left_type left_type; Chris@16: typedef typename Exp::right_type right_type; Chris@16: typedef typename right_type::arity right_arity; Chris@16: BOOST_STATIC_ASSERT_MSG(right_arity::value == 0, "The left shift operator requires an integer value for the shift operand."); Chris@16: typedef typename right_type::result_type right_value_type; Chris@16: BOOST_STATIC_ASSERT_MSG(is_integral::value, "The left shift operator requires an integer value for the shift operand."); Chris@16: typedef typename left_type::tag_type tag_type; Chris@16: do_assign_right_shift(e.left(), canonical_value(e.right().value()), tag_type()); Chris@16: } Chris@16: Chris@16: template Chris@16: void do_assign(const Exp& e, const detail::bitwise_complement&) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_integer, "The bitwise ~ operation is only valid for integer types"); Chris@16: using default_ops::eval_complement; Chris@16: self_type temp(e.left()); Chris@16: eval_complement(m_backend, temp.backend()); Chris@16: } Chris@16: Chris@16: template Chris@16: void do_assign(const Exp& e, const detail::complement_immediates&) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_integer, "The bitwise ~ operation is only valid for integer types"); Chris@16: using default_ops::eval_complement; Chris@16: eval_complement(m_backend, canonical_value(e.left().value())); Chris@16: } Chris@16: Chris@16: template Chris@16: void do_assign_right_shift(const Exp& e, const Val& val, const detail::terminal&) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_integer, "The right shift operation is only valid for integer types"); Chris@16: using default_ops::eval_right_shift; Chris@16: detail::check_shift_range(val, mpl::bool_<(sizeof(Val) > sizeof(std::size_t))>(), is_signed()); Chris@16: eval_right_shift(m_backend, canonical_value(e.value()), static_cast(val)); Chris@16: } Chris@16: Chris@16: template Chris@16: void do_assign_left_shift(const Exp& e, const Val& val, const detail::terminal&) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_integer, "The left shift operation is only valid for integer types"); Chris@16: using default_ops::eval_left_shift; Chris@16: detail::check_shift_range(val, mpl::bool_<(sizeof(Val) > sizeof(std::size_t))>(), is_signed()); Chris@16: eval_left_shift(m_backend, canonical_value(e.value()), static_cast(val)); Chris@16: } Chris@16: Chris@16: template Chris@16: void do_assign_right_shift(const Exp& e, const Val& val, const Tag&) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_integer, "The right shift operation is only valid for integer types"); Chris@16: using default_ops::eval_right_shift; Chris@16: self_type temp(e); Chris@16: detail::check_shift_range(val, mpl::bool_<(sizeof(Val) > sizeof(std::size_t))>(), is_signed()); Chris@16: eval_right_shift(m_backend, temp.backend(), static_cast(val)); Chris@16: } Chris@16: Chris@16: template Chris@16: void do_assign_left_shift(const Exp& e, const Val& val, const Tag&) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_integer, "The left shift operation is only valid for integer types"); Chris@16: using default_ops::eval_left_shift; Chris@16: self_type temp(e); Chris@16: detail::check_shift_range(val, mpl::bool_<(sizeof(Val) > sizeof(std::size_t))>(), is_signed()); Chris@16: eval_left_shift(m_backend, temp.backend(), static_cast(val)); Chris@16: } Chris@16: Chris@16: template Chris@16: void do_assign_function(const Exp& e, const mpl::int_<1>&) Chris@16: { Chris@16: e.left().value()(&m_backend); Chris@16: } Chris@16: template Chris@16: void do_assign_function(const Exp& e, const mpl::int_<2>&) Chris@16: { Chris@16: typedef typename Exp::right_type right_type; Chris@16: typedef typename right_type::tag_type tag_type; Chris@16: do_assign_function_1(e.left().value(), e.right_ref(), tag_type()); Chris@16: } Chris@16: template Chris@16: void do_assign_function_1(const F& f, const Exp& val, const detail::terminal&) Chris@16: { Chris@16: f(m_backend, function_arg_value(val)); Chris@16: } Chris@16: template Chris@16: void do_assign_function_1(const F& f, const Exp& val, const Tag&) Chris@16: { Chris@16: number t(val); Chris@16: f(m_backend, t.backend()); Chris@16: } Chris@16: template Chris@16: void do_assign_function(const Exp& e, const mpl::int_<3>&) Chris@16: { Chris@16: typedef typename Exp::middle_type middle_type; Chris@16: typedef typename middle_type::tag_type tag_type; Chris@16: typedef typename Exp::right_type end_type; Chris@16: typedef typename end_type::tag_type end_tag; Chris@16: do_assign_function_2(e.left().value(), e.middle_ref(), e.right_ref(), tag_type(), end_tag()); Chris@16: } Chris@16: template Chris@16: void do_assign_function_2(const F& f, const Exp1& val1, const Exp2& val2, const detail::terminal&, const detail::terminal&) Chris@16: { Chris@16: f(m_backend, function_arg_value(val1), function_arg_value(val2)); Chris@16: } Chris@16: template Chris@16: void do_assign_function_2(const F& f, const Exp1& val1, const Exp2& val2, const Tag1&, const detail::terminal&) Chris@16: { Chris@16: self_type temp1(val1); Chris@16: f(m_backend, BOOST_MP_MOVE(temp1.backend()), function_arg_value(val2)); Chris@16: } Chris@16: template Chris@16: void do_assign_function_2(const F& f, const Exp1& val1, const Exp2& val2, const detail::terminal&, const Tag2&) Chris@16: { Chris@16: self_type temp2(val2); Chris@16: f(m_backend, function_arg_value(val1), BOOST_MP_MOVE(temp2.backend())); Chris@16: } Chris@16: template Chris@16: void do_assign_function_2(const F& f, const Exp1& val1, const Exp2& val2, const Tag1&, const Tag2&) Chris@16: { Chris@16: self_type temp1(val1); Chris@16: self_type temp2(val2); Chris@16: f(m_backend, BOOST_MP_MOVE(temp1.backend()), BOOST_MP_MOVE(temp2.backend())); Chris@16: } Chris@16: Chris@16: template Chris@16: void do_assign_function(const Exp& e, const mpl::int_<4>&) Chris@16: { Chris@16: typedef typename Exp::left_middle_type left_type; Chris@16: typedef typename left_type::tag_type left_tag_type; Chris@16: typedef typename Exp::right_middle_type middle_type; Chris@16: typedef typename middle_type::tag_type middle_tag_type; Chris@16: typedef typename Exp::right_type right_type; Chris@16: typedef typename right_type::tag_type right_tag_type; Chris@16: do_assign_function_3a(e.left().value(), e.left_middle_ref(), e.right_middle_ref(), e.right_ref(), left_tag_type(), middle_tag_type(), right_tag_type()); Chris@16: } Chris@16: template Chris@16: void do_assign_function_3a(const F& f, const Exp1& val1, const Exp2& val2, const Exp3& val3, const detail::terminal&, const Tag2& t2, const Tag3& t3) Chris@16: { Chris@16: do_assign_function_3b(f, val1, val2, val3, t2, t3); Chris@16: } Chris@16: template Chris@16: void do_assign_function_3a(const F& f, const Exp1& val1, const Exp2& val2, const Exp3& val3, const Tag1&, const Tag2& t2, const Tag3& t3) Chris@16: { Chris@16: number t(val1); Chris@16: do_assign_function_3b(f, BOOST_MP_MOVE(t), val2, val3, t2, t3); Chris@16: } Chris@16: template Chris@16: void do_assign_function_3b(const F& f, const Exp1& val1, const Exp2& val2, const Exp3& val3, const detail::terminal&, const Tag3& t3) Chris@16: { Chris@16: do_assign_function_3c(f, val1, val2, val3, t3); Chris@16: } Chris@16: template Chris@16: void do_assign_function_3b(const F& f, const Exp1& val1, const Exp2& val2, const Exp3& val3, const Tag2& /*t2*/, const Tag3& t3) Chris@16: { Chris@16: number t(val2); Chris@16: do_assign_function_3c(f, val1, BOOST_MP_MOVE(t), val3, t3); Chris@16: } Chris@16: template Chris@16: void do_assign_function_3c(const F& f, const Exp1& val1, const Exp2& val2, const Exp3& val3, const detail::terminal&) Chris@16: { Chris@16: f(m_backend, function_arg_value(val1), function_arg_value(val2), function_arg_value(val3)); Chris@16: } Chris@16: template Chris@16: void do_assign_function_3c(const F& f, const Exp1& val1, const Exp2& val2, const Exp3& val3, const Tag3& /*t3*/) Chris@16: { Chris@16: number t(val3); Chris@16: do_assign_function_3c(f, val1, val2, BOOST_MP_MOVE(t), detail::terminal()); Chris@16: } Chris@16: Chris@16: template Chris@16: void do_add(const Exp& e, const detail::terminal&) Chris@16: { Chris@16: using default_ops::eval_add; Chris@16: eval_add(m_backend, canonical_value(e.value())); Chris@16: } Chris@16: Chris@16: template Chris@16: void do_add(const Exp& e, const detail::negate&) Chris@16: { Chris@16: typedef typename Exp::left_type left_type; Chris@16: do_subtract(e.left(), typename left_type::tag_type()); Chris@16: } Chris@16: Chris@16: template Chris@16: void do_add(const Exp& e, const detail::plus&) Chris@16: { Chris@16: typedef typename Exp::left_type left_type; Chris@16: typedef typename Exp::right_type right_type; Chris@16: do_add(e.left(), typename left_type::tag_type()); Chris@16: do_add(e.right(), typename right_type::tag_type()); Chris@16: } Chris@16: Chris@16: template Chris@16: void do_add(const Exp& e, const detail::minus&) Chris@16: { Chris@16: typedef typename Exp::left_type left_type; Chris@16: typedef typename Exp::right_type right_type; Chris@16: do_add(e.left(), typename left_type::tag_type()); Chris@16: do_subtract(e.right(), typename right_type::tag_type()); Chris@16: } Chris@16: Chris@16: template Chris@16: void do_add(const Exp& e, const unknown&) Chris@16: { Chris@16: self_type temp(e); Chris@16: do_add(detail::expression(temp), detail::terminal()); Chris@16: } Chris@16: Chris@16: template Chris@16: void do_add(const Exp& e, const detail::add_immediates&) Chris@16: { Chris@16: using default_ops::eval_add; Chris@16: eval_add(m_backend, canonical_value(e.left().value())); Chris@16: eval_add(m_backend, canonical_value(e.right().value())); Chris@16: } Chris@16: template Chris@16: void do_add(const Exp& e, const detail::subtract_immediates&) Chris@16: { Chris@16: using default_ops::eval_add; Chris@16: using default_ops::eval_subtract; Chris@16: eval_add(m_backend, canonical_value(e.left().value())); Chris@16: eval_subtract(m_backend, canonical_value(e.right().value())); Chris@16: } Chris@16: template Chris@16: void do_subtract(const Exp& e, const detail::terminal&) Chris@16: { Chris@16: using default_ops::eval_subtract; Chris@16: eval_subtract(m_backend, canonical_value(e.value())); Chris@16: } Chris@16: Chris@16: template Chris@16: void do_subtract(const Exp& e, const detail::negate&) Chris@16: { Chris@16: typedef typename Exp::left_type left_type; Chris@16: do_add(e.left(), typename left_type::tag_type()); Chris@16: } Chris@16: Chris@16: template Chris@16: void do_subtract(const Exp& e, const detail::plus&) Chris@16: { Chris@16: typedef typename Exp::left_type left_type; Chris@16: typedef typename Exp::right_type right_type; Chris@16: do_subtract(e.left(), typename left_type::tag_type()); Chris@16: do_subtract(e.right(), typename right_type::tag_type()); Chris@16: } Chris@16: Chris@16: template Chris@16: void do_subtract(const Exp& e, const detail::minus&) Chris@16: { Chris@16: typedef typename Exp::left_type left_type; Chris@16: typedef typename Exp::right_type right_type; Chris@16: do_subtract(e.left(), typename left_type::tag_type()); Chris@16: do_add(e.right(), typename right_type::tag_type()); Chris@16: } Chris@16: template Chris@16: void do_subtract(const Exp& e, const detail::add_immediates&) Chris@16: { Chris@16: using default_ops::eval_subtract; Chris@16: eval_subtract(m_backend, canonical_value(e.left().value())); Chris@16: eval_subtract(m_backend, canonical_value(e.right().value())); Chris@16: } Chris@16: template Chris@16: void do_subtract(const Exp& e, const detail::subtract_immediates&) Chris@16: { Chris@16: using default_ops::eval_add; Chris@16: using default_ops::eval_subtract; Chris@16: eval_subtract(m_backend, canonical_value(e.left().value())); Chris@16: eval_add(m_backend, canonical_value(e.right().value())); Chris@16: } Chris@16: template Chris@16: void do_subtract(const Exp& e, const unknown&) Chris@16: { Chris@16: self_type temp(e); Chris@16: do_subtract(detail::expression(temp), detail::terminal()); Chris@16: } Chris@16: Chris@16: template Chris@16: void do_multiplies(const Exp& e, const detail::terminal&) Chris@16: { Chris@16: using default_ops::eval_multiply; Chris@16: eval_multiply(m_backend, canonical_value(e.value())); Chris@16: } Chris@16: Chris@16: template Chris@16: void do_multiplies(const Exp& e, const detail::negate&) Chris@16: { Chris@16: typedef typename Exp::left_type left_type; Chris@16: do_multiplies(e.left(), typename left_type::tag_type()); Chris@16: m_backend.negate(); Chris@16: } Chris@16: Chris@16: template Chris@16: void do_multiplies(const Exp& e, const detail::multiplies&) Chris@16: { Chris@16: typedef typename Exp::left_type left_type; Chris@16: typedef typename Exp::right_type right_type; Chris@16: do_multiplies(e.left(), typename left_type::tag_type()); Chris@16: do_multiplies(e.right(), typename right_type::tag_type()); Chris@16: } Chris@101: // Chris@101: // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make Chris@101: // the disable_if dependent on the template argument (the size of 1 can never occur in practice). Chris@101: // Chris@16: template Chris@101: typename boost::disable_if_c::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1>::type Chris@101: do_multiplies(const Exp& e, const detail::divides&) Chris@16: { Chris@16: typedef typename Exp::left_type left_type; Chris@16: typedef typename Exp::right_type right_type; Chris@16: do_multiplies(e.left(), typename left_type::tag_type()); Chris@16: do_divide(e.right(), typename right_type::tag_type()); Chris@16: } Chris@16: Chris@16: template Chris@16: void do_multiplies(const Exp& e, const detail::multiply_immediates&) Chris@16: { Chris@16: using default_ops::eval_multiply; Chris@16: eval_multiply(m_backend, canonical_value(e.left().value())); Chris@16: eval_multiply(m_backend, canonical_value(e.right().value())); Chris@16: } Chris@101: // Chris@101: // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make Chris@101: // the disable_if dependent on the template argument (the size of 1 can never occur in practice). Chris@101: // Chris@16: template Chris@101: typename boost::disable_if_c::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1>::type Chris@101: do_multiplies(const Exp& e, const detail::divide_immediates&) Chris@16: { Chris@16: using default_ops::eval_multiply; Chris@16: using default_ops::eval_divide; Chris@16: eval_multiply(m_backend, canonical_value(e.left().value())); Chris@16: eval_divide(m_backend, canonical_value(e.right().value())); Chris@16: } Chris@16: template Chris@16: void do_multiplies(const Exp& e, const unknown&) Chris@16: { Chris@16: using default_ops::eval_multiply; Chris@16: self_type temp(e); Chris@16: eval_multiply(m_backend, temp.m_backend); Chris@16: } Chris@16: Chris@16: template Chris@16: void do_divide(const Exp& e, const detail::terminal&) Chris@16: { Chris@16: using default_ops::eval_divide; Chris@16: eval_divide(m_backend, canonical_value(e.value())); Chris@16: } Chris@16: Chris@16: template Chris@16: void do_divide(const Exp& e, const detail::negate&) Chris@16: { Chris@16: typedef typename Exp::left_type left_type; Chris@16: do_divide(e.left(), typename left_type::tag_type()); Chris@16: m_backend.negate(); Chris@16: } Chris@101: // Chris@101: // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make Chris@101: // the disable_if dependent on the template argument (the size of 1 can never occur in practice). Chris@101: // Chris@16: template Chris@101: typename boost::disable_if_c::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1>::type Chris@101: do_divide(const Exp& e, const detail::multiplies&) Chris@16: { Chris@16: typedef typename Exp::left_type left_type; Chris@16: typedef typename Exp::right_type right_type; Chris@16: do_divide(e.left(), typename left_type::tag_type()); Chris@16: do_divide(e.right(), typename right_type::tag_type()); Chris@16: } Chris@101: // Chris@101: // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make Chris@101: // the disable_if dependent on the template argument (the size of 1 can never occur in practice). Chris@101: // Chris@16: template Chris@101: typename boost::disable_if_c::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1>::type Chris@101: do_divide(const Exp& e, const detail::divides&) Chris@16: { Chris@16: typedef typename Exp::left_type left_type; Chris@16: typedef typename Exp::right_type right_type; Chris@16: do_divide(e.left(), typename left_type::tag_type()); Chris@16: do_multiplies(e.right(), typename right_type::tag_type()); Chris@16: } Chris@101: // Chris@101: // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make Chris@101: // the disable_if dependent on the template argument (the size of 1 can never occur in practice). Chris@101: // Chris@16: template Chris@101: typename boost::disable_if_c::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1>::type Chris@101: do_divides(const Exp& e, const detail::multiply_immediates&) Chris@16: { Chris@16: using default_ops::eval_divide; Chris@16: eval_divide(m_backend, canonical_value(e.left().value())); Chris@16: eval_divide(m_backend, canonical_value(e.right().value())); Chris@16: } Chris@101: // Chris@101: // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make Chris@101: // the disable_if dependent on the template argument (the size of 1 can never occur in practice). Chris@101: // Chris@16: template Chris@101: typename boost::disable_if_c::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1>::type Chris@101: do_divides(const Exp& e, const detail::divide_immediates&) Chris@16: { Chris@16: using default_ops::eval_multiply; Chris@16: using default_ops::eval_divide; Chris@16: eval_divide(m_backend, canonical_value(e.left().value())); Chris@16: mutiply(m_backend, canonical_value(e.right().value())); Chris@16: } Chris@16: Chris@16: template Chris@16: void do_divide(const Exp& e, const unknown&) Chris@16: { Chris@16: using default_ops::eval_multiply; Chris@16: self_type temp(e); Chris@16: eval_divide(m_backend, temp.m_backend); Chris@16: } Chris@16: Chris@16: template Chris@16: void do_modulus(const Exp& e, const detail::terminal&) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_integer, "The modulus operation is only valid for integer types"); Chris@16: using default_ops::eval_modulus; Chris@16: eval_modulus(m_backend, canonical_value(e.value())); Chris@16: } Chris@16: Chris@16: template Chris@16: void do_modulus(const Exp& e, const Unknown&) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_integer, "The modulus operation is only valid for integer types"); Chris@16: using default_ops::eval_modulus; Chris@16: self_type temp(e); Chris@16: eval_modulus(m_backend, canonical_value(temp)); Chris@16: } Chris@16: Chris@16: template Chris@16: void do_bitwise_and(const Exp& e, const detail::terminal&) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_integer, "The bitwise & operation is only valid for integer types"); Chris@16: using default_ops::eval_bitwise_and; Chris@16: eval_bitwise_and(m_backend, canonical_value(e.value())); Chris@16: } Chris@16: template Chris@16: void do_bitwise_and(const Exp& e, const detail::bitwise_and&) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_integer, "The bitwise & operation is only valid for integer types"); Chris@16: typedef typename Exp::left_type left_type; Chris@16: typedef typename Exp::right_type right_type; Chris@16: do_bitwise_and(e.left(), typename left_type::tag_type()); Chris@16: do_bitwise_and(e.right(), typename right_type::tag_type()); Chris@16: } Chris@16: template Chris@16: void do_bitwise_and(const Exp& e, const unknown&) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_integer, "The bitwise & operation is only valid for integer types"); Chris@16: using default_ops::eval_bitwise_and; Chris@16: self_type temp(e); Chris@16: eval_bitwise_and(m_backend, temp.m_backend); Chris@16: } Chris@16: Chris@16: template Chris@16: void do_bitwise_or(const Exp& e, const detail::terminal&) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_integer, "The bitwise | operation is only valid for integer types"); Chris@16: using default_ops::eval_bitwise_or; Chris@16: eval_bitwise_or(m_backend, canonical_value(e.value())); Chris@16: } Chris@16: template Chris@16: void do_bitwise_or(const Exp& e, const detail::bitwise_or&) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_integer, "The bitwise | operation is only valid for integer types"); Chris@16: typedef typename Exp::left_type left_type; Chris@16: typedef typename Exp::right_type right_type; Chris@16: do_bitwise_or(e.left(), typename left_type::tag_type()); Chris@16: do_bitwise_or(e.right(), typename right_type::tag_type()); Chris@16: } Chris@16: template Chris@16: void do_bitwise_or(const Exp& e, const unknown&) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_integer, "The bitwise | operation is only valid for integer types"); Chris@16: using default_ops::eval_bitwise_or; Chris@16: self_type temp(e); Chris@16: eval_bitwise_or(m_backend, temp.m_backend); Chris@16: } Chris@16: Chris@16: template Chris@16: void do_bitwise_xor(const Exp& e, const detail::terminal&) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types"); Chris@16: using default_ops::eval_bitwise_xor; Chris@16: eval_bitwise_xor(m_backend, canonical_value(e.value())); Chris@16: } Chris@16: template Chris@16: void do_bitwise_xor(const Exp& e, const detail::bitwise_xor&) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types"); Chris@16: typedef typename Exp::left_type left_type; Chris@16: typedef typename Exp::right_type right_type; Chris@16: do_bitwise_xor(e.left(), typename left_type::tag_type()); Chris@16: do_bitwise_xor(e.right(), typename right_type::tag_type()); Chris@16: } Chris@16: template Chris@16: void do_bitwise_xor(const Exp& e, const unknown&) Chris@16: { Chris@16: BOOST_STATIC_ASSERT_MSG(number_category::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types"); Chris@16: using default_ops::eval_bitwise_xor; Chris@16: self_type temp(e); Chris@16: eval_bitwise_xor(m_backend, temp.m_backend); Chris@16: } Chris@16: Chris@16: // Tests if the expression contains a reference to *this: Chris@16: template Chris@16: BOOST_MP_FORCEINLINE bool contains_self(const Exp& e)const BOOST_NOEXCEPT Chris@16: { Chris@16: return contains_self(e, typename Exp::arity()); Chris@16: } Chris@16: template Chris@16: BOOST_MP_FORCEINLINE bool contains_self(const Exp& e, mpl::int_<0> const&)const BOOST_NOEXCEPT Chris@16: { Chris@16: return is_realy_self(e.value()); Chris@16: } Chris@16: template Chris@16: BOOST_MP_FORCEINLINE bool contains_self(const Exp& e, mpl::int_<1> const&)const BOOST_NOEXCEPT Chris@16: { Chris@16: typedef typename Exp::left_type child_type; Chris@16: return contains_self(e.left(), typename child_type::arity()); Chris@16: } Chris@16: template Chris@16: BOOST_MP_FORCEINLINE bool contains_self(const Exp& e, mpl::int_<2> const&)const BOOST_NOEXCEPT Chris@16: { Chris@16: typedef typename Exp::left_type child0_type; Chris@16: typedef typename Exp::right_type child1_type; Chris@16: return contains_self(e.left(), typename child0_type::arity()) Chris@16: || contains_self(e.right(), typename child1_type::arity()); Chris@16: } Chris@16: template Chris@16: BOOST_MP_FORCEINLINE bool contains_self(const Exp& e, mpl::int_<3> const&)const BOOST_NOEXCEPT Chris@16: { Chris@16: typedef typename Exp::left_type child0_type; Chris@16: typedef typename Exp::middle_type child1_type; Chris@16: typedef typename Exp::right_type child2_type; Chris@16: return contains_self(e.left(), typename child0_type::arity()) Chris@16: || contains_self(e.middle(), typename child1_type::arity()) Chris@16: || contains_self(e.right(), typename child2_type::arity()); Chris@16: } Chris@16: Chris@16: // Test if the expression is a reference to *this: Chris@16: template Chris@16: BOOST_MP_FORCEINLINE BOOST_CONSTEXPR bool is_self(const Exp& e)const BOOST_NOEXCEPT Chris@16: { Chris@16: return is_self(e, typename Exp::arity()); Chris@16: } Chris@16: template Chris@16: BOOST_MP_FORCEINLINE BOOST_CONSTEXPR bool is_self(const Exp& e, mpl::int_<0> const&)const BOOST_NOEXCEPT Chris@16: { Chris@16: return is_realy_self(e.value()); Chris@16: } Chris@16: template Chris@16: BOOST_MP_FORCEINLINE BOOST_CONSTEXPR bool is_self(const Exp&, mpl::int_ const&)const BOOST_NOEXCEPT Chris@16: { Chris@16: return false; Chris@16: } Chris@16: Chris@16: template Chris@16: BOOST_MP_FORCEINLINE BOOST_CONSTEXPR bool is_realy_self(const Val&)const BOOST_NOEXCEPT{ return false; } Chris@16: BOOST_MP_FORCEINLINE BOOST_CONSTEXPR bool is_realy_self(const self_type& v)const BOOST_NOEXCEPT{ return &v == this; } Chris@16: Chris@16: static BOOST_MP_FORCEINLINE BOOST_CONSTEXPR const Backend& function_arg_value(const self_type& v) BOOST_NOEXCEPT { return v.backend(); } Chris@16: template Chris@16: static BOOST_MP_FORCEINLINE BOOST_CONSTEXPR const V& function_arg_value(const V& v) BOOST_NOEXCEPT { return v; } Chris@16: template Chris@16: static BOOST_MP_FORCEINLINE const A1& function_arg_value(const detail::expression& exp) BOOST_NOEXCEPT { return exp.value(); } Chris@16: template Chris@16: static BOOST_MP_FORCEINLINE BOOST_CONSTEXPR const Backend& function_arg_value(const detail::expression, A2, A3, A4>& exp) BOOST_NOEXCEPT { return exp.value().backend(); } Chris@16: Backend m_backend; Chris@16: Chris@16: public: Chris@16: // Chris@16: // These shouldn't really need to be public, or even member functions, but it makes implementing Chris@16: // the non-member operators way easier if they are: Chris@16: // Chris@16: static BOOST_MP_FORCEINLINE BOOST_CONSTEXPR const Backend& canonical_value(const self_type& v) BOOST_NOEXCEPT { return v.m_backend; } Chris@16: template Chris@16: static BOOST_MP_FORCEINLINE BOOST_CONSTEXPR const B2& canonical_value(const number& v) BOOST_NOEXCEPT { return v.backend(); } Chris@16: template Chris@16: static BOOST_MP_FORCEINLINE BOOST_CONSTEXPR typename boost::disable_if::type, V>, typename detail::canonical::type>::type Chris@16: canonical_value(const V& v) BOOST_NOEXCEPT { return static_cast::type>(v); } Chris@16: template Chris@16: static BOOST_MP_FORCEINLINE BOOST_CONSTEXPR typename boost::enable_if::type, V>, const V&>::type Chris@16: canonical_value(const V& v) BOOST_NOEXCEPT { return v; } Chris@16: static BOOST_MP_FORCEINLINE typename detail::canonical::type canonical_value(const std::string& v) BOOST_NOEXCEPT { return v.c_str(); } Chris@16: Chris@16: }; Chris@16: Chris@16: template Chris@16: inline std::ostream& operator << (std::ostream& os, const number& r) Chris@16: { Chris@16: std::streamsize d = os.precision(); Chris@16: std::string s = r.str(d, os.flags()); Chris@16: std::streamsize ss = os.width(); Chris@16: if(ss > static_cast(s.size())) Chris@16: { Chris@16: char fill = os.fill(); Chris@16: if((os.flags() & std::ios_base::left) == std::ios_base::left) Chris@16: s.append(static_cast(ss - s.size()), fill); Chris@16: else Chris@101: s.insert(static_cast(0), static_cast(ss - s.size()), fill); Chris@16: } Chris@16: return os << s; Chris@16: } Chris@16: Chris@16: namespace detail{ Chris@16: Chris@16: template Chris@16: inline std::ostream& operator << (std::ostream& os, const expression& r) Chris@16: { Chris@16: typedef typename expression::result_type value_type; Chris@16: value_type temp(r); Chris@16: return os << temp; Chris@16: } Chris@16: Chris@16: } // namespace detail Chris@16: Chris@16: template Chris@16: inline std::istream& operator >> (std::istream& is, number& r) Chris@16: { Chris@16: bool hex_format = (is.flags() & std::ios_base::hex) == std::ios_base::hex; Chris@16: bool oct_format = (is.flags() & std::ios_base::oct) == std::ios_base::oct; Chris@16: std::string s; Chris@16: is >> s; Chris@16: if(hex_format && (number_category::value == number_kind_integer) && ((s[0] != '0') || (s[1] != 'x'))) Chris@16: s.insert(s.find_first_not_of("+-"), "0x"); Chris@16: if(oct_format && (number_category::value == number_kind_integer) && (s[0] != '0')) Chris@16: s.insert(s.find_first_not_of("+-"), "0"); Chris@16: r.assign(s); Chris@16: return is; Chris@16: } Chris@16: Chris@16: template Chris@101: BOOST_MP_FORCEINLINE void swap(number& a, number& b) Chris@101: BOOST_NOEXCEPT_IF(noexcept(std::declval&>() = std::declval&>())) Chris@16: { Chris@16: a.swap(b); Chris@16: } Chris@16: Chris@16: } // namespace multiprecision Chris@16: Chris@16: template Chris@16: class rational; Chris@16: Chris@16: template Chris@16: inline std::istream& operator >> (std::istream& is, rational >& r) Chris@16: { Chris@16: std::string s1; Chris@16: multiprecision::number v1, v2; Chris@16: char c; Chris@16: bool have_hex = false; Chris@16: bool hex_format = (is.flags() & std::ios_base::hex) == std::ios_base::hex; Chris@16: bool oct_format = (is.flags() & std::ios_base::oct) == std::ios_base::oct; Chris@16: Chris@16: while((EOF != (c = static_cast(is.peek()))) && (c == 'x' || c == 'X' || c == '-' || c == '+' || (c >= '0' && c <= '9') || (have_hex && (c >= 'a' && c <= 'f')) || (have_hex && (c >= 'A' && c <= 'F')))) Chris@16: { Chris@16: if(c == 'x' || c == 'X') Chris@16: have_hex = true; Chris@16: s1.append(1, c); Chris@16: is.get(); Chris@16: } Chris@16: if(hex_format && ((s1[0] != '0') || (s1[1] != 'x'))) Chris@101: s1.insert(static_cast(0), "0x"); Chris@16: if(oct_format && (s1[0] != '0')) Chris@101: s1.insert(static_cast(0), "0"); Chris@16: v1.assign(s1); Chris@16: s1.erase(); Chris@16: if(c == '/') Chris@16: { Chris@16: is.get(); Chris@16: while((EOF != (c = static_cast(is.peek()))) && (c == 'x' || c == 'X' || c == '-' || c == '+' || (c >= '0' && c <= '9') || (have_hex && (c >= 'a' && c <= 'f')) || (have_hex && (c >= 'A' && c <= 'F')))) Chris@16: { Chris@16: if(c == 'x' || c == 'X') Chris@16: have_hex = true; Chris@16: s1.append(1, c); Chris@16: is.get(); Chris@16: } Chris@16: if(hex_format && ((s1[0] != '0') || (s1[1] != 'x'))) Chris@101: s1.insert(static_cast(0), "0x"); Chris@16: if(oct_format && (s1[0] != '0')) Chris@101: s1.insert(static_cast(0), "0"); Chris@16: v2.assign(s1); Chris@16: } Chris@16: else Chris@16: v2 = 1; Chris@16: r.assign(v1, v2); Chris@16: return is; Chris@16: } Chris@16: Chris@16: template Chris@16: typename boost::enable_if, bool>::type operator == (const rational >& a, const Arithmetic& b) Chris@16: { Chris@16: return a == multiprecision::number(b); Chris@16: } Chris@16: Chris@16: template Chris@16: typename boost::enable_if, bool>::type operator == (const Arithmetic& b, const rational >& a) Chris@16: { Chris@16: return a == multiprecision::number(b); Chris@16: } Chris@16: Chris@16: template Chris@16: typename boost::enable_if, bool>::type operator != (const rational >& a, const Arithmetic& b) Chris@16: { Chris@16: return a != multiprecision::number(b); Chris@16: } Chris@16: Chris@16: template Chris@16: typename boost::enable_if, bool>::type operator != (const Arithmetic& b, const rational >& a) Chris@16: { Chris@16: return a != multiprecision::number(b); Chris@16: } Chris@16: Chris@16: template Chris@16: inline multiprecision::number numerator(const rational >& a) Chris@16: { Chris@16: return a.numerator(); Chris@16: } Chris@16: Chris@16: template Chris@16: inline multiprecision::number denominator(const rational >& a) Chris@16: { Chris@16: return a.denominator(); Chris@16: } Chris@16: Chris@101: namespace multiprecision Chris@101: { Chris@101: Chris@101: template Chris@101: struct component_type > Chris@101: { Chris@101: typedef I type; Chris@101: }; Chris@101: Chris@101: } Chris@101: Chris@16: #ifdef BOOST_MSVC Chris@16: #pragma warning(pop) Chris@16: #endif Chris@16: Chris@16: } // namespaces Chris@16: Chris@16: #include Chris@16: Chris@16: #endif