]> Dogcows Code - chaz/yoink/blob - src/Moof/cml/et/scalar_promotions.h
bb6f8a271e7eed965376895a5065d21fda7b7b54
[chaz/yoink] / src / Moof / cml / et / scalar_promotions.h
1 /* -*- C++ -*- ------------------------------------------------------------
2
3 Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/
4
5 The Configurable Math Library (CML) is distributed under the terms of the
6 Boost Software License, v1.0 (see cml/LICENSE for details).
7
8 *-----------------------------------------------------------------------*/
9 /** @file
10 * @brief
11 */
12
13 #ifndef scalar_promotions_h
14 #define scalar_promotions_h
15
16 #include <complex>
17 #include <cml/core/cml_meta.h>
18
19 namespace cml {
20 namespace et {
21
22 // #define CML_USE_OLD_SCALAR_PROMOTIONS
23 #if !defined(CML_USE_OLD_SCALAR_PROMOTIONS)
24
25 /* The type promotion code below is a slightly modified version of:
26 * http://ubiety.uwaterloo.ca/~tveldhui/papers/techniques/techniques01.html
27 */
28 namespace detail {
29
30 template<class T>
31 struct precision_trait {
32 enum { precisionRank = 0,
33 knowPrecisionRank = 0 };
34 };
35
36 #define DECLARE_PRECISION(T,rank) \
37 template<> \
38 struct precision_trait< T > { \
39 enum { precisionRank = rank, \
40 knowPrecisionRank = 1 }; \
41 };
42
43 DECLARE_PRECISION(int,100)
44 DECLARE_PRECISION(unsigned int,200)
45 DECLARE_PRECISION(long,300)
46 DECLARE_PRECISION(unsigned long,400)
47
48 DECLARE_PRECISION(long long,425)
49 DECLARE_PRECISION(unsigned long long,475)
50
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)
57
58 template<class T>
59 struct autopromote_trait {
60 typedef T T_numtype;
61 };
62
63 #define DECLARE_AUTOPROMOTE(T1,T2) \
64 template<> \
65 struct autopromote_trait<T1> { \
66 typedef T2 T_numtype; \
67 };
68
69 // These are the odd cases where small integer types
70 // are automatically promoted to int or unsigned int for
71 // arithmetic.
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)
77
78 template<class T1, class T2, int promoteToT1>
79 struct promote2 {
80 typedef T1 T_promote;
81 };
82
83 template<class T1, class T2>
84 struct promote2<T1,T2,0> {
85 typedef T2 T_promote;
86 };
87
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;
93
94 // True if T1 is higher ranked
95 enum {
96 T1IsBetter =
97 (int) precision_trait<T1>::precisionRank >
98 (int) precision_trait<T2>::precisionRank,
99
100 // True if we know ranks for both T1 and T2
101 knowBothRanks =
102 precision_trait<T1>::knowPrecisionRank
103 && precision_trait<T2>::knowPrecisionRank,
104
105 // True if we know T1 but not T2
106 knowT1butNotT2 = precision_trait<T1>::knowPrecisionRank
107 && !(precision_trait<T2>::knowPrecisionRank),
108
109 // True if we know T2 but not T1
110 knowT2butNotT1 = precision_trait<T2>::knowPrecisionRank
111 && !(precision_trait<T1>::knowPrecisionRank),
112
113 // True if T1 is bigger than T2
114 T1IsLarger = sizeof(T1) >= sizeof(T2),
115
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)
121 };
122
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.
126
127 enum {
128 promoteToT1 = (knowBothRanks ? T1IsBetter : defaultPromotion)
129 ? 1 : 0
130 };
131
132 typedef typename promote2<T1,T2,promoteToT1>::T_promote T_promote;
133 };
134
135 } // namespace detail
136
137 /** Defers to detail::promote_trait<>. */
138 template<class E1, class E2> struct ScalarPromote
139 {
140 typedef typename detail::promote_trait<E1,E2>::T_promote type;
141 };
142
143 #else
144
145 namespace detail {
146
147 /** @class IntPromote
148 * @brief Helper template to int-promote a type.
149 */
150 template<class T> struct IntPromote
151 {
152 /* Signed -> signed int, unsigned -> unsigned int: */
153 typedef typename select_switch<T,
154 unsigned char, unsigned int,
155 unsigned short, unsigned int,
156 signed char, int,
157 char, int,
158 short, int,
159 T, T
160 >::result result;
161 };
162
163 } // namespace detail
164
165 /** @class ScalarPromote
166 * @brief Template for compile-time type promotion via C promotion rules.
167 */
168 template<class E1_in, class E2_in> struct ScalarPromote
169 {
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;
173
174 /* If sizeof(long) == sizeof(unsigned int), promote to unsigned long.
175 * Otherwise, sizeof(long) > sizeof(int), so promote to long.
176 */
177 typedef typename select_if<sizeof(long) == sizeof(unsigned int),
178 unsigned long,
179 long
180 >::result uint_promotion;
181
182 /* Do the selection on the promoted types: */
183 typedef typename select_switch<
184 type_pair<E1,E2>,
185
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,
190 #endif
191
192 type_pair<double,double>, double,
193 type_pair<double,E2>, double,
194 type_pair<E1,double>, double,
195
196 type_pair<float,float>, float,
197 type_pair<float,E2>, float,
198 type_pair<E1,float>, float,
199
200 type_pair<E1,E2>, void
201
202 >::result float_filter;
203
204 /* The promoted integral types really matter here: */
205 typedef typename select_switch<
206 type_pair<E1,E2>,
207
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,
211
212 type_pair<long,long>, long,
213 type_pair<long,unsigned int>, uint_promotion,
214 type_pair<unsigned int,long>, uint_promotion,
215
216 type_pair<long,E2>, long,
217 type_pair<E1,long>, long,
218
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,
222
223 type_pair<int,int>, int,
224 type_pair<int,E2>, int,
225 type_pair<E1,int>, int,
226
227 type_pair<E1,E2>, void
228
229 >::result int_filter;
230
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;
235 };
236 #endif
237
238 } // namespace et
239 } // namespace cml
240
241 #endif
242
243 // -------------------------------------------------------------------------
244 // vim:ft=cpp
This page took 0.039838 seconds and 3 git commands to generate.