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