]> git.donarmstrong.com Git - rsem.git/blob - boost/math/tools/promotion.hpp
RSEM Source Codes
[rsem.git] / boost / math / tools / promotion.hpp
1 // boost\math\tools\promotion.hpp
2
3 // Copyright John Maddock 2006.
4 // Copyright Paul A. Bristow 2006.
5
6 // Use, modification and distribution are subject to the
7 // Boost Software License, Version 1.0.
8 // (See accompanying file LICENSE_1_0.txt
9 // or copy at http://www.boost.org/LICENSE_1_0.txt)
10
11 // Promote arguments functions to allow math functions to have arguments
12 // provided as integer OR real (floating-point, built-in or UDT)
13 // (called ArithmeticType in functions that use promotion)
14 // that help to reduce the risk of creating multiple instantiations.
15 // Allows creation of an inline wrapper that forwards to a foo(RT, RT) function,
16 // so you never get to instantiate any mixed foo(RT, IT) functions.
17
18 #ifndef BOOST_MATH_PROMOTION_HPP
19 #define BOOST_MATH_PROMOTION_HPP
20
21 #ifdef _MSC_VER
22 #pragma once
23 #endif
24
25 // Boost type traits:
26 #include <boost/math/tools/config.hpp>
27 #include <boost/type_traits/is_floating_point.hpp> // for boost::is_floating_point;
28 #include <boost/type_traits/is_integral.hpp> // for boost::is_integral
29 #include <boost/type_traits/is_convertible.hpp> // for boost::is_convertible
30 #include <boost/type_traits/is_same.hpp>// for boost::is_same
31 #include <boost/type_traits/remove_cv.hpp>// for boost::remove_cv
32 // Boost Template meta programming:
33 #include <boost/mpl/if.hpp> // for boost::mpl::if_c.
34 #include <boost/mpl/and.hpp> // for boost::mpl::if_c.
35 #include <boost/mpl/or.hpp> // for boost::mpl::if_c.
36
37 #ifdef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
38 #include <boost/static_assert.hpp>
39 #endif
40
41 namespace boost
42 {
43   namespace math
44   {
45     namespace tools
46     {
47       // If either T1 or T2 is an integer type,
48       // pretend it was a double (for the purposes of further analysis).
49       // Then pick the wider of the two floating-point types
50       // as the actual signature to forward to.
51       // For example:
52       // foo(int, short) -> double foo(double, double);
53       // foo(int, float) -> double foo(double, double);
54       // Note: NOT float foo(float, float)
55       // foo(int, double) -> foo(double, double);
56       // foo(double, float) -> double foo(double, double);
57       // foo(double, float) -> double foo(double, double);
58       // foo(any-int-or-float-type, long double) -> foo(long double, long double);
59       // but ONLY float foo(float, float) is unchanged.
60       // So the only way to get an entirely float version is to call foo(1.F, 2.F),
61       // But since most (all?) the math functions convert to double internally,
62       // probably there would not be the hoped-for gain by using float here.
63
64       // This follows the C-compatible conversion rules of pow, etc
65       // where pow(int, float) is converted to pow(double, double).
66
67       template <class T>
68       struct promote_arg
69       { // If T is integral type, then promote to double.
70         typedef typename mpl::if_<is_integral<T>, double, T>::type type;
71       };
72       // These full specialisations reduce mpl::if_ usage and speed up
73       // compilation:
74       template <> struct promote_arg<float> { typedef float type; };
75       template <> struct promote_arg<double>{ typedef double type; };
76       template <> struct promote_arg<long double> { typedef long double type; };
77       template <> struct promote_arg<int> {  typedef double type; };
78
79       template <class T1, class T2>
80       struct promote_args_2
81       { // Promote, if necessary, & pick the wider of the two floating-point types.
82         // for both parameter types, if integral promote to double.
83         typedef typename promote_arg<T1>::type T1P; // T1 perhaps promoted.
84         typedef typename promote_arg<T2>::type T2P; // T2 perhaps promoted.
85
86         typedef typename mpl::if_<
87           typename mpl::and_<is_floating_point<T1P>, is_floating_point<T2P> >::type, // both T1P and T2P are floating-point?
88           typename mpl::if_< typename mpl::or_<is_same<long double, T1P>, is_same<long double, T2P> >::type, // either long double?
89             long double, // then result type is long double.
90             typename mpl::if_< typename mpl::or_<is_same<double, T1P>, is_same<double, T2P> >::type, // either double?
91             double, // result type is double.
92           float // else result type is float.
93           >::type
94           >::type,
95           // else one or the other is a user-defined type:
96           typename mpl::if_< ::boost::is_convertible<T1P, T2P>, T2P, T1P>::type>::type type;
97       }; // promote_arg2
98       // These full specialisations reduce mpl::if_ usage and speed up
99       // compilation:
100       template <> struct promote_args_2<float, float> { typedef float type; };
101       template <> struct promote_args_2<double, double>{ typedef double type; };
102       template <> struct promote_args_2<long double, long double> { typedef long double type; };
103       template <> struct promote_args_2<int, int> {  typedef double type; };
104       template <> struct promote_args_2<int, float> {  typedef double type; };
105       template <> struct promote_args_2<float, int> {  typedef double type; };
106       template <> struct promote_args_2<int, double> {  typedef double type; };
107       template <> struct promote_args_2<double, int> {  typedef double type; };
108       template <> struct promote_args_2<int, long double> {  typedef long double type; };
109       template <> struct promote_args_2<long double, int> {  typedef long double type; };
110       template <> struct promote_args_2<float, double> {  typedef double type; };
111       template <> struct promote_args_2<double, float> {  typedef double type; };
112       template <> struct promote_args_2<float, long double> {  typedef long double type; };
113       template <> struct promote_args_2<long double, float> {  typedef long double type; };
114       template <> struct promote_args_2<double, long double> {  typedef long double type; };
115       template <> struct promote_args_2<long double, double> {  typedef long double type; };
116
117       template <class T1, class T2=float, class T3=float, class T4=float, class T5=float, class T6=float>
118       struct promote_args
119       {
120          typedef typename promote_args_2<
121             typename remove_cv<T1>::type,
122             typename promote_args_2<
123                typename remove_cv<T2>::type,
124                typename promote_args_2<
125                   typename remove_cv<T3>::type,
126                   typename promote_args_2<
127                      typename remove_cv<T4>::type,
128                      typename promote_args_2<
129                         typename remove_cv<T5>::type, typename remove_cv<T6>::type
130                      >::type
131                   >::type
132                >::type
133             >::type
134          >::type type;
135
136 #ifdef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
137          //
138          // Guard against use of long double if it's not supported:
139          //
140          BOOST_STATIC_ASSERT((0 == ::boost::is_same<type, long double>::value));
141 #endif
142       };
143
144     } // namespace tools
145   } // namespace math
146 } // namespace boost
147
148 #endif // BOOST_MATH_PROMOTION_HPP
149