]> Dogcows Code - chaz/yoink/blobdiff - src/Moof/cml/et/scalar_promotions.h
version bump cml to version 1.0.2
[chaz/yoink] / src / Moof / cml / et / scalar_promotions.h
index 55d033ca5ef52a93053baa679618e5f00f2e8c39..5c6a4a1bc60aeeb2a4f6b374506dedc2d0c7a43b 100644 (file)
@@ -13,102 +13,133 @@ Boost Software License, v1.0 (see cml/LICENSE for details).
 #ifndef scalar_promotions_h
 #define scalar_promotions_h
 
+#include <complex>
 #include <cml/core/cml_meta.h>
 
 namespace cml {
 namespace et {
 
+/* The type promotion code below is a slightly modified version of:
+ * http://ubiety.uwaterloo.ca/~tveldhui/papers/techniques/techniques01.html
+ */
 namespace detail {
 
-/** @class IntPromote
- *  @brief Helper template to int-promote a type.
- */
-template<class T> struct IntPromote
-{
-    /* Signed -> signed int, unsigned -> unsigned int: */
-    typedef typename select_switch<T,
-            unsigned char,                       unsigned int,
-            unsigned short,                      unsigned int,
-            signed char,                         int,
-            char,                                int,
-            short,                               int,
-            T,                                   T
-    >::result   result;
+template<class T>
+struct precision_trait {
+    enum { precisionRank = 0,
+           knowPrecisionRank = 0 };
 };
 
-} // namespace detail
+#define DECLARE_PRECISION(T,rank)             \
+    template<>                                \
+    struct precision_trait< T > {             \
+        enum { precisionRank = rank,          \
+           knowPrecisionRank = 1 };           \
+    };
+
+DECLARE_PRECISION(int,100)
+DECLARE_PRECISION(unsigned int,200)
+DECLARE_PRECISION(long,300)
+DECLARE_PRECISION(unsigned long,400)
+
+DECLARE_PRECISION(long long,425)
+DECLARE_PRECISION(unsigned long long,475)
+
+DECLARE_PRECISION(float,500)
+DECLARE_PRECISION(double,600)
+DECLARE_PRECISION(long double,700)
+DECLARE_PRECISION(std::complex<float>,800)
+DECLARE_PRECISION(std::complex<double>,900)
+DECLARE_PRECISION(std::complex<long double>,1000)
+
+template<class T>
+struct autopromote_trait {
+    typedef T T_numtype;
+};
 
-/** @class ScalarPromote
- *  @brief Template for compile-time type promotion via C promotion rules.
- */
-template<class E1_in, class E2_in> struct ScalarPromote
-{
+#define DECLARE_AUTOPROMOTE(T1,T2)        \
+    template<>                            \
+    struct autopromote_trait<T1> {        \
+      typedef T2 T_numtype;               \
+    };
+
+// These are the odd cases where small integer types
+// are automatically promoted to int or unsigned int for
+// arithmetic.
+DECLARE_AUTOPROMOTE(bool, int)
+DECLARE_AUTOPROMOTE(char, int)
+DECLARE_AUTOPROMOTE(unsigned char, int)
+DECLARE_AUTOPROMOTE(short int, int)
+DECLARE_AUTOPROMOTE(short unsigned int, unsigned int)
+
+template<class T1, class T2, int promoteToT1>
+struct promote2 {
+    typedef T1 T_promote;
+};
 
-    /* Integral-promote the types (if possible). */
-    typedef typename detail::IntPromote<E1_in>::result  E1;
-    typedef typename detail::IntPromote<E2_in>::result  E2;
-
-    /* If sizeof(long) == sizeof(unsigned int), promote to unsigned long.
-     * Otherwise, sizeof(long) > sizeof(int), so promote to long.
-     */
-    typedef typename select_if<sizeof(long) == sizeof(unsigned int),
-            unsigned long,
-            long
-    >::result   uint_promotion;
-
-    /* Do the selection on the promoted types: */
-    typedef typename select_switch<
-        type_pair<E1,E2>,
-
-#if defined(CML_USE_LONG_DOUBLE)
-        type_pair<long double,long double>,       long double,
-        type_pair<long double,E2>,                long double,
-        type_pair<E1,long double>,                long double,
-#endif
+template<class T1, class T2>
+struct promote2<T1,T2,0> {
+    typedef T2 T_promote;
+};
 
-        type_pair<double,double>,                 double,
-        type_pair<double,E2>,                     double,
-        type_pair<E1,double>,                     double,
+template<class T1_orig, class T2_orig>
+struct promote_trait {
 
-        type_pair<float,float>,                   float,
-        type_pair<float,E2>,                      float,
-        type_pair<E1,float>,                      float,
+    // Need to remove const-ness:
+    typedef typename cml::remove_const<T1_orig>::type T1_non_const;
+    typedef typename cml::remove_const<T2_orig>::type T2_non_const;
 
-        type_pair<E1,E2>,                         void
+    // Handle promotion of small integers to int/unsigned int
+    typedef typename autopromote_trait<T1_non_const>::T_numtype T1;
+    typedef typename autopromote_trait<T2_non_const>::T_numtype T2;
 
-    >::result   float_filter;
+    // True if T1 is higher ranked
+    enum {
+      T1IsBetter =
+        (int) precision_trait<T1>::precisionRank >
+          (int) precision_trait<T2>::precisionRank,
 
-    /* The promoted integral types really matter here: */
-    typedef typename select_switch<
-        type_pair<E1,E2>,
+    // True if we know ranks for both T1 and T2
+      knowBothRanks =
+        precision_trait<T1>::knowPrecisionRank
+      && precision_trait<T2>::knowPrecisionRank,
 
-        type_pair<unsigned long,unsigned long>,   unsigned long,
-        type_pair<unsigned long,E2>,              unsigned long,
-        type_pair<E1,unsigned long>,              unsigned long,
+    // True if we know T1 but not T2
+      knowT1butNotT2 =  precision_trait<T1>::knowPrecisionRank
+        && !(precision_trait<T2>::knowPrecisionRank),
 
-        type_pair<long,long>,                     long,
-        type_pair<long,unsigned int>,             uint_promotion,
-        type_pair<unsigned int,long>,             uint_promotion,
+    // True if we know T2 but not T1
+      knowT2butNotT1 =  precision_trait<T2>::knowPrecisionRank
+        && !(precision_trait<T1>::knowPrecisionRank),
 
-        type_pair<long,E2>,                       long,
-        type_pair<E1,long>,                       long,
+    // True if T1 is bigger than T2
+      T1IsLarger = sizeof(T1) >= sizeof(T2),
 
-        type_pair<unsigned int,unsigned int>,     unsigned int,
-        type_pair<unsigned int,E2>,               unsigned int,
-        type_pair<E1,unsigned int>,               unsigned int,
+    // We know T1 but not T2: true
+    // We know T2 but not T1: false
+    // Otherwise, if T1 is bigger than T2: true
+      defaultPromotion = knowT1butNotT2 ? false :
+         (knowT2butNotT1 ? true : T1IsLarger)
+    };
 
-        type_pair<int,int>,                       int,
-        type_pair<int,E2>,                        int,
-        type_pair<E1,int>,                        int,
+    // If we have both ranks, then use them.
+    // If we have only one rank, then use the unknown type.
+    // If we have neither rank, then promote to the larger type.
 
-        type_pair<E1,E2>,                         void
+    enum {
+      promoteToT1 = (knowBothRanks ? T1IsBetter : defaultPromotion) 
+                        ? 1 : 0
+    };
 
-    >::result   int_filter;
+    typedef typename promote2<T1,T2,promoteToT1>::T_promote T_promote;
+};
 
-    /* Deduce the final type: */
-    typedef typename select_if<
-        same_type<float_filter,void>::is_true,
-        int_filter, float_filter>::result         type;
+} // namespace detail
+
+/** Defers to detail::promote_trait<>. */
+template<class E1, class E2> struct ScalarPromote
+{
+    typedef typename detail::promote_trait<E1,E2>::T_promote type;
 };
 
 } // namespace et
This page took 0.025172 seconds and 4 git commands to generate.