1 /* -*- C++ -*- ------------------------------------------------------------
3 Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/
5 The Configurable Math Library (CML) is distributed under the terms of the
6 Boost Software License, v1.0 (see cml/LICENSE for details).
8 *-----------------------------------------------------------------------*/
13 #ifndef scalar_promotions_h
14 #define scalar_promotions_h
17 #include <cml/core/cml_meta.h>
22 // #define CML_USE_OLD_SCALAR_PROMOTIONS
23 #if !defined(CML_USE_OLD_SCALAR_PROMOTIONS)
25 /* The type promotion code below is a slightly modified version of:
26 * http://ubiety.uwaterloo.ca/~tveldhui/papers/techniques/techniques01.html
31 struct precision_trait
{
32 enum { precisionRank
= 0,
33 knowPrecisionRank
= 0 };
36 #define DECLARE_PRECISION(T,rank) \
38 struct precision_trait< T > { \
39 enum { precisionRank = rank, \
40 knowPrecisionRank = 1 }; \
43 DECLARE_PRECISION(int,100)
44 DECLARE_PRECISION(unsigned int,200)
45 DECLARE_PRECISION(long,300)
46 DECLARE_PRECISION(unsigned long,400)
48 DECLARE_PRECISION(long long,425)
49 DECLARE_PRECISION(unsigned long long,475)
51 DECLARE_PRECISION(float,500)
52 DECLARE_PRECISION(double,600)
53 DECLARE_PRECISION(long double,700)
54 DECLARE_PRECISION(std::complex<float>,800)
55 DECLARE_PRECISION(std::complex<double>,900)
56 DECLARE_PRECISION(std::complex<long double>,1000)
59 struct autopromote_trait
{
63 #define DECLARE_AUTOPROMOTE(T1,T2) \
65 struct autopromote_trait<T1> { \
66 typedef T2 T_numtype; \
69 // These are the odd cases where small integer types
70 // are automatically promoted to int or unsigned int for
72 DECLARE_AUTOPROMOTE(bool, int)
73 DECLARE_AUTOPROMOTE(char, int)
74 DECLARE_AUTOPROMOTE(unsigned char, int)
75 DECLARE_AUTOPROMOTE(short int, int)
76 DECLARE_AUTOPROMOTE(short unsigned int, unsigned int)
78 template<class T1
, class T2
, int promoteToT1
>
83 template<class T1
, class T2
>
84 struct promote2
<T1
,T2
,0> {
88 template<class T1_orig
, class T2_orig
>
89 struct promote_trait
{
90 // Handle promotion of small integers to int/unsigned int
91 typedef typename autopromote_trait
<T1_orig
>::T_numtype T1
;
92 typedef typename autopromote_trait
<T2_orig
>::T_numtype T2
;
94 // True if T1 is higher ranked
97 (int) precision_trait
<T1
>::precisionRank
>
98 (int) precision_trait
<T2
>::precisionRank
,
100 // True if we know ranks for both T1 and T2
102 precision_trait
<T1
>::knowPrecisionRank
103 && precision_trait
<T2
>::knowPrecisionRank
,
105 // True if we know T1 but not T2
106 knowT1butNotT2
= precision_trait
<T1
>::knowPrecisionRank
107 && !(precision_trait
<T2
>::knowPrecisionRank
),
109 // True if we know T2 but not T1
110 knowT2butNotT1
= precision_trait
<T2
>::knowPrecisionRank
111 && !(precision_trait
<T1
>::knowPrecisionRank
),
113 // True if T1 is bigger than T2
114 T1IsLarger
= sizeof(T1
) >= sizeof(T2
),
116 // We know T1 but not T2: true
117 // We know T2 but not T1: false
118 // Otherwise, if T1 is bigger than T2: true
119 defaultPromotion
= knowT1butNotT2
? false :
120 (knowT2butNotT1
? true : T1IsLarger
)
123 // If we have both ranks, then use them.
124 // If we have only one rank, then use the unknown type.
125 // If we have neither rank, then promote to the larger type.
128 promoteToT1
= (knowBothRanks
? T1IsBetter
: defaultPromotion
)
132 typedef typename promote2
<T1
,T2
,promoteToT1
>::T_promote T_promote
;
135 } // namespace detail
137 /** Defers to detail::promote_trait<>. */
138 template<class E1
, class E2
> struct ScalarPromote
140 typedef typename
detail::promote_trait
<E1
,E2
>::T_promote type
;
147 /** @class IntPromote
148 * @brief Helper template to int-promote a type.
150 template<class T
> struct IntPromote
152 /* Signed -> signed int, unsigned -> unsigned int: */
153 typedef typename select_switch
<T
,
154 unsigned char, unsigned int,
155 unsigned short, unsigned int,
163 } // namespace detail
165 /** @class ScalarPromote
166 * @brief Template for compile-time type promotion via C promotion rules.
168 template<class E1_in
, class E2_in
> struct ScalarPromote
170 /* Integral-promote the types (if possible). */
171 typedef typename
detail::IntPromote
<E1_in
>::result E1
;
172 typedef typename
detail::IntPromote
<E2_in
>::result E2
;
174 /* If sizeof(long) == sizeof(unsigned int), promote to unsigned long.
175 * Otherwise, sizeof(long) > sizeof(int), so promote to long.
177 typedef typename select_if
<sizeof(long) == sizeof(unsigned int),
180 >::result uint_promotion
;
182 /* Do the selection on the promoted types: */
183 typedef typename select_switch
<
186 #if defined(CML_USE_LONG_DOUBLE)
187 type_pair
<long double,long double>, long double,
188 type_pair
<long double,E2
>, long double,
189 type_pair
<E1
,long double>, long double,
192 type_pair
<double,double>, double,
193 type_pair
<double,E2
>, double,
194 type_pair
<E1
,double>, double,
196 type_pair
<float,float>, float,
197 type_pair
<float,E2
>, float,
198 type_pair
<E1
,float>, float,
200 type_pair
<E1
,E2
>, void
202 >::result float_filter
;
204 /* The promoted integral types really matter here: */
205 typedef typename select_switch
<
208 type_pair
<unsigned long,unsigned long>, unsigned long,
209 type_pair
<unsigned long,E2
>, unsigned long,
210 type_pair
<E1
,unsigned long>, unsigned long,
212 type_pair
<long,long>, long,
213 type_pair
<long,unsigned int>, uint_promotion
,
214 type_pair
<unsigned int,long>, uint_promotion
,
216 type_pair
<long,E2
>, long,
217 type_pair
<E1
,long>, long,
219 type_pair
<unsigned int,unsigned int>, unsigned int,
220 type_pair
<unsigned int,E2
>, unsigned int,
221 type_pair
<E1
,unsigned int>, unsigned int,
223 type_pair
<int,int>, int,
224 type_pair
<int,E2
>, int,
225 type_pair
<E1
,int>, int,
227 type_pair
<E1
,E2
>, void
229 >::result int_filter
;
231 /* Deduce the final type: */
232 typedef typename select_if
<
233 same_type
<float_filter
,void>::is_true
,
234 int_filter
, float_filter
>::result type
;
243 // -------------------------------------------------------------------------