scalar_promotions.h

Go to the documentation of this file.
00001 /* -*- C++ -*- ------------------------------------------------------------
00002  
00003 Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/
00004 
00005 The Configurable Math Library (CML) is distributed under the terms of the
00006 Boost Software License, v1.0 (see cml/LICENSE for details).
00007 
00008  *-----------------------------------------------------------------------*/
00013 #ifndef scalar_promotions_h
00014 #define scalar_promotions_h
00015 
00016 #include <complex>
00017 #include <cml/core/cml_meta.h>
00018 
00019 namespace cml {
00020 namespace et {
00021 
00022 // #define CML_USE_OLD_SCALAR_PROMOTIONS
00023 #if !defined(CML_USE_OLD_SCALAR_PROMOTIONS)
00024 
00025 /* The type promotion code below is a slightly modified version of:
00026  * http://ubiety.uwaterloo.ca/~tveldhui/papers/techniques/techniques01.html
00027  */
00028 namespace detail {
00029 
00030 template<class T>
00031 struct precision_trait {
00032     enum { precisionRank = 0,
00033            knowPrecisionRank = 0 };
00034 };
00035 
00036 #define DECLARE_PRECISION(T,rank)             \
00037     template<>                                \
00038     struct precision_trait< T > {             \
00039         enum { precisionRank = rank,          \
00040            knowPrecisionRank = 1 };           \
00041     };
00042 
00043 DECLARE_PRECISION(int,100)
00044 DECLARE_PRECISION(unsigned int,200)
00045 DECLARE_PRECISION(long,300)
00046 DECLARE_PRECISION(unsigned long,400)
00047 
00048 DECLARE_PRECISION(long long,425)
00049 DECLARE_PRECISION(unsigned long long,475)
00050 
00051 DECLARE_PRECISION(float,500)
00052 DECLARE_PRECISION(double,600)
00053 DECLARE_PRECISION(long double,700)
00054 DECLARE_PRECISION(std::complex<float>,800)
00055 DECLARE_PRECISION(std::complex<double>,900)
00056 DECLARE_PRECISION(std::complex<long double>,1000)
00057 
00058 template<class T>
00059 struct autopromote_trait {
00060     typedef T T_numtype;
00061 };
00062 
00063 #define DECLARE_AUTOPROMOTE(T1,T2)        \
00064     template<>                            \
00065     struct autopromote_trait<T1> {        \
00066       typedef T2 T_numtype;               \
00067     };
00068 
00069 // These are the odd cases where small integer types
00070 // are automatically promoted to int or unsigned int for
00071 // arithmetic.
00072 DECLARE_AUTOPROMOTE(bool, int)
00073 DECLARE_AUTOPROMOTE(char, int)
00074 DECLARE_AUTOPROMOTE(unsigned char, int)
00075 DECLARE_AUTOPROMOTE(short int, int)
00076 DECLARE_AUTOPROMOTE(short unsigned int, unsigned int)
00077 
00078 template<class T1, class T2, int promoteToT1>
00079 struct promote2 {
00080     typedef T1 T_promote;
00081 };
00082 
00083 template<class T1, class T2>
00084 struct promote2<T1,T2,0> {
00085     typedef T2 T_promote;
00086 };
00087 
00088 template<class T1_orig, class T2_orig>
00089 struct promote_trait {
00090     // Handle promotion of small integers to int/unsigned int
00091     typedef typename autopromote_trait<T1_orig>::T_numtype T1;
00092     typedef typename autopromote_trait<T2_orig>::T_numtype T2;
00093 
00094     // True if T1 is higher ranked
00095     enum {
00096       T1IsBetter =
00097         (int) precision_trait<T1>::precisionRank >
00098           (int) precision_trait<T2>::precisionRank,
00099 
00100     // True if we know ranks for both T1 and T2
00101       knowBothRanks =
00102         precision_trait<T1>::knowPrecisionRank
00103       && precision_trait<T2>::knowPrecisionRank,
00104 
00105     // True if we know T1 but not T2
00106       knowT1butNotT2 =  precision_trait<T1>::knowPrecisionRank
00107         && !(precision_trait<T2>::knowPrecisionRank),
00108 
00109     // True if we know T2 but not T1
00110       knowT2butNotT1 =  precision_trait<T2>::knowPrecisionRank
00111         && !(precision_trait<T1>::knowPrecisionRank),
00112 
00113     // True if T1 is bigger than T2
00114       T1IsLarger = sizeof(T1) >= sizeof(T2),
00115 
00116     // We know T1 but not T2: true
00117     // We know T2 but not T1: false
00118     // Otherwise, if T1 is bigger than T2: true
00119       defaultPromotion = knowT1butNotT2 ? false :
00120          (knowT2butNotT1 ? true : T1IsLarger)
00121     };
00122 
00123     // If we have both ranks, then use them.
00124     // If we have only one rank, then use the unknown type.
00125     // If we have neither rank, then promote to the larger type.
00126 
00127     enum {
00128       promoteToT1 = (knowBothRanks ? T1IsBetter : defaultPromotion) 
00129                         ? 1 : 0
00130     };
00131 
00132     typedef typename promote2<T1,T2,promoteToT1>::T_promote T_promote;
00133 };
00134 
00135 } // namespace detail
00136 
00138 template<class E1, class E2> struct ScalarPromote
00139 {
00140     typedef typename detail::promote_trait<E1,E2>::T_promote type;
00141 };
00142 
00143 #else
00144 
00145 namespace detail {
00146 
00150 template<class T> struct IntPromote
00151 {
00152     /* Signed -> signed int, unsigned -> unsigned int: */
00153     typedef typename select_switch<T,
00154             unsigned char,                       unsigned int,
00155             unsigned short,                      unsigned int,
00156             signed char,                         int,
00157             char,                                int,
00158             short,                               int,
00159             T,                                   T
00160     >::result   result;
00161 };
00162 
00163 } // namespace detail
00164 
00168 template<class E1_in, class E2_in> struct ScalarPromote
00169 {
00170     /* Integral-promote the types (if possible). */
00171     typedef typename detail::IntPromote<E1_in>::result  E1;
00172     typedef typename detail::IntPromote<E2_in>::result  E2;
00173 
00174     /* If sizeof(long) == sizeof(unsigned int), promote to unsigned long.
00175      * Otherwise, sizeof(long) > sizeof(int), so promote to long.
00176      */
00177     typedef typename select_if<sizeof(long) == sizeof(unsigned int),
00178             unsigned long,
00179             long
00180     >::result   uint_promotion;
00181 
00182     /* Do the selection on the promoted types: */
00183     typedef typename select_switch<
00184         type_pair<E1,E2>,
00185 
00186 #if defined(CML_USE_LONG_DOUBLE)
00187         type_pair<long double,long double>,       long double,
00188         type_pair<long double,E2>,                long double,
00189         type_pair<E1,long double>,                long double,
00190 #endif
00191 
00192         type_pair<double,double>,                 double,
00193         type_pair<double,E2>,                     double,
00194         type_pair<E1,double>,                     double,
00195 
00196         type_pair<float,float>,                   float,
00197         type_pair<float,E2>,                      float,
00198         type_pair<E1,float>,                      float,
00199 
00200         type_pair<E1,E2>,                         void
00201 
00202     >::result   float_filter;
00203 
00204     /* The promoted integral types really matter here: */
00205     typedef typename select_switch<
00206         type_pair<E1,E2>,
00207 
00208         type_pair<unsigned long,unsigned long>,   unsigned long,
00209         type_pair<unsigned long,E2>,              unsigned long,
00210         type_pair<E1,unsigned long>,              unsigned long,
00211 
00212         type_pair<long,long>,                     long,
00213         type_pair<long,unsigned int>,             uint_promotion,
00214         type_pair<unsigned int,long>,             uint_promotion,
00215 
00216         type_pair<long,E2>,                       long,
00217         type_pair<E1,long>,                       long,
00218 
00219         type_pair<unsigned int,unsigned int>,     unsigned int,
00220         type_pair<unsigned int,E2>,               unsigned int,
00221         type_pair<E1,unsigned int>,               unsigned int,
00222 
00223         type_pair<int,int>,                       int,
00224         type_pair<int,E2>,                        int,
00225         type_pair<E1,int>,                        int,
00226 
00227         type_pair<E1,E2>,                         void
00228 
00229     >::result   int_filter;
00230 
00231     /* Deduce the final type: */
00232     typedef typename select_if<
00233         same_type<float_filter,void>::is_true,
00234         int_filter, float_filter>::result         type;
00235 };
00236 #endif
00237 
00238 } // namespace et
00239 } // namespace cml
00240 
00241 #endif
00242 
00243 // -------------------------------------------------------------------------
00244 // vim:ft=cpp

Generated on Sat Jul 18 19:35:20 2009 for CML 1.0 by  doxygen 1.5.9