Imported Upstream version 1.64.0
[platform/upstream/boost.git] / boost / multiprecision / debug_adaptor.hpp
1 ///////////////////////////////////////////////////////////////
2 //  Copyright 2012 John Maddock. Distributed under the Boost
3 //  Software License, Version 1.0. (See accompanying file
4 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
5
6 #ifndef BOOST_MATH_DEBUG_ADAPTER_HPP
7 #define BOOST_MATH_DEBUG_ADAPTER_HPP
8
9 #include <boost/multiprecision/traits/extract_exponent_type.hpp>
10 #include <boost/multiprecision/detail/integer_ops.hpp>
11
12 namespace boost{
13 namespace multiprecision{
14 namespace backends{
15
16 #ifdef BOOST_MSVC
17 #pragma warning(push)
18 #pragma warning(disable:4127) // conditional expression is constant
19 #endif
20    
21    template <class Backend>
22 struct debug_adaptor
23 {
24    typedef typename Backend::signed_types              signed_types;
25    typedef typename Backend::unsigned_types            unsigned_types;
26    typedef typename Backend::float_types               float_types;
27    typedef typename extract_exponent_type<
28       Backend, number_category<Backend>::value>::type  exponent_type;
29
30 private:
31    std::string debug_value;
32    Backend m_value;
33 public:
34    void update_view()
35    {
36 #ifndef BOOST_NO_EXCEPTIONS
37       try
38       {
39 #endif
40          debug_value = m_value.str(0, static_cast<std::ios_base::fmtflags>(0));
41 #ifndef BOOST_NO_EXCEPTIONS
42       }
43       catch(const std::exception& e)
44       {
45          debug_value = "String conversion failed with message: \"";
46          debug_value += e.what();
47          debug_value += "\"";
48       }
49 #endif
50    }
51    debug_adaptor()
52    {
53       update_view();
54    }
55    debug_adaptor(const debug_adaptor& o) : debug_value(o.debug_value), m_value(o.m_value)
56    {
57    }
58    debug_adaptor& operator = (const debug_adaptor& o)
59    {
60       debug_value = o.debug_value;
61       m_value = o.m_value;
62       return *this;
63    }
64    template <class T>
65    debug_adaptor(const T& i, const typename enable_if_c<is_convertible<T, Backend>::value>::type* = 0)
66       : m_value(i)
67    {
68       update_view();
69    }
70    template <class T>
71    debug_adaptor(const T& i, const T& j)
72       : m_value(i, j)
73    {
74       update_view();
75    }
76    template <class T>
77    typename enable_if_c<is_arithmetic<T>::value || is_convertible<T, Backend>::value, debug_adaptor&>::type operator = (const T& i)
78    {
79       m_value = i;
80       update_view();
81       return *this;
82    }
83    debug_adaptor& operator = (const char* s)
84    {
85       m_value = s;
86       update_view();
87       return *this;
88    }
89    void swap(debug_adaptor& o)
90    {
91       std::swap(m_value, o.value());
92       std::swap(debug_value, o.debug_value);
93    }
94    std::string str(std::streamsize digits, std::ios_base::fmtflags f)const
95    {
96       return m_value.str(digits, f);
97    }
98    void negate()
99    {
100       m_value.negate();
101       update_view();
102    }
103    int compare(const debug_adaptor& o)const
104    {
105       return m_value.compare(o.value());
106    }
107    template <class T>
108    int compare(const T& i)const
109    {
110       return m_value.compare(i);
111    }
112    Backend& value()
113    {
114       return m_value;
115    }
116    const Backend& value()const
117    {
118       return m_value;
119    }
120    template <class Archive>
121    void serialize(Archive& ar, const unsigned int /*version*/)
122    {
123       ar & m_value;
124       typedef typename Archive::is_loading tag;
125       if(tag::value)
126          update_view();
127    }
128    static unsigned default_precision() BOOST_NOEXCEPT
129    {
130       return Backend::default_precision();
131    }
132    static void default_precision(unsigned v) BOOST_NOEXCEPT
133    {
134       Backend::default_precision(v);
135    }
136    unsigned precision()const BOOST_NOEXCEPT
137    {
138       return value().precision();
139    }
140    void precision(unsigned digits10) BOOST_NOEXCEPT
141    {
142       value().precision(digits10);
143    }
144 };
145
146 template <class Backend>
147 inline Backend const& unwrap_debug_type(debug_adaptor<Backend> const& val)
148 {
149    return val.value();
150 }
151 template <class T>
152 inline const T& unwrap_debug_type(const T& val)
153 {
154    return val;
155 }
156
157 #define NON_MEMBER_OP1(name, str) \
158    template <class Backend>\
159    inline void BOOST_JOIN(eval_, name)(debug_adaptor<Backend>& result)\
160    {\
161       using default_ops::BOOST_JOIN(eval_, name);\
162       BOOST_JOIN(eval_, name)(result.value());\
163       result.update_view();\
164    }
165
166 #define NON_MEMBER_OP2(name, str) \
167    template <class Backend, class T>\
168    inline void BOOST_JOIN(eval_, name)(debug_adaptor<Backend>& result, const T& a)\
169    {\
170       using default_ops::BOOST_JOIN(eval_, name);\
171       BOOST_JOIN(eval_, name)(result.value(), unwrap_debug_type(a));\
172       result.update_view();\
173    }\
174    template <class Backend>\
175    inline void BOOST_JOIN(eval_, name)(debug_adaptor<Backend>& result, const debug_adaptor<Backend>& a)\
176    {\
177       using default_ops::BOOST_JOIN(eval_, name);\
178       BOOST_JOIN(eval_, name)(result.value(), unwrap_debug_type(a));\
179       result.update_view();\
180    }
181
182 #define NON_MEMBER_OP3(name, str) \
183    template <class Backend, class T, class U>\
184    inline void BOOST_JOIN(eval_, name)(debug_adaptor<Backend>& result, const T& a, const U& b)\
185    {\
186       using default_ops::BOOST_JOIN(eval_, name);\
187       BOOST_JOIN(eval_, name)(result.value(), unwrap_debug_type(a), unwrap_debug_type(b));\
188       result.update_view();\
189    }\
190    template <class Backend, class T>\
191    inline void BOOST_JOIN(eval_, name)(debug_adaptor<Backend>& result, const debug_adaptor<Backend>& a, const T& b)\
192    {\
193       using default_ops::BOOST_JOIN(eval_, name);\
194       BOOST_JOIN(eval_, name)(result.value(), unwrap_debug_type(a), unwrap_debug_type(b));\
195       result.update_view();\
196    }\
197    template <class Backend, class T>\
198    inline void BOOST_JOIN(eval_, name)(debug_adaptor<Backend>& result, const T& a, const debug_adaptor<Backend>& b)\
199    {\
200       using default_ops::BOOST_JOIN(eval_, name);\
201       BOOST_JOIN(eval_, name)(result.value(), unwrap_debug_type(a), unwrap_debug_type(b));\
202       result.update_view();\
203    }\
204    template <class Backend>\
205    inline void BOOST_JOIN(eval_, name)(debug_adaptor<Backend>& result, const debug_adaptor<Backend>& a, const debug_adaptor<Backend>& b)\
206    {\
207       using default_ops::BOOST_JOIN(eval_, name);\
208       BOOST_JOIN(eval_, name)(result.value(), unwrap_debug_type(a), unwrap_debug_type(b));\
209       result.update_view();\
210    }
211
212 #define NON_MEMBER_OP4(name, str) \
213    template <class Backend, class T, class U, class V>\
214    inline void BOOST_JOIN(eval_, name)(debug_adaptor<Backend>& result, const T& a, const U& b, const V& c)\
215    {\
216       using default_ops::BOOST_JOIN(eval_, name);\
217       BOOST_JOIN(eval_, name)(result.value(), unwrap_debug_type(a), unwrap_debug_type(b), unwrap_debug_type(c));\
218       result.update_view();\
219    }\
220    template <class Backend, class T>\
221    inline void BOOST_JOIN(eval_, name)(debug_adaptor<Backend>& result, const debug_adaptor<Backend>& a, const debug_adaptor<Backend>& b, const T& c)\
222    {\
223       using default_ops::BOOST_JOIN(eval_, name);\
224       BOOST_JOIN(eval_, name)(result.value(), unwrap_debug_type(a), unwrap_debug_type(b), unwrap_debug_type(c));\
225       result.update_view();\
226    }\
227    template <class Backend, class T>\
228    inline void BOOST_JOIN(eval_, name)(debug_adaptor<Backend>& result, const debug_adaptor<Backend>& a, const T& b, const debug_adaptor<Backend>& c)\
229    {\
230       using default_ops::BOOST_JOIN(eval_, name);\
231       BOOST_JOIN(eval_, name)(result.value(), unwrap_debug_type(a), unwrap_debug_type(b), unwrap_debug_type(c));\
232       result.update_view();\
233    }\
234    template <class Backend, class T>\
235    inline void BOOST_JOIN(eval_, name)(debug_adaptor<Backend>& result, const T& a, const debug_adaptor<Backend>& b, const debug_adaptor<Backend>& c)\
236    {\
237       using default_ops::BOOST_JOIN(eval_, name);\
238       BOOST_JOIN(eval_, name)(result.value(), unwrap_debug_type(a), unwrap_debug_type(b), unwrap_debug_type(c));\
239       result.update_view();\
240    }\
241    template <class Backend>\
242    inline void BOOST_JOIN(eval_, name)(debug_adaptor<Backend>& result, const debug_adaptor<Backend>& a, const debug_adaptor<Backend>& b, const debug_adaptor<Backend>& c)\
243    {\
244       using default_ops::BOOST_JOIN(eval_, name);\
245       BOOST_JOIN(eval_, name)(result.value(), unwrap_debug_type(a), unwrap_debug_type(b), unwrap_debug_type(c));\
246       result.update_view();\
247    }\
248    template <class Backend, class T, class U>\
249    inline void BOOST_JOIN(eval_, name)(debug_adaptor<Backend>& result, const debug_adaptor<Backend>& a, const T& b, const U& c)\
250    {\
251       using default_ops::BOOST_JOIN(eval_, name);\
252       BOOST_JOIN(eval_, name)(result.value(), unwrap_debug_type(a), unwrap_debug_type(b), unwrap_debug_type(c));\
253       result.update_view();\
254    }\
255
256 NON_MEMBER_OP2(add, "+=");
257 NON_MEMBER_OP2(subtract, "-=");
258 NON_MEMBER_OP2(multiply, "*=");
259 NON_MEMBER_OP2(divide, "/=");
260
261 template <class Backend, class R>
262 inline void eval_convert_to(R* result, const debug_adaptor<Backend>& val)
263 {
264    using default_ops::eval_convert_to;
265    eval_convert_to(result, val.value());
266 }
267
268 template <class Backend, class Exp>
269 inline void eval_frexp(debug_adaptor<Backend>& result, const debug_adaptor<Backend>& arg, Exp* exp)
270 {
271    eval_frexp(result.value(), arg.value(), exp);
272    result.update_view();
273 }
274
275 template <class Backend, class Exp>
276 inline void eval_ldexp(debug_adaptor<Backend>& result, const debug_adaptor<Backend>& arg, Exp exp)
277 {
278    eval_ldexp(result.value(), arg.value(), exp);
279    result.update_view();
280 }
281
282 template <class Backend, class Exp>
283 inline void eval_scalbn(debug_adaptor<Backend>& result, const debug_adaptor<Backend>& arg, Exp exp)
284 {
285    using default_ops::eval_scalbn;
286    eval_scalbn(result.value(), arg.value(), exp);
287    result.update_view();
288 }
289
290 template <class Backend>
291 inline typename Backend::exponent_type eval_ilogb(const debug_adaptor<Backend>& arg)
292 {
293    using default_ops::eval_ilogb;
294    return eval_ilogb(arg.value());
295 }
296
297 NON_MEMBER_OP2(floor, "floor");
298 NON_MEMBER_OP2(ceil, "ceil");
299 NON_MEMBER_OP2(sqrt, "sqrt");
300 NON_MEMBER_OP2(logb, "logb");
301
302 template <class Backend>
303 inline int eval_fpclassify(const debug_adaptor<Backend>& arg)
304 {
305    using default_ops::eval_fpclassify;
306    return eval_fpclassify(arg.value());
307 }
308
309 /*********************************************************************
310 *
311 * Optional arithmetic operations come next:
312 *
313 *********************************************************************/
314
315 NON_MEMBER_OP3(add, "+");
316 NON_MEMBER_OP3(subtract, "-");
317 NON_MEMBER_OP3(multiply, "*");
318 NON_MEMBER_OP3(divide, "/");
319 NON_MEMBER_OP3(multiply_add, "fused-multiply-add");
320 NON_MEMBER_OP3(multiply_subtract, "fused-multiply-subtract");
321 NON_MEMBER_OP4(multiply_add, "fused-multiply-add");
322 NON_MEMBER_OP4(multiply_subtract, "fused-multiply-subtract");
323
324 NON_MEMBER_OP1(increment, "increment");
325 NON_MEMBER_OP1(decrement, "decrement");
326
327 /*********************************************************************
328 *
329 * Optional integer operations come next:
330 *
331 *********************************************************************/
332
333 NON_MEMBER_OP2(modulus, "%=");
334 NON_MEMBER_OP3(modulus, "%");
335 NON_MEMBER_OP2(bitwise_or, "|=");
336 NON_MEMBER_OP3(bitwise_or, "|");
337 NON_MEMBER_OP2(bitwise_and, "&=");
338 NON_MEMBER_OP3(bitwise_and, "&");
339 NON_MEMBER_OP2(bitwise_xor, "^=");
340 NON_MEMBER_OP3(bitwise_xor, "^");
341 NON_MEMBER_OP4(qr, "quotient-and-remainder");
342 NON_MEMBER_OP2(complement, "~");
343
344 template <class Backend>
345 inline void eval_left_shift(debug_adaptor<Backend>& arg, unsigned a)
346 {
347    using default_ops::eval_left_shift;
348    eval_left_shift(arg.value(), a);
349    arg.update_view();\
350 }
351 template <class Backend>
352 inline void eval_left_shift(debug_adaptor<Backend>& arg, const debug_adaptor<Backend>& a, unsigned b)
353 {
354    using default_ops::eval_left_shift;
355    eval_left_shift(arg.value(), a.value(), b);
356    arg.update_view();\
357 }
358 template <class Backend>
359 inline void eval_right_shift(debug_adaptor<Backend>& arg, unsigned a)
360 {
361    using default_ops::eval_right_shift;
362    eval_right_shift(arg.value(), a);
363    arg.update_view();\
364 }
365 template <class Backend>
366 inline void eval_right_shift(debug_adaptor<Backend>& arg, const debug_adaptor<Backend>& a, unsigned b)
367 {
368    using default_ops::eval_right_shift;
369    eval_right_shift(arg.value(), a.value(), b);
370    arg.update_view();\
371 }
372
373 template <class Backend, class T>
374 inline unsigned eval_integer_modulus(const debug_adaptor<Backend>& arg, const T& a)
375 {
376    using default_ops::eval_integer_modulus;
377    return eval_integer_modulus(arg.value(), a);
378 }
379
380 template <class Backend>
381 inline unsigned eval_lsb(const debug_adaptor<Backend>& arg)
382 {
383    using default_ops::eval_lsb;
384    return eval_lsb(arg.value());
385 }
386
387 template <class Backend>
388 inline unsigned eval_msb(const debug_adaptor<Backend>& arg)
389 {
390    using default_ops::eval_msb;
391    return eval_msb(arg.value());
392 }
393
394 template <class Backend>
395 inline bool eval_bit_test(const debug_adaptor<Backend>& arg, unsigned a)
396 {
397    using default_ops::eval_bit_test;
398    return eval_bit_test(arg.value(), a);
399 }
400
401 template <class Backend>
402 inline void eval_bit_set(const debug_adaptor<Backend>& arg, unsigned a)
403 {
404    using default_ops::eval_bit_set;
405    eval_bit_set(arg.value(), a);
406    arg.update_view();\
407 }
408 template <class Backend>
409 inline void eval_bit_unset(const debug_adaptor<Backend>& arg, unsigned a)
410 {
411    using default_ops::eval_bit_unset;
412    eval_bit_unset(arg.value(), a);
413    arg.update_view();\
414 }
415 template <class Backend>
416 inline void eval_bit_flip(const debug_adaptor<Backend>& arg, unsigned a)
417 {
418    using default_ops::eval_bit_flip;
419    eval_bit_flip(arg.value(), a);
420    arg.update_view();\
421 }
422
423 NON_MEMBER_OP3(gcd, "gcd");
424 NON_MEMBER_OP3(lcm, "lcm");
425 NON_MEMBER_OP4(powm, "powm");
426
427 /*********************************************************************
428 *
429 * abs/fabs:
430 *
431 *********************************************************************/
432
433 NON_MEMBER_OP2(abs, "abs");
434 NON_MEMBER_OP2(fabs, "fabs");
435
436 /*********************************************************************
437 *
438 * Floating point functions:
439 *
440 *********************************************************************/
441
442 NON_MEMBER_OP2(trunc, "trunc");
443 NON_MEMBER_OP2(round, "round");
444 NON_MEMBER_OP2(exp, "exp");
445 NON_MEMBER_OP2(log, "log");
446 NON_MEMBER_OP2(log10, "log10");
447 NON_MEMBER_OP2(sin, "sin");
448 NON_MEMBER_OP2(cos, "cos");
449 NON_MEMBER_OP2(tan, "tan");
450 NON_MEMBER_OP2(asin, "asin");
451 NON_MEMBER_OP2(acos, "acos");
452 NON_MEMBER_OP2(atan, "atan");
453 NON_MEMBER_OP2(sinh, "sinh");
454 NON_MEMBER_OP2(cosh, "cosh");
455 NON_MEMBER_OP2(tanh, "tanh");
456 NON_MEMBER_OP3(fmod, "fmod");
457 NON_MEMBER_OP3(pow, "pow");
458 NON_MEMBER_OP3(atan2, "atan2");
459
460 template <class Backend>
461 int eval_signbit(const debug_adaptor<Backend>& val)
462 {
463    return eval_signbit(val.value());
464 }
465
466 template <class Backend>
467 std::size_t hash_value(const debug_adaptor<Backend>& val)
468 {
469    return hash_value(val.value());
470 }
471
472 } // namespace backends
473
474 using backends::debug_adaptor;
475
476 template<class Backend>
477 struct number_category<backends::debug_adaptor<Backend> > : public number_category<Backend> {};
478
479 #ifdef BOOST_MSVC
480 #pragma warning(pop)
481 #endif
482 }} // namespaces
483
484 namespace std{
485
486 template <class Backend, boost::multiprecision::expression_template_option ExpressionTemplates>
487 class numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::debug_adaptor<Backend>, ExpressionTemplates> >
488    : public std::numeric_limits<boost::multiprecision::number<Backend, ExpressionTemplates> >
489 {
490    typedef std::numeric_limits<boost::multiprecision::number<Backend, ExpressionTemplates> > base_type;
491    typedef boost::multiprecision::number<boost::multiprecision::backends::debug_adaptor<Backend>, ExpressionTemplates> number_type;
492 public:
493    static number_type (min)() BOOST_NOEXCEPT { return (base_type::min)(); }
494    static number_type (max)() BOOST_NOEXCEPT { return (base_type::max)(); }
495    static number_type lowest() BOOST_NOEXCEPT { return -(max)(); }
496    static number_type epsilon() BOOST_NOEXCEPT { return base_type::epsilon(); }
497    static number_type round_error() BOOST_NOEXCEPT { return epsilon() / 2; }
498    static number_type infinity() BOOST_NOEXCEPT { return base_type::infinity(); }
499    static number_type quiet_NaN() BOOST_NOEXCEPT { return base_type::quiet_NaN(); }
500    static number_type signaling_NaN() BOOST_NOEXCEPT { return base_type::signaling_NaN(); }
501    static number_type denorm_min() BOOST_NOEXCEPT { return base_type::denorm_min(); }
502 };
503
504 } // namespace std
505
506 namespace boost{ namespace math{
507
508 namespace policies{
509
510 template <class Backend, boost::multiprecision::expression_template_option ExpressionTemplates, class Policy>
511 struct precision< boost::multiprecision::number<boost::multiprecision::debug_adaptor<Backend>, ExpressionTemplates>, Policy>
512    : public precision<boost::multiprecision::number<Backend, ExpressionTemplates>, Policy>
513 {};
514
515 #undef NON_MEMBER_OP1
516 #undef NON_MEMBER_OP2
517 #undef NON_MEMBER_OP3
518 #undef NON_MEMBER_OP4
519
520 } // namespace policies
521
522 }} // namespaces boost::math
523
524
525 #endif