/////////////////////////////////////////////////////////////// // Copyright 2012 John Maddock. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt #ifndef BOOST_MATH_LOGGED_ADAPTER_HPP #define BOOST_MATH_LOGGED_ADAPTER_HPP #include #include namespace boost { namespace multiprecision { template inline void log_postfix_event(const Backend&, const char* /*event_description*/) { } template inline void log_postfix_event(const Backend&, const T&, const char* /*event_description*/) { } template inline void log_prefix_event(const Backend&, const char* /*event_description*/) { } template inline void log_prefix_event(const Backend&, const T&, const char* /*event_description*/) { } template inline void log_prefix_event(const Backend&, const T&, const U&, const char* /*event_description*/) { } template inline void log_prefix_event(const Backend&, const T&, const U&, const V&, const char* /*event_description*/) { } namespace backends { template struct logged_adaptor { using signed_types = typename Backend::signed_types ; using unsigned_types = typename Backend::unsigned_types; using float_types = typename Backend::float_types ; using exponent_type = typename extract_exponent_type::value>::type; private: Backend m_value; public: logged_adaptor() { log_postfix_event(m_value, "Default construct"); } logged_adaptor(const logged_adaptor& o) { log_prefix_event(m_value, o.value(), "Copy construct"); m_value = o.m_value; log_postfix_event(m_value, "Copy construct"); } // rvalue copy logged_adaptor(logged_adaptor&& o) { log_prefix_event(m_value, o.value(), "Move construct"); m_value = static_cast(o.m_value); log_postfix_event(m_value, "Move construct"); } logged_adaptor& operator=(logged_adaptor&& o) { log_prefix_event(m_value, o.value(), "Move Assignment"); m_value = static_cast(o.m_value); log_postfix_event(m_value, "Move construct"); return *this; } logged_adaptor& operator=(const logged_adaptor& o) { log_prefix_event(m_value, o.value(), "Assignment"); m_value = o.m_value; log_postfix_event(m_value, "Copy construct"); return *this; } template logged_adaptor(const T& i, const typename std::enable_if::value>::type* = 0) : m_value(i) { log_postfix_event(m_value, "construct from arithmetic type"); } template logged_adaptor(const logged_adaptor& i, const typename std::enable_if::value>::type* = 0) : m_value(i.value()) { log_postfix_event(m_value, "construct from arithmetic type"); } template typename std::enable_if::value || std::is_convertible::value, logged_adaptor&>::type operator=(const T& i) { log_prefix_event(m_value, i, "Assignment from arithmetic type"); m_value = i; log_postfix_event(m_value, "Assignment from arithmetic type"); return *this; } logged_adaptor& operator=(const char* s) { log_prefix_event(m_value, s, "Assignment from string type"); m_value = s; log_postfix_event(m_value, "Assignment from string type"); return *this; } void swap(logged_adaptor& o) { log_prefix_event(m_value, o.value(), "swap"); std::swap(m_value, o.value()); log_postfix_event(m_value, "swap"); } std::string str(std::streamsize digits, std::ios_base::fmtflags f) const { log_prefix_event(m_value, "Conversion to string"); std::string s = m_value.str(digits, f); log_postfix_event(m_value, s, "Conversion to string"); return s; } void negate() { log_prefix_event(m_value, "negate"); m_value.negate(); log_postfix_event(m_value, "negate"); } int compare(const logged_adaptor& o) const { log_prefix_event(m_value, o.value(), "compare"); int r = m_value.compare(o.value()); log_postfix_event(m_value, r, "compare"); return r; } template int compare(const T& i) const { log_prefix_event(m_value, i, "compare"); int r = m_value.compare(i); log_postfix_event(m_value, r, "compare"); return r; } Backend& value() { return m_value; } const Backend& value() const { return m_value; } template void serialize(Archive& ar, const unsigned int /*version*/) { log_prefix_event(m_value, "serialize"); ar& boost::make_nvp("value", m_value); log_postfix_event(m_value, "serialize"); } static unsigned default_precision() noexcept { return Backend::default_precision(); } static void default_precision(unsigned v) noexcept { Backend::default_precision(v); } unsigned precision() const noexcept { return value().precision(); } void precision(unsigned digits10) noexcept { value().precision(digits10); } }; template inline const T& unwrap_logged_type(const T& a) { return a; } template inline const Backend& unwrap_logged_type(const logged_adaptor& a) { return a.value(); } #define NON_MEMBER_OP1(name, str) \ template \ inline void BOOST_JOIN(eval_, name)(logged_adaptor & result) \ { \ using default_ops::BOOST_JOIN(eval_, name); \ log_prefix_event(result.value(), str); \ BOOST_JOIN(eval_, name) \ (result.value()); \ log_postfix_event(result.value(), str); \ } #define NON_MEMBER_OP2(name, str) \ template \ inline void BOOST_JOIN(eval_, name)(logged_adaptor & result, const T& a) \ { \ using default_ops::BOOST_JOIN(eval_, name); \ log_prefix_event(result.value(), unwrap_logged_type(a), str); \ BOOST_JOIN(eval_, name) \ (result.value(), unwrap_logged_type(a)); \ log_postfix_event(result.value(), str); \ } \ template \ inline void BOOST_JOIN(eval_, name)(logged_adaptor & result, const logged_adaptor& a) \ { \ using default_ops::BOOST_JOIN(eval_, name); \ log_prefix_event(result.value(), unwrap_logged_type(a), str); \ BOOST_JOIN(eval_, name) \ (result.value(), unwrap_logged_type(a)); \ log_postfix_event(result.value(), str); \ } #define NON_MEMBER_OP3(name, str) \ template \ inline void BOOST_JOIN(eval_, name)(logged_adaptor & result, const T& a, const U& b) \ { \ using default_ops::BOOST_JOIN(eval_, name); \ log_prefix_event(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), str); \ BOOST_JOIN(eval_, name) \ (result.value(), unwrap_logged_type(a), unwrap_logged_type(b)); \ log_postfix_event(result.value(), str); \ } \ template \ inline void BOOST_JOIN(eval_, name)(logged_adaptor & result, const logged_adaptor& a, const T& b) \ { \ using default_ops::BOOST_JOIN(eval_, name); \ log_prefix_event(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), str); \ BOOST_JOIN(eval_, name) \ (result.value(), unwrap_logged_type(a), unwrap_logged_type(b)); \ log_postfix_event(result.value(), str); \ } \ template \ inline void BOOST_JOIN(eval_, name)(logged_adaptor & result, const T& a, const logged_adaptor& b) \ { \ using default_ops::BOOST_JOIN(eval_, name); \ log_prefix_event(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), str); \ BOOST_JOIN(eval_, name) \ (result.value(), unwrap_logged_type(a), unwrap_logged_type(b)); \ log_postfix_event(result.value(), str); \ } \ template \ inline void BOOST_JOIN(eval_, name)(logged_adaptor & result, const logged_adaptor& a, const logged_adaptor& b) \ { \ using default_ops::BOOST_JOIN(eval_, name); \ log_prefix_event(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), str); \ BOOST_JOIN(eval_, name) \ (result.value(), unwrap_logged_type(a), unwrap_logged_type(b)); \ log_postfix_event(result.value(), str); \ } #define NON_MEMBER_OP4(name, str) \ template \ inline void BOOST_JOIN(eval_, name)(logged_adaptor & result, const T& a, const U& b, const V& c) \ { \ using default_ops::BOOST_JOIN(eval_, name); \ log_prefix_event(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c), str); \ BOOST_JOIN(eval_, name) \ (result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c)); \ log_postfix_event(result.value(), str); \ } \ template \ inline void BOOST_JOIN(eval_, name)(logged_adaptor & result, const logged_adaptor& a, const logged_adaptor& b, const T& c) \ { \ using default_ops::BOOST_JOIN(eval_, name); \ log_prefix_event(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c), str); \ BOOST_JOIN(eval_, name) \ (result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c)); \ log_postfix_event(result.value(), str); \ } \ template \ inline void BOOST_JOIN(eval_, name)(logged_adaptor & result, const logged_adaptor& a, const T& b, const logged_adaptor& c) \ { \ using default_ops::BOOST_JOIN(eval_, name); \ log_prefix_event(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c), str); \ BOOST_JOIN(eval_, name) \ (result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c)); \ log_postfix_event(result.value(), str); \ } \ template \ inline void BOOST_JOIN(eval_, name)(logged_adaptor & result, const T& a, const logged_adaptor& b, const logged_adaptor& c) \ { \ using default_ops::BOOST_JOIN(eval_, name); \ log_prefix_event(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c), str); \ BOOST_JOIN(eval_, name) \ (result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c)); \ log_postfix_event(result.value(), str); \ } \ template \ inline void BOOST_JOIN(eval_, name)(logged_adaptor & result, const logged_adaptor& a, const logged_adaptor& b, const logged_adaptor& c) \ { \ using default_ops::BOOST_JOIN(eval_, name); \ log_prefix_event(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c), str); \ BOOST_JOIN(eval_, name) \ (result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c)); \ log_postfix_event(result.value(), str); \ } \ template \ inline void BOOST_JOIN(eval_, name)(logged_adaptor & result, const logged_adaptor& a, const T& b, const U& c) \ { \ using default_ops::BOOST_JOIN(eval_, name); \ log_prefix_event(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c), str); \ BOOST_JOIN(eval_, name) \ (result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c)); \ log_postfix_event(result.value(), str); \ } NON_MEMBER_OP2(add, "+=") NON_MEMBER_OP2(subtract, "-=") NON_MEMBER_OP2(multiply, "*=") NON_MEMBER_OP2(divide, "/=") template inline void eval_convert_to(R* result, const logged_adaptor& val) { using default_ops::eval_convert_to; log_prefix_event(val.value(), "convert_to"); eval_convert_to(result, val.value()); log_postfix_event(val.value(), *result, "convert_to"); } template inline void eval_frexp(logged_adaptor& result, const logged_adaptor& arg, Exp* exp) { log_prefix_event(arg.value(), "frexp"); eval_frexp(result.value(), arg.value(), exp); log_postfix_event(result.value(), *exp, "frexp"); } template inline void eval_ldexp(logged_adaptor& result, const logged_adaptor& arg, Exp exp) { log_prefix_event(arg.value(), "ldexp"); eval_ldexp(result.value(), arg.value(), exp); log_postfix_event(result.value(), exp, "ldexp"); } template inline void eval_scalbn(logged_adaptor& result, const logged_adaptor& arg, Exp exp) { log_prefix_event(arg.value(), "scalbn"); eval_scalbn(result.value(), arg.value(), exp); log_postfix_event(result.value(), exp, "scalbn"); } template inline typename Backend::exponent_type eval_ilogb(const logged_adaptor& arg) { log_prefix_event(arg.value(), "ilogb"); typename Backend::exponent_type r = eval_ilogb(arg.value()); log_postfix_event(arg.value(), "ilogb"); return r; } NON_MEMBER_OP2(floor, "floor") NON_MEMBER_OP2(ceil, "ceil") NON_MEMBER_OP2(sqrt, "sqrt") template inline int eval_fpclassify(const logged_adaptor& arg) { using default_ops::eval_fpclassify; log_prefix_event(arg.value(), "fpclassify"); int r = eval_fpclassify(arg.value()); log_postfix_event(arg.value(), r, "fpclassify"); return r; } /********************************************************************* * * Optional arithmetic operations come next: * *********************************************************************/ NON_MEMBER_OP3(add, "+") NON_MEMBER_OP3(subtract, "-") NON_MEMBER_OP3(multiply, "*") NON_MEMBER_OP3(divide, "/") NON_MEMBER_OP3(multiply_add, "fused-multiply-add") NON_MEMBER_OP3(multiply_subtract, "fused-multiply-subtract") NON_MEMBER_OP4(multiply_add, "fused-multiply-add") NON_MEMBER_OP4(multiply_subtract, "fused-multiply-subtract") NON_MEMBER_OP1(increment, "increment") NON_MEMBER_OP1(decrement, "decrement") /********************************************************************* * * Optional integer operations come next: * *********************************************************************/ NON_MEMBER_OP2(modulus, "%=") NON_MEMBER_OP3(modulus, "%") NON_MEMBER_OP2(bitwise_or, "|=") NON_MEMBER_OP3(bitwise_or, "|") NON_MEMBER_OP2(bitwise_and, "&=") NON_MEMBER_OP3(bitwise_and, "&") NON_MEMBER_OP2(bitwise_xor, "^=") NON_MEMBER_OP3(bitwise_xor, "^") NON_MEMBER_OP4(qr, "quotient-and-remainder") NON_MEMBER_OP2(complement, "~") template inline void eval_left_shift(logged_adaptor& arg, std::size_t a) { using default_ops::eval_left_shift; log_prefix_event(arg.value(), a, "<<="); eval_left_shift(arg.value(), a); log_postfix_event(arg.value(), "<<="); } template inline void eval_left_shift(logged_adaptor& arg, const logged_adaptor& a, std::size_t b) { using default_ops::eval_left_shift; log_prefix_event(arg.value(), a, b, "<<"); eval_left_shift(arg.value(), a.value(), b); log_postfix_event(arg.value(), "<<"); } template inline void eval_right_shift(logged_adaptor& arg, std::size_t a) { using default_ops::eval_right_shift; log_prefix_event(arg.value(), a, ">>="); eval_right_shift(arg.value(), a); log_postfix_event(arg.value(), ">>="); } template inline void eval_right_shift(logged_adaptor& arg, const logged_adaptor& a, std::size_t b) { using default_ops::eval_right_shift; log_prefix_event(arg.value(), a, b, ">>"); eval_right_shift(arg.value(), a.value(), b); log_postfix_event(arg.value(), ">>"); } template inline unsigned eval_integer_modulus(const logged_adaptor& arg, const T& a) { using default_ops::eval_integer_modulus; log_prefix_event(arg.value(), a, "integer-modulus"); unsigned r = eval_integer_modulus(arg.value(), a); log_postfix_event(arg.value(), r, "integer-modulus"); return r; } template inline unsigned eval_lsb(const logged_adaptor& arg) { using default_ops::eval_lsb; log_prefix_event(arg.value(), "least-significant-bit"); unsigned r = eval_lsb(arg.value()); log_postfix_event(arg.value(), r, "least-significant-bit"); return r; } template inline unsigned eval_msb(const logged_adaptor& arg) { using default_ops::eval_msb; log_prefix_event(arg.value(), "most-significant-bit"); unsigned r = eval_msb(arg.value()); log_postfix_event(arg.value(), r, "most-significant-bit"); return r; } template inline bool eval_bit_test(const logged_adaptor& arg, unsigned a) { using default_ops::eval_bit_test; log_prefix_event(arg.value(), a, "bit-test"); bool r = eval_bit_test(arg.value(), a); log_postfix_event(arg.value(), r, "bit-test"); return r; } template inline void eval_bit_set(const logged_adaptor& arg, unsigned a) { using default_ops::eval_bit_set; log_prefix_event(arg.value(), a, "bit-set"); eval_bit_set(arg.value(), a); log_postfix_event(arg.value(), arg, "bit-set"); } template inline void eval_bit_unset(const logged_adaptor& arg, unsigned a) { using default_ops::eval_bit_unset; log_prefix_event(arg.value(), a, "bit-unset"); eval_bit_unset(arg.value(), a); log_postfix_event(arg.value(), arg, "bit-unset"); } template inline void eval_bit_flip(const logged_adaptor& arg, unsigned a) { using default_ops::eval_bit_flip; log_prefix_event(arg.value(), a, "bit-flip"); eval_bit_flip(arg.value(), a); log_postfix_event(arg.value(), arg, "bit-flip"); } NON_MEMBER_OP3(gcd, "gcd") NON_MEMBER_OP3(lcm, "lcm") NON_MEMBER_OP4(powm, "powm") /********************************************************************* * * abs/fabs: * *********************************************************************/ NON_MEMBER_OP2(abs, "abs") NON_MEMBER_OP2(fabs, "fabs") /********************************************************************* * * Floating point functions: * *********************************************************************/ NON_MEMBER_OP2(trunc, "trunc") NON_MEMBER_OP2(round, "round") NON_MEMBER_OP2(exp, "exp") NON_MEMBER_OP2(log, "log") NON_MEMBER_OP2(log10, "log10") NON_MEMBER_OP2(sin, "sin") NON_MEMBER_OP2(cos, "cos") NON_MEMBER_OP2(tan, "tan") NON_MEMBER_OP2(asin, "asin") NON_MEMBER_OP2(acos, "acos") NON_MEMBER_OP2(atan, "atan") NON_MEMBER_OP2(sinh, "sinh") NON_MEMBER_OP2(cosh, "cosh") NON_MEMBER_OP2(tanh, "tanh") NON_MEMBER_OP2(logb, "logb") NON_MEMBER_OP3(fmod, "fmod") NON_MEMBER_OP3(pow, "pow") NON_MEMBER_OP3(atan2, "atan2") template int eval_signbit(const logged_adaptor& val) { using default_ops::eval_signbit; return eval_signbit(val.value()); } template std::size_t hash_value(const logged_adaptor& val) { return hash_value(val.value()); } #define NON_MEMBER_COMPLEX_TO_REAL(name, str) \ template \ inline void BOOST_JOIN(eval_, name)(logged_adaptor & result, const logged_adaptor& a) \ { \ using default_ops::BOOST_JOIN(eval_, name); \ log_prefix_event(a.value(), a.value(), str); \ BOOST_JOIN(eval_, name) \ (result.value(), a.value()); \ log_postfix_event(result.value(), str); \ } \ template \ inline void BOOST_JOIN(eval_, name)(B1 & result, const logged_adaptor& a) \ { \ using default_ops::BOOST_JOIN(eval_, name); \ log_prefix_event(a.value(), a.value(), str); \ BOOST_JOIN(eval_, name) \ (result, a.value()); \ log_postfix_event(result, str); \ } NON_MEMBER_COMPLEX_TO_REAL(real, "real") NON_MEMBER_COMPLEX_TO_REAL(imag, "imag") template inline void assign_components(logged_adaptor& result, const V& v1, const U& v2) { assign_components(result.value(), v1, v2); } } // namespace backends using backends::logged_adaptor; template struct number_category > : public number_category {}; }} // namespace boost::multiprecision namespace std { template class numeric_limits, ExpressionTemplates> > : public std::numeric_limits > { using base_type = std::numeric_limits > ; using number_type = boost::multiprecision::number, ExpressionTemplates>; public: static number_type(min)() noexcept { return (base_type::min)(); } static number_type(max)() noexcept { return (base_type::max)(); } static number_type lowest() noexcept { return -(max)(); } static number_type epsilon() noexcept { return base_type::epsilon(); } static number_type round_error() noexcept { return epsilon() / 2; } static number_type infinity() noexcept { return base_type::infinity(); } static number_type quiet_NaN() noexcept { return base_type::quiet_NaN(); } static number_type signaling_NaN() noexcept { return base_type::signaling_NaN(); } static number_type denorm_min() noexcept { return base_type::denorm_min(); } }; } // namespace std namespace boost { namespace math { namespace policies { template struct precision, ExpressionTemplates>, Policy> : public precision, Policy> {}; } }} // namespace boost::math::policies #undef NON_MEMBER_OP1 #undef NON_MEMBER_OP2 #undef NON_MEMBER_OP3 #undef NON_MEMBER_OP4 #endif